1e29c41
From 81d6949acdad70ecfb130d3286eeab1b3a51937f Mon Sep 17 00:00:00 2001
1e29c41
From: Alexander Bokovoy <ab@samba.org>
1e29c41
Date: Wed, 7 Oct 2020 19:25:24 +0300
1e29c41
Subject: [PATCH 1/2] cli_credentials_parse_string: fix parsing of principals
1e29c41
1e29c41
When parsing a principal-like name, user name was left with full
1e29c41
principal instead of taking only the left part before '@' sign.
1e29c41
1e29c41
>>> from samba import credentials
1e29c41
>>> t = credentials.Credentials()
1e29c41
>>> t.parse_string('admin@realm.test', credentials.SPECIFIED)
1e29c41
>>> t.get_username()
1e29c41
'admin@realm.test'
1e29c41
1e29c41
The issue is that cli_credentials_set_username() does a talloc_strdup()
1e29c41
of the argument, so we need to change order of assignment to allow
1e29c41
talloc_strdup() to copy the right part of the string.
1e29c41
1e29c41
Signed-off-by: Alexander Bokovoy <ab@samba.org>
1e29c41
---
1e29c41
 auth/credentials/credentials.c | 5 ++---
1e29c41
 1 file changed, 2 insertions(+), 3 deletions(-)
1e29c41
1e29c41
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
1e29c41
index 77c35dd104b..06ac79058f9 100644
1e29c41
--- a/auth/credentials/credentials.c
1e29c41
+++ b/auth/credentials/credentials.c
1e29c41
@@ -840,11 +840,10 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials,
1e29c41
 		 * in order to undo the effect of
1e29c41
 		 * cli_credentials_guess().
1e29c41
 		 */
1e29c41
-		cli_credentials_set_username(credentials, uname, obtained);
1e29c41
-		cli_credentials_set_domain(credentials, "", obtained);
1e29c41
-
1e29c41
 		cli_credentials_set_principal(credentials, uname, obtained);
1e29c41
 		*p = 0;
1e29c41
+		cli_credentials_set_username(credentials, uname, obtained);
1e29c41
+		cli_credentials_set_domain(credentials, "", obtained);
1e29c41
 		cli_credentials_set_realm(credentials, p+1, obtained);
1e29c41
 		return;
