]> granicus.if.org Git - sudo/commitdiff
Move set_perms() to its own file and use POSIX saved uid or setreuid()
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 3 Nov 2000 05:37:44 +0000 (05:37 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 3 Nov 2000 05:37:44 +0000 (05:37 +0000)
if available.

Added stay_setuid option for systems that have libraries that perform
extra paranoia checks in system libraries for setuid programs (ie:
anything with issetugid(2)).

Makefile.in
defaults.c
defaults.h
set_perms.c [new file with mode: 0644]
sudo.c

index 6634272128d86d3bd67fcbe6d8c47379cebe6ee0..bdfef1153d2113bbc4a4ba37f926c760ca25cab3 100644 (file)
@@ -111,9 +111,9 @@ PROGS = @PROGS@
 
 SRCS = alloc.c alloca.c check.c defaults.c fileops.c find_path.c fnmatch.c \
        getcwd.c getspwuid.c goodpath.c interfaces.c lex.yy.c lsearch.c \
-       logging.c parse.c parse.lex parse.yacc putenv.c snprintf.c strcasecmp.c \
-       strerror.c sudo.c sudo.tab.c sudo_setenv.c testsudoers.c tgetpass.c \
-       utime.c visudo.c $(AUTH_SRCS)
+       logging.c parse.c parse.lex parse.yacc putenv.c set_perms.c snprintf.c \
+       strcasecmp.c strerror.c sudo.c sudo.tab.c sudo_setenv.c testsudoers.c \
+       tgetpass.c utime.c visudo.c $(AUTH_SRCS)
 
 AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
            auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
@@ -128,7 +128,7 @@ AUTH_OBJS = sudo_auth.o @AUTH_OBJS@
 PARSEOBJS = sudo.tab.o lex.yy.o alloc.o defaults.o
 
 SUDOBJS = check.o getspwuid.o goodpath.o fileops.o find_path.o interfaces.o \
-         logging.o parse.o sudo.o sudo_setenv.o tgetpass.o \
+         logging.o parse.o set_perms.o sudo.o sudo_setenv.o tgetpass.o \
          $(AUTH_OBJS) $(PARSEOBJS)
 
 VISUDOBJS = visudo.o fileops.o goodpath.o find_path.o $(PARSEOBJS)
@@ -204,6 +204,7 @@ find_path.o: find_path.c $(SUDODEP)
 getspwuid.o: getspwuid.c $(SUDODEP)
 goodpath.o: goodpath.c $(SUDODEP)
 logging.o: logging.c $(SUDODEP)
+set_perms.o: set_perms.c $(SUDODEP)
 sudo_setenv.o: sudo_setenv.c $(SUDODEP)
 tgetpass.o: tgetpass.c $(SUDODEP)
 visudo.o: visudo.c $(SUDODEP) version.h
index a711971b125cf92679dba163215994222208e687..827f8234581cdb793d099105af6f628e80456440 100644 (file)
@@ -202,6 +202,9 @@ struct sudo_defs_types sudo_defs_table[] = {
     }, {
        "set_logname", T_FLAG,
        "Set the LOGNAME and USER environment variables"
+    }, {
+       "stay_setuid", T_FLAG,
+       "Only set the effective uid to the target user, not the real uid"
     }, {
        "loglinelen", T_INT|T_BOOL,
        "Length at which to wrap log file lines (0 for no wrap): %d"
index 91a56c2659e6bf9fb8195f829b238ddebc0badad..4c0c578c1ea414ca5e409c5d88e2f3ce7727d502 100644 (file)
@@ -118,35 +118,36 @@ struct sudo_defs_types {
 #define I_TARGETPW             28
 #define I_LOGINCLASS           29
 #define I_LOGNAME              30
+#define I_STAY_SETUID          31
 
 /* Integer values */
-#define        I_LOGLEN        31      /* wrap log file line after N chars */
-#define        I_TS_TIMEOUT    32      /* timestamp stale after N minutes */
-#define        I_PW_TIMEOUT    33      /* exit if pass not entered in N minutes */
-#define        I_PW_TRIES      34      /* exit after N bad password tries */
-#define        I_UMASK         35      /* umask to use or 0777 to use user's */
+#define        I_LOGLEN        32      /* wrap log file line after N chars */
+#define        I_TS_TIMEOUT    33      /* timestamp stale after N minutes */
+#define        I_PW_TIMEOUT    34      /* exit if pass not entered in N minutes */
+#define        I_PW_TRIES      35      /* exit after N bad password tries */
+#define        I_UMASK         36      /* umask to use or 0777 to use user's */
 
 /* Strings */
-#define        I_LOGFILE       36      /* path to logfile (or NULL for none) */
-#define        I_MAILERPATH    37      /* path to sendmail or other mailer */
-#define        I_MAILERFLAGS   38      /* flags to pass to the mailer */
-#define        I_MAILTO        39      /* who to send bitch mail to */
-#define        I_MAILSUB       40      /* subject line of mail msg */
-#define        I_BADPASS_MSG   41      /* what to say when passwd is wrong */
-#define        I_TIMESTAMPDIR  42      /* path to timestamp dir */
-#define        I_EXEMPT_GRP    43      /* no password or PATH override for these */
-#define        I_PASSPROMPT    44      /* password prompt */
-#define        I_RUNAS_DEF     45      /* default user to run commands as */
-#define        I_SECURE_PATH   46      /* set $PATH to this if not NULL */
-#define        I_EDITOR        47      /* path to editor used by visudo */
+#define        I_LOGFILE       37      /* path to logfile (or NULL for none) */
+#define        I_MAILERPATH    38      /* path to sendmail or other mailer */
+#define        I_MAILERFLAGS   39      /* flags to pass to the mailer */
+#define        I_MAILTO        40      /* who to send bitch mail to */
+#define        I_MAILSUB       41      /* subject line of mail msg */
+#define        I_BADPASS_MSG   42      /* what to say when passwd is wrong */
+#define        I_TIMESTAMPDIR  43      /* path to timestamp dir */
+#define        I_EXEMPT_GRP    44      /* no password or PATH override for these */
+#define        I_PASSPROMPT    45      /* password prompt */
+#define        I_RUNAS_DEF     46      /* default user to run commands as */
+#define        I_SECURE_PATH   47      /* set $PATH to this if not NULL */
+#define        I_EDITOR        48      /* path to editor used by visudo */
 
 /* Integer versions of list/verify options */
-#define I_LISTPW       48
-#define I_VERIFYPW     49
+#define I_LISTPW       49
+#define I_VERIFYPW     50
 
 /* String versions of list/verify options */
-#define I_LISTPWSTR    50
-#define I_VERIFYPWSTR  51
+#define I_LISTPWSTR    51
+#define I_VERIFYPWSTR  52
 
 /*
  * Macros for accessing sudo_defs_table.
diff --git a/set_perms.c b/set_perms.c
new file mode 100644 (file)
index 0000000..694ee7d
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1994-1996,1998-2000 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif /* STDC_HEADERS */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <pwd.h>
+#include <errno.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#ifdef HAVE_LOGIN_CAP_H
+# include <login_cap.h>
+#endif
+
+#include "sudo.h"
+
+#ifndef lint
+static const char rcsid[] = "$Sudo$";
+#endif /* lint */
+
+/*
+ * It might be better to use sysconf(_SC_SAVED_IDS) instead but
+ * I'm * not aware of any system where this would be necessary.
+ */
+#ifdef _POSIX_SAVED_IDS
+# define TOGGLE_ROOT                                                   \
+       if (seteuid(0)) {                                               \
+           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,                       \
+               "seteuid(0)");                                          \
+       }
+# define TOGGLE_USER                                                   \
+       if (seteuid(user_uid)) {                                        \
+           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,                       \
+               "seteuid(%ld)", (long) user_uid);                       \
+       }
+#else
+# ifdef HAVE_SETREUID
+#  define TOGGLE_ROOT                                                  \
+       if (setreuid(user_uid, 0)) {                                    \
+           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,                       \
+               "setreuid(%ld, 0)", (long) user_uid);                   \
+       }
+#  define TOGGLE_USER                                                  \
+       if (setreuid(0, user_uid)) {                                    \
+           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,                       \
+               "setreuid(0, %ld)", (long) user_uid);                   \
+       }
+# else /* !_POSIX_SAVED_IDS && !HAVE_SETREUID */
+#  define TOGGLE_ROOT                                                  \
+       ;
+# define TOGGLE_USER                                                   \
+       if (seteuid(user_uid)) {                                        \
+           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,                       \
+               "seteuid(%ld)", (long) user_uid);                       \
+       }
+# endif /* HAVE_SETREUID */
+#endif /* _POSIX_SAVED_IDS */
+
+/*
+ * Set real and effective uids and gids based on perm.
+ * If we have POSIX saved IDs or setreuid(2) we can get away with only
+ * toggling the effective uid/gid unless we are headed for an exec().
+ */
+void
+set_perms(perm, sudo_mode)
+    int perm;
+    int sudo_mode;
+{
+    struct passwd *pw;
+    int error;
+    extern login_cap_t *lc;
+    extern char *runas_homedir;
+
+    /*
+     * If we only have setuid() and seteuid() we have to set both to root
+     * initially.
+     */
+#if !defined(_POSIX_SAVED_IDS) && !defined(HAVE_SETREUID)
+    if (setuid(0)) {
+       perror("setuid(0)");
+       exit(1);
+    }
+#endif
+
+    switch (perm) {
+       case PERM_ROOT:
+                               TOGGLE_ROOT;
+                               break;
+       case PERM_USER:
+                               (void) setegid(user_gid);
+                               TOGGLE_USER;
+                               break;
+                               
+       case PERM_FULL_USER:
+                               /* headed for exec() */
+                               (void) setgid(user_gid);
+                               if (setuid(user_uid)) {
+                                   perror("setuid(user_uid)");
+                                   exit(1);
+                               }
+                               break;
+
+       case PERM_RUNAS:
+                               /* headed for exec(), assume euid == 0 */
+                               /* XXX - add group/gid support */
+                               if (**user_runas == '#') {
+                                   if (def_flag(I_STAY_SETUID))
+                                       error = seteuid(atoi(*user_runas + 1));
+                                   else
+                                       error = setuid(atoi(*user_runas + 1));
+                                   if (error)
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "cannot set uid to %s", *user_runas);
+                               } else {
+                                   if (!(pw = getpwnam(*user_runas)))
+                                       log_error(NO_MAIL|MSG_ONLY,
+                                           "no passwd entry for %s!",
+                                           *user_runas);
+
+                                   /* Set $USER and $LOGNAME to target user */
+                                   if (def_flag(I_LOGNAME)) {
+                                       sudo_setenv("USER", pw->pw_name);
+                                       sudo_setenv("LOGNAME", pw->pw_name);
+                                   }
+
+#ifdef HAVE_LOGIN_CAP_H
+                                   if (def_flag(I_LOGINCLASS)) {
+                                       /*
+                                        * We don't have setusercontext()
+                                        * set the user since we may only
+                                        * want to set the effective uid.
+                                        */
+                                       error = setusercontext(lc, pw, pw->pw_uid,
+                                           LOGIN_SETGROUP|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY);
+                                       if (error)
+                                           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                               "setusercontext() failed for login class %s",
+                                               login_class);
+                                   } else
+#endif /* HAVE_LOGIN_CAP_H */
+                                   {
+                                       if (setgid(pw->pw_gid))
+                                           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                               "cannot set gid to %ld: %s",
+                                               (long) pw->pw_gid);
+#ifdef HAVE_INITGROUPS
+                                       /*
+                                        * Initialize group vector only if are
+                                        * going to run as a non-root user.
+                                        */
+                                       if (strcmp(*user_runas, "root") != 0 &&
+                                           initgroups(*user_runas, pw->pw_gid) < 0)
+                                           log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                               "cannot set group vector");
+#endif /* HAVE_INITGROUPS */
+                                   }
+                                   if (def_flag(I_STAY_SETUID))
+                                       error = seteuid(pw->pw_uid);
+                                   else
+                                       error = setuid(pw->pw_uid);
+                                   if (error)
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "cannot set uid to %ld",
+                                           (long) pw->pw_uid);
+                                   if (sudo_mode & MODE_RESET_HOME)
+                                       runas_homedir = pw->pw_dir;
+                               }
+                               break;
+
+       case PERM_SUDOERS:
+                               /* assume euid == 0, ruid == user */
+                               if (setegid(SUDOERS_GID))
+                                   log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                       "setegid(SUDOERS_GID)");
+
+                               /*
+                                * 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 defined(HAVE_SETREUID) && !defined(_POSIX_SAVED_IDS)
+                               if (SUDOERS_UID == 0) {
+                                   if ((SUDOERS_MODE & 040) && setreuid(0, 1))
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "setreuid(0, 1)");
+                               } else {
+                                   if (setreuid(0, SUDOERS_UID))
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "setreuid(0, SUDOERS_UID)");
+                               }
+#else
+                               if (SUDOERS_UID == 0) {
+                                   if ((SUDOERS_MODE & 040) && seteuid(1))
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "seteuid(1)");
+                               } else {
+                                   if (seteuid(SUDOERS_UID))
+                                       log_error(NO_MAIL|USE_ERRNO|MSG_ONLY,
+                                           "seteuid(SUDOERS_UID)");
+                               }
+#endif /* HAVE_SETREUID && !_POSIX_SAVED_IDS */
+                               break;
+    }
+}
diff --git a/sudo.c b/sudo.c
index 9bce204ccc19bf1b4e70935f35e35c284ae0b1b0..e8f600357ff8a862951790593a9efb3b6115cf26 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -96,6 +96,13 @@ extern char *getenv  __P((char *));
 static const char rcsid[] = "$Sudo$";
 #endif /* lint */
 
