]> granicus.if.org Git - sudo/commitdiff
Set aux group vector for PERM_RUNAS and restore group vector for
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 25 Nov 2007 13:07:21 +0000 (13:07 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 25 Nov 2007 13:07:21 +0000 (13:07 +0000)
PERM_ROOT if we previously changed it.  Stash the runas group vector
so we don't have to call initgroups more than once. Also add no-op
check to check_perms.

logging.c
set_perms.c

index bce2d2a299ed21e4d76897ea44e67e0f9c2ce856..32ec866a5a773864a7a6a3910714535703073d24 100644 (file)
--- a/logging.c
+++ b/logging.c
@@ -353,9 +353,8 @@ log_error(flags, fmt, va_alist)
     va_start(ap);
 #endif
 
-    /* Become root if we are not already to avoid user control */
-    if (geteuid() != 0)
-       set_perms(PERM_ROOT);
+    /* Become root if we are not already to avoid user interference */
+    set_perms(PERM_ROOT);
 
     /* Expand printf-style format + args. */
     evasprintf(&message, fmt, ap);
index 6548f6dd9aba422f50d2c1f8ac2a88fac0191fde..a98bc7d738e0a60be1ae288ecee7a578fc591313 100644 (file)
@@ -65,6 +65,10 @@ __unused static const char rcsid[] = "$Sudo$";
  * Prototypes
  */
 static void runas_setup                __P((void));
+static void runas_setgroups    __P((const char *, gid_t));
+static void restore_groups     __P((void));
+
+static int current_perm = -1;
 
 #ifdef HAVE_SETRESUID
 /*
@@ -77,11 +81,16 @@ void
 set_perms(perm)
     int perm;
 {
+    if (perm == current_perm)
+       return;
+
     switch (perm) {
        case PERM_ROOT:
                                if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID))
                                    errorx(1, "setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid");
                                (void) setresgid(-1, user_gid, -1);
+                               if (current_perm == PERM_RUNAS)
+                                   restore_groups();
                                break;
 
        case PERM_USER:
@@ -98,6 +107,7 @@ set_perms(perm)
                                break;
                                
        case PERM_RUNAS:
+                               runas_setgroups(runas_pw->pw_name, runas_pw->pw_gid);
                                (void) setresgid(-1, runas_gr ?
                                    runas_gr->gr_gid : runas_pw->pw_gid, -1);
                                if (setresuid(-1,
@@ -139,6 +149,8 @@ set_perms(perm)
                                    error(1, "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)");
                                break;
     }
+
+    current_perm = perm;
 }
 
 #else
@@ -154,6 +166,9 @@ void
 set_perms(perm)
     int perm;
 {
+    if (perm == current_perm)
+       return;
+
     switch (perm) {
        case PERM_ROOT:
                                if (setreuid(-1, ROOT_UID))
@@ -161,6 +176,8 @@ set_perms(perm)
                                if (setuid(ROOT_UID))
                                    error(1, "setuid(ROOT_UID)");
                                (void) setregid(-1, user_gid);
+                               if (current_perm == PERM_RUNAS)
+                                   restore_groups();
                                break;
 
        case PERM_USER:
@@ -177,6 +194,7 @@ set_perms(perm)
                                break;
                                
        case PERM_RUNAS:
+                               runas_setgroups(runas_pw->pw_name, runas_pw->pw_gid);
                                (void) setregid(-1, runas_gr ?
                                    runas_gr->gr_gid : runas_pw->pw_gid);
                                if (setreuid(-1,
@@ -217,6 +235,8 @@ set_perms(perm)
                                    error(1, "setreuid(ROOT_UID, timestamp_uid)");
                                break;
     }
+
+    current_perm = perm;
 }
 
 # else /* !HAVE_SETRESUID && !HAVE_SETREUID */
@@ -230,6 +250,9 @@ void
 set_perms(perm)
     int perm;
 {
+    if (perm == current_perm)
+       return;
+
     /*
      * Since we only have setuid() and seteuid() and semantics
      * for these calls differ on various systems, we set
@@ -244,6 +267,8 @@ set_perms(perm)
        case PERM_ROOT:
                                /* uid set above */
                                (void) setegid(user_gid);
+                               if (current_perm == PERM_RUNAS)
+                                   restore_groups();
                                break;
 
        case PERM_USER:
@@ -260,6 +285,7 @@ set_perms(perm)
                                break;
                                
        case PERM_RUNAS:
+                               runas_setgroups(runas_pw->pw_name, runas_pw->pw_gid);
                                (void) setegid(runas_gr ?
                                    runas_gr->gr_gid : runas_pw->pw_gid);
                                if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid))
