Blame SOURCES/0003-Use-an-intermediate-memory-cache-in-ksu.patch

4be148
From dccc80a469b1925fcfe7697406a69912efe4baa1 Mon Sep 17 00:00:00 2001
4be148
From: Nalin Dahyabhai <nalin@dahyabhai.net>
4be148
Date: Wed, 30 Oct 2013 21:45:35 -0400
4be148
Subject: [PATCH 3/7] Use an intermediate memory cache in ksu
4be148
4be148
Instead of copying source or obtained creds into the target cache and
4be148
changing ownership if everything succeeds, copy them into a MEMORY:
4be148
cache and then, if everything succeeds, create the target cache as the
4be148
target user.
4be148
4be148
We no longer need to clean up the temporary ccache when exiting in
4be148
most error cases.
4be148
4be148
Use a fake principal name ("_ksu/_ksu@_ksu") as the primary holder of
4be148
the temporary cache so that we won't accidentally select it when we
4be148
make a subsequent call to krb5_cc_cache_match() (to be added in a
4be148
later patch) to find the target location where the creds should be
4be148
stored for use while running as the target user.
4be148
---
4be148
 src/clients/ksu/ccache.c |  10 +--
4be148
 src/clients/ksu/ksu.h    |   4 +-
4be148
 src/clients/ksu/main.c   | 156 ++++++++++++++++++++++++-----------------------
4be148
 3 files changed, 87 insertions(+), 83 deletions(-)
4be148
4be148
diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
4be148
index 5f57279..d0fc389 100644
4be148
--- a/src/clients/ksu/ccache.c
4be148
+++ b/src/clients/ksu/ccache.c
4be148
@@ -47,14 +47,15 @@ void show_credential();
4be148
 */
4be148
 
4be148
 krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
4be148
-                                  primary_principal, restrict_creds, cc_out,
4be148
-                                  stored, target_uid)
4be148
+                                  primary_principal, restrict_creds,
4be148
+                                  target_principal, cc_out, stored, target_uid)
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
     /* OUT */
4be148
     krb5_ccache *cc_out;
4be148
@@ -86,10 +87,9 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
4be148
         return errno;
4be148
     }
4be148
 
4be148
-
4be148
-    if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){
4be148
+    retval = krb5_cc_initialize(context, *cc_other, target_principal);
4be148
+    if (retval)
4be148
         return retval;
4be148
-    }
4be148
 
4be148
     if (restrict_creds) {
4be148
         retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr,
4be148
diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
4be148
index e1e34f1..08bf01b 100644
4be148
--- a/src/clients/ksu/ksu.h
4be148
+++ b/src/clients/ksu/ksu.h
4be148
@@ -106,8 +106,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,
4be148
- krb5_boolean, krb5_ccache *, krb5_boolean *, uid_t);
4be148
+(krb5_context, krb5_ccache, char *, krb5_principal, krb5_boolean,
4be148
+ krb5_principal, krb5_ccache *, krb5_boolean *, uid_t);
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 8c49f94..d1bb8ca 100644
4be148
--- a/src/clients/ksu/main.c
4be148
+++ b/src/clients/ksu/main.c
4be148
@@ -42,10 +42,13 @@ char * gb_err = NULL;
4be148
 int quiet = 0;
4be148
 /***********/
4be148
 
4be148
+#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
4be148
+#define KS_TEMPORARY_PRINC "_ksu/_ksu@_ksu"
4be148
 #define _DEF_CSH "/bin/csh"
4be148
 static int set_env_var (char *, char *);
4be148
 static void sweep_up (krb5_context, krb5_ccache);
4be148
 static char * ontty (void);
4be148
+static krb5_error_code set_ccname_env(krb5_context, krb5_ccache);
4be148
 static void print_status( const char *fmt, ...)
4be148
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
4be148
     __attribute__ ((__format__ (__printf__, 1, 2)))
4be148
@@ -84,8 +87,8 @@ main (argc, argv)
4be148
     int option=0;
4be148
     int statusp=0;
