Print this page
NEX-17457 kernel share list fails to be updated after fs import
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
NEX-16159 Time spent sharing SMB filesystems could be reduced by optimizing smb_getdataset for default mount points
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-10098 Disabling SMB server service does not change the sharestate of a smb share to “offline”.(cstyle)
NEX-10098 Disabling SMB server service does not change the sharestate of a smb share to “offline”.
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-6949 SMB shares with no permission for root fail after restart
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6135 Pool cannot get exported while deletes is running
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4865 Still creating .$EXTEND directory with quotas disabled
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3863 Would like an SMB share property to enable/disable quotas
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-3673 CLONE NEX-2525 Customer cannot set Share Properties using MMC in Windows Server 2008 R2
Reviewed by: Alek Pinchuk <alek@nexenta.com>
NEX-1473 share unavailable after failover (copyright update)
NEX-1473 share unavailable after failover

@@ -17,11 +17,11 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * CDDL HEADER END
  *
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
  * SMB/CIFS share cache implementation.
  */

@@ -387,10 +387,11 @@
 smb_shr_add(smb_share_t *si)
 {
         struct stat st;
         smb_share_t *cached_si;
         nvlist_t *shrlist;
+        boolean_t created_zfs = B_FALSE;
         uint32_t status;
         int rc;
 
         assert(si != NULL);
 

@@ -414,19 +415,46 @@
 
         if (STYPE_ISDSK(si->shr_type)) {
                 /*
                  * If share type is STYPE_DISKTREE then the path to the
                  * share should exist so that we can add the share to cache.
+                 * If path is ZFS, add the .zfs/shares/<share> entry.
+                 *
+                 * Both actions may require privileges that main dropped,
+                 * so we need to temporarily make those effective.
                  */
+                if (smb_proc_takesem() == 0) {
+
+                        (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+                            PRIV_FILE_DAC_READ,
+                            PRIV_FILE_DAC_SEARCH,
+                            PRIV_FILE_DAC_WRITE,
+                            NULL);
+
                 rc = stat(si->shr_path, &st);
+                        if (rc == 0) {
+                                smb_shr_zfs_add(si);
+                                created_zfs = B_TRUE;
+                        }
+
+                        (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+                            PRIV_FILE_DAC_READ,
+                            PRIV_FILE_DAC_SEARCH,
+                            PRIV_FILE_DAC_WRITE,
+                            NULL);
+                        smb_proc_givesem();
+                } else {
+                        rc = NERR_InternalError;
+                }
                 if (rc != 0) {
                         smb_shr_cache_unlock();
                         return (NERR_ItemNotFound);
                 }
         }
 
         if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
+                /* This error should be impossible after findent above. */
                 smb_shr_cache_unlock();
                 return (status);
         }
 
         /* don't hold the lock across door call */

@@ -438,25 +466,45 @@
                 nvlist_free(shrlist);
 
                 if (rc == 0) {
                         smb_shr_publish(si->shr_name, si->shr_container);
 
-                        /* If path is ZFS, add the .zfs/shares/<share> entry. */
-                        smb_shr_zfs_add(si);
-
                         if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
                                 dfs_namespace_load(si->shr_name);
 
                         return (NERR_Success);
                 }
         }
 
+        /*
+         * Error code path, i.e. when the kernel could not accept
+         * the new share for some reason.
+         */
         if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
                 smb_shr_cache_delent(si->shr_name);
                 smb_shr_cache_unlock();
         }
 
+        if (created_zfs && smb_proc_takesem() == 0) {
+
+                (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_shr_zfs_remove(si);
+
+                (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_proc_givesem();
+        }
+
         /*
          * rc == ENOENT means the shared directory doesn't exist
          */
         return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
 }

@@ -503,13 +551,32 @@
                 }
         }
 
         /*
          * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
-         * to remove before cleanup of cache occurs.
+         * to remove before cleanup of cache occurs.  These actions
+         * require temporary elevation of privileges.
          */
