From 5da3f75a5975c09dc1db0b1ad146acf1d5f3ae41 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 10 Jan 2005 07:14:12 +0000 Subject: r4627: - simplified the dcerpc auth code using a common function - added support for "spnego" in binding strings. This enables SPNEGO auth in the dcerpc client code, using as many allter_context calls as are needed To try SPNEGO do this: smbtorture ncacn_ip_tcp:SERVER[spnego,seal] -Uadministrator%password RPC-SAMR (This used to be commit 9c0a3423f03111c110d21c0d3910e16aa1a8bf87) --- source4/librpc/rpc/dcerpc.h | 8 ++- source4/librpc/rpc/dcerpc_auth.c | 61 ++++++++++---------- source4/librpc/rpc/dcerpc_ntlm.c | 6 +- source4/librpc/rpc/dcerpc_schannel.c | 4 +- source4/librpc/rpc/dcerpc_spnego.c | 25 ++++---- source4/librpc/rpc/dcerpc_util.c | 107 ++++++++++++++--------------------- 6 files changed, 93 insertions(+), 118 deletions(-) diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 40ac18d13c..289e17fb81 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -119,17 +119,21 @@ struct dcerpc_pipe { #define DCERPC_SCHANNEL_ANY (DCERPC_SCHANNEL_BDC| \ DCERPC_SCHANNEL_DOMAIN| \ DCERPC_SCHANNEL_WORKSTATION) -/* use a 128 bit session key */ -#define DCERPC_SCHANNEL_128 (1<<12) #define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL_ANY) +/* use a 128 bit session key */ +#define DCERPC_SCHANNEL_128 (1<<12) + /* check incoming pad bytes */ #define DCERPC_DEBUG_PAD_CHECK (1<<13) /* set LIBNDR_FLAG_REF_ALLOC flag when decoding NDR */ #define DCERPC_NDR_REF_ALLOC (1<<14) +/* enable spnego auth */ +#define DCERPC_AUTH_SPNEGO (1<<15) + /* this is used to find pointers to calls */ diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index 4ff8fe549e..228a99d5c5 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -30,45 +30,33 @@ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p, const char *uuid, uint_t version) { - TALLOC_CTX *mem_ctx; + TALLOC_CTX *tmp_ctx = talloc_new(p); NTSTATUS status; - mem_ctx = talloc_init("dcerpc_bind_auth_ntlm"); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - - status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version); - talloc_destroy(mem_ctx); + status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version); + talloc_free(tmp_ctx); return status; } -NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t auth_level, +/* + perform a multi-part authenticated bind +*/ +NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t auth_level, const char *uuid, uint_t version) { NTSTATUS status; - TALLOC_CTX *mem_ctx; + TALLOC_CTX *tmp_ctx = talloc_new(p); DATA_BLOB credentials; DATA_BLOB null_data_blob = data_blob(NULL, 0); - mem_ctx = talloc_init("dcerpc_bind_auth"); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - if (!p->conn->security_state.generic_state) { status = gensec_client_start(p, &p->conn->security_state.generic_state); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + if (!NT_STATUS_IS_OK(status)) goto done; status = gensec_start_mech_by_authtype(p->conn->security_state.generic_state, auth_type, auth_level); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } + if (!NT_STATUS_IS_OK(status)) goto done; } p->conn->security_state.auth_info = talloc(p, struct dcerpc_auth); @@ -84,34 +72,44 @@ NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut p->conn->security_state.auth_info->auth_context_id = random(); p->conn->security_state.auth_info->credentials = null_data_blob; - status = gensec_update(p->conn->security_state.generic_state, mem_ctx, + status = gensec_update(p->conn->security_state.generic_state, tmp_ctx, null_data_blob, &credentials); - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; } p->conn->security_state.auth_info->credentials = credentials; - status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version); + status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version); if (!NT_STATUS_IS_OK(status)) { goto done; } - status = gensec_update(p->conn->security_state.generic_state, mem_ctx, + status = gensec_update(p->conn->security_state.generic_state, tmp_ctx, p->conn->security_state.auth_info->credentials, &credentials); - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; } - p->conn->security_state.auth_info->credentials = credentials; - - status = dcerpc_auth3(p->conn, mem_ctx); + do { + p->conn->security_state.auth_info->credentials = credentials; + + if (auth_type == DCERPC_AUTH_TYPE_SPNEGO) { + status = dcerpc_alter_context(p, tmp_ctx, &p->syntax, &p->transfer_syntax); + if (NT_STATUS_IS_OK(status)) { + status = gensec_update(p->conn->security_state.generic_state, tmp_ctx, + p->conn->security_state.auth_info->credentials, + &credentials); + } + } else { + status = dcerpc_auth3(p->conn, tmp_ctx); + } + } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); + done: - talloc_destroy(mem_ctx); + talloc_free(tmp_ctx); if (!NT_STATUS_IS_OK(status)) { talloc_free(p->conn->security_state.generic_state); @@ -123,3 +121,4 @@ done: return status; } + diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c index 8a83cea144..39b5e1c28c 100644 --- a/source4/librpc/rpc/dcerpc_ntlm.c +++ b/source4/librpc/rpc/dcerpc_ntlm.c @@ -72,9 +72,9 @@ NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p, return status; } - status = dcerpc_bind_auth3(p, DCERPC_AUTH_TYPE_NTLMSSP, - dcerpc_auth_level(p->conn), - uuid, version); + status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_NTLMSSP, + dcerpc_auth_level(p->conn), + uuid, version); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("Failed to bind to pipe with NTLMSSP: %s\n", nt_errstr(status))); diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 10852159a8..0e218c478f 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -448,8 +448,8 @@ NTSTATUS dcerpc_bind_auth_schannel_withkey(struct dcerpc_pipe *p, dce_schan_state = p->conn->security_state.generic_state->private_data; dce_schan_state->creds = talloc_reference(dce_schan_state, creds); - status = dcerpc_bind_auth3(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p->conn), - uuid, version); + status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p->conn), + uuid, version); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status))); diff --git a/source4/librpc/rpc/dcerpc_spnego.c b/source4/librpc/rpc/dcerpc_spnego.c index f67dd2c7cb..7290139f6e 100644 --- a/source4/librpc/rpc/dcerpc_spnego.c +++ b/source4/librpc/rpc/dcerpc_spnego.c @@ -24,22 +24,21 @@ #include "includes.h" -#if 0 -/* - metze, can you tell me what you're trying to do with this? -*/ - /* do spnego style authentication on a gensec pipe */ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p, - const char *uuid, uint_t version, - const char *domain, - const char *username, - const char *password) + const char *uuid, uint_t version, + const char *domain, + const char *username, + const char *password) { NTSTATUS status; + if (!(p->conn->flags & (DCERPC_SIGN | DCERPC_SEAL))) { + p->conn->flags |= DCERPC_CONNECT; + } + status = gensec_client_start(p, &p->conn->security_state.generic_state); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status))); @@ -84,10 +83,9 @@ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p, return status; } - status = dcerpc_bind_alter(p, DCERPC_AUTH_TYPE_SPNEGO, - dcerpc_auth_level(p->conn), - uuid, version); - + status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SPNEGO, + dcerpc_auth_level(p->conn), + uuid, version); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("Failed to bind to pipe with SPNEGO: %s\n", nt_errstr(status))); return status; @@ -95,4 +93,3 @@ NTSTATUS dcerpc_bind_auth_spnego(struct dcerpc_pipe *p, return status; } -#endif diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 305c1c7725..534c17678d 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -176,6 +176,7 @@ static const struct { {"sign", DCERPC_SIGN}, {"seal", DCERPC_SEAL}, {"connect", DCERPC_CONNECT}, + {"spnego", DCERPC_AUTH_SPNEGO}, {"validate", DCERPC_DEBUG_VALIDATE_BOTH}, {"print", DCERPC_DEBUG_PRINT_BOTH}, {"padcheck", DCERPC_DEBUG_PAD_CHECK}, @@ -772,6 +773,42 @@ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *bind } +/* + perform an authenticated bind if needed +*/ +static NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, + struct dcerpc_binding *binding, + const char *pipe_uuid, + uint32_t pipe_version, + const char *domain, + const char *username, + const char *password) +{ + NTSTATUS status; + + p->conn->flags = binding->flags; + + /* remember the binding string for possible secondary connections */ + p->conn->binding_string = dcerpc_binding_string(p, binding); + + if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { + status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, + domain, username, password); + } else if (username && username[0] && (binding->flags & DCERPC_AUTH_SPNEGO)) { + status = dcerpc_bind_auth_spnego(p, pipe_uuid, pipe_version, domain, username, password); + } else if (username && username[0]) { + status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password); + } else { + status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); + } + return status; +} + + /* 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(struct dcerpc_pipe **pp, @@ -846,24 +883,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **pp, return status; } - p->conn->flags = binding->flags; - - /* remember the binding string for possible secondary connections */ - p->conn->binding_string = dcerpc_binding_string(p, binding); - - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0] && - (binding->flags & (DCERPC_CONNECT|DCERPC_SIGN|DCERPC_SEAL))) { - status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); - - } - + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); talloc_free(p); return status; } @@ -916,22 +937,8 @@ static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **pp, return status; } - p->conn->flags = binding->flags; - - /* remember the binding string for possible secondary connections */ - p->conn->binding_string = dcerpc_binding_string(p, binding); - - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0]) { - status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); - } - + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); talloc_free(p); return status; } @@ -977,22 +984,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **pp, return status; } - p->conn->flags = binding->flags; - - /* remember the binding string for possible secondary connections */ - p->conn->binding_string = dcerpc_binding_string(p, binding); - - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0]) { - status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); - } - + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); talloc_free(p); return status; } @@ -1047,23 +1040,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **pp, return status; } - p->conn->flags = binding->flags; - - /* remember the binding string for possible secondary connections */ - p->conn->binding_string = dcerpc_binding_string(p, binding); - - if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) { - status = dcerpc_bind_auth_schannel(p, pipe_uuid, pipe_version, - domain, username, password); - } else if (username && username[0]) { - status = dcerpc_bind_auth_ntlm(p, pipe_uuid, pipe_version, domain, username, password); - } else { - status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version); - } - + status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, domain, username, password); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to bind to uuid %s - %s\n", - pipe_uuid, nt_errstr(status))); talloc_free(p); return status; } @@ -1171,7 +1149,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe * if (!tree) { return NT_STATUS_INVALID_PARAMETER; } - status = dcerpc_pipe_open_smb((*p2)->conn, tree, pipe_name); break; @@ -1180,7 +1157,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe * if (!NT_STATUS_IS_OK(status)) { return status; } - b.flags &= ~DCERPC_AUTH_OPTIONS; status = dcerpc_pipe_open_tcp((*p2)->conn, b.host, atoi(b.endpoint)); break; @@ -1189,7 +1165,6 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe * if (!NT_STATUS_IS_OK(status)) { return status; } - b.flags &= ~DCERPC_AUTH_OPTIONS; status = dcerpc_pipe_open_pipe((*p2)->conn, b.endpoint); break; -- cgit