Blob Blame History Raw
From 60295a63fadf04f6cd6db7919aa1dad6fb4f0596 Mon Sep 17 00:00:00 2001
From: Nalin Dahyabhai <nalin@dahyabhai.net>
Date: Wed, 30 Oct 2013 21:45:35 -0400
Subject: [PATCH 2/6] Use an in-memory cache until we need the target's

Instead of copying source or obtained creds into the target cache and
changing ownership if everything succeeds, copy them into a MEMORY:
cache and then, if everything succeeds, create the target cache as the
target user.
---
 src/clients/ksu/ksu.h  |   1 +
 src/clients/ksu/main.c | 133 +++++++++++++++++++++++++++++--------------------
 2 files changed, 80 insertions(+), 54 deletions(-)

diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
index 2a63c21..1d102a1 100644
--- a/src/clients/ksu/ksu.h
+++ b/src/clients/ksu/ksu.h
@@ -45,6 +45,7 @@
 #define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */
 
 #define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_"
+#define KRB5_TEMPORARY_CACHE "MEMORY:_ksu"
 
 #define KRB5_LOGIN_NAME ".k5login"
 #define KRB5_USERS_NAME ".k5users"
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
index e2ca06a..fa86c78 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -86,7 +86,7 @@ main (argc, argv)
     int statusp=0;
     krb5_error_code retval = 0;
     krb5_principal client = NULL;
-    krb5_ccache cc_target = NULL;
+    krb5_ccache cc_tmp = NULL, cc_target = NULL;
     krb5_context ksu_context;
     char * cc_target_tag = NULL;
     char * target_user = NULL;
@@ -452,14 +452,15 @@ main (argc, argv)
     }
 
     /*
-      Only when proper authentication and authorization
-      takes place, the target user becomes the owner of the cache.
-    */
-
-    /* we continue to run as source uid until
-       the middle of the copy, when becomewe become the target user
-       The cache is owned by the target user.*/
+     * Only after proper authentication and authorization has
+     * taken place, do we populate a cache for the target user.
+     */
 
