summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/librpc/rpc/dcerpc.h11
-rw-r--r--source4/librpc/rpc/dcerpc_util.c299
-rw-r--r--source4/torture/torture.c135
3 files changed, 320 insertions, 125 deletions
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 6b1bd9de33..fa2ced2537 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -89,3 +89,14 @@ struct dcerpc_interface_table {
const struct dcerpc_interface_call *calls;
const struct dcerpc_endpoint_list *endpoints;
};
+
+
+enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP};
+
+/* this describes a binding to a particular transport/pipe */
+struct dcerpc_binding {
+ enum dcerpc_transport_t transport;
+ const char *host;
+ const char **options;
+ uint32 flags;
+};
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 335761e10f..68623982e1 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -202,6 +202,20 @@ const struct dcerpc_interface_table *idl_iface_by_name(const char *name)
return NULL;
}
+/*
+ find a dcerpc interface by uuid
+*/
+const struct dcerpc_interface_table *idl_iface_by_uuid(const char *uuid)
+{
+ int i;
+ for (i=0;dcerpc_pipes[i];i++) {
+ if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0) {
+ return dcerpc_pipes[i];
+ }
+ }
+ return NULL;
+}
+
/*
@@ -241,3 +255,288 @@ NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
+
+
+/*
+ parse a binding string into a dcerpc_binding structure
+*/
+NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding *b)
+{
+ char *part1, *part2, *part3;
+ char *p;
+ int i, j, comma_count;
+ const struct {
+ const char *name;
+ enum dcerpc_transport_t transport;
+ } transports[] = {
+ {"ncacn_np", NCACN_NP},
+ {"ncacn_ip_tcp", NCACN_IP_TCP}
+ };
+ const struct {
+ const char *name;
+ uint32 flag;
+ } options[] = {
+ {"sign", DCERPC_SIGN},
+ {"seal", DCERPC_SEAL},
+ {"validate", DCERPC_DEBUG_VALIDATE_BOTH}
+ };
+
+ p = strchr(s, ':');
+ if (!p) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ part1 = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
+ if (!part1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ s = p+1;
+
+ p = strchr(s, ':');
+ if (!p) {
+ part2 = talloc_strdup(mem_ctx, s);
+ part3 = NULL;
+ } else {
+ part2 = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
+ part3 = talloc_strdup(mem_ctx, p+1);
+ }
+ if (!part2) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (strcasecmp(part1, transports[i].name) == 0) {
+ b->transport = transports[i].transport;
+ break;
+ }
+ }
+ if (i==ARRAY_SIZE(transports)) {
+ DEBUG(1,("Unknown dcerpc transport '%s'\n", part1));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ b->host = part2;
+ b->options = NULL;
+ b->flags = 0;
+
+ if (!part3) {
+ return NT_STATUS_OK;
+ }
+
+ /* the [] brackets are optional */
+ if (*part3 == '[' && part3[strlen(part3)-1] == ']') {
+ part3++;
+ part3[strlen(part3)-1] = 0;
+ }
+
+ comma_count = count_chars(part3, ',');
+ b->options = talloc_array_p(mem_ctx, const char *, comma_count+2);
+ if (!b->options) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; (p = strchr(part3, ',')); i++) {
+ b->options[i] = talloc_strndup(mem_ctx, part3, PTR_DIFF(p, part3));
+ if (!b->options[i]) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ part3 = p+1;
+ }
+ b->options[i] = part3;
+ b->options[i+1] = NULL;
+
+ /* some options are pre-parsed for convenience */
+ for (i=0;b->options[i];i++) {
+ for (j=0;j<ARRAY_SIZE(options);j++) {
+ if (strcasecmp(options[j].name, b->options[i]) == 0) {
+ b->flags |= options[j].flag;
+ break;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/* open a rpc connection to a rpc pipe on SMP using the binding
+ structure to determine the endpoint and options */
+static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const char *pipe_uuid,
+ uint32 pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+ BOOL retry;
+ struct cli_state *cli;
+ const char *pipe_name;
+
+ if (!binding->options || !binding->options[0]) {
+ const struct dcerpc_interface_table *table = idl_iface_by_uuid(pipe_uuid);
+ if (!table) {
+ DEBUG(0,("Unknown interface endpoint '%s'\n", pipe_uuid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ pipe_name = table->endpoints->names[0];
+ } else {
+ pipe_name = binding->options[0];
+ }
+
+ if (strncasecmp(pipe_name, "\\pipe\\", 6) == 0) {
+ pipe_name += 6;
+ }
+ if (strncasecmp(pipe_name, "/pipe/", 6) == 0) {
+ pipe_name += 6;
+ }
+
+ status = cli_full_connection(&cli, lp_netbios_name(),
+ binding->host, NULL,
+ "ipc$", "?????",
+ username, username[0]?domain:"",
+ password, 0, &retry);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_tdis(cli);
+ cli_shutdown(cli);
+ return status;
+ }
+
+ /* this ensures that the reference count is decremented so
+ a pipe close will really close the link */
+ cli_tree_close(cli->tree);
+
+ (*p)->flags = binding->flags;
+
+ if (binding->flags & (DCERPC_SIGN | DCERPC_SEAL)) {
+ status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
+ } else {
+ status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ dcerpc_pipe_close(*p);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/* open a rpc connection to a rpc pipe on SMP using the binding
+ structure to determine the endpoint and options */
+static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const char *pipe_uuid,
+ uint32 pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+ uint32 port = 0;
+
+ if (binding->options && binding->options[0]) {
+ port = atoi(binding->options[0]);
+ }
+
+ if (port == 0) {
+ status = dcerpc_epm_map_tcp_port(binding->host,
+ pipe_uuid, pipe_version,
+ &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n",
+ pipe_uuid, nt_errstr(status)));
+ return status;
+ }
+ DEBUG(1,("Mapped to DCERPC/TCP port %u\n", port));
+ }
+
+ status = dcerpc_pipe_open_tcp(p, binding->host, port);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* it doesn't seem to work to do a null NTLMSSP session without either sign
+ or seal, so force signing if we are doing ntlmssp */
+ if (username[0] && !(binding->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
+ binding->flags |= DCERPC_SIGN;
+ }
+
+ (*p)->flags = binding->flags;
+
+ if (!(binding->flags & (DCERPC_SIGN|DCERPC_SEAL)) && !username[0]) {
+ status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
+ } else {
+ status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
+ domain, username, password);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ dcerpc_pipe_close(*p);
+ return status;
+ }
+
+ return status;
+}
+
+
+/* open a rpc connection to a rpc pipe, using the specified
+ binding structure to determine the endpoint and options */
+NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p,
+ struct dcerpc_binding *binding,
+ const char *pipe_uuid,
+ uint32 pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+
+ switch (binding->transport) {
+ case NCACN_NP:
+ status = dcerpc_pipe_connect_ncacn_np(p, binding, pipe_uuid, pipe_version,
+ domain, username, password);
+ break;
+ case NCACN_IP_TCP:
+ status = dcerpc_pipe_connect_ncacn_ip_tcp(p, binding, pipe_uuid, pipe_version,
+ domain, username, password);
+ break;
+ }
+
+ return status;
+}
+
+
+/* open a rpc connection to a rpc pipe, using the specified string
+ binding to determine the endpoint and options */
+NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p,
+ const char *binding,
+ const char *pipe_uuid,
+ uint32 pipe_version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ struct dcerpc_binding b;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("dcerpc_pipe_connect");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ status = dcerpc_parse_binding(mem_ctx, binding, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ status = dcerpc_pipe_connect_b(p, &b, pipe_uuid, pipe_version, domain, username, password);
+
+ talloc_destroy(mem_ctx);
+ return status;
+}
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
index 9fc0bc7b4e..15e8ae9ec8 100644
--- a/source4/torture/torture.c
+++ b/source4/torture/torture.c
@@ -130,61 +130,6 @@ BOOL torture_close_connection(struct cli_state *c)
return ret;
}
-/* open a rpc connection to a named pipe */
-static NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p,
- const char *pipe_name,
- const char *pipe_uuid,
- uint32 pipe_version)
-{
- NTSTATUS status;
- char *host = lp_parm_string(-1, "torture", "host");
- const char *port_str = lp_parm_string(-1, "torture", "share");
- uint32 port = atoi(port_str);
-
- if (port == 0) {
- status = dcerpc_epm_map_tcp_port(host,
- pipe_uuid, pipe_version,
- &port);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n",
- pipe_name, nt_errstr(status)));
- return status;
- }
- DEBUG(1,("Mapped to DCERPC/TCP port %u\n", port));
- }
-
- DEBUG(2,("Connecting to dcerpc server %s:%u\n", host, port));
-
- status = dcerpc_pipe_open_tcp(p, host, port);
- if (!NT_STATUS_IS_OK(status)) {
- printf("Open of pipe '%s' failed with error (%s)\n",
- pipe_name, nt_errstr(status));
- return status;
- }
-
- /* always do NDR validation in smbtorture */
- (*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH;
-
-#if 0
- status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
-#else
- /* enable signing on tcp connections */
- (*p)->flags |= DCERPC_SIGN;
-
- /* bind to the pipe, using the uuid as the key */
- status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
- lp_workgroup(),
- lp_parm_string(-1, "torture", "username"),
- lp_parm_string(-1, "torture", "password"));
- if (!NT_STATUS_IS_OK(status)) {
- dcerpc_pipe_close(*p);
- return status;
- }
-#endif
-
- return status;
-}
-
/* open a rpc connection to a named pipe */
NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
@@ -192,59 +137,18 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
const char *pipe_uuid,
uint32 pipe_version)
{
- struct cli_state *cli;
NTSTATUS status;
- char *transport = lp_parm_string(-1, "torture", "transport");
-
- if (strcmp(transport, "ncacn_ip_tcp") == 0) {
- return torture_rpc_tcp(p, pipe_name, pipe_uuid, pipe_version);
- }
-
- if (strcmp(transport, "ncacn_np") != 0) {
- printf("Unsupported RPC transport '%s'\n", transport);
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- if (! *lp_parm_string(-1, "torture", "share")) {
- lp_set_cmdline("torture:share", "ipc$");
- }
+ char *binding = lp_parm_string(-1, "torture", "binding");
- if (!torture_open_connection(&cli)) {
- return NT_STATUS_UNSUCCESSFUL;
+ if (!binding) {
+ printf("You must specify a ncacn binding string\n");
+ return NT_STATUS_INVALID_PARAMETER;
}
- status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name);
- if (!NT_STATUS_IS_OK(status)) {
- printf("Open of pipe '%s' failed with error (%s)\n",
- pipe_name, nt_errstr(status));
- torture_close_connection(cli);
- return status;
- }
-
- /* this ensures that the reference count is decremented so
- a pipe close will really close the link */
- cli_tree_close(cli->tree);
-
- /* bind to the pipe, using the uuid as the key */
-#if 1
- status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
-#else
- /* enable signing on tcp connections */
- (*p)->flags |= DCERPC_SIGN;
-
- /* bind to the pipe, using the uuid as the key */
- status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
- lp_workgroup(),
- lp_parm_string(-1, "torture", "username"),
- lp_parm_string(-1, "torture", "password"));
-#endif
- if (!NT_STATUS_IS_OK(status)) {
- dcerpc_pipe_close(*p);
- return status;
- }
-
- /* always do NDR validation in smbtorture */
- (*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH;
+ status = dcerpc_pipe_connect(p, binding, pipe_uuid, pipe_version,
+ lp_workgroup(),
+ lp_parm_string(-1, "torture", "username"),
+ lp_parm_string(-1, "torture", "password"));
return status;
}
@@ -4221,23 +4125,8 @@ static void usage(void)
/* see if its a RPC transport specifier */
- if (strncmp(argv[1], "ncacn", 5) == 0) {
- char *transport = strdup(argv[1]);
- p = strchr_m(transport, ':');
- if (!p) usage();
- *p = 0;
- host = p+1;
- p = strchr_m(host, ':');
- if (p) {
- *p = 0;
- share = p+1;
- lp_set_cmdline("torture:share", share);
- } else {
- share = "";
- lp_set_cmdline("torture:share", share);
- }
- lp_set_cmdline("torture:host", host);
- lp_set_cmdline("torture:transport", transport);
+ if (strncmp(argv[1], "ncacn_", 6) == 0) {
+ lp_set_cmdline("torture:binding", argv[1]);
} else {
if (strncmp(argv[1], "//", 2)) {
usage();
@@ -4331,10 +4220,6 @@ static void usage(void)
}
}
- printf("host=%s share=%s user=%s myname=%s\n",
- host, share, lp_parm_string(-1, "torture", "username"),
- lp_netbios_name());
-
if (argc == optind) {
printf("You must specify a test to run, or 'ALL'\n");
} else {