libsmb: Fix a "assuming signed overflow does not occur" error
[kai/samba-autobuild/.git] / source3 / libsmb / namequery.c
index f5f4a7c1dcb3eaed93d81000ebd38dfdb26afeb1..f61e2507cce1b385bbda02fd7c54c52411ba5be8 100644 (file)
 */
 
 #include "includes.h"
+#include "libsmb/namequery.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "libads/sitename_cache.h"
-#include "libads/dns.h"
+#include "../lib/addns/dnsquery.h"
 #include "../libcli/netlogon/netlogon.h"
 #include "lib/async_req/async_sock.h"
+#include "lib/tsocket/tsocket.h"
 #include "libsmb/nmblib.h"
+#include "libsmb/unexpected.h"
+#include "../libcli/nbt/libnbt.h"
+#include "libads/kerberos_proto.h"
+#include "lib/gencache.h"
 
 /* nmbd.c sets this to True. */
 bool global_in_nmbd = False;
@@ -43,22 +49,14 @@ bool global_in_nmbd = False;
 #define SAFJOINKEY_FMT "SAFJOIN/DOMAIN/%s"
 #define SAFJOIN_TTL    3600
 
-static char *saf_key(const char *domain)
+static char *saf_key(TALLOC_CTX *mem_ctx, const char *domain)
 {
-       char *keystr;
-
-       asprintf_strupper_m(&keystr, SAFKEY_FMT, domain);
-
-       return keystr;
+       return talloc_asprintf_strupper_m(mem_ctx, SAFKEY_FMT, domain);
 }
 
-static char *saf_join_key(const char *domain)
+static char *saf_join_key(TALLOC_CTX *mem_ctx, const char *domain)
 {
-       char *keystr;
-
-       asprintf_strupper_m(&keystr, SAFJOINKEY_FMT, domain);
-
-       return keystr;
+       return talloc_asprintf_strupper_m(mem_ctx, SAFJOINKEY_FMT, domain);
 }
 
 /****************************************************************************
@@ -82,7 +80,11 @@ bool saf_store( const char *domain, const char *servername )
                return False;
        }
 
-       key = saf_key( domain );
+       key = saf_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_key() failed\n"));
+               return false;
+       }
        expire = time( NULL ) + lp_parm_int(-1, "saf","ttl", SAF_TTL);
 
        DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%u]\n",
@@ -90,7 +92,7 @@ bool saf_store( const char *domain, const char *servername )
 
        ret = gencache_set( key, servername, expire );
 
-       SAFE_FREE( key );
+       TALLOC_FREE( key );
 
        return ret;
 }
@@ -111,7 +113,11 @@ bool saf_join_store( const char *domain, const char *servername )
                return False;
        }
 
-       key = saf_join_key( domain );
+       key = saf_join_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_join_key() failed\n"));
+               return false;
+       }
        expire = time( NULL ) + lp_parm_int(-1, "saf","join ttl", SAFJOIN_TTL);
 
        DEBUG(10,("saf_join_store: domain = [%s], server = [%s], expire = [%u]\n",
@@ -119,7 +125,7 @@ bool saf_join_store( const char *domain, const char *servername )
 
        ret = gencache_set( key, servername, expire );
 
-       SAFE_FREE( key );
+       TALLOC_FREE( key );
 
        return ret;
 }
@@ -134,17 +140,25 @@ bool saf_delete( const char *domain )
                return False;
        }
 
-       key = saf_join_key(domain);
+       key = saf_join_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_join_key() failed\n"));
+               return false;
+       }
        ret = gencache_del(key);
-       SAFE_FREE(key);
+       TALLOC_FREE(key);
 
        if (ret) {
                DEBUG(10,("saf_delete[join]: domain = [%s]\n", domain ));
        }
 
-       key = saf_key(domain);
+       key = saf_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_key() failed\n"));
+               return false;
+       }
        ret = gencache_del(key);
-       SAFE_FREE(key);
+       TALLOC_FREE(key);
 
        if (ret) {
                DEBUG(10,("saf_delete: domain = [%s]\n", domain ));
@@ -156,7 +170,7 @@ bool saf_delete( const char *domain )
 /****************************************************************************
 ****************************************************************************/
 
-char *saf_fetch( const char *domain )
+char *saf_fetch(TALLOC_CTX *mem_ctx, const char *domain )
 {
        char *server = NULL;
        time_t timeout;
@@ -168,11 +182,15 @@ char *saf_fetch( const char *domain )
                return NULL;
        }
 
-       key = saf_join_key( domain );
+       key = saf_join_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_join_key() failed\n"));
+               return NULL;
+       }
 
-       ret = gencache_get( key, &server, &timeout );
+       ret = gencache_get( key, mem_ctx, &server, &timeout );
 
