diff options
author | Andrew Bartlett <abartlet@samba.org> | 2005-08-05 00:41:53 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:31:15 -0500 |
commit | 8db8279730c6d4ef6b03b9f96381dee890a8da57 (patch) | |
tree | 718b9b289624d91f50a89d4e579c10393c540027 /source4/auth | |
parent | 84da1a1050ee0f0cf5b2ecfec78291424b648c30 (diff) | |
download | samba-8db8279730c6d4ef6b03b9f96381dee890a8da57.tar.gz samba-8db8279730c6d4ef6b03b9f96381dee890a8da57.tar.xz samba-8db8279730c6d4ef6b03b9f96381dee890a8da57.zip |
r9084: 'resign' the sample PAC for the validation of the signature algorithms.
If we ever get problems with the kerberos code, it should show up as a
different signature in this PAC.
This involved returning more data from the pac functions, so changed
some callers and split up some functions.
Andrew Bartlett
(This used to be commit d514a7491208afa0533bf9e99601147eb69e08c9)
Diffstat (limited to 'source4/auth')
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 6 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 6 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 22 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 259 |
4 files changed, 196 insertions, 97 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 0a98b69f82..b6fda0402f 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -795,9 +795,9 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi gss_release_buffer(&min_stat, &pac); /* decode and verify the pac */ - nt_status = kerberos_decode_pac(mem_ctx, &logon_info, pac_blob, - gensec_gssapi_state->smb_krb5_context, - NULL, keyblock); + nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob, + gensec_gssapi_state->smb_krb5_context, + NULL, keyblock); if (NT_STATUS_IS_OK(nt_status)) { union netr_Validation validation; diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index 76f9171713..2568f11006 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -449,9 +449,9 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security account_name = principal; /* decode and verify the pac */ - nt_status = kerberos_decode_pac(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, - gensec_krb5_state->smb_krb5_context, - NULL, gensec_krb5_state->keyblock); + nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, + gensec_krb5_state->smb_krb5_context, + NULL, gensec_krb5_state->keyblock); /* IF we have the PAC - otherwise we need to get this * data from elsewere - local ldb, or (TODO) lookup of some diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index dcafea3c0c..0f1b0779b2 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -127,17 +127,29 @@ NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx, struct smb_krb5_context *smb_krb5_context, krb5_keytab *keytab); NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info_out, + struct PAC_DATA **pac_data_out, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, - krb5_keyblock *service_keyblock, - krb5_keyblock *krbtgt_keyblock); - -krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock); +NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + struct smb_krb5_context *smb_krb5_context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock); +krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info *server_info, krb5_context context, krb5_keyblock *krbtgt_keyblock, krb5_keyblock *server_keyblock, DATA_BLOB *pac); + +krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct PAC_DATA *pac_data, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + DATA_BLOB *pac); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index f561bdfe76..83679972d9 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -78,7 +78,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, } NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info_out, + struct PAC_DATA **pac_data_out, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, krb5_keyblock *krbtgt_keyblock, @@ -90,46 +90,50 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, struct PAC_SIGNATURE_DATA kdc_sig; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_LOGON_INFO *logon_info = NULL; - struct PAC_DATA pac_data; + struct PAC_DATA *pac_data; + DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); int i; - /* file_save("tmp_pac_data.dat",blob.data,blob.length); */ + pac_data = talloc(mem_ctx, struct PAC_DATA); + if (!pac_data) { + return NT_STATUS_NO_MEMORY; + } - status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data, - (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); + 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) { + 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) { + 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) { + if (!pac_data->buffers[i].info) { break; } - logon_info = pac_data.buffers[i].info->logon_info.info; + logon_info = pac_data->buffers[i].info->logon_info.info; break; case PAC_TYPE_SRV_CHECKSUM: - if (!pac_data.buffers[i].info) { + if (!pac_data->buffers[i].info) { break; } - srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum; - srv_sig = pac_data.buffers[i].info->srv_cksum; + srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum; + srv_sig = pac_data->buffers[i].info->srv_cksum; break; case PAC_TYPE_KDC_CHECKSUM: - if (!pac_data.buffers[i].info) { + if (!pac_data->buffers[i].info) { break; } - kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum; - kdc_sig = pac_data.buffers[i].info->kdc_cksum; + kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum; + kdc_sig = pac_data->buffers[i].info->kdc_cksum; break; case PAC_TYPE_LOGON_NAME: break; @@ -181,16 +185,56 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, } } +#if 0 + if (strcasecmp(logon_info->info3.base.account_name.string, + "Administrator")== 0) { + file_save("tmp_pac_data-admin.dat",blob.data,blob.length); + } +#endif + DEBUG(0,("account_name: %s [%s]\n", logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); - *logon_info_out = logon_info; + *pac_data_out = pac_data; return status; } + NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + struct smb_krb5_context *smb_krb5_context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock) +{ + NTSTATUS nt_status; + struct PAC_DATA *pac_data; + int i; + + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, + blob, + smb_krb5_context, + krbtgt_keyblock, + service_keyblock); + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + *logon_info = NULL; + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) { + continue; + } + *logon_info = pac_data->buffers[i].info->logon_info.info; + } + if (!*logon_info) { + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_OK; +} + static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, + DATA_BLOB *pac_data, struct PAC_SIGNATURE_DATA *sig, krb5_context context, krb5_keyblock *keyblock) @@ -205,15 +249,16 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, 0, &crypto); if (ret) { - DEBUG(0,("krb5_crypto_init() failed\n")); + DEBUG(0,("krb5_crypto_init() failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); return ret; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, - pac_data.data, - pac_data.length, + pac_data->data, + pac_data->length, &cksum); if (ret) { DEBUG(2, ("PAC Verification failed: %s\n", @@ -235,6 +280,107 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct PAC_DATA *pac_data, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + DATA_BLOB *pac) +{ + NTSTATUS nt_status; + krb5_error_code ret; + DATA_BLOB zero_blob = data_blob(NULL, 0); + DATA_BLOB tmp_blob = data_blob(NULL, 0); + DATA_BLOB service_checksum_blob; + struct PAC_SIGNATURE_DATA *kdc_checksum = NULL; + struct PAC_SIGNATURE_DATA *srv_checksum = NULL; + int i; + + /* First, just get the keytypes filled in (and lengths right, eventually) */ + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_KDC_CHECKSUM) { + continue; + } + kdc_checksum = &pac_data->buffers[i].info->kdc_cksum, + ret = make_pac_checksum(mem_ctx, &zero_blob, + kdc_checksum, + context, krbtgt_keyblock); + if (ret) { + DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + } + + for (i=0; i < pac_data->num_buffers; i++) { + if (pac_data->buffers[i].type != PAC_TYPE_SRV_CHECKSUM) { + continue; + } + srv_checksum = &pac_data->buffers[i].info->srv_cksum; + ret = make_pac_checksum(mem_ctx, &zero_blob, + srv_checksum, + context, service_keyblock); + if (ret) { + DEBUG(2, ("making service PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + } + + if (!kdc_checksum) { + DEBUG(2, ("Invalid PAC constructed for signing, no KDC checksum present!")); + return EINVAL; + } + if (!srv_checksum) { + DEBUG(2, ("Invalid PAC constructed for signing, no SRV checksum present!")); + return EINVAL; + } + + /* But wipe out the actual signatures */ + ZERO_STRUCT(kdc_checksum->signature); + ZERO_STRUCT(srv_checksum->signature); + + nt_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(nt_status)) { + DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + /* Then sign the result of the previous push, where the sig was zero'ed out */ + ret = make_pac_checksum(mem_ctx, &tmp_blob, srv_checksum, + context, service_keyblock); + + service_checksum_blob + = data_blob_const(srv_checksum->signature, sizeof(srv_checksum->signature)); + + /* Then sign Server checksum */ + ret = make_pac_checksum(mem_ctx, &service_checksum_blob, kdc_checksum, context, krbtgt_keyblock); + if (ret) { + DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + + /* And push it out again, this time to the world. This relies on determanistic pointer values */ + nt_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(nt_status)) { + DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + *pac = tmp_blob; + + return ret; +} + + + krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info *server_info, krb5_context context, krb5_keyblock *krbtgt_keyblock, @@ -242,9 +388,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB *pac) { NTSTATUS nt_status; - DATA_BLOB zero_blob = data_blob(NULL, 0); - DATA_BLOB tmp_blob = data_blob(NULL, 0); - DATA_BLOB service_checksum_blob; krb5_error_code ret; struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); struct netr_SamInfo3 *sam3; @@ -254,9 +397,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, union PAC_INFO *u_LOGON_NAME; struct PAC_LOGON_NAME *LOGON_NAME; union PAC_INFO *u_KDC_CHECKSUM; - struct PAC_SIGNATURE_DATA *KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; - struct PAC_SIGNATURE_DATA *SRV_CHECKSUM; enum { PAC_BUF_LOGON_INFO = 0, @@ -308,7 +449,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM; pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM; - SRV_CHECKSUM = &u_SRV_CHECKSUM->srv_cksum; /* KDC_CHECKSUM */ u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); @@ -318,7 +458,6 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, } pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM; pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM; - KDC_CHECKSUM = &u_KDC_CHECKSUM->kdc_cksum; /* now the real work begins... */ @@ -341,64 +480,12 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, LOGON_NAME->account_name = server_info->account_name; LOGON_NAME->logon_time = timeval_to_nttime(&tv); - - - /* First, just get the keytypes filled in (and lengths right, eventually) */ - ret = make_pac_checksum(mem_ctx, zero_blob, KDC_CHECKSUM, context, krbtgt_keyblock); - if (ret) { - DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - ret = make_pac_checksum(mem_ctx, zero_blob, SRV_CHECKSUM, context, service_keyblock); - if (ret) { - DEBUG(2, ("making service PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - /* But wipe out the actual signatures */ - ZERO_STRUCT(KDC_CHECKSUM->signature); - ZERO_STRUCT(SRV_CHECKSUM->signature); - - nt_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(nt_status)) { - DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); - talloc_free(pac_data); - return EINVAL; - } - - /* Then sign the result of the previous push, where the sig was zero'ed out */ - ret = make_pac_checksum(mem_ctx, tmp_blob, SRV_CHECKSUM, - context, service_keyblock); - - service_checksum_blob - = data_blob_const(SRV_CHECKSUM->signature, sizeof(SRV_CHECKSUM->signature)); - - /* Then sign Server checksum */ - ret = make_pac_checksum(mem_ctx, service_checksum_blob, KDC_CHECKSUM, context, krbtgt_keyblock); - if (ret) { - DEBUG(2, ("making krbtgt PAC checksum failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - talloc_free(pac_data); - return ret; - } - - /* And push it out again, this time to the world. This relies on determanistic pointer values */ - nt_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(nt_status)) { - DEBUG(1, ("PAC (final) push failed: %s\n", nt_errstr(nt_status))); - talloc_free(pac_data); - return EINVAL; - } - - *pac = tmp_blob; - + ret = kerberos_encode_pac(mem_ctx, + pac_data, + context, + krbtgt_keyblock, + service_keyblock, + pac); talloc_free(pac_data); return ret; } |