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 2011 Nexenta Systems, Inc.  All rights reserved.
37  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
38  * Use is subject to license terms.
39  */
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <sys/sysmacros.h>
45 #include <sys/uio.h>
46 #include <sys/buf.h>
47 #include <sys/modctl.h>
48 #include <sys/open.h>
49 #include <sys/file.h>
50 #include <sys/kmem.h>
51 #include <sys/conf.h>
52 #include <sys/cmn_err.h>
53 #include <sys/stat.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #include <sys/sunldi.h>
57 #include <sys/policy.h>
58 #include <sys/zone.h>
59 #include <sys/pathname.h>
60 #include <sys/mount.h>
61 #include <sys/sdt.h>
62 #include <fs/fs_subr.h>
63 #include <sys/modctl.h>
64 #include <sys/devops.h>
65 #include <sys/thread.h>
66 #include <sys/mkdev.h>
67 #include <sys/types.h>
68 #include <sys/zone.h>
69 
70 #include <netsmb/smb_osdep.h>
71 #include <netsmb/mchain.h>		/* for "htoles()" */
72 
73 #include <netsmb/smb.h>
74 #include <netsmb/smb_conn.h>
75 #include <netsmb/smb_subr.h>
76 #include <netsmb/smb_dev.h>
77 #include <netsmb/smb_pass.h>
78 
79 /* for version checks */
80 const uint32_t nsmb_version = NSMB_VERSION;
81 
82 /*
83  * Userland code loops through minor #s 0 to 1023, looking for one which opens.
84  * Intially we create minor 0 and leave it for anyone.  Minor zero will never
85  * actually get used - opening triggers creation of another (but private) minor,
86  * which userland code will get to and mark busy.
87  */
88 #define	SMBMINORS 1024
89 static void *statep;
90 static major_t nsmb_major;
91 static minor_t nsmb_minor = 1;
92 
93 #define	NSMB_MAX_MINOR  (1 << 8)
94 #define	NSMB_MIN_MINOR   (NSMB_MAX_MINOR + 1)
95 
96 #define	ILP32	1
97 #define	LP64	2
98 
99 static kmutex_t  dev_lck;
100 
101 /* Zone support */
102 zone_key_t nsmb_zone_key;
103 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
104 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
105 
106 /*
107  * cb_ops device operations.
108  */
109 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
110 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
111 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
112 				cred_t *credp, int *rvalp);
113 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
114 
115 /* smbfs cb_ops */
116 static struct cb_ops nsmb_cbops = {
117 	nsmb_open,	/* open */
118 	nsmb_close,	/* close */
119 	nodev,		/* strategy */
120 	nodev,		/* print */
121 	nodev,		/* dump */
122 	nodev,		/* read */
123 	nodev,		/* write */
124 	nsmb_ioctl,	/* ioctl */
125 	nodev,		/* devmap */
126 	nodev,		/* mmap */
127 	nodev,		/* segmap */
128 	nochpoll,	/* poll */
129 	ddi_prop_op,	/* prop_op */
130 	NULL,		/* stream */
131 	D_MP,		/* cb_flag */
132 	CB_REV,		/* rev */
133 	nodev,		/* int (*cb_aread)() */
134 	nodev		/* int (*cb_awrite)() */
135 };
136 
137 /*
138  * Device options
139  */
140 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
141 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
142 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
143 	void *arg, void **result);
144 
145 static struct dev_ops nsmb_ops = {
146 	DEVO_REV,	/* devo_rev, */
147 	0,		/* refcnt  */
148 	nsmb_getinfo,	/* info */
149 	nulldev,	/* identify */
150 	nulldev,	/* probe */
151 	nsmb_attach,	/* attach */
152 	nsmb_detach,	/* detach */
153 	nodev,		/* reset */
154 	&nsmb_cbops,	/* driver ops - devctl interfaces */
155 	NULL,		/* bus operations */
156 	NULL,		/* power */
157 	ddi_quiesce_not_needed,	/* quiesce */
158 };
159 
160 /*
161  * Module linkage information.
162  */
163 
164 static struct modldrv nsmb_modldrv = {
165 	&mod_driverops,				/* Driver module */
166 	"SMBFS network driver",
167 	&nsmb_ops				/* Driver ops */
168 };
169 
170 static struct modlinkage nsmb_modlinkage = {
171 	MODREV_1,
172 	(void *)&nsmb_modldrv,
173 	NULL
174 };
175 
176 int
177 _init(void)
178 {
179 	int error;
180 
181 	(void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
182 
183 	/* Can initialize some mutexes also. */
184 	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
185 	/*
186 	 * Create a major name and number.
187 	 */
188 	nsmb_major = ddi_name_to_major(NSMB_NAME);
189 	nsmb_minor = 0;
190 
191 	/* Connection data structures. */
192 	(void) smb_sm_init();
193 
194 	/* Initialize password Key chain DB. */
195 	smb_pkey_init();
196 
197 	/* Time conversion stuff. */
198 	smb_time_init();
199 
200 	/* Initialize crypto mechanisms. */
201 	smb_crypto_mech_init();
202 
203 	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
204 	    nsmb_zone_destroy);
205 
206 	/*
207 	 * Install the module.  Do this after other init,
208 	 * to prevent entrances before we're ready.
209 	 */
210 	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
211 
212 		/* Same as 2nd half of _fini */
213 		(void) zone_key_delete(nsmb_zone_key);
214 		smb_pkey_fini();
215 		smb_sm_done();
216 		mutex_destroy(&dev_lck);
217 		ddi_soft_state_fini(&statep);
218 
219 		return (error);
220 	}
221 
222 	return (0);
223 }
224 
225 int
226 _fini(void)
227 {
228 	int status;
229 
230 	/*
231 	 * Prevent unload if we have active VCs
232 	 * or stored passwords
233 	 */
234 	if ((status = smb_sm_idle()) != 0)
235 		return (status);
236 	if ((status = smb_pkey_idle()) != 0)
237 		return (status);
238 
239 	/*
240 	 * Remove the module.  Do this before destroying things,
241 	 * to prevent new entrances while we're destorying.
242 	 */
243 	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
244 		return (status);
245 	}
246 
247 	(void) zone_key_delete(nsmb_zone_key);
248 
249 	/* Time conversion stuff. */
250 	smb_time_fini();
251 
252 	/* Destroy password Key chain DB. */
253 	smb_pkey_fini();
254 
255 	smb_sm_done();
256 
257 	mutex_destroy(&dev_lck);
258 	ddi_soft_state_fini(&statep);
259 
260 	return (status);
261 }
262 
263 int
264 _info(struct modinfo *modinfop)
265 {
266 	return (mod_info(&nsmb_modlinkage, modinfop));
267 }
268 
269 /*ARGSUSED*/
270 static int
271 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
272 {
273 	int ret = DDI_SUCCESS;
274 
275 	switch (cmd) {
276 	case DDI_INFO_DEVT2DEVINFO:
277 		*result = 0;
278 		break;
279 	case DDI_INFO_DEVT2INSTANCE:
280 		*result = 0;
281 		break;
282 	default:
283 		ret = DDI_FAILURE;
284 	}
285 	return (ret);
286 }
287 
288 static int
289 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
290 {
291 	smb_dev_t *sdp;
292 
293 	if (cmd != DDI_ATTACH)
294 		return (DDI_FAILURE);
295 	/*
296 	 * only one instance - but we clone using the open routine
297 	 */
298 	if (ddi_get_instance(dip) > 0)
299 		return (DDI_FAILURE);
300 
301 	mutex_enter(&dev_lck);
302 
303 	/*
304 	 * This is the Zero'th minor device which is created.
305 	 */
306 	if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) {
307 		cmn_err(CE_WARN, "nsmb_attach: soft state alloc");
308 		goto attach_failed;
309 	}
310 	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
311 	    NULL) == DDI_FAILURE) {
312 		cmn_err(CE_WARN, "nsmb_attach: create minor");
313 		goto attach_failed;
314 	}
315 	if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) {
316 		cmn_err(CE_WARN, "nsmb_attach: get soft state");
317 		ddi_remove_minor_node(dip, NULL);
318 		goto attach_failed;
319 	}
320 
321 	sdp->sd_dip = dip;
322 	sdp->sd_seq = 0;
323 	sdp->sd_smbfid = -1;
324 	mutex_exit(&dev_lck);
325 	ddi_report_dev(dip);
326 	return (DDI_SUCCESS);
327 
328 attach_failed:
329 	ddi_soft_state_free(statep, 0);
330 	mutex_exit(&dev_lck);
331 	return (DDI_FAILURE);
332 }
333 
334 /*ARGSUSED*/
335 static int
336 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
337 {
338 
339 	if (cmd != DDI_DETACH)
340 		return (DDI_FAILURE);
341 	if (ddi_get_instance(dip) > 0)
342 		return (DDI_FAILURE);
343 
344 	ddi_soft_state_free(statep, 0);
345 	ddi_remove_minor_node(dip, NULL);
346 
347 	return (DDI_SUCCESS);
348 }
349 
350 /*ARGSUSED*/
351 static int
352 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags,	/* model.h */
353 	cred_t *cr, int *rvalp)
354 {
355 	smb_dev_t *sdp;
356 	int err;
357 
358 	sdp = ddi_get_soft_state(statep, getminor(dev));
359 	if (sdp == NULL) {
360 		return (DDI_FAILURE);
361 	}
362 	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
363 		return (EBADF);
364 	}
365 
366 	/*
367 	 * Dont give access if the zone id is not as the same as we
368 	 * set in the nsmb_open or dont belong to the global zone.
369 	 * Check if the user belongs to this zone..
370 	 */
371 	if (sdp->zoneid != getzoneid())
372 		return (EIO);
373 
374 	/*
375 	 * We have a zone_shutdown call back that kills all the VCs
376 	 * in a zone that's shutting down.  That action will cause
377 	 * all of these ioctls to fail on such VCs, so no need to
378 	 * check the zone status here on every ioctl call.
379 	 */
380 
381 	err = 0;
382 	switch (cmd) {
383 	case SMBIOC_GETVERS:
384 		(void) ddi_copyout(&nsmb_version, (void *)arg,
385 		    sizeof (nsmb_version), flags);
386 		break;
387 
388 	case SMBIOC_FLAGS2:
389 		err = smb_usr_get_flags2(sdp, arg, flags);
390 		break;
391 
392 	case SMBIOC_GETSSNKEY:
393 		err = smb_usr_get_ssnkey(sdp, arg, flags);
394 		break;
395 
396 	case SMBIOC_DUP_DEV:
397 		err = smb_usr_dup_dev(sdp, arg, flags);
398 		break;
399 
400 	case SMBIOC_REQUEST:
401 		err = smb_usr_simplerq(sdp, arg, flags, cr);
402 		break;
403 
404 	case SMBIOC_T2RQ:
405 		err = smb_usr_t2request(sdp, arg, flags, cr);
406 		break;
407 
408 	case SMBIOC_READ:
409 	case SMBIOC_WRITE:
410 		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
411 		break;
412 
413 	case SMBIOC_NTCREATE:
414 		err = smb_usr_ntcreate(sdp, arg, flags, cr);
415 		break;
416 
417 	case SMBIOC_PRINTJOB:
418 		err = smb_usr_printjob(sdp, arg, flags, cr);
419 		break;
420 
421 	case SMBIOC_CLOSEFH:
422 		err = smb_usr_closefh(sdp, cr);
423 		break;
424 
425 	case SMBIOC_SSN_CREATE:
426 	case SMBIOC_SSN_FIND:
427 		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
428 		break;
429 
430 	case SMBIOC_SSN_KILL:
431 	case SMBIOC_SSN_RELE:
432 		err = smb_usr_drop_ssn(sdp, cmd);
433 		break;
434 
435 	case SMBIOC_TREE_CONNECT:
436 	case SMBIOC_TREE_FIND:
437 		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
438 		break;
439 
440 	case SMBIOC_TREE_KILL:
441 	case SMBIOC_TREE_RELE:
442 		err = smb_usr_drop_tree(sdp, cmd);
443 		break;
444 
445 	case SMBIOC_IOD_WORK:
446 		err = smb_usr_iod_work(sdp, arg, flags, cr);
447 		break;
448 
449 	case SMBIOC_IOD_IDLE:
450 	case SMBIOC_IOD_RCFAIL:
451 		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
452 		break;
453 
454 	case SMBIOC_PK_ADD:
455 	case SMBIOC_PK_DEL:
456 	case SMBIOC_PK_CHK:
457 	case SMBIOC_PK_DEL_OWNER:
458 	case SMBIOC_PK_DEL_EVERYONE:
459 		err = smb_pkey_ioctl(cmd, arg, flags, cr);
460 		break;
461 
462 	default:
463 		err = ENOTTY;
464 		break;
465 	}
466 
467 	return (err);
468 }
469 
470 /*ARGSUSED*/
471 static int
472 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
473 {
474 	major_t new_major;
475 	smb_dev_t *sdp, *sdv;
476 
477 	mutex_enter(&dev_lck);
478 	for (; ; ) {
479 		minor_t start = nsmb_minor;
480 		do {
481 			if (nsmb_minor >= MAXMIN32) {
482 				if (nsmb_major == getmajor(*dev))
483 					nsmb_minor = NSMB_MIN_MINOR;
484 				else
485 					nsmb_minor = 0;
486 			} else {
487 				nsmb_minor++;
488 			}
489 			sdv = ddi_get_soft_state(statep, nsmb_minor);
490 		} while ((sdv != NULL) && (nsmb_minor != start));
491 		if (nsmb_minor == start) {
492 			/*
493 			 * The condition we need to solve here is  all the
494 			 * MAXMIN32(~262000) minors numbers are reached. We
495 			 * need to create a new major number.
496 			 * zfs uses getudev() to create a new major number.
497 			 */
498 			if ((new_major = getudev()) == (major_t)-1) {
499 				cmn_err(CE_WARN,
500 				    "nsmb: Can't get unique major "
501 				    "device number.");
502 				mutex_exit(&dev_lck);
503 				return (-1);
504 			}
505 			nsmb_major = new_major;
506 			nsmb_minor = 0;
507 		} else {
508 			break;
509 		}
510 	}
511 
512 	/*
513 	 * This is called by mount or open call.
514 	 * The open() routine is passed a pointer to a device number so
515 	 * that  the  driver  can  change the minor number. This allows
516 	 * drivers to dynamically  create minor instances of  the  dev-
517 	 * ice.  An  example of this might be a  pseudo-terminal driver
518 	 * that creates a new pseudo-terminal whenever it   is  opened.
519 	 * A driver that chooses the minor number dynamically, normally
520 	 * creates only one  minor  device  node  in   attach(9E)  with
521 	 * ddi_create_minor_node(9F) then changes the minor number com-
522 	 * ponent of *devp using makedevice(9F)  and  getmajor(9F)  The
523 	 * driver needs to keep track of available minor numbers inter-
524 	 * nally.
525 	 * Stuff the structure smb_dev.
526 	 * return.
527 	 */
528 
529 	if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) {
530 		mutex_exit(&dev_lck);
531 		return (ENXIO);
532 	}
533 	if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) {
534 		mutex_exit(&dev_lck);
535 		return (ENXIO);
536 	}
537 
538 	sdp->sd_seq = nsmb_minor;
539 	sdp->sd_cred = cr;
540 	sdp->sd_smbfid = -1;
541 	sdp->sd_flags |= NSMBFL_OPEN;
542 	sdp->zoneid = crgetzoneid(cr);
543 	mutex_exit(&dev_lck);
544 
545 	*dev = makedevice(nsmb_major, nsmb_minor);
546 
547 	return (0);
548 }
549 
550 /*ARGSUSED*/
551 static int
552 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
553 {
554 	minor_t inst = getminor(dev);
555 	smb_dev_t *sdp;
556 	int err;
557 
558 	mutex_enter(&dev_lck);
559 	/*
560 	 * 1. Check the validity of the minor number.
561 	 * 2. Release any shares/vc associated  with the connection.
562 	 * 3. Can close the minor number.
563 	 * 4. Deallocate any resources allocated in open() call.
564 	 */
565 
566 	sdp = ddi_get_soft_state(statep, inst);
567 	if (sdp != NULL)
568 		err = nsmb_close2(sdp, cr);
569 	else
570 		err = ENXIO;
571 
572 	/*
573 	 * Free the instance
574 	 */
575 	ddi_soft_state_free(statep, inst);
576 	mutex_exit(&dev_lck);
577 	return (err);
578 }
579 
580 static int
581 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
582 {
583 	struct smb_vc *vcp;
584 	struct smb_share *ssp;
585 
586 	if (sdp->sd_smbfid != -1)
587 		(void) smb_usr_closefh(sdp, cr);
588 
589 	ssp = sdp->sd_share;
590 	if (ssp != NULL)
591 		smb_share_rele(ssp);
592 
593 	vcp = sdp->sd_vc;
594 	if (vcp != NULL) {
595 		/*
596 		 * If this dev minor was opened by smbiod,
597 		 * mark this VC as "dead" because it now
598 		 * will have no IOD to service it.
599 		 */
600 		if (sdp->sd_flags & NSMBFL_IOD)
601 			smb_iod_disconnect(vcp);
602 		smb_vc_rele(vcp);
603 	}
604 
605 	return (0);
606 }
607 
608 /*
609  * Helper for SMBIOC_DUP_DEV
610  * Duplicate state from the FD @arg ("from") onto
611  * the FD for this device instance.
612  */
613 int
614 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
615 {
616 	file_t *fp = NULL;
617 	vnode_t *vp;
618 	smb_dev_t *from_sdp;
619 	dev_t dev;
620 	int32_t ufd;
621 	int err;
622 
623 	/* Should be no VC */
624 	if (sdp->sd_vc != NULL)
625 		return (EISCONN);
626 
627 	/*
628 	 * Get from_sdp (what we will duplicate)
629 	 */
630 	if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
631 		return (EFAULT);
632 	if ((fp = getf(ufd)) == NULL)
633 		return (EBADF);
634 	/* rele fp below */
635 	vp = fp->f_vnode;
636 	dev = vp->v_rdev;
637 	if (dev == 0 || dev == NODEV ||
638 	    getmajor(dev) != nsmb_major) {
639 		err = EINVAL;
640 		goto out;
641 	}
642 	from_sdp = ddi_get_soft_state(statep, getminor(dev));
643 	if (from_sdp == NULL) {
644 		err = EINVAL;
645 		goto out;
646 	}
647 
648 	/*
649 	 * Duplicate VC and share references onto this FD.
650 	 */
651 	if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
652 		smb_vc_hold(sdp->sd_vc);
653 	if ((sdp->sd_share = from_sdp->sd_share) != NULL)
654 		smb_share_hold(sdp->sd_share);
655 	sdp->sd_level = from_sdp->sd_level;
656 	err = 0;
657 
658 out:
659 	if (fp)
660 		releasef(ufd);
661 	return (err);
662 }
663 
664 
665 /*
666  * Helper used by smbfs_mount
667  */
668 int
669 smb_dev2share(int fd, struct smb_share **sspp)
670 {
671 	file_t *fp = NULL;
672 	vnode_t *vp;
673 	smb_dev_t *sdp;
674 	smb_share_t *ssp;
675 	dev_t dev;
676 	int err;
677 
678 	if ((fp = getf(fd)) == NULL)
679 		return (EBADF);
680 	/* rele fp below */
681 
682 	vp = fp->f_vnode;
683 	dev = vp->v_rdev;
684 	if (dev == 0 || dev == NODEV ||
685 	    getmajor(dev) != nsmb_major) {
686 		err = EINVAL;
687 		goto out;
688 	}
689 
690 	sdp = ddi_get_soft_state(statep, getminor(dev));
691 	if (sdp == NULL) {
692 		err = EINVAL;
693 		goto out;
694 	}
695 
696 	ssp = sdp->sd_share;
697 	if (ssp == NULL) {
698 		err = ENOTCONN;
699 		goto out;
700 	}
701 
702 	/*
703 	 * Our caller gains a ref. to this share.
704 	 */
705 	*sspp = ssp;
706 	smb_share_hold(ssp);
707 	err = 0;
708 
709 out:
710 	if (fp)
711 		releasef(fd);
712 	return (err);
713 }
714