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.
3840c0e231SGordon Ross  *
3940c0e231SGordon 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 
56*adee6784SGordon Ross #include <smb/winioctl.h>
574bff34e3Sthurlow #include <netsmb/smb.h>
584bff34e3Sthurlow #include <netsmb/smb_conn.h>
594bff34e3Sthurlow #include <netsmb/smb_rq.h>
604bff34e3Sthurlow #include <netsmb/smb_subr.h>
614bff34e3Sthurlow #include <netsmb/smb_dev.h>
624bff34e3Sthurlow 
63613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
64613a2f6bSGordon Ross 
654bff34e3Sthurlow /*
66613a2f6bSGordon Ross  * Ioctl function for SMBIOC_GETSSNKEY
67613a2f6bSGordon Ross  * Size copied out is SMBIOC_HASH_SZ.
68613a2f6bSGordon Ross  *
69613a2f6bSGordon Ross  * The RPC library needs this for encrypting things
70613a2f6bSGordon Ross  * like "set password" requests.  This is called
71613a2f6bSGordon Ross  * with an active RPC binding, so the connection
72613a2f6bSGordon Ross  * will already be active (but this checks).
734bff34e3Sthurlow  */
74613a2f6bSGordon Ross int
75613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
764bff34e3Sthurlow {
77613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
78613a2f6bSGordon Ross 
79613a2f6bSGordon Ross 	/* This ioctl requires an active session. */
80613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
81613a2f6bSGordon Ross 		return (ENOTCONN);
82613a2f6bSGordon Ross 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
83613a2f6bSGordon Ross 		return (ENOTCONN);
844bff34e3Sthurlow 
854bff34e3Sthurlow 	/*
86613a2f6bSGordon Ross 	 * Return the session key.
874bff34e3Sthurlow 	 */
8840c0e231SGordon Ross 	if (vcp->vc_ssnkey == NULL ||
8940c0e231SGordon Ross 	    vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
9040c0e231SGordon Ross 		return (EINVAL);
9140c0e231SGordon Ross 	if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
92613a2f6bSGordon Ross 	    SMBIOC_HASH_SZ, flags))
93613a2f6bSGordon Ross 		return (EFAULT);
94613a2f6bSGordon Ross 
95613a2f6bSGordon Ross 	return (0);
96613a2f6bSGordon Ross }
97613a2f6bSGordon Ross 
98613a2f6bSGordon Ross /*
9940c0e231SGordon Ross  * Ioctl function for SMBIOC_XACTNP (transact named pipe)
100613a2f6bSGordon Ross  */
101613a2f6bSGordon Ross int
10240c0e231SGordon Ross smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
1034bff34e3Sthurlow {
104613a2f6bSGordon Ross 	struct smb_cred scred;
105613a2f6bSGordon Ross 	struct smb_share *ssp;
106*adee6784SGordon Ross 	struct smb_fh *fhp;
10740c0e231SGordon Ross 	smbioc_xnp_t *ioc = NULL;
108*adee6784SGordon Ross 	struct mbchain send_mb;
109*adee6784SGordon Ross 	struct mdchain recv_md;
110*adee6784SGordon Ross 	uint32_t rdlen;
111*adee6784SGordon Ross 	int err, mbseg;
112613a2f6bSGordon Ross 
113*adee6784SGordon Ross 	/* This ioctl requires a file handle. */
114*adee6784SGordon Ross 	if ((fhp = sdp->sd_fh) == NULL)
115*adee6784SGordon Ross 		return (EINVAL);
116*adee6784SGordon Ross 	ssp = FHTOSS(fhp);
117*adee6784SGordon Ross 
118*adee6784SGordon Ross 	/* After reconnect, force close+reopen */
119*adee6784SGordon Ross 	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
120*adee6784SGordon Ross 		return (ESTALE);
121*adee6784SGordon Ross 
122*adee6784SGordon Ross 	bzero(&send_mb, sizeof (send_mb));
123*adee6784SGordon Ross 	bzero(&recv_md, sizeof (recv_md));
1244bff34e3Sthurlow 
125613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
126613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
127613a2f6bSGordon Ross 		err = EFAULT;
128613a2f6bSGordon Ross 		goto out;
1294bff34e3Sthurlow 	}
130613a2f6bSGordon Ross 
131430b4c46SGordon Ross 	/*
132*adee6784SGordon Ross 	 * Copyin the send data, into an mbchain,
133*adee6784SGordon Ross 	 * save output buffer size.
134430b4c46SGordon Ross 	 */
135*adee6784SGordon Ross 	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
136*adee6784SGordon Ross 	err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
137613a2f6bSGordon Ross 	if (err)
138613a2f6bSGordon Ross 		goto out;
139*adee6784SGordon Ross 	rdlen = ioc->ioc_rdlen;
140613a2f6bSGordon Ross 
141*adee6784SGordon Ross 	/*
142*adee6784SGordon Ross 	 * Run the SMB2 ioctl or SMB1 trans2
143*adee6784SGordon Ross 	 */
144*adee6784SGordon Ross 	smb_credinit(&scred, cr);
145*adee6784SGordon Ross 	if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
146*adee6784SGordon Ross 		err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
147*adee6784SGordon Ross 		    &send_mb, &recv_md, &rdlen,
148*adee6784SGordon Ross 		    FSCTL_PIPE_TRANSCEIVE, &scred);
149*adee6784SGordon Ross 	} else {
150*adee6784SGordon Ross 		err = smb_t2_xnp(ssp, fhp->fh_fid1,
151*adee6784SGordon Ross 		    &send_mb, &recv_md, &rdlen,
152*adee6784SGordon Ross 		    &ioc->ioc_more, &scred);
153*adee6784SGordon Ross 	}
154*adee6784SGordon Ross 	smb_credrele(&scred);
155613a2f6bSGordon Ross 
156613a2f6bSGordon Ross 	/* Copyout returned data. */
157*adee6784SGordon Ross 	if (err == 0 && recv_md.md_top != NULL) {
158*adee6784SGordon Ross 		/* User's buffer large enough for copyout? */
159*adee6784SGordon Ross 		size_t len = m_fixhdr(recv_md.md_top);
16040c0e231SGordon Ross 		if (len > ioc->ioc_rdlen) {
161613a2f6bSGordon Ross 			err = EMSGSIZE;
162613a2f6bSGordon Ross 			goto out;
163613a2f6bSGordon Ross 		}
164*adee6784SGordon Ross 		err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
165613a2f6bSGordon Ross 		if (err)
166613a2f6bSGordon Ross 			goto out;
167613a2f6bSGordon Ross 	} else
16840c0e231SGordon Ross 		ioc->ioc_rdlen = 0;
169613a2f6bSGordon Ross 
170*adee6784SGordon Ross 	/* Tell caller received length */
171*adee6784SGordon Ross 	if (rdlen <= ioc->ioc_rdlen) {
172*adee6784SGordon Ross 		/* Normal case */
173*adee6784SGordon Ross 		ioc->ioc_rdlen = rdlen;
174*adee6784SGordon Ross 	} else {
175*adee6784SGordon Ross 		/* Buffer overlow. Leave ioc_rdlen */
17640c0e231SGordon Ross 		ioc->ioc_more = 1;
177*adee6784SGordon Ross 	}
178613a2f6bSGordon Ross 
17902d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
180613a2f6bSGordon Ross 
181613a2f6bSGordon Ross out:
182430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
183613a2f6bSGordon Ross 
184613a2f6bSGordon Ross 	return (err);
1854bff34e3Sthurlow }
1864bff34e3Sthurlow 
187613a2f6bSGordon Ross /* helper for _t2request */
1884bff34e3Sthurlow static int
189613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
1904bff34e3Sthurlow {
191613a2f6bSGordon Ross 	int error;
192613a2f6bSGordon Ross 
193613a2f6bSGordon Ross 	if (len == 0)
194613a2f6bSGordon Ross 		return (0);
195613a2f6bSGordon Ross 	error = mb_init(mbp);
196613a2f6bSGordon Ross 	if (error)
197613a2f6bSGordon Ross 		return (error);
198613a2f6bSGordon Ross 	return (mb_put_mem(mbp, data, len, mbseg));
1994bff34e3Sthurlow }
2004bff34e3Sthurlow 
201613a2f6bSGordon Ross /*
202613a2f6bSGordon Ross  * Helper for nsmb_ioctl cases
203613a2f6bSGordon Ross  * SMBIOC_READ, SMBIOC_WRITE
204613a2f6bSGordon Ross  */
2051b34bc4aSbs int
206613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
2071b34bc4aSbs {
208613a2f6bSGordon Ross 	struct smb_cred scred;
209613a2f6bSGordon Ross 	struct smb_share *ssp;
210*adee6784SGordon Ross 	struct smb_fh *fhp;
211613a2f6bSGordon Ross 	smbioc_rw_t *ioc = NULL;
212613a2f6bSGordon Ross 	struct iovec aiov[1];
213613a2f6bSGordon Ross 	struct uio  auio;
214613a2f6bSGordon Ross 	int err;
215613a2f6bSGordon Ross 	uio_rw_t rw;
2161b34bc4aSbs 
217*adee6784SGordon Ross 	/* This ioctl requires a file handle. */
218*adee6784SGordon Ross 	if ((fhp = sdp->sd_fh) == NULL)
219*adee6784SGordon Ross 		return (EINVAL);
220*adee6784SGordon Ross 	ssp = FHTOSS(fhp);
221613a2f6bSGordon Ross 
222613a2f6bSGordon Ross 	/* After reconnect, force close+reopen */
223*adee6784SGordon Ross 	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
224613a2f6bSGordon Ross 		return (ESTALE);
225613a2f6bSGordon Ross 
226613a2f6bSGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
227613a2f6bSGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
228613a2f6bSGordon Ross 		err = EFAULT;
2291b34bc4aSbs 		goto out;
230613a2f6bSGordon Ross 	}
231613a2f6bSGordon Ross 
232613a2f6bSGordon Ross 	switch (cmd) {
233613a2f6bSGordon Ross 	case SMBIOC_READ:
234613a2f6bSGordon Ross 		rw = UIO_READ;
235613a2f6bSGordon Ross 		break;
236613a2f6bSGordon Ross 	case SMBIOC_WRITE:
237613a2f6bSGordon Ross 		rw = UIO_WRITE;
238613a2f6bSGordon Ross 		break;
239613a2f6bSGordon Ross 	default:
240613a2f6bSGordon Ross 		err = ENODEV;
241613a2f6bSGordon Ross 		goto out;
242613a2f6bSGordon Ross 	}
243613a2f6bSGordon Ross 
244613a2f6bSGordon Ross 	aiov[0].iov_base = ioc->ioc_base;
245613a2f6bSGordon Ross 	aiov[0].iov_len = (size_t)ioc->ioc_cnt;
246613a2f6bSGordon Ross 
247613a2f6bSGordon Ross 	auio.uio_iov = aiov;
248613a2f6bSGordon Ross 	auio.uio_iovcnt = 1;
249613a2f6bSGordon Ross 	auio.uio_loffset = ioc->ioc_offset;
250613a2f6bSGordon Ross 	auio.uio_segflg = (flags & FKIOCTL) ?
251613a2f6bSGordon Ross 	    UIO_SYSSPACE : UIO_USERSPACE;
252613a2f6bSGordon Ross 	auio.uio_fmode = 0;
253613a2f6bSGordon Ross 	auio.uio_resid = (size_t)ioc->ioc_cnt;
254613a2f6bSGordon Ross 
255*adee6784SGordon Ross 	smb_credinit(&scred, cr);
256*adee6784SGordon Ross 	err = smb_rwuio(fhp, rw, &auio, &scred, 0);
257*adee6784SGordon Ross 	smb_credrele(&scred);
258613a2f6bSGordon Ross 
259613a2f6bSGordon Ross 	/*
260613a2f6bSGordon Ross 	 * On return ioc_cnt holds the
261613a2f6bSGordon Ross 	 * number of bytes transferred.
262613a2f6bSGordon Ross 	 */
263613a2f6bSGordon Ross 	ioc->ioc_cnt -= auio.uio_resid;
264613a2f6bSGordon Ross 
26502d09e03SGordon Ross 	(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
266613a2f6bSGordon Ross 
2671b34bc4aSbs out:
268430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
269430b4c46SGordon Ross 
270430b4c46SGordon Ross 	return (err);
271430b4c46SGordon Ross }
272430b4c46SGordon Ross 
273430b4c46SGordon Ross /*
274430b4c46SGordon Ross  * Helper for nsmb_ioctl case
275430b4c46SGordon Ross  * SMBIOC_NTCREATE
276430b4c46SGordon Ross  */
277430b4c46SGordon Ross int
278430b4c46SGordon Ross smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
279430b4c46SGordon Ross {
280430b4c46SGordon Ross 	struct smb_cred scred;
281430b4c46SGordon Ross 	struct mbchain name_mb;
282430b4c46SGordon Ross 	struct smb_share *ssp;
283*adee6784SGordon Ross 	struct smb_fh *fhp = NULL;
284430b4c46SGordon Ross 	smbioc_ntcreate_t *ioc = NULL;
285430b4c46SGordon Ross 	int err, nmlen;
286430b4c46SGordon Ross 
287*adee6784SGordon Ross 	mb_init(&name_mb);
288*adee6784SGordon Ross 
289430b4c46SGordon Ross 	/* This ioctl requires a share. */
290430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
291430b4c46SGordon Ross 		return (ENOTCONN);
292430b4c46SGordon Ross 
293*adee6784SGordon Ross 	/* Must not already have a file handle. */
294*adee6784SGordon Ross 	if (sdp->sd_fh != NULL)
295430b4c46SGordon Ross 		return (EINVAL);
296430b4c46SGordon Ross 
297430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
298430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
299430b4c46SGordon Ross 		err = EFAULT;
300430b4c46SGordon Ross 		goto out;
301430b4c46SGordon Ross 	}
302430b4c46SGordon Ross 
303430b4c46SGordon Ross 	/* Build name_mb */
304430b4c46SGordon Ross 	ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
305430b4c46SGordon Ross 	nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
306430b4c46SGordon Ross 	err = smb_put_dmem(&name_mb, SSTOVC(ssp),
307430b4c46SGordon Ross 	    ioc->ioc_name, nmlen,
308430b4c46SGordon Ross 	    SMB_CS_NONE, NULL);
309430b4c46SGordon Ross 	if (err != 0)
310430b4c46SGordon Ross 		goto out;
311430b4c46SGordon Ross 
312*adee6784SGordon Ross 	err = smb_fh_create(ssp, &fhp);
313*adee6784SGordon Ross 	if (err != 0)
314*adee6784SGordon Ross 		goto out;
315*adee6784SGordon Ross 
316*adee6784SGordon Ross 	/*
317*adee6784SGordon Ross 	 * Do the OtW open, save the FID.
318*adee6784SGordon Ross 	 */
319*adee6784SGordon Ross 	smb_credinit(&scred, cr);
320430b4c46SGordon Ross 	err = smb_smb_ntcreate(ssp, &name_mb,
321430b4c46SGordon Ross 	    0,	/* create flags */
322430b4c46SGordon Ross 	    ioc->ioc_req_acc,
323430b4c46SGordon Ross 	    ioc->ioc_efattr,
324430b4c46SGordon Ross 	    ioc->ioc_share_acc,
325430b4c46SGordon Ross 	    ioc->ioc_open_disp,
326430b4c46SGordon Ross 	    ioc->ioc_creat_opts,
327430b4c46SGordon Ross 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
328430b4c46SGordon Ross 	    &scred,
329*adee6784SGordon Ross 	    fhp,
330430b4c46SGordon Ross 	    NULL,
331430b4c46SGordon Ross 	    NULL);
332*adee6784SGordon Ross 	smb_credrele(&scred);
333430b4c46SGordon Ross 	if (err != 0)
334430b4c46SGordon Ross 		goto out;
335430b4c46SGordon Ross 
336*adee6784SGordon Ross 	fhp->fh_rights = ioc->ioc_req_acc;
337*adee6784SGordon Ross 	smb_fh_opened(fhp);
338*adee6784SGordon Ross 	sdp->sd_fh = fhp;
339*adee6784SGordon Ross 	fhp = NULL;
340430b4c46SGordon Ross 
341430b4c46SGordon Ross out:
342*adee6784SGordon Ross 	if (fhp != NULL)
343*adee6784SGordon Ross 		smb_fh_rele(fhp);
344430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
345430b4c46SGordon Ross 	mb_done(&name_mb);
346430b4c46SGordon Ross 
347430b4c46SGordon Ross 	return (err);
348430b4c46SGordon Ross }
349430b4c46SGordon Ross 
350430b4c46SGordon Ross /*
351430b4c46SGordon Ross  * Helper for nsmb_ioctl case
352430b4c46SGordon Ross  * SMBIOC_PRINTJOB
353430b4c46SGordon Ross  */
354430b4c46SGordon Ross int
355430b4c46SGordon Ross smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
356430b4c46SGordon Ross {
357*adee6784SGordon Ross 	static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
358430b4c46SGordon Ross 	struct smb_cred scred;
359*adee6784SGordon Ross 	struct mbchain name_mb;
360430b4c46SGordon Ross 	struct smb_share *ssp;
361*adee6784SGordon Ross 	struct smb_fh *fhp = NULL;
362430b4c46SGordon Ross 	smbioc_printjob_t *ioc = NULL;
363*adee6784SGordon Ross 	int err, cklen, nmlen;
364*adee6784SGordon Ross 	uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
365*adee6784SGordon Ross 	    SA_RIGHT_FILE_READ_ATTRIBUTES;
366*adee6784SGordon Ross 
367*adee6784SGordon Ross 	mb_init(&name_mb);
368430b4c46SGordon Ross 
369430b4c46SGordon Ross 	/* This ioctl requires a share. */
370430b4c46SGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
371430b4c46SGordon Ross 		return (ENOTCONN);
372430b4c46SGordon Ross 
373430b4c46SGordon Ross 	/* The share must be a print queue. */
374430b4c46SGordon Ross 	if (ssp->ss_type != STYPE_PRINTQ)
375430b4c46SGordon Ross 		return (EINVAL);
376430b4c46SGordon Ross 
377*adee6784SGordon Ross 	/* Must not already have a file handle. */
378*adee6784SGordon Ross 	if (sdp->sd_fh != NULL)
379430b4c46SGordon Ross 		return (EINVAL);
380430b4c46SGordon Ross 
381430b4c46SGordon Ross 	smb_credinit(&scred, cr);
382430b4c46SGordon Ross 	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
383430b4c46SGordon Ross 	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
384430b4c46SGordon Ross 		err = EFAULT;
385430b4c46SGordon Ross 		goto out;
386430b4c46SGordon Ross 	}
387*adee6784SGordon Ross 
388*adee6784SGordon Ross 	/*
389*adee6784SGordon Ross 	 * Use the print job title as the file name to open, but
390*adee6784SGordon Ross 	 * check for invalid characters first.  See the notes in
391*adee6784SGordon Ross 	 * libsmbfs/smb/print.c about job name sanitizing.
392*adee6784SGordon Ross 	 */
393430b4c46SGordon Ross 	ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
394*adee6784SGordon Ross 	nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
395*adee6784SGordon Ross 	cklen = strcspn(ioc->ioc_title, invalid_chars);
396*adee6784SGordon Ross 	if (cklen < nmlen) {
397*adee6784SGordon Ross 		err = EINVAL;
398*adee6784SGordon Ross 		goto out;
399*adee6784SGordon Ross 	}
400430b4c46SGordon Ross 
401*adee6784SGordon Ross 	/* Build name_mb */
402*adee6784SGordon Ross 	err = smb_put_dmem(&name_mb, SSTOVC(ssp),
403*adee6784SGordon Ross 	    ioc->ioc_title, nmlen,
404*adee6784SGordon Ross 	    SMB_CS_NONE, NULL);
405430b4c46SGordon Ross 	if (err != 0)
406430b4c46SGordon Ross 		goto out;
407430b4c46SGordon Ross 
408*adee6784SGordon Ross 	err = smb_fh_create(ssp, &fhp);
409*adee6784SGordon Ross 	if (err != 0)
410*adee6784SGordon Ross 		goto out;
411*adee6784SGordon Ross 
412*adee6784SGordon Ross 	/*
413*adee6784SGordon Ross 	 * Do the OtW open, save the FID.
414*adee6784SGordon Ross 	 */
415*adee6784SGordon Ross 	smb_credinit(&scred, cr);
416*adee6784SGordon Ross 	if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
417*adee6784SGordon Ross 		err = smb2_smb_ntcreate(ssp, &name_mb,
418*adee6784SGordon Ross 		    NULL, NULL, /* cctx in, out */
419*adee6784SGordon Ross 		    0,	/* create flags */
420*adee6784SGordon Ross 		    access,
421*adee6784SGordon Ross 		    SMB_EFA_NORMAL,
422*adee6784SGordon Ross 		    NTCREATEX_SHARE_ACCESS_NONE,
423*adee6784SGordon Ross 		    NTCREATEX_DISP_CREATE,
424*adee6784SGordon Ross 		    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
425*adee6784SGordon Ross 		    NTCREATEX_IMPERSONATION_IMPERSONATION,
426*adee6784SGordon Ross 		    &scred,
427*adee6784SGordon Ross 		    &fhp->fh_fid2,
428*adee6784SGordon Ross 		    NULL,
429*adee6784SGordon Ross 		    NULL);
430*adee6784SGordon Ross 	} else {
431*adee6784SGordon Ross 		err = smb_smb_open_prjob(ssp, ioc->ioc_title,
432*adee6784SGordon Ross 		    ioc->ioc_setuplen, ioc->ioc_prmode,
433*adee6784SGordon Ross 		    &scred, &fhp->fh_fid1);
434*adee6784SGordon Ross 	}
435*adee6784SGordon Ross 	smb_credrele(&scred);
436*adee6784SGordon Ross 	if (err != 0)
437*adee6784SGordon Ross 		goto out;
438*adee6784SGordon Ross 
439*adee6784SGordon Ross 	fhp->fh_rights = access;
440*adee6784SGordon Ross 	smb_fh_opened(fhp);
441*adee6784SGordon Ross 	sdp->sd_fh = fhp;
442*adee6784SGordon Ross 	fhp = NULL;
443430b4c46SGordon Ross 
444430b4c46SGordon Ross out:
445*adee6784SGordon Ross 	if (fhp != NULL)
446*adee6784SGordon Ross 		smb_fh_rele(fhp);
447430b4c46SGordon Ross 	kmem_free(ioc, sizeof (*ioc));
448*adee6784SGordon Ross 	mb_done(&name_mb);
449430b4c46SGordon Ross 
450430b4c46SGordon Ross 	return (err);
451430b4c46SGordon Ross }
452430b4c46SGordon Ross 
453430b4c46SGordon Ross /*
454430b4c46SGordon Ross  * Helper for nsmb_ioctl case
455430b4c46SGordon Ross  * SMBIOC_CLOSEFH
456430b4c46SGordon Ross  */
457*adee6784SGordon Ross /*ARGSUSED*/
458430b4c46SGordon Ross int
459430b4c46SGordon Ross smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
460430b4c46SGordon Ross {
461*adee6784SGordon Ross 	struct smb_fh *fhp;
462430b4c46SGordon Ross 
463*adee6784SGordon Ross 	/* This ioctl requires a file handle. */
464*adee6784SGordon Ross 	if ((fhp = sdp->sd_fh) == NULL)
465*adee6784SGordon Ross 		return (EINVAL);
466*adee6784SGordon Ross 	sdp->sd_fh = NULL;
467430b4c46SGordon Ross 
468*adee6784SGordon Ross 	smb_fh_close(fhp);
469*adee6784SGordon Ross 	smb_fh_rele(fhp);
470613a2f6bSGordon Ross 
471*adee6784SGordon Ross 	return (0);
4721b34bc4aSbs }
4731b34bc4aSbs 
474613a2f6bSGordon Ross /*
475613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
476613a2f6bSGordon Ross  * Find or create a session (a.k.a. "VC" in here)
477613a2f6bSGordon Ross  */
4784bff34e3Sthurlow int
479613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
4804bff34e3Sthurlow {
481613a2f6bSGordon Ross 	struct smb_cred scred;
482613a2f6bSGordon Ross 	smbioc_ossn_t *ossn = NULL;
4834bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
4844bff34e3Sthurlow 	int error = 0;
485613a2f6bSGordon Ross 	uid_t realuid;
4864bff34e3Sthurlow 
487613a2f6bSGordon Ross 	/* Should be no VC */
488613a2f6bSGordon Ross 	if (sdp->sd_vc != NULL)
489613a2f6bSGordon Ross 		return (EISCONN);
490613a2f6bSGordon Ross 
491613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
492613a2f6bSGordon Ross 	ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
493613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
494613a2f6bSGordon Ross 		error = EFAULT;
495613a2f6bSGordon Ross 		goto out;
4964bff34e3Sthurlow 	}
497613a2f6bSGordon Ross 
498613a2f6bSGordon Ross 	/*
499613a2f6bSGordon Ross 	 * Only superuser can specify a UID or GID.
500613a2f6bSGordon Ross 	 */
501613a2f6bSGordon Ross 	realuid = crgetruid(cr);
502613a2f6bSGordon Ross 	if (ossn->ssn_owner == SMBM_ANY_OWNER)
503613a2f6bSGordon Ross 		ossn->ssn_owner = realuid;
504613a2f6bSGordon Ross 	else {
5054bff34e3Sthurlow 		/*
506613a2f6bSGordon Ross 		 * Do we have the privilege to create with the
507613a2f6bSGordon Ross 		 * specified uid?  (does uid == cr->cr_uid, etc.)
5084bff34e3Sthurlow 		 */
509613a2f6bSGordon Ross 		if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
510613a2f6bSGordon Ross 			error = EPERM;
511613a2f6bSGordon Ross 			goto out;
5124bff34e3Sthurlow 		}
513613a2f6bSGordon Ross 		/* ossn->ssn_owner is OK */
5144bff34e3Sthurlow 	}
5154bff34e3Sthurlow 
516613a2f6bSGordon Ross 	/*
517613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
518613a2f6bSGordon Ross 	 */
519613a2f6bSGordon Ross 	ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
520613a2f6bSGordon Ross 	ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
521613a2f6bSGordon Ross 	ossn->ssn_id.id_user[   SMBIOC_MAX_NAME-1] = '\0';
5224bff34e3Sthurlow 
523613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE)
524613a2f6bSGordon Ross 		ossn->ssn_vopt |= SMBVOPT_CREATE;
525613a2f6bSGordon Ross 	else /* FIND */
526613a2f6bSGordon Ross 		ossn->ssn_vopt &= ~SMBVOPT_CREATE;
5274bff34e3Sthurlow 
528613a2f6bSGordon Ross 	error = smb_vc_findcreate(ossn, &scred, &vcp);
5294bff34e3Sthurlow 	if (error)
5304bff34e3Sthurlow 		goto out;
531613a2f6bSGordon Ross 	ASSERT(vcp != NULL);
5324bff34e3Sthurlow 
5334bff34e3Sthurlow 	/*
534613a2f6bSGordon Ross 	 * We have a VC, held, but not locked.
535613a2f6bSGordon Ross 	 * If we're creating, mark this instance as
536613a2f6bSGordon Ross 	 * an open from IOD so close can do cleanup.
537613a2f6bSGordon Ross 	 *
538613a2f6bSGordon Ross 	 * XXX: Would be nice to have a back pointer
539613a2f6bSGordon Ross 	 * from the VC to this (IOD) sdp instance.
5404bff34e3Sthurlow 	 */
541613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_CREATE) {
542613a2f6bSGordon Ross 		if (vcp->iod_thr != NULL) {
543613a2f6bSGordon Ross 			error = EEXIST;
544613a2f6bSGordon Ross 			goto out;
545613a2f6bSGordon Ross 		}
546613a2f6bSGordon Ross 		sdp->sd_flags |= NSMBFL_IOD;
547613a2f6bSGordon Ross 	} else {
548613a2f6bSGordon Ross 		/*
549613a2f6bSGordon Ross 		 * Wait for it to finish connecting
550613a2f6bSGordon Ross 		 * (or reconnect) if necessary.
551613a2f6bSGordon Ross 		 */
552613a2f6bSGordon Ross 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
553613a2f6bSGordon Ross 			error = smb_iod_reconnect(vcp);
554613a2f6bSGordon Ross 			if (error != 0)
555613a2f6bSGordon Ross 				goto out;
556613a2f6bSGordon Ross 		}
557613a2f6bSGordon Ross 	}
558613a2f6bSGordon Ross 
559613a2f6bSGordon Ross 	/*
560613a2f6bSGordon Ross 	 * The VC has a hold from _findvc
561613a2f6bSGordon Ross 	 * which we keep until _SSN_RELE
562613a2f6bSGordon Ross 	 * or nsmb_close().
563613a2f6bSGordon Ross 	 */
564613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
565613a2f6bSGordon Ross 	sdp->sd_vc = vcp;
566613a2f6bSGordon Ross 	vcp = NULL;
567613a2f6bSGordon Ross 	(void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
5684bff34e3Sthurlow 
5694bff34e3Sthurlow out:
570613a2f6bSGordon Ross 	if (vcp) {
571613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
572613a2f6bSGordon Ross 		smb_vc_rele(vcp);
573613a2f6bSGordon Ross 	}
574430b4c46SGordon Ross 	kmem_free(ossn, sizeof (*ossn));
575613a2f6bSGordon Ross 	smb_credrele(&scred);
576613a2f6bSGordon Ross 
5774bff34e3Sthurlow 	return (error);
5784bff34e3Sthurlow }
5794bff34e3Sthurlow 
580613a2f6bSGordon Ross /*
581613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
582613a2f6bSGordon Ross  * Release or kill the current session.
583613a2f6bSGordon Ross  */
5844bff34e3Sthurlow int
585613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
5864bff34e3Sthurlow {
587613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
5884bff34e3Sthurlow 
589613a2f6bSGordon Ross 	/* Must have a VC. */
590613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
591613a2f6bSGordon Ross 		return (ENOTCONN);
5924bff34e3Sthurlow 
593613a2f6bSGordon Ross 	/* If we have a share ref, drop it too. */
594613a2f6bSGordon Ross 	if (sdp->sd_share) {
595613a2f6bSGordon Ross 		smb_share_rele(sdp->sd_share);
596613a2f6bSGordon Ross 		sdp->sd_share = NULL;
597613a2f6bSGordon Ross 		sdp->sd_level = SMBL_VC;
5984bff34e3Sthurlow 	}
5994bff34e3Sthurlow 
600613a2f6bSGordon Ross 	if (cmd == SMBIOC_SSN_KILL)
601613a2f6bSGordon Ross 		smb_vc_kill(vcp);
6024bff34e3Sthurlow 
603613a2f6bSGordon Ross 	/* Drop the VC ref. */
604613a2f6bSGordon Ross 	smb_vc_rele(vcp);
605613a2f6bSGordon Ross 	sdp->sd_vc = NULL;
606613a2f6bSGordon Ross 	sdp->sd_level = 0;
607613a2f6bSGordon Ross 
608613a2f6bSGordon Ross 	return (0);
6094bff34e3Sthurlow }
6104bff34e3Sthurlow 
6114bff34e3Sthurlow /*
612613a2f6bSGordon Ross  * Find or create a tree (connected share)
6134bff34e3Sthurlow  */
6144bff34e3Sthurlow int
615613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
6164bff34e3Sthurlow {
617613a2f6bSGordon Ross 	struct smb_cred scred;
618613a2f6bSGordon Ross 	smbioc_tcon_t *tcon = NULL;
619613a2f6bSGordon Ross 	struct smb_vc *vcp = NULL;
620613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
621613a2f6bSGordon Ross 	int error = 0;
6224bff34e3Sthurlow 
623613a2f6bSGordon Ross 	/* Must have a VC. */
624613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
625613a2f6bSGordon Ross 		return (ENOTCONN);
626613a2f6bSGordon Ross 	/* Should not have a share. */
627613a2f6bSGordon Ross 	if (sdp->sd_share != NULL)
628613a2f6bSGordon Ross 		return (EISCONN);
629613a2f6bSGordon Ross 
630613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
631613a2f6bSGordon Ross 	tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
632613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
633613a2f6bSGordon Ross 		error = EFAULT;
634613a2f6bSGordon Ross 		goto out;
6354bff34e3Sthurlow 	}
636613a2f6bSGordon Ross 
637613a2f6bSGordon Ross 	/*
638613a2f6bSGordon Ross 	 * Make sure the strings are null terminated.
639613a2f6bSGordon Ross 	 */
640613a2f6bSGordon Ross 	tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
641613a2f6bSGordon Ross 	tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
642613a2f6bSGordon Ross 
643613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT)
644613a2f6bSGordon Ross 		tcon->tc_opt |= SMBSOPT_CREATE;
645613a2f6bSGordon Ross 	else /* FIND */
646613a2f6bSGordon Ross 		tcon->tc_opt &= ~SMBSOPT_CREATE;
647613a2f6bSGordon Ross 
648613a2f6bSGordon Ross 	error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
6494bff34e3Sthurlow 	if (error)
650613a2f6bSGordon Ross 		goto out;
651613a2f6bSGordon Ross 	ASSERT(ssp != NULL);
652613a2f6bSGordon Ross 
653613a2f6bSGordon Ross 	/*
654613a2f6bSGordon Ross 	 * We have a share, held, but not locked.
655613a2f6bSGordon Ross 	 * If we're creating, do tree connect now,
656613a2f6bSGordon Ross 	 * otherwise let that wait for a request.
657613a2f6bSGordon Ross 	 */
658613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_CONNECT) {
659613a2f6bSGordon Ross 		error = smb_share_tcon(ssp, &scred);
660613a2f6bSGordon Ross 		if (error)
661613a2f6bSGordon Ross 			goto out;
6624bff34e3Sthurlow 	}
663613a2f6bSGordon Ross 
664613a2f6bSGordon Ross 	/*
665613a2f6bSGordon Ross 	 * Give caller the real share type from
666613a2f6bSGordon Ross 	 * the tree connect response, so they can
667613a2f6bSGordon Ross 	 * see if they got the requested type.
668613a2f6bSGordon Ross 	 */
669430b4c46SGordon Ross 	tcon->tc_sh.sh_type = ssp->ss_type;
670613a2f6bSGordon Ross 
671613a2f6bSGordon Ross 	/*
672613a2f6bSGordon Ross 	 * The share has a hold from _tcon
673613a2f6bSGordon Ross 	 * which we keep until nsmb_close()
674613a2f6bSGordon Ross 	 * or the SMBIOC_TDIS below.
675613a2f6bSGordon Ross 	 */
676613a2f6bSGordon Ross 	sdp->sd_level = SMBL_SHARE;
677613a2f6bSGordon Ross 	sdp->sd_share = ssp;
678613a2f6bSGordon Ross 	ssp = NULL;
679613a2f6bSGordon Ross 	(void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
680613a2f6bSGordon Ross 
681613a2f6bSGordon Ross out:
682613a2f6bSGordon Ross 	if (ssp) {
683613a2f6bSGordon Ross 		/* Error path: rele hold from _findcreate */
684613a2f6bSGordon Ross 		smb_share_rele(ssp);
6854bff34e3Sthurlow 	}
686430b4c46SGordon Ross 	/*
687430b4c46SGordon Ross 	 * This structure may contain a
688430b4c46SGordon Ross 	 * cleartext password, so zap it.
689430b4c46SGordon Ross 	 */
690430b4c46SGordon Ross 	bzero(tcon, sizeof (*tcon));
691430b4c46SGordon Ross 	kmem_free(tcon, sizeof (*tcon));
692613a2f6bSGordon Ross 	smb_credrele(&scred);
6934bff34e3Sthurlow 
694613a2f6bSGordon Ross 	return (error);
6954bff34e3Sthurlow }
6964bff34e3Sthurlow 
697613a2f6bSGordon Ross /*
698613a2f6bSGordon Ross  * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
699613a2f6bSGordon Ross  * Release or kill the current tree
700613a2f6bSGordon Ross  */
701613a2f6bSGordon Ross int
702613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
7034bff34e3Sthurlow {
704613a2f6bSGordon Ross 	struct smb_share *ssp = NULL;
7054bff34e3Sthurlow 
706613a2f6bSGordon Ross 	/* Must have a VC and a share. */
707613a2f6bSGordon Ross 	if (sdp->sd_vc == NULL)
708613a2f6bSGordon Ross 		return (ENOTCONN);
709613a2f6bSGordon Ross 	if ((ssp = sdp->sd_share) == NULL)
710613a2f6bSGordon Ross 		return (ENOTCONN);
711613a2f6bSGordon Ross 
712613a2f6bSGordon Ross 	if (cmd == SMBIOC_TREE_KILL)
713613a2f6bSGordon Ross 		smb_share_kill(ssp);
714613a2f6bSGordon Ross 
715613a2f6bSGordon Ross 	/* Drop the share ref. */
716613a2f6bSGordon Ross 	smb_share_rele(sdp->sd_share);
717613a2f6bSGordon Ross 	sdp->sd_share = NULL;
718613a2f6bSGordon Ross 	sdp->sd_level = SMBL_VC;
719613a2f6bSGordon Ross 
720613a2f6bSGordon Ross 	return (0);
7214bff34e3Sthurlow }
7224bff34e3Sthurlow 
723613a2f6bSGordon Ross /*
72440c0e231SGordon Ross  * Ioctl handler for all SMBIOC_IOD_...
725613a2f6bSGordon Ross  */
7264bff34e3Sthurlow int
72740c0e231SGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
7284bff34e3Sthurlow {
72940c0e231SGordon Ross 	struct smb_vc *vcp;
730613a2f6bSGordon Ross 	int err = 0;
7314bff34e3Sthurlow 
73240c0e231SGordon Ross 	/* Must be the IOD. */
73340c0e231SGordon Ross 	if ((sdp->sd_flags & NSMBFL_IOD) == 0)
73440c0e231SGordon Ross 		return (EINVAL);
73540c0e231SGordon Ross 	/* Must have a VC and no share. */
736613a2f6bSGordon Ross 	if ((vcp = sdp->sd_vc) == NULL)
7374bff34e3Sthurlow 		return (EINVAL);
73840c0e231SGordon Ross 	if (sdp->sd_share != NULL)
739613a2f6bSGordon Ross 		return (EINVAL);
740613a2f6bSGordon Ross 
741613a2f6bSGordon Ross 	/*
742613a2f6bSGordon Ross 	 * Is there already an IOD for this VC?
743613a2f6bSGordon Ross 	 * (Should never happen.)
744613a2f6bSGordon Ross 	 */
745613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
746613a2f6bSGordon Ross 	if (vcp->iod_thr == NULL)
747613a2f6bSGordon Ross 		vcp->iod_thr = curthread;
748613a2f6bSGordon Ross 	else
749613a2f6bSGordon Ross 		err = EEXIST;
750613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
751613a2f6bSGordon Ross 	if (err)
752613a2f6bSGordon Ross 		return (err);
753613a2f6bSGordon Ross 
754613a2f6bSGordon Ross 	/*
75540c0e231SGordon Ross 	 * Copy the "work" state, etc. into the VC,
75640c0e231SGordon Ross 	 * and back to the caller on the way out.
75740c0e231SGordon Ross 	 * Clear the "out only" part.
758613a2f6bSGordon Ross 	 */
759613a2f6bSGordon Ross 	if (ddi_copyin((void *)arg, &vcp->vc_work,
760613a2f6bSGordon Ross 	    sizeof (smbioc_ssn_work_t), flags)) {
761613a2f6bSGordon Ross 		err = EFAULT;
762613a2f6bSGordon Ross 		goto out;
7634bff34e3Sthurlow 	}
76440c0e231SGordon Ross 	vcp->vc_work.wk_out_state = 0;
765613a2f6bSGordon Ross 
76640c0e231SGordon Ross 	switch (cmd) {
767613a2f6bSGordon Ross 
76840c0e231SGordon Ross 	case SMBIOC_IOD_CONNECT:
769*adee6784SGordon Ross 		err = nsmb_iod_connect(vcp, cr);
77040c0e231SGordon Ross 		break;
771613a2f6bSGordon Ross 
77240c0e231SGordon Ross 	case SMBIOC_IOD_NEGOTIATE:
77340c0e231SGordon Ross 		err = nsmb_iod_negotiate(vcp, cr);
77440c0e231SGordon Ross 		break;
775613a2f6bSGordon Ross 
77640c0e231SGordon Ross 	case SMBIOC_IOD_SSNSETUP:
77740c0e231SGordon Ross 		err = nsmb_iod_ssnsetup(vcp, cr);
77840c0e231SGordon Ross 		break;
77940c0e231SGordon Ross 
78040c0e231SGordon Ross 	case SMBIOC_IOD_WORK:
78140c0e231SGordon Ross 		err = smb_iod_vc_work(vcp, flags, cr);
78240c0e231SGordon Ross 		break;
78340c0e231SGordon Ross 
78440c0e231SGordon Ross 	case SMBIOC_IOD_IDLE:
78540c0e231SGordon Ross 		err = smb_iod_vc_idle(vcp);
78640c0e231SGordon Ross 		break;
78740c0e231SGordon Ross 
78840c0e231SGordon Ross 	case SMBIOC_IOD_RCFAIL:
78940c0e231SGordon Ross 		err = smb_iod_vc_rcfail(vcp);
79040c0e231SGordon Ross 		break;
79140c0e231SGordon Ross 
79240c0e231SGordon Ross 	default:
79340c0e231SGordon Ross 		err = ENOTTY;
79440c0e231SGordon Ross 		break;
795613a2f6bSGordon Ross 	}
796613a2f6bSGordon Ross 
79740c0e231SGordon Ross out:
79840c0e231SGordon Ross 	vcp->vc_work.wk_out_state = vcp->vc_state;
79940c0e231SGordon Ross 	(void) ddi_copyout(&vcp->vc_work, (void *)arg,
80040c0e231SGordon Ross 	    sizeof (smbioc_ssn_work_t), flags);
80140c0e231SGordon Ross 
802613a2f6bSGordon Ross 	/*
803613a2f6bSGordon Ross 	 * The IOD thread is leaving the driver.  Clear iod_thr,
804613a2f6bSGordon Ross 	 * and wake up anybody waiting for us to quit.
805613a2f6bSGordon Ross 	 */
806613a2f6bSGordon Ross 	SMB_VC_LOCK(vcp);
807613a2f6bSGordon Ross 	vcp->iod_thr = NULL;
808613a2f6bSGordon Ross 	cv_broadcast(&vcp->vc_statechg);
809613a2f6bSGordon Ross 	SMB_VC_UNLOCK(vcp);
810613a2f6bSGordon Ross 
811613a2f6bSGordon Ross 	return (err);
8124bff34e3Sthurlow }
8134bff34e3Sthurlow 
8144bff34e3Sthurlow int
81540c0e231SGordon Ross smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
8164bff34e3Sthurlow {
81740c0e231SGordon Ross 	int err;
818613a2f6bSGordon Ross 
819613a2f6bSGordon Ross 	/*
82040c0e231SGordon Ross 	 * Serialize ioctl calls.  The smb_usr_... functions
82140c0e231SGordon Ross 	 * don't expect concurrent calls on a given sdp.
822613a2f6bSGordon Ross 	 */
82340c0e231SGordon Ross 	mutex_enter(&sdp->sd_lock);
82440c0e231SGordon Ross 	if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
82540c0e231SGordon Ross 		mutex_exit(&sdp->sd_lock);
82640c0e231SGordon Ross 		return (EBUSY);
82740c0e231SGordon Ross 	}
82840c0e231SGordon Ross 	sdp->sd_flags |= NSMBFL_IOCTL;
82940c0e231SGordon Ross 	mutex_exit(&sdp->sd_lock);
8304bff34e3Sthurlow 
83140c0e231SGordon Ross 	err = 0;
8324bff34e3Sthurlow 	switch (cmd) {
83340c0e231SGordon Ross 	case SMBIOC_GETVERS:
83440c0e231SGordon Ross 		(void) ddi_copyout(&nsmb_version, (void *)arg,
83540c0e231SGordon Ross 		    sizeof (nsmb_version), flags);
83640c0e231SGordon Ross 		break;
83740c0e231SGordon Ross 
83840c0e231SGordon Ross 	case SMBIOC_GETSSNKEY:
83940c0e231SGordon Ross 		err = smb_usr_get_ssnkey(sdp, arg, flags);
84040c0e231SGordon Ross 		break;
84140c0e231SGordon Ross 
84240c0e231SGordon Ross 	case SMBIOC_DUP_DEV:
84340c0e231SGordon Ross 		err = smb_usr_dup_dev(sdp, arg, flags);
84440c0e231SGordon Ross 		break;
84540c0e231SGordon Ross 
84640c0e231SGordon Ross 	case SMBIOC_XACTNP:
84740c0e231SGordon Ross 		err = smb_usr_xnp(sdp, arg, flags, cr);
84840c0e231SGordon Ross 		break;
84940c0e231SGordon Ross 
85040c0e231SGordon Ross 	case SMBIOC_READ:
85140c0e231SGordon Ross 	case SMBIOC_WRITE:
85240c0e231SGordon Ross 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
85340c0e231SGordon Ross 		break;
85440c0e231SGordon Ross 
85540c0e231SGordon Ross 	case SMBIOC_NTCREATE:
85640c0e231SGordon Ross 		err = smb_usr_ntcreate(sdp, arg, flags, cr);
85740c0e231SGordon Ross 		break;
85840c0e231SGordon Ross 
85940c0e231SGordon Ross 	case SMBIOC_PRINTJOB:
86040c0e231SGordon Ross 		err = smb_usr_printjob(sdp, arg, flags, cr);
8614bff34e3Sthurlow 		break;
862613a2f6bSGordon Ross 
86340c0e231SGordon Ross 	case SMBIOC_CLOSEFH:
86440c0e231SGordon Ross 		err = smb_usr_closefh(sdp, cr);
86540c0e231SGordon Ross 		break;
86640c0e231SGordon Ross 
86740c0e231SGordon Ross 	case SMBIOC_SSN_CREATE:
86840c0e231SGordon Ross 	case SMBIOC_SSN_FIND:
86940c0e231SGordon Ross 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
87040c0e231SGordon Ross 		break;
87140c0e231SGordon Ross 
87240c0e231SGordon Ross 	case SMBIOC_SSN_KILL:
87340c0e231SGordon Ross 	case SMBIOC_SSN_RELE:
87440c0e231SGordon Ross 		err = smb_usr_drop_ssn(sdp, cmd);
87540c0e231SGordon Ross 		break;
87640c0e231SGordon Ross 
87740c0e231SGordon Ross 	case SMBIOC_TREE_CONNECT:
87840c0e231SGordon Ross 	case SMBIOC_TREE_FIND:
87940c0e231SGordon Ross 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
88040c0e231SGordon Ross 		break;
88140c0e231SGordon Ross 
88240c0e231SGordon Ross 	case SMBIOC_TREE_KILL:
88340c0e231SGordon Ross 	case SMBIOC_TREE_RELE:
88440c0e231SGordon Ross 		err = smb_usr_drop_tree(sdp, cmd);
88540c0e231SGordon Ross 		break;
88640c0e231SGordon Ross 
88740c0e231SGordon Ross 	case SMBIOC_IOD_CONNECT:
88840c0e231SGordon Ross 	case SMBIOC_IOD_NEGOTIATE:
88940c0e231SGordon Ross 	case SMBIOC_IOD_SSNSETUP:
89040c0e231SGordon Ross 	case SMBIOC_IOD_WORK:
89140c0e231SGordon Ross 	case SMBIOC_IOD_IDLE:
892613a2f6bSGordon Ross 	case SMBIOC_IOD_RCFAIL:
89340c0e231SGordon Ross 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
89440c0e231SGordon Ross 		break;
89540c0e231SGordon Ross 
89640c0e231SGordon Ross 	case SMBIOC_PK_ADD:
89740c0e231SGordon Ross 	case SMBIOC_PK_DEL:
89840c0e231SGordon Ross 	case SMBIOC_PK_CHK:
89940c0e231SGordon Ross 	case SMBIOC_PK_DEL_OWNER:
90040c0e231SGordon Ross 	case SMBIOC_PK_DEL_EVERYONE:
90140c0e231SGordon Ross 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
9024bff34e3Sthurlow 		break;
903613a2f6bSGordon Ross 
9044bff34e3Sthurlow 	default:
905613a2f6bSGordon Ross 		err = ENOTTY;
90640c0e231SGordon Ross 		break;
9074bff34e3Sthurlow 	}
9084bff34e3Sthurlow 
90940c0e231SGordon Ross 	mutex_enter(&sdp->sd_lock);
91040c0e231SGordon Ross 	sdp->sd_flags &= ~NSMBFL_IOCTL;
91140c0e231SGordon Ross 	mutex_exit(&sdp->sd_lock);
9124bff34e3Sthurlow 
913613a2f6bSGordon Ross 	return (err);
9144bff34e3Sthurlow }
915