1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Client NDR RPC interface. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/errno.h> 33 #include <sys/fcntl.h> 34 #include <time.h> 35 #include <strings.h> 36 #include <assert.h> 37 #include <errno.h> 38 #include <thread.h> 39 #include <syslog.h> 40 #include <synch.h> 41 42 #include <netsmb/smbfs_api.h> 43 #include <smbsrv/libsmb.h> 44 #include <smbsrv/libsmbns.h> 45 #include <smbsrv/libmlrpc.h> 46 #include <smbsrv/libmlsvc.h> 47 #include <smbsrv/ndl/srvsvc.ndl> 48 #include <libsmbrdr.h> 49 #include <mlsvc.h> 50 51 static int ndr_xa_init(ndr_client_t *, ndr_xa_t *); 52 static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *); 53 static int ndr_xa_read(ndr_client_t *, ndr_xa_t *); 54 static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *); 55 static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *); 56 static void ndr_xa_release(ndr_client_t *); 57 58 59 /* 60 * This call must be made to initialize an RPC client structure and bind 61 * to the remote service before any RPCs can be exchanged with that service. 62 * 63 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle 64 * with the client context for an instance of the interface. The handle 65 * is zeroed to ensure that it doesn't look like a valid handle - 66 * handle content is provided by the remove service. 67 * 68 * The client points to this top-level handle so that we know when to 69 * unbind and teardown the connection. As each handle is initialized it 70 * will inherit a reference to the client context. 71 * 72 * Returns 0 or an NT_STATUS: 73 * NT_STATUS_BAD_NETWORK_PATH (get server addr) 74 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth) 75 * NT_STATUS_BAD_NETWORK_NAME (tcon, open) 76 * NT_STATUS_ACCESS_DENIED (open pipe) 77 * NT_STATUS_INVALID_PARAMETER (rpc bind) 78 * 79 * NT_STATUS_INTERNAL_ERROR (bad args etc) 80 * NT_STATUS_NO_MEMORY 81 */ 82 DWORD 83 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain, 84 char *username, const char *service) 85 { 86 struct smb_ctx *ctx = NULL; 87 ndr_client_t *clnt = NULL; 88 ndr_service_t *svc; 89 DWORD status; 90 int fd = -1; 91 int rc; 92 93 if (handle == NULL || server == NULL || server[0] == '\0' || 94 domain == NULL || username == NULL) 95 return (NT_STATUS_INTERNAL_ERROR); 96 97 /* In case the service was not registered... */ 98 if ((svc = ndr_svc_lookup_name(service)) == NULL) 99 return (NT_STATUS_INTERNAL_ERROR); 100 101 /* 102 * Some callers pass this when they want a NULL session. 103 * Todo: have callers pass an empty string for that. 104 */ 105 if (strcmp(username, MLSVC_ANON_USER) == 0) 106 username = ""; 107 108 /* 109 * Setup smbfs library handle, authenticate, connect to 110 * the IPC$ share. This will reuse an existing connection 111 * if the driver already has one for this combination of 112 * server, user, domain. It may return any of: 113 * NT_STATUS_BAD_NETWORK_PATH (get server addr) 114 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth) 115 * NT_STATUS_BAD_NETWORK_NAME (tcon) 116 */ 117 status = smbrdr_ctx_new(&ctx, server, domain, username); 118 if (status != NT_STATUS_SUCCESS) { 119 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new" 120 "(Srv=%s Dom=%s User=%s), %s (0x%x)", 121 server, domain, username, 122 xlate_nt_status(status), status); 123 /* Tell the DC Locator this DC failed. */ 124 smb_ddiscover_bad_dc(server); 125 goto errout; 126 } 127 128 /* 129 * Open the named pipe. 130 */ 131 fd = smb_fh_open(ctx, svc->endpoint, O_RDWR); 132 if (fd < 0) { 133 rc = errno; 134 syslog(LOG_DEBUG, "ndr_rpc_bind: " 135 "smb_fh_open (%s) err=%d", 136 svc->endpoint, rc); 137 switch (rc) { 138 case EACCES: 139 status = NT_STATUS_ACCESS_DENIED; 140 break; 141 default: 142 status = NT_STATUS_BAD_NETWORK_NAME; 143 break; 144 } 145 goto errout; 146 } 147 148 /* 149 * Setup the RPC client handle. 150 */ 151 if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) { 152 status = NT_STATUS_NO_MEMORY; 153 goto errout; 154 } 155 bzero(clnt, sizeof (ndr_client_t)); 156 157 clnt->handle = &handle->handle; 158 clnt->xa_init = ndr_xa_init; 159 clnt->xa_exchange = ndr_xa_exchange; 160 clnt->xa_read = ndr_xa_read; 161 clnt->xa_preserve = ndr_xa_preserve; 162 clnt->xa_destruct = ndr_xa_destruct; 163 clnt->xa_release = ndr_xa_release; 164 clnt->xa_private = ctx; 165 clnt->xa_fd = fd; 166 167 ndr_svc_binding_pool_init(&clnt->binding_list, 168 clnt->binding_pool, NDR_N_BINDING_POOL); 169 170 if ((clnt->heap = ndr_heap_create()) == NULL) { 171 status = NT_STATUS_NO_MEMORY; 172 goto errout; 173 } 174 175 /* 176 * Fill in the caller's handle. 177 */ 178 bzero(&handle->handle, sizeof (ndr_hdid_t)); 179 handle->clnt = clnt; 180 181 /* 182 * Do the OtW RPC bind. 183 */ 184 rc = ndr_clnt_bind(clnt, service, &clnt->binding); 185 switch (rc) { 186 case NDR_DRC_FAULT_OUT_OF_MEMORY: 187 status = NT_STATUS_NO_MEMORY; 188 break; 189 case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */ 190 status = NT_STATUS_INTERNAL_ERROR; 191 break; 192 default: 193 if (NDR_DRC_IS_FAULT(rc)) { 194 status = NT_STATUS_INVALID_PARAMETER; 195 break; 196 } 197 /* FALLTHROUGH */ 198 case NDR_DRC_OK: 199 return (NT_STATUS_SUCCESS); 200 } 201 202 syslog(LOG_DEBUG, "ndr_rpc_bind: " 203 "ndr_clnt_bind, %s (0x%x)", 204 xlate_nt_status(status), status); 205 206 errout: 207 handle->clnt = NULL; 208 if (clnt != NULL) { 209 ndr_heap_destroy(clnt->heap); 210 free(clnt); 211 } 212 if (ctx != NULL) { 213 if (fd != -1) 214 (void) smb_fh_close(fd); 215 smbrdr_ctx_free(ctx); 216 } 217 218 return (status); 219 } 220 221 /* 222 * Unbind and close the pipe to an RPC service. 223 * 224 * If the heap has been preserved we need to go through an xa release. 225 * The heap is preserved during an RPC call because that's where data 226 * returned from the server is stored. 227 * 228 * Otherwise we destroy the heap directly. 229 */ 230 void 231 ndr_rpc_unbind(mlsvc_handle_t *handle) 232 { 233 ndr_client_t *clnt = handle->clnt; 234 struct smb_ctx *ctx = clnt->xa_private; 235 236 if (clnt->heap_preserved) 237 ndr_clnt_free_heap(clnt); 238 else 239 ndr_heap_destroy(clnt->heap); 240 241 (void) smb_fh_close(clnt->xa_fd); 242 smbrdr_ctx_free(ctx); 243 free(clnt); 244 bzero(handle, sizeof (mlsvc_handle_t)); 245 } 246 247 /* 248 * Call the RPC function identified by opnum. The remote service is 249 * identified by the handle, which should have been initialized by 250 * ndr_rpc_bind. 251 * 252 * If the RPC call is successful (returns 0), the caller must call 253 * ndr_rpc_release to release the heap. Otherwise, we release the 254 * heap here. 255 */ 256 int 257 ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) 258 { 259 ndr_client_t *clnt = handle->clnt; 260 int rc; 261 262 if (ndr_rpc_get_heap(handle) == NULL) 263 return (-1); 264 265 rc = ndr_clnt_call(clnt->binding, opnum, params); 266 267 /* 268 * Always clear the nonull flag to ensure 269 * it is not applied to subsequent calls. 270 */ 271 clnt->nonull = B_FALSE; 272 273 if (NDR_DRC_IS_FAULT(rc)) { 274 ndr_rpc_release(handle); 275 return (-1); 276 } 277 278 return (0); 279 } 280 281 /* 282 * Outgoing strings should not be null terminated. 283 */ 284 void 285 ndr_rpc_set_nonull(mlsvc_handle_t *handle) 286 { 287 handle->clnt->nonull = B_TRUE; 288 } 289 290 /* 291 * Get the session key from a bound RPC client handle. 292 * 293 * The key returned is the 16-byte "user session key" 294 * established by the underlying authentication protocol 295 * (either Kerberos or NTLM). This key is needed for 296 * SAM RPC calls such as SamrSetInformationUser, etc. 297 * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25. 298 * 299 * Returns zero (success) or an errno. 300 */ 301 int 302 ndr_rpc_get_ssnkey(mlsvc_handle_t *handle, 303 unsigned char *ssn_key, size_t len) 304 { 305 ndr_client_t *clnt = handle->clnt; 306 int rc; 307 308 if (clnt == NULL) 309 return (EINVAL); 310 311 rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len); 312 return (rc); 313 } 314 315 void * 316 ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size) 317 { 318 ndr_heap_t *heap; 319 320 if ((heap = ndr_rpc_get_heap(handle)) == NULL) 321 return (NULL); 322 323 return (ndr_heap_malloc(heap, size)); 324 } 325 326 ndr_heap_t * 327 ndr_rpc_get_heap(mlsvc_handle_t *handle) 328 { 329 ndr_client_t *clnt = handle->clnt; 330 331 if (clnt->heap == NULL) 332 clnt->heap = ndr_heap_create(); 333 334 return (clnt->heap); 335 } 336 337 /* 338 * Must be called by RPC clients to free the heap after a successful RPC 339 * call, i.e. ndr_rpc_call returned 0. The caller should take a copy 340 * of any data returned by the RPC prior to calling this function because 341 * returned data is in the heap. 342 */ 343 void 344 ndr_rpc_release(mlsvc_handle_t *handle) 345 { 346 ndr_client_t *clnt = handle->clnt; 347 348 if (clnt->heap_preserved) 349 ndr_clnt_free_heap(clnt); 350 else 351 ndr_heap_destroy(clnt->heap); 352 353 clnt->heap = NULL; 354 } 355 356 /* 357 * Returns true if the handle is null. 358 * Otherwise returns false. 359 */ 360 boolean_t 361 ndr_is_null_handle(mlsvc_handle_t *handle) 362 { 363 static ndr_hdid_t zero_handle; 364 365 if (handle == NULL || handle->clnt == NULL) 366 return (B_TRUE); 367 368 if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t))) 369 return (B_TRUE); 370 371 return (B_FALSE); 372 } 373 374 /* 375 * Returns true if the handle is the top level bind handle. 376 * Otherwise returns false. 377 */ 378 boolean_t 379 ndr_is_bind_handle(mlsvc_handle_t *handle) 380 { 381 return (handle->clnt->handle == &handle->handle); 382 } 383 384 /* 385 * Pass the client reference from parent to child. 386 */ 387 void 388 ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent) 389 { 390 child->clnt = parent->clnt; 391 } 392 393 void 394 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status) 395 { 396 ndr_service_t *svc; 397 char *name = "NDR RPC"; 398 char *s = "unknown"; 399 400 switch (NT_SC_SEVERITY(status)) { 401 case NT_STATUS_SEVERITY_SUCCESS: 402 s = "success"; 403 break; 404 case NT_STATUS_SEVERITY_INFORMATIONAL: 405 s = "info"; 406 break; 407 case NT_STATUS_SEVERITY_WARNING: 408 s = "warning"; 409 break; 410 case NT_STATUS_SEVERITY_ERROR: 411 s = "error"; 412 break; 413 } 414 415 if (handle) { 416 svc = handle->clnt->binding->service; 417 name = svc->name; 418 } 419 420 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)", 421 name, opnum, s, xlate_nt_status(status), status); 422 } 423 424 /* 425 * The following functions provide the client callback interface. 426 * If the caller hasn't provided a heap, create one here. 427 */ 428 static int 429 ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa) 430 { 431 ndr_stream_t *recv_nds = &mxa->recv_nds; 432 ndr_stream_t *send_nds = &mxa->send_nds; 433 ndr_heap_t *heap = clnt->heap; 434 int rc; 435 436 if (heap == NULL) { 437 if ((heap = ndr_heap_create()) == NULL) 438 return (-1); 439 440 clnt->heap = heap; 441 } 442 443 mxa->heap = heap; 444 445 rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap); 446 if (rc == 0) 447 rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT, 448 NDR_MODE_RETURN_RECV, heap); 449 450 if (rc != 0) { 451 nds_destruct(&mxa->recv_nds); 452 nds_destruct(&mxa->send_nds); 453 ndr_heap_destroy(mxa->heap); 454 mxa->heap = NULL; 455 clnt->heap = NULL; 456 return (-1); 457 } 458 459 if (clnt->nonull) 460 NDS_SETF(send_nds, NDS_F_NONULL); 461 462 return (0); 463 } 464 465 /* 466 * This is the entry pointy for an RPC client call exchange with 467 * a server, which will result in an smbrdr SmbTransact request. 468 * 469 * SmbTransact should return the number of bytes received, which 470 * we record as the PDU size, or a negative error code. 471 */ 472 static int 473 ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa) 474 { 475 ndr_stream_t *recv_nds = &mxa->recv_nds; 476 ndr_stream_t *send_nds = &mxa->send_nds; 477 int err, more, nbytes; 478 479 nbytes = recv_nds->pdu_max_size; 480 err = smb_fh_xactnp(clnt->xa_fd, 481 send_nds->pdu_size, (char *)send_nds->pdu_base_offset, 482 &nbytes, (char *)recv_nds->pdu_base_offset, &more); 483 if (err) { 484 recv_nds->pdu_size = 0; 485 return (-1); 486 } 487 488 recv_nds->pdu_size = nbytes; 489 return (0); 490 } 491 492 /* 493 * This entry point will be invoked if the xa-exchange response contained 494 * only the first fragment of a multi-fragment response. The RPC client 495 * code will then make repeated xa-read requests to obtain the remaining 496 * fragments, which will result in smbrdr SmbReadX requests. 497 * 498 * SmbReadX should return the number of bytes received, in which case we 499 * expand the PDU size to include the received data, or a negative error 500 * code. 501 */ 502 static int 503 ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa) 504 { 505 ndr_stream_t *nds = &mxa->recv_nds; 506 int len; 507 int nbytes; 508 509 if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0) 510 return (-1); 511 512 nbytes = smb_fh_read(clnt->xa_fd, 0, len, 513 (char *)nds->pdu_base_offset + nds->pdu_size); 514 515 if (nbytes < 0) 516 return (-1); 517 518 nds->pdu_size += nbytes; 519 520 if (nds->pdu_size > nds->pdu_max_size) { 521 nds->pdu_size = nds->pdu_max_size; 522 return (-1); 523 } 524 525 return (nbytes); 526 } 527 528 /* 529 * Preserve the heap so that the client application has access to data 530 * returned from the server after an RPC call. 531 */ 532 static void 533 ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa) 534 { 535 assert(clnt->heap == mxa->heap); 536 537 clnt->heap_preserved = B_TRUE; 538 mxa->heap = NULL; 539 } 540 541 /* 542 * Dispose of the transaction streams. If the heap has not been 543 * preserved, we can destroy it here. 544 */ 545 static void 546 ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa) 547 { 548 nds_destruct(&mxa->recv_nds); 549 nds_destruct(&mxa->send_nds); 550 551 if (!clnt->heap_preserved) { 552 ndr_heap_destroy(mxa->heap); 553 mxa->heap = NULL; 554 clnt->heap = NULL; 555 } 556 } 557 558 /* 559 * Dispose of a preserved heap. 560 */ 561 static void 562 ndr_xa_release(ndr_client_t *clnt) 563 { 564 if (clnt->heap_preserved) { 565 ndr_heap_destroy(clnt->heap); 566 clnt->heap = NULL; 567 clnt->heap_preserved = B_FALSE; 568 } 569 }