s3-messages: make ndr_messaging.h part of messages.h.
[samba.git] / source3 / libsmb / namequery.c
index 34fe09b8c2988e475d4af827daefb09b1656de83..ef7aab6a6aacb44dcd531d4204404beee4df9fce 100644 (file)
 */
 
 #include "includes.h"
+#include "libads/sitename_cache.h"
+#include "libads/dns.h"
+#include "../libcli/netlogon/netlogon.h"
+#include "lib/async_req/async_sock.h"
+#include "libsmb/nmblib.h"
 
 /* nmbd.c sets this to True. */
 bool global_in_nmbd = False;
@@ -34,12 +39,23 @@ 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)
 {
        char *keystr;
 
-       asprintf( &keystr, SAFKEY_FMT, strupper_static(domain) );
+       asprintf_strupper_m(&keystr, SAFKEY_FMT, domain);
+
+       return keystr;
+}
+
+static char *saf_join_key(const char *domain)
+{
+       char *keystr;
+
+       asprintf_strupper_m(&keystr, SAFJOINKEY_FMT, domain);
 
        return keystr;
 }
@@ -65,11 +81,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 +94,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 +133,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 +167,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 );
 
@@ -158,11 +213,11 @@ static int generate_trn_id(void)
  Parse a node status response into an array of structures.
 ****************************************************************************/
 
