17052Samw /* 27052Samw * CDDL HEADER START 37052Samw * 47052Samw * The contents of this file are subject to the terms of the 57052Samw * Common Development and Distribution License (the "License"). 67052Samw * You may not use this file except in compliance with the License. 77052Samw * 87052Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97052Samw * or http://www.opensolaris.org/os/licensing. 107052Samw * See the License for the specific language governing permissions 117052Samw * and limitations under the License. 127052Samw * 137052Samw * When distributing Covered Code, include this CDDL HEADER in each 147052Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157052Samw * If applicable, add the following below this CDDL HEADER, with the 167052Samw * fields enclosed by brackets "[]" replaced with your own identifying 177052Samw * information: Portions Copyright [yyyy] [name of copyright owner] 187052Samw * 197052Samw * CDDL HEADER END 207052Samw */ 217052Samw /* 227052Samw * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237052Samw * Use is subject to license terms. 247052Samw */ 257052Samw 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_opipe.c 1.10 08/08/08 SMI" 277052Samw 287052Samw /* 297052Samw * This module provides the interface to NDR RPC. 307052Samw */ 317052Samw 327052Samw #include <sys/stat.h> 337052Samw #include <sys/door.h> 347052Samw #include <sys/door_data.h> 357052Samw #include <sys/uio.h> 367052Samw #include <sys/ksynch.h> 377052Samw #include <smbsrv/smb_incl.h> 387052Samw #include <smbsrv/smb_xdr.h> 397052Samw 407052Samw #define SMB_OPIPE_ISOPEN(OPIPE) \ 417052Samw (((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \ 427052Samw ((OPIPE)->p_hdr.oh_fid)) 437052Samw 447052Samw extern volatile uint32_t smb_fids; 457052Samw 467052Samw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 477052Samw static char *smb_opipe_lookup(const char *path); 487052Samw static uint32_t smb_opipe_fid(void); 497052Samw static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t); 507052Samw static void smb_opipe_enter(smb_opipe_t *); 517052Samw static void smb_opipe_exit(smb_opipe_t *); 527052Samw 537052Samw static door_handle_t smb_opipe_door_hd = NULL; 547052Samw static int smb_opipe_door_id = -1; 557052Samw static uint64_t smb_opipe_door_ncall = 0; 567052Samw static kmutex_t smb_opipe_door_mutex; 577052Samw static kcondvar_t smb_opipe_door_cv; 587052Samw 597052Samw static int smb_opipe_door_call(smb_opipe_t *); 607052Samw static int smb_opipe_door_upcall(smb_opipe_t *); 617052Samw static void smb_user_context_fini(smb_opipe_context_t *); 627052Samw 637052Samw /* 647052Samw * smb_opipe_open 657052Samw * 667052Samw * Open a well-known RPC named pipe. This routine should be called if 677052Samw * a file open is requested on a share of type STYPE_IPC. 687052Samw * If we recognize the pipe, we setup a new ofile. 697052Samw * 707052Samw * Returns 0 on success, Otherwise an NT status is returned to indicate 717052Samw * an error. 727052Samw */ 737052Samw int 747052Samw smb_opipe_open(smb_request_t *sr) 757052Samw { 767052Samw struct open_param *op = &sr->arg.open; 777052Samw smb_ofile_t *of; 787052Samw smb_opipe_t *opipe; 797052Samw smb_opipe_hdr_t hdr; 807052Samw smb_error_t err; 817052Samw char *pipe_name; 827052Samw 837052Samw if ((pipe_name = smb_opipe_lookup(op->fqi.path)) == NULL) 847052Samw return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 857052Samw 86*7348SJose.Borrego@Sun.COM op->create_options = 0; 87*7348SJose.Borrego@Sun.COM 88*7348SJose.Borrego@Sun.COM of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op, 897052Samw SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 907052Samw if (of == NULL) 917052Samw return (err.status); 927052Samw 937052Samw op->dsize = 0x01000; 947052Samw op->dattr = FILE_ATTRIBUTE_NORMAL; 957052Samw op->ftype = SMB_FTYPE_MESG_PIPE; 967052Samw op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 977052Samw op->devstate = SMB_PIPE_READMODE_MESSAGE 987052Samw | SMB_PIPE_TYPE_MESSAGE 997052Samw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 1007052Samw op->fileid = of->f_fid; 1017052Samw 1027052Samw sr->smb_fid = of->f_fid; 1037052Samw sr->fid_ofile = of; 1047052Samw 1057052Samw opipe = of->f_pipe; 1067052Samw mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 1077052Samw cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 1087052Samw smb_opipe_enter(opipe); 1097052Samw 1107052Samw opipe->p_name = pipe_name; 1117052Samw opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 1127052Samw 1137052Samw /* 1147052Samw * p_data points to the offset within p_doorbuf at which 1157052Samw * data will be written or read. 1167052Samw */ 1177052Samw opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr); 1187052Samw 1197052Samw if (smb_opipe_do_open(sr, opipe) != 0) { 1207052Samw /* 1217052Samw * On error, reset the header to clear the fid, 1227052Samw * which avoids confusion when smb_opipe_close() is 1237052Samw * called by smb_ofile_close(). 1247052Samw */ 1257052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 1267052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 1277052Samw smb_opipe_exit(opipe); 128*7348SJose.Borrego@Sun.COM smb_ofile_close(of, 0); 1297052Samw return (NT_STATUS_NO_MEMORY); 1307052Samw } 1317052Samw 1327052Samw smb_opipe_exit(opipe); 1337052Samw return (NT_STATUS_SUCCESS); 1347052Samw } 1357052Samw 1367052Samw /* 1377052Samw * smb_opipe_lookup 1387052Samw * 1397052Samw * Lookup a path to see if it's a well-known RPC named pipe that we support. 1407052Samw * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 1417052Samw * can be assumed, so all we need here are the service names. 1427052Samw * 1437052Samw * Returns a pointer to the pipe name (without any leading \'s) on sucess. 1447052Samw * Otherwise returns a null pointer. 1457052Samw */ 1467052Samw static char * 1477052Samw smb_opipe_lookup(const char *path) 1487052Samw { 1497052Samw static char *named_pipes[] = { 1507052Samw "LSARPC", 1517052Samw "NETLOGON", 1527052Samw "SAMR", 1537052Samw "SPOOLSS", 1547052Samw "SRVSVC", 1557052Samw "SVCCTL", 1567052Samw "WINREG", 1577052Samw "WKSSVC", 1587052Samw "EVENTLOG" 1597052Samw }; 1607052Samw 1617052Samw const char *name; 1627052Samw int i; 1637052Samw 1647052Samw if (path == NULL) 1657052Samw return (NULL); 1667052Samw 1677052Samw name = path; 1687052Samw name += strspn(name, "\\"); 1697052Samw if (utf8_strncasecmp(name, "PIPE", 4) == 0) { 1707052Samw path += 4; 1717052Samw name += strspn(name, "\\"); 1727052Samw } 1737052Samw 1747052Samw for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 1757052Samw if (utf8_strcasecmp(name, named_pipes[i]) == 0) 1767052Samw return (named_pipes[i]); 1777052Samw } 1787052Samw 1797052Samw return (NULL); 1807052Samw } 1817052Samw 1827052Samw /* 1837052Samw * Initialize the opipe header and context, and make the door call. 1847052Samw */ 1857052Samw static int 1867052Samw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 1877052Samw { 1887052Samw smb_opipe_context_t *ctx = &opipe->p_context; 1897052Samw smb_user_t *user = sr->uid_user; 1907052Samw uint8_t *buf = opipe->p_doorbuf; 1917052Samw uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 1927052Samw uint32_t len; 1937052Samw 1947052Samw smb_user_context_init(user, ctx); 1957052Samw len = xdr_sizeof(smb_opipe_context_xdr, ctx); 1967052Samw 1977052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 1987052Samw opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 1997052Samw opipe->p_hdr.oh_fid = smb_opipe_fid(); 2007052Samw 2017052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 2027052Samw return (-1); 2037052Samw 2047052Samw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 2057052Samw buf += len; 2067052Samw buflen -= len; 2077052Samw 2087052Samw if (smb_opipe_context_encode(ctx, buf, buflen) == -1) 2097052Samw return (-1); 2107052Samw 2117052Samw return (smb_opipe_door_call(opipe)); 2127052Samw } 2137052Samw 2147052Samw /* 2157052Samw * smb_opipe_fid 2167052Samw * 2177052Samw * The opipe_fid is an arbitrary id used to associate RPC requests 2187052Samw * with a binding handle. A new fid is returned on each call. 2197052Samw * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 2207052Samw * and SMB sometimes uses -1 to indicate all open fid's. 2217052Samw */ 2227052Samw static uint32_t 2237052Samw smb_opipe_fid(void) 2247052Samw { 2257052Samw static uint32_t opipe_fid; 2267052Samw static kmutex_t smb_opipe_fid_mutex; 2277052Samw 2287052Samw mutex_enter(&smb_opipe_fid_mutex); 2297052Samw 2307052Samw if (opipe_fid == 0) 2317052Samw opipe_fid = lbolt << 11; 2327052Samw 2337052Samw do { 2347052Samw ++opipe_fid; 2357052Samw } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 2367052Samw 2377052Samw mutex_exit(&smb_opipe_fid_mutex); 2387052Samw 2397052Samw return (opipe_fid); 2407052Samw } 2417052Samw 2427052Samw /* 2437052Samw * smb_opipe_close 2447052Samw * 2457052Samw * Called whenever an IPC file/pipe is closed. 2467052Samw */ 2477052Samw void 2487052Samw smb_opipe_close(smb_ofile_t *of) 2497052Samw { 2507052Samw smb_opipe_t *opipe; 2517052Samw 2527052Samw ASSERT(of); 2537052Samw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 2547052Samw ASSERT(of->f_pipe != NULL); 2557052Samw 2567052Samw opipe = of->f_pipe; 2577052Samw smb_opipe_enter(opipe); 2587052Samw 2597052Samw if (SMB_OPIPE_ISOPEN(opipe)) { 2607052Samw (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 2617052Samw (void) smb_opipe_door_call(opipe); 2627052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 2637052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 2647052Samw } 2657052Samw 2667052Samw smb_user_context_fini(&opipe->p_context); 2677052Samw smb_opipe_exit(opipe); 2687052Samw cv_destroy(&opipe->p_cv); 2697052Samw mutex_destroy(&opipe->p_mutex); 2707052Samw } 2717052Samw 2727052Samw static int 2737052Samw smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 2747052Samw { 2757052Samw opipe->p_hdr.oh_op = cmd; 2767052Samw opipe->p_hdr.oh_datalen = datalen; 2777052Samw opipe->p_hdr.oh_resid = 0; 2787052Samw opipe->p_hdr.oh_status = 0; 2797052Samw 2807052Samw return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 2817052Samw SMB_OPIPE_DOOR_BUFSIZE)); 2827052Samw } 2837052Samw 2847052Samw /* 2857052Samw * smb_opipe_transact 2867052Samw * 2877052Samw * This is the entry point for RPC bind and request transactions. 2887052Samw * The fid is an arbitrary id used to associate RPC requests with a 2897052Samw * particular binding handle. 2907052Samw * 2917052Samw * If the data to be returned is larger than the client expects, we 2927052Samw * return as much as the client can handle and report a buffer overflow 2937052Samw * warning, which informs the client that we have more data to return. 2947052Samw * The residual data remains in the pipe until the client claims it or 2957052Samw * closes the pipe. 2967052Samw */ 2977052Samw smb_sdrc_t 2987052Samw smb_opipe_transact(smb_request_t *sr, struct uio *uio) 2997052Samw { 3007052Samw smb_xa_t *xa; 3017052Samw smb_opipe_t *opipe; 3027052Samw struct mbuf *mhead; 3037052Samw int mdrcnt; 3047052Samw int nbytes; 3057052Samw int rc; 3067052Samw 3077052Samw if ((rc = smb_opipe_write(sr, uio)) != 0) { 3087052Samw if (rc == EBADF) 3097052Samw smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 3107052Samw ERRDOS, ERROR_INVALID_HANDLE); 3117052Samw else 3127052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3137052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3147052Samw return (SDRC_ERROR); 3157052Samw } 3167052Samw 3177052Samw xa = sr->r_xa; 3187052Samw mdrcnt = xa->smb_mdrcnt; 3197052Samw opipe = sr->fid_ofile->f_pipe; 3207052Samw smb_opipe_enter(opipe); 3217052Samw 3227052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 3237052Samw smb_opipe_exit(opipe); 3247052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3257052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3267052Samw return (SDRC_ERROR); 3277052Samw } 3287052Samw 3297052Samw rc = smb_opipe_door_call(opipe); 3307052Samw nbytes = opipe->p_hdr.oh_datalen; 3317052Samw 3327052Samw if (rc != 0) { 3337052Samw smb_opipe_exit(opipe); 3347052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3357052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3367052Samw return (SDRC_ERROR); 3377052Samw } 3387052Samw 3397052Samw if (nbytes) { 3407052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes); 3417052Samw xa->rep_data_mb.max_bytes = nbytes; 3427052Samw MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 3437052Samw } 3447052Samw 3457052Samw if (opipe->p_hdr.oh_resid) { 3467052Samw /* 3477052Samw * The pipe contains more data than mdrcnt, warn the 3487052Samw * client that there is more data in the pipe. 3497052Samw * Typically, the client will call SmbReadX, which 3507052Samw * will call smb_opipe_read, to get the data. 3517052Samw */ 3527052Samw smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 3537052Samw ERRDOS, ERROR_MORE_DATA); 3547052Samw } 3557052Samw 3567052Samw smb_opipe_exit(opipe); 3577052Samw return (SDRC_SUCCESS); 3587052Samw } 3597052Samw 3607052Samw /* 3617052Samw * smb_opipe_write 3627052Samw * 3637052Samw * Write RPC request data to the pipe. The client should call smb_opipe_read 3647052Samw * to complete the exchange and obtain the RPC response. 3657052Samw * 3667052Samw * Returns 0 on success or an errno on failure. 3677052Samw */ 3687052Samw int 3697052Samw smb_opipe_write(smb_request_t *sr, struct uio *uio) 3707052Samw { 3717052Samw smb_opipe_t *opipe; 3727052Samw uint32_t buflen; 3737052Samw uint32_t len; 3747052Samw int rc; 3757052Samw 3767052Samw ASSERT(sr->fid_ofile); 3777052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 3787052Samw ASSERT(sr->fid_ofile->f_pipe != NULL); 3797052Samw 3807052Samw opipe = sr->fid_ofile->f_pipe; 3817052Samw smb_opipe_enter(opipe); 3827052Samw 3837052Samw if (!SMB_OPIPE_ISOPEN(opipe)) { 3847052Samw smb_opipe_exit(opipe); 3857052Samw return (EBADF); 3867052Samw } 3877052Samw 3887052Samw rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 3897052Samw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 3907052Samw if (rc == -1 || len == 0) { 3917052Samw smb_opipe_exit(opipe); 3927052Samw return (ENOMEM); 3937052Samw } 3947052Samw 3957052Samw buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 3967052Samw (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 3977052Samw 3987052Samw rc = smb_opipe_door_call(opipe); 3997052Samw 4007052Samw smb_opipe_exit(opipe); 4017052Samw return ((rc == 0) ? 0 : EIO); 4027052Samw } 4037052Samw 4047052Samw /* 4057052Samw * smb_opipe_read 4067052Samw * 4077052Samw * This interface may be called because smb_opipe_transact could not return 4087052Samw * all of the data in the original transaction or to form the second half 4097052Samw * of a transaction set up using smb_opipe_write. Either way, we just need 4107052Samw * to read data from the pipe and return it. 4117052Samw * 4127052Samw * The response data is encoded into raw_data as required by the smb_read 4137052Samw * functions. The uio_resid value indicates the number of bytes read. 4147052Samw */ 4157052Samw int 4167052Samw smb_opipe_read(smb_request_t *sr, struct uio *uio) 4177052Samw { 4187052Samw smb_opipe_t *opipe; 4197052Samw struct mbuf *mhead; 4207052Samw uint32_t nbytes; 4217052Samw int rc; 4227052Samw 4237052Samw ASSERT(sr->fid_ofile); 4247052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 4257052Samw ASSERT(sr->fid_ofile->f_pipe != NULL); 4267052Samw 4277052Samw opipe = sr->fid_ofile->f_pipe; 4287052Samw smb_opipe_enter(opipe); 4297052Samw 4307052Samw if (!SMB_OPIPE_ISOPEN(opipe)) { 4317052Samw smb_opipe_exit(opipe); 4327052Samw return (EBADF); 4337052Samw } 4347052Samw 4357052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 4367052Samw smb_opipe_exit(opipe); 4377052Samw return (ENOMEM); 4387052Samw } 4397052Samw 4407052Samw rc = smb_opipe_door_call(opipe); 4417052Samw nbytes = opipe->p_hdr.oh_datalen; 4427052Samw 4437052Samw if (rc != 0 || nbytes > uio->uio_resid) { 4447052Samw smb_opipe_exit(opipe); 4457052Samw return (EIO); 4467052Samw } 4477052Samw 4487052Samw if (nbytes) { 4497052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes); 4507052Samw MBC_SETUP(&sr->raw_data, nbytes); 4517052Samw MBC_ATTACH_MBUF(&sr->raw_data, mhead); 4527052Samw uio->uio_resid -= nbytes; 4537052Samw } 4547052Samw 4557052Samw smb_opipe_exit(opipe); 4567052Samw return (rc); 4577052Samw } 4587052Samw 4597052Samw /* 4607052Samw * Named pipe I/O is serialized per fid to ensure that each request 4617052Samw * has exclusive opipe access for the duration of the request. 4627052Samw */ 4637052Samw static void 4647052Samw smb_opipe_enter(smb_opipe_t *opipe) 4657052Samw { 4667052Samw mutex_enter(&opipe->p_mutex); 4677052Samw 4687052Samw while (opipe->p_busy) 4697052Samw cv_wait(&opipe->p_cv, &opipe->p_mutex); 4707052Samw 4717052Samw opipe->p_busy = 1; 4727052Samw mutex_exit(&opipe->p_mutex); 4737052Samw } 4747052Samw 4757052Samw static void 4767052Samw smb_opipe_exit(smb_opipe_t *opipe) 4777052Samw { 4787052Samw mutex_enter(&opipe->p_mutex); 4797052Samw opipe->p_busy = 0; 4807052Samw cv_signal(&opipe->p_cv); 4817052Samw mutex_exit(&opipe->p_mutex); 4827052Samw } 4837052Samw 4847052Samw /* 4857052Samw * opipe door client (to user space door server). 4867052Samw */ 4877052Samw void 4887052Samw smb_opipe_door_init(void) 4897052Samw { 4907052Samw mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 4917052Samw cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 4927052Samw } 4937052Samw 4947052Samw void 4957052Samw smb_opipe_door_fini(void) 4967052Samw { 4977052Samw smb_opipe_door_close(); 4987052Samw cv_destroy(&smb_opipe_door_cv); 4997052Samw mutex_destroy(&smb_opipe_door_mutex); 5007052Samw } 5017052Samw 5027052Samw /* 5037052Samw * Open the (user space) door. If the door is already open, 5047052Samw * close it first because the door-id has probably changed. 5057052Samw */ 5067052Samw int 5077052Samw smb_opipe_door_open(int door_id) 5087052Samw { 5097052Samw smb_opipe_door_close(); 5107052Samw 5117052Samw mutex_enter(&smb_opipe_door_mutex); 5127052Samw smb_opipe_door_ncall = 0; 5137052Samw 5147052Samw if (smb_opipe_door_hd == NULL) { 5157052Samw smb_opipe_door_id = door_id; 5167052Samw smb_opipe_door_hd = door_ki_lookup(door_id); 5177052Samw } 5187052Samw 5197052Samw mutex_exit(&smb_opipe_door_mutex); 5207052Samw return ((smb_opipe_door_hd == NULL) ? -1 : 0); 5217052Samw } 5227052Samw 5237052Samw /* 5247052Samw * Close the (user space) door. 5257052Samw */ 5267052Samw void 5277052Samw smb_opipe_door_close(void) 5287052Samw { 5297052Samw mutex_enter(&smb_opipe_door_mutex); 5307052Samw 5317052Samw if (smb_opipe_door_hd != NULL) { 5327052Samw while (smb_opipe_door_ncall > 0) 5337052Samw cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 5347052Samw 5357052Samw door_ki_rele(smb_opipe_door_hd); 5367052Samw smb_opipe_door_hd = NULL; 5377052Samw } 5387052Samw 5397052Samw mutex_exit(&smb_opipe_door_mutex); 5407052Samw } 5417052Samw 5427052Samw /* 5437052Samw * opipe door call interface. 5447052Samw * Door serialization and call reference accounting is handled here. 5457052Samw */ 5467052Samw static int 5477052Samw smb_opipe_door_call(smb_opipe_t *opipe) 5487052Samw { 5497052Samw int rc; 5507052Samw 5517052Samw mutex_enter(&smb_opipe_door_mutex); 5527052Samw 5537052Samw if (smb_opipe_door_hd == NULL) { 5547052Samw mutex_exit(&smb_opipe_door_mutex); 5557052Samw 5567052Samw if (smb_opipe_door_open(smb_opipe_door_id) != 0) 5577052Samw return (-1); 5587052Samw 5597052Samw mutex_enter(&smb_opipe_door_mutex); 5607052Samw } 5617052Samw 5627052Samw ++smb_opipe_door_ncall; 5637052Samw mutex_exit(&smb_opipe_door_mutex); 5647052Samw 5657052Samw rc = smb_opipe_door_upcall(opipe); 5667052Samw 5677052Samw mutex_enter(&smb_opipe_door_mutex); 5687052Samw --smb_opipe_door_ncall; 5697052Samw cv_signal(&smb_opipe_door_cv); 5707052Samw mutex_exit(&smb_opipe_door_mutex); 5717052Samw return (rc); 5727052Samw } 5737052Samw 5747052Samw /* 5757052Samw * Door upcall wrapper - handles data marshalling. 5767052Samw * This function should only be called by smb_opipe_door_call. 5777052Samw */ 5787052Samw static int 5797052Samw smb_opipe_door_upcall(smb_opipe_t *opipe) 5807052Samw { 5817052Samw door_arg_t da; 5827052Samw smb_opipe_hdr_t hdr; 5837052Samw int i; 5847052Samw int rc; 5857052Samw 5867052Samw da.data_ptr = (char *)opipe->p_doorbuf; 5877052Samw da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 5887052Samw da.desc_ptr = NULL; 5897052Samw da.desc_num = 0; 5907052Samw da.rbuf = (char *)opipe->p_doorbuf; 5917052Samw da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 5927052Samw 5937052Samw for (i = 0; i < 3; ++i) { 5947052Samw if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 5957052Samw NULL, SIZE_MAX, 0)) == 0) 5967052Samw break; 5977052Samw 5987052Samw if (rc != EAGAIN && rc != EINTR) 5997052Samw return (-1); 6007052Samw } 6017052Samw 6027052Samw if (rc != 0) 6037052Samw return (-1); 6047052Samw 6057052Samw if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 6067052Samw return (-1); 6077052Samw 6087052Samw if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 6097052Samw (hdr.oh_fid != opipe->p_hdr.oh_fid) || 6107052Samw (hdr.oh_op != opipe->p_hdr.oh_op) || 6117052Samw (hdr.oh_status != 0) || 6127052Samw (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 6137052Samw return (-1); 6147052Samw } 6157052Samw 6167052Samw opipe->p_hdr.oh_datalen = hdr.oh_datalen; 6177052Samw opipe->p_hdr.oh_resid = hdr.oh_resid; 6187052Samw return (0); 6197052Samw } 6207052Samw 6217052Samw void 6227052Samw smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx) 6237052Samw { 6247052Samw smb_session_t *session; 6257052Samw 6267052Samw ASSERT(user); 6277052Samw ASSERT(user->u_domain); 6287052Samw ASSERT(user->u_name); 6297052Samw 6307052Samw session = user->u_session; 6317052Samw ASSERT(session); 6327052Samw ASSERT(session->workstation); 6337052Samw 6347052Samw ctx->oc_session_id = session->s_kid; 6357052Samw ctx->oc_native_os = session->native_os; 6367052Samw ctx->oc_ipaddr = session->ipaddr; 6377052Samw ctx->oc_uid = user->u_uid; 6387052Samw ctx->oc_logon_time = user->u_logon_time; 6397052Samw ctx->oc_flags = user->u_flags; 6407052Samw 6417052Samw ctx->oc_domain_len = user->u_domain_len; 6427052Samw ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len); 6437052Samw 6447052Samw ctx->oc_account_len = user->u_name_len; 6457052Samw ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len); 6467052Samw 6477052Samw ctx->oc_workstation_len = strlen(session->workstation) + 1; 6487052Samw ctx->oc_workstation = smb_kstrdup(session->workstation, 6497052Samw ctx->oc_workstation_len); 6507052Samw } 6517052Samw 6527052Samw static void 6537052Samw smb_user_context_fini(smb_opipe_context_t *ctx) 6547052Samw { 6557052Samw if (ctx) { 6567052Samw if (ctx->oc_domain) 6577052Samw kmem_free(ctx->oc_domain, ctx->oc_domain_len); 6587052Samw if (ctx->oc_account) 6597052Samw kmem_free(ctx->oc_account, ctx->oc_account_len); 6607052Samw if (ctx->oc_workstation) 6617052Samw kmem_free(ctx->oc_workstation, ctx->oc_workstation_len); 6627052Samw bzero(ctx, sizeof (smb_opipe_context_t)); 6637052Samw } 6647052Samw } 6657052Samw 6667052Samw void 6677052Samw smb_user_list_free(smb_dr_ulist_t *userlist) 6687052Samw { 6697052Samw int i; 6707052Samw 6717052Samw if (userlist) { 6727052Samw for (i = 0; i < userlist->dul_cnt; i++) 6737052Samw smb_user_context_fini(&userlist->dul_users[i]); 6747052Samw } 6757052Samw } 676