xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 3db3f65c6274eb042354801a308c8e9bc4994553)
1*3db3f65cSamw /*
2*3db3f65cSamw  * CDDL HEADER START
3*3db3f65cSamw  *
4*3db3f65cSamw  * The contents of this file are subject to the terms of the
5*3db3f65cSamw  * Common Development and Distribution License (the "License").
6*3db3f65cSamw  * You may not use this file except in compliance with the License.
7*3db3f65cSamw  *
8*3db3f65cSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3db3f65cSamw  * or http://www.opensolaris.org/os/licensing.
10*3db3f65cSamw  * See the License for the specific language governing permissions
11*3db3f65cSamw  * and limitations under the License.
12*3db3f65cSamw  *
13*3db3f65cSamw  * When distributing Covered Code, include this CDDL HEADER in each
14*3db3f65cSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3db3f65cSamw  * If applicable, add the following below this CDDL HEADER, with the
16*3db3f65cSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17*3db3f65cSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3db3f65cSamw  *
19*3db3f65cSamw  * CDDL HEADER END
20*3db3f65cSamw  */
21*3db3f65cSamw /*
22*3db3f65cSamw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*3db3f65cSamw  * Use is subject to license terms.
24*3db3f65cSamw  */
25*3db3f65cSamw 
26*3db3f65cSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3db3f65cSamw 
28*3db3f65cSamw /*
29*3db3f65cSamw  * This module provides the interface to NDR RPC.
30*3db3f65cSamw  */
31*3db3f65cSamw 
32*3db3f65cSamw #include <sys/stat.h>
33*3db3f65cSamw #include <sys/door.h>
34*3db3f65cSamw #include <sys/door_data.h>
35*3db3f65cSamw #include <sys/uio.h>
36*3db3f65cSamw #include <sys/ksynch.h>
37*3db3f65cSamw #include <smbsrv/smb_incl.h>
38*3db3f65cSamw #include <smbsrv/smb_xdr.h>
39*3db3f65cSamw 
40*3db3f65cSamw #define	SMB_OPIPE_ISOPEN(OPIPE)	\
41*3db3f65cSamw 	(((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \
42*3db3f65cSamw 	((OPIPE)->p_hdr.oh_fid))
43*3db3f65cSamw 
44*3db3f65cSamw extern volatile uint32_t smb_fids;
45*3db3f65cSamw 
46*3db3f65cSamw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
47*3db3f65cSamw static char *smb_opipe_lookup(const char *path);
48*3db3f65cSamw static uint32_t smb_opipe_fid(void);
49*3db3f65cSamw static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t);
50*3db3f65cSamw static void smb_opipe_enter(smb_opipe_t *);
51*3db3f65cSamw static void smb_opipe_exit(smb_opipe_t *);
52*3db3f65cSamw 
53*3db3f65cSamw static door_handle_t smb_opipe_door_hd = NULL;
54*3db3f65cSamw static int smb_opipe_door_id = -1;
55*3db3f65cSamw static uint64_t smb_opipe_door_ncall = 0;
56*3db3f65cSamw static kmutex_t smb_opipe_door_mutex;
57*3db3f65cSamw static kcondvar_t smb_opipe_door_cv;
58*3db3f65cSamw 
59*3db3f65cSamw static int smb_opipe_door_call(smb_opipe_t *);
60*3db3f65cSamw static int smb_opipe_door_upcall(smb_opipe_t *);
61*3db3f65cSamw static void smb_user_context_fini(smb_opipe_context_t *);
62*3db3f65cSamw 
63*3db3f65cSamw /*
64*3db3f65cSamw  * smb_opipe_open
65*3db3f65cSamw  *
66*3db3f65cSamw  * Open a well-known RPC named pipe. This routine should be called if
67*3db3f65cSamw  * a file open is requested on a share of type STYPE_IPC.
68*3db3f65cSamw  * If we recognize the pipe, we setup a new ofile.
69*3db3f65cSamw  *
70*3db3f65cSamw  * Returns 0 on success, Otherwise an NT status is returned to indicate
71*3db3f65cSamw  * an error.
72*3db3f65cSamw  */
73*3db3f65cSamw int
74*3db3f65cSamw smb_opipe_open(smb_request_t *sr)
75*3db3f65cSamw {
76*3db3f65cSamw 	struct open_param *op = &sr->arg.open;
77*3db3f65cSamw 	smb_ofile_t *of;
78*3db3f65cSamw 	smb_opipe_t *opipe;
79*3db3f65cSamw 	smb_opipe_hdr_t hdr;
80*3db3f65cSamw 	smb_error_t err;
81*3db3f65cSamw 	char *pipe_name;
82*3db3f65cSamw 
83*3db3f65cSamw 	if ((pipe_name = smb_opipe_lookup(op->fqi.path)) == NULL)
84*3db3f65cSamw 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
85*3db3f65cSamw 
86*3db3f65cSamw 	of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid,
87*3db3f65cSamw 	    op->desired_access, 0, op->share_access,
88*3db3f65cSamw 	    SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
89*3db3f65cSamw 	if (of == NULL)
90*3db3f65cSamw 		return (err.status);
91*3db3f65cSamw 
92*3db3f65cSamw 	op->dsize = 0x01000;
93*3db3f65cSamw 	op->dattr = FILE_ATTRIBUTE_NORMAL;
94*3db3f65cSamw 	op->ftype = SMB_FTYPE_MESG_PIPE;
95*3db3f65cSamw 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
96*3db3f65cSamw 	op->devstate = SMB_PIPE_READMODE_MESSAGE
97*3db3f65cSamw 	    | SMB_PIPE_TYPE_MESSAGE
98*3db3f65cSamw 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
99*3db3f65cSamw 	op->fileid = of->f_fid;
100*3db3f65cSamw 	op->create_options = 0;
101*3db3f65cSamw 
102*3db3f65cSamw 	sr->smb_fid = of->f_fid;
103*3db3f65cSamw 	sr->fid_ofile = of;
104*3db3f65cSamw 
105*3db3f65cSamw 	opipe = of->f_pipe;
106*3db3f65cSamw 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
107*3db3f65cSamw 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
108*3db3f65cSamw 	smb_opipe_enter(opipe);
109*3db3f65cSamw 
110*3db3f65cSamw 	opipe->p_name = pipe_name;
111*3db3f65cSamw 	opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
112*3db3f65cSamw 
113*3db3f65cSamw 	/*
114*3db3f65cSamw 	 * p_data points to the offset within p_doorbuf at which
115*3db3f65cSamw 	 * data will be written or read.
116*3db3f65cSamw 	 */
117*3db3f65cSamw 	opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr);
118*3db3f65cSamw 
119*3db3f65cSamw 	if (smb_opipe_do_open(sr, opipe) != 0) {
120*3db3f65cSamw 		/*
121*3db3f65cSamw 		 * On error, reset the header to clear the fid,
122*3db3f65cSamw 		 * which avoids confusion when smb_opipe_close() is
123*3db3f65cSamw 		 * called by smb_ofile_close().
124*3db3f65cSamw 		 */
125*3db3f65cSamw 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
126*3db3f65cSamw 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
127*3db3f65cSamw 		smb_opipe_exit(opipe);
128*3db3f65cSamw 		(void) smb_ofile_close(of, 0);
129*3db3f65cSamw 		return (NT_STATUS_NO_MEMORY);
130*3db3f65cSamw 	}
131*3db3f65cSamw 
132*3db3f65cSamw 	smb_opipe_exit(opipe);
133*3db3f65cSamw 	return (NT_STATUS_SUCCESS);
134*3db3f65cSamw }
135*3db3f65cSamw 
136*3db3f65cSamw /*
137*3db3f65cSamw  * smb_opipe_lookup
138*3db3f65cSamw  *
139*3db3f65cSamw  * Lookup a path to see if it's a well-known RPC named pipe that we support.
140*3db3f65cSamw  * The full pipe path will be in the form \\PIPE\\SERVICE.  The first part
141*3db3f65cSamw  * can be assumed, so all we need here are the service names.
142*3db3f65cSamw  *
143*3db3f65cSamw  * Returns a pointer to the pipe name (without any leading \'s) on sucess.
144*3db3f65cSamw  * Otherwise returns a null pointer.
145*3db3f65cSamw  */
146*3db3f65cSamw static char *
147*3db3f65cSamw smb_opipe_lookup(const char *path)
148*3db3f65cSamw {
149*3db3f65cSamw 	static char *named_pipes[] = {
150*3db3f65cSamw 		"LSARPC",
151*3db3f65cSamw 		"NETLOGON",
152*3db3f65cSamw 		"SAMR",
153*3db3f65cSamw 		"SPOOLSS",
154*3db3f65cSamw 		"SRVSVC",
155*3db3f65cSamw 		"SVCCTL",
156*3db3f65cSamw 		"WINREG",
157*3db3f65cSamw 		"WKSSVC",
158*3db3f65cSamw 		"EVENTLOG"
159*3db3f65cSamw 	};
160*3db3f65cSamw 
161*3db3f65cSamw 	const char *name;
162*3db3f65cSamw 	int i;
163*3db3f65cSamw 
164*3db3f65cSamw 	if (path == NULL)
165*3db3f65cSamw 		return (NULL);
166*3db3f65cSamw 
167*3db3f65cSamw 	name = path;
168*3db3f65cSamw 	name += strspn(name, "\\");
169*3db3f65cSamw 	if (utf8_strncasecmp(name, "PIPE", 4) == 0) {
170*3db3f65cSamw 		path += 4;
171*3db3f65cSamw 		name += strspn(name, "\\");
172*3db3f65cSamw 	}
173*3db3f65cSamw 
174*3db3f65cSamw 	for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
175*3db3f65cSamw 		if (utf8_strcasecmp(name, named_pipes[i]) == 0)
176*3db3f65cSamw 			return (named_pipes[i]);
177*3db3f65cSamw 	}
178*3db3f65cSamw 
179*3db3f65cSamw 	return (NULL);
180*3db3f65cSamw }
181*3db3f65cSamw 
182*3db3f65cSamw /*
183*3db3f65cSamw  * Initialize the opipe header and context, and make the door call.
184*3db3f65cSamw  */
185*3db3f65cSamw static int
186*3db3f65cSamw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
187*3db3f65cSamw {
188*3db3f65cSamw 	smb_opipe_context_t *ctx = &opipe->p_context;
189*3db3f65cSamw 	smb_user_t *user = sr->uid_user;
190*3db3f65cSamw 	uint8_t *buf = opipe->p_doorbuf;
191*3db3f65cSamw 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
192*3db3f65cSamw 	uint32_t len;
193*3db3f65cSamw 
194*3db3f65cSamw 	smb_user_context_init(user, ctx);
195*3db3f65cSamw 	len = xdr_sizeof(smb_opipe_context_xdr, ctx);
196*3db3f65cSamw 
197*3db3f65cSamw 	bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
198*3db3f65cSamw 	opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC;
199*3db3f65cSamw 	opipe->p_hdr.oh_fid = smb_opipe_fid();
200*3db3f65cSamw 
201*3db3f65cSamw 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1)
202*3db3f65cSamw 		return (-1);
203*3db3f65cSamw 
204*3db3f65cSamw 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
205*3db3f65cSamw 	buf += len;
206*3db3f65cSamw 	buflen -= len;
207*3db3f65cSamw 
208*3db3f65cSamw 	if (smb_opipe_context_encode(ctx, buf, buflen) == -1)
209*3db3f65cSamw 		return (-1);
210*3db3f65cSamw 
211*3db3f65cSamw 	return (smb_opipe_door_call(opipe));
212*3db3f65cSamw }
213*3db3f65cSamw 
214*3db3f65cSamw /*
215*3db3f65cSamw  * smb_opipe_fid
216*3db3f65cSamw  *
217*3db3f65cSamw  * The opipe_fid is an arbitrary id used to associate RPC requests
218*3db3f65cSamw  * with a binding handle.  A new fid is returned on each call.
219*3db3f65cSamw  * 0 or -1 are not assigned: 0 is used to indicate an invalid fid
220*3db3f65cSamw  * and SMB sometimes uses -1 to indicate all open fid's.
221*3db3f65cSamw  */
222*3db3f65cSamw static uint32_t
223*3db3f65cSamw smb_opipe_fid(void)
224*3db3f65cSamw {
225*3db3f65cSamw 	static uint32_t opipe_fid;
226*3db3f65cSamw 	static kmutex_t smb_opipe_fid_mutex;
227*3db3f65cSamw 
228*3db3f65cSamw 	mutex_enter(&smb_opipe_fid_mutex);
229*3db3f65cSamw 
230*3db3f65cSamw 	if (opipe_fid == 0)
231*3db3f65cSamw 		opipe_fid = lbolt << 11;
232*3db3f65cSamw 
233*3db3f65cSamw 	do {
234*3db3f65cSamw 		++opipe_fid;
235*3db3f65cSamw 	} while (opipe_fid == 0 || opipe_fid == (uint32_t)-1);
236*3db3f65cSamw 
237*3db3f65cSamw 	mutex_exit(&smb_opipe_fid_mutex);
238*3db3f65cSamw 
239*3db3f65cSamw 	return (opipe_fid);
240*3db3f65cSamw }
241*3db3f65cSamw 
242*3db3f65cSamw /*
243*3db3f65cSamw  * smb_opipe_close
244*3db3f65cSamw  *
245*3db3f65cSamw  * Called whenever an IPC file/pipe is closed.
246*3db3f65cSamw  */
247*3db3f65cSamw void
248*3db3f65cSamw smb_opipe_close(smb_ofile_t *of)
249*3db3f65cSamw {
250*3db3f65cSamw 	smb_opipe_t *opipe;
251*3db3f65cSamw 
252*3db3f65cSamw 	ASSERT(of);
253*3db3f65cSamw 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
254*3db3f65cSamw 	ASSERT(of->f_pipe != NULL);
255*3db3f65cSamw 
256*3db3f65cSamw 	opipe = of->f_pipe;
257*3db3f65cSamw 	smb_opipe_enter(opipe);
258*3db3f65cSamw 
259*3db3f65cSamw 	if (SMB_OPIPE_ISOPEN(opipe)) {
260*3db3f65cSamw 		(void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0);
261*3db3f65cSamw 		(void) smb_opipe_door_call(opipe);
262*3db3f65cSamw 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
263*3db3f65cSamw 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
264*3db3f65cSamw 	}
265*3db3f65cSamw 
266*3db3f65cSamw 	smb_user_context_fini(&opipe->p_context);
267*3db3f65cSamw 	smb_opipe_exit(opipe);
268*3db3f65cSamw 	cv_destroy(&opipe->p_cv);
269*3db3f65cSamw 	mutex_destroy(&opipe->p_mutex);
270*3db3f65cSamw }
271*3db3f65cSamw 
272*3db3f65cSamw static int
273*3db3f65cSamw smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
274*3db3f65cSamw {
275*3db3f65cSamw 	opipe->p_hdr.oh_op = cmd;
276*3db3f65cSamw 	opipe->p_hdr.oh_datalen = datalen;
277*3db3f65cSamw 	opipe->p_hdr.oh_resid = 0;
278*3db3f65cSamw 	opipe->p_hdr.oh_status = 0;
279*3db3f65cSamw 
280*3db3f65cSamw 	return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
281*3db3f65cSamw 	    SMB_OPIPE_DOOR_BUFSIZE));
282*3db3f65cSamw }
283*3db3f65cSamw 
284*3db3f65cSamw /*
285*3db3f65cSamw  * smb_opipe_transact
286*3db3f65cSamw  *
287*3db3f65cSamw  * This is the entry point for RPC bind and request transactions.
288*3db3f65cSamw  * The fid is an arbitrary id used to associate RPC requests with a
289*3db3f65cSamw  * particular binding handle.
290*3db3f65cSamw  *
291*3db3f65cSamw  * If the data to be returned is larger than the client expects, we
292*3db3f65cSamw  * return as much as the client can handle and report a buffer overflow
293*3db3f65cSamw  * warning, which informs the client that we have more data to return.
294*3db3f65cSamw  * The residual data remains in the pipe until the client claims it or
295*3db3f65cSamw  * closes the pipe.
296*3db3f65cSamw  */
297*3db3f65cSamw smb_sdrc_t
298*3db3f65cSamw smb_opipe_transact(smb_request_t *sr, struct uio *uio)
299*3db3f65cSamw {
300*3db3f65cSamw 	smb_xa_t *xa;
301*3db3f65cSamw 	smb_opipe_t *opipe;
302*3db3f65cSamw 	struct mbuf *mhead;
303*3db3f65cSamw 	int mdrcnt;
304*3db3f65cSamw 	int nbytes;
305*3db3f65cSamw 	int rc;
306*3db3f65cSamw 
307*3db3f65cSamw 	if ((rc = smb_opipe_write(sr, uio)) != 0) {
308*3db3f65cSamw 		if (rc == EBADF)
309*3db3f65cSamw 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
310*3db3f65cSamw 			    ERRDOS, ERROR_INVALID_HANDLE);
311*3db3f65cSamw 		else
312*3db3f65cSamw 			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
313*3db3f65cSamw 			    ERRDOS, ERROR_INTERNAL_ERROR);
314*3db3f65cSamw 		return (SDRC_ERROR);
315*3db3f65cSamw 	}
316*3db3f65cSamw 
317*3db3f65cSamw 	xa = sr->r_xa;
318*3db3f65cSamw 	mdrcnt = xa->smb_mdrcnt;
319*3db3f65cSamw 	opipe = sr->fid_ofile->f_pipe;
320*3db3f65cSamw 	smb_opipe_enter(opipe);
321*3db3f65cSamw 
322*3db3f65cSamw 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
323*3db3f65cSamw 		smb_opipe_exit(opipe);
324*3db3f65cSamw 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
325*3db3f65cSamw 		    ERRDOS, ERROR_INTERNAL_ERROR);
326*3db3f65cSamw 		return (SDRC_ERROR);
327*3db3f65cSamw 	}
328*3db3f65cSamw 
329*3db3f65cSamw 	rc = smb_opipe_door_call(opipe);
330*3db3f65cSamw 	nbytes = opipe->p_hdr.oh_datalen;
331*3db3f65cSamw 
332*3db3f65cSamw 	if (rc != 0) {
333*3db3f65cSamw 		smb_opipe_exit(opipe);
334*3db3f65cSamw 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
335*3db3f65cSamw 		    ERRDOS, ERROR_INTERNAL_ERROR);
336*3db3f65cSamw 		return (SDRC_ERROR);
337*3db3f65cSamw 	}
338*3db3f65cSamw 
339*3db3f65cSamw 	if (nbytes) {
340*3db3f65cSamw 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
341*3db3f65cSamw 		xa->rep_data_mb.max_bytes = nbytes;
342*3db3f65cSamw 		MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
343*3db3f65cSamw 	}
344*3db3f65cSamw 
345*3db3f65cSamw 	if (opipe->p_hdr.oh_resid) {
346*3db3f65cSamw 		/*
347*3db3f65cSamw 		 * The pipe contains more data than mdrcnt, warn the
348*3db3f65cSamw 		 * client that there is more data in the pipe.
349*3db3f65cSamw 		 * Typically, the client will call SmbReadX, which
350*3db3f65cSamw 		 * will call smb_opipe_read, to get the data.
351*3db3f65cSamw 		 */
352*3db3f65cSamw 		smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
353*3db3f65cSamw 		    ERRDOS, ERROR_MORE_DATA);
354*3db3f65cSamw 	}
355*3db3f65cSamw 
356*3db3f65cSamw 	smb_opipe_exit(opipe);
357*3db3f65cSamw 	return (SDRC_SUCCESS);
358*3db3f65cSamw }
359*3db3f65cSamw 
360*3db3f65cSamw /*
361*3db3f65cSamw  * smb_opipe_write
362*3db3f65cSamw  *
363*3db3f65cSamw  * Write RPC request data to the pipe.  The client should call smb_opipe_read
364*3db3f65cSamw  * to complete the exchange and obtain the RPC response.
365*3db3f65cSamw  *
366*3db3f65cSamw  * Returns 0 on success or an errno on failure.
367*3db3f65cSamw  */
368*3db3f65cSamw int
369*3db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio)
370*3db3f65cSamw {
371*3db3f65cSamw 	smb_opipe_t *opipe;
372*3db3f65cSamw 	uint32_t buflen;
373*3db3f65cSamw 	uint32_t len;
374*3db3f65cSamw 	int rc;
375*3db3f65cSamw 
376*3db3f65cSamw 	ASSERT(sr->fid_ofile);
377*3db3f65cSamw 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
378*3db3f65cSamw 	ASSERT(sr->fid_ofile->f_pipe != NULL);
379*3db3f65cSamw 
380*3db3f65cSamw 	opipe = sr->fid_ofile->f_pipe;
381*3db3f65cSamw 	smb_opipe_enter(opipe);
382*3db3f65cSamw 
383*3db3f65cSamw 	if (!SMB_OPIPE_ISOPEN(opipe)) {
384*3db3f65cSamw 		smb_opipe_exit(opipe);
385*3db3f65cSamw 		return (EBADF);
386*3db3f65cSamw 	}
387*3db3f65cSamw 
388*3db3f65cSamw 	rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
389*3db3f65cSamw 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
390*3db3f65cSamw 	if (rc == -1 || len == 0) {
391*3db3f65cSamw 		smb_opipe_exit(opipe);
392*3db3f65cSamw 		return (ENOMEM);
393*3db3f65cSamw 	}
394*3db3f65cSamw 
395*3db3f65cSamw 	buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
396*3db3f65cSamw 	(void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
397*3db3f65cSamw 
398*3db3f65cSamw 	rc = smb_opipe_door_call(opipe);
399*3db3f65cSamw 
400*3db3f65cSamw 	smb_opipe_exit(opipe);
401*3db3f65cSamw 	return ((rc == 0) ? 0 : EIO);
402*3db3f65cSamw }
403*3db3f65cSamw 
404*3db3f65cSamw /*
405*3db3f65cSamw  * smb_opipe_read
406*3db3f65cSamw  *
407*3db3f65cSamw  * This interface may be called because smb_opipe_transact could not return
408*3db3f65cSamw  * all of the data in the original transaction or to form the second half
409*3db3f65cSamw  * of a transaction set up using smb_opipe_write.  Either way, we just need
410*3db3f65cSamw  * to read data from the pipe and return it.
411*3db3f65cSamw  *
412*3db3f65cSamw  * The response data is encoded into raw_data as required by the smb_read
413*3db3f65cSamw  * functions.  The uio_resid value indicates the number of bytes read.
414*3db3f65cSamw  */
415*3db3f65cSamw int
416*3db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio)
417*3db3f65cSamw {
418*3db3f65cSamw 	smb_opipe_t *opipe;
419*3db3f65cSamw 	struct mbuf *mhead;
420*3db3f65cSamw 	uint32_t nbytes;
421*3db3f65cSamw 	int rc;
422*3db3f65cSamw 
423*3db3f65cSamw 	ASSERT(sr->fid_ofile);
424*3db3f65cSamw 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
425*3db3f65cSamw 	ASSERT(sr->fid_ofile->f_pipe != NULL);
426*3db3f65cSamw 
427*3db3f65cSamw 	opipe = sr->fid_ofile->f_pipe;
428*3db3f65cSamw 	smb_opipe_enter(opipe);
429*3db3f65cSamw 
430*3db3f65cSamw 	if (!SMB_OPIPE_ISOPEN(opipe)) {
431*3db3f65cSamw 		smb_opipe_exit(opipe);
432*3db3f65cSamw 		return (EBADF);
433*3db3f65cSamw 	}
434*3db3f65cSamw 
435*3db3f65cSamw 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
436*3db3f65cSamw 		smb_opipe_exit(opipe);
437*3db3f65cSamw 		return (ENOMEM);
438*3db3f65cSamw 	}
439*3db3f65cSamw 
440*3db3f65cSamw 	rc = smb_opipe_door_call(opipe);
441*3db3f65cSamw 	nbytes = opipe->p_hdr.oh_datalen;
442*3db3f65cSamw 
443*3db3f65cSamw 	if (rc != 0 || nbytes > uio->uio_resid) {
444*3db3f65cSamw 		smb_opipe_exit(opipe);
445*3db3f65cSamw 		return (EIO);
446*3db3f65cSamw 	}
447*3db3f65cSamw 
448*3db3f65cSamw 	if (nbytes) {
449*3db3f65cSamw 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
450*3db3f65cSamw 		MBC_SETUP(&sr->raw_data, nbytes);
451*3db3f65cSamw 		MBC_ATTACH_MBUF(&sr->raw_data, mhead);
452*3db3f65cSamw 		uio->uio_resid -= nbytes;
453*3db3f65cSamw 	}
454*3db3f65cSamw 
455*3db3f65cSamw 	smb_opipe_exit(opipe);
456*3db3f65cSamw 	return (rc);
457*3db3f65cSamw }
458*3db3f65cSamw 
459*3db3f65cSamw /*
460*3db3f65cSamw  * Named pipe I/O is serialized per fid to ensure that each request
461*3db3f65cSamw  * has exclusive opipe access for the duration of the request.
462*3db3f65cSamw  */
463*3db3f65cSamw static void
464*3db3f65cSamw smb_opipe_enter(smb_opipe_t *opipe)
465*3db3f65cSamw {
466*3db3f65cSamw 	mutex_enter(&opipe->p_mutex);
467*3db3f65cSamw 
468*3db3f65cSamw 	while (opipe->p_busy)
469*3db3f65cSamw 		cv_wait(&opipe->p_cv, &opipe->p_mutex);
470*3db3f65cSamw 
471*3db3f65cSamw 	opipe->p_busy = 1;
472*3db3f65cSamw 	mutex_exit(&opipe->p_mutex);
473*3db3f65cSamw }
474*3db3f65cSamw 
475*3db3f65cSamw static void
476*3db3f65cSamw smb_opipe_exit(smb_opipe_t *opipe)
477*3db3f65cSamw {
478*3db3f65cSamw 	mutex_enter(&opipe->p_mutex);
479*3db3f65cSamw 	opipe->p_busy = 0;
480*3db3f65cSamw 	cv_signal(&opipe->p_cv);
481*3db3f65cSamw 	mutex_exit(&opipe->p_mutex);
482*3db3f65cSamw }
483*3db3f65cSamw 
484*3db3f65cSamw /*
485*3db3f65cSamw  * opipe door client (to user space door server).
486*3db3f65cSamw  */
487*3db3f65cSamw void
488*3db3f65cSamw smb_opipe_door_init(void)
489*3db3f65cSamw {
490*3db3f65cSamw 	mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
491*3db3f65cSamw 	cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
492*3db3f65cSamw }
493*3db3f65cSamw 
494*3db3f65cSamw void
495*3db3f65cSamw smb_opipe_door_fini(void)
496*3db3f65cSamw {
497*3db3f65cSamw 	smb_opipe_door_close();
498*3db3f65cSamw 	cv_destroy(&smb_opipe_door_cv);
499*3db3f65cSamw 	mutex_destroy(&smb_opipe_door_mutex);
500*3db3f65cSamw }
501*3db3f65cSamw 
502*3db3f65cSamw /*
503*3db3f65cSamw  * Open the (user space) door.  If the door is already open,
504*3db3f65cSamw  * close it first because the door-id has probably changed.
505*3db3f65cSamw  */
506*3db3f65cSamw int
507*3db3f65cSamw smb_opipe_door_open(int door_id)
508*3db3f65cSamw {
509*3db3f65cSamw 	smb_opipe_door_close();
510*3db3f65cSamw 
511*3db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
512*3db3f65cSamw 	smb_opipe_door_ncall = 0;
513*3db3f65cSamw 
514*3db3f65cSamw 	if (smb_opipe_door_hd == NULL) {
515*3db3f65cSamw 		smb_opipe_door_id = door_id;
516*3db3f65cSamw 		smb_opipe_door_hd = door_ki_lookup(door_id);
517*3db3f65cSamw 	}
518*3db3f65cSamw 
519*3db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
520*3db3f65cSamw 	return ((smb_opipe_door_hd == NULL)  ? -1 : 0);
521*3db3f65cSamw }
522*3db3f65cSamw 
523*3db3f65cSamw /*
524*3db3f65cSamw  * Close the (user space) door.
525*3db3f65cSamw  */
526*3db3f65cSamw void
527*3db3f65cSamw smb_opipe_door_close(void)
528*3db3f65cSamw {
529*3db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
530*3db3f65cSamw 
531*3db3f65cSamw 	if (smb_opipe_door_hd != NULL) {
532*3db3f65cSamw 		while (smb_opipe_door_ncall > 0)
533*3db3f65cSamw 			cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
534*3db3f65cSamw 
535*3db3f65cSamw 		door_ki_rele(smb_opipe_door_hd);
536*3db3f65cSamw 		smb_opipe_door_hd = NULL;
537*3db3f65cSamw 	}
538*3db3f65cSamw 
539*3db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
540*3db3f65cSamw }
541*3db3f65cSamw 
542*3db3f65cSamw /*
543*3db3f65cSamw  * opipe door call interface.
544*3db3f65cSamw  * Door serialization and call reference accounting is handled here.
545*3db3f65cSamw  */
546*3db3f65cSamw static int
547*3db3f65cSamw smb_opipe_door_call(smb_opipe_t *opipe)
548*3db3f65cSamw {
549*3db3f65cSamw 	int rc;
550*3db3f65cSamw 
551*3db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
552*3db3f65cSamw 
553*3db3f65cSamw 	if (smb_opipe_door_hd == NULL) {
554*3db3f65cSamw 		mutex_exit(&smb_opipe_door_mutex);
555*3db3f65cSamw 
556*3db3f65cSamw 		if (smb_opipe_door_open(smb_opipe_door_id) != 0)
557*3db3f65cSamw 			return (-1);
558*3db3f65cSamw 
559*3db3f65cSamw 		mutex_enter(&smb_opipe_door_mutex);
560*3db3f65cSamw 	}
561*3db3f65cSamw 
562*3db3f65cSamw 	++smb_opipe_door_ncall;
563*3db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
564*3db3f65cSamw 
565*3db3f65cSamw 	rc = smb_opipe_door_upcall(opipe);
566*3db3f65cSamw 
567*3db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
568*3db3f65cSamw 	--smb_opipe_door_ncall;
569*3db3f65cSamw 	cv_signal(&smb_opipe_door_cv);
570*3db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
571*3db3f65cSamw 	return (rc);
572*3db3f65cSamw }
573*3db3f65cSamw 
574*3db3f65cSamw /*
575*3db3f65cSamw  * Door upcall wrapper - handles data marshalling.
576*3db3f65cSamw  * This function should only be called by smb_opipe_door_call.
577*3db3f65cSamw  */
578*3db3f65cSamw static int
579*3db3f65cSamw smb_opipe_door_upcall(smb_opipe_t *opipe)
580*3db3f65cSamw {
581*3db3f65cSamw 	door_arg_t da;
582*3db3f65cSamw 	smb_opipe_hdr_t hdr;
583*3db3f65cSamw 	int i;
584*3db3f65cSamw 	int rc;
585*3db3f65cSamw 
586*3db3f65cSamw 	da.data_ptr = (char *)opipe->p_doorbuf;
587*3db3f65cSamw 	da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
588*3db3f65cSamw 	da.desc_ptr = NULL;
589*3db3f65cSamw 	da.desc_num = 0;
590*3db3f65cSamw 	da.rbuf = (char *)opipe->p_doorbuf;
591*3db3f65cSamw 	da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
592*3db3f65cSamw 
593*3db3f65cSamw 	for (i = 0; i < 3; ++i) {
594*3db3f65cSamw 		if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
595*3db3f65cSamw 		    NULL, SIZE_MAX, 0)) == 0)
596*3db3f65cSamw 			break;
597*3db3f65cSamw 
598*3db3f65cSamw 		if (rc != EAGAIN && rc != EINTR)
599*3db3f65cSamw 			return (-1);
600*3db3f65cSamw 	}
601*3db3f65cSamw 
602*3db3f65cSamw 	if (rc != 0)
603*3db3f65cSamw 		return (-1);
604*3db3f65cSamw 
605*3db3f65cSamw 	if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1)
606*3db3f65cSamw 		return (-1);
607*3db3f65cSamw 
608*3db3f65cSamw 	if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) ||
609*3db3f65cSamw 	    (hdr.oh_fid != opipe->p_hdr.oh_fid) ||
610*3db3f65cSamw 	    (hdr.oh_op != opipe->p_hdr.oh_op) ||
611*3db3f65cSamw 	    (hdr.oh_status != 0) ||
612*3db3f65cSamw 	    (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
613*3db3f65cSamw 		return (-1);
614*3db3f65cSamw 	}
615*3db3f65cSamw 
616*3db3f65cSamw 	opipe->p_hdr.oh_datalen = hdr.oh_datalen;
617*3db3f65cSamw 	opipe->p_hdr.oh_resid = hdr.oh_resid;
618*3db3f65cSamw 	return (0);
619*3db3f65cSamw }
620*3db3f65cSamw 
621*3db3f65cSamw void
622*3db3f65cSamw smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx)
623*3db3f65cSamw {
624*3db3f65cSamw 	smb_session_t *session;
625*3db3f65cSamw 
626*3db3f65cSamw 	ASSERT(user);
627*3db3f65cSamw 	ASSERT(user->u_domain);
628*3db3f65cSamw 	ASSERT(user->u_name);
629*3db3f65cSamw 
630*3db3f65cSamw 	session = user->u_session;
631*3db3f65cSamw 	ASSERT(session);
632*3db3f65cSamw 	ASSERT(session->workstation);
633*3db3f65cSamw 
634*3db3f65cSamw 	ctx->oc_session_id = session->s_kid;
635*3db3f65cSamw 	ctx->oc_native_os = session->native_os;
636*3db3f65cSamw 	ctx->oc_ipaddr = session->ipaddr;
637*3db3f65cSamw 	ctx->oc_uid = user->u_uid;
638*3db3f65cSamw 	ctx->oc_logon_time = user->u_logon_time;
639*3db3f65cSamw 	ctx->oc_flags = user->u_flags;
640*3db3f65cSamw 
641*3db3f65cSamw 	ctx->oc_domain_len = user->u_domain_len;
642*3db3f65cSamw 	ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len);
643*3db3f65cSamw 
644*3db3f65cSamw 	ctx->oc_account_len = user->u_name_len;
645*3db3f65cSamw 	ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len);
646*3db3f65cSamw 
647*3db3f65cSamw 	ctx->oc_workstation_len = strlen(session->workstation) + 1;
648*3db3f65cSamw 	ctx->oc_workstation = smb_kstrdup(session->workstation,
649*3db3f65cSamw 	    ctx->oc_workstation_len);
650*3db3f65cSamw }
651*3db3f65cSamw 
652*3db3f65cSamw static void
653*3db3f65cSamw smb_user_context_fini(smb_opipe_context_t *ctx)
654*3db3f65cSamw {
655*3db3f65cSamw 	if (ctx) {
656*3db3f65cSamw 		if (ctx->oc_domain)
657*3db3f65cSamw 			kmem_free(ctx->oc_domain, ctx->oc_domain_len);
658*3db3f65cSamw 		if (ctx->oc_account)
659*3db3f65cSamw 			kmem_free(ctx->oc_account, ctx->oc_account_len);
660*3db3f65cSamw 		if (ctx->oc_workstation)
661*3db3f65cSamw 			kmem_free(ctx->oc_workstation, ctx->oc_workstation_len);
662*3db3f65cSamw 		bzero(ctx, sizeof (smb_opipe_context_t));
663*3db3f65cSamw 	}
664*3db3f65cSamw }
665*3db3f65cSamw 
666*3db3f65cSamw void
667*3db3f65cSamw smb_user_list_free(smb_dr_ulist_t *userlist)
668*3db3f65cSamw {
669*3db3f65cSamw 	int i;
670*3db3f65cSamw 
671*3db3f65cSamw 	if (userlist) {
672*3db3f65cSamw 		for (i = 0; i < userlist->dul_cnt; i++)
673*3db3f65cSamw 			smb_user_context_fini(&userlist->dul_users[i]);
674*3db3f65cSamw 	}
675*3db3f65cSamw }
676