Blame SOURCES/0004-Make-ksu-respect-the-default_ccache_name-setting.patch

4be148
From 3a456898af626dcab4e1ab0749ca2ccb9ad6162b Mon Sep 17 00:00:00 2001
4be148
From: Nalin Dahyabhai <nalin@dahyabhai.net>
4be148
Date: Wed, 30 Oct 2013 21:47:14 -0400
4be148
Subject: [PATCH 4/7] Make ksu respect the default_ccache_name setting
4be148
4be148
Move the logic for resolving and initializing a cache that we're
4be148
copying creds into out of krb5_ccache_copy(), and let the caller deal
4be148
with it.  Add a helper functions to select/resolve an output ccache in
4be148
the default location for the target user after we've switched to the
4be148
target user's privileges.  If the destination is a collection, take
4be148
care not to change which subsidiary is its primary, and reuse a
4be148
subsidiary cache if we can.  If the destination is not a collection,
4be148
append a unique value to its name to make a new ccache.
4be148
4be148
[ghudson@mit.edu: some changes to variable names and comments; move
4be148
responsibility for getting target ccache name from
4be148
resolve_target_ccache to main]
4be148
4be148
ticket: 7984 (new)
4be148
---
4be148
 src/clients/ksu/ccache.c |  35 +++------
4be148
 src/clients/ksu/ksu.h    |   6 +-
4be148
 src/clients/ksu/main.c   | 181 ++++++++++++++++++++++++++++++++++++++---------
4be148
 3 files changed, 157 insertions(+), 65 deletions(-)
4be148
4be148
diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
4be148
index d0fc389..4693bd4 100644
4be148
--- a/src/clients/ksu/ccache.c
4be148
+++ b/src/clients/ksu/ccache.c
4be148
@@ -46,59 +46,41 @@ void show_credential();
4be148
    with k5 beta 3 release.
4be148
 */
4be148
 
4be148
-krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
4be148
-                                  primary_principal, restrict_creds,
4be148
-                                  target_principal, cc_out, stored, target_uid)
4be148
+krb5_error_code krb5_ccache_copy(context, cc_def, target_principal, cc_target,
4be148
+                                 restrict_creds, primary_principal, stored)
4be148
 /* IN */
4be148
     krb5_context context;
4be148
     krb5_ccache cc_def;
4be148
-    char *cc_other_tag;
4be148
-    krb5_principal primary_principal;
4be148
-    krb5_boolean restrict_creds;
4be148
     krb5_principal target_principal;
4be148
-    uid_t target_uid;
4be148
+    krb5_ccache cc_target;
4be148
+    krb5_boolean restrict_creds;
4be148
+    krb5_principal primary_principal;
4be148
     /* OUT */
4be148
-    krb5_ccache *cc_out;
4be148
     krb5_boolean *stored;
4be148
 {
4be148
     int i=0;
4be148
-    krb5_ccache  * cc_other;
4be148
     krb5_error_code retval=0;
4be148
     krb5_creds ** cc_def_creds_arr = NULL;
4be148
     krb5_creds ** cc_other_creds_arr = NULL;
4be148
 
4be148
-    cc_other = (krb5_ccache *)  xcalloc(1, sizeof (krb5_ccache));
4be148
-
4be148
-    if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
4be148
-        com_err(prog_name, retval, _("resolving ccache %s"), cc_other_tag);
4be148
-        return retval;
4be148
-    }
4be148
-
4be148
     if (ks_ccache_is_initialized(context, cc_def)) {
4be148
         if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){
4be148
             return retval;
4be148
         }
4be148
     }
4be148
 
4be148
-    if (ks_ccache_name_is_initialized(context, cc_other_tag))
4be148
-        return EINVAL;
4be148
-
4be148
-    if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
4be148
-        return errno;
4be148
-    }
4be148
-
4be148
-    retval = krb5_cc_initialize(context, *cc_other, target_principal);
4be148
+    retval = krb5_cc_initialize(context, cc_target, target_principal);
4be148
     if (retval)
4be148
         return retval;
4be148
 
4be148
     if (restrict_creds) {
4be148
-        retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr,
4be148
+        retval = krb5_store_some_creds(context, cc_target, cc_def_creds_arr,
4be148
                                        cc_other_creds_arr, primary_principal,
4be148
                                        stored);
4be148
     } else {
4be148
         *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr,
4be148
                                                primary_principal);
