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