xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c (revision 430b4c467020edf2445feb0c21db01c88b86243a)
14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
359c9af259SGordon Ross /*
36*430b4c46SGordon Ross  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
37613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
389c9af259SGordon Ross  * Use is subject to license terms.
399c9af259SGordon Ross  */
404bff34e3Sthurlow 
414bff34e3Sthurlow #include <sys/param.h>
424bff34e3Sthurlow #include <sys/kmem.h>
434bff34e3Sthurlow #include <sys/systm.h>
444bff34e3Sthurlow #include <sys/policy.h>
454bff34e3Sthurlow #include <sys/conf.h>
464bff34e3Sthurlow #include <sys/proc.h>
474bff34e3Sthurlow #include <sys/fcntl.h>
48613a2f6bSGordon Ross #include <sys/file.h>
494bff34e3Sthurlow #include <sys/socket.h>
50613a2f6bSGordon Ross #include <sys/sunddi.h>
514bff34e3Sthurlow #include <sys/cmn_err.h>
524bff34e3Sthurlow 
534bff34e3Sthurlow #include <netsmb/smb_osdep.h>
544bff34e3Sthurlow 
554bff34e3Sthurlow #include <netsmb/smb.h>
564bff34e3Sthurlow #include <netsmb/smb_conn.h>
574bff34e3Sthurlow #include <netsmb/smb_rq.h>
584bff34e3Sthurlow #include <netsmb/smb_subr.h>
594bff34e3Sthurlow #include <netsmb/smb_dev.h>
604bff34e3Sthurlow 
61613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
62613a2f6bSGordon Ross 
634bff34e3Sthurlow /*
64613a2f6bSGordon Ross  * Ioctl function for SMBIOC_FLAGS2
654bff34e3Sthurlow  */
66613a2f6bSGordon Ross int
67613a2f6bSGordon Ross smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
68613a2f6bSGordon Ross {
69613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
70613a2f6bSGordon Ross 
71613a2f6bSGordon Ross 	/* This ioctl requires a session. */
72613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
73613a2f6bSGordon Ross 		return (ENOTCONN);
74613a2f6bSGordon Ross 
75613a2f6bSGordon Ross 	/*
76613a2f6bSGordon Ross 	 * Return the flags2 value.
77613a2f6bSGordon Ross 	 */
78613a2f6bSGordon Ross 	if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
79613a2f6bSGordon Ross 	    sizeof (u_int16_t), flags))
80613a2f6bSGordon Ross 		return (EFAULT);
81613a2f6bSGordon Ross 
82613a2f6bSGordon Ross 	return (0);
83613a2f6bSGordon Ross }
844bff34e3Sthurlow 
854bff34e3Sthurlow /*
86613a2f6bSGordon Ross  * Ioctl function for SMBIOC_GETSSNKEY
87613a2f6bSGordon Ross  * Size copied out is SMBIOC_HASH_SZ.
88613a2f6bSGordon Ross  *
89613a2f6bSGordon Ross  * The RPC library needs this for encrypting things
90613a2f6bSGordon Ross  * like "set password" requests.  This is called
91613a2f6bSGordon Ross  * with an active RPC binding, so the connection
92613a2f6bSGordon Ross  * will already be active (but this checks).
934bff34e3Sthurlow  */
94613a2f6bSGordon Ross int
95613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
964bff34e3Sthurlow {
97613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
98613a2f6bSGordon Ross 
99613a2f6bSGordon Ross 	/* This ioctl requires an active session. */
100613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
101613a2f6bSGordon Ross 		return (ENOTCONN);
102613a2f6bSGordon Ross 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
103613a2f6bSGordon Ross 		return (ENOTCONN);
1044bff34e3Sthurlow 
1054bff34e3Sthurlow 	/*
106613a2f6bSGordon Ross 	 * Return the session key.
1074bff34e3Sthurlow 	 */
108613a2f6bSGordon Ross 	if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
109613a2f6bSGordon Ross 	    SMBIOC_HASH_SZ, flags))
110613a2f6bSGordon Ross 		return (EFAULT);
111613a2f6bSGordon Ross 
112613a2f6bSGordon Ross 	return (0);
113613a2f6bSGordon Ross }
114613a2f6bSGordon Ross 
115613a2f6bSGordon Ross /*
116613a2f6bSGordon Ross  * Ioctl function for SMBIOC_REQUEST
117613a2f6bSGordon Ross  */
118613a2f6bSGordon Ross int
119613a2f6bSGordon Ross smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
120613a2f6bSGordon Ross {
121613a2f6bSGordon Ross 	struct smb_cred scred;
122613a2f6bSGordon Ross 	struct smb_share *ssp;
123613a2f6bSGordon Ross 	smbioc_rq_t *ioc = NULL;
124613a2f6bSGordon Ross 	struct smb_rq *rqp = NULL;
125613a2f6bSGordon Ross 	struct mbchain *mbp;
126613a2f6bSGordon Ross 	struct mdchain *mdp;
127613a2f6bSGordon Ross 	uint32_t rsz;
128613a2f6bSGordon Ross 	int err, mbseg;
129613a2f6bSGordon Ross 
130613a2f6bSGordon Ross 	/* This ioctl requires a share. */
131613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
132613a2f6bSGordon Ross 		return (ENOTCONN);
133613a2f6bSGordon Ross 
134613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
135613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
136613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
137613a2f6bSGordon Ross 		err = EFAULT;
138613a2f6bSGordon Ross 		goto out;
1394bff34e3Sthurlow 	}
1404bff34e3Sthurlow 
141613a2f6bSGordon Ross 	/* See ddi_copyin, ddi_copyout */
142613a2f6bSGordon Ross 	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
1434bff34e3Sthurlow 
1444bff34e3Sthurlow 	/*
145613a2f6bSGordon Ross 	 * Lots of SMB commands could be safe, but
146613a2f6bSGordon Ross 	 * these are the only ones used by libsmbfs.
1474bff34e3Sthurlow 	 */
148613a2f6bSGordon Ross 	switch (ioc->ioc_cmd) {
149613a2f6bSGordon Ross 		/* These are OK */
150613a2f6bSGordon Ross 	case SMB_COM_CLOSE:
151613a2f6bSGordon Ross 	case SMB_COM_FLUSH:
152613a2f6bSGordon Ross 	case SMB_COM_NT_CREATE_ANDX:
153613a2f6bSGordon Ross 	case SMB_COM_OPEN_PRINT_FILE:
154613a2f6bSGordon Ross 	case SMB_COM_CLOSE_PRINT_FILE:
155613a2f6bSGordon Ross 		break;
156613a2f6bSGordon Ross 
157613a2f6bSGordon Ross 	default:
158613a2f6bSGordon Ross 		err = EPERM;
159613a2f6bSGordon Ross 		goto out;
1604bff34e3Sthurlow 	}
1614bff34e3Sthurlow 
162613a2f6bSGordon Ross 	err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
163613a2f6bSGordon Ross 	if (err)
164613a2f6bSGordon Ross 		goto out;
165613a2f6bSGordon Ross 
166613a2f6bSGordon Ross 	mbp = &rqp->sr_rq;
167613a2f6bSGordon Ross 	err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
168613a2f6bSGordon Ross 
169613a2f6bSGordon Ross 	err = smb_rq_simple(rqp);
170613a2f6bSGordon Ross 	if (err == 0) {
171613a2f6bSGordon Ross 		/*
172613a2f6bSGordon Ross 		 * This may have been an open, so save the
173613a2f6bSGordon Ross 		 * generation ID of the share, which we
174613a2f6bSGordon Ross 		 * check before trying read or write.
175613a2f6bSGordon Ross 		 */
176613a2f6bSGordon Ross 		sdp->sd_vcgenid = ssp->ss_vcgenid;
177613a2f6bSGordon Ross 
178613a2f6bSGordon Ross 		/*
179613a2f6bSGordon Ross 		 * Have reply data. to copyout.
180613a2f6bSGordon Ross 		 * SMB header already parsed.
181613a2f6bSGordon Ross 		 */
182613a2f6bSGordon Ross 		mdp = &rqp->sr_rp;
183613a2f6bSGordon Ross 		rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
184613a2f6bSGordon Ross 		if (ioc->ioc_rbufsz < rsz) {
185613a2f6bSGordon Ross 			err = EOVERFLOW;
186613a2f6bSGordon Ross 			goto out;
187613a2f6bSGordon Ross 		}
188613a2f6bSGordon Ross 		ioc->ioc_rbufsz = rsz;
189613a2f6bSGordon Ross 		err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
190613a2f6bSGordon Ross 		if (err)
191613a2f6bSGordon Ross 			goto out;
192613a2f6bSGordon Ross 
1934bff34e3Sthurlow 	}
1944bff34e3Sthurlow 
195613a2f6bSGordon Ross 	ioc->ioc_errclass = rqp->sr_errclass;
196613a2f6bSGordon Ross 	ioc->ioc_serror = rqp->sr_serror;
197613a2f6bSGordon Ross 	ioc->ioc_error = rqp->sr_error;
19802d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
1994bff34e3Sthurlow 
200613a2f6bSGordon Ross out:
201613a2f6bSGordon Ross 	if (rqp != NULL)
202613a2f6bSGordon Ross 		smb_rq_done(rqp); /* free rqp */
203*430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
204613a2f6bSGordon Ross 	smb_credrele(&scred);
205613a2f6bSGordon Ross 
206613a2f6bSGordon Ross 	return (err);
2074bff34e3Sthurlow 
2084bff34e3Sthurlow }
2094bff34e3Sthurlow 
210613a2f6bSGordon Ross /*
211613a2f6bSGordon Ross  * Ioctl function for SMBIOC_T2RQ
212613a2f6bSGordon Ross  */
213613a2f6bSGordon Ross int
214613a2f6bSGordon Ross smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
2154bff34e3Sthurlow {
216613a2f6bSGordon Ross 	struct smb_cred scred;
217613a2f6bSGordon Ross 	struct smb_share *ssp;
218613a2f6bSGordon Ross 	smbioc_t2rq_t *ioc = NULL;
219613a2f6bSGordon Ross 	struct smb_t2rq *t2p = NULL;
220613a2f6bSGordon Ross 	struct mdchain *mdp;
221613a2f6bSGordon Ross 	int err, len, mbseg;
222613a2f6bSGordon Ross 
223613a2f6bSGordon Ross 	/* This ioctl requires a share. */
224613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
225613a2f6bSGordon Ross 		return (ENOTCONN);
2264bff34e3Sthurlow 
227613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
228613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
229613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
230613a2f6bSGordon Ross 		err = EFAULT;
231613a2f6bSGordon Ross 		goto out;
2324bff34e3Sthurlow 	}
233613a2f6bSGordon Ross 
234613a2f6bSGordon Ross 	/* See ddi_copyin, ddi_copyout */
235613a2f6bSGordon Ross 	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
236613a2f6bSGordon Ross 
237613a2f6bSGordon Ross 	if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
238613a2f6bSGordon Ross 		err = EINVAL;
239613a2f6bSGordon Ross 		goto out;
240613a2f6bSGordon Ross 	}
241613a2f6bSGordon Ross 
242*430b4c46SGordon Ross 	/*
243*430b4c46SGordon Ross 	 * Fill in the FID for libsmbfs transact named pipe.
244*430b4c46SGordon Ross 	 */
245*430b4c46SGordon Ross 	if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
246*430b4c46SGordon Ross 		if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
247*430b4c46SGordon Ross 			err = ESTALE;
248*430b4c46SGordon Ross 			goto out;
249*430b4c46SGordon Ross 		}
250*430b4c46SGordon Ross 		ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
251*430b4c46SGordon Ross 	}
252*430b4c46SGordon Ross 
253613a2f6bSGordon Ross 	t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
254613a2f6bSGordon Ross 	err = smb_t2_init(t2p, SSTOCP(ssp),
255613a2f6bSGordon Ross 	    ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
256613a2f6bSGordon Ross 	if (err)
257613a2f6bSGordon Ross 		goto out;
258*430b4c46SGordon Ross 	t2p->t2_setupcount = ioc->ioc_setupcnt;
259*430b4c46SGordon Ross 	t2p->t2_setupdata  = ioc->ioc_setup;
260613a2f6bSGordon Ross 
261613a2f6bSGordon Ross 	/* This ioc member is a fixed-size array. */
262613a2f6bSGordon Ross 	if (ioc->ioc_name[0]) {
263613a2f6bSGordon Ross 		/* Get the name length - carefully! */
264613a2f6bSGordon Ross 		ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
265613a2f6bSGordon Ross 		t2p->t_name_len = strlen(ioc->ioc_name);
266613a2f6bSGordon Ross 		t2p->t_name = ioc->ioc_name;
267613a2f6bSGordon Ross 	}
268613a2f6bSGordon Ross 	t2p->t2_maxscount = 0;
269613a2f6bSGordon Ross 	t2p->t2_maxpcount = ioc->ioc_rparamcnt;
270613a2f6bSGordon Ross 	t2p->t2_maxdcount = ioc->ioc_rdatacnt;
271613a2f6bSGordon Ross 
272613a2f6bSGordon Ross 	/* Transmit parameters */
273613a2f6bSGordon Ross 	err = smb_cpdatain(&t2p->t2_tparam,
274613a2f6bSGordon Ross 	    ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
275613a2f6bSGordon Ross 	if (err)
276613a2f6bSGordon Ross 		goto out;
277613a2f6bSGordon Ross 
278613a2f6bSGordon Ross 	/* Transmit data */
279613a2f6bSGordon Ross 	err = smb_cpdatain(&t2p->t2_tdata,
280613a2f6bSGordon Ross 	    ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
281613a2f6bSGordon Ross 	if (err)
282613a2f6bSGordon Ross 		goto out;
283613a2f6bSGordon Ross 
284613a2f6bSGordon Ross 	err = smb_t2_request(t2p);
285613a2f6bSGordon Ross 
286613a2f6bSGordon Ross 	/* Copyout returned parameters. */
287613a2f6bSGordon Ross 	mdp = &t2p->t2_rparam;
288613a2f6bSGordon Ross 	if (err == 0 && mdp->md_top != NULL) {
289613a2f6bSGordon Ross 		/* User's buffer large enough? */
290613a2f6bSGordon Ross 		len = m_fixhdr(mdp->md_top);
291613a2f6bSGordon Ross 		if (len > ioc->ioc_rparamcnt) {
292613a2f6bSGordon Ross 			err = EMSGSIZE;
293613a2f6bSGordon Ross 			goto out;
294613a2f6bSGordon Ross 		}
295613a2f6bSGordon Ross 		ioc->ioc_rparamcnt = (ushort_t)len;
296613a2f6bSGordon Ross 		err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
297613a2f6bSGordon Ross 		if (err)
298613a2f6bSGordon Ross 			goto out;
299613a2f6bSGordon Ross 	} else
300613a2f6bSGordon Ross 		ioc->ioc_rparamcnt = 0;
301613a2f6bSGordon Ross 
302613a2f6bSGordon Ross 	/* Copyout returned data. */
303613a2f6bSGordon Ross 	mdp = &t2p->t2_rdata;
304613a2f6bSGordon Ross 	if (err == 0 && mdp->md_top != NULL) {
305613a2f6bSGordon Ross 		/* User's buffer large enough? */
306613a2f6bSGordon Ross 		len = m_fixhdr(mdp->md_top);
307613a2f6bSGordon Ross 		if (len > ioc->ioc_rdatacnt) {
308613a2f6bSGordon Ross 			err = EMSGSIZE;
309613a2f6bSGordon Ross 			goto out;
310613a2f6bSGordon Ross 		}
311613a2f6bSGordon Ross 		ioc->ioc_rdatacnt = (ushort_t)len;
312613a2f6bSGordon Ross 		err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
313613a2f6bSGordon Ross 		if (err)
314613a2f6bSGordon Ross 			goto out;
315613a2f6bSGordon Ross 	} else
316613a2f6bSGordon Ross 		ioc->ioc_rdatacnt = 0;
317613a2f6bSGordon Ross 
318613a2f6bSGordon Ross 	ioc->ioc_errclass = t2p->t2_sr_errclass;
319613a2f6bSGordon Ross 	ioc->ioc_serror = t2p->t2_sr_serror;
320613a2f6bSGordon Ross 	ioc->ioc_error = t2p->t2_sr_error;
321613a2f6bSGordon Ross 	ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
322613a2f6bSGordon Ross 
32302d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
324613a2f6bSGordon Ross 
325613a2f6bSGordon Ross 
326613a2f6bSGordon Ross out:
327613a2f6bSGordon Ross 	if (t2p != NULL) {
328613a2f6bSGordon Ross 		/* Note: t2p->t_name no longer allocated */
329613a2f6bSGordon Ross 		smb_t2_done(t2p);
330613a2f6bSGordon Ross 		kmem_free(t2p, sizeof (*t2p));
331613a2f6bSGordon Ross 	}
332*430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
333613a2f6bSGordon Ross 	smb_credrele(&scred);
334613a2f6bSGordon Ross 
335613a2f6bSGordon Ross 	return (err);
3364bff34e3Sthurlow }
3374bff34e3Sthurlow 
338613a2f6bSGordon Ross /* helper for _t2request */
3394bff34e3Sthurlow static int
340613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
3414bff34e3Sthurlow {
342613a2f6bSGordon Ross 	int error;
343613a2f6bSGordon Ross 
344613a2f6bSGordon Ross 	if (len == 0)
345613a2f6bSGordon Ross 		return (0);
346613a2f6bSGordon Ross 	error = mb_init(mbp);
347613a2f6bSGordon Ross 	if (error)
348613a2f6bSGordon Ross 		return (error);
349613a2f6bSGordon Ross 	return (mb_put_mem(mbp, data, len, mbseg));
3504bff34e3Sthurlow }
3514bff34e3Sthurlow 
352613a2f6bSGordon Ross /*
353613a2f6bSGordon Ross  * Helper for nsmb_ioctl cases
354613a2f6bSGordon Ross  * SMBIOC_READ, SMBIOC_WRITE
355613a2f6bSGordon Ross  */
3561b34bc4aSbs int
357613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
3581b34bc4aSbs {
359613a2f6bSGordon Ross 	struct smb_cred scred;
360613a2f6bSGordon Ross 	struct smb_share *ssp;
361613a2f6bSGordon Ross 	smbioc_rw_t *ioc = NULL;
362613a2f6bSGordon Ross 	struct iovec aiov[1];
363613a2f6bSGordon Ross 	struct uio  auio;
364*430b4c46SGordon Ross 	uint16_t fh;
365613a2f6bSGordon Ross 	int err;
366613a2f6bSGordon Ross 	uio_rw_t rw;
3671b34bc4aSbs 
368613a2f6bSGordon Ross 	/* This ioctl requires a share. */
369613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
370613a2f6bSGordon Ross 		return (ENOTCONN);
371613a2f6bSGordon Ross 
372613a2f6bSGordon Ross 	/* After reconnect, force close+reopen */
373613a2f6bSGordon Ross 	if (sdp->sd_vcgenid != ssp->ss_vcgenid)
374613a2f6bSGordon Ross 		return (ESTALE);
375613a2f6bSGordon Ross 
376613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
377613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
378613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
379613a2f6bSGordon Ross 		err = EFAULT;
3801b34bc4aSbs 		goto out;
381613a2f6bSGordon Ross 	}
382613a2f6bSGordon Ross 
383613a2f6bSGordon Ross 	switch (cmd) {
384613a2f6bSGordon Ross 	case SMBIOC_READ:
385613a2f6bSGordon Ross 		rw = UIO_READ;
386613a2f6bSGordon Ross 		break;
387613a2f6bSGordon Ross 	case SMBIOC_WRITE:
388613a2f6bSGordon Ross 		rw = UIO_WRITE;
389613a2f6bSGordon Ross 		break;
390613a2f6bSGordon Ross 	default:
391613a2f6bSGordon Ross 		err = ENODEV;
392613a2f6bSGordon Ross 		goto out;
393613a2f6bSGordon Ross 	}
394613a2f6bSGordon Ross 
395*430b4c46SGordon Ross 	/*
396*430b4c46SGordon Ross 	 * If caller passes -1 in ioc_fh, then
397*430b4c46SGordon Ross 	 * use the FID from SMBIOC_NTCREATE.
398*430b4c46SGordon Ross 	 */
399*430b4c46SGordon Ross 	if (ioc->ioc_fh == -1)
400*430b4c46SGordon Ross 		fh = (uint16_t)sdp->sd_smbfid;
401*430b4c46SGordon Ross 	else
402*430b4c46SGordon Ross 		fh = (uint16_t)ioc->ioc_fh;
403613a2f6bSGordon Ross 
404613a2f6bSGordon Ross 	aiov[0].iov_base = ioc->ioc_base;
405613a2f6bSGordon Ross 	aiov[0].iov_len = (size_t)ioc->ioc_cnt;
406613a2f6bSGordon Ross 
407613a2f6bSGordon Ross 	auio.uio_iov = aiov;
408613a2f6bSGordon Ross 	auio.uio_iovcnt = 1;
409613a2f6bSGordon Ross 	auio.uio_loffset = ioc->ioc_offset;
410613a2f6bSGordon Ross 	auio.uio_segflg = (flags & FKIOCTL) ?
411613a2f6bSGordon Ross 	    UIO_SYSSPACE : UIO_USERSPACE;
412613a2f6bSGordon Ross 	auio.uio_fmode = 0;
413613a2f6bSGordon Ross 	auio.uio_resid = (size_t)ioc->ioc_cnt;
414613a2f6bSGordon Ross 
415613a2f6bSGordon Ross 	err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
416613a2f6bSGordon Ross 
417613a2f6bSGordon Ross 	/*
418613a2f6bSGordon Ross 	 * On return ioc_cnt holds the
419613a2f6bSGordon Ross 	 * number of bytes transferred.
420613a2f6bSGordon Ross 	 */
421613a2f6bSGordon Ross 	ioc->ioc_cnt -= auio.uio_resid;
422613a2f6bSGordon Ross 
42302d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
424613a2f6bSGordon Ross 
4251b34bc4aSbs out:
426*430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
427*430b4c46SGordon Ross 	smb_credrele(&scred);
428*430b4c46SGordon Ross 
429*430b4c46SGordon Ross 	return (err);
430*430b4c46SGordon Ross }
431*430b4c46SGordon Ross 
432*430b4c46SGordon Ross /*
433*430b4c46SGordon Ross  * Helper for nsmb_ioctl case
434*430b4c46SGordon Ross  * SMBIOC_NTCREATE
435*430b4c46SGordon Ross  */
436*430b4c46SGordon Ross int
437*430b4c46SGordon Ross smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
438*430b4c46SGordon Ross {
439*430b4c46SGordon Ross 	struct smb_cred scred;
440*430b4c46SGordon Ross 	struct mbchain name_mb;
441*430b4c46SGordon Ross 	struct smb_share *ssp;
442*430b4c46SGordon Ross 	smbioc_ntcreate_t *ioc = NULL;
443*430b4c46SGordon Ross 	uint16_t fid;
444*430b4c46SGordon Ross 	int err, nmlen;
445*430b4c46SGordon Ross 
446*430b4c46SGordon Ross 	/* This ioctl requires a share. */
447*430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
448*430b4c46SGordon Ross 		return (ENOTCONN);
449*430b4c46SGordon Ross 
450*430b4c46SGordon Ross 	/* Must not be already open. */
451*430b4c46SGordon Ross 	if (sdp->sd_smbfid != -1)
452*430b4c46SGordon Ross 		return (EINVAL);
453*430b4c46SGordon Ross 
454*430b4c46SGordon Ross 	mb_init(&name_mb);
455*430b4c46SGordon Ross 	smb_credinit(&scred, cr);
456*430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
457*430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
458*430b4c46SGordon Ross 		err = EFAULT;
459*430b4c46SGordon Ross 		goto out;
460*430b4c46SGordon Ross 	}
461*430b4c46SGordon Ross 
462*430b4c46SGordon Ross 	/* Build name_mb */
463*430b4c46SGordon Ross 	ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
464*430b4c46SGordon Ross 	nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
465*430b4c46SGordon Ross 	err = smb_put_dmem(&name_mb, SSTOVC(ssp),
466*430b4c46SGordon Ross 	    ioc->ioc_name, nmlen,
467*430b4c46SGordon Ross 	    SMB_CS_NONE, NULL);
468*430b4c46SGordon Ross 	if (err != 0)
469*430b4c46SGordon Ross 		goto out;
470*430b4c46SGordon Ross 
471*430b4c46SGordon Ross 	/* Do the OtW open, save the FID. */
472*430b4c46SGordon Ross 	err = smb_smb_ntcreate(ssp, &name_mb,
473*430b4c46SGordon Ross 	    0,	/* create flags */
474*430b4c46SGordon Ross 	    ioc->ioc_req_acc,
475*430b4c46SGordon Ross 	    ioc->ioc_efattr,
476*430b4c46SGordon Ross 	    ioc->ioc_share_acc,
477*430b4c46SGordon Ross 	    ioc->ioc_open_disp,
478*430b4c46SGordon Ross 	    ioc->ioc_creat_opts,
479*430b4c46SGordon Ross 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
480*430b4c46SGordon Ross 	    &scred,
481*430b4c46SGordon Ross 	    &fid,
482*430b4c46SGordon Ross 	    NULL,
483*430b4c46SGordon Ross 	    NULL);
484*430b4c46SGordon Ross 	if (err != 0)
485*430b4c46SGordon Ross 		goto out;
486*430b4c46SGordon Ross 
487*430b4c46SGordon Ross 	sdp->sd_smbfid = fid;
488*430b4c46SGordon Ross 	sdp->sd_vcgenid = ssp->ss_vcgenid;
489*430b4c46SGordon Ross 
490*430b4c46SGordon Ross out:
491*430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
492*430b4c46SGordon Ross 	smb_credrele(&scred);
493*430b4c46SGordon Ross 	mb_done(&name_mb);
494*430b4c46SGordon Ross 
495*430b4c46SGordon Ross 	return (err);
496*430b4c46SGordon Ross }
497*430b4c46SGordon Ross 
498*430b4c46SGordon Ross /*
499*430b4c46SGordon Ross  * Helper for nsmb_ioctl case
500*430b4c46SGordon Ross  * SMBIOC_PRINTJOB
501*430b4c46SGordon Ross  */
502*430b4c46SGordon Ross int
503*430b4c46SGordon Ross smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
504*430b4c46SGordon Ross {
505*430b4c46SGordon Ross 	struct smb_cred scred;
506*430b4c46SGordon Ross 	struct smb_share *ssp;
507*430b4c46SGordon Ross 	smbioc_printjob_t *ioc = NULL;
508*430b4c46SGordon Ross 	uint16_t fid;
509*430b4c46SGordon Ross 	int err;
510*430b4c46SGordon Ross 
511*430b4c46SGordon Ross 	/* This ioctl requires a share. */
512*430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
513*430b4c46SGordon Ross 		return (ENOTCONN);
514*430b4c46SGordon Ross 
515*430b4c46SGordon Ross 	/* The share must be a print queue. */
516*430b4c46SGordon Ross 	if (ssp->ss_type != STYPE_PRINTQ)
517*430b4c46SGordon Ross 		return (EINVAL);
518*430b4c46SGordon Ross 
519*430b4c46SGordon Ross 	/* Must not be already open. */
520*430b4c46SGordon Ross 	if (sdp->sd_smbfid != -1)
521*430b4c46SGordon Ross 		return (EINVAL);
522*430b4c46SGordon Ross 
523*430b4c46SGordon Ross 	smb_credinit(&scred, cr);
524*430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
525*430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
526*430b4c46SGordon Ross 		err = EFAULT;
527*430b4c46SGordon Ross 		goto out;
528*430b4c46SGordon Ross 	}
529*430b4c46SGordon Ross 	ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
530*430b4c46SGordon Ross 
531*430b4c46SGordon Ross 	/* Do the OtW open, save the FID. */
532*430b4c46SGordon Ross 	err = smb_smb_open_prjob(ssp, ioc->ioc_title,
533*430b4c46SGordon Ross 	    ioc->ioc_setuplen, ioc->ioc_prmode,
534*430b4c46SGordon Ross 	    &scred, &fid);
535*430b4c46SGordon Ross 	if (err != 0)
536*430b4c46SGordon Ross 		goto out;
537*430b4c46SGordon Ross 
538*430b4c46SGordon Ross 	sdp->sd_smbfid = fid;
539*430b4c46SGordon Ross 	sdp->sd_vcgenid = ssp->ss_vcgenid;
540*430b4c46SGordon Ross 
541*430b4c46SGordon Ross out:
542*430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
543*430b4c46SGordon Ross 	smb_credrele(&scred);
544*430b4c46SGordon Ross 
545*430b4c46SGordon Ross 	return (err);
546*430b4c46SGordon Ross }
547*430b4c46SGordon Ross 
548*430b4c46SGordon Ross /*
549*430b4c46SGordon Ross  * Helper for nsmb_ioctl case
550*430b4c46SGordon Ross  * SMBIOC_CLOSEFH
551*430b4c46SGordon Ross  */
552*430b4c46SGordon Ross int
553*430b4c46SGordon Ross smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
554*430b4c46SGordon Ross {
555*430b4c46SGordon Ross 	struct smb_cred scred;
556*430b4c46SGordon Ross 	struct smb_share *ssp;
557*430b4c46SGordon Ross 	uint16_t fid;
558*430b4c46SGordon Ross 	int err;
559*430b4c46SGordon Ross 
560*430b4c46SGordon Ross 	/* This ioctl requires a share. */
561*430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
562*430b4c46SGordon Ross 		return (ENOTCONN);
563*430b4c46SGordon Ross 
564*430b4c46SGordon Ross 	if (sdp->sd_smbfid == -1)
565*430b4c46SGordon Ross 		return (0);
566*430b4c46SGordon Ross 	fid = (uint16_t)sdp->sd_smbfid;
567*430b4c46SGordon Ross 	sdp->sd_smbfid = -1;
568*430b4c46SGordon Ross 
569*430b4c46SGordon Ross 	smb_credinit(&scred, cr);
570*430b4c46SGordon Ross 	if (ssp->ss_type == STYPE_PRINTQ)
571*430b4c46SGordon Ross 		err = smb_smb_close_prjob(ssp, fid, &scred);
572*430b4c46SGordon Ross 	else
573*430b4c46SGordon Ross 		err = smb_smb_close(ssp, fid, NULL, &scred);
574613a2f6bSGordon Ross 	smb_credrele(&scred);
575613a2f6bSGordon Ross 
576613a2f6bSGordon Ross 	return (err);
5771b34bc4aSbs }
5781b34bc4aSbs 
579613a2f6bSGordon Ross /*
580613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
581613a2f6bSGordon Ross  * Find or create a session (a.k.a. "VC" in here)
582613a2f6bSGordon Ross  */
5834bff34e3Sthurlow int
584613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
5854bff34e3Sthurlow {
586613a2f6bSGordon Ross 	struct smb_cred scred;
587613a2f6bSGordon Ross 	smbioc_ossn_t *ossn = NULL;
5884bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
5894bff34e3Sthurlow 	int error = 0;
590613a2f6bSGordon Ross 	uid_t realuid;
5914bff34e3Sthurlow 
592613a2f6bSGordon Ross 	/* Should be no VC */
593613a2f6bSGordon Ross 	if (sdp->sd_vc != NULL)
594613a2f6bSGordon Ross 		return (EISCONN);
595613a2f6bSGordon Ross 
596613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
597613a2f6bSGordon Ross 	ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
598613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
599613a2f6bSGordon Ross 		error = EFAULT;
600613a2f6bSGordon Ross 		goto out;
6014bff34e3Sthurlow 	}
602613a2f6bSGordon Ross 
603613a2f6bSGordon Ross 	/*
604613a2f6bSGordon Ross 	 * Only superuser can specify a UID or GID.
605613a2f6bSGordon Ross 	 */
606613a2f6bSGordon Ross 	realuid = crgetruid(cr);
607613a2f6bSGordon Ross 	if (ossn->ssn_owner == SMBM_ANY_OWNER)
608613a2f6bSGordon Ross 		ossn->ssn_owner = realuid;
609613a2f6bSGordon Ross 	else {
6104bff34e3Sthurlow 		/*
611613a2f6bSGordon Ross 		 * Do we have the privilege to create with the
612613a2f6bSGordon Ross 		 * specified uid?  (does uid == cr->cr_uid, etc.)
6134bff34e3Sthurlow 		 */
614613a2f6bSGordon Ross 		if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
615613a2f6bSGordon Ross 			error = EPERM;
616613a2f6bSGordon Ross 			goto out;
6174bff34e3Sthurlow 		}
618613a2f6bSGordon Ross 		/* ossn->ssn_owner is OK */
6194bff34e3Sthurlow 	}
6204bff34e3Sthurlow 
621613a2f6bSGordon Ross 	/*
622613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
623613a2f6bSGordon Ross 	 */
624613a2f6bSGordon Ross 	ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
625613a2f6bSGordon Ross 	ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
626613a2f6bSGordon Ross 	ossn->ssn_id.id_user[   SMBIOC_MAX_NAME-1] = '\0';
6274bff34e3Sthurlow 
628613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE)
629613a2f6bSGordon Ross 		ossn->ssn_vopt |= SMBVOPT_CREATE;
630613a2f6bSGordon Ross 	else /* FIND */
631613a2f6bSGordon Ross 		ossn->ssn_vopt &= ~SMBVOPT_CREATE;
6324bff34e3Sthurlow 
633613a2f6bSGordon Ross 	error = smb_vc_findcreate(ossn, &scred, &vcp);
6344bff34e3Sthurlow 	if (error)
6354bff34e3Sthurlow 		goto out;
636613a2f6bSGordon Ross 	ASSERT(vcp != NULL);
6374bff34e3Sthurlow 
6384bff34e3Sthurlow 	/*
639613a2f6bSGordon Ross 	 * We have a VC, held, but not locked.
640613a2f6bSGordon Ross 	 * If we're creating, mark this instance as
641613a2f6bSGordon Ross 	 * an open from IOD so close can do cleanup.
642613a2f6bSGordon Ross 	 *
643613a2f6bSGordon Ross 	 * XXX: Would be nice to have a back pointer
644613a2f6bSGordon Ross 	 * from the VC to this (IOD) sdp instance.
6454bff34e3Sthurlow 	 */
646613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE) {
647613a2f6bSGordon Ross 		if (vcp->iod_thr != NULL) {
648613a2f6bSGordon Ross 			error = EEXIST;
649613a2f6bSGordon Ross 			goto out;
650613a2f6bSGordon Ross 		}
651613a2f6bSGordon Ross 		sdp->sd_flags |= NSMBFL_IOD;
652613a2f6bSGordon Ross 	} else {
653613a2f6bSGordon Ross 		/*
654613a2f6bSGordon Ross 		 * Wait for it to finish connecting
655613a2f6bSGordon Ross 		 * (or reconnect) if necessary.
656613a2f6bSGordon Ross 		 */
657613a2f6bSGordon Ross 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
658613a2f6bSGordon Ross 			error = smb_iod_reconnect(vcp);
659613a2f6bSGordon Ross 			if (error != 0)
660613a2f6bSGordon Ross 				goto out;
661613a2f6bSGordon Ross 		}
662613a2f6bSGordon Ross 	}
663613a2f6bSGordon Ross 
664613a2f6bSGordon Ross 	/*
665613a2f6bSGordon Ross 	 * The VC has a hold from _findvc
666613a2f6bSGordon Ross 	 * which we keep until _SSN_RELE
667613a2f6bSGordon Ross 	 * or nsmb_close().
668613a2f6bSGordon Ross 	 */
669613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
670613a2f6bSGordon Ross 	sdp->sd_vc = vcp;
671613a2f6bSGordon Ross 	vcp = NULL;
672613a2f6bSGordon Ross 	(void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
6734bff34e3Sthurlow 
6744bff34e3Sthurlow out:
675613a2f6bSGordon Ross 	if (vcp) {
676613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
677613a2f6bSGordon Ross 		smb_vc_rele(vcp);
678613a2f6bSGordon Ross 	}
679*430b4c46SGordon Ross 	kmem_free(ossn, sizeof (*ossn));
680613a2f6bSGordon Ross 	smb_credrele(&scred);
681613a2f6bSGordon Ross 
6824bff34e3Sthurlow 	return (error);
6834bff34e3Sthurlow }
6844bff34e3Sthurlow 
685613a2f6bSGordon Ross /*
686613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
687613a2f6bSGordon Ross  * Release or kill the current session.
688613a2f6bSGordon Ross  */
6894bff34e3Sthurlow int
690613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
6914bff34e3Sthurlow {
692613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
6934bff34e3Sthurlow 
694613a2f6bSGordon Ross 	/* Must have a VC. */
695613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
696613a2f6bSGordon Ross 		return (ENOTCONN);
6974bff34e3Sthurlow 
698613a2f6bSGordon Ross 	/* If we have a share ref, drop it too. */
699613a2f6bSGordon Ross 	if (sdp->sd_share) {
700613a2f6bSGordon Ross 		smb_share_rele(sdp->sd_share);
701613a2f6bSGordon Ross 		sdp->sd_share = NULL;
702613a2f6bSGordon Ross 		sdp->sd_level = SMBL_VC;
7034bff34e3Sthurlow 	}
7044bff34e3Sthurlow 
705613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_KILL)
706613a2f6bSGordon Ross 		smb_vc_kill(vcp);
7074bff34e3Sthurlow 
708613a2f6bSGordon Ross 	/* Drop the VC ref. */
709613a2f6bSGordon Ross 	smb_vc_rele(vcp);
710613a2f6bSGordon Ross 	sdp->sd_vc = NULL;
711613a2f6bSGordon Ross 	sdp->sd_level = 0;
712613a2f6bSGordon Ross 
713613a2f6bSGordon Ross 	return (0);
7144bff34e3Sthurlow }
7154bff34e3Sthurlow 
7164bff34e3Sthurlow /*
717613a2f6bSGordon Ross  * Find or create a tree (connected share)
7184bff34e3Sthurlow  */
7194bff34e3Sthurlow int
720613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
7214bff34e3Sthurlow {
722613a2f6bSGordon Ross 	struct smb_cred scred;
723613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
724613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
725613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
726613a2f6bSGordon Ross 	int error = 0;
7274bff34e3Sthurlow 
728613a2f6bSGordon Ross 	/* Must have a VC. */
729613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
730613a2f6bSGordon Ross 		return (ENOTCONN);
731613a2f6bSGordon Ross 	/* Should not have a share. */
732613a2f6bSGordon Ross 	if (sdp->sd_share != NULL)
733613a2f6bSGordon Ross 		return (EISCONN);
734613a2f6bSGordon Ross 
735613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
736613a2f6bSGordon Ross 	tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
737613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
738613a2f6bSGordon Ross 		error = EFAULT;
739613a2f6bSGordon Ross 		goto out;
7404bff34e3Sthurlow 	}
741613a2f6bSGordon Ross 
742613a2f6bSGordon Ross 	/*
743613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
744613a2f6bSGordon Ross 	 */
745613a2f6bSGordon Ross 	tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
746613a2f6bSGordon Ross 	tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
747613a2f6bSGordon Ross 
748613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT)
749613a2f6bSGordon Ross 		tcon->tc_opt |= SMBSOPT_CREATE;
750613a2f6bSGordon Ross 	else /* FIND */
751613a2f6bSGordon Ross 		tcon->tc_opt &= ~SMBSOPT_CREATE;
752613a2f6bSGordon Ross 
753613a2f6bSGordon Ross 	error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
7544bff34e3Sthurlow 	if (error)
755613a2f6bSGordon Ross 		goto out;
756613a2f6bSGordon Ross 	ASSERT(ssp != NULL);
757613a2f6bSGordon Ross 
758613a2f6bSGordon Ross 	/*
759613a2f6bSGordon Ross 	 * We have a share, held, but not locked.
760613a2f6bSGordon Ross 	 * If we're creating, do tree connect now,
761613a2f6bSGordon Ross 	 * otherwise let that wait for a request.
762613a2f6bSGordon Ross 	 */
763613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT) {
764613a2f6bSGordon Ross 		error = smb_share_tcon(ssp, &scred);
765613a2f6bSGordon Ross 		if (error)
766613a2f6bSGordon Ross 			goto out;
7674bff34e3Sthurlow 	}
768613a2f6bSGordon Ross 
769613a2f6bSGordon Ross 	/*
770613a2f6bSGordon Ross 	 * Give caller the real share type from
771613a2f6bSGordon Ross 	 * the tree connect response, so they can
772613a2f6bSGordon Ross 	 * see if they got the requested type.
773613a2f6bSGordon Ross 	 */
774*430b4c46SGordon Ross 	tcon->tc_sh.sh_type = ssp->ss_type;
775613a2f6bSGordon Ross 
776613a2f6bSGordon Ross 	/*
777613a2f6bSGordon Ross 	 * The share has a hold from _tcon
778613a2f6bSGordon Ross 	 * which we keep until nsmb_close()
779613a2f6bSGordon Ross 	 * or the SMBIOC_TDIS below.
780613a2f6bSGordon Ross 	 */
781613a2f6bSGordon Ross 	sdp->sd_level = SMBL_SHARE;
782613a2f6bSGordon Ross 	sdp->sd_share = ssp;
783613a2f6bSGordon Ross 	ssp = NULL;
784613a2f6bSGordon Ross 	(void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
785613a2f6bSGordon Ross 
786613a2f6bSGordon Ross out:
787613a2f6bSGordon Ross 	if (ssp) {
788613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
789613a2f6bSGordon Ross 		smb_share_rele(ssp);
7904bff34e3Sthurlow 	}
791*430b4c46SGordon Ross 	/*
792*430b4c46SGordon Ross 	 * This structure may contain a
793*430b4c46SGordon Ross 	 * cleartext password, so zap it.
794*430b4c46SGordon Ross 	 */
795*430b4c46SGordon Ross 	bzero(tcon, sizeof (*tcon));
796*430b4c46SGordon Ross 	kmem_free(tcon, sizeof (*tcon));
797613a2f6bSGordon Ross 	smb_credrele(&scred);
7984bff34e3Sthurlow 
799613a2f6bSGordon Ross 	return (error);
8004bff34e3Sthurlow }
8014bff34e3Sthurlow 
802613a2f6bSGordon Ross /*
803613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
804613a2f6bSGordon Ross  * Release or kill the current tree
805613a2f6bSGordon Ross  */
806613a2f6bSGordon Ross int
807613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
8084bff34e3Sthurlow {
809613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
8104bff34e3Sthurlow 
811613a2f6bSGordon Ross 	/* Must have a VC and a share. */
812613a2f6bSGordon Ross 	if (sdp->sd_vc == NULL)
813613a2f6bSGordon Ross 		return (ENOTCONN);
814613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
815613a2f6bSGordon Ross 		return (ENOTCONN);
816613a2f6bSGordon Ross 
817613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_KILL)
818613a2f6bSGordon Ross 		smb_share_kill(ssp);
819613a2f6bSGordon Ross 
820613a2f6bSGordon Ross 	/* Drop the share ref. */
821613a2f6bSGordon Ross 	smb_share_rele(sdp->sd_share);
822613a2f6bSGordon Ross 	sdp->sd_share = NULL;
823613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
824613a2f6bSGordon Ross 
825613a2f6bSGordon Ross 	return (0);
8264bff34e3Sthurlow }
8274bff34e3Sthurlow 
828613a2f6bSGordon Ross 
829613a2f6bSGordon Ross /*
830613a2f6bSGordon Ross  * Ioctl function: SMBIOC_IOD_WORK
831613a2f6bSGordon Ross  *
832613a2f6bSGordon Ross  * Become the reader (IOD) thread, until either the connection is
833613a2f6bSGordon Ross  * reset by the server, or until the connection is idle longer than
834613a2f6bSGordon Ross  * some max time. (max idle time not yet implemented)
835613a2f6bSGordon Ross  */
8364bff34e3Sthurlow int
837613a2f6bSGordon Ross smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
8384bff34e3Sthurlow {
839613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
840613a2f6bSGordon Ross 	int err = 0;
8414bff34e3Sthurlow 
842613a2f6bSGordon Ross 	/* Must have a valid session. */
843613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
8444bff34e3Sthurlow 		return (EINVAL);
845613a2f6bSGordon Ross 	if (vcp->vc_flags & SMBV_GONE)
846613a2f6bSGordon Ross 		return (EINVAL);
847613a2f6bSGordon Ross 
848613a2f6bSGordon Ross 	/*
849613a2f6bSGordon Ross 	 * Is there already an IOD for this VC?
850613a2f6bSGordon Ross 	 * (Should never happen.)
851613a2f6bSGordon Ross 	 */
852613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
853613a2f6bSGordon Ross 	if (vcp->iod_thr == NULL)
854613a2f6bSGordon Ross 		vcp->iod_thr = curthread;
855613a2f6bSGordon Ross 	else
856613a2f6bSGordon Ross 		err = EEXIST;
857613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
858613a2f6bSGordon Ross 	if (err)
859613a2f6bSGordon Ross 		return (err);
860613a2f6bSGordon Ross 
861613a2f6bSGordon Ross 	/*
862613a2f6bSGordon Ross 	 * Copy the "work" state, etc. into the VC
863613a2f6bSGordon Ross 	 * The MAC key is copied separately.
864613a2f6bSGordon Ross 	 */
865613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, &vcp->vc_work,
866613a2f6bSGordon Ross 	    sizeof (smbioc_ssn_work_t), flags)) {
867613a2f6bSGordon Ross 		err = EFAULT;
868613a2f6bSGordon Ross 		goto out;
8694bff34e3Sthurlow 	}
870613a2f6bSGordon Ross 	if (vcp->vc_u_maclen) {
871613a2f6bSGordon Ross 		vcp->vc_mackeylen = vcp->vc_u_maclen;
872613a2f6bSGordon Ross 		vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
873613a2f6bSGordon Ross 		if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
874613a2f6bSGordon Ross 		    vcp->vc_mackeylen, flags)) {
875613a2f6bSGordon Ross 			err = EFAULT;
876613a2f6bSGordon Ross 			goto out;
8774bff34e3Sthurlow 		}
8789c9af259SGordon Ross 	}
879613a2f6bSGordon Ross 
880613a2f6bSGordon Ross 	err = smb_iod_vc_work(vcp, cr);
881613a2f6bSGordon Ross 
882613a2f6bSGordon Ross 	/* Caller wants state here. */
883613a2f6bSGordon Ross 	vcp->vc_work.wk_out_state = vcp->vc_state;
884613a2f6bSGordon Ross 
885613a2f6bSGordon Ross 	(void) ddi_copyout(&vcp->vc_work, (void *)arg,
886613a2f6bSGordon Ross 	    sizeof (smbioc_ssn_work_t), flags);
887613a2f6bSGordon Ross 
888613a2f6bSGordon Ross out:
889613a2f6bSGordon Ross 	if (vcp->vc_mackey) {
890613a2f6bSGordon Ross 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
891613a2f6bSGordon Ross 		vcp->vc_mackey = NULL;
892613a2f6bSGordon Ross 		vcp->vc_mackeylen = 0;
893613a2f6bSGordon Ross 	}
894613a2f6bSGordon Ross 
895613a2f6bSGordon Ross 	/*
896613a2f6bSGordon Ross 	 * The IOD thread is leaving the driver.  Clear iod_thr,
897613a2f6bSGordon Ross 	 * and wake up anybody waiting for us to quit.
898613a2f6bSGordon Ross 	 */
899613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
900613a2f6bSGordon Ross 	vcp->iod_thr = NULL;
901613a2f6bSGordon Ross 	cv_broadcast(&vcp->vc_statechg);
902613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
903613a2f6bSGordon Ross 
904613a2f6bSGordon Ross 	return (err);
9054bff34e3Sthurlow }
9064bff34e3Sthurlow 
9074bff34e3Sthurlow /*
908613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
909613a2f6bSGordon Ross  *
910613a2f6bSGordon Ross  * Wait for user-level requests to be enqueued on this session,
911613a2f6bSGordon Ross  * and then return to the user-space helper, which will then
912613a2f6bSGordon Ross  * initiate a reconnect, etc.
9134bff34e3Sthurlow  */
9144bff34e3Sthurlow int
915613a2f6bSGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
9164bff34e3Sthurlow {
917613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
918613a2f6bSGordon Ross 	int err = 0;
919613a2f6bSGordon Ross 
920613a2f6bSGordon Ross 	/* Must have a valid session. */
921613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
922613a2f6bSGordon Ross 		return (EINVAL);
923613a2f6bSGordon Ross 	if (vcp->vc_flags & SMBV_GONE)
924613a2f6bSGordon Ross 		return (EINVAL);
925613a2f6bSGordon Ross 
926613a2f6bSGordon Ross 	/*
927613a2f6bSGordon Ross 	 * Is there already an IOD for this VC?
928613a2f6bSGordon Ross 	 * (Should never happen.)
929613a2f6bSGordon Ross 	 */
930613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
931613a2f6bSGordon Ross 	if (vcp->iod_thr == NULL)
932613a2f6bSGordon Ross 		vcp->iod_thr = curthread;
933613a2f6bSGordon Ross 	else
934613a2f6bSGordon Ross 		err = EEXIST;
935613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
936613a2f6bSGordon Ross 	if (err)
937613a2f6bSGordon Ross 		return (err);
938613a2f6bSGordon Ross 
939613a2f6bSGordon Ross 	/* nothing to copyin */
9404bff34e3Sthurlow 
9414bff34e3Sthurlow 	switch (cmd) {
942613a2f6bSGordon Ross 	case SMBIOC_IOD_IDLE:
943613a2f6bSGordon Ross 		err = smb_iod_vc_idle(vcp);
9444bff34e3Sthurlow 		break;
945613a2f6bSGordon Ross 
946613a2f6bSGordon Ross 	case SMBIOC_IOD_RCFAIL:
947613a2f6bSGordon Ross 		err = smb_iod_vc_rcfail(vcp);
9484bff34e3Sthurlow 		break;
949613a2f6bSGordon Ross 
9504bff34e3Sthurlow 	default:
951613a2f6bSGordon Ross 		err = ENOTTY;
952613a2f6bSGordon Ross 		goto out;
9534bff34e3Sthurlow 	}
9544bff34e3Sthurlow 
955613a2f6bSGordon Ross 	/* Both of these ioctls copy out the new state. */
956613a2f6bSGordon Ross 	(void) ddi_copyout(&vcp->vc_state, (void *)arg,
957613a2f6bSGordon Ross 	    sizeof (int), flags);
9584bff34e3Sthurlow 
959613a2f6bSGordon Ross out:
9604bff34e3Sthurlow 	/*
961613a2f6bSGordon Ross 	 * The IOD thread is leaving the driver.  Clear iod_thr,
962613a2f6bSGordon Ross 	 * and wake up anybody waiting for us to quit.
9634bff34e3Sthurlow 	 */
964613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
965613a2f6bSGordon Ross 	vcp->iod_thr = NULL;
966613a2f6bSGordon Ross 	cv_broadcast(&vcp->vc_statechg);
967613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
9684bff34e3Sthurlow 
969613a2f6bSGordon Ross 	return (err);
9704bff34e3Sthurlow }
971