xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 7348:73b61202d5d6)
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