summaryrefslogtreecommitdiff
path: root/source3/libsmb/namequery.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/namequery.c')
-rw-r--r--source3/libsmb/namequery.c896
1 files changed, 729 insertions, 167 deletions
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index ef7aab6a6a..dca740d3e6 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include "../lib/util/tevent_ntstatus.h"
#include "libads/sitename_cache.h"
#include "libads/dns.h"
#include "../libcli/netlogon/netlogon.h"
@@ -196,6 +197,26 @@ char *saf_fetch( const char *domain )
return server;
}
+static void set_socket_addr_v4(struct sockaddr_storage *addr)
+{
+ if (!interpret_string_addr(addr, lp_socket_address(),
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ zero_sockaddr(addr);
+ }
+ if (addr->ss_family != AF_INET) {
+ zero_sockaddr(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.
****************************************************************************/
@@ -225,7 +246,7 @@ static struct node_status *parse_node_status(TALLOC_CTX *mem_ctx, char *p,
if (*num_names == 0)
return NULL;
- ret = TALLOC_ARRAY(mem_ctx, struct node_status,*num_names);
+ ret = talloc_array(mem_ctx, struct node_status,*num_names);
if (!ret)
return NULL;
@@ -704,10 +725,7 @@ struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
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);
- }
+ set_socket_addr_v4(&state->my_addr);
ZERO_STRUCT(p);
nmb->header.name_trn_id = generate_trn_id();
@@ -891,10 +909,7 @@ bool name_status_find(const char *q_name,
return false;
}
- if (!interpret_string_addr(&ss, lp_socket_address(),
- AI_NUMERICHOST|AI_PASSIVE)) {
- zero_sockaddr(&ss);
- }
+ set_socket_addr_v4(&ss);
/* W2K PDC's seem not to respond to '*'#0. JRA */
make_nmb_name(&nname, q_name, q_type);
@@ -962,9 +977,9 @@ static int addr_compare(const struct sockaddr_storage *ss1,
for (i=0;i<num_interfaces;i++) {
const struct sockaddr_storage *pss = iface_n_bcast(i);
- unsigned char *p_ss1 = NULL;
- unsigned char *p_ss2 = NULL;
- unsigned char *p_if = NULL;
+ const unsigned char *p_ss1 = NULL;
+ const unsigned char *p_ss2 = NULL;
+ const unsigned char *p_if = NULL;
size_t len = 0;
int bits1, bits2;
@@ -973,21 +988,21 @@ static int addr_compare(const struct sockaddr_storage *ss1,
continue;
}
if (pss->ss_family == AF_INET) {
- p_if = (unsigned char *)
+ p_if = (const unsigned char *)
&((const struct sockaddr_in *)pss)->sin_addr;
- p_ss1 = (unsigned char *)
+ p_ss1 = (const unsigned char *)
&((const struct sockaddr_in *)ss1)->sin_addr;
- p_ss2 = (unsigned char *)
+ p_ss2 = (const unsigned char *)
&((const struct sockaddr_in *)ss2)->sin_addr;
len = 4;
}
#if defined(HAVE_IPV6)
if (pss->ss_family == AF_INET6) {
- p_if = (unsigned char *)
+ p_if = (const unsigned char *)
&((const struct sockaddr_in6 *)pss)->sin6_addr;
- p_ss1 = (unsigned char *)
+ p_ss1 = (const unsigned char *)
&((const struct sockaddr_in6 *)ss1)->sin6_addr;
- p_ss2 = (unsigned char *)
+ p_ss2 = (const unsigned char *)
&((const struct sockaddr_in6 *)ss2)->sin6_addr;
len = 16;
}
@@ -1002,14 +1017,14 @@ static int addr_compare(const struct sockaddr_storage *ss1,
}
/* Bias towards directly reachable IPs */
- if (iface_local((struct sockaddr *)ss1)) {
+ if (iface_local((const struct sockaddr *)ss1)) {
if (ss1->ss_family == AF_INET) {
max_bits1 += 32;
} else {
max_bits1 += 128;
}
}
- if (iface_local((struct sockaddr *)ss2)) {
+ if (iface_local((const struct sockaddr *)ss2)) {
if (ss2->ss_family == AF_INET) {
max_bits2 += 32;
} else {
@@ -1084,7 +1099,8 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
}
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);
}
@@ -1111,7 +1127,7 @@ static int remove_duplicate_addrs2(struct ip_service *iplist, int 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);
+ struct ip_service *iplist_new = talloc_array(frame, struct ip_service, count);
int i, j;
if (iplist_new == NULL) {
@@ -1177,7 +1193,6 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
struct packet_struct p;
struct nmb_packet *nmb = &p.packet.nmb;
struct sockaddr_in *in_addr;
- struct timeval timeout;
req = tevent_req_create(mem_ctx, &state, struct name_query_state);
if (req == NULL) {
@@ -1202,10 +1217,7 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
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);
- }
+ set_socket_addr_v4(&state->my_addr);
ZERO_STRUCT(p);
nmb->header.name_trn_id = generate_trn_id();
@@ -1243,14 +1255,6 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
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;
}
@@ -1261,6 +1265,7 @@ static bool name_query_validator(struct packet_struct *p, void *private_data)
private_data, struct name_query_state);
struct nmb_packet *nmb = &p->packet.nmb;
struct sockaddr_storage *tmp_addrs;
+ bool got_unique_netbios_name = false;
int i;
debug_nmb_packet(p);
@@ -1322,7 +1327,7 @@ static bool name_query_validator(struct packet_struct *p, void *private_data)
return false;
}
- tmp_addrs = TALLOC_REALLOC_ARRAY(
+ tmp_addrs = talloc_realloc(
state, state->addrs, struct sockaddr_storage,
state->num_addrs + nmb->answers->rdlength/6);
if (tmp_addrs == NULL) {
@@ -1335,11 +1340,32 @@ static bool name_query_validator(struct packet_struct *p, void *private_data)
"from %s ( ", inet_ntoa(p->ip)));
for (i=0; i<nmb->answers->rdlength/6; i++) {
+ uint16_t flags;
struct in_addr ip;
+ struct sockaddr_storage addr;
+ int j;
+
+ flags = RSVAL(&nmb->answers->rdata[i*6], 0);
+ got_unique_netbios_name |= ((flags & 0x8000) == 0);
+
putip((char *)&ip,&nmb->answers->rdata[2+i*6]);
- in_addr_to_sockaddr_storage(
- &state->addrs[state->num_addrs], ip);
+ in_addr_to_sockaddr_storage(&addr, ip);
+
+ for (j=0; j<state->num_addrs; j++) {
+ if (sockaddr_equal(
+ (struct sockaddr *)(void *)&addr,
+ (struct sockaddr *)(void *)&state->addrs[j])) {
+ break;
+ }
+ }
+ if (j < state->num_addrs) {
+ /* Already got it */
+ continue;
+ }
+
DEBUGADD(2,("%s ",inet_ntoa(ip)));
+
+ state->addrs[state->num_addrs] = addr;
state->num_addrs += 1;
}
DEBUGADD(2,(")\n"));
@@ -1360,10 +1386,10 @@ static bool name_query_validator(struct packet_struct *p, void *private_data)
if (state->bcast) {
/*
- * We have to collect all entries coming in from
- * broadcast queries
+ * We have to collect all entries coming in from broadcast
+ * queries. If we got a unique name, we're done.
*/
- return false;
+ return got_unique_netbios_name;
}
/*
* WINS responses are accepted when they are received
@@ -1407,9 +1433,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;
@@ -1433,6 +1468,7 @@ NTSTATUS name_query(const char *name, int name_type,
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
struct tevent_req *req;
+ struct timeval timeout;
NTSTATUS status = NT_STATUS_NO_MEMORY;
ev = tevent_context_init(frame);
@@ -1443,6 +1479,14 @@ NTSTATUS name_query(const char *name, int name_type,
if (req == NULL) {
goto fail;
}
+ if (bcast) {
+ timeout = timeval_current_ofs(0, 250000);
+ } else {
+ timeout = timeval_current_ofs(2, 0);
+ }
+ if (!tevent_req_set_endtime(req, ev, timeout)) {
+ goto fail;
+ }
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
@@ -1482,113 +1526,507 @@ static bool convert_ss2service(struct ip_service **return_iplist,
return true;
}
+struct name_queries_state {
+ struct tevent_context *ev;
+ const char *name;
+ int name_type;
+ bool bcast;
+ bool recurse;
+ const struct sockaddr_storage *addrs;
+ int num_addrs;
+ int wait_msec;
+ int timeout_msec;
+
+ struct tevent_req **subreqs;
+ int num_received;
+ int num_sent;
+
+ int received_index;
+ struct sockaddr_storage *result_addrs;
+ int num_result_addrs;
+ uint8_t flags;
+};
+
+static void name_queries_done(struct tevent_req *subreq);
+static void name_queries_next(struct tevent_req *subreq);
+
+/*
+ * Send a name query to multiple destinations with a wait time in between
+ */
+
+static struct tevent_req *name_queries_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ const char *name, int name_type,
+ bool bcast, bool recurse,
+ const struct sockaddr_storage *addrs,
+ int num_addrs, int wait_msec, int timeout_msec)
+{
+ struct tevent_req *req, *subreq;
+ struct name_queries_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct name_queries_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->name = name;
+ state->name_type = name_type;
+ state->bcast = bcast;
+ state->recurse = recurse;
+ state->addrs = addrs;
+ state->num_addrs = num_addrs;
+ state->wait_msec = wait_msec;
+ state->timeout_msec = timeout_msec;
+
+ state->subreqs = talloc_zero_array(
+ state, struct tevent_req *, num_addrs);
+ if (tevent_req_nomem(state->subreqs, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->num_sent = 0;
+
+ subreq = name_query_send(
+ state->subreqs, state->ev, name, name_type, bcast, recurse,
+ &state->addrs[state->num_sent]);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(
+ subreq, state->ev,
+ timeval_current_ofs(0, state->timeout_msec * 1000))) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, name_queries_done, req);
+
+ state->subreqs[state->num_sent] = subreq;
+ state->num_sent += 1;
+
+ if (state->num_sent < state->num_addrs) {
+ subreq = tevent_wakeup_send(
+ state, state->ev,
+ timeval_current_ofs(0, state->wait_msec * 1000));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, name_queries_next, req);
+ }
+ return req;
+}
+
+static void name_queries_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct name_queries_state *state = tevent_req_data(
+ req, struct name_queries_state);
+ int i;
+ NTSTATUS status;
+
+ status = name_query_recv(subreq, state, &state->result_addrs,
+ &state->num_result_addrs, &state->flags);
+
+ for (i=0; i<state->num_sent; i++) {
+ if (state->subreqs[i] == subreq) {
+ break;
+ }
+ }
+ if (i == state->num_sent) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+ TALLOC_FREE(state->subreqs[i]);
+
+ state->num_received += 1;
+
+ if (!NT_STATUS_IS_OK(status)) {
+
+ if (state->num_received >= state->num_addrs) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ /*
+ * Still outstanding requests, just wait
+ */
+ return;
+ }
+ state->received_index = i;
+ tevent_req_done(req);
+}
+
+static void name_queries_next(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct name_queries_state *state = tevent_req_data(
+ req, struct name_queries_state);
+
+ if (!tevent_wakeup_recv(subreq)) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ subreq = name_query_send(
+ state->subreqs, state->ev,
+ state->name, state->name_type, state->bcast, state->recurse,
+ &state->addrs[state->num_sent]);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, name_queries_done, req);
+ if (!tevent_req_set_endtime(
+ subreq, state->ev,
+ timeval_current_ofs(0, state->timeout_msec * 1000))) {
+ tevent_req_oom(req);
+ return;
+ }
+ state->subreqs[state->num_sent] = subreq;
+ state->num_sent += 1;
+
+ if (state->num_sent < state->num_addrs) {
+ subreq = tevent_wakeup_send(
+ state, state->ev,
+ timeval_current_ofs(0, state->wait_msec * 1000));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, name_queries_next, req);
+ }
+}
+
+static NTSTATUS name_queries_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **result_addrs,
+ int *num_result_addrs, uint8_t *flags,
+ int *received_index)
+{
+ struct name_queries_state *state = tevent_req_data(
+ req, struct name_queries_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+
+ if (result_addrs != NULL) {
+ *result_addrs = talloc_move(mem_ctx, &state->result_addrs);
+ }
+ if (num_result_addrs != NULL) {
+ *num_result_addrs = state->num_result_addrs;
+ }
+ if (flags != NULL) {
+ *flags = state->flags;
+ }
+ if (received_index != NULL) {
+ *received_index = state->received_index;
+ }
+ return NT_STATUS_OK;
+}
+
/********************************************************
Resolve via "bcast" method.
*********************************************************/
-NTSTATUS name_resolve_bcast(const char *name,
- int name_type,
- struct ip_service **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)
{
- int i;
- int num_interfaces = iface_count();
- struct sockaddr_storage *ss_list;
- struct sockaddr_storage ss;
- NTSTATUS status = NT_STATUS_NOT_FOUND;
+ struct tevent_req *req, *subreq;
+ struct name_resolve_bcast_state *state;
+ struct sockaddr_storage *bcast_addrs;
+ int i, num_addrs, num_bcast_addrs;
- if (lp_disable_netbios()) {
- DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n",
- name, name_type));
- return NT_STATUS_INVALID_PARAMETER;
+ req = tevent_req_create(mem_ctx, &state,
+ struct name_resolve_bcast_state);
+ if (req == NULL) {
+ return NULL;
}
- *return_iplist = NULL;
- *return_count = 0;
+ if (lp_disable_netbios()) {
+ 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));
- if (!interpret_string_addr(&ss, lp_socket_address(),
- AI_NUMERICHOST|AI_PASSIVE)) {
- zero_sockaddr(&ss);
+ num_addrs = iface_count();
+ bcast_addrs = talloc_array(state, struct sockaddr_storage, num_addrs);
+ if (tevent_req_nomem(bcast_addrs, req)) {
+ return tevent_req_post(req, ev);
}
/*
* Lookup the name on all the interfaces, return on
* the first successful match.
*/
- for( i = num_interfaces-1; i >= 0; i--) {
+ num_bcast_addrs = 0;
+
+ for (i=0; i<num_addrs; i++) {
const struct sockaddr_storage *pss = iface_n_bcast(i);
- /* Done this way to fix compiler error on IRIX 5.x */
- if (!pss) {
+ if (pss->ss_family != AF_INET) {
continue;
}
- status = name_query(name, name_type, true, true, pss,
- talloc_tos(), &ss_list, return_count,
- NULL);
- if (NT_STATUS_IS_OK(status)) {
- goto success;
- }
+ bcast_addrs[num_bcast_addrs] = *pss;
+ num_bcast_addrs += 1;
}
- /* failed - no response */
+ 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;
+}
- return status;
+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;
-success:
+ 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);
+}
- if (!convert_ss2service(return_iplist, ss_list, *return_count) )
- status = NT_STATUS_NO_MEMORY;
+NTSTATUS name_resolve_bcast_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **addrs,
+ int *num_addrs)
+{
+ struct name_resolve_bcast_state *state = tevent_req_data(
+ req, struct name_resolve_bcast_state);
+ NTSTATUS status;
+
+ 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;
+}
- TALLOC_FREE(ss_list);
+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 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_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;
}
-/********************************************************
- Resolve via "wins" method.
-*********************************************************/
+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;
-NTSTATUS resolve_wins(const char *name,
- int name_type,
- struct ip_service **return_iplist,
- int *return_count)
+ 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)
{
- int t, i;
- char **wins_tags;
- struct sockaddr_storage src_ss, *ss_list = NULL;
- struct in_addr src_ip;
+ 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;
+
+ if (state->num_servers == 0) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ return tevent_req_post(req, ev);
+ }
+
+ 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))) {
+ tevent_req_oom(req);
+ 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;
- if (lp_disable_netbios()) {
- DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n",
- name, name_type));
- return NT_STATUS_INVALID_PARAMETER;
+ 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());
- *return_iplist = NULL;
- *return_count = 0;
+ if (state->num_sent == state->num_servers) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ return;
+ }
- DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n",
- name, name_type));
+ in_addr_to_sockaddr_storage(
+ &state->server, state->servers[state->num_sent]);
- if (wins_srv_count() < 1) {
- DEBUG(3,("resolve_wins: WINS server resolution selected "
- "and no WINS servers listed.\n"));
- return NT_STATUS_INVALID_PARAMETER;
+ 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))) {
+ tevent_req_oom(req);
+ return;
+ }
+ tevent_req_set_callback(subreq, query_wins_list_done, req);
+}
- /* we try a lookup on each of the WINS tags in turn */
- wins_tags = wins_srv_tags();
+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 (!wins_tags) {
- /* huh? no tags?? give up in disgust */
- return NT_STATUS_INVALID_PARAMETER;
+ 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 */
@@ -1603,80 +2041,164 @@ 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]));
+ if (num_alive == 0) {
+ continue;
+ }
- 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);
+ 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;
+ }
- /* exit loop if we got a list of addresses */
+ if (state->num_sent == 0) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ goto fail;
+ }
- if (NT_STATUS_IS_OK(status)) {
- goto success;
- }
+ wins_srv_tags_free(wins_tags);
+ return req;
+fail:
+ wins_srv_tags_free(wins_tags);
+ return tevent_req_post(req, ev);
+}
- 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;
- }
- }
+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 = query_wins_list_recv(subreq, state, &state->addrs,
+ &state->num_addrs, &state->flags);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return;
}
- wins_srv_tags_free(wins_tags);
- return NT_STATUS_NO_LOGON_SERVERS;
+ state->num_received += 1;
-success:
+ if (state->num_received < state->num_sent) {
+ /*
+ * Wait for the others
+ */
+ return;
+ }
+ tevent_req_nterror(req, status);
+}
- status = NT_STATUS_OK;
- if (!convert_ss2service(return_iplist, ss_list, *return_count))
- status = NT_STATUS_INVALID_PARAMETER;
+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;
- TALLOC_FREE(ss_list);
- wins_srv_tags_free(wins_tags);
+ 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 "wins" method.
+*********************************************************/
+
+NTSTATUS resolve_wins(const char *name,
+ int name_type,
+ TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **return_iplist,
+ int *return_count)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = resolve_wins_send(ev, ev, name, name_type);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = resolve_wins_recv(req, mem_ctx, return_iplist, return_count,
+ NULL);
+fail:
+ TALLOC_FREE(ev);
return status;
}
@@ -1744,6 +2266,7 @@ 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 "
@@ -1768,6 +2291,32 @@ 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,
@@ -2044,19 +2593,32 @@ NTSTATUS internal_resolve_name(const char *name,
}
} 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")) {
- status = name_resolve_bcast(name, name_type,
- return_iplist,
- return_count);
+ struct sockaddr_storage *ss_list;
+ status = name_resolve_bcast(
+ 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 {
@@ -2152,7 +2714,7 @@ bool resolve_name(const char *name,
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);
@@ -2165,7 +2727,7 @@ 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);
@@ -2203,7 +2765,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;
}
@@ -2229,7 +2791,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++;
}
}
@@ -2238,7 +2800,7 @@ NTSTATUS resolve_name_list(TALLOC_CTX *ctx,
return NT_STATUS_BAD_NETWORK_NAME;
}
- *return_ss_arr = TALLOC_ARRAY(ctx,
+ *return_ss_arr = talloc_array(ctx,
struct sockaddr_storage,
num_entries);
if (!(*return_ss_arr)) {
@@ -2248,7 +2810,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;
}
}