The branch, master has been updated via 8132edf1197 s3:libads: let cldap_ping_list() use cldap_multi_netlogon() via ab6b9465eda s3:libads: split out ads_fill_cldap_reply() out of ads_try_connect() from c2e235efd40 s3:modules - fix read of uninitialized memory
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 8132edf119757ee91070facffef016c93de9c2a6 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Aug 24 16:11:06 2022 +0200 s3:libads: let cldap_ping_list() use cldap_multi_netlogon() We have a list of ip addresses, so we can request them all together under a single timeout, instead of asking each ip with it's own timeout. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> Autobuild-User(master): Andreas Schneider <a...@cryptomilk.org> Autobuild-Date(master): Thu Sep 8 08:12:46 UTC 2022 on sn-devel-184 commit ab6b9465eda9f219bbed3bd65e89668e5e2c93c6 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Aug 24 16:36:17 2022 +0200 s3:libads: split out ads_fill_cldap_reply() out of ads_try_connect() Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/libads/ldap.c | 246 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 44 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index e7e34998f74..da5a924cde0 100755 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -25,6 +25,7 @@ #include "ads.h" #include "libads/sitename_cache.h" #include "libads/cldap.h" +#include "../lib/tsocket/tsocket.h" #include "../lib/addns/dnsquery.h" #include "../libds/common/flags.h" #include "smbldap.h" @@ -249,43 +250,23 @@ bool ads_closest_dc(ADS_STRUCT *ads) return False; } - -/* - try a connection to a given ldap server, returning True and setting the servers IP - in the ads struct if successful - */ -static bool ads_try_connect(ADS_STRUCT *ads, bool gc, - struct sockaddr_storage *ss) +static bool ads_fill_cldap_reply(ADS_STRUCT *ads, + bool gc, + const struct sockaddr_storage *ss, + const struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply) { - struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply; TALLOC_CTX *frame = talloc_stackframe(); bool ret = false; char addr[INET6_ADDRSTRLEN]; ADS_STATUS status; - if (ss == NULL) { - TALLOC_FREE(frame); - return False; - } - print_sockaddr(addr, sizeof(addr), ss); - DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n", - addr, ads->server.realm)); - - ZERO_STRUCT( cldap_reply ); - - if ( !ads_cldap_netlogon_5(frame, ss, ads->server.realm, &cldap_reply ) ) { - DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", addr)); - ret = false; - goto out; - } - /* Check the CLDAP reply flags */ - if ( !(cldap_reply.server_type & NBT_SERVER_LDAP) ) { - DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n", - addr)); + if (!(cldap_reply->server_type & NBT_SERVER_LDAP)) { + DBG_WARNING("%s's CLDAP reply says it is not an LDAP server!\n", + addr); ret = false; goto out; } @@ -299,14 +280,14 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, TALLOC_FREE(ads->config.client_site_name); TALLOC_FREE(ads->server.workgroup); - if (!check_cldap_reply_required_flags(cldap_reply.server_type, + if (!check_cldap_reply_required_flags(cldap_reply->server_type, ads->config.flags)) { ret = false; goto out; } ads->config.ldap_server_name = talloc_strdup(ads, - cldap_reply.pdc_dns_name); + cldap_reply->pdc_dns_name); if (ads->config.ldap_server_name == NULL) { DBG_WARNING("Out of memory\n"); ret = false; @@ -315,7 +296,7 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, ads->config.realm = talloc_asprintf_strupper_m(ads, "%s", - cldap_reply.dns_domain); + cldap_reply->dns_domain); if (ads->config.realm == NULL) { DBG_WARNING("Out of memory\n"); ret = false; @@ -330,9 +311,9 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, goto out; } - if (*cldap_reply.server_site) { + if (*cldap_reply->server_site) { ads->config.server_site_name = - talloc_strdup(ads, cldap_reply.server_site); + talloc_strdup(ads, cldap_reply->server_site); if (ads->config.server_site_name == NULL) { DBG_WARNING("Out of memory\n"); ret = false; @@ -340,9 +321,9 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, } } - if (*cldap_reply.client_site) { + if (*cldap_reply->client_site) { ads->config.client_site_name = - talloc_strdup(ads, cldap_reply.client_site); + talloc_strdup(ads, cldap_reply->client_site); if (ads->config.client_site_name == NULL) { DBG_WARNING("Out of memory\n"); ret = false; @@ -350,7 +331,7 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, } } - ads->server.workgroup = talloc_strdup(ads, cldap_reply.domain_name); + ads->server.workgroup = talloc_strdup(ads, cldap_reply->domain_name); if (ads->server.workgroup == NULL) { DBG_WARNING("Out of memory\n"); ret = false; @@ -361,11 +342,11 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, ads->ldap.ss = *ss; /* Store our site name. */ - sitename_store( cldap_reply.domain_name, cldap_reply.client_site); - sitename_store( cldap_reply.dns_domain, cldap_reply.client_site); + sitename_store(cldap_reply->domain_name, cldap_reply->client_site); + sitename_store(cldap_reply->dns_domain, cldap_reply->client_site); /* Leave this until last so that the flags are not clobbered */ - ads->config.flags = cldap_reply.server_type; + ads->config.flags = cldap_reply->server_type; ret = true; @@ -375,6 +356,48 @@ static bool ads_try_connect(ADS_STRUCT *ads, bool gc, return ret; } +/* + try a connection to a given ldap server, returning True and setting the servers IP + in the ads struct if successful + */ +static bool ads_try_connect(ADS_STRUCT *ads, bool gc, + struct sockaddr_storage *ss) +{ + struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply = {}; + TALLOC_CTX *frame = talloc_stackframe(); + bool ok; + char addr[INET6_ADDRSTRLEN] = { 0, }; + + if (ss == NULL) { + TALLOC_FREE(frame); + return false; + } + + print_sockaddr(addr, sizeof(addr), ss); + + DBG_INFO("ads_try_connect: sending CLDAP request to %s (realm: %s)\n", + addr, ads->server.realm); + + ok = ads_cldap_netlogon_5(frame, ss, ads->server.realm, &cldap_reply); + if (!ok) { + DBG_NOTICE("ads_cldap_netlogon_5(%s, %s) failed.\n", + addr, ads->server.realm); + TALLOC_FREE(frame); + return false; + } + + ok = ads_fill_cldap_reply(ads, gc, ss, &cldap_reply); + if (!ok) { + DBG_NOTICE("ads_fill_cldap_reply(%s, %s) failed.\n", + addr, ads->server.realm); + TALLOC_FREE(frame); + return false; + } + + TALLOC_FREE(frame); + return true; +} + /********************************************************************** send a cldap ping to list of servers, one at a time, until one of them answers it's an ldap server. Record success in the ADS_STRUCT. @@ -386,11 +409,44 @@ static NTSTATUS cldap_ping_list(ADS_STRUCT *ads, struct samba_sockaddr *sa_list, size_t count) { + TALLOC_CTX *frame = talloc_stackframe(); + struct timeval endtime = timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0); + uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; + struct tsocket_address **ts_list = NULL; + const struct tsocket_address * const *ts_list_const = NULL; + struct samba_sockaddr **req_sa_list = NULL; + struct netlogon_samlogon_response **responses = NULL; + size_t num_requests = 0; + NTSTATUS status; size_t i; - bool ok; + bool ok = false; + bool retry; + + ts_list = talloc_zero_array(frame, + struct tsocket_address *, + count); + if (ts_list == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + req_sa_list = talloc_zero_array(frame, + struct samba_sockaddr *, + count); + if (req_sa_list == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + +again: + /* + * The retry loop is bound by the timeout + */ + retry = false; for (i = 0; i < count; i++) { char server[INET6_ADDRSTRLEN]; + int ret; if (is_zero_addr(&sa_list[i].u.ss)) { continue; @@ -398,22 +454,124 @@ static NTSTATUS cldap_ping_list(ADS_STRUCT *ads, print_sockaddr(server, sizeof(server), &sa_list[i].u.ss); - if (!NT_STATUS_IS_OK( - check_negative_conn_cache(domain, server))) + status = check_negative_conn_cache(domain, server); + if (!NT_STATUS_IS_OK(status)) { continue; + } - /* Returns ok only if it matches the correct server type */ - ok = ads_try_connect(ads, false, &sa_list[i].u.ss); + ret = tsocket_address_inet_from_strings(ts_list, "ip", + server, LDAP_PORT, + &ts_list[num_requests]); + if (ret != 0) { + status = map_nt_error_from_unix(errno); + DBG_WARNING("Failed to create tsocket_address for %s - %s\n", + server, nt_errstr(status)); + TALLOC_FREE(frame); + return status; + } + + req_sa_list[num_requests] = &sa_list[i]; + num_requests += 1; + } + if (num_requests == 0) { + status = NT_STATUS_NO_LOGON_SERVERS; + DBG_WARNING("domain[%s] num_requests[%zu] for count[%zu] - %s\n", + domain, num_requests, count, nt_errstr(status)); + TALLOC_FREE(frame); + return status; + } + + ts_list_const = (const struct tsocket_address * const *)ts_list; + + status = cldap_multi_netlogon(frame, + ts_list_const, num_requests, + ads->server.realm, NULL, + nt_version, + 1, endtime, &responses); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("cldap_multi_netlogon(realm=%s, num_requests=%zu) " + "for count[%zu] - %s\n", + ads->server.realm, + num_requests, count, + nt_errstr(status)); + TALLOC_FREE(frame); + return NT_STATUS_NO_LOGON_SERVERS; + } + + for (i = 0; i < num_requests; i++) { + struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply = NULL; + char server[INET6_ADDRSTRLEN]; + + if (responses[i] == NULL) { + 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); + continue; + } + + cldap_reply = &responses[i]->data.nt5_ex; + + /* Returns ok only if it matches the correct server type */ + ok = ads_fill_cldap_reply(ads, + false, + &req_sa_list[i]->u.ss, + cldap_reply); if (ok) { + DBG_DEBUG("realm[%s]: selected %s => %s\n", + ads->server.realm, + server, cldap_reply->pdc_dns_name); + if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) { + NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX, + cldap_reply); + } + TALLOC_FREE(frame); return NT_STATUS_OK; } - /* keep track of failures */ + DBG_NOTICE("realm[%s] server %s %s - not usable\n", + ads->server.realm, + server, cldap_reply->pdc_dns_name); + if (CHECK_DEBUGLVL(DBGLVL_NOTICE)) { + NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX, + cldap_reply); + } + add_failed_connection_entry(domain, server, + NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID); + retry = true; + } + + if (retry) { + bool expired; + + expired = timeval_expired(&endtime); + if (!expired) { + goto 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", + ads->server.realm, + num_requests, count, nt_errstr(status)); + TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } -- Samba Shared Repository