summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli')
-rw-r--r--source4/libcli/config.mk7
-rw-r--r--source4/libcli/finddcs.c245
-rw-r--r--source4/libcli/libcli.h4
-rw-r--r--source4/libcli/security/dom_sid.c5
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;