+        if (smb_proc_takesem() == 0) {
+
+                (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
         smb_shr_zfs_remove(si);
+
+                (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_proc_givesem();
+        }
+
         (void) smb_shr_encode(si, &shrlist);
 
         (void) strlcpy(container, si->shr_container, sizeof (container));
         dfsroot = ((si->shr_flags & SMB_SHRF_DFSROOT) != 0);
         smb_shr_cache_delent(sharename);

@@ -568,14 +635,30 @@
         }
 
         bcopy(from_si, &to_si, sizeof (smb_share_t));
         (void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
 
-
         /* If path is ZFS, rename the .zfs/shares/<share> entry. */
+        if (smb_proc_takesem() == 0) {
+
+                (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
         smb_shr_zfs_rename(from_si, &to_si);
 
+                (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_proc_givesem();
+        }
+
         if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
                 smb_shr_cache_unlock();
                 return (status);
         }
 

@@ -626,18 +709,19 @@
  * Modifies an existing share. Properties that can be modified are:
  *
  *   o comment
  *   o AD container
  *   o host access
- *   o abe
+ *   o flags
  */
 uint32_t
 smb_shr_modify(smb_share_t *new_si)
 {
+        smb_share_t old_si;
         smb_share_t *si;
         boolean_t adc_changed = B_FALSE;
-        char old_container[MAXPATHLEN];
+        boolean_t quota_flag_changed = B_FALSE;
         uint32_t access, flag;
         nvlist_t *shrlist;
 
         assert(new_si != NULL);
 

@@ -653,20 +737,24 @@
                 /* IPC$ share cannot be modified */
                 smb_shr_cache_unlock();
                 return (ERROR_ACCESS_DENIED);
         }
 
+        /*
+         * Keep a copy of what the share entry looks like before we
+         * modify it.  We need this for things like unpublishing
+         * from the old share container, removing the quota dir.
+         */
+        bcopy(si, &old_si, sizeof (old_si));
+
+        /* Share comment */
         (void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
 
-        adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
-        if (adc_changed) {
-                /* save current container - needed for unpublishing */
-                (void) strlcpy(old_container, si->shr_container,
-                    sizeof (old_container));
+        /* Container */
                 (void) strlcpy(si->shr_container, new_si->shr_container,
                     sizeof (si->shr_container));
-        }
+        adc_changed = (strcmp(old_si.shr_container, si->shr_container) != 0);
 
         flag = (new_si->shr_flags & SMB_SHRF_ABE);
         si->shr_flags &= ~SMB_SHRF_ABE;
         si->shr_flags |= flag;
 

@@ -680,18 +768,34 @@
 
         flag = (new_si->shr_flags & SMB_SHRF_DFSROOT);
         si->shr_flags &= ~SMB_SHRF_DFSROOT;
         si->shr_flags |= flag;
 
+        flag = (new_si->shr_flags & SMB_SHRF_CA);
+        si->shr_flags &= ~SMB_SHRF_CA;
+        si->shr_flags |= flag;
+
+        flag = (new_si->shr_flags & SMB_SHRF_FSO);
+        si->shr_flags &= ~SMB_SHRF_FSO;
+        si->shr_flags |= flag;
+
+        flag = (new_si->shr_flags & SMB_SHRF_QUOTAS);
+        si->shr_flags &= ~SMB_SHRF_QUOTAS;
+        si->shr_flags |= flag;
+        if ((old_si.shr_flags ^ si->shr_flags) & SMB_SHRF_QUOTAS)
+                quota_flag_changed = B_TRUE;
+
         flag = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
         si->shr_flags &= ~SMB_SHRF_CSC_MASK;
         si->shr_flags |= flag;
 
         access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
         si->shr_flags &= ~SMB_SHRF_ACC_ALL;
         si->shr_flags |= access;
 
+        si->shr_encrypt = new_si->shr_encrypt;
+
         if (access & SMB_SHRF_ACC_NONE)
                 (void) strlcpy(si->shr_access_none, new_si->shr_access_none,
                     sizeof (si->shr_access_none));
 
         if (access & SMB_SHRF_ACC_RO)

@@ -713,14 +817,35 @@
                         nvlist_free(shrlist);
                 }
         }
 
         if (adc_changed) {
-                smb_shr_unpublish(new_si->shr_name, old_container);
+                smb_shr_unpublish(old_si.shr_name, old_si.shr_container);
                 smb_shr_publish(new_si->shr_name, new_si->shr_container);
         }
 
+        /* The following required privileges we dropped. */
+        if (quota_flag_changed && smb_proc_takesem() == 0) {
+
+                (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_shr_zfs_remove(&old_si);
+                smb_shr_zfs_add(si);
+
+                (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+                    PRIV_FILE_DAC_READ,
+                    PRIV_FILE_DAC_SEARCH,
+                    PRIV_FILE_DAC_WRITE,
+                    NULL);
+
+                smb_proc_givesem();
+        }
+
         return (NERR_Success);
 }
 
 /*
  * smb_shr_exists

@@ -1434,11 +1559,16 @@
  * All functions in this section are private
  * ============================================
  */
 
 /*
- * Load shares from sharemgr
+ * Loads the SMB shares, from sharemgr, then:
+ *     - calls smb_shr_add which:
+ *         - adds the share into the share cache
+ *         - adds the share into in-kernel kshare table
+ *         - publishes the share in ADS
+ *     - updates the share list in sharefs/sharetab
  */
 /*ARGSUSED*/
 void *
 smb_shr_load(void *args)
 {

@@ -1445,14 +1575,11 @@
         sa_handle_t handle;
         sa_group_t group, subgroup;
         char *gstate;
         boolean_t gdisabled;
 
-        (void) mutex_lock(&smb_shr_exec_mtx);
-        (void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
-            MAXPATHLEN);
-        (void) mutex_unlock(&smb_shr_exec_mtx);
+        smb_shr_load_execinfo();
 
         if ((handle = smb_shr_sa_enter()) == NULL) {
                 syslog(LOG_ERR, "smb_shr_load: load failed");
                 return (NULL);
         }

@@ -1479,11 +1606,55 @@
         }
         smb_shr_sa_exit();
         return (NULL);
 }
 
+void
+smb_shr_load_execinfo()
+{
+        (void) mutex_lock(&smb_shr_exec_mtx);
+        (void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
+            MAXPATHLEN);
+        (void) mutex_unlock(&smb_shr_exec_mtx);
+}
+
 /*
+ * Handles disabling shares in sharefs when stoping smbd
+ */
+void
+smb_shr_unload()
+{
+        smb_shriter_t iterator;
+        smb_share_t *si;
+        sa_handle_t handle;
+        int rc;
+
+        if ((handle = smb_shr_sa_enter()) == NULL) {
+                syslog(LOG_ERR, "smb_shr_unload: failed");
+                return;
+        }
+
+        smb_shr_iterinit(&iterator);
+
+        while ((si = smb_shr_iterate(&iterator)) != NULL) {
+
+                /* Skip transient shares, IPC$, ... */
+                if ((si->shr_flags & SMB_SHRF_TRANS) ||
+                    STYPE_ISIPC(si->shr_type))
+                        continue;
+
+                rc = sa_delete_sharetab(handle, si->shr_path, "smb");
+                if (rc) {
+                        syslog(LOG_ERR,
+                            "sharefs remove %s failed, rc=%d, err=%d",
+                            si->shr_path, rc, errno);
+                }
+        }
+        smb_shr_sa_exit();
+}
+
+/*
  * Load the shares contained in the specified group.
  *
  * Don't process groups on which the smb protocol is disabled.
  * The top level ZFS group won't have the smb protocol enabled
  * but sub-groups will.

@@ -1533,10 +1704,11 @@
 {
         smb_share_t si;
         char *sharename;
         uint32_t status;
         boolean_t loaded;
+        int rc;
 
         if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
                 return (NERR_InternalError);
 
         loaded = smb_shr_exists(sharename);

@@ -1556,10 +1728,16 @@
                 syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
                     si.shr_name, status);
                 return (status);
         }
 
+        rc = sa_update_sharetab(share, "smb");
+        if (rc) {
+                syslog(LOG_ERR, "sharefs add %s failed, rc=%d, err=%d",
+                    sharename, rc, errno);
+        }
+
         return (NERR_Success);
 }
 
 static char *
 smb_shr_sa_getprop(sa_optionset_t opts, char *propname)

@@ -1646,10 +1824,38 @@
         if (val != NULL) {
                 smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
                 free(val);
         }
 
+        val = smb_shr_sa_getprop(opts, SHOPT_CA);
+        if (val != NULL) {
+                smb_shr_sa_setflag(val, si, SMB_SHRF_CA);
+                free(val);
+        }
+
+        val = smb_shr_sa_getprop(opts, SHOPT_FSO);
+        if (val != NULL) {
+                smb_shr_sa_setflag(val, si, SMB_SHRF_FSO);
+                free(val);
+        }
+
+        val = smb_shr_sa_getprop(opts, SHOPT_QUOTAS);
+        if (val != NULL) {
+                /* Turn the flag on or off */
+                smb_shr_sa_setflag(val, si, SMB_SHRF_QUOTAS);
+                free(val);
+        } else {
+                /* Default for this is enabled. */
+                si->shr_flags |= SMB_SHRF_QUOTAS;
+        }
+
+        val = smb_shr_sa_getprop(opts, SHOPT_ENCRYPT);
+        if (val != NULL) {
+                smb_cfg_set_require(val, &si->shr_encrypt);
+                free(val);
+        }
+
         val = smb_shr_sa_getprop(opts, SHOPT_CSC);
         if (val != NULL) {
                 smb_shr_sa_csc_option(val, si);
                 free(val);
         }

