Fix the loop unrolling inside resolve_ads().
authorJeremy Allison <jra@samba.org>
Mon, 30 Apr 2012 23:32:51 +0000 (16:32 -0700)
committerKarolin Seeger <kseeger@samba.org>
Sat, 30 Jun 2012 11:43:52 +0000 (13:43 +0200)
If we don't get an IP list don't use interpret_string_addr(), as this only returns one address, use interpret_string_addr_internal() instead.

The last 4 patches address bug #8910 (resolve_ads() code can return zero
addresses and miss valid DC IP addresses).
(cherry picked from commit b9d3f8258396873d6ec8b6ea9ad066e2f1f8e973)

source3/libsmb/namequery.c

index 671cb76caad8f46e918f5e8f90af7a6760fa1b51..af76f3f85db08c63cff2e3e13400ae0839ad9339 100644 (file)
@@ -1287,7 +1287,7 @@ static NTSTATUS resolve_ads(const char *name,
                            struct ip_service **return_iplist,
                            int *return_count)
 {
-       int                     i, j;
+       int                     i;
        NTSTATUS                status;
        TALLOC_CTX              *ctx;
        struct dns_rr_srv       *dcs = NULL;
@@ -1336,7 +1336,11 @@ static NTSTATUS resolve_ads(const char *name,
        }
 
        for (i=0;i<numdcs;i++) {
-               numaddrs += MAX(dcs[i].num_ips,1);
+               if (!dcs[i].ss_s) {
+                       numaddrs += 1;
+               } else {
+                       numaddrs += dcs[i].num_ips;
+               }
        }
 
        if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) ==
@@ -1350,42 +1354,75 @@ static NTSTATUS resolve_ads(const char *name,
        /* now unroll the list of IP addresses */
 
        *return_count = 0;
-       i = 0;
-       j = 0;
-       while ( i < numdcs && (*return_count<numaddrs) ) {
-               struct ip_service *r = &(*return_iplist)[*return_count];
-
-               r->port = dcs[i].port;
-
-               /* If we don't have an IP list for a name, lookup it up */
 
+       for (i = 0; i < numdcs; i++) {
+               /* If we don't have an IP list for a name, look it up */
                if (!dcs[i].ss_s) {
-                       interpret_string_addr(&r->ss, dcs[i].hostname, 0);
-                       i++;
-                       j = 0;
-               } else {
-                       /* use the IP addresses from the SRV sresponse */
-
-                       if ( j >= dcs[i].num_ips ) {
-                               i++;
-                               j = 0;
+                       /* We need to get all IP addresses here. */
+                       struct addrinfo *res = NULL;
+                       struct addrinfo *p;
+                       int extra_addrs = 0;
+
+                       if (!interpret_string_addr_internal(&res,
+                                               dcs[i].hostname,
+                                               0)) {
                                continue;
                        }
-
-                       r->ss = dcs[i].ss_s[j];
-                       j++;
-               }
-
-               /* make sure it is a valid IP.  I considered checking the
-                * negative connection cache, but this is the wrong place
-                * for it. Maybe only as a hack. After think about it, if
-                * all of the IP addresses returned from DNS are dead, what
-                * hope does a netbios name lookup have ? The standard reason
-                * for falling back to netbios lookups is that our DNS server
-                * doesn't know anything about the DC's   -- jerry */
-
-               if (!is_zero_addr((struct sockaddr *)&r->ss)) {
-                       (*return_count)++;
+                       /* Add in every IP from the lookup. How
+                          many is that ? */
+                       for (p = res; p; p = p->ai_next) {
+                               if (is_zero_addr((struct sockaddr *)p->ai_addr)) {
+                                       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);
+                                       }
+                                       talloc_destroy(ctx);
+                                       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((struct sockaddr *)&(*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 sresponse */
+                       int 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((struct sockaddr *)&(*return_iplist)[*return_count].ss)) {
+                                       continue;
+                               }
+                               (*return_count)++;
+                               /* Should never happen, but still... */
+                               if (*return_count>=numaddrs) {
+                                       break;
+                               }
+                       }
                }
        }