[sssd/f20] Backport simplification of ccache management from 1.11.1
Jakub Hrozek
jhrozek at fedoraproject.org
Mon Sep 23 12:46:55 UTC 2013
commit 41b3a01afa70c32787258641bc916bd9a58f91e0
Author: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon Sep 23 12:23:42 2013 +0200
Backport simplification of ccache management from 1.11.1
- Resolves: rhbz#1010553 - sssd setting KRB5CCNAME=(null) on login
...d-calls-to-change-and-restore-credentials.patch | 168 ++++++
...krb5-Add-helper-to-destroy-ccache-as-user.patch | 154 ++++++
...Use-krb5_cc_destroy-to-remove-old-ccaches.patch | 279 ++++++++++
...lace-type-specific-ccache-principal-check.patch | 357 ++++++++++++
...5-Move-determination-of-user-being-active.patch | 220 ++++++++
...b5-move-template-check-to-initializzation.patch | 160 ++++++
0007-krb5-Make-check_for_valid_tgt-static.patch | 201 +++++++
...krb5-Use-new-function-to-validate-ccaches.patch | 568 +++++++++++++++++++
...rb5-Unify-function-to-create-ccache-files.patch | 348 ++++++++++++
...move-unused-ccache-backend-infrastructure.patch | 337 +++++++++++
0011-krb5-Remove-unused-function.patch | 69 +++
0012-krb5-Add-file-dir-path-precheck.patch | 97 ++++
0013-krb5_child-Simplify-ccache-creation.patch | 582 ++++++++++++++++++++
0014-krb5-Remove-unused-helper-functions.patch | 127 +++++
sssd.spec | 20 +-
15 files changed, 3686 insertions(+), 1 deletions(-)
---
diff --git a/0001-krb5-Add-calls-to-change-and-restore-credentials.patch b/0001-krb5-Add-calls-to-change-and-restore-credentials.patch
new file mode 100644
index 0000000..e377e55
--- /dev/null
+++ b/0001-krb5-Add-calls-to-change-and-restore-credentials.patch
@@ -0,0 +1,168 @@
+From 0371fbcf60d4dd8e25b9bb0a83029c812b66f3d6 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Wed, 28 Aug 2013 21:19:32 -0400
+Subject: [PATCH 01/14] krb5: Add calls to change and restore credentials
+
+In some cases we want to temporarily assume user credentials but allow the
+process to regain back the original credentials (normally regaining uid 0).
+
+Related:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_become_user.c | 125 ++++++++++++++++++++++++++++++++++
+ src/providers/krb5/krb5_utils.h | 6 ++
+ 2 files changed, 131 insertions(+)
+
+diff --git a/src/providers/krb5/krb5_become_user.c b/src/providers/krb5/krb5_become_user.c
+index 70bc5630ece21505b58bd1a8795d7ab4b7864460..567cf237569f70a6b0fd500327438f2dbb08d24d 100644
+--- a/src/providers/krb5/krb5_become_user.c
++++ b/src/providers/krb5/krb5_become_user.c
+@@ -70,3 +70,128 @@ errno_t become_user(uid_t uid, gid_t gid)
+ return EOK;
+ }
+
++struct sss_creds {
++ uid_t uid;
++ gid_t gid;
++ int num_gids;
++ gid_t gids[];
++};
++
++errno_t restore_creds(struct sss_creds *saved_creds);
++
++/* This is a reversible version of become_user, and returns the saved
++ * credentials so that creds can be switched back calling restore_creds */
++errno_t switch_creds(TALLOC_CTX *mem_ctx,
++ uid_t uid, gid_t gid,
++ int num_gids, gid_t *gids,
++ struct sss_creds **saved_creds)
++{
++ struct sss_creds *ssc = NULL;
++ int size;
++ int ret;
++
++ DEBUG(SSSDBG_FUNC_DATA, ("Switch user to [%d][%d].\n", uid, gid));
++
++ if (saved_creds) {
++ /* save current user credentials */
++ size = getgroups(0, NULL);
++ if (size == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Getgroups failed! (%d, %s)\n",
++ ret, strerror(ret)));
++ goto done;
++ }
++
++ ssc = talloc_size(mem_ctx,
++ (sizeof(struct sss_creds) + size * sizeof(gid_t)));
++ if (!ssc) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation failed!\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++ ssc->num_gids = size;
++
++ size = getgroups(ssc->num_gids, ssc->gids);
++ if (size == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Getgroups failed! (%d, %s)\n",
++ ret, strerror(ret)));
++ /* free ssc immediately otherwise the code will try to restore
++ * wrong creds */
++ talloc_zfree(ssc);
++ goto done;
++ }
++
++ /* we care only about effective ids */
++ ssc->uid = geteuid();
++ ssc->gid = getegid();
++ }
++
++ /* if we are regaining root set euid first so that we have CAP_SETUID back,
++ * ane the other calls work too, otherwise call it last so that we can
++ * change groups before we loose CAP_SETUID */
++ if (uid == 0) {
++ ret = setresuid(0, 0, 0);
++ if (ret == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE,
++ ("setresuid failed [%d][%s].\n", ret, strerror(ret)));
++ goto done;
++ }
++ }
++
++ /* TODO: use prctl to get/set capabilities too ? */
++
++ /* try to setgroups first should always work if CAP_SETUID is set,
++ * otherwise it will always fail, failure is not critical though as
++ * generally we only really care about uid and at mot primary gid */
++ ret = setgroups(num_gids, gids);
++ if (ret == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_TRACE_FUNC,
++ ("setgroups failed [%d][%s].\n", ret, strerror(ret)));
++ }
++
++ /* change gid now, (leaves saved gid to current, so we can restore) */
++ ret = setresgid(-1, gid, -1);
++ if (ret == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE,
++ ("setresgid failed [%d][%s].\n", ret, strerror(ret)));
++ goto done;
++ }
++
++ if (uid != 0) {
++ /* change uid, (leaves saved uid to current, so we can restore) */
++ ret = setresuid(-1, uid, -1);
++ if (ret == -1) {
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE,
++ ("setresuid failed [%d][%s].\n", ret, strerror(ret)));
++ goto done;
++ }
++ }
++
++ ret = 0;
++
++done:
++ if (ret) {
++ if (ssc) {
++ /* attempt to restore creds first */
++ restore_creds(ssc);
++ talloc_free(ssc);
++ }
++ } else if (saved_creds) {
++ *saved_creds = ssc;
++ }
++ return ret;
++}
++
++errno_t restore_creds(struct sss_creds *saved_creds)
++{
++ return switch_creds(saved_creds,
++ saved_creds->uid,
++ saved_creds->gid,
++ saved_creds->num_gids,
++ saved_creds->gids, NULL);
++}
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index cdc9f23641905cff300077f708087e98ba683e0d..aac3ec72ec7e1664ae96cc4e53d368e22448f5f1 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -80,6 +80,12 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+ bool case_sensitive, bool *private_path);
+
+ errno_t become_user(uid_t uid, gid_t gid);
++struct sss_creds;
++errno_t switch_creds(TALLOC_CTX *mem_ctx,
++ uid_t uid, gid_t gid,
++ int num_gids, gid_t *gids,
++ struct sss_creds **saved_creds);
++errno_t restore_creds(struct sss_creds *saved_creds);
+
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ struct tgt_times *tgtt);
+--
+1.8.3.1
+
diff --git a/0002-krb5-Add-helper-to-destroy-ccache-as-user.patch b/0002-krb5-Add-helper-to-destroy-ccache-as-user.patch
new file mode 100644
index 0000000..6c4c8b5
--- /dev/null
+++ b/0002-krb5-Add-helper-to-destroy-ccache-as-user.patch
@@ -0,0 +1,154 @@
+From 04c49a183f49c28f9ef900bdbc4eb30f23278e17 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Wed, 28 Aug 2013 22:12:07 -0400
+Subject: [PATCH 02/14] krb5: Add helper to destroy ccache as user
+
+This function safely destroy a ccache given a cache name and user crdentials.
+It becomes the user so no possible races can compromise the system, then
+uses libkrb5 functions to properly destroy a ccache, independently of the
+cache type.
+Finally restores the original credentials after closing the ccache handlers.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_utils.c | 109 ++++++++++++++++++++++++++++++++++++++++
+ src/providers/krb5/krb5_utils.h | 2 +
+ 2 files changed, 111 insertions(+)
+
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 6bf1cf610dd20afc7a600e9505c4bae2ff675fcc..1141f3fc839a78927dab5f50267c52d5b44b46ba 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -818,6 +818,115 @@ done:
+ }
+
+
++struct sss_krb5_ccache {
++ struct sss_creds *creds;
++ krb5_context context;
++ krb5_ccache ccache;
++};
++
++static int sss_free_krb5_ccache(void *mem)
++{
++ struct sss_krb5_ccache *cc = talloc_get_type(mem, struct sss_krb5_ccache);
++
++ if (cc->ccache) {
++ krb5_cc_close(cc->context, cc->ccache);
++ }
++ krb5_free_context(cc->context);
++ restore_creds(cc->creds);
++ return 0;
++}
++
++static errno_t sss_open_ccache_as_user(TALLOC_CTX *mem_ctx,
++ const char *ccname,
++ uid_t uid, gid_t gid,
++ struct sss_krb5_ccache **ccache)
++{
++ struct sss_krb5_ccache *cc;
++ krb5_error_code kerr;
++ errno_t ret;
++
++ cc = talloc_zero(mem_ctx, struct sss_krb5_ccache);
++ if (!cc) {
++ return ENOMEM;
++ }
++ talloc_set_destructor((TALLOC_CTX *)cc, sss_free_krb5_ccache);
++
++ ret = switch_creds(cc, uid, gid, 0, NULL, &cc->creds);
++ if (ret) {
++ goto done;
++ }
++
++ kerr = krb5_init_context(&cc->context);
++ if (kerr) {
++ ret = EIO;
++ goto done;
++ }
++
++ kerr = krb5_cc_resolve(cc->context, ccname, &cc->ccache);
++ if (kerr == KRB5_FCC_NOFILE || cc->ccache == NULL) {
++ DEBUG(SSSDBG_TRACE_FUNC, ("ccache %s is missing or empty\n", ccname));
++ ret = ERR_NOT_FOUND;
++ goto done;
++ } else if (kerr != 0) {
++ KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
++ DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
++ ret = ERR_INTERNAL;
++ goto done;
++ }
++
++ ret = EOK;
++
++done:
++ if (ret) {
++ talloc_free(cc);
++ } else {
++ *ccache = cc;
++ }
++ return ret;
++}
++
++static errno_t sss_destroy_ccache(struct sss_krb5_ccache *cc)
++{
++ krb5_error_code kerr;
++ errno_t ret;
++
++ kerr = krb5_cc_destroy(cc->context, cc->ccache);
++ if (kerr) {
++ KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
++ DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_destroy failed.\n"));
++ ret = EIO;
++ }
++
++ /* krb5_cc_destroy frees cc->ccache in all events */
++ cc->ccache = NULL;
++
++ return ret;
++}
++
++errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid)
++{
++ struct sss_krb5_ccache *cc = NULL;
++ TALLOC_CTX *tmp_ctx;
++ errno_t ret;
++
++ tmp_ctx = talloc_new(NULL);
++ if (tmp_ctx == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
++ return ENOMEM;
++ }
++
++ ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
++ if (ret) {
++ goto done;
++ }
++
++ ret = sss_destroy_ccache(cc);
++
++done:
++ talloc_free(tmp_ctx);
++ return ret;
++}
++
+
+ /*======== ccache back end utilities ========*/
+ struct sss_krb5_cc_be *
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index aac3ec72ec7e1664ae96cc4e53d368e22448f5f1..ebcfe938af913f107b8816c3209b690ac90e797e 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -87,6 +87,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ struct sss_creds **saved_creds);
+ errno_t restore_creds(struct sss_creds *saved_creds);
+
++errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
++
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ struct tgt_times *tgtt);
+
+--
+1.8.3.1
+
diff --git a/0003-krb5-Use-krb5_cc_destroy-to-remove-old-ccaches.patch b/0003-krb5-Use-krb5_cc_destroy-to-remove-old-ccaches.patch
new file mode 100644
index 0000000..d18f7c2
--- /dev/null
+++ b/0003-krb5-Use-krb5_cc_destroy-to-remove-old-ccaches.patch
@@ -0,0 +1,279 @@
+From a70e88f62e8ba48c5042b881f20ed6586cb135a8 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Wed, 28 Aug 2013 23:18:37 -0400
+Subject: [PATCH 03/14] krb5: Use krb5_cc_destroy to remove old ccaches
+
+This completely replaces the per-ccache-type custom code to remove old cacches
+and instead uses libkrb5 base doperations (krb5_cc_destroy) and operating as
+the user owner.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ Makefile.am | 2 ++
+ src/providers/krb5/krb5_auth.c | 63 +++++++++++-------------------------
+ src/providers/krb5/krb5_utils.c | 71 -----------------------------------------
+ src/providers/krb5/krb5_utils.h | 2 --
+ src/tests/krb5_child-test.c | 2 +-
+ 5 files changed, 21 insertions(+), 119 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 150f53e72cfa68dc5d32aa90ad475a72000ba3fb..25a4cbf83c790b85fab9ccccd611f59704a5b301 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -962,6 +962,7 @@ strtonum_tests_LDADD = \
+ krb5_utils_tests_SOURCES = \
+ src/tests/krb5_utils-tests.c \
+ src/providers/krb5/krb5_utils.c \
++ src/providers/krb5/krb5_become_user.c \
+ src/providers/krb5/krb5_common.c \
+ src/util/sss_krb5.c \
+ src/util/find_uid.c \
+@@ -1532,6 +1533,7 @@ libsss_ldap_la_SOURCES = \
+ src/providers/ldap/ldap_access.c \
+ src/providers/krb5/krb5_common.c \
+ src/providers/krb5/krb5_utils.c \
++ src/providers/krb5/krb5_become_user.c \
+ src/util/user_info_msg.c \
+ src/util/sss_ldap.c \
+ src/util/sss_krb5.c
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index db0aa936ff5577afedf72cb43f1c71485e16505c..5d33dddb6d3bf28c7021580a3859a257b1507210 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -40,48 +40,19 @@
+ #include "providers/krb5/krb5_auth.h"
+ #include "providers/krb5/krb5_utils.h"
+
+-static errno_t safe_remove_old_ccache_file(struct sss_krb5_cc_be *cc_be,
+- const char *princ,
+- const char *old_ccache,
+- const char *new_ccache)
++static errno_t safe_remove_old_ccache_file(const char *old_ccache,
++ const char *new_ccache,
++ uid_t uid, gid_t gid)
+ {
+- int ret;
+- enum sss_krb5_cc_type old_type;
+- struct sss_krb5_cc_be *old_cc_ops;
+-
+- if (old_ccache == NULL) {
+- DEBUG(SSSDBG_FUNC_DATA, ("No old ccache, nothing to do\n"));
+- return EOK;
+- }
+-
+- if (new_ccache == NULL) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Missing new ccache file, old ccache file is not deleted.\n"));
+- return EINVAL;
+- }
+-
+- old_type = sss_krb5_get_type(old_ccache);
+- old_cc_ops = get_cc_be_ops(old_type);
+- if (!old_cc_ops) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get ccache operations\n"));
+- return EINVAL;
+- }
+-
+- if (cc_be->type == old_type &&
+- strcmp(old_ccache, new_ccache) == 0) {
++ if ((old_ccache == new_ccache)
++ || (old_ccache && new_ccache
++ && (strcmp(old_ccache, new_ccache) == 0))) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("New and old ccache file are the same, "
+- "no one will be deleted.\n"));
++ "none will be deleted.\n"));
+ return EOK;
+ }
+
+- ret = old_cc_ops->remove(old_ccache);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Cannot remove ccache [%s]\n", old_ccache));
+- return EIO;
+- }
+-
+- return EOK;
++ return sss_krb5_cc_destroy(old_ccache, uid, gid);
+ }
+
+ static errno_t
+@@ -1037,8 +1008,8 @@ static void krb5_auth_done(struct tevent_req *subreq)
+ * used. */
+ if (pd->cmd == SSS_PAM_AUTHENTICATE && !kr->active_ccache) {
+ if (kr->old_ccname != NULL) {
+- ret = safe_remove_old_ccache_file(kr->cc_be, kr->upn,
+- kr->old_ccname, "dummy");
++ ret = safe_remove_old_ccache_file(kr->old_ccname, NULL,
++ kr->uid, kr->gid);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to remove old ccache file [%s], "
+ "please remove it manually.\n", kr->old_ccname));
+@@ -1114,12 +1085,14 @@ static void krb5_auth_done(struct tevent_req *subreq)
+ goto done;
+ }
+
+- ret = safe_remove_old_ccache_file(kr->cc_be, kr->upn,
+- kr->old_ccname, store_ccname);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_MINOR_FAILURE,
+- ("Failed to remove old ccache file [%s], "
+- "please remove it manually.\n", kr->old_ccname));
++ if (kr->old_ccname) {
++ ret = safe_remove_old_ccache_file(kr->old_ccname, store_ccname,
++ kr->uid, kr->gid);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_MINOR_FAILURE,
++ ("Failed to remove old ccache file [%s], "
++ "please remove it manually.\n", kr->old_ccname));
++ }
+ }
+
+ ret = krb5_save_ccname(state, state->sysdb, state->domain,
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 1141f3fc839a78927dab5f50267c52d5b44b46ba..0245cc9d008f64e00717dc3e878357ddf2fae9fa 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -1120,42 +1120,11 @@ cc_file_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
+ return talloc_strdup(mem_ctx, location);
+ }
+
+-errno_t
+-cc_file_remove(const char *location)
+-{
+- errno_t ret;
+- const char *filename;
+-
+- filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
+- if (!filename) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n", location));
+- return EINVAL;
+- }
+-
+- if (filename[0] != '/') {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Ccache file name [%s] is not an absolute path.\n", filename));
+- return EINVAL;
+- }
+-
+- errno = 0;
+- ret = unlink(filename);
+- if (ret == -1 && errno != ENOENT) {
+- ret = errno;
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("unlink [%s] failed [%d][%s].\n", filename, ret,
+- strerror(ret)));
+- return ret;
+- }
+- return EOK;
+-}
+-
+ struct sss_krb5_cc_be file_cc = {
+ .type = SSS_KRB5_TYPE_FILE,
+ .create = cc_file_create,
+ .check_existing = cc_file_check_existing,
+ .ccache_for_princ = cc_file_cache_for_princ,
+- .remove = cc_file_remove,
+ };
+
+ #ifdef HAVE_KRB5_CC_COLLECTION
+@@ -1333,32 +1302,11 @@ done:
+ return name;
+ }
+
+-errno_t
+-cc_dir_remove(const char *location)
+-{
+- const char *subsidiary;
+-
+- if (sss_krb5_get_type(location) != SSS_KRB5_TYPE_DIR) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR\n", location));
+- return EINVAL;
+- }
+-
+- subsidiary = sss_krb5_cc_file_path(location);
+- if (!subsidiary) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get subsidiary cache from %s\n",
+- location));
+- return EINVAL;
+- }
+-
+- return cc_file_remove(subsidiary);
+-}
+-
+ struct sss_krb5_cc_be dir_cc = {
+ .type = SSS_KRB5_TYPE_DIR,
+ .create = cc_dir_create,
+ .check_existing = cc_dir_check_existing,
+ .ccache_for_princ = cc_dir_cache_for_princ,
+- .remove = cc_dir_remove
+ };
+
+
+@@ -1485,30 +1433,11 @@ done:
+ return name;
+ }
+
+-errno_t
+-cc_keyring_remove(const char *location)
+-{
+- const char *residual;
+-
+- residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+- if (!residual) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("%s is not of type KEYRING:\n", location));
+- return EINVAL;
+- }
+-
+- /* No special steps are needed to create a kernel keyring.
+- * Everything is handled in libkrb5.
+- */
+- return EOK;
+-}
+-
+ struct sss_krb5_cc_be keyring_cc = {
+ .type = SSS_KRB5_TYPE_KEYRING,
+ .create = cc_keyring_create,
+ .check_existing = cc_keyring_check_existing,
+ .ccache_for_princ = cc_keyring_cache_for_princ,
+- .remove = cc_keyring_remove
+ };
+
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index ebcfe938af913f107b8816c3209b690ac90e797e..ac29d61e9e4efe963c835e8646ce540e09dc8dd7 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -52,7 +52,6 @@ typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid,
+ typedef const char * (*cc_be_ccache_for_princ)(TALLOC_CTX *mem_ctx,
+ const char *location,
+ const char *princ);
+-typedef errno_t (*cc_be_remove)(const char *location);
+
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+@@ -61,7 +60,6 @@ struct sss_krb5_cc_be {
+ cc_be_create_fn create;
+ cc_be_check_existing check_existing;
+ cc_be_ccache_for_princ ccache_for_princ;
+- cc_be_remove remove;
+ };
+
+ extern struct sss_krb5_cc_be file_cc;
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index 24d077289d64d52488a3419ffc4494f59d6bc5df..dff62ab64dd1948d20da6b640a0570ee8ea6b11d 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -561,7 +561,7 @@ done:
+ if (rm_ccache && ctx->res
+ && ctx->res->ccname
+ && ctx->kr) {
+- ctx->kr->krb5_ctx->cc_be->remove(ctx->res->ccname);
++ sss_krb5_cc_destroy(ctx->res->ccname, ctx->kr->uid, ctx->kr->gid);
+ }
+ free(password);
+ talloc_free(ctx);
+--
+1.8.3.1
+
diff --git a/0004-krb5-Replace-type-specific-ccache-principal-check.patch b/0004-krb5-Replace-type-specific-ccache-principal-check.patch
new file mode 100644
index 0000000..c47eebd
--- /dev/null
+++ b/0004-krb5-Replace-type-specific-ccache-principal-check.patch
@@ -0,0 +1,357 @@
+From 1536e39c191a013bc50bb6fd4b8eaef11cf0d436 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 00:58:24 -0400
+Subject: [PATCH 04/14] krb5: Replace type-specific ccache/principal check
+
+Instead of having duplicate functions that are type custom use a signle common
+function that also performs access to the cache as the user owner, implicitly
+validating correctness of ownership.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 11 +-
+ src/providers/krb5/krb5_utils.c | 220 +++++++++++++++-------------------------
+ src/providers/krb5/krb5_utils.h | 6 +-
+ 3 files changed, 89 insertions(+), 148 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 5d33dddb6d3bf28c7021580a3859a257b1507210..976fdec097a06ae5b211a5a93dcb13b9548031ef 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -837,7 +837,6 @@ static void krb5_auth_done(struct tevent_req *subreq)
+ uint8_t *buf = NULL;
+ ssize_t len = -1;
+ struct krb5_child_response *res;
+- const char *store_ccname;
+ struct fo_server *search_srv;
+ krb5_deltat renew_interval_delta;
+ char *renew_interval_str;
+@@ -1076,17 +1075,15 @@ static void krb5_auth_done(struct tevent_req *subreq)
+ goto done;
+ }
+
+- store_ccname = kr->cc_be->ccache_for_princ(kr, kr->ccname,
+- kr->upn);
+- if (store_ccname == NULL) {
++ ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn);
++ if (ret) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("No ccache for %s in %s?\n", kr->upn, kr->ccname));
+- ret = EIO;
+ goto done;
+ }
+
+ if (kr->old_ccname) {
+- ret = safe_remove_old_ccache_file(kr->old_ccname, store_ccname,
++ ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname,
+ kr->uid, kr->gid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+@@ -1096,7 +1093,7 @@ static void krb5_auth_done(struct tevent_req *subreq)
+ }
+
+ ret = krb5_save_ccname(state, state->sysdb, state->domain,
+- pd->user, store_ccname);
++ pd->user, kr->ccname);
+ if (ret) {
+ DEBUG(1, ("krb5_save_ccname failed.\n"));
+ goto done;
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 0245cc9d008f64e00717dc3e878357ddf2fae9fa..ce3cab60d71a8b3329eeedbd82bec6ecb750948c 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -928,6 +928,89 @@ done:
+ }
+
+
++/* This function is called only as a way to validate that we have the
++ * right cache */
++errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
++ const char *ccname, const char *principal)
++{
++ struct sss_krb5_ccache *cc = NULL;
++ krb5_principal ccprinc = NULL;
++ krb5_principal kprinc = NULL;
++ krb5_error_code kerr;
++ const char *cc_type;
++ TALLOC_CTX *tmp_ctx;
++ errno_t ret;
++
++ tmp_ctx = talloc_new(NULL);
++ if (tmp_ctx == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
++ return ENOMEM;
++ }
++
++ ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
++ if (ret) {
++ goto done;
++ }
++
++ cc_type = krb5_cc_get_type(cc->context, cc->ccache);
++
++ DEBUG(SSSDBG_TRACE_INTERNAL,
++ ("Searching for [%s] in cache of type [%s]\n", principal, cc_type));
++
++ kerr = krb5_parse_name(cc->context, principal, &kprinc);
++ if (kerr != 0) {
++ KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
++ DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
++ ret = ERR_INTERNAL;
++ goto done;
++ }
++
++ kerr = krb5_cc_get_principal(cc->context, cc->ccache, &ccprinc);
++ if (kerr != 0) {
++ KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
++ DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_get_principal failed.\n"));
++ }
++
++ if (ccprinc) {
++ if (krb5_principal_compare(cc->context, kprinc, ccprinc) == TRUE) {
++ /* found in the primary ccache */
++ ret = EOK;
++ goto done;
++ }
++ }
++
++#ifdef HAVE_KRB5_CC_COLLECTION
++
++ if (krb5_cc_support_switch(cc->context, cc_type)) {
++
++ krb5_cc_close(cc->context, cc->ccache);
++ cc->ccache = NULL;
++
++ kerr = krb5_cc_set_default_name(cc->context, ccname);
++ if (kerr != 0) {
++ KRB5_DEBUG(SSSDBG_MINOR_FAILURE, cc->context, kerr);
++ /* try to continue despite failure */
++ }
++
++ kerr = krb5_cc_cache_match(cc->context, kprinc, &cc->ccache);
++ if (kerr == 0) {
++ ret = EOK;
++ goto done;
++ }
++ KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, cc->context, kerr);
++ }
++
++#endif /* HAVE_KRB5_CC_COLLECTION */
++
++ ret = ERR_NOT_FOUND;
++
++done:
++ krb5_free_principal(cc->context, ccprinc);
++ krb5_free_principal(cc->context, kprinc);
++ talloc_free(tmp_ctx);
++ return ret;
++}
++
+ /*======== ccache back end utilities ========*/
+ struct sss_krb5_cc_be *
+ get_cc_be_ops(enum sss_krb5_cc_type type)
+@@ -1113,18 +1196,10 @@ cc_file_check_existing(const char *location, uid_t uid,
+ return EOK;
+ }
+
+-const char *
+-cc_file_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
+- const char *princ)
+-{
+- return talloc_strdup(mem_ctx, location);
+-}
+-
+ struct sss_krb5_cc_be file_cc = {
+ .type = SSS_KRB5_TYPE_FILE,
+ .create = cc_file_create,
+ .check_existing = cc_file_check_existing,
+- .ccache_for_princ = cc_file_cache_for_princ,
+ };
+
+ #ifdef HAVE_KRB5_CC_COLLECTION
+@@ -1246,67 +1321,10 @@ done:
+ return ret;
+ }
+
+-const char *
+-cc_dir_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
+- const char *princ)
+-{
+- krb5_context context = NULL;
+- krb5_error_code krberr;
+- char *name = NULL;
+- const char *ccname;
+- krb5_principal client_principal = NULL;
+-
+- ccname = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
+- if (!ccname) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get ccname file from %s\n",
+- location));
+- return NULL;
+- }
+-
+- /* ccname already points to a subsidiary cache */
+- if (ccname[0] == ':' && ccname[1] && ccname[1] == '/') {
+- return talloc_strdup(mem_ctx, location);
+- }
+-
+- krberr = krb5_init_context(&context);
+- if (krberr) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n"));
+- return NULL;
+- }
+-
+- krberr = krb5_parse_name(context, princ, &client_principal);
+- if (krberr != 0) {
+- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
+- DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- /* This function is called only as a way to validate that,
+- * we have the right cache
+- */
+- name = sss_get_ccache_name_for_principal(mem_ctx, context,
+- client_principal, location);
+- if (name == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get full name of ccache\n"));
+- goto done;
+- }
+-
+- talloc_zfree(name);
+- /* everytime return location for dir_cache */
+- name = talloc_strdup(mem_ctx, location);
+-
+-done:
+- krb5_free_principal(context, client_principal);
+- krb5_free_context(context);
+-
+- return name;
+-}
+-
+ struct sss_krb5_cc_be dir_cc = {
+ .type = SSS_KRB5_TYPE_DIR,
+ .create = cc_dir_create,
+ .check_existing = cc_dir_check_existing,
+- .ccache_for_princ = cc_dir_cache_for_princ,
+ };
+
+
+@@ -1362,82 +1380,10 @@ cc_keyring_check_existing(const char *location, uid_t uid,
+ return EOK;
+ }
+
+-const char *
+-cc_keyring_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
+- const char *princ)
+-{
+- krb5_context context = NULL;
+- krb5_error_code krberr;
+- char *name = NULL;
+- const char *residual;
+- size_t i;
+- size_t count;
+- krb5_principal client_principal = NULL;
+-
+- residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+- if (!residual) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get residual from %s\n",
+- location));
+- return NULL;
+- }
+-
+- /* residual already points to a subsidiary cache if it of the
+- * form "KEYRING:<type>:<UID>:krb5_cc_XXXXXXX"
+- * For simplicity, we'll count the colons, up to three.
+- */
+- i = count = 0;
+- while (residual[i] && count < 3) {
+- if (residual[i] == ':') {
+- count ++;
+- }
+- i++;
+- }
+-
+- if (count >= 3) {
+- return talloc_strdup(mem_ctx, location);
+- }
+-
+- krberr = krb5_init_context(&context);
+- if (krberr) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n"));
+- return NULL;
+- }
+-
+- krberr = krb5_parse_name(context, princ, &client_principal);
+- if (krberr != 0) {
+- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
+- DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- name = sss_get_ccache_name_for_principal(mem_ctx, context,
+- client_principal, location);
+- if (name == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get full name of ccache\n"));
+- goto done;
+- }
+-
+- talloc_zfree(name);
+-
+- /* Always return the master name here.
+- * We do the above only to ensure that the
+- * principal-specific name exists and can
+- * be found.
+- */
+- name = talloc_strdup(mem_ctx, location);
+-
+-done:
+- krb5_free_principal(context, client_principal);
+- krb5_free_context(context);
+-
+- return name;
+-}
+-
+ struct sss_krb5_cc_be keyring_cc = {
+ .type = SSS_KRB5_TYPE_KEYRING,
+ .create = cc_keyring_create,
+ .check_existing = cc_keyring_check_existing,
+- .ccache_for_princ = cc_keyring_cache_for_princ,
+ };
+
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index ac29d61e9e4efe963c835e8646ce540e09dc8dd7..a73098d4090199c5a49bdf0adf5115e9120eeb5b 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -49,9 +49,6 @@ typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+ const char *cc_template, bool *active,
+ bool *valid);
+-typedef const char * (*cc_be_ccache_for_princ)(TALLOC_CTX *mem_ctx,
+- const char *location,
+- const char *princ);
+
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+@@ -59,7 +56,6 @@ struct sss_krb5_cc_be {
+
+ cc_be_create_fn create;
+ cc_be_check_existing check_existing;
+- cc_be_ccache_for_princ ccache_for_princ;
+ };
+
+ extern struct sss_krb5_cc_be file_cc;
+@@ -86,6 +82,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ errno_t restore_creds(struct sss_creds *saved_creds);
+
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
++errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
++ const char *ccname, const char *principal);
+
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ struct tgt_times *tgtt);
+--
+1.8.3.1
+
diff --git a/0005-krb5-Move-determination-of-user-being-active.patch b/0005-krb5-Move-determination-of-user-being-active.patch
new file mode 100644
index 0000000..8172582
--- /dev/null
+++ b/0005-krb5-Move-determination-of-user-being-active.patch
@@ -0,0 +1,220 @@
+From bfd32c9e8f302d7722838a68572c6801f5640657 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 11:31:23 -0400
+Subject: [PATCH 05/14] krb5: Move determination of user being active
+
+The way a user is checked for being active does not depend on the ccache
+type so move that check out of the ccache specific functions.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 10 +++++++--
+ src/providers/krb5/krb5_utils.c | 47 +++++++----------------------------------
+ src/providers/krb5/krb5_utils.h | 3 +--
+ 3 files changed, 17 insertions(+), 43 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 976fdec097a06ae5b211a5a93dcb13b9548031ef..178f18a3c5dec4772a59c6d6cfbcdc419c20d48c 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -76,7 +76,7 @@ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ cc_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
+
+ ret = old_cc_ops->check_existing(old_ccache, kr->uid, realm, kr->upn,
+- cc_template, active, valid);
++ cc_template, valid);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Saved ccache %s doesn't exist.\n", old_ccache));
+@@ -84,11 +84,17 @@ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ }
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+- ("Cannot check if saved ccache %s is active and valid\n",
++ ("Cannot check if saved ccache %s is valid\n",
+ old_ccache));
+ return ret;
+ }
+
++ ret = check_if_uid_is_active(kr->uid, active);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("check_if_uid_is_active failed.\n"));
++ return ret;
++ }
++
+ return EOK;
+ }
+
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index ce3cab60d71a8b3329eeedbd82bec6ecb750948c..7f2ca2d5ba570e3467ec7dc4060f58f38b1f3428 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -1066,14 +1066,11 @@ cc_file_create(const char *location, pcre *illegal_re,
+ }
+
+ static errno_t
+-cc_residual_is_used(uid_t uid, const char *ccname,
+- enum sss_krb5_cc_type type, bool *result)
++cc_residual_exists(uid_t uid, const char *ccname,
++ enum sss_krb5_cc_type type)
+ {
+ int ret;
+ struct stat stat_buf;
+- bool active;
+-
+- *result = false;
+
+ if (ccname == NULL || *ccname == '\0') {
+ return EINVAL;
+@@ -1086,7 +1083,6 @@ cc_residual_is_used(uid_t uid, const char *ccname,
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_FUNC_DATA, ("Cache file [%s] does not exist, "
+ "it will be recreated\n", ccname));
+- *result = false;
+ return ENOENT;
+ }
+
+@@ -1123,20 +1119,6 @@ cc_residual_is_used(uid_t uid, const char *ccname,
+ return EINVAL;
+ }
+
+- ret = check_if_uid_is_active(uid, &active);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_OP_FAILURE, ("check_if_uid_is_active failed.\n"));
+- return ret;
+- }
+-
+- if (!active) {
+- DEBUG(SSSDBG_TRACE_FUNC, ("User [%d] is not active\n", uid));
+- } else {
+- DEBUG(SSSDBG_TRACE_LIBS,
+- ("User [%d] is still active, reusing ccache [%s].\n",
+- uid, ccname));
+- *result = true;
+- }
+ return EOK;
+ }
+
+@@ -1157,10 +1139,9 @@ cc_check_template(const char *cc_template)
+ errno_t
+ cc_file_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_active, bool *_valid)
++ const char *cc_template, bool *_valid)
+ {
+ errno_t ret;
+- bool active;
+ bool valid;
+ const char *filename;
+
+@@ -1175,14 +1156,13 @@ cc_file_check_existing(const char *location, uid_t uid,
+ return EINVAL;
+ }
+
+- ret = cc_residual_is_used(uid, filename, SSS_KRB5_TYPE_FILE, &active);
++ ret = cc_residual_exists(uid, filename, SSS_KRB5_TYPE_FILE);
+ if (ret != EOK) {
+ if (ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not check if ccache is active.\n"));
+ }
+ cc_check_template(cc_template);
+- active = false;
+ return ret;
+ }
+
+@@ -1191,7 +1171,6 @@ cc_file_check_existing(const char *location, uid_t uid,
+ return ret;
+ }
+
+- *_active = active;
+ *_valid = valid;
+ return EOK;
+ }
+@@ -1222,10 +1201,8 @@ cc_dir_create(const char *location, pcre *illegal_re,
+ errno_t
+ cc_dir_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_active, bool *_valid)
++ const char *cc_template, bool *_valid)
+ {
+- bool active;
+- bool active_primary = false;
+ bool valid;
+ enum sss_krb5_cc_type type;
+ const char *filename;
+@@ -1279,7 +1256,7 @@ cc_dir_check_existing(const char *location, uid_t uid,
+ dir = tmp;
+ }
+
+- ret = cc_residual_is_used(uid, dir, SSS_KRB5_TYPE_DIR, &active);
++ ret = cc_residual_exists(uid, dir, SSS_KRB5_TYPE_DIR);
+ if (ret != EOK) {
+ if (ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+@@ -1298,8 +1275,7 @@ cc_dir_check_existing(const char *location, uid_t uid,
+ ret = ENOMEM;
+ goto done;
+ }
+- ret = cc_residual_is_used(uid, primary_file, SSS_KRB5_TYPE_FILE,
+- &active_primary);
++ ret = cc_residual_exists(uid, primary_file, SSS_KRB5_TYPE_FILE);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not check if file 'primary' [%s] in dir ccache"
+@@ -1312,7 +1288,6 @@ cc_dir_check_existing(const char *location, uid_t uid,
+ goto done;
+ }
+
+- *_active = active;
+ *_valid = valid;
+ ret = EOK;
+
+@@ -1351,11 +1326,9 @@ cc_keyring_create(const char *location, pcre *illegal_re,
+ errno_t
+ cc_keyring_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_active,
+- bool *_valid)
++ const char *cc_template, bool *_valid)
+ {
+ errno_t ret;
+- bool active;
+ bool valid;
+ const char *residual;
+
+@@ -1366,16 +1339,12 @@ cc_keyring_check_existing(const char *location, uid_t uid,
+ return EINVAL;
+ }
+
+- /* The keyring cache is always active */
+- active = true;
+-
+ /* Check if any user is actively using this cache */
+ ret = check_cc_validity(location, realm, princ, &valid);
+ if (ret != EOK) {
+ return ret;
+ }
+
+- *_active = active;
+ *_valid = valid;
+ return EOK;
+ }
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index a73098d4090199c5a49bdf0adf5115e9120eeb5b..ca33205817cbb726a75b809f71d1fb1589744e15 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -47,8 +47,7 @@ typedef errno_t (*cc_be_create_fn)(const char *location, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path);
+ typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *active,
+- bool *valid);
++ const char *cc_template, bool *valid);
+
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+--
+1.8.3.1
+
diff --git a/0006-krb5-move-template-check-to-initializzation.patch b/0006-krb5-move-template-check-to-initializzation.patch
new file mode 100644
index 0000000..63b350f
--- /dev/null
+++ b/0006-krb5-move-template-check-to-initializzation.patch
@@ -0,0 +1,160 @@
+From 5dc3b01fd9b2fa244e7c2820ce04602c9f059370 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 12:21:39 -0400
+Subject: [PATCH 06/14] krb5: move template check to initializzation
+
+The randomized template check realy only makes sense for the FILE ccache
+which is the only one that normally needs to use randomizing chars.
+Also it is better to warn the admin early rather than to warn 'when it
+is too late'.
+So move the check at initialization time when we determine what the
+template actually is.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 5 +----
+ src/providers/krb5/krb5_common.c | 17 +++++++++++++++++
+ src/providers/krb5/krb5_utils.c | 22 +++-------------------
+ src/providers/krb5/krb5_utils.h | 2 +-
+ 4 files changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 178f18a3c5dec4772a59c6d6cfbcdc419c20d48c..ca00ce7a3aefa6dae3116f57c994d1f5cd1f50ea 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -60,7 +60,6 @@ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ const char *realm, bool *active, bool *valid)
+ {
+ struct sss_krb5_cc_be *old_cc_ops;
+- const char *cc_template;
+ errno_t ret;
+
+ /* ccache file might be of a different type if the user changed
+@@ -73,10 +72,8 @@ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ return EINVAL;
+ }
+
+- cc_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL);
+-
+ ret = old_cc_ops->check_existing(old_ccache, kr->uid, realm, kr->upn,
+- cc_template, valid);
++ valid);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Saved ccache %s doesn't exist.\n", old_ccache));
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index c7ce574d513702132cb7e0c8ca4f1f1b80430f0b..de7ae0a8fe345c38f9458fb9642a5c1b83c906f5 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -144,6 +144,19 @@ static errno_t sss_get_system_ccname_template(TALLOC_CTX *mem_ctx,
+ }
+ #endif
+
++static void sss_check_cc_template(const char *cc_template)
++{
++ size_t template_len;
++
++ template_len = strlen(cc_template);
++ if (template_len >= 6 &&
++ strcmp(cc_template + (template_len - 6), "XXXXXX") != 0) {
++ DEBUG(SSSDBG_CONF_SETTINGS, ("ccache file name template [%s] doesn't "
++ "contain randomizing characters (XXXXXX), file might not "
++ "be rewritable\n", cc_template));
++ }
++}
++
+ errno_t check_and_export_options(struct dp_option *opts,
+ struct sss_domain_info *dom,
+ struct krb5_ctx *krb5_ctx)
+@@ -282,6 +295,10 @@ errno_t check_and_export_options(struct dp_option *opts,
+ switch (cc_be) {
+ case SSS_KRB5_TYPE_FILE:
+ DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type FILE\n"));
++ /* warn if the file type (which is usally created in a sticky bit
++ * laden directory) does not have randomizing chracters */
++ sss_check_cc_template(ccname);
++
+ krb5_ctx->cc_be = &file_cc;
+ if (ccname[0] != '/') {
+ /* FILE:/path/to/cc */
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 7f2ca2d5ba570e3467ec7dc4060f58f38b1f3428..b174462ee4e8f3992e6d9c06f91118098c598149 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -1122,24 +1122,10 @@ cc_residual_exists(uid_t uid, const char *ccname,
+ return EOK;
+ }
+
+-static void
+-cc_check_template(const char *cc_template)
+-{
+- size_t template_len;
+-
+- template_len = strlen(cc_template);
+- if (template_len >= 6 &&
+- strcmp(cc_template + (template_len - 6), "XXXXXX") != 0) {
+- DEBUG(SSSDBG_CONF_SETTINGS, ("ccache file name template [%s] doesn't "
+- "contain randomizing characters (XXXXXX), file might not "
+- "be rewritable\n", cc_template));
+- }
+-}
+-
+ errno_t
+ cc_file_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_valid)
++ bool *_valid)
+ {
+ errno_t ret;
+ bool valid;
+@@ -1162,7 +1148,6 @@ cc_file_check_existing(const char *location, uid_t uid,
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not check if ccache is active.\n"));
+ }
+- cc_check_template(cc_template);
+ return ret;
+ }
+
+@@ -1201,7 +1186,7 @@ cc_dir_create(const char *location, pcre *illegal_re,
+ errno_t
+ cc_dir_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_valid)
++ bool *_valid)
+ {
+ bool valid;
+ enum sss_krb5_cc_type type;
+@@ -1262,7 +1247,6 @@ cc_dir_check_existing(const char *location, uid_t uid,
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not check if ccache is active.\n"));
+ }
+- cc_check_template(cc_template);
+ goto done;
+ }
+
+@@ -1326,7 +1310,7 @@ cc_keyring_create(const char *location, pcre *illegal_re,
+ errno_t
+ cc_keyring_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *_valid)
++ bool *_valid)
+ {
+ errno_t ret;
+ bool valid;
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index ca33205817cbb726a75b809f71d1fb1589744e15..e241666289193bdc3c5eccadfffc4d3d669dff16 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -47,7 +47,7 @@ typedef errno_t (*cc_be_create_fn)(const char *location, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path);
+ typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+- const char *cc_template, bool *valid);
++ bool *valid);
+
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+--
+1.8.3.1
+
diff --git a/0007-krb5-Make-check_for_valid_tgt-static.patch b/0007-krb5-Make-check_for_valid_tgt-static.patch
new file mode 100644
index 0000000..377cfb3
--- /dev/null
+++ b/0007-krb5-Make-check_for_valid_tgt-static.patch
@@ -0,0 +1,201 @@
+From c121e65ed592bf3611053ee38032fd33c8d1b285 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 12:27:49 -0400
+Subject: [PATCH 07/14] krb5: Make check_for_valid_tgt() static
+
+check_for_valid_tgt() is used exclusively in krb5_uitls.c so move it there.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_utils.c | 74 +++++++++++++++++++++++++++++++++++++++++
+ src/util/sss_krb5.c | 72 ---------------------------------------
+ src/util/sss_krb5.h | 4 ---
+ 3 files changed, 74 insertions(+), 76 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index b174462ee4e8f3992e6d9c06f91118098c598149..463a5eb409d076825f25d45c034d58f4a89780eb 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -761,6 +761,80 @@ done:
+ return ret;
+ }
+
++static krb5_error_code check_for_valid_tgt(krb5_context context,
++ krb5_ccache ccache,
++ const char *realm,
++ const char *client_princ_str,
++ bool *result)
++{
++ krb5_error_code krberr;
++ TALLOC_CTX *tmp_ctx = NULL;
++ krb5_creds mcred;
++ krb5_creds cred;
++ char *server_name = NULL;
++ krb5_principal client_principal = NULL;
++ krb5_principal server_principal = NULL;
++
++ *result = false;
++
++ tmp_ctx = talloc_new(NULL);
++ if (tmp_ctx == NULL) {
++ DEBUG(1, ("talloc_new failed.\n"));
++ return ENOMEM;
++ }
++
++ server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
++ if (server_name == NULL) {
++ DEBUG(1, ("talloc_asprintf failed.\n"));
++ krberr = ENOMEM;
++ goto done;
++ }
++
++ krberr = krb5_parse_name(context, server_name, &server_principal);
++ if (krberr != 0) {
++ DEBUG(1, ("krb5_parse_name failed.\n"));
++ goto done;
++ }
++
++ krberr = krb5_parse_name(context, client_princ_str, &client_principal);
++ if (krberr != 0) {
++ DEBUG(1, ("krb5_parse_name failed.\n"));
++ goto done;
++ }
++
++ memset(&mcred, 0, sizeof(mcred));
++ memset(&cred, 0, sizeof(mcred));
++ mcred.client = client_principal;
++ mcred.server = server_principal;
++
++ krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
++ if (krberr != 0) {
++ DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
++ krberr = 0;
++ goto done;
++ }
++
++ DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
++
++ if (cred.times.endtime > time(NULL)) {
++ DEBUG(3, ("TGT is valid.\n"));
++ *result = true;
++ }
++ krb5_free_cred_contents(context, &cred);
++
++ krberr = 0;
++
++done:
++ if (client_principal != NULL) {
++ krb5_free_principal(context, client_principal);
++ }
++ if (server_principal != NULL) {
++ krb5_free_principal(context, server_principal);
++ }
++ talloc_free(tmp_ctx);
++ return krberr;
++}
++
+ static errno_t
+ check_cc_validity(const char *location,
+ const char *realm,
+diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
+index b25ed24919555666422e6a87ded8688ca76c345f..440edab8a4624b33b7d358e64ead93949fc3de88 100644
+--- a/src/util/sss_krb5.c
++++ b/src/util/sss_krb5.c
+@@ -546,78 +546,6 @@ void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name)
+ }
+
+
+-krb5_error_code check_for_valid_tgt(krb5_context context,
+- krb5_ccache ccache, const char *realm,
+- const char *client_princ_str, bool *result)
+-{
+- krb5_error_code krberr;
+- TALLOC_CTX *tmp_ctx = NULL;
+- krb5_creds mcred;
+- krb5_creds cred;
+- char *server_name = NULL;
+- krb5_principal client_principal = NULL;
+- krb5_principal server_principal = NULL;
+-
+- *result = false;
+-
+- tmp_ctx = talloc_new(NULL);
+- if (tmp_ctx == NULL) {
+- DEBUG(1, ("talloc_new failed.\n"));
+- return ENOMEM;
+- }
+-
+- server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+- if (server_name == NULL) {
+- DEBUG(1, ("talloc_asprintf failed.\n"));
+- krberr = ENOMEM;
+- goto done;
+- }
+-
+- krberr = krb5_parse_name(context, server_name, &server_principal);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- krberr = krb5_parse_name(context, client_princ_str, &client_principal);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- memset(&mcred, 0, sizeof(mcred));
+- memset(&cred, 0, sizeof(mcred));
+- mcred.client = client_principal;
+- mcred.server = server_principal;
+-
+- krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
+- krberr = 0;
+- goto done;
+- }
+-
+- DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
+-
+- if (cred.times.endtime > time(NULL)) {
+- DEBUG(3, ("TGT is valid.\n"));
+- *result = true;
+- }
+- krb5_free_cred_contents(context, &cred);
+-
+- krberr = 0;
+-
+-done:
+- if (client_principal != NULL) {
+- krb5_free_principal(context, client_principal);
+- }
+- if (server_principal != NULL) {
+- krb5_free_principal(context, server_principal);
+- }
+- talloc_free(tmp_ctx);
+- return krberr;
+-}
+-
+ krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_expire_callback(
+ krb5_context context,
+ krb5_get_init_creds_opt *opt,
+diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
+index b1074f813a6b12d132b8c3d0290ad914b003e70f..aaf2a64882254ba173fb57c5dab47d246082392c 100644
+--- a/src/util/sss_krb5.h
++++ b/src/util/sss_krb5.h
+@@ -70,10 +70,6 @@ void KRB5_CALLCONV sss_krb5_get_init_creds_opt_free (krb5_context context,
+
+ void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name);
+
+-krb5_error_code check_for_valid_tgt(krb5_context context,
+- krb5_ccache ccache, const char *realm,
+- const char *client_princ_str, bool *result);
+-
+ int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
+ krb5_context context, krb5_keytab keytab);
+
+--
+1.8.3.1
+
diff --git a/0008-krb5-Use-new-function-to-validate-ccaches.patch b/0008-krb5-Use-new-function-to-validate-ccaches.patch
new file mode 100644
index 0000000..9274577
--- /dev/null
+++ b/0008-krb5-Use-new-function-to-validate-ccaches.patch
@@ -0,0 +1,568 @@
+From 84ce563e3f430eec1225a6f8493eb0a6c9a3013a Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 16:35:43 -0400
+Subject: [PATCH 08/14] krb5: Use new function to validate ccaches
+
+This function replaces and combines check_for_valid_tgt() and type specific
+functions that checked for ccache existence by using generic krb5 cache
+function and executing them as the target user (implicitly validate the
+target use rcan properly access the ccache).
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 30 ++-
+ src/providers/krb5/krb5_utils.c | 423 +++++++---------------------------------
+ src/providers/krb5/krb5_utils.h | 6 +-
+ 3 files changed, 88 insertions(+), 371 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index ca00ce7a3aefa6dae3116f57c994d1f5cd1f50ea..1ea179be3af48b16129aeb4c2d850a66244f7d08 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -59,27 +59,25 @@ static errno_t
+ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ const char *realm, bool *active, bool *valid)
+ {
+- struct sss_krb5_cc_be *old_cc_ops;
+ errno_t ret;
+
+- /* ccache file might be of a different type if the user changed
+- * configuration
+- */
+- old_cc_ops = get_cc_be_ops_ccache(old_ccache);
+- if (old_cc_ops == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Cannot get operations on saved ccache %s\n", old_ccache));
+- return EINVAL;
+- }
++ *active = false;
++ *valid = false;
+
+- ret = old_cc_ops->check_existing(old_ccache, kr->uid, realm, kr->upn,
+- valid);
+- if (ret == ENOENT) {
++ ret = sss_krb5_cc_verify_ccache(old_ccache,
++ kr->uid, kr->gid,
++ realm, kr->upn);
++ switch (ret) {
++ case ERR_NOT_FOUND:
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Saved ccache %s doesn't exist.\n", old_ccache));
+- return ret;
+- }
+- if (ret != EOK) {
++ return ENOENT;
++ case EINVAL:
++ /* cache found but no tgt or expired */
++ case EOK:
++ *valid = true;
++ break;
++ default:
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Cannot check if saved ccache %s is valid\n",
+ old_ccache));
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 463a5eb409d076825f25d45c034d58f4a89780eb..c4849e74bd43b096b585398970f5b81e946212e9 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -761,136 +761,6 @@ done:
+ return ret;
+ }
+
+-static krb5_error_code check_for_valid_tgt(krb5_context context,
+- krb5_ccache ccache,
+- const char *realm,
+- const char *client_princ_str,
+- bool *result)
+-{
+- krb5_error_code krberr;
+- TALLOC_CTX *tmp_ctx = NULL;
+- krb5_creds mcred;
+- krb5_creds cred;
+- char *server_name = NULL;
+- krb5_principal client_principal = NULL;
+- krb5_principal server_principal = NULL;
+-
+- *result = false;
+-
+- tmp_ctx = talloc_new(NULL);
+- if (tmp_ctx == NULL) {
+- DEBUG(1, ("talloc_new failed.\n"));
+- return ENOMEM;
+- }
+-
+- server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
+- if (server_name == NULL) {
+- DEBUG(1, ("talloc_asprintf failed.\n"));
+- krberr = ENOMEM;
+- goto done;
+- }
+-
+- krberr = krb5_parse_name(context, server_name, &server_principal);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- krberr = krb5_parse_name(context, client_princ_str, &client_principal);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_parse_name failed.\n"));
+- goto done;
+- }
+-
+- memset(&mcred, 0, sizeof(mcred));
+- memset(&cred, 0, sizeof(mcred));
+- mcred.client = client_principal;
+- mcred.server = server_principal;
+-
+- krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
+- if (krberr != 0) {
+- DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
+- krberr = 0;
+- goto done;
+- }
+-
+- DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
+-
+- if (cred.times.endtime > time(NULL)) {
+- DEBUG(3, ("TGT is valid.\n"));
+- *result = true;
+- }
+- krb5_free_cred_contents(context, &cred);
+-
+- krberr = 0;
+-
+-done:
+- if (client_principal != NULL) {
+- krb5_free_principal(context, client_principal);
+- }
+- if (server_principal != NULL) {
+- krb5_free_principal(context, server_principal);
+- }
+- talloc_free(tmp_ctx);
+- return krberr;
+-}
+-
+-static errno_t
+-check_cc_validity(const char *location,
+- const char *realm,
+- const char *princ,
+- bool *_valid)
+-{
+- errno_t ret;
+- bool valid = false;
+- krb5_ccache ccache = NULL;
+- krb5_context context = NULL;
+- krb5_error_code krberr;
+-
+- krberr = krb5_init_context(&context);
+- if (krberr) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
+- return EIO;
+- }
+-
+- krberr = krb5_cc_resolve(context, location, &ccache);
+- if (krberr == KRB5_FCC_NOFILE || ccache == NULL) {
+- /* KRB5_FCC_NOFILE would be returned if the directory components
+- * of the DIR cache do not exist, which is the case in /run
+- * after a reboot
+- */
+- DEBUG(SSSDBG_TRACE_FUNC,
+- ("ccache %s is missing or empty\n", location));
+- valid = false;
+- ret = EOK;
+- goto done;
+- } else if (krberr != 0) {
+- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
+- DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
+- ret = EIO;
+- goto done;
+- }
+-
+- krberr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
+- if (krberr != EOK) {
+- KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Could not check if ccache contains a valid principal\n"));
+- ret = EIO;
+- goto done;
+- }
+-
+- ret = EOK;
+-
+-done:
+- if (ret == EOK) {
+- *_valid = valid;
+- }
+- if (ccache) krb5_cc_close(context, ccache);
+- krb5_free_context(context);
+- return ret;
+-}
+-
+
+ struct sss_krb5_ccache {
+ struct sss_creds *creds;
+@@ -1085,6 +955,78 @@ done:
+ return ret;
+ }
+
++errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
++ const char *realm, const char *principal)
++{
++ struct sss_krb5_ccache *cc = NULL;
++ TALLOC_CTX *tmp_ctx = NULL;
++ krb5_principal tgt_princ = NULL;
++ krb5_principal princ = NULL;
++ char *tgt_name;
++ krb5_creds mcred = { 0 };
++ krb5_creds cred = { 0 };
++ krb5_error_code kerr;
++ errno_t ret;
++
++ tmp_ctx = talloc_new(NULL);
++ if (tmp_ctx == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n"));
++ return ENOMEM;
++ }
++
++ ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
++ if (ret) {
++ goto done;
++ }
++
++ tgt_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
++ if (!tgt_name) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ kerr = krb5_parse_name(cc->context, tgt_name, &tgt_princ);
++ if (kerr) {
++ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
++ if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
++ else ret = ERR_INTERNAL;
++ goto done;
++ }
++
++ kerr = krb5_parse_name(cc->context, principal, &princ);
++ if (kerr) {
++ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
++ if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
++ else ret = ERR_INTERNAL;
++ goto done;
++ }
++
++ mcred.client = princ;
++ mcred.server = tgt_princ;
++ mcred.times.endtime = time(NULL);
++
++ kerr = krb5_cc_retrieve_cred(cc->context, cc->ccache,
++ KRB5_TC_MATCH_TIMES, &mcred, &cred);
++ if (kerr) {
++ if (kerr == KRB5_CC_NOTFOUND) {
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("TGT not found or expired.\n"));
++ ret = EINVAL;
++ } else {
++ KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
++ ret = ERR_INTERNAL;
++ }
++ }
++ krb5_free_cred_contents(cc->context, &cred);
++
++done:
++ if (tgt_princ) krb5_free_principal(cc->context, tgt_princ);
++ if (princ) krb5_free_principal(cc->context, princ);
++ talloc_free(tmp_ctx);
++ return ret;
++}
++
++
+ /*======== ccache back end utilities ========*/
+ struct sss_krb5_cc_be *
+ get_cc_be_ops(enum sss_krb5_cc_type type)
+@@ -1139,105 +1081,9 @@ cc_file_create(const char *location, pcre *illegal_re,
+ return create_ccache_dir_head(filename, illegal_re, uid, gid, private_path);
+ }
+
+-static errno_t
+-cc_residual_exists(uid_t uid, const char *ccname,
+- enum sss_krb5_cc_type type)
+-{
+- int ret;
+- struct stat stat_buf;
+-
+- if (ccname == NULL || *ccname == '\0') {
+- return EINVAL;
+- }
+-
+- ret = lstat(ccname, &stat_buf);
+-
+- if (ret == -1) {
+- ret = errno;
+- if (ret == ENOENT) {
+- DEBUG(SSSDBG_FUNC_DATA, ("Cache file [%s] does not exist, "
+- "it will be recreated\n", ccname));
+- return ENOENT;
+- }
+-
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("stat failed [%d][%s].\n", ret, strerror(ret)));
+- return ret;
+- }
+-
+- if (stat_buf.st_uid != uid) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Cache file [%s] exists, but is owned by [%d] instead of "
+- "[%d].\n", ccname, stat_buf.st_uid, uid));
+- return EINVAL;
+- }
+-
+- switch (type) {
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- ret = S_ISDIR(stat_buf.st_mode);
+- break;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+- case SSS_KRB5_TYPE_FILE:
+- ret = S_ISREG(stat_buf.st_mode);
+- break;
+- default:
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Unsupported ccache type\n"));
+- return EINVAL;
+- }
+-
+- if (ret == 0) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Cache file [%s] exists, but is not the expected type\n",
+- ccname));
+- return EINVAL;
+- }
+-
+- return EOK;
+-}
+-
+-errno_t
+-cc_file_check_existing(const char *location, uid_t uid,
+- const char *realm, const char *princ,
+- bool *_valid)
+-{
+- errno_t ret;
+- bool valid;
+- const char *filename;
+-
+- filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
+- if (!filename) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n", location));
+- return EINVAL;
+- }
+-
+- if (filename[0] != '/') {
+- DEBUG(SSSDBG_OP_FAILURE, ("Only absolute path names are allowed.\n"));
+- return EINVAL;
+- }
+-
+- ret = cc_residual_exists(uid, filename, SSS_KRB5_TYPE_FILE);
+- if (ret != EOK) {
+- if (ret != ENOENT) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Could not check if ccache is active.\n"));
+- }
+- return ret;
+- }
+-
+- ret = check_cc_validity(location, realm, princ, &valid);
+- if (ret != EOK) {
+- return ret;
+- }
+-
+- *_valid = valid;
+- return EOK;
+-}
+-
+ struct sss_krb5_cc_be file_cc = {
+ .type = SSS_KRB5_TYPE_FILE,
+ .create = cc_file_create,
+- .check_existing = cc_file_check_existing,
+ };
+
+ #ifdef HAVE_KRB5_CC_COLLECTION
+@@ -1257,107 +1103,9 @@ cc_dir_create(const char *location, pcre *illegal_re,
+ return create_ccache_dir_head(dir_name, illegal_re, uid, gid, private_path);
+ }
+
+-errno_t
+-cc_dir_check_existing(const char *location, uid_t uid,
+- const char *realm, const char *princ,
+- bool *_valid)
+-{
+- bool valid;
+- enum sss_krb5_cc_type type;
+- const char *filename;
+- const char *dir;
+- char *tmp;
+- char *primary_file;
+- errno_t ret;
+- TALLOC_CTX *tmp_ctx;
+-
+- type = sss_krb5_get_type(location);
+- if (type != SSS_KRB5_TYPE_DIR) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR:\n", location));
+- return EINVAL;
+- }
+-
+- filename = sss_krb5_cc_file_path(location);
+- if (!filename) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Existing ccname does not contain path into the collection"));
+- return EINVAL;
+- }
+-
+- if (filename[0] != '/') {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Only absolute path names are allowed.\n"));
+- return EINVAL;
+- }
+-
+- tmp_ctx = talloc_new(NULL);
+- if (tmp_ctx == NULL) {
+- DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+- return ENOMEM;
+- }
+-
+- tmp = talloc_strdup(tmp_ctx, filename);
+- if (!tmp) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n"));
+- ret = ENOMEM;
+- goto done;
+- }
+-
+- if (0 == strncmp(location, "DIR::", 5)) {
+- dir = dirname(tmp);
+- if (!dir) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Cannot get base directory of %s.\n", tmp));
+- ret = EINVAL;
+- goto done;
+- }
+- } else {
+- dir = tmp;
+- }
+-
+- ret = cc_residual_exists(uid, dir, SSS_KRB5_TYPE_DIR);
+- if (ret != EOK) {
+- if (ret != ENOENT) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Could not check if ccache is active.\n"));
+- }
+- goto done;
+- }
+-
+- /* If primary file isn't in ccache dir, we will ignore it.
+- * But if primary file has wrong permissions, we will fail.
+- */
+- primary_file = talloc_asprintf(tmp_ctx, "%s/primary", dir);
+- if (!primary_file) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf failed.\n"));
+- ret = ENOMEM;
+- goto done;
+- }
+- ret = cc_residual_exists(uid, primary_file, SSS_KRB5_TYPE_FILE);
+- if (ret != EOK && ret != ENOENT) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Could not check if file 'primary' [%s] in dir ccache"
+- " is active.\n", primary_file));
+- goto done;
+- }
+-
+- ret = check_cc_validity(location, realm, princ, &valid);
+- if (ret != EOK) {
+- goto done;
+- }
+-
+- *_valid = valid;
+- ret = EOK;
+-
+-done:
+- talloc_free(tmp_ctx);
+- return ret;
+-}
+-
+ struct sss_krb5_cc_be dir_cc = {
+ .type = SSS_KRB5_TYPE_DIR,
+ .create = cc_dir_create,
+- .check_existing = cc_dir_check_existing,
+ };
+
+
+@@ -1381,36 +1129,9 @@ cc_keyring_create(const char *location, pcre *illegal_re,
+ return EOK;
+ }
+
+-errno_t
+-cc_keyring_check_existing(const char *location, uid_t uid,
+- const char *realm, const char *princ,
+- bool *_valid)
+-{
+- errno_t ret;
+- bool valid;
+- const char *residual;
+-
+- residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+- if (!residual) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("%s is not of type KEYRING:\n", location));
+- return EINVAL;
+- }
+-
+- /* Check if any user is actively using this cache */
+- ret = check_cc_validity(location, realm, princ, &valid);
+- if (ret != EOK) {
+- return ret;
+- }
+-
+- *_valid = valid;
+- return EOK;
+-}
+-
+ struct sss_krb5_cc_be keyring_cc = {
+ .type = SSS_KRB5_TYPE_KEYRING,
+ .create = cc_keyring_create,
+- .check_existing = cc_keyring_check_existing,
+ };
+
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index e241666289193bdc3c5eccadfffc4d3d669dff16..b364f87aa6e6f0070e8acb5559ee92f2e001e0a5 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -45,16 +45,12 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+ /* Operations on a credential cache */
+ typedef errno_t (*cc_be_create_fn)(const char *location, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path);
+-typedef errno_t (*cc_be_check_existing)(const char *location, uid_t uid,
+- const char *realm, const char *princ,
+- bool *valid);
+
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+ enum sss_krb5_cc_type type;
+
+ cc_be_create_fn create;
+- cc_be_check_existing check_existing;
+ };
+
+ extern struct sss_krb5_cc_be file_cc;
+@@ -83,6 +79,8 @@ errno_t restore_creds(struct sss_creds *saved_creds);
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
+ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+ const char *ccname, const char *principal);
++errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
++ const char *realm, const char *principal);
+
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ struct tgt_times *tgtt);
+--
+1.8.3.1
+
diff --git a/0009-krb5-Unify-function-to-create-ccache-files.patch b/0009-krb5-Unify-function-to-create-ccache-files.patch
new file mode 100644
index 0000000..00797d2
--- /dev/null
+++ b/0009-krb5-Unify-function-to-create-ccache-files.patch
@@ -0,0 +1,348 @@
+From 1c022b3556f442f57326c4a3f250128b1bd232ae Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 17:25:01 -0400
+Subject: [PATCH 09/14] krb5: Unify function to create ccache files
+
+Only 2 types (FILE and DIR) need to precreate files or directories
+on the file system, and the 2 functions were basically identical.
+
+Consolidate all in one common function and use that function directly
+where needed instead of using indirection.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 6 ++--
+ src/providers/krb5/krb5_utils.c | 71 ++++++++++-------------------------------
+ src/providers/krb5/krb5_utils.h | 14 ++------
+ src/tests/krb5_child-test.c | 6 ++--
+ src/tests/krb5_utils-tests.c | 40 +++++++++++------------
+ 5 files changed, 43 insertions(+), 94 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 1ea179be3af48b16129aeb4c2d850a66244f7d08..d2c53f98c04cda01c2a8e0efe038f5cd5fa82839 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -333,9 +333,9 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
+ return EINVAL;
+ }
+
+- ret = kr->cc_be->create(kr->ccname,
+- kr->krb5_ctx->illegal_path_re,
+- kr->uid, kr->gid, private_path);
++ ret = sss_krb5_precreate_ccache(kr->ccname,
++ kr->krb5_ctx->illegal_path_re,
++ kr->uid, kr->gid, private_path);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("ccache creation failed.\n"));
+ return ret;
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index c4849e74bd43b096b585398970f5b81e946212e9..83e61e14ecc116b9556231c5d8a0f55b63260c77 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -722,19 +722,31 @@ done:
+ return EOK;
+ }
+
+-static errno_t
+-create_ccache_dir_head(const char *parent, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path)
++errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
++ uid_t uid, gid_t gid, bool private_path)
+ {
++ TALLOC_CTX *tmp_ctx = NULL;
++ const char *filename;
+ char *ccdirname;
+- TALLOC_CTX *tmp_ctx = NULL;
+ char *end;
+ errno_t ret;
+
++ if (ccname[0] == '/') {
++ filename = ccname;
++ } else if (strncmp(ccname, "FILE:", 5) == 0) {
++ filename = ccname + 5;
++ } else if (strncmp(ccname, "DIR:", 4) == 0) {
++ filename = ccname + 4;
++ } else {
++ /* only FILE and DIR types need precreation so far, we ignore any
++ * other type */
++ return EOK;
++ }
++
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+- ccdirname = talloc_strdup(tmp_ctx, parent);
++ ccdirname = talloc_strdup(tmp_ctx, filename);
+ if (ccdirname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n"));
+ ret = ENOMEM;
+@@ -1066,72 +1078,23 @@ get_cc_be_ops_ccache(const char *ccache)
+ }
+
+ /*======== Operations on the FILE: back end ========*/
+-errno_t
+-cc_file_create(const char *location, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path)
+-{
+- const char *filename;
+-
+- filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
+- if (filename == NULL) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location));
+- return EINVAL;
+- }
+-
+- return create_ccache_dir_head(filename, illegal_re, uid, gid, private_path);
+-}
+
+ struct sss_krb5_cc_be file_cc = {
+ .type = SSS_KRB5_TYPE_FILE,
+- .create = cc_file_create,
+ };
+
+ #ifdef HAVE_KRB5_CC_COLLECTION
+ /*======== Operations on the DIR: back end ========*/
+-errno_t
+-cc_dir_create(const char *location, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path)
+-{
+- const char *dir_name;
+-
+- dir_name = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
+- if (dir_name == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Bad residual type\n"));
+- return EINVAL;
+- }
+-
+- return create_ccache_dir_head(dir_name, illegal_re, uid, gid, private_path);
+-}
+
+ struct sss_krb5_cc_be dir_cc = {
+ .type = SSS_KRB5_TYPE_DIR,
+- .create = cc_dir_create,
+ };
+
+
+ /*======== Operations on the KEYRING: back end ========*/
+
+-errno_t
+-cc_keyring_create(const char *location, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path)
+-{
+- const char *residual;
+-
+- residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+- if (residual == NULL) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location));
+- return EINVAL;
+- }
+-
+- /* No special steps are needed to create a kernel keyring.
+- * Everything is handled in libkrb5.
+- */
+- return EOK;
+-}
+-
+ struct sss_krb5_cc_be keyring_cc = {
+ .type = SSS_KRB5_TYPE_KEYRING,
+- .create = cc_keyring_create,
+ };
+
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index b364f87aa6e6f0070e8acb5559ee92f2e001e0a5..5f720335aab1ac6e493843ac197c5af881a9b998 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -42,15 +42,9 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+ const char *user,
+ const char *upn);
+
+-/* Operations on a credential cache */
+-typedef errno_t (*cc_be_create_fn)(const char *location, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path);
+-
+ /* A ccache back end */
+ struct sss_krb5_cc_be {
+ enum sss_krb5_cc_type type;
+-
+- cc_be_create_fn create;
+ };
+
+ extern struct sss_krb5_cc_be file_cc;
+@@ -58,9 +52,6 @@ extern struct sss_krb5_cc_be file_cc;
+ errno_t create_ccache_dir(const char *dirname, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path);
+
+-errno_t cc_file_create(const char *filename, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path);
+-
+ struct sss_krb5_cc_be *get_cc_be_ops(enum sss_krb5_cc_type type);
+ struct sss_krb5_cc_be *get_cc_be_ops_ccache(const char *ccache);
+
+@@ -76,6 +67,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
+ struct sss_creds **saved_creds);
+ errno_t restore_creds(struct sss_creds *saved_creds);
+
++errno_t sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re,
++ uid_t uid, gid_t gid, bool private_path);
+ errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid);
+ errno_t sss_krb5_check_ccache_princ(uid_t uid, gid_t gid,
+ const char *ccname, const char *principal);
+@@ -90,9 +83,6 @@ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ extern struct sss_krb5_cc_be dir_cc;
+ extern struct sss_krb5_cc_be keyring_cc;
+
+-errno_t cc_dir_create(const char *location, pcre *illegal_re,
+- uid_t uid, gid_t gid, bool private_path);
+-
+ #endif /* HAVE_KRB5_CC_COLLECTION */
+
+
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index dff62ab64dd1948d20da6b640a0570ee8ea6b11d..5ea30014f9c8f748e85506627b7f40d72b913b1b 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -287,9 +287,9 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+ DEBUG(SSSDBG_FUNC_DATA, ("ccname [%s] uid [%llu] gid [%llu]\n",
+ kr->ccname, kr->uid, kr->gid));
+
+- ret = kr->krb5_ctx->cc_be->create(kr->ccname,
+- kr->krb5_ctx->illegal_path_re,
+- kr->uid, kr->gid, private);
++ ret = sss_krb5_precreate_ccache(kr->ccname,
++ kr->krb5_ctx->illegal_path_re,
++ kr->uid, kr->gid, private);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("create_ccache_dir failed.\n"));
+ goto fail;
+diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
+index 4715774ff189700bc1cbeb6c90f4438445a594b0..ea0292569135e0fc22a44251cfc4e8719a15837f 100644
+--- a/src/tests/krb5_utils-tests.c
++++ b/src/tests/krb5_utils-tests.c
+@@ -117,14 +117,14 @@ START_TEST(test_pub_ccache_dir)
+
+ ret = chmod(testpath, 0754);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, 12345, 12345, false);
+- fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL "
++ ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345, false);
++ fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
+ "while x-bit is missing.");
+
+ ret = chmod(testpath, 0755);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, 12345, 12345, false);
+- fail_unless(ret == EOK, "cc_file_create failed.");
++ ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345, false);
++ fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
+
+ check_dir(subdirname, 0, 0, 01777);
+ RMDIR(subdirname);
+@@ -158,7 +158,7 @@ START_TEST(test_pub_ccache_dir_in_user_dir)
+ filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname);
+ fail_unless(filename != NULL, "talloc_asprintf failed.");
+
+- ret = cc_file_create(filename, NULL, 12345, 12345, false);
++ ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345, false);
+ fail_unless(ret == EINVAL, "Creating public ccache dir in user dir "
+ "does not failed with EINVAL.");
+
+@@ -193,14 +193,14 @@ START_TEST(test_priv_ccache_dir)
+
+ ret = chmod(testpath, 0754);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, uid, gid, true);
+- fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL "
++ ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid, true);
++ fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
+ "while x-bit is missing.");
+
+ ret = chmod(testpath, 0755);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, uid, gid, true);
+- fail_unless(ret == EOK, "cc_file_create failed.");
++ ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid, true);
++ fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
+
+ check_dir(subdir, uid, gid, 0700);
+ RMDIR(subdir);
+@@ -248,14 +248,14 @@ START_TEST(test_private_ccache_dir_in_user_dir)
+
+ ret = chmod(user_dir, 0600);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, uid, gid, true);
+- fail_unless(ret == EINVAL, "cc_file_create does not return EINVAL "
++ ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid, true);
++ fail_unless(ret == EINVAL, "sss_krb5_precreate_ccache does not return EINVAL "
+ "while x-bit is missing.");
+
+ ret = chmod(user_dir, 0700);
+ fail_unless(ret == EOK, "chmod failed.");
+- ret = cc_file_create(filename, NULL, uid, gid, true);
+- fail_unless(ret == EOK, "cc_file_create failed.");
++ ret = sss_krb5_precreate_ccache(filename, NULL, uid, gid, true);
++ fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed.");
+
+ check_dir(dn3, uid, gid, 0700);
+ RMDIR(dn3);
+@@ -292,7 +292,7 @@ START_TEST(test_private_ccache_dir_in_wrong_user_dir)
+ filename = talloc_asprintf(tmp_ctx, "%s/ccfile", subdirname);
+ fail_unless(filename != NULL, "talloc_asprintf failed.");
+
+- ret = cc_file_create(filename, NULL, 12345, 12345, true);
++ ret = sss_krb5_precreate_ccache(filename, NULL, 12345, 12345, true);
+ fail_unless(ret == EINVAL, "Creating private ccache dir in wrong user "
+ "dir does not failed with EINVAL.");
+
+@@ -357,7 +357,6 @@ START_TEST(test_illegal_patterns)
+ }
+ END_TEST
+
+-#ifdef HAVE_KRB5_CC_COLLECTION
+ START_TEST(test_cc_dir_create)
+ {
+ char *residual;
+@@ -386,8 +385,8 @@ START_TEST(test_cc_dir_create)
+ residual = talloc_asprintf(tmp_ctx, "DIR:%s/%s", dirname, "ccdir");
+ fail_unless(residual != NULL, "talloc_asprintf failed.");
+
+- ret = cc_dir_create(residual, illegal_re, uid, gid, true);
+- fail_unless(ret == EOK, "cc_dir_create failed\n");
++ ret = sss_krb5_precreate_ccache(residual, illegal_re, uid, gid, true);
++ fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed\n");
+ ret = rmdir(dirname);
+ if (ret < 0) ret = errno;
+ fail_unless(ret == 0, "Cannot remove %s: %s\n", dirname, strerror(ret));
+@@ -399,8 +398,8 @@ START_TEST(test_cc_dir_create)
+ residual = talloc_asprintf(tmp_ctx, "DIR:%s/%s", dirname, "ccdir/");
+ fail_unless(residual != NULL, "talloc_asprintf failed.");
+
+- ret = cc_dir_create(residual, illegal_re, uid, gid, true);
+- fail_unless(ret == EOK, "cc_dir_create failed\n");
++ ret = sss_krb5_precreate_ccache(residual, illegal_re, uid, gid, true);
++ fail_unless(ret == EOK, "sss_krb5_precreate_ccache failed\n");
+ ret = rmdir(dirname);
+ if (ret < 0) ret = errno;
+ fail_unless(ret == 0, "Cannot remove %s: %s\n", dirname, strerror(ret));
+@@ -408,7 +407,6 @@ START_TEST(test_cc_dir_create)
+ free(cwd);
+ }
+ END_TEST
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+
+
+ void setup_talloc_context(void)
+@@ -774,9 +772,7 @@ Suite *krb5_utils_suite (void)
+ tcase_add_checked_fixture (tc_create_dir, setup_create_dir,
+ teardown_create_dir);
+ tcase_add_test (tc_create_dir, test_illegal_patterns);
+-#ifdef HAVE_KRB5_CC_COLLECTION
+ tcase_add_test (tc_create_dir, test_cc_dir_create);
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+ if (getuid() == 0) {
+ tcase_add_test (tc_create_dir, test_priv_ccache_dir);
+ tcase_add_test (tc_create_dir, test_private_ccache_dir_in_user_dir);
+--
+1.8.3.1
+
diff --git a/0010-krb5-Remove-unused-ccache-backend-infrastructure.patch b/0010-krb5-Remove-unused-ccache-backend-infrastructure.patch
new file mode 100644
index 0000000..93ccba0
--- /dev/null
+++ b/0010-krb5-Remove-unused-ccache-backend-infrastructure.patch
@@ -0,0 +1,337 @@
+From d20a5a74666413cadbf64c02eb656a5a3b4bb1de Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 20:11:42 -0400
+Subject: [PATCH 10/14] krb5: Remove unused ccache backend infrastructure
+
+Remove struct sss_krb5_cc_be and the remaining functions that reference
+it as they are all unused now.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 26 -----------------
+ src/providers/krb5/krb5_auth.h | 1 -
+ src/providers/krb5/krb5_common.c | 54 ++++++++++--------------------------
+ src/providers/krb5/krb5_common.h | 2 --
+ src/providers/krb5/krb5_utils.c | 60 ----------------------------------------
+ src/providers/krb5/krb5_utils.h | 17 ------------
+ src/tests/krb5_child-test.c | 23 ---------------
+ 7 files changed, 15 insertions(+), 168 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index d2c53f98c04cda01c2a8e0efe038f5cd5fa82839..1585f709655853827f2778010452a58657add5d0 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -324,15 +324,6 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
+ return ENOMEM;
+ }
+
+- if (kr->cc_be == NULL) {
+- kr->cc_be = get_cc_be_ops_ccache(kr->ccname);
+- }
+- if (kr->cc_be == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Cannot get operations on new ccache %s\n", kr->ccname));
+- return EINVAL;
+- }
+-
+ ret = sss_krb5_precreate_ccache(kr->ccname,
+ kr->krb5_ctx->illegal_path_re,
+ kr->uid, kr->gid, private_path);
+@@ -340,19 +331,6 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr,
+ DEBUG(SSSDBG_OP_FAILURE, ("ccache creation failed.\n"));
+ return ret;
+ }
+- } else {
+- DEBUG(SSSDBG_MINOR_FAILURE,
+- ("Saved ccache %s if of different type than ccache in "
+- "configuration file, reusing the old ccache\n",
+- kr->old_ccname));
+-
+- kr->cc_be = get_cc_be_ops_ccache(kr->old_ccname);
+- if (kr->cc_be == NULL) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Cannot get operations on saved ccache %s\n",
+- kr->old_ccname));
+- return EINVAL;
+- }
+ }
+
+ return EOK;
+@@ -614,10 +592,6 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
+ goto done;
+ }
+
+- /* The type of the ccache might change during the request if we
+- * end up reusing an old ccache */
+- kr->cc_be = krb5_ctx->cc_be;
+-
+ ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],
+ SYSDB_CCACHE_FILE,
+ NULL);
+diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
+index d31925dae6187b3c839e32502fd349e4d64deb32..022dc9b7645f18d01a8a334371e178aa470d92a1 100644
+--- a/src/providers/krb5/krb5_auth.h
++++ b/src/providers/krb5/krb5_auth.h
+@@ -41,7 +41,6 @@ struct krb5child_req {
+ struct pam_data *pd;
+ struct krb5_ctx *krb5_ctx;
+
+- struct sss_krb5_cc_be *cc_be;
+ const char *ccname;
+ const char *old_ccname;
+ const char *homedir;
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index de7ae0a8fe345c38f9458fb9642a5c1b83c906f5..dedb734fc397d3df3eb7717b19c56051fb2243bb 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -167,7 +167,6 @@ errno_t check_and_export_options(struct dp_option *opts,
+ const char *dummy;
+ char *use_fast_str;
+ char *fast_principal;
+- enum sss_krb5_cc_type cc_be;
+ char *ccname;
+
+ tmp_ctx = talloc_new(NULL);
+@@ -291,53 +290,30 @@ errno_t check_and_export_options(struct dp_option *opts,
+ }
+ }
+
+- cc_be = sss_krb5_get_type(ccname);
+- switch (cc_be) {
+- case SSS_KRB5_TYPE_FILE:
++ if ((ccname[0] == '/') || (strncmp(ccname, "FILE:", 5) == 0)) {
+ DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type FILE\n"));
+ /* warn if the file type (which is usally created in a sticky bit
+ * laden directory) does not have randomizing chracters */
+ sss_check_cc_template(ccname);
+
+- krb5_ctx->cc_be = &file_cc;
+- if (ccname[0] != '/') {
+- /* FILE:/path/to/cc */
+- break;
+- }
+-
+- DEBUG(SSSDBG_CONF_SETTINGS, ("The ccname template was "
++ if (ccname[0] == '/') {
++ /* /path/to/cc prepend FILE: */
++ DEBUG(SSSDBG_CONF_SETTINGS, ("The ccname template was "
+ "missing an explicit type, but is an absolute "
+ "path specifier. Assuming FILE:\n"));
+
+- ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname);
+- if (!ccname) {
+- ret = ENOMEM;
+- goto done;
++ ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname);
++ if (!ccname) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ ret = dp_opt_set_string(opts, KRB5_CCNAME_TMPL, ccname);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("dp_opt_set_string failed.\n"));
++ goto done;
++ }
+ }
+-
+- ret = dp_opt_set_string(opts, KRB5_CCNAME_TMPL, ccname);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("dp_opt_set_string failed.\n"));
+- goto done;
+- }
+- break;
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type DIR\n"));
+- krb5_ctx->cc_be = &dir_cc;
+- break;
+-
+- case SSS_KRB5_TYPE_KEYRING:
+- DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type KEYRING\n"));
+- krb5_ctx->cc_be = &keyring_cc;
+- break;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- default:
+- DEBUG(SSSDBG_OP_FAILURE, ("Unknown ccname database\n"));
+- ret = EINVAL;
+- goto done;
+ }
+
+ ret = EOK;
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index e56bd496e04a7a5c8776a34648aabe0f2d73a3b9..eac0d6b1f0c0fec4a107a7b830d8b0c927f4fe42 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -89,7 +89,6 @@ struct krb5_service {
+ struct fo_service;
+ struct deferred_auth_ctx;
+ struct renew_tgt_ctx;
+-struct sss_krb5_cc_be;
+
+ enum krb5_config_type {
+ K5C_GENERIC,
+@@ -127,7 +126,6 @@ struct krb5_ctx {
+ struct krb5_service *kpasswd_service;
+ int child_debug_fd;
+
+- struct sss_krb5_cc_be *cc_be;
+ pcre *illegal_path_re;
+
+ struct deferred_auth_ctx *deferred_auth_ctx;
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index 83e61e14ecc116b9556231c5d8a0f55b63260c77..d0ccd2d7e03bcabe07113b5abb43d9119b35321c 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -1039,66 +1039,6 @@ done:
+ }
+
+
+-/*======== ccache back end utilities ========*/
+-struct sss_krb5_cc_be *
+-get_cc_be_ops(enum sss_krb5_cc_type type)
+-{
+- struct sss_krb5_cc_be *be = NULL;
+-
+- switch (type) {
+- case SSS_KRB5_TYPE_FILE:
+- be = &file_cc;
+- break;
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- be = &dir_cc;
+- break;
+-
+- case SSS_KRB5_TYPE_KEYRING:
+- be = &keyring_cc;
+- break;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- case SSS_KRB5_TYPE_UNKNOWN:
+- be = NULL;
+- break;
+- }
+-
+- return be;
+-}
+-
+-struct sss_krb5_cc_be *
+-get_cc_be_ops_ccache(const char *ccache)
+-{
+- enum sss_krb5_cc_type type;
+-
+- type = sss_krb5_get_type(ccache);
+- return get_cc_be_ops(type);
+-}
+-
+-/*======== Operations on the FILE: back end ========*/
+-
+-struct sss_krb5_cc_be file_cc = {
+- .type = SSS_KRB5_TYPE_FILE,
+-};
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+-/*======== Operations on the DIR: back end ========*/
+-
+-struct sss_krb5_cc_be dir_cc = {
+- .type = SSS_KRB5_TYPE_DIR,
+-};
+-
+-
+-/*======== Operations on the KEYRING: back end ========*/
+-
+-struct sss_krb5_cc_be keyring_cc = {
+- .type = SSS_KRB5_TYPE_KEYRING,
+-};
+-
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+ errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
+ char *domain_name,
+ struct sss_domain_info **dom)
+diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
+index 5f720335aab1ac6e493843ac197c5af881a9b998..e41309e765b58f7cd2567f1d13fea30d093fd344 100644
+--- a/src/providers/krb5/krb5_utils.h
++++ b/src/providers/krb5/krb5_utils.h
+@@ -42,19 +42,9 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
+ const char *user,
+ const char *upn);
+
+-/* A ccache back end */
+-struct sss_krb5_cc_be {
+- enum sss_krb5_cc_type type;
+-};
+-
+-extern struct sss_krb5_cc_be file_cc;
+-
+ errno_t create_ccache_dir(const char *dirname, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path);
+
+-struct sss_krb5_cc_be *get_cc_be_ops(enum sss_krb5_cc_type type);
+-struct sss_krb5_cc_be *get_cc_be_ops_ccache(const char *ccache);
+-
+ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
+ const char *template, bool file_mode,
+ bool case_sensitive, bool *private_path);
+@@ -78,13 +68,6 @@ errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
+ struct tgt_times *tgtt);
+
+-#ifdef HAVE_KRB5_CC_COLLECTION
+-
+-extern struct sss_krb5_cc_be dir_cc;
+-extern struct sss_krb5_cc_be keyring_cc;
+-
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+
+ errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
+ char *domain_name,
+diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
+index 5ea30014f9c8f748e85506627b7f40d72b913b1b..c32ccc318e9826d598bb29a766ed1839fd9bf066 100644
+--- a/src/tests/krb5_child-test.c
++++ b/src/tests/krb5_child-test.c
+@@ -196,7 +196,6 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+ const char *ccname, const char *ccname_template,
+ int timeout)
+ {
+- enum sss_krb5_cc_type cc_be;
+ struct krb5child_req *kr;
+ struct passwd *pwd;
+ bool private = false;
+@@ -262,28 +261,6 @@ create_dummy_req(TALLOC_CTX *mem_ctx, const char *user,
+ }
+ if (!kr->ccname) goto fail;
+
+- cc_be = sss_krb5_get_type(kr->ccname);
+- switch (cc_be) {
+- case SSS_KRB5_TYPE_FILE:
+- kr->krb5_ctx->cc_be = &file_cc;
+- break;
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- kr->krb5_ctx->cc_be = &dir_cc;
+- break;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+- default:
+- if (tmpl[0] != '/') {
+- DEBUG(SSSDBG_OP_FAILURE, ("Unkown ccname database\n"));
+- ret = EINVAL;
+- goto fail;
+- }
+- DEBUG(SSSDBG_CONF_SETTINGS, ("The ccname template was "
+- "missing an explicit type, but looks like an absolute "
+- "path specifier. Assuming FILE:\n"));
+- kr->krb5_ctx->cc_be = &file_cc;
+- break;
+- }
+ DEBUG(SSSDBG_FUNC_DATA, ("ccname [%s] uid [%llu] gid [%llu]\n",
+ kr->ccname, kr->uid, kr->gid));
+
+--
+1.8.3.1
+
diff --git a/0011-krb5-Remove-unused-function.patch b/0011-krb5-Remove-unused-function.patch
new file mode 100644
index 0000000..d5019ea
--- /dev/null
+++ b/0011-krb5-Remove-unused-function.patch
@@ -0,0 +1,69 @@
+From 0dbcc64a5cee58d5fffaaef923302d9c7a951a7d Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Fri, 30 Aug 2013 20:55:38 -0400
+Subject: [PATCH 11/14] krb5: Remove unused function
+
+Related:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/util/sss_krb5.c | 30 ------------------------------
+ src/util/sss_krb5.h | 2 --
+ 2 files changed, 32 deletions(-)
+
+diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
+index 440edab8a4624b33b7d358e64ead93949fc3de88..d4fee42a0297d5bb46135669a5fc12857ea95936 100644
+--- a/src/util/sss_krb5.c
++++ b/src/util/sss_krb5.c
+@@ -921,36 +921,6 @@ sss_krb5_residual_by_type(const char *full_location,
+ }
+
+ const char *
+-sss_krb5_cc_file_path(const char *full_location)
+-{
+- enum sss_krb5_cc_type cc_type;
+- const char *residual;
+-
+- cc_type = sss_krb5_get_type(full_location);
+- residual = sss_krb5_residual_by_type(full_location, cc_type);
+-
+- switch(cc_type) {
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_KEYRING:
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+- case SSS_KRB5_TYPE_FILE:
+- return residual;
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- /* DIR::/run/user/tkt_foo */
+- if (residual[0] == ':') {
+- ++residual;
+- }
+- return residual;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+- case SSS_KRB5_TYPE_UNKNOWN:
+- break;
+- }
+-
+- return NULL;
+-}
+-
+-const char *
+ sss_krb5_residual_check_type(const char *full_location,
+ enum sss_krb5_cc_type expected_type)
+ {
+diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
+index aaf2a64882254ba173fb57c5dab47d246082392c..efde48b62170a142ebfca907013c3558ec47f428 100644
+--- a/src/util/sss_krb5.h
++++ b/src/util/sss_krb5.h
+@@ -154,8 +154,6 @@ sss_krb5_get_type(const char *full_location);
+ const char *
+ sss_krb5_residual_by_type(const char *full_location, enum sss_krb5_cc_type type);
+ const char *
+-sss_krb5_cc_file_path(const char *full_location);
+-const char *
+ sss_krb5_residual_check_type(const char *full_location,
+ enum sss_krb5_cc_type expected_type);
+
+--
+1.8.3.1
+
diff --git a/0012-krb5-Add-file-dir-path-precheck.patch b/0012-krb5-Add-file-dir-path-precheck.patch
new file mode 100644
index 0000000..f4c5a5c
--- /dev/null
+++ b/0012-krb5-Add-file-dir-path-precheck.patch
@@ -0,0 +1,97 @@
+From 14050f35224360883e20ebd810d3eb40f39267cf Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Sat, 31 Aug 2013 14:21:22 -0400
+Subject: [PATCH 12/14] krb5: Add file/dir path precheck
+
+Add a precheck on the actual existence at all of the file/dir ccname
+targeted (for FILE/DIR types), and bail early if nothing is available.
+
+While testing I found out that without this check, the krb5_cc_resolve()
+function we call as user to check old paths would try to create the
+directory if it didn't exist.
+
+With a ccname of DIR:/tmp/ccdir_1000 saved in the user entry this would
+cause two undesirable side effects:
+
+First it would actually create a directory with the old name, when it
+should not.
+
+Second, because for some reason the umask is set to 0127 in sssd_be, it
+would create the directory with permission 600 (missing the 'x' traverse
+bit on the directory. If the new ccache has the same name it would cause
+the krb5_child process to fal to store the credential cache in it.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_auth.c | 1 +
+ src/providers/krb5/krb5_utils.c | 34 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 35 insertions(+)
+
+diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
+index 1585f709655853827f2778010452a58657add5d0..7cfa3e943c15c0f515f3372079cee18dd7978c92 100644
+--- a/src/providers/krb5/krb5_auth.c
++++ b/src/providers/krb5/krb5_auth.c
+@@ -69,6 +69,7 @@ check_old_ccache(const char *old_ccache, struct krb5child_req *kr,
+ realm, kr->upn);
+ switch (ret) {
+ case ERR_NOT_FOUND:
++ case ENOENT:
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Saved ccache %s doesn't exist.\n", old_ccache));
+ return ENOENT;
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index d0ccd2d7e03bcabe07113b5abb43d9119b35321c..bb933d7f722cbef90b73f4a721382165572c69b9 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -967,6 +967,30 @@ done:
+ return ret;
+ }
+
++static errno_t sss_low_level_path_check(const char *ccname)
++{
++ const char *filename;
++ struct stat buf;
++ int ret;
++
++ if (ccname[0] == '/') {
++ filename = ccname;
++ } else if (strncmp(ccname, "FILE:", 5) == 0) {
++ filename = ccname + 5;
++ } else if (strncmp(ccname, "DIR:", 4) == 0) {
++ filename = ccname + 4;
++ if (filename[0] == ':') filename += 1;
++ } else {
++ /* only FILE and DIR types need file checks so far, we ignore any
++ * other type */
++ return EOK;
++ }
++
++ ret = stat(filename, &buf);
++ if (ret == -1) return errno;
++ return EOK;
++}
++
+ errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+ const char *realm, const char *principal)
+ {
+@@ -980,6 +1004,16 @@ errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
+ krb5_error_code kerr;
+ errno_t ret;
+
++ /* first of all verify if the old ccache file/dir exists as we may be
++ * trying to verify if an old ccache exists at all. If no file/dir
++ * exists bail out immediately otherwise a following krb5_cc_resolve()
++ * call may actually create paths and files we do not want to have
++ * around */
++ ret = sss_low_level_path_check(ccname);
++ if (ret) {
++ return ret;
++ }
++
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new failed.\n"));
+--
+1.8.3.1
+
diff --git a/0013-krb5_child-Simplify-ccache-creation.patch b/0013-krb5_child-Simplify-ccache-creation.patch
new file mode 100644
index 0000000..ab4c6f8
--- /dev/null
+++ b/0013-krb5_child-Simplify-ccache-creation.patch
@@ -0,0 +1,582 @@
+From a6a0d4edebccd3cf04f9813fc65185845626b5d4 Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Mon, 2 Sep 2013 23:52:46 -0400
+Subject: [PATCH 13/14] krb5_child: Simplify ccache creation
+
+The containing ccache directory is precreated by the parent code,
+so there is no special need to do so here for any type.
+Also the special handling for the FILE ccache temporary file is not really
+useful, because libkrb5 internally unlinks and then recreate the file, so
+mkstemp cannot really prevent subtle races, it can only make sure the file is
+unique at creation time.
+
+Resolves:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/providers/krb5/krb5_child.c | 480 ++++++++--------------------------------
+ 1 file changed, 90 insertions(+), 390 deletions(-)
+
+diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
+index 842b50e6e23cf9b00f51c0a01cfd960e4156ee21..4f56736de152d1443add8b69db261faf3b75529f 100644
+--- a/src/providers/krb5/krb5_child.c
++++ b/src/providers/krb5/krb5_child.c
+@@ -424,11 +424,7 @@ static krb5_error_code create_empty_cred(krb5_context ctx, krb5_principal princ,
+
+ done:
+ if (kerr != 0) {
+- if (cred != NULL && cred->client != NULL) {
+- krb5_free_principal(ctx, cred->client);
+- }
+-
+- free(cred);
++ krb5_free_creds(ctx, cred);
+ } else {
+ *_cred = cred;
+ }
+@@ -436,281 +432,38 @@ done:
+ return kerr;
+ }
+
+-#ifdef HAVE_KRB5_CC_COLLECTION
+-static bool need_switch_to_principal(krb5_context ctx, krb5_principal princ)
+-{
+- krb5_error_code kerr;
+- krb5_ccache default_cc = NULL;
+- krb5_principal default_princ = NULL;
+- char *default_full_name = NULL;
+- char *full_name = NULL;
+- bool ret = false;
+-
+- kerr = krb5_cc_default(ctx, &default_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_TRACE_INTERNAL, kerr);
+- goto done;
+- }
+-
+- kerr = krb5_cc_get_principal(ctx, default_cc, &default_princ);
+- if (kerr == KRB5_FCC_NOFILE) {
+- /* There is not any default cache. */
+- ret = true;
+- goto done;
+- } else if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_TRACE_INTERNAL, kerr);
+- goto done;
+- }
+-
+- kerr = krb5_unparse_name(ctx, default_princ, &default_full_name);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_TRACE_INTERNAL, kerr);
+- goto done;
+- }
+-
+- kerr = krb5_unparse_name(ctx, princ, &full_name);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_TRACE_INTERNAL, kerr);
+- goto done;
+- }
+-
+- DEBUG(SSSDBG_FUNC_DATA,
+- ("Comparing default principal [%s] and new principal [%s].\n",
+- default_full_name, full_name));
+- if (0 == strcmp(default_full_name, full_name)) {
+- ret = true;
+- }
+-
+-done:
+- if (default_cc != NULL) {
+- kerr = krb5_cc_close(ctx, default_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+- }
+-
+- /* all functions can be safely called with NULL. */
+- krb5_free_principal(ctx, default_princ);
+- krb5_free_unparsed_name(ctx, default_full_name);
+- krb5_free_unparsed_name(ctx, full_name);
+-
+- return ret;
+-}
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+-static krb5_error_code
+-store_creds_in_ccache(krb5_context ctx, krb5_principal princ,
+- krb5_ccache cc, krb5_creds *creds)
+-{
+- krb5_error_code kerr;
+- krb5_creds *l_cred;
+- char *ccname;
+-
+- if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
+- kerr = krb5_cc_get_full_name(ctx, cc, &ccname);
+- if (kerr != 0) {
+- DEBUG(SSSDBG_TRACE_ALL,
+- ("Couldn't determine full name of ccache\n"));
+- } else {
+- DEBUG(SSSDBG_TRACE_ALL,
+- ("Storing credentials in [%s]\n", ccname));
+- krb5_free_string(ctx, ccname);
+- }
+- }
+-
+- kerr = krb5_cc_initialize(ctx, cc, princ);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+-
+- if (creds == NULL) {
+- kerr = create_empty_cred(ctx, princ, &l_cred);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+- } else {
+- l_cred = creds;
+- }
+-
+- kerr = krb5_cc_store_cred(ctx, cc, l_cred);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- if (need_switch_to_principal(ctx, princ)) {
+- kerr = krb5_cc_switch(ctx, cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+- }
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- kerr = krb5_cc_close(ctx, cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+-
+-done:
+- return kerr;
+-}
+
+-static krb5_error_code create_ccache_file(krb5_context ctx,
+- krb5_principal princ,
+- char *ccname, krb5_creds *creds)
++static errno_t handle_randomized(char *in)
+ {
+- krb5_error_code kerr;
+- krb5_ccache tmp_cc = NULL;
+- char *cc_file_name;
+- int fd = -1;
+ size_t ccname_len;
+- char *dummy;
+- char *tmp_ccname;
+- TALLOC_CTX *tmp_ctx = NULL;
+- mode_t old_umask;
++ char *ccname = NULL;
++ int ret;
++ int fd;
+
+- DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
+-
+- if (strncmp(ccname, "FILE:", 5) == 0) {
+- cc_file_name = ccname + 5;
++ /* We only treat the FILE type case in a special way due to the history
++ * of storing FILE type ccache in /tmp and associated security issues */
++ if (in[0] == '/') {
++ ccname = in;
++ } else if (strncmp(in, "FILE:", 5) == 0) {
++ ccname = in + 5;
+ } else {
+- cc_file_name = ccname;
+- }
+-
+- if (cc_file_name[0] != '/') {
+- DEBUG(1, ("Ccache filename is not an absolute path.\n"));
+- return EINVAL;
+- }
+-
+- tmp_ctx = talloc_new(tmp_ctx);
+- if (tmp_ctx == NULL) {
+- DEBUG(1, ("talloc_new failed.\n"));
+- return ENOMEM;
+- }
+-
+- dummy = strrchr(cc_file_name, '/');
+- tmp_ccname = talloc_strndup(tmp_ctx, cc_file_name,
+- (size_t) (dummy-cc_file_name));
+- if (tmp_ccname == NULL) {
+- DEBUG(1, ("talloc_strdup failed.\n"));
+- kerr = ENOMEM;
+- goto done;
+- }
+- tmp_ccname = talloc_asprintf_append(tmp_ccname, "/.krb5cc_dummy_XXXXXX");
+- if (tmp_ccname == NULL) {
+- kerr = ENOMEM;
+- goto done;
+- }
+-
+- old_umask = umask(077);
+- fd = mkstemp(tmp_ccname);
+- umask(old_umask);
+- if (fd == -1) {
+- kerr = errno;
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("mkstemp failed [%d][%s].\n", kerr, strerror(kerr)));
+- goto done;
+- }
+-
+- kerr = krb5_cc_resolve(ctx, tmp_ccname, &tmp_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+- goto done;
+- }
+-
+- kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
+- if (fd != -1) {
+- close(fd);
+- fd = -1;
+- }
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+- goto done;
+- }
+-
+-
+- ccname_len = strlen(cc_file_name);
+- if (ccname_len >= 6 && strcmp(cc_file_name + (ccname_len - 6), "XXXXXX") == 0) {
+- fd = mkstemp(cc_file_name);
++ return EOK;
++ }
++
++ ccname_len = strlen(ccname);
++ if (ccname_len >= 6 && strcmp(ccname + (ccname_len - 6), "XXXXXX") == 0) {
++ /* NOTE: this call is only used to create a unique name, as later
++ * krb5_cc_initialize() will unlink and recreate the file.
++ * This is ok because this part of the code is called with
++ * privileges already dropped when handling user ccache, or the ccache
++ * is stored in a private directory. So we do not have huge issues if
++ * something races, we mostly care only about not accidentally use
++ * an existing name and thus failing in the process of saving the
++ * cache. Malicious races can only be avoided by libkrb5 itself. */
++ fd = mkstemp(ccname);
+ if (fd == -1) {
+- kerr = errno;
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("mkstemp failed [%d][%s].\n", kerr, strerror(kerr)));
+- goto done;
+- }
+- }
+-
+- kerr = rename(tmp_ccname, cc_file_name);
+- if (kerr == -1) {
+- kerr = errno;
+- DEBUG(1, ("rename failed [%d][%s].\n", kerr, strerror(kerr)));
+- }
+-
+- DEBUG(SSSDBG_TRACE_LIBS, ("Created ccache file: [%s]\n", ccname));
+-
+-done:
+- if (kerr != 0 && tmp_cc != NULL) {
+- krb5_cc_destroy(ctx, tmp_cc);
+- }
+-
+- if (fd != -1) {
+- close(fd);
+- }
+-
+- talloc_free(tmp_ctx);
+- return kerr;
+-}
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+-
+-static errno_t
+-create_ccdir(const char *dirname, uid_t uid, gid_t gid)
+-{
+- mode_t old_umask;
+- struct stat statbuf;
+- errno_t ret;
+-
+- old_umask = umask(0000);
+- ret = mkdir(dirname, 0700);
+- umask(old_umask);
+- if (ret == -1) {
+- /* Failing the mkdir is only OK if the directory already
+- * exists AND it is owned by the same user and group and
+- * has the correct permissions.
+- */
+- ret = errno;
+- if (ret == EEXIST) {
+- errno = 0;
+- ret = stat(dirname, &statbuf);
+- if (ret == -1) {
+- ret = errno;
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("stat failed [%d]: %s\n", ret, strerror(ret)));
+- return EIO;
+- }
+-
+- if (statbuf.st_uid != uid || statbuf.st_gid != gid) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("The directory %s is owned by %d/%d, expected %d/%d\n",
+- dirname, statbuf.st_uid, statbuf.st_gid, uid, gid));
+- return EACCES;
+- }
+-
+- if ((statbuf.st_mode & ~S_IFMT) != 0700) {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("The directory %s has wrong permissions %o, expected 0700\n",
+- dirname, (statbuf.st_mode & ~S_IFMT)));
+- return EACCES;
+- }
+- } else {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("mkdir [%s] failed [%d]: %s\n",
+- dirname, ret, strerror(ret)));
++ ret = errno;
++ DEBUG(SSSDBG_CRIT_FAILURE, ("mkstemp(\"%s\") failed!\n", ccname));
+ return ret;
+ }
+ }
+@@ -718,136 +471,79 @@ create_ccdir(const char *dirname, uid_t uid, gid_t gid)
+ return EOK;
+ }
+
+-static krb5_error_code
+-create_ccache_in_dir(uid_t uid, gid_t gid,
+- krb5_context ctx,
+- krb5_principal princ,
+- char *ccname, krb5_creds *creds)
++/* NOTE: callers rely on 'name' being *changed* if it needs to be randomized,
++ * as they will then send the name back to the new name via the return call
++ * k5c_attach_ccname_msg(). Callers will send in a copy of the name if they
++ * do not care for changes. */
++static krb5_error_code create_ccache(char *ccname, krb5_creds *creds)
+ {
++ krb5_context kctx = NULL;
++ krb5_ccache kcc = NULL;
++ const char *type;
+ krb5_error_code kerr;
+- krb5_ccache tmp_cc = NULL;
+- const char *dirname;
+-
+- DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
+-
+- dirname = sss_krb5_residual_check_type(ccname, SSS_KRB5_TYPE_DIR);
+- if (dirname == NULL) {
+- return EIO;
++#ifdef HAVE_KRB5_CC_COLLECTION
++ krb5_ccache cckcc;
++ bool switch_to_cc = false;
++#endif
++
++ /* Set a restrictive umask, just in case we end up creating any file */
++ umask(077);
++
++ /* we create a new context here as the main process one may have been
++ * opened as root and contain possibly references (even open handles ?)
++ * to resources we do not have or do not want to have access to */
++ kerr = krb5_init_context(&kctx);
++ if (kerr) {
++ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
++ return ERR_INTERNAL;
+ }
+
+- if (dirname[0] == ':') {
+- /* Cache name in the form of DIR::filepath represents a single
+- * ccache in a collection that we are trying to reuse.
+- * See src/lib/krb5/ccache/cc_dir.c in the MIT Kerberos tree.
+- */
+- kerr = krb5_cc_resolve(ctx, ccname, &tmp_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+- } else if (dirname[0] == '/') {
+- /* An absolute path denotes that krb5_child should create a new
+- * ccache. We can afford to just call mkdir(dirname) because we
+- * only want the last component to be created.
+- */
++ kerr = handle_randomized(ccname);
++ if (kerr) goto done;
+
+- kerr = create_ccdir(dirname, uid, gid);
+- if (kerr) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Cannot create directory %s\n", dirname));
+- goto done;
+- }
++ kerr = krb5_cc_resolve(kctx, ccname, &kcc);
++ if (kerr) goto done;
+
+- kerr = krb5_cc_set_default_name(ctx, ccname);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
++ type = krb5_cc_get_type(kctx, kcc);
++ DEBUG(SSSDBG_TRACE_ALL, ("Initializing ccache of type [%s]\n", type));
+
+- kerr = krb5_cc_new_unique(ctx, "DIR", NULL, &tmp_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
++#ifdef HAVE_KRB5_CC_COLLECTION
++ if (krb5_cc_support_switch(kctx, type)) {
++ kerr = krb5_cc_set_default_name(kctx, ccname);
++ if (kerr) goto done;
++
++ kerr = krb5_cc_cache_match(kctx, creds->client, &cckcc);
++ if (kerr == KRB5_CC_NOTFOUND) {
++ kerr = krb5_cc_new_unique(kctx, type, NULL, &cckcc);
++ switch_to_cc = true;
+ }
+- } else {
+- DEBUG(SSSDBG_CRIT_FAILURE,
+- ("Wrong residual format for DIR in ccache %s\n", ccname));
+- return EIO;
++ if (kerr) goto done;
++ krb5_cc_close(kctx, kcc);
++ kcc = cckcc;
+ }
++#endif
+
+- kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_OP_FAILURE, kerr);
+- goto done;
+- }
+-
+-done:
+- if (kerr != 0 && tmp_cc != NULL) {
+- krb5_cc_destroy(ctx, tmp_cc);
+- }
+- return kerr;
+-}
+-
+-static krb5_error_code
+-create_ccache_keyring(krb5_context ctx,
+- krb5_principal princ,
+- char *ccname,
+- krb5_creds *creds)
+-{
+- krb5_error_code kerr;
+- krb5_ccache tmp_cc = NULL;
+-
+- DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
++ kerr = krb5_cc_initialize(kctx, kcc, creds->client);
++ if (kerr) goto done;
+
+- kerr = krb5_cc_resolve(ctx, ccname, &tmp_cc);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+- goto done;
+- }
++ kerr = krb5_cc_store_cred(kctx, kcc, creds);
++ if (kerr) goto done;
+
+- kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
+- if (kerr != 0) {
+- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+- goto done;
++#ifdef HAVE_KRB5_CC_COLLECTION
++ if (switch_to_cc) {
++ kerr = krb5_cc_switch(kctx, kcc);
++ if (kerr) goto done;
+ }
++#endif
+
+ done:
+- if (kerr != 0 && tmp_cc != NULL) {
+- krb5_cc_destroy(ctx, tmp_cc);
++ if (kcc) {
++ /* FIXME: should we krb5_cc_destroy in case of error ? */
++ krb5_cc_close(kctx, kcc);
+ }
+-
+ return kerr;
+ }
+
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+-static krb5_error_code
+-create_ccache(uid_t uid, gid_t gid, krb5_context ctx,
+- krb5_principal princ, char *ccname, krb5_creds *creds)
+-{
+- enum sss_krb5_cc_type cctype;
+-
+- cctype = sss_krb5_get_type(ccname);
+- switch (cctype) {
+- case SSS_KRB5_TYPE_FILE:
+- return create_ccache_file(ctx, princ, ccname, creds);
+-
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- return create_ccache_in_dir(uid, gid, ctx, princ, ccname, creds);
+-
+- case SSS_KRB5_TYPE_KEYRING:
+- return create_ccache_keyring(ctx, princ, ccname, creds);
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- default:
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown cache type\n"));
+- return EINVAL;
+- }
+-
+- return EINVAL; /* Should never get here */
+-}
+-
+ static errno_t pack_response_packet(TALLOC_CTX *mem_ctx, errno_t error,
+ struct response_data *resp_list,
+ uint8_t **_buf, size_t *_len)
+@@ -1176,7 +872,7 @@ static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx,
+ }
+
+ /* Use the updated principal in the creds in case canonicalized */
+- kerr = create_ccache_file(ctx, creds.client, ccname, &creds);
++ kerr = create_ccache(ccname, &creds);
+ if (kerr != 0) {
+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+ goto done;
+@@ -1255,8 +951,7 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr,
+ }
+
+ /* Use the updated principal in the creds in case canonicalized */
+- kerr = create_ccache(kr->uid, kr->gid, kr->ctx,
+- principal, cc_name, kr->creds);
++ kerr = create_ccache(cc_name, kr->creds);
+ if (kerr != 0) {
+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+ goto done;
+@@ -1647,18 +1342,23 @@ done:
+
+ static errno_t create_empty_ccache(struct krb5_req *kr)
+ {
++ krb5_creds *creds = NULL;
+ krb5_error_code kerr;
+
+ DEBUG(SSSDBG_TRACE_LIBS, ("Creating empty ccache\n"));
+
+- kerr = create_ccache(kr->uid, kr->gid, kr->ctx,
+- kr->princ, kr->ccname, NULL);
++ kerr = create_empty_cred(kr->ctx, kr->princ, &creds);
++ if (kerr == 0) {
++ kerr = create_ccache(kr->ccname, creds);
++ }
+ if (kerr != 0) {
+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+ } else {
+ kerr = k5c_attach_ccname_msg(kr);
+ }
+
++ krb5_free_creds(kr->ctx, creds);
++
+ return map_krb5_error(kerr);
+ }
+
+--
+1.8.3.1
+
diff --git a/0014-krb5-Remove-unused-helper-functions.patch b/0014-krb5-Remove-unused-helper-functions.patch
new file mode 100644
index 0000000..bbfec9e
--- /dev/null
+++ b/0014-krb5-Remove-unused-helper-functions.patch
@@ -0,0 +1,127 @@
+From 077fa994f62641a13665b6a07d38b3d5a903dcdc Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo at redhat.com>
+Date: Tue, 3 Sep 2013 20:57:58 -0400
+Subject: [PATCH 14/14] krb5: Remove unused helper functions
+
+these functions are not needed anymore.
+
+Related:
+https://fedorahosted.org/sssd/ticket/2061
+---
+ src/util/sss_krb5.c | 80 -----------------------------------------------------
+ src/util/sss_krb5.h | 8 ------
+ 2 files changed, 88 deletions(-)
+
+diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
+index d4fee42a0297d5bb46135669a5fc12857ea95936..f8a7e6f9be15c7b2dfee9906af914533bd8ac4cd 100644
+--- a/src/util/sss_krb5.c
++++ b/src/util/sss_krb5.c
+@@ -854,86 +854,6 @@ sss_krb5_free_keytab_entry_contents(krb5_context context,
+ }
+ #endif
+
+-#define SSS_KRB5_FILE "FILE:"
+-#define SSS_KRB5_DIR "DIR:"
+-#define SSS_KRB5_KEYRING "KEYRING:"
+-
+-enum sss_krb5_cc_type
+-sss_krb5_get_type(const char *full_location)
+-{
+- if (!full_location) {
+- return SSS_KRB5_TYPE_UNKNOWN;
+- }
+-
+- if (strncmp(full_location, SSS_KRB5_FILE,
+- sizeof(SSS_KRB5_FILE)-1) == 0) {
+- return SSS_KRB5_TYPE_FILE;
+- }
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- else if (strncmp(full_location, SSS_KRB5_DIR,
+- sizeof(SSS_KRB5_DIR)-1) == 0) {
+- return SSS_KRB5_TYPE_DIR;
+- }
+- else if (strncmp(full_location, SSS_KRB5_KEYRING,
+- sizeof(SSS_KRB5_KEYRING)-1) == 0) {
+- return SSS_KRB5_TYPE_KEYRING;
+- }
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- else if (full_location[0] == '/') {
+- return SSS_KRB5_TYPE_FILE;
+- }
+-
+- return SSS_KRB5_TYPE_UNKNOWN;
+-}
+-
+-const char *
+-sss_krb5_residual_by_type(const char *full_location,
+- enum sss_krb5_cc_type type)
+-{
+- size_t offset;
+-
+- if (full_location == NULL) return NULL;
+-
+- switch (type) {
+- case SSS_KRB5_TYPE_FILE:
+- if (full_location[0] == '/') {
+- offset = 0;
+- } else {
+- offset = sizeof(SSS_KRB5_FILE)-1;
+- }
+- break;
+-#ifdef HAVE_KRB5_CC_COLLECTION
+- case SSS_KRB5_TYPE_DIR:
+- offset = sizeof(SSS_KRB5_DIR)-1;
+- break;
+-
+- case SSS_KRB5_TYPE_KEYRING:
+- offset = sizeof(SSS_KRB5_KEYRING)-1;
+- break;
+-#endif /* HAVE_KRB5_CC_COLLECTION */
+-
+- default:
+- return NULL;
+- }
+-
+- return full_location + offset;
+-}
+-
+-const char *
+-sss_krb5_residual_check_type(const char *full_location,
+- enum sss_krb5_cc_type expected_type)
+-{
+- enum sss_krb5_cc_type type;
+-
+- type = sss_krb5_get_type(full_location);
+- if (type != expected_type) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Unexpected ccache type\n"));
+- return NULL;
+- }
+-
+- return sss_krb5_residual_by_type(full_location, type);
+-}
+
+ #ifdef HAVE_KRB5_SET_TRACE_CALLBACK
+
+diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
+index efde48b62170a142ebfca907013c3558ec47f428..db47e0a6b61fc706cdadc74ad1d4c1e9e7ef3589 100644
+--- a/src/util/sss_krb5.h
++++ b/src/util/sss_krb5.h
+@@ -149,14 +149,6 @@ enum sss_krb5_cc_type {
+ SSS_KRB5_TYPE_UNKNOWN
+ };
+
+-enum sss_krb5_cc_type
+-sss_krb5_get_type(const char *full_location);
+-const char *
+-sss_krb5_residual_by_type(const char *full_location, enum sss_krb5_cc_type type);
+-const char *
+-sss_krb5_residual_check_type(const char *full_location,
+- enum sss_krb5_cc_type expected_type);
+-
+ /* === Compatibility routines for the Heimdal Kerberos implementation === */
+
+ void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ,
+--
+1.8.3.1
+
diff --git a/sssd.spec b/sssd.spec
index e76a9f5..82b306e 100644
--- a/sssd.spec
+++ b/sssd.spec
@@ -8,7 +8,7 @@
Name: sssd
Version: 1.11.0
-Release: 1%{?dist}
+Release: 2%{?dist}
Group: Applications/System
Summary: System Security Services Daemon
License: GPLv3+
@@ -17,6 +17,20 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
### Patches ###
+Patch0001: 0001-krb5-Add-calls-to-change-and-restore-credentials.patch
+Patch0002: 0002-krb5-Add-helper-to-destroy-ccache-as-user.patch
+Patch0003: 0003-krb5-Use-krb5_cc_destroy-to-remove-old-ccaches.patch
+Patch0004: 0004-krb5-Replace-type-specific-ccache-principal-check.patch
+Patch0005: 0005-krb5-Move-determination-of-user-being-active.patch
+Patch0006: 0006-krb5-move-template-check-to-initializzation.patch
+Patch0007: 0007-krb5-Make-check_for_valid_tgt-static.patch
+Patch0008: 0008-krb5-Use-new-function-to-validate-ccaches.patch
+Patch0009: 0009-krb5-Unify-function-to-create-ccache-files.patch
+Patch0010: 0010-krb5-Remove-unused-ccache-backend-infrastructure.patch
+Patch0011: 0011-krb5-Remove-unused-function.patch
+Patch0012: 0012-krb5-Add-file-dir-path-precheck.patch
+Patch0013: 0013-krb5_child-Simplify-ccache-creation.patch
+Patch0014: 0014-krb5-Remove-unused-helper-functions.patch
### Dependencies ###
Requires: sssd-common = %{version}-%{release}
@@ -676,6 +690,10 @@ fi
%postun -n libsss_idmap -p /sbin/ldconfig
%changelog
+* Wed Aug 28 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.11.0-2
+- Backport simplification of ccache management from 1.11.1
+- Resolves: rhbz#1010553 - sssd setting KRB5CCNAME=(null) on login
+
* Wed Aug 28 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.11.0-1
- New upstream release 1.11.0
- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.11.0
More information about the scm-commits
mailing list