Fix the loop unrolling inside resolve_ads(). If we don't get an IP list don't use...
authorJeremy Allison <jra@samba.org>
Mon, 30 Apr 2012 18:05:51 +0000 (11:05 -0700)
committerKarolin Seeger <kseeger@samba.org>
Sat, 26 May 2012 20:16:01 +0000 (22:16 +0200)
Autobuild-User: Jeremy Allison <jra@samba.org>
Autobuild-Date: Mon Apr 30 23:21:16 CEST 2012 on sn-devel-104
(cherry picked from commit 1270cfb45ffa0bbcacf7254b5b45f492a8dcde77)

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

source3/libsmb/namequery.c

index 9ba8aac43ffac169ebf178d71bf7451637390b20..d0ab62fbbebcc9a0ae921f74151d633cf60e5dde 100644 (file)
@@ -1866,7 +1866,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;
@@ -1915,8 +1915,12 @@ 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)) ==
                        NULL ) {
@@ -1929,42 +1933,77 @@ 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;
 
+       while ( i < numdcs && (*return_count<numaddrs) ) {
                /* If we don't have an IP list for a name, lookup 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(&r->ss)) {
-                       (*return_count)++;
+                       /* Add in every IP from the lookup. How
+                          many is that ? */
+                       for (p = res; p; p = p->ai_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);
+                                       }
+                                       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(&(*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(&(*return_iplist)[*return_count].ss)) {
+                                       continue;
+                               }
+                                (*return_count)++;
+                               /* Should never happen, but still... */
+                               if (*return_count>=numaddrs) {
+                                       break;
+                               }
+                       }
                }
        }