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 srvsvc_server_info_t svinfo; 90 DWORD status; 91 int fd = -1; 92 int rc; 93 94 if (handle == NULL || server == NULL || server[0] == '\0' || 95 domain == NULL || username == NULL) 96 return (NT_STATUS_INTERNAL_ERROR); 97 98 /* In case the service was not registered... */ 99 if ((svc = ndr_svc_lookup_name(service)) == NULL) 100 return (NT_STATUS_INTERNAL_ERROR); 101 102 /* 103 * Set the default based on the assumption that most 104 * servers will be Windows 2000 or later. This used to 105 * try to get the actual server version, but that RPC 106 * is not necessarily allowed anymore, so don't bother. 107 */ 108 bzero(&svinfo, sizeof (srvsvc_server_info_t)); 109 svinfo.sv_platform_id = SV_PLATFORM_ID_NT; 110 svinfo.sv_version_major = 5; 111 svinfo.sv_version_minor = 0; 112 svinfo.sv_type = SV_TYPE_DEFAULT; 113 svinfo.sv_os = NATIVE_OS_WIN2000; 114 115 /* 116 * Some callers pass this when they want a NULL session. 117 * Todo: have callers pass an empty string for that. 118 */ 119 if (strcmp(username, MLSVC_ANON_USER) == 0) 120 username = ""; 121 122 /* 123 * Setup smbfs library handle, authenticate, connect to 124 * the IPC$ share. This will reuse an existing connection 125 * if the driver already has one for this combination of 126 * server, user, domain. It may return any of: 127 * NT_STATUS_BAD_NETWORK_PATH (get server addr) 128 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth) 129 * NT_STATUS_BAD_NETWORK_NAME (tcon) 130 */ 131 status = smbrdr_ctx_new(&ctx, server, domain, username); 132 if (status != NT_STATUS_SUCCESS) { 133 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new" 134 "(Srv=%s Dom=%s User=%s), %s (0x%x)", 135 server, domain, username, 136 xlate_nt_status(status), status); 137 /* Tell the DC Locator this DC failed. */ 138 smb_ddiscover_bad_dc(server); 139 goto errout; 140 } 141 142 /* 143 * Open the named pipe. 144 */ 145 fd = smb_fh_open(ctx, svc->endpoint, O_RDWR); 146 if (fd < 0) { 147 rc = errno; 148 syslog(LOG_DEBUG, "ndr_rpc_bind: " 149 "smb_fh_open (%s) err=%d", 150 svc->endpoint, rc); 151 switch (rc) { 152 case EACCES: 153 status = NT_STATUS_ACCESS_DENIED; 154 break; 155 default: 156 status = NT_STATUS_BAD_NETWORK_NAME; 157 break; 158 } 159 goto errout; 160 } 161 162 /* 163 * Setup the RPC client handle. 164 */ 165 if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) { 166 status = NT_STATUS_NO_MEMORY; 167 goto errout; 168 } 169 bzero(clnt, sizeof (ndr_client_t)); 170 171 clnt->handle = &handle->handle; 172 clnt->xa_init = ndr_xa_init; 173 clnt->xa_exchange = ndr_xa_exchange; 174 clnt->xa_read = ndr_xa_read; 175 clnt->xa_preserve = ndr_xa_preserve; 176 clnt->xa_destruct = ndr_xa_destruct; 177 clnt->xa_release = ndr_xa_release; 178 clnt->xa_private = ctx; 179 clnt->xa_fd = fd; 180 181 ndr_svc_binding_pool_init(&clnt->binding_list, 182 clnt->binding_pool, NDR_N_BINDING_POOL); 183 184 if ((clnt->heap = ndr_heap_create()) == NULL) { 185 status = NT_STATUS_NO_MEMORY; 186 goto errout; 187 } 188 189 /* 190 * Fill in the caller's handle. 191 */ 192 bzero(&handle->handle, sizeof (ndr_hdid_t)); 193 handle->clnt = clnt; 194 bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t)); 195 196 /* 197 * Do the OtW RPC bind. 198 */ 199 rc = ndr_clnt_bind(clnt, service, &clnt->binding); 200 switch (rc) { 201 case NDR_DRC_FAULT_OUT_OF_MEMORY: 202 status = NT_STATUS_NO_MEMORY; 203 break; 204 case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */ 205 status = NT_STATUS_INTERNAL_ERROR; 206 break; 207 default: 208 if (NDR_DRC_IS_FAULT(rc)) { 209 status = NT_STATUS_INVALID_PARAMETER; 210 break; 211 } 212 /* FALLTHROUGH */ 213 case NDR_DRC_OK: 214 return (NT_STATUS_SUCCESS); 215 } 216 217 syslog(LOG_DEBUG, "ndr_rpc_bind: " 218 "ndr_clnt_bind, %s (0x%x)", 219 xlate_nt_status(status), status); 220 221 errout: 222 handle->clnt = NULL; 223 if (clnt != NULL) { 224 ndr_heap_destroy(clnt->heap); 225 free(clnt); 226 } 227 if (ctx != NULL) { 228 if (fd != -1) 229 (void) smb_fh_close(fd); 230 smbrdr_ctx_free(ctx); 231 } 232 233 return (status); 234 } 235 236 /* 237 * Unbind and close the pipe to an RPC service. 238 * 239 * If the heap has been preserved we need to go through an xa release. 240 * The heap is preserved during an RPC call because that's where data 241 * returned from the server is stored. 242 * 243 * Otherwise we destroy the heap directly. 244 */ 245 void 246 ndr_rpc_unbind(mlsvc_handle_t *handle) 247 { 248 ndr_client_t *clnt = handle->clnt; 249 struct smb_ctx *ctx = clnt->xa_private; 250 251 if (clnt->heap_preserved) 252 ndr_clnt_free_heap(clnt); 253 else 254 ndr_heap_destroy(clnt->heap); 255 256 (void) smb_fh_close(clnt->xa_fd); 257 smbrdr_ctx_free(ctx); 258 free(clnt); 259 bzero(handle, sizeof (mlsvc_handle_t)); 260 } 261 262 /* 263 * Call the RPC function identified by opnum. The remote service is 264 * identified by the handle, which should have been initialized by 265 * ndr_rpc_bind. 266 * 267 * If the RPC call is successful (returns 0), the caller must call 268 * ndr_rpc_release to release the heap. Otherwise, we release the 269 * heap here. 270 */ 271 int 272 ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) 273 { 274 ndr_client_t *clnt = handle->clnt; 275 int rc; 276 277 if (ndr_rpc_get_heap(handle) == NULL) 278 return (-1); 279 280 rc = ndr_clnt_call(clnt->binding, opnum, params); 281 282 /* 283 * Always clear the nonull flag to ensure 284 * it is not applied to subsequent calls. 285 */ 286 clnt->nonull = B_FALSE; 287 288 if (NDR_DRC_IS_FAULT(rc)) { 289 ndr_rpc_release(handle); 290 return (-1); 291 } 292 293 return (0); 294 } 295 296 /* 297 * Outgoing strings should not be null terminated. 298 */ 299 void 300 ndr_rpc_set_nonull(mlsvc_handle_t *handle) 301 { 302 handle->clnt->nonull = B_TRUE; 303 } 304 305 /* 306 * Return a reference to the server info. 307 */ 308 const srvsvc_server_info_t * 309 ndr_rpc_server_info(mlsvc_handle_t *handle) 310 { 311 return (&handle->svinfo); 312 } 313 314 /* 315 * Return the RPC server OS level. 316 */ 317 uint32_t 318 ndr_rpc_server_os(mlsvc_handle_t *handle) 319 { 320 return (handle->svinfo.sv_os); 321 } 322 323 /* 324 * Get the session key from a bound RPC client handle. 325 * 326 * The key returned is the 16-byte "user session key" 327 * established by the underlying authentication protocol 328 * (either Kerberos or NTLM). This key is needed for 329 * SAM RPC calls such as SamrSetInformationUser, etc. 330 * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25. 331 * 332 * Returns zero (success) or an errno. 333 */ 334 int 335 ndr_rpc_get_ssnkey(mlsvc_handle_t *handle, 336 unsigned char *ssn_key, size_t len) 337 { 338 ndr_client_t *clnt = handle->clnt; 339 int rc; 340 341 if (clnt == NULL) 342 return (EINVAL); 343 344 rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len); 345 return (rc); 346 } 347 348 void * 349 ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size) 350 { 351 ndr_heap_t *heap; 352 353 if ((heap = ndr_rpc_get_heap(handle)) == NULL) 354 return (NULL); 355 356 return (ndr_heap_malloc(heap, size)); 357 } 358 359 ndr_heap_t * 360 ndr_rpc_get_heap(mlsvc_handle_t *handle) 361 { 362 ndr_client_t *clnt = handle->clnt; 363 364 if (clnt->heap == NULL) 365 clnt->heap = ndr_heap_create(); 366 367 return (clnt->heap); 368 } 369 370 /* 371 * Must be called by RPC clients to free the heap after a successful RPC 372 * call, i.e. ndr_rpc_call returned 0. The caller should take a copy 373 * of any data returned by the RPC prior to calling this function because 374 * returned data is in the heap. 375 */ 376 void 377 ndr_rpc_release(mlsvc_handle_t *handle) 378 { 379 ndr_client_t *clnt = handle->clnt; 380 381 if (clnt->heap_preserved) 382 ndr_clnt_free_heap(clnt); 383 else 384 ndr_heap_destroy(clnt->heap); 385 386 clnt->heap = NULL; 387 } 388 389 /* 390 * Returns true if the handle is null. 391 * Otherwise returns false. 392 */ 393 boolean_t 394 ndr_is_null_handle(mlsvc_handle_t *handle) 395 { 396 static ndr_hdid_t zero_handle; 397 398 if (handle == NULL || handle->clnt == NULL) 399 return (B_TRUE); 400 401 if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t))) 402 return (B_TRUE); 403 404 return (B_FALSE); 405 } 406 407 /* 408 * Returns true if the handle is the top level bind handle. 409 * Otherwise returns false. 410 */ 411 boolean_t 412 ndr_is_bind_handle(mlsvc_handle_t *handle) 413 { 414 return (handle->clnt->handle == &handle->handle); 415 } 416 417 /* 418 * Pass the client reference from parent to child. 419 */ 420 void 421 ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent) 422 { 423 child->clnt = parent->clnt; 424 bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t)); 425 } 426 427 void 428 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status) 429 { 430 ndr_service_t *svc; 431 char *name = "NDR RPC"; 432 char *s = "unknown"; 433 434 switch (NT_SC_SEVERITY(status)) { 435 case NT_STATUS_SEVERITY_SUCCESS: 436 s = "success"; 437 break; 438 case NT_STATUS_SEVERITY_INFORMATIONAL: 439 s = "info"; 440 break; 441 case NT_STATUS_SEVERITY_WARNING: 442 s = "warning"; 443 break; 444 case NT_STATUS_SEVERITY_ERROR: 445 s = "error"; 446 break; 447 } 448 449 if (handle) { 450 svc = handle->clnt->binding->service; 451 name = svc->name; 452 } 453 454 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)", 455 name, opnum, s, xlate_nt_status(status), status); 456 } 457 458 /* 459 * The following functions provide the client callback interface. 460 * If the caller hasn't provided a heap, create one here. 461 */ 462 static int 463 ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa) 464 { 465 ndr_stream_t *recv_nds = &mxa->recv_nds; 466 ndr_stream_t *send_nds = &mxa->send_nds; 467 ndr_heap_t *heap = clnt->heap; 468 int rc; 469 470 if (heap == NULL) { 471 if ((heap = ndr_heap_create()) == NULL) 472 return (-1); 473 474 clnt->heap = heap; 475 } 476 477 mxa->heap = heap; 478 479 rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap); 480 if (rc == 0) 481 rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT, 482 NDR_MODE_RETURN_RECV, heap); 483 484 if (rc != 0) { 485 nds_destruct(&mxa->recv_nds); 486 nds_destruct(&mxa->send_nds); 487 ndr_heap_destroy(mxa->heap); 488 mxa->heap = NULL; 489 clnt->heap = NULL; 490 return (-1); 491 } 492 493 if (clnt->nonull) 494 NDS_SETF(send_nds, NDS_F_NONULL); 495 496 return (0); 497 } 498 499 /* 500 * This is the entry pointy for an RPC client call exchange with 501 * a server, which will result in an smbrdr SmbTransact request. 502 * 503 * SmbTransact should return the number of bytes received, which 504 * we record as the PDU size, or a negative error code. 505 */ 506 static int 507 ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa) 508 { 509 ndr_stream_t *recv_nds = &mxa->recv_nds; 510 ndr_stream_t *send_nds = &mxa->send_nds; 511 int err, more, nbytes; 512 513 nbytes = recv_nds->pdu_max_size; 514 err = smb_fh_xactnp(clnt->xa_fd, 515 send_nds->pdu_size, (char *)send_nds->pdu_base_offset, 516 &nbytes, (char *)recv_nds->pdu_base_offset, &more); 517 if (err) { 518 recv_nds->pdu_size = 0; 519 return (-1); 520 } 521 522 recv_nds->pdu_size = nbytes; 523 return (0); 524 } 525 526 /* 527 * This entry point will be invoked if the xa-exchange response contained 528 * only the first fragment of a multi-fragment response. The RPC client 529 * code will then make repeated xa-read requests to obtain the remaining 530 * fragments, which will result in smbrdr SmbReadX requests. 531 * 532 * SmbReadX should return the number of bytes received, in which case we 533 * expand the PDU size to include the received data, or a negative error 534 * code. 535 */ 536 static int 537 ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa) 538 { 539 ndr_stream_t *nds = &mxa->recv_nds; 540 int len; 541 int nbytes; 542 543 if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0) 544 return (-1); 545 546 nbytes = smb_fh_read(clnt->xa_fd, 0, len, 547 (char *)nds->pdu_base_offset + nds->pdu_size); 548 549 if (nbytes < 0) 550 return (-1); 551 552 nds->pdu_size += nbytes; 553 554 if (nds->pdu_size > nds->pdu_max_size) { 555 nds->pdu_size = nds->pdu_max_size; 556 return (-1); 557 } 558 559 return (nbytes); 560 } 561 562 /* 563 * Preserve the heap so that the client application has access to data 564 * returned from the server after an RPC call. 565 */ 566 static void 567 ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa) 568 { 569 assert(clnt->heap == mxa->heap); 570 571 clnt->heap_preserved = B_TRUE; 572 mxa->heap = NULL; 573 } 574 575 /* 576 * Dispose of the transaction streams. If the heap has not been 577 * preserved, we can destroy it here. 578 */ 579 static void 580 ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa) 581 { 582 nds_destruct(&mxa->recv_nds); 583 nds_destruct(&mxa->send_nds); 584 585 if (!clnt->heap_preserved) { 586 ndr_heap_destroy(mxa->heap); 587 mxa->heap = NULL; 588 clnt->heap = NULL; 589 } 590 } 591 592 /* 593 * Dispose of a preserved heap. 594 */ 595 static void 596 ndr_xa_release(ndr_client_t *clnt) 597 { 598 if (clnt->heap_preserved) { 599 ndr_heap_destroy(clnt->heap); 600 clnt->heap = NULL; 601 clnt->heap_preserved = B_FALSE; 602 } 603 }