diff options
author | Alexander Bokovoy <abokovoy@redhat.com> | 2012-08-20 13:26:20 +0300 |
---|---|---|
committer | Alexander Bokovoy <abokovoy@redhat.com> | 2012-08-22 17:20:56 +0300 |
commit | 14c48ba6fbb27a9d116da20f59be1cf5887b9b9e (patch) | |
tree | 247d017437db30010ef54c0c9c5dea6a96fceb93 /daemons | |
parent | e8d4cc65f8db57709e944400b9dac80c692fd950 (diff) | |
download | freeipa-14c48ba6fbb27a9d116da20f59be1cf5887b9b9e.tar.gz freeipa-14c48ba6fbb27a9d116da20f59be1cf5887b9b9e.tar.xz freeipa-14c48ba6fbb27a9d116da20f59be1cf5887b9b9e.zip |
Recover from invalid cached kerberos credentials in ipasam
When developing and testing in the same environment, multiple re-installs
may be needed. This means previously issued and cached Kerberos credentials
will become invalid upon new install.
ipasam passdb module for Samba uses Kerberos authentication when talking to
IPA LDAP server. Obtained Kerberos credentials are cached during their lifetime.
However, the ccache is not removed automatically and if IPA setup is made
again, cached credentials are used, only to discover that they are invalid.
With this change invalid correctly obtained cached credentials are recognized
and, if LDAP SASL bind fails, new credentials are requested from the KDC.
https://fedorahosted.org/freeipa/ticket/3009
Diffstat (limited to 'daemons')
-rw-r--r-- | daemons/ipa-sam/ipa_sam.c | 114 |
1 files changed, 77 insertions, 37 deletions
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c index aa54429b5..059109374 100644 --- a/daemons/ipa-sam/ipa_sam.c +++ b/daemons/ipa-sam/ipa_sam.c @@ -3204,49 +3204,70 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s return ret; } -static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *data, krb5_error_code rc) -{ + +static void bind_callback_cleanup_creds(struct ipasam_sasl_interact_priv *datap) { + krb5_free_cred_contents(datap->context, &datap->creds); + + if (datap->options) { + krb5_get_init_creds_opt_free(datap->context, datap->options); + datap->options = NULL; + } +} + +static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *datap, krb5_error_code rc) { const char *errstring = NULL; - if (!data->context) { + if (!datap->context) { return; } if (rc) { - errstring = krb5_get_error_message(data->context, rc); + errstring = krb5_get_error_message(datap->context, rc); DEBUG(0,("kerberos error: code=%d, message=%s\n", rc, errstring)); - krb5_free_error_message(data->context, errstring); + krb5_free_error_message(datap->context, errstring); } - krb5_free_cred_contents(data->context, &data->creds); + bind_callback_cleanup_creds(datap); + + if (datap->keytab) { + krb5_kt_close(datap->context, datap->keytab); + datap->keytab = NULL; + } - if (data->options) { - krb5_get_init_creds_opt_free(data->context, data->options); - data->options = NULL; + if (datap->ccache) { + krb5_cc_close(datap->context, datap->ccache); + datap->ccache = NULL; } - if (data->keytab) { - krb5_kt_close(data->context, data->keytab); - data->keytab = NULL; + if (datap->principal) { + krb5_free_principal(datap->context, datap->principal); + datap->principal = NULL; } - if (data->ccache) { - krb5_cc_close(data->context, data->ccache); - data->ccache = NULL; + krb5_free_context(datap->context); + datap->context = NULL; +} + +static krb5_error_code bind_callback_obtain_creds(struct ipasam_sasl_interact_priv *datap) { + krb5_error_code rc; + + rc = krb5_get_init_creds_opt_alloc(datap->context, &datap->options); + if (rc) { + return rc; } - if (data->principal) { - krb5_free_principal(data->context, data->principal); - data->principal = NULL; + rc = krb5_get_init_creds_opt_set_out_ccache(datap->context, datap->options, datap->ccache); + if (rc) { + return rc; } - krb5_free_context(data->context); - data->context = NULL; + rc = krb5_get_init_creds_keytab(datap->context, &datap->creds, datap->principal, datap->keytab, + 0, NULL, datap->options); + return rc; } extern const char * lp_dedicated_keytab_file(void); -static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, void* ipasam_priv) -{ +static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, void* ipasam_priv) { krb5_error_code rc; krb5_creds *out_creds = NULL; krb5_creds in_creds; @@ -3311,33 +3332,52 @@ static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, vo krb5_free_principal(data.context, in_creds.client); if (rc) { - rc = krb5_get_init_creds_opt_alloc(data.context, &data.options); + rc = bind_callback_obtain_creds(&data); if (rc) { bind_callback_cleanup(&data, rc); return LDAP_LOCAL_ERROR; } + } - rc = krb5_get_init_creds_opt_set_out_ccache(data.context, data.options, data.ccache); - if (rc) { - bind_callback_cleanup(&data, rc); - return LDAP_LOCAL_ERROR; - } + ret = ldap_sasl_interactive_bind_s(ldap_struct, + NULL, "GSSAPI", + NULL, NULL, + LDAP_SASL_QUIET, + ldap_sasl_interact, &data); - rc = krb5_get_init_creds_keytab(data.context, &data.creds, data.principal, data.keytab, - 0, NULL, data.options); + /* By now we have 'ret' for LDAP result and 'rc' for Kerberos result + * if ret is LDAP_INVALID_CREDENTIALS, LDAP server rejected our ccache. There may be several issues: + * + * 1. Credentials are invalid due to outdated ccache leftover from previous install + * Wipe out old ccache and start again + * + * 2. Key in the keytab is not enough to obtain ticket for cifs/FQDN@REALM service + * Cannot continue without proper keytab + * + * Only process (1) because (2) and other errors will be taken care of by smbd after multiple retries. + * + * Since both smbd and winbindd will use this passdb module, on startup both will try to access the same + * ccache. It may happen that if ccache was missing or contained invalid cached credentials, that one of + * them will complain loudly about missing ccache file at the time when the other one will be creating + * a new ccache file by the above call of bind_callback_obtain_creds(). This is expected and correct behavior. + * + */ + if ((ret == LDAP_INVALID_CREDENTIALS) && (rc == 0)) { + bind_callback_cleanup_creds(&data); + rc = bind_callback_obtain_creds(&data); if (rc) { bind_callback_cleanup(&data, rc); return LDAP_LOCAL_ERROR; } + ret = ldap_sasl_interactive_bind_s(ldap_struct, + NULL, "GSSAPI", + NULL, NULL, + LDAP_SASL_QUIET, + ldap_sasl_interact, &data); } - ret = ldap_sasl_interactive_bind_s(ldap_struct, - NULL, "GSSAPI", - NULL, NULL, - LDAP_SASL_QUIET, - ldap_sasl_interact, &data); - if (ret != LDAP_SUCCESS) { - DEBUG(0, ("bind_callback: cannot perform interactive SASL bind with GSSAPI\n")); + if (LDAP_SECURITY_ERROR(ret)) { + DEBUG(0, ("bind_callback: cannot perform interactive SASL bind with GSSAPI. LDAP security error is %d\n", ret)); } if (out_creds) { |