diff options
Diffstat (limited to 'source4/auth/kerberos')
-rw-r--r-- | source4/auth/kerberos/clikrb5.c | 10 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 49 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 96 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_verify.c | 216 |
4 files changed, 149 insertions, 222 deletions
diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c index 40c1e254f8..e3f2057b44 100644 --- a/source4/auth/kerberos/clikrb5.c +++ b/source4/auth/kerberos/clikrb5.c @@ -375,11 +375,13 @@ cleanup_princ: #if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING) char *context_error = krb5_get_error_string(context); - ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error); - krb5_free_error_string(context, context_error); -#else - ret = talloc_strdup(mem_ctx, error_message(code)); + if (context_error) { + ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error); + krb5_free_error_string(context, context_error); + return ret; + } #endif + ret = talloc_strdup(mem_ctx, error_message(code)); return ret; } diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index 39bba5f46f..9535094e2b 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -92,13 +92,12 @@ krb5_error_code ads_krb5_mk_req(krb5_context context, krb5_data *outbuf); DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, krb5_ticket *tkt); - NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, + const DATA_BLOB *enc_ticket, + krb5_ticket **tkt, DATA_BLOB *ap_rep, krb5_keyblock **keyblock); int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, @@ -125,6 +124,10 @@ krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, krb5_principal *salt_princ); +krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *princ); NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, @@ -134,26 +137,30 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, 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, - krb5_context 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, - time_t tgs_authtime, - DATA_BLOB *pac); - -krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime); + NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime); + 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); + DATA_BLOB *pac) ; + 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 *service_keyblock, + krb5_principal client_principal, + time_t tgs_authtime, + DATA_BLOB *pac); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index b26a25eac1..3294699070 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -33,11 +33,11 @@ #include "librpc/gen_ndr/ndr_krb5pac.h" #include "auth/auth.h" -static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - krb5_context context, - krb5_keyblock *keyblock) +static krb5_error_code 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; @@ -55,7 +55,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, if (ret) { DEBUG(0,("krb5_crypto_init() failed: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); - return NT_STATUS_FOOBAR; + return ret; } ret = krb5_verify_checksum(context, crypto, @@ -63,18 +63,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, 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 NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; + return ret; } NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, @@ -82,17 +73,23 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock) + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime) { + krb5_error_code ret; NTSTATUS status; struct PAC_SIGNATURE_DATA srv_sig; struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL; struct PAC_SIGNATURE_DATA kdc_sig; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_LOGON_INFO *logon_info = NULL; + struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_DATA *pac_data; DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); + NTTIME tgs_authtime_nttime; + krb5_principal client_principal_pac; int i; pac_data = talloc(mem_ctx, struct PAC_DATA); @@ -136,6 +133,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, kdc_sig = pac_data->buffers[i].info->kdc_cksum; break; case PAC_TYPE_LOGON_NAME: + logon_name = &pac_data->buffers[i].info->logon_name; break; default: break; @@ -163,28 +161,54 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, '\0', 16); /* verify by service_key */ - status = check_pac_checksum(mem_ctx, + ret = check_pac_checksum(mem_ctx, modified_pac_blob, &srv_sig, context, service_keyblock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("PAC Decode: Failed to verify the service signature\n")); - return status; + if (ret) { + DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_ACCESS_DENIED; } if (krbtgt_keyblock) { DATA_BLOB service_checksum_blob = data_blob_const(srv_sig_ptr->signature, sizeof(srv_sig_ptr->signature)); - status = check_pac_checksum(mem_ctx, + ret = check_pac_checksum(mem_ctx, service_checksum_blob, &kdc_sig, context, krbtgt_keyblock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("PAC Decode: Failed to verify the krbtgt signature\n")); - return status; + if (ret) { + DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_ACCESS_DENIED; } } + /* Convert to NT time, so as not to loose accuracy in comparison */ + unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); + + if (tgs_authtime_nttime != logon_name->logon_time) { + DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n")); + DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time))); + DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime))); + return NT_STATUS_ACCESS_DENIED; + } + + ret = krb5_parse_name_norealm(context, logon_name->account_name, &client_principal_pac); + if (ret) { + DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", + logon_name->account_name, + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) { + DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", + logon_name->account_name)); + return NT_STATUS_ACCESS_DENIED; + } + #if 0 if (strcasecmp(logon_info->info3.base.account_name.string, "Administrator")== 0) { @@ -205,7 +229,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock) + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime) { NTSTATUS nt_status; struct PAC_DATA *pac_data; @@ -215,7 +241,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, blob, context, krbtgt_keyblock, - service_keyblock); + service_keyblock, + client_principal, + tgs_authtime); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -275,6 +303,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, if (cksum.checksum.length == sizeof(sig->signature)) { memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature)); } + free_Checksum(&cksum); return 0; } @@ -385,6 +414,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, krb5_context context, krb5_keyblock *krbtgt_keyblock, krb5_keyblock *service_keyblock, + krb5_principal client_principal, time_t tgs_authtime, DATA_BLOB *pac) { @@ -400,6 +430,8 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, union PAC_INFO *u_KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; + char *name; + enum { PAC_BUF_LOGON_INFO = 0, PAC_BUF_LOGON_NAME = 1, @@ -478,11 +510,15 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, LOGON_INFO->info3 = *sam3; LOGON_INFO->info3.base.last_logon = timeval_to_nttime(&tv); - LOGON_NAME->account_name = server_info->account_name; - + ret = krb5_unparse_name_norealm(context, client_principal, &name); + if (ret) { + return ret; + } + LOGON_NAME->account_name = talloc_strdup(LOGON_NAME, name); + free(name); /* this logon_time field is absolutely critical. This is what - caused all our pac troubles :-) + caused all our PAC troubles :-) */ unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime); diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c index b140eb6ae9..dec084299b 100644 --- a/source4/auth/kerberos/kerberos_verify.c +++ b/source4/auth/kerberos/kerberos_verify.c @@ -71,9 +71,10 @@ DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data) ***********************************************************************************/ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *service, - const DATA_BLOB *ticket, krb5_data *p_packet, + const krb5_data *p_packet, + krb5_flags *ap_req_options, krb5_ticket **pp_tkt, krb5_keyblock **keyblock) { @@ -146,12 +147,10 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex } number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + ret = krb5_rd_req_return_keyblock(context, auth_context, p_packet, kt_entry.principal, keytab, - NULL, pp_tkt, keyblock); + ap_req_options, 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", @@ -216,121 +215,28 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex } /********************************************************************************** - Try to verify a ticket using the secrets.tdb. -***********************************************************************************/ - -static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, - struct cli_credentials *machine_account, - krb5_context context, - krb5_auth_context auth_context, - krb5_principal salt_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, - krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) -{ - krb5_error_code ret = 0; - krb5_error_code our_ret; - krb5_data password; - krb5_enctype *enctypes = NULL; - int i; - char *password_s = talloc_strdup(mem_ctx, cli_credentials_get_password(machine_account)); - if (!password_s) { - DEBUG(1, ("ads_secrets_verify_ticket: Could not obtain password for our local machine account!\n")); - return ENOENT; - } - - ZERO_STRUCTP(keyblock); - - password.data = password_s; - password.length = strlen(password_s); - - /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - - if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) { - DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n", - error_message(ret))); - - krb5_free_principal(context, salt_princ); - return ret; - } - - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; - - /* We need to setup a auth context with each possible encoding type in turn. */ - - ret = KRB5_BAD_ENCTYPE; - for (i=0;enctypes[i];i++) { - krb5_keyblock *key = NULL; - - if (!(key = malloc_p(krb5_keyblock))) { - break; - } - - if (create_kerberos_key_from_string(context, salt_princ, &password, key, enctypes[i])) { - SAFE_FREE(key); - continue; - } - - krb5_auth_con_setuseruserkey(context, auth_context, key); - - krb5_free_keyblock(context, key); - - 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", - (unsigned int)enctypes[i] )); - ret = our_ret; - break; - } - - DEBUG((our_ret != KRB5_BAD_ENCTYPE) ? 3 : 10, - ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", - (unsigned int)enctypes[i], smb_get_krb5_error_message(context, our_ret, mem_ctx))); - - if (our_ret != KRB5_BAD_ENCTYPE) { - ret = our_ret; - } - } - - free_kerberos_etypes(context, enctypes); - - return ret; -} - -/********************************************************************************** Verify an incoming ticket and parse out the principal name and authorization_data if available. ***********************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, + const DATA_BLOB *enc_ticket, + krb5_ticket **tkt, DATA_BLOB *ap_rep, krb5_keyblock **keyblock) { - NTSTATUS sret = NT_STATUS_LOGON_FAILURE; + krb5_keyblock *local_keyblock; krb5_data packet; - krb5_ticket *tkt = NULL; krb5_principal salt_princ; int ret; + krb5_flags ap_req_options = 0; - char *malloc_principal; - - NTSTATUS creds_nt_status; + NTSTATUS creds_nt_status, status; struct cli_credentials *machine_account; - ZERO_STRUCT(packet); - ZERO_STRUCTP(auth_data); - ZERO_STRUCTP(ap_rep); - machine_account = cli_credentials_init(mem_ctx); cli_credentials_set_conf(machine_account); creds_nt_status = cli_credentials_set_machine_account(machine_account); @@ -360,78 +266,54 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, * directory. This will eventually prevent replay attacks */ + packet.length = enc_ticket->length; + packet.data = (krb5_pointer)enc_ticket->data; + ret = ads_keytab_verify_ticket(mem_ctx, smb_krb5_context->krb5_context, auth_context, - service, ticket, &packet, &tkt, keyblock); + service, &packet, &ap_req_options, tkt, &local_keyblock); if (ret && machine_account) { - ret = ads_secrets_verify_ticket(mem_ctx, machine_account, smb_krb5_context->krb5_context, auth_context, - salt_princ, ticket, - &packet, &tkt, keyblock); - } - - if (ret) { - goto out; + krb5_keytab keytab; + krb5_principal server; + status = create_memory_keytab(mem_ctx, machine_account, smb_krb5_context, + &keytab); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, + &server); + if (ret == 0) { + ret = krb5_rd_req_return_keyblock(smb_krb5_context->krb5_context, auth_context, &packet, + server, + keytab, &ap_req_options, tkt, + &local_keyblock); + } } - ret = krb5_mk_rep(smb_krb5_context->krb5_context, auth_context, &packet); if (ret) { - DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", + DEBUG(3,("ads_secrets_verify_ticket: failed to decrypt with error %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); - goto out; - } - - *ap_rep = data_blob_talloc(mem_ctx, packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; - -#if 0 - file_save("/tmp/ticket.dat", ticket->data, ticket->length); -#endif - - *auth_data = get_auth_data_from_tkt(mem_ctx, tkt); - - *auth_data = unwrap_pac(mem_ctx, auth_data); - -#if 0 - if (tkt->enc_part2) { - file_save("/tmp/authdata.dat", - tkt->enc_part2->authorization_data[0]->contents, - tkt->enc_part2->authorization_data[0]->length); + return NT_STATUS_LOGON_FAILURE; } -#endif + *keyblock = local_keyblock; - if ((ret = krb5_unparse_name(smb_krb5_context->krb5_context, get_principal_from_tkt(tkt), - &malloc_principal))) { - DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n", - smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); - sret = NT_STATUS_LOGON_FAILURE; - goto out; - } - - *principal = talloc_strdup(mem_ctx, malloc_principal); - SAFE_FREE(malloc_principal); - if (!principal) { - DEBUG(3,("ads_verify_ticket: talloc_strdup() failed\n")); - sret = NT_STATUS_NO_MEMORY; - goto out; - } - - sret = NT_STATUS_OK; - - out: - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(auth_data); - } - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(ap_rep); - } - - if (tkt != NULL) { - krb5_free_ticket(smb_krb5_context->krb5_context, tkt); + if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) { + krb5_data packet_out; + ret = krb5_mk_rep(smb_krb5_context->krb5_context, *auth_context, &packet_out); + if (ret) { + krb5_free_ticket(smb_krb5_context->krb5_context, *tkt); + + DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", + smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + return NT_STATUS_LOGON_FAILURE; + } + + *ap_rep = data_blob_talloc(mem_ctx, packet_out.data, packet_out.length); + krb5_free_data_contents(smb_krb5_context->krb5_context, &packet_out); + } else { + *ap_rep = data_blob(NULL, 0); } - return sret; + return NT_STATUS_OK; } #endif /* HAVE_KRB5 */ |