4be148
-        retval = krb5_store_all_creds(context, *cc_other, cc_def_creds_arr,
4be148
+        retval = krb5_store_all_creds(context, cc_target, cc_def_creds_arr,
4be148
                                       cc_other_creds_arr);
4be148
     }
4be148
 
4be148
@@ -118,7 +100,6 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
4be148
         }
4be148
     }
4be148
 
4be148
-    *cc_out = *cc_other;
4be148
     return retval;
4be148
 }
4be148
 
4be148
diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
4be148
index 08bf01b..fbbf217 100644
4be148
--- a/src/clients/ksu/ksu.h
4be148
+++ b/src/clients/ksu/ksu.h
4be148
@@ -44,8 +44,6 @@
4be148
 #define KRB5_DEFAULT_OPTIONS 0
4be148
 #define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */
4be148
 
4be148
-#define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_"
4be148
-
4be148
 #define KRB5_LOGIN_NAME ".k5login"
4be148
 #define KRB5_USERS_NAME ".k5users"
4be148
 #define USE_DEFAULT_REALM_NAME "."
4be148
@@ -106,8 +104,8 @@ extern krb5_error_code get_best_principal
4be148
 
4be148
 /* ccache.c */
4be148
 extern krb5_error_code krb5_ccache_copy
4be148
-(krb5_context, krb5_ccache, char *, krb5_principal, krb5_boolean,
4be148
- krb5_principal, krb5_ccache *, krb5_boolean *, uid_t);
4be148
+(krb5_context, krb5_ccache, krb5_principal, krb5_ccache,
4be148
+ krb5_boolean, krb5_principal, krb5_boolean *);
4be148
 
4be148
 extern krb5_error_code krb5_store_all_creds
4be148
 (krb5_context, krb5_ccache, krb5_creds **, krb5_creds **);
4be148
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
4be148
index d1bb8ca..41a3bf8 100644
4be148
--- a/src/clients/ksu/main.c
4be148
+++ b/src/clients/ksu/main.c
4be148
@@ -54,6 +54,10 @@ static void print_status( const char *fmt, ...)
4be148
     __attribute__ ((__format__ (__printf__, 1, 2)))
4be148
 #endif
4be148
     ;
4be148
+static krb5_error_code resolve_target_cache(krb5_context ksu_context,
4be148
+                                            krb5_principal princ,
4be148
+                                            krb5_ccache *ccache_out,
4be148
+                                            krb5_boolean *ccache_reused);
4be148
 
4be148
 /* Note -e and -a options are mutually exclusive */
4be148
 /* insure the proper specification of target user as well as catching
4be148
@@ -112,7 +116,7 @@ main (argc, argv)
4be148
     extern char * getpass(), *crypt();
4be148
     int pargc;
4be148
     char ** pargv;
4be148
-    krb5_boolean stored = FALSE;
4be148
+    krb5_boolean stored = FALSE, cc_reused = FALSE;
4be148
     krb5_principal  kdc_server;
4be148
     krb5_boolean zero_password;
4be148
     krb5_boolean restrict_creds;
4be148
@@ -416,23 +420,8 @@ main (argc, argv)
4be148
         exit(1);
4be148
     }
4be148
 
4be148
-    /*
4be148
-     * Make sure that the new ticket file does not already exist.
4be148
-     * This is run as source_uid because it is reasonable to
4be148
-     * require the source user to have write to where the target
4be148
-     * cache will be created.
4be148
-     */
4be148
-    cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE, sizeof(char));
4be148
-    do {
4be148
-        snprintf(cc_target_tag, KRB5_SEC_BUFFSIZE, "%s%ld.%d",
4be148
-                 KRB5_SECONDARY_CACHE,
4be148
-                 (long)target_uid, gen_sym());
4be148
-    } while (ks_ccache_name_is_initialized(ksu_context, cc_target_tag));
4be148
-
4be148
-    if (auth_debug){
4be148
+    if (auth_debug)
4be148
         fprintf(stderr, " source cache =  %s\n", cc_source_tag);
4be148
-        fprintf(stderr, " target cache =  %s\n", cc_target_tag);
4be148
-    }
4be148
 
