1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
3*4bff34e3Sthurlow  * All rights reserved.
4*4bff34e3Sthurlow  *
5*4bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
6*4bff34e3Sthurlow  * modification, are permitted provided that the following conditions
7*4bff34e3Sthurlow  * are met:
8*4bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*4bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*4bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
13*4bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*4bff34e3Sthurlow  *    must display the following acknowledgement:
15*4bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
16*4bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*4bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
18*4bff34e3Sthurlow  *    without specific prior written permission.
19*4bff34e3Sthurlow  *
20*4bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*4bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*4bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*4bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*4bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*4bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*4bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*4bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*4bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*4bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*4bff34e3Sthurlow  * SUCH DAMAGE.
31*4bff34e3Sthurlow  *
32*4bff34e3Sthurlow  * $Id: smb_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $
33*4bff34e3Sthurlow  */
34*4bff34e3Sthurlow 
35*4bff34e3Sthurlow /*
36*4bff34e3Sthurlow  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37*4bff34e3Sthurlow  * Use is subject to license terms.
38*4bff34e3Sthurlow  */
39*4bff34e3Sthurlow 
40*4bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*4bff34e3Sthurlow 
42*4bff34e3Sthurlow #include <sys/types.h>
43*4bff34e3Sthurlow #include <sys/param.h>
44*4bff34e3Sthurlow #include <sys/errno.h>
45*4bff34e3Sthurlow #include <sys/sysmacros.h>
46*4bff34e3Sthurlow #include <sys/uio.h>
47*4bff34e3Sthurlow #include <sys/buf.h>
48*4bff34e3Sthurlow #include <sys/modctl.h>
49*4bff34e3Sthurlow #include <sys/open.h>
50*4bff34e3Sthurlow #include <sys/file.h>
51*4bff34e3Sthurlow #include <sys/kmem.h>
52*4bff34e3Sthurlow #include <sys/conf.h>
53*4bff34e3Sthurlow #include <sys/cmn_err.h>
54*4bff34e3Sthurlow #include <sys/stat.h>
55*4bff34e3Sthurlow #include <sys/ddi.h>
56*4bff34e3Sthurlow #include <sys/sunddi.h>
57*4bff34e3Sthurlow #include <sys/sunldi.h>
58*4bff34e3Sthurlow #include <sys/policy.h>
59*4bff34e3Sthurlow #include <sys/zone.h>
60*4bff34e3Sthurlow #include <sys/pathname.h>
61*4bff34e3Sthurlow #include <sys/mount.h>
62*4bff34e3Sthurlow #include <sys/sdt.h>
63*4bff34e3Sthurlow #include <fs/fs_subr.h>
64*4bff34e3Sthurlow #include <sys/modctl.h>
65*4bff34e3Sthurlow #include <sys/devops.h>
66*4bff34e3Sthurlow #include <sys/thread.h>
67*4bff34e3Sthurlow #include <sys/mkdev.h>
68*4bff34e3Sthurlow #include <sys/types.h>
69*4bff34e3Sthurlow #include <sys/zone.h>
70*4bff34e3Sthurlow 
71*4bff34e3Sthurlow #ifdef APPLE
72*4bff34e3Sthurlow #include <sys/smb_apple.h>
73*4bff34e3Sthurlow #else
74*4bff34e3Sthurlow #include <netsmb/smb_osdep.h>
75*4bff34e3Sthurlow #endif
76*4bff34e3Sthurlow 
77*4bff34e3Sthurlow #include <netsmb/mchain.h>		/* for "htoles()" */
78*4bff34e3Sthurlow 
79*4bff34e3Sthurlow #include <netsmb/smb.h>
80*4bff34e3Sthurlow #include <netsmb/smb_conn.h>
81*4bff34e3Sthurlow #include <netsmb/smb_subr.h>
82*4bff34e3Sthurlow #include <netsmb/smb_dev.h>
83*4bff34e3Sthurlow #include <netsmb/smb_pass.h>
84*4bff34e3Sthurlow 
85*4bff34e3Sthurlow /* for version checks */
86*4bff34e3Sthurlow const uint32_t nsmb_version = NSMB_VERSION;
87*4bff34e3Sthurlow 
88*4bff34e3Sthurlow /*
89*4bff34e3Sthurlow  * Userland code loops through minor #s 0 to 1023, looking for one which opens.
90*4bff34e3Sthurlow  * Intially we create minor 0 and leave it for anyone.  Minor zero will never
91*4bff34e3Sthurlow  * actually get used - opening triggers creation of another (but private) minor,
92*4bff34e3Sthurlow  * which userland code will get to and mark busy.
93*4bff34e3Sthurlow  */
94*4bff34e3Sthurlow #define	SMBMINORS 1024
95*4bff34e3Sthurlow static void *statep;
96*4bff34e3Sthurlow static major_t nsmb_major;
97*4bff34e3Sthurlow static minor_t nsmb_minor = 1;
98*4bff34e3Sthurlow 
99*4bff34e3Sthurlow #define	NSMB_MAX_MINOR  (1 << 8)
100*4bff34e3Sthurlow #define	NSMB_MIN_MINOR   (NSMB_MAX_MINOR + 1)
101*4bff34e3Sthurlow 
102*4bff34e3Sthurlow #define	ILP32	1
103*4bff34e3Sthurlow #define	LP64	2
104*4bff34e3Sthurlow 
105*4bff34e3Sthurlow static kmutex_t  dev_lck;
106*4bff34e3Sthurlow 
107*4bff34e3Sthurlow /* Zone support */
108*4bff34e3Sthurlow zone_key_t nsmb_zone_key;
109*4bff34e3Sthurlow extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
110*4bff34e3Sthurlow extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
111*4bff34e3Sthurlow 
112*4bff34e3Sthurlow /*
113*4bff34e3Sthurlow  * cb_ops device operations.
114*4bff34e3Sthurlow  */
115*4bff34e3Sthurlow static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
116*4bff34e3Sthurlow static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
117*4bff34e3Sthurlow static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
118*4bff34e3Sthurlow 				cred_t *credp, int *rvalp);
119*4bff34e3Sthurlow /* smbfs cb_ops */
120*4bff34e3Sthurlow static struct cb_ops nsmb_cbops = {
121*4bff34e3Sthurlow 	nsmb_open,	/* open */
122*4bff34e3Sthurlow 	nsmb_close,	/* close */
123*4bff34e3Sthurlow 	nodev,		/* strategy */
124*4bff34e3Sthurlow 	nodev,		/* print */
125*4bff34e3Sthurlow 	nodev,		/* dump */
126*4bff34e3Sthurlow 	nodev,		/* read */
127*4bff34e3Sthurlow 	nodev,		/* write */
128*4bff34e3Sthurlow 	nsmb_ioctl,	/* ioctl */
129*4bff34e3Sthurlow 	nodev,		/* devmap */
130*4bff34e3Sthurlow 	nodev,		/* mmap */
131*4bff34e3Sthurlow 	nodev,		/* segmap */
132*4bff34e3Sthurlow 	nochpoll,	/* poll */
133*4bff34e3Sthurlow 	ddi_prop_op,	/* prop_op */
134*4bff34e3Sthurlow 	NULL,		/* stream */
135*4bff34e3Sthurlow 	D_MP,		/* cb_flag */
136*4bff34e3Sthurlow 	CB_REV,		/* rev */
137*4bff34e3Sthurlow 	nodev,		/* int (*cb_aread)() */
138*4bff34e3Sthurlow 	nodev		/* int (*cb_awrite)() */
139*4bff34e3Sthurlow };
140*4bff34e3Sthurlow 
141*4bff34e3Sthurlow /*
142*4bff34e3Sthurlow  * Device options
143*4bff34e3Sthurlow  */
144*4bff34e3Sthurlow static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
145*4bff34e3Sthurlow static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
146*4bff34e3Sthurlow static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
147*4bff34e3Sthurlow 	void *arg, void **result);
148*4bff34e3Sthurlow 
149*4bff34e3Sthurlow static struct dev_ops nsmb_ops = {
150*4bff34e3Sthurlow 	DEVO_REV,	/* devo_rev, */
151*4bff34e3Sthurlow 	0,		/* refcnt  */
152*4bff34e3Sthurlow 	nsmb_getinfo,	/* info */
153*4bff34e3Sthurlow 	nulldev,	/* identify */
154*4bff34e3Sthurlow 	nulldev,	/* probe */
155*4bff34e3Sthurlow 	nsmb_attach,	/* attach */
156*4bff34e3Sthurlow 	nsmb_detach,	/* detach */
157*4bff34e3Sthurlow 	nodev,		/* reset */
158*4bff34e3Sthurlow 	&nsmb_cbops,	/* driver ops - devctl interfaces */
159*4bff34e3Sthurlow 	NULL,		/* bus operations */
160*4bff34e3Sthurlow 	NULL		/* power */
161*4bff34e3Sthurlow };
162*4bff34e3Sthurlow 
163*4bff34e3Sthurlow /*
164*4bff34e3Sthurlow  * Module linkage information.
165*4bff34e3Sthurlow  */
166*4bff34e3Sthurlow 
167*4bff34e3Sthurlow static struct modldrv nsmb_modldrv = {
168*4bff34e3Sthurlow 	&mod_driverops,				/* Driver module */
169*4bff34e3Sthurlow 	"SMBFS network driver v" NSMB_VER_STR,
170*4bff34e3Sthurlow 	&nsmb_ops				/* Driver ops */
171*4bff34e3Sthurlow };
172*4bff34e3Sthurlow 
173*4bff34e3Sthurlow static struct modlinkage nsmb_modlinkage = {
174*4bff34e3Sthurlow 	MODREV_1,
175*4bff34e3Sthurlow 	(void *)&nsmb_modldrv,
176*4bff34e3Sthurlow 	NULL
177*4bff34e3Sthurlow };
178*4bff34e3Sthurlow 
179*4bff34e3Sthurlow int
180*4bff34e3Sthurlow _init(void)
181*4bff34e3Sthurlow {
182*4bff34e3Sthurlow 	int error;
183*4bff34e3Sthurlow 
184*4bff34e3Sthurlow 	ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
185*4bff34e3Sthurlow 
186*4bff34e3Sthurlow 	/* Can initialize some mutexes also. */
187*4bff34e3Sthurlow 	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
188*4bff34e3Sthurlow 	/*
189*4bff34e3Sthurlow 	 * Create a major name and number.
190*4bff34e3Sthurlow 	 */
191*4bff34e3Sthurlow 	nsmb_major = ddi_name_to_major(NSMB_NAME);
192*4bff34e3Sthurlow 	nsmb_minor = 0;
193*4bff34e3Sthurlow 
194*4bff34e3Sthurlow 	/* Connection data structures. */
195*4bff34e3Sthurlow 	(void) smb_sm_init();
196*4bff34e3Sthurlow 
197*4bff34e3Sthurlow 	/* Initialize password Key chain DB. */
198*4bff34e3Sthurlow 	smb_pkey_init();
199*4bff34e3Sthurlow 
200*4bff34e3Sthurlow 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
201*4bff34e3Sthurlow 	    nsmb_zone_destroy);
202*4bff34e3Sthurlow 
203*4bff34e3Sthurlow 	/*
204*4bff34e3Sthurlow 	 * Install the module.  Do this after other init,
205*4bff34e3Sthurlow 	 * to prevent entrances before we're ready.
206*4bff34e3Sthurlow 	 */
207*4bff34e3Sthurlow 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
208*4bff34e3Sthurlow 
209*4bff34e3Sthurlow 		/* Same as 2nd half of _fini */
210*4bff34e3Sthurlow 		(void) zone_key_delete(nsmb_zone_key);
211*4bff34e3Sthurlow 		smb_pkey_fini();
212*4bff34e3Sthurlow 		smb_sm_done();
213*4bff34e3Sthurlow 		mutex_destroy(&dev_lck);
214*4bff34e3Sthurlow 		ddi_soft_state_fini(&statep);
215*4bff34e3Sthurlow 
216*4bff34e3Sthurlow 		return (error);
217*4bff34e3Sthurlow 	}
218*4bff34e3Sthurlow 
219*4bff34e3Sthurlow 	return (0);
220*4bff34e3Sthurlow }
221*4bff34e3Sthurlow 
222*4bff34e3Sthurlow int
223*4bff34e3Sthurlow _fini(void)
224*4bff34e3Sthurlow {
225*4bff34e3Sthurlow 	int status;
226*4bff34e3Sthurlow 
227*4bff34e3Sthurlow 	/*
228*4bff34e3Sthurlow 	 * Prevent unload if we have active VCs
229*4bff34e3Sthurlow 	 * or stored passwords
230*4bff34e3Sthurlow 	 */
231*4bff34e3Sthurlow 	if ((status = smb_sm_idle()) != 0)
232*4bff34e3Sthurlow 		return (status);
233*4bff34e3Sthurlow 	if ((status = smb_pkey_idle()) != 0)
234*4bff34e3Sthurlow 		return (status);
235*4bff34e3Sthurlow 
236*4bff34e3Sthurlow 	/*
237*4bff34e3Sthurlow 	 * Remove the module.  Do this before destroying things,
238*4bff34e3Sthurlow 	 * to prevent new entrances while we're destorying.
239*4bff34e3Sthurlow 	 */
240*4bff34e3Sthurlow 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
241*4bff34e3Sthurlow 		return (status);
242*4bff34e3Sthurlow 	}
243*4bff34e3Sthurlow 
244*4bff34e3Sthurlow 	(void) zone_key_delete(nsmb_zone_key);
245*4bff34e3Sthurlow 
246*4bff34e3Sthurlow 	/* Destroy password Key chain DB. */
247*4bff34e3Sthurlow 	smb_pkey_fini();
248*4bff34e3Sthurlow 
249*4bff34e3Sthurlow 	smb_sm_done();
250*4bff34e3Sthurlow 
251*4bff34e3Sthurlow 	mutex_destroy(&dev_lck);
252*4bff34e3Sthurlow 	ddi_soft_state_fini(&statep);
253*4bff34e3Sthurlow 
254*4bff34e3Sthurlow 	return (status);
255*4bff34e3Sthurlow }
256*4bff34e3Sthurlow 
257*4bff34e3Sthurlow int
258*4bff34e3Sthurlow _info(struct modinfo *modinfop)
259*4bff34e3Sthurlow {
260*4bff34e3Sthurlow 	return (mod_info(&nsmb_modlinkage, modinfop));
261*4bff34e3Sthurlow }
262*4bff34e3Sthurlow 
263*4bff34e3Sthurlow /*ARGSUSED*/
264*4bff34e3Sthurlow static int
265*4bff34e3Sthurlow nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
266*4bff34e3Sthurlow {
267*4bff34e3Sthurlow 	int ret = DDI_SUCCESS;
268*4bff34e3Sthurlow 
269*4bff34e3Sthurlow 	switch (cmd) {
270*4bff34e3Sthurlow 	case DDI_INFO_DEVT2DEVINFO:
271*4bff34e3Sthurlow 		*result = 0;
272*4bff34e3Sthurlow 		break;
273*4bff34e3Sthurlow 	case DDI_INFO_DEVT2INSTANCE:
274*4bff34e3Sthurlow 		*result = 0;
275*4bff34e3Sthurlow 		break;
276*4bff34e3Sthurlow 	default:
277*4bff34e3Sthurlow 		ret = DDI_FAILURE;
278*4bff34e3Sthurlow 	}
279*4bff34e3Sthurlow 	return (ret);
280*4bff34e3Sthurlow }
281*4bff34e3Sthurlow 
282*4bff34e3Sthurlow static int
283*4bff34e3Sthurlow nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
284*4bff34e3Sthurlow {
285*4bff34e3Sthurlow 	smb_dev_t *sdp;
286*4bff34e3Sthurlow 
287*4bff34e3Sthurlow 	if (cmd != DDI_ATTACH)
288*4bff34e3Sthurlow 		return (DDI_FAILURE);
289*4bff34e3Sthurlow 	/*
290*4bff34e3Sthurlow 	 * only one instance - but we clone using the open routine
291*4bff34e3Sthurlow 	 */
292*4bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
293*4bff34e3Sthurlow 		return (DDI_FAILURE);
294*4bff34e3Sthurlow 
295*4bff34e3Sthurlow 	mutex_enter(&dev_lck);
296*4bff34e3Sthurlow 
297*4bff34e3Sthurlow 	/*
298*4bff34e3Sthurlow 	 * This is the Zero'th minor device which is created.
299*4bff34e3Sthurlow 	 */
300*4bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) {
301*4bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: soft state alloc");
302*4bff34e3Sthurlow 		goto attach_failed;
303*4bff34e3Sthurlow 	}
304*4bff34e3Sthurlow 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
305*4bff34e3Sthurlow 	    NULL) == DDI_FAILURE) {
306*4bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: create minor");
307*4bff34e3Sthurlow 		goto attach_failed;
308*4bff34e3Sthurlow 	}
309*4bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) {
310*4bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: get soft state");
311*4bff34e3Sthurlow 		ddi_remove_minor_node(dip, NULL);
312*4bff34e3Sthurlow 		goto attach_failed;
313*4bff34e3Sthurlow 	}
314*4bff34e3Sthurlow 
315*4bff34e3Sthurlow 	/*
316*4bff34e3Sthurlow 	 * Need to see if this field is required.
317*4bff34e3Sthurlow 	 * REVISIT
318*4bff34e3Sthurlow 	 */
319*4bff34e3Sthurlow 	sdp->smb_dip = dip;
320*4bff34e3Sthurlow 	sdp->sd_seq = 0;
321*4bff34e3Sthurlow 	sdp->sd_opened = 1;
322*4bff34e3Sthurlow 
323*4bff34e3Sthurlow 	mutex_exit(&dev_lck);
324*4bff34e3Sthurlow 	ddi_report_dev(dip);
325*4bff34e3Sthurlow 	return (DDI_SUCCESS);
326*4bff34e3Sthurlow 
327*4bff34e3Sthurlow attach_failed:
328*4bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
329*4bff34e3Sthurlow 	mutex_exit(&dev_lck);
330*4bff34e3Sthurlow 	return (DDI_FAILURE);
331*4bff34e3Sthurlow }
332*4bff34e3Sthurlow 
333*4bff34e3Sthurlow /*ARGSUSED*/
334*4bff34e3Sthurlow static int
335*4bff34e3Sthurlow nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
336*4bff34e3Sthurlow {
337*4bff34e3Sthurlow 
338*4bff34e3Sthurlow 	if (cmd != DDI_DETACH)
339*4bff34e3Sthurlow 		return (DDI_FAILURE);
340*4bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
341*4bff34e3Sthurlow 		return (DDI_FAILURE);
342*4bff34e3Sthurlow 
343*4bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
344*4bff34e3Sthurlow 	ddi_remove_minor_node(dip, NULL);
345*4bff34e3Sthurlow 
346*4bff34e3Sthurlow 	return (DDI_SUCCESS);
347*4bff34e3Sthurlow }
348*4bff34e3Sthurlow 
349*4bff34e3Sthurlow /*ARGSUSED*/
350*4bff34e3Sthurlow static int
351*4bff34e3Sthurlow nsmb_ioctl(dev_t dev,
352*4bff34e3Sthurlow 	    int cmd,
353*4bff34e3Sthurlow 	    intptr_t arg,
354*4bff34e3Sthurlow 	    int mode,
355*4bff34e3Sthurlow 	    cred_t *credp,
356*4bff34e3Sthurlow 	    int *rvalp)
357*4bff34e3Sthurlow {
358*4bff34e3Sthurlow 	smb_dev_t *sdp;
359*4bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
360*4bff34e3Sthurlow 	struct smb_share *ssp = NULL;
361*4bff34e3Sthurlow 	struct smb_cred scred;
362*4bff34e3Sthurlow 	int err, error;
363*4bff34e3Sthurlow 	uid_t uid;
364*4bff34e3Sthurlow 
365*4bff34e3Sthurlow 	/* Free any+all of these at end of switch. */
366*4bff34e3Sthurlow 	smbioc_lookup_t *sioc = NULL;
367*4bff34e3Sthurlow 	smbioc_rq_t *srq = NULL;
368*4bff34e3Sthurlow 	smbioc_rw_t *rwrq = NULL;
369*4bff34e3Sthurlow 	smbioc_t2rq_t *strq = NULL;
370*4bff34e3Sthurlow 	smbioc_pk_t  *pk = NULL;
371*4bff34e3Sthurlow 
372*4bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
373*4bff34e3Sthurlow 	if (sdp == NULL) {
374*4bff34e3Sthurlow 		return (DDI_FAILURE);
375*4bff34e3Sthurlow 	}
376*4bff34e3Sthurlow 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
377*4bff34e3Sthurlow 		return (EBADF);
378*4bff34e3Sthurlow 	}
379*4bff34e3Sthurlow 
380*4bff34e3Sthurlow 	/*
381*4bff34e3Sthurlow 	 * Dont give access if the zone id is not as the same as we
382*4bff34e3Sthurlow 	 * set in the nsmb_open or dont belong to the global zone.
383*4bff34e3Sthurlow 	 * Check if the user belongs to this zone..
384*4bff34e3Sthurlow 	 */
385*4bff34e3Sthurlow 	if (sdp->zoneid != getzoneid())
386*4bff34e3Sthurlow 		return (EIO);
387*4bff34e3Sthurlow 	if (cmd != SMBIOC_TDIS &&
388*4bff34e3Sthurlow 	    zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)
389*4bff34e3Sthurlow 		return (EIO);
390*4bff34e3Sthurlow 
391*4bff34e3Sthurlow 
392*4bff34e3Sthurlow 	error = 0;
393*4bff34e3Sthurlow 	smb_credinit(&scred, curproc, credp);
394*4bff34e3Sthurlow 	switch (cmd) {
395*4bff34e3Sthurlow 		case SMBIOC_GETVERS:
396*4bff34e3Sthurlow 			ddi_copyout(&nsmb_version, (void *)arg,
397*4bff34e3Sthurlow 			    sizeof (nsmb_version), mode);
398*4bff34e3Sthurlow 			break;
399*4bff34e3Sthurlow 
400*4bff34e3Sthurlow 		case SMBIOC_REQUEST:
401*4bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
402*4bff34e3Sthurlow 				error = ENOTCONN;
403*4bff34e3Sthurlow 				break;
404*4bff34e3Sthurlow 			}
405*4bff34e3Sthurlow 			srq = kmem_alloc(sizeof (*srq), KM_SLEEP);
406*4bff34e3Sthurlow 			if (ddi_copyin((void *) arg, srq,
407*4bff34e3Sthurlow 			    sizeof (*srq), mode)) {
408*4bff34e3Sthurlow 				error = EFAULT;
409*4bff34e3Sthurlow 				break;
410*4bff34e3Sthurlow 			}
411*4bff34e3Sthurlow 			error = smb_usr_simplerequest(sdp->sd_share,
412*4bff34e3Sthurlow 			    srq, &scred);
413*4bff34e3Sthurlow 			ddi_copyout(srq, (void *)arg,
414*4bff34e3Sthurlow 			    SMBIOC_RQ_COPYOUT_SIZE, mode);
415*4bff34e3Sthurlow 			break;
416*4bff34e3Sthurlow 
417*4bff34e3Sthurlow 		case SMBIOC_T2RQ:
418*4bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
419*4bff34e3Sthurlow 				error = ENOTCONN;
420*4bff34e3Sthurlow 				break;
421*4bff34e3Sthurlow 			}
422*4bff34e3Sthurlow 			strq = kmem_alloc(sizeof (*strq), KM_SLEEP);
423*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, strq,
424*4bff34e3Sthurlow 			    sizeof (*strq), mode)) {
425*4bff34e3Sthurlow 				error = EFAULT;
426*4bff34e3Sthurlow 				break;
427*4bff34e3Sthurlow 			}
428*4bff34e3Sthurlow 			error = smb_usr_t2request(sdp->sd_share, strq, &scred);
429*4bff34e3Sthurlow 			ddi_copyout(strq, (void *)arg,
430*4bff34e3Sthurlow 			    SMBIOC_T2RQ_COPYOUT_SIZE, mode);
431*4bff34e3Sthurlow 			break;
432*4bff34e3Sthurlow 
433*4bff34e3Sthurlow 		case SMBIOC_READ:
434*4bff34e3Sthurlow 		case SMBIOC_WRITE:
435*4bff34e3Sthurlow 			if ((ssp = sdp->sd_share) == NULL) {
436*4bff34e3Sthurlow 				error = ENOTCONN;
437*4bff34e3Sthurlow 				break;
438*4bff34e3Sthurlow 			}
439*4bff34e3Sthurlow 			rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP);
440*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, rwrq,
441*4bff34e3Sthurlow 			    sizeof (*rwrq), mode)) {
442*4bff34e3Sthurlow 				error = EFAULT;
443*4bff34e3Sthurlow 				break;
444*4bff34e3Sthurlow 			}
445*4bff34e3Sthurlow 			error = smb_usr_rw(ssp, rwrq, cmd, &scred);
446*4bff34e3Sthurlow 			ddi_copyout(rwrq, (void *)arg,
447*4bff34e3Sthurlow 			    SMBIOC_RW_COPYOUT_SIZE, mode);
448*4bff34e3Sthurlow 			break;
449*4bff34e3Sthurlow 
450*4bff34e3Sthurlow 		case SMBIOC_NEGOTIATE:
451*4bff34e3Sthurlow 			/* Should be no VC (and no share) */
452*4bff34e3Sthurlow 			if (sdp->sd_vc || sdp->sd_share) {
453*4bff34e3Sthurlow 				error = EISCONN;
454*4bff34e3Sthurlow 				break;
455*4bff34e3Sthurlow 			}
456*4bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
457*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
458*4bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
459*4bff34e3Sthurlow 				error = EFAULT;
460*4bff34e3Sthurlow 				break;
461*4bff34e3Sthurlow 			}
462*4bff34e3Sthurlow 			vcp = NULL;
463*4bff34e3Sthurlow 			ssp = NULL;
464*4bff34e3Sthurlow 			error = smb_usr_negotiate(sioc, &scred, &vcp);
465*4bff34e3Sthurlow 			if (error)
466*4bff34e3Sthurlow 				break;
467*4bff34e3Sthurlow 			if (vcp) {
468*4bff34e3Sthurlow 				/*
469*4bff34e3Sthurlow 				 * The VC has a hold from _negotiate
470*4bff34e3Sthurlow 				 * which we keep until nsmb_close().
471*4bff34e3Sthurlow 				 */
472*4bff34e3Sthurlow 				sdp->sd_level = SMBL_VC;
473*4bff34e3Sthurlow 				sdp->sd_vc = vcp;
474*4bff34e3Sthurlow 				/*
475*4bff34e3Sthurlow 				 * If we just created this VC, and
476*4bff34e3Sthurlow 				 * this minor is doing the setup,
477*4bff34e3Sthurlow 				 * keep track of that fact here.
478*4bff34e3Sthurlow 				 */
479*4bff34e3Sthurlow 				if (vcp->vc_state < SMBIOD_ST_VCACTIVE)
480*4bff34e3Sthurlow 					sdp->sd_flags |= NSMBFL_NEWVC;
481*4bff34e3Sthurlow 
482*4bff34e3Sthurlow 			}
483*4bff34e3Sthurlow 			/*
484*4bff34e3Sthurlow 			 * Copyout the "out token" (security blob).
485*4bff34e3Sthurlow 			 *
486*4bff34e3Sthurlow 			 * This code used to be near the end of
487*4bff34e3Sthurlow 			 * smb_usr_negotiate().  Moved the copyout
488*4bff34e3Sthurlow 			 * calls here so we know the "mode"
489*4bff34e3Sthurlow 			 */
490*4bff34e3Sthurlow 			if (vcp->vc_outtok) {
491*4bff34e3Sthurlow 				/*
492*4bff34e3Sthurlow 				 * Note: will copyout sioc below
493*4bff34e3Sthurlow 				 * including sioc.vc_outtoklen,
494*4bff34e3Sthurlow 				 * so we no longer put the length
495*4bff34e3Sthurlow 				 * at the start of the outtok data.
496*4bff34e3Sthurlow 				 */
497*4bff34e3Sthurlow 				sioc->ioc_ssn.ioc_outtoklen =
498*4bff34e3Sthurlow 				    vcp->vc_outtoklen;
499*4bff34e3Sthurlow 				err = ddi_copyout(
500*4bff34e3Sthurlow 				    vcp->vc_outtok,
501*4bff34e3Sthurlow 				    sioc->ioc_ssn.ioc_outtok,
502*4bff34e3Sthurlow 				    vcp->vc_outtoklen, mode);
503*4bff34e3Sthurlow 				if (err) {
504*4bff34e3Sthurlow 					error = EFAULT;
505*4bff34e3Sthurlow 					break;
506*4bff34e3Sthurlow 				}
507*4bff34e3Sthurlow 				/*
508*4bff34e3Sthurlow 				 * Save this blob in vc_negtok.
509*4bff34e3Sthurlow 				 * We need it in case we have to
510*4bff34e3Sthurlow 				 * reconnect.
511*4bff34e3Sthurlow 				 *
512*4bff34e3Sthurlow 				 * Set vc_negtok = vc_outtok
513*4bff34e3Sthurlow 				 * but free vc_negtok first.
514*4bff34e3Sthurlow 				 */
515*4bff34e3Sthurlow 				if (vcp->vc_negtok) {
516*4bff34e3Sthurlow 					kmem_free(
517*4bff34e3Sthurlow 					    vcp->vc_negtok,
518*4bff34e3Sthurlow 					    vcp->vc_negtoklen);
519*4bff34e3Sthurlow 					vcp->vc_negtok = NULL;
520*4bff34e3Sthurlow 					vcp->vc_negtoklen = 0;
521*4bff34e3Sthurlow 				}
522*4bff34e3Sthurlow 				vcp->vc_negtok    = vcp->vc_outtok;
523*4bff34e3Sthurlow 				vcp->vc_negtoklen = vcp->vc_outtoklen;
524*4bff34e3Sthurlow 				vcp->vc_outtok = NULL;
525*4bff34e3Sthurlow 				vcp->vc_outtoklen = 0;
526*4bff34e3Sthurlow 			}
527*4bff34e3Sthurlow 			/*
528*4bff34e3Sthurlow 			 * Added copyout here of (almost)
529*4bff34e3Sthurlow 			 * the whole struct, even though
530*4bff34e3Sthurlow 			 * the lib only needs _outtoklen.
531*4bff34e3Sthurlow 			 * We may put other things in this
532*4bff34e3Sthurlow 			 * struct that user-land needs.
533*4bff34e3Sthurlow 			 */
534*4bff34e3Sthurlow 			err = ddi_copyout(sioc, (void *)arg,
535*4bff34e3Sthurlow 			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
536*4bff34e3Sthurlow 			if (err)
537*4bff34e3Sthurlow 				error = EFAULT;
538*4bff34e3Sthurlow 			break;
539*4bff34e3Sthurlow 
540*4bff34e3Sthurlow 		case SMBIOC_SSNSETUP:
541*4bff34e3Sthurlow 			/* Must have a VC, but no share. */
542*4bff34e3Sthurlow 			if (sdp->sd_share) {
543*4bff34e3Sthurlow 				error = EISCONN;
544*4bff34e3Sthurlow 				break;
545*4bff34e3Sthurlow 			}
546*4bff34e3Sthurlow 			if (!sdp->sd_vc) {
547*4bff34e3Sthurlow 				error = ENOTCONN;
548*4bff34e3Sthurlow 				break;
549*4bff34e3Sthurlow 			}
550*4bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
551*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
552*4bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
553*4bff34e3Sthurlow 				error = EFAULT;
554*4bff34e3Sthurlow 				break;
555*4bff34e3Sthurlow 			}
556*4bff34e3Sthurlow 			vcp = sdp->sd_vc;
557*4bff34e3Sthurlow 			ssp = NULL;
558*4bff34e3Sthurlow 			error = smb_usr_ssnsetup(sioc, &scred, vcp);
559*4bff34e3Sthurlow 			if (error)
560*4bff34e3Sthurlow 				break;
561*4bff34e3Sthurlow 			/*
562*4bff34e3Sthurlow 			 * If this minor has finished ssn setup,
563*4bff34e3Sthurlow 			 * turn off the NEWVC flag, otherwise we
564*4bff34e3Sthurlow 			 * will kill this VC when we close.
565*4bff34e3Sthurlow 			 */
566*4bff34e3Sthurlow 			if (vcp->vc_state == SMBIOD_ST_VCACTIVE)
567*4bff34e3Sthurlow 				sdp->sd_flags &= ~NSMBFL_NEWVC;
568*4bff34e3Sthurlow 			/*
569*4bff34e3Sthurlow 			 * Copyout the "out token" (security blob).
570*4bff34e3Sthurlow 			 *
571*4bff34e3Sthurlow 			 * This code used to be near the end of
572*4bff34e3Sthurlow 			 * smb_usr_ssnsetup().  Moved the copyout
573*4bff34e3Sthurlow 			 * calls here so we know the "mode"
574*4bff34e3Sthurlow 			 */
575*4bff34e3Sthurlow 			if (vcp->vc_outtok) {
576*4bff34e3Sthurlow 				/*
577*4bff34e3Sthurlow 				 * Note: will copyout sioc below
578*4bff34e3Sthurlow 				 * including sioc.vc_outtoklen,
579*4bff34e3Sthurlow 				 * so we no longer put the length
580*4bff34e3Sthurlow 				 * at the start of the outtok data.
581*4bff34e3Sthurlow 				 */
582*4bff34e3Sthurlow 				sioc->ioc_ssn.ioc_outtoklen =
583*4bff34e3Sthurlow 				    vcp->vc_outtoklen;
584*4bff34e3Sthurlow 				err = ddi_copyout(
585*4bff34e3Sthurlow 				    vcp->vc_outtok,
586*4bff34e3Sthurlow 				    sioc->ioc_ssn.ioc_outtok,
587*4bff34e3Sthurlow 				    vcp->vc_outtoklen, mode);
588*4bff34e3Sthurlow 				if (err) {
589*4bff34e3Sthurlow 					error = EFAULT;
590*4bff34e3Sthurlow 					break;
591*4bff34e3Sthurlow 				}
592*4bff34e3Sthurlow 				/*
593*4bff34e3Sthurlow 				 * Done with vc_outtok.  Similar,
594*4bff34e3Sthurlow 				 * but NOT the same as after the
595*4bff34e3Sthurlow 				 * smb_usr_negotiate call above.
596*4bff34e3Sthurlow 				 */
597*4bff34e3Sthurlow 				kmem_free(
598*4bff34e3Sthurlow 				    vcp->vc_outtok,
599*4bff34e3Sthurlow 				    vcp->vc_outtoklen);
600*4bff34e3Sthurlow 				vcp->vc_outtok = NULL;
601*4bff34e3Sthurlow 				vcp->vc_outtoklen = 0;
602*4bff34e3Sthurlow 			}
603*4bff34e3Sthurlow 			/* Added copyout here... (see above) */
604*4bff34e3Sthurlow 			err = ddi_copyout(sioc, (void *)arg,
605*4bff34e3Sthurlow 			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
606*4bff34e3Sthurlow 			if (err)
607*4bff34e3Sthurlow 				error = EFAULT;
608*4bff34e3Sthurlow 			break;
609*4bff34e3Sthurlow 
610*4bff34e3Sthurlow 		case SMBIOC_TCON:
611*4bff34e3Sthurlow 			/* Must have a VC, but no share. */
612*4bff34e3Sthurlow 			if (sdp->sd_share) {
613*4bff34e3Sthurlow 				error = EISCONN;
614*4bff34e3Sthurlow 				break;
615*4bff34e3Sthurlow 			}
616*4bff34e3Sthurlow 			if (!sdp->sd_vc) {
617*4bff34e3Sthurlow 				error = ENOTCONN;
618*4bff34e3Sthurlow 				break;
619*4bff34e3Sthurlow 			}
620*4bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
621*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
622*4bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
623*4bff34e3Sthurlow 				error = EFAULT;
624*4bff34e3Sthurlow 				break;
625*4bff34e3Sthurlow 			}
626*4bff34e3Sthurlow 			vcp = sdp->sd_vc;
627*4bff34e3Sthurlow 			ssp = NULL;
628*4bff34e3Sthurlow 			error = smb_usr_tcon(sioc, &scred, vcp, &ssp);
629*4bff34e3Sthurlow 			if (error)
630*4bff34e3Sthurlow 				break;
631*4bff34e3Sthurlow 			if (ssp) {
632*4bff34e3Sthurlow 				/*
633*4bff34e3Sthurlow 				 * The share has a hold from _tcon
634*4bff34e3Sthurlow 				 * which we keep until nsmb_close()
635*4bff34e3Sthurlow 				 * or the SMBIOC_TDIS below.
636*4bff34e3Sthurlow 				 */
637*4bff34e3Sthurlow 				sdp->sd_share = ssp;
638*4bff34e3Sthurlow 				sdp->sd_level = SMBL_SHARE;
639*4bff34e3Sthurlow 			}
640*4bff34e3Sthurlow 			/* No need for copyout here. */
641*4bff34e3Sthurlow 			break;
642*4bff34e3Sthurlow 
643*4bff34e3Sthurlow 		case SMBIOC_TDIS:
644*4bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
645*4bff34e3Sthurlow 				error = ENOTCONN;
646*4bff34e3Sthurlow 				break;
647*4bff34e3Sthurlow 			}
648*4bff34e3Sthurlow 			smb_share_rele(sdp->sd_share);
649*4bff34e3Sthurlow 			sdp->sd_share = NULL;
650*4bff34e3Sthurlow 			sdp->sd_level = SMBL_VC;
651*4bff34e3Sthurlow 			break;
652*4bff34e3Sthurlow 		case SMBIOC_FLAGS2:
653*4bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
654*4bff34e3Sthurlow 				error = ENOTCONN;
655*4bff34e3Sthurlow 				break;
656*4bff34e3Sthurlow 			}
657*4bff34e3Sthurlow 			if (!sdp->sd_vc) {
658*4bff34e3Sthurlow 				error = ENOTCONN;
659*4bff34e3Sthurlow 				break;
660*4bff34e3Sthurlow 			}
661*4bff34e3Sthurlow 			vcp = sdp->sd_vc;
662*4bff34e3Sthurlow 			/*
663*4bff34e3Sthurlow 			 * Return the flags2 value.
664*4bff34e3Sthurlow 			 */
665*4bff34e3Sthurlow 			ddi_copyout(&vcp->vc_hflags2, (void *)arg,
666*4bff34e3Sthurlow 			    sizeof (u_int16_t), mode);
667*4bff34e3Sthurlow 			break;
668*4bff34e3Sthurlow 
669*4bff34e3Sthurlow 		case SMBIOC_PK_ADD:
670*4bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
671*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
672*4bff34e3Sthurlow 			    sizeof (*pk), mode)) {
673*4bff34e3Sthurlow 				error = EFAULT;
674*4bff34e3Sthurlow 				break;
675*4bff34e3Sthurlow 			}
676*4bff34e3Sthurlow 			error = smb_pkey_add(pk, credp);
677*4bff34e3Sthurlow 			break;
678*4bff34e3Sthurlow 
679*4bff34e3Sthurlow 		case SMBIOC_PK_DEL:
680*4bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
681*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
682*4bff34e3Sthurlow 			    sizeof (*pk), mode)) {
683*4bff34e3Sthurlow 				error = EFAULT;
684*4bff34e3Sthurlow 				break;
685*4bff34e3Sthurlow 			}
686*4bff34e3Sthurlow 			error = smb_pkey_del(pk, credp);
687*4bff34e3Sthurlow 			break;
688*4bff34e3Sthurlow 
689*4bff34e3Sthurlow 		case SMBIOC_PK_CHK:
690*4bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
691*4bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
692*4bff34e3Sthurlow 			    sizeof (*pk), mode)) {
693*4bff34e3Sthurlow 				error = EFAULT;
694*4bff34e3Sthurlow 				break;
695*4bff34e3Sthurlow 			}
696*4bff34e3Sthurlow 			error = smb_pkey_check(pk, credp);
697*4bff34e3Sthurlow 			/*
698*4bff34e3Sthurlow 			 * Note: Intentionally DO NOT copyout
699*4bff34e3Sthurlow 			 * the pasword here.  It can only be
700*4bff34e3Sthurlow 			 * retrieved by internal calls.  This
701*4bff34e3Sthurlow 			 * ioctl only tells the caller if the
702*4bff34e3Sthurlow 			 * keychain entry exists.
703*4bff34e3Sthurlow 			 */
704*4bff34e3Sthurlow 			break;
705*4bff34e3Sthurlow 
706*4bff34e3Sthurlow 		case SMBIOC_PK_DEL_OWNER:
707*4bff34e3Sthurlow 			uid = crgetruid(credp);
708*4bff34e3Sthurlow 			error = smb_pkey_deluid(uid, credp);
709*4bff34e3Sthurlow 			break;
710*4bff34e3Sthurlow 
711*4bff34e3Sthurlow 		case SMBIOC_PK_DEL_EVERYONE:
712*4bff34e3Sthurlow 			uid = (uid_t)-1;
713*4bff34e3Sthurlow 			error = smb_pkey_deluid(uid, credp);
714*4bff34e3Sthurlow 			break;
715*4bff34e3Sthurlow 
716*4bff34e3Sthurlow 		default:
717*4bff34e3Sthurlow 			error = ENODEV;
718*4bff34e3Sthurlow 	}
719*4bff34e3Sthurlow 
720*4bff34e3Sthurlow 	/*
721*4bff34e3Sthurlow 	 * Let's just do all the kmem_free stuff HERE,
722*4bff34e3Sthurlow 	 * instead of at every switch break.
723*4bff34e3Sthurlow 	 */
724*4bff34e3Sthurlow 
725*4bff34e3Sthurlow 	/* SMBIOC_REQUEST */
726*4bff34e3Sthurlow 	if (srq)
727*4bff34e3Sthurlow 		kmem_free(srq, sizeof (*srq));
728*4bff34e3Sthurlow 
729*4bff34e3Sthurlow 	/* SMBIOC_T2RQ */
730*4bff34e3Sthurlow 	if (strq)
731*4bff34e3Sthurlow 		kmem_free(strq, sizeof (*strq));
732*4bff34e3Sthurlow 
733*4bff34e3Sthurlow 	/* SMBIOC_READ */
734*4bff34e3Sthurlow 	/* SMBIOC_WRITE */
735*4bff34e3Sthurlow 	if (rwrq)
736*4bff34e3Sthurlow 		kmem_free(rwrq, sizeof (*rwrq));
737*4bff34e3Sthurlow 
738*4bff34e3Sthurlow 	/* SMBIOC_NEGOTIATE */
739*4bff34e3Sthurlow 	/* SMBIOC_SSNSETUP */
740*4bff34e3Sthurlow 	/* SMBIOC_TCON */
741*4bff34e3Sthurlow 	if (sioc) {
742*4bff34e3Sthurlow 		/*
743*4bff34e3Sthurlow 		 * This data structure may contain
744*4bff34e3Sthurlow 		 * cleartext passwords, so zap it.
745*4bff34e3Sthurlow 		 */
746*4bff34e3Sthurlow 		bzero(sioc, sizeof (*sioc));
747*4bff34e3Sthurlow 		kmem_free(sioc, sizeof (*sioc));
748*4bff34e3Sthurlow 	}
749*4bff34e3Sthurlow 
750*4bff34e3Sthurlow 	/* SMBIOC_PK_... */
751*4bff34e3Sthurlow 	if (pk) {
752*4bff34e3Sthurlow 		/*
753*4bff34e3Sthurlow 		 * This data structure may contain
754*4bff34e3Sthurlow 		 * cleartext passwords, so zap it.
755*4bff34e3Sthurlow 		 */
756*4bff34e3Sthurlow 		bzero(pk, sizeof (*pk));
757*4bff34e3Sthurlow 		kmem_free(pk, sizeof (*pk));
758*4bff34e3Sthurlow 	}
759*4bff34e3Sthurlow 
760*4bff34e3Sthurlow 	smb_credrele(&scred);
761*4bff34e3Sthurlow 
762*4bff34e3Sthurlow 	return (error);
763*4bff34e3Sthurlow }
764*4bff34e3Sthurlow 
765*4bff34e3Sthurlow /*ARGSUSED*/
766*4bff34e3Sthurlow static int
767*4bff34e3Sthurlow nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
768*4bff34e3Sthurlow {
769*4bff34e3Sthurlow 	major_t new_major;
770*4bff34e3Sthurlow 	smb_dev_t *sdp, *sdv;
771*4bff34e3Sthurlow 
772*4bff34e3Sthurlow 	mutex_enter(&dev_lck);
773*4bff34e3Sthurlow 	for (; ; ) {
774*4bff34e3Sthurlow 		minor_t start = nsmb_minor;
775*4bff34e3Sthurlow 		do {
776*4bff34e3Sthurlow 			if (nsmb_minor >= MAXMIN32) {
777*4bff34e3Sthurlow 				if (nsmb_major == getmajor(*dev))
778*4bff34e3Sthurlow 					nsmb_minor = NSMB_MIN_MINOR;
779*4bff34e3Sthurlow 				else
780*4bff34e3Sthurlow 					nsmb_minor = 0;
781*4bff34e3Sthurlow 			} else {
782*4bff34e3Sthurlow 				nsmb_minor++;
783*4bff34e3Sthurlow 			}
784*4bff34e3Sthurlow 			sdv = ddi_get_soft_state(statep, nsmb_minor);
785*4bff34e3Sthurlow 		} while ((sdv != NULL) && (nsmb_minor != start));
786*4bff34e3Sthurlow 		if (nsmb_minor == start) {
787*4bff34e3Sthurlow 			/*
788*4bff34e3Sthurlow 			 * The condition we need to solve here is  all the
789*4bff34e3Sthurlow 			 * MAXMIN32(~262000) minors numbers are reached. We
790*4bff34e3Sthurlow 			 * need to create a new major number.
791*4bff34e3Sthurlow 			 * zfs uses getudev() to create a new major number.
792*4bff34e3Sthurlow 			 */
793*4bff34e3Sthurlow 			if ((new_major = getudev()) == (major_t)-1) {
794*4bff34e3Sthurlow 				cmn_err(CE_WARN,
795*4bff34e3Sthurlow 				    "nsmb: Can't get unique major "
796*4bff34e3Sthurlow 				    "device number.");
797*4bff34e3Sthurlow 				mutex_exit(&dev_lck);
798*4bff34e3Sthurlow 				return (-1);
799*4bff34e3Sthurlow 			}
800*4bff34e3Sthurlow 			nsmb_major = new_major;
801*4bff34e3Sthurlow 			nsmb_minor = 0;
802*4bff34e3Sthurlow 		} else {
803*4bff34e3Sthurlow 			break;
804*4bff34e3Sthurlow 		}
805*4bff34e3Sthurlow 	}
806*4bff34e3Sthurlow 
807*4bff34e3Sthurlow 	/*
808*4bff34e3Sthurlow 	 * This is called by mount or open call.
809*4bff34e3Sthurlow 	 * The open() routine is passed a pointer to a device number so
810*4bff34e3Sthurlow 	 * that  the  driver  can  change the minor number. This allows
811*4bff34e3Sthurlow 	 * drivers to dynamically  create minor instances of  the  dev-
812*4bff34e3Sthurlow 	 * ice.  An  example of this might be a  pseudo-terminal driver
813*4bff34e3Sthurlow 	 * that creates a new pseudo-terminal whenever it   is  opened.
814*4bff34e3Sthurlow 	 * A driver that chooses the minor number dynamically, normally
815*4bff34e3Sthurlow 	 * creates only one  minor  device  node  in   attach(9E)  with
816*4bff34e3Sthurlow 	 * ddi_create_minor_node(9F) then changes the minor number com-
817*4bff34e3Sthurlow 	 * ponent of *devp using makedevice(9F)  and  getmajor(9F)  The
818*4bff34e3Sthurlow 	 * driver needs to keep track of available minor numbers inter-
819*4bff34e3Sthurlow 	 * nally.
820*4bff34e3Sthurlow 	 * Stuff the structure smb_dev.
821*4bff34e3Sthurlow 	 * return.
822*4bff34e3Sthurlow 	 */
823*4bff34e3Sthurlow 
824*4bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) {
825*4bff34e3Sthurlow 		mutex_exit(&dev_lck);
826*4bff34e3Sthurlow 		return (ENXIO);
827*4bff34e3Sthurlow 	}
828*4bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) {
829*4bff34e3Sthurlow 		mutex_exit(&dev_lck);
830*4bff34e3Sthurlow 		return (ENXIO);
831*4bff34e3Sthurlow 	}
832*4bff34e3Sthurlow 
833*4bff34e3Sthurlow 	sdp->sd_opened = 1;
834*4bff34e3Sthurlow 	sdp->sd_seq = nsmb_minor;
835*4bff34e3Sthurlow 	sdp->smb_cred = cr;
836*4bff34e3Sthurlow 	sdp->sd_flags |= NSMBFL_OPEN;
837*4bff34e3Sthurlow 	sdp->zoneid = crgetzoneid(cr);
838*4bff34e3Sthurlow 	mutex_exit(&dev_lck);
839*4bff34e3Sthurlow 
840*4bff34e3Sthurlow 	*dev = makedevice(nsmb_major, nsmb_minor);
841*4bff34e3Sthurlow 
842*4bff34e3Sthurlow 	return (0);
843*4bff34e3Sthurlow }
844*4bff34e3Sthurlow 
845*4bff34e3Sthurlow /*ARGSUSED*/
846*4bff34e3Sthurlow static int
847*4bff34e3Sthurlow nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
848*4bff34e3Sthurlow {
849*4bff34e3Sthurlow 	struct smb_vc *vcp;
850*4bff34e3Sthurlow 	struct smb_share *ssp;
851*4bff34e3Sthurlow 	struct smb_cred scred;
852*4bff34e3Sthurlow 	minor_t inst = getminor(dev);
853*4bff34e3Sthurlow 	smb_dev_t *sdp;
854*4bff34e3Sthurlow 
855*4bff34e3Sthurlow 	mutex_enter(&dev_lck);
856*4bff34e3Sthurlow 	/*
857*4bff34e3Sthurlow 	 * 1. Check the validity of the minor number.
858*4bff34e3Sthurlow 	 * 2. Release any shares/vc associated  with the connection.
859*4bff34e3Sthurlow 	 * 3. Can close the minor number.
860*4bff34e3Sthurlow 	 * 4. Deallocate any resources allocated in open() call.
861*4bff34e3Sthurlow 	 */
862*4bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
863*4bff34e3Sthurlow 
864*4bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, inst);
865*4bff34e3Sthurlow 
866*4bff34e3Sthurlow 	/*
867*4bff34e3Sthurlow 	 * time to call ddi_get_soft_state()
868*4bff34e3Sthurlow 	 */
869*4bff34e3Sthurlow 	ssp = sdp->sd_share;
870*4bff34e3Sthurlow 	if (ssp != NULL)
871*4bff34e3Sthurlow 		smb_share_rele(ssp);
872*4bff34e3Sthurlow 	vcp = sdp->sd_vc;
873*4bff34e3Sthurlow 	if (vcp != NULL) {
874*4bff34e3Sthurlow 		/*
875*4bff34e3Sthurlow 		 * If this dev minor was doing session setup
876*4bff34e3Sthurlow 		 * and failed to authenticate (or whatever)
877*4bff34e3Sthurlow 		 * then we need to "kill" the VC here so any
878*4bff34e3Sthurlow 		 * other threads waiting for the VC setup to
879*4bff34e3Sthurlow 		 * finish will drop their references.
880*4bff34e3Sthurlow 		 */
881*4bff34e3Sthurlow 		if (sdp->sd_flags & NSMBFL_NEWVC)
882*4bff34e3Sthurlow 			smb_vc_kill(vcp);
883*4bff34e3Sthurlow 		smb_vc_rele(vcp);
884*4bff34e3Sthurlow 	}
885*4bff34e3Sthurlow 	smb_credrele(&scred);
886*4bff34e3Sthurlow 
887*4bff34e3Sthurlow 	/*
888*4bff34e3Sthurlow 	 * Free the instance
889*4bff34e3Sthurlow 	 */
890*4bff34e3Sthurlow 	ddi_soft_state_free(statep, inst);
891*4bff34e3Sthurlow 	mutex_exit(&dev_lck);
892*4bff34e3Sthurlow 	return (0);
893*4bff34e3Sthurlow }
894*4bff34e3Sthurlow 
895*4bff34e3Sthurlow int
896*4bff34e3Sthurlow smb_dev2share(int fd, struct smb_share **sspp)
897*4bff34e3Sthurlow {
898*4bff34e3Sthurlow 	register vnode_t *vp;
899*4bff34e3Sthurlow 	smb_dev_t *sdp;
900*4bff34e3Sthurlow 	struct smb_share *ssp;
901*4bff34e3Sthurlow 	dev_t dev;
902*4bff34e3Sthurlow 	file_t *fp;
903*4bff34e3Sthurlow 
904*4bff34e3Sthurlow 	if ((fp = getf(fd)) == NULL)
905*4bff34e3Sthurlow 		return (set_errno(EBADF));
906*4bff34e3Sthurlow 	vp = fp->f_vnode;
907*4bff34e3Sthurlow 	dev = vp->v_rdev;
908*4bff34e3Sthurlow 	if (dev == NULL) {
909*4bff34e3Sthurlow 		releasef(fd);
910*4bff34e3Sthurlow 		return (EBADF);
911*4bff34e3Sthurlow 	}
912*4bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
913*4bff34e3Sthurlow 	if (sdp == NULL) {
914*4bff34e3Sthurlow 		releasef(fd);
915*4bff34e3Sthurlow 		return (DDI_FAILURE);
916*4bff34e3Sthurlow 	}
917*4bff34e3Sthurlow 	ssp = sdp->sd_share;
918*4bff34e3Sthurlow 	if (ssp == NULL) {
919*4bff34e3Sthurlow 		releasef(fd);
920*4bff34e3Sthurlow 		return (ENOTCONN);
921*4bff34e3Sthurlow 	}
922*4bff34e3Sthurlow 	/*
923*4bff34e3Sthurlow 	 * The share is already locked and referenced by the TCON ioctl
924*4bff34e3Sthurlow 	 * We NULL to hand off share to caller (mount)
925*4bff34e3Sthurlow 	 * This allows further ioctls against connection, for instance
926*4bff34e3Sthurlow 	 * another tree connect and mount, in the automounter case
927*4bff34e3Sthurlow 	 *
928*4bff34e3Sthurlow 	 * We're effectively giving our reference to the mount.
929*4bff34e3Sthurlow 	 *
930*4bff34e3Sthurlow 	 * XXX: I'm not sure I like this.  I'd rather see the ioctl
931*4bff34e3Sthurlow 	 * caller do something explicit to give up this reference,
932*4bff34e3Sthurlow 	 * (i.e. SMBIOC_TDIS above) and increment the hold here.
933*4bff34e3Sthurlow 	 */
934*4bff34e3Sthurlow 	sdp->sd_share = NULL;
935*4bff34e3Sthurlow 	releasef(fd);
936*4bff34e3Sthurlow 	*sspp = ssp;
937*4bff34e3Sthurlow 	return (0);
938*4bff34e3Sthurlow }
939