diff options
author | Andrew Bartlett <abartlet@samba.org> | 2006-01-12 03:02:00 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:50:54 -0500 |
commit | b135f4467f8413f6ac44df54b8430305f6c26c0c (patch) | |
tree | 1c0aba065ecfc3b2262f201bae4a77dc609bd46a /source4/libcli | |
parent | d68b0b12b956b4b70953806e8cb4d9f6207057ed (diff) | |
download | samba-b135f4467f8413f6ac44df54b8430305f6c26c0c.tar.gz samba-b135f4467f8413f6ac44df54b8430305f6c26c0c.tar.bz2 samba-b135f4467f8413f6ac44df54b8430305f6c26c0c.zip |
r12858: This moves the libnet_LookupPdc code to use a GetDC request to find
the remote server's name, or in the absence of a local nbt_server to
communicate with (or without root access), a node status request.
The result is that we are in a better position to use kerberos, as well
as to remove the 'password server' mandatory parameter for the samsync
and samdump commands. (I need this to put these into SWAT).
The only problem I have is that I must create a messaging context, which
requires a server ID. As a client process, I don't expect to get
messages, but it is currently required for replies, so I generate a
random() number. We probably need the servers to accept connections on
streamed sockets too, for client-only tasks that want IRPC.
Because I wanted to test this code, I have put the NET-API-* tests into
our test scripts, to ensure they pass and keep passing. They are good
frontends onto the libnet system, and I see no reason not to test them.
In doing so the NET-API-RPCCONNECT test was simplified to take a
binding string on the command line, removing duplicate code, and
testing the combinations in the scripts instead.
(I have done a bit of work on the list shares code in libnet_share.c
to make it pass 'make test')
In the future, I would like to extend the libcli/findds.c code (based
off volker's winbind/wb_async_helpers.c, which is why it shows up a bit
odd in the patch) to handle getting multiple name replies, sending a
getdc request to each in turn.
(posted to samba-technical for review, and I'll happily update with
any comments)
Andrew Bartlett
(This used to be commit 7ccddfd3515fc2c0d6f447c768ccbf7a220c3380)
Diffstat (limited to 'source4/libcli')
-rw-r--r-- | source4/libcli/config.mk | 7 | ||||
-rw-r--r-- | source4/libcli/finddcs.c | 245 | ||||
-rw-r--r-- | source4/libcli/libcli.h | 4 | ||||
-rw-r--r-- | source4/libcli/security/dom_sid.c | 5 |
4 files changed, 260 insertions, 1 deletions
diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 20219be0f4..0040339fd2 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -87,6 +87,11 @@ OBJ_FILES = \ resolve/host.o REQUIRED_SUBSYSTEMS = LIBCLI_NBT +[SUBSYSTEM::LIBCLI_FINDDCS] +OBJ_FILES = \ + finddcs.o +REQUIRED_SUBSYSTEMS = LIBCLI_NBT MESSAGING + [LIBRARY::LIBCLI] MAJOR_VERSION = 0 MINOR_VERSION = 0 @@ -94,7 +99,7 @@ RELEASE_VERSION = 1 DESCRIPTION = SMB/CIFS client library REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBCLI_UTILS LIBCLI_AUTH \ LIBCLI_SMB_COMPOSITE LIBCLI_NBT LIB_SECURITY LIBCLI_RESOLVE \ - LIBCLI_DGRAM LIBCLI_SMB2 + LIBCLI_DGRAM LIBCLI_SMB2 LIBCLI_FINDDCS [SUBSYSTEM::LIBSMB] REQUIRED_SUBSYSTEMS = LIBCLI SOCKET diff --git a/source4/libcli/finddcs.c b/source4/libcli/finddcs.c new file mode 100644 index 0000000000..ff4b255a13 --- /dev/null +++ b/source4/libcli/finddcs.c @@ -0,0 +1,245 @@ +/* + Unix SMB/CIFS implementation. + + a composite API for finding a DC and its name + + Copyright (C) Volker Lendecke 2005 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "include/includes.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/composite/composite.h" +#include "libcli/libcli.h" + +struct finddcs_state { + struct composite_context *ctx; + struct messaging_context *msg_ctx; + + const char *domain_name; + struct dom_sid *domain_sid; + + struct nbtd_getdcname r; + struct nbt_name_status node_status; + + int num_dcs; + struct nbt_dc_name *dcs; +}; + +static void finddcs_name_resolved(struct composite_context *ctx); +static void finddcs_getdc_replied(struct irpc_request *ireq); +static void fallback_node_status(struct finddcs_state *state); +static void fallback_node_status_replied(struct nbt_name_request *name_req); + +/* + * Setup and send off the a normal name resolution for the target name. + * + * The domain_sid parameter is optional, and is used in the subsequent getdc request. + * + * This will try a GetDC request, but this may not work. It will try + * a node status as a fallback, then return no name (but still include + * the IP) + */ + +struct composite_context *finddcs_send(TALLOC_CTX *mem_ctx, + const char *domain_name, + int name_type, + struct dom_sid *domain_sid, + const char **methods, + struct event_context *event_ctx, + struct messaging_context *msg_ctx) +{ + struct composite_context *result, *ctx; + struct finddcs_state *state; + struct nbt_name name; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = event_ctx; + + state = talloc(result, struct finddcs_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->domain_name = talloc_strdup(state, domain_name); + if (state->domain_name == NULL) goto failed; + state->domain_sid = domain_sid; + if (domain_sid != NULL) { + if (talloc_reference(state, domain_sid) == NULL) { + goto failed; + } + } + state->msg_ctx = msg_ctx; + + make_nbt_name(&name, state->domain_name, name_type); + ctx = resolve_name_send(&name, result->event_ctx, + methods); + + if (ctx == NULL) goto failed; + ctx->async.fn = finddcs_name_resolved; + ctx->async.private_data = state; + + return result; + +failed: + talloc_free(result); + return NULL; +} + +/* Having got an name query answer, fire off a GetDC request, so we + * can find the target's all-important name. (Kerberos and some + * netlogon operations are quite picky about names) + * + * The name is a courtasy, if we don't find it, don't compleatly fail. + * + * However, if the nbt server is down, fall back to a node status + * request + */ +static void finddcs_name_resolved(struct composite_context *ctx) +{ + struct finddcs_state *state = + talloc_get_type(ctx->async.private_data, struct finddcs_state); + struct irpc_request *ireq; + uint32_t *nbt_servers; + const char *address; + + state->ctx->status = resolve_name_recv(ctx, state, &address); + if (!composite_is_ok(state->ctx)) return; + + state->num_dcs = 1; + state->dcs = talloc_array(state, struct nbt_dc_name, state->num_dcs); + if (composite_nomem(state->dcs, state->ctx)) return; + + state->dcs[0].address = talloc_steal(state->dcs, address); + + /* Try and find the nbt server. We are not going to fail if + * we can't get the name, it will just be a disapointment. + * The nbt server just might not be running */ + nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server"); + if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) { + fallback_node_status(state); + return; + } + + state->r.in.domainname = state->domain_name; + state->r.in.ip_address = state->dcs[0].address; + state->r.in.my_computername = lp_netbios_name(); + state->r.in.my_accountname = talloc_asprintf(state, "%s$", + lp_netbios_name()); + if (composite_nomem(state->r.in.my_accountname, state->ctx)) return; + state->r.in.account_control = ACB_WSTRUST; + state->r.in.domain_sid = state->domain_sid; + + ireq = irpc_call_send(state->msg_ctx, nbt_servers[0], + &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME, + &state->r, state); + if (!ireq) { + fallback_node_status(state); + return; + } + + composite_continue_irpc(state->ctx, ireq, finddcs_getdc_replied, state); +} + +/* Called when the GetDC request returns */ +static void finddcs_getdc_replied(struct irpc_request *ireq) +{ + struct finddcs_state *state = + talloc_get_type(ireq->async.private, struct finddcs_state); + + state->ctx->status = irpc_call_recv(ireq); + if (!composite_is_ok(state->ctx)) return; + + state->dcs[0].name = talloc_steal(state->dcs, state->r.out.dcname); + composite_done(state->ctx); +} + +/* The GetDC request might not be availible (such as occours when the + * NBT server is down). Fallback to a node status. It is the best + * hope we have... */ +static void fallback_node_status(struct finddcs_state *state) +{ + struct nbt_name_socket *nbtsock; + struct nbt_name_request *name_req; + + state->node_status.in.name.name = "*"; + state->node_status.in.name.type = NBT_NAME_CLIENT; + state->node_status.in.name.scope = NULL; + state->node_status.in.dest_addr = state->dcs[0].address; + state->node_status.in.timeout = 1; + state->node_status.in.retries = 2; + + nbtsock = nbt_name_socket_init(state, state->ctx->event_ctx); + if (composite_nomem(nbtsock, state->ctx)) return; + + name_req = nbt_name_status_send(nbtsock, &state->node_status); + if (composite_nomem(name_req, state->ctx)) return; + + composite_continue_nbt(state->ctx, + name_req, + fallback_node_status_replied, + state); +} + +/* We have a node status reply (or perhaps a timeout) */ +static void fallback_node_status_replied(struct nbt_name_request *name_req) +{ + struct finddcs_state *state = talloc_get_type(name_req->async.private, struct finddcs_state); + state->ctx->status = nbt_name_status_recv(name_req, state, &state->node_status); + if (!composite_is_ok(state->ctx)) return; + + if (state->node_status.out.status.num_names > 0) { + state->dcs[0].name = talloc_steal(state->dcs, state->node_status.out.status.names[0].name); + composite_done(state->ctx); + return; + } + composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS); +} + +NTSTATUS finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, + int *num_dcs, struct nbt_dc_name **dcs) +{ + NTSTATUS status = composite_wait(c); + if (NT_STATUS_IS_OK(status)) { + struct finddcs_state *state = + talloc_get_type(c->private_data, struct finddcs_state); + *num_dcs = state->num_dcs; + *dcs = talloc_steal(mem_ctx, state->dcs); + } + talloc_free(c); + return status; +} + +NTSTATUS finddcs(TALLOC_CTX *mem_ctx, + const char *domain_name, int name_type, + struct dom_sid *domain_sid, + const char **methods, + struct event_context *event_ctx, + struct messaging_context *msg_ctx, + int *num_dcs, struct nbt_dc_name **dcs) +{ + struct composite_context *c = finddcs_send(mem_ctx, + domain_name, name_type, + domain_sid, methods, + event_ctx, msg_ctx); + return finddcs_recv(c, mem_ctx, num_dcs, dcs); +} diff --git a/source4/libcli/libcli.h b/source4/libcli/libcli.h index 917ab27519..76fa13525e 100644 --- a/source4/libcli/libcli.h +++ b/source4/libcli/libcli.h @@ -41,5 +41,9 @@ struct clilist_file_info { const char *short_name; }; +struct nbt_dc_name { + const char *address; + const char *name; +}; #include "libcli/libcli_proto.h" diff --git a/source4/libcli/security/dom_sid.c b/source4/libcli/security/dom_sid.c index 646a513df5..b5ced9fcc2 100644 --- a/source4/libcli/security/dom_sid.c +++ b/source4/libcli/security/dom_sid.c @@ -157,6 +157,11 @@ struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid) { struct dom_sid *ret; int i; + + if (!dom_sid) { + return NULL; + } + ret = talloc(mem_ctx, struct dom_sid); if (!ret) { return NULL; |