4be148
     /*
4be148
      * After proper authentication and authorization, populate a cache for the
4be148
@@ -455,14 +444,19 @@ main (argc, argv)
4be148
         com_err(prog_name, retval, _("while parsing temporary name"));
4be148
         exit(1);
4be148
     }
4be148
-    retval = krb5_ccache_copy(ksu_context, cc_source, KS_TEMPORARY_CACHE,
4be148
-                              client, restrict_creds, tmp_princ, &cc_tmp,
4be148
-                              &stored, 0);
4be148
+    retval = krb5_cc_resolve(ksu_context, KS_TEMPORARY_CACHE, &cc_tmp);
4be148
+    if (retval) {
4be148
+        com_err(prog_name, retval, _("while creating temporary cache"));
4be148
+        exit(1);
4be148
+    }
4be148
+    retval = krb5_ccache_copy(ksu_context, cc_source, tmp_princ, cc_tmp,
4be148
+                              restrict_creds, client, &stored);
4be148
     if (retval) {
4be148
         com_err(prog_name, retval, _("while copying cache %s to %s"),
4be148
                 krb5_cc_get_name(ksu_context, cc_source), KS_TEMPORARY_CACHE);
4be148
         exit(1);
4be148
     }
4be148
+    krb5_cc_close(ksu_context, cc_source);
4be148
 
4be148
     /* Become root for authentication*/
4be148
 
4be148
@@ -686,23 +680,38 @@ main (argc, argv)
4be148
         exit(1);
4be148
     }
4be148
 
