diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source4/libcli/resolve/resolve.c | |
parent | Initial commit. (diff) | |
download | samba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/libcli/resolve/resolve.c')
-rw-r--r-- | source4/libcli/resolve/resolve.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/source4/libcli/resolve/resolve.c b/source4/libcli/resolve/resolve.c new file mode 100644 index 0000000..db2606b --- /dev/null +++ b/source4/libcli/resolve/resolve.c @@ -0,0 +1,342 @@ +/* + Unix SMB/CIFS implementation. + + general name resolution interface + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2007 + + 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/>. +*/ + +#include "includes.h" +#include "libcli/composite/composite.h" +#include "libcli/resolve/resolve.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "system/network.h" +#include "lib/socket/socket.h" +#include "../lib/util/dlinklist.h" +#include "lib/tsocket/tsocket.h" +#include "lib/util/util_net.h" + +#undef strcasecmp + +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); + + +struct resolve_context { + struct resolve_method { + resolve_name_send_fn send_fn; + resolve_name_recv_fn recv_fn; + void *privdata; + struct resolve_method *prev, *next; + } *methods; +}; + +/** + * Initialize a resolve context + */ +struct resolve_context *resolve_context_init(TALLOC_CTX *mem_ctx) +{ + return talloc_zero(mem_ctx, struct resolve_context); +} + +/** + * Add a resolve method + */ +bool resolve_context_add_method(struct resolve_context *ctx, resolve_name_send_fn send_fn, + resolve_name_recv_fn recv_fn, void *userdata) +{ + struct resolve_method *method = talloc_zero(ctx, struct resolve_method); + + if (method == NULL) + return false; + + method->send_fn = send_fn; + method->recv_fn = recv_fn; + method->privdata = userdata; + DLIST_ADD_END(ctx->methods, method); + return true; +} + +/** + handle completion of one name resolve method +*/ +static void resolve_handler(struct composite_context *creq) +{ + struct composite_context *c = (struct composite_context *)creq->async.private_data; + 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, &state->names); + + if (!NT_STATUS_IS_OK(c->status)) { + state->method = state->method->next; + state->creq = setup_next_method(c); + if (state->creq != NULL) { + return; + } + } + + if (!NT_STATUS_IS_OK(c->status)) { + c->state = COMPOSITE_STATE_ERROR; + } else { + c->state = COMPOSITE_STATE_DONE; + } + if (c->async.fn) { + c->async.fn(c); + } +} + + +static struct composite_context *setup_next_method(struct composite_context *c) +{ + struct resolve_state *state = talloc_get_type(c->private_data, struct resolve_state); + struct composite_context *creq = NULL; + + do { + if (state->method) { + 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; + + } while (!creq && state->method); + + if (creq) { + creq->async.fn = resolve_handler; + creq->async.private_data = c; + } + + return creq; +} + +/* + general name resolution - async send + */ +struct composite_context *resolve_name_all_send(struct resolve_context *ctx, + TALLOC_CTX *mem_ctx, + uint32_t flags, /* RESOLVE_NAME_FLAG_* */ + uint16_t port, + struct nbt_name *name, + struct tevent_context *event_ctx) +{ + struct composite_context *c; + struct resolve_state *state; + + if (event_ctx == NULL) { + return NULL; + } + + 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 resolve_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; + + state->ctx = talloc_reference(state, ctx); + if (composite_nomem(state->ctx, c)) return c; + + if (is_ipaddress(state->name.name) || + strcasecmp(state->name.name, "localhost") == 0) { + state->addrs = talloc_array(state, struct socket_address *, 2); + if (composite_nomem(state->addrs, c)) return c; + state->addrs[0] = socket_address_from_strings(state->addrs, "ip", + state->name.name, 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; + } + + state->method = ctx->methods; + if (state->method == NULL) { + composite_error(c, NT_STATUS_BAD_NETWORK_NAME); + return c; + } + state->creq = setup_next_method(c); + if (composite_nomem(state->creq, c)) return c; + + return c; +} + +/* + general name resolution method - recv side + */ +NTSTATUS resolve_name_all_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 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; +} + +struct composite_context *resolve_name_ex_send(struct resolve_context *ctx, + TALLOC_CTX *mem_ctx, + uint32_t flags, /* RESOLVE_NAME_FLAG_* */ + uint16_t port, + struct nbt_name *name, + struct tevent_context *event_ctx) +{ + return resolve_name_all_send(ctx, mem_ctx, flags, port, name, event_ctx); +} + +struct composite_context *resolve_name_send(struct resolve_context *ctx, + TALLOC_CTX *mem_ctx, + struct nbt_name *name, + struct tevent_context *event_ctx) +{ + return resolve_name_ex_send(ctx, mem_ctx, 0, 0, name, event_ctx); +} + +NTSTATUS resolve_name_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + const char **reply_addr) +{ + NTSTATUS status; + struct socket_address **addrs = NULL; + + status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL); + + if (NT_STATUS_IS_OK(status)) { + struct tsocket_address *t_addr = socket_address_to_tsocket_address(addrs, addrs[0]); + if (!t_addr) { + return NT_STATUS_NO_MEMORY; + } + + *reply_addr = tsocket_address_inet_addr_string(t_addr, mem_ctx); + talloc_free(addrs); + if (!*reply_addr) { + return NT_STATUS_NO_MEMORY; + } + } + + return status; +} + +/* + receive multiple responses from resolve_name_send() + */ +NTSTATUS resolve_name_multiple_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + const char ***reply_addrs) +{ + NTSTATUS status; + struct socket_address **addrs = NULL; + int i; + + status = resolve_name_all_recv(c, mem_ctx, &addrs, NULL); + NT_STATUS_NOT_OK_RETURN(status); + + /* count the addresses */ + for (i=0; addrs[i]; i++) ; + + *reply_addrs = talloc_array(mem_ctx, const char *, i+1); + NT_STATUS_HAVE_NO_MEMORY(*reply_addrs); + + for (i=0; addrs[i]; i++) { + struct tsocket_address *t_addr = socket_address_to_tsocket_address(addrs, addrs[i]); + NT_STATUS_HAVE_NO_MEMORY(t_addr); + + (*reply_addrs)[i] = tsocket_address_inet_addr_string(t_addr, *reply_addrs); + NT_STATUS_HAVE_NO_MEMORY((*reply_addrs)[i]); + } + (*reply_addrs)[i] = NULL; + + talloc_free(addrs); + + return status; +} + +/* + general name resolution - sync call + */ +NTSTATUS resolve_name_ex(struct resolve_context *ctx, + uint32_t flags, /* RESOLVE_NAME_FLAG_* */ + uint16_t port, + struct nbt_name *name, + TALLOC_CTX *mem_ctx, + const char **reply_addr, + struct tevent_context *ev) +{ + struct composite_context *c = resolve_name_ex_send(ctx, mem_ctx, flags, port, name, ev); + return resolve_name_recv(c, mem_ctx, reply_addr); +} + + +/* Initialise a struct nbt_name with a NULL scope */ + +void make_nbt_name(struct nbt_name *nbt, const char *name, int type) +{ + nbt->name = name; + nbt->scope = NULL; + nbt->type = type; +} + +/* Initialise a struct nbt_name with a NBT_NAME_CLIENT (0x00) name */ + +void make_nbt_name_client(struct nbt_name *nbt, const char *name) +{ + make_nbt_name(nbt, name, NBT_NAME_CLIENT); +} + +/* Initialise a struct nbt_name with a NBT_NAME_SERVER (0x20) name */ + +void make_nbt_name_server(struct nbt_name *nbt, const char *name) +{ + make_nbt_name(nbt, name, NBT_NAME_SERVER); +} + + |