]> granicus.if.org Git - sudo/commitdiff
Revamp set_perms. We now use a version based on setresuid() or setreuid()
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 22 Nov 2002 19:09:49 +0000 (19:09 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 22 Nov 2002 19:09:49 +0000 (19:09 +0000)
when possible since that allows us to support the stay_setuid option and
we always know exactly what the semantics will be (various Linux kernels
have broken POSIX saved uid support).

set_perms.c
sudo.c
sudo.h

index 45374eb077d0681af37a519418a6b7192c8550e0..d672d65fa735fb2cffaa8686d910c2c1967d2366 100644 (file)
@@ -153,14 +153,87 @@ set_perms_posix(perm)
 }
 #endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
 
-#ifdef HAVE_SETREUID
+#ifdef HAVE_SETRESUID
+/*
+ * Set real and effective and saved uids and gids based on perm.
+ * We always retain a saved uid of 0 unless we are headed for an exec().
+ * We only flip the effective gid since it only changes for PERM_SUDOERS.
+ * This version of set_perms() works fine with the "stay_setuid" option.
+ */
+void
+set_perms_suid(perm)
+    int perm;
+{
+    int error;
+
+    switch (perm) {
+       case PERM_FULL_ROOT:
+       case PERM_ROOT:
+                               if (setresuid(0, 0, 0))
+                                   fatal("setresuid(0, 0, 0) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0);
+                               break;
+
+       case PERM_USER:
+                               (void) setresgid(user_gid, -1, -1);
+                               if (setresuid(user_uid, user_uid, 0))
+                                   fatal("setresuid(user_uid, user_uid, 0)", 1);
+                               break;
+                               
+       case PERM_FULL_USER:
+                               /* headed for exec() */
+                               (void) setgid(user_gid);
+                               if (setresuid(user_uid, user_uid, user_uid))
+                                   fatal("setresuid(user_uid, user_uid, user_uid)", 1);
+                               break;
+                               
+       case PERM_RUNAS:
+                               /* headed for exec(), assume euid == 0 */
+                               runas_setup();
+                               error = setresuid(def_flag(I_STAY_SETUID) ?
+                                   user_uid : runas_pw->pw_uid,
+                                   runas_pw->pw_uid, runas_pw->pw_uid);
+                               if (error)
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_SUDOERS:
+                               /* assume euid == 0, ruid == user */
+                               if (setresgid(SUDOERS_GID, -1, -1))
+                                   fatal("unable to change to sudoers gid", 1);
+
+                               /*
+                                * If SUDOERS_UID == 0 and SUDOERS_MODE
+                                * is group readable we use a non-zero
+                                * uid in order to avoid NFS lossage.
+                                * Using uid 1 is a bit bogus but should
+                                * work on all OS's.
+                                */
+                               if (SUDOERS_UID == 0) {
+                                   if ((SUDOERS_MODE & 040) && setresuid(0, 1, 0))
+                                       fatal("setresuid(0, 1, 0)", 1);
+                               } else {
+                                   if (setresuid(0, SUDOERS_UID, 0))
+                                       fatal("setresuid(0, SUDOERS_UID, 0)", 1);
+                               }
+                               break;
+       case PERM_TIMESTAMP:
+                               if (setresuid(0, timestamp_uid, 0))
+                                   fatal("setresuid(0, timestamp_uid, 0)", 1);
+                               break;
+    }
+}
+
+#else
+# ifdef HAVE_SETREUID
+
 /*
  * Set real and effective uids and gids based on perm.
  * We always retain a real or effective uid of 0 unless
  * we are headed for an exec().
+ * This version of set_perms() works fine with the "stay_setuid" option.
  */
 void
-set_perms_fallback(perm)
+set_perms_suid(perm)
     int perm;
 {
     int error;
@@ -168,12 +241,12 @@ set_perms_fallback(perm)
     switch (perm) {
        case PERM_FULL_ROOT:
        case PERM_ROOT:
-                               if (setuid(0))
-                                   fatal("setuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-setreuid", 0);
+                               if (setreuid(0, 0))
+                                   fatal("setreuid(0, 0) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0);
                                break;
 
        case PERM_USER:
-                               (void) setegid(user_gid);
+                               (void) setregid(user_gid, -1);
                                if (setreuid(0, user_uid))
                                    fatal("setreuid(0, user_uid)", 1);
                                break;
@@ -181,24 +254,23 @@ set_perms_fallback(perm)
        case PERM_FULL_USER:
                                /* headed for exec() */
                                (void) setgid(user_gid);
-                               if (setuid(user_uid))
-                                   fatal("setuid(user_uid)", 1);
+                               if (setreuid(user_uid, user_uid))
+                                   fatal("setreuid(user_uid, user_uid)", 1);
                                break;
                                
        case PERM_RUNAS:
                                /* headed for exec(), assume euid == 0 */
                                runas_setup();
-                               if (def_flag(I_STAY_SETUID))
-                                   error = setreuid(user_uid, runas_pw->pw_uid);
-                               else
-                                   error = setuid(runas_pw->pw_uid);
+                               error = setreuid(def_flag(I_STAY_SETUID) ?
+                                   user_uid : runas_pw->pw_uid,
+                                   runas_pw->pw_uid);
                                if (error)
                                    fatal("unable to change to runas uid", 1);
                                break;
 
        case PERM_SUDOERS:
                                /* assume euid == 0, ruid == user */
-                               if (setegid(SUDOERS_GID))
+                               if (setregid(SUDOERS_GID, -1))
                                    fatal("unable to change to sudoers gid", 1);
 
                                /*
@@ -223,20 +295,20 @@ set_perms_fallback(perm)
     }
 }
 
-#else
+# else
 
 /*
  * Set real and effective uids and gids based on perm.
  * NOTE: does not support the "stay_setuid" option.
  */
 void
-set_perms_fallback(perm)
+set_perms_nosuid(perm)
     int perm;
 {
 
     /*
      * Since we only have setuid() and seteuid() we have to set
-     * real and effective uidss to 0 initially.
+     * real and effective uids to 0 initially.
      */
     if (setuid(0))
        fatal("setuid(0)", 1);
@@ -288,7 +360,8 @@ set_perms_fallback(perm)
                                break;
     }
 }
-#endif /* HAVE_SETREUID */
+# endif /* HAVE_SETREUID */
+#endif /* HAVE_SETRESUID */
 
 static void
 runas_setup()
diff --git a/sudo.c b/sudo.c
index 1ceec693799a0cb53239cace29dd7cbc672b4b2e..304cbd8f542b9d7202785f62ebaebaf67f0e8194 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -260,17 +260,18 @@ main(argc, argv, envp)
     validated = sudoers_lookup(pwflag);
 
     /*
-     * If we have POSIX saved uids and the stay_setuid flag was not set,
-     * set the real, effective and saved uids to 0 and use set_perms_fallback()
+     * If we are using set_perms_posix() and the stay_setuid flag was not set,
+     * set the real, effective and saved uids to 0 and use set_perms_nosuid()
      * instead of set_perms_posix().
      */
-#if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
+#if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
+    !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
     if (!def_flag(I_STAY_SETUID) && set_perms == set_perms_posix) {
        if (setuid(0)) {
            perror("setuid(0)");
            exit(1);
        }
-       set_perms = set_perms_fallback;
+       set_perms = set_perms_nosuid;
     }
 #endif
 
@@ -901,13 +902,23 @@ initial_setup()
     for (fd = maxfd; fd > STDERR_FILENO; fd--)
        (void) close(fd);
 
-    /* Set set_perms pointer to the correct function */
-#if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
+    /*
+     * Make set_perms point to the correct function.
+     * If we are using setresuid() or setreuid() we only need to set this
+     * once.  If we are using POSIX saved uids we will switch to
+     * set_perms_nosuid after sudoers has been parsed if the "stay_suid"
+     * option is not set.
+     */
+#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID)
+    set_perms = set_perms_suid;
+#else
+# if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
     if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009)
        set_perms = set_perms_posix;
     else
-#endif
-       set_perms = set_perms_fallback;
+# endif
+       set_perms = set_perms_nosuid;
+#endif /* HAVE_SETRESUID || HAVE_SETREUID */
 }
 
 #ifdef HAVE_LOGIN_CAP_H
diff --git a/sudo.h b/sudo.h
index 47d860195f7ebc552d9c3e5915858bb32ad523d8..884f8f80b92474881393a0419affc9406abc4bb9 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -202,8 +202,9 @@ int find_path               __P((char *, char **, char *));
 void check_user                __P((void));
 void verify_user       __P((struct passwd *, char *));
 int sudoers_lookup     __P((int));
+void set_perms_nosuid  __P((int));
 void set_perms_posix   __P((int));
-void set_perms_fallback        __P((int));
+void set_perms_suid    __P((int));
 void remove_timestamp  __P((int));
 int check_secureware   __P((char *));
 void sia_attempt_auth  __P((void));
@@ -235,7 +236,7 @@ extern int Argc;
 extern char **Argv;
 extern FILE *sudoers_fp;
 extern int tgetpass_flags;
-extern int timestamp_uid;
+extern uid_t timestamp_uid;
 
 extern void (*set_perms) __P((int));
 #endif