The branch, master has been updated via c1ee6fe9a48 s3/libsmb: check the negative-conn-cache in resolve_ads() via 5217bd1a233 s3/libsmb: check command in make_dc_info_from_cldap_reply() via d3000d7df09 libads: check for if DCs are in paused state when processing CLDAP replies via a397801598e s3/libads: get rid of additional loop calling add_failed_connection_entry() via 63051a2dcbe s3:libads: let get_kdc_ip_string() check for a blacklisted server name via 08c8760ad97 s3:libads: let cldap_ping_list() check for a blacklisted server name via ce80451f3af winbindd: blacklist servers returning ACCESS_DENIED/authoritative=0 via 7fed75c495e winbindd: always use winbind_add_failed_connection_entry() wrapper via 613ac83fb76 s3:conncache: improve debugging for the negative connection cache from 750f6847f04 dsdb: fix bug 15872, use-after-free
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c1ee6fe9a489a8923d607e14d26768935a398849 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 3 18:42:04 2025 +0200 s3/libsmb: check the negative-conn-cache in resolve_ads() This way we throw away blacklisted servers right away when learning about them from the DNS SRV query. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> Autobuild-User(master): Günther Deschner <g...@samba.org> Autobuild-Date(master): Wed Jul 30 10:10:21 UTC 2025 on atb-devel-224 commit 5217bd1a2334825fed32f40c57f72464d126aac0 Author: Ralph Boehme <s...@samba.org> Date: Wed Jul 2 18:49:51 2025 +0200 s3/libsmb: check command in make_dc_info_from_cldap_reply() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit d3000d7df09de724694aa0682b9750b8c7767514 Author: Ralph Boehme <s...@samba.org> Date: Thu Jul 3 12:50:53 2025 +0200 libads: check for if DCs are in paused state when processing CLDAP replies BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit a397801598eef4b0381a64a37af1845e9e85a50f Author: Ralph Boehme <s...@samba.org> Date: Tue Jul 1 18:19:32 2025 +0200 s3/libads: get rid of additional loop calling add_failed_connection_entry() Just call add_failed_connection_entry() in the initial loop at all places where we have a "bad" result. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit 63051a2dcbe3a4a07f029e0c18aa90bd3f56b0a4 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Jul 4 18:07:51 2023 +0200 s3:libads: let get_kdc_ip_string() check for a blacklisted server name BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit 08c8760ad9706b62755e35acaa121647344a4c9e Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 16 13:09:14 2022 +0100 s3:libads: let cldap_ping_list() check for a blacklisted server name If we black listed a server we should not use it even if it responses to CLDAP requests. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Pair-Programmed-With: Ralph Boehme <s...@samba.org> Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit ce80451f3af4418d1c83be009b58b3824c071cae Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 16 14:23:16 2022 +0100 winbindd: blacklist servers returning ACCESS_DENIED/authoritative=0 https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit 7fed75c495ead8f476c805b91cc6624ebf933427 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 16 14:18:50 2022 +0100 winbindd: always use winbind_add_failed_connection_entry() wrapper We should not use add_failed_connection_entry() directly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> commit 613ac83fb7666f5b132187d5587053e0d7dcd46d Author: Stefan Metzmacher <me...@samba.org> Date: Wed Feb 16 14:18:20 2022 +0100 s3:conncache: improve debugging for the negative connection cache BUG: https://bugzilla.samba.org/show_bug.cgi?id=14981 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Reviewed-by: Guenther Deschner <g...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/libads/kerberos.c | 22 +++++++++ source3/libads/ldap.c | 46 ++++++++++++++----- source3/libads/netlogon_ping.c | 13 ++++-- source3/libsmb/conncache.c | 8 ++-- source3/libsmb/dsgetdcname.c | 6 +++ source3/libsmb/namequery.c | 25 ++++++++-- source3/winbindd/winbindd_cm.c | 2 +- source3/winbindd/winbindd_pam.c | 96 ++++++++++++++++++++++++++++++++++++++- source3/winbindd/winbindd_proto.h | 4 ++ 9 files changed, 196 insertions(+), 26 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 145bc36cdb2..c1f3f3ce356 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -1235,10 +1235,32 @@ static char *get_kdc_ip_string(char *mem_ctx, } for (i=0; i<num_dcs; i++) { + struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply = NULL; + char addr[INET6_ADDRSTRLEN]; + if (responses[i] == NULL) { continue; } + if (responses[i]->ntver != NETLOGON_NT_VERSION_5EX) { + continue; + } + + print_sockaddr(addr, sizeof(addr), &dc_addrs[i]); + + cldap_reply = &responses[i]->data.nt5_ex; + + if (cldap_reply->pdc_dns_name != NULL) { + status = check_negative_conn_cache( + realm, + cldap_reply->pdc_dns_name); + if (!NT_STATUS_IS_OK(status)) { + /* propagate blacklisting from name to ip */ + add_failed_connection_entry(realm, addr, status); + continue; + } + } + /* Append to the string - inefficient but not done often. */ talloc_asprintf_addbuf(&kdc_str, "\t\tkdc = %s\n", diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 016402d5ca6..af467cfe390 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -518,21 +518,53 @@ again: struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply = NULL; char server[INET6_ADDRSTRLEN]; + print_sockaddr(server, sizeof(server), &req_sa_list[i]->u.ss); + if (responses[i] == NULL) { + add_failed_connection_entry( + domain, + server, + NT_STATUS_INVALID_NETWORK_RESPONSE); continue; } - print_sockaddr(server, sizeof(server), &req_sa_list[i]->u.ss); - if (responses[i]->ntver != NETLOGON_NT_VERSION_5EX) { DBG_NOTICE("realm=[%s] nt_version mismatch: 0x%08x for %s\n", ads->server.realm, responses[i]->ntver, server); + add_failed_connection_entry( + domain, + server, + NT_STATUS_INVALID_NETWORK_RESPONSE); continue; } cldap_reply = &responses[i]->data.nt5_ex; + if (cldap_reply->pdc_dns_name != NULL) { + status = check_negative_conn_cache( + domain, + cldap_reply->pdc_dns_name); + if (!NT_STATUS_IS_OK(status)) { + /* + * only use the server if it's not black listed + * by name + */ + DBG_NOTICE("realm=[%s] server=[%s][%s] " + "black listed: %s\n", + ads->server.realm, + server, + cldap_reply->pdc_dns_name, + nt_errstr(status)); + /* propagate blacklisting from name to ip */ + add_failed_connection_entry(domain, + server, + status); + retry = true; + continue; + } + } + /* Returns ok only if it matches the correct server type */ ok = ads_fill_cldap_reply(ads, false, @@ -571,16 +603,6 @@ again: } } - /* keep track of failures as all were not suitable */ - for (i = 0; i < num_requests; i++) { - char server[INET6_ADDRSTRLEN]; - - print_sockaddr(server, sizeof(server), &req_sa_list[i]->u.ss); - - add_failed_connection_entry(domain, server, - NT_STATUS_UNSUCCESSFUL); - } - status = NT_STATUS_NO_LOGON_SERVERS; DBG_WARNING("realm[%s] no valid response " "num_requests[%zu] for count[%zu] - %s\n", diff --git a/source3/libads/netlogon_ping.c b/source3/libads/netlogon_ping.c index c94af8fbc57..22f5a56b395 100644 --- a/source3/libads/netlogon_ping.c +++ b/source3/libads/netlogon_ping.c @@ -787,23 +787,30 @@ static void netlogon_pings_done(struct tevent_req *subreq) state->num_received += 1; if (NT_STATUS_IS_OK(status)) { + enum netlogon_command cmd; uint32_t ret_flags; - bool ok; + bool ok = true; switch (response->ntver) { case NETLOGON_NT_VERSION_5EX: ret_flags = response->data.nt5_ex.server_type; + cmd = response->data.nt5_ex.command; + ok &= !(cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE || + cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE_EX); break; case NETLOGON_NT_VERSION_5: ret_flags = response->data.nt5.server_type; + cmd = response->data.nt5.command; + ok &= !(cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE || + cmd == LOGON_SAM_LOGON_PAUSE_RESPONSE_EX); break; default: ret_flags = 0; break; } - ok = check_cldap_reply_required_flags(ret_flags, - state->required_flags); + ok &= check_cldap_reply_required_flags(ret_flags, + state->required_flags); if (ok) { state->responses[i] = talloc_move(state->responses, &response); diff --git a/source3/libsmb/conncache.c b/source3/libsmb/conncache.c index 7310b508a3b..353c1e8f930 100644 --- a/source3/libsmb/conncache.c +++ b/source3/libsmb/conncache.c @@ -147,8 +147,9 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server) if (gencache_get(key, talloc_tos(), &value, NULL)) result = negative_conn_cache_valuedecode(value); done: - DEBUG(9,("check_negative_conn_cache returning result %d for domain %s " - "server %s\n", NT_STATUS_V(result), domain, server)); + DBG_PREFIX(NT_STATUS_IS_OK(result) ? DBGLVL_DEBUG : DBGLVL_INFO, + ("returning result %s for domain %s " + "server %s\n", nt_errstr(result), domain, server)); TALLOC_FREE(key); TALLOC_FREE(value); return result; @@ -187,7 +188,8 @@ void add_failed_connection_entry(const char *domain, const char *server, if (gencache_set(key, value, time(NULL) + FAILED_CONNECTION_CACHE_TIMEOUT)) DEBUG(9,("add_failed_connection_entry: added domain %s (%s) " - "to failed conn cache\n", domain, server )); + "to failed conn cache %s\n", domain, server, + nt_errstr(result))); else DEBUG(1,("add_failed_connection_entry: failed to add " "domain %s (%s) to failed conn cache\n", diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index 6bbe4e0b4ad..695f0c38d85 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -755,6 +755,12 @@ static NTSTATUS make_dc_info_from_cldap_reply( char addr[INET6_ADDRSTRLEN]; + if (r->command == LOGON_SAM_LOGON_PAUSE_RESPONSE || + r->command == LOGON_SAM_LOGON_PAUSE_RESPONSE_EX) + { + return NT_STATUS_NETLOGON_NOT_STARTED; + } + if (sa != NULL) { print_sockaddr(addr, sizeof(addr), &sa->u.ss); dc_address = addr; diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index a54ca2f74d3..0b762af64af 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -2617,6 +2617,14 @@ static NTSTATUS resolve_ads(TALLOC_CTX *ctx, for(i = 0; i < numdcs; i++) { /* Copy all the IP addresses from the SRV response */ size_t j; + + status = check_negative_conn_cache(name, dcs[i].hostname); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Skipping blacklisted server [%s] " + "for domain [%s]", dcs[i].hostname, name); + continue; + } + for (j = 0; j < dcs[i].num_ips; j++) { char addr[INET6_ADDRSTRLEN]; @@ -2625,12 +2633,19 @@ static NTSTATUS resolve_ads(TALLOC_CTX *ctx, continue; } + print_sockaddr(addr, + sizeof(addr), + &srv_addrs[num_srv_addrs]); + DBG_DEBUG("SRV lookup %s got IP[%zu] %s\n", - name, - j, - print_sockaddr(addr, - sizeof(addr), - &srv_addrs[num_srv_addrs])); + name, j, addr); + + status = check_negative_conn_cache(name, addr); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Skipping blacklisted server [%s] " + "for domain [%s]", addr, name); + continue; + } num_srv_addrs++; } diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 15a2f60c532..c5ea918cff7 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -322,7 +322,7 @@ void set_domain_online_request(struct winbindd_domain *domain) Add -ve connection cache entries for domain and realm. ****************************************************************/ -static void winbind_add_failed_connection_entry( +void winbind_add_failed_connection_entry( const struct winbindd_domain *domain, const char *server, NTSTATUS result) diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 49e8e845c0f..d77320558be 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1637,6 +1637,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, { int attempts = 0; int netr_attempts = 0; + int invalid_servers = 0; bool retry = false; bool valid_result = false; NTSTATUS result; @@ -1705,10 +1706,9 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, DEBUG(3, ("This is the third problem for this " "particular call, adding DC to the " "negative cache list: %s %s\n", domain->name, domain->dcname)); - add_failed_connection_entry(domain->name, + winbind_add_failed_connection_entry(domain, domain->dcname, result); - saf_delete(domain->name); } /* Only allow 3 retries */ @@ -1798,6 +1798,98 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, &validation); } + /* + * MS-NRPC 3.5.4.5.1 NetrLogonSamLogonEx (Opnum 39) says: + * ... + * + * Authoritative: ... + * This Boolean value indicates whether the validation + * information is final. This field is necessary because + * the request might be forwarded through multiple servers. + * + * The value TRUE indicates that the validation information + * is an authoritative response and MUST remain unchanged. + * + * The value FALSE indicates that the validation information + * is not an authoritative response and that the client can + * resend the request to another server. + * + * ... + * If the server cannot service the request due to an + * implementation-specific condition, the server + * returns STATUS_ACCESS_DENIED. + * ... + * + * One reason for this is that SysvolReady is still 0 in + * HKLM\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters + * It means there are problems with sysvol replication. + * + * The response looks like this: + * + * netr_LogonSamLogonEx: struct netr_LogonSamLogonEx + * out: struct netr_LogonSamLogonEx + * validation : * + * validation : union netr_Validation(case 6) + * sam6 : NULL + * authoritative : * + * authoritative : 0x00 (0) + * flags : * + * flags : 0x00000000 (0) + * 0: NETLOGON_SAMLOGON_FLAG_PASS_TO_FOREST_ROOT + * 0: NETLOGON_SAMLOGON_FLAG_PASS_CROSS_FOREST_HOP + * 0: NETLOGON_SAMLOGON_FLAG_RODC_TO_OTHER_DOMAIN + * 0: NETLOGON_SAMLOGON_FLAG_RODC_NTLM_REQUEST + * result : NT_STATUS_ACCESS_DENIED + * + * In that case we'll mark the dc as broken and retry. + * In order to prevent a fallback to a local user due to + * authoritative=0, we reset authoritative=1 and continue + * with NT_STATUS_NETLOGON_NOT_STARTED. + * + * In the end we may result in NT_STATUS_NO_LOGON_SERVERS + * if we never reach 'valid_result = true'. + * This matches what windows does. In a chain of transitive + * trusts the ACCESS_DENIED/authoritative=0 is not propagated + * instead of NT_STATUS_NO_LOGON_SERVERS/authoritative=1 is + * passed along the chain if there's no other DC is available. + */ + if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && + *authoritative == 0) + { + reset_cm_connection_on_error( + domain, + netlogon_pipe->binding_handle, + result); + + *authoritative = true; + result = NT_STATUS_NETLOGON_NOT_STARTED; + DBG_WARNING("sam_logon[%s\\%s] returned ACCESS_DENIED " + "authoritative=0.\n" + "The DC may have set SysvolReady=0 in " + "HKLM\\SYSTEM\\CurrentControlSet\\Services" + "\\Netlogon\\Parameters\n" + "%s: Adding DC to the negative cache list: " + "%s %s\n", + domainname, + username, + nt_errstr(result), + domain->name, + domain->dcname); + + winbind_add_failed_connection_entry(domain, + domain->dcname, + result); + + /* Only allow 3 retries */ + if (invalid_servers < 3) { + DBG_NOTICE("Retry another server\n"); + invalid_servers++; + retry = true; + continue; + } + break; + } + /* * we increment this after the "feature negotiation" * for can_do_samlogon_ex and can_do_validation6 diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 3734ab49086..45e20ba3a81 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -206,6 +206,10 @@ void winbind_msg_domain_online(struct messaging_context *msg_ctx, void set_domain_offline(struct winbindd_domain *domain); void set_domain_online_request(struct winbindd_domain *domain); +void winbind_add_failed_connection_entry( + const struct winbindd_domain *domain, + const char *server, + NTSTATUS result); struct cli_credentials; NTSTATUS winbindd_get_trust_credentials(struct winbindd_domain *domain, -- Samba Shared Repository