-static NODE_STATUS_STRUCT *parse_node_status(char *p,
+static struct node_status *parse_node_status(TALLOC_CTX *mem_ctx, char *p,
                                int *num_names,
                                struct node_status_extra *extra)
 {
-       NODE_STATUS_STRUCT *ret;
+       struct node_status *ret;
        int i;
 
        *num_names = CVAL(p,0);
@@ -170,7 +225,7 @@ static NODE_STATUS_STRUCT *parse_node_status(char *p,
        if (*num_names == 0)
                return NULL;
 
-       ret = SMB_MALLOC_ARRAY(NODE_STATUS_STRUCT,*num_names);
+       ret = TALLOC_ARRAY(mem_ctx, struct node_status,*num_names);
        if (!ret)
                return NULL;
 
@@ -193,33 +248,468 @@ static NODE_STATUS_STRUCT *parse_node_status(char *p,
        return ret;
 }
 
+struct sock_packet_read_state {
+       struct tevent_context *ev;
+       enum packet_type type;
+       int trn_id;
+
+       struct nb_packet_reader *reader;
+       struct tevent_req *reader_req;
+
+       int sock;
+       struct tevent_req *socket_req;
+       uint8_t buf[1024];
+       struct sockaddr_storage addr;
+       socklen_t addr_len;
+
+       bool (*validator)(struct packet_struct *p,
+                         void *private_data);
+       void *private_data;
+
+       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 nb_packet_reader *reader,
+       enum packet_type type,
+       int trn_id,
+       bool (*validator)(struct packet_struct *p, void *private_data),
+       void *private_data)
+{
+       struct tevent_req *req;
+       struct sock_packet_read_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct sock_packet_read_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       talloc_set_destructor(state, sock_packet_read_state_destructor);
+       state->ev = ev;
+       state->reader = reader;
+       state->sock = sock;
+       state->type = type;
+       state->trn_id = trn_id;
+       state->validator = validator;
+       state->private_data = private_data;
+
+       if (reader != NULL) {
+               state->reader_req = nb_packet_read_send(state, ev, reader);
+               if (tevent_req_nomem(state->reader_req, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(
+                       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);
+       if (tevent_req_nomem(state->socket_req, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
+                               req);
+
+       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(
+               subreq, struct tevent_req);
+       struct sock_packet_read_state *state = tevent_req_data(
+               req, struct sock_packet_read_state);
+       NTSTATUS status;
+
+       status = nb_packet_read_recv(subreq, &state->packet);
+
+       TALLOC_FREE(state->reader_req);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               if (state->socket_req != NULL) {
+                       /*
+                        * Still waiting for socket
+                        */
+                       return;
+               }
+               /*
+                * Both socket and packet reader failed
+                */
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       if ((state->validator != NULL) &&
+           !state->validator(state->packet, state->private_data)) {
+               DEBUG(10, ("validator failed\n"));
+
+               free_packet(state->packet);
+               state->packet = NULL;
+
+               state->reader_req = nb_packet_read_send(state, state->ev,
+                                                       state->reader);
+               if (tevent_req_nomem(state->reader_req, req)) {
+                       return;
+               }
+               tevent_req_set_callback(
+                       state->reader_req, sock_packet_read_got_packet, req);
+               return;
+       }
+
+       TALLOC_FREE(state->socket_req);
+       tevent_req_done(req);
+}
+
+static void sock_packet_read_got_socket(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct sock_packet_read_state *state = tevent_req_data(
+               req, struct sock_packet_read_state);
+       struct sockaddr_in *in_addr;
+       ssize_t received;
+       int err;
+
+       received = recvfrom_recv(subreq, &err);
+
+       TALLOC_FREE(state->socket_req);
+
+       if (received == -1) {
+               if (state->reader_req != NULL) {
+                       /*
+                        * Still waiting for reader
+                        */
+                       return;
+               }
+               /*
+                * Both socket and reader failed
+                */
+               tevent_req_nterror(req, map_nt_error_from_unix(err));
+               return;
+       }
+       if (state->addr.ss_family != AF_INET) {
+               goto retry;
+       }
+       in_addr = (struct sockaddr_in *)(void *)&state->addr;
+
+       state->packet = parse_packet((char *)state->buf, received, state->type,
+                                    in_addr->sin_addr, in_addr->sin_port);
+       if (state->packet == NULL) {
+               DEBUG(10, ("parse_packet failed\n"));
+               goto retry;
+       }
+       if ((state->trn_id != -1) &&
+           (state->trn_id != packet_trn_id(state->packet))) {
+               DEBUG(10, ("Expected transaction id %d, got %d\n",
+                          state->trn_id, packet_trn_id(state->packet)));
+               goto retry;
+       }
+
+       if ((state->validator != NULL) &&
+           !state->validator(state->packet, state->private_data)) {
+               DEBUG(10, ("validator failed\n"));
+               goto retry;
+       }
+
+       tevent_req_done(req);
+       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);
+       if (tevent_req_nomem(state->socket_req, req)) {
+               return;
+       }
+       tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
+                               req);
+}
+
+static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
+                                     struct packet_struct **ppacket)
+{
+       struct sock_packet_read_state *state = tevent_req_data(
+               req, struct sock_packet_read_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *ppacket = state->packet;
+       state->packet = NULL;
+       return NT_STATUS_OK;
+}
+
+struct nb_trans_state {
+       struct tevent_context *ev;
+       int sock;
+       struct nb_packet_reader *reader;
+
+       const struct sockaddr_storage *dst_addr;
+       uint8_t *buf;
+       size_t buflen;
+       enum packet_type type;
+       int trn_id;
+
+       bool (*validator)(struct packet_struct *p,
+                         void *private_data);
+       void *private_data;
+
+       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);
+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,
+       bool bcast,
+       uint8_t *buf, size_t buflen,
+       enum packet_type type, int trn_id,
+       bool (*validator)(struct packet_struct *p,
+                         void *private_data),
+       void *private_data)
+{
+       struct tevent_req *req, *subreq;
+       struct nb_trans_state *state;
+
+       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;
+       state->trn_id = trn_id;
+       state->validator = validator;
+       state->private_data = private_data;
+
+       state->sock = open_socket_in(SOCK_DGRAM, 0, 3, my_addr, True);
+       if (state->sock == -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");
+       }
+
+       subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, nb_trans_got_reader, req);
+       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(
+               subreq, struct tevent_req);
+       struct nb_trans_state *state = tevent_req_data(
+               req, struct nb_trans_state);
+       NTSTATUS status;
+
+       status = nb_packet_reader_recv(subreq, state, &state->reader);
+       TALLOC_FREE(subreq);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("nmbd not around\n"));
+               state->reader = NULL;
+       }
+
+       subreq = sock_packet_read_send(
+               state, state->ev, state->sock,
+               state->reader, state->type, state->trn_id,
+               state->validator, state->private_data);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       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);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, nb_trans_sent, req);
+}
+
+static void nb_trans_sent(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct nb_trans_state *state = tevent_req_data(
+               req, struct nb_trans_state);
+       ssize_t sent;
+       int err;
+
+       sent = sendto_recv(subreq, &err);
+       TALLOC_FREE(subreq);
+       if (sent == -1) {
+               DEBUG(10, ("sendto failed: %s\n", strerror(err)));
+               tevent_req_nterror(req, map_nt_error_from_unix(err));
+               return;
+       }
+       subreq = tevent_wakeup_send(state, state->ev,
+                                   timeval_current_ofs(1, 0));
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, nb_trans_send_next, req);
+}
+
+static void nb_trans_send_next(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct nb_trans_state *state = tevent_req_data(
+               req, struct nb_trans_state);
+       bool ret;
+
+       ret = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ret) {
+               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);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, nb_trans_sent, req);
+}
+
+static void nb_trans_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct nb_trans_state *state = tevent_req_data(
+               req, struct nb_trans_state);
+       NTSTATUS status;
+
+       status = sock_packet_read_recv(subreq, &state->packet);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static NTSTATUS nb_trans_recv(struct tevent_req *req,
+                             struct packet_struct **ppacket)
+{
+       struct nb_trans_state *state = tevent_req_data(
+               req, struct nb_trans_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *ppacket = state->packet;
+       state->packet = NULL;
+       return NT_STATUS_OK;
+}
 
 /****************************************************************************
  Do a NBT node status query on an open socket and return an array of
  structures holding the returned names or NULL if the query failed.
 **************************************************************************/
 
-NODE_STATUS_STRUCT *node_status_query(int fd,
-                                       struct nmb_name *name,
-                                       const struct sockaddr_storage *to_ss,
-                                       int *num_names,
-                                       struct node_status_extra *extra)
+struct node_status_query_state {
+       struct sockaddr_storage my_addr;
+       struct sockaddr_storage addr;
+       uint8_t buf[1024];
+       ssize_t buflen;
+       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);
+
+struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct nmb_name *name,
+                                         const struct sockaddr_storage *addr)
 {
-       bool found=False;
-       int retries = 2;
-       int retry_time = 2000;
-       struct timeval tval;
+       struct tevent_req *req, *subreq;
+       struct node_status_query_state *state;
        struct packet_struct p;
-       struct packet_struct *p2;
        struct nmb_packet *nmb = &p.packet.nmb;
-       NODE_STATUS_STRUCT *ret;
+       struct sockaddr_in *in_addr;
 
-       ZERO_STRUCT(p);
+       req = tevent_req_create(mem_ctx, &state,
+                               struct node_status_query_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       talloc_set_destructor(state, node_status_query_state_destructor);
 
-       if (to_ss->ss_family != AF_INET) {
+       if (addr->ss_family != AF_INET) {
                /* Can't do node status to IPv6 */
-               return NULL;
+               tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+               return tevent_req_post(req, ev);
        }
+
+       state->addr = *addr;
+       in_addr = (struct sockaddr_in *)(void *)&state->addr;
+       in_addr->sin_port = htons(NMB_PORT);
+
+       if (!interpret_string_addr(&state->my_addr, lp_socket_address(),
+                                  AI_NUMERICHOST|AI_PASSIVE)) {
+               zero_sockaddr(&state->my_addr);
+       }
+
+       ZERO_STRUCT(p);
        nmb->header.name_trn_id = generate_trn_id();
        nmb->header.opcode = 0;
        nmb->header.response = false;
@@ -237,55 +727,127 @@ NODE_STATUS_STRUCT *node_status_query(int fd,
        nmb->question.question_type = 0x21;
        nmb->question.question_class = 0x1;
 
-       p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
-       p.port = NMB_PORT;
-       p.fd = fd;
-       p.timestamp = time(NULL);
-       p.packet_type = NMB_PACKET;
+       state->buflen = build_packet((char *)state->buf, sizeof(state->buf),
+                                    &p);
+       if (state->buflen == 0) {
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               DEBUG(10, ("build_packet failed\n"));
+               return tevent_req_post(req, ev);
+       }
+
+       subreq = nb_trans_send(state, ev, &state->my_addr, &state->addr, false,
+                              state->buf, state->buflen,
+                              NMB_PACKET, nmb->header.name_trn_id,
+                              node_status_query_validator, NULL);
+       if (tevent_req_nomem(subreq, req)) {
+               DEBUG(10, ("nb_trans_send failed\n"));
+               return tevent_req_post(req, ev);
+       }
+       if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(10, 0))) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, node_status_query_done, req);
+       return req;
+}
 
-       GetTimeOfDay(&tval);
+static bool node_status_query_validator(struct packet_struct *p,
+                                       void *private_data)
+{
+       struct nmb_packet *nmb = &p->packet.nmb;
+       debug_nmb_packet(p);
+
+       if (nmb->header.opcode != 0 ||
+           nmb->header.nm_flags.bcast ||
+           nmb->header.rcode ||
+           !nmb->header.ancount ||
+           nmb->answers->rr_type != 0x21) {
+               /*
+                * XXXX what do we do with this? could be a redirect,
+                * but we'll discard it for the moment
+                */
+               return false;
+       }
+       return true;
+}
 
-       if (!send_packet(&p))
-               return NULL;
+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;
+}
 
-       retries--;
+static void node_status_query_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct node_status_query_state *state = tevent_req_data(
+               req, struct node_status_query_state);
+       NTSTATUS status;
 
