summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libnet/libnet_join.c2
-rw-r--r--source4/librpc/rpc/dcerpc.c60
-rw-r--r--source4/librpc/rpc/dcerpc_connect.c5
-rw-r--r--source4/librpc/rpc/dcerpc_util.c131
-rw-r--r--source4/torture/rpc/bind.c2
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",