[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Fri Jun 16 05:40:02 UTC 2017


The branch, master has been updated
       via  aafc1c2 dsdb: Remember the last ACL we read during a search and what it expanded to
       via  f7bcf7b dsdb: Cache the result of checking the parent ACL
       via  dda4c89 WHATSNEW: change the default for "map untrusted to domain" to "auto"
       via  bcd558e docs-xml: change the default for "map untrusted to domain" to "auto"
       via  b6e2dda docs-xml: document "map untrusted to domain = auto"
       via  ab36c1d docs-xml: improve documentation of "map untrusted to domain"
       via  bd69a3e auth3: prepare the logic for "map untrusted to domain = auto"
       via  a4839de auth3: call is_trusted_domain() as the last condition make_user_info_map()
      from  2a92cc1 gitignore: ignore .gpg-* generated files (for ubuntu 16.04)

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit aafc1c28289933e05d7434c79c0dda2caef0fde8
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 13 15:23:14 2017 +1200

    dsdb: Remember the last ACL we read during a search and what it expanded to
    
    It may well be the same as the next one we need to check, so we can
    avoid parsing it again.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Fri Jun 16 07:39:24 CEST 2017 on sn-devel-144

commit f7bcf7b972044ae0749e567a16d222d218ffaf5f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 13 14:26:49 2017 +1200

    dsdb: Cache the result of checking the parent ACL
    
    This should help a lot for large one-level searches and for subtree searches that are of
    flat tree structures
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit dda4c891268e79b3aba317fae93ca0eacc2fcdd5
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Apr 7 11:22:25 2017 +0200

    WHATSNEW: change the default for "map untrusted to domain" to "auto"
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit bcd558eb50814dfdc68bf49f082f9f644651cb38
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Mar 22 12:11:26 2017 +0100

    docs-xml: change the default for "map untrusted to domain" to "auto"
    
    This makes the behaviour much more robust, particularly with forest child
    domains over one-way forest trusts.
    
    Sadly we don't support this kind of setup with our current ADDC, so
    there's no way to have automated tests for this behaviour, but
    at least we know it doesn't break any existing tests.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=8630
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b6e2ddaee1867b49710d22ebcb6c87b2f0a54a29
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Mar 22 12:11:26 2017 +0100

    docs-xml: document "map untrusted to domain = auto"
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=8630
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit ab36c1d152e231be644dc7413ad5b6816f45e24f
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jun 10 13:30:44 2017 +0200

    docs-xml: improve documentation of "map untrusted to domain"
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=8630
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit bd69a3e2e9a57713c6641de4f92e7e23488e457b
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Mar 22 12:08:20 2017 +0100

    auth3: prepare the logic for "map untrusted to domain = auto"
    
    This implements the same behavior as Windows,
    we should pass the domain and account names given
    by the client directly to the auth backends,
    they can decide if they are able to process the
    authentication pass it to the next backend.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=8630
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit a4839defc2000d4d18e1f5d479e4e2048c4fab0a
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Mar 16 15:09:26 2017 +0100

    auth3: call is_trusted_domain() as the last condition make_user_info_map()
    
    We should avoid contacting winbind if we already know the domain is our
    local sam or our primary domain.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=8630
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 WHATSNEW.txt                                       |   4 +-
 .../smbdotconf/security/mapuntrustedtodomain.xml   |  49 ++++--
 lib/param/loadparm.c                               |   2 +
 source3/auth/auth_util.c                           |  12 +-
 source3/param/loadparm.c                           |   2 +-
 source4/dsdb/samdb/ldb_modules/acl_read.c          | 177 +++++++++++++++++++--
 6 files changed, 218 insertions(+), 28 deletions(-)


Changeset truncated at 500 lines:

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 1a36e88..8b646f9 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -102,7 +102,9 @@ smb.conf changes
   --------------                -----------             -------
   auth event notification       New parameter           no
   auth methods                  Deprecated
-  map untrusted to domain       Deprecated
+  map untrusted to domain       New value/              auto
+                                Default changed/
+                                Deprecated
   profile acls                  Deprecated
   strict sync                   Default changed         yes
 
diff --git a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml b/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
index 496e7c2..f782a51 100644
--- a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
+++ b/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml
@@ -1,32 +1,55 @@
 <samba:parameter name="map untrusted to domain"
                  context="G"
-                 type="boolean"
+                 type="enum"
+                 enumlist="enum_bool_auto"
                  deprecated="1"
                  xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
 <description>
     <para>
-    If a client connects to smbd using an untrusted domain name, such as
-    BOGUS\user, smbd replaces the BOGUS domain with it's SAM name before
+    By default, and with <smbconfoption name="map untrusted to domain">auto</smbconfoption>
+    smbd will defer the decision whether the domain name provided by the
+    client is a valid domain name to the Domain Controller (DC) of
+    the domain it is a member of, if it is not a DC.  If the DC indicates
+    that the domain portion is unknown, then a local authentication is performed.
+    Standalone servers always ignore the domain.  This is basically the same as
+    the behavior implemented in Windows.
+    </para>
+
+    <para>
+    With <smbconfoption name="map untrusted to domain">no</smbconfoption>,
+    if a client connects to smbd using an untrusted domain name, such as
+    BOGUS\user, smbd replaces the BOGUS domain with it's SAM name
+    (forcing local authentication) before
     attempting to authenticate that user.  In the case where smbd is acting as
-    a PDC this will be DOMAIN\user.  In the case where smbd is acting as a
+    a NT4 PDC/BDC this will be DOMAIN\user.  In the case where smbd is acting as a
     domain member server or a standalone server this will be WORKSTATION\user.
+    While this appears similar to the behaviour of
+    <smbconfoption name="map untrusted to domain">auto</smbconfoption>,
+    the difference is that smbd will use a cached (maybe incomplete) list
+    of trusted domains in order to classify a domain as "untrusted"
+    before contacting any DC first.
     </para>
 
     <para>
-    In previous versions of Samba (pre 3.4), if smbd was acting as a domain
-    member server, the BOGUS domain name would instead be replaced by the
-    primary domain which smbd was a member of.  In this case authentication
-    would be deferred off to a DC using the credentials DOMAIN\user.
+    With <smbconfoption name="map untrusted to domain">yes</smbconfoption>,
+    smbd provides the legacy behavior matching that of versions of Samba pre 3.4:
+    the BOGUS domain name would always be replaced by the
+    primary domain before attempting to authenticate that user.
+    This will be DOMAIN\user in all server roles except active directory domain controller.
     </para>
 
     <para>
-    When this parameter is set to <constant>yes</constant> smbd provides the
-    legacy behavior of mapping untrusted domain names to the primary domain.
-    When smbd is not acting as a domain member server, this parameter has no
-    effect.
+    <smbconfoption name="map untrusted to domain">no</smbconfoption>,
+    was the default up to Samba 4.6.
     </para>
 
+    <para>
+    <smbconfoption name="map untrusted to domain">auto</smbconfoption> was added
+    and become the default with Samba 4.7.0. As the option is marked as
+    <constant>deprecated</constant> it will be removed in a future release, while the behavior of
+    <smbconfoption name="map untrusted to domain">auto</smbconfoption> will be kept.
+    </para>
 </description>
 
-<value type="default">no</value>
+<value type="default">auto</value>
 </samba:parameter>
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 860f3e2..9f32d7b 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2835,6 +2835,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
 	lpcfg_do_global_parameter(lp_ctx, "guest account", GUEST_ACCOUNT);
 
+	lpcfg_do_global_parameter(lp_ctx, "map untrusted to domain", "auto");
+
 	lpcfg_do_global_parameter(lp_ctx, "client schannel", "auto");
 
 	lpcfg_do_global_parameter(lp_ctx, "smb encrypt", "default");
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index ffd60e0..1021f2a 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -111,6 +111,7 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 	bool was_mapped;
 	char *internal_username = NULL;
 	bool upn_form = false;
+	int map_untrusted = lp_map_untrusted_to_domain();
 
 	if (client_domain[0] == '\0' && strchr(smb_name, '@')) {
 		upn_form = true;
@@ -134,13 +135,16 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
 	 * non-domain member box will also map to WORKSTATION\user.
 	 * This also deals with the client passing in a "" domain */
 
-	if (!upn_form && !is_trusted_domain(domain) &&
+	if (map_untrusted != Auto && !upn_form &&
 	    !strequal(domain, my_sam_name()) &&
-	    !strequal(domain, get_global_sam_name())) {
-		if (lp_map_untrusted_to_domain())
+	    !strequal(domain, get_global_sam_name()) &&
+	    !is_trusted_domain(domain))
+	{
+		if (map_untrusted) {
 			domain = my_sam_name();
-		else
+		} else {
 			domain = get_global_sam_name();
+		}
 		DEBUG(5, ("Mapped domain from [%s] to [%s] for user [%s] from "
 			  "workstation [%s]\n",
 			  client_domain, domain, smb_name, workstation_name));
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 91ecba8..297a7e9 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -859,7 +859,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
 
 	Globals.min_receivefile_size = 0;
 
-	Globals.map_untrusted_to_domain = false;
+	Globals.map_untrusted_to_domain = Auto;
 	Globals.multicast_dns_register = true;
 
 	Globals.smb2_max_read = DEFAULT_SMB2_MAX_READ;
diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c
index f15633f..3c9cf7c 100644
--- a/source4/dsdb/samdb/ldb_modules/acl_read.c
+++ b/source4/dsdb/samdb/ldb_modules/acl_read.c
@@ -50,10 +50,18 @@ struct aclread_context {
 	bool added_objectSid;
 	bool added_objectClass;
 	bool indirsync;
+
+	/* cache on the last parent we checked in this search */
+	struct ldb_dn *last_parent_dn;
+	int last_parent_check_ret;
 };
 
 struct aclread_private {
 	bool enabled;
+
+	/* cache of the last SD we read during any search */
+	struct security_descriptor *sd_cached;
+	struct ldb_val sd_cached_blob;
 };
 
 static void aclread_mark_inaccesslible(struct ldb_message_element *el) {
@@ -64,6 +72,162 @@ static bool aclread_is_inaccessible(struct ldb_message_element *el) {
 	return el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
 }
 
+/*
+ * the object has a parent, so we have to check for visibility
+ *
+ * This helper function uses a per-search cache to avoid checking the
+ * parent object for each of many possible children.  This is likely
+ * to help on SCOPE_ONE searches and on typical tree structures for
+ * SCOPE_SUBTREE, where an OU has many users as children.
+ *
+ * We rely for safety on the DB being locked for reads during the full
+ * search.
+ */
+static int aclread_check_parent(struct aclread_context *ac,
+				struct ldb_message *msg,
+				struct ldb_request *req)
+{
+	int ret;
+	struct ldb_dn *parent_dn = NULL;
+
+	/* We may have a cached result from earlier in this search */
+	if (ac->last_parent_dn != NULL) {
+		/*
+		 * We try the no-allocation ldb_dn_compare_base()
+		 * first however it will not tell parents and
+		 * grand-parents apart
+		 */
+		int cmp_base = ldb_dn_compare_base(ac->last_parent_dn,
+						   msg->dn);
+		if (cmp_base == 0) {
+			/* Now check if it is a direct parent */
+			parent_dn = ldb_dn_get_parent(ac, msg->dn);
+			if (parent_dn == NULL) {
+				return ldb_oom(ldb_module_get_ctx(ac->module));
+			}
+			if (ldb_dn_compare(ac->last_parent_dn,
+					   parent_dn) == 0) {
+				TALLOC_FREE(parent_dn);
+
+				/*
+				 * If we checked the same parent last
+				 * time, then return the cached
+				 * result.
+				 *
+				 * The cache is valid as long as the
+				 * search as the DB is read locked and
+				 * the session_info (connected user)
+				 * is constant.
+				 */
+				return ac->last_parent_check_ret;
+			}
+		}
+	}
+
+	{
+		TALLOC_CTX *frame = NULL;
+		frame = talloc_stackframe();
+
+		/*
+		 * This may have been set in the block above, don't
+		 * re-parse
+		 */
+		if (parent_dn == NULL) {
+			parent_dn = ldb_dn_get_parent(ac, msg->dn);
+			if (parent_dn == NULL) {
+				TALLOC_FREE(frame);
+				return ldb_oom(ldb_module_get_ctx(ac->module));
+			}
+		}
+		ret = dsdb_module_check_access_on_dn(ac->module,
+						     frame,
+						     parent_dn,
+						     SEC_ADS_LIST,
+						     NULL, req);
+		talloc_unlink(ac, ac->last_parent_dn);
+		ac->last_parent_dn = parent_dn;
+		ac->last_parent_check_ret = ret;
+
+		TALLOC_FREE(frame);
+	}
+	return ret;
+}
+
+/*
+ * The sd returned from this function is valid until the next call on
+ * this module context
+ *
+ * This helper function uses a cache on the module private data to
+ * speed up repeated use of the same SD.
+ */
+
+static int aclread_get_sd_from_ldb_message(struct aclread_context *ac,
+					   struct ldb_message *acl_res,
+					   struct security_descriptor **sd)
+{
+	struct ldb_message_element *sd_element;
+	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+	struct aclread_private *private_data
+		= talloc_get_type(ldb_module_get_private(ac->module),
+				  struct aclread_private);
+	enum ndr_err_code ndr_err;
+
+	sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor");
+	if (sd_element == NULL) {
+		return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS,
+				 "nTSecurityDescriptor is missing");
+	}
+
+	if (sd_element->num_values != 1) {
+		return ldb_operr(ldb);
+	}
+
+	/*
+	 * The time spent in ndr_pull_security_descriptor() is quite
+	 * expensive, so we check if this is the same binary blob as last
+	 * time, and if so return the memory tree from that previous parse.
+	 */
+
+	if (private_data->sd_cached != NULL &&
+	    private_data->sd_cached_blob.data != NULL &&
+	    ldb_val_equal_exact(&sd_element->values[0],
+				&private_data->sd_cached_blob)) {
+		*sd = private_data->sd_cached;
+		return LDB_SUCCESS;
+	}
+
+	*sd = talloc(private_data, struct security_descriptor);
+	if(!*sd) {
+		return ldb_oom(ldb);
+	}
+	ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, *sd,
+			     (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		TALLOC_FREE(*sd);
+		return ldb_operr(ldb);
+	}
+
+	talloc_unlink(private_data, private_data->sd_cached_blob.data);
+	if (ac->added_nTSecurityDescriptor) {
+		private_data->sd_cached_blob = sd_element->values[0];
+		talloc_steal(private_data, sd_element->values[0].data);
+	} else {
+		private_data->sd_cached_blob = ldb_val_dup(private_data,
+							   &sd_element->values[0]);
+		if (private_data->sd_cached_blob.data == NULL) {
+			TALLOC_FREE(*sd);
+			return ldb_operr(ldb);
+		}
+	}
+
+	talloc_unlink(private_data, private_data->sd_cached);
+	private_data->sd_cached = *sd;
+
+	return LDB_SUCCESS;
+}
+
+
 static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
 	struct ldb_context *ldb;
@@ -72,7 +236,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 	struct ldb_message *msg;
 	int ret, num_of_attrs = 0;
 	unsigned int i, k = 0;
-	struct security_descriptor *sd;
+	struct security_descriptor *sd = NULL;
 	struct dom_sid *sid = NULL;
 	TALLOC_CTX *tmp_ctx;
 	uint32_t instanceType;
@@ -91,7 +255,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 	switch (ares->type) {
 	case LDB_REPLY_ENTRY:
 		msg = ares->message;
-		ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, msg, &sd);
+		ret = aclread_get_sd_from_ldb_message(ac, msg, &sd);
 		if (ret != LDB_SUCCESS) {
 			ldb_debug_set(ldb, LDB_DEBUG_FATAL,
 				      "acl_read: cannot get descriptor of %s: %s\n",
@@ -123,13 +287,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 		if (!ldb_dn_is_null(msg->dn) && !(instanceType & INSTANCE_TYPE_IS_NC_HEAD))
 		{
 			/* the object has a parent, so we have to check for visibility */
-			struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, msg->dn);
-
-			ret = dsdb_module_check_access_on_dn(ac->module,
-							     tmp_ctx,
-							     parent_dn,
-							     SEC_ADS_LIST,
-							     NULL, req);
+			ret = aclread_check_parent(ac, msg, req);
+			
 			if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
 				talloc_free(tmp_ctx);
 				return LDB_SUCCESS;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list