-       while (1) {
-               struct timeval tval2;
-               GetTimeOfDay(&tval2);
-               if (TvalDiff(&tval,&tval2) > retry_time) {
-                       if (!retries)
-                               break;
-                       if (!found && !send_packet(&p))
-                               return NULL;
-                       GetTimeOfDay(&tval);
-                       retries--;
-               }
+       status = nb_trans_recv(subreq, &state->packet);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       tevent_req_done(req);
+}
 
-               if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
-                       struct nmb_packet *nmb2 = &p2->packet.nmb;
-                       debug_nmb_packet(p2);
-
-                       if (nmb2->header.opcode != 0 ||
-                           nmb2->header.nm_flags.bcast ||
-                           nmb2->header.rcode ||
-                           !nmb2->header.ancount ||
-                           nmb2->answers->rr_type != 0x21) {
-                               /* XXXX what do we do with this? could be a
-                                  redirect, but we'll discard it for the
-                                  moment */
-                               free_packet(p2);
-                               continue;
-                       }
+NTSTATUS node_status_query_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                               struct node_status **pnode_status,
+                               int *pnum_names,
+                               struct node_status_extra *extra)
+{
+       struct node_status_query_state *state = tevent_req_data(
+               req, struct node_status_query_state);
+       struct node_status *node_status;
+       int num_names;
+       NTSTATUS status;
 
-                       ret = parse_node_status(&nmb2->answers->rdata[0],
-                                       num_names, extra);
-                       free_packet(p2);
-                       return ret;
-               }
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       node_status = parse_node_status(
+               mem_ctx, &state->packet->packet.nmb.answers->rdata[0],
+               &num_names, extra);
+       if (node_status == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
+       *pnode_status = node_status;
+       *pnum_names = num_names;
+       return NT_STATUS_OK;
+}
 
-       return NULL;
+NTSTATUS node_status_query(TALLOC_CTX *mem_ctx, struct nmb_name *name,
+                          const struct sockaddr_storage *addr,
+                          struct node_status **pnode_status,
+                          int *pnum_names,
+                          struct node_status_extra *extra)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = node_status_query_send(ev, ev, name, addr);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = node_status_query_recv(req, mem_ctx, pnode_status,
+                                       pnum_names, extra);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
 }
 
 /****************************************************************************
@@ -301,11 +863,11 @@ bool name_status_find(const char *q_name,
 {
        char addr[INET6_ADDRSTRLEN];
        struct sockaddr_storage ss;
-       NODE_STATUS_STRUCT *status = NULL;
+       struct node_status *addrs = NULL;
        struct nmb_name nname;
        int count, i;
-       int sock;
        bool result = false;
+       NTSTATUS status;
 
        if (lp_disable_netbios()) {
                DEBUG(5,("name_status_find(%s#%02x): netbios is disabled\n",
@@ -331,28 +893,26 @@ bool name_status_find(const char *q_name,
 
        if (!interpret_string_addr(&ss, lp_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
-               zero_addr(&ss, AF_INET);
+               zero_sockaddr(&ss);
        }
 
-       sock = open_socket_in(SOCK_DGRAM, 0, 3, &ss, True);
-       if (sock == -1)
-               goto done;
-
        /* W2K PDC's seem not to respond to '*'#0. JRA */
        make_nmb_name(&nname, q_name, q_type);
-       status = node_status_query(sock, &nname, to_ss, &count, NULL);
-       close(sock);
-       if (!status)
+       status = node_status_query(talloc_tos(), &nname, to_ss,
+                                  &addrs, &count, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
                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 (addrs[i].type == type && ! (addrs[i].flags & 0x80))
                        break;
        }
        if (i == count)
                goto done;
 