@@ -297,6 +323,8 @@ set_perms(perm)
                                    error(1, "seteuid(timestamp_uid)");
                                break;
     }
+
+    current_perm = perm;
 }
 
 # else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
@@ -310,11 +338,15 @@ void
 set_perms(perm)
     int perm;
 {
+    if (perm == current_perm)
+       return;
 
     switch (perm) {
        case PERM_ROOT:
                                if (setuid(ROOT_UID))
                                        error(1, "setuid(ROOT_UID)");
+                               if (current_perm == PERM_RUNAS)
+                                   restore_groups();
                                break;
 
        case PERM_FULL_USER:
@@ -336,11 +368,67 @@ set_perms(perm)
                                /* Unsupported since we can't set euid. */
                                break;
     }
+
+    current_perm = perm;
 }
 #  endif /* HAVE_SETEUID */
 # endif /* HAVE_SETREUID */
 #endif /* HAVE_SETRESUID */
 
+#ifdef HAVE_INITGROUPS
+static void
+runas_setgroups(name, basegid)
+    const char *name;
+    gid_t basegid;
+{
+    static int ngroups = -1;
+    static gid_t *groups;
+
+    if (def_preserve_groups)
+       return;
+
+    /*
+     * Use stashed copy of runas groups if available, else initgroups and stash.
+     */
+    if (ngroups == -1) {
+       if (initgroups(name, basegid) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
+       if ((ngroups = getgroups(0, NULL)) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't get runas ngroups");
+       groups = emalloc2(ngroups, MAX(sizeof(gid_t), sizeof(int)));
+       if (getgroups(ngroups, groups) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
+    } else {
+       if (setgroups(ngroups, groups) < 0)
+           log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
+    }
+}
+
+static void
+restore_groups()
+{
+    if (setgroups(user_ngroups, user_groups) < 0)
+       log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
+}
+
+#else
+
+static void
+runas_setgroups(name, basegid)
+    const char *name;
+    gid_t basegid;
+{
+    /* STUB */
+}
+
+static void
+restore_groups()
+{
+    /* STUB */
+}
+
+#endif /* HAVE_INITGROUPS */
+
 static void
 runas_setup()
 {
@@ -359,10 +447,7 @@ runas_setup()
 #ifdef HAVE_LOGIN_CAP_H
        if (def_use_loginclass) {
            /*
-             * We don't have setusercontext() set the user since we
-             * may only want to set the effective uid.  Depending on
-             * sudoers and/or command line arguments we may not want
-             * setusercontext() to call initgroups().
+             * We only use setusercontext() set the nice value and rlimits.
             */
            flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
            if (!def_preserve_groups)
@@ -375,19 +460,13 @@ runas_setup()
                else
                    warning("unable to set user context");
            }
-       } else
-#endif /* HAVE_LOGIN_CAP_H */
-       {
-           if (setgid(gid))
-               warning("cannot set gid to runas gid");
-#ifdef HAVE_INITGROUPS
-           /*
-            * Initialize group vector unless asked not to.
-            */
-           if (!def_preserve_groups &&
-               initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0)
-               warning("cannot set group vector");
-#endif /* HAVE_INITGROUPS */
        }
+#endif /* HAVE_LOGIN_CAP_H */
+       if (setgid(gid))
+           warning("cannot set gid to runas gid");
+       /*
+        * Initialize group vector
+        */
+       runas_setgroups(runas_pw->pw_name, runas_pw->pw_gid);
     }
 }