#include "includes.h"
#include "../lib/util/tevent_ntstatus.h"
#include "libads/sitename_cache.h"
-#include "libads/dns.h"
+#include "../lib/addns/dnsquery.h"
#include "../libcli/netlogon/netlogon.h"
#include "lib/async_req/async_sock.h"
#include "libsmb/nmblib.h"
+#include "../libcli/nbt/libnbt.h"
/* nmbd.c sets this to True. */
bool global_in_nmbd = False;
#define SAFJOINKEY_FMT "SAFJOIN/DOMAIN/%s"
#define SAFJOIN_TTL 3600
-static char *saf_key(const char *domain)
+static char *saf_key(TALLOC_CTX *mem_ctx, const char *domain)
{
- char *keystr;
-
- asprintf_strupper_m(&keystr, SAFKEY_FMT, domain);
-
- return keystr;
+ return talloc_asprintf_strupper_m(mem_ctx, SAFKEY_FMT, domain);
}
-static char *saf_join_key(const char *domain)
+static char *saf_join_key(TALLOC_CTX *mem_ctx, const char *domain)
{
- char *keystr;
-
- asprintf_strupper_m(&keystr, SAFJOINKEY_FMT, domain);
-
- return keystr;
+ return talloc_asprintf_strupper_m(mem_ctx, SAFJOINKEY_FMT, domain);
}
/****************************************************************************
return False;
}
- key = saf_key( domain );
+ key = saf_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_key() failed\n"));
+ return false;
+ }
expire = time( NULL ) + lp_parm_int(-1, "saf","ttl", SAF_TTL);
DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%u]\n",
ret = gencache_set( key, servername, expire );
- SAFE_FREE( key );
+ TALLOC_FREE( key );
return ret;
}
return False;
}
- key = saf_join_key( domain );
+ key = saf_join_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_join_key() failed\n"));
+ return false;
+ }
expire = time( NULL ) + lp_parm_int(-1, "saf","join ttl", SAFJOIN_TTL);
DEBUG(10,("saf_join_store: domain = [%s], server = [%s], expire = [%u]\n",
ret = gencache_set( key, servername, expire );
- SAFE_FREE( key );
+ TALLOC_FREE( key );
return ret;
}
return False;
}
- key = saf_join_key(domain);
+ key = saf_join_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_join_key() failed\n"));
+ return false;
+ }
ret = gencache_del(key);
- SAFE_FREE(key);
+ TALLOC_FREE(key);
if (ret) {
DEBUG(10,("saf_delete[join]: domain = [%s]\n", domain ));
}
- key = saf_key(domain);
+ key = saf_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_key() failed\n"));
+ return false;
+ }
ret = gencache_del(key);
- SAFE_FREE(key);
+ TALLOC_FREE(key);
if (ret) {
DEBUG(10,("saf_delete: domain = [%s]\n", domain ));
/****************************************************************************
****************************************************************************/
-char *saf_fetch( const char *domain )
+char *saf_fetch(TALLOC_CTX *mem_ctx, const char *domain )
{
char *server = NULL;
time_t timeout;
return NULL;
}
- key = saf_join_key( domain );
+ key = saf_join_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_join_key() failed\n"));
+ return NULL;
+ }
- ret = gencache_get( key, &server, &timeout );
+ ret = gencache_get( key, mem_ctx, &server, &timeout );
- SAFE_FREE( key );
+ TALLOC_FREE( key );
if ( ret ) {
DEBUG(5,("saf_fetch[join]: Returning \"%s\" for \"%s\" domain\n",
return server;
}
- key = saf_key( domain );
+ key = saf_key(talloc_tos(), domain);
+ if (key == NULL) {
+ DEBUG(1, ("saf_key() failed\n"));
+ return NULL;
+ }
- ret = gencache_get( key, &server, &timeout );
+ ret = gencache_get( key, mem_ctx, &server, &timeout );
- SAFE_FREE( key );
+ TALLOC_FREE( key );
if ( !ret ) {
DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n",
static void set_socket_addr_v4(struct sockaddr_storage *addr)
{
- if (!interpret_string_addr(addr, lp_socket_address(),
+ if (!interpret_string_addr(addr, lp_nbt_client_socket_address(),
AI_NUMERICHOST|AI_PASSIVE)) {
zero_sockaddr(addr);
}
}
}
+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.
****************************************************************************/
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;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- ev = tevent_context_init(frame);
+ ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
Remove any duplicate address/port pairs in the list
*********************************************************************/
-static int remove_duplicate_addrs2(struct ip_service *iplist, int count )
+int remove_duplicate_addrs2(struct ip_service *iplist, int count )
{
int i, j;
DEBUG(10,("remove_duplicate_addrs2: "
"looking for duplicate address/port pairs\n"));
- /* one loop to remove duplicates */
+ /* One loop to set duplicates to a zero addr. */
for ( i=0; i<count; i++ ) {
if ( is_zero_addr(&iplist[i].ss)) {
continue;
}
for ( j=i+1; j<count; j++ ) {
- if (sockaddr_equal((struct sockaddr *)&iplist[i].ss, (struct sockaddr *)&iplist[j].ss) &&
+ if (sockaddr_equal((struct sockaddr *)(void *)&iplist[i].ss,
+ (struct sockaddr *)(void *)&iplist[j].ss) &&
iplist[i].port == iplist[j].port) {
zero_sockaddr(&iplist[j].ss);
}
}
}
- /* one loop to clean up any holes we left */
- /* first ip should never be a zero_ip() */
- for (i = 0; i<count; ) {
- if (is_zero_addr(&iplist[i].ss) ) {
- if (i != count-1) {
- memmove(&iplist[i], &iplist[i+1],
- (count - i - 1)*sizeof(iplist[i]));
+ /* Now remove any addresses set to zero above. */
+ for (i = 0; i < count; i++) {
+ while (i < count &&
+ is_zero_addr(&iplist[i].ss)) {
+ if (count-i-1>0) {
+ memmove(&iplist[i],
+ &iplist[i+1],
+ (count-i-1)*sizeof(struct ip_service));
}
count--;
- continue;
}
- i++;
}
return count;
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) {
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) {
putip((char *)&ip,&nmb->answers->rdata[2+i*6]);
in_addr_to_sockaddr_storage(&addr, ip);
+ if (is_zero_addr(&addr)) {
+ continue;
+ }
+
for (j=0; j<state->num_addrs; j++) {
if (sockaddr_equal(
- (struct sockaddr *)&addr,
- (struct sockaddr *)&state->addrs[j])) {
+ (struct sockaddr *)(void *)&addr,
+ (struct sockaddr *)(void *)&state->addrs[j])) {
break;
}
}
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;
struct timeval timeout;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- ev = tevent_context_init(frame);
+ ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
}
/********************************************************
- convert an array if struct sockaddr_storage to struct ip_service
+ Convert an array if struct sockaddr_storage to struct ip_service
return false on failure. Port is set to PORT_NONE;
+ pcount is [in/out] - it is the length of ss_list on input,
+ and the length of return_iplist on output as we remove any
+ zero addresses from ss_list.
*********************************************************/
static bool convert_ss2service(struct ip_service **return_iplist,
const struct sockaddr_storage *ss_list,
- int count)
+ int *pcount)
{
int i;
+ int orig_count = *pcount;
+ int real_count = 0;
- if ( count==0 || !ss_list )
+ if (orig_count==0 || !ss_list )
return False;
+ /* Filter out zero addrs. */
+ for ( i=0; i<orig_count; i++ ) {
+ if (is_zero_addr(&ss_list[i])) {
+ continue;
+ }
+ real_count++;
+ }
+ if (real_count==0) {
+ return false;
+ }
+
/* copy the ip address; port will be PORT_NONE */
- if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) ==
+ if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, real_count)) ==
NULL) {
DEBUG(0,("convert_ip2service: malloc failed "
- "for %d enetries!\n", count ));
+ "for %d enetries!\n", real_count ));
return False;
}
- for ( i=0; i<count; i++ ) {
- (*return_iplist)[i].ss = ss_list[i];
- (*return_iplist)[i].port = PORT_NONE;
+ for ( i=0, real_count = 0; i<orig_count; i++ ) {
+ if (is_zero_addr(&ss_list[i])) {
+ continue;
+ }
+ (*return_iplist)[real_count].ss = ss_list[i];
+ (*return_iplist)[real_count].port = PORT_NONE;
+ real_count++;
}
+ *pcount = real_count;
return true;
}
if (!tevent_req_set_endtime(
subreq, state->ev,
timeval_current_ofs(0, state->timeout_msec * 1000))) {
- tevent_req_nomem(NULL, req);
+ tevent_req_oom(req);
return tevent_req_post(req, ev);
}
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_nomem(NULL, req);
+ tevent_req_oom(req);
return;
}
state->subreqs[state->num_sent] = subreq;
return NT_STATUS_OK;
}
-static NTSTATUS name_queries(const char *name, int name_type,
- bool bcast, bool recurse,
- const struct sockaddr_storage *addrs,
- int num_addrs, int wait_msec, int timeout_msec,
- TALLOC_CTX *mem_ctx,
- struct sockaddr_storage **result_addrs,
- int *num_result_addrs, uint8_t *flags,
- int *received_index)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
- struct tevent_req *req;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
-
- ev = event_context_init(frame);
- if (ev == NULL) {
- goto fail;
- }
- req = name_queries_send(frame, ev, name, name_type, bcast,
- recurse, addrs, num_addrs, wait_msec,
- timeout_msec);
- if (req == NULL) {
- goto fail;
- }
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
- goto fail;
- }
- status = name_queries_recv(req, mem_ctx, result_addrs,
- num_result_addrs, flags, received_index);
- fail:
- TALLOC_FREE(frame);
- return status;
-}
-
/********************************************************
Resolve via "bcast" method.
*********************************************************/
-NTSTATUS name_resolve_bcast(const char *name,
- int name_type,
- TALLOC_CTX *mem_ctx,
- struct sockaddr_storage **return_iplist,
- int *return_count)
+struct name_resolve_bcast_state {
+ struct sockaddr_storage *addrs;
+ int num_addrs;
+};
+
+static void name_resolve_bcast_done(struct tevent_req *subreq);
+
+struct tevent_req *name_resolve_bcast_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name,
+ int name_type)
{
+ struct tevent_req *req, *subreq;
+ struct name_resolve_bcast_state *state;
struct sockaddr_storage *bcast_addrs;
int i, num_addrs, num_bcast_addrs;
+ req = tevent_req_create(mem_ctx, &state,
+ struct name_resolve_bcast_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
if (lp_disable_netbios()) {
- DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n",
- name, name_type));
- return NT_STATUS_INVALID_PARAMETER;
+ DEBUG(5, ("name_resolve_bcast(%s#%02x): netbios is disabled\n",
+ name, name_type));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
}
/*
* "bcast" means do a broadcast lookup on all the local interfaces.
*/
- DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup "
- "for name %s<0x%x>\n", name, name_type));
+ DEBUG(3, ("name_resolve_bcast: Attempting broadcast lookup "
+ "for name %s<0x%x>\n", name, name_type));
num_addrs = iface_count();
- bcast_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
- num_addrs);
- if (bcast_addrs == NULL) {
- return NT_STATUS_NO_MEMORY;
+ bcast_addrs = talloc_array(state, struct sockaddr_storage, num_addrs);
+ if (tevent_req_nomem(bcast_addrs, req)) {
+ return tevent_req_post(req, ev);
}
/*
num_bcast_addrs += 1;
}
- return name_queries(name, name_type, true, true,
- bcast_addrs, num_bcast_addrs, 0, 1000,
- mem_ctx, return_iplist, return_count,
- NULL, NULL);
+ subreq = name_queries_send(state, ev, name, name_type, true, true,
+ bcast_addrs, num_bcast_addrs, 0, 1000);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, name_resolve_bcast_done, req);
+ return req;
}
-/********************************************************
- Resolve via "wins" method.
-*********************************************************/
+static void name_resolve_bcast_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct name_resolve_bcast_state *state = tevent_req_data(
+ req, struct name_resolve_bcast_state);
+ NTSTATUS status;
-NTSTATUS resolve_wins(const char *name,
- int name_type,
- struct ip_service **return_iplist,
- int *return_count)
+ status = name_queries_recv(subreq, state,
+ &state->addrs, &state->num_addrs,
+ NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS name_resolve_bcast_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **addrs,
+ int *num_addrs)
{
- int t, i;
- char **wins_tags;
- struct sockaddr_storage src_ss, *ss_list = NULL;
- struct in_addr src_ip;
+ struct name_resolve_bcast_state *state = tevent_req_data(
+ req, struct name_resolve_bcast_state);
NTSTATUS status;
- if (lp_disable_netbios()) {
- DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n",
- name, name_type));
- return NT_STATUS_INVALID_PARAMETER;
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
}
+ *addrs = talloc_move(mem_ctx, &state->addrs);
+ *num_addrs = state->num_addrs;
+ return NT_STATUS_OK;
+}
- *return_iplist = NULL;
- *return_count = 0;
+NTSTATUS name_resolve_bcast(const char *name,
+ int name_type,
+ TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **return_iplist,
+ int *return_count)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n",
- name, name_type));
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = name_resolve_bcast_send(frame, ev, name, name_type);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = name_resolve_bcast_recv(req, mem_ctx, return_iplist,
+ return_count);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
- if (wins_srv_count() < 1) {
- DEBUG(3,("resolve_wins: WINS server resolution selected "
- "and no WINS servers listed.\n"));
- return NT_STATUS_INVALID_PARAMETER;
+struct query_wins_list_state {
+ struct tevent_context *ev;
+ const char *name;
+ uint8_t name_type;
+ struct in_addr *servers;
+ uint32_t num_servers;
+ struct sockaddr_storage server;
+ uint32_t num_sent;
+
+ struct sockaddr_storage *addrs;
+ int num_addrs;
+ uint8_t flags;
+};
+
+static void query_wins_list_done(struct tevent_req *subreq);
+
+/*
+ * Query a list of (replicating) wins servers in sequence, call them
+ * dead if they don't reply
+ */
+
+static struct tevent_req *query_wins_list_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct in_addr src_ip, const char *name, uint8_t name_type,
+ struct in_addr *servers, int num_servers)
+{
+ struct tevent_req *req, *subreq;
+ struct query_wins_list_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct query_wins_list_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->ev = ev;
+ state->name = name;
+ state->name_type = name_type;
+ state->servers = servers;
+ state->num_servers = num_servers;
- /* we try a lookup on each of the WINS tags in turn */
- wins_tags = wins_srv_tags();
+ if (state->num_servers == 0) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ return tevent_req_post(req, ev);
+ }
- if (!wins_tags) {
- /* huh? no tags?? give up in disgust */
- return NT_STATUS_INVALID_PARAMETER;
+ in_addr_to_sockaddr_storage(
+ &state->server, state->servers[state->num_sent]);
+
+ subreq = name_query_send(state, state->ev,
+ state->name, state->name_type,
+ false, true, &state->server);
+ state->num_sent += 1;
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(subreq, state->ev,
+ timeval_current_ofs(2, 0))) {
+ 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;
+
+ status = name_query_recv(subreq, state,
+ &state->addrs, &state->num_addrs,
+ &state->flags);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ wins_srv_died(state->servers[state->num_sent-1],
+ my_socket_addr_v4());
+
+ if (state->num_sent == state->num_servers) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ return;
+ }
+
+ in_addr_to_sockaddr_storage(
+ &state->server, state->servers[state->num_sent]);
+
+ subreq = name_query_send(state, state->ev,
+ state->name, state->name_type,
+ false, true, &state->server);
+ state->num_sent += 1;
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ if (!tevent_req_set_endtime(subreq, state->ev,
+ timeval_current_ofs(2, 0))) {
+ tevent_req_oom(req);
+ return;
+ }
+ tevent_req_set_callback(subreq, query_wins_list_done, req);
+}
+
+static NTSTATUS query_wins_list_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct sockaddr_storage **addrs,
+ int *num_addrs,
+ uint8_t *flags)
+{
+ struct query_wins_list_state *state = tevent_req_data(
+ req, struct query_wins_list_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (addrs != NULL) {
+ *addrs = talloc_move(mem_ctx, &state->addrs);
+ }
+ if (num_addrs != NULL) {
+ *num_addrs = state->num_addrs;
+ }
+ if (flags != NULL) {
+ *flags = state->flags;
+ }
+ return NT_STATUS_OK;
+}
+
+struct resolve_wins_state {
+ int num_sent;
+ int num_received;
+
+ struct sockaddr_storage *addrs;
+ int num_addrs;
+ uint8_t flags;
+};
+
+static void resolve_wins_done(struct tevent_req *subreq);
+
+struct tevent_req *resolve_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *name,
+ int name_type)
+{
+ struct tevent_req *req, *subreq;
+ struct resolve_wins_state *state;
+ char **wins_tags = NULL;
+ struct sockaddr_storage src_ss;
+ struct in_addr src_ip;
+ int i, num_wins_tags;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct resolve_wins_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (wins_srv_count() < 1) {
+ DEBUG(3,("resolve_wins: WINS server resolution selected "
+ "and no WINS servers listed.\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
}
/* the address we will be sending from */
- if (!interpret_string_addr(&src_ss, lp_socket_address(),
+ if (!interpret_string_addr(&src_ss, lp_nbt_client_socket_address(),
AI_NUMERICHOST|AI_PASSIVE)) {
zero_sockaddr(&src_ss);
}
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 = ((const struct sockaddr_in *)(void *)&src_ss)->sin_addr;
+
+ wins_tags = wins_srv_tags();
+ if (wins_tags == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
}
- src_ip = ((struct sockaddr_in *)&src_ss)->sin_addr;
+ 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;
+ }
- /* 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;
+ 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;
+ }
+
+ 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;
+ }
- 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);
+ if (state->num_sent == 0) {
+ tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
+ goto fail;
+ }
- /* exit loop if we got a list of addresses */
+ wins_srv_tags_free(wins_tags);
+ return req;
+fail:
+ wins_srv_tags_free(wins_tags);
+ return tevent_req_post(req, ev);
+}
- if (NT_STATUS_IS_OK(status)) {
- goto success;
- }
+static void resolve_wins_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct resolve_wins_state *state = tevent_req_data(
+ req, struct resolve_wins_state);
+ NTSTATUS status;
- 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;
- }
- }
+ 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;
+
+ if (state->num_received < state->num_sent) {
+ /*
+ * Wait for the others
+ */
+ return;
+ }
+ tevent_req_nterror(req, status);
+}
-success:
+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;
- status = NT_STATUS_OK;
- if (!convert_ss2service(return_iplist, ss_list, *return_count))
- status = 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;
+}
- TALLOC_FREE(ss_list);
- wins_srv_tags_free(wins_tags);
+/********************************************************
+ 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 = samba_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;
}
if (NT_STATUS_IS_OK(status)) {
if (convert_ss2service(return_iplist,
ss_list,
- *return_count)) {
+ return_count)) {
talloc_free(ctx);
return NT_STATUS_OK;
} else {
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 "
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,
ZERO_STRUCT(ss);
memcpy(&ss, res->ai_addr, res->ai_addrlen);
+ if (is_zero_addr(&ss)) {
+ continue;
+ }
+
*return_count += 1;
*return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
struct ip_service **return_iplist,
int *return_count)
{
- int i, j;
+ int i;
NTSTATUS status;
TALLOC_CTX *ctx;
struct dns_rr_srv *dcs = NULL;
}
/* The DNS code needs fixing to find IPv6 addresses... JRA. */
-
switch (name_type) {
case 0x1b:
DEBUG(5,("resolve_ads: Attempting to resolve "
"PDC for %s using DNS\n", name));
- status = ads_dns_query_pdc(ctx, name, &dcs, &numdcs);
+ status = ads_dns_query_pdc(ctx,
+ name,
+ &dcs,
+ &numdcs);
break;
case 0x1c:
DEBUG(5,("resolve_ads: Attempting to resolve "
"DCs for %s using DNS\n", name));
- status = ads_dns_query_dcs(ctx, name, sitename, &dcs,
+ status = ads_dns_query_dcs(ctx,
+ name,
+ sitename,
+ &dcs,
&numdcs);
break;
case KDC_NAME_TYPE:
DEBUG(5,("resolve_ads: Attempting to resolve "
"KDCs for %s using DNS\n", name));
- status = ads_dns_query_kdcs(ctx, name, sitename, &dcs,
+ status = ads_dns_query_kdcs(ctx,
+ name,
+ sitename,
+ &dcs,
&numdcs);
break;
default:
}
for (i=0;i<numdcs;i++) {
- numaddrs += MAX(dcs[i].num_ips,1);
- }
+ if (!dcs[i].ss_s) {
+ numaddrs += 1;
+ } else {
+ numaddrs += dcs[i].num_ips;
+ }
+ }
if ((*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) ==
NULL ) {
/* now unroll the list of IP addresses */
*return_count = 0;
- i = 0;
- j = 0;
- while ( i < numdcs && (*return_count<numaddrs) ) {
- struct ip_service *r = &(*return_iplist)[*return_count];
-
- r->port = dcs[i].port;
+ for (i = 0; i < numdcs && (*return_count<numaddrs); i++ ) {
/* If we don't have an IP list for a name, lookup it up */
-
if (!dcs[i].ss_s) {
- interpret_string_addr(&r->ss, dcs[i].hostname, 0);
- i++;
- j = 0;
- } else {
- /* use the IP addresses from the SRV sresponse */
-
- if ( j >= dcs[i].num_ips ) {
- i++;
- j = 0;
+ /* We need to get all IP addresses here. */
+ struct addrinfo *res = NULL;
+ struct addrinfo *p;
+ int extra_addrs = 0;
+
+ if (!interpret_string_addr_internal(&res,
+ dcs[i].hostname,
+ 0)) {
continue;
}
-
- r->ss = dcs[i].ss_s[j];
- j++;
- }
-
- /* make sure it is a valid IP. I considered checking the
- * negative connection cache, but this is the wrong place
- * for it. Maybe only as a hack. After think about it, if
- * all of the IP addresses returned from DNS are dead, what
- * hope does a netbios name lookup have ? The standard reason
- * for falling back to netbios lookups is that our DNS server
- * doesn't know anything about the DC's -- jerry */
-
- if (!is_zero_addr(&r->ss)) {
- (*return_count)++;
+ /* Add in every IP from the lookup. How
+ many is that ? */
+ for (p = res; p; p = p->ai_next) {
+ struct sockaddr_storage ss;
+ memcpy(&ss, p->ai_addr, p->ai_addrlen);
+ if (is_zero_addr(&ss)) {
+ continue;
+ }
+ extra_addrs++;
+ }
+ if (extra_addrs > 1) {
+ /* We need to expand the return_iplist array
+ as we only budgeted for one address. */
+ numaddrs += (extra_addrs-1);
+ *return_iplist = SMB_REALLOC_ARRAY(*return_iplist,
+ struct ip_service,
+ numaddrs);
+ if (*return_iplist == NULL) {
+ if (res) {
+ freeaddrinfo(res);
+ }
+ talloc_destroy(ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ for (p = res; p; p = p->ai_next) {
+ (*return_iplist)[*return_count].port = dcs[i].port;
+ memcpy(&(*return_iplist)[*return_count].ss,
+ p->ai_addr,
+ p->ai_addrlen);
+ if (is_zero_addr(&(*return_iplist)[*return_count].ss)) {
+ continue;
+ }
+ (*return_count)++;
+ /* Should never happen, but still... */
+ if (*return_count>=numaddrs) {
+ break;
+ }
+ }
+ if (res) {
+ freeaddrinfo(res);
+ }
+ } else {
+ /* use all the IP addresses from the SRV sresponse */
+ int j;
+ for (j = 0; j < dcs[i].num_ips; j++) {
+ (*return_iplist)[*return_count].port = dcs[i].port;
+ (*return_iplist)[*return_count].ss = dcs[i].ss_s[j];
+ if (is_zero_addr(&(*return_iplist)[*return_count].ss)) {
+ continue;
+ }
+ (*return_count)++;
+ /* Should never happen, but still... */
+ if (*return_count>=numaddrs) {
+ break;
+ }
+ }
}
}
const char *sitename,
struct ip_service **return_iplist,
int *return_count,
- const char *resolve_order)
+ const char **resolve_order)
{
- char *tok;
- const char *ptr;
+ const char *tok;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
int i;
TALLOC_CTX *frame = NULL;
SAFE_FREE(*return_iplist);
return NT_STATUS_INVALID_PARAMETER;
}
+ if (is_zero_addr(&(*return_iplist)->ss)) {
+ SAFE_FREE(*return_iplist);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
*return_count = 1;
return NT_STATUS_OK;
}
/* Check name cache */
if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+ *return_count = remove_duplicate_addrs2(*return_iplist,
+ *return_count );
/* This could be a negative response */
if (*return_count > 0) {
return NT_STATUS_OK;
/* set the name resolution order */
- if (strcmp( resolve_order, "NULL") == 0) {
+ if (resolve_order && strcmp(resolve_order[0], "NULL") == 0) {
DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
return NT_STATUS_INVALID_PARAMETER;
}
- if (!resolve_order[0]) {
- ptr = "host";
- } else {
- ptr = resolve_order;
+ if (!resolve_order || !resolve_order[0]) {
+ static const char *host_order[] = { "host", NULL };
+ resolve_order = host_order;
}
/* iterate through the name resolution backends */
frame = talloc_stackframe();
- while (next_token_talloc(frame, &ptr, &tok, LIST_SEP)) {
+ for (i=0; resolve_order[i]; i++) {
+ tok = resolve_order[i];
+
if((strequal(tok, "host") || strequal(tok, "hosts"))) {
status = resolve_hosts(name, name_type, return_iplist,
return_count);
}
} 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;
}
}
if (NT_STATUS_IS_OK(status)) {
if (!convert_ss2service(return_iplist,
ss_list,
- *return_count)) {
+ return_count)) {
status = NT_STATUS_NO_MEMORY;
}
goto done;
controllers including the PDC in iplist[1..n]. Iterating over
the iplist when the PDC is down will cause two sets of timeouts. */
- if ( *return_count ) {
- *return_count = remove_duplicate_addrs2(*return_iplist,
- *return_count );
- }
+ *return_count = remove_duplicate_addrs2(*return_iplist, *return_count );
/* Save in name cache */
if ( DEBUGLEVEL >= 100 ) {
}
}
- namecache_store(name, name_type, *return_count, *return_iplist);
+ if (*return_count) {
+ namecache_store(name, name_type, *return_count, *return_iplist);
+ }
/* Display some debugging info */
struct ip_service *ss_list = NULL;
char *sitename = NULL;
int count = 0;
+ NTSTATUS status;
if (is_ipaddress(name)) {
return interpret_string_addr(return_ss, name, AI_NUMERICHOST);
}
- sitename = sitename_fetch(lp_realm()); /* wild guess */
+ sitename = sitename_fetch(talloc_tos(), lp_realm()); /* wild guess */
- if (NT_STATUS_IS_OK(internal_resolve_name(name, name_type, sitename,
- &ss_list, &count,
- lp_name_resolve_order()))) {
+ status = internal_resolve_name(name, name_type, sitename,
+ &ss_list, &count,
+ lp_name_resolve_order());
+ if (NT_STATUS_IS_OK(status)) {
int i;
if (prefer_ipv4) {
for (i=0; i<count; i++) {
if (!is_zero_addr(&ss_list[i].ss) &&
- !is_broadcast_addr((struct sockaddr *)&ss_list[i].ss) &&
+ !is_broadcast_addr((struct sockaddr *)(void *)&ss_list[i].ss) &&
(ss_list[i].ss.ss_family == AF_INET)) {
*return_ss = ss_list[i].ss;
SAFE_FREE(ss_list);
- SAFE_FREE(sitename);
+ TALLOC_FREE(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((struct sockaddr *)&ss_list[i].ss)) {
+ !is_broadcast_addr((struct sockaddr *)(void *)&ss_list[i].ss)) {
*return_ss = ss_list[i].ss;
SAFE_FREE(ss_list);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
return True;
}
}
}
SAFE_FREE(ss_list);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
return False;
}
*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;
}
return NT_STATUS_OK;
}
- sitename = sitename_fetch(lp_realm()); /* wild guess */
+ sitename = sitename_fetch(ctx, lp_realm()); /* wild guess */
status = internal_resolve_name(name, name_type, sitename,
&ss_list, &count,
lp_name_resolve_order());
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
if (!NT_STATUS_IS_OK(status)) {
return status;
/* 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++;
}
}
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)) {
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;
}
}
struct ip_service *ip_list = NULL;
int count = 0;
NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-
+ static const char *ads_order[] = { "ads", NULL };
/* Look up #1B name */
if (lp_security() == SEC_ADS) {
status = internal_resolve_name(domain, 0x1b, NULL, &ip_list,
- &count, "ads");
+ &count, ads_order);
}
if (!NT_STATUS_IS_OK(status) || count == 0) {
&count,
lp_name_resolve_order());
if (!NT_STATUS_IS_OK(status)) {
+ SAFE_FREE(ip_list);
return false;
}
}
enum dc_lookup_type lookup_type,
bool *ordered)
{
- char *resolve_order = NULL;
+ const char **resolve_order = NULL;
char *saf_servername = NULL;
char *pserver = NULL;
const char *p;
are disabled and ads_only is True, then set the string to
NULL. */
- resolve_order = talloc_strdup(ctx, lp_name_resolve_order());
+ resolve_order = lp_name_resolve_order();
if (!resolve_order) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
- strlower_m(resolve_order);
if (lookup_type == DC_ADS_ONLY) {
- if (strstr( resolve_order, "host")) {
- resolve_order = talloc_strdup(ctx, "ads");
+ if (str_list_check_ci(resolve_order, "host")) {
+ static const char *ads_order[] = { "ads", NULL };
+ resolve_order = ads_order;
/* DNS SRV lookups used by the ads resolver
are already sorted by priority and weight */
*ordered = true;
} else {
- resolve_order = talloc_strdup(ctx, "NULL");
+ /* this is quite bizarre! */
+ static const char *null_order[] = { "NULL", NULL };
+ resolve_order = null_order;
}
} else if (lookup_type == DC_KDC_ONLY) {
+ static const char *kdc_order[] = { "kdc", NULL };
/* DNS SRV lookups used by the ads/kdc resolver
are already sorted by priority and weight */
*ordered = true;
- resolve_order = talloc_strdup(ctx, "kdc");
+ resolve_order = kdc_order;
}
if (!resolve_order) {
status = NT_STATUS_NO_MEMORY;
/* fetch the server we have affinity for. Add the
'password server' list to a search for our domain controllers */
- saf_servername = saf_fetch( domain);
+ saf_servername = saf_fetch(ctx, domain);
if (strequal(domain, lp_workgroup()) || strequal(domain, lp_realm())) {
pserver = talloc_asprintf(ctx, "%s, %s",
saf_servername ? saf_servername : "",
- lp_passwordserver());
+ lp_password_server());
} else {
pserver = talloc_asprintf(ctx, "%s, *",
saf_servername ? saf_servername : "");
}
- SAFE_FREE(saf_servername);
+ TALLOC_FREE(saf_servername);
if (!pserver) {
status = NT_STATUS_NO_MEMORY;
goto out;
/* if we have no addresses and haven't done the auto lookup, then
just return the list of DC's. Or maybe we just failed. */
- if ((num_addresses == 0)) {
+ if (num_addresses == 0) {
if (done_auto_lookup) {
DEBUG(4,("get_dc_list: no servers found\n"));
status = NT_STATUS_NO_LOGON_SERVERS;
/* need to remove duplicates in the list if we have any
explicit password servers */
- if (local_count) {
- local_count = remove_duplicate_addrs2(return_iplist,
- local_count );
- }
+ local_count = remove_duplicate_addrs2(return_iplist, local_count );
/* For DC's we always prioritize IPv4 due to W2K3 not
* supporting LDAP, KRB5 or CLDAP over IPv6. */
*count = 0;
DEBUG(8,("get_sorted_dc_list: attempting lookup "
- "for name %s (sitename %s) using [%s]\n",
+ "for name %s (sitename %s)\n",
domain,
- sitename ? sitename : "NULL",
- (ads_only ? "ads" : lp_name_resolve_order())));
+ sitename ? sitename : "NULL"));
if (ads_only) {
lookup_type = DC_ADS_ONLY;