Print this page
NEX-19857 ads_site broken in sharectl get/set smb
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-17523 Enable SMB3 server by default
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-17289 Minimal SMB 3.0.2 support
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9497 SMB should bypass ACL traverse checking
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-10019 SMB server min_protocol setting
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
NEX-2314 SMB server debug logging needs improvement
NEX-1852 re-enable Kerberos-style AD join (try 2)
NEX-1638 Updated DC Locator
 Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com
NEX-1050 enable_smb2 should be smb2_enable
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-56 extended security NTLMSSP, inbound
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SFR-56 Identity Management for UNIX (IDMU) authentication support
re #6813 rb1757 port 2976 Child folder visibility through shares

@@ -18,11 +18,11 @@
  *
  * 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.
  */
 
 /*
  * CIFS configuration management library
  */

@@ -64,10 +64,11 @@
 #define IDMAP_FMRI_PREFIX               "system/idmap"
 #define MACHINE_SID                     "machine_sid"
 #define MACHINE_UUID                    "machine_uuid"
 #define IDMAP_DOMAIN                    "domain_name"
 #define IDMAP_PREF_DC                   "preferred_dc"
+#define IDMAP_SITE_NAME                 "site_name"
 #define IDMAP_PG_NAME                   "config"
 
 #define SMB_SECMODE_WORKGRP_STR         "workgroup"
 #define SMB_SECMODE_DOMAIN_STR          "domain"
 

@@ -143,22 +144,61 @@
         {SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0},
         {SMB_CI_SMB2_ENABLE_OLD, "smb2_enable", SCF_TYPE_BOOLEAN, 0},
         {SMB_CI_INITIAL_CREDITS, "initial_credits", SCF_TYPE_INTEGER, 0},
         {SMB_CI_MAXIMUM_CREDITS, "maximum_credits", SCF_TYPE_INTEGER, 0},
         {SMB_CI_MAX_PROTOCOL, "max_protocol", SCF_TYPE_ASTRING, 0},
+        {SMB_CI_ENCRYPT, "encrypt", SCF_TYPE_ASTRING, 0},
+        {SMB_CI_MIN_PROTOCOL, "min_protocol", SCF_TYPE_ASTRING, 0},
+        {SMB_CI_BYPASS_TRAVERSE_CHECKING,
+            "bypass_traverse_checking", SCF_TYPE_BOOLEAN, 0},
 
         /* SMB_CI_MAX */
 };
 
+/*
+ * We store the max SMB protocol version in SMF as a string,
+ * (for convenience of svccfg etc) but the programmatic get/set
+ * interfaces use the numeric form.
+ *
+ * The numeric values are as defined in the [MS-SMB2] spec.
+ * except for how we represent "1" (for SMB1) which is an
+ * arbitrary value below SMB2_VERS_BASE.
+ */
+static struct str_val
+smb_versions[] = {
+        { "3.02",       SMB_VERS_3_02 },
+        { "3.0",        SMB_VERS_3_0 },
+        { "2.1",        SMB_VERS_2_1 },
+        { "2.002",      SMB_VERS_2_002 },
+        { "1",          SMB_VERS_1 },
+        { NULL,         0 }
+};
+
 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
 
 static boolean_t smb_is_base64(unsigned char c);
 static char *smb_base64_encode(char *str_to_encode);
 static char *smb_base64_decode(char *encoded_str);
 static int smb_config_get_idmap_preferred_dc(char *, int);
 static int smb_config_set_idmap_preferred_dc(char *);
+static int smb_config_get_idmap_site_name(char *, int);
+static int smb_config_set_idmap_site_name(char *);
 
