summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-sam
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/ipa-sam')
-rw-r--r--daemons/ipa-sam/ipa_sam.c114
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) {