4be148
-    retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag,
4be148
-                              client, FALSE, client, &cc_target, &stored,
4be148
-                              target_pwd->pw_uid);
4be148
+    retval = resolve_target_cache(ksu_context, client, &cc_target, &cc_reused);
4be148
+    if (retval)
4be148
+        exit(1);
4be148
+    retval = krb5_cc_get_full_name(ksu_context, cc_target, &cc_target_tag);
4be148
     if (retval) {
4be148
-        com_err(prog_name, retval, _("while copying cache %s to %s"),
4be148
-                KS_TEMPORARY_CACHE, cc_target_tag);
4be148
+        com_err(prog_name, retval, _("while getting name of target ccache"));
4be148
+        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
+    if (auth_debug)
4be148
+        fprintf(stderr, " target cache =  %s\n", cc_target_tag);
4be148
+    if (cc_reused)
4be148
+        keep_target_cache = TRUE;
4be148
 
4be148
-    if (stored && !ks_ccache_is_initialized(ksu_context, cc_target)) {
4be148
-        com_err(prog_name, errno,
4be148
-                _("%s does not have correct permissions for %s, %s aborted"),
4be148
-                target_user, cc_target_tag, prog_name);
4be148
-        exit(1);
4be148
+    if (stored) {
4be148
+        retval = krb5_ccache_copy(ksu_context, cc_tmp, client, cc_target,
4be148
+                                  FALSE, client, &stored);
4be148
+        if (retval) {
4be148
+            com_err(prog_name, retval, _("while copying cache %s to %s"),
4be148
+                    KS_TEMPORARY_CACHE, cc_target_tag);
4be148
+            exit(1);
4be148
+        }
4be148
+
4be148
+        if (!ks_ccache_is_initialized(ksu_context, cc_target)) {
4be148
+            com_err(prog_name, errno,
4be148
+                    _("%s does not have correct permissions for %s, "
4be148
+                      "%s aborted"), target_user, cc_target_tag, prog_name);
4be148
+            exit(1);
4be148
+        }
4be148
     }
4be148
 
4be148
-    free(cc_target_tag);
4be148
+    krb5_free_string(ksu_context, cc_target_tag);
4be148
 
4be148
     /* Set the cc env name to target. */
4be148
     retval = set_ccname_env(ksu_context, cc_target);
4be148
@@ -711,9 +720,6 @@ main (argc, argv)
4be148
         exit(1);
4be148
     }
4be148
 
4be148
-    if ( cc_source)
4be148
-        krb5_cc_close(ksu_context, cc_source);
4be148
-
4be148
     if (cmd){
4be148
         if ((source_uid == 0) || (source_uid == target_uid )){
4be148
             exec_cmd = cmd;
4be148
@@ -803,6 +809,113 @@ set_ccname_env(krb5_context ksu_context, krb5_ccache ccache)
4be148
     return retval;
4be148
 }
4be148
 
4be148
+/*
4be148
+ * Get the configured default ccache name.  Unset KRB5CCNAME and force a
4be148
+ * recomputation so we don't use values for the source user.  Print an error
4be148
+ * message on failure.
4be148
+ */
4be148
+static krb5_error_code
4be148
+get_configured_defccname(krb5_context context, char **target_out)
4be148
+{
4be148
+    krb5_error_code retval;
4be148
+    const char *defname;
4be148
+    char *target;
4be148
+
4be148
+    *target_out = NULL;
4be148
+
4be148
+    if (unsetenv(KRB5_ENV_CCNAME) != 0) {
4be148
+        retval = errno;
4be148
+        com_err(prog_name, retval, _("while clearing the value of %s"),
4be148
+                KRB5_ENV_CCNAME);
4be148
+        return retval;
4be148
+    }
4be148
+
4be148
+    /* Make sure we don't have a cached value for a different uid. */
4be148
+    retval = krb5_cc_set_default_name(context, NULL);
4be148
+    if (retval != 0) {
4be148
+        com_err(prog_name, retval, _("while resetting target ccache name"));
4be148
+        return retval;
4be148
+    }
4be148
+
4be148
+    defname = krb5_cc_default_name(context);
4be148
+    target = (defname == NULL) ? NULL : strdup(defname);
4be148
+    if (target == NULL) {
4be148
+        com_err(prog_name, ENOMEM, _("while determining target ccache name"));
4be148
+        return ENOMEM;
4be148
+    }
4be148
+    *target_out = target;
4be148
+    return 0;
4be148
+}
4be148
+
4be148
+/* Determine where the target user's creds should be stored.  Print an error
4be148
+ * message on failure. */
4be148
+static krb5_error_code
4be148
+resolve_target_cache(krb5_context context, krb5_principal princ,
4be148
+                     krb5_ccache *ccache_out, krb5_boolean *ccache_reused)
4be148
+{
4be148
+    krb5_error_code retval;
4be148
+    krb5_boolean switchable, reused = FALSE;
4be148
+    krb5_ccache ccache = NULL;
4be148
+    char *sep, *ccname = NULL, *target;
4be148
+
4be148
+    *ccache_out = NULL;
4be148
+    *ccache_reused = FALSE;
4be148
+
4be148
+    retval = get_configured_defccname(context, &target);
4be148
+    if (retval != 0)
4be148
+        return retval;
4be148
+
4be148
+    /* Check if the configured default name uses a switchable type. */
4be148
+    sep = strchr(target, ':');
4be148
+    *sep = '\0';
4be148
+    switchable = krb5_cc_support_switch(context, target);
4be148
+    *sep = ':';
4be148
+
4be148
+    if (!switchable) {
4be148
+        /* Try to avoid destroying an in-use target ccache by coming up with
4be148
+         * the name of a cache that doesn't exist yet. */
4be148
+        do {
4be148
+            free(ccname);
4be148
+            if (asprintf(&ccname, "%s.%d", target, gen_sym()) < 0) {
4be148
+                retval = ENOMEM;
4be148
+                com_err(prog_name, ENOMEM,
4be148
+                        _("while allocating memory for target ccache name"));
4be148
+                goto cleanup;
4be148
+            }
4be148
+        } while (ks_ccache_name_is_initialized(context, ccname));
4be148
+        retval = krb5_cc_resolve(context, ccname, &ccache);
4be148
+    } else {
4be148
+        /* Look for a cache in the collection that we can reuse. */
4be148
+        retval = krb5_cc_cache_match(context, princ, &ccache);
4be148
+        if (retval == 0) {
4be148
+            reused = TRUE;
4be148
+        } else {
4be148
+            /* There isn't one, so create a new one. */
4be148
+            *sep = '\0';
4be148
+            retval = krb5_cc_new_unique(context, target, NULL, &ccache);
4be148
+            *sep = ':';
4be148
+            if (retval) {
4be148
+                com_err(prog_name, retval,
4be148
+                        _("while creating new target ccache"));
4be148
+                goto cleanup;
4be148
+            }
4be148
+            retval = krb5_cc_initialize(context, ccache, princ);
4be148
+            if (retval) {
4be148
+                com_err(prog_name, retval,
4be148
+                        _("while initializing target cache"));
4be148
+                goto cleanup;
4be148
+            }
4be148
+        }
4be148
+    }
4be148
+
4be148
+    *ccache_out = ccache;
4be148
+    *ccache_reused = reused;
4be148
+
4be148
+cleanup:
4be148
+    free(target);
4be148
+    return retval;
4be148
+}
4be148
+
4be148
 #ifdef HAVE_GETUSERSHELL
4be148
 
4be148
 int standard_shell(sh)
4be148
-- 
4be148
2.0.4
4be148