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