+    /*
+     * We read the set of creds we want to copy from the source ccache as the
+     * source uid, become root for authentication, and then become the target
+     * user to handle authorization and creating the target user's cache.
+     */
 
     /* if root ksu's to a regular user, then
        then only the credentials for that particular user
@@ -468,19 +469,23 @@ main (argc, argv)
     if ((source_uid == 0) && (target_uid != 0)) {
 
         if ((retval = krb5_ccache_copy_restricted(ksu_context,  cc_source,
-                                                  cc_target_tag, client,
-                                                  &cc_target, &stored,
-                                                  target_uid))){
+                                                  KRB5_TEMPORARY_CACHE, client,
+                                                  &cc_tmp, &stored,
+                                                  0))){
             com_err(prog_name, retval, _("while copying cache %s to %s"),
-                    krb5_cc_get_name(ksu_context, cc_source), cc_target_tag);
+                    krb5_cc_get_name(ksu_context, cc_source),
+                    KRB5_TEMPORARY_CACHE);
             exit(1);
         }
 
     } else {
-        if ((retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag,
-                                       client,&cc_target, &stored, target_uid))) {
+
+        retval = krb5_ccache_copy(ksu_context, cc_source, KRB5_TEMPORARY_CACHE,
+                                  client, &cc_tmp, &stored, 0);
+        if (retval) {
             com_err(prog_name, retval, _("while copying cache %s to %s"),
-                    krb5_cc_get_name(ksu_context, cc_source), cc_target_tag);
+                    krb5_cc_get_name(ksu_context, cc_source),
+                    KRB5_TEMPORARY_CACHE);
             exit(1);
         }
 
@@ -502,7 +507,7 @@ main (argc, argv)
                                       &kdc_server))){
                 com_err(prog_name, retval,
                         _("while creating tgt for local realm"));
-                sweep_up(ksu_context, cc_target);
+                sweep_up(ksu_context, cc_tmp);
                 exit(1);
             }
 
@@ -510,13 +515,13 @@ main (argc, argv)
                               "enter it here and are logged\n"));
             fprintf(stderr, _("         in remotely using an unsecure "
                               "(non-encrypted) channel.\n"));
-            if (krb5_get_tkt_via_passwd (ksu_context, &cc_target, client,
-                                         kdc_server, &options,
-                                         &zero_password) == FALSE){
+            if (krb5_get_tkt_via_passwd(ksu_context, &cc_tmp, client,
+                                        kdc_server, &options,
+                                        &zero_password) == FALSE){
 
                 if (zero_password == FALSE){
                     fprintf(stderr, _("Goodbye\n"));
-                    sweep_up(ksu_context, cc_target);
+                    sweep_up(ksu_context, cc_tmp);
                     exit(1);
                 }
 
@@ -535,15 +540,16 @@ main (argc, argv)
     if (source_uid && (source_uid != target_uid)) {
         char * client_name;
 
-        auth_val = krb5_auth_check(ksu_context, client, localhostname, &options,
-                                   target_user,cc_target, &path_passwd, target_uid);
+        auth_val = krb5_auth_check(ksu_context, client, localhostname,
+                                   &options, target_user, cc_tmp,
+                                   &path_passwd, target_uid);
 
         /* if Kerberos authentication failed then exit */
         if (auth_val ==FALSE){
             fprintf(stderr, _("Authentication failed.\n"));
             syslog(LOG_WARNING, "'%s %s' authentication failed for %s%s",
                    prog_name,target_user,source_user,ontty());
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
 
@@ -576,7 +582,7 @@ main (argc, argv)
 
         if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) {
             com_err(prog_name, retval, _("When unparsing name"));
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
 
@@ -589,7 +595,7 @@ main (argc, argv)
         if (krb5_seteuid(target_uid)) {
             com_err(prog_name, errno, _("while switching to target for "
                                         "authorization check"));
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
 
@@ -597,14 +603,14 @@ main (argc, argv)
                                          cmd, &authorization_val, &exec_cmd))){
             com_err(prog_name,retval, _("while checking authorization"));
             krb5_seteuid(0); /*So we have some chance of sweeping up*/
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
 
         if (krb5_seteuid(0)) {
             com_err(prog_name, errno, _("while switching back from target "
                                         "after authorization check"));
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
         if (authorization_val == TRUE){
@@ -646,21 +652,23 @@ main (argc, argv)
 
             }
 
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
     }
 
     if( some_rest_copy){
-        if ((retval = krb5_ccache_filter(ksu_context, cc_target, client))){
+        retval = krb5_ccache_filter(ksu_context, cc_tmp, client);
+        if (retval) {
             com_err(prog_name,retval, _("while calling cc_filter"));
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
     }
 
     if (all_rest_copy){
-        if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){
+        retval = krb5_cc_initialize(ksu_context, cc_tmp, client);
+        if (retval) {
             com_err(prog_name, retval, _("while erasing target cache"));
             exit(1);
         }
@@ -682,7 +690,7 @@ main (argc, argv)
 
     if (!standard_shell(target_pwd->pw_shell) && source_uid) {
         fprintf(stderr, _("ksu: permission denied (shell).\n"));
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 #endif /* HAVE_GETUSERSHELL */
@@ -692,43 +700,33 @@ main (argc, argv)
         if(set_env_var("USER", target_pwd->pw_name)){
             fprintf(stderr,
                     _("ksu: couldn't set environment variable USER\n"));
-            sweep_up(ksu_context, cc_target);
+            sweep_up(ksu_context, cc_tmp);
             exit(1);
         }
     }
 
     if(set_env_var( "HOME", target_pwd->pw_dir)){
         fprintf(stderr, _("ksu: couldn't set environment variable HOME\n"));
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 
     if(set_env_var( "SHELL", shell)){
         fprintf(stderr, _("ksu: couldn't set environment variable SHELL\n"));
-        sweep_up(ksu_context, cc_target);
-        exit(1);
-    }
-
-    /* set the cc env name to target */
-
-    if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){
-        fprintf(stderr, _("ksu: couldn't set environment variable %s\n"),
-                KRB5_ENV_CCNAME);
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 
     /* set permissions */
     if (setgid(target_pwd->pw_gid) < 0) {
         perror("ksu: setgid");
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 
-
     if (initgroups(target_user, target_pwd->pw_gid)) {
         fprintf(stderr, _("ksu: initgroups failed.\n"));
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 
@@ -748,22 +746,49 @@ main (argc, argv)
      */
     if (setluid((uid_t) pwd->pw_uid) < 0) {
         perror("setluid");
-        sweep_up(ksu_context, cc_target);
+        sweep_up(ksu_context, cc_tmp);
         exit(1);
     }
 #endif  /* HAVE_SETLUID */
 
-    if (setuid(target_pwd->pw_uid) < 0) {
+    if (seteuid(0) < 0 || seteuid(target_pwd->pw_uid) < 0) {
+        perror("ksu: seteuid");
+        sweep_up(ksu_context, cc_tmp);
+        exit(1);
+    }
+
+    retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag,
+                              client, &cc_target, &stored,
+                              target_pwd->pw_uid);
+    if (retval) {
+        com_err(prog_name, retval, _("while copying cache %s to %s"),
+                krb5_cc_get_name(ksu_context, cc_tmp), cc_target_tag);
+        exit(1);
+    }
+
+    if (setuid(0) < 0 || setuid(target_pwd->pw_uid) < 0) {
         perror("ksu: setuid");
         sweep_up(ksu_context, cc_target);
         exit(1);
     }
 
-    if (access( cc_target_tag_tmp, R_OK | W_OK )){
-        com_err(prog_name, errno,
-                _("%s does not have correct permissions for %s, %s aborted"),
-                target_user, cc_target_tag_tmp, prog_name);
-        exit(1);
+    /* set the cc env name to target */
+    if (stored) {
+        if (krb5_cc_get_full_name(ksu_context, cc_target,
+                                  &cc_target_tag) == 0) {
+            if (set_env_var(KRB5_ENV_CCNAME, cc_target_tag)){
+                fprintf(stderr,
+                        _("ksu: couldn't set environment variable %s\n"),
+                        KRB5_ENV_CCNAME);
+                sweep_up(ksu_context, cc_target);
+                exit(1);
+            }
+            krb5_free_string(ksu_context, cc_target_tag);
+        } else {
+            com_err(prog_name, retval, _("while reading cache name from %s"),
+                    cc_target_tag);
+            exit(1);
+        }
     }
 
     if ( cc_source)
-- 
1.8.4.2