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