diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-06-29 09:40:10 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:56:49 -0500 |
commit | dc9f55dbec5f892b39d924d5fd033b5eec1e14e4 (patch) | |
tree | dd6932fb92fef55787b9a20671dd8c8f71ef3b6d /source4/librpc | |
parent | a440e8f3b518d25c5fb9c9fa896cb7704974f346 (diff) | |
download | samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.gz samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.bz2 samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.zip |
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/ndr/ndr.c | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 58 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 2 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_auth.c | 27 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_ntlm.c | 41 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_schannel.c | 378 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 6 |
7 files changed, 377 insertions, 137 deletions
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index 6b89cb4cd2..d2e85f6aec 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -741,7 +741,7 @@ NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32_t leve /* pull a struct from a blob using NDR */ -NTSTATUS ndr_pull_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, +NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, NTSTATUS (*fn)(struct ndr_pull *, int , void *)) { struct ndr_pull *ndr; diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 5d5469da7f..8afc556528 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -42,9 +42,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void) p->mem_ctx = mem_ctx; p->call_id = 1; p->security_state.auth_info = NULL; - ZERO_STRUCT(p->security_state.generic_state.user); - p->security_state.generic_state.private_data = NULL; - p->security_state.generic_state.ops = NULL; + p->security_state.generic_state = NULL; p->binding_string = NULL; p->flags = 0; p->srv_max_xmit_frag = 0; @@ -60,8 +58,8 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p) if (!p) return; p->reference_count--; if (p->reference_count <= 0) { - if (p->security_state.generic_state.ops) { - p->security_state.generic_state.ops->end(&p->security_state.generic_state); + if (p->security_state.generic_state) { + gensec_end(&p->security_state.generic_state); } p->transport.shutdown_pipe(p); talloc_destroy(p->mem_ctx); @@ -132,7 +130,7 @@ 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.ops) { + if (!p->security_state.auth_info || !p->security_state.generic_state) { return dcerpc_pull(blob, mem_ctx, pkt); } @@ -186,21 +184,19 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, /* check signature or unseal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = p->security_state - .generic_state.ops->unseal(&p->security_state.generic_state, - mem_ctx, - pkt->u.response.stub_and_verifier.data, - pkt->u.response.stub_and_verifier.length, - &auth.credentials); + status = gensec_unseal_packet(p->security_state.generic_state, + mem_ctx, + pkt->u.response.stub_and_verifier.data, + pkt->u.response.stub_and_verifier.length, + &auth.credentials); break; - + case DCERPC_AUTH_LEVEL_INTEGRITY: - status = p->security_state - .generic_state.ops->check_sig(&p->security_state.generic_state, - mem_ctx, - pkt->u.response.stub_and_verifier.data, - pkt->u.response.stub_and_verifier.length, - &auth.credentials); + status = gensec_check_packet(p->security_state.generic_state, + mem_ctx, + pkt->u.response.stub_and_verifier.data, + pkt->u.response.stub_and_verifier.length, + &auth.credentials); break; case DCERPC_AUTH_LEVEL_NONE: @@ -232,7 +228,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, struct ndr_push *ndr; /* non-signed packets are simpler */ - if (!p->security_state.auth_info || !p->security_state.generic_state.ops) { + if (!p->security_state.auth_info || !p->security_state.generic_state) { return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info); } @@ -257,21 +253,19 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* sign or seal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = p->security_state - .generic_state.ops->seal(&p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); + status = gensec_seal_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + &p->security_state.auth_info->credentials); break; case DCERPC_AUTH_LEVEL_INTEGRITY: - status = p->security_state - .generic_state.ops->sign(&p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); + status = gensec_sign_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + &p->security_state.auth_info->credentials); break; case DCERPC_AUTH_LEVEL_NONE: diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index a513b72a16..4f50b261e2 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -28,7 +28,7 @@ enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP}; struct dcerpc_pipe; struct dcerpc_security { struct dcerpc_auth *auth_info; - struct gensec_security generic_state; + struct gensec_security *generic_state; }; struct dcerpc_pipe { diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index e5fad1f082..07601e4724 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -56,15 +56,14 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, return NT_STATUS_NO_MEMORY; } - if (!p->security_state.generic_state.ops) { - - p->security_state.generic_state.ops = gensec_security_by_authtype(auth_type); - if (!p->security_state.generic_state.ops) { - status = NT_STATUS_INVALID_PARAMETER; - goto done; + if (!p->security_state.generic_state) { + status = gensec_client_start(&p->security_state.generic_state); + if (!NT_STATUS_IS_OK(status)) { + return status; } - status = p->security_state.generic_state.ops->client_start(&p->security_state.generic_state); + status = gensec_start_mech_by_authtype(p->security_state.generic_state, auth_type); + if (!NT_STATUS_IS_OK(status)) { return status; } @@ -90,10 +89,10 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, p->security_state.auth_info->auth_level = DCERPC_AUTH_LEVEL_NONE; } - status = p->security_state.generic_state.ops->update(&p->security_state.generic_state, mem_ctx, - p->security_state.auth_info->credentials, - &credentials); - + status = gensec_update(p->security_state.generic_state, mem_ctx, + p->security_state.auth_info->credentials, + &credentials); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; } @@ -105,9 +104,9 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, goto done; } - status = p->security_state.generic_state.ops->update(&p->security_state.generic_state, mem_ctx, - p->security_state.auth_info->credentials, - &credentials); + status = gensec_update(p->security_state.generic_state, mem_ctx, + p->security_state.auth_info->credentials, + &credentials); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { goto done; diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c index 398e3f1aa3..0f02669eb1 100644 --- a/source4/librpc/rpc/dcerpc_ntlm.c +++ b/source4/librpc/rpc/dcerpc_ntlm.c @@ -33,12 +33,47 @@ NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p, { NTSTATUS status; - p->security_state.generic_state.user.domain = domain; - p->security_state.generic_state.user.name = username; - p->security_state.generic_state.user.password = password; + 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))); + return status; + } + status = gensec_set_domain(p->security_state.generic_state, domain); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", + domain, nt_errstr(status))); + return status; + } + + status = gensec_set_username(p->security_state.generic_state, username); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", + username, nt_errstr(status))); + return status; + } + + status = gensec_set_password(p->security_state.generic_state, password); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start set GENSEC client password: %s\n", + nt_errstr(status))); + return status; + } + + status = gensec_start_mech_by_authtype(p->security_state.generic_state, DCERPC_AUTH_TYPE_NTLMSSP); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start set GENSEC client NTLMSSP mechanism: %s\n", + nt_errstr(status))); + return status; + } + status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_NTLMSSP, uuid, version); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("Failed to bind to pipe with NTLMSSP: %s\n", nt_errstr(status))); + return status; + } + return status; } diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index b43dd0788a..ffe60b1bae 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -22,21 +22,24 @@ #include "includes.h" -#define DCERPC_SCHANNEL_STATE_START 0 -#define DCERPC_SCHANNEL_STATE_UPDATE_1 1 +enum schannel_position { + DCERPC_SCHANNEL_STATE_START = 0, + DCERPC_SCHANNEL_STATE_UPDATE_1 +}; struct dcerpc_schannel_state { TALLOC_CTX *mem_ctx; - uint8_t state; - struct schannel_bind bind_schannel; + enum schannel_position state; struct schannel_state *schannel_state; + struct creds_CredentialState creds; + char *account_name; }; static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p, - const char *domain, - const char *username, - const char *password, - int chan_type, + const char *domain, + const char *username, + const char *password, + int chan_type, uint8_t new_session_key[16]); /* @@ -45,39 +48,39 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p, These will become static again, when we get dynamic registration, and decrpc_schannel_security_ops come back here. */ -static NTSTATUS dcerpc_schannel_unseal(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, DATA_BLOB *sig) +static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + uint8_t *data, size_t length, DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - + return schannel_unseal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig); } -static NTSTATUS dcerpc_schannel_check_sig(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const DATA_BLOB *sig) +static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const uint8_t *data, size_t length, + const DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; return schannel_check_packet(dce_schan_state->schannel_state, data, length, sig); } -static NTSTATUS dcerpc_schannel_seal(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - DATA_BLOB *sig) +static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + uint8_t *data, size_t length, + DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; return schannel_seal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig); } -static NTSTATUS dcerpc_schannel_sign(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - DATA_BLOB *sig) +static NTSTATUS dcerpc_schannel_sign_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const uint8_t *data, size_t length, + DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; @@ -85,47 +88,233 @@ static NTSTATUS dcerpc_schannel_sign(struct gensec_security *gensec_security, } static NTSTATUS dcerpc_schannel_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) + DATA_BLOB *session_key) { return NT_STATUS_NOT_IMPLEMENTED; } static NTSTATUS dcerpc_schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) + const DATA_BLOB in, DATA_BLOB *out) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; NTSTATUS status; struct schannel_bind bind_schannel; + struct schannel_bind_ack bind_schannel_ack; + const char *account_name; + + switch (gensec_security->gensec_role) { + case GENSEC_CLIENT: + if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) { + /* we could parse the bind ack, but we don't know what it is yet */ + return NT_STATUS_OK; + } + + bind_schannel.unknown1 = 0; +#if 0 + /* to support this we'd need to have access to the full domain name */ + bind_schannel.bind_type = 23; + bind_schannel.u.info23.domain = gensec_security->user.domain; + bind_schannel.u.info23.account_name = gensec_security->user.name; + bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(out_mem_ctx, fulldomainname); + bind_schannel.u.info23.workstation = str_format_nbt_domain(out_mem_ctx, gensec_security->user.name); +#else + bind_schannel.bind_type = 3; + bind_schannel.u.info3.domain = gensec_security->user.domain; + bind_schannel.u.info3.account_name = gensec_security->user.name; +#endif + + status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel, + (ndr_push_flags_fn_t)ndr_push_schannel_bind); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not create schannel bind: %s\n", + nt_errstr(status))); + return status; + } + + dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1; + + return NT_STATUS_MORE_PROCESSING_REQUIRED; + case GENSEC_SERVER: + + if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) { + /* no third leg on this protocol */ + return NT_STATUS_OK; + } + + /* parse the schannel startup blob */ + status = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel, + (ndr_pull_flags_fn_t)ndr_pull_schannel_bind); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (bind_schannel.bind_type == 23) { + account_name = bind_schannel.u.info23.account_name; + } else { + account_name = bind_schannel.u.info3.account_name; + } + + /* pull the session key for this client */ + status = schannel_fetch_session_key(out_mem_ctx, account_name, &dce_schan_state->creds); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not find session key for attempted schannel connection on %s: %s\n", + account_name, nt_errstr(status))); + return status; + } + + dce_schan_state->account_name = talloc_strdup(dce_schan_state->mem_ctx, account_name); + + /* start up the schannel server code */ + status = schannel_start(&dce_schan_state->schannel_state, + dce_schan_state->creds.session_key, False); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not initialise schannel state for account %s: %s\n", + account_name, nt_errstr(status))); + return status; + } + + bind_schannel_ack.unknown1 = 1; + bind_schannel_ack.unknown2 = 0; + bind_schannel_ack.unknown3 = 0x6c0000; + + status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack, + (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not return schannel bind ack for account %s: %s\n", + account_name, nt_errstr(status))); + return status; + } + + dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1; + + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + return NT_STATUS_INVALID_PARAMETER; +} + +/** + * Return the credentials of a logged on user, including session keys + * etc. + * + * Only valid after a successful authentication + * + * May only be called once per authentication. + * + */ + +NTSTATUS dcerpc_schannel_session_info(struct gensec_security *gensec_security, + struct auth_session_info **session_info) +{ + struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; + TALLOC_CTX *mem_ctx; + mem_ctx = talloc_init("dcerpc_schannel_start"); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } - if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) { - return NT_STATUS_OK; + (*session_info) = talloc_p(mem_ctx, struct auth_session_info); + if (*session_info == NULL) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; } - dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1; + ZERO_STRUCTP(*session_info); + (*session_info)->mem_ctx = mem_ctx; + (*session_info)->refcount = 1; + + (*session_info)->workstation = talloc_strdup(mem_ctx, dce_schan_state->account_name); + if ((*session_info)->workstation == NULL) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} + + +/** + * Return the struct creds_CredentialState. + * + * Make sure not to call this unless gensec is using schannel... + */ + +NTSTATUS dcerpc_schannel_creds(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + struct creds_CredentialState **creds) +{ + struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; - bind_schannel.unknown1 = 0; -#if 0 - /* to support this we'd need to have access to the full domain name */ - bind_schannel.bind_type = 23; - bind_schannel.u.info23.domain = gensec_security->user.domain; - bind_schannel.u.info23.account_name = gensec_security->user.name; - bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(dce_schan_state->mem_ctx, fulldomainname); - bind_schannel.u.info23.workstation = str_format_nbt_domain(dce_schan_state->mem_ctx, gensec_security->user.name); -#else - bind_schannel.bind_type = 3; - bind_schannel.u.info3.domain = gensec_security->user.domain; - bind_schannel.u.info3.account_name = gensec_security->user.name; -#endif + *creds = talloc_p(mem_ctx, struct creds_CredentialState); + if (*creds) { + return NT_STATUS_NO_MEMORY; + } + + **creds = dce_schan_state->creds; + return NT_STATUS_OK; +} + + +static NTSTATUS dcerpc_schannel_start(struct gensec_security *gensec_security) +{ + struct dcerpc_schannel_state *dce_schan_state; + TALLOC_CTX *mem_ctx; + mem_ctx = talloc_init("dcerpc_schannel_start"); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state); + if (!dce_schan_state) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + dce_schan_state->mem_ctx = mem_ctx; + dce_schan_state->state = DCERPC_SCHANNEL_STATE_START; + + + gensec_security->private_data = dce_schan_state; + + return NT_STATUS_OK; +} + +static NTSTATUS dcerpc_schannel_server_start(struct gensec_security *gensec_security) +{ + NTSTATUS status; + + status = dcerpc_schannel_start(gensec_security); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return NT_STATUS_OK; +} + +static NTSTATUS dcerpc_schannel_client_start(struct gensec_security *gensec_security) +{ + NTSTATUS status; + struct dcerpc_schannel_state *dce_schan_state; + + status = dcerpc_schannel_start(gensec_security); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + dce_schan_state = gensec_security->private_data; - status = ndr_push_struct_blob(out, dce_schan_state->mem_ctx, &bind_schannel, - (ndr_push_flags_fn_t)ndr_push_schannel_bind); + status = schannel_start(&dce_schan_state->schannel_state, + gensec_security->user.schan_session_key, + True); if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start schannel client\n")); return status; } - return NT_STATUS_MORE_PROCESSING_REQUIRED; + dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16); + return NT_STATUS_OK; } +/* + end crypto state +*/ static void dcerpc_schannel_end(struct gensec_security *gensec_security) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; @@ -138,18 +327,6 @@ static void dcerpc_schannel_end(struct gensec_security *gensec_security) } -static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = { - .name = "dcerpc_schannel", - .auth_type = DCERPC_AUTH_TYPE_SCHANNEL, - .update = dcerpc_schannel_update, - .seal = dcerpc_schannel_seal, - .sign = dcerpc_schannel_sign, - .check_sig = dcerpc_schannel_check_sig, - .unseal = dcerpc_schannel_unseal, - .session_key = dcerpc_schannel_session_key, - .end = dcerpc_schannel_end -}; - /* get a schannel key using a netlogon challenge on a secondary pipe */ @@ -251,11 +428,13 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p, const char *password) { NTSTATUS status; - struct dcerpc_schannel_state *dce_schan_state; - TALLOC_CTX *mem_ctx; - uint8_t session_key[16]; int chan_type = 0; + status = gensec_client_start(&p->security_state.generic_state); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (p->flags & DCERPC_SCHANNEL_BDC) { chan_type = SEC_CHAN_BDC; } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) { @@ -265,44 +444,75 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p, } status = dcerpc_schannel_key(p, domain, - username, - password, - chan_type, session_key); + username, + password, + chan_type, + p->security_state.generic_state->user.schan_session_key); if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to fetch schannel session key: %s\n", nt_errstr(status))); + gensec_end(&p->security_state.generic_state); return status; } - - mem_ctx = talloc_init("dcerpc_schannel_start"); - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; + + status = gensec_set_username(p->security_state.generic_state, username); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to set schannel username to %s: %s\n", username, nt_errstr(status))); + gensec_end(&p->security_state.generic_state); + return status; + } + + status = gensec_set_domain(p->security_state.generic_state, domain); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to set schannel domain to %s: %s\n", domain, nt_errstr(status))); + gensec_end(&p->security_state.generic_state); + return status; } + + status = gensec_start_mech_by_authtype(p->security_state.generic_state, DCERPC_AUTH_TYPE_SCHANNEL); - dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state); - if (!dce_schan_state) { - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start SCHANNEL GENSEC backend: %s\n", nt_errstr(status))); + gensec_end(&p->security_state.generic_state); + return status; } - dce_schan_state->mem_ctx = mem_ctx; + status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL, + uuid, version); - status = schannel_start(&dce_schan_state->schannel_state, session_key, True); if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status))); + gensec_end(&p->security_state.generic_state); return status; } - dce_schan_state->state = DCERPC_SCHANNEL_STATE_START; - - p->security_state.generic_state.user.domain = domain; - p->security_state.generic_state.user.name = username; - p->security_state.generic_state.user.password = password; + return NT_STATUS_OK; +} - p->security_state.generic_state.ops = &gensec_dcerpc_schannel_security_ops; - p->security_state.generic_state.private_data = dce_schan_state; - dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16); +static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = { + .name = "dcerpc_schannel", + .auth_type = DCERPC_AUTH_TYPE_SCHANNEL, + .client_start = dcerpc_schannel_client_start, + .server_start = dcerpc_schannel_server_start, + .update = dcerpc_schannel_update, + .seal_packet = dcerpc_schannel_seal_packet, + .sign_packet = dcerpc_schannel_sign_packet, + .check_packet = dcerpc_schannel_check_packet, + .unseal_packet = dcerpc_schannel_unseal_packet, + .session_key = dcerpc_schannel_session_key, + .session_info = dcerpc_schannel_session_info, + .end = dcerpc_schannel_end +}; - status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL, - uuid, version); +NTSTATUS gensec_dcerpc_schannel_init(void) +{ + NTSTATUS ret; + ret = register_backend("gensec", &gensec_dcerpc_schannel_security_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register '%s' gensec backend!\n", + gensec_dcerpc_schannel_security_ops.name)); + return ret; + } - return status; + return ret; } diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 82aa5aa1f3..d5cd2ab6fe 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -503,6 +503,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); dcerpc_pipe_close(*p); + *p = NULL; return status; } @@ -569,6 +570,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status))); dcerpc_pipe_close(*p); + *p = NULL; return status; } @@ -697,8 +699,8 @@ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p, { struct cli_tree *tree; - if (p->security_state.generic_state.ops) { - return p->security_state.generic_state.ops->session_key(&p->security_state.generic_state, session_key); + if (p->security_state.generic_state) { + return gensec_session_key(p->security_state.generic_state, session_key); } tree = dcerpc_smb_tree(p); |