+static uint32_t
+smb_convert_version_str(const char *version)
+{
+        uint32_t dialect = 0;
+        int i;
+
+        for (i = 0; smb_versions[i].str != NULL; i++) {
+                if (strcmp(version, smb_versions[i].str) == 0)
+                        dialect = smb_versions[i].val;
+        }
+
+        return (dialect);
+}
+
 char *
 smb_config_getname(smb_cfg_id_t id)
 {
         smb_cfg_param_t *cfg;
         cfg = smb_config_getent(id);

@@ -375,10 +415,12 @@
 
         *cbuf = '\0';
         cfg = smb_config_getent(id);
         assert(cfg->sc_type == SCF_TYPE_ASTRING);
 
+        if (id == SMB_CI_ADS_SITE)
+                return (smb_config_get_idmap_site_name(cbuf, bufsz));
         if (id == SMB_CI_DOMAIN_SRV)
                 return (smb_config_get_idmap_preferred_dc(cbuf, bufsz));
 
         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
         if (handle == NULL)

@@ -581,10 +623,12 @@
         char *pg;
 
         cfg = smb_config_getent(id);
         assert(cfg->sc_type == SCF_TYPE_ASTRING);
 
+        if (id == SMB_CI_ADS_SITE)
+                return (smb_config_set_idmap_site_name(value));
         if (id == SMB_CI_DOMAIN_SRV)
                 return (smb_config_set_idmap_preferred_dc(value));
 
         protected = B_FALSE;
 

@@ -622,11 +666,53 @@
                 }
 
                 value = tmp;
         }
 
+        /*
+         * We don't want people who care enough about protecting their data
+         * by requiring encryption to accidentally expose their data
+         * by lowering the protocol, so prevent them from going below 3.0
+         * if encryption is required.
+         * Also, ensure that max_protocol >= min_protocol.
+         */
+        if (id == SMB_CI_MAX_PROTOCOL) {
+                smb_cfg_val_t encrypt;
+                uint32_t min;
+                uint32_t val;
+
+                encrypt = smb_config_get_require(SMB_CI_ENCRYPT);
+                min = smb_config_get_min_protocol();
+                val = smb_convert_version_str(value);
+
+                if (encrypt == SMB_CONFIG_REQUIRED &&
+                    val < SMB_VERS_3_0) {
+                        syslog(LOG_ERR, "Cannot set smbd/max_protocol below 3.0"
+                            " while smbd/encrypt == required.");
+                        rc = SMBD_SMF_INVALID_ARG;
+                } else if (val < min) {
+                        syslog(LOG_ERR, "Cannot set smbd/max_protocol to less"
+                            " than smbd/min_protocol.");
+                        rc = SMBD_SMF_INVALID_ARG;
+                }
+        } else if (id == SMB_CI_MIN_PROTOCOL) {
+                uint32_t max;
+                uint32_t val;
+
+                max = smb_config_get_max_protocol();
+                val = smb_convert_version_str(value);
+
+                if (val > max) {
+                        syslog(LOG_ERR, "Cannot set smbd/min_protocol to more"
+                            " than smbd/max_protocol.");
+                        rc = SMBD_SMF_INVALID_ARG;
+                }
+        }
+
+        if (rc == SMBD_SMF_OK) {
         rc = smb_smf_set_string_property(handle, cfg->sc_name, value);
+        }
 
         free(tmp);
         (void) smb_smf_end_transaction(handle);
         smb_smf_scf_fini(handle);
         return (rc);

@@ -875,10 +961,34 @@
 {
         return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
             IDMAP_PREF_DC, value));
 }
 
+static int
+smb_config_get_idmap_site_name(char *cbuf, int bufsz)
+{
+        char *s;
+        int len, rc = -1;
+
+        s = smb_config_getenv_generic(IDMAP_SITE_NAME,
+            IDMAP_FMRI_PREFIX, IDMAP_PG_NAME);
+        if (s != NULL) {
+                len = strlcpy(cbuf, s, bufsz);
+                if (len < bufsz)
+                        rc = 0;
+                free(s);
+        }
+        return (rc);
+}
+
+static int
+smb_config_set_idmap_site_name(char *value)
+{
+        return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
+            IDMAP_SITE_NAME, value));
+}
+
 /*
  * smb_config_set_idmap_domain
  *
  * Set the "config/domain_name" parameter from IDMAP SMF repository.
  */

@@ -1085,64 +1195,71 @@
 
         assert(0);
         return (NULL);
 }
 