+/* XXX - for debugging, will become a runtime option */
+#ifdef STAY_SETUID
+# define SETUID(_x)    seteuid(_x)
+#else
+# define SETUID(_x)    setuid(_x)
+#endif /* XXX */
+
 /*
  * Local type declarations
  */
@@ -135,7 +142,7 @@ struct interface *interfaces;
 int num_interfaces;
 int tgetpass_flags;
 extern int errorlineno;
-static char *runas_homedir = NULL;     /* XXX */
+char *runas_homedir = NULL;    /* XXX */
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
 static struct rlimit corelimit;
 #endif /* RLIMIT_CORE */
@@ -931,145 +938,6 @@ clean_env(envp, badenv_table, naughtyenv_table)
     }
 }
 
-/*
- * Set real and effective uids and gids based on perm.
- */
-void
-set_perms(perm, sudo_mode)
-    int perm;
-    int sudo_mode;
-{
-    struct passwd *pw;
-
-    /*
-     * First, set real & effective uids to root.
-     * If perm is PERM_ROOT then we don't need to do anything else.
-     */
-    if (setuid(0)) {
-       perror("setuid(0)");
-       exit(1);
-    }
-
-    switch (perm) {
-       case PERM_USER:
-                               (void) setgid(user_gid);
-
-                               if (seteuid(user_uid)) {
-                                   perror("seteuid(user_uid)");
-                                   exit(1);
-                               }
-                               break;
-                               
-       case PERM_FULL_USER:
-                               (void) setgid(user_gid);
-
-                               if (setuid(user_uid)) {
-                                   perror("setuid(user_uid)");
-                                   exit(1);
-                               }
-                               break;
-
-       case PERM_RUNAS:
-                               /* XXX - add group/gid support */
-                               if (**user_runas == '#') {
-                                   if (setuid(atoi(*user_runas + 1))) {
-                                       (void) fprintf(stderr,
-                                           "%s: cannot set uid to %s: %s\n",
-                                           Argv[0], *user_runas, strerror(errno));
-                                       exit(1);
-                                   }
-                               } else {
-                                   if (!(pw = getpwnam(*user_runas))) {
-                                       (void) fprintf(stderr,
-                                           "%s: no passwd entry for %s!\n",
-                                           Argv[0], *user_runas);
-                                       exit(1);
-                                   }
-
-                                   /* Set $USER and $LOGNAME to target user */
-                                   if (def_flag(I_LOGNAME)) {
-                                       sudo_setenv("USER", pw->pw_name);
-                                       sudo_setenv("LOGNAME", pw->pw_name);
-                                   }
-
-#ifdef HAVE_LOGIN_CAP_H
-                                   if (def_flag(I_LOGINCLASS)) {
-                                       /*
-                                        * setusercontext() will set uid/gid/etc
-                                        * for us so no need to do it below.
-                                        */
-                                       if (setusercontext(lc, pw, pw->pw_uid,
-                                           LOGIN_SETUSER|LOGIN_SETGROUP|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY))
-                                           log_error(
-                                               NO_MAIL|USE_ERRNO|MSG_ONLY,
-                                               "setusercontext() failed for login class %s",
-                                               login_class);
-                                       else
-                                           break;
-                                   }
-#endif /* HAVE_LOGIN_CAP_H */
-
-                                   if (setgid(pw->pw_gid)) {
-                                       (void) fprintf(stderr,
-                                           "%s: cannot set gid to %ld: %s\n",
-                                           Argv[0], (long) pw->pw_gid,
-                                           strerror(errno));
-                                       exit(1);
-                                   }
-#ifdef HAVE_INITGROUPS
-                                   /*
-                                    * Initialize group vector only if are
-                                    * going to run as a non-root user.
-                                    */
-                                   if (strcmp(*user_runas, "root") != 0 &&
-                                       initgroups(*user_runas, pw->pw_gid)
-                                       == -1) {
-                                       (void) fprintf(stderr,
-                                           "%s: cannot set group vector: %s\n",
-                                           Argv[0], strerror(errno));
-                                       exit(1);
-                                   }
-#endif /* HAVE_INITGROUPS */
-                                   if (setuid(pw->pw_uid)) {
-                                       (void) fprintf(stderr,
-                                           "%s: cannot set uid to %ld: %s\n",
-                                           Argv[0], (long) pw->pw_uid,
-                                           strerror(errno));
-                                       exit(1);
-                                   }
-                                   if (sudo_mode & MODE_RESET_HOME)
-                                       runas_homedir = pw->pw_dir;
-                               }
-                               break;
-
-       case PERM_SUDOERS:
-                               if (setgid(SUDOERS_GID)) {
-                                   perror("setgid(SUDOERS_GID)");
-                                   exit(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) && seteuid(1)) {
-                                       perror("seteuid(1)");
-                                       exit(1);
-                                   }
-                               } else {
-                                   if (seteuid(SUDOERS_UID)) {
-                                       perror("seteuid(SUDOERS_UID)");
-                                       exit(1);
-                                   }
-                               }
-                               break;
-    }
-}
-
 /*
  * Close all open files (except std*) and turn off core dumps.
  */