Protect all of the name resolution methods from returning null addrs. Ensure all...
[samba.git] / source3 / libsmb / namequery.c
index ad16452e3e650d90edf1411bf11fb12a7be14712..671cb76caad8f46e918f5e8f90af7a6760fa1b51 100644 (file)
@@ -34,6 +34,8 @@ bool global_in_nmbd = False;
 ****************************************************************************/
 #define SAFKEY_FMT     "SAF/DOMAIN/%s"
 #define SAF_TTL                900
+#define SAFJOINKEY_FMT "SAFJOIN/DOMAIN/%s"
+#define SAFJOIN_TTL    3600
 
 static char *saf_key(const char *domain)
 {
@@ -44,6 +46,15 @@ static char *saf_key(const char *domain)
        return keystr;
 }
 
+static char *saf_join_key(const char *domain)
+{
+       char *keystr;
+
+       asprintf_strupper_m(&keystr, SAFJOINKEY_FMT, domain);
+
+       return keystr;
+}
+
 /****************************************************************************
 ****************************************************************************/
 
@@ -65,11 +76,8 @@ bool saf_store( const char *domain, const char *servername )
                return False;
        }
 
-       if ( !gencache_init() )
-               return False;
-
        key = saf_key( domain );
-       expire = time( NULL ) + SAF_TTL;
+       expire = time( NULL ) + lp_parm_int(-1, "saf","ttl", SAF_TTL);
 
        DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%u]\n",
                domain, servername, (unsigned int)expire ));
@@ -81,6 +89,35 @@ bool saf_store( const char *domain, const char *servername )
        return ret;
 }
 
+bool saf_join_store( const char *domain, const char *servername )
+{
+       char *key;
+       time_t expire;
+       bool ret = False;
+
+       if ( !domain || !servername ) {
+               DEBUG(2,("saf_join_store: Refusing to store empty domain or servername!\n"));
+               return False;
+       }
+
+       if ( (strlen(domain) == 0) || (strlen(servername) == 0) ) {
+               DEBUG(0,("saf_join_store: refusing to store 0 length domain or servername!\n"));
+               return False;
+       }
+
+       key = saf_join_key( domain );
+       expire = time( NULL ) + lp_parm_int(-1, "saf","join ttl", SAFJOIN_TTL);
+
+       DEBUG(10,("saf_join_store: domain = [%s], server = [%s], expire = [%u]\n",
+               domain, servername, (unsigned int)expire ));
+
+       ret = gencache_set( key, servername, expire );
+
+       SAFE_FREE( key );
+
+       return ret;
+}
+
 bool saf_delete( const char *domain )
 {
        char *key;
@@ -91,18 +128,22 @@ bool saf_delete( const char *domain )
                return False;
        }
 
-       if ( !gencache_init() )
-               return False;
+       key = saf_join_key(domain);
+       ret = gencache_del(key);
+       SAFE_FREE(key);
+
+       if (ret) {
+               DEBUG(10,("saf_delete[join]: domain = [%s]\n", domain ));
+       }
 
        key = saf_key(domain);
        ret = gencache_del(key);
+       SAFE_FREE(key);
 
        if (ret) {
                DEBUG(10,("saf_delete: domain = [%s]\n", domain ));
        }
 
-       SAFE_FREE( key );
-
        return ret;
 }
 
@@ -121,8 +162,17 @@ char *saf_fetch( const char *domain )
                return NULL;
        }
 
-       if ( !gencache_init() )
-               return False;
+       key = saf_join_key( domain );
+
+       ret = gencache_get( key, &server, &timeout );
+
+       SAFE_FREE( key );
+
+       if ( ret ) {
+               DEBUG(5,("saf_fetch[join]: Returning \"%s\" for \"%s\" domain\n",
+                       server, domain ));
+               return server;
+       }
 
        key = saf_key( domain );
 
