--- old/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Mon Aug  5 17:17:15 2019
+++ new/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Mon Aug  5 17:17:15 2019
@@ -20,7 +20,7 @@
  */
 /*
  * 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.
  */
 
 /*
@@ -66,6 +66,7 @@
 #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"
@@ -145,10 +146,33 @@
 	{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);
@@ -156,7 +180,23 @@
 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)
 {
@@ -377,6 +417,8 @@
 	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));
 
@@ -583,6 +625,8 @@
 	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));
 
@@ -624,8 +668,50 @@
 		value = tmp;
 	}
 
-	rc = smb_smf_set_string_property(handle, cfg->sc_name, value);
+	/*
+	 * 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);
@@ -877,6 +963,30 @@
 	    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
  *
@@ -1087,61 +1197,68 @@
 	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;
+	if (smb_convert_version_str(value) != 0)
+		return (0);
 
-	for (i = 0; smb_versions[i].str != NULL; i++) {
-		if (strcmp(value, smb_versions[i].str) == 0)
-			return (0);
-	}
-
 	return (-1);
 }
 
@@ -1247,4 +1364,22 @@
 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);
 }
