From 642ba4bfeee9951957287647628fa82269a318b1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 25 Sep 2004 07:25:51 +0000 Subject: r2614: support CONNECT level DCE/RPC security in both client and server. CONNECT security uses NTLMSSP, but does not do any signing or sealing (or equivalently, its like signing, but with a zero filled checksum). (This used to be commit f4660857bc708db7f5aa7487bf7ab04bffe68928) --- source4/librpc/rpc/dcerpc.c | 52 +++++++++++++++++++++++++++++++++++++--- source4/librpc/rpc/dcerpc.h | 21 ++++++++-------- source4/librpc/rpc/dcerpc_ntlm.c | 4 ++++ source4/librpc/rpc/dcerpc_util.c | 11 +++------ source4/rpc_server/dcesrv_auth.c | 43 +++++++++++++++++++++++++++++++-- 5 files changed, 108 insertions(+), 23 deletions(-) (limited to 'source4') diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 99051e75b6..23e9f04d96 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -145,6 +145,32 @@ static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX * return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt); } +/* + generate a CONNECT level verifier +*/ +static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob) +{ + *blob = data_blob_talloc(mem_ctx, NULL, 16); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + SIVAL(blob->data, 0, 1); + memset(blob->data+4, 0, 12); + return NT_STATUS_OK; +} + +/* + generate a CONNECT level verifier +*/ +static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob) +{ + if (blob->length != 16 || + IVAL(blob->data, 0) != 1) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + /* parse a possibly signed blob into a dcerpc request packet structure */ @@ -158,7 +184,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, DATA_BLOB auth_blob; /* non-signed packets are simpler */ - if (!p->security_state.auth_info || !p->security_state.generic_state) { + if (!p->security_state.auth_info || + !p->security_state.generic_state) { return dcerpc_pull(p, blob, mem_ctx, pkt); } @@ -181,6 +208,11 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, return status; } + if (pkt->auth_length == 0 && + p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) { + return NT_STATUS_OK; + } + auth_blob.length = 8 + pkt->auth_length; /* check for a valid length */ @@ -233,7 +265,11 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, blob->length - auth.credentials.length, &auth.credentials); break; - + + case DCERPC_AUTH_LEVEL_CONNECT: + status = dcerpc_check_connect_verifier(&auth.credentials); + break; + case DCERPC_AUTH_LEVEL_NONE: break; @@ -264,7 +300,8 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, DATA_BLOB creds2; /* non-signed packets are simpler */ - if (!p->security_state.auth_info || !p->security_state.generic_state) { + if (!p->security_state.auth_info || + !p->security_state.generic_state) { return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info); } @@ -297,6 +334,10 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, data_blob_clear(&p->security_state.auth_info->credentials); break; + case DCERPC_AUTH_LEVEL_CONNECT: + status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials); + break; + case DCERPC_AUTH_LEVEL_NONE: p->security_state.auth_info->credentials = data_blob(NULL, 0); break; @@ -351,6 +392,9 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length); break; + case DCERPC_AUTH_LEVEL_CONNECT: + break; + case DCERPC_AUTH_LEVEL_NONE: p->security_state.auth_info->credentials = data_blob(NULL, 0); break; @@ -1247,6 +1291,8 @@ uint32 dcerpc_auth_level(struct dcerpc_pipe *p) auth_level = DCERPC_AUTH_LEVEL_PRIVACY; } else if (p->flags & DCERPC_SIGN) { auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + } else if (p->flags & DCERPC_CONNECT) { + auth_level = DCERPC_AUTH_LEVEL_CONNECT; } else { auth_level = DCERPC_AUTH_LEVEL_NONE; } diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 242a18368f..011d70ec0c 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -88,28 +88,29 @@ struct dcerpc_pipe { #define DCERPC_DEBUG_VALIDATE_OUT (1<<3) #define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT) -#define DCERPC_SIGN (1<<4) -#define DCERPC_SEAL (1<<5) +#define DCERPC_CONNECT (1<<4) +#define DCERPC_SIGN (1<<5) +#define DCERPC_SEAL (1<<6) -#define DCERPC_PUSH_BIGENDIAN (1<<6) -#define DCERPC_PULL_BIGENDIAN (1<<7) +#define DCERPC_PUSH_BIGENDIAN (1<<7) +#define DCERPC_PULL_BIGENDIAN (1<<8) -#define DCERPC_SCHANNEL_BDC (1<<8) -#define DCERPC_SCHANNEL_WORKSTATION (1<<9) -#define DCERPC_SCHANNEL_DOMAIN (1<<10) +#define DCERPC_SCHANNEL_BDC (1<<9) +#define DCERPC_SCHANNEL_WORKSTATION (1<<10) +#define DCERPC_SCHANNEL_DOMAIN (1<<11) #define DCERPC_SCHANNEL_ANY (DCERPC_SCHANNEL_BDC| \ DCERPC_SCHANNEL_DOMAIN| \ DCERPC_SCHANNEL_WORKSTATION) /* use a 128 bit session key */ -#define DCERPC_SCHANNEL_128 (1<<11) +#define DCERPC_SCHANNEL_128 (1<<12) #define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL_ANY) /* check incoming pad bytes */ -#define DCERPC_DEBUG_PAD_CHECK (1<<12) +#define DCERPC_DEBUG_PAD_CHECK (1<<13) /* set LIBNDR_FLAG_REF_ALLOC flag when decoding NDR */ -#define DCERPC_NDR_REF_ALLOC (1<<13) +#define DCERPC_NDR_REF_ALLOC (1<<14) /* this is used to find pointers to calls diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c index eab80a333b..905be5b76c 100644 --- a/source4/librpc/rpc/dcerpc_ntlm.c +++ b/source4/librpc/rpc/dcerpc_ntlm.c @@ -33,6 +33,10 @@ NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p, { NTSTATUS status; + if (!(p->flags & (DCERPC_SIGN | DCERPC_SEAL))) { + p->flags |= DCERPC_CONNECT; + } + status = gensec_client_start(&p->security_state.generic_state); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status))); diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 2c9ae0354a..2a715eac1d 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -275,6 +275,7 @@ static const struct { } ncacn_options[] = { {"sign", DCERPC_SIGN}, {"seal", DCERPC_SEAL}, + {"connect", DCERPC_CONNECT}, {"validate", DCERPC_DEBUG_VALIDATE_BOTH}, {"print", DCERPC_DEBUG_PRINT_BOTH}, {"padcheck", DCERPC_DEBUG_PAD_CHECK}, @@ -495,7 +496,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, 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_SIGN | DCERPC_SEAL))) { + } 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); @@ -548,12 +549,6 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, return status; } - /* it doesn't seem to work to do a null NTLMSSP session without either sign - or seal, so force signing if we are doing ntlmssp */ - if (username && username[0] && !(binding->flags & (DCERPC_SIGN|DCERPC_SEAL))) { - binding->flags |= DCERPC_SIGN; - } - (*p)->flags = binding->flags; /* remember the binding string for possible secondary connections */ @@ -562,7 +557,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, 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_SIGN | DCERPC_SEAL))) { + } 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); diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index e2a798c1ae..bfdf557bdf 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -31,7 +31,8 @@ NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn, { NTSTATUS status; if (auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY && - auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { + auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY && + auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_CONNECT) { DEBUG(2,("auth_level %d not supported in dcesrv auth\n", auth->auth_info->auth_level)); return NT_STATUS_INVALID_PARAMETER; @@ -191,6 +192,34 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call) return True; } + +/* + generate a CONNECT level verifier +*/ +static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob) +{ + *blob = data_blob_talloc(mem_ctx, NULL, 16); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + SIVAL(blob->data, 0, 1); + memset(blob->data+4, 0, 12); + return NT_STATUS_OK; +} + +/* + generate a CONNECT level verifier +*/ +static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob) +{ + if (blob->length != 16 || + IVAL(blob->data, 0) != 1) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + + /* check credentials on a request */ @@ -260,6 +289,10 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) &auth.credentials); break; + case DCERPC_AUTH_LEVEL_CONNECT: + status = dcesrv_check_connect_verifier(&auth.credentials); + break; + default: status = NT_STATUS_INVALID_LEVEL; break; @@ -340,7 +373,7 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call, payload_length, blob->data, blob->length - dce_conn->auth_state.auth_info->credentials.length, - &dce_conn->auth_state.auth_info->credentials); + &dce_conn->auth_state.auth_info->credentials); break; case DCERPC_AUTH_LEVEL_INTEGRITY: @@ -353,6 +386,12 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call, &dce_conn->auth_state.auth_info->credentials); break; + + case DCERPC_AUTH_LEVEL_CONNECT: + status = dcesrv_connect_verifier(call->mem_ctx, + &dce_conn->auth_state.auth_info->credentials); + break; + default: status = NT_STATUS_INVALID_LEVEL; break; -- cgit