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.c120
-rw-r--r--source4/torture/rpc/bind.c2
5 files changed, 80 insertions, 109 deletions
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c
index fb28eaed2f..608568bc53 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(tmp_ctx, &samr_pipe,
+ status = dcerpc_pipe_auth(&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 cd33d3d14b..adf67a7ba1 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -490,6 +490,20 @@ 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)
@@ -555,27 +569,19 @@ static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NT
dcerpc_connection_dead(conn, status);
}
- 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;
-
- 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;
+ 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;
+ }
+
+ /* assume its an ordinary request */
+ dcerpc_request_recv_data(conn, blob, &pkt);
}
@@ -591,6 +597,13 @@ 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));
@@ -1528,6 +1541,13 @@ 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 d69db51eb4..66b0af178b 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(ctx, s, &s->pipe);
+ c->status = dcerpc_pipe_auth_recv(s, &s->pipe);
if (!composite_is_ok(c)) return;
composite_done(c);
@@ -1170,7 +1170,8 @@ 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)) {
- *p2 = talloc_steal(s->pipe, s->pipe2);
+ talloc_steal(s->pipe, s->pipe2);
+ *p2 = s->pipe2;
}
talloc_free(c);
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 6c8ed7ecd8..158c5e3fe0 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -976,14 +976,12 @@ struct pipe_auth_state {
struct dcerpc_binding *binding;
const struct dcerpc_interface_table *table;
struct cli_credentials *credentials;
+ uint8_t next_auth_type;
+ BOOL try_ntlm_fallback;
};
-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);
+static void continue_new_auth_bind(struct composite_context *ctx);
/*
@@ -1002,52 +1000,44 @@ 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_auth_auto(struct composite_context *ctx)
+static void continue_recv_bind(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);
- 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);
+ status = dcerpc_bind_auth_recv(ctx);
+ if (s->try_ntlm_fallback && NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
struct composite_context *sec_conn_req;
-
+ s->try_ntlm_fallback = False;
+ s->next_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_ntlmssp_connection, c);
+ composite_continue(c, sec_conn_req, continue_new_auth_bind, c);
return;
- } 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);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
struct composite_context *sec_conn_req;
if (cli_credentials_wrong_password(s->credentials)) {
+ s->next_auth_type = DCERPC_AUTH_TYPE_SPNEGO;
/* 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_spnego_after_wrong_pass, c);
+ composite_continue(c, sec_conn_req, continue_new_auth_bind, c);
+
+ return;
}
}
+ c->status = status;
if (!composite_is_ok(c)) return;
@@ -1055,44 +1045,14 @@ static void continue_auth_auto(struct composite_context *ctx)
}
/*
- 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;
+ 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
- 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
+ Calls back to stage 2 to process the response.
*/
-static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
+static void continue_new_auth_bind(struct composite_context *ctx)
{
struct composite_context *c;
struct pipe_auth_state *s;
@@ -1104,27 +1064,25 @@ static void continue_spnego_after_wrong_pass(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, DCERPC_AUTH_TYPE_SPNEGO,
+ s->credentials, s->next_auth_type,
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);
+ composite_continue(c, auth_req, continue_recv_bind, c);
}
/*
Stage 2 of pipe_auth: Receive result of non-authenticated bind request
*/
-static void continue_auth_none(struct composite_context *ctx)
+static void continue_auth_recv_none(struct composite_context *ctx)
{
struct composite_context *c = talloc_get_type(ctx->async.private_data,
struct composite_context);
@@ -1225,29 +1183,23 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
} else if (s->binding->flags & DCERPC_AUTH_NTLM) {
auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
} else {
- 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_type = DCERPC_AUTH_TYPE_SPNEGO;
+ s->try_ntlm_fallback = True;
}
-
+
auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
- s->credentials, auth_type,
+ 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, c);
+ composite_continue(c, auth_req, continue_recv_bind, 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);
+ composite_continue(c, auth_none_req, continue_auth_recv_none, c);
}
return c;
@@ -1261,7 +1213,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, TALLOC_CTX *mem_ctx,
+NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c,
struct dcerpc_pipe **p)
{
NTSTATUS status;
@@ -1274,7 +1226,6 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
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;
}
@@ -1288,8 +1239,7 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
This may change *p, as it rebinds to a new pipe due to authentication fallback
*/
-NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
- struct dcerpc_pipe **p,
+NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe **p,
struct dcerpc_binding *binding,
const struct dcerpc_interface_table *table,
struct cli_credentials *credentials)
@@ -1297,7 +1247,7 @@ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
struct composite_context *c;
c = dcerpc_pipe_auth_send(*p, binding, table, credentials);
- return dcerpc_pipe_auth_recv(c, mem_ctx, p);
+ return dcerpc_pipe_auth_recv(c, p);
}
diff --git a/source4/torture/rpc/bind.c b/source4/torture/rpc/bind.c
index 17580737f8..9467ad3d38 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(mem_ctx, &p, binding, &dcerpc_table_lsarpc, cmdline_credentials);
+ status = dcerpc_pipe_auth(&p, binding, &dcerpc_table_lsarpc, cmdline_credentials);
if (NT_STATUS_IS_OK(status)) {
printf("(incorrectly) allowed re-bind to uuid %s - %s\n",