Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
re #11128 nsmb_close locking and teardown deadlock

@@ -29,13 +29,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 /*
- * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/errno.h>

@@ -59,48 +60,64 @@
 #include <sys/sdt.h>
 #include <fs/fs_subr.h>
 #include <sys/modctl.h>
 #include <sys/devops.h>
 #include <sys/thread.h>
-#include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/zone.h>
 
 #include <netsmb/smb_osdep.h>
 #include <netsmb/mchain.h>              /* for "htoles()" */
 
 #include <netsmb/smb.h>
+#include <netsmb/smb2.h>
 #include <netsmb/smb_conn.h>
 #include <netsmb/smb_subr.h>
 #include <netsmb/smb_dev.h>
 #include <netsmb/smb_pass.h>
 
+#ifndef _KERNEL
+#include <libfknsmb.h>
+
+#define _init(v)        nsmb_drv_init(v)
+#define _fini(v)        nsmb_drv_fini(v)
+
+#endif  /* _KERNEL */
+
 #define NSMB_MIN_MINOR  1
 #define NSMB_MAX_MINOR  L_MAXMIN32
 
 /* for version checks */
 const uint32_t nsmb_version = NSMB_VERSION;
 
+/* for smb_nbst_create() */
+dev_t nsmb_dev_tcp = NODEV;
+dev_t nsmb_dev_tcp6 = NODEV;
+
 static void *statep;
 static major_t nsmb_major;
 static minor_t last_minor = NSMB_MIN_MINOR;
-static dev_info_t *nsmb_dip;
 static kmutex_t  dev_lck;
 
-/* Zone support */
-zone_key_t nsmb_zone_key;
-extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
-extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
-
 /*
  * cb_ops device operations.
  */
 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
                                 cred_t *credp, int *rvalp);
 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
 
+#ifdef  _KERNEL
+
+static dev_info_t *nsmb_dip;
+
+/* Zone support */
+zone_key_t nsmb_zone_key;
+extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
+extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
+
 /* smbfs cb_ops */
 static struct cb_ops nsmb_cbops = {
         nsmb_open,      /* open */
         nsmb_close,     /* close */
         nodev,          /* strategy */

@@ -158,14 +175,18 @@
         MODREV_1,
         (void *)&nsmb_modldrv,
         NULL
 };
 
+#endif  /* _KERNEL */
+
 int
 _init(void)
 {
+#ifdef  _KERNEL
         int error;
+#endif  /* _KERNEL */
 
         (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
 
         /* Can initialize some mutexes also. */
         mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);

@@ -174,16 +195,11 @@
         (void) smb_sm_init();
 
         /* Initialize password Key chain DB. */
         smb_pkey_init();
 
-        /* Time conversion stuff. */
-        smb_time_init();
-
-        /* Initialize crypto mechanisms. */
-        smb_crypto_mech_init();
-
+#ifdef  _KERNEL
         zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
             nsmb_zone_destroy);
 
         /*
          * Install the module.  Do this after other init,

@@ -198,10 +214,18 @@
                 mutex_destroy(&dev_lck);
                 ddi_soft_state_fini(&statep);
 
                 return (error);
         }
+#else   /* _KERNEL */
+        streams_msg_init();
+        /* No attach, so need to set major. */
+        nsmb_major = 1;
+        /* And these, for smb_nbst_create() */
+        nsmb_dev_tcp = AF_INET;
+        nsmb_dev_tcp6 = AF_INET6;
+#endif  /* _KERNEL */
 
         return (0);
 }
 
 int

@@ -216,23 +240,22 @@
         if ((status = smb_sm_idle()) != 0)
                 return (status);
         if ((status = smb_pkey_idle()) != 0)
                 return (status);
 
+#ifdef  _KERNEL
         /*
          * Remove the module.  Do this before destroying things,
          * to prevent new entrances while we're destorying.
          */
         if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
                 return (status);
         }
 
         (void) zone_key_delete(nsmb_zone_key);
+#endif  /* _KERNEL */
 
-        /* Time conversion stuff. */
-        smb_time_fini();
-
         /* Destroy password Key chain DB. */
         smb_pkey_fini();
 
         smb_sm_done();
 

@@ -240,10 +263,12 @@
         ddi_soft_state_fini(&statep);
 
         return (status);
 }
 
+#ifdef  _KERNEL
+
 int
 _info(struct modinfo *modinfop)
 {
         return (mod_info(&nsmb_modlinkage, modinfop));
 }

@@ -268,10 +293,11 @@
 }
 
 static int
 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
+        major_t tmaj;
 
         if (cmd != DDI_ATTACH)
                 return (DDI_FAILURE);
 
         /*

@@ -292,10 +318,24 @@
          * We need the major number a couple places,
          * i.e. in smb_dev2share()
          */
         nsmb_major = ddi_name_to_major(NSMB_NAME);
 
