summaryrefslogtreecommitdiff
path: root/source4/librpc/rpc/dcerpc_util.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2006-05-04 10:03:41 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:05:36 -0500
commit5f4d86f955d939e96ec9b81c8a9d080aab4354b6 (patch)
treeb785a6c2aa092fea9bd64391cc45915788b31692 /source4/librpc/rpc/dcerpc_util.c
parent086c9cc5f4a9145ee93060db2eebb3badc325e44 (diff)
downloadsamba-5f4d86f955d939e96ec9b81c8a9d080aab4354b6.tar.gz
samba-5f4d86f955d939e96ec9b81c8a9d080aab4354b6.tar.bz2
samba-5f4d86f955d939e96ec9b81c8a9d080aab4354b6.zip
r15426: Implement SPNEGO as the default RPC authentication mechanism. Where
this isn't supported, fallback to NTLM. Also, where we get a failure as 'logon failure', try and do a '3 tries' for the password, like we already do for CIFS. (Incomplete: needs a mapping between RPC errors and the logon failure NTSTATUS). Because we don't yet support Kerberos sign/seal to win2k3 SP1 for DCE/RPC, disable this (causing SPNEGO to negotiate NTLM) when kerberos isn't demanded. Andrew Bartlett (This used to be commit b3212d1fb91b26c1d326a289560106dffe1d2e80)
Diffstat (limited to 'source4/librpc/rpc/dcerpc_util.c')
-rw-r--r--source4/librpc/rpc/dcerpc_util.c156
1 files changed, 143 insertions, 13 deletions
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index dc2eded967..6c8ed7ecd8 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -141,6 +141,7 @@ static const struct {
{"seal", DCERPC_SEAL},
{"connect", DCERPC_CONNECT},
{"spnego", DCERPC_AUTH_SPNEGO},
+ {"ntlm", DCERPC_AUTH_NTLM},
{"krb5", DCERPC_AUTH_KRB5},
{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
{"print", DCERPC_DEBUG_PRINT_BOTH},
@@ -936,7 +937,7 @@ struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
epmapper_binding->endpoint = NULL;
/* initiate rpc pipe connection */
- pipe_connect_req = dcerpc_pipe_connect_b_send(c, &s->pipe, epmapper_binding, &dcerpc_table_epmapper,
+ pipe_connect_req = dcerpc_pipe_connect_b_send(c, epmapper_binding, &dcerpc_table_epmapper,
anon_creds, c->event_ctx);
if (composite_nomem(pipe_connect_req, c)) return c;
@@ -981,6 +982,8 @@ struct pipe_auth_state {
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);
/*
@@ -1011,6 +1014,111 @@ static void continue_auth(struct composite_context *ctx)
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)
+{
+ struct composite_context *c = talloc_get_type(ctx->async.private_data,
+ struct composite_context);
+
+ 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;
+
+ /* 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);
+
+ 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);
+ struct composite_context *sec_conn_req;
+ if (cli_credentials_wrong_password(s->credentials)) {
+ /* 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);
+ }
+ }
+
+ if (!composite_is_ok(c)) return;
+
+ composite_done(c);
+}
+
+/*
+ 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;
+
+ 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_spnego_after_wrong_pass(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;
+
+ 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,
+ 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);
+}
/*
@@ -1042,6 +1150,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
struct composite_context *auth_schannel_req;
struct composite_context *auth_req;
struct composite_context *auth_none_req;
+ struct dcerpc_connection *conn;
/* composite context allocation and setup */
c = talloc_zero(NULL, struct composite_context);
@@ -1060,10 +1169,11 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
s->credentials = credentials;
s->pipe = p;
- s->pipe->conn->flags = binding->flags;
+ conn = s->pipe->conn;
+ conn->flags = binding->flags;
/* remember the binding string for possible secondary connections */
- s->pipe->conn->binding_string = dcerpc_binding_string(p, binding);
+ conn->binding_string = dcerpc_binding_string(p, binding);
if (!cli_credentials_is_anonymous(s->credentials) &&
(binding->flags & DCERPC_SCHANNEL) &&
@@ -1074,13 +1184,13 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
* first */
auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table,
s->credentials,
- dcerpc_auth_level(s->pipe->conn));
+ dcerpc_auth_level(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 &&
+ !(conn->transport.transport == NCACN_NP &&
!(s->binding->flags & DCERPC_SIGN) &&
!(s->binding->flags & DCERPC_SEAL))) {
@@ -1092,7 +1202,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
uint8_t auth_type;
- if ((s->pipe->conn->flags & (DCERPC_SIGN|DCERPC_SEAL)) == 0) {
+ if ((conn->flags & (DCERPC_SIGN|DCERPC_SEAL)) == 0) {
/*
we are doing an authenticated connection,
but not using sign or seal. We must force
@@ -1100,7 +1210,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
type doesn't allow authentication
information to be passed.
*/
- s->pipe->conn->flags |= DCERPC_CONNECT;
+ conn->flags |= DCERPC_CONNECT;
}
if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
@@ -1112,13 +1222,22 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
} else if (s->binding->flags & DCERPC_SCHANNEL) {
auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
- } else {
+ } 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_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
s->credentials, auth_type,
- dcerpc_auth_level(s->pipe->conn),
+ dcerpc_auth_level(conn),
s->table->authservices->names[0]);
if (composite_nomem(auth_req, c)) return c;
@@ -1137,8 +1256,13 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
/*
Receive result of authenticated bind request on dcerpc pipe
+
+ This returns *p, which may be different to the one originally
+ 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;
@@ -1149,6 +1273,9 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c)
char *uuid_str = GUID_string(s->pipe, &s->table->syntax_id.uuid);
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;
}
talloc_free(c);
@@ -1158,16 +1285,19 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c)
/*
Perform an authenticated bind if needed - sync version
+
+ 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)
{
struct composite_context *c;
- c = dcerpc_pipe_auth_send(p, binding, table, credentials);
- return dcerpc_pipe_auth_recv(c);
+ c = dcerpc_pipe_auth_send(*p, binding, table, credentials);
+ return dcerpc_pipe_auth_recv(c, mem_ctx, p);
}