diff options
Diffstat (limited to 'source4/libcli/resolve')
-rw-r--r-- | source4/libcli/resolve/bcast.c | 32 | ||||
-rw-r--r-- | source4/libcli/resolve/dns_ex.c | 532 | ||||
-rw-r--r-- | source4/libcli/resolve/host.c | 209 | ||||
-rw-r--r-- | source4/libcli/resolve/nbtlist.c | 53 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve.c | 45 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve.h | 22 | ||||
-rw-r--r-- | source4/libcli/resolve/testsuite.c | 4 | ||||
-rw-r--r-- | source4/libcli/resolve/wins.c | 33 |
8 files changed, 639 insertions, 291 deletions
diff --git a/source4/libcli/resolve/bcast.c b/source4/libcli/resolve/bcast.c index 0a71ebed99..866ce7a152 100644 --- a/source4/libcli/resolve/bcast.c +++ b/source4/libcli/resolve/bcast.c @@ -37,7 +37,8 @@ struct resolve_bcast_data { */ struct composite_context *resolve_name_bcast_send(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, - void *userdata, + void *userdata, uint32_t flags, + uint16_t port, struct nbt_name *name) { int num_interfaces; @@ -63,7 +64,9 @@ struct composite_context *resolve_name_bcast_send(TALLOC_CTX *mem_ctx, } address_list[count] = NULL; - c = resolve_name_nbtlist_send(mem_ctx, event_ctx, name, address_list, data->ifaces, data->nbt_port, data->nbt_timeout, true, false); + c = resolve_name_nbtlist_send(mem_ctx, event_ctx, flags, port, name, + address_list, data->ifaces, data->nbt_port, + data->nbt_timeout, true, false); talloc_free(address_list); return c; @@ -74,9 +77,10 @@ struct composite_context *resolve_name_bcast_send(TALLOC_CTX *mem_ctx, */ NTSTATUS resolve_name_bcast_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) + struct socket_address ***addrs, + char ***names) { - NTSTATUS status = resolve_name_nbtlist_recv(c, mem_ctx, addrs); + NTSTATUS status = resolve_name_nbtlist_recv(c, mem_ctx, addrs, names); if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { /* this makes much more sense for a bcast name resolution timeout */ @@ -85,26 +89,6 @@ NTSTATUS resolve_name_bcast_recv(struct composite_context *c, return status; } -/* - broadcast name resolution method - sync call - */ -NTSTATUS resolve_name_bcast(struct nbt_name *name, - TALLOC_CTX *mem_ctx, - struct interface *ifaces, - uint16_t nbt_port, - int nbt_timeout, - struct socket_address ***addrs) -{ - struct resolve_bcast_data *data = talloc(mem_ctx, struct resolve_bcast_data); - struct composite_context *c; - data->ifaces = talloc_reference(data, ifaces); - data->nbt_port = nbt_port; - data->nbt_timeout = nbt_timeout; - - c = resolve_name_bcast_send(mem_ctx, NULL, data, name); - return resolve_name_bcast_recv(c, mem_ctx, addrs); -} - bool resolve_context_add_bcast_method(struct resolve_context *ctx, struct interface *ifaces, uint16_t nbt_port, int nbt_timeout) { struct resolve_bcast_data *data = talloc(ctx, struct resolve_bcast_data); diff --git a/source4/libcli/resolve/dns_ex.c b/source4/libcli/resolve/dns_ex.c new file mode 100644 index 0000000000..948ad9f134 --- /dev/null +++ b/source4/libcli/resolve/dns_ex.c @@ -0,0 +1,532 @@ +/* + Unix SMB/CIFS implementation. + + async getaddrinfo()/dns_lookup() name resolution module + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Stefan Metzmacher 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + this module uses a fork() per getaddrinfo() or dns_looup() call. + At first that might seem crazy, but it is actually very fast, + and solves many of the tricky problems of keeping a child + hanging around in a librar (like what happens when the parent forks). + We use a talloc destructor to ensure that the child is cleaned up + when we have finished with this name resolution. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "system/network.h" +#include "system/filesys.h" +#include "lib/socket/socket.h" +#include "libcli/composite/composite.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "libcli/resolve/resolve.h" +#include "heimdal/lib/roken/resolve.h" + +struct dns_ex_state { + bool do_fallback; + uint32_t flags; + uint16_t port; + struct nbt_name name; + struct socket_address **addrs; + char **names; + pid_t child; + int child_fd; + struct fd_event *fde; + struct event_context *event_ctx; +}; + +/* + kill off a wayward child if needed. This allows us to stop an async + name resolution without leaving a potentially blocking call running + in a child +*/ +static int dns_ex_destructor(struct dns_ex_state *state) +{ + int status; + + kill(state->child, SIGTERM); + close(state->child_fd); + if (waitpid(state->child, &status, WNOHANG) == 0) { + kill(state->child, SIGKILL); + waitpid(state->child, &status, 0); + } + + return 0; +} + +/* + the blocking child +*/ +static void run_child_dns_lookup(struct dns_ex_state *state, int fd) +{ + struct dns_reply *reply; + struct resource_record *rr; + uint32_t count = 0; + uint32_t srv_valid = 0; + struct resource_record **srv_rr; + uint32_t addrs_valid = 0; + struct resource_record **addrs_rr; + char *addrs; + bool first; + uint32_t i; + bool do_srv = (state->flags & RESOLVE_NAME_FLAG_DNS_SRV); + + /* this is the blocking call we are going to lots of trouble + to avoid in the parent */ + reply = dns_lookup(state->name.name, do_srv?"SRV":"A"); + if (!reply) { + goto done; + } + + if (do_srv) { + dns_srv_order(reply); + } + + /* Loop over all returned records and pick the "srv" records */ + for (rr=reply->head; rr; rr=rr->next) { + /* we are only interested in the IN class */ + if (rr->class != C_IN) { + continue; + } + + if (do_srv) { + /* we are only interested in SRV records */ + if (rr->type != T_SRV) { + continue; + } + + /* verify we actually have a SRV record here */ + if (!rr->u.srv) { + continue; + } + + /* Verify we got a port */ + if (rr->u.srv->port == 0) { + continue; + } + } else { + /* we are only interested in A records */ + /* TODO: add AAAA support */ + if (rr->type != T_A) { + continue; + } + + /* verify we actually have a A record here */ + if (!rr->u.a) { + continue; + } + } + count++; + } + + if (count == 0) { + goto done; + } + + srv_rr = talloc_zero_array(state, + struct resource_record *, + count); + if (!srv_rr) { + goto done; + } + + addrs_rr = talloc_zero_array(state, + struct resource_record *, + count); + if (!addrs_rr) { + goto done; + } + + /* Loop over all returned records and pick the records */ + for (rr=reply->head;rr;rr=rr->next) { + /* we are only interested in the IN class */ + if (rr->class != C_IN) { + continue; + } + + if (do_srv) { + /* we are only interested in SRV records */ + if (rr->type != T_SRV) { + continue; + } + + /* verify we actually have a srv record here */ + if (!rr->u.srv) { + continue; + } + + /* Verify we got a port */ + if (rr->u.srv->port == 0) { + continue; + } + + srv_rr[srv_valid] = rr; + srv_valid++; + } else { + /* we are only interested in A records */ + /* TODO: add AAAA support */ + if (rr->type != T_A) { + continue; + } + + /* verify we actually have a A record here */ + if (!rr->u.a) { + continue; + } + + addrs_rr[addrs_valid] = rr; + addrs_valid++; + } + } + + for (i=0; i < srv_valid; i++) { + for (rr=reply->head;rr;rr=rr->next) { + + if (rr->class != C_IN) { + continue; + } + + /* we are only interested in SRV records */ + if (rr->type != T_A) { + continue; + } + + /* verify we actually have a srv record here */ + if (strcmp(&srv_rr[i]->u.srv->target[0], rr->domain) != 0) { + continue; + } + + addrs_rr[i] = rr; + addrs_valid++; + break; + } + } + + if (addrs_valid == 0) { + goto done; + } + + addrs = talloc_strdup(state, ""); + if (!addrs) { + goto done; + } + first = true; + for (i=0; i < count; i++) { + uint16_t port; + if (!addrs_rr[i]) { + continue; + } + + if (srv_rr[i] && + (state->flags & RESOLVE_NAME_FLAG_OVERWRITE_PORT)) { + port = srv_rr[i]->u.srv->port; + } else { + port = state->port; + } + + addrs = talloc_asprintf_append_buffer(addrs, "%s%s:%u/%s", + first?"":",", + inet_ntoa(*addrs_rr[i]->u.a), + port, + addrs_rr[i]->domain); + if (!addrs) { + goto done; + } + first = false; + } + + if (addrs) { + write(fd, addrs, talloc_get_size(addrs)); + } + +done: + close(fd); +} + +/* + the blocking child +*/ +static void run_child_getaddrinfo(struct dns_ex_state *state, int fd) +{ + int ret; + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *res_list = NULL; + char *addrs; + bool first; + + ZERO_STRUCT(hints); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET;/* TODO: add AF_INET6 support */ + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; + + ret = getaddrinfo(state->name.name, "0", &hints, &res_list); + if (ret == EAI_NODATA && state->do_fallback) { + /* getaddrinfo() doesn't handle CNAME records */ + run_child_dns_lookup(state, fd); + return; + } + if (ret != 0) { + goto done; + } + + addrs = talloc_strdup(state, ""); + if (!addrs) { + goto done; + } + first = true; + for (res = res_list; res; res = res->ai_next) { + struct sockaddr_in *in; + + if (res->ai_family != AF_INET) { + continue; + } + in = (struct sockaddr_in *)res->ai_addr; + + addrs = talloc_asprintf_append_buffer(addrs, "%s%s:%u/%s", + first?"":",", + inet_ntoa(in->sin_addr), + state->port, + state->name.name); + if (!addrs) { + goto done; + } + first = false; + } + + if (addrs) { + write(fd, addrs, talloc_get_size(addrs)); + } +done: + if (res_list) { + freeaddrinfo(res_list); + } + close(fd); +} + +/* + handle a read event on the pipe +*/ +static void pipe_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *private_data) +{ + struct composite_context *c = talloc_get_type(private_data, struct composite_context); + struct dns_ex_state *state = talloc_get_type(c->private_data, + struct dns_ex_state); + char *address; + uint32_t num_addrs, i; + char **addrs; + int ret; + int status; + int value = 0; + + /* if we get any event from the child then we know that we + won't need to kill it off */ + talloc_set_destructor(state, NULL); + + if (ioctl(state->child_fd, FIONREAD, &value) != 0) { + value = 8192; + } + + address = talloc_array(state, char, value+1); + if (address) { + /* yes, we don't care about EAGAIN or other niceities + here. They just can't happen with this parent/child + relationship, and even if they did then giving an error is + the right thing to do */ + ret = read(state->child_fd, address, value); + } else { + ret = -1; + } + close(state->child_fd); + if (waitpid(state->child, &status, WNOHANG) == 0) { + kill(state->child, SIGKILL); + waitpid(state->child, &status, 0); + } + + if (ret <= 0) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + /* enusre the address looks good */ + address[ret] = 0; + + addrs = str_list_make(state, address, ","); + if (composite_nomem(addrs, c)) return; + + num_addrs = str_list_length((const char * const *)addrs); + + state->addrs = talloc_array(state, struct socket_address *, + num_addrs+1); + if (composite_nomem(state->addrs, c)) return; + + state->names = talloc_array(state, char *, num_addrs+1); + if (composite_nomem(state->names, c)) return; + + for (i=0; i < num_addrs; i++) { + uint32_t port = 0; + char *p = strrchr(addrs[i], ':'); + char *n; + + if (!p) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + *p = '\0'; + p++; + + n = strrchr(p, '/'); + if (!n) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + *n = '\0'; + n++; + + if (strcmp(addrs[i], "0.0.0.0") == 0 || + inet_addr(addrs[i]) == INADDR_NONE) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + port = strtoul(p, NULL, 10); + if (port > UINT16_MAX) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + state->addrs[i] = socket_address_from_strings(state->addrs, + "ipv4", + addrs[i], + port); + if (composite_nomem(state->addrs[i], c)) return; + + state->names[i] = talloc_strdup(state->names, n); + if (composite_nomem(state->names[i], c)) return; + } + state->addrs[i] = NULL; + state->names[i] = NULL; + + composite_done(c); +} + +/* + getaddrinfo() or dns_lookup() name resolution method - async send + */ +struct composite_context *resolve_name_dns_ex_send(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + void *privdata, + uint32_t flags, + uint16_t port, + struct nbt_name *name, + bool do_fallback) +{ + struct composite_context *c; + struct dns_ex_state *state; + int fd[2] = { -1, -1 }; + int ret; + + c = composite_create(mem_ctx, event_ctx); + if (c == NULL) return NULL; + + if (flags & RESOLVE_NAME_FLAG_FORCE_NBT) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return c; + } + + state = talloc_zero(c, struct dns_ex_state); + if (composite_nomem(state, c)) return c; + c->private_data = state; + + c->status = nbt_name_dup(state, name, &state->name); + if (!composite_is_ok(c)) return c; + + /* setup a pipe to chat to our child */ + ret = pipe(fd); + if (ret == -1) { + composite_error(c, map_nt_error_from_unix(errno)); + return c; + } + + state->do_fallback = do_fallback; + state->flags = flags; + state->port = port; + + state->child_fd = fd[0]; + state->event_ctx = c->event_ctx; + + /* we need to put the child in our event context so + we know when the dns_lookup() has finished */ + state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ, + pipe_handler, c); + if (composite_nomem(state->fde, c)) { + close(fd[0]); + close(fd[1]); + return c; + } + + state->child = fork(); + if (state->child == (pid_t)-1) { + composite_error(c, map_nt_error_from_unix(errno)); + return c; + } + + if (state->child == 0) { + close(fd[0]); + if (state->flags & RESOLVE_NAME_FLAG_FORCE_DNS) { + run_child_dns_lookup(state, fd[1]); + } else { + run_child_getaddrinfo(state, fd[1]); + } + _exit(0); + } + close(fd[1]); + + /* cleanup wayward children */ + talloc_set_destructor(state, dns_ex_destructor); + + return c; +} + +/* + getaddrinfo() or dns_lookup() name resolution method - recv side +*/ +NTSTATUS resolve_name_dns_ex_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + struct socket_address ***addrs, + char ***names) +{ + NTSTATUS status; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct dns_ex_state *state = talloc_get_type(c->private_data, + struct dns_ex_state); + *addrs = talloc_steal(mem_ctx, state->addrs); + if (names) { + *names = talloc_steal(mem_ctx, state->names); + } + } + + talloc_free(c); + return status; +} diff --git a/source4/libcli/resolve/host.c b/source4/libcli/resolve/host.c index 7b1aef803e..b7eaf4bef5 100644 --- a/source4/libcli/resolve/host.c +++ b/source4/libcli/resolve/host.c @@ -1,33 +1,25 @@ /* Unix SMB/CIFS implementation. - async gethostbyname() name resolution module + async "host" name resolution module Copyright (C) Andrew Tridgell 2005 - + Copyright (C) Stefan Metzmacher 2008 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* - this module uses a fork() per gethostbyname() call. At first that - might seem crazy, but it is actually very fast, and solves many of - the tricky problems of keeping a child hanging around in a library - (like what happens when the parent forks). We use a talloc - destructor to ensure that the child is cleaned up when we have - finished with this name resolution. -*/ - #include "includes.h" #include "lib/events/events.h" #include "system/network.h" @@ -37,201 +29,28 @@ #include "librpc/gen_ndr/ndr_nbt.h" #include "libcli/resolve/resolve.h" -struct host_state { - struct nbt_name name; - struct socket_address **addrs; - pid_t child; - int child_fd; - struct fd_event *fde; - struct event_context *event_ctx; -}; - - /* - kill off a wayward child if needed. This allows us to stop an async - name resolution without leaving a potentially blocking call running - in a child -*/ -static int host_destructor(struct host_state *state) -{ - int status; - - kill(state->child, SIGTERM); - close(state->child_fd); - if (waitpid(state->child, &status, WNOHANG) == 0) { - kill(state->child, SIGKILL); - waitpid(state->child, &status, 0); - } - - return 0; -} - -/* - the blocking child -*/ -static void run_child(struct composite_context *c, int fd) -{ - struct host_state *state = talloc_get_type(c->private_data, struct host_state); - struct in_addr ip; - const char *address; - - /* this is the blocking call we are going to lots of trouble - to avoid in the parent */ - ip = interpret_addr2(state->name.name); - - address = inet_ntoa(ip); - if (address != NULL) { - write(fd, address, strlen(address)+1); - } - close(fd); -} - -/* - handle a read event on the pipe -*/ -static void pipe_handler(struct event_context *ev, struct fd_event *fde, - uint16_t flags, void *private_data) -{ - struct composite_context *c = talloc_get_type(private_data, struct composite_context); - struct host_state *state = talloc_get_type(c->private_data, struct host_state); - char address[128]; - int ret; - int status; - - /* if we get any event from the child then we know that we - won't need to kill it off */ - talloc_set_destructor(state, NULL); - - /* yes, we don't care about EAGAIN or other niceities - here. They just can't happen with this parent/child - relationship, and even if they did then giving an error is - the right thing to do */ - ret = read(state->child_fd, address, sizeof(address)-1); - close(state->child_fd); - if (waitpid(state->child, &status, WNOHANG) == 0) { - kill(state->child, SIGKILL); - waitpid(state->child, &status, 0); - } - if (ret <= 0) { - composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); - return; - } - - /* enusre the address looks good */ - address[ret] = 0; - if (strcmp(address, "0.0.0.0") == 0 || - inet_addr(address) == INADDR_NONE) { - composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); - return; - } - - state->addrs = talloc_array(state, struct socket_address *, 2); - if (composite_nomem(state->addrs, c)) return; - - state->addrs[0] = socket_address_from_strings(state->addrs, - "ipv4", - address, - 0); - if (composite_nomem(state->addrs[0], c)) return; - state->addrs[1] = NULL; - - composite_done(c); -} - -/* - gethostbyname name resolution method - async send + getaddrinfo() (with fallback to dns_lookup()) name resolution method - async send */ struct composite_context *resolve_name_host_send(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, - void *privdata, + void *privdata, uint32_t flags, + uint16_t port, struct nbt_name *name) { - struct composite_context *c; - struct host_state *state; - int fd[2] = { -1, -1 }; - int ret; - - c = composite_create(mem_ctx, event_ctx); - if (c == NULL) return NULL; - - if (composite_nomem(c->event_ctx, c)) return c; - - state = talloc(c, struct host_state); - if (composite_nomem(state, c)) return c; - c->private_data = state; - - c->status = nbt_name_dup(state, name, &state->name); - if (!composite_is_ok(c)) return c; - - /* setup a pipe to chat to our child */ - ret = pipe(fd); - if (ret == -1) { - composite_error(c, map_nt_error_from_unix(errno)); - return c; - } - - state->child_fd = fd[0]; - state->event_ctx = c->event_ctx; - - /* we need to put the child in our event context so - we know when the gethostbyname() has finished */ - state->fde = event_add_fd(c->event_ctx, c, state->child_fd, EVENT_FD_READ, - pipe_handler, c); - if (composite_nomem(state->fde, c)) { - close(fd[0]); - close(fd[1]); - return c; - } - - state->child = fork(); - if (state->child == (pid_t)-1) { - composite_error(c, map_nt_error_from_unix(errno)); - return c; - } - - - if (state->child == 0) { - close(fd[0]); - run_child(c, fd[1]); - _exit(0); - } - close(fd[1]); - - /* cleanup wayward children */ - talloc_set_destructor(state, host_destructor); - - return c; + return resolve_name_dns_ex_send(mem_ctx, event_ctx, NULL, flags, + port, name, true); } /* - gethostbyname name resolution method - recv side + getaddrinfo() (with fallback to dns_lookup()) name resolution method - recv side */ NTSTATUS resolve_name_host_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) -{ - NTSTATUS status; - - status = composite_wait(c); - - if (NT_STATUS_IS_OK(status)) { - struct host_state *state = talloc_get_type(c->private_data, struct host_state); - *addrs = talloc_steal(mem_ctx, state->addrs); - } - - talloc_free(c); - return status; -} - -/* - gethostbyname name resolution method - sync call - */ -NTSTATUS resolve_name_host(struct nbt_name *name, - TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) + struct socket_address ***addrs, + char ***names) { - struct composite_context *c = resolve_name_host_send(mem_ctx, NULL, NULL, name); - return resolve_name_host_recv(c, mem_ctx, addrs); + return resolve_name_dns_ex_recv(c, mem_ctx, addrs, names); } bool resolve_context_add_host_method(struct resolve_context *ctx) diff --git a/source4/libcli/resolve/nbtlist.c b/source4/libcli/resolve/nbtlist.c index 9c53fcb7ec..734fd5a5bc 100644 --- a/source4/libcli/resolve/nbtlist.c +++ b/source4/libcli/resolve/nbtlist.c @@ -34,12 +34,15 @@ #include "libcli/resolve/resolve.h" struct nbtlist_state { + uint16_t flags; + uint16_t port; struct nbt_name name; struct nbt_name_socket *nbtsock; int num_queries; struct nbt_name_request **queries; struct nbt_name_query *io_queries; struct socket_address **addrs; + char **names; struct interface *ifaces; }; @@ -81,14 +84,21 @@ static void nbtlist_handler(struct nbt_name_request *req) q->out.num_addrs + 1); if (composite_nomem(state->addrs, c)) return; + state->names = talloc_array(state, char *, q->out.num_addrs + 1); + if (composite_nomem(state->names, c)) return; + for (i=0;i<q->out.num_addrs;i++) { state->addrs[i] = socket_address_from_strings(state->addrs, "ipv4", q->out.reply_addrs[i], - 0); + state->port); if (composite_nomem(state->addrs[i], c)) return; + + state->names[i] = talloc_strdup(state->names, state->name.name); + if (composite_nomem(state->names[i], c)) return; } state->addrs[i] = NULL; + state->names[i] = NULL; composite_done(c); } @@ -98,6 +108,8 @@ static void nbtlist_handler(struct nbt_name_request *req) */ struct composite_context *resolve_name_nbtlist_send(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, + uint32_t flags, + uint16_t port, struct nbt_name *name, const char **address_list, struct interface *ifaces, @@ -113,12 +125,23 @@ struct composite_context *resolve_name_nbtlist_send(TALLOC_CTX *mem_ctx, c = composite_create(mem_ctx, event_ctx); if (c == NULL) return NULL; - if (composite_nomem(c->event_ctx, c)) return c; + if (flags & RESOLVE_NAME_FLAG_FORCE_DNS) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return c; + } + + if (strlen(name->name) > 15) { + composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return c; + } state = talloc(c, struct nbtlist_state); if (composite_nomem(state, c)) return c; c->private_data = state; + state->flags = flags; + state->port = port; + c->status = nbt_name_dup(state, name, &state->name); if (!composite_is_ok(c)) return c; @@ -180,7 +203,8 @@ struct composite_context *resolve_name_nbtlist_send(TALLOC_CTX *mem_ctx, */ NTSTATUS resolve_name_nbtlist_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) + struct socket_address ***addrs, + char ***names) { NTSTATUS status; @@ -189,29 +213,12 @@ NTSTATUS resolve_name_nbtlist_recv(struct composite_context *c, if (NT_STATUS_IS_OK(status)) { struct nbtlist_state *state = talloc_get_type(c->private_data, struct nbtlist_state); *addrs = talloc_steal(mem_ctx, state->addrs); + if (names) { + *names = talloc_steal(mem_ctx, state->names); + } } talloc_free(c); return status; } -/* - nbt list of addresses name resolution method - sync call - */ -NTSTATUS resolve_name_nbtlist(struct nbt_name *name, - TALLOC_CTX *mem_ctx, - const char **address_list, - struct interface *ifaces, - uint16_t nbt_port, - int nbt_timeout, - bool broadcast, bool wins_lookup, - struct socket_address ***addrs) -{ - struct composite_context *c = resolve_name_nbtlist_send(mem_ctx, NULL, - name, address_list, - ifaces, nbt_port, - nbt_timeout, - broadcast, wins_lookup); - return resolve_name_nbtlist_recv(c, mem_ctx, addrs); -} - diff --git a/source4/libcli/resolve/resolve.c b/source4/libcli/resolve/resolve.c index 7d1c48cbee..752678abb8 100644 --- a/source4/libcli/resolve/resolve.c +++ b/source4/libcli/resolve/resolve.c @@ -21,7 +21,6 @@ */ #include "includes.h" -#include "lib/events/events.h" #include "libcli/composite/composite.h" #include "libcli/resolve/resolve.h" #include "librpc/gen_ndr/ndr_nbt.h" @@ -32,9 +31,12 @@ struct resolve_state { struct resolve_context *ctx; struct resolve_method *method; + uint32_t flags; + uint16_t port; struct nbt_name name; struct composite_context *creq; struct socket_address **addrs; + char **names; }; static struct composite_context *setup_next_method(struct composite_context *c); @@ -84,7 +86,7 @@ static void resolve_handler(struct composite_context *creq) struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); const struct resolve_method *method = state->method; - c->status = method->recv_fn(creq, state, &state->addrs); + c->status = method->recv_fn(creq, state, &state->addrs, &state->names); if (!NT_STATUS_IS_OK(c->status)) { state->method = state->method->next; @@ -112,7 +114,11 @@ static struct composite_context *setup_next_method(struct composite_context *c) do { if (state->method) { - creq = state->method->send_fn(c, c->event_ctx, state->method->privdata, &state->name); + creq = state->method->send_fn(c, c->event_ctx, + state->method->privdata, + state->flags, + state->port, + &state->name); } if (creq == NULL && state->method) state->method = state->method->next; @@ -130,6 +136,8 @@ static struct composite_context *setup_next_method(struct composite_context *c) general name resolution - async send */ struct composite_context *resolve_name_all_send(struct resolve_context *ctx, + uint32_t flags, + uint16_t port, struct nbt_name *name, struct event_context *event_ctx) { @@ -149,6 +157,9 @@ struct composite_context *resolve_name_all_send(struct resolve_context *ctx, if (composite_nomem(state, c)) return c; c->private_data = state; + state->flags = flags; + state->port = port; + c->status = nbt_name_dup(state, name, &state->name); if (!composite_is_ok(c)) return c; @@ -165,6 +176,11 @@ struct composite_context *resolve_name_all_send(struct resolve_context *ctx, inet_ntoa(ip), 0); if (composite_nomem(state->addrs[0], c)) return c; state->addrs[1] = NULL; + state->names = talloc_array(state, char *, 2); + if (composite_nomem(state->names, c)) return c; + state->names[0] = talloc_strdup(state->names, state->name.name); + if (composite_nomem(state->names[0], c)) return c; + state->names[1] = NULL; composite_done(c); return c; } @@ -185,7 +201,8 @@ struct composite_context *resolve_name_all_send(struct resolve_context *ctx, */ NTSTATUS resolve_name_all_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) + struct socket_address ***addrs, + char ***names) { NTSTATUS status; @@ -194,30 +211,20 @@ NTSTATUS resolve_name_all_recv(struct composite_context *c, if (NT_STATUS_IS_OK(status)) { struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); *addrs = talloc_steal(mem_ctx, state->addrs); + if (names) { + *names = talloc_steal(mem_ctx, state->names); + } } talloc_free(c); return status; } -/* - general name resolution - sync call - */ -NTSTATUS resolve_all_name(struct resolve_context *ctx, - struct nbt_name *name, - TALLOC_CTX *mem_ctx, - struct socket_address ***addrs, - struct event_context *ev) -{ - struct composite_context *c = resolve_name_all_send(ctx, name, ev); - return resolve_name_all_recv(c, mem_ctx, addrs); -} - struct composite_context *resolve_name_send(struct resolve_context *ctx, struct nbt_name *name, struct event_context *event_ctx) { - return resolve_name_all_send(ctx, name, event_ctx); + return resolve_name_all_send(ctx, 0, 0, name, event_ctx); } NTSTATUS resolve_name_recv(struct composite_context *c, @@ -227,7 +234,7 @@ NTSTATUS resolve_name_recv(struct composite_context *c, NTSTATUS status; struct socket_address **addrs = NULL; - status = resolve_name_all_recv(c, mem_ctx, &addrs); + status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL); if (NT_STATUS_IS_OK(status)) { *reply_addr = talloc_steal(mem_ctx, addrs[0]->addr); diff --git a/source4/libcli/resolve/resolve.h b/source4/libcli/resolve/resolve.h index 01fc930fce..b55ab83f2a 100644 --- a/source4/libcli/resolve/resolve.h +++ b/source4/libcli/resolve/resolve.h @@ -19,21 +19,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __RESOLVE_H__ -#define __RESOLVE_H__ +#ifndef __LIBCLI_RESOLVE_H__ +#define __LIBCLI_RESOLVE_H__ struct socket_address; +struct event_context; #include "../libcli/nbt/libnbt.h" + +/* force that only NBT name resolution is used */ +#define RESOLVE_NAME_FLAG_FORCE_NBT 0x00000001 +/* force that only DNS name resolution is used */ +#define RESOLVE_NAME_FLAG_FORCE_DNS 0x00000002 +/* tell the dns resolver to do a DNS SRV lookup */ +#define RESOLVE_NAME_FLAG_DNS_SRV 0x00000004 +/* allow the resolver to overwrite the given port, e.g. for DNS SRV */ +#define RESOLVE_NAME_FLAG_OVERWRITE_PORT 0x00000008 + typedef struct composite_context *(*resolve_name_send_fn)(TALLOC_CTX *mem_ctx, struct event_context *, void *privdata, + uint32_t flags, + uint16_t port, struct nbt_name *); typedef NTSTATUS (*resolve_name_recv_fn)(struct composite_context *creq, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs); + struct socket_address ***addrs, + char ***names); #include "libcli/resolve/proto.h" struct interface; #include "libcli/resolve/lp_proto.h" -#endif /* __RESOLVE_H__ */ +#endif /* __LIBCLI_RESOLVE_H__ */ diff --git a/source4/libcli/resolve/testsuite.c b/source4/libcli/resolve/testsuite.c index 34de1158a5..f1d1fbc85c 100644 --- a/source4/libcli/resolve/testsuite.c +++ b/source4/libcli/resolve/testsuite.c @@ -44,9 +44,9 @@ static bool test_async_resolve(struct torture_context *tctx) host, timelimit); while (timeval_elapsed(&tv) < timelimit) { struct socket_address **s; - struct composite_context *c = resolve_name_host_send(mem_ctx, ev, NULL, &n); + struct composite_context *c = resolve_name_host_send(mem_ctx, ev, NULL, 0, 0, &n); torture_assert(tctx, c != NULL, "resolve_name_host_send"); - torture_assert_ntstatus_ok(tctx, resolve_name_host_recv(c, mem_ctx, &s), + torture_assert_ntstatus_ok(tctx, resolve_name_host_recv(c, mem_ctx, &s, NULL), "async resolve failed"); count++; } diff --git a/source4/libcli/resolve/wins.c b/source4/libcli/resolve/wins.c index ae142f7054..1940688ecb 100644 --- a/source4/libcli/resolve/wins.c +++ b/source4/libcli/resolve/wins.c @@ -40,11 +40,16 @@ struct composite_context *resolve_name_wins_send( TALLOC_CTX *mem_ctx, struct event_context *event_ctx, void *userdata, + uint32_t flags, + uint16_t port, struct nbt_name *name) { struct resolve_wins_data *wins_data = talloc_get_type(userdata, struct resolve_wins_data); if (wins_data->address_list == NULL) return NULL; - return resolve_name_nbtlist_send(mem_ctx, event_ctx, name, wins_data->address_list, wins_data->ifaces, wins_data->nbt_port, wins_data->nbt_timeout, false, true); + return resolve_name_nbtlist_send(mem_ctx, event_ctx, flags, port, name, + wins_data->address_list, wins_data->ifaces, + wins_data->nbt_port, wins_data->nbt_timeout, + false, true); } /* @@ -52,30 +57,10 @@ struct composite_context *resolve_name_wins_send( */ NTSTATUS resolve_name_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct socket_address ***addrs) + struct socket_address ***addrs, + char ***names) { - return resolve_name_nbtlist_recv(c, mem_ctx, addrs); -} - -/* - wins name resolution method - sync call - */ -NTSTATUS resolve_name_wins(struct nbt_name *name, - TALLOC_CTX *mem_ctx, - const char **address_list, - struct interface *ifaces, - uint16_t nbt_port, - int nbt_timeout, - struct socket_address ***addrs) -{ - struct composite_context *c; - struct resolve_wins_data *wins_data = talloc(mem_ctx, struct resolve_wins_data); - wins_data->address_list = address_list; - wins_data->ifaces = ifaces; - wins_data->nbt_port = nbt_port; - wins_data->nbt_timeout = nbt_timeout; - c = resolve_name_wins_send(mem_ctx, NULL, wins_data, name); - return resolve_name_wins_recv(c, mem_ctx, addrs); + return resolve_name_nbtlist_recv(c, mem_ctx, addrs, names); } bool resolve_context_add_wins_method(struct resolve_context *ctx, const char **address_list, struct interface *ifaces, uint16_t nbt_port, int nbt_timeout) |