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_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow /*
364bff34e3Sthurlow  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
374bff34e3Sthurlow  * Use is subject to license terms.
384bff34e3Sthurlow  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/types.h>
414bff34e3Sthurlow #include <sys/param.h>
424bff34e3Sthurlow #include <sys/errno.h>
434bff34e3Sthurlow #include <sys/sysmacros.h>
444bff34e3Sthurlow #include <sys/uio.h>
454bff34e3Sthurlow #include <sys/buf.h>
464bff34e3Sthurlow #include <sys/modctl.h>
474bff34e3Sthurlow #include <sys/open.h>
484bff34e3Sthurlow #include <sys/file.h>
494bff34e3Sthurlow #include <sys/kmem.h>
504bff34e3Sthurlow #include <sys/conf.h>
514bff34e3Sthurlow #include <sys/cmn_err.h>
524bff34e3Sthurlow #include <sys/stat.h>
534bff34e3Sthurlow #include <sys/ddi.h>
544bff34e3Sthurlow #include <sys/sunddi.h>
554bff34e3Sthurlow #include <sys/sunldi.h>
564bff34e3Sthurlow #include <sys/policy.h>
574bff34e3Sthurlow #include <sys/zone.h>
584bff34e3Sthurlow #include <sys/pathname.h>
594bff34e3Sthurlow #include <sys/mount.h>
604bff34e3Sthurlow #include <sys/sdt.h>
614bff34e3Sthurlow #include <fs/fs_subr.h>
624bff34e3Sthurlow #include <sys/modctl.h>
634bff34e3Sthurlow #include <sys/devops.h>
644bff34e3Sthurlow #include <sys/thread.h>
654bff34e3Sthurlow #include <sys/mkdev.h>
664bff34e3Sthurlow #include <sys/types.h>
674bff34e3Sthurlow #include <sys/zone.h>
684bff34e3Sthurlow 
694bff34e3Sthurlow #ifdef APPLE
704bff34e3Sthurlow #include <sys/smb_apple.h>
714bff34e3Sthurlow #else
724bff34e3Sthurlow #include <netsmb/smb_osdep.h>
734bff34e3Sthurlow #endif
744bff34e3Sthurlow 
754bff34e3Sthurlow #include <netsmb/mchain.h>		/* for "htoles()" */
764bff34e3Sthurlow 
774bff34e3Sthurlow #include <netsmb/smb.h>
784bff34e3Sthurlow #include <netsmb/smb_conn.h>
794bff34e3Sthurlow #include <netsmb/smb_subr.h>
804bff34e3Sthurlow #include <netsmb/smb_dev.h>
814bff34e3Sthurlow #include <netsmb/smb_pass.h>
824bff34e3Sthurlow 
834bff34e3Sthurlow /* for version checks */
844bff34e3Sthurlow const uint32_t nsmb_version = NSMB_VERSION;
854bff34e3Sthurlow 
864bff34e3Sthurlow /*
874bff34e3Sthurlow  * Userland code loops through minor #s 0 to 1023, looking for one which opens.
884bff34e3Sthurlow  * Intially we create minor 0 and leave it for anyone.  Minor zero will never
894bff34e3Sthurlow  * actually get used - opening triggers creation of another (but private) minor,
904bff34e3Sthurlow  * which userland code will get to and mark busy.
914bff34e3Sthurlow  */
924bff34e3Sthurlow #define	SMBMINORS 1024
934bff34e3Sthurlow static void *statep;
944bff34e3Sthurlow static major_t nsmb_major;
954bff34e3Sthurlow static minor_t nsmb_minor = 1;
964bff34e3Sthurlow 
974bff34e3Sthurlow #define	NSMB_MAX_MINOR  (1 << 8)
984bff34e3Sthurlow #define	NSMB_MIN_MINOR   (NSMB_MAX_MINOR + 1)
994bff34e3Sthurlow 
1004bff34e3Sthurlow #define	ILP32	1
1014bff34e3Sthurlow #define	LP64	2
1024bff34e3Sthurlow 
1034bff34e3Sthurlow static kmutex_t  dev_lck;
1044bff34e3Sthurlow 
1054bff34e3Sthurlow /* Zone support */
1064bff34e3Sthurlow zone_key_t nsmb_zone_key;
1074bff34e3Sthurlow extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
1084bff34e3Sthurlow extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
1094bff34e3Sthurlow 
1104bff34e3Sthurlow /*
1114bff34e3Sthurlow  * cb_ops device operations.
1124bff34e3Sthurlow  */
1134bff34e3Sthurlow static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
1144bff34e3Sthurlow static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
1154bff34e3Sthurlow static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1164bff34e3Sthurlow 				cred_t *credp, int *rvalp);
1174bff34e3Sthurlow /* smbfs cb_ops */
1184bff34e3Sthurlow static struct cb_ops nsmb_cbops = {
1194bff34e3Sthurlow 	nsmb_open,	/* open */
1204bff34e3Sthurlow 	nsmb_close,	/* close */
1214bff34e3Sthurlow 	nodev,		/* strategy */
1224bff34e3Sthurlow 	nodev,		/* print */
1234bff34e3Sthurlow 	nodev,		/* dump */
1244bff34e3Sthurlow 	nodev,		/* read */
1254bff34e3Sthurlow 	nodev,		/* write */
1264bff34e3Sthurlow 	nsmb_ioctl,	/* ioctl */
1274bff34e3Sthurlow 	nodev,		/* devmap */
1284bff34e3Sthurlow 	nodev,		/* mmap */
1294bff34e3Sthurlow 	nodev,		/* segmap */
1304bff34e3Sthurlow 	nochpoll,	/* poll */
1314bff34e3Sthurlow 	ddi_prop_op,	/* prop_op */
1324bff34e3Sthurlow 	NULL,		/* stream */
1334bff34e3Sthurlow 	D_MP,		/* cb_flag */
1344bff34e3Sthurlow 	CB_REV,		/* rev */
1354bff34e3Sthurlow 	nodev,		/* int (*cb_aread)() */
1364bff34e3Sthurlow 	nodev		/* int (*cb_awrite)() */
1374bff34e3Sthurlow };
1384bff34e3Sthurlow 
1394bff34e3Sthurlow /*
1404bff34e3Sthurlow  * Device options
1414bff34e3Sthurlow  */
1424bff34e3Sthurlow static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1434bff34e3Sthurlow static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1444bff34e3Sthurlow static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1454bff34e3Sthurlow 	void *arg, void **result);
1464bff34e3Sthurlow 
1474bff34e3Sthurlow static struct dev_ops nsmb_ops = {
1484bff34e3Sthurlow 	DEVO_REV,	/* devo_rev, */
1494bff34e3Sthurlow 	0,		/* refcnt  */
1504bff34e3Sthurlow 	nsmb_getinfo,	/* info */
1514bff34e3Sthurlow 	nulldev,	/* identify */
1524bff34e3Sthurlow 	nulldev,	/* probe */
1534bff34e3Sthurlow 	nsmb_attach,	/* attach */
1544bff34e3Sthurlow 	nsmb_detach,	/* detach */
1554bff34e3Sthurlow 	nodev,		/* reset */
1564bff34e3Sthurlow 	&nsmb_cbops,	/* driver ops - devctl interfaces */
1574bff34e3Sthurlow 	NULL,		/* bus operations */
1584bff34e3Sthurlow 	NULL		/* power */
1594bff34e3Sthurlow };
1604bff34e3Sthurlow 
1614bff34e3Sthurlow /*
1624bff34e3Sthurlow  * Module linkage information.
1634bff34e3Sthurlow  */
1644bff34e3Sthurlow 
1654bff34e3Sthurlow static struct modldrv nsmb_modldrv = {
1664bff34e3Sthurlow 	&mod_driverops,				/* Driver module */
1674bff34e3Sthurlow 	"SMBFS network driver v" NSMB_VER_STR,
1684bff34e3Sthurlow 	&nsmb_ops				/* Driver ops */
1694bff34e3Sthurlow };
1704bff34e3Sthurlow 
1714bff34e3Sthurlow static struct modlinkage nsmb_modlinkage = {
1724bff34e3Sthurlow 	MODREV_1,
1734bff34e3Sthurlow 	(void *)&nsmb_modldrv,
1744bff34e3Sthurlow 	NULL
1754bff34e3Sthurlow };
1764bff34e3Sthurlow 
1774bff34e3Sthurlow int
1784bff34e3Sthurlow _init(void)
1794bff34e3Sthurlow {
1804bff34e3Sthurlow 	int error;
1814bff34e3Sthurlow 
1824bff34e3Sthurlow 	ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
1834bff34e3Sthurlow 
1844bff34e3Sthurlow 	/* Can initialize some mutexes also. */
1854bff34e3Sthurlow 	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
1864bff34e3Sthurlow 	/*
1874bff34e3Sthurlow 	 * Create a major name and number.
1884bff34e3Sthurlow 	 */
1894bff34e3Sthurlow 	nsmb_major = ddi_name_to_major(NSMB_NAME);
1904bff34e3Sthurlow 	nsmb_minor = 0;
1914bff34e3Sthurlow 
1924bff34e3Sthurlow 	/* Connection data structures. */
1934bff34e3Sthurlow 	(void) smb_sm_init();
1944bff34e3Sthurlow 
1954bff34e3Sthurlow 	/* Initialize password Key chain DB. */
1964bff34e3Sthurlow 	smb_pkey_init();
1974bff34e3Sthurlow 
1984bff34e3Sthurlow 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
1994bff34e3Sthurlow 	    nsmb_zone_destroy);
2004bff34e3Sthurlow 
2014bff34e3Sthurlow 	/*
2024bff34e3Sthurlow 	 * Install the module.  Do this after other init,
2034bff34e3Sthurlow 	 * to prevent entrances before we're ready.
2044bff34e3Sthurlow 	 */
2054bff34e3Sthurlow 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
2064bff34e3Sthurlow 
2074bff34e3Sthurlow 		/* Same as 2nd half of _fini */
2084bff34e3Sthurlow 		(void) zone_key_delete(nsmb_zone_key);
2094bff34e3Sthurlow 		smb_pkey_fini();
2104bff34e3Sthurlow 		smb_sm_done();
2114bff34e3Sthurlow 		mutex_destroy(&dev_lck);
2124bff34e3Sthurlow 		ddi_soft_state_fini(&statep);
2134bff34e3Sthurlow 
2144bff34e3Sthurlow 		return (error);
2154bff34e3Sthurlow 	}
2164bff34e3Sthurlow 
2174bff34e3Sthurlow 	return (0);
2184bff34e3Sthurlow }
2194bff34e3Sthurlow 
2204bff34e3Sthurlow int
2214bff34e3Sthurlow _fini(void)
2224bff34e3Sthurlow {
2234bff34e3Sthurlow 	int status;
2244bff34e3Sthurlow 
2254bff34e3Sthurlow 	/*
2264bff34e3Sthurlow 	 * Prevent unload if we have active VCs
2274bff34e3Sthurlow 	 * or stored passwords
2284bff34e3Sthurlow 	 */
2294bff34e3Sthurlow 	if ((status = smb_sm_idle()) != 0)
2304bff34e3Sthurlow 		return (status);
2314bff34e3Sthurlow 	if ((status = smb_pkey_idle()) != 0)
2324bff34e3Sthurlow 		return (status);
2334bff34e3Sthurlow 
2344bff34e3Sthurlow 	/*
2354bff34e3Sthurlow 	 * Remove the module.  Do this before destroying things,
2364bff34e3Sthurlow 	 * to prevent new entrances while we're destorying.
2374bff34e3Sthurlow 	 */
2384bff34e3Sthurlow 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
2394bff34e3Sthurlow 		return (status);
2404bff34e3Sthurlow 	}
2414bff34e3Sthurlow 
2424bff34e3Sthurlow 	(void) zone_key_delete(nsmb_zone_key);
2434bff34e3Sthurlow 
2444bff34e3Sthurlow 	/* Destroy password Key chain DB. */
2454bff34e3Sthurlow 	smb_pkey_fini();
2464bff34e3Sthurlow 
2474bff34e3Sthurlow 	smb_sm_done();
2484bff34e3Sthurlow 
2494bff34e3Sthurlow 	mutex_destroy(&dev_lck);
2504bff34e3Sthurlow 	ddi_soft_state_fini(&statep);
2514bff34e3Sthurlow 
2524bff34e3Sthurlow 	return (status);
2534bff34e3Sthurlow }
2544bff34e3Sthurlow 
2554bff34e3Sthurlow int
2564bff34e3Sthurlow _info(struct modinfo *modinfop)
2574bff34e3Sthurlow {
2584bff34e3Sthurlow 	return (mod_info(&nsmb_modlinkage, modinfop));
2594bff34e3Sthurlow }
2604bff34e3Sthurlow 
2614bff34e3Sthurlow /*ARGSUSED*/
2624bff34e3Sthurlow static int
2634bff34e3Sthurlow nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2644bff34e3Sthurlow {
2654bff34e3Sthurlow 	int ret = DDI_SUCCESS;
2664bff34e3Sthurlow 
2674bff34e3Sthurlow 	switch (cmd) {
2684bff34e3Sthurlow 	case DDI_INFO_DEVT2DEVINFO:
2694bff34e3Sthurlow 		*result = 0;
2704bff34e3Sthurlow 		break;
2714bff34e3Sthurlow 	case DDI_INFO_DEVT2INSTANCE:
2724bff34e3Sthurlow 		*result = 0;
2734bff34e3Sthurlow 		break;
2744bff34e3Sthurlow 	default:
2754bff34e3Sthurlow 		ret = DDI_FAILURE;
2764bff34e3Sthurlow 	}
2774bff34e3Sthurlow 	return (ret);
2784bff34e3Sthurlow }
2794bff34e3Sthurlow 
2804bff34e3Sthurlow static int
2814bff34e3Sthurlow nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2824bff34e3Sthurlow {
2834bff34e3Sthurlow 	smb_dev_t *sdp;
2844bff34e3Sthurlow 
2854bff34e3Sthurlow 	if (cmd != DDI_ATTACH)
2864bff34e3Sthurlow 		return (DDI_FAILURE);
2874bff34e3Sthurlow 	/*
2884bff34e3Sthurlow 	 * only one instance - but we clone using the open routine
2894bff34e3Sthurlow 	 */
2904bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
2914bff34e3Sthurlow 		return (DDI_FAILURE);
2924bff34e3Sthurlow 
2934bff34e3Sthurlow 	mutex_enter(&dev_lck);
2944bff34e3Sthurlow 
2954bff34e3Sthurlow 	/*
2964bff34e3Sthurlow 	 * This is the Zero'th minor device which is created.
2974bff34e3Sthurlow 	 */
2984bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) {
2994bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: soft state alloc");
3004bff34e3Sthurlow 		goto attach_failed;
3014bff34e3Sthurlow 	}
3024bff34e3Sthurlow 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
3034bff34e3Sthurlow 	    NULL) == DDI_FAILURE) {
3044bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: create minor");
3054bff34e3Sthurlow 		goto attach_failed;
3064bff34e3Sthurlow 	}
3074bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) {
3084bff34e3Sthurlow 		cmn_err(CE_WARN, "nsmb_attach: get soft state");
3094bff34e3Sthurlow 		ddi_remove_minor_node(dip, NULL);
3104bff34e3Sthurlow 		goto attach_failed;
3114bff34e3Sthurlow 	}
3124bff34e3Sthurlow 
3134bff34e3Sthurlow 	/*
3144bff34e3Sthurlow 	 * Need to see if this field is required.
3154bff34e3Sthurlow 	 * REVISIT
3164bff34e3Sthurlow 	 */
3174bff34e3Sthurlow 	sdp->smb_dip = dip;
3184bff34e3Sthurlow 	sdp->sd_seq = 0;
3194bff34e3Sthurlow 	sdp->sd_opened = 1;
3204bff34e3Sthurlow 
3214bff34e3Sthurlow 	mutex_exit(&dev_lck);
3224bff34e3Sthurlow 	ddi_report_dev(dip);
3234bff34e3Sthurlow 	return (DDI_SUCCESS);
3244bff34e3Sthurlow 
3254bff34e3Sthurlow attach_failed:
3264bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
3274bff34e3Sthurlow 	mutex_exit(&dev_lck);
3284bff34e3Sthurlow 	return (DDI_FAILURE);
3294bff34e3Sthurlow }
3304bff34e3Sthurlow 
3314bff34e3Sthurlow /*ARGSUSED*/
3324bff34e3Sthurlow static int
3334bff34e3Sthurlow nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3344bff34e3Sthurlow {
3354bff34e3Sthurlow 
3364bff34e3Sthurlow 	if (cmd != DDI_DETACH)
3374bff34e3Sthurlow 		return (DDI_FAILURE);
3384bff34e3Sthurlow 	if (ddi_get_instance(dip) > 0)
3394bff34e3Sthurlow 		return (DDI_FAILURE);
3404bff34e3Sthurlow 
3414bff34e3Sthurlow 	ddi_soft_state_free(statep, 0);
3424bff34e3Sthurlow 	ddi_remove_minor_node(dip, NULL);
3434bff34e3Sthurlow 
3444bff34e3Sthurlow 	return (DDI_SUCCESS);
3454bff34e3Sthurlow }
3464bff34e3Sthurlow 
3474bff34e3Sthurlow /*ARGSUSED*/
3484bff34e3Sthurlow static int
3494bff34e3Sthurlow nsmb_ioctl(dev_t dev,
3504bff34e3Sthurlow 	    int cmd,
3514bff34e3Sthurlow 	    intptr_t arg,
3524bff34e3Sthurlow 	    int mode,
3534bff34e3Sthurlow 	    cred_t *credp,
3544bff34e3Sthurlow 	    int *rvalp)
3554bff34e3Sthurlow {
3564bff34e3Sthurlow 	smb_dev_t *sdp;
3574bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
3584bff34e3Sthurlow 	struct smb_share *ssp = NULL;
3594bff34e3Sthurlow 	struct smb_cred scred;
3604bff34e3Sthurlow 	int err, error;
3614bff34e3Sthurlow 	uid_t uid;
3624bff34e3Sthurlow 
3634bff34e3Sthurlow 	/* Free any+all of these at end of switch. */
3644bff34e3Sthurlow 	smbioc_lookup_t *sioc = NULL;
3654bff34e3Sthurlow 	smbioc_rq_t *srq = NULL;
3664bff34e3Sthurlow 	smbioc_rw_t *rwrq = NULL;
3674bff34e3Sthurlow 	smbioc_t2rq_t *strq = NULL;
3684bff34e3Sthurlow 	smbioc_pk_t  *pk = NULL;
3694bff34e3Sthurlow 
3704bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
3714bff34e3Sthurlow 	if (sdp == NULL) {
3724bff34e3Sthurlow 		return (DDI_FAILURE);
3734bff34e3Sthurlow 	}
3744bff34e3Sthurlow 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
3754bff34e3Sthurlow 		return (EBADF);
3764bff34e3Sthurlow 	}
3774bff34e3Sthurlow 
3784bff34e3Sthurlow 	/*
3794bff34e3Sthurlow 	 * Dont give access if the zone id is not as the same as we
3804bff34e3Sthurlow 	 * set in the nsmb_open or dont belong to the global zone.
3814bff34e3Sthurlow 	 * Check if the user belongs to this zone..
3824bff34e3Sthurlow 	 */
3834bff34e3Sthurlow 	if (sdp->zoneid != getzoneid())
3844bff34e3Sthurlow 		return (EIO);
3854bff34e3Sthurlow 	if (cmd != SMBIOC_TDIS &&
3864bff34e3Sthurlow 	    zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)
3874bff34e3Sthurlow 		return (EIO);
3884bff34e3Sthurlow 
3894bff34e3Sthurlow 
3904bff34e3Sthurlow 	error = 0;
3914bff34e3Sthurlow 	smb_credinit(&scred, curproc, credp);
3924bff34e3Sthurlow 	switch (cmd) {
3934bff34e3Sthurlow 		case SMBIOC_GETVERS:
3944bff34e3Sthurlow 			ddi_copyout(&nsmb_version, (void *)arg,
3954bff34e3Sthurlow 			    sizeof (nsmb_version), mode);
3964bff34e3Sthurlow 			break;
3974bff34e3Sthurlow 
3984bff34e3Sthurlow 		case SMBIOC_REQUEST:
3994bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
4004bff34e3Sthurlow 				error = ENOTCONN;
4014bff34e3Sthurlow 				break;
4024bff34e3Sthurlow 			}
4034bff34e3Sthurlow 			srq = kmem_alloc(sizeof (*srq), KM_SLEEP);
4044bff34e3Sthurlow 			if (ddi_copyin((void *) arg, srq,
4054bff34e3Sthurlow 			    sizeof (*srq), mode)) {
4064bff34e3Sthurlow 				error = EFAULT;
4074bff34e3Sthurlow 				break;
4084bff34e3Sthurlow 			}
4094bff34e3Sthurlow 			error = smb_usr_simplerequest(sdp->sd_share,
4104bff34e3Sthurlow 			    srq, &scred);
4114bff34e3Sthurlow 			ddi_copyout(srq, (void *)arg,
4124bff34e3Sthurlow 			    SMBIOC_RQ_COPYOUT_SIZE, mode);
4134bff34e3Sthurlow 			break;
4144bff34e3Sthurlow 
4154bff34e3Sthurlow 		case SMBIOC_T2RQ:
4164bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
4174bff34e3Sthurlow 				error = ENOTCONN;
4184bff34e3Sthurlow 				break;
4194bff34e3Sthurlow 			}
4204bff34e3Sthurlow 			strq = kmem_alloc(sizeof (*strq), KM_SLEEP);
4214bff34e3Sthurlow 			if (ddi_copyin((void *)arg, strq,
4224bff34e3Sthurlow 			    sizeof (*strq), mode)) {
4234bff34e3Sthurlow 				error = EFAULT;
4244bff34e3Sthurlow 				break;
4254bff34e3Sthurlow 			}
4264bff34e3Sthurlow 			error = smb_usr_t2request(sdp->sd_share, strq, &scred);
4274bff34e3Sthurlow 			ddi_copyout(strq, (void *)arg,
4284bff34e3Sthurlow 			    SMBIOC_T2RQ_COPYOUT_SIZE, mode);
4294bff34e3Sthurlow 			break;
4304bff34e3Sthurlow 
4314bff34e3Sthurlow 		case SMBIOC_READ:
4324bff34e3Sthurlow 		case SMBIOC_WRITE:
4334bff34e3Sthurlow 			if ((ssp = sdp->sd_share) == NULL) {
4344bff34e3Sthurlow 				error = ENOTCONN;
4354bff34e3Sthurlow 				break;
4364bff34e3Sthurlow 			}
4374bff34e3Sthurlow 			rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP);
4384bff34e3Sthurlow 			if (ddi_copyin((void *)arg, rwrq,
4394bff34e3Sthurlow 			    sizeof (*rwrq), mode)) {
4404bff34e3Sthurlow 				error = EFAULT;
4414bff34e3Sthurlow 				break;
4424bff34e3Sthurlow 			}
4434bff34e3Sthurlow 			error = smb_usr_rw(ssp, rwrq, cmd, &scred);
4444bff34e3Sthurlow 			ddi_copyout(rwrq, (void *)arg,
4454bff34e3Sthurlow 			    SMBIOC_RW_COPYOUT_SIZE, mode);
4464bff34e3Sthurlow 			break;
4474bff34e3Sthurlow 
4481b34bc4aSbs 		case SMBIOC_FINDVC:
4491b34bc4aSbs 			/* Should be no VC and no share */
4501b34bc4aSbs 			if (sdp->sd_vc || sdp->sd_share) {
4511b34bc4aSbs 				error = EISCONN;
4521b34bc4aSbs 				break;
4531b34bc4aSbs 			}
4541b34bc4aSbs 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
4551b34bc4aSbs 			if (ddi_copyin((void *)arg, sioc,
4561b34bc4aSbs 			    sizeof (*sioc), mode)) {
4571b34bc4aSbs 				error = EFAULT;
4581b34bc4aSbs 				break;
4591b34bc4aSbs 			}
4601b34bc4aSbs 			vcp = NULL;
4611b34bc4aSbs 			ssp = NULL;
4621b34bc4aSbs 			error = smb_usr_findvc(sioc, &scred, &vcp);
4631b34bc4aSbs 			if (error)
4641b34bc4aSbs 				break;
4651b34bc4aSbs 			if (vcp) {
4661b34bc4aSbs 				/*
4671b34bc4aSbs 				 * The VC has a hold from _findvc
4681b34bc4aSbs 				 * which we keep until nsmb_close().
4691b34bc4aSbs 				 */
4701b34bc4aSbs 				sdp->sd_level = SMBL_VC;
4711b34bc4aSbs 				sdp->sd_vc = vcp;
4721b34bc4aSbs 			}
4731b34bc4aSbs 			(void) ddi_copyout(sioc, (void *)arg,
4741b34bc4aSbs 			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
4751b34bc4aSbs 
4761b34bc4aSbs 			break;
4771b34bc4aSbs 
4784bff34e3Sthurlow 		case SMBIOC_NEGOTIATE:
4794bff34e3Sthurlow 			/* Should be no VC (and no share) */
4804bff34e3Sthurlow 			if (sdp->sd_vc || sdp->sd_share) {
4814bff34e3Sthurlow 				error = EISCONN;
4824bff34e3Sthurlow 				break;
4834bff34e3Sthurlow 			}
4844bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
4854bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
4864bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
4874bff34e3Sthurlow 				error = EFAULT;
4884bff34e3Sthurlow 				break;
4894bff34e3Sthurlow 			}
4904bff34e3Sthurlow 			vcp = NULL;
4914bff34e3Sthurlow 			ssp = NULL;
4924bff34e3Sthurlow 			error = smb_usr_negotiate(sioc, &scred, &vcp);
4934bff34e3Sthurlow 			if (error)
4944bff34e3Sthurlow 				break;
4954bff34e3Sthurlow 			if (vcp) {
4964bff34e3Sthurlow 				/*
4974bff34e3Sthurlow 				 * The VC has a hold from _negotiate
4984bff34e3Sthurlow 				 * which we keep until nsmb_close().
4994bff34e3Sthurlow 				 */
5004bff34e3Sthurlow 				sdp->sd_level = SMBL_VC;
5014bff34e3Sthurlow 				sdp->sd_vc = vcp;
5024bff34e3Sthurlow 				/*
5034bff34e3Sthurlow 				 * If we just created this VC, and
5044bff34e3Sthurlow 				 * this minor is doing the setup,
5054bff34e3Sthurlow 				 * keep track of that fact here.
5064bff34e3Sthurlow 				 */
5074bff34e3Sthurlow 				if (vcp->vc_state < SMBIOD_ST_VCACTIVE)
5084bff34e3Sthurlow 					sdp->sd_flags |= NSMBFL_NEWVC;
5094bff34e3Sthurlow 
5104bff34e3Sthurlow 			}
5114bff34e3Sthurlow 			/*
5124bff34e3Sthurlow 			 * Copyout the "out token" (security blob).
5134bff34e3Sthurlow 			 *
5144bff34e3Sthurlow 			 * This code used to be near the end of
5154bff34e3Sthurlow 			 * smb_usr_negotiate().  Moved the copyout
5164bff34e3Sthurlow 			 * calls here so we know the "mode"
5174bff34e3Sthurlow 			 */
5184bff34e3Sthurlow 			if (vcp->vc_outtok) {
5194bff34e3Sthurlow 				/*
5204bff34e3Sthurlow 				 * Note: will copyout sioc below
5214bff34e3Sthurlow 				 * including sioc.vc_outtoklen,
5224bff34e3Sthurlow 				 * so we no longer put the length
5234bff34e3Sthurlow 				 * at the start of the outtok data.
5244bff34e3Sthurlow 				 */
5254bff34e3Sthurlow 				sioc->ioc_ssn.ioc_outtoklen =
5264bff34e3Sthurlow 				    vcp->vc_outtoklen;
5274bff34e3Sthurlow 				err = ddi_copyout(
5284bff34e3Sthurlow 				    vcp->vc_outtok,
5294bff34e3Sthurlow 				    sioc->ioc_ssn.ioc_outtok,
5304bff34e3Sthurlow 				    vcp->vc_outtoklen, mode);
5314bff34e3Sthurlow 				if (err) {
5324bff34e3Sthurlow 					error = EFAULT;
5334bff34e3Sthurlow 					break;
5344bff34e3Sthurlow 				}
5354bff34e3Sthurlow 				/*
5364bff34e3Sthurlow 				 * Save this blob in vc_negtok.
5374bff34e3Sthurlow 				 * We need it in case we have to
5384bff34e3Sthurlow 				 * reconnect.
5394bff34e3Sthurlow 				 *
5404bff34e3Sthurlow 				 * Set vc_negtok = vc_outtok
5414bff34e3Sthurlow 				 * but free vc_negtok first.
5424bff34e3Sthurlow 				 */
5434bff34e3Sthurlow 				if (vcp->vc_negtok) {
5444bff34e3Sthurlow 					kmem_free(
5454bff34e3Sthurlow 					    vcp->vc_negtok,
5464bff34e3Sthurlow 					    vcp->vc_negtoklen);
5474bff34e3Sthurlow 					vcp->vc_negtok = NULL;
5484bff34e3Sthurlow 					vcp->vc_negtoklen = 0;
5494bff34e3Sthurlow 				}
5504bff34e3Sthurlow 				vcp->vc_negtok    = vcp->vc_outtok;
5514bff34e3Sthurlow 				vcp->vc_negtoklen = vcp->vc_outtoklen;
5524bff34e3Sthurlow 				vcp->vc_outtok = NULL;
5534bff34e3Sthurlow 				vcp->vc_outtoklen = 0;
5544bff34e3Sthurlow 			}
5554bff34e3Sthurlow 			/*
5564bff34e3Sthurlow 			 * Added copyout here of (almost)
5574bff34e3Sthurlow 			 * the whole struct, even though
5584bff34e3Sthurlow 			 * the lib only needs _outtoklen.
5594bff34e3Sthurlow 			 * We may put other things in this
5604bff34e3Sthurlow 			 * struct that user-land needs.
5614bff34e3Sthurlow 			 */
5624bff34e3Sthurlow 			err = ddi_copyout(sioc, (void *)arg,
5634bff34e3Sthurlow 			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
5644bff34e3Sthurlow 			if (err)
5654bff34e3Sthurlow 				error = EFAULT;
5664bff34e3Sthurlow 			break;
5674bff34e3Sthurlow 
5684bff34e3Sthurlow 		case SMBIOC_SSNSETUP:
5694bff34e3Sthurlow 			/* Must have a VC, but no share. */
5704bff34e3Sthurlow 			if (sdp->sd_share) {
5714bff34e3Sthurlow 				error = EISCONN;
5724bff34e3Sthurlow 				break;
5734bff34e3Sthurlow 			}
5744bff34e3Sthurlow 			if (!sdp->sd_vc) {
5754bff34e3Sthurlow 				error = ENOTCONN;
5764bff34e3Sthurlow 				break;
5774bff34e3Sthurlow 			}
5784bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
5794bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
5804bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
5814bff34e3Sthurlow 				error = EFAULT;
5824bff34e3Sthurlow 				break;
5834bff34e3Sthurlow 			}
5844bff34e3Sthurlow 			vcp = sdp->sd_vc;
5854bff34e3Sthurlow 			ssp = NULL;
5864bff34e3Sthurlow 			error = smb_usr_ssnsetup(sioc, &scred, vcp);
5874bff34e3Sthurlow 			if (error)
5884bff34e3Sthurlow 				break;
5894bff34e3Sthurlow 			/*
5904bff34e3Sthurlow 			 * If this minor has finished ssn setup,
5914bff34e3Sthurlow 			 * turn off the NEWVC flag, otherwise we
5924bff34e3Sthurlow 			 * will kill this VC when we close.
5934bff34e3Sthurlow 			 */
5944bff34e3Sthurlow 			if (vcp->vc_state == SMBIOD_ST_VCACTIVE)
5954bff34e3Sthurlow 				sdp->sd_flags &= ~NSMBFL_NEWVC;
5964bff34e3Sthurlow 			/*
5974bff34e3Sthurlow 			 * Copyout the "out token" (security blob).
5984bff34e3Sthurlow 			 *
5994bff34e3Sthurlow 			 * This code used to be near the end of
6004bff34e3Sthurlow 			 * smb_usr_ssnsetup().  Moved the copyout
6014bff34e3Sthurlow 			 * calls here so we know the "mode"
6024bff34e3Sthurlow 			 */
6034bff34e3Sthurlow 			if (vcp->vc_outtok) {
6044bff34e3Sthurlow 				/*
6054bff34e3Sthurlow 				 * Note: will copyout sioc below
6064bff34e3Sthurlow 				 * including sioc.vc_outtoklen,
6074bff34e3Sthurlow 				 * so we no longer put the length
6084bff34e3Sthurlow 				 * at the start of the outtok data.
6094bff34e3Sthurlow 				 */
6104bff34e3Sthurlow 				sioc->ioc_ssn.ioc_outtoklen =
6114bff34e3Sthurlow 				    vcp->vc_outtoklen;
6124bff34e3Sthurlow 				err = ddi_copyout(
6134bff34e3Sthurlow 				    vcp->vc_outtok,
6144bff34e3Sthurlow 				    sioc->ioc_ssn.ioc_outtok,
6154bff34e3Sthurlow 				    vcp->vc_outtoklen, mode);
6164bff34e3Sthurlow 				if (err) {
6174bff34e3Sthurlow 					error = EFAULT;
6184bff34e3Sthurlow 					break;
6194bff34e3Sthurlow 				}
6204bff34e3Sthurlow 				/*
6214bff34e3Sthurlow 				 * Done with vc_outtok.  Similar,
6224bff34e3Sthurlow 				 * but NOT the same as after the
6234bff34e3Sthurlow 				 * smb_usr_negotiate call above.
6244bff34e3Sthurlow 				 */
6254bff34e3Sthurlow 				kmem_free(
6264bff34e3Sthurlow 				    vcp->vc_outtok,
6274bff34e3Sthurlow 				    vcp->vc_outtoklen);
6284bff34e3Sthurlow 				vcp->vc_outtok = NULL;
6294bff34e3Sthurlow 				vcp->vc_outtoklen = 0;
6304bff34e3Sthurlow 			}
6314bff34e3Sthurlow 			/* Added copyout here... (see above) */
6324bff34e3Sthurlow 			err = ddi_copyout(sioc, (void *)arg,
6334bff34e3Sthurlow 			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
6344bff34e3Sthurlow 			if (err)
6354bff34e3Sthurlow 				error = EFAULT;
6364bff34e3Sthurlow 			break;
6374bff34e3Sthurlow 
6384bff34e3Sthurlow 		case SMBIOC_TCON:
6394bff34e3Sthurlow 			/* Must have a VC, but no share. */
6404bff34e3Sthurlow 			if (sdp->sd_share) {
6414bff34e3Sthurlow 				error = EISCONN;
6424bff34e3Sthurlow 				break;
6434bff34e3Sthurlow 			}
6444bff34e3Sthurlow 			if (!sdp->sd_vc) {
6454bff34e3Sthurlow 				error = ENOTCONN;
6464bff34e3Sthurlow 				break;
6474bff34e3Sthurlow 			}
6484bff34e3Sthurlow 			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
6494bff34e3Sthurlow 			if (ddi_copyin((void *)arg, sioc,
6504bff34e3Sthurlow 			    sizeof (*sioc), mode)) {
6514bff34e3Sthurlow 				error = EFAULT;
6524bff34e3Sthurlow 				break;
6534bff34e3Sthurlow 			}
6544bff34e3Sthurlow 			vcp = sdp->sd_vc;
6554bff34e3Sthurlow 			ssp = NULL;
6564bff34e3Sthurlow 			error = smb_usr_tcon(sioc, &scred, vcp, &ssp);
6574bff34e3Sthurlow 			if (error)
6584bff34e3Sthurlow 				break;
6594bff34e3Sthurlow 			if (ssp) {
6604bff34e3Sthurlow 				/*
6614bff34e3Sthurlow 				 * The share has a hold from _tcon
6624bff34e3Sthurlow 				 * which we keep until nsmb_close()
6634bff34e3Sthurlow 				 * or the SMBIOC_TDIS below.
6644bff34e3Sthurlow 				 */
6654bff34e3Sthurlow 				sdp->sd_share = ssp;
6664bff34e3Sthurlow 				sdp->sd_level = SMBL_SHARE;
6674bff34e3Sthurlow 			}
6684bff34e3Sthurlow 			/* No need for copyout here. */
6694bff34e3Sthurlow 			break;
6704bff34e3Sthurlow 
6714bff34e3Sthurlow 		case SMBIOC_TDIS:
6724bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
6734bff34e3Sthurlow 				error = ENOTCONN;
6744bff34e3Sthurlow 				break;
6754bff34e3Sthurlow 			}
6764bff34e3Sthurlow 			smb_share_rele(sdp->sd_share);
6774bff34e3Sthurlow 			sdp->sd_share = NULL;
6784bff34e3Sthurlow 			sdp->sd_level = SMBL_VC;
6794bff34e3Sthurlow 			break;
6804bff34e3Sthurlow 		case SMBIOC_FLAGS2:
6814bff34e3Sthurlow 			if (sdp->sd_share == NULL) {
6824bff34e3Sthurlow 				error = ENOTCONN;
6834bff34e3Sthurlow 				break;
6844bff34e3Sthurlow 			}
6854bff34e3Sthurlow 			if (!sdp->sd_vc) {
6864bff34e3Sthurlow 				error = ENOTCONN;
6874bff34e3Sthurlow 				break;
6884bff34e3Sthurlow 			}
6894bff34e3Sthurlow 			vcp = sdp->sd_vc;
6904bff34e3Sthurlow 			/*
6914bff34e3Sthurlow 			 * Return the flags2 value.
6924bff34e3Sthurlow 			 */
6934bff34e3Sthurlow 			ddi_copyout(&vcp->vc_hflags2, (void *)arg,
6944bff34e3Sthurlow 			    sizeof (u_int16_t), mode);
6954bff34e3Sthurlow 			break;
6964bff34e3Sthurlow 
6974bff34e3Sthurlow 		case SMBIOC_PK_ADD:
6984bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
6994bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
7004bff34e3Sthurlow 			    sizeof (*pk), mode)) {
7014bff34e3Sthurlow 				error = EFAULT;
7024bff34e3Sthurlow 				break;
7034bff34e3Sthurlow 			}
7044bff34e3Sthurlow 			error = smb_pkey_add(pk, credp);
7054bff34e3Sthurlow 			break;
7064bff34e3Sthurlow 
7074bff34e3Sthurlow 		case SMBIOC_PK_DEL:
7084bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
7094bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
7104bff34e3Sthurlow 			    sizeof (*pk), mode)) {
7114bff34e3Sthurlow 				error = EFAULT;
7124bff34e3Sthurlow 				break;
7134bff34e3Sthurlow 			}
7144bff34e3Sthurlow 			error = smb_pkey_del(pk, credp);
7154bff34e3Sthurlow 			break;
7164bff34e3Sthurlow 
7174bff34e3Sthurlow 		case SMBIOC_PK_CHK:
7184bff34e3Sthurlow 			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
7194bff34e3Sthurlow 			if (ddi_copyin((void *)arg, pk,
7204bff34e3Sthurlow 			    sizeof (*pk), mode)) {
7214bff34e3Sthurlow 				error = EFAULT;
7224bff34e3Sthurlow 				break;
7234bff34e3Sthurlow 			}
7244bff34e3Sthurlow 			error = smb_pkey_check(pk, credp);
7254bff34e3Sthurlow 			/*
7264bff34e3Sthurlow 			 * Note: Intentionally DO NOT copyout
7274bff34e3Sthurlow 			 * the pasword here.  It can only be
7284bff34e3Sthurlow 			 * retrieved by internal calls.  This
7294bff34e3Sthurlow 			 * ioctl only tells the caller if the
7304bff34e3Sthurlow 			 * keychain entry exists.
7314bff34e3Sthurlow 			 */
7324bff34e3Sthurlow 			break;
7334bff34e3Sthurlow 
7344bff34e3Sthurlow 		case SMBIOC_PK_DEL_OWNER:
7354bff34e3Sthurlow 			uid = crgetruid(credp);
7364bff34e3Sthurlow 			error = smb_pkey_deluid(uid, credp);
7374bff34e3Sthurlow 			break;
7384bff34e3Sthurlow 
7394bff34e3Sthurlow 		case SMBIOC_PK_DEL_EVERYONE:
7404bff34e3Sthurlow 			uid = (uid_t)-1;
7414bff34e3Sthurlow 			error = smb_pkey_deluid(uid, credp);
7424bff34e3Sthurlow 			break;
7434bff34e3Sthurlow 
7444bff34e3Sthurlow 		default:
7454bff34e3Sthurlow 			error = ENODEV;
7464bff34e3Sthurlow 	}
7474bff34e3Sthurlow 
7484bff34e3Sthurlow 	/*
7494bff34e3Sthurlow 	 * Let's just do all the kmem_free stuff HERE,
7504bff34e3Sthurlow 	 * instead of at every switch break.
7514bff34e3Sthurlow 	 */
7524bff34e3Sthurlow 
7534bff34e3Sthurlow 	/* SMBIOC_REQUEST */
7544bff34e3Sthurlow 	if (srq)
7554bff34e3Sthurlow 		kmem_free(srq, sizeof (*srq));
7564bff34e3Sthurlow 
7574bff34e3Sthurlow 	/* SMBIOC_T2RQ */
7584bff34e3Sthurlow 	if (strq)
7594bff34e3Sthurlow 		kmem_free(strq, sizeof (*strq));
7604bff34e3Sthurlow 
7614bff34e3Sthurlow 	/* SMBIOC_READ */
7624bff34e3Sthurlow 	/* SMBIOC_WRITE */
7634bff34e3Sthurlow 	if (rwrq)
7644bff34e3Sthurlow 		kmem_free(rwrq, sizeof (*rwrq));
7654bff34e3Sthurlow 
7661b34bc4aSbs 	/* SMBIOC_FINDVC */
7674bff34e3Sthurlow 	/* SMBIOC_NEGOTIATE */
7684bff34e3Sthurlow 	/* SMBIOC_SSNSETUP */
7694bff34e3Sthurlow 	/* SMBIOC_TCON */
7704bff34e3Sthurlow 	if (sioc) {
7714bff34e3Sthurlow 		/*
7724bff34e3Sthurlow 		 * This data structure may contain
7734bff34e3Sthurlow 		 * cleartext passwords, so zap it.
7744bff34e3Sthurlow 		 */
7754bff34e3Sthurlow 		bzero(sioc, sizeof (*sioc));
7764bff34e3Sthurlow 		kmem_free(sioc, sizeof (*sioc));
7774bff34e3Sthurlow 	}
7784bff34e3Sthurlow 
7794bff34e3Sthurlow 	/* SMBIOC_PK_... */
7804bff34e3Sthurlow 	if (pk) {
7814bff34e3Sthurlow 		/*
7824bff34e3Sthurlow 		 * This data structure may contain
7834bff34e3Sthurlow 		 * cleartext passwords, so zap it.
7844bff34e3Sthurlow 		 */
7854bff34e3Sthurlow 		bzero(pk, sizeof (*pk));
7864bff34e3Sthurlow 		kmem_free(pk, sizeof (*pk));
7874bff34e3Sthurlow 	}
7884bff34e3Sthurlow 
7894bff34e3Sthurlow 	smb_credrele(&scred);
7904bff34e3Sthurlow 
7914bff34e3Sthurlow 	return (error);
7924bff34e3Sthurlow }
7934bff34e3Sthurlow 
7944bff34e3Sthurlow /*ARGSUSED*/
7954bff34e3Sthurlow static int
7964bff34e3Sthurlow nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
7974bff34e3Sthurlow {
7984bff34e3Sthurlow 	major_t new_major;
7994bff34e3Sthurlow 	smb_dev_t *sdp, *sdv;
8004bff34e3Sthurlow 
8014bff34e3Sthurlow 	mutex_enter(&dev_lck);
8024bff34e3Sthurlow 	for (; ; ) {
8034bff34e3Sthurlow 		minor_t start = nsmb_minor;
8044bff34e3Sthurlow 		do {
8054bff34e3Sthurlow 			if (nsmb_minor >= MAXMIN32) {
8064bff34e3Sthurlow 				if (nsmb_major == getmajor(*dev))
8074bff34e3Sthurlow 					nsmb_minor = NSMB_MIN_MINOR;
8084bff34e3Sthurlow 				else
8094bff34e3Sthurlow 					nsmb_minor = 0;
8104bff34e3Sthurlow 			} else {
8114bff34e3Sthurlow 				nsmb_minor++;
8124bff34e3Sthurlow 			}
8134bff34e3Sthurlow 			sdv = ddi_get_soft_state(statep, nsmb_minor);
8144bff34e3Sthurlow 		} while ((sdv != NULL) && (nsmb_minor != start));
8154bff34e3Sthurlow 		if (nsmb_minor == start) {
8164bff34e3Sthurlow 			/*
8174bff34e3Sthurlow 			 * The condition we need to solve here is  all the
8184bff34e3Sthurlow 			 * MAXMIN32(~262000) minors numbers are reached. We
8194bff34e3Sthurlow 			 * need to create a new major number.
8204bff34e3Sthurlow 			 * zfs uses getudev() to create a new major number.
8214bff34e3Sthurlow 			 */
8224bff34e3Sthurlow 			if ((new_major = getudev()) == (major_t)-1) {
8234bff34e3Sthurlow 				cmn_err(CE_WARN,
8244bff34e3Sthurlow 				    "nsmb: Can't get unique major "
8254bff34e3Sthurlow 				    "device number.");
8264bff34e3Sthurlow 				mutex_exit(&dev_lck);
8274bff34e3Sthurlow 				return (-1);
8284bff34e3Sthurlow 			}
8294bff34e3Sthurlow 			nsmb_major = new_major;
8304bff34e3Sthurlow 			nsmb_minor = 0;
8314bff34e3Sthurlow 		} else {
8324bff34e3Sthurlow 			break;
8334bff34e3Sthurlow 		}
8344bff34e3Sthurlow 	}
8354bff34e3Sthurlow 
8364bff34e3Sthurlow 	/*
8374bff34e3Sthurlow 	 * This is called by mount or open call.
8384bff34e3Sthurlow 	 * The open() routine is passed a pointer to a device number so
8394bff34e3Sthurlow 	 * that  the  driver  can  change the minor number. This allows
8404bff34e3Sthurlow 	 * drivers to dynamically  create minor instances of  the  dev-
8414bff34e3Sthurlow 	 * ice.  An  example of this might be a  pseudo-terminal driver
8424bff34e3Sthurlow 	 * that creates a new pseudo-terminal whenever it   is  opened.
8434bff34e3Sthurlow 	 * A driver that chooses the minor number dynamically, normally
8444bff34e3Sthurlow 	 * creates only one  minor  device  node  in   attach(9E)  with
8454bff34e3Sthurlow 	 * ddi_create_minor_node(9F) then changes the minor number com-
8464bff34e3Sthurlow 	 * ponent of *devp using makedevice(9F)  and  getmajor(9F)  The
8474bff34e3Sthurlow 	 * driver needs to keep track of available minor numbers inter-
8484bff34e3Sthurlow 	 * nally.
8494bff34e3Sthurlow 	 * Stuff the structure smb_dev.
8504bff34e3Sthurlow 	 * return.
8514bff34e3Sthurlow 	 */
8524bff34e3Sthurlow 
8534bff34e3Sthurlow 	if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) {
8544bff34e3Sthurlow 		mutex_exit(&dev_lck);
8554bff34e3Sthurlow 		return (ENXIO);
8564bff34e3Sthurlow 	}
8574bff34e3Sthurlow 	if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) {
8584bff34e3Sthurlow 		mutex_exit(&dev_lck);
8594bff34e3Sthurlow 		return (ENXIO);
8604bff34e3Sthurlow 	}
8614bff34e3Sthurlow 
8624bff34e3Sthurlow 	sdp->sd_opened = 1;
8634bff34e3Sthurlow 	sdp->sd_seq = nsmb_minor;
8644bff34e3Sthurlow 	sdp->smb_cred = cr;
8654bff34e3Sthurlow 	sdp->sd_flags |= NSMBFL_OPEN;
8664bff34e3Sthurlow 	sdp->zoneid = crgetzoneid(cr);
8674bff34e3Sthurlow 	mutex_exit(&dev_lck);
8684bff34e3Sthurlow 
8694bff34e3Sthurlow 	*dev = makedevice(nsmb_major, nsmb_minor);
8704bff34e3Sthurlow 
8714bff34e3Sthurlow 	return (0);
8724bff34e3Sthurlow }
8734bff34e3Sthurlow 
8744bff34e3Sthurlow /*ARGSUSED*/
8754bff34e3Sthurlow static int
8764bff34e3Sthurlow nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
8774bff34e3Sthurlow {
8784bff34e3Sthurlow 	struct smb_vc *vcp;
8794bff34e3Sthurlow 	struct smb_share *ssp;
8804bff34e3Sthurlow 	struct smb_cred scred;
8814bff34e3Sthurlow 	minor_t inst = getminor(dev);
8824bff34e3Sthurlow 	smb_dev_t *sdp;
8834bff34e3Sthurlow 
8844bff34e3Sthurlow 	mutex_enter(&dev_lck);
8854bff34e3Sthurlow 	/*
8864bff34e3Sthurlow 	 * 1. Check the validity of the minor number.
8874bff34e3Sthurlow 	 * 2. Release any shares/vc associated  with the connection.
8884bff34e3Sthurlow 	 * 3. Can close the minor number.
8894bff34e3Sthurlow 	 * 4. Deallocate any resources allocated in open() call.
8904bff34e3Sthurlow 	 */
8914bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
8924bff34e3Sthurlow 
8934bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, inst);
8944bff34e3Sthurlow 
8954bff34e3Sthurlow 	/*
8964bff34e3Sthurlow 	 * time to call ddi_get_soft_state()
8974bff34e3Sthurlow 	 */
8984bff34e3Sthurlow 	ssp = sdp->sd_share;
8994bff34e3Sthurlow 	if (ssp != NULL)
9004bff34e3Sthurlow 		smb_share_rele(ssp);
9014bff34e3Sthurlow 	vcp = sdp->sd_vc;
9024bff34e3Sthurlow 	if (vcp != NULL) {
9034bff34e3Sthurlow 		/*
9044bff34e3Sthurlow 		 * If this dev minor was doing session setup
9054bff34e3Sthurlow 		 * and failed to authenticate (or whatever)
906*6723e17fSGordon Ross 		 * then we need to put the VC in a state that
907*6723e17fSGordon Ross 		 * allows later commands to try again.
9084bff34e3Sthurlow 		 */
9094bff34e3Sthurlow 		if (sdp->sd_flags & NSMBFL_NEWVC)
910*6723e17fSGordon Ross 			smb_iod_disconnect(vcp);
9114bff34e3Sthurlow 		smb_vc_rele(vcp);
9124bff34e3Sthurlow 	}
9134bff34e3Sthurlow 	smb_credrele(&scred);
9144bff34e3Sthurlow 
9154bff34e3Sthurlow 	/*
9164bff34e3Sthurlow 	 * Free the instance
9174bff34e3Sthurlow 	 */
9184bff34e3Sthurlow 	ddi_soft_state_free(statep, inst);
9194bff34e3Sthurlow 	mutex_exit(&dev_lck);
9204bff34e3Sthurlow 	return (0);
9214bff34e3Sthurlow }
9224bff34e3Sthurlow 
9234bff34e3Sthurlow int
9244bff34e3Sthurlow smb_dev2share(int fd, struct smb_share **sspp)
9254bff34e3Sthurlow {
9264bff34e3Sthurlow 	register vnode_t *vp;
9274bff34e3Sthurlow 	smb_dev_t *sdp;
9284bff34e3Sthurlow 	struct smb_share *ssp;
9294bff34e3Sthurlow 	dev_t dev;
9304bff34e3Sthurlow 	file_t *fp;
9314bff34e3Sthurlow 
9324bff34e3Sthurlow 	if ((fp = getf(fd)) == NULL)
9334bff34e3Sthurlow 		return (set_errno(EBADF));
9344bff34e3Sthurlow 	vp = fp->f_vnode;
9354bff34e3Sthurlow 	dev = vp->v_rdev;
9364bff34e3Sthurlow 	if (dev == NULL) {
9374bff34e3Sthurlow 		releasef(fd);
9384bff34e3Sthurlow 		return (EBADF);
9394bff34e3Sthurlow 	}
9404bff34e3Sthurlow 	sdp = ddi_get_soft_state(statep, getminor(dev));
9414bff34e3Sthurlow 	if (sdp == NULL) {
9424bff34e3Sthurlow 		releasef(fd);
9434bff34e3Sthurlow 		return (DDI_FAILURE);
9444bff34e3Sthurlow 	}
9454bff34e3Sthurlow 	ssp = sdp->sd_share;
9464bff34e3Sthurlow 	if (ssp == NULL) {
9474bff34e3Sthurlow 		releasef(fd);
9484bff34e3Sthurlow 		return (ENOTCONN);
9494bff34e3Sthurlow 	}
9504bff34e3Sthurlow 	/*
9514bff34e3Sthurlow 	 * The share is already locked and referenced by the TCON ioctl
9524bff34e3Sthurlow 	 * We NULL to hand off share to caller (mount)
9534bff34e3Sthurlow 	 * This allows further ioctls against connection, for instance
9544bff34e3Sthurlow 	 * another tree connect and mount, in the automounter case
9554bff34e3Sthurlow 	 *
9564bff34e3Sthurlow 	 * We're effectively giving our reference to the mount.
9574bff34e3Sthurlow 	 *
9584bff34e3Sthurlow 	 * XXX: I'm not sure I like this.  I'd rather see the ioctl
9594bff34e3Sthurlow 	 * caller do something explicit to give up this reference,
9604bff34e3Sthurlow 	 * (i.e. SMBIOC_TDIS above) and increment the hold here.
9614bff34e3Sthurlow 	 */
9624bff34e3Sthurlow 	sdp->sd_share = NULL;
9634bff34e3Sthurlow 	releasef(fd);
9644bff34e3Sthurlow 	*sspp = ssp;
9654bff34e3Sthurlow 	return (0);
9664bff34e3Sthurlow }
967