+        /*
+         * We also need major numbers for t_kopen
+         */
+        tmaj = ddi_name_to_major("tcp");
+        if (tmaj == DDI_MAJOR_T_NONE)
+                cmn_err(CE_NOTE, "no tcp major?");
+        else
+                nsmb_dev_tcp = makedevice(tmaj, 0);
+        tmaj = ddi_name_to_major("tcp6");
+        if (tmaj == DDI_MAJOR_T_NONE)
+                cmn_err(CE_NOTE, "no tcp6 major?");
+        else
+                nsmb_dev_tcp6 = makedevice(tmaj, 0);
+
         nsmb_dip = dip;
         ddi_report_dev(dip);
         return (DDI_SUCCESS);
 }
 

@@ -313,21 +353,80 @@
         ddi_remove_minor_node(dip, NULL);
 
         return (DDI_SUCCESS);
 }
 
+#else   /* _KERNEL */
+
+/*
+ * Wrappers for libfknsmb: ioctl, open, close, load
+ */
+
 /*ARGSUSED*/
+int
+nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
+{
+        dev_t dev = expldev(dev32);
+        cred_t *cr = CRED();
+        int err;
+
+        err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
+        return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
+{
+        dev_t dev = expldev(*dev32p);
+        int err;
+
+        err = nsmb_open(&dev, flags, otyp, CRED());
+        if (err == 0) {
+                /*
+                 * We have NSMB_MAX_MINOR == L_MAXMIN32
+                 * therefore cmpldev never fails.
+                 */
+                VERIFY(cmpldev(dev32p, dev) != 0);
+        }
+        return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_close(dev32_t dev32, int flags, int otyp)
+{
+        dev_t dev = expldev(dev32);
+        int err;
+
+        err = nsmb_close(dev, flags, otyp, CRED());
+        return (err);
+}
+
+/*
+ * This function intentionally does nothing.  It's used only to
+ * force libfknsmb to load at program start so one can set
+ * breakpoints etc. without debugger "force load" tricks.
+ */
+void
+nsmb_drv_load(void)
+{
+}
+
+#endif  /* _KERNEL */
+
+/*ARGSUSED*/
 static int
 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
     cred_t *cr, int *rvalp)
 {
         smb_dev_t *sdp;
         int err;
 
         sdp = ddi_get_soft_state(statep, getminor(dev));
         if (sdp == NULL) {
-                return (DDI_FAILURE);
+                return (EBADF);
         }
         if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
                 return (EBADF);
         }
 

@@ -344,112 +443,12 @@
          * in a zone that's shutting down.  That action will cause
          * all of these ioctls to fail on such VCs, so no need to
          * check the zone status here on every ioctl call.
          */
 
-        /*
-         * Serialize ioctl calls.  The smb_usr_... functions
-         * don't expect concurrent calls on a given sdp.
-         */
-        mutex_enter(&sdp->sd_lock);
-        if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
-                mutex_exit(&sdp->sd_lock);
-                return (EBUSY);
-        }
-        sdp->sd_flags |= NSMBFL_IOCTL;
-        mutex_exit(&sdp->sd_lock);
+        err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);
 
