13db3f65cSamw /* 23db3f65cSamw * CDDL HEADER START 33db3f65cSamw * 43db3f65cSamw * The contents of this file are subject to the terms of the 53db3f65cSamw * Common Development and Distribution License (the "License"). 63db3f65cSamw * You may not use this file except in compliance with the License. 73db3f65cSamw * 83db3f65cSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93db3f65cSamw * or http://www.opensolaris.org/os/licensing. 103db3f65cSamw * See the License for the specific language governing permissions 113db3f65cSamw * and limitations under the License. 123db3f65cSamw * 133db3f65cSamw * When distributing Covered Code, include this CDDL HEADER in each 143db3f65cSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153db3f65cSamw * If applicable, add the following below this CDDL HEADER, with the 163db3f65cSamw * fields enclosed by brackets "[]" replaced with your own identifying 173db3f65cSamw * information: Portions Copyright [yyyy] [name of copyright owner] 183db3f65cSamw * 193db3f65cSamw * CDDL HEADER END 203db3f65cSamw */ 213db3f65cSamw /* 22*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233db3f65cSamw * Use is subject to license terms. 243db3f65cSamw */ 253db3f65cSamw 263db3f65cSamw /* 273db3f65cSamw * This module provides the interface to NDR RPC. 283db3f65cSamw */ 293db3f65cSamw 303db3f65cSamw #include <sys/stat.h> 313db3f65cSamw #include <sys/door.h> 323db3f65cSamw #include <sys/door_data.h> 333db3f65cSamw #include <sys/uio.h> 343db3f65cSamw #include <sys/ksynch.h> 353db3f65cSamw #include <smbsrv/smb_incl.h> 363db3f65cSamw #include <smbsrv/smb_xdr.h> 373db3f65cSamw 383db3f65cSamw #define SMB_OPIPE_ISOPEN(OPIPE) \ 393db3f65cSamw (((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \ 403db3f65cSamw ((OPIPE)->p_hdr.oh_fid)) 413db3f65cSamw 423db3f65cSamw extern volatile uint32_t smb_fids; 433db3f65cSamw 443db3f65cSamw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 453db3f65cSamw static char *smb_opipe_lookup(const char *path); 463db3f65cSamw static uint32_t smb_opipe_fid(void); 473db3f65cSamw static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t); 483db3f65cSamw static void smb_opipe_enter(smb_opipe_t *); 493db3f65cSamw static void smb_opipe_exit(smb_opipe_t *); 503db3f65cSamw 513db3f65cSamw static door_handle_t smb_opipe_door_hd = NULL; 523db3f65cSamw static int smb_opipe_door_id = -1; 533db3f65cSamw static uint64_t smb_opipe_door_ncall = 0; 543db3f65cSamw static kmutex_t smb_opipe_door_mutex; 553db3f65cSamw static kcondvar_t smb_opipe_door_cv; 563db3f65cSamw 573db3f65cSamw static int smb_opipe_door_call(smb_opipe_t *); 583db3f65cSamw static int smb_opipe_door_upcall(smb_opipe_t *); 593db3f65cSamw static void smb_user_context_fini(smb_opipe_context_t *); 603db3f65cSamw 613db3f65cSamw /* 623db3f65cSamw * smb_opipe_open 633db3f65cSamw * 643db3f65cSamw * Open a well-known RPC named pipe. This routine should be called if 653db3f65cSamw * a file open is requested on a share of type STYPE_IPC. 663db3f65cSamw * If we recognize the pipe, we setup a new ofile. 673db3f65cSamw * 683db3f65cSamw * Returns 0 on success, Otherwise an NT status is returned to indicate 693db3f65cSamw * an error. 703db3f65cSamw */ 713db3f65cSamw int 723db3f65cSamw smb_opipe_open(smb_request_t *sr) 733db3f65cSamw { 74*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States open_param_t *op = &sr->arg.open; 753db3f65cSamw smb_ofile_t *of; 763db3f65cSamw smb_opipe_t *opipe; 773db3f65cSamw smb_opipe_hdr_t hdr; 783db3f65cSamw smb_error_t err; 793db3f65cSamw char *pipe_name; 803db3f65cSamw 813db3f65cSamw if ((pipe_name = smb_opipe_lookup(op->fqi.path)) == NULL) 823db3f65cSamw return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 833db3f65cSamw 84c8ec8eeaSjose borrego op->create_options = 0; 85c8ec8eeaSjose borrego 86c8ec8eeaSjose borrego of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op, 873db3f65cSamw SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 88*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 893db3f65cSamw if (of == NULL) 903db3f65cSamw return (err.status); 913db3f65cSamw 92*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (!smb_tree_is_connected(sr->tid_tree)) { 93*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_close(of, 0); 94*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_release(of); 95*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 96*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 97*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 983db3f65cSamw op->dsize = 0x01000; 993db3f65cSamw op->dattr = FILE_ATTRIBUTE_NORMAL; 1003db3f65cSamw op->ftype = SMB_FTYPE_MESG_PIPE; 1013db3f65cSamw op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 1023db3f65cSamw op->devstate = SMB_PIPE_READMODE_MESSAGE 1033db3f65cSamw | SMB_PIPE_TYPE_MESSAGE 1043db3f65cSamw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 1053db3f65cSamw op->fileid = of->f_fid; 1063db3f65cSamw 1073db3f65cSamw sr->smb_fid = of->f_fid; 1083db3f65cSamw sr->fid_ofile = of; 1093db3f65cSamw 1103db3f65cSamw opipe = of->f_pipe; 1113db3f65cSamw mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 1123db3f65cSamw cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 1133db3f65cSamw smb_opipe_enter(opipe); 1143db3f65cSamw 1153db3f65cSamw opipe->p_name = pipe_name; 1163db3f65cSamw opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 1173db3f65cSamw 1183db3f65cSamw /* 1193db3f65cSamw * p_data points to the offset within p_doorbuf at which 1203db3f65cSamw * data will be written or read. 1213db3f65cSamw */ 1223db3f65cSamw opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr); 1233db3f65cSamw 1243db3f65cSamw if (smb_opipe_do_open(sr, opipe) != 0) { 1253db3f65cSamw /* 1263db3f65cSamw * On error, reset the header to clear the fid, 1273db3f65cSamw * which avoids confusion when smb_opipe_close() is 1283db3f65cSamw * called by smb_ofile_close(). 1293db3f65cSamw */ 1303db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 1313db3f65cSamw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 1323db3f65cSamw smb_opipe_exit(opipe); 133c8ec8eeaSjose borrego smb_ofile_close(of, 0); 1343db3f65cSamw return (NT_STATUS_NO_MEMORY); 1353db3f65cSamw } 1363db3f65cSamw smb_opipe_exit(opipe); 1373db3f65cSamw return (NT_STATUS_SUCCESS); 1383db3f65cSamw } 1393db3f65cSamw 1403db3f65cSamw /* 1413db3f65cSamw * smb_opipe_lookup 1423db3f65cSamw * 1433db3f65cSamw * Lookup a path to see if it's a well-known RPC named pipe that we support. 1443db3f65cSamw * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 1453db3f65cSamw * can be assumed, so all we need here are the service names. 1463db3f65cSamw * 1473db3f65cSamw * Returns a pointer to the pipe name (without any leading \'s) on sucess. 1483db3f65cSamw * Otherwise returns a null pointer. 1493db3f65cSamw */ 1503db3f65cSamw static char * 1513db3f65cSamw smb_opipe_lookup(const char *path) 1523db3f65cSamw { 1533db3f65cSamw static char *named_pipes[] = { 1543db3f65cSamw "LSARPC", 1553db3f65cSamw "NETLOGON", 1563db3f65cSamw "SAMR", 1573db3f65cSamw "SPOOLSS", 1583db3f65cSamw "SRVSVC", 1593db3f65cSamw "SVCCTL", 1603db3f65cSamw "WINREG", 1613db3f65cSamw "WKSSVC", 1623db3f65cSamw "EVENTLOG" 1633db3f65cSamw }; 1643db3f65cSamw 1653db3f65cSamw const char *name; 1663db3f65cSamw int i; 1673db3f65cSamw 1683db3f65cSamw if (path == NULL) 1693db3f65cSamw return (NULL); 1703db3f65cSamw 1713db3f65cSamw name = path; 1723db3f65cSamw name += strspn(name, "\\"); 1733db3f65cSamw if (utf8_strncasecmp(name, "PIPE", 4) == 0) { 1743db3f65cSamw path += 4; 1753db3f65cSamw name += strspn(name, "\\"); 1763db3f65cSamw } 1773db3f65cSamw 1783db3f65cSamw for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 1793db3f65cSamw if (utf8_strcasecmp(name, named_pipes[i]) == 0) 1803db3f65cSamw return (named_pipes[i]); 1813db3f65cSamw } 1823db3f65cSamw 1833db3f65cSamw return (NULL); 1843db3f65cSamw } 1853db3f65cSamw 1863db3f65cSamw /* 1873db3f65cSamw * Initialize the opipe header and context, and make the door call. 1883db3f65cSamw */ 1893db3f65cSamw static int 1903db3f65cSamw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 1913db3f65cSamw { 1923db3f65cSamw smb_opipe_context_t *ctx = &opipe->p_context; 1933db3f65cSamw smb_user_t *user = sr->uid_user; 1943db3f65cSamw uint8_t *buf = opipe->p_doorbuf; 1953db3f65cSamw uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 1963db3f65cSamw uint32_t len; 1973db3f65cSamw 1983db3f65cSamw smb_user_context_init(user, ctx); 1993db3f65cSamw len = xdr_sizeof(smb_opipe_context_xdr, ctx); 2003db3f65cSamw 2013db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 2023db3f65cSamw opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 2033db3f65cSamw opipe->p_hdr.oh_fid = smb_opipe_fid(); 2043db3f65cSamw 2053db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 2063db3f65cSamw return (-1); 2073db3f65cSamw 2083db3f65cSamw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 2093db3f65cSamw buf += len; 2103db3f65cSamw buflen -= len; 2113db3f65cSamw 2123db3f65cSamw if (smb_opipe_context_encode(ctx, buf, buflen) == -1) 2133db3f65cSamw return (-1); 2143db3f65cSamw 2153db3f65cSamw return (smb_opipe_door_call(opipe)); 2163db3f65cSamw } 2173db3f65cSamw 2183db3f65cSamw /* 2193db3f65cSamw * smb_opipe_fid 2203db3f65cSamw * 2213db3f65cSamw * The opipe_fid is an arbitrary id used to associate RPC requests 2223db3f65cSamw * with a binding handle. A new fid is returned on each call. 2233db3f65cSamw * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 2243db3f65cSamw * and SMB sometimes uses -1 to indicate all open fid's. 2253db3f65cSamw */ 2263db3f65cSamw static uint32_t 2273db3f65cSamw smb_opipe_fid(void) 2283db3f65cSamw { 2293db3f65cSamw static uint32_t opipe_fid; 2303db3f65cSamw static kmutex_t smb_opipe_fid_mutex; 2313db3f65cSamw 2323db3f65cSamw mutex_enter(&smb_opipe_fid_mutex); 2333db3f65cSamw 2343db3f65cSamw if (opipe_fid == 0) 2353db3f65cSamw opipe_fid = lbolt << 11; 2363db3f65cSamw 2373db3f65cSamw do { 2383db3f65cSamw ++opipe_fid; 2393db3f65cSamw } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 2403db3f65cSamw 2413db3f65cSamw mutex_exit(&smb_opipe_fid_mutex); 2423db3f65cSamw 2433db3f65cSamw return (opipe_fid); 2443db3f65cSamw } 2453db3f65cSamw 2463db3f65cSamw /* 2473db3f65cSamw * smb_opipe_close 2483db3f65cSamw * 2493db3f65cSamw * Called whenever an IPC file/pipe is closed. 2503db3f65cSamw */ 2513db3f65cSamw void 2523db3f65cSamw smb_opipe_close(smb_ofile_t *of) 2533db3f65cSamw { 2543db3f65cSamw smb_opipe_t *opipe; 2553db3f65cSamw 2563db3f65cSamw ASSERT(of); 2573db3f65cSamw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 2583db3f65cSamw ASSERT(of->f_pipe != NULL); 2593db3f65cSamw 2603db3f65cSamw opipe = of->f_pipe; 2613db3f65cSamw smb_opipe_enter(opipe); 2623db3f65cSamw 2633db3f65cSamw if (SMB_OPIPE_ISOPEN(opipe)) { 2643db3f65cSamw (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 2653db3f65cSamw (void) smb_opipe_door_call(opipe); 2663db3f65cSamw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 2673db3f65cSamw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 2683db3f65cSamw } 2693db3f65cSamw 2703db3f65cSamw smb_user_context_fini(&opipe->p_context); 2713db3f65cSamw smb_opipe_exit(opipe); 2723db3f65cSamw cv_destroy(&opipe->p_cv); 2733db3f65cSamw mutex_destroy(&opipe->p_mutex); 2743db3f65cSamw } 2753db3f65cSamw 2763db3f65cSamw static int 2773db3f65cSamw smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 2783db3f65cSamw { 2793db3f65cSamw opipe->p_hdr.oh_op = cmd; 2803db3f65cSamw opipe->p_hdr.oh_datalen = datalen; 2813db3f65cSamw opipe->p_hdr.oh_resid = 0; 2823db3f65cSamw opipe->p_hdr.oh_status = 0; 2833db3f65cSamw 2843db3f65cSamw return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 2853db3f65cSamw SMB_OPIPE_DOOR_BUFSIZE)); 2863db3f65cSamw } 2873db3f65cSamw 2883db3f65cSamw /* 2893db3f65cSamw * smb_opipe_transact 2903db3f65cSamw * 2913db3f65cSamw * This is the entry point for RPC bind and request transactions. 2923db3f65cSamw * The fid is an arbitrary id used to associate RPC requests with a 2933db3f65cSamw * particular binding handle. 2943db3f65cSamw * 2953db3f65cSamw * If the data to be returned is larger than the client expects, we 2963db3f65cSamw * return as much as the client can handle and report a buffer overflow 2973db3f65cSamw * warning, which informs the client that we have more data to return. 2983db3f65cSamw * The residual data remains in the pipe until the client claims it or 2993db3f65cSamw * closes the pipe. 3003db3f65cSamw */ 3013db3f65cSamw smb_sdrc_t 3023db3f65cSamw smb_opipe_transact(smb_request_t *sr, struct uio *uio) 3033db3f65cSamw { 3043db3f65cSamw smb_xa_t *xa; 3053db3f65cSamw smb_opipe_t *opipe; 3063db3f65cSamw struct mbuf *mhead; 3073db3f65cSamw int mdrcnt; 3083db3f65cSamw int nbytes; 3093db3f65cSamw int rc; 3103db3f65cSamw 3113db3f65cSamw if ((rc = smb_opipe_write(sr, uio)) != 0) { 3123db3f65cSamw if (rc == EBADF) 3133db3f65cSamw smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 3143db3f65cSamw ERRDOS, ERROR_INVALID_HANDLE); 3153db3f65cSamw else 3163db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3173db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 3183db3f65cSamw return (SDRC_ERROR); 3193db3f65cSamw } 3203db3f65cSamw 3213db3f65cSamw xa = sr->r_xa; 3223db3f65cSamw mdrcnt = xa->smb_mdrcnt; 3233db3f65cSamw opipe = sr->fid_ofile->f_pipe; 3243db3f65cSamw smb_opipe_enter(opipe); 3253db3f65cSamw 3263db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 3273db3f65cSamw smb_opipe_exit(opipe); 3283db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3293db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 3303db3f65cSamw return (SDRC_ERROR); 3313db3f65cSamw } 3323db3f65cSamw 3333db3f65cSamw rc = smb_opipe_door_call(opipe); 3343db3f65cSamw nbytes = opipe->p_hdr.oh_datalen; 3353db3f65cSamw 3363db3f65cSamw if (rc != 0) { 3373db3f65cSamw smb_opipe_exit(opipe); 3383db3f65cSamw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3393db3f65cSamw ERRDOS, ERROR_INTERNAL_ERROR); 3403db3f65cSamw return (SDRC_ERROR); 3413db3f65cSamw } 3423db3f65cSamw 3433db3f65cSamw if (nbytes) { 3443db3f65cSamw mhead = smb_mbuf_get(opipe->p_data, nbytes); 3453db3f65cSamw xa->rep_data_mb.max_bytes = nbytes; 3463db3f65cSamw MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 3473db3f65cSamw } 3483db3f65cSamw 3493db3f65cSamw if (opipe->p_hdr.oh_resid) { 3503db3f65cSamw /* 3513db3f65cSamw * The pipe contains more data than mdrcnt, warn the 3523db3f65cSamw * client that there is more data in the pipe. 3533db3f65cSamw * Typically, the client will call SmbReadX, which 3543db3f65cSamw * will call smb_opipe_read, to get the data. 3553db3f65cSamw */ 3563db3f65cSamw smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 3573db3f65cSamw ERRDOS, ERROR_MORE_DATA); 3583db3f65cSamw } 3593db3f65cSamw 3603db3f65cSamw smb_opipe_exit(opipe); 3613db3f65cSamw return (SDRC_SUCCESS); 3623db3f65cSamw } 3633db3f65cSamw 3643db3f65cSamw /* 3653db3f65cSamw * smb_opipe_write 3663db3f65cSamw * 3673db3f65cSamw * Write RPC request data to the pipe. The client should call smb_opipe_read 3683db3f65cSamw * to complete the exchange and obtain the RPC response. 3693db3f65cSamw * 3703db3f65cSamw * Returns 0 on success or an errno on failure. 3713db3f65cSamw */ 3723db3f65cSamw int 3733db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio) 3743db3f65cSamw { 3753db3f65cSamw smb_opipe_t *opipe; 3763db3f65cSamw uint32_t buflen; 3773db3f65cSamw uint32_t len; 3783db3f65cSamw int rc; 3793db3f65cSamw 3803db3f65cSamw ASSERT(sr->fid_ofile); 3813db3f65cSamw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 3823db3f65cSamw ASSERT(sr->fid_ofile->f_pipe != NULL); 3833db3f65cSamw 3843db3f65cSamw opipe = sr->fid_ofile->f_pipe; 3853db3f65cSamw smb_opipe_enter(opipe); 3863db3f65cSamw 3873db3f65cSamw if (!SMB_OPIPE_ISOPEN(opipe)) { 3883db3f65cSamw smb_opipe_exit(opipe); 3893db3f65cSamw return (EBADF); 3903db3f65cSamw } 3913db3f65cSamw 3923db3f65cSamw rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 3933db3f65cSamw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 3943db3f65cSamw if (rc == -1 || len == 0) { 3953db3f65cSamw smb_opipe_exit(opipe); 3963db3f65cSamw return (ENOMEM); 3973db3f65cSamw } 3983db3f65cSamw 3993db3f65cSamw buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 4003db3f65cSamw (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 4013db3f65cSamw 4023db3f65cSamw rc = smb_opipe_door_call(opipe); 4033db3f65cSamw 4043db3f65cSamw smb_opipe_exit(opipe); 4053db3f65cSamw return ((rc == 0) ? 0 : EIO); 4063db3f65cSamw } 4073db3f65cSamw 4083db3f65cSamw /* 4093db3f65cSamw * smb_opipe_read 4103db3f65cSamw * 4113db3f65cSamw * This interface may be called because smb_opipe_transact could not return 4123db3f65cSamw * all of the data in the original transaction or to form the second half 4133db3f65cSamw * of a transaction set up using smb_opipe_write. Either way, we just need 4143db3f65cSamw * to read data from the pipe and return it. 4153db3f65cSamw * 4163db3f65cSamw * The response data is encoded into raw_data as required by the smb_read 4173db3f65cSamw * functions. The uio_resid value indicates the number of bytes read. 4183db3f65cSamw */ 4193db3f65cSamw int 4203db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio) 4213db3f65cSamw { 4223db3f65cSamw smb_opipe_t *opipe; 4233db3f65cSamw struct mbuf *mhead; 4243db3f65cSamw uint32_t nbytes; 4253db3f65cSamw int rc; 4263db3f65cSamw 4273db3f65cSamw ASSERT(sr->fid_ofile); 4283db3f65cSamw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 4293db3f65cSamw ASSERT(sr->fid_ofile->f_pipe != NULL); 4303db3f65cSamw 4313db3f65cSamw opipe = sr->fid_ofile->f_pipe; 4323db3f65cSamw smb_opipe_enter(opipe); 4333db3f65cSamw 4343db3f65cSamw if (!SMB_OPIPE_ISOPEN(opipe)) { 4353db3f65cSamw smb_opipe_exit(opipe); 4363db3f65cSamw return (EBADF); 4373db3f65cSamw } 4383db3f65cSamw 4393db3f65cSamw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 4403db3f65cSamw smb_opipe_exit(opipe); 4413db3f65cSamw return (ENOMEM); 4423db3f65cSamw } 4433db3f65cSamw 4443db3f65cSamw rc = smb_opipe_door_call(opipe); 4453db3f65cSamw nbytes = opipe->p_hdr.oh_datalen; 4463db3f65cSamw 4473db3f65cSamw if (rc != 0 || nbytes > uio->uio_resid) { 4483db3f65cSamw smb_opipe_exit(opipe); 4493db3f65cSamw return (EIO); 4503db3f65cSamw } 4513db3f65cSamw 4523db3f65cSamw if (nbytes) { 4533db3f65cSamw mhead = smb_mbuf_get(opipe->p_data, nbytes); 4543db3f65cSamw MBC_SETUP(&sr->raw_data, nbytes); 4553db3f65cSamw MBC_ATTACH_MBUF(&sr->raw_data, mhead); 4563db3f65cSamw uio->uio_resid -= nbytes; 4573db3f65cSamw } 4583db3f65cSamw 4593db3f65cSamw smb_opipe_exit(opipe); 4603db3f65cSamw return (rc); 4613db3f65cSamw } 4623db3f65cSamw 4633db3f65cSamw /* 4643db3f65cSamw * Named pipe I/O is serialized per fid to ensure that each request 4653db3f65cSamw * has exclusive opipe access for the duration of the request. 4663db3f65cSamw */ 4673db3f65cSamw static void 4683db3f65cSamw smb_opipe_enter(smb_opipe_t *opipe) 4693db3f65cSamw { 4703db3f65cSamw mutex_enter(&opipe->p_mutex); 4713db3f65cSamw 4723db3f65cSamw while (opipe->p_busy) 4733db3f65cSamw cv_wait(&opipe->p_cv, &opipe->p_mutex); 4743db3f65cSamw 4753db3f65cSamw opipe->p_busy = 1; 4763db3f65cSamw mutex_exit(&opipe->p_mutex); 4773db3f65cSamw } 4783db3f65cSamw 4793db3f65cSamw static void 4803db3f65cSamw smb_opipe_exit(smb_opipe_t *opipe) 4813db3f65cSamw { 4823db3f65cSamw mutex_enter(&opipe->p_mutex); 4833db3f65cSamw opipe->p_busy = 0; 4843db3f65cSamw cv_signal(&opipe->p_cv); 4853db3f65cSamw mutex_exit(&opipe->p_mutex); 4863db3f65cSamw } 4873db3f65cSamw 4883db3f65cSamw /* 4893db3f65cSamw * opipe door client (to user space door server). 4903db3f65cSamw */ 4913db3f65cSamw void 4923db3f65cSamw smb_opipe_door_init(void) 4933db3f65cSamw { 4943db3f65cSamw mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 4953db3f65cSamw cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 4963db3f65cSamw } 4973db3f65cSamw 4983db3f65cSamw void 4993db3f65cSamw smb_opipe_door_fini(void) 5003db3f65cSamw { 5013db3f65cSamw smb_opipe_door_close(); 5023db3f65cSamw cv_destroy(&smb_opipe_door_cv); 5033db3f65cSamw mutex_destroy(&smb_opipe_door_mutex); 5043db3f65cSamw } 5053db3f65cSamw 5063db3f65cSamw /* 5073db3f65cSamw * Open the (user space) door. If the door is already open, 5083db3f65cSamw * close it first because the door-id has probably changed. 5093db3f65cSamw */ 5103db3f65cSamw int 5113db3f65cSamw smb_opipe_door_open(int door_id) 5123db3f65cSamw { 5133db3f65cSamw smb_opipe_door_close(); 5143db3f65cSamw 5153db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 5163db3f65cSamw smb_opipe_door_ncall = 0; 5173db3f65cSamw 5183db3f65cSamw if (smb_opipe_door_hd == NULL) { 5193db3f65cSamw smb_opipe_door_id = door_id; 5203db3f65cSamw smb_opipe_door_hd = door_ki_lookup(door_id); 5213db3f65cSamw } 5223db3f65cSamw 5233db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 5243db3f65cSamw return ((smb_opipe_door_hd == NULL) ? -1 : 0); 5253db3f65cSamw } 5263db3f65cSamw 5273db3f65cSamw /* 5283db3f65cSamw * Close the (user space) door. 5293db3f65cSamw */ 5303db3f65cSamw void 5313db3f65cSamw smb_opipe_door_close(void) 5323db3f65cSamw { 5333db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 5343db3f65cSamw 5353db3f65cSamw if (smb_opipe_door_hd != NULL) { 5363db3f65cSamw while (smb_opipe_door_ncall > 0) 5373db3f65cSamw cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 5383db3f65cSamw 5393db3f65cSamw door_ki_rele(smb_opipe_door_hd); 5403db3f65cSamw smb_opipe_door_hd = NULL; 5413db3f65cSamw } 5423db3f65cSamw 5433db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 5443db3f65cSamw } 5453db3f65cSamw 5463db3f65cSamw /* 5473db3f65cSamw * opipe door call interface. 5483db3f65cSamw * Door serialization and call reference accounting is handled here. 5493db3f65cSamw */ 5503db3f65cSamw static int 5513db3f65cSamw smb_opipe_door_call(smb_opipe_t *opipe) 5523db3f65cSamw { 5533db3f65cSamw int rc; 5543db3f65cSamw 5553db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 5563db3f65cSamw 5573db3f65cSamw if (smb_opipe_door_hd == NULL) { 5583db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 5593db3f65cSamw 5603db3f65cSamw if (smb_opipe_door_open(smb_opipe_door_id) != 0) 5613db3f65cSamw return (-1); 5623db3f65cSamw 5633db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 5643db3f65cSamw } 5653db3f65cSamw 5663db3f65cSamw ++smb_opipe_door_ncall; 5673db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 5683db3f65cSamw 5693db3f65cSamw rc = smb_opipe_door_upcall(opipe); 5703db3f65cSamw 5713db3f65cSamw mutex_enter(&smb_opipe_door_mutex); 5723db3f65cSamw --smb_opipe_door_ncall; 5733db3f65cSamw cv_signal(&smb_opipe_door_cv); 5743db3f65cSamw mutex_exit(&smb_opipe_door_mutex); 5753db3f65cSamw return (rc); 5763db3f65cSamw } 5773db3f65cSamw 5783db3f65cSamw /* 5793db3f65cSamw * Door upcall wrapper - handles data marshalling. 5803db3f65cSamw * This function should only be called by smb_opipe_door_call. 5813db3f65cSamw */ 5823db3f65cSamw static int 5833db3f65cSamw smb_opipe_door_upcall(smb_opipe_t *opipe) 5843db3f65cSamw { 5853db3f65cSamw door_arg_t da; 5863db3f65cSamw smb_opipe_hdr_t hdr; 5873db3f65cSamw int i; 5883db3f65cSamw int rc; 5893db3f65cSamw 5903db3f65cSamw da.data_ptr = (char *)opipe->p_doorbuf; 5913db3f65cSamw da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 5923db3f65cSamw da.desc_ptr = NULL; 5933db3f65cSamw da.desc_num = 0; 5943db3f65cSamw da.rbuf = (char *)opipe->p_doorbuf; 5953db3f65cSamw da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 5963db3f65cSamw 5973db3f65cSamw for (i = 0; i < 3; ++i) { 5983db3f65cSamw if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 5993db3f65cSamw NULL, SIZE_MAX, 0)) == 0) 6003db3f65cSamw break; 6013db3f65cSamw 6023db3f65cSamw if (rc != EAGAIN && rc != EINTR) 6033db3f65cSamw return (-1); 6043db3f65cSamw } 6053db3f65cSamw 6063db3f65cSamw if (rc != 0) 6073db3f65cSamw return (-1); 6083db3f65cSamw 6093db3f65cSamw if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 6103db3f65cSamw return (-1); 6113db3f65cSamw 6123db3f65cSamw if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 6133db3f65cSamw (hdr.oh_fid != opipe->p_hdr.oh_fid) || 6143db3f65cSamw (hdr.oh_op != opipe->p_hdr.oh_op) || 6153db3f65cSamw (hdr.oh_status != 0) || 6163db3f65cSamw (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 6173db3f65cSamw return (-1); 6183db3f65cSamw } 6193db3f65cSamw 6203db3f65cSamw opipe->p_hdr.oh_datalen = hdr.oh_datalen; 6213db3f65cSamw opipe->p_hdr.oh_resid = hdr.oh_resid; 6223db3f65cSamw return (0); 6233db3f65cSamw } 6243db3f65cSamw 6253db3f65cSamw void 6263db3f65cSamw smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx) 6273db3f65cSamw { 6283db3f65cSamw smb_session_t *session; 6293db3f65cSamw 6303db3f65cSamw ASSERT(user); 6313db3f65cSamw ASSERT(user->u_domain); 6323db3f65cSamw ASSERT(user->u_name); 6333db3f65cSamw 6343db3f65cSamw session = user->u_session; 6353db3f65cSamw ASSERT(session); 6363db3f65cSamw ASSERT(session->workstation); 6373db3f65cSamw 6383db3f65cSamw ctx->oc_session_id = session->s_kid; 6393db3f65cSamw ctx->oc_native_os = session->native_os; 6403db3f65cSamw ctx->oc_ipaddr = session->ipaddr; 6413db3f65cSamw ctx->oc_uid = user->u_uid; 6423db3f65cSamw ctx->oc_logon_time = user->u_logon_time; 6433db3f65cSamw ctx->oc_flags = user->u_flags; 6443db3f65cSamw 6453db3f65cSamw ctx->oc_domain_len = user->u_domain_len; 6463db3f65cSamw ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len); 6473db3f65cSamw 6483db3f65cSamw ctx->oc_account_len = user->u_name_len; 6493db3f65cSamw ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len); 6503db3f65cSamw 6513db3f65cSamw ctx->oc_workstation_len = strlen(session->workstation) + 1; 6523db3f65cSamw ctx->oc_workstation = smb_kstrdup(session->workstation, 6533db3f65cSamw ctx->oc_workstation_len); 6543db3f65cSamw } 6553db3f65cSamw 6563db3f65cSamw static void 6573db3f65cSamw smb_user_context_fini(smb_opipe_context_t *ctx) 6583db3f65cSamw { 6593db3f65cSamw if (ctx) { 6603db3f65cSamw if (ctx->oc_domain) 6613db3f65cSamw kmem_free(ctx->oc_domain, ctx->oc_domain_len); 6623db3f65cSamw if (ctx->oc_account) 6633db3f65cSamw kmem_free(ctx->oc_account, ctx->oc_account_len); 6643db3f65cSamw if (ctx->oc_workstation) 6653db3f65cSamw kmem_free(ctx->oc_workstation, ctx->oc_workstation_len); 6663db3f65cSamw bzero(ctx, sizeof (smb_opipe_context_t)); 6673db3f65cSamw } 6683db3f65cSamw } 6693db3f65cSamw 6703db3f65cSamw void 6713db3f65cSamw smb_user_list_free(smb_dr_ulist_t *userlist) 6723db3f65cSamw { 6733db3f65cSamw int i; 6743db3f65cSamw 6753db3f65cSamw if (userlist) { 6763db3f65cSamw for (i = 0; i < userlist->dul_cnt; i++) 6773db3f65cSamw smb_user_context_fini(&userlist->dul_users[i]); 6783db3f65cSamw } 6793db3f65cSamw } 680