2 * Copyright (c) 2000-2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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.
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/sysmacros.h>
45 #include <sys/modctl.h>
50 #include <sys/cmn_err.h>
53 #include <sys/sunddi.h>
54 #include <sys/sunldi.h>
55 #include <sys/policy.h>
57 #include <sys/pathname.h>
58 #include <sys/mount.h>
60 #include <sys/fs_subr.h>
61 #include <sys/modctl.h>
62 #include <sys/devops.h>
63 #include <sys/thread.h>
64 #include <sys/types.h>
67 #include <netsmb/smb_osdep.h>
68 #include <netsmb/mchain.h> /* for "htoles()" */
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>
76 #define NSMB_MIN_MINOR 1
77 #define NSMB_MAX_MINOR L_MAXMIN32
79 /* for version checks */
80 const uint32_t nsmb_version
= NSMB_VERSION
;
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
;
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
);
94 * cb_ops device operations.
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
);
103 static struct cb_ops nsmb_cbops
= {
104 nsmb_open
, /* open */
105 nsmb_close
, /* close */
106 nodev
, /* strategy */
111 nsmb_ioctl
, /* ioctl */
116 ddi_prop_op
, /* prop_op */
120 nodev
, /* int (*cb_aread)() */
121 nodev
/* int (*cb_awrite)() */
127 static int nsmb_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
128 static int nsmb_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
129 static int nsmb_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
,
130 void *arg
, void **result
);
132 static struct dev_ops nsmb_ops
= {
133 DEVO_REV
, /* devo_rev, */
135 nsmb_getinfo
, /* info */
136 nulldev
, /* identify */
138 nsmb_attach
, /* attach */
139 nsmb_detach
, /* detach */
141 &nsmb_cbops
, /* driver ops - devctl interfaces */
142 NULL
, /* bus operations */
144 ddi_quiesce_not_needed
, /* quiesce */
148 * Module linkage information.
151 static struct modldrv nsmb_modldrv
= {
152 &mod_driverops
, /* Driver module */
153 "SMBFS network driver",
154 &nsmb_ops
/* Driver ops */
157 static struct modlinkage nsmb_modlinkage
= {
159 (void *)&nsmb_modldrv
,
168 (void) ddi_soft_state_init(&statep
, sizeof (smb_dev_t
), 1);
170 /* Can initialize some mutexes also. */
171 mutex_init(&dev_lck
, NULL
, MUTEX_DRIVER
, NULL
);
173 /* Connection data structures. */
174 (void) smb_sm_init();
176 /* Initialize password Key chain DB. */
179 /* Time conversion stuff. */
182 /* Initialize crypto mechanisms. */
183 smb_crypto_mech_init();
185 zone_key_create(&nsmb_zone_key
, NULL
, nsmb_zone_shutdown
,
189 * Install the module. Do this after other init,
190 * to prevent entrances before we're ready.
192 if ((error
= mod_install((&nsmb_modlinkage
))) != 0) {
194 /* Same as 2nd half of _fini */
195 (void) zone_key_delete(nsmb_zone_key
);
198 mutex_destroy(&dev_lck
);
199 ddi_soft_state_fini(&statep
);
213 * Prevent unload if we have active VCs
214 * or stored passwords
216 if ((status
= smb_sm_idle()) != 0)
218 if ((status
= smb_pkey_idle()) != 0)
222 * Remove the module. Do this before destroying things,
223 * to prevent new entrances while we're destorying.
225 if ((status
= mod_remove(&nsmb_modlinkage
)) != 0) {
229 (void) zone_key_delete(nsmb_zone_key
);
231 /* Time conversion stuff. */
234 /* Destroy password Key chain DB. */
239 mutex_destroy(&dev_lck
);
240 ddi_soft_state_fini(&statep
);
246 _info(struct modinfo
*modinfop
)
248 return (mod_info(&nsmb_modlinkage
, modinfop
));
253 nsmb_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
255 int ret
= DDI_SUCCESS
;
258 case DDI_INFO_DEVT2DEVINFO
:
261 case DDI_INFO_DEVT2INSTANCE
:
271 nsmb_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
274 if (cmd
!= DDI_ATTACH
)
275 return (DDI_FAILURE
);
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.
282 if (ddi_get_instance(dip
) > 0)
283 return (DDI_FAILURE
);
285 if (ddi_create_minor_node(dip
, "nsmb", S_IFCHR
, 0, DDI_PSEUDO
,
287 cmn_err(CE_WARN
, "nsmb_attach: create minor");
288 return (DDI_FAILURE
);
292 * We need the major number a couple places,
293 * i.e. in smb_dev2share()
295 nsmb_major
= ddi_name_to_major(NSMB_NAME
);
299 return (DDI_SUCCESS
);
304 nsmb_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
307 if (cmd
!= DDI_DETACH
)
308 return (DDI_FAILURE
);
309 if (ddi_get_instance(dip
) > 0)
310 return (DDI_FAILURE
);
313 ddi_remove_minor_node(dip
, NULL
);
315 return (DDI_SUCCESS
);
320 nsmb_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int flags
, /* model.h */
321 cred_t
*cr
, int *rvalp
)
326 sdp
= ddi_get_soft_state(statep
, getminor(dev
));
328 return (DDI_FAILURE
);
330 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0) {
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..
339 if (sdp
->zoneid
!= getzoneid())
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.
350 * Serialize ioctl calls. The smb_usr_... functions
351 * don't expect concurrent calls on a given sdp.
353 mutex_enter(&sdp
->sd_lock
);
354 if ((sdp
->sd_flags
& NSMBFL_IOCTL
) != 0) {
355 mutex_exit(&sdp
->sd_lock
);
358 sdp
->sd_flags
|= NSMBFL_IOCTL
;
359 mutex_exit(&sdp
->sd_lock
);
364 (void) ddi_copyout(&nsmb_version
, (void *)arg
,
365 sizeof (nsmb_version
), flags
);
369 err
= smb_usr_get_flags2(sdp
, arg
, flags
);
372 case SMBIOC_GETSSNKEY
:
373 err
= smb_usr_get_ssnkey(sdp
, arg
, flags
);
377 err
= smb_usr_dup_dev(sdp
, arg
, flags
);
381 err
= smb_usr_simplerq(sdp
, arg
, flags
, cr
);
385 err
= smb_usr_t2request(sdp
, arg
, flags
, cr
);
390 err
= smb_usr_rw(sdp
, cmd
, arg
, flags
, cr
);
393 case SMBIOC_NTCREATE
:
394 err
= smb_usr_ntcreate(sdp
, arg
, flags
, cr
);
397 case SMBIOC_PRINTJOB
:
398 err
= smb_usr_printjob(sdp
, arg
, flags
, cr
);
402 err
= smb_usr_closefh(sdp
, cr
);
405 case SMBIOC_SSN_CREATE
:
406 case SMBIOC_SSN_FIND
:
407 err
= smb_usr_get_ssn(sdp
, cmd
, arg
, flags
, cr
);
410 case SMBIOC_SSN_KILL
:
411 case SMBIOC_SSN_RELE
:
412 err
= smb_usr_drop_ssn(sdp
, cmd
);
415 case SMBIOC_TREE_CONNECT
:
416 case SMBIOC_TREE_FIND
:
417 err
= smb_usr_get_tree(sdp
, cmd
, arg
, flags
, cr
);
420 case SMBIOC_TREE_KILL
:
421 case SMBIOC_TREE_RELE
:
422 err
= smb_usr_drop_tree(sdp
, cmd
);
425 case SMBIOC_IOD_WORK
:
426 err
= smb_usr_iod_work(sdp
, arg
, flags
, cr
);
429 case SMBIOC_IOD_IDLE
:
430 case SMBIOC_IOD_RCFAIL
:
431 err
= smb_usr_iod_ioctl(sdp
, cmd
, arg
, flags
);
437 case SMBIOC_PK_DEL_OWNER
:
438 case SMBIOC_PK_DEL_EVERYONE
:
439 err
= smb_pkey_ioctl(cmd
, arg
, flags
, cr
);
447 mutex_enter(&sdp
->sd_lock
);
448 sdp
->sd_flags
&= ~NSMBFL_IOCTL
;
449 mutex_exit(&sdp
->sd_lock
);
455 * This does "clone" open, meaning it automatically
456 * assigns an available minor unit for each open.
460 nsmb_open(dev_t
*dev
, int flags
, int otyp
, cred_t
*cr
)
465 mutex_enter(&dev_lck
);
467 for (m
= last_minor
+ 1; m
!= last_minor
; m
++) {
468 if (m
> NSMB_MAX_MINOR
)
471 if (ddi_get_soft_state(statep
, m
) == NULL
) {
477 /* No available minor units. */
478 mutex_exit(&dev_lck
);
482 /* NB: dev_lck still held */
483 if (ddi_soft_state_zalloc(statep
, m
) == DDI_FAILURE
) {
484 mutex_exit(&dev_lck
);
487 if ((sdp
= ddi_get_soft_state(statep
, m
)) == NULL
) {
488 mutex_exit(&dev_lck
);
491 *dev
= makedevice(nsmb_major
, m
);
492 mutex_exit(&dev_lck
);
495 sdp
->sd_flags
|= NSMBFL_OPEN
;
496 sdp
->zoneid
= crgetzoneid(cr
);
497 mutex_init(&sdp
->sd_lock
, NULL
, MUTEX_DRIVER
, NULL
);
504 nsmb_close(dev_t dev
, int flags
, int otyp
, cred_t
*cr
)
506 minor_t inst
= getminor(dev
);
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.
517 sdp
= ddi_get_soft_state(statep
, inst
);
519 err
= nsmb_close2(sdp
, cr
);
526 mutex_enter(&dev_lck
);
527 ddi_soft_state_free(statep
, inst
);
528 mutex_exit(&dev_lck
);
533 nsmb_close2(smb_dev_t
*sdp
, cred_t
*cr
)
536 struct smb_share
*ssp
;
538 if (sdp
->sd_smbfid
!= -1)
539 (void) smb_usr_closefh(sdp
, cr
);
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.
552 if (sdp
->sd_flags
& NSMBFL_IOD
)
553 smb_iod_disconnect(vcp
);
556 mutex_destroy(&sdp
->sd_lock
);
562 * Helper for SMBIOC_DUP_DEV
563 * Duplicate state from the FD @arg ("from") onto
564 * the FD for this device instance.
567 smb_usr_dup_dev(smb_dev_t
*sdp
, intptr_t arg
, int flags
)
576 /* Should be no VC */
577 if (sdp
->sd_vc
!= NULL
)
581 * Get from_sdp (what we will duplicate)
583 if (ddi_copyin((void *) arg
, &ufd
, sizeof (ufd
), flags
))
585 if ((fp
= getf(ufd
)) == NULL
)
590 if (dev
== 0 || dev
== NODEV
||
591 getmajor(dev
) != nsmb_major
) {
595 from_sdp
= ddi_get_soft_state(statep
, getminor(dev
));
596 if (from_sdp
== NULL
) {
602 * Duplicate VC and share references onto this FD.
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
;
619 * Helper used by smbfs_mount
622 smb_dev2share(int fd
, struct smb_share
**sspp
)
631 if ((fp
= getf(fd
)) == NULL
)
637 if (dev
== 0 || dev
== NODEV
||
638 getmajor(dev
) != nsmb_major
) {
643 sdp
= ddi_get_soft_state(statep
, getminor(dev
));
656 * Our caller gains a ref. to this share.