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 
33 /*
34  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
35  * Use is subject to license terms.
36  *
37  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
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/types.h>
66 #include <sys/zone.h>
67 
68 #include <netsmb/smb_osdep.h>
69 #include <netsmb/mchain.h>		/* for "htoles()" */
70 
71 #include <netsmb/smb.h>
72 #include <netsmb/smb_conn.h>
73 #include <netsmb/smb_subr.h>
74 #include <netsmb/smb_dev.h>
75 #include <netsmb/smb_pass.h>
76 
77 #ifndef	_KERNEL
78 #include <libfknsmb.h>
79 
80 #define	_init(v)	nsmb_drv_init(v)
81 #define	_fini(v)	nsmb_drv_fini(v)
82 
83 #endif	/* _KERNEL */
84 
85 #define	NSMB_MIN_MINOR	1
86 #define	NSMB_MAX_MINOR	L_MAXMIN32
87 
88 /* for version checks */
89 const uint32_t nsmb_version = NSMB_VERSION;
90 
91 static void *statep;
92 static major_t nsmb_major;
93 static minor_t last_minor = NSMB_MIN_MINOR;
94 static kmutex_t  dev_lck;
95 
96 /*
97  * cb_ops device operations.
98  */
99 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
100 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
101 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
102 				cred_t *credp, int *rvalp);
103 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
104 
105 #ifdef	_KERNEL
106 
107 static dev_info_t *nsmb_dip;
108 
109 /* Zone support */
110 zone_key_t nsmb_zone_key;
111 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
112 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
113 
114 /* smbfs cb_ops */
115 static struct cb_ops nsmb_cbops = {
116 	nsmb_open,	/* open */
117 	nsmb_close,	/* close */
118 	nodev,		/* strategy */
119 	nodev,		/* print */
120 	nodev,		/* dump */
121 	nodev,		/* read */
122 	nodev,		/* write */
123 	nsmb_ioctl,	/* ioctl */
124 	nodev,		/* devmap */
125 	nodev,		/* mmap */
126 	nodev,		/* segmap */
127 	nochpoll,	/* poll */
128 	ddi_prop_op,	/* prop_op */
129 	NULL,		/* stream */
130 	D_MP,		/* cb_flag */
131 	CB_REV,		/* rev */
132 	nodev,		/* int (*cb_aread)() */
133 	nodev		/* int (*cb_awrite)() */
134 };
135 
136 /*
137  * Device options
138  */
139 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
140 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
141 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
142 	void *arg, void **result);
143 
144 static struct dev_ops nsmb_ops = {
145 	DEVO_REV,	/* devo_rev, */
146 	0,		/* refcnt  */
147 	nsmb_getinfo,	/* info */
148 	nulldev,	/* identify */
149 	nulldev,	/* probe */
150 	nsmb_attach,	/* attach */
151 	nsmb_detach,	/* detach */
152 	nodev,		/* reset */
153 	&nsmb_cbops,	/* driver ops - devctl interfaces */
154 	NULL,		/* bus operations */
155 	NULL,		/* power */
156 	ddi_quiesce_not_needed,	/* quiesce */
157 };
158 
159 /*
160  * Module linkage information.
161  */
162 
163 static struct modldrv nsmb_modldrv = {
164 	&mod_driverops,				/* Driver module */
165 	"SMBFS network driver",
166 	&nsmb_ops				/* Driver ops */
167 };
168 
169 static struct modlinkage nsmb_modlinkage = {
170 	MODREV_1,
171 	(void *)&nsmb_modldrv,
172 	NULL
173 };
174 
175 #endif	/* _KERNEL */
176 
177 int
178 _init(void)
179 {
180 #ifdef	_KERNEL
181 	int error;
182 #endif	/* _KERNEL */
183 
184 	(void) 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 	/* Connection data structures. */
190 	(void) smb_sm_init();
191 
192 	/* Initialize password Key chain DB. */
193 	smb_pkey_init();
194 
195 	/* Time conversion stuff. */
196 	smb_time_init();
197 
198 	/* Initialize crypto mechanisms. */
199 	smb_crypto_mech_init();
200 
201 #ifdef	_KERNEL
202 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
203 	    nsmb_zone_destroy);
204 
205 	/*
206 	 * Install the module.  Do this after other init,
207 	 * to prevent entrances before we're ready.
208 	 */
209 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
210 
211 		/* Same as 2nd half of _fini */
212 		(void) zone_key_delete(nsmb_zone_key);
213 		smb_pkey_fini();
214 		smb_sm_done();
215 		mutex_destroy(&dev_lck);
216 		ddi_soft_state_fini(&statep);
217 
218 		return (error);
219 	}
220 #else	/* _KERNEL */
221 	streams_msg_init();
222 	/* No attach, so need to set major. */
223 	nsmb_major = 1;
224 #endif	/* _KERNEL */
225 
226 	return (0);
227 }
228 
229 int
230 _fini(void)
231 {
232 	int status;
233 
234 	/*
235 	 * Prevent unload if we have active VCs
236 	 * or stored passwords
237 	 */
238 	if ((status = smb_sm_idle()) != 0)
239 		return (status);
240 	if ((status = smb_pkey_idle()) != 0)
241 		return (status);
242 
243 #ifdef	_KERNEL
244 	/*
245 	 * Remove the module.  Do this before destroying things,
246 	 * to prevent new entrances while we're destorying.
247 	 */
248 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
249 		return (status);
250 	}
251 
252 	(void) zone_key_delete(nsmb_zone_key);
253 #endif	/* _KERNEL */
254 
255 	/* Time conversion stuff. */
256 	smb_time_fini();
257 
258 	/* Destroy password Key chain DB. */
259 	smb_pkey_fini();
260 
261 	smb_sm_done();
262 
263 	mutex_destroy(&dev_lck);
264 	ddi_soft_state_fini(&statep);
265 
266 	return (status);
267 }
268 
269 #ifdef	_KERNEL
270 
271 int
272 _info(struct modinfo *modinfop)
273 {
274 	return (mod_info(&nsmb_modlinkage, modinfop));
275 }
276 
277 /*ARGSUSED*/
278 static int
279 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
280 {
281 	int ret = DDI_SUCCESS;
282 
283 	switch (cmd) {
284 	case DDI_INFO_DEVT2DEVINFO:
285 		*result = nsmb_dip;
286 		break;
287 	case DDI_INFO_DEVT2INSTANCE:
288 		*result = NULL;
289 		break;
290 	default:
291 		ret = DDI_FAILURE;
292 	}
293 	return (ret);
294 }
295 
296 static int
297 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
298 {
299 
300 	if (cmd != DDI_ATTACH)
301 		return (DDI_FAILURE);
302 
303 	/*
304 	 * We only support only one "instance".  Note that
305 	 * "instances" are different from minor units.
306 	 * We get one (unique) minor unit per open.
307 	 */
308 	if (ddi_get_instance(dip) > 0)
309 		return (DDI_FAILURE);
310 
311 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
312 	    NULL) == DDI_FAILURE) {
313 		cmn_err(CE_WARN, "nsmb_attach: create minor");
314 		return (DDI_FAILURE);
315 	}
316 
317 	/*
318 	 * We need the major number a couple places,
319 	 * i.e. in smb_dev2share()
320 	 */
321 	nsmb_major = ddi_name_to_major(NSMB_NAME);
322 
323 	nsmb_dip = dip;
324 	ddi_report_dev(dip);
325 	return (DDI_SUCCESS);
326 }
327 
328 /*ARGSUSED*/
329 static int
330 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
331 {
332 
333 	if (cmd != DDI_DETACH)
334 		return (DDI_FAILURE);
335 	if (ddi_get_instance(dip) > 0)
336 		return (DDI_FAILURE);
337 
338 	nsmb_dip = NULL;
339 	ddi_remove_minor_node(dip, NULL);
340 
341 	return (DDI_SUCCESS);
342 }
343 
344 #else	/* _KERNEL */
345 
346 /*
347  * Wrappers for libfknsmb: ioctl, open, close, load
348  */
349 
350 /*ARGSUSED*/
351 int
352 nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
353 {
354 	dev_t dev = expldev(dev32);
355 	cred_t *cr = CRED();
356 	int err;
357 
358 	err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
359 	return (err);
360 }
361 
362 /*ARGSUSED*/
363 int
364 nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
365 {
366 	dev_t dev = expldev(*dev32p);
367 	int err;
368 
369 	err = nsmb_open(&dev, flags, otyp, CRED());
370 	if (err == 0) {
371 		/*
372 		 * We have NSMB_MAX_MINOR == L_MAXMIN32
373 		 * therefore cmpldev never fails.
374 		 */
375 		VERIFY(cmpldev(dev32p, dev) != 0);
376 	}
377 	return (err);
378 }
379 
380 /*ARGSUSED*/
381 int
382 nsmb_drv_close(dev32_t dev32, int flags, int otyp)
383 {
384 	dev_t dev = expldev(dev32);
385 	int err;
386 
387 	err = nsmb_close(dev, flags, otyp, CRED());
388 	return (err);
389 }
390 
391 /*
392  * This function intentionally does nothing.  It's used only to
393  * force libfknsmb to load at program start so one can set
394  * breakpoints etc. without debugger "force load" tricks.
395  */
396 void
397 nsmb_drv_load(void)
398 {
399 }
400 
401 #endif	/* _KERNEL */
402 
403 /*ARGSUSED*/
404 static int
405 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags,	/* model.h */
406     cred_t *cr, int *rvalp)
407 {
408 	smb_dev_t *sdp;
409 	int err;
410 
411 	sdp = ddi_get_soft_state(statep, getminor(dev));
412 	if (sdp == NULL) {
413 		return (EBADF);
414 	}
415 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
416 		return (EBADF);
417 	}
418 
419 	/*
420 	 * Dont give access if the zone id is not as the same as we
421 	 * set in the nsmb_open or dont belong to the global zone.
422 	 * Check if the user belongs to this zone..
423 	 */
424 	if (sdp->zoneid != getzoneid())
425 		return (EIO);
426 
427 	/*
428 	 * We have a zone_shutdown call back that kills all the VCs
429 	 * in a zone that's shutting down.  That action will cause
430 	 * all of these ioctls to fail on such VCs, so no need to
431 	 * check the zone status here on every ioctl call.
432 	 */
433 
434 	/*
435 	 * Serialize ioctl calls.  The smb_usr_... functions
436 	 * don't expect concurrent calls on a given sdp.
437 	 */
438 	mutex_enter(&sdp->sd_lock);
439 	if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
440 		mutex_exit(&sdp->sd_lock);
441 		return (EBUSY);
442 	}
443 	sdp->sd_flags |= NSMBFL_IOCTL;
444 	mutex_exit(&sdp->sd_lock);
445 
446 	err = 0;
447 	switch (cmd) {
448 	case SMBIOC_GETVERS:
449 		(void) ddi_copyout(&nsmb_version, (void *)arg,
450 		    sizeof (nsmb_version), flags);
451 		break;
452 
453 	case SMBIOC_FLAGS2:
454 		err = smb_usr_get_flags2(sdp, arg, flags);
455 		break;
456 
457 	case SMBIOC_GETSSNKEY:
458 		err = smb_usr_get_ssnkey(sdp, arg, flags);
459 		break;
460 
461 	case SMBIOC_DUP_DEV:
462 		err = smb_usr_dup_dev(sdp, arg, flags);
463 		break;
464 
465 	case SMBIOC_REQUEST:
466 		err = smb_usr_simplerq(sdp, arg, flags, cr);
467 		break;
468 
469 	case SMBIOC_T2RQ:
470 		err = smb_usr_t2request(sdp, arg, flags, cr);
471 		break;
472 
473 	case SMBIOC_READ:
474 	case SMBIOC_WRITE:
475 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
476 		break;
477 
478 	case SMBIOC_NTCREATE:
479 		err = smb_usr_ntcreate(sdp, arg, flags, cr);
480 		break;
481 
482 	case SMBIOC_PRINTJOB:
483 		err = smb_usr_printjob(sdp, arg, flags, cr);
484 		break;
485 
486 	case SMBIOC_CLOSEFH:
487 		err = smb_usr_closefh(sdp, cr);
488 		break;
489 
490 	case SMBIOC_SSN_CREATE:
491 	case SMBIOC_SSN_FIND:
492 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
493 		break;
494 
495 	case SMBIOC_SSN_KILL:
496 	case SMBIOC_SSN_RELE:
497 		err = smb_usr_drop_ssn(sdp, cmd);
498 		break;
499 
500 	case SMBIOC_TREE_CONNECT:
501 	case SMBIOC_TREE_FIND:
502 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
503 		break;
504 
505 	case SMBIOC_TREE_KILL:
506 	case SMBIOC_TREE_RELE:
507 		err = smb_usr_drop_tree(sdp, cmd);
508 		break;
509 
510 	case SMBIOC_IOD_WORK:
511 		err = smb_usr_iod_work(sdp, arg, flags, cr);
512 		break;
513 
514 	case SMBIOC_IOD_IDLE:
515 	case SMBIOC_IOD_RCFAIL:
516 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
517 		break;
518 
519 	case SMBIOC_PK_ADD:
520 	case SMBIOC_PK_DEL:
521 	case SMBIOC_PK_CHK:
522 	case SMBIOC_PK_DEL_OWNER:
523 	case SMBIOC_PK_DEL_EVERYONE:
524 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
525 		break;
526 
527 	default:
528 		err = ENOTTY;
529 		break;
530 	}
531 
532 	mutex_enter(&sdp->sd_lock);
533 	sdp->sd_flags &= ~NSMBFL_IOCTL;
534 	mutex_exit(&sdp->sd_lock);
535 
536 	return (err);
537 }
538 
539 /*
540  * This does "clone" open, meaning it automatically
541  * assigns an available minor unit for each open.
542  */
543 /*ARGSUSED*/
544 static int
545 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
546 {
547 	smb_dev_t *sdp;
548 	minor_t m;
549 
550 	mutex_enter(&dev_lck);
551 
552 	for (m = last_minor + 1; m != last_minor; m++) {
553 		if (m > NSMB_MAX_MINOR)
554 			m = NSMB_MIN_MINOR;
555 
556 		if (ddi_get_soft_state(statep, m) == NULL) {
557 			last_minor = m;
558 			goto found;
559 		}
560 	}
561 
562 	/* No available minor units. */
563 	mutex_exit(&dev_lck);
564 	return (ENXIO);
565 
566 found:
567 	/* NB: dev_lck still held */
568 	if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) {
569 		mutex_exit(&dev_lck);
570 		return (ENXIO);
571 	}
572 	if ((sdp = ddi_get_soft_state(statep, m)) == NULL) {
573 		mutex_exit(&dev_lck);
574 		return (ENXIO);
575 	}
576 	*dev = makedevice(nsmb_major, m);
577 	mutex_exit(&dev_lck);
578 
579 	sdp->sd_smbfid = -1;
580 	sdp->sd_flags |= NSMBFL_OPEN;
581 	sdp->zoneid = crgetzoneid(cr);
582 	mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
583 
584 	return (0);
585 }
586 
587 /*ARGSUSED*/
588 static int
589 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
590 {
591 	minor_t inst = getminor(dev);
592 	smb_dev_t *sdp;
593 	int err;
594 
595 	/*
596 	 * 1. Check the validity of the minor number.
597 	 * 2. Release any shares/vc associated  with the connection.
598 	 * 3. Can close the minor number.
599 	 * 4. Deallocate any resources allocated in open() call.
600 	 */
601 
602 	sdp = ddi_get_soft_state(statep, inst);
603 	if (sdp != NULL)
604 		err = nsmb_close2(sdp, cr);
605 	else
606 		err = ENXIO;
607 
608 	/*
609 	 * Free the instance
610 	 */
611 	mutex_enter(&dev_lck);
612 	ddi_soft_state_free(statep, inst);
613 	mutex_exit(&dev_lck);
614 	return (err);
615 }
616 
617 static int
618 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
619 {
620 	struct smb_vc *vcp;
621 	struct smb_share *ssp;
622 
623 	if (sdp->sd_smbfid != -1)
624 		(void) smb_usr_closefh(sdp, cr);
625 
626 	ssp = sdp->sd_share;
627 	if (ssp != NULL)
628 		smb_share_rele(ssp);
629 
630 	vcp = sdp->sd_vc;
631 	if (vcp != NULL) {
632 		/*
633 		 * If this dev minor was opened by smbiod,
634 		 * mark this VC as "dead" because it now
635 		 * will have no IOD to service it.
636 		 */
637 		if (sdp->sd_flags & NSMBFL_IOD)
638 			smb_iod_disconnect(vcp);
639 		smb_vc_rele(vcp);
640 	}
641 	mutex_destroy(&sdp->sd_lock);
642 
643 	return (0);
644 }
645 
646 /*
647  * Helper for SMBIOC_DUP_DEV
648  * Duplicate state from the FD @arg ("from") onto
649  * the FD for this device instance.
650  */
651 int
652 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
653 {
654 #ifdef	_KERNEL
655 	file_t *fp = NULL;
656 	vnode_t *vp;
657 #endif	/* _KERNEL */
658 	smb_dev_t *from_sdp;
659 	dev_t dev;
660 	int32_t ufd;
661 	int err;
662 
663 	/* Should be no VC */
664 	if (sdp->sd_vc != NULL)
665 		return (EISCONN);
666 
667 	/*
668 	 * Get from_sdp (what we will duplicate)
669 	 */
670 	if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
671 		return (EFAULT);
672 #ifdef	_KERNEL
673 	if ((fp = getf(ufd)) == NULL)
674 		return (EBADF);
675 	/* rele fp below */
676 	vp = fp->f_vnode;
677 	dev = vp->v_rdev;
678 #else	/* _KERNEL */
679 	/*
680 	 * No getf(ufd) -- ufd is really a dev32_t
681 	 */
682 	dev = expldev((dev32_t)ufd);
683 #endif	/* _KERNEL */
684 	if (dev == 0 || dev == NODEV ||
685 	    getmajor(dev) != nsmb_major) {
686 		err = EINVAL;
687 		goto out;
688 	}
689 
690 	from_sdp = ddi_get_soft_state(statep, getminor(dev));
691 	if (from_sdp == NULL) {
692 		err = EINVAL;
693 		goto out;
694 	}
695 
696 	/*
697 	 * Duplicate VC and share references onto this FD.
698 	 */
699 	if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
700 		smb_vc_hold(sdp->sd_vc);
701 	if ((sdp->sd_share = from_sdp->sd_share) != NULL)
702 		smb_share_hold(sdp->sd_share);
703 	sdp->sd_level = from_sdp->sd_level;
704 	err = 0;
705 
706 out:
707 #ifdef	_KERNEL
708 	if (fp)
709 		releasef(ufd);
710 #endif	/* _KERNEL */
711 	return (err);
712 }
713 
714 
715 /*
716  * Helper used by smbfs_mount
717  */
718 int
719 smb_dev2share(int fd, struct smb_share **sspp)
720 {
721 #ifdef	_KERNEL
722 	file_t *fp = NULL;
723 	vnode_t *vp;
724 #endif	/* _KERNEL */
725 	smb_dev_t *sdp;
726 	smb_share_t *ssp;
727 	dev_t dev;
728 	int err;
729 
730 #ifdef	_KERNEL
731 	if ((fp = getf(fd)) == NULL)
732 		return (EBADF);
733 	/* rele fp below */
734 	vp = fp->f_vnode;
735 	dev = vp->v_rdev;
736 #else	/* _KERNEL */
737 	/*
738 	 * No getf(ufd) -- fd is really a dev32_t
739 	 */
740 	dev = expldev((dev32_t)fd);
741 #endif	/* _KERNEL */
742 	if (dev == 0 || dev == NODEV ||
743 	    getmajor(dev) != nsmb_major) {
744 		err = EINVAL;
745 		goto out;
746 	}
747 
748 	sdp = ddi_get_soft_state(statep, getminor(dev));
749 	if (sdp == NULL) {
750 		err = EINVAL;
751 		goto out;
752 	}
753 
754 	ssp = sdp->sd_share;
755 	if (ssp == NULL) {
756 		err = ENOTCONN;
757 		goto out;
758 	}
759 
760 	/*
761 	 * Our caller gains a ref. to this share.
762 	 */
763 	*sspp = ssp;
764 	smb_share_hold(ssp);
765 	err = 0;
766 
767 out:
768 #ifdef	_KERNEL
769 	if (fp)
770 		releasef(fd);
771 #endif	/* _KERNEL */
772 	return (err);
773 }
774