4be148
     krb5_error_code retval = 0;
4be148
-    krb5_principal client = NULL;
4be148
-    krb5_ccache cc_target = NULL;
4be148
+    krb5_principal client = NULL, tmp_princ = NULL;
4be148
+    krb5_ccache cc_tmp = NULL, cc_target = NULL;
4be148
     krb5_context ksu_context;
4be148
     char * cc_target_tag = NULL;
4be148
     char * target_user = NULL;
4be148
@@ -93,7 +96,6 @@ main (argc, argv)
4be148
 
4be148
     krb5_ccache cc_source = NULL;
4be148
     const char * cc_source_tag = NULL;
4be148
-    uid_t source_gid;
4be148
     const char * cc_source_tag_tmp = NULL;
4be148
     char * cmd = NULL, * exec_cmd = NULL;
4be148
     int errflg = 0;
4be148
@@ -342,8 +344,6 @@ main (argc, argv)
4be148
     /* allocate space and copy the usernamane there */
4be148
     source_user = xstrdup(pwd->pw_name);
4be148
     source_uid = pwd->pw_uid;
4be148
-    source_gid = pwd->pw_gid;
4be148
-
4be148
 
4be148
     if (!strcmp(SOURCE_USER_LOGIN, target_user)){
4be148
         target_user = xstrdup (source_user);
4be148
@@ -435,25 +435,32 @@ main (argc, argv)
4be148
     }
4be148
 
4be148
     /*
4be148
-      Only when proper authentication and authorization
4be148
-      takes place, the target user becomes the owner of the cache.
4be148
-    */
4be148
-
4be148
-    /* we continue to run as source uid until
4be148
-       the middle of the copy, when becomewe become the target user
4be148
-       The cache is owned by the target user.*/
4be148
+     * After proper authentication and authorization, populate a cache for the
4be148
+     * target user.
4be148
+     */
4be148
 
4be148
+    /*
4be148
+     * We read the set of creds we want to copy from the source ccache as the
4be148
+     * source uid, become root for authentication, and then become the target
4be148
+     * user to handle authorization and creating the target user's cache.
4be148
+     */
4be148
 
4be148
     /* if root ksu's to a regular user, then
4be148
        then only the credentials for that particular user
4be148
        should be copied */
4be148
 
4be148
     restrict_creds = (source_uid == 0) && (target_uid != 0);
4be148
-    retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, client,
4be148
-                              restrict_creds, &cc_target, &stored, target_uid);
4be148
+    retval = krb5_parse_name(ksu_context, KS_TEMPORARY_PRINC, &tmp_princ);
4be148
+    if (retval) {
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
     if (retval) {
4be148
         com_err(prog_name, retval, _("while copying cache %s to %s"),
4be148
-                krb5_cc_get_name(ksu_context, cc_source), cc_target_tag);
4be148
+                krb5_cc_get_name(ksu_context, cc_source), KS_TEMPORARY_CACHE);
4be148
         exit(1);
4be148
     }
4be148
 
4be148
@@ -473,7 +480,6 @@ main (argc, argv)
4be148
                                       &kdc_server))){
4be148
                 com_err(prog_name, retval,
4be148
                         _("while creating tgt for local realm"));
4be148
-                sweep_up(ksu_context, cc_target);
4be148
                 exit(1);
4be148
             }
4be148
 
4be148
@@ -481,13 +487,12 @@ main (argc, argv)
4be148
                               "enter it here and are logged\n"));
4be148
             fprintf(stderr, _("         in remotely using an unsecure "
4be148
                               "(non-encrypted) channel.\n"));
