From 1a4c2ca60bfb6289d658df5806b4fb6a91d0bb24 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 6 Mar 2017 14:32:18 +0100 Subject: [PATCH 01/22] wbinfo: Add "authoritative" to wbinfo -a output Signed-off-by: Volker Lendecke --- nsswitch/wbinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c index 80b245a7f5c..57f2b3be336 100644 --- a/nsswitch/wbinfo.c +++ b/nsswitch/wbinfo.c @@ -1823,13 +1823,15 @@ static bool wbinfo_auth_crap(char *username, bool use_ntlmv2, bool use_lanman) if (wbc_status == WBC_ERR_AUTH_ERROR) { d_fprintf(stderr, - "wbcAuthenticateUserEx(%s%c%s): error code was %s (0x%x)\n" + "wbcAuthenticateUserEx(%s%c%s): error code was " + "%s (0x%x, authoritative=%"PRIu8")\n" "error message was: %s\n", name_domain, winbind_separator(), name_user, err->nt_string, err->nt_status, + err->authoritative, err->display_string); wbcFreeMemory(err); } else if (WBC_ERROR_IS_OK(wbc_status)) { -- 2.11.0 From b640ec65c6d9a50f8b935aab848e050310b96c97 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 11 Feb 2017 15:05:52 +0100 Subject: [PATCH 02/22] auth3: Don't try other auth modules on any error So far if any kind of error has happened, we just tried further auth modules. An auth module should have the chance to definitely say "no, this is a valid error, no further attempts anywhere else". The protocol so far was for an auth module to return NT_STATUS_NOT_IMPLEMENTED if it wanted to pass on to other modules, but any error led to the next auth modules also being given a try. This patch makes any auth module return code except NOT_IMPLEMENTED to terminate the loop, such that every module has to explicitly request to pass on to the next module via NOT_IMPLEMENTED. All modules we reference in make_auth_context_subsystem() have code to explicitly say "not for me please" with NOT_IMPLEMENTED. This *might* break existing setups which fail in for example "guest" or "winbind" due to other reasons. I prefer it this way though, because adding another parameter like "This is a real authoritative failure, don't go looking somewhere else" will only add to the mess. Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 1cbe46e6756..61e8ce65086 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -250,9 +250,7 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, auth_method->name, user_info->client.account_name, nt_errstr(nt_status))); } - if (NT_STATUS_IS_OK(nt_status)) { - break; - } + break; } /* successful authentication */ -- 2.11.0 From 845fcb2900977fc4eeea34af7dd228bd413dea7f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 11 Feb 2017 15:44:01 +0100 Subject: [PATCH 03/22] auth3: Simplify the logic in auth_check_ntlm_password Move everything but the strict loop logic outside. This makes the loop exit condition clearer to me: Anything but NOT_IMPLEMENTED breaks the loop. Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 58 ++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 61e8ce65086..104b0aa47a6 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -170,6 +170,7 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER; const char *unix_username; auth_methods *auth_method; + const char *auth_method_name = ""; struct auth_serversupplied_info *server_info; if (user_info == NULL || auth_context == NULL || pserver_info == NULL) { @@ -214,51 +215,50 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, } for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) { - NTSTATUS result; + + auth_method_name = auth_method->name; if (user_info->flags & USER_INFO_LOCAL_SAM_ONLY && !(auth_method->flags & AUTH_METHOD_LOCAL_SAM)) { continue; } - result = auth_method->auth(auth_context, - auth_method->private_data, - talloc_tos(), - user_info, - &server_info); - - /* check if the module did anything */ - if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name)); - if (user_info->flags & USER_INFO_LOCAL_SAM_ONLY) { - /* we don't expose the NT_STATUS_NOT_IMPLEMENTED - * internals, except when the caller is only probing - * one method, as they may do the fallback - */ - nt_status = result; - } - continue; - } - - nt_status = result; + nt_status = auth_method->auth(auth_context, + auth_method->private_data, + talloc_tos(), + user_info, + &server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", - auth_method->name, user_info->client.account_name)); - } else { - DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", - auth_method->name, user_info->client.account_name, nt_errstr(nt_status))); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { + break; } - break; + DBG_DEBUG("%s had nothing to say\n", auth_method->name); } - /* successful authentication */ + /* check if the module did anything */ + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED) && + ((user_info->flags & USER_INFO_LOCAL_SAM_ONLY) == 0)) { + /* + * we don't expose the NT_STATUS_NOT_IMPLEMENTED + * internals, except when the caller is only probing + * one method, as they may do the fallback + */ + nt_status = NT_STATUS_NO_SUCH_USER; + } if (!NT_STATUS_IS_OK(nt_status)) { + DBG_INFO("%s authentication for user [%s] FAILED with " + "error %s\n", + auth_method_name, + user_info->client.account_name, + nt_errstr(nt_status)); goto fail; } + DBG_NOTICE("%s authentication for user [%s] succeeded\n", + auth_method_name, user_info->client.account_name); + unix_username = server_info->unix_name; /* We skip doing this step if the caller asked us not to */ -- 2.11.0 From f9a5918cbab0b9cc5d40365e15b9e7b74c0137bc Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 19 Feb 2017 15:37:51 +0100 Subject: [PATCH 04/22] auth3: Implement local sam fallback for !authoritative error This is in the spirit of the "map untrusted to domain" parameter: We fall back to the local SAM when we get a non-authoritative NO_SUCH_USER from our domain controller. Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 104b0aa47a6..e73381793bd 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -481,7 +481,8 @@ NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, case ROLE_DOMAIN_MEMBER: DEBUG(5,("Making default auth method list for server role = 'domain member'\n")); auth_method_list = str_list_make_v3( - talloc_tos(), "guest sam winbind:ntdomain", + talloc_tos(), + "guest winbind:ntdomain sam_ignoredomain", NULL); break; case ROLE_DOMAIN_BDC: @@ -489,7 +490,7 @@ NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, DEBUG(5,("Making default auth method list for DC\n")); auth_method_list = str_list_make_v3( talloc_tos(), - "guest sam winbind:trustdomain", + "guest winbind:trustdomain sam_ignoredomain", NULL); break; case ROLE_STANDALONE: -- 2.11.0 From bc1aa53e0b5cfff72977f7d70908bd08cd103ce7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 19 Feb 2017 15:40:00 +0100 Subject: [PATCH 05/22] auth3: Remove the "map untrusted to domain" parameter This was a flawed parameter: We can't know whether a domain is trusted or not. The only way we reliably know about this is to ask the DC and get a non-authoritative NO_SUCH_USER. Signed-off-by: Volker Lendecke --- .../smbdotconf/security/mapuntrustedtodomain.xml | 31 ---------------------- source3/auth/auth.c | 3 ++- source3/auth/auth_util.c | 25 ----------------- source3/param/loadparm.c | 1 - 4 files changed, 2 insertions(+), 58 deletions(-) delete mode 100644 docs-xml/smbdotconf/security/mapuntrustedtodomain.xml diff --git a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml b/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml deleted file mode 100644 index 126411a9c52..00000000000 --- a/docs-xml/smbdotconf/security/mapuntrustedtodomain.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - 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 - 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 - domain member server or a standalone server this will be WORKSTATION\user. - - - - 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. - - - - When this parameter is set to yes 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. - - - - -no - diff --git a/source3/auth/auth.c b/source3/auth/auth.c index e73381793bd..6dbcebb80ae 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -497,7 +497,8 @@ NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = yes\n")); if (lp_encrypt_passwords()) { auth_method_list = str_list_make_v3( - talloc_tos(), "guest sam", + talloc_tos(), + "guest sam_ignoredomain", NULL); } else { DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = no\n")); diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 5d9f0e0270f..f380d6d0649 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -108,11 +108,6 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx, NTSTATUS result; bool was_mapped; char *internal_username = NULL; - bool upn_form = false; - - if (client_domain[0] == '\0' && strchr(smb_name, '@')) { - upn_form = true; - } was_mapped = map_username(talloc_tos(), smb_name, &internal_username); if (!internal_username) { @@ -124,26 +119,6 @@ NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx, domain = client_domain; - /* If you connect to a Windows domain member using a bogus domain name, - * the Windows box will map the BOGUS\user to SAMNAME\user. Thus, if - * the Windows box is a DC the name will become DOMAIN\user and be - * authenticated against AD, if the Windows box is a member server but - * not a DC the name will become WORKSTATION\user. A standalone - * 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) && - !strequal(domain, my_sam_name()) && - !strequal(domain, get_global_sam_name())) { - if (lp_map_untrusted_to_domain()) - domain = my_sam_name(); - 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)); - } - /* We know that the given domain is trusted (and we are allowing them), * it is our global SAM name, or for legacy behavior it is our * primary domain name */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index c65e613feea..15071e22cab 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -856,7 +856,6 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.min_receivefile_size = 0; - Globals.map_untrusted_to_domain = false; Globals.multicast_dns_register = true; Globals.smb2_max_read = DEFAULT_SMB2_MAX_READ; -- 2.11.0 From e60a177a2cbc2c9e905040bc73c0987cb8724a85 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 16:41:53 +0100 Subject: [PATCH 06/22] auth3: Only ask the local domain on a PDC We do the fallback via sam_ignoredomain later. This is needed so that in a later commit netlogond3 can return !authoritative correctly. Signed-off-by: Volker Lendecke --- source3/auth/auth_sam.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c index c4100d5a4e1..e03bdb06632 100644 --- a/source3/auth/auth_sam.c +++ b/source3/auth/auth_sam.c @@ -90,7 +90,7 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, } case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: - if ( !is_local_name && !is_my_domain ) { + if ( !is_my_domain ) { DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", user_info->mapped.domain_name)); return NT_STATUS_NOT_IMPLEMENTED; -- 2.11.0 From 71f04681f878ee20e08e1cf3dc52a724571ea51d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 17:08:18 +0100 Subject: [PATCH 07/22] auth3: Add "methods" to make_auth_context_fixed Both relevant callers have different unique needs: winbind only needs to look at the sam. netlogond3 must not do the sam_ignoredomain fallback, but for trusted domains must do the winbind fallback. Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 19 +++++++++++++++++-- source3/auth/proto.h | 2 +- source3/rpc_server/netlogon/srv_netlog_nt.c | 3 ++- source3/torture/pdbtest.c | 3 ++- source3/winbindd/winbindd_pam.c | 3 ++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 6dbcebb80ae..8717a44afd1 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -532,12 +532,27 @@ NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, Make a auth_info struct with a fixed challenge ***************************************************************************/ -NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, +NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, const char *methods, struct auth_context **auth_context, uchar chal[8]) { NTSTATUS nt_status; - nt_status = make_auth_context_subsystem(mem_ctx, auth_context); + + if (methods != NULL) { + char **method_list; + + method_list = str_list_make_v3(talloc_tos(), methods, NULL); + if (method_list == NULL) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = make_auth_context_text_list(mem_ctx, auth_context, + method_list); + TALLOC_FREE(method_list); + } else { + nt_status = make_auth_context_subsystem(mem_ctx, auth_context); + } + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } diff --git a/source3/auth/proto.h b/source3/auth/proto.h index 5fd315846d8..d55b134d5b4 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -40,7 +40,7 @@ bool load_auth_module(struct auth_context *auth_context, const char *module, auth_methods **ret) ; NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, struct auth_context **auth_context); -NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, +NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, const char *methods, struct auth_context **auth_context, uchar chal[8]) ; diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index ef2c8278afb..5bccde3b79b 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1587,7 +1587,8 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, const char *wksname = nt_workstation; const char *workgroup = lp_workgroup(); - status = make_auth_context_fixed(talloc_tos(), &auth_context, + status = make_auth_context_fixed(talloc_tos(), "sam winbind", + &auth_context, logon->network->challenge); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source3/torture/pdbtest.c b/source3/torture/pdbtest.c index fe51a764798..d833a84e107 100644 --- a/source3/torture/pdbtest.c +++ b/source3/torture/pdbtest.c @@ -298,7 +298,8 @@ static bool test_auth(TALLOC_CTX *mem_ctx, struct samu *pdb_entry) return False; } - status = make_auth_context_fixed(NULL, &auth_context, challenge.data); + status = make_auth_context_fixed(NULL, NULL, &auth_context, + challenge.data); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to test authentication with check_sam_security_info3: %s\n", nt_errstr(status))); diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 782b28a0173..8380d36aff4 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1268,7 +1268,8 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx, user_info->flags |= USER_INFO_INTERACTIVE_LOGON; } - status = make_auth_context_fixed(frame, &auth_context, challenge->data); + status = make_auth_context_fixed(frame, "sam", &auth_context, + challenge->data); if (!NT_STATUS_IS_OK(status)) { DBG_ERR("make_auth_context_fixed failed: %s\n", -- 2.11.0 From 886d39d1bf79507083333027819103c44897af0a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 16:46:38 +0100 Subject: [PATCH 08/22] auth3: Make make_auth_context_text_list public Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 6 +++--- source3/auth/proto.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 8717a44afd1..3549b2cb87c 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -420,9 +420,9 @@ bool load_auth_module(struct auth_context *auth_context, Make a auth_info struct for the auth subsystem ***************************************************************************/ -static NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx, - struct auth_context **auth_context, - char **text_list) +NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx, + struct auth_context **auth_context, + char **text_list) { auth_methods *list = NULL; auth_methods *t, *method = NULL; diff --git a/source3/auth/proto.h b/source3/auth/proto.h index d55b134d5b4..c41a3d7ed40 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -40,6 +40,9 @@ bool load_auth_module(struct auth_context *auth_context, const char *module, auth_methods **ret) ; NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx, struct auth_context **auth_context); +NTSTATUS make_auth_context_text_list(TALLOC_CTX *mem_ctx, + struct auth_context **auth_context, + char **text_list); NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, const char *methods, struct auth_context **auth_context, uchar chal[8]) ; -- 2.11.0 From aa79dc9c747551806af683adcec0794e4f86d62d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 17:15:13 +0100 Subject: [PATCH 09/22] netlogond3: Do not fall back to local for interactive login This the same as the "make_auth_context_fixed" for network logins --- source3/rpc_server/netlogon/srv_netlog_nt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 5bccde3b79b..9002f232979 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1634,6 +1634,12 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, on */ { uint8_t chal[8]; + char **methods; + + methods = str_list_make_v3(talloc_tos(), "sam winbind", NULL); + if (methods == NULL) { + return NT_STATUS_NO_MEMORY; + } #ifdef DEBUG_PASSWORD if (logon != r->in.logon) { @@ -1652,8 +1658,9 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, DEBUG(100,("decrypt of nt owf password:")); dump_data(100, logon->password->ntpassword.hash, 16); #endif - status = make_auth_context_subsystem(talloc_tos(), - &auth_context); + status = make_auth_context_text_list( + talloc_tos(), &auth_context, methods); + TALLOC_FREE(methods); if (!NT_STATUS_IS_OK(status)) { return status; } -- 2.11.0 From 417d74edbd17498115c561fe4dbc6b98b6e538ef Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 9 Mar 2017 15:19:06 +0100 Subject: [PATCH 10/22] netlogond3: "authorititative" is a uint8 Signed-off-by: Volker Lendecke --- source3/rpc_server/netlogon/srv_netlog_nt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 9002f232979..f2fbb779b3c 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1510,7 +1510,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, return NT_STATUS_INTERNAL_ERROR; } - *r->out.authoritative = true; /* authoritative response */ + *r->out.authoritative = 1; /* authoritative response */ switch (r->in.validation_level) { case 2: -- 2.11.0 From caa94a85dded06884e388e599143cfd97b38ae0f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 9 Mar 2017 15:22:51 +0100 Subject: [PATCH 11/22] auth3: Return NT_STATUS_NOT_IMPLEMENTED from auth_check_ntlm_password There are 3 callers: winbindd sam auth, netlogond3 and auth_ntlmssp. winbind sam auth and netlogond3 need to return !authoritative on NOT_IMPLEMENTED, auth_ntlmssp needs to drop that info. So I think it's better that we better not use the USER_INFO_LOCAL_SAM_ONLY flag to indicate special behaviour. In winbind and netlogond we have a special auth_methods list now. Signed-off-by: Volker Lendecke --- source3/auth/auth.c | 16 ---------------- source3/auth/auth_ntlmssp.c | 4 ++++ source3/rpc_server/netlogon/srv_netlog_nt.c | 13 +++++-------- source3/winbindd/winbindd_pam.c | 2 +- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 3549b2cb87c..94847dc0e81 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -218,11 +218,6 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, auth_method_name = auth_method->name; - if (user_info->flags & USER_INFO_LOCAL_SAM_ONLY - && !(auth_method->flags & AUTH_METHOD_LOCAL_SAM)) { - continue; - } - nt_status = auth_method->auth(auth_context, auth_method->private_data, talloc_tos(), @@ -236,17 +231,6 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, DBG_DEBUG("%s had nothing to say\n", auth_method->name); } - /* check if the module did anything */ - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED) && - ((user_info->flags & USER_INFO_LOCAL_SAM_ONLY) == 0)) { - /* - * we don't expose the NT_STATUS_NOT_IMPLEMENTED - * internals, except when the caller is only probing - * one method, as they may do the fallback - */ - nt_status = NT_STATUS_NO_SUCH_USER; - } - if (!NT_STATUS_IS_OK(nt_status)) { DBG_INFO("%s authentication for user [%s] FAILED with " "error %s\n", diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c index a0e49027af9..b7a23184561 100644 --- a/source3/auth/auth_ntlmssp.c +++ b/source3/auth/auth_ntlmssp.c @@ -186,6 +186,10 @@ NTSTATUS auth3_check_password(struct auth4_context *auth4_context, user_info->client.domain_name, user_info->client.account_name, nt_errstr(nt_status))); + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { + nt_status = NT_STATUS_NO_SUCH_USER; + } } username_was_mapped = mapped_user_info->was_mapped; diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index f2fbb779b3c..820f0dedddc 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1701,14 +1701,11 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, /* Check account and password */ if (!NT_STATUS_IS_OK(status)) { - /* If we don't know what this domain is, we need to - indicate that we are not authoritative. This - allows the client to decide if it needs to try - a local user. Fix by jpjanosi@us.ibm.com, #2976 */ - if ( NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) - && !strequal(nt_domain, get_global_sam_name()) - && !is_trusted_domain(nt_domain) ) - *r->out.authoritative = false; /* We are not authoritative */ + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) { + status = NT_STATUS_NO_SUCH_USER; + r->out.authoritative = 0; + } TALLOC_FREE(server_info); return status; diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 8380d36aff4..aa5eb8999e3 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1262,7 +1262,7 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx, user_info->mapped_state = True; /* We don't want to come back to winbindd or to do PAM account checks */ - user_info->flags |= USER_INFO_LOCAL_SAM_ONLY | USER_INFO_INFO3_AND_NO_AUTHZ; + user_info->flags |= USER_INFO_INFO3_AND_NO_AUTHZ; if (interactive) { user_info->flags |= USER_INFO_INTERACTIVE_LOGON; -- 2.11.0 From 18a497c4dd77d21e44ea287039f18dcbb58bf1a7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 26 Feb 2017 14:56:24 +0100 Subject: [PATCH 12/22] map_user_info: Factor out map_userinfo_crack_user_principal --- source4/auth/ntlm/auth_util.c | 131 ++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index e3d196c2453..ea06f595801 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -26,7 +26,7 @@ #include "libcli/auth/libcli_auth.h" #include "param/param.h" #include "auth/ntlm/auth_proto.h" -#include "librpc/gen_ndr/drsuapi.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" #include "dsdb/samdb/samdb.h" /* this default function can be used by mostly all backends @@ -38,6 +38,67 @@ NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TAL return NT_STATUS_NOT_IMPLEMENTED; } +static NTSTATUS map_userinfo_crack_user_principal( + struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + const char *account, char **res_domain, char **res_account) +{ + WERROR werr; + TALLOC_CTX *tmp_ctx; + struct drsuapi_DsNameInfo1 info1; + NTSTATUS status = NT_STATUS_NO_SUCH_USER; + char *backslash, *domain, *account_name; + + tmp_ctx = talloc_new(mem_ctx); + + werr = DsCrackNameOneName(sam_ctx, tmp_ctx, 0, + DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, + DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, + account, + &info1); + if (!W_ERROR_IS_OK(werr)) { + DBG_NOTICE("Failed cracknames of account '%s': %s\n", + account, win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto fail; + } + + if (info1.status != DRSUAPI_DS_NAME_STATUS_OK) { + char *err = NDR_PRINT_STRUCT_STRING( + tmp_ctx, drsuapi_DsNameStatus, (void *)info1.status); + DBG_NOTICE("Cracknames of account '%s' -> %s\n", + account, err); + goto fail; + } + + /* info1.result_name is in DOMAIN\username + * form, which we need to split up into the + * user_info_mapped structure + */ + backslash = strchr_m(info1.result_name, '\\'); + if (backslash == NULL) { + DBG_NOTICE("Cracknames of account '%s' " + "gave invalid result '%s'\n", + account, info1.result_name); + goto fail; + } + + domain = talloc_strndup(tmp_ctx, info1.result_name, + backslash - info1.result_name); + account_name = talloc_strdup(tmp_ctx, backslash+1); + + if ((domain == NULL) || (account_name == NULL)) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + *res_domain = talloc_move(mem_ctx, &domain); + *res_account = talloc_move(mem_ctx, &account_name); + status = NT_STATUS_OK; +fail: + TALLOC_FREE(tmp_ctx); + return status; +} + /**************************************************************************** Create an auth_usersupplied_data structure after appropriate mapping. ****************************************************************************/ @@ -65,67 +126,13 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, /* use cracknames to work out what domain is being asked for */ if (strchr_m(user_info->client.account_name, '@') != NULL) { - werr = DsCrackNameOneName(sam_ctx, tmp_ctx, 0, - DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, - DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, - user_info->client.account_name, - &info1); - if (!W_ERROR_IS_OK(werr)) { - DEBUG(2,("map_user_info: Failed cracknames of account '%s'\n", - user_info->client.account_name)); - talloc_free(tmp_ctx); - return werror_to_ntstatus(werr); - } - switch (info1.status) { - case DRSUAPI_DS_NAME_STATUS_OK: - break; - case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_FOUND\n", - user_info->client.account_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> DOMAIN_ONLY\n", - user_info->client.account_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> NOT_UNIQUE\n", - user_info->client.account_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> RESOLVE_ERROR\n", - user_info->client.account_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - default: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n", - user_info->client.account_name, info1.status)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - } - /* info1.result_name is in DOMAIN\username - * form, which we need to split up into the - * user_info_mapped structure - */ - domain = talloc_strdup(tmp_ctx, info1.result_name); - if (domain == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - account_name = strchr_m(domain, '\\'); - if (account_name == NULL) { - DEBUG(2,("map_user_info: Cracknames of account '%s' gave invalid result '%s'\n", - user_info->client.account_name, info1.result_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - } - *account_name = 0; - account_name = talloc_strdup(tmp_ctx, account_name+1); - if (account_name == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; + NTSTATUS status; + + status = map_userinfo_crack_user_principal( + sam_ctx, tmp_ctx, user_info->client.account_name, + &domain, &account_name); + if (!NT_STATUS_IS_OK(status)) { + return status; } } else { const char *domain_name = default_domain; -- 2.11.0 From 4219e1abed995ecd3f919a9c24e9e49f83503637 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 26 Feb 2017 15:26:47 +0100 Subject: [PATCH 13/22] map_user_info: Factor out map_userinfo_crack_domain --- source4/auth/ntlm/auth_util.c | 131 +++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index ea06f595801..d9d9639f506 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -99,6 +99,72 @@ fail: return status; } +static NTSTATUS map_userinfo_crack_domain( + struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + const char *domain, char **pres_domain) +{ + WERROR werr; + TALLOC_CTX *tmp_ctx; + struct drsuapi_DsNameInfo1 info1; + NTSTATUS status = NT_STATUS_NO_MEMORY; + char *backslash, *res_domain; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + goto fail; + } + + domain = talloc_asprintf(tmp_ctx, "%s\\", domain); + if (domain == NULL) { + goto fail; + } + + werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0, + DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, + DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, + domain, + &info1); + if (!W_ERROR_IS_OK(werr)) { + DBG_NOTICE("Failed cracknames of domain '%s': %s\n", + domain, win_errstr(werr)); + status = werror_to_ntstatus(werr); + goto fail; + } + + if ((info1.status != DRSUAPI_DS_NAME_STATUS_OK) && + (info1.status != DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY)) { + char *err = NDR_PRINT_STRUCT_STRING( + tmp_ctx, drsuapi_DsNameStatus, (void *)info1.status); + DBG_NOTICE("Cracknames of domain '%s' -> %s\n", + domain, err); + status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto fail; + } + + backslash = strchr_m(info1.result_name, '\\'); + if (backslash == NULL) { + DBG_NOTICE("Cracknames of domain '%s' " + "gave invalid result '%s'\n", + domain, info1.result_name); + status = NT_STATUS_NO_SUCH_USER; + goto fail; + } + + res_domain = talloc_strndup(tmp_ctx, info1.result_name, + backslash - info1.result_name); + if (res_domain == NULL) { + goto fail; + } + + *pres_domain = talloc_move(mem_ctx, &res_domain); + status = NT_STATUS_OK; + +fail: + talloc_free(tmp_ctx); + return status; +} + + /**************************************************************************** Create an auth_usersupplied_data structure after appropriate mapping. ****************************************************************************/ @@ -111,8 +177,6 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, char *domain; char *account_name; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - WERROR werr; - struct drsuapi_DsNameInfo1 info1; DEBUG(5,("map_user_info_cracknames: Mapping user [%s]\\[%s] from workstation [%s]\n", user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); @@ -132,72 +196,23 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, sam_ctx, tmp_ctx, user_info->client.account_name, &domain, &account_name); if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); return status; } } else { + NTSTATUS status; const char *domain_name = default_domain; + if (user_info->client.domain_name && *user_info->client.domain_name) { domain_name = user_info->client.domain_name; } - domain_name = talloc_asprintf(tmp_ctx, "%s\\", domain_name); - if (domain_name == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - werr = DsCrackNameOneName(sam_ctx, mem_ctx, 0, - DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, - DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, - domain_name, - &info1); - if (!W_ERROR_IS_OK(werr)) { - DEBUG(2,("map_user_info: Failed cracknames of domain '%s'\n", - domain_name)); - talloc_free(tmp_ctx); - return werror_to_ntstatus(werr); - } - - /* we use the account_name as-is, but get the - * domain name from cracknames if possible */ - account_name = talloc_strdup(mem_ctx, user_info->client.account_name); - if (account_name == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - switch (info1.status) { - case DRSUAPI_DS_NAME_STATUS_OK: - case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: - domain = talloc_strdup(tmp_ctx, info1.result_name); - if (domain == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - if (domain[strlen_m(domain)-1] == '\\') { - domain[strlen_m(domain)-1] = 0; - } - break; - case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: - /* the domain is unknown - use the - default domain */ - domain = talloc_strdup(tmp_ctx, default_domain); - break; - case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: - DEBUG(2,("map_user_info: Cracknames of domain '%s' -> NOT_UNIQUE\n", - domain_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: - DEBUG(2,("map_user_info: Cracknames of domain '%s' -> RESOLVE_ERROR\n", - domain_name)); - talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; - default: - DEBUG(2,("map_user_info: Cracknames of account '%s' -> unknown error %u\n", - domain_name, info1.status)); + status = map_userinfo_crack_domain( + sam_ctx, tmp_ctx, domain_name, &domain); + if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); - return NT_STATUS_NO_SUCH_USER; + return status; } - /* domain and account_name are filled in above */ } *user_info_mapped = talloc_zero(mem_ctx, struct auth_usersupplied_info); -- 2.11.0 From 00e0fbc82ef65ac6e9f6033c02c62c2448c9863a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 26 Feb 2017 16:17:48 +0100 Subject: [PATCH 14/22] map_user_info: Retry user@domain --- source4/auth/ntlm/auth_util.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index d9d9639f506..09d6db1c0e6 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -209,6 +209,28 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, status = map_userinfo_crack_domain( sam_ctx, tmp_ctx, domain_name, &domain); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) || + NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) + { + char *princ; + + princ = talloc_asprintf( + tmp_ctx, "%s@%s", + user_info->client.account_name, + user_info->client.domain_name); + if (princ == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + DBG_DEBUG("Retrying with principal %s\n", princ); + + status = map_userinfo_crack_user_principal( + sam_ctx, tmp_ctx, princ, + &domain, &account_name); + } + if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return status; -- 2.11.0 From 0b8639ad4529bd7ec3400d0766fd5bc115dac9a5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 2 Mar 2017 11:28:18 +0100 Subject: [PATCH 15/22] winbindd: NT_STATUS_CANT_ACCESS_DOMAIN_INFO means "Dunno" Signed-off-by: Volker Lendecke --- source3/winbindd/winbindd_pam.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index aa5eb8999e3..cb75b52d362 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1338,6 +1338,16 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, result = cm_connect_netlogon(domain, &netlogon_pipe); + if (NT_STATUS_EQUAL(result, + NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { + /* + * This means we don't have a trust account. + */ + *authoritative = 0; + result = NT_STATUS_NO_SUCH_USER; + break; + } + if (!NT_STATUS_IS_OK(result)) { DEBUG(3,("Could not open handle to NETLOGON pipe " "(error: %s, attempts: %d)\n", -- 2.11.0 From e9c5b0f09ecea9e30ae6b0532bf84e37867401eb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 17:25:51 +0100 Subject: [PATCH 16/22] netlogond4: Implement !authoritative --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index afa9b1c91e1..6e08be22610 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -984,8 +984,26 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal return NT_STATUS_INVALID_PARAMETER; } + /* + * For the moment this is missing trusted domain support. We + * only look at the local dsdb. This flag makes + * auth_check_password pass up NT_STATUS_NOT_IMPLEMENTED + * properly to us so that we can return !authoritative + * correctly. + */ + + user_info->flags |= USER_INFO_LOCAL_SAM_ONLY; + nt_status = auth_check_password(auth_context, mem_ctx, user_info, &user_info_dc); - /* TODO: set *r->out.authoritative = 0 on specific errors */ + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { + *r->out.authoritative = 0; + nt_status = NT_STATUS_NO_SUCH_USER; + + /* + * This is the place to asynchronously do a winbind + * trusted domain query + */ + } NT_STATUS_NOT_OK_RETURN(nt_status); switch (r->in.validation_level) { -- 2.11.0 From 3408e395fe357285dacac791d992ced8f11cb171 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 4 Mar 2017 22:02:58 +0100 Subject: [PATCH 17/22] netlogond4: Only look at samstrict sam_ignoredomain also counts as AUTH_METHOD_LOCAL_SAM, which makes queries to a bogus domain an authoritative failure --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 6e08be22610..2f49e933f07 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -852,6 +852,14 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal struct netr_SamInfo2 *sam2 = NULL; struct netr_SamInfo3 *sam3 = NULL; struct netr_SamInfo6 *sam6 = NULL; + char **tmp; + const char **auth_methods; + + tmp = str_list_make(mem_ctx, "sam", NULL); + if (tmp == NULL) { + return NT_STATUS_NO_MEMORY; + } + auth_methods = discard_const_p(const char *, tmp); *r->out.authoritative = 1; @@ -869,10 +877,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal case NetlogonServiceTransitiveInformation: /* TODO: we need to deny anonymous access here */ - nt_status = auth_context_create(mem_ctx, - dce_call->event_ctx, dce_call->msg_ctx, - dce_call->conn->dce_ctx->lp_ctx, - &auth_context); + nt_status = auth_context_create_methods( + mem_ctx, auth_methods, + dce_call->event_ctx, dce_call->msg_ctx, + dce_call->conn->dce_ctx->lp_ctx, NULL, + &auth_context); NT_STATUS_NOT_OK_RETURN(nt_status); user_info->logon_parameters = r->in.logon->password->identity_info.parameter_control; @@ -896,10 +905,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal case NetlogonNetworkTransitiveInformation: /* TODO: we need to deny anonymous access here */ - nt_status = auth_context_create(mem_ctx, - dce_call->event_ctx, dce_call->msg_ctx, - dce_call->conn->dce_ctx->lp_ctx, - &auth_context); + nt_status = auth_context_create_methods( + mem_ctx, auth_methods, + dce_call->event_ctx, dce_call->msg_ctx, + dce_call->conn->dce_ctx->lp_ctx, NULL, + &auth_context); NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = auth_context_set_challenge(auth_context, r->in.logon->network->challenge, "netr_LogonSamLogonWithFlags"); -- 2.11.0 From a5fe424a7049bc66157c74d43134a78d31981d74 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 5 Mar 2017 19:13:04 +0100 Subject: [PATCH 18/22] auth4: Implement !authoritative Doing the map_user_info in auth_check_password_send is wrong: At that point we don't know if we are doing sam_strict or sam_ignoredomain. Defaulting to a domain in map_user_info makes sam_strict impossible. Move the map_user_info into the backends. --- source4/auth/ntlm/auth.c | 27 +------ source4/auth/ntlm/auth_sam.c | 154 ++++++++++++++++++++++++++++----------- source4/auth/ntlm/auth_winbind.c | 2 +- 3 files changed, 116 insertions(+), 67 deletions(-) diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index 05d6c3cb75e..fadfe605fa1 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -282,29 +282,6 @@ _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx, state->auth_ctx = auth_ctx; state->user_info = user_info; - if (!user_info->mapped_state) { - int server_role = lpcfg_server_role(auth_ctx->lp_ctx); - struct auth_usersupplied_info *user_info_tmp; - - nt_status = map_user_info( - auth_ctx->sam_ctx, req, - server_role == ROLE_ACTIVE_DIRECTORY_DC, - lpcfg_workgroup(auth_ctx->lp_ctx), - user_info, &user_info_tmp); - - if (tevent_req_nterror(req, nt_status)) { - return tevent_req_post(req, ev); - } - user_info = user_info_tmp; - state->user_info = user_info_tmp; - } - - DEBUGADD(3,("auth_check_password_send: " - "mapped user is: [%s]\\[%s]@[%s]\n", - user_info->mapped.domain_name, - user_info->mapped.account_name, - user_info->workstation_name)); - nt_status = auth_get_challenge(auth_ctx, chal); if (tevent_req_nterror(req, nt_status)) { DEBUG(0,("auth_check_password_send: " @@ -608,12 +585,12 @@ const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context * auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL); break; case ROLE_DOMAIN_MEMBER: - auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL); + auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL); break; case ROLE_DOMAIN_BDC: case ROLE_DOMAIN_PDC: case ROLE_ACTIVE_DIRECTORY_DC: - auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL); + auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL); break; } return discard_const_p(const char *, auth_methods); diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c index 90eabcaf506..277b0d50f8f 100644 --- a/source4/auth/ntlm/auth_sam.c +++ b/source4/auth/ntlm/auth_sam.c @@ -629,59 +629,131 @@ static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx return NT_STATUS_OK; } -static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) +static NTSTATUS authsam_check_password_ignoredomain( + struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_user_info_dc **user_info_dc) { - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + if (!user_info->client.account_name || !*user_info->client.account_name) { return NT_STATUS_NOT_IMPLEMENTED; } - return NT_STATUS_OK; + if (!user_info->mapped_state) { + struct auth4_context *auth_ctx = ctx->auth_ctx; + struct auth_usersupplied_info *user_info_tmp; + NTSTATUS status; + + status = map_user_info( + auth_ctx->sam_ctx, mem_ctx, + false, /* no cracknames please */ + lpcfg_workgroup(auth_ctx->lp_ctx), + user_info, &user_info_tmp); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + user_info_tmp->mapped.domain_name = talloc_strdup( + user_info_tmp, lpcfg_workgroup(auth_ctx->lp_ctx)); + if (user_info_tmp->mapped.domain_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + user_info = user_info_tmp; + } + + DBG_DEBUG("%s\\%s\n", user_info->mapped.domain_name, + user_info->client.account_name); + + return authsam_check_password_internals(ctx, mem_ctx, user_info, + user_info_dc); } -/**************************************************************************** -Check SAM security (above) but with a few extra checks. -****************************************************************************/ -static NTSTATUS authsam_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) +static NTSTATUS authsam_check_password_strict( + struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_user_info_dc **user_info_dc) { - bool is_local_name, is_my_domain; + struct auth4_context *auth_ctx = ctx->auth_ctx; - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; + if (!user_info->mapped_state) { + int server_role = lpcfg_server_role(auth_ctx->lp_ctx); + struct auth_usersupplied_info *user_info_tmp; + NTSTATUS status; + + status = map_user_info( + auth_ctx->sam_ctx, mem_ctx, + server_role == ROLE_ACTIVE_DIRECTORY_DC, + lpcfg_workgroup(auth_ctx->lp_ctx), + user_info, &user_info_tmp); + + if (NT_STATUS_EQUAL(status, + NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + user_info = user_info_tmp; } - is_local_name = lpcfg_is_myname(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); - is_my_domain = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); + DBG_DEBUG("%s\\%s\n", user_info->mapped.domain_name, + user_info->client.account_name); - /* check whether or not we service this domain/workgroup name */ switch (lpcfg_server_role(ctx->auth_ctx->lp_ctx)) { - case ROLE_STANDALONE: - return NT_STATUS_OK; - - case ROLE_DOMAIN_MEMBER: - if (!is_local_name) { - DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; + case ROLE_STANDALONE: + break; + + case ROLE_DOMAIN_MEMBER: { + bool is_local_name; + + is_local_name = lpcfg_is_myname( + auth_ctx->lp_ctx, user_info->mapped.domain_name); + if (!is_local_name) { + DBG_INFO("%s is not one of my local names " + "(DOMAIN_MEMBER)\n", + user_info->mapped.domain_name); + return NT_STATUS_NOT_IMPLEMENTED; + } + break; + } + + case ROLE_ACTIVE_DIRECTORY_DC: { + bool is_my_domain; + + is_my_domain = lpcfg_is_mydomain( + auth_ctx->lp_ctx, user_info->mapped.domain_name); + if (!is_my_domain) { + DBG_INFO("%s is not my domain name (DC)\n", + user_info->mapped.domain_name); + return NT_STATUS_NOT_IMPLEMENTED; + } + break; + } + } + + return authsam_check_password_internals(ctx, mem_ctx, user_info, + user_info_dc); +} - case ROLE_ACTIVE_DIRECTORY_DC: - if (!is_local_name && !is_my_domain) { - DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; - } +static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; +} - DEBUG(6,("authsam_check_password: lpcfg_server_role() has an undefined value\n")); - return NT_STATUS_NOT_IMPLEMENTED; +/**************************************************************************** +Check SAM security (above) but with a few extra checks. +****************************************************************************/ +static NTSTATUS authsam_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; } @@ -698,7 +770,7 @@ static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx, static const struct auth_operations sam_ignoredomain_ops = { .name = "sam_ignoredomain", .want_check = authsam_ignoredomain_want_check, - .check_password = authsam_check_password_internals, + .check_password = authsam_check_password_ignoredomain, .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, .flags = AUTH_METHOD_LOCAL_SAM }; @@ -706,7 +778,7 @@ static const struct auth_operations sam_ignoredomain_ops = { static const struct auth_operations sam_ops = { .name = "sam", .want_check = authsam_want_check, - .check_password = authsam_check_password_internals, + .check_password = authsam_check_password_strict, .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, .flags = AUTH_METHOD_LOCAL_SAM }; diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c index 6f1976de723..a3a129cb9c6 100644 --- a/source4/auth/ntlm/auth_winbind.c +++ b/source4/auth/ntlm/auth_winbind.c @@ -37,7 +37,7 @@ static NTSTATUS winbind_want_check(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info) { - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + if (!user_info->client.account_name || !*user_info->client.account_name) { return NT_STATUS_NOT_IMPLEMENTED; } -- 2.11.0 From 7c70881c6ede9b20ee09e1aaaf9051de1a0d0895 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 6 Mar 2017 08:30:07 +0100 Subject: [PATCH 19/22] auth4: Handle DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY in map_userinfo_crack_user_principal --- source4/auth/ntlm/auth_util.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c index 09d6db1c0e6..439a492d68d 100644 --- a/source4/auth/ntlm/auth_util.c +++ b/source4/auth/ntlm/auth_util.c @@ -62,6 +62,18 @@ static NTSTATUS map_userinfo_crack_user_principal( goto fail; } + if (info1.status == DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY) { + *res_account = NULL; + *res_domain = talloc_strdup( + mem_ctx, info1.dns_domain_name); + if (*res_domain == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + status = NT_STATUS_OK; + goto fail; + } + if (info1.status != DRSUAPI_DS_NAME_STATUS_OK) { char *err = NDR_PRINT_STRUCT_STRING( tmp_ctx, drsuapi_DsNameStatus, (void *)info1.status); @@ -175,18 +187,12 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, struct auth_usersupplied_info **user_info_mapped) { char *domain; - char *account_name; + char *account_name = NULL; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); DEBUG(5,("map_user_info_cracknames: Mapping user [%s]\\[%s] from workstation [%s]\n", user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); - account_name = talloc_strdup(tmp_ctx, user_info->client.account_name); - if (!account_name) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - /* use cracknames to work out what domain is being asked for */ if (strchr_m(user_info->client.account_name, '@') != NULL) { @@ -237,6 +243,16 @@ static NTSTATUS map_user_info_cracknames(struct ldb_context *sam_ctx, } } + if (account_name == NULL) { + account_name = talloc_strdup( + tmp_ctx, user_info->client.account_name); + } + + if (account_name == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + *user_info_mapped = talloc_zero(mem_ctx, struct auth_usersupplied_info); if (!*user_info_mapped) { talloc_free(tmp_ctx); -- 2.11.0 From 1f0b19625aee213e0556cdb9c6b14480cf39840d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 13:53:39 +0100 Subject: [PATCH 20/22] rpc_client3: Fix some crashes for NULL cli_state in cli_pipe Signed-off-by: Volker Lendecke --- source3/rpc_client/cli_netlogon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 634c78bfe45..9f1d952ec82 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -174,7 +174,7 @@ NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli, DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, action, creds->account_name, creds->computer_name, - smbXcli_conn_remote_name(cli->conn))); + cli ? smbXcli_conn_remote_name(cli->conn) : "local")); if (!force_reauth) { TALLOC_FREE(frame); return NT_STATUS_OK; @@ -189,7 +189,7 @@ NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli, if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n", __FUNCTION__, - smbXcli_conn_remote_name(cli->conn), + cli ? smbXcli_conn_remote_name(cli->conn) : "local", nt_errstr(status))); TALLOC_FREE(frame); return status; @@ -215,7 +215,7 @@ NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli, DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, creds->account_name, creds->computer_name, - smbXcli_conn_remote_name(cli->conn))); + cli ? smbXcli_conn_remote_name(cli->conn) : "local")); TALLOC_FREE(frame); return NT_STATUS_OK; -- 2.11.0 From a0d50da9c08c550d99fdb6d309c0fe5a24347185 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 13:54:53 +0100 Subject: [PATCH 21/22] rpc_client3: Allow to connect to local unix socket Signed-off-by: Volker Lendecke --- source3/rpc_client/cli_pipe.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 14f7fbc907f..176345e76f2 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -3057,6 +3057,26 @@ static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli, table, presult); case NCACN_NP: return rpc_pipe_open_np(cli, table, presult); + case NCACN_UNIX_STREAM: { + char *socket_path; + NTSTATUS status; + + socket_path = talloc_asprintf(talloc_tos(), "%s/DEFAULT", + lp_ncalrpc_dir()); + if (socket_path == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = rpc_pipe_open_ncalrpc( + NULL, socket_path, table, presult); + + DBG_DEBUG("rpc_pipe_open_ncalrpc(%s) returned %s\n", + socket_path, nt_errstr(status)); + + TALLOC_FREE(socket_path); + + return status; + } default: return NT_STATUS_NOT_IMPLEMENTED; } -- 2.11.0 From 6d7cbb5693b6b86487627a1213ccdc32da32c8c2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Mar 2017 13:56:19 +0100 Subject: [PATCH 22/22] winbind3: On a AD DC, ask the local netlogon pipe for local auth Signed-off-by: Volker Lendecke --- source3/winbindd/winbindd_cm.c | 10 ++++++++++ source3/winbindd/winbindd_pam.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 3df4af3ff10..64fda3451a8 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -3357,6 +3357,16 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, return status; } + if (domain->primary && !domain->rodc && + (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)) { + if (domain->dcname == NULL) { + domain->dcname = talloc_strdup( + domain, lp_netbios_name()); + } + return cm_connect_netlogon_transport( + domain, NCACN_UNIX_STREAM, cli); + } + if (domain->active_directory && domain->can_do_ncacn_ip_tcp) { status = cm_connect_netlogon_transport(domain, NCACN_IP_TCP, cli); if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) || diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index cb75b52d362..6a1f2e196ca 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1238,6 +1238,11 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx, int rc; TALLOC_CTX *frame = talloc_stackframe(); + if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) { + TALLOC_FREE(frame); + return NT_STATUS_NOT_IMPLEMENTED; + } + rc = tsocket_address_inet_from_strings(frame, "ip", "127.0.0.1", -- 2.11.0