Imported Upstream version 1.6.8p5
[debian/sudo] / set_perms.c
index 300f5b3f388a951390615f244cdf2220812613e0..70cb60291cb43c54e8e190e7704458ca8c0608ce 100644 (file)
@@ -1,35 +1,21 @@
 /*
- * Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
+ * Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * 4. Products derived from this software may not be called "Sudo" nor
- *    may "Sudo" appear in their names without specific prior written
- *    permission from the author.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
 #include "config.h"
 #include "sudo.h"
 
 #ifndef lint
-static const char rcsid[] = "$Sudo: set_perms.c,v 1.12 2002/01/22 02:00:25 millert Exp $";
+static const char rcsid[] = "$Sudo: set_perms.c,v 1.30 2004/05/27 23:12:02 millert Exp $";
 #endif /* lint */
 
+#ifdef __TANDEM
+# define ROOT_UID      65535
+#else
+# define ROOT_UID      0
+#endif
+
 /*
  * Prototypes
  */
 static void runas_setup                __P((void));
 static void fatal              __P((char *, int));
 
-#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)
 /*
  * Set real and effective uids and gids based on perm.
  * Since we have POSIX saved IDs we can get away with just
  * toggling the effective uid/gid unless we are headed for an exec().
  */
 void
-set_perms_posix(perm, sudo_mode)
+set_perms_posix(perm)
     int perm;
