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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This module provides the interface to NDR RPC. 28 */ 29 30 #include <sys/stat.h> 31 #include <sys/door.h> 32 #include <sys/door_data.h> 33 #include <sys/uio.h> 34 #include <sys/ksynch.h> 35 #include <smbsrv/smb_incl.h> 36 #include <smbsrv/smb_xdr.h> 37 38 #define SMB_OPIPE_ISOPEN(OPIPE) \ 39 (((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \ 40 ((OPIPE)->p_hdr.oh_fid)) 41 42 extern volatile uint32_t smb_fids; 43 44 static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 45 static char *smb_opipe_lookup(const char *path); 46 static uint32_t smb_opipe_fid(void); 47 static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t); 48 static void smb_opipe_enter(smb_opipe_t *); 49 static void smb_opipe_exit(smb_opipe_t *); 50 51 static door_handle_t smb_opipe_door_hd = NULL; 52 static int smb_opipe_door_id = -1; 53 static uint64_t smb_opipe_door_ncall = 0; 54 static kmutex_t smb_opipe_door_mutex; 55 static kcondvar_t smb_opipe_door_cv; 56 57 static int smb_opipe_door_call(smb_opipe_t *); 58 static int smb_opipe_door_upcall(smb_opipe_t *); 59 60 /* 61 * smb_opipe_open 62 * 63 * Open a well-known RPC named pipe. This routine should be called if 64 * a file open is requested on a share of type STYPE_IPC. 65 * If we recognize the pipe, we setup a new ofile. 66 * 67 * Returns 0 on success, Otherwise an NT status is returned to indicate 68 * an error. 69 */ 70 int 71 smb_opipe_open(smb_request_t *sr) 72 { 73 open_param_t *op = &sr->arg.open; 74 smb_ofile_t *of; 75 smb_opipe_t *opipe; 76 smb_opipe_hdr_t hdr; 77 smb_error_t err; 78 char *pipe_name; 79 80 if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL) 81 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 82 83 op->create_options = 0; 84 85 of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op, 86 SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 87 88 if (of == NULL) 89 return (err.status); 90 91 if (!smb_tree_is_connected(sr->tid_tree)) { 92 smb_ofile_close(of, 0); 93 smb_ofile_release(of); 94 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 95 } 96 97 op->dsize = 0x01000; 98 op->dattr = FILE_ATTRIBUTE_NORMAL; 99 op->ftype = SMB_FTYPE_MESG_PIPE; 100 op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 101 op->devstate = SMB_PIPE_READMODE_MESSAGE 102 | SMB_PIPE_TYPE_MESSAGE 103 | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 104 op->fileid = of->f_fid; 105 106 sr->smb_fid = of->f_fid; 107 sr->fid_ofile = of; 108 109 opipe = of->f_pipe; 110 mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 111 cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 112 smb_opipe_enter(opipe); 113 114 opipe->p_name = pipe_name; 115 opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 116 117 /* 118 * p_data points to the offset within p_doorbuf at which 119 * data will be written or read. 120 */ 121 opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr); 122 123 if (smb_opipe_do_open(sr, opipe) != 0) { 124 /* 125 * On error, reset the header to clear the fid, 126 * which avoids confusion when smb_opipe_close() is 127 * called by smb_ofile_close(). 128 */ 129 bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 130 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 131 smb_opipe_exit(opipe); 132 smb_ofile_close(of, 0); 133 return (NT_STATUS_NO_MEMORY); 134 } 135 smb_opipe_exit(opipe); 136 return (NT_STATUS_SUCCESS); 137 } 138 139 /* 140 * smb_opipe_lookup 141 * 142 * Lookup a path to see if it's a well-known RPC named pipe that we support. 143 * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 144 * can be assumed, so all we need here are the service names. 145 * 146 * Returns a pointer to the pipe name (without any leading \'s) on sucess. 147 * Otherwise returns a null pointer. 148 */ 149 static char * 150 smb_opipe_lookup(const char *path) 151 { 152 static char *named_pipes[] = { 153 "LSARPC", 154 "NETLOGON", 155 "SAMR", 156 "SPOOLSS", 157 "SRVSVC", 158 "SVCCTL", 159 "WINREG", 160 "WKSSVC", 161 "EVENTLOG" 162 }; 163 164 const char *name; 165 int i; 166 167 if (path == NULL) 168 return (NULL); 169 170 name = path; 171 name += strspn(name, "\\"); 172 if (utf8_strncasecmp(name, "PIPE", 4) == 0) { 173 path += 4; 174 name += strspn(name, "\\"); 175 } 176 177 for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 178 if (utf8_strcasecmp(name, named_pipes[i]) == 0) 179 return (named_pipes[i]); 180 } 181 182 return (NULL); 183 } 184 185 /* 186 * Initialize the opipe header and context, and make the door call. 187 */ 188 static int 189 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 190 { 191 smb_opipe_context_t *ctx = &opipe->p_context; 192 smb_user_t *user = sr->uid_user; 193 uint8_t *buf = opipe->p_doorbuf; 194 uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 195 uint32_t len; 196 197 smb_user_context_init(user, ctx); 198 len = xdr_sizeof(smb_opipe_context_xdr, ctx); 199 200 bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 201 opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 202 opipe->p_hdr.oh_fid = smb_opipe_fid(); 203 204 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 205 return (-1); 206 207 len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 208 buf += len; 209 buflen -= len; 210 211 if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1) 212 return (-1); 213 214 return (smb_opipe_door_call(opipe)); 215 } 216 217 /* 218 * smb_opipe_fid 219 * 220 * The opipe_fid is an arbitrary id used to associate RPC requests 221 * with a binding handle. A new fid is returned on each call. 222 * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 223 * and SMB sometimes uses -1 to indicate all open fid's. 224 */ 225 static uint32_t 226 smb_opipe_fid(void) 227 { 228 static uint32_t opipe_fid; 229 static kmutex_t smb_opipe_fid_mutex; 230 231 mutex_enter(&smb_opipe_fid_mutex); 232 233 if (opipe_fid == 0) 234 opipe_fid = lbolt << 11; 235 236 do { 237 ++opipe_fid; 238 } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 239 240 mutex_exit(&smb_opipe_fid_mutex); 241 242 return (opipe_fid); 243 } 244 245 /* 246 * smb_opipe_close 247 * 248 * Called whenever an IPC file/pipe is closed. 249 */ 250 void 251 smb_opipe_close(smb_ofile_t *of) 252 { 253 smb_opipe_t *opipe; 254 255 ASSERT(of); 256 ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 257 ASSERT(of->f_pipe != NULL); 258 259 opipe = of->f_pipe; 260 smb_opipe_enter(opipe); 261 262 if (SMB_OPIPE_ISOPEN(opipe)) { 263 (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 264 (void) smb_opipe_door_call(opipe); 265 bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 266 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 267 } 268 269 smb_user_context_fini(&opipe->p_context); 270 smb_opipe_exit(opipe); 271 cv_destroy(&opipe->p_cv); 272 mutex_destroy(&opipe->p_mutex); 273 } 274 275 static int 276 smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 277 { 278 opipe->p_hdr.oh_op = cmd; 279 opipe->p_hdr.oh_datalen = datalen; 280 opipe->p_hdr.oh_resid = 0; 281 opipe->p_hdr.oh_status = 0; 282 283 return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 284 SMB_OPIPE_DOOR_BUFSIZE)); 285 } 286 287 /* 288 * smb_opipe_transact 289 * 290 * This is the entry point for RPC bind and request transactions. 291 * The fid is an arbitrary id used to associate RPC requests with a 292 * particular binding handle. 293 * 294 * If the data to be returned is larger than the client expects, we 295 * return as much as the client can handle and report a buffer overflow 296 * warning, which informs the client that we have more data to return. 297 * The residual data remains in the pipe until the client claims it or 298 * closes the pipe. 299 */ 300 smb_sdrc_t 301 smb_opipe_transact(smb_request_t *sr, struct uio *uio) 302 { 303 smb_xa_t *xa; 304 smb_opipe_t *opipe; 305 struct mbuf *mhead; 306 int mdrcnt; 307 int nbytes; 308 int rc; 309 310 if ((rc = smb_opipe_write(sr, uio)) != 0) { 311 if (rc == EBADF) 312 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 313 ERRDOS, ERROR_INVALID_HANDLE); 314 else 315 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 316 ERRDOS, ERROR_INTERNAL_ERROR); 317 return (SDRC_ERROR); 318 } 319 320 xa = sr->r_xa; 321 mdrcnt = xa->smb_mdrcnt; 322 opipe = sr->fid_ofile->f_pipe; 323 smb_opipe_enter(opipe); 324 325 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 326 smb_opipe_exit(opipe); 327 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 328 ERRDOS, ERROR_INTERNAL_ERROR); 329 return (SDRC_ERROR); 330 } 331 332 rc = smb_opipe_door_call(opipe); 333 nbytes = opipe->p_hdr.oh_datalen; 334 335 if (rc != 0) { 336 smb_opipe_exit(opipe); 337 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 338 ERRDOS, ERROR_INTERNAL_ERROR); 339 return (SDRC_ERROR); 340 } 341 342 if (nbytes) { 343 mhead = smb_mbuf_get(opipe->p_data, nbytes); 344 xa->rep_data_mb.max_bytes = nbytes; 345 MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 346 } 347 348 if (opipe->p_hdr.oh_resid) { 349 /* 350 * The pipe contains more data than mdrcnt, warn the 351 * client that there is more data in the pipe. 352 * Typically, the client will call SmbReadX, which 353 * will call smb_opipe_read, to get the data. 354 */ 355 smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 356 ERRDOS, ERROR_MORE_DATA); 357 } 358 359 smb_opipe_exit(opipe); 360 return (SDRC_SUCCESS); 361 } 362 363 /* 364 * smb_opipe_write 365 * 366 * Write RPC request data to the pipe. The client should call smb_opipe_read 367 * to complete the exchange and obtain the RPC response. 368 * 369 * Returns 0 on success or an errno on failure. 370 */ 371 int 372 smb_opipe_write(smb_request_t *sr, struct uio *uio) 373 { 374 smb_opipe_t *opipe; 375 uint32_t buflen; 376 uint32_t len; 377 int rc; 378 379 ASSERT(sr->fid_ofile); 380 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 381 ASSERT(sr->fid_ofile->f_pipe != NULL); 382 383 opipe = sr->fid_ofile->f_pipe; 384 smb_opipe_enter(opipe); 385 386 if (!SMB_OPIPE_ISOPEN(opipe)) { 387 smb_opipe_exit(opipe); 388 return (EBADF); 389 } 390 391 rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 392 len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 393 if (rc == -1 || len == 0) { 394 smb_opipe_exit(opipe); 395 return (ENOMEM); 396 } 397 398 buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 399 (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 400 401 rc = smb_opipe_door_call(opipe); 402 403 smb_opipe_exit(opipe); 404 return ((rc == 0) ? 0 : EIO); 405 } 406 407 /* 408 * smb_opipe_read 409 * 410 * This interface may be called because smb_opipe_transact could not return 411 * all of the data in the original transaction or to form the second half 412 * of a transaction set up using smb_opipe_write. Either way, we just need 413 * to read data from the pipe and return it. 414 * 415 * The response data is encoded into raw_data as required by the smb_read 416 * functions. The uio_resid value indicates the number of bytes read. 417 */ 418 int 419 smb_opipe_read(smb_request_t *sr, struct uio *uio) 420 { 421 smb_opipe_t *opipe; 422 struct mbuf *mhead; 423 uint32_t nbytes; 424 int rc; 425 426 ASSERT(sr->fid_ofile); 427 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 428 ASSERT(sr->fid_ofile->f_pipe != NULL); 429 430 opipe = sr->fid_ofile->f_pipe; 431 smb_opipe_enter(opipe); 432 433 if (!SMB_OPIPE_ISOPEN(opipe)) { 434 smb_opipe_exit(opipe); 435 return (EBADF); 436 } 437 438 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 439 smb_opipe_exit(opipe); 440 return (ENOMEM); 441 } 442 443 rc = smb_opipe_door_call(opipe); 444 nbytes = opipe->p_hdr.oh_datalen; 445 446 if (rc != 0 || nbytes > uio->uio_resid) { 447 smb_opipe_exit(opipe); 448 return (EIO); 449 } 450 451 if (nbytes) { 452 mhead = smb_mbuf_get(opipe->p_data, nbytes); 453 MBC_SETUP(&sr->raw_data, nbytes); 454 MBC_ATTACH_MBUF(&sr->raw_data, mhead); 455 uio->uio_resid -= nbytes; 456 } 457 458 smb_opipe_exit(opipe); 459 return (rc); 460 } 461 462 /* 463 * Named pipe I/O is serialized per fid to ensure that each request 464 * has exclusive opipe access for the duration of the request. 465 */ 466 static void 467 smb_opipe_enter(smb_opipe_t *opipe) 468 { 469 mutex_enter(&opipe->p_mutex); 470 471 while (opipe->p_busy) 472 cv_wait(&opipe->p_cv, &opipe->p_mutex); 473 474 opipe->p_busy = 1; 475 mutex_exit(&opipe->p_mutex); 476 } 477 478 static void 479 smb_opipe_exit(smb_opipe_t *opipe) 480 { 481 mutex_enter(&opipe->p_mutex); 482 opipe->p_busy = 0; 483 cv_signal(&opipe->p_cv); 484 mutex_exit(&opipe->p_mutex); 485 } 486 487 /* 488 * opipe door client (to user space door server). 489 */ 490 void 491 smb_opipe_door_init(void) 492 { 493 mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 494 cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 495 } 496 497 void 498 smb_opipe_door_fini(void) 499 { 500 smb_opipe_door_close(); 501 cv_destroy(&smb_opipe_door_cv); 502 mutex_destroy(&smb_opipe_door_mutex); 503 } 504 505 /* 506 * Open the (user space) door. If the door is already open, 507 * close it first because the door-id has probably changed. 508 */ 509 int 510 smb_opipe_door_open(int door_id) 511 { 512 smb_opipe_door_close(); 513 514 mutex_enter(&smb_opipe_door_mutex); 515 smb_opipe_door_ncall = 0; 516 517 if (smb_opipe_door_hd == NULL) { 518 smb_opipe_door_id = door_id; 519 smb_opipe_door_hd = door_ki_lookup(door_id); 520 } 521 522 mutex_exit(&smb_opipe_door_mutex); 523 return ((smb_opipe_door_hd == NULL) ? -1 : 0); 524 } 525 526 /* 527 * Close the (user space) door. 528 */ 529 void 530 smb_opipe_door_close(void) 531 { 532 mutex_enter(&smb_opipe_door_mutex); 533 534 if (smb_opipe_door_hd != NULL) { 535 while (smb_opipe_door_ncall > 0) 536 cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 537 538 door_ki_rele(smb_opipe_door_hd); 539 smb_opipe_door_hd = NULL; 540 } 541 542 mutex_exit(&smb_opipe_door_mutex); 543 } 544 545 /* 546 * opipe door call interface. 547 * Door serialization and call reference accounting is handled here. 548 */ 549 static int 550 smb_opipe_door_call(smb_opipe_t *opipe) 551 { 552 int rc; 553 554 mutex_enter(&smb_opipe_door_mutex); 555 556 if (smb_opipe_door_hd == NULL) { 557 mutex_exit(&smb_opipe_door_mutex); 558 559 if (smb_opipe_door_open(smb_opipe_door_id) != 0) 560 return (-1); 561 562 mutex_enter(&smb_opipe_door_mutex); 563 } 564 565 ++smb_opipe_door_ncall; 566 mutex_exit(&smb_opipe_door_mutex); 567 568 rc = smb_opipe_door_upcall(opipe); 569 570 mutex_enter(&smb_opipe_door_mutex); 571 --smb_opipe_door_ncall; 572 cv_signal(&smb_opipe_door_cv); 573 mutex_exit(&smb_opipe_door_mutex); 574 return (rc); 575 } 576 577 /* 578 * Door upcall wrapper - handles data marshalling. 579 * This function should only be called by smb_opipe_door_call. 580 */ 581 static int 582 smb_opipe_door_upcall(smb_opipe_t *opipe) 583 { 584 door_arg_t da; 585 smb_opipe_hdr_t hdr; 586 int i; 587 int rc; 588 589 da.data_ptr = (char *)opipe->p_doorbuf; 590 da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 591 da.desc_ptr = NULL; 592 da.desc_num = 0; 593 da.rbuf = (char *)opipe->p_doorbuf; 594 da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 595 596 for (i = 0; i < 3; ++i) { 597 if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 598 NULL, SIZE_MAX, 0)) == 0) 599 break; 600 601 if (rc != EAGAIN && rc != EINTR) 602 return (-1); 603 } 604 605 if (rc != 0) 606 return (-1); 607 608 if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 609 return (-1); 610 611 if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 612 (hdr.oh_fid != opipe->p_hdr.oh_fid) || 613 (hdr.oh_op != opipe->p_hdr.oh_op) || 614 (hdr.oh_status != 0) || 615 (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 616 return (-1); 617 } 618 619 opipe->p_hdr.oh_datalen = hdr.oh_datalen; 620 opipe->p_hdr.oh_resid = hdr.oh_resid; 621 return (0); 622 } 623 624 void 625 smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx) 626 { 627 smb_session_t *session; 628 629 ASSERT(user); 630 ASSERT(user->u_domain); 631 ASSERT(user->u_name); 632 633 session = user->u_session; 634 ASSERT(session); 635 ASSERT(session->workstation); 636 637 ctx->oc_session_id = session->s_kid; 638 ctx->oc_native_os = session->native_os; 639 ctx->oc_ipaddr = session->ipaddr; 640 ctx->oc_uid = user->u_uid; 641 ctx->oc_logon_time = user->u_logon_time; 642 ctx->oc_flags = user->u_flags; 643 644 ctx->oc_domain_len = user->u_domain_len; 645 ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len); 646 647 ctx->oc_account_len = user->u_name_len; 648 ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len); 649 650 ctx->oc_workstation_len = strlen(session->workstation) + 1; 651 ctx->oc_workstation = smb_kstrdup(session->workstation, 652 ctx->oc_workstation_len); 653 } 654 655 void 656 smb_user_context_fini(smb_opipe_context_t *ctx) 657 { 658 if (ctx) { 659 if (ctx->oc_domain) 660 kmem_free(ctx->oc_domain, ctx->oc_domain_len); 661 if (ctx->oc_account) 662 kmem_free(ctx->oc_account, ctx->oc_account_len); 663 if (ctx->oc_workstation) 664 kmem_free(ctx->oc_workstation, ctx->oc_workstation_len); 665 bzero(ctx, sizeof (smb_opipe_context_t)); 666 } 667 } 668