+static uint32_t
+smb_config_get_protocol(smb_cfg_id_t id, char *name, uint32_t default_val)
+{
+        char str[SMB_VERSTR_LEN];
+        int rc;
+        uint32_t val;
 
+        rc = smb_config_getstr(id, str, sizeof (str));
+        if (rc == SMBD_SMF_OK) {
+                val = smb_convert_version_str(str);
+                if (val != 0)
+                        return (val);
+                if (str[0] != '\0') {
+                        syslog(LOG_ERR, "smbd/%s value invalid: %s", name, str);
+                }
+        }
+
+        return (default_val);
+}
+
 /*
- * We store the max SMB protocol version in SMF as a string,
- * (for convenience of svccfg etc) but the programmatic get/set
- * interfaces use the numeric form.
- *
- * The numeric values are as defined in the [MS-SMB2] spec.
- * except for how we represent "1" (for SMB1) which is an
- * arbitrary value below SMB2_VERS_BASE.
+ * The service manifest has empty values by default for min_protocol and
+ * max_protocol. The expectation is that when those values are empty, we don't
+ * constrain the range of supported protocol versions (and allow use of the
+ * whole range that we implement). For that reason, this should usually be the
+ * highest protocol version we implement.
  */
-static struct str_val
-smb_versions[] = {
-        { "3.0",        SMB_VERS_3_0 },
-        { "2.1",        SMB_VERS_2_1 },
-        { "2.002",      SMB_VERS_2_002 },
-        { "1",          SMB_VERS_1 },
-        { NULL,         0 }
-};
+uint32_t max_protocol_default = SMB_VERS_3_02;
 
+uint32_t
+smb_config_get_max_protocol(void)
+{
+        uint32_t max;
+
+        max = smb_config_get_protocol(SMB_CI_MAX_PROTOCOL, "max_protocol",
+            max_protocol_default);
+
+        return (max);
+}
+
 /*
- * This really should be the latest (SMB_VERS_3_0)
- * but we're being cautious with SMB3 for a while.
+ * This should eventually be SMB_VERS_2_BASE
  */
-uint32_t max_protocol_default = SMB_VERS_2_1;
+uint32_t min_protocol_default = SMB_VERS_1;
 
 uint32_t
-smb_config_get_max_protocol(void)
+smb_config_get_min_protocol(void)
 {
-        char str[SMB_VERSTR_LEN];
-        int i, rc;
+        uint32_t min;
 
-        rc = smb_config_getstr(SMB_CI_MAX_PROTOCOL, str, sizeof (str));
-        if (rc == SMBD_SMF_OK) {
-                for (i = 0; smb_versions[i].str != NULL; i++) {
-                        if (strcmp(str, smb_versions[i].str) == 0)
-                                return (smb_versions[i].val);
-                }
-                if (str[0] != '\0') {
-                        syslog(LOG_ERR, "smbd/max_protocol value invalid");
-                }
-        }
+        min = smb_config_get_protocol(SMB_CI_MIN_PROTOCOL, "min_protocol",
+            min_protocol_default);
 
-        return (max_protocol_default);
+        return (min);
 }
 
 int
 smb_config_check_protocol(char *value)
 {
-        int i;
-
-        for (i = 0; smb_versions[i].str != NULL; i++) {
-                if (strcmp(value, smb_versions[i].str) == 0)
+        if (smb_convert_version_str(value) != 0)
                         return (0);
-        }
 
         return (-1);
 }
 
 /*

@@ -1245,6 +1362,24 @@
  */
 void
 smb_config_upgrade(void)
 {
         upgrade_smb2_enable();
+}
+
+smb_cfg_val_t
+smb_config_get_require(smb_cfg_id_t id)
+{
+        int rc;
+        char str[sizeof ("required")];
+
+        rc = smb_config_getstr(id, str, sizeof (str));
+        if (rc != SMBD_SMF_OK)
+                return (SMB_CONFIG_DISABLED);
+
+        if (strncmp(str, "required", sizeof (str)) == 0)
+                return (SMB_CONFIG_REQUIRED);
+        if (strncmp(str, "enabled", sizeof (str)) == 0)
+                return (SMB_CONFIG_ENABLED);
+
+        return (SMB_CONFIG_DISABLED);
 }