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