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