-       pull_ascii_nstring(name, sizeof(fstring), status[i].name);
+       pull_ascii_nstring(name, sizeof(fstring), addrs[i].name);
 
        /* Store the result in the cache. */
        /* but don't store an entry for 0x1c names here.  Here we have
@@ -365,7 +925,7 @@ bool name_status_find(const char *q_name,
        result = true;
 
  done:
-       SAFE_FREE(status);
+       TALLOC_FREE(addrs);
 
        DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
 
@@ -382,18 +942,18 @@ bool name_status_find(const char *q_name,
 */
 
 static int addr_compare(const struct sockaddr_storage *ss1,
-               const struct sockaddr_storage *ss2)
+                       const struct sockaddr_storage *ss2)
 {
        int max_bits1=0, max_bits2=0;
        int num_interfaces = iface_count();
        int i;
 
-       /* Sort IPv6 addresses first. */
+       /* Sort IPv4 addresses first. */
        if (ss1->ss_family != ss2->ss_family) {
                if (ss2->ss_family == AF_INET) {
-                       return -1;
-               } else {
                        return 1;
+               } else {
+                       return -1;
                }
        }
 
@@ -442,14 +1002,14 @@ static int addr_compare(const struct sockaddr_storage *ss1,
        }
 
        /* Bias towards directly reachable IPs */
-       if (iface_local(ss1)) {
+       if (iface_local((struct sockaddr *)ss1)) {
                if (ss1->ss_family == AF_INET) {
                        max_bits1 += 32;
                } else {
                        max_bits1 += 128;
                }
        }
-       if (iface_local(ss2)) {
+       if (iface_local((struct sockaddr *)ss2)) {
                if (ss2->ss_family == AF_INET) {
                        max_bits2 += 32;
                } else {
@@ -494,8 +1054,7 @@ static void sort_addr_list(struct sockaddr_storage *sslist, int count)
                return;
        }
 
-       qsort(sslist, count, sizeof(struct sockaddr_storage),
-                       QSORT_CAST addr_compare);
+       TYPESAFE_QSORT(sslist, count, addr_compare);
 }
 
 static void sort_service_list(struct ip_service *servlist, int count)
@@ -504,8 +1063,7 @@ static void sort_service_list(struct ip_service *servlist, int count)
                return;
        }
 
-       qsort(servlist, count, sizeof(struct ip_service),
-                       QSORT_CAST ip_service_compare);
+       TYPESAFE_QSORT(servlist, count, ip_service_compare);
 }
 
 /**********************************************************************
@@ -526,9 +1084,9 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
                }
 
                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, AF_INET);
+                               zero_sockaddr(&iplist[j].ss);
                        }
                }
        }
@@ -550,6 +1108,38 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
        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.
@@ -557,43 +1147,67 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
  *timed_out is set if we failed by timing out
 ****************************************************************************/
 
-struct sockaddr_storage *name_query(int fd,
-                       const char *name,
-                       int name_type,
-                       bool bcast,
-                       bool recurse,
-                       const struct sockaddr_storage *to_ss,
-                       int *count,
-                       int *flags,
-                       bool *timed_out)
+struct name_query_state {
+       struct sockaddr_storage my_addr;
+       struct sockaddr_storage addr;
+       bool bcast;
+
+
+       uint8_t buf[1024];
+       ssize_t buflen;
+
+       NTSTATUS validate_error;
+       uint8_t flags;
+
+       struct sockaddr_storage *addrs;
+       int num_addrs;
+};
+
+static bool name_query_validator(struct packet_struct *p, void *private_data);
+static void name_query_done(struct tevent_req *subreq);
+
+struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev,
+                                  const char *name, int name_type,
+                                  bool bcast, bool recurse,
+                                  const struct sockaddr_storage *addr)
 {
-       bool found=false;
-       int i, retries = 3;
-       int retry_time = bcast?250:2000;
-       struct timeval tval;
+       struct tevent_req *req, *subreq;
+       struct name_query_state *state;
        struct packet_struct p;
-       struct packet_struct *p2;
        struct nmb_packet *nmb = &p.packet.nmb;
-       struct sockaddr_storage *ss_list = NULL;
+       struct sockaddr_in *in_addr;
+       struct timeval timeout;
 
-       if (lp_disable_netbios()) {
-               DEBUG(5,("name_query(%s#%02x): netbios is disabled\n",
-                                       name, name_type));
+       req = tevent_req_create(mem_ctx, &state, struct name_query_state);
+       if (req == NULL) {
                return NULL;
        }
+       state->bcast = bcast;
 
-       if (to_ss->ss_family != AF_INET) {
-               return NULL;
+       if (addr->ss_family != AF_INET) {
+               /* Can't do node status to IPv6 */
+               tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+               return tevent_req_post(req, ev);
        }
 
-       if (timed_out) {
-               *timed_out = false;
+       if (lp_disable_netbios()) {
+               DEBUG(5,("name_query(%s#%02x): netbios is disabled\n",
+                                       name, name_type));
+               tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
+               return tevent_req_post(req, ev);
        }
 
-       memset((char *)&p,'\0',sizeof(p));
-       (*count) = 0;
-       (*flags) = 0;
+       state->addr = *addr;
+       in_addr = (struct sockaddr_in *)(void *)&state->addr;
+       in_addr->sin_port = htons(NMB_PORT);
+
+       if (!interpret_string_addr(&state->my_addr, lp_socket_address(),
+                                  AI_NUMERICHOST|AI_PASSIVE)) {
+               zero_sockaddr(&state->my_addr);
+       }
 
+       ZERO_STRUCT(p);
        nmb->header.name_trn_id = generate_trn_id();
        nmb->header.opcode = 0;
        nmb->header.response = false;
@@ -613,270 +1227,229 @@ struct sockaddr_storage *name_query(int fd,
        nmb->question.question_type = 0x20;
        nmb->question.question_class = 0x1;
 
-       p.ip = ((struct sockaddr_in *)to_ss)->sin_addr;
-       p.port = NMB_PORT;
-       p.fd = fd;
-       p.timestamp = time(NULL);
-       p.packet_type = NMB_PACKET;
-
-       GetTimeOfDay(&tval);
+       state->buflen = build_packet((char *)state->buf, sizeof(state->buf),
+                                    &p);
+       if (state->buflen == 0) {
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               DEBUG(10, ("build_packet failed\n"));
+               return tevent_req_post(req, ev);
+       }
 
-       if (!send_packet(&p))
-               return NULL;
+       subreq = nb_trans_send(state, ev, &state->my_addr, &state->addr, bcast,
+                              state->buf, state->buflen,
+                              NMB_PACKET, nmb->header.name_trn_id,
+                              name_query_validator, state);
+       if (tevent_req_nomem(subreq, req)) {
+               DEBUG(10, ("nb_trans_send failed\n"));
+               return tevent_req_post(req, ev);
+       }
+       if (bcast) {
+               timeout = timeval_current_ofs(0, 250000);
+       } else {
+               timeout = timeval_current_ofs(2, 0);
+       }
+       if (!tevent_req_set_endtime(req, ev, timeout)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, name_query_done, req);
+       return req;
+}
 
-       retries--;
+static bool name_query_validator(struct packet_struct *p, void *private_data)
+{
+       struct name_query_state *state = talloc_get_type_abort(
+               private_data, struct name_query_state);
+       struct nmb_packet *nmb = &p->packet.nmb;
+       struct sockaddr_storage *tmp_addrs;
+       int i;
 
-       while (1) {
-               struct timeval tval2;
+       debug_nmb_packet(p);
 
-               GetTimeOfDay(&tval2);
-               if (TvalDiff(&tval,&tval2) > retry_time) {
-                       if (!retries)
+       /*
+        * If we get a Negative Name Query Response from a WINS
+        * server, we should report it and give up.
+        */
+       if( 0 == nmb->header.opcode     /* A query response   */
+           && !state->bcast            /* from a WINS server */
+           && nmb->header.rcode        /* Error returned     */
+               ) {
+
+               if( DEBUGLVL( 3 ) ) {
+                       /* Only executed if DEBUGLEVEL >= 3 */
+                       dbgtext( "Negative name query "
+                                "response, rcode 0x%02x: ",
+                                nmb->header.rcode );
+                       switch( nmb->header.rcode ) {
+                       case 0x01:
+                               dbgtext("Request was invalidly formatted.\n");
                                break;
-                       if (!found && !send_packet(&p))
-                               return NULL;
-                       GetTimeOfDay(&tval);
-                       retries--;
-               }
-
-               if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
-                       struct nmb_packet *nmb2 = &p2->packet.nmb;
-                       debug_nmb_packet(p2);
-
-                       /* If we get a Negative Name Query Response from a WINS
-                        * server, we should report it and give up.
-                        */
-                       if( 0 == nmb2->header.opcode    /* A query response   */
-                           && !(bcast)                 /* from a WINS server */
-                           && nmb2->header.rcode       /* Error returned     */
-                               ) {
-
-                               if( DEBUGLVL( 3 ) ) {
-                                       /* Only executed if DEBUGLEVEL >= 3 */
-                                       dbgtext( "Negative name query "
-                                               "response, rcode 0x%02x: ",
-                                               nmb2->header.rcode );
-                                       switch( nmb2->header.rcode ) {
-                                       case 0x01:
-                                               dbgtext( "Request "
-                                               "was invalidly formatted.\n" );
-                                               break;
-                                       case 0x02:
-                                               dbgtext( "Problem with NBNS, "
-                                               "cannot process name.\n");
-                                               break;
-                                       case 0x03:
-                                               dbgtext( "The name requested "
-                                               "does not exist.\n" );
-                                               break;
-                                       case 0x04:
-                                               dbgtext( "Unsupported request "
-                                               "error.\n" );
-                                               break;
-                                       case 0x05:
-                                               dbgtext( "Query refused "
-                                               "error.\n" );
-                                               break;
-                                       default:
-                                               dbgtext( "Unrecognized error "
-                                               "code.\n" );
-                                               break;
-                                       }
-                               }
-                               free_packet(p2);
-                               return( NULL );
-                       }
-
-                       if (nmb2->header.opcode != 0 ||
-                           nmb2->header.nm_flags.bcast ||
-                           nmb2->header.rcode ||
-                           !nmb2->header.ancount) {
-                               /*
-                                * XXXX what do we do with this? Could be a
-                                * redirect, but we'll discard it for the
-                                * moment.
-                                */
-                               free_packet(p2);
-                               continue;
-                       }
-
-                       ss_list = SMB_REALLOC_ARRAY(ss_list,
-                                               struct sockaddr_storage,
-                                               (*count) +
-                                               nmb2->answers->rdlength/6);
-
-                       if (!ss_list) {
-                               DEBUG(0,("name_query: Realloc failed.\n"));
-                               free_packet(p2);
-                               return NULL;
-                       }
-
-                       DEBUG(2,("Got a positive name query response "
-                                       "from %s ( ",
-                                       inet_ntoa(p2->ip)));
-
-                       for (i=0;i<nmb2->answers->rdlength/6;i++) {
-                               struct in_addr ip;
-                               putip((char *)&ip,&nmb2->answers->rdata[2+i*6]);
-                               in_addr_to_sockaddr_storage(&ss_list[(*count)],
-                                               ip);
-                               DEBUGADD(2,("%s ",inet_ntoa(ip)));
-                               (*count)++;
-                       }
-                       DEBUGADD(2,(")\n"));
-
-                       found=true;
-                       retries=0;
-                       /* We add the flags back ... */
-                       if (nmb2->header.response)
-                               (*flags) |= NM_FLAGS_RS;
-                       if (nmb2->header.nm_flags.authoritative)
-                               (*flags) |= NM_FLAGS_AA;
-                       if (nmb2->header.nm_flags.trunc)
-                               (*flags) |= NM_FLAGS_TC;
-                       if (nmb2->header.nm_flags.recursion_desired)
-                               (*flags) |= NM_FLAGS_RD;
-                       if (nmb2->header.nm_flags.recursion_available)
-                               (*flags) |= NM_FLAGS_RA;
-                       if (nmb2->header.nm_flags.bcast)
-                               (*flags) |= NM_FLAGS_B;
-                       free_packet(p2);
-                       /*
-                        * If we're doing a unicast lookup we only
-                        * expect one reply. Don't wait the full 2
-                        * seconds if we got one. JRA.
-                        */
-                       if(!bcast && found)
+                       case 0x02:
+                               dbgtext("Problem with NBNS, cannot process "
+                                       "name.\n");
+                               break;
+                       case 0x03:
+                               dbgtext("The name requested does not "
+                                       "exist.\n");
+                               break;
+                       case 0x04:
+                               dbgtext("Unsupported request error.\n");
+                               break;
+                       case 0x05:
+                               dbgtext("Query refused error.\n");
                                break;
+                       default:
+                               dbgtext("Unrecognized error code.\n" );
+                               break;
+                       }
                }
+
+               /*
+                * We accept this packet as valid, but tell the upper
+                * layers that it's a negative response.
+                */
+               state->validate_error = NT_STATUS_NOT_FOUND;
+               return true;
        }
 
-       /* only set timed_out if we didn't fund what we where looking for*/
+       if (nmb->header.opcode != 0 ||
+           nmb->header.nm_flags.bcast ||
+           nmb->header.rcode ||
+           !nmb->header.ancount) {
+               /*
+                * XXXX what do we do with this? Could be a redirect,
+                * but we'll discard it for the moment.
+                */
+               return false;
+       }
 
-       if ( !found && timed_out ) {
-               *timed_out = true;
+       tmp_addrs = TALLOC_REALLOC_ARRAY(
+               state, state->addrs, struct sockaddr_storage,
+               state->num_addrs + nmb->answers->rdlength/6);
+       if (tmp_addrs == NULL) {
+               state->validate_error = NT_STATUS_NO_MEMORY;
+               return true;
        }
+       state->addrs = tmp_addrs;
 
-       /* sort the ip list so we choose close servers first if possible */
-       sort_addr_list(ss_list, *count);
+       DEBUG(2,("Got a positive name query response "
+                "from %s ( ", inet_ntoa(p->ip)));
 
-       return ss_list;
+       for (i=0; i<nmb->answers->rdlength/6; i++) {
+               struct in_addr ip;
+               putip((char *)&ip,&nmb->answers->rdata[2+i*6]);
+               in_addr_to_sockaddr_storage(
+                       &state->addrs[state->num_addrs], ip);
+               DEBUGADD(2,("%s ",inet_ntoa(ip)));
+               state->num_addrs += 1;
+       }
+       DEBUGADD(2,(")\n"));
+
+       /* We add the flags back ... */
+       if (nmb->header.response)
+               state->flags |= NM_FLAGS_RS;
+       if (nmb->header.nm_flags.authoritative)
+               state->flags |= NM_FLAGS_AA;
+       if (nmb->header.nm_flags.trunc)
+               state->flags |= NM_FLAGS_TC;
+       if (nmb->header.nm_flags.recursion_desired)
+               state->flags |= NM_FLAGS_RD;
+       if (nmb->header.nm_flags.recursion_available)
+               state->flags |= NM_FLAGS_RA;
+       if (nmb->header.nm_flags.bcast)
+               state->flags |= NM_FLAGS_B;
+
+       if (state->bcast) {
+               /*
+                * We have to collect all entries coming in from
+                * broadcast queries
+                */
+               return false;
+       }
+       /*
+        * WINS responses are accepted when they are received
+        */
+       return true;
 }
 
-/********************************************************
- Start parsing the lmhosts file.
-*********************************************************/
-
-XFILE *startlmhosts(const char *fname)
+static void name_query_done(struct tevent_req *subreq)
 {
-       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;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct name_query_state *state = tevent_req_data(
+               req, struct name_query_state);
+       NTSTATUS status;
+       struct packet_struct *p = NULL;
+
+       status = nb_trans_recv(subreq, &p);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
-       return fp;
+       if (!NT_STATUS_IS_OK(state->validate_error)) {
+               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);
 }
 
-/********************************************************
- Parse the next line in the lmhosts file.
-*********************************************************/
-
-bool getlmhostsent(XFILE *fp, pstring name, int *name_type,
-               struct sockaddr_storage *pss)
+NTSTATUS name_query_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                        struct sockaddr_storage **addrs, int *num_addrs,
+                        uint8_t *flags)
 {
-       pstring line;
-
-       while(!x_feof(fp) && !x_ferror(fp)) {
-               pstring ip,flags,extra;
-               const char *ptr;
-               char *ptr1;
-               int count = 0;
-
-               *name_type = -1;
-
-               if (!fgets_slash(line,sizeof(pstring),fp)) {
-                       continue;
-               }
-
-               if (*line == '#') {
-                       continue;
-               }
-
-               pstrcpy(ip,"");
-               pstrcpy(name,"");
-               pstrcpy(flags,"");
-
-               ptr = line;
-
-               if (next_token(&ptr,ip   ,NULL,sizeof(ip)))
-                       ++count;
-               if (next_token(&ptr,name ,NULL, sizeof(pstring)))
-                       ++count;
-               if (next_token(&ptr,flags,NULL, sizeof(flags)))
-                       ++count;
-               if (next_token(&ptr,extra,NULL, sizeof(extra)))
-                       ++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;
-               }
-
-               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 '#' */
-               }
+       struct name_query_state *state = tevent_req_data(
+               req, struct name_query_state);
+       NTSTATUS status;
 
-               return true;
+       if (tevent_req_is_nterror(req, &status)
+           && !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               return status;
        }
-
-       return false;
+       if (state->num_addrs == 0) {
+               return NT_STATUS_NOT_FOUND;
+       }
+       *addrs = talloc_move(mem_ctx, &state->addrs);
+       sort_addr_list(*addrs, state->num_addrs);
+       *num_addrs = state->num_addrs;
+       if (flags != NULL) {
+               *flags = state->flags;
+       }
+       return NT_STATUS_OK;
 }
 
-/********************************************************
- Finish parsing the lmhosts file.
-*********************************************************/
-
-void endlmhosts(XFILE *fp)
+NTSTATUS name_query(const char *name, int name_type,
+                   bool bcast, bool recurse,
+                   const struct sockaddr_storage *to_ss,
+                   TALLOC_CTX *mem_ctx,
+                   struct sockaddr_storage **addrs,
+                   int *num_addrs, uint8_t *flags)
 {
-       x_fclose(fp);
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = name_query_send(ev, ev, name, name_type, bcast, recurse, to_ss);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = name_query_recv(req, mem_ctx, addrs, num_addrs, flags);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
 }
 
 /********************************************************
@@ -918,11 +1491,11 @@ NTSTATUS name_resolve_bcast(const char *name,
                        struct ip_service **return_iplist,
                        int *return_count)
 {
-       int sock, i;
+       int i;
        int num_interfaces = iface_count();
        struct sockaddr_storage *ss_list;
        struct sockaddr_storage ss;
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_NOT_FOUND;
 
        if (lp_disable_netbios()) {
                DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n",
@@ -942,47 +1515,38 @@ NTSTATUS name_resolve_bcast(const char *name,
 
        if (!interpret_string_addr(&ss, lp_socket_address(),
                                AI_NUMERICHOST|AI_PASSIVE)) {
-               zero_addr(&ss, AF_INET);
+               zero_sockaddr(&ss);
        }
 
-       sock = open_socket_in( SOCK_DGRAM, 0, 3, &ss, true );
-       if (sock == -1) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       set_socket_options(sock,"SO_BROADCAST");
        /*
         * Lookup the name on all the interfaces, return on
         * the first successful match.
         */
        for( i = num_interfaces-1; i >= 0; i--) {
                const struct sockaddr_storage *pss = iface_n_bcast(i);
-               int flags;
 
                /* Done this way to fix compiler error on IRIX 5.x */
                if (!pss) {
                        continue;
                }
-               ss_list = name_query(sock, name, name_type, true,
-                                   true, pss, return_count, &flags, NULL);
-               if (ss_list) {
+               status = name_query(name, name_type, true, true, pss,
+                                   talloc_tos(), &ss_list, return_count,
+                                   NULL);
+               if (NT_STATUS_IS_OK(status)) {
                        goto success;
                }
        }
 
        /* failed - no response */
 
-       close(sock);
-       return NT_STATUS_UNSUCCESSFUL;
+       return status;
 
 success:
 
-       status = NT_STATUS_OK;
        if (!convert_ss2service(return_iplist, ss_list, *return_count) )
-               status = NT_STATUS_INVALID_PARAMETER;
+               status = NT_STATUS_NO_MEMORY;
 
-       SAFE_FREE(ss_list);
-       close(sock);
+       TALLOC_FREE(ss_list);
        return status;
 }
 
@@ -995,7 +1559,7 @@ NTSTATUS resolve_wins(const char *name,
                struct ip_service **return_iplist,
                int *return_count)
 {
-       int sock, t, i;
+       int t, i;
        char **wins_tags;
        struct sockaddr_storage src_ss, *ss_list = NULL;
        struct in_addr src_ip;
@@ -1030,7 +1594,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, AF_INET);
+               zero_sockaddr(&src_ss);
        }
 
        if (src_ss.ss_family != AF_INET) {
@@ -1039,6 +1603,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;
        }
 
@@ -1051,8 +1616,6 @@ NTSTATUS resolve_wins(const char *name,
                for (i=0; i<srv_count; i++) {
                        struct sockaddr_storage wins_ss;
                        struct in_addr wins_ip;
-                       int flags;
-                       bool timed_out;
 
                        wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip);
 
@@ -1070,35 +1633,31 @@ NTSTATUS resolve_wins(const char *name,
                                "and tag '%s'\n",
                                inet_ntoa(wins_ip), wins_tags[t]));
 
-                       sock = open_socket_in(SOCK_DGRAM, 0, 3, &src_ss, true);
-                       if (sock == -1) {
-                               continue;
-                       }
-
                        in_addr_to_sockaddr_storage(&wins_ss, wins_ip);
-                       ss_list = name_query(sock,
-                                               name,
+                       status = name_query(name,
                                                name_type,
                                                false,
                                                true,
                                                &wins_ss,
+                                               talloc_tos(),
+                                               &ss_list,
                                                return_count,
-                                               &flags,
-                                               &timed_out);
+                                               NULL);
 
                        /* exit loop if we got a list of addresses */
 
-                       if (ss_list)
+                       if (NT_STATUS_IS_OK(status)) {
                                goto success;
+                       }
 
-                       close(sock);
-
-                       if (timed_out) {
-                               /* Timed out wating for WINS server to respond.
+                       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 definately isn't in this
+                               /* The name definitely isn't in this
                                   group of WINS servers.
                                   goto the next group  */
                                break;
@@ -1115,9 +1674,8 @@ success:
        if (!convert_ss2service(return_iplist, ss_list, *return_count))
                status = NT_STATUS_INVALID_PARAMETER;
 
-       SAFE_FREE(ss_list);
+       TALLOC_FREE(ss_list);
        wins_srv_tags_free(wins_tags);
-       close(sock);
 
        return status;
 }
@@ -1133,12 +1691,9 @@ static NTSTATUS resolve_lmhosts(const char *name, int name_type,
        /*
         * "lmhosts" means parse the local lmhosts file.
         */
-
-       XFILE *fp;
-       pstring lmhost_name;
-       int name_type2;
-       struct sockaddr_storage return_ss;
+       struct sockaddr_storage *ss_list;
        NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+       TALLOC_CTX *ctx = NULL;
 
        *return_iplist = NULL;
        *return_count = 0;
@@ -1147,42 +1702,28 @@ static NTSTATUS resolve_lmhosts(const char *name, int name_type,
                "Attempting lmhosts lookup for name %s<0x%x>\n",
                name, name_type));
 
-       fp = startlmhosts(dyn_LMHOSTSFILE);
-
-       if ( fp == NULL )
-               return NT_STATUS_NO_SUCH_FILE;
-
-       while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ss)) {
-
-               if (!strequal(name, lmhost_name))
-                       continue;
-
-               if ((name_type2 != -1) && (name_type != name_type2))
-                       continue;
-
-               *return_iplist = SMB_REALLOC_ARRAY((*return_iplist),
-                                       struct ip_service,
-                                       (*return_count)+1);
+       ctx = talloc_init("resolve_lmhosts");
+       if (!ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-               if ((*return_iplist) == NULL) {
-                       endlmhosts(fp);
-                       DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
+       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;
                }
-
-               (*return_iplist)[*return_count].ss = return_ss;
-               (*return_iplist)[*return_count].port = PORT_NONE;
-               *return_count += 1;
-
-               /* we found something */
-               status = NT_STATUS_OK;
-
-               /* Multiple names only for DC lookup */
-               if (name_type != 0x1c)
-                       break;
        }
-
-       endlmhosts(fp);
+       talloc_free(ctx);
        return status;
 }
 
@@ -1222,6 +1763,11 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_ADDRCONFIG;
 
+#if !defined(HAVE_IPV6)
+       /* Unless we have IPv6, we really only want IPv4 addresses back. */
+       hints.ai_family = AF_INET;
+#endif
+
        ret = getaddrinfo(name,
                        NULL,
                        &hints,
@@ -1239,7 +1785,7 @@ 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);
 
                *return_count += 1;
@@ -1269,11 +1815,14 @@ static NTSTATUS resolve_hosts(const char *name, int name_type,
  Resolve via "ADS" method.
 *********************************************************/
 
-NTSTATUS resolve_ads(const char *name,
-                       int name_type,
-                       const char *sitename,
-                       struct ip_service **return_iplist,
-                       int *return_count)
+/* Special name type used to cause a _kerberos DNS lookup. */
+#define KDC_NAME_TYPE 0xDCDC
+
+static NTSTATUS resolve_ads(const char *name,
+                           int name_type,
+                           const char *sitename,
+                           struct ip_service **return_iplist,
+                           int *return_count)
 {
        int                     i, j;
        NTSTATUS                status;
@@ -1341,15 +1890,14 @@ NTSTATUS resolve_ads(const char *name,
        i = 0;
        j = 0;
        while ( i < numdcs && (*return_count<numaddrs) ) {
-               struct in_addr ip;
                struct ip_service *r = &(*return_iplist)[*return_count];
 
                r->port = dcs[i].port;
 
                /* If we don't have an IP list for a name, lookup it up */
 
-               if (!dcs[i].ips) {
-                       ip = *interpret_addr2(dcs[i].hostname);
+               if (!dcs[i].ss_s) {
+                       interpret_string_addr(&r->ss, dcs[i].hostname, 0);
                        i++;
                        j = 0;
                } else {
@@ -1361,12 +1909,10 @@ NTSTATUS resolve_ads(const char *name,
                                continue;
                        }
 
-                       ip = dcs[i].ips[j];
+                       r->ss = dcs[i].ss_s[j];
                        j++;
                }
 
-               in_addr_to_sockaddr_storage(&r->ss, ip);
-
                /* 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
@@ -1396,23 +1942,23 @@ NTSTATUS resolve_ads(const char *name,
 **********************************************************************/
 
 NTSTATUS internal_resolve_name(const char *name,
-                               int name_type,
+                               int name_type,
                                const char *sitename,
                                struct ip_service **return_iplist,
                                int *return_count,
                                const char *resolve_order)
 {
-       pstring name_resolve_list;
-       fstring tok;
+       char *tok;
        const char *ptr;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        int i;
+       TALLOC_CTX *frame = NULL;
 
        *return_iplist = NULL;
        *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)) ==
@@ -1455,21 +2001,16 @@ NTSTATUS internal_resolve_name(const char *name,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!resolve_order) {
-               pstrcpy(name_resolve_list, lp_name_resolve_order());
-       } else {
-               pstrcpy(name_resolve_list, resolve_order);
-       }
-
-       if (!name_resolve_list[0]) {
+       if (!resolve_order[0]) {
                ptr = "host";
        } else {
-               ptr = name_resolve_list;
+               ptr = resolve_order;
        }
 
        /* iterate through the name resolution backends */
 
-       while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
+       frame = talloc_stackframe();
+       while (next_token_talloc(frame, &ptr, &tok, LIST_SEP)) {
                if((strequal(tok, "host") || strequal(tok, "hosts"))) {
                        status = resolve_hosts(name, name_type, return_iplist,
                                               return_count);
@@ -1526,6 +2067,7 @@ NTSTATUS internal_resolve_name(const char *name,
 
        /* All of the resolve_* functions above have returned false. */
 
+       TALLOC_FREE(frame);
        SAFE_FREE(*return_iplist);
        *return_count = 0;
 
@@ -1576,6 +2118,7 @@ NTSTATUS internal_resolve_name(const char *name,
                DEBUG(10, ("\n"));
        }
 
+       TALLOC_FREE(frame);
        return status;
 }
 
@@ -1588,7 +2131,8 @@ 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;
@@ -1605,10 +2149,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(&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)) {
+                                       !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss)) {
                                *return_ss = ss_list[i].ss;
                                SAFE_FREE(ss_list);
                                SAFE_FREE(sitename);
@@ -1622,6 +2179,87 @@ bool resolve_name(const char *name,
        return False;
 }
 
+/********************************************************
+ Internal interface to resolve a name into a list of IP addresses.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
+               const char *name,
+               int name_type,
+               struct sockaddr_storage **return_ss_arr,
+               unsigned int *p_num_entries)
+{
+       struct ip_service *ss_list = NULL;
+       char *sitename = NULL;
+       int count = 0;
+       int i;
+       unsigned int num_entries;
+       NTSTATUS status;
+
+       *p_num_entries = 0;
+       *return_ss_arr = NULL;
+
+       if (is_ipaddress(name)) {
+               *return_ss_arr = TALLOC_P(ctx, struct sockaddr_storage);
+               if (!*return_ss_arr) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               if (!interpret_string_addr(*return_ss_arr, name, AI_NUMERICHOST)) {
+                       TALLOC_FREE(*return_ss_arr);
+                       return NT_STATUS_BAD_NETWORK_NAME;
+               }
+               *p_num_entries = 1;
+               return NT_STATUS_OK;
+       }
+
+       sitename = sitename_fetch(lp_realm()); /* wild guess */
+
+       status = internal_resolve_name(name, name_type, sitename,
+                                                 &ss_list, &count,
+                                                 lp_name_resolve_order());
+       SAFE_FREE(sitename);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* 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)) {
+                       num_entries++;
+               }
+       }
+       if (num_entries == 0) {
+               SAFE_FREE(ss_list);
+               return NT_STATUS_BAD_NETWORK_NAME;
+       }
+
+       *return_ss_arr = TALLOC_ARRAY(ctx,
+                               struct sockaddr_storage,
+                               num_entries);
+       if (!(*return_ss_arr)) {
+               SAFE_FREE(ss_list);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       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)) {
+                       (*return_ss_arr)[num_entries++] = ss_list[i].ss;
+               }
+       }
+
+       status = NT_STATUS_OK;
+       *p_num_entries = num_entries;
+
+       SAFE_FREE(ss_list);
+       return NT_STATUS_OK;
+}
+
 /********************************************************
  Find the IP address of the master browser or DMB for a workgroup.
 *********************************************************/
@@ -1713,20 +2351,28 @@ static NTSTATUS get_dc_list(const char *domain,
                        enum dc_lookup_type lookup_type,
                        bool *ordered)
 {
-       fstring resolve_order;
-       char *saf_servername;
-       pstring pserver;
+       char *resolve_order = NULL;
+       char *saf_servername = NULL;
+       char *pserver = NULL;
        const char *p;
-       char *port_str;
+       char *port_str = NULL;
        int port;
-       fstring name;
+       char *name;
        int num_addresses = 0;
        int  local_count, i, j;
        struct ip_service *return_iplist = NULL;
        struct ip_service *auto_ip_list = NULL;
-       bool done_auto_lookup = False;
+       bool done_auto_lookup = false;
        int auto_count = 0;
        NTSTATUS status;
+       TALLOC_CTX *ctx = talloc_init("get_dc_list");
+
+       *ip_list = NULL;
+       *count = 0;
+
+       if (!ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        *ordered = False;
 
@@ -1736,23 +2382,31 @@ static NTSTATUS get_dc_list(const char *domain,
           are disabled and ads_only is True, then set the string to
           NULL. */
 
-       fstrcpy(resolve_order, lp_name_resolve_order());
+       resolve_order = talloc_strdup(ctx, 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")) {
-                       fstrcpy( resolve_order, "ads");
+                       resolve_order = talloc_strdup(ctx, "ads");
 
                        /* DNS SRV lookups used by the ads resolver
                           are already sorted by priority and weight */
                        *ordered = true;
                } else {
-                        fstrcpy(resolve_order, "NULL");
+                        resolve_order = talloc_strdup(ctx, "NULL");
                }
        } else if (lookup_type == DC_KDC_ONLY) {
                /* DNS SRV lookups used by the ads/kdc resolver
                   are already sorted by priority and weight */
                *ordered = true;
-               fstrcpy(resolve_order, "kdc");
+               resolve_order = talloc_strdup(ctx, "kdc");
+       }
+       if (!resolve_order) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
        }
 
        /* fetch the server we have affinity for.  Add the
@@ -1761,22 +2415,27 @@ static NTSTATUS get_dc_list(const char *domain,
        saf_servername = saf_fetch( domain);
 
        if (strequal(domain, lp_workgroup()) || strequal(domain, lp_realm())) {
-               pstr_sprintf(pserver, "%s, %s",
+               pserver = talloc_asprintf(ctx, "%s, %s",
                        saf_servername ? saf_servername : "",
                        lp_passwordserver());
        } else {
-               pstr_sprintf(pserver, "%s, *",
+               pserver = talloc_asprintf(ctx, "%s, *",
                        saf_servername ? saf_servername : "");
        }
 
-       SAFE_FREE( saf_servername );
+       SAFE_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"));
-               return internal_resolve_name(domain, 0x1C, sitename, ip_list,
+               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 ));
@@ -1789,8 +2448,8 @@ static NTSTATUS get_dc_list(const char *domain,
         */
 
        p = pserver;
-       while (next_token(&p,name,LIST_SEP,sizeof(name))) {
-               if (strequal(name, "*")) {
+       while (next_token_talloc(ctx, &p, &name, LIST_SEP)) {
+               if (!done_auto_lookup && strequal(name, "*")) {
                        status = internal_resolve_name(domain, 0x1C, sitename,
                                                       &auto_ip_list,
                                                       &auto_count,
@@ -1812,18 +2471,19 @@ static NTSTATUS get_dc_list(const char *domain,
        if ((num_addresses == 0)) {
                if (done_auto_lookup) {
                        DEBUG(4,("get_dc_list: no servers found\n"));
-                       SAFE_FREE(auto_ip_list);
-                       return NT_STATUS_NO_LOGON_SERVERS;
+                       status = NT_STATUS_NO_LOGON_SERVERS;
+                       goto out;
                }
-               return internal_resolve_name(domain, 0x1C, sitename, ip_list,
+               status = internal_resolve_name(domain, 0x1C, sitename, ip_list,
                                             count, resolve_order);
+               goto out;
        }
 
        if ((return_iplist = SMB_MALLOC_ARRAY(struct ip_service,
                                        num_addresses)) == NULL) {
                DEBUG(3,("get_dc_list: malloc fail !\n"));
-               SAFE_FREE(auto_ip_list);
-               return NT_STATUS_NO_MEMORY;
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
        }
 
        p = pserver;
@@ -1832,7 +2492,7 @@ static NTSTATUS get_dc_list(const char *domain,
        /* fill in the return list now with real IP's */
 
        while ((local_count<num_addresses) &&
-                       next_token(&p,name,LIST_SEP,sizeof(name))) {
+                       next_token_talloc(ctx, &p, &name, LIST_SEP)) {
                struct sockaddr_storage name_ss;
 
                /* copy any addersses from the auto lookup */
@@ -1877,7 +2537,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),
@@ -1899,8 +2559,6 @@ static NTSTATUS get_dc_list(const char *domain,
                }
        }
 
-       SAFE_FREE(auto_ip_list);
-
        /* need to remove duplicates in the list if we have any
           explicit password servers */
 
@@ -1909,6 +2567,13 @@ static NTSTATUS get_dc_list(const char *domain,
                                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 ) {
                DEBUG(4,("get_dc_list: returning %d ip addresses "
                                "in an %sordered list\n",
@@ -1928,7 +2593,19 @@ static NTSTATUS get_dc_list(const char *domain,
        *ip_list = return_iplist;
        *count = local_count;
 
-       return ( *count != 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS );
+       status = ( *count != 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS );
+
+  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;
 }
 
 /*********************************************************************
@@ -1941,10 +2618,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,
@@ -1957,7 +2637,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;
        }
 
@@ -1988,6 +2679,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;
        }