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_kproto.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 success. 147 * Otherwise returns a null pointer. 148 */ 149 static char * 150 smb_opipe_lookup(const char *path) 151 { 152 static char *named_pipes[] = { 153 "lsass", 154 "LSARPC", 155 "NETLOGON", 156 "SAMR", 157 "SPOOLSS", 158 "SRVSVC", 159 "SVCCTL", 160 "WINREG", 161 "WKSSVC", 162 "EVENTLOG" 163 }; 164 165 const char *name; 166 int i; 167 168 if (path == NULL) 169 return (NULL); 170 171 name = path; 172 name += strspn(name, "\\"); 173 if (smb_strcasecmp(name, "PIPE", 4) == 0) { 174 path += 4; 175 name += strspn(name, "\\"); 176 } 177 178 for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 179 if (smb_strcasecmp(name, named_pipes[i], 0) == 0) 180 return (named_pipes[i]); 181 } 182 183 return (NULL); 184 } 185 186 /* 187 * Initialize the opipe header and context, and make the door call. 188 */ 189 static int 190 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 191 { 192 smb_netuserinfo_t *userinfo = &opipe->p_user; 193 smb_user_t *user = sr->uid_user; 194 uint8_t *buf = opipe->p_doorbuf; 195 uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 196 uint32_t len; 197 198 smb_user_netinfo_init(user, userinfo); 199 len = xdr_sizeof(smb_netuserinfo_xdr, userinfo); 200 201 bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 202 opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 203 opipe->p_hdr.oh_fid = smb_opipe_fid(); 204 205 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 206 return (-1); 207 208 len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 209 buf += len; 210 buflen -= len; 211 212 if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1) 213 return (-1); 214 215 return (smb_opipe_door_call(opipe)); 216 } 217 218 /* 219 * smb_opipe_fid 220 * 221 * The opipe_fid is an arbitrary id used to associate RPC requests 222 * with a binding handle. A new fid is returned on each call. 223 * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 224 * and SMB sometimes uses -1 to indicate all open fid's. 225 */ 226 static uint32_t 227 smb_opipe_fid(void) 228 { 229 static uint32_t opipe_fid; 230 static kmutex_t smb_opipe_fid_mutex; 231 232 mutex_enter(&smb_opipe_fid_mutex); 233 234 if (opipe_fid == 0) 235 opipe_fid = ddi_get_lbolt() << 11; 236 237 do { 238 ++opipe_fid; 239 } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 240 241 mutex_exit(&smb_opipe_fid_mutex); 242 243 return (opipe_fid); 244 } 245 246 /* 247 * smb_opipe_close 248 * 249 * Called whenever an IPC file/pipe is closed. 250 */ 251 void 252 smb_opipe_close(smb_ofile_t *of) 253 { 254 smb_opipe_t *opipe; 255 256 ASSERT(of); 257 ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 258 ASSERT(of->f_pipe != NULL); 259 260 opipe = of->f_pipe; 261 smb_opipe_enter(opipe); 262 263 if (SMB_OPIPE_ISOPEN(opipe)) { 264 (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 265 (void) smb_opipe_door_call(opipe); 266 bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 267 kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 268 } 269 270 smb_user_netinfo_fini(&opipe->p_user); 271 smb_opipe_exit(opipe); 272 cv_destroy(&opipe->p_cv); 273 mutex_destroy(&opipe->p_mutex); 274 } 275 276 static int 277 smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 278 { 279 opipe->p_hdr.oh_op = cmd; 280 opipe->p_hdr.oh_datalen = datalen; 281 opipe->p_hdr.oh_resid = 0; 282 opipe->p_hdr.oh_status = 0; 283 284 return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 285 SMB_OPIPE_DOOR_BUFSIZE)); 286 } 287 288 /* 289 * smb_opipe_transact 290 * 291 * This is the entry point for RPC bind and request transactions. 292 * The fid is an arbitrary id used to associate RPC requests with a 293 * particular binding handle. 294 * 295 * If the data to be returned is larger than the client expects, we 296 * return as much as the client can handle and report a buffer overflow 297 * warning, which informs the client that we have more data to return. 298 * The residual data remains in the pipe until the client claims it or 299 * closes the pipe. 300 */ 301 smb_sdrc_t 302 smb_opipe_transact(smb_request_t *sr, struct uio *uio) 303 { 304 smb_xa_t *xa; 305 smb_opipe_t *opipe; 306 struct mbuf *mhead; 307 int mdrcnt; 308 int nbytes; 309 int rc; 310 311 if ((rc = smb_opipe_write(sr, uio)) != 0) { 312 if (rc == EBADF) 313 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 314 ERRDOS, ERROR_INVALID_HANDLE); 315 else 316 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 317 ERRDOS, ERROR_INTERNAL_ERROR); 318 return (SDRC_ERROR); 319 } 320 321 xa = sr->r_xa; 322 mdrcnt = xa->smb_mdrcnt; 323 opipe = sr->fid_ofile->f_pipe; 324 smb_opipe_enter(opipe); 325 326 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 327 smb_opipe_exit(opipe); 328 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 329 ERRDOS, ERROR_INTERNAL_ERROR); 330 return (SDRC_ERROR); 331 } 332 333 rc = smb_opipe_door_call(opipe); 334 nbytes = opipe->p_hdr.oh_datalen; 335 336 if (rc != 0) { 337 smb_opipe_exit(opipe); 338 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 339 ERRDOS, ERROR_INTERNAL_ERROR); 340 return (SDRC_ERROR); 341 } 342 343 if (nbytes) { 344 mhead = smb_mbuf_get(opipe->p_data, nbytes); 345 xa->rep_data_mb.max_bytes = nbytes; 346 MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 347 } 348 349 if (opipe->p_hdr.oh_resid) { 350 /* 351 * The pipe contains more data than mdrcnt, warn the 352 * client that there is more data in the pipe. 353 * Typically, the client will call SmbReadX, which 354 * will call smb_opipe_read, to get the data. 355 */ 356 smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 357 ERRDOS, ERROR_MORE_DATA); 358 } 359 360 smb_opipe_exit(opipe); 361 return (SDRC_SUCCESS); 362 } 363 364 /* 365 * smb_opipe_write 366 * 367 * Write RPC request data to the pipe. The client should call smb_opipe_read 368 * to complete the exchange and obtain the RPC response. 369 * 370 * Returns 0 on success or an errno on failure. 371 */ 372 int 373 smb_opipe_write(smb_request_t *sr, struct uio *uio) 374 { 375 smb_opipe_t *opipe; 376 uint32_t buflen; 377 uint32_t len; 378 int rc; 379 380 ASSERT(sr->fid_ofile); 381 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 382 ASSERT(sr->fid_ofile->f_pipe != NULL); 383 384 opipe = sr->fid_ofile->f_pipe; 385 smb_opipe_enter(opipe); 386 387 if (!SMB_OPIPE_ISOPEN(opipe)) { 388 smb_opipe_exit(opipe); 389 return (EBADF); 390 } 391 392 rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 393 len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 394 if (rc == -1 || len == 0) { 395 smb_opipe_exit(opipe); 396 return (ENOMEM); 397 } 398 399 buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 400 (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 401 402 rc = smb_opipe_door_call(opipe); 403 404 smb_opipe_exit(opipe); 405 return ((rc == 0) ? 0 : EIO); 406 } 407 408 /* 409 * smb_opipe_read 410 * 411 * This interface may be called because smb_opipe_transact could not return 412 * all of the data in the original transaction or to form the second half 413 * of a transaction set up using smb_opipe_write. Either way, we just need 414 * to read data from the pipe and return it. 415 * 416 * The response data is encoded into raw_data as required by the smb_read 417 * functions. The uio_resid value indicates the number of bytes read. 418 */ 419 int 420 smb_opipe_read(smb_request_t *sr, struct uio *uio) 421 { 422 smb_opipe_t *opipe; 423 struct mbuf *mhead; 424 uint32_t nbytes; 425 int rc; 426 427 ASSERT(sr->fid_ofile); 428 ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 429 ASSERT(sr->fid_ofile->f_pipe != NULL); 430 431 opipe = sr->fid_ofile->f_pipe; 432 smb_opipe_enter(opipe); 433 434 if (!SMB_OPIPE_ISOPEN(opipe)) { 435 smb_opipe_exit(opipe); 436 return (EBADF); 437 } 438 439 if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 440 smb_opipe_exit(opipe); 441 return (ENOMEM); 442 } 443 444 rc = smb_opipe_door_call(opipe); 445 nbytes = opipe->p_hdr.oh_datalen; 446 447 if (rc != 0 || nbytes > uio->uio_resid) { 448 smb_opipe_exit(opipe); 449 return (EIO); 450 } 451 452 if (nbytes) { 453 mhead = smb_mbuf_get(opipe->p_data, nbytes); 454 MBC_SETUP(&sr->raw_data, nbytes); 455 MBC_ATTACH_MBUF(&sr->raw_data, mhead); 456 uio->uio_resid -= nbytes; 457 } 458 459 smb_opipe_exit(opipe); 460 return (rc); 461 } 462 463 /* 464 * Named pipe I/O is serialized per fid to ensure that each request 465 * has exclusive opipe access for the duration of the request. 466 */ 467 static void 468 smb_opipe_enter(smb_opipe_t *opipe) 469 { 470 mutex_enter(&opipe->p_mutex); 471 472 while (opipe->p_busy) 473 cv_wait(&opipe->p_cv, &opipe->p_mutex); 474 475 opipe->p_busy = 1; 476 mutex_exit(&opipe->p_mutex); 477 } 478 479 static void 480 smb_opipe_exit(smb_opipe_t *opipe) 481 { 482 mutex_enter(&opipe->p_mutex); 483 opipe->p_busy = 0; 484 cv_signal(&opipe->p_cv); 485 mutex_exit(&opipe->p_mutex); 486 } 487 488 /* 489 * opipe door client (to user space door server). 490 */ 491 void 492 smb_opipe_door_init(void) 493 { 494 mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 495 cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 496 } 497 498 void 499 smb_opipe_door_fini(void) 500 { 501 smb_opipe_door_close(); 502 cv_destroy(&smb_opipe_door_cv); 503 mutex_destroy(&smb_opipe_door_mutex); 504 } 505 506 /* 507 * Open the (user space) door. If the door is already open, 508 * close it first because the door-id has probably changed. 509 */ 510 int 511 smb_opipe_door_open(int door_id) 512 { 513 smb_opipe_door_close(); 514 515 mutex_enter(&smb_opipe_door_mutex); 516 smb_opipe_door_ncall = 0; 517 518 if (smb_opipe_door_hd == NULL) { 519 smb_opipe_door_id = door_id; 520 smb_opipe_door_hd = door_ki_lookup(door_id); 521 } 522 523 mutex_exit(&smb_opipe_door_mutex); 524 return ((smb_opipe_door_hd == NULL) ? -1 : 0); 525 } 526 527 /* 528 * Close the (user space) door. 529 */ 530 void 531 smb_opipe_door_close(void) 532 { 533 mutex_enter(&smb_opipe_door_mutex); 534 535 if (smb_opipe_door_hd != NULL) { 536 while (smb_opipe_door_ncall > 0) 537 cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 538 539 door_ki_rele(smb_opipe_door_hd); 540 smb_opipe_door_hd = NULL; 541 } 542 543 mutex_exit(&smb_opipe_door_mutex); 544 } 545 546 /* 547 * opipe door call interface. 548 * Door serialization and call reference accounting is handled here. 549 */ 550 static int 551 smb_opipe_door_call(smb_opipe_t *opipe) 552 { 553 int rc; 554 555 mutex_enter(&smb_opipe_door_mutex); 556 557 if (smb_opipe_door_hd == NULL) { 558 mutex_exit(&smb_opipe_door_mutex); 559 560 if (smb_opipe_door_open(smb_opipe_door_id) != 0) 561 return (-1); 562 563 mutex_enter(&smb_opipe_door_mutex); 564 } 565 566 ++smb_opipe_door_ncall; 567 mutex_exit(&smb_opipe_door_mutex); 568 569 rc = smb_opipe_door_upcall(opipe); 570 571 mutex_enter(&smb_opipe_door_mutex); 572 --smb_opipe_door_ncall; 573 cv_signal(&smb_opipe_door_cv); 574 mutex_exit(&smb_opipe_door_mutex); 575 return (rc); 576 } 577 578 /* 579 * Door upcall wrapper - handles data marshalling. 580 * This function should only be called by smb_opipe_door_call. 581 */ 582 static int 583 smb_opipe_door_upcall(smb_opipe_t *opipe) 584 { 585 door_arg_t da; 586 smb_opipe_hdr_t hdr; 587 int i; 588 int rc; 589 590 da.data_ptr = (char *)opipe->p_doorbuf; 591 da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 592 da.desc_ptr = NULL; 593 da.desc_num = 0; 594 da.rbuf = (char *)opipe->p_doorbuf; 595 da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 596 597 for (i = 0; i < 3; ++i) { 598 if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 599 NULL, SIZE_MAX, 0)) == 0) 600 break; 601 602 if (rc != EAGAIN && rc != EINTR) 603 return (-1); 604 } 605 606 if (rc != 0) 607 return (-1); 608 609 if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 610 return (-1); 611 612 if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 613 (hdr.oh_fid != opipe->p_hdr.oh_fid) || 614 (hdr.oh_op != opipe->p_hdr.oh_op) || 615 (hdr.oh_status != 0) || 616 (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 617 return (-1); 618 } 619 620 opipe->p_hdr.oh_datalen = hdr.oh_datalen; 621 opipe->p_hdr.oh_resid = hdr.oh_resid; 622 return (0); 623 } 624