diff options
author | Rafal Szczesniak <mimir@samba.org> | 2006-03-09 23:21:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:56:52 -0500 |
commit | a1f08df37c5b4e6b093da961de5105929363b68a (patch) | |
tree | 3e13357dbb7f31d3a88041d70a299a0667f55e2f | |
parent | dabc0b41160615ff872491e4b133be5018eef4e8 (diff) | |
download | samba-a1f08df37c5b4e6b093da961de5105929363b68a.tar.gz samba-a1f08df37c5b4e6b093da961de5105929363b68a.tar.bz2 samba-a1f08df37c5b4e6b093da961de5105929363b68a.zip |
r14123: Huge lump of code making all of our dcerpc connect code
asynchronous. Build is ok, and so are the tests.
More comments to follow.
rafal
(This used to be commit a74fb6c5a2f968c56aff8ce39ce2ce9375d19b81)
-rw-r--r-- | source4/librpc/rpc/dcerpc_connect.c | 690 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_schannel.c | 385 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 539 |
3 files changed, 1233 insertions, 381 deletions
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index defebe4b15..f73a4de2be 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -43,7 +43,7 @@ struct pipe_np_smb_state { /* Stage 3 of ncacn_np_smb: Named pipe opened (or not) */ -void continue_pipe_open_smb(struct composite_context *ctx) +static void continue_pipe_open_smb(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -52,9 +52,8 @@ void continue_pipe_open_smb(struct composite_context *ctx) /* receive result of named pipe open request on smb */ c->status = dcerpc_pipe_open_smb_recv(ctx); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to open pipe %s - %s\n", s->io.pipe_name, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -64,7 +63,7 @@ void continue_pipe_open_smb(struct composite_context *ctx) /* Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection */ -void continue_smb_connect(struct composite_context *ctx) +static void continue_smb_connect(struct composite_context *ctx) { struct composite_context *open_ctx; struct composite_context *c = talloc_get_type(ctx->async.private_data, @@ -74,9 +73,8 @@ void continue_smb_connect(struct composite_context *ctx) /* receive result of smb connect request */ c->status = smb_composite_connect_recv(ctx, c); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to connect to %s - %s\n", s->io.binding->host, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -86,10 +84,7 @@ void continue_smb_connect(struct composite_context *ctx) /* send named pipe open request */ open_ctx = dcerpc_pipe_open_smb_send(s->io.pipe->conn, s->tree, s->io.pipe_name); - if (open_ctx == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - return; - } + if (composite_nomem(open_ctx, c)) return; composite_continue(c, open_ctx, continue_pipe_open_smb, c); } @@ -112,10 +107,7 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ if (c == NULL) return NULL; s = talloc_zero(c, struct pipe_np_smb_state); - if (s == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s, c)) return c; c->state = COMPOSITE_STATE_IN_PROGRESS; c->private_data = s; @@ -133,6 +125,9 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ conn->in.service_type = NULL; conn->in.workgroup = lp_workgroup(); + /* verify if called_name has been allocated when uppercasing */ + if (composite_nomem(conn->in.called_name, c)) return c; + /* * provide proper credentials - user supplied, but allow a * fallback to anonymous if this is an schannel connection @@ -148,14 +143,9 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ /* send smb connect request */ conn_req = smb_composite_connect_send(conn, s->io.pipe->conn, s->io.pipe->conn->event_ctx); - if (!conn_req) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(conn_req, c)) return c; composite_continue(c, conn_req, continue_smb_connect, c); - -done: return c; } @@ -193,7 +183,7 @@ struct pipe_np_smb2_state { /* Stage 3 of ncacn_np_smb: Named pipe opened (or not) */ -void continue_pipe_open_smb2(struct composite_context *ctx) +static void continue_pipe_open_smb2(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -202,9 +192,8 @@ void continue_pipe_open_smb2(struct composite_context *ctx) /* receive result of named pipe open request on smb2 */ c->status = dcerpc_pipe_open_smb2_recv(ctx); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to open pipe %s - %s\n", s->io.pipe_name, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -215,7 +204,7 @@ void continue_pipe_open_smb2(struct composite_context *ctx) /* Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection */ -void continue_smb2_connect(struct composite_context *ctx) +static void continue_smb2_connect(struct composite_context *ctx) { struct composite_context *open_req; struct composite_context *c = talloc_get_type(ctx->async.private_data, @@ -225,9 +214,8 @@ void continue_smb2_connect(struct composite_context *ctx) /* receive result of smb2 connect request */ c->status = smb2_connect_recv(ctx, c, &s->tree); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to connect to %s - %s\n", s->io.binding->host, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -236,10 +224,7 @@ void continue_smb2_connect(struct composite_context *ctx) /* send named pipe open request */ open_req = dcerpc_pipe_open_smb2_send(s->io.pipe->conn, s->tree, s->io.pipe_name); - if (open_req == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - return; - } + if (composite_nomem(open_req, c)) return; composite_continue(c, open_req, continue_pipe_open_smb2, c); } @@ -261,10 +246,7 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(TALLOC_CTX *mem if (c == NULL) return NULL; s = talloc_zero(c, struct pipe_np_smb2_state); - if (s == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s, c)) return c; c->state = COMPOSITE_STATE_IN_PROGRESS; c->private_data = s; @@ -278,10 +260,7 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(TALLOC_CTX *mem */ if (s->io.binding->flags & DCERPC_SCHANNEL) { s->io.creds = cli_credentials_init(mem_ctx); - if (s->io.creds) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s->io.creds, c)) return c; cli_credentials_set_anonymous(s->io.creds); cli_credentials_guess(s->io.creds); @@ -290,14 +269,10 @@ struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(TALLOC_CTX *mem /* send smb2 connect request */ conn_req = smb2_connect_send(mem_ctx, s->io.binding->host, "IPC$", s->io.creds, c->event_ctx); - if (conn_req == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(conn_req, c)) return c; composite_continue(c, conn_req, continue_smb2_connect, c); -done: return c; } @@ -336,7 +311,7 @@ struct pipe_ip_tcp_state { /* Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not) */ -void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx) +static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -345,10 +320,9 @@ void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx) /* receive result of named pipe open request on tcp/ip */ c->status = dcerpc_pipe_open_tcp_recv(ctx); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to connect to %s:%d - %s\n", s->host, s->port, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -372,10 +346,7 @@ struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ if (c == NULL) return NULL; s = talloc_zero(c, struct pipe_ip_tcp_state); - if (s == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s, c)) return c; c->state = COMPOSITE_STATE_IN_PROGRESS; c->private_data = s; @@ -388,13 +359,9 @@ struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ /* send pipe open request on tcp/ip */ pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->port); - if (pipe_req == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(pipe_req, c)) return c; composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c); -done: return c; } @@ -432,7 +399,7 @@ struct pipe_unix_state { /* Stage 2 of ncacn_unix: rpc pipe opened (or not) */ -void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx) +static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -441,10 +408,9 @@ void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx) /* receive result of pipe open request on unix socket */ c->status = dcerpc_pipe_open_unix_stream_recv(ctx); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to open unix socket %s - %s\n", s->io.binding->endpoint, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -468,10 +434,7 @@ struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX if (c == NULL) return NULL; s = talloc_zero(c, struct pipe_unix_state); - if (s == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s, c)) return c; c->state = COMPOSITE_STATE_IN_PROGRESS; c->private_data = s; @@ -484,20 +447,16 @@ struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX if (!io->binding->endpoint) { DEBUG(0, ("Path to unix socket not specified\n")); composite_error(c, NT_STATUS_INVALID_PARAMETER); - goto done; + return c; } s->path = talloc_strdup(c, io->binding->endpoint); /* path is a binding endpoint here */ /* send pipe open request on unix socket */ pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.pipe->conn, s->path); - if (pipe_req == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(pipe_req, c)) return c; composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c); -done: return c; } @@ -534,7 +493,7 @@ struct pipe_ncalrpc_state { /* Stage 2 of ncalrpc: rpc pipe opened (or not) */ -void continue_pipe_open_ncalrpc(struct composite_context *ctx) +static void continue_pipe_open_ncalrpc(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -543,10 +502,9 @@ void continue_pipe_open_ncalrpc(struct composite_context *ctx) /* receive result of pipe open request on ncalrpc */ c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx); - if (!NT_STATUS_IS_OK(c->status)) { + if (!composite_is_ok(c)) { DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", s->io.binding->endpoint, nt_errstr(c->status))); - composite_error(c, c->status); return; } @@ -570,10 +528,7 @@ struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx, if (c == NULL) return NULL; s = talloc_zero(c, struct pipe_ncalrpc_state); - if (s == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(s, c)) return c; c->state = COMPOSITE_STATE_IN_PROGRESS; c->private_data = s; @@ -584,13 +539,9 @@ struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx, /* send pipe open request */ pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, s->io.binding->endpoint); - if (pipe_req == NULL) { - composite_error(c, NT_STATUS_NO_MEMORY); - goto done; - } + if (composite_nomem(pipe_req, c)) return c; composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c); -done: return c; } @@ -616,3 +567,582 @@ NTSTATUS dcerpc_pipe_connect_ncalrpc(TALLOC_CTX *mem_ctx, struct composite_context *c = dcerpc_pipe_connect_ncalrpc_send(mem_ctx, io); return dcerpc_pipe_connect_ncalrpc_recv(c); } + + +struct pipe_connect_state { + struct dcerpc_pipe *pipe; + struct dcerpc_binding *binding; + const struct dcerpc_interface_table *table; + struct cli_credentials *credentials; +}; + + +static void continue_map_binding(struct composite_context *ctx); +static void continue_connect(struct composite_context *c, struct pipe_connect_state *s); +static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx); +static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx); +static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx); +static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx); +static void continue_pipe_connect_ncalrpc(struct composite_context *ctx); +static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s); +static void continue_pipe_auth(struct composite_context *ctx); + + +static void continue_map_binding(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_epm_map_binding_recv(ctx); + if (!composite_is_ok(c)) { + DEBUG(0,("Failed to map DCERPC endpoint for '%s' - %s\n", + GUID_string(c, &s->table->uuid), nt_errstr(c->status))); + return; + } + + DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint)); + + continue_connect(c, s); +} + + +static void continue_connect(struct composite_context *c, struct pipe_connect_state *s) +{ + struct dcerpc_pipe_connect pc; + + /* potential exits to another stage by sending an async request */ + struct composite_context *ncacn_np_smb2_req; + struct composite_context *ncacn_np_smb_req; + struct composite_context *ncacn_ip_tcp_req; + struct composite_context *ncacn_unix_req; + struct composite_context *ncalrpc_req; + + /* dcerpc pipe connect input parameters */ + pc.pipe = s->pipe; + pc.binding = s->binding; + pc.interface = s->table; + pc.creds = s->credentials; + + switch (s->binding->transport) { + case NCACN_NP: + if (pc.binding->flags & DCERPC_SMB2) { + /* new varient of SMB a.k.a. SMB2 */ + ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc); + if (composite_nomem(ncacn_np_smb2_req, c)) return; + + composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c); + return; + + } else { + /* good old ordinary SMB */ + ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc); + if (composite_nomem(ncacn_np_smb_req, c)) return; + + composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c); + return; + } + break; + + case NCACN_IP_TCP: + ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc); + if (composite_nomem(ncacn_ip_tcp_req, c)) return; + + composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c); + return; + + case NCACN_UNIX_STREAM: + ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc); + if (composite_nomem(ncacn_unix_req, c)) return; + + composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c); + return; + + case NCALRPC: + ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc); + if (composite_nomem(ncalrpc_req, c)) return; + + composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c); + return; + + default: + composite_error(c, NT_STATUS_NOT_SUPPORTED); + } +} + + +static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx); + if (!composite_is_ok(c)) return; + + continue_pipe_connect(c, s); +} + + +static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx); + if (!composite_is_ok(c)) return; + + continue_pipe_connect(c, s); +} + + +static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx); + if (!composite_is_ok(c)) return; + + continue_pipe_connect(c, s); +} + + +static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx); + if (!composite_is_ok(c)) return; + + continue_pipe_connect(c, s); +} + + +static void continue_pipe_connect_ncalrpc(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_connect_state *s = talloc_get_type(c->private_data, + struct pipe_connect_state); + + c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx); + if (!composite_is_ok(c)) return; + + continue_pipe_connect(c, s); +} + + +static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s) +{ + struct composite_context *auth_bind_req; + + s->pipe->binding = s->binding; + if (!talloc_reference(s->pipe, s->binding)) { + composite_error(c, NT_STATUS_NO_MEMORY); + return; + } + + auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table, + s->credentials); + if (composite_nomem(auth_bind_req, c)) return; + + composite_continue(c, auth_bind_req, continue_pipe_auth, c); +} + + +static void continue_pipe_auth(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + + c->status = dcerpc_pipe_auth_recv(ctx); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx, + struct dcerpc_pipe **pp, + struct dcerpc_binding *binding, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials, + struct event_context *ev) +{ + struct composite_context *c; + struct pipe_connect_state *s; + + struct composite_context *binding_req; + + /* composite context allocation and setup */ + c = talloc_zero(parent_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct pipe_connect_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + + (*pp) = NULL; + + /* initialise dcerpc pipe structure */ + s->pipe = dcerpc_pipe_init(c, ev); + if (composite_nomem(s->pipe, c)) return c; + + c->event_ctx = s->pipe->conn->event_ctx; + (*pp) = s->pipe; + + s->binding = binding; + s->table = table; + s->credentials = credentials; + + switch (s->binding->transport) { + case NCACN_NP: + case NCACN_IP_TCP: + case NCALRPC: + if (!s->binding->endpoint) { + binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table, + s->pipe->conn->event_ctx); + composite_continue(c, binding_req, continue_map_binding, c); + return c; + } + + default: + break; + } + + continue_connect(c, s); + return c; +} + + +NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, + struct dcerpc_pipe **p) +{ + NTSTATUS status; + struct pipe_connect_state *s; + + status = composite_wait(c); + + if (NT_STATUS_IS_OK(status) && p) { + s = talloc_get_type(c->private_data, struct pipe_connect_state); + talloc_steal(mem_ctx, s->pipe); + *p = s->pipe; + } + + talloc_free(c); + return status; +} + + +/* + open a rpc connection to a rpc pipe, using the specified + binding structure to determine the endpoint and options - sync version +*/ +NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx, + struct dcerpc_pipe **pp, + struct dcerpc_binding *binding, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials, + struct event_context *ev) +{ + struct composite_context *c; + + c = dcerpc_pipe_connect_b_send(parent_ctx, pp, binding, table, + credentials, ev); + return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp); +} + + +struct pipe_conn_state { + struct dcerpc_pipe *pipe; +}; + + +static void continue_pipe_connect_b(struct composite_context *ctx); + +struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx, + struct dcerpc_pipe **pp, + const char *binding, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials, + struct event_context *ev) +{ + NTSTATUS status; + struct composite_context *c; + struct pipe_conn_state *s; + struct dcerpc_binding *b; + struct composite_context *pipe_conn_req; + + c = talloc_zero(parent_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct pipe_conn_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + + status = dcerpc_parse_binding(c, binding, &b); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding)); + composite_error(c, status); + return c; + } + + DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b))); + + pipe_conn_req = dcerpc_pipe_connect_b_send(c, &s->pipe, b, table, + credentials, ev); + c->event_ctx = s->pipe->conn->event_ctx; + + if (composite_nomem(pipe_conn_req, c)) return c; + + composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c); + return c; +} + + +static void continue_pipe_connect_b(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct pipe_conn_state *s = talloc_get_type(c->private_data, + struct pipe_conn_state); + + c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c, + TALLOC_CTX *mem_ctx, + struct dcerpc_pipe **pp) +{ + NTSTATUS status; + struct pipe_conn_state *s; + + status = composite_wait(c); + if (NT_STATUS_IS_OK(status) && pp) { + s = talloc_get_type(c->private_data, struct pipe_conn_state); + *pp = talloc_steal(mem_ctx, s->pipe); + } + + talloc_free(c); + return status; +} + + +/* + open a rpc connection to a rpc pipe, using the specified string + binding to determine the endpoint and options - sync version +*/ +NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, + struct dcerpc_pipe **pp, + const char *binding, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials, + struct event_context *ev) +{ + struct composite_context *c; + c = dcerpc_pipe_connect_send(parent_ctx, pp, binding, table, + credentials, ev); + return dcerpc_pipe_connect_recv(c, parent_ctx, pp); +} + + +struct sec_conn_state { + struct dcerpc_pipe *pipe; + struct dcerpc_pipe **pipe2; + struct dcerpc_binding *binding; + struct smbcli_tree *tree; +}; + + +static void continue_open_smb(struct composite_context *ctx); +static void continue_open_tcp(struct composite_context *ctx); +static void continue_open_pipe(struct composite_context *ctx); +static void continue_pipe_open(struct composite_context *c); + + +struct composite_context* dcerpc_secondary_connection_send(TALLOC_CTX *mem_ctx, + struct dcerpc_pipe *p, + struct dcerpc_pipe **p2, + struct dcerpc_binding *b) +{ + struct composite_context *c; + struct sec_conn_state *s; + struct composite_context *pipe_smb_req; + struct composite_context *pipe_tcp_req; + struct composite_context *pipe_ncalrpc_req; + + c = talloc_zero(mem_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct sec_conn_state); + if (s == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + return c; + } + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + + s->pipe = p; + s->pipe2 = p2; + s->binding = b; + + (*s->pipe2) = dcerpc_pipe_init(s->pipe, s->pipe->conn->event_ctx); + if (s->pipe2 == NULL) { + composite_error(c, NT_STATUS_NO_MEMORY); + return c; + } + + c->event_ctx = (*s->pipe2)->conn->event_ctx; + + switch (s->pipe->conn->transport.transport) { + case NCACN_NP: + s->tree = dcerpc_smb_tree(s->pipe->conn); + if (!s->tree) { + composite_error(c, NT_STATUS_INVALID_PARAMETER); + return c; + } + + pipe_smb_req = dcerpc_pipe_open_smb_send((*s->pipe2)->conn, s->tree, + s->binding->endpoint); + if (composite_nomem(pipe_smb_req, c)) return c; + + composite_continue(c, pipe_smb_req, continue_open_smb, c); + return c; + + case NCACN_IP_TCP: + pipe_tcp_req = dcerpc_pipe_open_tcp_send((*s->pipe2)->conn, + s->binding->host, + atoi(s->binding->endpoint)); + if (composite_nomem(pipe_tcp_req, c)) return c; + + composite_continue(c, pipe_tcp_req, continue_open_tcp, c); + return c; + + case NCALRPC: + pipe_ncalrpc_req = dcerpc_pipe_open_pipe_send((*s->pipe2)->conn, + s->binding->endpoint); + if (composite_nomem(pipe_ncalrpc_req, c)) return c; + + composite_continue(c, pipe_ncalrpc_req, continue_open_pipe, c); + return c; + + default: + composite_error(c, NT_STATUS_NOT_SUPPORTED); + } + + return c; +} + + +static void continue_open_smb(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct sec_conn_state *s = talloc_get_type(c->private_data, + struct sec_conn_state); + + c->status = dcerpc_pipe_open_smb_recv(ctx); + if (!composite_is_ok(c)) { + talloc_free(*s->pipe2); + return; + } + + continue_pipe_open(c); +} + + +static void continue_open_tcp(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct sec_conn_state *s = talloc_get_type(c->private_data, + struct sec_conn_state); + + c->status = dcerpc_pipe_open_tcp_recv(ctx); + if (!composite_is_ok(c)) { + talloc_free(*s->pipe2); + return; + } + + continue_pipe_open(c); +} + + +static void continue_open_pipe(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct sec_conn_state *s = talloc_get_type(c->private_data, + struct sec_conn_state); + + c->status = dcerpc_pipe_open_pipe_recv(ctx); + if (!composite_is_ok(c)) { + talloc_free(*s->pipe2); + return; + } + + continue_pipe_open(c); +} + + +static void continue_pipe_open(struct composite_context *c) +{ + struct sec_conn_state *s; + + s = talloc_get_type(c->private_data, struct sec_conn_state); + + (*s->pipe2)->conn->flags = s->pipe->conn->flags; + (*s->pipe2)->binding = s->binding; + if (!talloc_reference((*s->pipe2), s->binding)) { + composite_error(c, NT_STATUS_NO_MEMORY); + return; + } + + composite_done(c); +} + + +NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + + talloc_free(c); + return status; +} + + +/* + create a secondary dcerpc connection from a primary connection + - sync version + + if the primary is a SMB connection then the secondary connection + will be on the same SMB connection, but use a new fnum +*/ +NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, + struct dcerpc_pipe **p2, + struct dcerpc_binding *b) +{ + struct composite_context *c; + + c = dcerpc_secondary_connection_send(NULL, p, p2, b); + return dcerpc_secondary_connection_recv(c); +} diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 01b6d099aa..dd9afb3a27 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -23,142 +23,325 @@ #include "includes.h" #include "auth/auth.h" +#include "libcli/composite/composite.h" #include "libcli/auth/proto.h" -/* - get a schannel key using a netlogon challenge on a secondary pipe -*/ -static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, - struct dcerpc_pipe *p, - struct cli_credentials *credentials) -{ - NTSTATUS status; - struct dcerpc_binding *b; - struct dcerpc_pipe *p2; + +struct schannel_key_state { + struct dcerpc_pipe *pipe; + struct dcerpc_pipe *pipe2; + struct dcerpc_binding *binding; + struct cli_credentials *credentials; + struct creds_CredentialState *creds; + uint32_t negotiate_flags; + struct netr_Credential credentials1; + struct netr_Credential credentials2; + struct netr_Credential credentials3; struct netr_ServerReqChallenge r; struct netr_ServerAuthenticate2 a; - struct netr_Credential credentials1, credentials2, credentials3; const struct samr_Password *mach_pwd; - uint32_t negotiate_flags; - struct creds_CredentialState *creds; - creds = talloc(tmp_ctx, struct creds_CredentialState); - if (!creds) { - return NT_STATUS_NO_MEMORY; +}; + + +static void continue_secondary_connection(struct composite_context *ctx); +static void continue_bind_auth_none(struct composite_context *ctx); +static void continue_srv_challenge(struct rpc_request *req); +static void continue_srv_auth2(struct rpc_request *req); + + +static void continue_epm_map_binding(struct composite_context *ctx) +{ + struct composite_context *c; + struct schannel_key_state *s; + struct composite_context *sec_conn_req; + + c = talloc_get_type(ctx->async.private_data, struct composite_context); + s = talloc_get_type(c->private_data, struct schannel_key_state); + + c->status = dcerpc_epm_map_binding_recv(ctx); + if (!composite_is_ok(c)) { + DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n", + DCERPC_NETLOGON_UUID, nt_errstr(c->status))); + return; } - if (p->conn->flags & DCERPC_SCHANNEL_128) { - negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; - } else { - negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS; + sec_conn_req = dcerpc_secondary_connection_send(c, s->pipe, &s->pipe2, + s->binding); + if (composite_nomem(sec_conn_req, c)) return; + + composite_continue(c, sec_conn_req, continue_secondary_connection, c); +} + + +static void continue_secondary_connection(struct composite_context *ctx) +{ + struct composite_context *c; + struct schannel_key_state *s; + struct composite_context *auth_none_req; + + c = talloc_get_type(ctx->async.private_data, struct composite_context); + s = talloc_get_type(c->private_data, struct schannel_key_state); + + c->status = dcerpc_secondary_connection_recv(ctx); + if (!composite_is_ok(c)) return; + + auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe2, &dcerpc_table_netlogon); + if (composite_nomem(auth_none_req, c)) return; + + composite_continue(c, auth_none_req, continue_bind_auth_none, c); +} + + +static void continue_bind_auth_none(struct composite_context *ctx) +{ + struct composite_context *c; + struct schannel_key_state *s; + struct rpc_request *srv_challenge_req; + + c = talloc_get_type(ctx->async.private_data, struct composite_context); + s = talloc_get_type(c->private_data, struct schannel_key_state); + + c->status = dcerpc_bind_auth_none_recv(ctx); + if (!composite_is_ok(c)) { + talloc_free(s->pipe2); + return; } + s->r.in.server_name = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe)); + if (composite_nomem(s->r.in.server_name, c)) return; + s->r.in.computer_name = cli_credentials_get_workstation(s->credentials); + s->r.in.credentials = &s->credentials1; + s->r.out.credentials = &s->credentials2; + + generate_random_buffer(s->credentials1.data, sizeof(s->credentials1.data)); + /* - step 1 - establish a netlogon connection, with no authentication + request a netlogon challenge */ - b = talloc(tmp_ctx, struct dcerpc_binding); - if (!b) { - return NT_STATUS_NO_MEMORY; - } - *b = *p->binding; - - /* Make binding string for netlogon, not the other pipe */ - status = dcerpc_epm_map_binding(tmp_ctx, b, - &dcerpc_table_netlogon, - p->conn->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n", - DCERPC_NETLOGON_UUID, nt_errstr(status))); - return status; - } + srv_challenge_req = dcerpc_netr_ServerReqChallenge_send(s->pipe2, c, &s->r); + if (composite_nomem(srv_challenge_req, c)) return; - status = dcerpc_secondary_connection(p, &p2, b); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + composite_continue_rpc(c, srv_challenge_req, continue_srv_challenge, c); +} + + +static void continue_srv_challenge(struct rpc_request *req) +{ + struct composite_context *c; + struct schannel_key_state *s; + struct rpc_request *srv_auth2_req; - status = dcerpc_bind_auth_none(p2, &dcerpc_table_netlogon); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(p2); - return status; - } + c = talloc_get_type(req->async.private, struct composite_context); + s = talloc_get_type(c->private_data, struct schannel_key_state); + + c->status = dcerpc_ndr_request_recv(req); + if (!composite_is_ok(c)) return; /* - step 2 - request a netlogon challenge + authenticate on the netlogon pipe */ - r.in.server_name = talloc_asprintf(tmp_ctx, "\\\\%s", dcerpc_server_name(p)); - r.in.computer_name = cli_credentials_get_workstation(credentials); - r.in.credentials = &credentials1; - r.out.credentials = &credentials2; - generate_random_buffer(credentials1.data, sizeof(credentials1.data)); + s->mach_pwd = cli_credentials_get_nt_hash(s->credentials, c); + + creds_client_init(s->creds, &s->credentials1, &s->credentials2, + s->mach_pwd, &s->credentials3, s->negotiate_flags); + + s->a.in.server_name = s->r.in.server_name; + s->a.in.account_name = cli_credentials_get_username(s->credentials); + s->a.in.secure_channel_type = + cli_credentials_get_secure_channel_type(s->credentials); + s->a.in.computer_name = cli_credentials_get_workstation(s->credentials); + s->a.in.negotiate_flags = &s->negotiate_flags; + s->a.in.credentials = &s->credentials3; + s->a.out.negotiate_flags = &s->negotiate_flags; + s->a.out.credentials = &s->credentials3; + + srv_auth2_req = dcerpc_netr_ServerAuthenticate2_send(s->pipe2, c, &s->a); + if (composite_nomem(srv_auth2_req, c)) return; + + composite_continue_rpc(c, srv_auth2_req, continue_srv_auth2, c); +} + - status = dcerpc_netr_ServerReqChallenge(p2, tmp_ctx, &r); - if (!NT_STATUS_IS_OK(status)) { - return status; +static void continue_srv_auth2(struct rpc_request *req) +{ + struct composite_context *c; + struct schannel_key_state *s; + + c = talloc_get_type(req->async.private, struct composite_context); + s = talloc_get_type(c->private_data, struct schannel_key_state); + + c->status = dcerpc_ndr_request_recv(req); + if (!composite_is_ok(c)) return; + + if (!creds_client_check(s->creds, s->a.out.credentials)) { + composite_error(c, NT_STATUS_UNSUCCESSFUL); + return; } - /* - step 3 - authenticate on the netlogon pipe - */ - mach_pwd = cli_credentials_get_nt_hash(credentials, tmp_ctx); - - creds_client_init(creds, &credentials1, &credentials2, - mach_pwd, &credentials3, - negotiate_flags); - - a.in.server_name = r.in.server_name; - a.in.account_name = cli_credentials_get_username(credentials); - a.in.secure_channel_type = - cli_credentials_get_secure_channel_type(credentials); - a.in.computer_name = cli_credentials_get_workstation(credentials); - a.in.negotiate_flags = &negotiate_flags; - a.out.negotiate_flags = &negotiate_flags; - a.in.credentials = &credentials3; - a.out.credentials = &credentials3; - - status = dcerpc_netr_ServerAuthenticate2(p2, tmp_ctx, &a); - if (!NT_STATUS_IS_OK(status)) { - return status; + cli_credentials_set_netlogon_creds(s->credentials, s->creds); + talloc_free(s->pipe2); + + composite_done(c); +} + + +/* + initiate getting a schannel key using a netlogon challenge on a secondary pipe +*/ +struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx, + struct dcerpc_pipe *p, + struct cli_credentials *credentials) +{ + struct composite_context *c; + struct schannel_key_state *s; + struct composite_context *epm_map_req; + + c = talloc_zero(mem_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct schannel_key_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + c->event_ctx = p->conn->event_ctx; + + s->pipe = p; + s->credentials = credentials; + + s->creds = talloc(c, struct creds_CredentialState); + if (composite_nomem(s->creds, c)) return c; + + if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) { + s->negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + } else { + s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS; } - if (!creds_client_check(creds, a.out.credentials)) { - return NT_STATUS_UNSUCCESSFUL; + s->binding = talloc(c, struct dcerpc_binding); + if (composite_nomem(s->binding, c)) return c; + + *s->binding = *s->pipe->binding; + + epm_map_req = dcerpc_epm_map_binding_send(c, s->binding, + &dcerpc_table_netlogon, + s->pipe->conn->event_ctx); + if (composite_nomem(epm_map_req, c)) return c; + + composite_continue(c, epm_map_req, continue_epm_map_binding, c); + return c; +} + + +NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + + talloc_free(c); + return status; +} + + +struct auth_schannel_state { + struct dcerpc_pipe *pipe; + struct cli_credentials *credentials; + const struct dcerpc_interface_table *table; + uint8_t auth_level; +}; + + +static void continue_bind_auth(struct composite_context *ctx); + + +static void continue_schannel_key(struct composite_context *ctx) +{ + struct composite_context *auth_req; + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct auth_schannel_state *s = talloc_get_type(c->private_data, + struct auth_schannel_state); + + c->status = dcerpc_schannel_key_recv(ctx); + if (!composite_is_ok(c)) { + DEBUG(1, ("Failed to setup credentials for account %s: %s\n", + cli_credentials_get_username(s->credentials), nt_errstr(c->status))); + return; } - cli_credentials_set_netlogon_creds(credentials, creds); + auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, + DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level, + NULL); + if (composite_nomem(auth_req, c)) return; + + composite_continue(c, auth_req, continue_bind_auth, c); +} - /* - the schannel session key is now in creds.session_key - we no longer need the netlogon pipe open - */ - talloc_free(p2); +static void continue_bind_auth(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + + c->status = dcerpc_bind_auth_recv(ctx); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, + struct dcerpc_pipe *p, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials, + uint8_t auth_level) +{ + struct composite_context *c; + struct auth_schannel_state *s; + struct composite_context *schan_key_req; - return NT_STATUS_OK; + c = talloc_zero(tmp_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct auth_schannel_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + c->event_ctx = p->conn->event_ctx; + + s->pipe = p; + s->credentials = credentials; + s->table = table; + s->auth_level = auth_level; + + schan_key_req = dcerpc_schannel_key_send(c, p, credentials); + if (composite_nomem(schan_key_req, c)) return c; + + composite_continue(c, schan_key_req, continue_schannel_key, c); + return c; +} + + +NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + + talloc_free(c); + return status; } + NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, struct dcerpc_pipe *p, const struct dcerpc_interface_table *table, struct cli_credentials *credentials, uint8_t auth_level) { - NTSTATUS status; - - /* Fills in NETLOGON credentials */ - status = dcerpc_schannel_key(tmp_ctx, - p, credentials); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to setup credentials for account %s: %s\n", - cli_credentials_get_username(credentials), - nt_errstr(status))); - return status; - } + struct composite_context *c; - return dcerpc_bind_auth(p, table, credentials, - DCERPC_AUTH_TYPE_SCHANNEL, auth_level, - NULL); + c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, + auth_level); + return dcerpc_bind_auth_schannel_recv(c); } - diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 41121889e0..d314a3b3de 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -23,6 +23,7 @@ */ #include "includes.h" +#include "libcli/composite/composite.h" #include "librpc/gen_ndr/ndr_epmapper.h" #include "librpc/gen_ndr/ndr_dcerpc.h" #include "librpc/gen_ndr/ndr_misc.h" @@ -757,14 +758,182 @@ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding * return NT_STATUS_OK; } + +struct epm_map_binding_state { + struct dcerpc_binding *binding; + const struct dcerpc_interface_table *table; + struct dcerpc_pipe *pipe; + struct epm_twr_t twr; + struct epm_twr_t *twr_r; + struct epm_Map r; +}; + + +static void continue_epm_recv_binding(struct composite_context *ctx); +static void continue_epm_map(struct rpc_request *req); + + +static void continue_epm_recv_binding(struct composite_context *ctx) +{ + struct policy_handle handle; + struct GUID guid; + struct rpc_request *map_req; + + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + struct epm_map_binding_state *s = talloc_get_type(c->private_data, + struct epm_map_binding_state); + + c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe); + if (!composite_is_ok(c)) return; + + ZERO_STRUCT(handle); + ZERO_STRUCT(guid); + + s->binding->object = s->table->uuid; + s->binding->object_version = s->table->if_version; + + c->status = dcerpc_binding_build_tower(s->pipe, s->binding, &s->twr.tower); + if (!composite_is_ok(c)) return; + + /* with some nice pretty paper around it of course */ + s->r.in.object = &guid; + s->r.in.map_tower = &s->twr; + s->r.in.entry_handle = &handle; + s->r.in.max_towers = 1; + s->r.out.entry_handle = &handle; + + map_req = dcerpc_epm_Map_send(s->pipe, c, &s->r); + if (composite_nomem(map_req, c)) return; + + composite_continue_rpc(c, map_req, continue_epm_map, c); +} + + +static void continue_epm_map(struct rpc_request *req) +{ + struct composite_context *c = talloc_get_type(req->async.private, + struct composite_context); + struct epm_map_binding_state *s = talloc_get_type(c->private_data, + struct epm_map_binding_state); + + c->status = dcerpc_ndr_request_recv(req); + if (!composite_is_ok(c)) return; + + if (s->r.out.result != 0 || s->r.out.num_towers != 1) { + composite_error(c, NT_STATUS_PORT_UNREACHABLE); + return; + } + + s->twr_r = s->r.out.towers[0].twr; + if (s->twr_r == NULL) { + composite_error(c, NT_STATUS_PORT_UNREACHABLE); + return; + } + + if (s->twr_r->tower.num_floors != s->twr.tower.num_floors || + s->twr_r->tower.floors[3].lhs.protocol != s->twr.tower.floors[3].lhs.protocol) { + composite_error(c, NT_STATUS_PORT_UNREACHABLE); + return; + } + + s->binding->endpoint = talloc_reference(s->binding, + dcerpc_floor_get_rhs_data(c, &s->twr_r->tower.floors[3])); + composite_done(c); +} + + +struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx, + struct dcerpc_binding *binding, + const struct dcerpc_interface_table *table, + struct event_context *ev) +{ + struct composite_context *c; + struct epm_map_binding_state *s; + struct composite_context *pipe_connect_req; + + NTSTATUS status; + struct dcerpc_binding *epmapper_binding; + int i; + + /* composite context allocation and setup */ + c = talloc_zero(mem_ctx, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct epm_map_binding_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + c->event_ctx = ev; + + s->binding = binding; + s->table = table; + + struct cli_credentials *anon_creds = cli_credentials_init(mem_ctx); + cli_credentials_set_conf(anon_creds); + cli_credentials_set_anonymous(anon_creds); + + /* First, check if there is a default endpoint specified in the IDL */ + + if (table) { + struct dcerpc_binding *default_binding; + + /* Find one of the default pipes for this interface */ + for (i = 0; i < table->endpoints->count; i++) { + status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding); + + if (NT_STATUS_IS_OK(status)) { + if (default_binding->transport == binding->transport && default_binding->endpoint) { + binding->endpoint = talloc_reference(binding, default_binding->endpoint); + talloc_free(default_binding); + + composite_done(c); + return c; + + } else { + talloc_free(default_binding); + } + } + } + } + + epmapper_binding = talloc_zero(c, struct dcerpc_binding); + if (composite_nomem(epmapper_binding, c)) return c; + + epmapper_binding->transport = binding->transport; + epmapper_binding->host = talloc_reference(epmapper_binding, binding->host); + epmapper_binding->options = NULL; + epmapper_binding->flags = 0; + epmapper_binding->endpoint = NULL; + + pipe_connect_req = dcerpc_pipe_connect_b_send(c, &s->pipe, epmapper_binding, &dcerpc_table_epmapper, + anon_creds, ev); + if (composite_nomem(pipe_connect_req, c)) return c; + + composite_continue(c, pipe_connect_req, continue_epm_recv_binding, c); + return c; +} + + +NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c) +{ + NTSTATUS status = composite_wait(c); + + talloc_free(c); + return status; +} + + + NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, const struct dcerpc_interface_table *table, struct event_context *ev) { struct dcerpc_pipe *p; NTSTATUS status; - struct epm_Map r; struct policy_handle handle; struct GUID guid; + struct epm_Map r; struct epm_twr_t twr, *twr_r; struct dcerpc_binding *epmapper_binding; int i; @@ -865,6 +1034,175 @@ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *bind } +struct pipe_auth_state { + struct dcerpc_pipe *pipe; + struct dcerpc_binding *binding; + const struct dcerpc_interface_table *table; + struct cli_credentials *credentials; +}; + + +static void continue_auth_schannel(struct composite_context *ctx); +static void continue_auth(struct composite_context *ctx); +static void continue_auth_none(struct composite_context *ctx); + + +static void continue_auth_schannel(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + + c->status = dcerpc_bind_auth_schannel_recv(ctx); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +static void continue_auth(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + + c->status = dcerpc_bind_auth_recv(ctx); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +static void continue_auth_none(struct composite_context *ctx) +{ + struct composite_context *c = talloc_get_type(ctx->async.private_data, + struct composite_context); + + c->status = dcerpc_bind_auth_none_recv(ctx); + if (!composite_is_ok(c)) return; + + composite_done(c); +} + + +struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, + struct dcerpc_binding *binding, + const struct dcerpc_interface_table *table, + struct cli_credentials *credentials) +{ + struct composite_context *c; + struct pipe_auth_state *s; + struct composite_context *auth_schannel_req; + struct composite_context *auth_req; + struct composite_context *auth_none_req; + + /* composite context allocation and setup */ + c = talloc_zero(NULL, struct composite_context); + if (c == NULL) return NULL; + + s = talloc_zero(c, struct pipe_auth_state); + if (composite_nomem(s, c)) return c; + + c->state = COMPOSITE_STATE_IN_PROGRESS; + c->private_data = s; + c->event_ctx = p->conn->event_ctx; + + s->binding = binding; + s->table = table; + s->credentials = credentials; + s->pipe = p; + + s->pipe->conn->flags = binding->flags; + + /* remember the binding string for possible secondary connections */ + s->pipe->conn->binding_string = dcerpc_binding_string(p, binding); + + if (!cli_credentials_is_anonymous(s->credentials) && + (binding->flags & DCERPC_SCHANNEL) && + !cli_credentials_get_netlogon_creds(s->credentials)) { + + /* If we don't already have netlogon credentials for + * the schannel bind, then we have to get these + * first */ + auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table, + s->credentials, + dcerpc_auth_level(s->pipe->conn)); + if (composite_nomem(auth_schannel_req, c)) return c; + + composite_continue(c, auth_schannel_req, continue_auth_schannel, c); + + } else if (!cli_credentials_is_anonymous(s->credentials) && + !(s->pipe->conn->transport.transport == NCACN_NP && + !(s->binding->flags & DCERPC_SIGN) && + !(s->binding->flags & DCERPC_SEAL))) { + + /* Perform an authenticated DCE-RPC bind, except where + * we ask for a connection on NCACN_NP, and that + * connection is not signed or sealed. For that case + * we rely on the already authenticated CIFS connection + */ + + uint8_t auth_type; + + if ((s->pipe->conn->flags & (DCERPC_SIGN|DCERPC_SEAL)) == 0) { + /* + we are doing an authenticated connection, + but not using sign or seal. We must force + the CONNECT dcerpc auth type as a NONE auth + type doesn't allow authentication + information to be passed. + */ + s->pipe->conn->flags |= DCERPC_CONNECT; + } + + if (s->binding->flags & DCERPC_AUTH_SPNEGO) { + auth_type = DCERPC_AUTH_TYPE_SPNEGO; + + } else if (s->binding->flags & DCERPC_AUTH_KRB5) { + auth_type = DCERPC_AUTH_TYPE_KRB5; + + } else if (s->binding->flags & DCERPC_SCHANNEL) { + auth_type = DCERPC_AUTH_TYPE_SCHANNEL; + + } else { + auth_type = DCERPC_AUTH_TYPE_NTLMSSP; + } + + auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, + s->credentials, auth_type, + dcerpc_auth_level(s->pipe->conn), + s->table->authservices->names[0]); + if (composite_nomem(auth_req, c)) return c; + + composite_continue(c, auth_req, continue_auth, c); + + } else { + auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table); + if (composite_nomem(auth_none_req, c)) return c; + + composite_continue(c, auth_none_req, continue_auth_none, c); + } + + return c; +} + + +NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c) +{ + NTSTATUS status; + + struct pipe_auth_state *s = talloc_get_type(c->private_data, + struct pipe_auth_state); + status = composite_wait(c); + if (!NT_STATUS_IS_OK(status)) { + char *uuid_str = GUID_string(s->pipe, &s->table->uuid); + DEBUG(0, ("Failed to bind to uuid %s - %s\n", uuid_str, nt_errstr(status))); + talloc_free(uuid_str); + } + + talloc_free(c); + return status; +} + + /* perform an authenticated bind if needed */ @@ -943,205 +1281,6 @@ NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, } -/* open a rpc connection to a rpc pipe on SMB using the binding - structure to determine the endpoint and options */ -static NTSTATUS dcerpc_pipe_connect_ncacn_np(TALLOC_CTX *tmp_ctx, - struct dcerpc_pipe_connect *io) -{ - if (io->binding->flags & DCERPC_SMB2) { - return dcerpc_pipe_connect_ncacn_np_smb2(tmp_ctx, io); - - } - return dcerpc_pipe_connect_ncacn_np_smb(tmp_ctx, io); -} - - -/* open a rpc connection to a rpc pipe, using the specified - binding structure to determine the endpoint and options */ -NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx, - struct dcerpc_pipe **pp, - struct dcerpc_binding *binding, - const struct dcerpc_interface_table *table, - struct cli_credentials *credentials, - struct event_context *ev) -{ - NTSTATUS status = NT_STATUS_INVALID_PARAMETER; - struct dcerpc_pipe *p; - struct dcerpc_pipe_connect pc; - - TALLOC_CTX *tmp_ctx; - - (*pp) = NULL; - - p = dcerpc_pipe_init(parent_ctx, ev); - if (p == NULL) { - return NT_STATUS_NO_MEMORY; - } - tmp_ctx = talloc_named(p, 0, "dcerpc_pipe_connect_b tmp_ctx"); - - switch (binding->transport) { - case NCACN_NP: - case NCACN_IP_TCP: - case NCALRPC: - if (!binding->endpoint) { - status = dcerpc_epm_map_binding(tmp_ctx, binding, table, - p->conn->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to map DCERPC endpoint for '%s' - %s\n", - GUID_string(tmp_ctx, &table->uuid), nt_errstr(status))); - talloc_free(tmp_ctx); - return status; - } - DEBUG(2,("Mapped to DCERPC endpoint %s\n", binding->endpoint)); - } - break; - - /* Fall through to next switch statement */ - - default: - break; - } - - pc.pipe = p; - pc.binding = binding; - pc.interface = table; - pc.creds = credentials; - - switch (binding->transport) { - case NCACN_NP: - status = dcerpc_pipe_connect_ncacn_np(tmp_ctx, &pc); - break; - - case NCACN_IP_TCP: - status = dcerpc_pipe_connect_ncacn_ip_tcp(tmp_ctx, &pc); - break; - - case NCACN_UNIX_STREAM: - status = dcerpc_pipe_connect_ncacn_unix_stream(tmp_ctx, &pc); - break; - - case NCALRPC: - status = dcerpc_pipe_connect_ncalrpc(tmp_ctx, &pc); - break; - - default: - return NT_STATUS_NOT_SUPPORTED; - } - - if (!NT_STATUS_IS_OK(status)) { - talloc_free(p); - return status; - } - - p->binding = binding; - if (!talloc_reference(p, binding)) { - return NT_STATUS_NO_MEMORY; - } - - status = dcerpc_pipe_auth(p, binding, table, credentials); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(p); - return status; - } - *pp = p; - talloc_free(tmp_ctx); - - 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(TALLOC_CTX *parent_ctx, - struct dcerpc_pipe **pp, - const char *binding, - const struct dcerpc_interface_table *table, - struct cli_credentials *credentials, - struct event_context *ev) -{ - struct dcerpc_binding *b; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_named(parent_ctx, 0, "dcerpc_pipe_connect tmp_ctx"); - if (!tmp_ctx) { - return NT_STATUS_NO_MEMORY; - } - - status = dcerpc_parse_binding(tmp_ctx, binding, &b); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding)); - talloc_free(tmp_ctx); - return status; - } - - DEBUG(3,("Using binding %s\n", dcerpc_binding_string(tmp_ctx, b))); - - status = dcerpc_pipe_connect_b(tmp_ctx, pp, b, table, credentials, ev); - - if (NT_STATUS_IS_OK(status)) { - *pp = talloc_steal(parent_ctx, *pp); - } - talloc_free(tmp_ctx); - - return status; -} - - -/* - create a secondary dcerpc connection from a primary connection - - if the primary is a SMB connection then the secondary connection - will be on the same SMB connection, but use a new fnum -*/ -NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe **p2, - struct dcerpc_binding *b) - - -{ - struct smbcli_tree *tree; - NTSTATUS status = NT_STATUS_INVALID_PARAMETER; - - (*p2) = dcerpc_pipe_init(p, p->conn->event_ctx); - if (*p2 == NULL) { - return NT_STATUS_NO_MEMORY; - } - - switch (p->conn->transport.transport) { - case NCACN_NP: - tree = dcerpc_smb_tree(p->conn); - if (!tree) { - return NT_STATUS_INVALID_PARAMETER; - } - status = dcerpc_pipe_open_smb((*p2)->conn, tree, b->endpoint); - break; - - case NCACN_IP_TCP: - status = dcerpc_pipe_open_tcp((*p2)->conn, b->host, atoi(b->endpoint)); - break; - - case NCALRPC: - status = dcerpc_pipe_open_pipe((*p2)->conn, b->endpoint); - break; - - default: - return NT_STATUS_NOT_SUPPORTED; - } - - if (!NT_STATUS_IS_OK(status)) { - talloc_free(*p2); - return status; - } - - (*p2)->conn->flags = p->conn->flags; - (*p2)->binding = b; - if (!talloc_reference(*p2, b)) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key) { |