From: Todd C. Miller Date: Fri, 22 Nov 2002 19:09:49 +0000 (+0000) Subject: Revamp set_perms. We now use a version based on setresuid() or setreuid() X-Git-Tag: SUDO_1_6_7~108 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b152da4cdb9b1999f51a5ec499a184025b971ef7;p=sudo Revamp set_perms. We now use a version based on setresuid() or setreuid() 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). --- diff --git a/set_perms.c b/set_perms.c index 45374eb07..d672d65fa 100644 --- a/set_perms.c +++ b/set_perms.c @@ -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 1ceec6937..304cbd8f5 100644 --- 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 47d860195..884f8f80b 100644 --- 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