diff options
Diffstat (limited to 'source3/libads/kerberos_verify.c')
-rw-r--r-- | source3/libads/kerberos_verify.c | 130 |
1 files changed, 113 insertions, 17 deletions
diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index de3fdeb9de6..b903b2a6eb8 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -31,6 +31,87 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); #endif +static bool ads_dedicated_keytab_verify_ticket(krb5_context context, + krb5_auth_context auth_context, + const DATA_BLOB *ticket, + krb5_ticket **pp_tkt, + krb5_keyblock **keyblock, + krb5_error_code *perr) +{ + krb5_error_code ret = 0; + bool auth_ok = false; + krb5_keytab keytab = NULL; + krb5_keytab_entry kt_entry; + krb5_ticket *dec_ticket = NULL; + + krb5_data packet; + krb5_kvno kvno = 0; + krb5_enctype enctype; + + *pp_tkt = NULL; + *keyblock = NULL; + *perr = 0; + + ZERO_STRUCT(kt_entry); + + ret = smb_krb5_open_keytab(context, lp_dedicated_keytab_file(), true, + &keytab); + if (ret) { + DEBUG(1, ("smb_krb5_open_keytab failed (%s)\n", + error_message(ret))); + goto out; + } + + packet.length = ticket->length; + packet.data = (char *)ticket->data; + + ret = krb5_rd_req(context, &auth_context, &packet, NULL, keytab, + NULL, &dec_ticket); + if (ret) { + DEBUG(0, ("krb5_rd_req failed (%s)\n", error_message(ret))); + goto out; + } + +#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */ + enctype = dec_ticket->ticket.key.keytype; +#else /* MIT */ + enctype = dec_ticket->enc_part.enctype; + kvno = dec_ticket->enc_part.kvno; +#endif + + /* Get the key for checking the pac signature */ + ret = krb5_kt_get_entry(context, keytab, dec_ticket->server, + kvno, enctype, &kt_entry); + if (ret) { + DEBUG(0, ("krb5_kt_get_entry failed (%s)\n", + error_message(ret))); + goto out; + } + + ret = krb5_copy_keyblock(context, KRB5_KT_KEY(&kt_entry), keyblock); + smb_krb5_kt_free_entry(context, &kt_entry); + + if (ret) { + DEBUG(0, ("failed to copy key: %s\n", + error_message(ret))); + goto out; + } + + auth_ok = true; + *pp_tkt = dec_ticket; + dec_ticket = NULL; + + out: + if (dec_ticket) + krb5_free_ticket(context, dec_ticket); + + if (keytab) + krb5_kt_close(context, keytab); + + *perr = ret; + return auth_ok; +} + /********************************************************************************** Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so it's more like what microsoft does... see comment in utils/net_ads.c in the @@ -437,22 +518,38 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } } - /* Try secrets.tdb first and fallback to the krb5.keytab if - necessary */ - - auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, - ticket, &tkt, &keyblock, &ret); - - if (!auth_ok && - (ret == KRB5KRB_AP_ERR_TKT_NYV || - ret == KRB5KRB_AP_ERR_TKT_EXPIRED || - ret == KRB5KRB_AP_ERR_SKEW)) { - goto auth_failed; - } - - if (!auth_ok && lp_use_kerberos_keytab()) { - auth_ok = ads_keytab_verify_ticket(context, auth_context, - ticket, &tkt, &keyblock, &ret); + switch (lp_kerberos_method()) { + default: + case KERBEROS_VERIFY_SECRETS: + auth_ok = ads_secrets_verify_ticket(context, auth_context, + host_princ, ticket, &tkt, &keyblock, &ret); + break; + case KERBEROS_VERIFY_SYSTEM_KEYTAB: + auth_ok = ads_keytab_verify_ticket(context, auth_context, + ticket, &tkt, &keyblock, &ret); + break; + case KERBEROS_VERIFY_DEDICATED_KEYTAB: + auth_ok = ads_dedicated_keytab_verify_ticket(context, + auth_context, ticket, &tkt, &keyblock, &ret); + break; + case KERBEROS_VERIFY_SECRETS_AND_KEYTAB: + /* First try secrets.tdb and fallback to the krb5.keytab if + necessary. This is the pre 3.4 behavior when + "use kerberos keytab" was true.*/ + auth_ok = ads_secrets_verify_ticket(context, auth_context, + host_princ, ticket, &tkt, &keyblock, &ret); + + if (!auth_ok) { + /* Only fallback if we failed to decrypt the ticket */ + if (ret != KRB5KRB_AP_ERR_TKT_NYV && + ret != KRB5KRB_AP_ERR_TKT_EXPIRED && + ret != KRB5KRB_AP_ERR_SKEW) { + auth_ok = ads_keytab_verify_ticket(context, + auth_context, ticket, &tkt, &keyblock, + &ret); + } + } + break; } if ( use_replay_cache ) { @@ -465,7 +562,6 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, #endif } - auth_failed: if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); |