1e29c41
 	} else if ((p = strchr_m(uname,'\\'))
1e29c41
-- 
1e29c41
2.28.0
1e29c41
1e29c41
1e29c41
From fa38bebb993011428612d51819530218d8358f5e Mon Sep 17 00:00:00 2001
1e29c41
From: Alexander Bokovoy <ab@samba.org>
1e29c41
Date: Mon, 13 Jan 2020 16:04:20 +0200
1e29c41
Subject: [PATCH 2/2] lookup_name: allow lookup for own realm
1e29c41
1e29c41
When using security tab in Windows Explorer, a lookup over a trusted
1e29c41
forest might come as realm\name instead of NetBIOS domain name:
1e29c41
1e29c41
--------------------------------------------------------------------
1e29c41
[2020/01/13 11:12:39.859134,  1, pid=33253, effective(1732401004, 1732401004), real(1732401004, 0), class=rpc_parse] ../../librpc/ndr/ndr.c:471(ndr_print_function_debug)
1e29c41
       lsa_LookupNames3: struct lsa_LookupNames3
1e29c41
          in: struct lsa_LookupNames3
1e29c41
              handle                   : *
1e29c41
                  handle: struct policy_handle
1e29c41
                      handle_type              : 0x00000000 (0)
1e29c41
                      uuid                     : 0000000e-0000-0000-1c5e-a750e5810000
1e29c41
              num_names                : 0x00000001 (1)
1e29c41
              names: ARRAY(1)
1e29c41
                  names: struct lsa_String
1e29c41
                      length                   : 0x001e (30)
1e29c41
                      size                     : 0x0020 (32)
1e29c41
                      string                   : *
1e29c41
                          string                   : 'ipa.test\admins'
1e29c41
              sids                     : *
1e29c41
                  sids: struct lsa_TransSidArray3
1e29c41
                      count                    : 0x00000000 (0)
1e29c41
                      sids                     : NULL
1e29c41
              level                    : LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 (6)
1e29c41
              count                    : *
1e29c41
                  count                    : 0x00000000 (0)
1e29c41
              lookup_options           : LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES (0)
1e29c41
              client_revision          : LSA_CLIENT_REVISION_2 (2)
1e29c41
--------------------------------------------------------------------
1e29c41
1e29c41
Allow this lookup using realm to be done against primary domain.
1e29c41
1e29c41
Refactor user name parsing code to reuse cli_credentials_* API to be
1e29c41
consistent with other places. cli_credentials_parse_string() handles
1e29c41
both domain and realm-based user name variants.
1e29c41
1e29c41
Signed-off-by: Alexander Bokovoy <ab@samba.org>
1e29c41
---
1e29c41
 source3/passdb/lookup_sid.c | 75 ++++++++++++++++++++++++++-----------
1e29c41
 1 file changed, 53 insertions(+), 22 deletions(-)
1e29c41
1e29c41
diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
1e29c41
index 82c47b3145b..39d599fed27 100644
1e29c41
--- a/source3/passdb/lookup_sid.c
1e29c41
+++ b/source3/passdb/lookup_sid.c
1e29c41
@@ -29,6 +29,7 @@
1e29c41
 #include "../libcli/security/security.h"
1e29c41
 #include "lib/winbind_util.h"
1e29c41
 #include "../librpc/gen_ndr/idmap.h"
1e29c41
+#include "auth/credentials/credentials.h"
1e29c41
 
1e29c41
 static bool lookup_unix_user_name(const char *name, struct dom_sid *sid)
1e29c41
 {
1e29c41
@@ -78,52 +79,82 @@ bool lookup_name(TALLOC_CTX *mem_ctx,
1e29c41
 		 const char **ret_domain, const char **ret_name,
1e29c41
 		 struct dom_sid *ret_sid, enum lsa_SidType *ret_type)
1e29c41
 {
1e29c41
-	char *p;
1e29c41
 	const char *tmp;
1e29c41
 	const char *domain = NULL;
1e29c41
 	const char *name = NULL;
1e29c41
+	const char *realm = NULL;
1e29c41
 	uint32_t rid;
1e29c41
 	struct dom_sid sid;
1e29c41
 	enum lsa_SidType type;
1e29c41
 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1e29c41
+	struct cli_credentials *creds = NULL;
1e29c41
 
1e29c41
 	if (tmp_ctx == NULL) {
1e29c41
 		DEBUG(0, ("talloc_new failed\n"));
1e29c41
 		return false;
1e29c41
 	}
1e29c41
 
1e29c41
-	p = strchr_m(full_name, '\\');
1e29c41
-
1e29c41
-	if (p != NULL) {
1e29c41
-		domain = talloc_strndup(tmp_ctx, full_name,
1e29c41
-					PTR_DIFF(p, full_name));
1e29c41
-		name = talloc_strdup(tmp_ctx, p+1);
1e29c41
-	} else {
1e29c41
-		domain = talloc_strdup(tmp_ctx, "");
1e29c41
-		name = talloc_strdup(tmp_ctx, full_name);
1e29c41
+	creds = cli_credentials_init(tmp_ctx);
1e29c41
+	if (creds == NULL) {
1e29c41
+		DEBUG(0, ("cli_credentials_init failed\n"));
1e29c41
+		return false;
1e29c41
 	}
1e29c41
 
1e29c41
-	if ((domain == NULL) || (name == NULL)) {
1e29c41
-		DEBUG(0, ("talloc failed\n"));
1e29c41
-		TALLOC_FREE(tmp_ctx);
1e29c41
+	cli_credentials_parse_string(creds, full_name, CRED_SPECIFIED);
1e29c41
+	name = cli_credentials_get_username(creds);
1e29c41
+	domain = cli_credentials_get_domain(creds);
1e29c41
+	realm = cli_credentials_get_realm(creds);
1e29c41
+
1e29c41
+	/* At this point we have:
1e29c41
+	 * - name -- normal name or empty string
1e29c41
+	 * - domain -- either NULL or domain name
1e29c41
+	 * - realm -- either NULL or realm name
1e29c41
+	 *
1e29c41
+	 * domain and realm are exclusive to each other
1e29c41
+	 * the code below in lookup_name assumes domain
1e29c41
+	 * to be at least empty string, not NULL
1e29c41
+	*/
1e29c41
+
1e29c41
+	if ((name == NULL) || (name[0] == '\0')) {
1e29c41
+		DEBUG(0, ("lookup_name with empty name, exit\n"));
1e29c41
 		return false;
1e29c41
 	}
1e29c41
 
1e29c41
+	if ((domain == NULL) && (realm == NULL)) {
1e29c41
+		domain = talloc_strdup(creds, "");
1e29c41
+	}
1e29c41
+
1e29c41
 	DEBUG(10,("lookup_name: %s => domain=[%s], name=[%s]\n",
1e29c41
 		full_name, domain, name));
1e29c41
 	DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
1e29c41
 
1e29c41
-	if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) &&
1e29c41
-	    strequal(domain, get_global_sam_name()))
1e29c41
-	{
1e29c41
+	/* Windows clients may send a LookupNames request with both NetBIOS
1e29c41
+	 * domain name- and realm-qualified user names. Thus, we need to check
1e29c41
+	 * both against both of the SAM domain name and realm, if set. Since
1e29c41
+	 * domain name and realm in the request are exclusive, test the one
1e29c41
+	 * that is specified.  cli_credentials_parse_string() will either set
1e29c41
+	 * realm or wouldn't so we can use it to detect if realm was specified.
1e29c41
+	 */
1e29c41
+	if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) {
1e29c41
+		const char *domain_name = realm ? realm : domain;
1e29c41
+		bool check_global_sam = false;
1e29c41
+
1e29c41
+		if (domain_name[0] != '\0') {
1e29c41
+			check_global_sam = strequal(domain_name, get_global_sam_name());
1e29c41
+			if (!check_global_sam && lp_realm() != NULL) {
1e29c41
+				check_global_sam = strequal(domain_name, lp_realm());
1e29c41
+			}
1e29c41
+		}
1e29c41
 
1e29c41
-		/* It's our own domain, lookup the name in passdb */
1e29c41
-		if (lookup_global_sam_name(name, flags, &rid, &type)) {
1e29c41
-			sid_compose(&sid, get_global_sam_sid(), rid);
1e29c41
-			goto ok;
1e29c41
+		if (check_global_sam) {
1e29c41
+			/* It's our own domain, lookup the name in passdb */
1e29c41
+			if (lookup_global_sam_name(name, flags, &rid, &type)) {
1e29c41
+				sid_compose(&sid, get_global_sam_sid(), rid);
1e29c41
+				goto ok;
1e29c41
+			}
1e29c41
+			TALLOC_FREE(tmp_ctx);
1e29c41
+			return false;
1e29c41
 		}
1e29c41
-		TALLOC_FREE(tmp_ctx);
1e29c41
-		return false;
1e29c41
 	}
1e29c41
 
1e29c41
 	if ((flags & LOOKUP_NAME_BUILTIN) &&
1e29c41
-- 
1e29c41
2.28.0
1e29c41