@@ -2021,26 +2227,28 @@
         }
 }
 
 /*
  * If the share path refers to a ZFS file system, add the
- * .zfs/shares/<share> object and call smb_quota_add_fs()
- * to initialize quota support for the share.
+ * .zfs/shares/<share> object and add or remove the special
+ * directory and file telling clients about quota support.
  */
 static void
 smb_shr_zfs_add(smb_share_t *si)
 {
         libzfs_handle_t *libhd;
         zfs_handle_t *zfshd;
         int ret;
         char buf[MAXPATHLEN];   /* dataset or mountpoint */
 
-        if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
+        if ((libhd = libzfs_init()) == NULL)
                 return;
 
-        if ((libhd = libzfs_init()) == NULL)
+        if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
+                libzfs_fini(libhd);
                 return;
+        }
 
         if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
                 libzfs_fini(libhd);
                 return;
         }

@@ -2049,40 +2257,42 @@
         ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
         if (ret != 0 && errno != EAGAIN && errno != EEXIST)
                 syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
                     si->shr_name, strerror(errno));
 
-        if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
-            NULL, NULL, 0, B_FALSE) == 0) {
+        ret = zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT,
+            buf, MAXPATHLEN, NULL, NULL, 0, B_FALSE);
+        if (ret != 0) {
+                syslog(LOG_INFO, "share: failed to get mountpoint: "
+                    "%s\n", si->shr_name);
+        } else {
+                if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0) {
                 smb_quota_add_fs(buf);
+                } else {
+                        smb_quota_remove_fs(buf);
         }
