diff options
Diffstat (limited to 'source4/librpc/rpc')
-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 |
6 files changed, 376 insertions, 136 deletions
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); |