-       SAFE_FREE( key );
+       TALLOC_FREE( key );
 
        if ( ret ) {
                DEBUG(5,("saf_fetch[join]: Returning \"%s\" for \"%s\" domain\n",
@@ -180,11 +198,15 @@ char *saf_fetch( const char *domain )
                return server;
        }
 
-       key = saf_key( domain );
+       key = saf_key(talloc_tos(), domain);
+       if (key == NULL) {
+               DEBUG(1, ("saf_key() failed\n"));
+               return NULL;
+       }
 
-       ret = gencache_get( key, &server, &timeout );
+       ret = gencache_get( key, mem_ctx, &server, &timeout );
 
-       SAFE_FREE( key );
+       TALLOC_FREE( key );
 
        if ( !ret ) {
                DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n",
@@ -199,7 +221,7 @@ char *saf_fetch( const char *domain )
 
 static void set_socket_addr_v4(struct sockaddr_storage *addr)
 {
-       if (!interpret_string_addr(addr, lp_socket_address(),
+       if (!interpret_string_addr(addr, lp_nbt_client_socket_address(),
                                   AI_NUMERICHOST|AI_PASSIVE)) {
                zero_sockaddr(addr);
        }
@@ -208,15 +230,24 @@ static void set_socket_addr_v4(struct sockaddr_storage *addr)
        }
 }
 
+static struct in_addr my_socket_addr_v4(void)
+{
+       struct sockaddr_storage my_addr;
+       struct sockaddr_in *in_addr = (struct sockaddr_in *)((char *)&my_addr);
+
+       set_socket_addr_v4(&my_addr);
+       return in_addr->sin_addr;
+}
+
 /****************************************************************************
  Generate a random trn_id.
 ****************************************************************************/
 
 static int generate_trn_id(void)
 {
-       uint16 id;
+       uint16_t id;
 
-       generate_random_buffer((uint8 *)&id, sizeof(id));
+       generate_random_buffer((uint8_t *)&id, sizeof(id));
 
        return id % (unsigned)0x7FFF;
 }
@@ -243,7 +274,7 @@ static struct node_status *parse_node_status(TALLOC_CTX *mem_ctx, char *p,
 
        p++;
        for (i=0;i< *num_names;i++) {
-               StrnCpy(ret[i].name,p,15);
+               strlcpy(ret[i].name,p,16);
                trim_char(ret[i].name,'\0',' ');
                ret[i].type = CVAL(p,15);
                ret[i].flags = p[16];
@@ -268,11 +299,10 @@ struct sock_packet_read_state {
        struct nb_packet_reader *reader;
        struct tevent_req *reader_req;
 
-       int sock;
+       struct tdgram_context *sock;
        struct tevent_req *socket_req;
-       uint8_t buf[1024];
-       struct sockaddr_storage addr;
-       socklen_t addr_len;
+       uint8_t *buf;
+       struct tsocket_address *addr;
 
        bool (*validator)(struct packet_struct *p,
                          void *private_data);
@@ -281,14 +311,13 @@ struct sock_packet_read_state {
        struct packet_struct *packet;
 };
 
-static int sock_packet_read_state_destructor(struct sock_packet_read_state *s);
 static void sock_packet_read_got_packet(struct tevent_req *subreq);
 static void sock_packet_read_got_socket(struct tevent_req *subreq);
 
 static struct tevent_req *sock_packet_read_send(
        TALLOC_CTX *mem_ctx,
        struct tevent_context *ev,
-       int sock, /* dgram socket */
+       struct tdgram_context *sock,
        struct nb_packet_reader *reader,
        enum packet_type type,
        int trn_id,
@@ -303,7 +332,6 @@ static struct tevent_req *sock_packet_read_send(
        if (req == NULL) {
                return NULL;
        }
-       talloc_set_destructor(state, sock_packet_read_state_destructor);
        state->ev = ev;
        state->reader = reader;
        state->sock = sock;
@@ -321,10 +349,7 @@ static struct tevent_req *sock_packet_read_send(
                        state->reader_req, sock_packet_read_got_packet, req);
        }
 
-       state->addr_len = sizeof(state->addr);
-       state->socket_req = recvfrom_send(state, ev, sock,
-                                         state->buf, sizeof(state->buf), 0,
-                                         &state->addr, &state->addr_len);
+       state->socket_req = tdgram_recvfrom_send(state, ev, state->sock);
        if (tevent_req_nomem(state->socket_req, req)) {
                return tevent_req_post(req, ev);
        }
@@ -334,15 +359,6 @@ static struct tevent_req *sock_packet_read_send(
        return req;
 }
 
-static int sock_packet_read_state_destructor(struct sock_packet_read_state *s)
-{
-       if (s->packet != NULL) {
-               free_packet(s->packet);
-               s->packet = NULL;
-       }
-       return 0;
-}
-
 static void sock_packet_read_got_packet(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
@@ -351,7 +367,7 @@ static void sock_packet_read_got_packet(struct tevent_req *subreq)
                req, struct sock_packet_read_state);
        NTSTATUS status;
 
-       status = nb_packet_read_recv(subreq, &state->packet);
+       status = nb_packet_read_recv(subreq, state, &state->packet);
 
        TALLOC_FREE(state->reader_req);
 
@@ -373,8 +389,7 @@ static void sock_packet_read_got_packet(struct tevent_req *subreq)
            !state->validator(state->packet, state->private_data)) {
                DEBUG(10, ("validator failed\n"));
 
-               free_packet(state->packet);
-               state->packet = NULL;
+               TALLOC_FREE(state->packet);
 
                state->reader_req = nb_packet_read_send(state, state->ev,
                                                        state->reader);
@@ -396,11 +411,17 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct sock_packet_read_state *state = tevent_req_data(
                req, struct sock_packet_read_state);
-       struct sockaddr_in *in_addr;
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+       } addr;
+       ssize_t ret;
        ssize_t received;
        int err;
+       bool ok;
 
-       received = recvfrom_recv(subreq, &err);
+       received = tdgram_recvfrom_recv(subreq, &err, state,
+                                       &state->buf, &state->addr);
 
        TALLOC_FREE(state->socket_req);
 
@@ -417,13 +438,21 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq)
                tevent_req_nterror(req, map_nt_error_from_unix(err));
                return;
        }
-       if (state->addr.ss_family != AF_INET) {
+       ok = tsocket_address_is_inet(state->addr, "ipv4");
+       if (!ok) {
                goto retry;
        }
-       in_addr = (struct sockaddr_in *)(void *)&state->addr;
+       ret = tsocket_address_bsd_sockaddr(state->addr,
+                                          &addr.sa,
+                                          sizeof(addr.sin));
+       if (ret == -1) {
+               tevent_req_nterror(req, map_nt_error_from_unix(errno));
+               return;
+       }
 
-       state->packet = parse_packet((char *)state->buf, received, state->type,
-                                    in_addr->sin_addr, in_addr->sin_port);
+       state->packet = parse_packet_talloc(
+               state, (char *)state->buf, received, state->type,
+               addr.sin.sin_addr, addr.sin.sin_port);
        if (state->packet == NULL) {
                DEBUG(10, ("parse_packet failed\n"));
                goto retry;
@@ -445,13 +474,11 @@ static void sock_packet_read_got_socket(struct tevent_req *subreq)
        return;
 
 retry:
-       if (state->packet != NULL) {
-               free_packet(state->packet);
-               state->packet = NULL;
-       }
-       state->socket_req = recvfrom_send(state, state->ev, state->sock,
-                                         state->buf, sizeof(state->buf), 0,
-                                         &state->addr, &state->addr_len);
+       TALLOC_FREE(state->packet);
+       TALLOC_FREE(state->buf);
+       TALLOC_FREE(state->addr);
+
+       state->socket_req = tdgram_recvfrom_send(state, state->ev, state->sock);
        if (tevent_req_nomem(state->socket_req, req)) {
                return;
        }
@@ -460,6 +487,7 @@ retry:
 }
 
 static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
+                                     TALLOC_CTX *mem_ctx,
                                      struct packet_struct **ppacket)
 {
        struct sock_packet_read_state *state = tevent_req_data(
@@ -469,17 +497,17 @@ static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       *ppacket = state->packet;
-       state->packet = NULL;
+       *ppacket = talloc_move(mem_ctx, &state->packet);
        return NT_STATUS_OK;
 }
 
 struct nb_trans_state {
        struct tevent_context *ev;
-       int sock;
+       struct tdgram_context *sock;
        struct nb_packet_reader *reader;
 
-       const struct sockaddr_storage *dst_addr;
+       struct tsocket_address *src_addr;
+       struct tsocket_address *dst_addr;
        uint8_t *buf;
        size_t buflen;
        enum packet_type type;
@@ -492,7 +520,6 @@ struct nb_trans_state {
        struct packet_struct *packet;
 };
 
-static int nb_trans_state_destructor(struct nb_trans_state *s);
 static void nb_trans_got_reader(struct tevent_req *subreq);
 static void nb_trans_done(struct tevent_req *subreq);
 static void nb_trans_sent(struct tevent_req *subreq);
@@ -501,8 +528,8 @@ static void nb_trans_send_next(struct tevent_req *subreq);
 static struct tevent_req *nb_trans_send(
        TALLOC_CTX *mem_ctx,
        struct tevent_context *ev,
-       const struct sockaddr_storage *my_addr,
-       const struct sockaddr_storage *dst_addr,
+       const struct sockaddr_storage *_my_addr,
+       const struct sockaddr_storage *_dst_addr,
        bool bcast,
        uint8_t *buf, size_t buflen,
        enum packet_type type, int trn_id,
@@ -510,16 +537,21 @@ static struct tevent_req *nb_trans_send(
                          void *private_data),
        void *private_data)
 {
+       const struct sockaddr *my_addr =
+               discard_const_p(const struct sockaddr, _my_addr);
+       size_t my_addr_len = sizeof(*_my_addr);
+       const struct sockaddr *dst_addr =
+               discard_const_p(const struct sockaddr, _dst_addr);
+       size_t dst_addr_len = sizeof(*_dst_addr);
        struct tevent_req *req, *subreq;
        struct nb_trans_state *state;
+       int ret;
 
        req = tevent_req_create(mem_ctx, &state, struct nb_trans_state);
        if (req == NULL) {
                return NULL;
        }
-       talloc_set_destructor(state, nb_trans_state_destructor);
        state->ev = ev;
-       state->dst_addr = dst_addr;
        state->buf = buf;
        state->buflen = buflen;
        state->type = type;
@@ -527,15 +559,27 @@ static struct tevent_req *nb_trans_send(
        state->validator = validator;
        state->private_data = private_data;
 
-       state->sock = open_socket_in(SOCK_DGRAM, 0, 3, my_addr, True);
-       if (state->sock == -1) {
+       ret = tsocket_address_bsd_from_sockaddr(state,
+                                               my_addr, my_addr_len,
+                                               &state->src_addr);
+       if (ret == -1) {
                tevent_req_nterror(req, map_nt_error_from_unix(errno));
-               DEBUG(10, ("open_socket_in failed: %s\n", strerror(errno)));
                return tevent_req_post(req, ev);
        }
 
-       if (bcast) {
-               set_socket_options(state->sock,"SO_BROADCAST");
+       ret = tsocket_address_bsd_from_sockaddr(state,
+                                               dst_addr, dst_addr_len,
+                                               &state->dst_addr);
+       if (ret == -1) {
+               tevent_req_nterror(req, map_nt_error_from_unix(errno));
+               return tevent_req_post(req, ev);
+       }
+
+       ret = tdgram_inet_udp_broadcast_socket(state->src_addr, state,
+                                              &state->sock);
+       if (ret == -1) {
+               tevent_req_nterror(req, map_nt_error_from_unix(errno));
+               return tevent_req_post(req, ev);
        }
 
        subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
@@ -546,19 +590,6 @@ static struct tevent_req *nb_trans_send(
        return req;
 }
 
-static int nb_trans_state_destructor(struct nb_trans_state *s)
-{
-       if (s->sock != -1) {
-               close(s->sock);
-               s->sock = -1;
-       }
-       if (s->packet != NULL) {
-               free_packet(s->packet);
-               s->packet = NULL;
-       }
-       return 0;
-}
-
 static void nb_trans_got_reader(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
@@ -584,8 +615,10 @@ static void nb_trans_got_reader(struct tevent_req *subreq)
        }
        tevent_req_set_callback(subreq, nb_trans_done, req);
 
-       subreq = sendto_send(state, state->ev, state->sock,
-                            state->buf, state->buflen, 0, state->dst_addr);
+       subreq = tdgram_sendto_send(state, state->ev,
+                                   state->sock,
+                                   state->buf, state->buflen,
+                                   state->dst_addr);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -601,7 +634,7 @@ static void nb_trans_sent(struct tevent_req *subreq)
        ssize_t sent;
        int err;
 
-       sent = sendto_recv(subreq, &err);
+       sent = tdgram_sendto_recv(subreq, &err);
        TALLOC_FREE(subreq);
        if (sent == -1) {
                DEBUG(10, ("sendto failed: %s\n", strerror(err)));
@@ -630,8 +663,10 @@ static void nb_trans_send_next(struct tevent_req *subreq)
                tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
                return;
        }
-       subreq = sendto_send(state, state->ev, state->sock,
-                            state->buf, state->buflen, 0, state->dst_addr);
+       subreq = tdgram_sendto_send(state, state->ev,
+                                   state->sock,
+                                   state->buf, state->buflen,
+                                   state->dst_addr);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -646,7 +681,7 @@ static void nb_trans_done(struct tevent_req *subreq)
                req, struct nb_trans_state);
        NTSTATUS status;
 
-       status = sock_packet_read_recv(subreq, &state->packet);
+       status = sock_packet_read_recv(subreq, state, &state->packet);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
@@ -654,7 +689,7 @@ static void nb_trans_done(struct tevent_req *subreq)
        tevent_req_done(req);
 }
 
-static NTSTATUS nb_trans_recv(struct tevent_req *req,
+static NTSTATUS nb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                              struct packet_struct **ppacket)
 {
        struct nb_trans_state *state = tevent_req_data(
@@ -664,8 +699,7 @@ static NTSTATUS nb_trans_recv(struct tevent_req *req,
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       *ppacket = state->packet;
-       state->packet = NULL;
+       *ppacket = talloc_move(mem_ctx, &state->packet);
        return NT_STATUS_OK;
 }
 
@@ -682,8 +716,6 @@ struct node_status_query_state {
        struct packet_struct *packet;
 };
 
-static int node_status_query_state_destructor(
-       struct node_status_query_state *s);
 static bool node_status_query_validator(struct packet_struct *p,
                                        void *private_data);
 static void node_status_query_done(struct tevent_req *subreq);
@@ -704,7 +736,6 @@ struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
        if (req == NULL) {
                return NULL;
        }
-       talloc_set_destructor(state, node_status_query_state_destructor);
 
        if (addr->ss_family != AF_INET) {
                /* Can't do node status to IPv6 */
@@ -779,16 +810,6 @@ static bool node_status_query_validator(struct packet_struct *p,
        return true;
 }
 
-static int node_status_query_state_destructor(
-       struct node_status_query_state *s)
-{
-       if (s->packet != NULL) {
-               free_packet(s->packet);
-               s->packet = NULL;
-       }
-       return 0;
-}
-
 static void node_status_query_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
@@ -797,7 +818,7 @@ static void node_status_query_done(struct tevent_req *subreq)
                req, struct node_status_query_state);
        NTSTATUS status;
 
-       status = nb_trans_recv(subreq, &state->packet);
+       status = nb_trans_recv(subreq, state, &state->packet);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
@@ -841,7 +862,7 @@ NTSTATUS node_status_query(TALLOC_CTX *mem_ctx, struct nmb_name *name,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       ev = tevent_context_init(frame);
+       ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
                goto fail;
        }
@@ -859,6 +880,42 @@ NTSTATUS node_status_query(TALLOC_CTX *mem_ctx, struct nmb_name *name,
        return status;
 }
 
+static bool name_status_lmhosts(const struct sockaddr_storage *paddr,
+                               int qname_type, fstring pname)
+{
+       FILE *f;
+       char *name;
+       int name_type;
+       struct sockaddr_storage addr;
+
+       if (paddr->ss_family != AF_INET) {
+               return false;
+       }
+
+       f = startlmhosts(get_dyn_LMHOSTSFILE());
+       if (f == NULL) {
+               return false;
+       }
+
+       while (getlmhostsent(talloc_tos(), f, &name, &name_type, &addr)) {
+               if (addr.ss_family != AF_INET) {
+                       continue;
+               }
+               if (name_type != qname_type) {
+                       continue;
+               }
+               if (memcmp(&((const struct sockaddr_in *)paddr)->sin_addr,
+                          &((const struct sockaddr_in *)&addr)->sin_addr,
+                          sizeof(struct in_addr)) == 0) {
+                       fstrcpy(pname, name);
+                       endlmhosts(f);
+                       return true;
+               }
+       }
+       endlmhosts(f);
+       return false;
+}
+
 /****************************************************************************
  Find the first type XX name in a node status reply - used for finding
  a servers name given its IP. Return the matched name in *name.
@@ -900,6 +957,13 @@ bool name_status_find(const char *q_name,
                return false;
        }
 
+       result = name_status_lmhosts(to_ss, type, name);
+       if (result) {
+               DBG_DEBUG("Found name %s in lmhosts\n", name);
+               namecache_status_store(q_name, q_type, type, to_ss, name);
+               return true;
+       }
+
        set_socket_addr_v4(&ss);
 
        /* W2K PDC's seem not to respond to '*'#0. JRA */
@@ -1029,7 +1093,7 @@ static int addr_compare(const struct sockaddr_storage *ss1,
  compare 2 ldap IPs by nearness to our interfaces - used in qsort
 *******************************************************************/
 
-int ip_service_compare(struct ip_service *ss1, struct ip_service *ss2)
+static int ip_service_compare(struct ip_service *ss1, struct ip_service *ss2)
 {
        int result;
 
@@ -1076,39 +1140,39 @@ static void sort_service_list(struct ip_service *servlist, int count)
  Remove any duplicate address/port pairs in the list
  *********************************************************************/
 
-static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
+int remove_duplicate_addrs2(struct ip_service *iplist, int count )
 {
        int i, j;
 
        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)) {
                        continue;
                }
 
                for ( j=i+1; j<count; j++ ) {
-                       if (sockaddr_equal((struct sockaddr *)&iplist[i].ss, (struct sockaddr *)&iplist[j].ss) &&
+                       if (sockaddr_equal((struct sockaddr *)(void *)&iplist[i].ss,
+                                          (struct sockaddr *)(void *)&iplist[j].ss) &&
                                        iplist[i].port == iplist[j].port) {
                                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(&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;
@@ -1341,10 +1405,14 @@ static bool name_query_validator(struct packet_struct *p, void *private_data)
                putip((char *)&ip,&nmb->answers->rdata[2+i*6]);
                in_addr_to_sockaddr_storage(&addr, ip);
 
+               if (is_zero_addr(&addr)) {
+                       continue;
+               }
+
                for (j=0; j<state->num_addrs; j++) {
                        if (sockaddr_equal(
-                                   (struct sockaddr *)&addr,
-                                   (struct sockaddr *)&state->addrs[j])) {
+                                   (struct sockaddr *)(void *)&addr,
+                                   (struct sockaddr *)(void *)&state->addrs[j])) {
                                break;
                        }
                }
@@ -1396,7 +1464,7 @@ static void name_query_done(struct tevent_req *subreq)
        NTSTATUS status;
        struct packet_struct *p = NULL;
 
-       status = nb_trans_recv(subreq, &p);
+       status = nb_trans_recv(subreq, state, &p);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
@@ -1405,13 +1473,6 @@ static void name_query_done(struct tevent_req *subreq)
                tevent_req_nterror(req, state->validate_error);
                return;
        }
-       if (p != NULL) {
-               /*
-                * Free the packet here, we've collected the response in the
-                * validator
-                */
-               free_packet(p);
-       }
        tevent_req_done(req);
 }
 
@@ -1423,9 +1484,18 @@ NTSTATUS name_query_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                req, struct name_query_state);
        NTSTATUS status;
 
-       if (tevent_req_is_nterror(req, &status)
-           && !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               return status;
+       if (tevent_req_is_nterror(req, &status)) {
+               if (state->bcast &&
+                   NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+                       /*
+                        * In the broadcast case we collect replies until the
+                        * timeout.
+                        */
+                       status = NT_STATUS_OK;
+               }
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
        }
        if (state->num_addrs == 0) {
                return NT_STATUS_NOT_FOUND;
@@ -1452,7 +1522,7 @@ NTSTATUS name_query(const char *name, int name_type,
        struct timeval timeout;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       ev = tevent_context_init(frame);
+       ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
                goto fail;
        }
@@ -1478,32 +1548,53 @@ NTSTATUS name_query(const char *name, int name_type,
 }
 
 /********************************************************
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(&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(&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;
 }
 
@@ -1576,7 +1667,6 @@ static struct tevent_req *name_queries_send(
        if (!tevent_req_set_endtime(
                    subreq, state->ev,
                    timeval_current_ofs(0, state->timeout_msec * 1000))) {
-               tevent_req_nomem(NULL, req);
                return tevent_req_post(req, ev);
        }
        tevent_req_set_callback(subreq, name_queries_done, req);
@@ -1659,7 +1749,6 @@ static void name_queries_next(struct tevent_req *subreq)
        if (!tevent_req_set_endtime(
                    subreq, state->ev,
                    timeval_current_ofs(0, state->timeout_msec * 1000))) {
-               tevent_req_nomem(NULL, req);
                return;
        }
        state->subreqs[state->num_sent] = subreq;
@@ -1704,71 +1793,51 @@ static NTSTATUS name_queries_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS name_queries(const char *name, int name_type,
-                            bool bcast, bool recurse,
-                            const struct sockaddr_storage *addrs,
-                            int num_addrs, int wait_msec, int timeout_msec,
-                            TALLOC_CTX *mem_ctx,
-                            struct sockaddr_storage **result_addrs,
-                            int *num_result_addrs, uint8_t *flags,
-                            int *received_index)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct event_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       ev = event_context_init(frame);
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = name_queries_send(frame, ev, name, name_type, bcast,
-                               recurse, addrs, num_addrs, wait_msec,
-                               timeout_msec);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
-       }
-       status = name_queries_recv(req, mem_ctx, result_addrs,
-                                  num_result_addrs, flags, received_index);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 /********************************************************
  Resolve via "bcast" method.
 *********************************************************/
 
-NTSTATUS name_resolve_bcast(const char *name,
-                       int name_type,
-                       TALLOC_CTX *mem_ctx,
-                       struct sockaddr_storage **return_iplist,
-                       int *return_count)
+struct name_resolve_bcast_state {
+       struct sockaddr_storage *addrs;
+       int num_addrs;
+};
+
+static void name_resolve_bcast_done(struct tevent_req *subreq);
+
+struct tevent_req *name_resolve_bcast_send(TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          const char *name,
+                                          int name_type)
 {
+       struct tevent_req *req, *subreq;
+       struct name_resolve_bcast_state *state;
        struct sockaddr_storage *bcast_addrs;
        int i, num_addrs, num_bcast_addrs;
 
+       req = tevent_req_create(mem_ctx, &state,
+                               struct name_resolve_bcast_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
        if (lp_disable_netbios()) {
-               DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n",
-                                       name, name_type));
-               return NT_STATUS_INVALID_PARAMETER;
+               DEBUG(5, ("name_resolve_bcast(%s#%02x): netbios is disabled\n",
+                         name, name_type));
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return tevent_req_post(req, ev);
        }
 
        /*
         * "bcast" means do a broadcast lookup on all the local interfaces.
         */
 
-       DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup "
-               "for name %s<0x%x>\n", name, name_type));
+       DEBUG(3, ("name_resolve_bcast: Attempting broadcast lookup "
+                 "for name %s<0x%x>\n", name, name_type));
 
        num_addrs = iface_count();
-       bcast_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
-                                  num_addrs);
-       if (bcast_addrs == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       bcast_addrs = talloc_array(state, struct sockaddr_storage, num_addrs);
+       if (tevent_req_nomem(bcast_addrs, req)) {
+               return tevent_req_post(req, ev);
        }
 
        /*
@@ -1787,55 +1856,249 @@ NTSTATUS name_resolve_bcast(const char *name,
                num_bcast_addrs += 1;
        }
 
-       return name_queries(name, name_type, true, true,
-                           bcast_addrs, num_bcast_addrs, 0, 1000,
-                           mem_ctx, return_iplist, return_count,
-                           NULL, NULL);
+       subreq = name_queries_send(state, ev, name, name_type, true, true,
+                                  bcast_addrs, num_bcast_addrs, 0, 1000);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, name_resolve_bcast_done, req);
+       return req;
 }
 
-/********************************************************
- Resolve via "wins" method.
-*********************************************************/
+static void name_resolve_bcast_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct name_resolve_bcast_state *state = tevent_req_data(
+               req, struct name_resolve_bcast_state);
+       NTSTATUS status;
 
-NTSTATUS resolve_wins(const char *name,
-               int name_type,
-               struct ip_service **return_iplist,
-               int *return_count)
+       status = name_queries_recv(subreq, state,
+                                  &state->addrs, &state->num_addrs,
+                                  NULL, NULL);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
+NTSTATUS name_resolve_bcast_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                                struct sockaddr_storage **addrs,
+                                int *num_addrs)
 {
-       int t, i;
-       char **wins_tags;
-       struct sockaddr_storage src_ss, *ss_list = NULL;
-       struct in_addr src_ip;
+       struct name_resolve_bcast_state *state = tevent_req_data(
+               req, struct name_resolve_bcast_state);
        NTSTATUS status;
 
-       if (lp_disable_netbios()) {
-               DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n",
-                                       name, name_type));
-               return NT_STATUS_INVALID_PARAMETER;
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
        }
+       *addrs = talloc_move(mem_ctx, &state->addrs);
+       *num_addrs = state->num_addrs;
+       return NT_STATUS_OK;
+}
 
-       *return_iplist = NULL;
-       *return_count = 0;
+NTSTATUS name_resolve_bcast(const char *name,
+                       int name_type,
+                       TALLOC_CTX *mem_ctx,
+                       struct sockaddr_storage **return_iplist,
+                       int *return_count)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n",
-                               name, name_type));
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = name_resolve_bcast_send(frame, ev, name, name_type);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = name_resolve_bcast_recv(req, mem_ctx, return_iplist,
+                                        return_count);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
 
-       if (wins_srv_count() < 1) {
-               DEBUG(3,("resolve_wins: WINS server resolution selected "
-                       "and no WINS servers listed.\n"));
-               return NT_STATUS_INVALID_PARAMETER;
+struct query_wins_list_state {
+       struct tevent_context *ev;
+       const char *name;
+       uint8_t name_type;
+       struct in_addr *servers;
+       uint32_t num_servers;
+       struct sockaddr_storage server;
+       uint32_t num_sent;
+
+       struct sockaddr_storage *addrs;
+       int num_addrs;
+       uint8_t flags;
+};
+
+static void query_wins_list_done(struct tevent_req *subreq);
+
+/*
+ * Query a list of (replicating) wins servers in sequence, call them
+ * dead if they don't reply
+ */
+
+static struct tevent_req *query_wins_list_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       struct in_addr src_ip, const char *name, uint8_t name_type,
+       struct in_addr *servers, int num_servers)
+{
+       struct tevent_req *req, *subreq;
+       struct query_wins_list_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct query_wins_list_state);
+       if (req == NULL) {
+               return NULL;
        }
+       state->ev = ev;
+       state->name = name;
+       state->name_type = name_type;
+       state->servers = servers;
+       state->num_servers = num_servers;
 
-       /* we try a lookup on each of the WINS tags in turn */
-       wins_tags = wins_srv_tags();
+       if (state->num_servers == 0) {
+               tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+               return tevent_req_post(req, ev);
+       }
 
-       if (!wins_tags) {
-               /* huh? no tags?? give up in disgust */
-               return NT_STATUS_INVALID_PARAMETER;
+       in_addr_to_sockaddr_storage(
+               &state->server, state->servers[state->num_sent]);
+
+       subreq = name_query_send(state, state->ev,
+                                state->name, state->name_type,
+                                false, true, &state->server);
+       state->num_sent += 1;
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       if (!tevent_req_set_endtime(subreq, state->ev,
+                                   timeval_current_ofs(2, 0))) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, query_wins_list_done, req);
+       return req;
+}
+
+static void query_wins_list_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct query_wins_list_state *state = tevent_req_data(
+               req, struct query_wins_list_state);
+       NTSTATUS status;
+
+       status = name_query_recv(subreq, state,
+                                &state->addrs, &state->num_addrs,
+                                &state->flags);
+       TALLOC_FREE(subreq);
+       if (NT_STATUS_IS_OK(status)) {
+               tevent_req_done(req);
+               return;
+       }
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+       wins_srv_died(state->servers[state->num_sent-1],
+                     my_socket_addr_v4());
+
+       if (state->num_sent == state->num_servers) {
+               tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+               return;
+       }
+
+       in_addr_to_sockaddr_storage(
+               &state->server, state->servers[state->num_sent]);
+
+       subreq = name_query_send(state, state->ev,
+                                state->name, state->name_type,
+                                false, true, &state->server);
+       state->num_sent += 1;
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       if (!tevent_req_set_endtime(subreq, state->ev,
+                                   timeval_current_ofs(2, 0))) {
+               return;
+       }
+       tevent_req_set_callback(subreq, query_wins_list_done, req);
+}
+
+static NTSTATUS query_wins_list_recv(struct tevent_req *req,
+                                    TALLOC_CTX *mem_ctx,
+                                    struct sockaddr_storage **addrs,
+                                    int *num_addrs,
+                                    uint8_t *flags)
+{
+       struct query_wins_list_state *state = tevent_req_data(
+               req, struct query_wins_list_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       if (addrs != NULL) {
+               *addrs = talloc_move(mem_ctx, &state->addrs);
+       }
+       if (num_addrs != NULL) {
+               *num_addrs = state->num_addrs;
+       }
+       if (flags != NULL) {
+               *flags = state->flags;
+       }
+       return NT_STATUS_OK;
+}
+
+struct resolve_wins_state {
+       int num_sent;
+       int num_received;
+
+       struct sockaddr_storage *addrs;
+       int num_addrs;
+       uint8_t flags;
+};
+
+static void resolve_wins_done(struct tevent_req *subreq);
+
+struct tevent_req *resolve_wins_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev,
+                                    const char *name,
+                                    int name_type)
+{
+       struct tevent_req *req, *subreq;
+       struct resolve_wins_state *state;
+       char **wins_tags = NULL;
+       struct sockaddr_storage src_ss;
+       struct in_addr src_ip;
+       int i, num_wins_tags;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct resolve_wins_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (wins_srv_count() < 1) {
+               DEBUG(3,("resolve_wins: WINS server resolution selected "
+                       "and no WINS servers listed.\n"));
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto fail;
        }
 
        /* the address we will be sending from */
-       if (!interpret_string_addr(&src_ss, lp_socket_address(),
+       if (!interpret_string_addr(&src_ss, lp_nbt_client_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
                zero_sockaddr(&src_ss);
        }
@@ -1846,137 +2109,174 @@ 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;
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto fail;
        }
 
-       src_ip = ((struct sockaddr_in *)&src_ss)->sin_addr;
+       src_ip = ((const struct sockaddr_in *)(void *)&src_ss)->sin_addr;
 
-       /* in the worst case we will try every wins server with every
-          tag! */
-       for (t=0; wins_tags && wins_tags[t]; t++) {
-               int srv_count = wins_srv_count_tag(wins_tags[t]);
-               for (i=0; i<srv_count; i++) {
-                       struct sockaddr_storage wins_ss;
-                       struct in_addr wins_ip;
+       wins_tags = wins_srv_tags();
+       if (wins_tags == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto fail;
+       }
+
+       num_wins_tags = 0;
+       while (wins_tags[num_wins_tags] != NULL) {
+               num_wins_tags += 1;
+       }
+
+       for (i=0; i<num_wins_tags; i++) {
+               int num_servers, num_alive;
+               struct in_addr *servers, *alive;
+               int j;
+
+               if (!wins_server_tag_ips(wins_tags[i], talloc_tos(),
+                                        &servers, &num_servers)) {
+                       DEBUG(10, ("wins_server_tag_ips failed for tag %s\n",
+                                  wins_tags[i]));
+                       continue;
+               }
+
+               alive = talloc_array(state, struct in_addr, num_servers);
+               if (tevent_req_nomem(alive, req)) {
+                       goto fail;
+               }
 
-                       wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip);
+               num_alive = 0;
+               for (j=0; j<num_servers; j++) {
+                       struct in_addr wins_ip = servers[j];
 
                        if (global_in_nmbd && ismyip_v4(wins_ip)) {
                                /* yikes! we'll loop forever */
                                continue;
                        }
-
                        /* skip any that have been unresponsive lately */
                        if (wins_srv_is_dead(wins_ip, src_ip)) {
                                continue;
                        }
+                       DEBUG(3, ("resolve_wins: using WINS server %s "
+                                "and tag '%s'\n",
+                                 inet_ntoa(wins_ip), wins_tags[i]));
+                       alive[num_alive] = wins_ip;
+                       num_alive += 1;
+               }
+               TALLOC_FREE(servers);
 
-                       DEBUG(3,("resolve_wins: using WINS server %s "
-                               "and tag '%s'\n",
-                               inet_ntoa(wins_ip), wins_tags[t]));
-
-                       in_addr_to_sockaddr_storage(&wins_ss, wins_ip);
-                       status = name_query(name,
-                                               name_type,
-                                               false,
-                                               true,
-                                               &wins_ss,
-                                               talloc_tos(),
-                                               &ss_list,
-                                               return_count,
-                                               NULL);
-
-                       /* exit loop if we got a list of addresses */
-
-                       if (NT_STATUS_IS_OK(status)) {
-                               goto success;
-                       }
+               if (num_alive == 0) {
+                       continue;
+               }
 
-                       if (NT_STATUS_EQUAL(status,
-                                           NT_STATUS_IO_TIMEOUT)) {
-                               /* Timed out waiting for WINS server to
-                                * respond.
-                                * Mark it dead. */
-                               wins_srv_died(wins_ip, src_ip);
-                       } else {
-                               /* The name definitely isn't in this
-                                  group of WINS servers.
-                                  goto the next group  */
-                               break;
-                       }
+               subreq = query_wins_list_send(
+                       state, ev, src_ip, name, name_type,
+                       alive, num_alive);
+               if (tevent_req_nomem(subreq, req)) {
+                       goto fail;
                }
+               tevent_req_set_callback(subreq, resolve_wins_done, req);
+               state->num_sent += 1;
        }
 
+       if (state->num_sent == 0) {
+               tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+               goto fail;
+       }
+
+       wins_srv_tags_free(wins_tags);
+       return req;
+fail:
        wins_srv_tags_free(wins_tags);
-       return NT_STATUS_NO_LOGON_SERVERS;
+       return tevent_req_post(req, ev);
+}
 
-success:
+static void resolve_wins_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct resolve_wins_state *state = tevent_req_data(
+               req, struct resolve_wins_state);
+       NTSTATUS status;
 
-       status = NT_STATUS_OK;
-       if (!convert_ss2service(return_iplist, ss_list, *return_count))
-               status = NT_STATUS_INVALID_PARAMETER;
+       status = query_wins_list_recv(subreq, state, &state->addrs,
+                                     &state->num_addrs, &state->flags);
+       if (NT_STATUS_IS_OK(status)) {
+               tevent_req_done(req);
+               return;
+       }
 
-       TALLOC_FREE(ss_list);
-       wins_srv_tags_free(wins_tags);
+       state->num_received += 1;
 
-       return status;
+       if (state->num_received < state->num_sent) {
+               /*
+                * Wait for the others
+                */
+               return;
+       }
+       tevent_req_nterror(req, status);
+}
+
+NTSTATUS resolve_wins_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                          struct sockaddr_storage **addrs,
+                          int *num_addrs, uint8_t *flags)
+{
+       struct resolve_wins_state *state = tevent_req_data(
+               req, struct resolve_wins_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       if (addrs != NULL) {
+               *addrs = talloc_move(mem_ctx, &state->addrs);
+       }
+       if (num_addrs != NULL) {
+               *num_addrs = state->num_addrs;
+       }
+       if (flags != NULL) {
+               *flags = state->flags;
+       }
+       return NT_STATUS_OK;
 }
 
 /********************************************************
- Resolve via "lmhosts" method.
+ Resolve via "wins" method.
 *********************************************************/
 
-static NTSTATUS resolve_lmhosts(const char *name, int name_type,
-                               struct ip_service **return_iplist,
-                               int *return_count)
+NTSTATUS resolve_wins(const char *name,
+               int name_type,
+               TALLOC_CTX *mem_ctx,
+               struct sockaddr_storage **return_iplist,
+               int *return_count)
 {
-       /*
-        * "lmhosts" means parse the local lmhosts file.
-        */
-       struct sockaddr_storage *ss_list;
-       NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-       TALLOC_CTX *ctx = NULL;
-
-       *return_iplist = NULL;
-       *return_count = 0;
-
-       DEBUG(3,("resolve_lmhosts: "
-               "Attempting lmhosts lookup for name %s<0x%x>\n",
-               name, name_type));
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       ctx = talloc_init("resolve_lmhosts");
-       if (!ctx) {
-               return NT_STATUS_NO_MEMORY;
+       ev = samba_tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               goto fail;
        }
-
-       status = resolve_lmhosts_file_as_sockaddr(get_dyn_LMHOSTSFILE(), 
-                                                 name, name_type, 
-                                                 ctx, 
-                                                 &ss_list, 
-                                                 return_count);
-       if (NT_STATUS_IS_OK(status)) {
-               if (convert_ss2service(return_iplist, 
-                                      ss_list,
-                                      *return_count)) {
-                       talloc_free(ctx);
-                       return NT_STATUS_OK;
-               } else {
-                       talloc_free(ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
+       req = resolve_wins_send(ev, ev, name, name_type);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
        }
-       talloc_free(ctx);
+       status = resolve_wins_recv(req, mem_ctx, return_iplist, return_count,
+                                  NULL);
+fail:
+       TALLOC_FREE(ev);
        return status;
 }
 
-
 /********************************************************
  Resolve via "hosts" method.
 *********************************************************/
 
 static NTSTATUS resolve_hosts(const char *name, int name_type,
-                             struct ip_service **return_iplist,
+                             TALLOC_CTX *mem_ctx,
+                             struct sockaddr_storage **return_iplist,
                              int *return_count)
 {
        /*
@@ -1987,7 +2287,6 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
        struct addrinfo *res = NULL;
        int ret = -1;
        int i = 0;
-       const char *dns_hosts_file;
 
        if ( name_type != 0x20 && name_type != 0x0) {
                DEBUG(5, ("resolve_hosts: not appropriate "
@@ -2012,32 +2311,6 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
        hints.ai_family = AF_INET;
 #endif
 
-       dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
-       if (dns_hosts_file) {
-               struct sockaddr_storage *ss_list;
-               NTSTATUS status;
-               TALLOC_CTX *ctx = talloc_stackframe();
-               if (!ctx) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               status = resolve_dns_hosts_file_as_sockaddr(dns_hosts_file, name, false,
-                                                           ctx, &ss_list, return_count);
-               if (NT_STATUS_IS_OK(status)) {
-                       if (convert_ss2service(return_iplist,
-                                              ss_list,
-                                              *return_count)) {
-                               talloc_free(ctx);
-                               return NT_STATUS_OK;
-                       } else {
-                               talloc_free(ctx);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-               talloc_free(ctx);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        ret = getaddrinfo(name,
                        NULL,
                        &hints,
@@ -2058,18 +2331,21 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
                ZERO_STRUCT(ss);
                memcpy(&ss, res->ai_addr, res->ai_addrlen);
 
+               if (is_zero_addr(&ss)) {
+                       continue;
+               }
+
                *return_count += 1;
 
-               *return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
-                                               struct ip_service,
-                                               *return_count);
+               *return_iplist = talloc_realloc(
+                       mem_ctx, *return_iplist, struct sockaddr_storage,
+                       *return_count);
                if (!*return_iplist) {
                        DEBUG(3,("resolve_hosts: malloc fail !\n"));
                        freeaddrinfo(ailist);
                        return NT_STATUS_NO_MEMORY;
                }
-               (*return_iplist)[i].ss = ss;
-               (*return_iplist)[i].port = PORT_NONE;
+               (*return_iplist)[i] = ss;
                i++;
        }
        if (ailist) {
@@ -2094,7 +2370,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;
@@ -2112,24 +2388,32 @@ static NTSTATUS resolve_ads(const char *name,
        }
 
        /* The DNS code needs fixing to find IPv6 addresses... JRA. */
-
        switch (name_type) {
                case 0x1b:
                        DEBUG(5,("resolve_ads: Attempting to resolve "
                                 "PDC for %s using DNS\n", name));
-                       status = ads_dns_query_pdc(ctx, name, &dcs, &numdcs);
+                       status = ads_dns_query_pdc(ctx,
+                                                  name,
+                                                  &dcs,
+                                                  &numdcs);
                        break;
 
                case 0x1c:
                        DEBUG(5,("resolve_ads: Attempting to resolve "
                                 "DCs for %s using DNS\n", name));
-                       status = ads_dns_query_dcs(ctx, name, sitename, &dcs,
+                       status = ads_dns_query_dcs(ctx,
+                                                  name,
+                                                  sitename,
+                                                  &dcs,
                                                   &numdcs);
                        break;
                case KDC_NAME_TYPE:
                        DEBUG(5,("resolve_ads: Attempting to resolve "
                                 "KDCs for %s using DNS\n", name));
-                       status = ads_dns_query_kdcs(ctx, name, sitename, &dcs,
+                       status = ads_dns_query_kdcs(ctx,
+                                                   name,
+                                                   sitename,
+                                                   &dcs,
                                                    &numdcs);
                        break;
                default:
@@ -2142,10 +2426,21 @@ static NTSTATUS resolve_ads(const char *name,
                return status;
        }
 
-       for (i=0;i<numdcs;i++) {
-               numaddrs += MAX(dcs[i].num_ips,1);
+       if (numdcs == 0) {
+               *return_iplist = NULL;
+               *return_count = 0;
+               talloc_destroy(ctx);
+               return NT_STATUS_OK;
        }
 
+       for (i=0;i<numdcs;i++) {
+               if (!dcs[i].ss_s) {
+                       numaddrs += 1;
+               } else {
+                       numaddrs += dcs[i].num_ips;
+               }
+        }
+
        if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) ==
                        NULL ) {
                DEBUG(0,("resolve_ads: malloc failed for %d entries\n",
@@ -2157,47 +2452,114 @@ 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;
 
+       for (i = 0; i < numdcs && (*return_count<numaddrs); i++ ) {
                /* 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++;
+                       /* 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 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;
+                               }
+                       }
                }
+       }
+
+       talloc_destroy(ctx);
+       return NT_STATUS_OK;
+}
+
+static const char **filter_out_nbt_lookup(TALLOC_CTX *mem_ctx,
+                                         const char **resolve_order)
+{
+       size_t i, len, result_idx;
+       const char **result;
 
-               /* 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 */
+       len = 0;
+       while (resolve_order[len] != NULL) {
+               len += 1;
+       }
+
+       result = talloc_array(mem_ctx, const char *, len+1);
+       if (result == NULL) {
+               return NULL;
+       }
 
-               if (!is_zero_addr(&r->ss)) {
-                       (*return_count)++;
+       result_idx = 0;
+
+       for (i=0; i<len; i++) {
+               const char *tok = resolve_order[i];
+
+               if (strequal(tok, "lmhosts") || strequal(tok, "wins") ||
+                   strequal(tok, "bcast")) {
+                       continue;
                }
+               result[result_idx++] = tok;
        }
+       result[result_idx] = NULL;
 
-       talloc_destroy(ctx);
-       return NT_STATUS_OK;
+       return result;
 }
 
 /*******************************************************************
@@ -2216,10 +2578,9 @@ NTSTATUS internal_resolve_name(const char *name,
                                const char *sitename,
                                struct ip_service **return_iplist,
                                int *return_count,
-                               const char *resolve_order)
+                               const char **resolve_order)
 {
-       char *tok;
-       const char *ptr;
+       const char *tok;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        int i;
        TALLOC_CTX *frame = NULL;
@@ -2249,6 +2610,10 @@ NTSTATUS internal_resolve_name(const char *name,
                        SAFE_FREE(*return_iplist);
                        return NT_STATUS_INVALID_PARAMETER;
                }
+               if (is_zero_addr(&(*return_iplist)->ss)) {
+                       SAFE_FREE(*return_iplist);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
                *return_count = 1;
                return NT_STATUS_OK;
        }
@@ -2256,6 +2621,8 @@ 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;
@@ -2266,25 +2633,46 @@ NTSTATUS internal_resolve_name(const char *name,
 
        /* set the name resolution order */
 
-       if (strcmp( resolve_order, "NULL") == 0) {
+       if (resolve_order && strcmp(resolve_order[0], "NULL") == 0) {
                DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!resolve_order[0]) {
-               ptr = "host";
-       } else {
-               ptr = resolve_order;
+       if (!resolve_order || !resolve_order[0]) {
+               static const char *host_order[] = { "host", NULL };
+               resolve_order = host_order;
+       }
+
+       frame = talloc_stackframe();
+
+       if ((strlen(name) > MAX_NETBIOSNAME_LEN - 1) ||
+           (strchr(name, '.') != NULL)) {
+               /*
+                * Don't do NBT lookup, the name would not fit anyway
+                */
+               resolve_order = filter_out_nbt_lookup(frame, resolve_order);
+               if (resolve_order == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
        /* iterate through the name resolution backends */
 
-       frame = talloc_stackframe();
-       while (next_token_talloc(frame, &ptr, &tok, LIST_SEP)) {
+       for (i=0; resolve_order[i]; i++) {
+               tok = resolve_order[i];
+
                if((strequal(tok, "host") || strequal(tok, "hosts"))) {
-                       status = resolve_hosts(name, name_type, return_iplist,
+                       struct sockaddr_storage *ss_list;
+                       status = resolve_hosts(name, name_type,
+                                              talloc_tos(), &ss_list,
                                               return_count);
                        if (NT_STATUS_IS_OK(status)) {
+                               if (!convert_ss2service(return_iplist,
+                                                       ss_list,
+                                                       return_count)) {
+                                       status = NT_STATUS_NO_MEMORY;
+                               }
                                goto done;
                        }
                } else if(strequal( tok, "kdc")) {
@@ -2306,23 +2694,37 @@ NTSTATUS internal_resolve_name(const char *name,
                        if (NT_STATUS_IS_OK(status)) {
                                goto done;
                        }
-               } else if(strequal( tok, "lmhosts")) {
-                       status = resolve_lmhosts(name, name_type,
-                                                return_iplist, return_count);
+               } else if (strequal(tok, "lmhosts")) {
+                       struct sockaddr_storage *ss_list;
+                       status = resolve_lmhosts_file_as_sockaddr(
+                               get_dyn_LMHOSTSFILE(), name, name_type,
+                               talloc_tos(), &ss_list, return_count);
                        if (NT_STATUS_IS_OK(status)) {
+                               if (!convert_ss2service(return_iplist,
+                                                       ss_list,
+                                                       return_count)) {
+                                       status = NT_STATUS_NO_MEMORY;
+                               }
                                goto done;
                        }
-               } else if(strequal( tok, "wins")) {
+               } else if (strequal(tok, "wins")) {
                        /* don't resolve 1D via WINS */
+                       struct sockaddr_storage *ss_list;
                        if (name_type != 0x1D) {
                                status = resolve_wins(name, name_type,
-                                                     return_iplist,
+                                                     talloc_tos(),
+                                                     &ss_list,
                                                      return_count);
                                if (NT_STATUS_IS_OK(status)) {
+                                       if (!convert_ss2service(return_iplist,
+                                                               ss_list,
+                                                               return_count)) {
+                                               status = NT_STATUS_NO_MEMORY;
+                                       }
                                        goto done;
                                }
                        }
-               } else if(strequal( tok, "bcast")) {
+               } else if (strequal(tok, "bcast")) {
                        struct sockaddr_storage *ss_list;
                        status = name_resolve_bcast(
                                name, name_type, talloc_tos(),
@@ -2330,7 +2732,7 @@ NTSTATUS internal_resolve_name(const char *name,
                        if (NT_STATUS_IS_OK(status)) {
                                if (!convert_ss2service(return_iplist,
                                                        ss_list,
-                                                       *return_count)) {
+                                                       return_count)) {
                                        status = NT_STATUS_NO_MEMORY;
                                }
                                goto done;
@@ -2356,10 +2758,7 @@ 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 ) {
@@ -2375,7 +2774,9 @@ 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 */
 
@@ -2413,26 +2814,31 @@ bool resolve_name(const char *name,
        struct ip_service *ss_list = NULL;
        char *sitename = NULL;
        int count = 0;
+       NTSTATUS status;
+       TALLOC_CTX *frame = NULL;
 
        if (is_ipaddress(name)) {
                return interpret_string_addr(return_ss, name, AI_NUMERICHOST);
        }
 
-       sitename = sitename_fetch(lp_realm()); /* wild guess */
+       frame = talloc_stackframe();
 
-       if (NT_STATUS_IS_OK(internal_resolve_name(name, name_type, sitename,
-                                                 &ss_list, &count,
-                                                 lp_name_resolve_order()))) {
+       sitename = sitename_fetch(frame, lp_realm()); /* wild guess */
+
+       status = internal_resolve_name(name, name_type, sitename,
+                                      &ss_list, &count,
+                                      lp_name_resolve_order());
+       if (NT_STATUS_IS_OK(status)) {
                int i;
 
                if (prefer_ipv4) {
                        for (i=0; i<count; i++) {
                                if (!is_zero_addr(&ss_list[i].ss) &&
-                                               !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss) &&
+                                   !is_broadcast_addr((struct sockaddr *)(void *)&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);
+                                       TALLOC_FREE(frame);
                                        return True;
                                }
                        }
@@ -2441,17 +2847,17 @@ bool resolve_name(const char *name,
                /* only return valid addresses for TCP connections */
                for (i=0; i<count; i++) {
                        if (!is_zero_addr(&ss_list[i].ss) &&
-                                       !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss)) {
+                           !is_broadcast_addr((struct sockaddr *)(void *)&ss_list[i].ss)) {
                                *return_ss = ss_list[i].ss;
                                SAFE_FREE(ss_list);
-                               SAFE_FREE(sitename);
+                               TALLOC_FREE(frame);
                                return True;
                        }
                }
        }
 
        SAFE_FREE(ss_list);
-       SAFE_FREE(sitename);
+       TALLOC_FREE(frame);
        return False;
 }
 
@@ -2479,7 +2885,7 @@ NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
        *return_ss_arr = NULL;
 
        if (is_ipaddress(name)) {
-               *return_ss_arr = TALLOC_P(ctx, struct sockaddr_storage);
+               *return_ss_arr = talloc(ctx, struct sockaddr_storage);
                if (!*return_ss_arr) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -2491,12 +2897,12 @@ NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
                return NT_STATUS_OK;
        }
 
-       sitename = sitename_fetch(lp_realm()); /* wild guess */
+       sitename = sitename_fetch(ctx, lp_realm()); /* wild guess */
 
        status = internal_resolve_name(name, name_type, sitename,
                                                  &ss_list, &count,
                                                  lp_name_resolve_order());
-       SAFE_FREE(sitename);
+       TALLOC_FREE(sitename);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -2505,7 +2911,7 @@ 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((struct sockaddr *)&ss_list[i].ss)) {
+                   !is_broadcast_addr((struct sockaddr *)(void *)&ss_list[i].ss)) {
                        num_entries++;
                }
        }
@@ -2524,7 +2930,7 @@ 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((struct sockaddr *)&ss_list[i].ss)) {
+                   !is_broadcast_addr((struct sockaddr *)(void *)&ss_list[i].ss)) {
                        (*return_ss_arr)[num_entries++] = ss_list[i].ss;
                }
        }
@@ -2581,12 +2987,12 @@ bool get_pdc_ip(const char *domain, struct sockaddr_storage *pss)
        struct ip_service *ip_list = NULL;
        int count = 0;
        NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-
+       static const char *ads_order[] = { "ads", NULL };
        /* Look up #1B name */
 
        if (lp_security() == SEC_ADS) {
                status = internal_resolve_name(domain, 0x1b, NULL, &ip_list,
-                                              &count, "ads");
+                                              &count, ads_order);
        }
 
        if (!NT_STATUS_IS_OK(status) || count == 0) {
@@ -2594,6 +3000,7 @@ bool get_pdc_ip(const char *domain, struct sockaddr_storage *pss)
                                               &count,
                                               lp_name_resolve_order());
                if (!NT_STATUS_IS_OK(status)) {
+                       SAFE_FREE(ip_list);
                        return false;
                }
        }
@@ -2627,29 +3034,26 @@ static NTSTATUS get_dc_list(const char *domain,
                        enum dc_lookup_type lookup_type,
                        bool *ordered)
 {
-       char *resolve_order = NULL;
+       const char **resolve_order = NULL;
        char *saf_servername = NULL;
        char *pserver = NULL;
        const char *p;
        char *port_str = NULL;
        int port;
        char *name;
-       int num_addresses = 0;
-       int  local_count, i, j;
+       size_t num_addresses = 0;
+       size_t local_count, i;
        struct ip_service *return_iplist = NULL;
        struct ip_service *auto_ip_list = NULL;
        bool done_auto_lookup = false;
        int auto_count = 0;
        NTSTATUS status;
-       TALLOC_CTX *ctx = talloc_init("get_dc_list");
+       TALLOC_CTX *ctx = talloc_stackframe();
+       int auto_name_type = 0x1C;
 
        *ip_list = NULL;
        *count = 0;
 
-       if (!ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        *ordered = False;
 
        /* if we are restricted to solely using DNS for looking
@@ -2658,62 +3062,53 @@ static NTSTATUS get_dc_list(const char *domain,
           are disabled and ads_only is True, then set the string to
           NULL. */
 
-       resolve_order = talloc_strdup(ctx, lp_name_resolve_order());
+       resolve_order = lp_name_resolve_order();
        if (!resolve_order) {
                status = NT_STATUS_NO_MEMORY;
                goto out;
        }
-       strlower_m(resolve_order);
        if (lookup_type == DC_ADS_ONLY)  {
-               if (strstr( resolve_order, "host")) {
-                       resolve_order = talloc_strdup(ctx, "ads");
+               if (str_list_check_ci(resolve_order, "host")) {
+                       static const char *ads_order[] = { "ads", NULL };
+                       resolve_order = ads_order;
 
                        /* DNS SRV lookups used by the ads resolver
                           are already sorted by priority and weight */
                        *ordered = true;
                } else {
-                        resolve_order = talloc_strdup(ctx, "NULL");
+                       /* this is quite bizarre! */
+                       static const char *null_order[] = { "NULL", NULL };
+                        resolve_order = null_order;
                }
        } else if (lookup_type == DC_KDC_ONLY) {
+               static const char *kdc_order[] = { "kdc", NULL };
                /* DNS SRV lookups used by the ads/kdc resolver
                   are already sorted by priority and weight */
                *ordered = true;
-               resolve_order = talloc_strdup(ctx, "kdc");
-       }
-       if (!resolve_order) {
-               status = NT_STATUS_NO_MEMORY;
-               goto out;
+               resolve_order = kdc_order;
+               auto_name_type = KDC_NAME_TYPE;
        }
 
        /* fetch the server we have affinity for.  Add the
           'password server' list to a search for our domain controllers */
 
-       saf_servername = saf_fetch( domain);
+       saf_servername = saf_fetch(ctx, domain);
 
        if (strequal(domain, lp_workgroup()) || strequal(domain, lp_realm())) {
                pserver = talloc_asprintf(ctx, "%s, %s",
                        saf_servername ? saf_servername : "",
-                       lp_passwordserver());
+                       lp_password_server());
        } else {
                pserver = talloc_asprintf(ctx, "%s, *",
                        saf_servername ? saf_servername : "");
        }
 
-       SAFE_FREE(saf_servername);
+       TALLOC_FREE(saf_servername);
        if (!pserver) {
                status = NT_STATUS_NO_MEMORY;
                goto out;
        }
 
-       /* if we are starting from scratch, just lookup DOMAIN<0x1c> */
-
-       if (!*pserver ) {
-               DEBUG(10,("get_dc_list: no preferred domain controllers.\n"));
-               status = internal_resolve_name(domain, 0x1C, sitename, ip_list,
-                                            count, resolve_order);
-               goto out;
-       }
-
        DEBUG(3,("get_dc_list: preferred server list: \"%s\"\n", pserver ));
 
        /*
@@ -2726,7 +3121,8 @@ static NTSTATUS get_dc_list(const char *domain,
        p = pserver;
        while (next_token_talloc(ctx, &p, &name, LIST_SEP)) {
                if (!done_auto_lookup && strequal(name, "*")) {
-                       status = internal_resolve_name(domain, 0x1C, sitename,
+                       status = internal_resolve_name(domain, auto_name_type,
+                                                      sitename,
                                                       &auto_ip_list,
                                                       &auto_count,
                                                       resolve_order);
@@ -2744,13 +3140,14 @@ static NTSTATUS get_dc_list(const char *domain,
        /* if we have no addresses and haven't done the auto lookup, then
           just return the list of DC's.  Or maybe we just failed. */
 
-       if ((num_addresses == 0)) {
+       if (num_addresses == 0) {
                if (done_auto_lookup) {
                        DEBUG(4,("get_dc_list: no servers found\n"));
                        status = NT_STATUS_NO_LOGON_SERVERS;
                        goto out;
                }
-               status = internal_resolve_name(domain, 0x1C, sitename, ip_list,
+               status = internal_resolve_name(domain, auto_name_type,
+                                              sitename, ip_list,
                                             count, resolve_order);
                goto out;
        }
@@ -2771,9 +3168,10 @@ static NTSTATUS get_dc_list(const char *domain,
                        next_token_talloc(ctx, &p, &name, LIST_SEP)) {
                struct sockaddr_storage name_ss;
 
-               /* copy any addersses from the auto lookup */
+               /* copy any addresses from the auto lookup */
 
                if (strequal(name, "*")) {
+                       int j;
                        for (j=0; j<auto_count; j++) {
                                char addr[INET6_ADDRSTRLEN];
                                print_sockaddr(addr,
@@ -2802,13 +3200,19 @@ static NTSTATUS get_dc_list(const char *domain,
                /* added support for address:port syntax for ads
                 * (not that I think anyone will ever run the LDAP
                 * server in an AD domain on something other than
-                * port 389 */
+                * port 389
+                * However, the port should not be used for kerberos
+                */
 
-               port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
+               port = (lookup_type == DC_ADS_ONLY) ? LDAP_PORT :
+                       ((lookup_type == DC_KDC_ONLY) ? DEFAULT_KRB5_PORT :
+                        PORT_NONE);
                if ((port_str=strchr(name, ':')) != NULL) {
                        *port_str = '\0';
-                       port_str++;
-                       port = atoi(port_str);
+                       if (lookup_type != DC_KDC_ONLY) {
+                               port_str++;
+                               port = atoi(port_str);
+                       }
                }
 
                /* explicit lookup; resolve_name() will
@@ -2838,10 +3242,7 @@ 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. */
@@ -2851,7 +3252,7 @@ static NTSTATUS get_dc_list(const char *domain,
        }
 
        if ( DEBUGLEVEL >= 4 ) {
-               DEBUG(4,("get_dc_list: returning %d ip addresses "
+               DEBUG(4,("get_dc_list: returning %zu ip addresses "
                                "in an %sordered list\n",
                                local_count,
                                *ordered ? "":"un"));
@@ -2902,10 +3303,9 @@ NTSTATUS get_sorted_dc_list( const char *domain,
        *count = 0;
 
        DEBUG(8,("get_sorted_dc_list: attempting lookup "
-               "for name %s (sitename %s) using [%s]\n",
+               "for name %s (sitename %s)\n",
                domain,
-               sitename ? sitename : "NULL",
-               (ads_only ? "ads" : lp_name_resolve_order())));
+                sitename ? sitename : "NULL"));
 
        if (ads_only) {
                lookup_type = DC_ADS_ONLY;