diff options
Diffstat (limited to 'source4/libcli/resolve/host.c')
-rw-r--r-- | source4/libcli/resolve/host.c | 209 |
1 files changed, 14 insertions, 195 deletions
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) |