@@ -239,7 +289,8 @@ NODE_STATUS_STRUCT *node_status_query(int fd,
 
        p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
        p.port = NMB_PORT;
-       p.fd = fd;
+       p.recv_fd = -1;
+       p.send_fd = fd;
        p.timestamp = time(NULL);
        p.packet_type = NMB_PACKET;
 
@@ -331,7 +382,7 @@ bool name_status_find(const char *q_name,
 
        if (!interpret_string_addr(&ss, lp_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
-               zero_addr(&ss);
+               zero_sockaddr(&ss);
        }
 
        sock = open_socket_in(SOCK_DGRAM, 0, 3, &ss, True);
@@ -346,7 +397,8 @@ bool name_status_find(const char *q_name,
                goto done;
 
        for (i=0;i<count;i++) {
-               if (status[i].type == type)
+                /* Find first one of the requested type that's not a GROUP. */
+               if (status[i].type == type && ! (status[i].flags & 0x80))
                        break;
        }
        if (i == count)
@@ -381,19 +433,19 @@ bool name_status_find(const char *q_name,
   comparison function used by sort_addr_list
 */
 
-static int addr_compare(const struct sockaddr_storage *ss1,
-               const struct sockaddr_storage *ss2)
+static int addr_compare(const struct sockaddr *ss1,
+               const struct sockaddr *ss2)
 {
        int max_bits1=0, max_bits2=0;
        int num_interfaces = iface_count();
        int i;
 
-       /* Sort IPv6 addresses first. */
-       if (ss1->ss_family != ss2->ss_family) {
-               if (ss2->ss_family == AF_INET) {
-                       return -1;
-               } else {
+       /* Sort IPv4 addresses first. */
+       if (ss1->sa_family != ss2->sa_family) {
+               if (ss2->sa_family == AF_INET) {
                        return 1;
+               } else {
+                       return -1;
                }
        }
 
@@ -408,7 +460,7 @@ static int addr_compare(const struct sockaddr_storage *ss1,
                size_t len = 0;
                int bits1, bits2;
 
-               if (pss->ss_family != ss1->ss_family) {
+               if (pss->ss_family != ss1->sa_family) {
                        /* Ignore interfaces of the wrong type. */
                        continue;
                }
@@ -443,14 +495,14 @@ static int addr_compare(const struct sockaddr_storage *ss1,
 
        /* Bias towards directly reachable IPs */
        if (iface_local(ss1)) {
-               if (ss1->ss_family == AF_INET) {
+               if (ss1->sa_family == AF_INET) {
                        max_bits1 += 32;
                } else {
                        max_bits1 += 128;
                }
        }
        if (iface_local(ss2)) {
-               if (ss2->ss_family == AF_INET) {
+               if (ss2->sa_family == AF_INET) {
                        max_bits2 += 32;
                } else {
                        max_bits2 += 128;
@@ -467,7 +519,7 @@ int ip_service_compare(struct ip_service *ss1, struct ip_service *ss2)
 {
        int result;
 
-       if ((result = addr_compare(&ss1->ss, &ss2->ss)) != 0) {
+       if ((result = addr_compare((struct sockaddr *)&ss1->ss, (struct sockaddr *)&ss2->ss)) != 0) {
                return result;
        }
 
@@ -519,37 +571,68 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
        DEBUG(10,("remove_duplicate_addrs2: "
                        "looking for duplicate address/port pairs\n"));
 
-       /* one loop to remove duplicates */
+       /* One loop to set duplicates to a zero addr. */
        for ( i=0; i<count; i++ ) {
-               if ( is_zero_addr(&iplist[i].ss)) {
+               if ( is_zero_addr((struct sockaddr *)&iplist[i].ss)) {
                        continue;
                }
 
                for ( j=i+1; j<count; j++ ) {
-                       if (addr_equal(&iplist[i].ss, &iplist[j].ss) &&
+                       if (sockaddr_equal((struct sockaddr *)&iplist[i].ss, (struct sockaddr *)&iplist[j].ss) &&
                                        iplist[i].port == iplist[j].port) {
-                               zero_addr(&iplist[j].ss);
+                               zero_sockaddr(&iplist[j].ss);
                        }
                }
        }
 
-       /* one loop to clean up any holes we left */
-       /* first ip should never be a zero_ip() */
-       for (i = 0; i<count; ) {
-               if (is_zero_addr(&iplist[i].ss) ) {
-                       if (i != count-1) {
-                               memmove(&iplist[i], &iplist[i+1],
-                                       (count - i - 1)*sizeof(iplist[i]));
+       /* Now remove any addresses set to zero above. */
+       for (i = 0; i < count; i++) {
+               while (i < count &&
+                               is_zero_addr((struct sockaddr *)&iplist[i].ss)) {
+                       if (count-i-1>0) {
+                               memmove(&iplist[i],
+                                       &iplist[i+1],
+                                       (count-i-1)*sizeof(struct ip_service));
                        }
                        count--;
-                       continue;
                }
-               i++;
        }
 
        return count;
 }
 
+static bool prioritize_ipv4_list(struct ip_service *iplist, int count)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct ip_service *iplist_new = TALLOC_ARRAY(frame, struct ip_service, count);
+       int i, j;
+
+       if (iplist_new == NULL) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       j = 0;
+
+       /* Copy IPv4 first. */
+       for (i = 0; i < count; i++) {
+               if (iplist[i].ss.ss_family == AF_INET) {
+                       iplist_new[j++] = iplist[i];
+               }
+       }
+
+       /* Copy IPv6. */
+       for (i = 0; i < count; i++) {
+               if (iplist[i].ss.ss_family != AF_INET) {
+                       iplist_new[j++] = iplist[i];
+               }
+       }
+
+       memcpy(iplist, iplist_new, sizeof(struct ip_service)*count);
+       TALLOC_FREE(frame);
+       return true;
+}
+
 /****************************************************************************
  Do a netbios name query to find someones IP.
  Returns an array of IP addresses or NULL if none.
@@ -615,7 +698,8 @@ struct sockaddr_storage *name_query(int fd,
 
        p.ip = ((struct sockaddr_in *)to_ss)->sin_addr;
        p.port = NMB_PORT;
-       p.fd = fd;
+       p.recv_fd = -1;
+       p.send_fd = fd;
        p.timestamp = time(NULL);
        p.packet_type = NMB_PACKET;
 
@@ -764,160 +848,53 @@ struct sockaddr_storage *name_query(int fd,
 }
 
 /********************************************************
- Start parsing the lmhosts file.
-*********************************************************/
-
-XFILE *startlmhosts(const char *fname)
-{
-       XFILE *fp = x_fopen(fname,O_RDONLY, 0);
-       if (!fp) {
-               DEBUG(4,("startlmhosts: Can't open lmhosts file %s. "
-                       "Error was %s\n",
-                       fname, strerror(errno)));
-               return NULL;
-       }
-       return fp;
-}
-
-/********************************************************
- Parse the next line in the lmhosts file.
-*********************************************************/
-
-bool getlmhostsent(TALLOC_CTX *ctx, XFILE *fp, char **pp_name, int *name_type,
-               struct sockaddr_storage *pss)
-{
-       char line[1024];
-
-       *pp_name = NULL;
-
-       while(!x_feof(fp) && !x_ferror(fp)) {
-               char *ip = NULL;
-               char *flags = NULL;
-               char *extra = NULL;
-               char *name = NULL;
-               const char *ptr;
-               char *ptr1 = NULL;
-               int count = 0;
-
-               *name_type = -1;
-
-               if (!fgets_slash(line,sizeof(line),fp)) {
-                       continue;
-               }
-
-               if (*line == '#') {
-                       continue;
-               }
-
-               ptr = line;
-
-               if (next_token_talloc(ctx, &ptr, &ip, NULL))
-                       ++count;
-               if (next_token_talloc(ctx, &ptr, &name, NULL))
-                       ++count;
-               if (next_token_talloc(ctx, &ptr, &flags, NULL))
-                       ++count;
-               if (next_token_talloc(ctx, &ptr, &extra, NULL))
-                       ++count;
-
-               if (count <= 0)
-                       continue;
-
-               if (count > 0 && count < 2) {
-                       DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",
-                                               line));
-                       continue;
-               }
-
-               if (count >= 4) {
-                       DEBUG(0,("getlmhostsent: too many columns "
-                               "in lmhosts file (obsolete syntax)\n"));
-                       continue;
-               }
-
-               if (!flags) {
-                       flags = talloc_strdup(ctx, "");
-                       if (!flags) {
-                               continue;
-                       }
-               }
-
-               DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n",
-                                       ip, name, flags));
-
-               if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
-                       DEBUG(0,("getlmhostsent: group flag "
-                               "in lmhosts ignored (obsolete)\n"));
-                       continue;
-               }
-
-               if (!interpret_string_addr(pss, ip, AI_NUMERICHOST)) {
-                       DEBUG(0,("getlmhostsent: invalid address "
-                               "%s.\n", ip));
-               }
-
-               /* Extra feature. If the name ends in '#XX',
-                * where XX is a hex number, then only add that name type. */
-               if((ptr1 = strchr_m(name, '#')) != NULL) {
-                       char *endptr;
-                       ptr1++;
-
-                       *name_type = (int)strtol(ptr1, &endptr, 16);
-                       if(!*ptr1 || (endptr == ptr1)) {
-                               DEBUG(0,("getlmhostsent: invalid name "
-                                       "%s containing '#'.\n", name));
-                               continue;
-                       }
-
-                       *(--ptr1) = '\0'; /* Truncate at the '#' */
-               }
-
-               *pp_name = talloc_strdup(ctx, name);
-               if (!*pp_name) {
-                       return false;
-               }
-               return true;
-       }
-
-       return false;
-}
-
-/********************************************************
- Finish parsing the lmhosts file.
-*********************************************************/
-
-void endlmhosts(XFILE *fp)
-{
-       x_fclose(fp);
-}
-
-/********************************************************
- convert an array if struct sockaddr_storage to struct ip_service
+ Convert an array if struct sockaddr_storage to struct ip_service
  return false on failure.  Port is set to PORT_NONE;
+ pcount is [in/out] - it is the length of ss_list on input,
+ and the length of return_iplist on output as we remove any
+ zero addresses from ss_list.
 *********************************************************/
 
 static bool convert_ss2service(struct ip_service **return_iplist,
                const struct sockaddr_storage *ss_list,
-               int count)
+               int *pcount)
 {
        int i;
+       int orig_count = *pcount;
+       int real_count = 0;
 
-       if ( count==0 || !ss_list )
+       if (orig_count==0 || !ss_list )
                return False;
 
+       /* Filter out zero addrs. */
+       for ( i=0; i<orig_count; i++ ) {
+               if (is_zero_addr((struct sockaddr *)&ss_list[i])) {
+                       continue;
+               }
+               real_count++;
+       }
+       if (real_count==0) {
+               return false;
+       }
+
        /* copy the ip address; port will be PORT_NONE */
-       if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) ==
+       if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, real_count)) ==
                        NULL) {
                DEBUG(0,("convert_ip2service: malloc failed "
-                       "for %d enetries!\n", count ));
+                       "for %d enetries!\n", real_count ));
                return False;
        }
 
-       for ( i=0; i<count; i++ ) {
-               (*return_iplist)[i].ss   = ss_list[i];
-               (*return_iplist)[i].port = PORT_NONE;
+       for ( i=0, real_count = 0; i<orig_count; i++ ) {
+               if (is_zero_addr((struct sockaddr *)&ss_list[i])) {
+                       continue;
+               }
+               (*return_iplist)[real_count].ss   = ss_list[i];
+               (*return_iplist)[real_count].port = PORT_NONE;
+               real_count++;
        }
 
+       *pcount = real_count;
        return true;
 }
 
@@ -954,7 +931,7 @@ NTSTATUS name_resolve_bcast(const char *name,
 
        if (!interpret_string_addr(&ss, lp_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
-               zero_addr(&ss);
+               zero_sockaddr(&ss);
        }
 
        sock = open_socket_in( SOCK_DGRAM, 0, 3, &ss, true );
@@ -990,7 +967,7 @@ NTSTATUS name_resolve_bcast(const char *name,
 success:
 
        status = NT_STATUS_OK;
-       if (!convert_ss2service(return_iplist, ss_list, *return_count) )
+       if (!convert_ss2service(return_iplist, ss_list, return_count) )
                status = NT_STATUS_INVALID_PARAMETER;
 
        SAFE_FREE(ss_list);
@@ -1042,7 +1019,7 @@ NTSTATUS resolve_wins(const char *name,
        /* the address we will be sending from */
        if (!interpret_string_addr(&src_ss, lp_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
-               zero_addr(&src_ss);
+               zero_sockaddr(&src_ss);
        }
 
        if (src_ss.ss_family != AF_INET) {
@@ -1051,6 +1028,7 @@ NTSTATUS resolve_wins(const char *name,
                DEBUG(3,("resolve_wins: cannot receive WINS replies "
                        "on IPv6 address %s\n",
                        addr));
+               wins_srv_tags_free(wins_tags);
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1124,7 +1102,7 @@ NTSTATUS resolve_wins(const char *name,
 success:
 
        status = NT_STATUS_OK;
-       if (!convert_ss2service(return_iplist, ss_list, *return_count))
+       if (!convert_ss2service(return_iplist, ss_list, return_count))
                status = NT_STATUS_INVALID_PARAMETER;
 
        SAFE_FREE(ss_list);
@@ -1269,9 +1247,13 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
                        continue;
                }
 
-               memset(&ss, '\0', sizeof(ss));
+               ZERO_STRUCT(ss);
                memcpy(&ss, res->ai_addr, res->ai_addrlen);
 
+               if (is_zero_addr((struct sockaddr *)&ss)) {
+                       continue;
+               }
+
                *return_count += 1;
 
                *return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
@@ -1402,7 +1384,7 @@ static NTSTATUS resolve_ads(const char *name,
                 * 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)) {
+               if (!is_zero_addr((struct sockaddr *)&r->ss)) {
                        (*return_count)++;
                }
        }
@@ -1422,8 +1404,8 @@ static NTSTATUS resolve_ads(const char *name,
  resolve_hosts() when looking up DC's via SRV RR entries in DNS
 **********************************************************************/
 
-static NTSTATUS internal_resolve_name(const char *name,
-                               int name_type,
+NTSTATUS internal_resolve_name(const char *name,
+                               int name_type,
                                const char *sitename,
                                struct ip_service **return_iplist,
                                int *return_count,
@@ -1439,7 +1421,7 @@ static NTSTATUS internal_resolve_name(const char *name,
        *return_count = 0;
 
        DEBUG(10, ("internal_resolve_name: looking up %s#%x (sitename %s)\n",
-                       name, name_type, sitename ? sitename : NULL));
+                       name, name_type, sitename ? sitename : "(null)"));
 
        if (is_ipaddress(name)) {
                if ((*return_iplist = SMB_MALLOC_P(struct ip_service)) ==
@@ -1460,6 +1442,10 @@ static NTSTATUS internal_resolve_name(const char *name,
                        SAFE_FREE(*return_iplist);
                        return NT_STATUS_INVALID_PARAMETER;
                }
+               if (is_zero_addr((struct sockaddr *)&(*return_iplist)->ss)) {
+                       SAFE_FREE(*return_iplist);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
                *return_count = 1;
                return NT_STATUS_OK;
        }
@@ -1467,6 +1453,8 @@ static NTSTATUS internal_resolve_name(const char *name,
        /* Check name cache */
 
        if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+               *return_count = remove_duplicate_addrs2(*return_iplist,
+                                       *return_count );
                /* This could be a negative response */
                if (*return_count > 0) {
                        return NT_STATUS_OK;
@@ -1561,10 +1549,7 @@ static NTSTATUS internal_resolve_name(const char *name,
        controllers including the PDC in iplist[1..n].  Iterating over
        the iplist when the PDC is down will cause two sets of timeouts. */
 
-       if ( *return_count ) {
-               *return_count = remove_duplicate_addrs2(*return_iplist,
-                                       *return_count );
-       }
+       *return_count = remove_duplicate_addrs2(*return_iplist, *return_count );
 
        /* Save in name cache */
        if ( DEBUGLEVEL >= 100 ) {
@@ -1580,7 +1565,9 @@ static NTSTATUS internal_resolve_name(const char *name,
                }
        }
 
-       namecache_store(name, name_type, *return_count, *return_iplist);
+       if (*return_count) {
+               namecache_store(name, name_type, *return_count, *return_iplist);
+       }
 
        /* Display some debugging info */
 
@@ -1612,7 +1599,8 @@ static NTSTATUS internal_resolve_name(const char *name,
 
 bool resolve_name(const char *name,
                struct sockaddr_storage *return_ss,
-               int name_type)
+               int name_type,
+               bool prefer_ipv4)
 {
        struct ip_service *ss_list = NULL;
        char *sitename = NULL;
@@ -1629,10 +1617,23 @@ bool resolve_name(const char *name,
                                                  lp_name_resolve_order()))) {
                int i;
 
+               if (prefer_ipv4) {
+                       for (i=0; i<count; i++) {
+                               if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                               !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                               (ss_list[i].ss.ss_family == AF_INET)) {
+                                       *return_ss = ss_list[i].ss;
+                                       SAFE_FREE(ss_list);
+                                       SAFE_FREE(sitename);
+                                       return True;
+                               }
+                       }
+               }
+
                /* only return valid addresses for TCP connections */
                for (i=0; i<count; i++) {
-                       if (!is_zero_addr(&ss_list[i].ss) &&
-                                       !is_broadcast_addr(&ss_list[i].ss)) {
+                       if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                       !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss)) {
                                *return_ss = ss_list[i].ss;
                                SAFE_FREE(ss_list);
                                SAFE_FREE(sitename);
@@ -1695,8 +1696,8 @@ NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
 
        /* only return valid addresses for TCP connections */
        for (i=0, num_entries = 0; i<count; i++) {
-               if (!is_zero_addr(&ss_list[i].ss) &&
-                               !is_broadcast_addr(&ss_list[i].ss)) {
+               if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
+                               !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss)) {
                        num_entries++;
                }
        }
@@ -1714,8 +1715,8 @@ NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
        }
 
        for (i=0, num_entries = 0; i<count; i++) {
-               if (!is_zero_addr(&ss_list[i].ss) &&
-                               !is_broadcast_addr(&ss_list[i].ss)) {
+               if (!is_zero_addr((struct sockaddr *)&ss_list[i].ss) &&
+                               !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss)) {
                        (*return_ss_arr)[num_entries++] = ss_list[i].ss;
                }
        }
@@ -1834,6 +1835,9 @@ static NTSTATUS get_dc_list(const char *domain,
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_init("get_dc_list");
 
+       *ip_list = NULL;
+       *count = 0;
+
        if (!ctx) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1913,7 +1917,7 @@ static NTSTATUS get_dc_list(const char *domain,
 
        p = pserver;
        while (next_token_talloc(ctx, &p, &name, LIST_SEP)) {
-               if (strequal(name, "*")) {
+               if (!done_auto_lookup && strequal(name, "*")) {
                        status = internal_resolve_name(domain, 0x1C, sitename,
                                                       &auto_ip_list,
                                                       &auto_count,
@@ -2001,7 +2005,7 @@ static NTSTATUS get_dc_list(const char *domain,
 
                /* explicit lookup; resolve_name() will
                 * handle names & IP addresses */
-               if (resolve_name( name, &name_ss, 0x20 )) {
+               if (resolve_name( name, &name_ss, 0x20, true )) {
                        char addr[INET6_ADDRSTRLEN];
                        print_sockaddr(addr,
                                        sizeof(addr),
@@ -2026,9 +2030,13 @@ static NTSTATUS get_dc_list(const char *domain,
        /* need to remove duplicates in the list if we have any
           explicit password servers */
 
-       if (local_count) {
-               local_count = remove_duplicate_addrs2(return_iplist,
-                               local_count );
+       local_count = remove_duplicate_addrs2(return_iplist, local_count );
+
+       /* For DC's we always prioritize IPv4 due to W2K3 not
+        * supporting LDAP, KRB5 or CLDAP over IPv6. */
+
+       if (local_count && return_iplist) {
+               prioritize_ipv4_list(return_iplist, local_count);
        }
 
        if ( DEBUGLEVEL >= 4 ) {
@@ -2054,6 +2062,12 @@ static NTSTATUS get_dc_list(const char *domain,
 
   out:
 
+       if (!NT_STATUS_IS_OK(status)) {
+               SAFE_FREE(return_iplist);
+               *ip_list = NULL;
+               *count = 0;
+       }
+
        SAFE_FREE(auto_ip_list);
        TALLOC_FREE(ctx);
        return status;
@@ -2069,10 +2083,13 @@ NTSTATUS get_sorted_dc_list( const char *domain,
                        int *count,
                        bool ads_only )
 {
-       bool ordered;
+       bool ordered = false;
        NTSTATUS status;
        enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP;
 
+       *ip_list = NULL;
+       *count = 0;
+
        DEBUG(8,("get_sorted_dc_list: attempting lookup "
                "for name %s (sitename %s) using [%s]\n",
                domain,
@@ -2085,7 +2102,18 @@ NTSTATUS get_sorted_dc_list( const char *domain,
 
        status = get_dc_list(domain, sitename, ip_list,
                        count, lookup_type, &ordered);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_LOGON_SERVERS)
+           && sitename) {
+               DEBUG(3,("get_sorted_dc_list: no server for name %s available"
+                        " in site %s, fallback to all servers\n",
+                        domain, sitename));
+               status = get_dc_list(domain, NULL, ip_list,
+                                    count, lookup_type, &ordered);
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
+               SAFE_FREE(*ip_list);
+               *count = 0;
                return status;
        }
 
@@ -2116,6 +2144,8 @@ NTSTATUS get_kdc_list( const char *realm,
                        count, DC_KDC_ONLY, &ordered);
 
        if (!NT_STATUS_IS_OK(status)) {
+               SAFE_FREE(*ip_list);
+               *count = 0;
                return status;
        }