summaryrefslogtreecommitdiff
path: root/auth
diff options
context:
space:
mode:
authorSamuel Cabrero <scabrero@suse.de>2019-03-27 17:12:09 +0100
committerJeremy Allison <jra@samba.org>2019-04-29 19:15:48 +0000
commitd88f1c82b2fa682ca3ed0256b4728f7e1b6999fc (patch)
treef067caedad62a2a5a5d1e17c73ba7b2c9c77f7fc /auth
parent937ad9d2a00d1b993d37ff5801fd301eccd87556 (diff)
downloadsamba-d88f1c82b2fa682ca3ed0256b4728f7e1b6999fc.tar.gz
credentials: Workaround krb5_cc_remove_cred not implemented in MIT kerberos
Signed-off-by: Samuel Cabrero <scabrero@suse.de> Reviewed-by: Andreas Schneider <asn@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Autobuild-User(master): Jeremy Allison <jra@samba.org> Autobuild-Date(master): Mon Apr 29 19:15:48 UTC 2019 on sn-devel-184
Diffstat (limited to 'auth')
-rw-r--r--auth/credentials/credentials_krb5.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c
index 901c573c655..20e677e521a 100644
--- a/auth/credentials/credentials_krb5.c
+++ b/auth/credentials/credentials_krb5.c
@@ -365,6 +365,144 @@ _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
return 0;
}
+#ifndef SAMBA4_USES_HEIMDAL
+/*
+ * This function is a workaround for old MIT Kerberos versions which did not
+ * implement the krb5_cc_remove_cred function. It creates a temporary
+ * credentials cache to copy the credentials in the current cache
+ * except the one we want to remove and then overwrites the contents of the
+ * current cache with the temporary copy.
+ */
+static krb5_error_code krb5_cc_remove_cred_wrap(struct ccache_container *ccc,
+ krb5_creds *creds)
+{
+ krb5_ccache dummy_ccache = NULL;
+ krb5_creds cached_creds = {0};
+ krb5_cc_cursor cursor = NULL;
+ krb5_error_code code;
+ char *dummy_name;
+
+ dummy_name = talloc_asprintf(ccc,
+ "MEMORY:copy_ccache-%p",
+ &ccc->ccache);
+ if (dummy_name == NULL) {
+ return KRB5_CC_NOMEM;
+ }
+
+ code = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context,
+ dummy_name,
+ &dummy_ccache);
+ if (code != 0) {
+ DBG_ERR("krb5_cc_resolve failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ TALLOC_FREE(dummy_name);
+ return code;
+ }
+
+ TALLOC_FREE(dummy_name);
+
+ code = krb5_cc_start_seq_get(ccc->smb_krb5_context->krb5_context,
+ ccc->ccache,
+ &cursor);
+ if (code != 0) {
+ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+
+ DBG_ERR("krb5_cc_start_seq_get failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+
+ while ((code = krb5_cc_next_cred(ccc->smb_krb5_context->krb5_context,
+ ccc->ccache,
+ &cursor,
+ &cached_creds)) == 0) {
+ /* If the principal matches skip it and do not copy to the
+ * temporary cache as this is the one we want to remove */
+ if (krb5_principal_compare_flags(
+ ccc->smb_krb5_context->krb5_context,
+ creds->server,
+ cached_creds.server,
+ 0)) {
+ continue;
+ }
+
+ code = krb5_cc_store_cred(
+ ccc->smb_krb5_context->krb5_context,
+ dummy_ccache,
+ &cached_creds);
+ if (code != 0) {
+ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+ DBG_ERR("krb5_cc_store_cred failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+ }
+
+ if (code == KRB5_CC_END) {
+ krb5_cc_end_seq_get(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache,
+ &cursor);
+ code = 0;
+ }
+
+ if (code != 0) {
+ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+ DBG_ERR("krb5_cc_next_cred failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+
+ code = krb5_cc_initialize(ccc->smb_krb5_context->krb5_context,
+ ccc->ccache,
+ creds->client);
+ if (code != 0) {
+ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+ DBG_ERR("krb5_cc_initialize failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+
+ code = krb5_cc_copy_creds(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache,
+ ccc->ccache);
+ if (code != 0) {
+ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+ DBG_ERR("krb5_cc_copy_creds failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+
+ code = krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
+ dummy_ccache);
+ if (code != 0) {
+ DBG_ERR("krb5_cc_destroy failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ code, ccc));
+ return code;
+ }
+
+ return code;
+}
+#endif
+
/*
* Indicate the we failed to log in to this service/host with these
* credentials. The caller passes an unsigned int which they
@@ -429,6 +567,13 @@ _PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred
}
ret = krb5_cc_remove_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds);
+#ifndef SAMBA4_USES_HEIMDAL
+ if (ret == KRB5_CC_NOSUPP) {
+ /* Old MIT kerberos versions did not implement
+ * krb5_cc_remove_cred */
+ ret = krb5_cc_remove_cred_wrap(ccc, &creds);
+ }
+#endif
krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds);
krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds2);
if (ret != 0) {
@@ -438,6 +583,10 @@ _PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred
* creds don't exist, which is why we do a separate
* krb5_cc_retrieve_cred() above.
*/
+ DBG_ERR("krb5_cc_remove_cred failed: %s\n",
+ smb_get_krb5_error_message(
+ ccc->smb_krb5_context->krb5_context,
+ ret, ccc));
return false;
}
return true;