diff options
-rw-r--r-- | source4/libnet/libnet_join.c | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 60 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_connect.c | 5 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 131 | ||||
-rw-r--r-- | source4/torture/rpc/bind.c | 2 |
5 files changed, 115 insertions, 85 deletions
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c index 608568bc53..fb28eaed2f 100644 --- a/source4/libnet/libnet_join.c +++ b/source4/libnet/libnet_join.c @@ -482,7 +482,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru samr_pipe = connect_with_info->out.dcerpc_pipe; - status = dcerpc_pipe_auth(&samr_pipe, + status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe, connect_with_info->out.dcerpc_pipe->binding, &dcerpc_table_samr, ctx->cred); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index adf67a7ba1..cd33d3d14b 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -490,20 +490,6 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason) } /* - map a fault reason to a NTSTATUS -*/ -static NTSTATUS dcerpc_map_fault(uint32_t status) -{ - switch (status) { - case DCERPC_FAULT_OP_RNG_ERROR: - return NT_STATUS_ILLEGAL_FUNCTION; - case DCERPC_FAULT_ACCESS_DENIED: - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_NET_WRITE_FAULT; -} - -/* mark the dcerpc connection dead. All outstanding requests get an error */ static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status) @@ -569,19 +555,27 @@ static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NT dcerpc_connection_dead(conn, status); } - if (conn->bind_private) { - talloc_steal(conn->bind_private, blob->data); - dcerpc_bind_recv_data(conn, &pkt); - return; - } - if (conn->alter_private) { - talloc_steal(conn->alter_private, blob->data); - dcerpc_alter_recv_data(conn, &pkt); - return; - } + switch (pkt.ptype) { + case DCERPC_PKT_BIND_NAK: + case DCERPC_PKT_BIND_ACK: + if (conn->bind_private) { + talloc_steal(conn->bind_private, blob->data); + dcerpc_bind_recv_data(conn, &pkt); + } + break; - /* assume its an ordinary request */ - dcerpc_request_recv_data(conn, blob, &pkt); + case DCERPC_PKT_ALTER_RESP: + if (conn->alter_private) { + talloc_steal(conn->alter_private, blob->data); + dcerpc_alter_recv_data(conn, &pkt); + } + break; + + default: + /* assume its an ordinary request */ + dcerpc_request_recv_data(conn, blob, &pkt); + break; + } } @@ -597,13 +591,6 @@ static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_p /* mark the connection as not waiting for a bind reply */ conn->bind_private = NULL; - if (pkt->ptype == DCERPC_PKT_FAULT) { - DEBUG(2,("dcerpc: bind faulted: reason %s\n", - dcerpc_errstr(c, pkt->u.fault.status))); - composite_error(c, dcerpc_map_fault(pkt->u.fault.status)); - return; - } - if (pkt->ptype == DCERPC_PKT_BIND_NAK) { DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt->u.bind_nak.reject_reason)); @@ -1541,13 +1528,6 @@ static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_ /* mark the connection as not waiting for a alter context reply */ conn->alter_private = NULL; - if (pkt->ptype == DCERPC_PKT_FAULT) { - DEBUG(2,("dcerpc: alter context faulted: reason %s\n", - dcerpc_errstr(c, pkt->u.fault.status))); - composite_error(c, dcerpc_map_fault(pkt->u.fault.status)); - return; - } - if (pkt->ptype == DCERPC_PKT_ALTER_RESP && pkt->u.alter_resp.num_results == 1 && pkt->u.alter_resp.ctx_list[0].result != 0) { diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index 66b0af178b..d69db51eb4 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -764,7 +764,7 @@ static void continue_pipe_auth(struct composite_context *ctx) struct composite_context); struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state); - c->status = dcerpc_pipe_auth_recv(s, &s->pipe); + c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe); if (!composite_is_ok(c)) return; composite_done(c); @@ -1170,8 +1170,7 @@ NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c, s = talloc_get_type(c->private_data, struct sec_conn_state); if (NT_STATUS_IS_OK(status)) { - talloc_steal(s->pipe, s->pipe2); - *p2 = s->pipe2; + *p2 = talloc_steal(s->pipe, s->pipe2); } talloc_free(c); diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 5b341b9359..6c8ed7ecd8 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -976,12 +976,14 @@ struct pipe_auth_state { struct dcerpc_binding *binding; const struct dcerpc_interface_table *table; struct cli_credentials *credentials; - uint8_t auth_type; - BOOL try_ntlm_fallback; }; -static void continue_new_auth_bind(struct composite_context *ctx); +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_ntlmssp_connection(struct composite_context *ctx); +static void continue_spnego_after_wrong_pass(struct composite_context *ctx); /* @@ -1000,32 +1002,42 @@ static void continue_auth_schannel(struct composite_context *ctx) /* + Stage 2 of pipe_auth: Receive result of authenticated bind request +*/ +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); +} +/* Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks: SPNEGO -> NTLMSSP */ -static void continue_recv_bind(struct composite_context *ctx) +static void continue_auth_auto(struct composite_context *ctx) { - NTSTATUS status; struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); - struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state); - status = dcerpc_bind_auth_recv(ctx); - if (s->auth_type == DCERPC_AUTH_TYPE_SPNEGO - && s->try_ntlm_fallback - && NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + c->status = dcerpc_bind_auth_recv(ctx); + if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) { + struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state); struct composite_context *sec_conn_req; - s->try_ntlm_fallback = False; - s->auth_type = DCERPC_AUTH_TYPE_NTLMSSP; + /* send a request for secondary rpc connection */ sec_conn_req = dcerpc_secondary_connection_send(s->pipe, s->binding); if (composite_nomem(sec_conn_req, c)) return; - composite_continue(c, sec_conn_req, continue_new_auth_bind, c); + composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c); return; - } else if (s->auth_type == DCERPC_AUTH_TYPE_SPNEGO && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) { + struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state); struct composite_context *sec_conn_req; if (cli_credentials_wrong_password(s->credentials)) { /* send a request for secondary rpc connection */ @@ -1033,12 +1045,9 @@ static void continue_recv_bind(struct composite_context *ctx) s->binding); if (composite_nomem(sec_conn_req, c)) return; - composite_continue(c, sec_conn_req, continue_new_auth_bind, c); - - return; + composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c); } } - c->status = status; if (!composite_is_ok(c)) return; @@ -1046,14 +1055,44 @@ static void continue_recv_bind(struct composite_context *ctx) } /* - Stage 3 of pipe_auth (fallback to NTLMSSP case/SPNEGO password retry case): - - Receive secondary rpc connection (the first one can't be used any - more, due to the bind nak) and perform authenticated bind request + Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary + rpc connection (the first one can't be used any more, due to the + bind nak) and perform authenticated bind request +*/ +static void continue_ntlmssp_connection(struct composite_context *ctx) +{ + struct composite_context *c; + struct pipe_auth_state *s; + struct composite_context *auth_req; + struct dcerpc_pipe *p2; + + c = talloc_get_type(ctx->async.private_data, struct composite_context); + s = talloc_get_type(c->private_data, struct pipe_auth_state); + + /* receive secondary rpc connection */ + c->status = dcerpc_secondary_connection_recv(ctx, &p2); + talloc_steal(s, p2); + talloc_steal(p2, s->pipe); + s->pipe = p2; - Calls back to stage 2 to process the response. + if (!composite_is_ok(c)) return; + + /* initiate a authenticated bind */ + auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, + s->credentials, DCERPC_AUTH_TYPE_NTLMSSP, + dcerpc_auth_level(s->pipe->conn), + s->table->authservices->names[0]); + if (composite_nomem(auth_req, c)) return; + + composite_continue(c, auth_req, continue_auth, c); +} + +/* + Stage 3 of pipe_auth (retry on wrong password): Receive secondary + rpc connection (the first one can't be used any more, due to the + bind nak) and perform authenticated bind request */ -static void continue_new_auth_bind(struct composite_context *ctx) +static void continue_spnego_after_wrong_pass(struct composite_context *ctx) { struct composite_context *c; struct pipe_auth_state *s; @@ -1065,25 +1104,27 @@ static void continue_new_auth_bind(struct composite_context *ctx) /* receive secondary rpc connection */ c->status = dcerpc_secondary_connection_recv(ctx, &p2); + talloc_steal(s, p2); + talloc_steal(p2, s->pipe); s->pipe = p2; if (!composite_is_ok(c)) return; /* initiate a authenticated bind */ auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, - s->credentials, s->auth_type, + s->credentials, DCERPC_AUTH_TYPE_SPNEGO, dcerpc_auth_level(s->pipe->conn), s->table->authservices->names[0]); if (composite_nomem(auth_req, c)) return; - composite_continue(c, auth_req, continue_recv_bind, c); + composite_continue(c, auth_req, continue_auth, c); } /* Stage 2 of pipe_auth: Receive result of non-authenticated bind request */ -static void continue_auth_recv_none(struct composite_context *ctx) +static void continue_auth_none(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); @@ -1158,6 +1199,8 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, * connection is not signed or sealed. For that case * we rely on the already authenticated CIFS connection */ + + uint8_t auth_type; if ((conn->flags & (DCERPC_SIGN|DCERPC_SEAL)) == 0) { /* @@ -1171,34 +1214,40 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, } if (s->binding->flags & DCERPC_AUTH_SPNEGO) { - s->auth_type = DCERPC_AUTH_TYPE_SPNEGO; + auth_type = DCERPC_AUTH_TYPE_SPNEGO; } else if (s->binding->flags & DCERPC_AUTH_KRB5) { - s->auth_type = DCERPC_AUTH_TYPE_KRB5; + auth_type = DCERPC_AUTH_TYPE_KRB5; } else if (s->binding->flags & DCERPC_SCHANNEL) { - s->auth_type = DCERPC_AUTH_TYPE_SCHANNEL; + auth_type = DCERPC_AUTH_TYPE_SCHANNEL; } else if (s->binding->flags & DCERPC_AUTH_NTLM) { - s->auth_type = DCERPC_AUTH_TYPE_NTLMSSP; + auth_type = DCERPC_AUTH_TYPE_NTLMSSP; } else { - s->auth_type = DCERPC_AUTH_TYPE_SPNEGO; - s->try_ntlm_fallback = True; + auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, + s->credentials, DCERPC_AUTH_TYPE_SPNEGO, + dcerpc_auth_level(conn), + s->table->authservices->names[0]); + if (composite_nomem(auth_req, c)) return c; + + composite_continue(c, auth_req, continue_auth_auto, c); + return c; } - + auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, - s->credentials, s->auth_type, + s->credentials, auth_type, dcerpc_auth_level(conn), s->table->authservices->names[0]); if (composite_nomem(auth_req, c)) return c; - composite_continue(c, auth_req, continue_recv_bind, 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_recv_none, c); + composite_continue(c, auth_none_req, continue_auth_none, c); } return c; @@ -1212,7 +1261,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, supllied, as it rebinds to a new pipe due to authentication fallback */ -NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, +NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct dcerpc_pipe **p) { NTSTATUS status; @@ -1225,6 +1274,7 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, DEBUG(0, ("Failed to bind to uuid %s - %s\n", uuid_str, nt_errstr(status))); talloc_free(uuid_str); } else { + talloc_steal(mem_ctx, s->pipe); *p = s->pipe; } @@ -1238,7 +1288,8 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, This may change *p, as it rebinds to a new pipe due to authentication fallback */ -NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe **p, +NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx, + struct dcerpc_pipe **p, struct dcerpc_binding *binding, const struct dcerpc_interface_table *table, struct cli_credentials *credentials) @@ -1246,7 +1297,7 @@ NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe **p, struct composite_context *c; c = dcerpc_pipe_auth_send(*p, binding, table, credentials); - return dcerpc_pipe_auth_recv(c, p); + return dcerpc_pipe_auth_recv(c, mem_ctx, p); } diff --git a/source4/torture/rpc/bind.c b/source4/torture/rpc/bind.c index 9467ad3d38..17580737f8 100644 --- a/source4/torture/rpc/bind.c +++ b/source4/torture/rpc/bind.c @@ -63,7 +63,7 @@ BOOL torture_multi_bind(struct torture_context *torture) return False; } - status = dcerpc_pipe_auth(&p, binding, &dcerpc_table_lsarpc, cmdline_credentials); + status = dcerpc_pipe_auth(mem_ctx, &p, binding, &dcerpc_table_lsarpc, cmdline_credentials); if (NT_STATUS_IS_OK(status)) { printf("(incorrectly) allowed re-bind to uuid %s - %s\n", |