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

Reply via email to