-    int sudo_mode;
 {
     int error;
 
     switch (perm) {
        case PERM_ROOT:
-                               if (seteuid(0))
-                                   fatal("seteuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
+                               if (seteuid(ROOT_UID))
+                                   fatal("seteuid(ROOT_UID) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0);
                                break;
 
        case PERM_FULL_ROOT:
                                /* headed for exec() */
-                               (void) seteuid(0);
-                               if (setuid(0))
-                                   fatal("setuid(0)", 1);
+                               (void) seteuid(ROOT_UID);
+                               if (setuid(ROOT_UID))
+                                   fatal("setuid(ROOT_UID)", 1);
                                break;
 
        case PERM_USER:
@@ -115,9 +107,14 @@ set_perms_posix(perm, sudo_mode)
                                break;
                                
        case PERM_RUNAS:
-                               /* headed for exec(), assume euid == 0 */
+                               if (seteuid(runas_pw->pw_uid))
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_FULL_RUNAS:
+                               /* headed for exec(), assume euid == ROOT_UID */
                                runas_setup();
-                               if (def_flag(I_STAY_SETUID))
+                               if (def_stay_setuid)
                                    error = seteuid(runas_pw->pw_uid);
                                else
                                    error = setuid(runas_pw->pw_uid);
@@ -126,18 +123,18 @@ set_perms_posix(perm, sudo_mode)
                                break;
 
        case PERM_SUDOERS:
-                               /* assume euid == 0, ruid == user */
+                               /* assume euid == ROOT_UID, ruid == user */
                                if (setegid(SUDOERS_GID))
                                    fatal("unable to change to sudoers gid", 1);
 
                                /*
-                                * If SUDOERS_UID == 0 and SUDOERS_MODE
+                                * If SUDOERS_UID == ROOT_UID 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_UID == ROOT_UID) {
                                    if ((SUDOERS_MODE & 040) && seteuid(1))
                                        fatal("seteuid(1)", 1);
                                } else {
@@ -145,95 +142,187 @@ set_perms_posix(perm, sudo_mode)
                                        fatal("seteuid(SUDOERS_UID)", 1);
                                }
                                break;
+       case PERM_TIMESTAMP:
+                               if (seteuid(timestamp_uid))
+                                   fatal("seteuid(timestamp_uid)", 1);
+                               break;
+
     }
 }
 #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(ROOT_UID, ROOT_UID, ROOT_UID))
+                                   fatal("setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0);
+                               break;
+
+       case PERM_USER:
+                               (void) setresgid(-1, user_gid, -1);
+                               if (setresuid(user_uid, user_uid, ROOT_UID))
+                                   fatal("setresuid(user_uid, user_uid, ROOT_UID)", 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:
+                               if (setresuid(-1, runas_pw->pw_uid, -1))
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_FULL_RUNAS:
+                               /* headed for exec(), assume euid == ROOT_UID */
+                               runas_setup();
+                               error = setresuid(def_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 == ROOT_UID, ruid == user */
+                               if (setresgid(-1, SUDOERS_GID, -1))
+                                   fatal("unable to change to sudoers gid", 1);
+
+                               /*
+                                * If SUDOERS_UID == ROOT_UID 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 == ROOT_UID) {
+                                   if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID))
+                                       fatal("setresuid(ROOT_UID, 1, ROOT_UID)", 1);
+                               } else {
+                                   if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID))
+                                       fatal("setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)", 1);
+                               }
+                               break;
+       case PERM_TIMESTAMP:
+                               if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID))
+                                   fatal("setresuid(ROOT_UID, timestamp_uid, ROOT_UID)", 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 always retain a real or effective uid of ROOT_UID unless
  * we are headed for an exec().
+ * This version of set_perms() works fine with the "stay_setuid" option.
  */
 void
-set_perms_fallback(perm, sudo_mode)
+set_perms_suid(perm)
     int perm;
-    int sudo_mode;
 {
     int error;
 
     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(-1, ROOT_UID))
+                                   fatal("setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0);
+                               if (setuid(ROOT_UID))
+                                   fatal("setuid(ROOT_UID)", 1);
                                break;
 
        case PERM_USER:
-                               (void) setegid(user_gid);
-                               if (setreuid(0, user_uid))
-                                   fatal("setreuid(0, user_uid)", 1);
+                               (void) setregid(-1, user_gid);
+                               if (setreuid(ROOT_UID, user_uid))
+                                   fatal("setreuid(ROOT_UID, user_uid)", 1);
                                break;
                                
        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 */
+                               if (setreuid(-1, runas_pw->pw_uid))
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_FULL_RUNAS:
+                               /* headed for exec(), assume euid == ROOT_UID */
                                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_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))
+                               /* assume euid == ROOT_UID, ruid == user */
+                               if (setregid(-1, SUDOERS_GID))
                                    fatal("unable to change to sudoers gid", 1);
 
                                /*
-                                * If SUDOERS_UID == 0 and SUDOERS_MODE
+                                * If SUDOERS_UID == ROOT_UID 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) && setreuid(0, 1))
-                                       fatal("setreuid(0, 1)", 1);
+                               if (SUDOERS_UID == ROOT_UID) {
+                                   if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1))
+                                       fatal("setreuid(ROOT_UID, 1)", 1);
                                } else {
-                                   if (setreuid(0, SUDOERS_UID))
-                                       fatal("setreuid(0, SUDOERS_UID)", 1);
+                                   if (setreuid(ROOT_UID, SUDOERS_UID))
+                                       fatal("setreuid(ROOT_UID, SUDOERS_UID)", 1);
                                }
                                break;
+       case PERM_TIMESTAMP:
+                               if (setreuid(ROOT_UID, timestamp_uid))
+                                   fatal("setreuid(ROOT_UID, timestamp_uid)", 1);
+                               break;
     }
 }
 
-#else
+# else
+#  ifdef HAVE_SETREUID
 
 /*
  * Set real and effective uids and gids based on perm.
  * NOTE: does not support the "stay_setuid" option.
  */
 void
-set_perms_fallback(perm, sudo_mode)
+set_perms_nosuid(perm)
     int perm;
-    int sudo_mode;
 {
 
     /*
      * Since we only have setuid() and seteuid() we have to set
-     * real and effective uidss to 0 initially.
+     * real and effective uids to ROOT_UID initially.
      */
-    if (setuid(0))
-       fatal("setuid(0)", 1);
+    if (setuid(ROOT_UID))
+       fatal("setuid(ROOT_UID)", 1);
 
     switch (perm) {
        case PERM_USER:
@@ -250,25 +339,30 @@ set_perms_fallback(perm, sudo_mode)
                                break;
                                
        case PERM_RUNAS:
-                               /* headed for exec(), assume euid == 0 */
+                               if (seteuid(runas_pw->pw_uid))
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_FULL_RUNAS:
+                               /* headed for exec(), assume euid == ROOT_UID */
                                runas_setup();
                                if (setuid(runas_pw->pw_uid))
                                    fatal("unable to change to runas uid", 1);
                                break;
 
        case PERM_SUDOERS:
-                               /* assume euid == 0, ruid == user */
+                               /* assume euid == ROOT_UID, ruid == user */
                                if (setegid(SUDOERS_GID))
                                    fatal("unable to change to sudoers gid", 1);
 
                                /*
-                                * If SUDOERS_UID == 0 and SUDOERS_MODE
+                                * If SUDOERS_UID == ROOT_UID 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_UID == ROOT_UID) {
                                    if ((SUDOERS_MODE & 040) && seteuid(1))
                                        fatal("seteuid(1)", 1);
                                } else {
@@ -276,9 +370,55 @@ set_perms_fallback(perm, sudo_mode)
                                        fatal("seteuid(SUDOERS_UID)", 1);
                                }
                                break;
+       case PERM_TIMESTAMP:
+                               if (seteuid(timestamp_uid))
+                                   fatal("seteuid(timestamp_uid)", 1);
+                               break;
+    }
+}
+
+#  else
+
+/*
+ * Set uids and gids based on perm via setuid() and setgid().
+ * NOTE: does not support the "stay_setuid" or timestampowner options.
+ *       Also, SUDOERS_UID and SUDOERS_GID are not used.
+ */
+void
+set_perms_nosuid(perm)
+    int perm;
+{
+
+    switch (perm) {
+       case PERM_FULL_ROOT:
+       case PERM_ROOT:
+                               if (setuid(ROOT_UID))
+                                       fatal("setuid(ROOT_UID)", 1);
+                               break;
+
+       case PERM_FULL_USER:
+                               (void) setgid(user_gid);
+                               if (setuid(user_uid))
+                                   fatal("setuid(user_uid)", 1);
+                               break;
+                               
+       case PERM_FULL_RUNAS:
+                               runas_setup();
+                               if (setuid(runas_pw->pw_uid))
+                                   fatal("unable to change to runas uid", 1);
+                               break;
+
+       case PERM_USER:
+       case PERM_SUDOERS:
+       case PERM_RUNAS:
+       case PERM_TIMESTAMP:
+                               /* Unsupported since we can't set euid. */
+                               break;
     }
 }
-#endif /* HAVE_SETREUID */
+#  endif /* HAVE_SETEUID */
+# endif /* HAVE_SETREUID */
+#endif /* HAVE_SETRESUID */
 
 static void
 runas_setup()
@@ -294,7 +434,7 @@ runas_setup()
 #endif /* HAVE_PAM */
 
 #ifdef HAVE_LOGIN_CAP_H
-       if (def_flag(I_USE_LOGINCLASS)) {
+       if (def_use_loginclass) {
            /*
              * We don't have setusercontext() set the user since we
              * may only want to set the effective uid.  Depending on
@@ -302,14 +442,18 @@ runas_setup()
              * setusercontext() to call initgroups().
             */
            flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
-           if (!def_flag(I_PRESERVE_GROUPS))
-               flags |= LOGIN_SETGROUP;
+           if (!def_preserve_groups)
+               SET(flags, LOGIN_SETGROUP);
            else if (setgid(runas_pw->pw_gid))
                perror("cannot set gid to runas gid");
            error = setusercontext(lc, runas_pw,
                runas_pw->pw_uid, flags);
-           if (error)
-               perror("unable to set user context");
+           if (error) {
+               if (runas_pw->pw_uid != ROOT_UID)
+                   fatal("unable to set user context", 1);
+               else
+                   perror("unable to set user context");
+           }
        } else
 #endif /* HAVE_LOGIN_CAP_H */
        {
@@ -319,7 +463,7 @@ runas_setup()
            /*
             * Initialize group vector unless asked not to.
             */
-           if (!def_flag(I_PRESERVE_GROUPS) &&
+           if (!def_preserve_groups &&
                initgroups(*user_runas, runas_pw->pw_gid) < 0)
                perror("cannot set group vector");
 #endif /* HAVE_INITGROUPS */
@@ -330,6 +474,7 @@ runas_setup()
 static void
 fatal(str, printerr)
     char *str;
+    int printerr;
 {
 
     if (str) {