From: Jeremy Allison Date: Tue, 21 Jul 2020 02:50:04 +0000 (-0700) Subject: s3: libsmb: Rewrite resolve_ads() to use the previously added dns_lookup_list() function. X-Git-Tag: talloc-2.3.2~944 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d53ade5beb5d793066c3b57b715da2e8692ecb9f;p=thirdparty%2Fsamba.git s3: libsmb: Rewrite resolve_ads() to use the previously added dns_lookup_list() function. Clean up internals - a LOT. This one needs careful review. Ditch the (unused) port returns from the SRV replies. Internally uses talloc'ed arrays of struct sockaddr_storage which it then convert to MALLOC'ed struct ip_service. Still returns struct ip_service but this will be fixed in the next commit. Signed-off-by: Jeremy Allison Reviewed-by: Isaac Boukris --- diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index feef0c74395..92638b86090 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -2280,7 +2280,6 @@ fail: return status; } -#if 0 /******************************************************** Resolve a list of DNS names to a list of IP addresses. As this is a DC / LDAP / KDC lookup any IP address will @@ -2360,7 +2359,6 @@ static NTSTATUS dns_lookup_list(TALLOC_CTX *ctx, *pp_addrs = ret_addrs; return NT_STATUS_OK; } -#endif /******************************************************** Resolve via "hosts" method. @@ -2469,6 +2467,14 @@ static NTSTATUS resolve_ads(TALLOC_CTX *ctx, struct dns_rr_srv *dcs = NULL; int numdcs = 0; int numaddrs = 0; + size_t num_srv_addrs = 0; + struct sockaddr_storage *srv_addrs = NULL; + size_t num_dns_addrs = 0; + struct sockaddr_storage *dns_addrs = NULL; + size_t num_dns_names = 0; + const char **dns_lookup_names = NULL; + struct ip_service *iplist = NULL; + if ((name_type != 0x1c) && (name_type != KDC_NAME_TYPE) && (name_type != 0x1b)) { @@ -2508,107 +2514,197 @@ static NTSTATUS resolve_ads(TALLOC_CTX *ctx, break; } - if ( !NT_STATUS_IS_OK( status ) ) { + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(dcs); return status; } if (numdcs == 0) { *return_iplist = NULL; *return_count = 0; + TALLOC_FREE(dcs); return NT_STATUS_OK; } - for (i=0;i IP address. This is dns_addrs. + * + * Finally we will merge these two arrays to create the + * return ip_service array. + */ + + /* First count the sizes of each array. */ + for(i = 0; i < numdcs; i++) { + if (dcs[i].ss_s != NULL) { + /* IP address returned in SRV record. */ + if (num_srv_addrs + dcs[i].num_ips < num_srv_addrs) { + /* Wrap check. */ + TALLOC_FREE(dcs); + return NT_STATUS_INVALID_PARAMETER; + } + /* Add in the number of addresses we got. */ + num_srv_addrs += dcs[i].num_ips; + /* + * If we got any IP addresses zero out + * the hostname so we know we've already + * processed this entry and won't add it + * to the dns_lookup_names array we use + * to do DNS queries below. + */ + dcs[i].hostname = NULL; } else { - numaddrs += dcs[i].num_ips; + /* Ensure we have a hostname to lookup. */ + if (dcs[i].hostname == NULL) { + continue; + } + /* No IP address returned in SRV record. */ + if (num_dns_names + 1 < num_dns_names) { + /* Wrap check. */ + TALLOC_FREE(dcs); + return NT_STATUS_INVALID_PARAMETER; + } + /* One more name to lookup. */ + num_dns_names += 1; } - } + } - if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) == - NULL ) { - DEBUG(0,("resolve_ads: malloc failed for %d entries\n", - numaddrs )); + /* Allocate the list of IP addresses we already have. */ + srv_addrs = talloc_zero_array(ctx, + struct sockaddr_storage, + num_srv_addrs); + if (srv_addrs == NULL) { + TALLOC_FREE(dcs); return NT_STATUS_NO_MEMORY; } - /* now unroll the list of IP addresses */ - - *return_count = 0; + /* Copy the addresses we already have. */ + num_srv_addrs = 0; + for(i = 0; i < numdcs; i++) { + /* Copy all the IP addresses from the SRV response */ + size_t j; + for (j = 0; j < dcs[i].num_ips; j++) { + char addr[INET6_ADDRSTRLEN]; - for (i = 0; i < numdcs && (*return_countai_next) { - struct sockaddr_storage ss; - memcpy(&ss, p->ai_addr, p->ai_addrlen); - if (is_zero_addr(&ss)) { - continue; - } - extra_addrs++; - } - if (extra_addrs > 1) { - /* We need to expand the return_iplist array - as we only budgeted for one address. */ - numaddrs += (extra_addrs-1); - *return_iplist = SMB_REALLOC_ARRAY(*return_iplist, - struct ip_service, - numaddrs); - if (*return_iplist == NULL) { - if (res) { - freeaddrinfo(res); - } - return NT_STATUS_NO_MEMORY; - } - } - for (p = res; p; p = p->ai_next) { - (*return_iplist)[*return_count].port = dcs[i].port; - memcpy(&(*return_iplist)[*return_count].ss, - p->ai_addr, - p->ai_addrlen); - if (is_zero_addr(&(*return_iplist)[*return_count].ss)) { - continue; - } - (*return_count)++; - /* Should never happen, but still... */ - if (*return_count>=numaddrs) { - break; - } - } - if (res) { - freeaddrinfo(res); - } - } else { - /* use all the IP addresses from the SRV response */ - size_t j; - for (j = 0; j < dcs[i].num_ips; j++) { - (*return_iplist)[*return_count].port = dcs[i].port; - (*return_iplist)[*return_count].ss = dcs[i].ss_s[j]; - if (is_zero_addr(&(*return_iplist)[*return_count].ss)) { - continue; - } - (*return_count)++; - /* Should never happen, but still... */ - if (*return_count>=numaddrs) { - break; - } - } + + DBG_DEBUG("SRV lookup %s got IP[%zu] %s\n", + name, + j, + print_sockaddr(addr, + sizeof(addr), + &srv_addrs[num_srv_addrs])); + + num_srv_addrs++; } } + /* Allocate the array of hostnames we must look up. */ + dns_lookup_names = talloc_zero_array(ctx, + const char *, + num_dns_names); + if (dns_lookup_names == NULL) { + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + return NT_STATUS_NO_MEMORY; + } + + num_dns_names = 0; + for(i = 0; i < numdcs; i++) { + if (dcs[i].hostname == NULL) { + /* + * Must have been a SRV return with an IP address. + * We don't need to look up this hostname. + */ + continue; + } + dns_lookup_names[num_dns_names] = dcs[i].hostname; + num_dns_names++; + } + + /* Lookup the addresses on the dns_lookup_list. */ + status = dns_lookup_list(ctx, + num_dns_names, + dns_lookup_names, + &num_dns_addrs, + &dns_addrs); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + TALLOC_FREE(dns_lookup_names); + return status; + } + + /* + * Combine the two sockaddr_storage arrays into a MALLOC'ed + * ipservice array return. + */ + + numaddrs = num_srv_addrs + num_dns_addrs; + /* Wrap check + bloody int conversion check :-(. */ + if (numaddrs < num_srv_addrs || + numaddrs < 0) { + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + TALLOC_FREE(dns_addrs); + TALLOC_FREE(dns_lookup_names); + return NT_STATUS_INVALID_PARAMETER; + } + + if (numaddrs == 0) { + /* Keep the same semantics for zero names. */ + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + TALLOC_FREE(dns_addrs); + TALLOC_FREE(dns_lookup_names); + *return_iplist = NULL; + *return_count = 0; + return NT_STATUS_OK; + } + + iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs); + if (iplist == NULL) { + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + TALLOC_FREE(dns_addrs); + TALLOC_FREE(dns_lookup_names); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_srv_addrs; i++) { + iplist[i].ss = srv_addrs[i]; + iplist[i].port = 0; + } + for (i = 0; i < num_dns_addrs; i++) { + iplist[num_srv_addrs+i].ss = dns_addrs[i]; + iplist[i].port = 0; + } + + TALLOC_FREE(dcs); + TALLOC_FREE(srv_addrs); + TALLOC_FREE(dns_addrs); + TALLOC_FREE(dns_lookup_names); + + *return_iplist = iplist; + *return_count = numaddrs; return NT_STATUS_OK; }