summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--source4/libnet/config.mk2
-rw-r--r--source4/libnet/libnet_join.c22
-rw-r--r--source4/libnet/libnet_lookup.c48
-rw-r--r--source4/libnet/libnet_lookup.h12
-rw-r--r--source4/libnet/libnet_passwd.c8
-rw-r--r--source4/libnet/libnet_rpc.c45
-rw-r--r--source4/libnet/libnet_rpc.h4
-rw-r--r--source4/libnet/libnet_share.c56
-rw-r--r--source4/libnet/libnet_time.c8
-rw-r--r--source4/libnet/libnet_user.c18
-rw-r--r--source4/libnet/libnet_vampire.c2
-rwxr-xr-xsource4/script/tests/test_nbt.sh2
-rwxr-xr-xsource4/script/tests/test_rpc.sh6
-rw-r--r--source4/torture/libnet/libnet_lookup.c26
-rw-r--r--source4/torture/libnet/libnet_rpc.c85
-rw-r--r--source4/torture/libnet/libnet_share.c2
20 files changed, 451 insertions, 156 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;
diff --git a/source4/libnet/config.mk b/source4/libnet/config.mk
index b76fe0c7e5..baf81e36e6 100644
--- a/source4/libnet/config.mk
+++ b/source4/libnet/config.mk
@@ -25,6 +25,6 @@ OBJ_FILES = \
userinfo.o \
userman.o \
domain.o
-REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBSAMBA3 LIBCLI_CLDAP gensec_schannel
+REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBCLI_FINDDCS LIBSAMBA3 LIBCLI_CLDAP LIBCLI_FINDDCS gensec_schannel
# End SUBSYSTEM LIBNET
#################################
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c
index 4f566a36a8..616c80b1a4 100644
--- a/source4/libnet/libnet_join.c
+++ b/source4/libnet/libnet_join.c
@@ -272,7 +272,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
status = dcerpc_pipe_connect_b(tmp_ctx,
&drsuapi_pipe,
drsuapi_binding,
- &dcerpc_table_drsuapi,
+ &dcerpc_table_drsuapi,
ctx->cred,
ctx->event_ctx);
if (!NT_STATUS_IS_OK(status)) {
@@ -635,8 +635,8 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
/* prepare connect to the LSA pipe of PDC */
if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
- c->level = LIBNET_RPC_CONNECT_PDC;
- c->in.domain_name = r->in.domain_name;
+ c->level = LIBNET_RPC_CONNECT_PDC;
+ c->in.name = r->in.domain_name;
} else {
c->level = LIBNET_RPC_CONNECT_BINDING;
c->in.binding = r->in.binding;
@@ -998,7 +998,9 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
/* We created a new user, but they didn't come out the right type?!? */
r->out.error_string
= talloc_asprintf(mem_ctx,
- "We asked to create a new machine account (%s) of type %s, but we got an account of type %s. This is unexpected. Perhaps delete the account and try again.\n",
+ "We asked to create a new machine account (%s) of type %s, "
+ "but we got an account of type %s. This is unexpected. "
+ "Perhaps delete the account and try again.\n",
r->in.account_name, new_account_type, old_account_type);
talloc_free(tmp_ctx);
return NT_STATUS_INVALID_PARAMETER;
@@ -1008,7 +1010,9 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
/* TODO: We should allow a --force option to override, and redo this from the top setting r.in.recreate_account */
r->out.error_string
= talloc_asprintf(mem_ctx,
- "The machine account (%s) already exists in the domain %s, but is a %s. You asked to join as a %s. Please delete the account and try again.\n",
+ "The machine account (%s) already exists in the domain %s, "
+ "but is a %s. You asked to join as a %s. Please delete "
+ "the account and try again.\n",
r->in.account_name, domain_name, old_account_type, new_account_type);
talloc_free(tmp_ctx);
return NT_STATUS_USER_EXISTS;
@@ -1045,7 +1049,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
}
/* reset flags (if required) */
- if (acct_flags != qui.out.info->info16.acct_flags) {
+ if (acct_flags != qui.out.info->info16.acct_flags) {
ZERO_STRUCT(u_info);
u_info.info16.acct_flags = acct_flags;
@@ -1160,7 +1164,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
if ((r->in.netbios_name != NULL) && (r->in.level != LIBNET_JOIN_AUTOMATIC)) {
netbios_name = r->in.netbios_name;
} else {
- netbios_name = talloc_asprintf(tmp_mem, "%s", lp_netbios_name());
+ netbios_name = talloc_reference(tmp_mem, lp_netbios_name());
if (!netbios_name) {
r->out.error_string = NULL;
talloc_free(tmp_mem);
@@ -1437,8 +1441,8 @@ NTSTATUS libnet_Join(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct lib
}
r->out.error_string = talloc_asprintf(mem_ctx,
- "Invalid secure channel type specified (%08X) attempting to join domain %s",
- r->in.secure_channel_type, r->in.domain_name);
+ "Invalid secure channel type specified (%08X) attempting to join domain %s",
+ r->in.secure_channel_type, r->in.domain_name);
return NT_STATUS_INVALID_PARAMETER;
}
diff --git a/source4/libnet/libnet_lookup.c b/source4/libnet/libnet_lookup.c
index e64ab6a291..1c1604f407 100644
--- a/source4/libnet/libnet_lookup.c
+++ b/source4/libnet/libnet_lookup.c
@@ -26,7 +26,8 @@
#include "lib/events/events.h"
#include "libnet/libnet.h"
#include "libcli/composite/composite.h"
-
+#include "lib/messaging/messaging.h"
+#include "lib/messaging/irpc.h"
struct lookup_state {
struct composite_context *resolve_ctx;
@@ -162,20 +163,49 @@ NTSTATUS libnet_LookupHost(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
/**
* Sends asynchronous LookupPdc request
*/
-struct composite_context* libnet_LookupPdc_send(struct libnet_context *ctx,
- struct libnet_Lookup *io)
+struct composite_context* libnet_LookupDCs_send(struct libnet_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct libnet_LookupDCs *io)
{
- io->in.type = NBT_NAME_PDC;
- return libnet_Lookup_send(ctx, io);
+ struct messaging_context *msg_ctx = messaging_init(mem_ctx, random() % 0x10000000, ctx->event_ctx);
+ struct composite_context *c;
+ if (!msg_ctx) {
+ return NULL;
+ }
+ c = finddcs_send(mem_ctx,
+ io->in.domain_name,
+ NBT_NAME_PDC,
+ NULL, ctx->name_res_methods,
+ ctx->event_ctx, msg_ctx);
+ return c;
}
+/**
+ * Waits for and receives results of asynchronous Lookup call
+ *
+ * @param c composite context returned by asynchronous Lookup call
+ * @param mem_ctx memory context of the call
+ * @param io pointer to results (and arguments) of the call
+ * @return nt status code of execution
+ */
+
+NTSTATUS libnet_LookupDCs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+ struct libnet_LookupDCs *io)
+{
+ NTSTATUS status;
+ status = finddcs_recv(c, mem_ctx, &io->out.num_dcs, &io->out.dcs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return status;
+}
/**
* Synchronous version of LookupPdc
*/
-NTSTATUS libnet_LookupPdc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
- struct libnet_Lookup *io)
+NTSTATUS libnet_LookupDCs(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
+ struct libnet_LookupDCs *io)
{
- struct composite_context *c = libnet_LookupPdc_send(ctx, io);
- return libnet_Lookup_recv(c, mem_ctx, io);
+ struct composite_context *c = libnet_LookupDCs_send(ctx, mem_ctx, io);
+ return libnet_LookupDCs_recv(c, mem_ctx, io);
}
diff --git a/source4/libnet/libnet_lookup.h b/source4/libnet/libnet_lookup.h
index e5b2d58fd3..c786eb0a43 100644
--- a/source4/libnet/libnet_lookup.h
+++ b/source4/libnet/libnet_lookup.h
@@ -29,3 +29,15 @@ struct libnet_Lookup {
const char **address;
} out;
};
+
+struct libnet_LookupDCs {
+ struct {
+ const char *domain_name;
+ int name_type;
+ } in;
+ struct {
+ int num_dcs;
+ struct nbt_dc_name *dcs;
+ } out;
+};
+
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c
index bd09e306ce..fe5239f4b6 100644
--- a/source4/libnet/libnet_passwd.c
+++ b/source4/libnet/libnet_passwd.c
@@ -53,7 +53,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
/* prepare connect to the SAMR pipe of the users domain PDC */
c.level = LIBNET_RPC_CONNECT_PDC;
- c.in.domain_name = r->samr.in.domain_name;
+ c.in.name = r->samr.in.domain_name;
c.in.dcerpc_iface = &dcerpc_table_samr;
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
@@ -513,9 +513,9 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
union libnet_SetPassword r2;
/* prepare connect to the SAMR pipe of users domain PDC */
- c.level = LIBNET_RPC_CONNECT_PDC;
- c.in.domain_name = r->samr.in.domain_name;
- c.in.dcerpc_iface = &dcerpc_table_samr;
+ c.level = LIBNET_RPC_CONNECT_PDC;
+ c.in.name = r->samr.in.domain_name;
+ c.in.dcerpc_iface = &dcerpc_table_samr;
/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
status = libnet_RpcConnect(ctx, mem_ctx, &c);
diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c
index 6b94734f9b..ffed674f1f 100644
--- a/source4/libnet/libnet_rpc.c
+++ b/source4/libnet/libnet_rpc.c
@@ -21,7 +21,7 @@
#include "includes.h"
#include "libnet/libnet.h"
-
+#include "libcli/libcli.h"
/**
* Connects rpc pipe on remote server
@@ -39,9 +39,10 @@ static NTSTATUS libnet_RpcConnectSrv(struct libnet_context *ctx, TALLOC_CTX *mem
/* prepare binding string */
switch (r->level) {
+ case LIBNET_RPC_CONNECT_DC:
case LIBNET_RPC_CONNECT_PDC:
case LIBNET_RPC_CONNECT_SERVER:
- binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", r->in.domain_name);
+ binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", r->in.name);
break;
case LIBNET_RPC_CONNECT_BINDING:
@@ -81,24 +82,45 @@ static NTSTATUS libnet_RpcConnectPdc(struct libnet_context *ctx, TALLOC_CTX *mem
{
NTSTATUS status;
struct libnet_RpcConnect r2;
- struct libnet_Lookup f;
+ struct libnet_LookupDCs f;
+ const char *connect_name;
- f.in.hostname = r->in.domain_name;
- f.in.methods = NULL;
- f.out.address = NULL;
+ f.in.domain_name = r->in.name;
+ switch (r->level) {
+ case LIBNET_RPC_CONNECT_PDC:
+ f.in.name_type = NBT_NAME_PDC;
+ break;
+ case LIBNET_RPC_CONNECT_DC:
+ f.in.name_type = NBT_NAME_LOGON;
+ break;
+ default:
+ break;
+ }
+ f.out.num_dcs = 0;
+ f.out.dcs = NULL;
/* find the domain pdc first */
- status = libnet_LookupPdc(ctx, mem_ctx, &f);
+ status = libnet_LookupDCs(ctx, mem_ctx, &f);
if (!NT_STATUS_IS_OK(status)) {
- r->out.error_string = talloc_asprintf(mem_ctx, "libnet_LookupPdc failed: %s",
+ r->out.error_string = talloc_asprintf(mem_ctx, "libnet_LookupDCs failed: %s",
nt_errstr(status));
return status;
}
+ /* we might not have got back a name. Fall back to the IP */
+ if (f.out.dcs[0].name) {
+ connect_name = f.out.dcs[0].name;
+ } else {
+ connect_name = f.out.dcs[0].address;
+ }
+
/* ok, pdc has been found so do attempt to rpc connect */
- r2.level = LIBNET_RPC_CONNECT_SERVER;
- r2.in.domain_name = talloc_strdup(mem_ctx, f.out.address[0]);
- r2.in.dcerpc_iface = r->in.dcerpc_iface;
+ r2.level = LIBNET_RPC_CONNECT_SERVER;
+
+ /* This will cause yet another name resolution, but at least
+ * we pass the right name down the stack now */
+ r2.in.name = talloc_strdup(mem_ctx, connect_name);
+ r2.in.dcerpc_iface = r->in.dcerpc_iface;
status = libnet_RpcConnect(ctx, mem_ctx, &r2);
@@ -130,6 +152,7 @@ NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
return libnet_RpcConnectSrv(ctx, mem_ctx, r);
case LIBNET_RPC_CONNECT_PDC:
+ case LIBNET_RPC_CONNECT_DC:
return libnet_RpcConnectPdc(ctx, mem_ctx, r);
}
diff --git a/source4/libnet/libnet_rpc.h b/source4/libnet/libnet_rpc.h
index d2a83bf642..5505e69a09 100644
--- a/source4/libnet/libnet_rpc.h
+++ b/source4/libnet/libnet_rpc.h
@@ -27,6 +27,8 @@ enum libnet_RpcConnect_level {
LIBNET_RPC_CONNECT_SERVER, /* connect to a standalone rpc server */
LIBNET_RPC_CONNECT_PDC, /* connect to a domain pdc (resolves domain
name to a pdc address before connecting) */
+ LIBNET_RPC_CONNECT_DC, /* connect to any DC (resolves domain
+ name to a DC address before connecting) */
LIBNET_RPC_CONNECT_BINDING /* specified binding string */
};
@@ -34,7 +36,7 @@ struct libnet_RpcConnect {
enum libnet_RpcConnect_level level;
struct {
- const char *domain_name;
+ const char *name;
const char *binding;
const struct dcerpc_interface_table *dcerpc_iface;
} in;
diff --git a/source4/libnet/libnet_share.c b/source4/libnet/libnet_share.c
index 9422cdd306..0f5a3aeb52 100644
--- a/source4/libnet/libnet_share.c
+++ b/source4/libnet/libnet_share.c
@@ -30,10 +30,16 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx,
struct srvsvc_NetShareEnumAll s;
uint32_t resume_handle;
struct srvsvc_NetShareCtr0 ctr0;
+ struct srvsvc_NetShareCtr1 ctr1;
+ struct srvsvc_NetShareCtr2 ctr2;
+ struct srvsvc_NetShareCtr501 ctr501;
+ struct srvsvc_NetShareCtr502 ctr502;
- c.level = LIBNET_RPC_CONNECT_SERVER;
- c.in.domain_name = r->in.server_name;
- c.in.dcerpc_iface = &dcerpc_table_srvsvc;
+ c.level = LIBNET_RPC_CONNECT_SERVER;
+ c.in.name = r->in.server_name;
+ c.in.dcerpc_iface = &dcerpc_table_srvsvc;
+
+ s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", c.in.name);
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
@@ -46,11 +52,36 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx,
}
s.in.level = r->in.level;
- s.in.ctr.ctr0 = &ctr0;
+ switch (s.in.level) {
+ case 0:
+ s.in.ctr.ctr0 = &ctr0;
+ ZERO_STRUCT(ctr0);
+ break;
+ case 1:
+ s.in.ctr.ctr1 = &ctr1;
+ ZERO_STRUCT(ctr1);
+ break;
+ case 2:
+ s.in.ctr.ctr2 = &ctr2;
+ ZERO_STRUCT(ctr2);
+ break;
+ case 501:
+ s.in.ctr.ctr501 = &ctr501;
+ ZERO_STRUCT(ctr501);
+ break;
+ case 502:
+ s.in.ctr.ctr502 = &ctr502;
+ ZERO_STRUCT(ctr502);
+ break;
+ default:
+ r->out.error_string = talloc_asprintf(mem_ctx,
+ "libnet_ListShares: Invalid info level requested: %d\n",
+ s.in.level);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
s.in.max_buffer = ~0;
s.in.resume_handle = &resume_handle;
- ZERO_STRUCT(ctr0);
status = dcerpc_srvsvc_NetShareEnumAll(c.out.dcerpc_pipe, mem_ctx, &s);
@@ -63,6 +94,9 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx,
}
if (!W_ERROR_IS_OK(s.out.result) && !W_ERROR_EQUAL(s.out.result, WERR_MORE_DATA)) {
+ r->out.error_string = talloc_asprintf(mem_ctx,
+ "srvsvc_NetShareEnumAll on server '%s' failed: %s",
+ r->in.server_name, win_errstr(s.out.result));
goto disconnect;
}
@@ -82,9 +116,9 @@ NTSTATUS libnet_AddShare(struct libnet_context *ctx,
struct libnet_RpcConnect c;
struct srvsvc_NetShareAdd s;
- c.level = LIBNET_RPC_CONNECT_SERVER;
- c.in.domain_name = r->in.server_name;
- c.in.dcerpc_iface = &dcerpc_table_srvsvc;
+ c.level = LIBNET_RPC_CONNECT_SERVER;
+ c.in.name = r->in.server_name;
+ c.in.dcerpc_iface = &dcerpc_table_srvsvc;
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
@@ -121,9 +155,9 @@ NTSTATUS libnet_DelShare(struct libnet_context *ctx,
struct libnet_RpcConnect c;
struct srvsvc_NetShareDel s;
- c.level = LIBNET_RPC_CONNECT_SERVER;
- c.in.domain_name = r->in.server_name;
- c.in.dcerpc_iface = &dcerpc_table_srvsvc;
+ c.level = LIBNET_RPC_CONNECT_SERVER;
+ c.in.name = r->in.server_name;
+ c.in.dcerpc_iface = &dcerpc_table_srvsvc;
status = libnet_RpcConnect(ctx, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/libnet/libnet_time.c b/source4/libnet/libnet_time.c
index 7d480a5348..c7f8c79db5 100644
--- a/source4/libnet/libnet_time.c
+++ b/source4/libnet/libnet_time.c
@@ -33,9 +33,9 @@ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX *
struct tm tm;
/* prepare connect to the SRVSVC pipe of a timeserver */
- c.level = LIBNET_RPC_CONNECT_SERVER;
- c.in.domain_name = r->srvsvc.in.server_name;
- c.in.dcerpc_iface = &dcerpc_table_srvsvc;
+ c.level = LIBNET_RPC_CONNECT_SERVER;
+ c.in.name = r->srvsvc.in.server_name;
+ c.in.dcerpc_iface = &dcerpc_table_srvsvc;
/* 1. connect to the SRVSVC pipe of a timeserver */
status = libnet_RpcConnect(ctx, mem_ctx, &c);
@@ -47,7 +47,7 @@ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX *
}
/* prepare srvsvc_NetrRemoteTOD */
- tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.domain_name);
+ tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.name);
/* 2. try srvsvc_NetRemoteTOD */
status = dcerpc_srvsvc_NetRemoteTOD(c.out.dcerpc_pipe, mem_ctx, &tod);
diff --git a/source4/libnet/libnet_user.c b/source4/libnet/libnet_user.c
index 629fbf8e05..50cb14d290 100644
--- a/source4/libnet/libnet_user.c
+++ b/source4/libnet/libnet_user.c
@@ -27,23 +27,13 @@ NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
{
NTSTATUS status;
struct libnet_RpcConnect cn;
- struct libnet_Lookup fp;
struct libnet_rpc_domain_open dom_io;
struct libnet_rpc_useradd user_io;
- const char *address;
- /* find domain pdc */
- fp.in.hostname = r->in.domain_name;
- fp.in.methods = NULL;
- fp.out.address = &address;
-
- status = libnet_LookupPdc(ctx, mem_ctx, &fp);
- if (!NT_STATUS_IS_OK(status)) return status;
-
- /* connect rpc service of remote server */
- cn.level = LIBNET_RPC_CONNECT_SERVER;
- cn.in.domain_name = talloc_strdup(mem_ctx, *fp.out.address);
- cn.in.dcerpc_iface = &dcerpc_table_samr;
+ /* connect rpc service of remote DC */
+ cn.level = LIBNET_RPC_CONNECT_PDC;
+ cn.in.name = talloc_strdup(mem_ctx, r->in.domain_name);
+ cn.in.dcerpc_iface = &dcerpc_table_samr;
status = libnet_RpcConnect(ctx, mem_ctx, &cn);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c
index d9c25d053e..dc271ba577 100644
--- a/source4/libnet/libnet_vampire.c
+++ b/source4/libnet/libnet_vampire.c
@@ -210,7 +210,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx
/* Setup schannel */
nt_status = dcerpc_pipe_connect_b(samsync_ctx, &p, b,
- &dcerpc_table_netlogon,
+ &dcerpc_table_netlogon,
machine_account, ctx->event_ctx);
if (!NT_STATUS_IS_OK(nt_status)) {
diff --git a/source4/script/tests/test_nbt.sh b/source4/script/tests/test_nbt.sh
index c230547db5..3aa558c589 100755
--- a/source4/script/tests/test_nbt.sh
+++ b/source4/script/tests/test_nbt.sh
@@ -21,7 +21,7 @@ export PATH
testit "nmblookup -U $SERVER $SERVER" bin/nmblookup $TORTURE_OPTIONS -U $SERVER $SERVER || failed=`expr $failed + 1`
testit "nmblookup $SERVER" bin/nmblookup $TORTURE_OPTIONS $SERVER || failed=`expr $failed + 1`
-for f in NBT-REGISTER NBT-WINS NBT-WINSREPLICATION; do
+for f in NBT-REGISTER NBT-WINS NBT-WINSREPLICATION NET-API-LOOKUP NET-API-LOOKUPHOST NET-API-LOOKUPPDC; do
testit "$f" bin/smbtorture $TORTURE_OPTIONS //$SERVER/_none_ $f || failed=`expr $failed + 1`
done
diff --git a/source4/script/tests/test_rpc.sh b/source4/script/tests/test_rpc.sh
index 7056300e28..21bd31bd24 100755
--- a/source4/script/tests/test_rpc.sh
+++ b/source4/script/tests/test_rpc.sh
@@ -2,9 +2,9 @@
# add tests to this list as they start passing, so we test
# that they stay passing
-ncacn_np_tests="RPC-SPOOLSS RPC-JOIN RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND"
-ncalrpc_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND"
-ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND"
+ncacn_np_tests="RPC-SPOOLSS RPC-JOIN RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER"
+ncalrpc_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER"
+ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER"
slow_ncacn_np_tests="RPC-SAMLOGON"
slow_ncalrpc_tests="RPC-SAMLOGON"
slow_ncacn_ip_tcp_tests="RPC-SAMLOGON"
diff --git a/source4/torture/libnet/libnet_lookup.c b/source4/torture/libnet/libnet_lookup.c
index b6f23fd58c..c95ee58e49 100644
--- a/source4/torture/libnet/libnet_lookup.c
+++ b/source4/torture/libnet/libnet_lookup.c
@@ -40,8 +40,7 @@ BOOL torture_lookup(void)
address = talloc_array(ctx, const char, 16);
- lookup.in.hostname = lp_netbios_name();
- lookup.in.methods = lp_name_resolve_order();
+ lookup.in.hostname = lp_parm_string(-1, "torture", "host");
lookup.in.type = NBT_NAME_CLIENT;
lookup.out.address = &address;
@@ -77,8 +76,7 @@ BOOL torture_lookup_host(void)
address = talloc_array(mem_ctx, const char, 16);
- lookup.in.hostname = lp_netbios_name();
- lookup.in.methods = lp_name_resolve_order();
+ lookup.in.hostname = lp_parm_string(-1, "torture", "host");
lookup.out.address = &address;
status = libnet_LookupHost(ctx, mem_ctx, &lookup);
@@ -103,24 +101,28 @@ BOOL torture_lookup_pdc(void)
NTSTATUS status;
TALLOC_CTX *mem_ctx;
struct libnet_context *ctx;
- struct libnet_Lookup lookup;
- const char *address;
+ struct libnet_LookupDCs *lookup;
mem_ctx = talloc_init("test_lookup_pdc");
ctx = libnet_context_init(NULL);
ctx->cred = cmdline_credentials;
- address = talloc_array(mem_ctx, const char, 16);
+ talloc_steal(ctx, mem_ctx);
- lookup.in.hostname = lp_workgroup();
- lookup.in.methods = lp_name_resolve_order();
- lookup.out.address = &address;
+ lookup = talloc(mem_ctx, struct libnet_LookupDCs);
+ if (!lookup) {
+ ret = False;
+ goto done;
+ }
+
+ lookup->in.domain_name = lp_workgroup();
+ lookup->in.name_type = NBT_NAME_PDC;
- status = libnet_LookupPdc(ctx, mem_ctx, &lookup);
+ status = libnet_LookupDCs(ctx, mem_ctx, lookup);
if (!NT_STATUS_IS_OK(status)) {
- printf("Couldn't lookup pdc %s: %s\n", lookup.in.hostname, nt_errstr(status));
+ printf("Couldn't lookup pdc %s: %s\n", lookup->in.domain_name, nt_errstr(status));
ret = False;
goto done;
}
diff --git a/source4/torture/libnet/libnet_rpc.c b/source4/torture/libnet/libnet_rpc.c
index 99055fac0d..418f579728 100644
--- a/source4/torture/libnet/libnet_rpc.c
+++ b/source4/torture/libnet/libnet_rpc.c
@@ -24,20 +24,19 @@
#include "libnet/libnet.h"
-BOOL test_lsa_np_connect(struct libnet_context *ctx)
+static BOOL test_lsa_connect(struct libnet_context *ctx)
{
NTSTATUS status;
struct libnet_RpcConnect connect;
connect.level = LIBNET_RPC_CONNECT_BINDING;
- connect.in.domain_name = lp_workgroup();
- connect.in.binding = talloc_asprintf(ctx, "ncacn_np:%s", lp_workgroup());
+ connect.in.binding = lp_parm_string(-1, "torture", "binding");
connect.in.dcerpc_iface = &dcerpc_table_lsarpc;
status = libnet_RpcConnect(ctx, ctx, &connect);
if (!NT_STATUS_IS_OK(status)) {
printf("Couldn't connect to rpc service %s on %s: %s\n",
- connect.in.dcerpc_iface->name, connect.in.domain_name,
+ connect.in.dcerpc_iface->name, connect.in.binding,
nt_errstr(status));
return False;
@@ -47,20 +46,19 @@ BOOL test_lsa_np_connect(struct libnet_context *ctx)
}
-BOOL test_samr_np_connect(struct libnet_context *ctx)
+static BOOL test_samr_connect(struct libnet_context *ctx)
{
NTSTATUS status;
struct libnet_RpcConnect connect;
connect.level = LIBNET_RPC_CONNECT_BINDING;
- connect.in.domain_name = lp_workgroup();
- connect.in.binding = talloc_asprintf(ctx, "ncacn_np:%s", lp_workgroup());
+ connect.in.binding = lp_parm_string(-1, "torture", "binding");
connect.in.dcerpc_iface = &dcerpc_table_samr;
status = libnet_RpcConnect(ctx, ctx, &connect);
if (!NT_STATUS_IS_OK(status)) {
printf("Couldn't connect to rpc service %s on %s: %s\n",
- connect.in.dcerpc_iface->name, connect.in.domain_name,
+ connect.in.dcerpc_iface->name, connect.in.binding,
nt_errstr(status));
return False;
@@ -69,53 +67,6 @@ BOOL test_samr_np_connect(struct libnet_context *ctx)
return True;
}
-
-BOOL test_lsa_tcpip_connect(struct libnet_context *ctx)
-{
- NTSTATUS status;
- struct libnet_RpcConnect connect;
- connect.level = LIBNET_RPC_CONNECT_BINDING;
- connect.in.domain_name = lp_workgroup();
- connect.in.binding = talloc_asprintf(ctx, "ncacn_ip_tcp:%s", lp_netbios_name());
- connect.in.dcerpc_iface = &dcerpc_table_lsarpc;
-
- status = libnet_RpcConnect(ctx, ctx, &connect);
-
- if (!NT_STATUS_IS_OK(status)) {
- printf("Couldn't connect to rpc service %s on %s: %s\n",
- connect.in.dcerpc_iface->name, connect.in.domain_name,
- nt_errstr(status));
-
- return False;
- }
-
- return True;
-}
-
-
-BOOL test_samr_tcpip_connect(struct libnet_context *ctx)
-{
- NTSTATUS status;
- struct libnet_RpcConnect connect;
- connect.level = LIBNET_RPC_CONNECT_BINDING;
- connect.in.domain_name = lp_workgroup();
- connect.in.binding = talloc_asprintf(ctx, "ncacn_ip_tcp:%s", lp_netbios_name());
- connect.in.dcerpc_iface = &dcerpc_table_samr;
-
- status = libnet_RpcConnect(ctx, ctx, &connect);
-
- if (!NT_STATUS_IS_OK(status)) {
- printf("Couldn't connect to rpc service %s on %s: %s\n",
- connect.in.dcerpc_iface->name, connect.in.domain_name,
- nt_errstr(status));
-
- return False;
- }
-
- return True;
-}
-
-
BOOL torture_rpc_connect(void)
{
struct libnet_context *ctx;
@@ -123,27 +74,15 @@ BOOL torture_rpc_connect(void)
ctx = libnet_context_init(NULL);
ctx->cred = cmdline_credentials;
- printf("Testing connection to lsarpc interface via named pipe\n");
- if (!test_lsa_np_connect(ctx)) {
- printf("failed to connect lsarpc interface via named pipe\n");
- return False;
- }
-
- printf("Testing connection to SAMR service via named pipe\n");
- if (!test_samr_np_connect(ctx)) {
- printf("failed to connect samr interface via named pipe\n");
- return False;
- }
-
- printf("Testing connection to LSA service via tcp/ip\n");
- if (!test_lsa_tcpip_connect(ctx)) {
- printf("failed to connect lsarpc interface via tcp/ip\n");
+ printf("Testing connection to lsarpc interface\n");
+ if (!test_lsa_connect(ctx)) {
+ printf("failed to connect lsarpc interface\n");
return False;
}
- printf("Testing connection to SAMR service via tcp/ip\n");
- if (!test_samr_tcpip_connect(ctx)) {
- printf("failed to connect samr interface via tcp/ip\n");
+ printf("Testing connection to SAMR service\n");
+ if (!test_samr_connect(ctx)) {
+ printf("failed to connect samr interface\n");
return False;
}
diff --git a/source4/torture/libnet/libnet_share.c b/source4/torture/libnet/libnet_share.c
index 5489f42ac8..93919a4129 100644
--- a/source4/torture/libnet/libnet_share.c
+++ b/source4/torture/libnet/libnet_share.c
@@ -148,7 +148,7 @@ BOOL torture_listshares(void)
status = libnet_ListShares(libnetctx, mem_ctx, &share);
if (!NT_STATUS_IS_OK(status)) {
- printf("libnet_ListShare level %u failed - %s\n", share.in.level, nt_errstr(status));
+ printf("libnet_ListShare level %u failed - %s\n", share.in.level, share.out.error_string);
ret = False;
goto done;
}