diff options
Diffstat (limited to 'source4/auth/kerberos/kerberos_pac.c')
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 182 |
1 files changed, 167 insertions, 15 deletions
diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index 9d57245798..e1d05b9949 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -28,16 +28,16 @@ #include "system/kerberos.h" #include "system/time.h" #include "system/network.h" +#include "auth/auth.h" #include "auth/kerberos/kerberos.h" #include "librpc/gen_ndr/ndr_krb5pac.h" #include "auth/auth.h" -static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - struct smb_krb5_context *smb_krb5_context, - krb5_keyblock *keyblock, - uint32_t keyusage) +static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) { krb5_error_code ret; krb5_crypto crypto; @@ -48,7 +48,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, cksum.checksum.data = sig->signature; - ret = krb5_crypto_init(smb_krb5_context->krb5_context, + ret = krb5_crypto_init(context, keyblock, 0, &crypto); @@ -56,7 +56,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, DEBUG(0,("krb5_crypto_init() failed\n")); return NT_STATUS_FOOBAR; } - ret = krb5_verify_checksum(smb_krb5_context->krb5_context, + ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, pac_data.data, @@ -64,10 +64,10 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, &cksum); if (ret) { DEBUG(2, ("PAC Verification failed: %s\n", - smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + smb_get_krb5_error_message(context, ret, mem_ctx))); } - krb5_crypto_destroy(smb_krb5_context->krb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (ret) { return NT_STATUS_ACCESS_DENIED; @@ -92,6 +92,8 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); int i; + file_save("/tmp/pac.in", blob.data, blob.length); + 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)) { @@ -127,7 +129,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum; kdc_sig = pac_data.buffers[i].info->kdc_cksum; break; - case PAC_TYPE_UNKNOWN_10: + case PAC_TYPE_LOGON_NAME: break; default: break; @@ -154,11 +156,13 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, memset(&modified_pac_blob.data[modified_pac_blob.length - 44], '\0', 16); - /* verify by servie_key */ - status = kerberos_pac_checksum(mem_ctx, - modified_pac_blob, &srv_sig, - smb_krb5_context, keyblock, 0); + file_save("/tmp/pac.in.blanked", modified_pac_blob.data, modified_pac_blob.length); + /* verify by service_key */ + status = check_pac_checksum(mem_ctx, + modified_pac_blob, &srv_sig, + smb_krb5_context->krb5_context, keyblock); + if (!NT_STATUS_IS_OK(status)) { return status; } @@ -170,3 +174,151 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, return status; } +static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) +{ + krb5_error_code ret; + krb5_crypto crypto; + Checksum cksum; + + + ret = krb5_crypto_init(context, + keyblock, + 0, + &crypto); + if (ret) { + DEBUG(0,("krb5_crypto_init() failed\n")); + return ret; + } + ret = krb5_create_checksum(context, + crypto, + KRB5_KU_OTHER_CKSUM, + 0, + pac_data.data, + pac_data.length, + &cksum); + if (ret) { + DEBUG(2, ("PAC Verification failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + } + + krb5_crypto_destroy(context, crypto); + + if (ret) { + return ret; + } + + sig->type = cksum.cksumtype; + if (cksum.checksum.length == sizeof(sig->signature)) { + memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature)); + } + + return 0; +} + + krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + krb5_context context, + krb5_keyblock *keyblock, + krb5_data *pac) +{ + NTSTATUS nt_status; + DATA_BLOB tmp_blob = data_blob(NULL, 0); + krb5_error_code ret; + struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); + struct netr_SamBaseInfo *sam; + struct timeval tv = timeval_current(); + + if (!pac_data) { + return ENOMEM; + } + + pac_data->num_buffers = 4; + pac_data->version = 0; + + pac_data->buffers = talloc_array(pac_data, + struct PAC_BUFFER, + pac_data->num_buffers); + + if (!pac_data->buffers) { + talloc_free(pac_data); + return ENOMEM; + } + pac_data->buffers[0].type = PAC_TYPE_LOGON_INFO; + pac_data->buffers[0].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + nt_status = auth_convert_server_info_sambaseinfo(pac_data->buffers[0].info, + server_info, &sam); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + pac_data->buffers[0].info->logon_info.info3.base = *sam; + + pac_data->buffers[1].type = PAC_TYPE_LOGON_NAME; + pac_data->buffers[1].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + pac_data->buffers[1].info->logon_name.account_name + = server_info->account_name; + pac_data->buffers[1].info->logon_name.logon_time + = timeval_to_nttime(&tv); + + pac_data->buffers[2].type = PAC_TYPE_KDC_CHECKSUM; + pac_data->buffers[2].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + pac_data->buffers[3].type = PAC_TYPE_SRV_CHECKSUM; + pac_data->buffers[3].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + /* First, just get the keytypes filled in (and lengths right, eventually) */ + ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[2].info->srv_cksum, + context, keyblock); + if (ret) { + DEBUG(2, ("making 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(pac_data->buffers[2].info->kdc_cksum.signature); + ZERO_STRUCT(pac_data->buffers[3].info->srv_cksum.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 push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + file_save("/tmp/pac.out.blank", tmp_blob.data, tmp_blob.length); + + /* Then sign the result of the previous push, where the sig was zero'ed out */ + ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[3].info->srv_cksum, + context, keyblock); + + /* And push it out 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 push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + file_save("/tmp/pac.out.signed", tmp_blob.data, tmp_blob.length); + + ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length); + + talloc_free(pac_data); + return ret; +} + |