4be148
-            if (krb5_get_tkt_via_passwd (ksu_context, &cc_target, client,
4be148
-                                         kdc_server, &options,
4be148
-                                         &zero_password) == FALSE){
4be148
+            if (krb5_get_tkt_via_passwd(ksu_context, &cc_tmp, client,
4be148
+                                        kdc_server, &options,
4be148
+                                        &zero_password) == FALSE){
4be148
 
4be148
                 if (zero_password == FALSE){
4be148
                     fprintf(stderr, _("Goodbye\n"));
4be148
-                    sweep_up(ksu_context, cc_target);
4be148
                     exit(1);
4be148
                 }
4be148
 
4be148
@@ -506,48 +511,20 @@ main (argc, argv)
4be148
     if (source_uid && (source_uid != target_uid)) {
4be148
         char * client_name;
4be148
 
4be148
-        auth_val = krb5_auth_check(ksu_context, client, localhostname, &options,
4be148
-                                   target_user,cc_target, &path_passwd, target_uid);
4be148
+        auth_val = krb5_auth_check(ksu_context, client, localhostname,
4be148
+                                   &options, target_user, cc_tmp,
4be148
+                                   &path_passwd, target_uid);
4be148
 
4be148
         /* if Kerberos authentication failed then exit */
4be148
         if (auth_val ==FALSE){
4be148
             fprintf(stderr, _("Authentication failed.\n"));
4be148
             syslog(LOG_WARNING, "'%s %s' authentication failed for %s%s",
4be148
                    prog_name,target_user,source_user,ontty());
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
 
4be148
-#if 0
4be148
-        /* At best, this avoids a single kdc request
4be148
-           It is hard to implement dealing with file permissions and
4be148
-           is unnecessary.  It is important
4be148
-           to properly handle races in chown if this code is ever re-enabled.
4be148
-        */
4be148
-        /* cache the tickets if possible in the source cache */
4be148
-        if (!path_passwd){
4be148
-
4be148
-            if ((retval = krb5_ccache_overwrite(ksu_context, cc_target, cc_source,
4be148
-                                                client))){
4be148
-                com_err (prog_name, retval,
4be148
-                         "while copying cache %s to %s",
4be148
-                         krb5_cc_get_name(ksu_context, cc_target),
4be148
-                         krb5_cc_get_name(ksu_context, cc_source));
4be148
-                sweep_up(ksu_context, cc_target);
4be148
-                exit(1);
4be148
-            }
4be148
-            if (chown(cc_source_tag_tmp, source_uid, source_gid)){
4be148
-                com_err(prog_name, errno,
4be148
-                        "while changing owner for %s",
4be148
-                        cc_source_tag_tmp);
4be148
-                exit(1);
4be148
-            }
4be148
-        }
4be148
-#endif /*0*/
4be148
-
4be148
         if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) {
4be148
             com_err(prog_name, retval, _("When unparsing name"));
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
 
4be148
@@ -560,7 +537,6 @@ main (argc, argv)
4be148
         if (krb5_seteuid(target_uid)) {
4be148
             com_err(prog_name, errno, _("while switching to target for "
4be148
                                         "authorization check"));
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
 
4be148
@@ -568,14 +544,12 @@ main (argc, argv)
4be148
                                          cmd, &authorization_val, &exec_cmd))){
4be148
             com_err(prog_name,retval, _("while checking authorization"));
4be148
             krb5_seteuid(0); /*So we have some chance of sweeping up*/
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
 
4be148
         if (krb5_seteuid(0)) {
4be148
             com_err(prog_name, errno, _("while switching back from target "
4be148
                                         "after authorization check"));
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
         if (authorization_val == TRUE){
4be148
@@ -617,25 +591,25 @@ main (argc, argv)
4be148
 
4be148
             }
4be148
 
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
     }
4be148
 
4be148
     if( some_rest_copy){
4be148
-        if ((retval = krb5_ccache_filter(ksu_context, cc_target, client))){
4be148
+        retval = krb5_ccache_filter(ksu_context, cc_tmp, client);
4be148
+        if (retval) {
4be148
             com_err(prog_name,retval, _("while calling cc_filter"));
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
     }
4be148
 
4be148
     if (all_rest_copy){
4be148
-        if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){
4be148
+        retval = krb5_cc_initialize(ksu_context, cc_tmp, tmp_princ);
4be148
+        if (retval) {
4be148
             com_err(prog_name, retval, _("while erasing target cache"));
4be148
             exit(1);
4be148
         }
4be148
-
4be148
+        stored = FALSE;
4be148
     }
4be148
 
4be148
     /* get the shell of the user, this will be the shell used by su */
4be148
@@ -653,7 +627,6 @@ main (argc, argv)
4be148
 
4be148
     if (!standard_shell(target_pwd->pw_shell) && source_uid) {
4be148
         fprintf(stderr, _("ksu: permission denied (shell).\n"));
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 #endif /* HAVE_GETUSERSHELL */
4be148
@@ -663,43 +636,28 @@ main (argc, argv)
4be148
         if(set_env_var("USER", target_pwd->pw_name)){
4be148
             fprintf(stderr,
4be148
                     _("ksu: couldn't set environment variable USER\n"));
4be148
-            sweep_up(ksu_context, cc_target);
4be148
             exit(1);
4be148
         }
4be148
     }
4be148
 
4be148
     if(set_env_var( "HOME", target_pwd->pw_dir)){
4be148
         fprintf(stderr, _("ksu: couldn't set environment variable HOME\n"));
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 
4be148
     if(set_env_var( "SHELL", shell)){
4be148
         fprintf(stderr, _("ksu: couldn't set environment variable SHELL\n"));
4be148
-        sweep_up(ksu_context, cc_target);
4be148
-        exit(1);
4be148
-    }
4be148
-
4be148
-    /* set the cc env name to target */
4be148
-
4be148
-    if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){
4be148
-        fprintf(stderr, _("ksu: couldn't set environment variable %s\n"),
4be148
-                KRB5_ENV_CCNAME);
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 
4be148
     /* set permissions */
4be148
     if (setgid(target_pwd->pw_gid) < 0) {
4be148
         perror("ksu: setgid");
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 
4be148
-
4be148
     if (initgroups(target_user, target_pwd->pw_gid)) {
4be148
         fprintf(stderr, _("ksu: initgroups failed.\n"));
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 
4be148
@@ -719,13 +677,36 @@ main (argc, argv)
4be148
      */
4be148
     if (setluid((uid_t) pwd->pw_uid) < 0) {
4be148
         perror("setluid");
4be148
-        sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
 #endif  /* HAVE_SETLUID */
4be148
 
4be148
     if (setuid(target_pwd->pw_uid) < 0) {
4be148
         perror("ksu: setuid");
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
+    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 (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
+    }
4be148
+
4be148
+    free(cc_target_tag);
4be148
+
4be148
+    /* Set the cc env name to target. */
4be148
+    retval = set_ccname_env(ksu_context, cc_target);
4be148
+    if (retval != 0) {
4be148
         sweep_up(ksu_context, cc_target);
4be148
         exit(1);
4be148
     }
4be148
@@ -799,6 +780,29 @@ main (argc, argv)
4be148
     }
4be148
 }
4be148
 
4be148
+/* Set KRB5CCNAME in the environment to point to ccache.  Print an error
4be148
+ * message on failure. */
4be148
+static krb5_error_code
4be148
+set_ccname_env(krb5_context ksu_context, krb5_ccache ccache)
4be148
+{
4be148
+    krb5_error_code retval;
4be148
+    char *ccname;
4be148
+
4be148
+    retval = krb5_cc_get_full_name(ksu_context, ccache, &ccname);
4be148
+    if (retval) {
4be148
+        com_err(prog_name, retval, _("while reading cache name from ccache"));
4be148
+        return retval;
4be148
+    }
4be148
+    if (set_env_var(KRB5_ENV_CCNAME, ccname)) {
4be148
+        retval = errno;
4be148
+        fprintf(stderr,
4be148
+                _("ksu: couldn't set environment variable %s\n"),
4be148
+                KRB5_ENV_CCNAME);
4be148
+    }
4be148
+    krb5_free_string(ksu_context, ccname);
4be148
+    return retval;
4be148
+}
4be148
+
4be148
 #ifdef HAVE_GETUSERSHELL
4be148
 
4be148
 int standard_shell(sh)
4be148
-- 
4be148
2.0.4
4be148