-        err = 0;
-        switch (cmd) {
-        case SMBIOC_GETVERS:
-                (void) ddi_copyout(&nsmb_version, (void *)arg,
-                    sizeof (nsmb_version), flags);
-                break;
-
-        case SMBIOC_FLAGS2:
-                err = smb_usr_get_flags2(sdp, arg, flags);
-                break;
-
-        case SMBIOC_GETSSNKEY:
-                err = smb_usr_get_ssnkey(sdp, arg, flags);
-                break;
-
-        case SMBIOC_DUP_DEV:
-                err = smb_usr_dup_dev(sdp, arg, flags);
-                break;
-
-        case SMBIOC_REQUEST:
-                err = smb_usr_simplerq(sdp, arg, flags, cr);
-                break;
-
-        case SMBIOC_T2RQ:
-                err = smb_usr_t2request(sdp, arg, flags, cr);
-                break;
-
-        case SMBIOC_READ:
-        case SMBIOC_WRITE:
-                err = smb_usr_rw(sdp, cmd, arg, flags, cr);
-                break;
-
-        case SMBIOC_NTCREATE:
-                err = smb_usr_ntcreate(sdp, arg, flags, cr);
-                break;
-
-        case SMBIOC_PRINTJOB:
-                err = smb_usr_printjob(sdp, arg, flags, cr);
-                break;
-
-        case SMBIOC_CLOSEFH:
-                err = smb_usr_closefh(sdp, cr);
-                break;
-
-        case SMBIOC_SSN_CREATE:
-        case SMBIOC_SSN_FIND:
-                err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
-                break;
-
-        case SMBIOC_SSN_KILL:
-        case SMBIOC_SSN_RELE:
-                err = smb_usr_drop_ssn(sdp, cmd);
-                break;
-
-        case SMBIOC_TREE_CONNECT:
-        case SMBIOC_TREE_FIND:
-                err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
-                break;
-
-        case SMBIOC_TREE_KILL:
-        case SMBIOC_TREE_RELE:
-                err = smb_usr_drop_tree(sdp, cmd);
-                break;
-
-        case SMBIOC_IOD_WORK:
-                err = smb_usr_iod_work(sdp, arg, flags, cr);
-                break;
-
-        case SMBIOC_IOD_IDLE:
-        case SMBIOC_IOD_RCFAIL:
-                err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
-                break;
-
-        case SMBIOC_PK_ADD:
-        case SMBIOC_PK_DEL:
-        case SMBIOC_PK_CHK:
-        case SMBIOC_PK_DEL_OWNER:
-        case SMBIOC_PK_DEL_EVERYONE:
-                err = smb_pkey_ioctl(cmd, arg, flags, cr);
-                break;
-
-        default:
-                err = ENOTTY;
-                break;
-        }
-
-        mutex_enter(&sdp->sd_lock);
-        sdp->sd_flags &= ~NSMBFL_IOCTL;
-        mutex_exit(&sdp->sd_lock);
-
         return (err);
 }
 
 /*
  * This does "clone" open, meaning it automatically

@@ -489,11 +488,10 @@
                 return (ENXIO);
         }
         *dev = makedevice(nsmb_major, m);
         mutex_exit(&dev_lck);
 
-        sdp->sd_smbfid = -1;
         sdp->sd_flags |= NSMBFL_OPEN;
         sdp->zoneid = crgetzoneid(cr);
         mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
 
         return (0);

@@ -527,18 +525,21 @@
         ddi_soft_state_free(statep, inst);
         mutex_exit(&dev_lck);
         return (err);
 }
 
+/*ARGSUSED*/
 static int
 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
 {
         struct smb_vc *vcp;
         struct smb_share *ssp;
+        struct smb_fh *fhp;
 
-        if (sdp->sd_smbfid != -1)
-                (void) smb_usr_closefh(sdp, cr);
+        fhp = sdp->sd_fh;
+        if (fhp != NULL)
+                smb_fh_rele(fhp);
 
         ssp = sdp->sd_share;
         if (ssp != NULL)
                 smb_share_rele(ssp);
 

@@ -564,12 +565,14 @@
  * the FD for this device instance.
  */
 int
 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
 {
+#ifdef  _KERNEL
         file_t *fp = NULL;
         vnode_t *vp;
+#endif  /* _KERNEL */
         smb_dev_t *from_sdp;
         dev_t dev;
         int32_t ufd;
         int err;
 

@@ -580,20 +583,28 @@
         /*
          * Get from_sdp (what we will duplicate)
          */
         if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
                 return (EFAULT);
+#ifdef  _KERNEL
         if ((fp = getf(ufd)) == NULL)
                 return (EBADF);
         /* rele fp below */
         vp = fp->f_vnode;
         dev = vp->v_rdev;
+#else   /* _KERNEL */
+        /*
+         * No getf(ufd) -- ufd is really a dev32_t
+         */
+        dev = expldev((dev32_t)ufd);
+#endif  /* _KERNEL */
         if (dev == 0 || dev == NODEV ||
             getmajor(dev) != nsmb_major) {
                 err = EINVAL;
                 goto out;
         }
+
         from_sdp = ddi_get_soft_state(statep, getminor(dev));
         if (from_sdp == NULL) {
                 err = EINVAL;
                 goto out;
         }

@@ -607,12 +618,14 @@
                 smb_share_hold(sdp->sd_share);
         sdp->sd_level = from_sdp->sd_level;
         err = 0;
 
 out:
+#ifdef  _KERNEL
         if (fp)
                 releasef(ufd);
+#endif  /* _KERNEL */
         return (err);
 }
 
 
 /*

@@ -619,23 +632,31 @@
  * Helper used by smbfs_mount
  */
 int
 smb_dev2share(int fd, struct smb_share **sspp)
 {
+#ifdef  _KERNEL
         file_t *fp = NULL;
         vnode_t *vp;
+#endif  /* _KERNEL */
         smb_dev_t *sdp;
         smb_share_t *ssp;
         dev_t dev;
         int err;
 
+#ifdef  _KERNEL
         if ((fp = getf(fd)) == NULL)
                 return (EBADF);
         /* rele fp below */
-
         vp = fp->f_vnode;
         dev = vp->v_rdev;
+#else   /* _KERNEL */
+        /*
+         * No getf(ufd) -- fd is really a dev32_t
+         */
+        dev = expldev((dev32_t)fd);
+#endif  /* _KERNEL */
         if (dev == 0 || dev == NODEV ||
             getmajor(dev) != nsmb_major) {
                 err = EINVAL;
                 goto out;
         }

@@ -658,9 +679,11 @@
         *sspp = ssp;
         smb_share_hold(ssp);
         err = 0;
 
 out:
+#ifdef  _KERNEL
         if (fp)
                 releasef(fd);
+#endif  /* _KERNEL */
         return (err);
 }