diff options
Diffstat (limited to 'source4/auth/kerberos')
-rw-r--r-- | source4/auth/kerberos/config.mk | 1 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 7 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 182 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_verify.c | 17 |
4 files changed, 184 insertions, 23 deletions
diff --git a/source4/auth/kerberos/config.mk b/source4/auth/kerberos/config.mk index 62710f3cc4..56ce64fdb1 100644 --- a/source4/auth/kerberos/config.mk +++ b/source4/auth/kerberos/config.mk @@ -8,5 +8,6 @@ ADD_OBJ_FILES = \ auth/kerberos/kerberos_util.o \ auth/kerberos/kerberos_pac.o \ auth/kerberos/gssapi_parse.o +REQUIRED_SUBSYSTEMS = KERBEROS_LIB NDR_KRB5PAC # End SUBSYSTEM KERBEROS ################################# diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index ca0bbbed0e..1fd48197f8 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -97,7 +97,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, char **principal, DATA_BLOB *auth_data, DATA_BLOB *ap_rep, - krb5_keyblock *keyblock); + krb5_keyblock **keyblock); int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, const char *principal, const char *password, time_t *expire_time, time_t *kdc_time); @@ -132,5 +132,10 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, krb5_keyblock *keyblock); +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); #endif /* HAVE_KRB5 */ 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; +} + diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c index 01b8a75c95..b140eb6ae9 100644 --- a/source4/auth/kerberos/kerberos_verify.c +++ b/source4/auth/kerberos/kerberos_verify.c @@ -75,7 +75,7 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex const char *service, const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { krb5_error_code ret = 0; krb5_keytab keytab = NULL; @@ -149,7 +149,9 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex p_packet->length = ticket->length; p_packet->data = (krb5_pointer)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req(context, &auth_context, p_packet, kt_entry.principal, keytab, NULL, pp_tkt); + ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + kt_entry.principal, keytab, + NULL, pp_tkt, keyblock); if (ret) { last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n", @@ -224,7 +226,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, krb5_principal salt_princ, const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { krb5_error_code ret = 0; krb5_error_code our_ret; @@ -274,9 +276,10 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, krb5_free_keyblock(context, key); - our_ret = krb5_rd_req(context, &auth_context, p_packet, - NULL, - NULL, NULL, pp_tkt); + our_ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + NULL, + NULL, NULL, pp_tkt, + keyblock); if (!our_ret) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", @@ -311,7 +314,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, char **principal, DATA_BLOB *auth_data, DATA_BLOB *ap_rep, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; krb5_data packet; |