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 /*
36613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
379c9af259SGordon Ross  * Use is subject to license terms.
38*40c0e231SGordon Ross  *
39*40c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
409c9af259SGordon Ross  */
414bff34e3Sthurlow 
424bff34e3Sthurlow #include <sys/param.h>
434bff34e3Sthurlow #include <sys/kmem.h>
444bff34e3Sthurlow #include <sys/systm.h>
454bff34e3Sthurlow #include <sys/policy.h>
464bff34e3Sthurlow #include <sys/conf.h>
474bff34e3Sthurlow #include <sys/proc.h>
484bff34e3Sthurlow #include <sys/fcntl.h>
49613a2f6bSGordon Ross #include <sys/file.h>
504bff34e3Sthurlow #include <sys/socket.h>
51613a2f6bSGordon Ross #include <sys/sunddi.h>
524bff34e3Sthurlow #include <sys/cmn_err.h>
534bff34e3Sthurlow 
544bff34e3Sthurlow #include <netsmb/smb_osdep.h>
554bff34e3Sthurlow 
564bff34e3Sthurlow #include <netsmb/smb.h>
574bff34e3Sthurlow #include <netsmb/smb_conn.h>
584bff34e3Sthurlow #include <netsmb/smb_rq.h>
594bff34e3Sthurlow #include <netsmb/smb_subr.h>
604bff34e3Sthurlow #include <netsmb/smb_dev.h>
614bff34e3Sthurlow 
62613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
63613a2f6bSGordon Ross 
644bff34e3Sthurlow /*
65613a2f6bSGordon Ross  * Ioctl function for SMBIOC_GETSSNKEY
66613a2f6bSGordon Ross  * Size copied out is SMBIOC_HASH_SZ.
67613a2f6bSGordon Ross  *
68613a2f6bSGordon Ross  * The RPC library needs this for encrypting things
69613a2f6bSGordon Ross  * like "set password" requests.  This is called
70613a2f6bSGordon Ross  * with an active RPC binding, so the connection
71613a2f6bSGordon Ross  * will already be active (but this checks).
724bff34e3Sthurlow  */
73613a2f6bSGordon Ross int
74613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
754bff34e3Sthurlow {
76613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
77613a2f6bSGordon Ross 
78613a2f6bSGordon Ross 	/* This ioctl requires an active session. */
79613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
80613a2f6bSGordon Ross 		return (ENOTCONN);
81613a2f6bSGordon Ross 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
82613a2f6bSGordon Ross 		return (ENOTCONN);
834bff34e3Sthurlow 
844bff34e3Sthurlow 	/*
85613a2f6bSGordon Ross 	 * Return the session key.
864bff34e3Sthurlow 	 */
87*40c0e231SGordon Ross 	if (vcp->vc_ssnkey == NULL ||
88*40c0e231SGordon Ross 	    vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
89*40c0e231SGordon Ross 		return (EINVAL);
90*40c0e231SGordon Ross 	if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
91613a2f6bSGordon Ross 	    SMBIOC_HASH_SZ, flags))
92613a2f6bSGordon Ross 		return (EFAULT);
93613a2f6bSGordon Ross 
94613a2f6bSGordon Ross 	return (0);
95613a2f6bSGordon Ross }
96613a2f6bSGordon Ross 
97613a2f6bSGordon Ross /*
98*40c0e231SGordon Ross  * Ioctl function for SMBIOC_XACTNP (transact named pipe)
99613a2f6bSGordon Ross  */
100613a2f6bSGordon Ross int
101*40c0e231SGordon Ross smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
1024bff34e3Sthurlow {
103613a2f6bSGordon Ross 	struct smb_cred scred;
104613a2f6bSGordon Ross 	struct smb_share *ssp;
105*40c0e231SGordon Ross 	smbioc_xnp_t *ioc = NULL;
106613a2f6bSGordon Ross 	struct smb_t2rq *t2p = NULL;
107613a2f6bSGordon Ross 	struct mdchain *mdp;
108613a2f6bSGordon Ross 	int err, len, mbseg;
109*40c0e231SGordon Ross 	uint16_t setup[2];
110613a2f6bSGordon Ross 
111613a2f6bSGordon Ross 	/* This ioctl requires a share. */
112613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
113613a2f6bSGordon Ross 		return (ENOTCONN);
1144bff34e3Sthurlow 
115613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
116613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
117613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
118613a2f6bSGordon Ross 		err = EFAULT;
119613a2f6bSGordon Ross 		goto out;
1204bff34e3Sthurlow 	}
121613a2f6bSGordon Ross 
122613a2f6bSGordon Ross 	/* See ddi_copyin, ddi_copyout */
123613a2f6bSGordon Ross 	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
124613a2f6bSGordon Ross 
125430b4c46SGordon Ross 	/*
126430b4c46SGordon Ross 	 * Fill in the FID for libsmbfs transact named pipe.
127430b4c46SGordon Ross 	 */
128*40c0e231SGordon Ross 	if (ioc->ioc_fh == -1) {
129430b4c46SGordon Ross 		if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
130430b4c46SGordon Ross 			err = ESTALE;
131430b4c46SGordon Ross 			goto out;
132430b4c46SGordon Ross 		}
133*40c0e231SGordon Ross 		ioc->ioc_fh = sdp->sd_smbfid;
134430b4c46SGordon Ross 	}
135430b4c46SGordon Ross 
136*40c0e231SGordon Ross 	setup[0] = TRANS_TRANSACT_NAMED_PIPE;
137*40c0e231SGordon Ross 	setup[1] = (uint16_t)ioc->ioc_fh;
138*40c0e231SGordon Ross 
139613a2f6bSGordon Ross 	t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
140*40c0e231SGordon Ross 	err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &scred);
141613a2f6bSGordon Ross 	if (err)
142613a2f6bSGordon Ross 		goto out;
143*40c0e231SGordon Ross 	t2p->t2_setupcount = 2;
144*40c0e231SGordon Ross 	t2p->t2_setupdata  = setup;
145*40c0e231SGordon Ross 
146*40c0e231SGordon Ross 	t2p->t_name = "\\PIPE\\";
147*40c0e231SGordon Ross 	t2p->t_name_len = 6;
148*40c0e231SGordon Ross 
149613a2f6bSGordon Ross 	t2p->t2_maxscount = 0;
150*40c0e231SGordon Ross 	t2p->t2_maxpcount = 0;
151*40c0e231SGordon Ross 	t2p->t2_maxdcount = ioc->ioc_rdlen;
152613a2f6bSGordon Ross 
153*40c0e231SGordon Ross 	/* Transmit parameters (none) */
154613a2f6bSGordon Ross 
155613a2f6bSGordon Ross 	/* Transmit data */
156613a2f6bSGordon Ross 	err = smb_cpdatain(&t2p->t2_tdata,
157*40c0e231SGordon Ross 	    ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
158613a2f6bSGordon Ross 	if (err)
159613a2f6bSGordon Ross 		goto out;
160613a2f6bSGordon Ross 
161613a2f6bSGordon Ross 	err = smb_t2_request(t2p);
162613a2f6bSGordon Ross 
163*40c0e231SGordon Ross 	/* No returned parameters. */
164613a2f6bSGordon Ross 
165613a2f6bSGordon Ross 	/* Copyout returned data. */
166613a2f6bSGordon Ross 	mdp = &t2p->t2_rdata;
167613a2f6bSGordon Ross 	if (err == 0 && mdp->md_top != NULL) {
168613a2f6bSGordon Ross 		/* User's buffer large enough? */
169613a2f6bSGordon Ross 		len = m_fixhdr(mdp->md_top);
170*40c0e231SGordon Ross 		if (len > ioc->ioc_rdlen) {
171613a2f6bSGordon Ross 			err = EMSGSIZE;
172613a2f6bSGordon Ross 			goto out;
173613a2f6bSGordon Ross 		}
174*40c0e231SGordon Ross 		ioc->ioc_rdlen = (ushort_t)len;
175613a2f6bSGordon Ross 		err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
176613a2f6bSGordon Ross 		if (err)
177613a2f6bSGordon Ross 			goto out;
178613a2f6bSGordon Ross 	} else
179*40c0e231SGordon Ross 		ioc->ioc_rdlen = 0;
180613a2f6bSGordon Ross 
181*40c0e231SGordon Ross 	if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
182*40c0e231SGordon Ross 		ioc->ioc_more = 1;
183613a2f6bSGordon Ross 
18402d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
185613a2f6bSGordon Ross 
186613a2f6bSGordon Ross 
187613a2f6bSGordon Ross out:
188613a2f6bSGordon Ross 	if (t2p != NULL) {
189613a2f6bSGordon Ross 		/* Note: t2p->t_name no longer allocated */
190613a2f6bSGordon Ross 		smb_t2_done(t2p);
191613a2f6bSGordon Ross 		kmem_free(t2p, sizeof (*t2p));
192613a2f6bSGordon Ross 	}
193430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
194613a2f6bSGordon Ross 	smb_credrele(&scred);
195613a2f6bSGordon Ross 
196613a2f6bSGordon Ross 	return (err);
1974bff34e3Sthurlow }
1984bff34e3Sthurlow 
199613a2f6bSGordon Ross /* helper for _t2request */
2004bff34e3Sthurlow static int
201613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
2024bff34e3Sthurlow {
203613a2f6bSGordon Ross 	int error;
204613a2f6bSGordon Ross 
205613a2f6bSGordon Ross 	if (len == 0)
206613a2f6bSGordon Ross 		return (0);
207613a2f6bSGordon Ross 	error = mb_init(mbp);
208613a2f6bSGordon Ross 	if (error)
209613a2f6bSGordon Ross 		return (error);
210613a2f6bSGordon Ross 	return (mb_put_mem(mbp, data, len, mbseg));
2114bff34e3Sthurlow }
2124bff34e3Sthurlow 
213613a2f6bSGordon Ross /*
214613a2f6bSGordon Ross  * Helper for nsmb_ioctl cases
215613a2f6bSGordon Ross  * SMBIOC_READ, SMBIOC_WRITE
216613a2f6bSGordon Ross  */
2171b34bc4aSbs int
218613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
2191b34bc4aSbs {
220613a2f6bSGordon Ross 	struct smb_cred scred;
221613a2f6bSGordon Ross 	struct smb_share *ssp;
222613a2f6bSGordon Ross 	smbioc_rw_t *ioc = NULL;
223613a2f6bSGordon Ross 	struct iovec aiov[1];
224613a2f6bSGordon Ross 	struct uio  auio;
225430b4c46SGordon Ross 	uint16_t fh;
226613a2f6bSGordon Ross 	int err;
227613a2f6bSGordon Ross 	uio_rw_t rw;
2281b34bc4aSbs 
229613a2f6bSGordon Ross 	/* This ioctl requires a share. */
230613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
231613a2f6bSGordon Ross 		return (ENOTCONN);
232613a2f6bSGordon Ross 
233613a2f6bSGordon Ross 	/* After reconnect, force close+reopen */
234613a2f6bSGordon Ross 	if (sdp->sd_vcgenid != ssp->ss_vcgenid)
235613a2f6bSGordon Ross 		return (ESTALE);
236613a2f6bSGordon Ross 
237613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
238613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
239613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
240613a2f6bSGordon Ross 		err = EFAULT;
2411b34bc4aSbs 		goto out;
242613a2f6bSGordon Ross 	}
243613a2f6bSGordon Ross 
244613a2f6bSGordon Ross 	switch (cmd) {
245613a2f6bSGordon Ross 	case SMBIOC_READ:
246613a2f6bSGordon Ross 		rw = UIO_READ;
247613a2f6bSGordon Ross 		break;
248613a2f6bSGordon Ross 	case SMBIOC_WRITE:
249613a2f6bSGordon Ross 		rw = UIO_WRITE;
250613a2f6bSGordon Ross 		break;
251613a2f6bSGordon Ross 	default:
252613a2f6bSGordon Ross 		err = ENODEV;
253613a2f6bSGordon Ross 		goto out;
254613a2f6bSGordon Ross 	}
255613a2f6bSGordon Ross 
256430b4c46SGordon Ross 	/*
257430b4c46SGordon Ross 	 * If caller passes -1 in ioc_fh, then
258430b4c46SGordon Ross 	 * use the FID from SMBIOC_NTCREATE.
259430b4c46SGordon Ross 	 */
260430b4c46SGordon Ross 	if (ioc->ioc_fh == -1)
261430b4c46SGordon Ross 		fh = (uint16_t)sdp->sd_smbfid;
262430b4c46SGordon Ross 	else
263430b4c46SGordon Ross 		fh = (uint16_t)ioc->ioc_fh;
264613a2f6bSGordon Ross 
265613a2f6bSGordon Ross 	aiov[0].iov_base = ioc->ioc_base;
266613a2f6bSGordon Ross 	aiov[0].iov_len = (size_t)ioc->ioc_cnt;
267613a2f6bSGordon Ross 
268613a2f6bSGordon Ross 	auio.uio_iov = aiov;
269613a2f6bSGordon Ross 	auio.uio_iovcnt = 1;
270613a2f6bSGordon Ross 	auio.uio_loffset = ioc->ioc_offset;
271613a2f6bSGordon Ross 	auio.uio_segflg = (flags & FKIOCTL) ?
272613a2f6bSGordon Ross 	    UIO_SYSSPACE : UIO_USERSPACE;
273613a2f6bSGordon Ross 	auio.uio_fmode = 0;
274613a2f6bSGordon Ross 	auio.uio_resid = (size_t)ioc->ioc_cnt;
275613a2f6bSGordon Ross 
276613a2f6bSGordon Ross 	err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
277613a2f6bSGordon Ross 
278613a2f6bSGordon Ross 	/*
279613a2f6bSGordon Ross 	 * On return ioc_cnt holds the
280613a2f6bSGordon Ross 	 * number of bytes transferred.
281613a2f6bSGordon Ross 	 */
282613a2f6bSGordon Ross 	ioc->ioc_cnt -= auio.uio_resid;
283613a2f6bSGordon Ross 
28402d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
285613a2f6bSGordon Ross 
2861b34bc4aSbs out:
287430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
288430b4c46SGordon Ross 	smb_credrele(&scred);
289430b4c46SGordon Ross 
290430b4c46SGordon Ross 	return (err);
291430b4c46SGordon Ross }
292430b4c46SGordon Ross 
293430b4c46SGordon Ross /*
294430b4c46SGordon Ross  * Helper for nsmb_ioctl case
295430b4c46SGordon Ross  * SMBIOC_NTCREATE
296430b4c46SGordon Ross  */
297430b4c46SGordon Ross int
298430b4c46SGordon Ross smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
299430b4c46SGordon Ross {
300430b4c46SGordon Ross 	struct smb_cred scred;
301430b4c46SGordon Ross 	struct mbchain name_mb;
302430b4c46SGordon Ross 	struct smb_share *ssp;
303430b4c46SGordon Ross 	smbioc_ntcreate_t *ioc = NULL;
304430b4c46SGordon Ross 	uint16_t fid;
305430b4c46SGordon Ross 	int err, nmlen;
306430b4c46SGordon Ross 
307430b4c46SGordon Ross 	/* This ioctl requires a share. */
308430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
309430b4c46SGordon Ross 		return (ENOTCONN);
310430b4c46SGordon Ross 
311430b4c46SGordon Ross 	/* Must not be already open. */
312430b4c46SGordon Ross 	if (sdp->sd_smbfid != -1)
313430b4c46SGordon Ross 		return (EINVAL);
314430b4c46SGordon Ross 
315430b4c46SGordon Ross 	mb_init(&name_mb);
316430b4c46SGordon Ross 	smb_credinit(&scred, cr);
317430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
318430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
319430b4c46SGordon Ross 		err = EFAULT;
320430b4c46SGordon Ross 		goto out;
321430b4c46SGordon Ross 	}
322430b4c46SGordon Ross 
323430b4c46SGordon Ross 	/* Build name_mb */
324430b4c46SGordon Ross 	ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
325430b4c46SGordon Ross 	nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
326430b4c46SGordon Ross 	err = smb_put_dmem(&name_mb, SSTOVC(ssp),
327430b4c46SGordon Ross 	    ioc->ioc_name, nmlen,
328430b4c46SGordon Ross 	    SMB_CS_NONE, NULL);
329430b4c46SGordon Ross 	if (err != 0)
330430b4c46SGordon Ross 		goto out;
331430b4c46SGordon Ross 
332430b4c46SGordon Ross 	/* Do the OtW open, save the FID. */
333430b4c46SGordon Ross 	err = smb_smb_ntcreate(ssp, &name_mb,
334430b4c46SGordon Ross 	    0,	/* create flags */
335430b4c46SGordon Ross 	    ioc->ioc_req_acc,
336430b4c46SGordon Ross 	    ioc->ioc_efattr,
337430b4c46SGordon Ross 	    ioc->ioc_share_acc,
338430b4c46SGordon Ross 	    ioc->ioc_open_disp,
339430b4c46SGordon Ross 	    ioc->ioc_creat_opts,
340430b4c46SGordon Ross 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
341430b4c46SGordon Ross 	    &scred,
342430b4c46SGordon Ross 	    &fid,
343430b4c46SGordon Ross 	    NULL,
344430b4c46SGordon Ross 	    NULL);
345430b4c46SGordon Ross 	if (err != 0)
346430b4c46SGordon Ross 		goto out;
347430b4c46SGordon Ross 
348430b4c46SGordon Ross 	sdp->sd_smbfid = fid;
349430b4c46SGordon Ross 	sdp->sd_vcgenid = ssp->ss_vcgenid;
350430b4c46SGordon Ross 
351430b4c46SGordon Ross out:
352430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
353430b4c46SGordon Ross 	smb_credrele(&scred);
354430b4c46SGordon Ross 	mb_done(&name_mb);
355430b4c46SGordon Ross 
356430b4c46SGordon Ross 	return (err);
357430b4c46SGordon Ross }
358430b4c46SGordon Ross 
359430b4c46SGordon Ross /*
360430b4c46SGordon Ross  * Helper for nsmb_ioctl case
361430b4c46SGordon Ross  * SMBIOC_PRINTJOB
362430b4c46SGordon Ross  */
363430b4c46SGordon Ross int
364430b4c46SGordon Ross smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
365430b4c46SGordon Ross {
366430b4c46SGordon Ross 	struct smb_cred scred;
367430b4c46SGordon Ross 	struct smb_share *ssp;
368430b4c46SGordon Ross 	smbioc_printjob_t *ioc = NULL;
369430b4c46SGordon Ross 	uint16_t fid;
370430b4c46SGordon Ross 	int err;
371430b4c46SGordon Ross 
372430b4c46SGordon Ross 	/* This ioctl requires a share. */
373430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
374430b4c46SGordon Ross 		return (ENOTCONN);
375430b4c46SGordon Ross 
376430b4c46SGordon Ross 	/* The share must be a print queue. */
377430b4c46SGordon Ross 	if (ssp->ss_type != STYPE_PRINTQ)
378430b4c46SGordon Ross 		return (EINVAL);
379430b4c46SGordon Ross 
380430b4c46SGordon Ross 	/* Must not be already open. */
381430b4c46SGordon Ross 	if (sdp->sd_smbfid != -1)
382430b4c46SGordon Ross 		return (EINVAL);
383430b4c46SGordon Ross 
384430b4c46SGordon Ross 	smb_credinit(&scred, cr);
385430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
386430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
387430b4c46SGordon Ross 		err = EFAULT;
388430b4c46SGordon Ross 		goto out;
389430b4c46SGordon Ross 	}
390430b4c46SGordon Ross 	ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
391430b4c46SGordon Ross 
392430b4c46SGordon Ross 	/* Do the OtW open, save the FID. */
393430b4c46SGordon Ross 	err = smb_smb_open_prjob(ssp, ioc->ioc_title,
394430b4c46SGordon Ross 	    ioc->ioc_setuplen, ioc->ioc_prmode,
395430b4c46SGordon Ross 	    &scred, &fid);
396430b4c46SGordon Ross 	if (err != 0)
397430b4c46SGordon Ross 		goto out;
398430b4c46SGordon Ross 
399430b4c46SGordon Ross 	sdp->sd_smbfid = fid;
400430b4c46SGordon Ross 	sdp->sd_vcgenid = ssp->ss_vcgenid;
401430b4c46SGordon Ross 
402430b4c46SGordon Ross out:
403430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
404430b4c46SGordon Ross 	smb_credrele(&scred);
405430b4c46SGordon Ross 
406430b4c46SGordon Ross 	return (err);
407430b4c46SGordon Ross }
408430b4c46SGordon Ross 
409430b4c46SGordon Ross /*
410430b4c46SGordon Ross  * Helper for nsmb_ioctl case
411430b4c46SGordon Ross  * SMBIOC_CLOSEFH
412430b4c46SGordon Ross  */
413430b4c46SGordon Ross int
414430b4c46SGordon Ross smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
415430b4c46SGordon Ross {
416430b4c46SGordon Ross 	struct smb_cred scred;
417430b4c46SGordon Ross 	struct smb_share *ssp;
418430b4c46SGordon Ross 	uint16_t fid;
419430b4c46SGordon Ross 	int err;
420430b4c46SGordon Ross 
421430b4c46SGordon Ross 	/* This ioctl requires a share. */
422430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
423430b4c46SGordon Ross 		return (ENOTCONN);
424430b4c46SGordon Ross 
425430b4c46SGordon Ross 	if (sdp->sd_smbfid == -1)
426430b4c46SGordon Ross 		return (0);
427430b4c46SGordon Ross 	fid = (uint16_t)sdp->sd_smbfid;
428430b4c46SGordon Ross 	sdp->sd_smbfid = -1;
429430b4c46SGordon Ross 
430430b4c46SGordon Ross 	smb_credinit(&scred, cr);
431430b4c46SGordon Ross 	if (ssp->ss_type == STYPE_PRINTQ)
432430b4c46SGordon Ross 		err = smb_smb_close_prjob(ssp, fid, &scred);
433430b4c46SGordon Ross 	else
434430b4c46SGordon Ross 		err = smb_smb_close(ssp, fid, NULL, &scred);
435613a2f6bSGordon Ross 	smb_credrele(&scred);
436613a2f6bSGordon Ross 
437613a2f6bSGordon Ross 	return (err);
4381b34bc4aSbs }
4391b34bc4aSbs 
440613a2f6bSGordon Ross /*
441613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
442613a2f6bSGordon Ross  * Find or create a session (a.k.a. "VC" in here)
443613a2f6bSGordon Ross  */
4444bff34e3Sthurlow int
445613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
4464bff34e3Sthurlow {
447613a2f6bSGordon Ross 	struct smb_cred scred;
448613a2f6bSGordon Ross 	smbioc_ossn_t *ossn = NULL;
4494bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
4504bff34e3Sthurlow 	int error = 0;
451613a2f6bSGordon Ross 	uid_t realuid;
4524bff34e3Sthurlow 
453613a2f6bSGordon Ross 	/* Should be no VC */
454613a2f6bSGordon Ross 	if (sdp->sd_vc != NULL)
455613a2f6bSGordon Ross 		return (EISCONN);
456613a2f6bSGordon Ross 
457613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
458613a2f6bSGordon Ross 	ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
459613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
460613a2f6bSGordon Ross 		error = EFAULT;
461613a2f6bSGordon Ross 		goto out;
4624bff34e3Sthurlow 	}
463613a2f6bSGordon Ross 
464613a2f6bSGordon Ross 	/*
465613a2f6bSGordon Ross 	 * Only superuser can specify a UID or GID.
466613a2f6bSGordon Ross 	 */
467613a2f6bSGordon Ross 	realuid = crgetruid(cr);
468613a2f6bSGordon Ross 	if (ossn->ssn_owner == SMBM_ANY_OWNER)
469613a2f6bSGordon Ross 		ossn->ssn_owner = realuid;
470613a2f6bSGordon Ross 	else {
4714bff34e3Sthurlow 		/*
472613a2f6bSGordon Ross 		 * Do we have the privilege to create with the
473613a2f6bSGordon Ross 		 * specified uid?  (does uid == cr->cr_uid, etc.)
4744bff34e3Sthurlow 		 */
475613a2f6bSGordon Ross 		if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
476613a2f6bSGordon Ross 			error = EPERM;
477613a2f6bSGordon Ross 			goto out;
4784bff34e3Sthurlow 		}
479613a2f6bSGordon Ross 		/* ossn->ssn_owner is OK */
4804bff34e3Sthurlow 	}
4814bff34e3Sthurlow 
482613a2f6bSGordon Ross 	/*
483613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
484613a2f6bSGordon Ross 	 */
485613a2f6bSGordon Ross 	ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
486613a2f6bSGordon Ross 	ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
487613a2f6bSGordon Ross 	ossn->ssn_id.id_user[   SMBIOC_MAX_NAME-1] = '\0';
4884bff34e3Sthurlow 
489613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE)
490613a2f6bSGordon Ross 		ossn->ssn_vopt |= SMBVOPT_CREATE;
491613a2f6bSGordon Ross 	else /* FIND */
492613a2f6bSGordon Ross 		ossn->ssn_vopt &= ~SMBVOPT_CREATE;
4934bff34e3Sthurlow 
494613a2f6bSGordon Ross 	error = smb_vc_findcreate(ossn, &scred, &vcp);
4954bff34e3Sthurlow 	if (error)
4964bff34e3Sthurlow 		goto out;
497613a2f6bSGordon Ross 	ASSERT(vcp != NULL);
4984bff34e3Sthurlow 
4994bff34e3Sthurlow 	/*
500613a2f6bSGordon Ross 	 * We have a VC, held, but not locked.
501613a2f6bSGordon Ross 	 * If we're creating, mark this instance as
502613a2f6bSGordon Ross 	 * an open from IOD so close can do cleanup.
503613a2f6bSGordon Ross 	 *
504613a2f6bSGordon Ross 	 * XXX: Would be nice to have a back pointer
505613a2f6bSGordon Ross 	 * from the VC to this (IOD) sdp instance.
5064bff34e3Sthurlow 	 */
507613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE) {
508613a2f6bSGordon Ross 		if (vcp->iod_thr != NULL) {
509613a2f6bSGordon Ross 			error = EEXIST;
510613a2f6bSGordon Ross 			goto out;
511613a2f6bSGordon Ross 		}
512613a2f6bSGordon Ross 		sdp->sd_flags |= NSMBFL_IOD;
513613a2f6bSGordon Ross 	} else {
514613a2f6bSGordon Ross 		/*
515613a2f6bSGordon Ross 		 * Wait for it to finish connecting
516613a2f6bSGordon Ross 		 * (or reconnect) if necessary.
517613a2f6bSGordon Ross 		 */
518613a2f6bSGordon Ross 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
519613a2f6bSGordon Ross 			error = smb_iod_reconnect(vcp);
520613a2f6bSGordon Ross 			if (error != 0)
521613a2f6bSGordon Ross 				goto out;
522613a2f6bSGordon Ross 		}
523613a2f6bSGordon Ross 	}
524613a2f6bSGordon Ross 
525613a2f6bSGordon Ross 	/*
526613a2f6bSGordon Ross 	 * The VC has a hold from _findvc
527613a2f6bSGordon Ross 	 * which we keep until _SSN_RELE
528613a2f6bSGordon Ross 	 * or nsmb_close().
529613a2f6bSGordon Ross 	 */
530613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
531613a2f6bSGordon Ross 	sdp->sd_vc = vcp;
532613a2f6bSGordon Ross 	vcp = NULL;
533613a2f6bSGordon Ross 	(void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
5344bff34e3Sthurlow 
5354bff34e3Sthurlow out:
536613a2f6bSGordon Ross 	if (vcp) {
537613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
538613a2f6bSGordon Ross 		smb_vc_rele(vcp);
539613a2f6bSGordon Ross 	}
540430b4c46SGordon Ross 	kmem_free(ossn, sizeof (*ossn));
541613a2f6bSGordon Ross 	smb_credrele(&scred);
542613a2f6bSGordon Ross 
5434bff34e3Sthurlow 	return (error);
5444bff34e3Sthurlow }
5454bff34e3Sthurlow 
546613a2f6bSGordon Ross /*
547613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
548613a2f6bSGordon Ross  * Release or kill the current session.
549613a2f6bSGordon Ross  */
5504bff34e3Sthurlow int
551613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
5524bff34e3Sthurlow {
553613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
5544bff34e3Sthurlow 
555613a2f6bSGordon Ross 	/* Must have a VC. */
556613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
557613a2f6bSGordon Ross 		return (ENOTCONN);
5584bff34e3Sthurlow 
559613a2f6bSGordon Ross 	/* If we have a share ref, drop it too. */
560613a2f6bSGordon Ross 	if (sdp->sd_share) {
561613a2f6bSGordon Ross 		smb_share_rele(sdp->sd_share);
562613a2f6bSGordon Ross 		sdp->sd_share = NULL;
563613a2f6bSGordon Ross 		sdp->sd_level = SMBL_VC;
5644bff34e3Sthurlow 	}
5654bff34e3Sthurlow 
566613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_KILL)
567613a2f6bSGordon Ross 		smb_vc_kill(vcp);
5684bff34e3Sthurlow 
569613a2f6bSGordon Ross 	/* Drop the VC ref. */
570613a2f6bSGordon Ross 	smb_vc_rele(vcp);
571613a2f6bSGordon Ross 	sdp->sd_vc = NULL;
572613a2f6bSGordon Ross 	sdp->sd_level = 0;
573613a2f6bSGordon Ross 
574613a2f6bSGordon Ross 	return (0);
5754bff34e3Sthurlow }
5764bff34e3Sthurlow 
5774bff34e3Sthurlow /*
578613a2f6bSGordon Ross  * Find or create a tree (connected share)
5794bff34e3Sthurlow  */
5804bff34e3Sthurlow int
581613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
5824bff34e3Sthurlow {
583613a2f6bSGordon Ross 	struct smb_cred scred;
584613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
585613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
586613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
587613a2f6bSGordon Ross 	int error = 0;
5884bff34e3Sthurlow 
589613a2f6bSGordon Ross 	/* Must have a VC. */
590613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
591613a2f6bSGordon Ross 		return (ENOTCONN);
592613a2f6bSGordon Ross 	/* Should not have a share. */
593613a2f6bSGordon Ross 	if (sdp->sd_share != NULL)
594613a2f6bSGordon Ross 		return (EISCONN);
595613a2f6bSGordon Ross 
596613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
597613a2f6bSGordon Ross 	tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
598613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
599613a2f6bSGordon Ross 		error = EFAULT;
600613a2f6bSGordon Ross 		goto out;
6014bff34e3Sthurlow 	}
602613a2f6bSGordon Ross 
603613a2f6bSGordon Ross 	/*
604613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
605613a2f6bSGordon Ross 	 */
606613a2f6bSGordon Ross 	tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
607613a2f6bSGordon Ross 	tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
608613a2f6bSGordon Ross 
609613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT)
610613a2f6bSGordon Ross 		tcon->tc_opt |= SMBSOPT_CREATE;
611613a2f6bSGordon Ross 	else /* FIND */
612613a2f6bSGordon Ross 		tcon->tc_opt &= ~SMBSOPT_CREATE;
613613a2f6bSGordon Ross 
614613a2f6bSGordon Ross 	error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
6154bff34e3Sthurlow 	if (error)
616613a2f6bSGordon Ross 		goto out;
617613a2f6bSGordon Ross 	ASSERT(ssp != NULL);
618613a2f6bSGordon Ross 
619613a2f6bSGordon Ross 	/*
620613a2f6bSGordon Ross 	 * We have a share, held, but not locked.
621613a2f6bSGordon Ross 	 * If we're creating, do tree connect now,
622613a2f6bSGordon Ross 	 * otherwise let that wait for a request.
623613a2f6bSGordon Ross 	 */
624613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT) {
625613a2f6bSGordon Ross 		error = smb_share_tcon(ssp, &scred);
626613a2f6bSGordon Ross 		if (error)
627613a2f6bSGordon Ross 			goto out;
6284bff34e3Sthurlow 	}
629613a2f6bSGordon Ross 
630613a2f6bSGordon Ross 	/*
631613a2f6bSGordon Ross 	 * Give caller the real share type from
632613a2f6bSGordon Ross 	 * the tree connect response, so they can
633613a2f6bSGordon Ross 	 * see if they got the requested type.
634613a2f6bSGordon Ross 	 */
635430b4c46SGordon Ross 	tcon->tc_sh.sh_type = ssp->ss_type;
636613a2f6bSGordon Ross 
637613a2f6bSGordon Ross 	/*
638613a2f6bSGordon Ross 	 * The share has a hold from _tcon
639613a2f6bSGordon Ross 	 * which we keep until nsmb_close()
640613a2f6bSGordon Ross 	 * or the SMBIOC_TDIS below.
641613a2f6bSGordon Ross 	 */
642613a2f6bSGordon Ross 	sdp->sd_level = SMBL_SHARE;
643613a2f6bSGordon Ross 	sdp->sd_share = ssp;
644613a2f6bSGordon Ross 	ssp = NULL;
645613a2f6bSGordon Ross 	(void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
646613a2f6bSGordon Ross 
647613a2f6bSGordon Ross out:
648613a2f6bSGordon Ross 	if (ssp) {
649613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
650613a2f6bSGordon Ross 		smb_share_rele(ssp);
6514bff34e3Sthurlow 	}
652430b4c46SGordon Ross 	/*
653430b4c46SGordon Ross 	 * This structure may contain a
654430b4c46SGordon Ross 	 * cleartext password, so zap it.
655430b4c46SGordon Ross 	 */
656430b4c46SGordon Ross 	bzero(tcon, sizeof (*tcon));
657430b4c46SGordon Ross 	kmem_free(tcon, sizeof (*tcon));
658613a2f6bSGordon Ross 	smb_credrele(&scred);
6594bff34e3Sthurlow 
660613a2f6bSGordon Ross 	return (error);
6614bff34e3Sthurlow }
6624bff34e3Sthurlow 
663613a2f6bSGordon Ross /*
664613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
665613a2f6bSGordon Ross  * Release or kill the current tree
666613a2f6bSGordon Ross  */
667613a2f6bSGordon Ross int
668613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
6694bff34e3Sthurlow {
670613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
6714bff34e3Sthurlow 
672613a2f6bSGordon Ross 	/* Must have a VC and a share. */
673613a2f6bSGordon Ross 	if (sdp->sd_vc == NULL)
674613a2f6bSGordon Ross 		return (ENOTCONN);
675613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
676613a2f6bSGordon Ross 		return (ENOTCONN);
677613a2f6bSGordon Ross 
678613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_KILL)
679613a2f6bSGordon Ross 		smb_share_kill(ssp);
680613a2f6bSGordon Ross 
681613a2f6bSGordon Ross 	/* Drop the share ref. */
682613a2f6bSGordon Ross 	smb_share_rele(sdp->sd_share);
683613a2f6bSGordon Ross 	sdp->sd_share = NULL;
684613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
685613a2f6bSGordon Ross 
686613a2f6bSGordon Ross 	return (0);
6874bff34e3Sthurlow }
6884bff34e3Sthurlow 
689613a2f6bSGordon Ross /*
690*40c0e231SGordon Ross  * Ioctl handler for all SMBIOC_IOD_...
691613a2f6bSGordon Ross  */
6924bff34e3Sthurlow int
693*40c0e231SGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
6944bff34e3Sthurlow {
695*40c0e231SGordon Ross 	struct smb_vc *vcp;
696613a2f6bSGordon Ross 	int err = 0;
6974bff34e3Sthurlow 
698*40c0e231SGordon Ross 	/* Must be the IOD. */
699*40c0e231SGordon Ross 	if ((sdp->sd_flags & NSMBFL_IOD) == 0)
700*40c0e231SGordon Ross 		return (EINVAL);
701*40c0e231SGordon Ross 	/* Must have a VC and no share. */
702613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
7034bff34e3Sthurlow 		return (EINVAL);
704*40c0e231SGordon Ross 	if (sdp->sd_share != NULL)
705613a2f6bSGordon Ross 		return (EINVAL);
706613a2f6bSGordon Ross 
707613a2f6bSGordon Ross 	/*
708613a2f6bSGordon Ross 	 * Is there already an IOD for this VC?
709613a2f6bSGordon Ross 	 * (Should never happen.)
710613a2f6bSGordon Ross 	 */
711613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
712613a2f6bSGordon Ross 	if (vcp->iod_thr == NULL)
713613a2f6bSGordon Ross 		vcp->iod_thr = curthread;
714613a2f6bSGordon Ross 	else
715613a2f6bSGordon Ross 		err = EEXIST;
716613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
717613a2f6bSGordon Ross 	if (err)
718613a2f6bSGordon Ross 		return (err);
719613a2f6bSGordon Ross 
720613a2f6bSGordon Ross 	/*
721*40c0e231SGordon Ross 	 * Copy the "work" state, etc. into the VC,
722*40c0e231SGordon Ross 	 * and back to the caller on the way out.
723*40c0e231SGordon Ross 	 * Clear the "out only" part.
724613a2f6bSGordon Ross 	 */
725613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, &vcp->vc_work,
726613a2f6bSGordon Ross 	    sizeof (smbioc_ssn_work_t), flags)) {
727613a2f6bSGordon Ross 		err = EFAULT;
728613a2f6bSGordon Ross 		goto out;
7294bff34e3Sthurlow 	}
730*40c0e231SGordon Ross 	vcp->vc_work.wk_out_state = 0;
731613a2f6bSGordon Ross 
732*40c0e231SGordon Ross 	switch (cmd) {
733613a2f6bSGordon Ross 
734*40c0e231SGordon Ross 	case SMBIOC_IOD_CONNECT:
735*40c0e231SGordon Ross 		err = nsmb_iod_connect(vcp);
736*40c0e231SGordon Ross 		break;
737613a2f6bSGordon Ross 
738*40c0e231SGordon Ross 	case SMBIOC_IOD_NEGOTIATE:
739*40c0e231SGordon Ross 		err = nsmb_iod_negotiate(vcp, cr);
740*40c0e231SGordon Ross 		break;
741613a2f6bSGordon Ross 
742*40c0e231SGordon Ross 	case SMBIOC_IOD_SSNSETUP:
743*40c0e231SGordon Ross 		err = nsmb_iod_ssnsetup(vcp, cr);
744*40c0e231SGordon Ross 		break;
745*40c0e231SGordon Ross 
746*40c0e231SGordon Ross 	case SMBIOC_IOD_WORK:
747*40c0e231SGordon Ross 		err = smb_iod_vc_work(vcp, flags, cr);
748*40c0e231SGordon Ross 		break;
749*40c0e231SGordon Ross 
750*40c0e231SGordon Ross 	case SMBIOC_IOD_IDLE:
751*40c0e231SGordon Ross 		err = smb_iod_vc_idle(vcp);
752*40c0e231SGordon Ross 		break;
753*40c0e231SGordon Ross 
754*40c0e231SGordon Ross 	case SMBIOC_IOD_RCFAIL:
755*40c0e231SGordon Ross 		err = smb_iod_vc_rcfail(vcp);
756*40c0e231SGordon Ross 		break;
757*40c0e231SGordon Ross 
758*40c0e231SGordon Ross 	default:
759*40c0e231SGordon Ross 		err = ENOTTY;
760*40c0e231SGordon Ross 		break;
761613a2f6bSGordon Ross 	}
762613a2f6bSGordon Ross 
763*40c0e231SGordon Ross out:
764*40c0e231SGordon Ross 	vcp->vc_work.wk_out_state = vcp->vc_state;
765*40c0e231SGordon Ross 	(void) ddi_copyout(&vcp->vc_work, (void *)arg,
766*40c0e231SGordon Ross 	    sizeof (smbioc_ssn_work_t), flags);
767*40c0e231SGordon Ross 
768613a2f6bSGordon Ross 	/*
769613a2f6bSGordon Ross 	 * The IOD thread is leaving the driver.  Clear iod_thr,
770613a2f6bSGordon Ross 	 * and wake up anybody waiting for us to quit.
771613a2f6bSGordon Ross 	 */
772613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
773613a2f6bSGordon Ross 	vcp->iod_thr = NULL;
774613a2f6bSGordon Ross 	cv_broadcast(&vcp->vc_statechg);
775613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
776613a2f6bSGordon Ross 
777613a2f6bSGordon Ross 	return (err);
7784bff34e3Sthurlow }
7794bff34e3Sthurlow 
7804bff34e3Sthurlow int
781*40c0e231SGordon Ross smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
7824bff34e3Sthurlow {
783*40c0e231SGordon Ross 	int err;
784613a2f6bSGordon Ross 
785613a2f6bSGordon Ross 	/*
786*40c0e231SGordon Ross 	 * Serialize ioctl calls.  The smb_usr_... functions
787*40c0e231SGordon Ross 	 * don't expect concurrent calls on a given sdp.
788613a2f6bSGordon Ross 	 */
789*40c0e231SGordon Ross 	mutex_enter(&sdp->sd_lock);
790*40c0e231SGordon Ross 	if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
791*40c0e231SGordon Ross 		mutex_exit(&sdp->sd_lock);
792*40c0e231SGordon Ross 		return (EBUSY);
793*40c0e231SGordon Ross 	}
794*40c0e231SGordon Ross 	sdp->sd_flags |= NSMBFL_IOCTL;
795*40c0e231SGordon Ross 	mutex_exit(&sdp->sd_lock);
7964bff34e3Sthurlow 
797*40c0e231SGordon Ross 	err = 0;
7984bff34e3Sthurlow 	switch (cmd) {
799*40c0e231SGordon Ross 	case SMBIOC_GETVERS:
800*40c0e231SGordon Ross 		(void) ddi_copyout(&nsmb_version, (void *)arg,
801*40c0e231SGordon Ross 		    sizeof (nsmb_version), flags);
802*40c0e231SGordon Ross 		break;
803*40c0e231SGordon Ross 
804*40c0e231SGordon Ross 	case SMBIOC_GETSSNKEY:
805*40c0e231SGordon Ross 		err = smb_usr_get_ssnkey(sdp, arg, flags);
806*40c0e231SGordon Ross 		break;
807*40c0e231SGordon Ross 
808*40c0e231SGordon Ross 	case SMBIOC_DUP_DEV:
809*40c0e231SGordon Ross 		err = smb_usr_dup_dev(sdp, arg, flags);
810*40c0e231SGordon Ross 		break;
811*40c0e231SGordon Ross 
812*40c0e231SGordon Ross 	case SMBIOC_XACTNP:
813*40c0e231SGordon Ross 		err = smb_usr_xnp(sdp, arg, flags, cr);
814*40c0e231SGordon Ross 		break;
815*40c0e231SGordon Ross 
816*40c0e231SGordon Ross 	case SMBIOC_READ:
817*40c0e231SGordon Ross 	case SMBIOC_WRITE:
818*40c0e231SGordon Ross 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
819*40c0e231SGordon Ross 		break;
820*40c0e231SGordon Ross 
821*40c0e231SGordon Ross 	case SMBIOC_NTCREATE:
822*40c0e231SGordon Ross 		err = smb_usr_ntcreate(sdp, arg, flags, cr);
823*40c0e231SGordon Ross 		break;
824*40c0e231SGordon Ross 
825*40c0e231SGordon Ross 	case SMBIOC_PRINTJOB:
826*40c0e231SGordon Ross 		err = smb_usr_printjob(sdp, arg, flags, cr);
8274bff34e3Sthurlow 		break;
828613a2f6bSGordon Ross 
829*40c0e231SGordon Ross 	case SMBIOC_CLOSEFH:
830*40c0e231SGordon Ross 		err = smb_usr_closefh(sdp, cr);
831*40c0e231SGordon Ross 		break;
832*40c0e231SGordon Ross 
833*40c0e231SGordon Ross 	case SMBIOC_SSN_CREATE:
834*40c0e231SGordon Ross 	case SMBIOC_SSN_FIND:
835*40c0e231SGordon Ross 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
836*40c0e231SGordon Ross 		break;
837*40c0e231SGordon Ross 
838*40c0e231SGordon Ross 	case SMBIOC_SSN_KILL:
839*40c0e231SGordon Ross 	case SMBIOC_SSN_RELE:
840*40c0e231SGordon Ross 		err = smb_usr_drop_ssn(sdp, cmd);
841*40c0e231SGordon Ross 		break;
842*40c0e231SGordon Ross 
843*40c0e231SGordon Ross 	case SMBIOC_TREE_CONNECT:
844*40c0e231SGordon Ross 	case SMBIOC_TREE_FIND:
845*40c0e231SGordon Ross 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
846*40c0e231SGordon Ross 		break;
847*40c0e231SGordon Ross 
848*40c0e231SGordon Ross 	case SMBIOC_TREE_KILL:
849*40c0e231SGordon Ross 	case SMBIOC_TREE_RELE:
850*40c0e231SGordon Ross 		err = smb_usr_drop_tree(sdp, cmd);
851*40c0e231SGordon Ross 		break;
852*40c0e231SGordon Ross 
853*40c0e231SGordon Ross 	case SMBIOC_IOD_CONNECT:
854*40c0e231SGordon Ross 	case SMBIOC_IOD_NEGOTIATE:
855*40c0e231SGordon Ross 	case SMBIOC_IOD_SSNSETUP:
856*40c0e231SGordon Ross 	case SMBIOC_IOD_WORK:
857*40c0e231SGordon Ross 	case SMBIOC_IOD_IDLE:
858613a2f6bSGordon Ross 	case SMBIOC_IOD_RCFAIL:
859*40c0e231SGordon Ross 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
860*40c0e231SGordon Ross 		break;
861*40c0e231SGordon Ross 
862*40c0e231SGordon Ross 	case SMBIOC_PK_ADD:
863*40c0e231SGordon Ross 	case SMBIOC_PK_DEL:
864*40c0e231SGordon Ross 	case SMBIOC_PK_CHK:
865*40c0e231SGordon Ross 	case SMBIOC_PK_DEL_OWNER:
866*40c0e231SGordon Ross 	case SMBIOC_PK_DEL_EVERYONE:
867*40c0e231SGordon Ross 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
8684bff34e3Sthurlow 		break;
869613a2f6bSGordon Ross 
8704bff34e3Sthurlow 	default:
871613a2f6bSGordon Ross 		err = ENOTTY;
872*40c0e231SGordon Ross 		break;
8734bff34e3Sthurlow 	}
8744bff34e3Sthurlow 
875*40c0e231SGordon Ross 	mutex_enter(&sdp->sd_lock);
876*40c0e231SGordon Ross 	sdp->sd_flags &= ~NSMBFL_IOCTL;
877*40c0e231SGordon Ross 	mutex_exit(&sdp->sd_lock);
8784bff34e3Sthurlow 
879613a2f6bSGordon Ross 	return (err);
8804bff34e3Sthurlow }
881