From a76630000720a0c6e793f47c5444b58fcd7154b5 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sun, 25 Nov 2007 13:07:21 +0000 Subject: [PATCH] Set aux group vector for PERM_RUNAS and restore group vector for 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 | 5 +-- set_perms.c | 113 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/logging.c b/logging.c index bce2d2a29..32ec866a5 100644 --- 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); diff --git a/set_perms.c b/set_perms.c index 6548f6dd9..a98bc7d73 100644 --- a/set_perms.c +++ b/set_perms.c @@ -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); } } -- 2.40.0