From: Alexander Bokovoy Date: Wed, 4 Nov 2020 12:21:33 +0000 (+0200) Subject: lookup_name: allow lookup for own realm X-Git-Tag: talloc-2.3.2~70 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f901691209867b32c2d7c5c9274eee196f541654;p=thirdparty%2Fsamba.git lookup_name: allow lookup for own realm When using a security tab in Windows Explorer, a lookup over a trusted forest might come as realm\name instead of NetBIOS domain name: -------------------------------------------------------------------- [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) lsa_LookupNames3: struct lsa_LookupNames3 in: struct lsa_LookupNames3 handle : * handle: struct policy_handle handle_type : 0x00000000 (0) uuid : 0000000e-0000-0000-1c5e-a750e5810000 num_names : 0x00000001 (1) names: ARRAY(1) names: struct lsa_String length : 0x001e (30) size : 0x0020 (32) string : * string : 'ipa.test\admins' sids : * sids: struct lsa_TransSidArray3 count : 0x00000000 (0) sids : NULL level : LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 (6) count : * count : 0x00000000 (0) lookup_options : LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES (0) client_revision : LSA_CLIENT_REVISION_2 (2) -------------------------------------------------------------------- Allow this lookup using realm to be done against primary domain when we are a domain controller. This corresponds to FreeIPA use of Samba as a DC. For normal domain members a realm-based lookup falls back to a lookup over to its own domain controller with the help of winbindd. Refactor user name parsing code to reuse cli_credentials_* API to be consistent with other places. cli_credentials_parse_name() handles both domain and realm-based user name variants. Signed-off-by: Alexander Bokovoy Reviewed-by: Andreas Schneider Reviewed-by: Stefan Metzmacher Autobuild-User(master): Alexander Bokovoy Autobuild-Date(master): Wed Nov 4 16:23:40 UTC 2020 on sn-devel-184 --- diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index ff8a16619a8..dc32cd9753b 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -29,6 +29,7 @@ #include "../libcli/security/security.h" #include "lib/winbind_util.h" #include "../librpc/gen_ndr/idmap.h" +#include "auth/credentials/credentials.h" static bool lookup_unix_user_name(const char *name, struct dom_sid *sid) { @@ -78,52 +79,85 @@ bool lookup_name(TALLOC_CTX *mem_ctx, const char **ret_domain, const char **ret_name, struct dom_sid *ret_sid, enum lsa_SidType *ret_type) { - char *p; const char *tmp; const char *domain = NULL; const char *name = NULL; + const char *realm = NULL; uint32_t rid; struct dom_sid sid; enum lsa_SidType type; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct cli_credentials *creds = NULL; if (tmp_ctx == NULL) { DEBUG(0, ("talloc_new failed\n")); return false; } - p = strchr_m(full_name, '\\'); - - if (p != NULL) { - domain = talloc_strndup(tmp_ctx, full_name, - PTR_DIFF(p, full_name)); - name = talloc_strdup(tmp_ctx, p+1); - } else { - domain = talloc_strdup(tmp_ctx, ""); - name = talloc_strdup(tmp_ctx, full_name); + creds = cli_credentials_init(tmp_ctx); + if (creds == NULL) { + DEBUG(0, ("cli_credentials_init failed\n")); + return false; } - if ((domain == NULL) || (name == NULL)) { - DEBUG(0, ("talloc failed\n")); + cli_credentials_parse_name(creds, full_name, CRED_SPECIFIED); + name = cli_credentials_get_username(creds); + domain = cli_credentials_get_domain(creds); + realm = cli_credentials_get_realm(creds); + + /* At this point we have: + * - name -- normal name or empty string + * - domain -- either NULL or domain name + * - realm -- either NULL or realm name + * + * domain and realm are exclusive to each other + * the code below in lookup_name assumes domain + * to be at least empty string, not NULL + */ + + if (name == NULL) { + DEBUG(0, ("lookup_name with empty name, exit\n")); TALLOC_FREE(tmp_ctx); return false; } + if ((domain == NULL) && (realm == NULL)) { + domain = talloc_strdup(creds, ""); + } + DEBUG(10,("lookup_name: %s => domain=[%s], name=[%s]\n", full_name, domain, name)); DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); - if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) && - strequal(domain, get_global_sam_name())) - { + /* Windows clients may send a LookupNames request with both NetBIOS + * domain name- and realm-qualified user names. Thus, we need to check + * both against both of the SAM domain name and realm, if set. Since + * domain name and realm in the request are exclusive, test the one + * that is specified. cli_credentials_parse_string() will either set + * realm or wouldn't so we can use it to detect if realm was specified. + */ + if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) { + const char *domain_name = realm ? realm : domain; + bool check_global_sam = false; + + if (domain_name[0] != '\0') { + check_global_sam = strequal(domain_name, get_global_sam_name()); + if (!check_global_sam && lp_realm() != NULL) { + /* Only consider realm when we are DC + * otherwise use lookup through winbind */ + check_global_sam = strequal(domain_name, lp_realm()) && IS_DC; + } + } - /* It's our own domain, lookup the name in passdb */ - if (lookup_global_sam_name(name, flags, &rid, &type)) { - sid_compose(&sid, get_global_sam_sid(), rid); - goto ok; + if (check_global_sam) { + /* It's our own domain, lookup the name in passdb */ + if (lookup_global_sam_name(name, flags, &rid, &type)) { + sid_compose(&sid, get_global_sam_sid(), rid); + goto ok; + } + TALLOC_FREE(tmp_ctx); + return false; } - TALLOC_FREE(tmp_ctx); - return false; } if ((flags & LOOKUP_NAME_BUILTIN) &&