+        }
 
-
         zfs_close(zfshd);
         libzfs_fini(libhd);
 }
 
 /*
  * If the share path refers to a ZFS file system, remove the
- * .zfs/shares/<share> object, and call smb_quota_remove_fs()
- * to end quota support for the share.
+ * .zfs/shares/<share> object.
  */
 static void
 smb_shr_zfs_remove(smb_share_t *si)
 {
         libzfs_handle_t *libhd;
-        zfs_handle_t *zfshd;
         int ret;
         char buf[MAXPATHLEN];   /* dataset or mountpoint */
 
-        if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
-                return;
-
         if ((libhd = libzfs_init()) == NULL)
                 return;
 
-        if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
+        if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
                 libzfs_fini(libhd);
                 return;
         }
 
         errno = 0;

@@ -2089,16 +2299,16 @@
         ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
         if (ret != 0 && errno != EAGAIN)
                 syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
                     si->shr_name, strerror(errno));
 
-        if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
-            NULL, NULL, 0, B_FALSE) == 0) {
-                smb_quota_remove_fs(buf);
-        }
+        /*
+         * We could remove the quotas directory here, but that adds
+         * significantly to the time required for a zpool export,
+         * so just leave it here and fixup when we share next.
+         */
 
-        zfs_close(zfshd);
         libzfs_fini(libhd);
 }
 
 /*
  * If the share path refers to a ZFS file system, rename the

@@ -2110,15 +2320,17 @@
         libzfs_handle_t *libhd;
         zfs_handle_t *zfshd;
         int ret;
         char dataset[MAXPATHLEN];
 
-        if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
+        if ((libhd = libzfs_init()) == NULL)
                 return;
 
-        if ((libhd = libzfs_init()) == NULL)
+        if (smb_getdataset(libhd, from->shr_path, dataset, MAXPATHLEN) != 0) {
+                libzfs_fini(libhd);
                 return;
+        }
 
         if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
                 libzfs_fini(libhd);
                 return;
         }

@@ -2413,13 +2625,26 @@
                 rc |= nvlist_add_string(smb, SHOPT_CATIA, "true");
         if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
                 rc |= nvlist_add_string(smb, SHOPT_GUEST, "true");
         if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
                 rc |= nvlist_add_string(smb, SHOPT_DFSROOT, "true");
+        if ((si->shr_flags & SMB_SHRF_CA) != 0)
+                rc |= nvlist_add_string(smb, SHOPT_CA, "true");
+        if ((si->shr_flags & SMB_SHRF_FSO) != 0)
+                rc |= nvlist_add_string(smb, SHOPT_FSO, "true");
+        if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0)
+                rc |= nvlist_add_string(smb, SHOPT_QUOTAS, "true");
 
+        if (si->shr_encrypt == SMB_CONFIG_REQUIRED)
+                rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "required");
+        else if (si->shr_encrypt == SMB_CONFIG_ENABLED)
+                rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "enabled");
+        else
+                rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "disabled");
+
         if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
-                rc |= nvlist_add_string(smb, "Autohome", "true");
+                rc |= nvlist_add_string(smb, SHOPT_AUTOHOME, "true");
                 rc |= nvlist_add_uint32(smb, "uid", si->shr_uid);
                 rc |= nvlist_add_uint32(smb, "gid", si->shr_gid);
         }
 
         if ((csc = smb_shr_sa_csc_name(si)) != NULL)