diff options
author | Stefan Metzmacher <metze@samba.org> | 2004-08-12 07:37:49 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:57:55 -0500 |
commit | 8a0f6c9c7909162a9669197bc0238d0636de69da (patch) | |
tree | 21490966191464eab0097b37fe57651eccfed607 /source4/libcli/auth/gensec_krb5.c | |
parent | 63c5ca7d583691fae5ccf0b760f24b9d11a2141b (diff) | |
download | samba-8a0f6c9c7909162a9669197bc0238d0636de69da.tar.gz samba-8a0f6c9c7909162a9669197bc0238d0636de69da.tar.bz2 samba-8a0f6c9c7909162a9669197bc0238d0636de69da.zip |
r1770: here's the krb5 server code,
there're some cleanups needed and we need to verify the PAC correctly
and create the auth_session_info correctly...
metze
(This used to be commit d8fe497097ee49611bb05c4a2fed36912d8e16b4)
Diffstat (limited to 'source4/libcli/auth/gensec_krb5.c')
-rw-r--r-- | source4/libcli/auth/gensec_krb5.c | 264 |
1 files changed, 257 insertions, 7 deletions
diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c index f5f02d1421..260b256934 100644 --- a/source4/libcli/auth/gensec_krb5.c +++ b/source4/libcli/auth/gensec_krb5.c @@ -38,14 +38,167 @@ enum GENSEC_KRB5_STATE { struct gensec_krb5_state { TALLOC_CTX *mem_ctx; DATA_BLOB session_key; - DATA_BLOB pac; + struct PAC_LOGON_INFO logon_info; enum GENSEC_KRB5_STATE state_position; krb5_context krb5_context; krb5_auth_context krb5_auth_context; krb5_ccache krb5_ccache; krb5_data ticket; + krb5_keyblock krb5_keyblock; }; +static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + struct gensec_krb5_state *gensec_krb5_state, + uint32 cksum_type) +{ + krb5_error_code ret; + krb5_crypto crypto; + Checksum cksum; + + cksum.cksumtype = (CKSUMTYPE)sig->type; + cksum.checksum.length = sizeof(sig->signature); + cksum.checksum.data = sig->signature; + + + ret = krb5_crypto_init(gensec_krb5_state->krb5_context, + &gensec_krb5_state->krb5_keyblock, + cksum_type, + &crypto); + if (ret) { + DEBUG(0,("krb5_crypto_init() failed\n")); + return NT_STATUS_FOOBAR; + } + + ret = krb5_verify_checksum(gensec_krb5_state->krb5_context, + crypto, + cksum_type, + pac_data.data, + pac_data.length, + &cksum); + + krb5_crypto_destroy(gensec_krb5_state->krb5_context, crypto); + + if (ret) { + DEBUG(0,("NOT verifying PAC checksums yet!\n")); + //return NT_STATUS_LOGON_FAILURE; + } else { + DEBUG(0,("PAC checksums verified!\n")); + } + + return NT_STATUS_OK; +} + +NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO *logon_info_out, + DATA_BLOB blob, + struct gensec_krb5_state *gensec_krb5_state) +{ + NTSTATUS status; + struct PAC_SIGNATURE_DATA srv_sig; + uint8_t *srv_key = NULL; + struct PAC_SIGNATURE_DATA kdc_sig; + uint8_t *kdc_key = NULL; + struct PAC_LOGON_INFO *logon_info = NULL; + struct PAC_DATA pac_data; + DATA_BLOB tmp_blob; + int i; + + status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data, + (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("can't parse the PAC\n")); + return status; + } + + if (pac_data.num_buffers < 3) { + /* we need logon_ingo, service_key and kdc_key */ + DEBUG(0,("less than 3 PAC buffers\n")); + return NT_STATUS_FOOBAR; + } + + for (i=0; i < pac_data.num_buffers; i++) { + switch (pac_data.buffers[i].type) { + case PAC_TYPE_LOGON_INFO: + if (!pac_data.buffers[i].info) { + break; + } + logon_info = &pac_data.buffers[i].info->logon_info; + break; + case PAC_TYPE_SRV_CHECKSUM: + if (!pac_data.buffers[i].info) { + break; + } + srv_key = (uint8_t *)&pac_data.buffers[i].info->srv_cksum.signature; + srv_sig = pac_data.buffers[i].info->srv_cksum; + break; + case PAC_TYPE_KDC_CHECKSUM: + if (!pac_data.buffers[i].info) { + break; + } + kdc_key = (uint8_t *)&pac_data.buffers[i].info->kdc_cksum.signature; + kdc_sig = pac_data.buffers[i].info->kdc_cksum; + break; + case PAC_TYPE_UNKNOWN_10: + break; + default: + break; + } + } + + if (!logon_info) { + DEBUG(0,("PAC no logon_info\n")); + return NT_STATUS_FOOBAR; + } + + if (!srv_key) { + DEBUG(0,("PAC no srv_key\n")); + return NT_STATUS_FOOBAR; + } + + if (!kdc_key) { + DEBUG(0,("PAC no kdc_key\n")); + return NT_STATUS_FOOBAR; + } + + /* clear the kdc_key */ + memset(kdc_key , '\0', 16); + + status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* verify by kdc_key */ + status = gensec_krb5_pac_checksum(tmp_blob, &kdc_sig, gensec_krb5_state, 0); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* clear the service_key */ + memset(srv_key , '\0', 16); + + status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* verify by servie_key */ + status = gensec_krb5_pac_checksum(tmp_blob, &srv_sig, gensec_krb5_state, 0); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(0,("account_name: %s [%s]\n",logon_info->account_name.string, logon_info->full_name.string)); + *logon_info_out = *logon_info; + + return status; +} + static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) { struct gensec_krb5_state *gensec_krb5_state; @@ -334,7 +487,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL } return nt_status; } - + case GENSEC_KRB5_SERVER_START: { char *principal; @@ -348,19 +501,25 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALL gensec_krb5_state->krb5_context, gensec_krb5_state->krb5_auth_context, lp_realm(), &in, - &principal, &pac, &unwrapped_out); + &principal, &pac, &unwrapped_out, + &gensec_krb5_state->krb5_keyblock); } else { /* TODO: check the tok_id */ nt_status = ads_verify_ticket(out_mem_ctx, gensec_krb5_state->krb5_context, gensec_krb5_state->krb5_auth_context, lp_realm(), &unwrapped_in, - &principal, &pac, &unwrapped_out); + &principal, &pac, &unwrapped_out, + &gensec_krb5_state->krb5_keyblock); } - gensec_krb5_state->pac = data_blob_talloc_steal(out_mem_ctx, gensec_krb5_state->mem_ctx, - &pac); - /* TODO: parse the pac */ + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + /* decode and verify the pac */ + nt_status = gensec_krb5_decode_pac(gensec_krb5_state->mem_ctx, &gensec_krb5_state->logon_info, pac, + gensec_krb5_state); if (NT_STATUS_IS_OK(nt_status)) { gensec_krb5_state->state_position = GENSEC_KRB5_DONE; @@ -413,6 +572,95 @@ static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, return NT_STATUS_NO_USER_SESSION_KEY; } } +/* +struct gensec_krb5_state { + TALLOC_CTX *mem_ctx; + DATA_BLOB session_key; + struct PAC_LOGON_INFO logon_info; + enum GENSEC_KRB5_STATE state_position; + krb5_context krb5_context; + krb5_auth_context krb5_auth_context; + krb5_ccache krb5_ccache; + krb5_data ticket; + krb5_keyblock krb5_keyblock; +}; +struct auth_session_info +{ + TALLOC_CTX *mem_ctx; + + int refcount; + + NT_USER_TOKEN *nt_user_token; + + struct auth_serversupplied_info *server_info; + + DATA_BLOB session_key; + + const char *workstation; +}; +*/ +static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, + struct auth_session_info **session_info_out) +{ + struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data; + TALLOC_CTX *mem_ctx; + struct auth_session_info *session_info = NULL; + struct PAC_LOGON_INFO *logon_info = &gensec_krb5_state->logon_info; + struct nt_user_token *ptoken; + struct dom_sid *sid; + + *session_info_out = NULL; + + mem_ctx = talloc_init("krb5: session_info"); + + session_info = talloc_p(mem_ctx, struct auth_session_info); + if (!session_info) { + return NT_STATUS_NO_MEMORY; + } + + session_info->mem_ctx = mem_ctx; + session_info->refcount = 1; + session_info->server_info = NULL; + + ptoken = talloc_p(session_info->mem_ctx, struct nt_user_token); + if (!ptoken) { + return NT_STATUS_NO_MEMORY; + } + + ptoken->num_sids = 0; + + ptoken->user_sids = talloc_array_p(mem_ctx, struct dom_sid*, logon_info->groups_count + 2); + if (!ptoken->user_sids) { + return NT_STATUS_NO_MEMORY; + } + + + sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid); + ptoken->user_sids[0] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->user_rid); + ptoken->num_sids++; + sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid); + ptoken->user_sids[1] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->group_rid); + ptoken->num_sids++; + + for (;ptoken->num_sids < logon_info->groups_count; ptoken->num_sids++) { + sid = dom_sid_dup(session_info->mem_ctx, logon_info->dom_sid); + ptoken->user_sids[ptoken->num_sids] = dom_sid_add_rid(session_info->mem_ctx, sid, logon_info->groups[ptoken->num_sids - 2].rid); + } + + debug_nt_user_token(DBGC_AUTH, 0, ptoken); + + session_info->nt_user_token = ptoken; + + session_info->session_key = data_blob_talloc(session_info->mem_ctx, + gensec_krb5_state->session_key.data, + gensec_krb5_state->session_key.length); + + session_info->workstation = NULL; + + *session_info_out = session_info; + + return NT_STATUS_OK; +} static const struct gensec_security_ops gensec_krb5_security_ops = { @@ -423,6 +671,7 @@ static const struct gensec_security_ops gensec_krb5_security_ops = { .server_start = gensec_krb5_server_start, .update = gensec_krb5_update, .session_key = gensec_krb5_session_key, + .session_info = gensec_krb5_session_info, .end = gensec_krb5_end }; @@ -434,6 +683,7 @@ static const struct gensec_security_ops gensec_ms_krb5_security_ops = { .server_start = gensec_krb5_server_start, .update = gensec_krb5_update, .session_key = gensec_krb5_session_key, + .session_info = gensec_krb5_session_info, .end = gensec_krb5_end }; |