+++ /dev/null
-/*
- * Copyright (c) 1994-1996,1998-2010 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * 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.
- *
- * 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.
- *
- * 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 <sys/types.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif /* HAVE_STRINGS_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#include <errno.h>
-#include <grp.h>
-#ifdef HAVE_LOGIN_CAP_H
-# include <login_cap.h>
-#endif
-
-#include "sudo.h"
-
-#ifdef __TANDEM
-# define ROOT_UID 65535
-#else
-# define ROOT_UID 0
-#endif
-
-/*
- * Prototypes
- */
-static void runas_setup __P((void));
-static void runas_setgroups __P((void));
-static void restore_groups __P((void));
-
-static int current_perm = -1;
-
-#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.
- */
-int
-set_perms(perm)
- int perm;
-{
- const char *errstr;
- int noexit;
-
- noexit = ISSET(perm, PERM_NOEXIT);
- CLR(perm, PERM_MASK);
-
- if (perm == current_perm)
- return(1);
-
- switch (perm) {
- case PERM_ROOT:
- if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) {
- errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)";
- goto bad;
- }
- (void) setresgid(-1, user_gid, -1);
- if (current_perm == PERM_RUNAS)
- restore_groups();
- break;
-
- case PERM_USER:
- (void) setresgid(-1, user_gid, -1);
- if (setresuid(user_uid, user_uid, ROOT_UID)) {
- errstr = "setresuid(user_uid, user_uid, ROOT_UID)";
- goto bad;
- }
- break;
-
- case PERM_FULL_USER:
- /* headed for exec() */
- (void) setgid(user_gid);
- if (setresuid(user_uid, user_uid, user_uid)) {
- errstr = "setresuid(user_uid, user_uid, user_uid)";
- goto bad;
- }
- break;
-
- case PERM_RUNAS:
- runas_setgroups();
- (void) setresgid(-1, runas_gr ?
- runas_gr->gr_gid : runas_pw->pw_gid, -1);
- if (setresuid(-1, runas_pw ? runas_pw->pw_uid :
- user_uid, -1)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_FULL_RUNAS:
- /* headed for exec(), assume euid == ROOT_UID */
- runas_setup();
- if (setresuid(def_stay_setuid ?
- user_uid : runas_pw->pw_uid,
- runas_pw->pw_uid, runas_pw->pw_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_SUDOERS:
- /* assume euid == ROOT_UID, ruid == user */
- if (setresgid(-1, SUDOERS_GID, -1))
- error(1, "unable to change to sudoers gid");
-
- /*
- * 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)) {
- errstr = "setresuid(ROOT_UID, 1, ROOT_UID)";
- goto bad;
- }
- } else {
- if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) {
- errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)";
- goto bad;
- }
- }
- break;
- case PERM_TIMESTAMP:
- if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) {
- errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)";
- goto bad;
- }
- break;
- }
-
- current_perm = perm;
- return(1);
-bad:
- warningx("%s: %s", errstr,
- errno == EAGAIN ? "too many processes" : strerror(errno));
- if (noexit)
- return(0);
- exit(1);
-}
-
-#else
-# ifdef HAVE_SETREUID
-
-/*
- * Set real and effective uids and gids based on perm.
- * 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.
- */
-int
-set_perms(perm)
- int perm;
-{
- const char *errstr;
- int noexit;
-
- noexit = ISSET(perm, PERM_NOEXIT);
- CLR(perm, PERM_MASK);
-
- if (perm == current_perm)
- return(1);
-
- switch (perm) {
- case PERM_ROOT:
- if (setreuid(-1, ROOT_UID)) {
- errstr = "setreuid(-1, ROOT_UID)";
- goto bad;
- }
- if (setuid(ROOT_UID)) {
- errstr = "setuid(ROOT_UID)";
- goto bad;
- }
- (void) setregid(-1, user_gid);
- if (current_perm == PERM_RUNAS)
- restore_groups();
- break;
-
- case PERM_USER:
- (void) setregid(-1, user_gid);
- if (setreuid(ROOT_UID, user_uid)) {
- errstr = "setreuid(ROOT_UID, user_uid)";
- goto bad;
- }
- break;
-
- case PERM_FULL_USER:
- /* headed for exec() */
- (void) setgid(user_gid);
- if (setreuid(user_uid, user_uid)) {
- errstr = "setreuid(user_uid, user_uid)";
- goto bad;
- }
- break;
-
- case PERM_RUNAS:
- runas_setgroups();
- (void) setregid(-1, runas_gr ?
- runas_gr->gr_gid : runas_pw->pw_gid);
- if (setreuid(-1,
- runas_pw ? runas_pw->pw_uid : user_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_FULL_RUNAS:
- /* headed for exec(), assume euid == ROOT_UID */
- runas_setup();
- if (setreuid(def_stay_setuid ? user_uid :
- runas_pw->pw_uid, runas_pw->pw_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_SUDOERS:
- /* assume euid == ROOT_UID, ruid == user */
- if (setregid(-1, SUDOERS_GID))
- error(1, "unable to change to sudoers gid");
-
- /*
- * 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) && setreuid(ROOT_UID, 1)) {
- errstr = "setreuid(ROOT_UID, 1)";
- goto bad;
- }
- } else {
- if (setreuid(ROOT_UID, SUDOERS_UID)) {
- errstr = "setreuid(ROOT_UID, SUDOERS_UID)";
- goto bad;
- }
- }
- break;
- case PERM_TIMESTAMP:
- if (setreuid(ROOT_UID, timestamp_uid)) {
- errstr = "setreuid(ROOT_UID, timestamp_uid)";
- goto bad;
- }
- break;
- }
-
- current_perm = perm;
- return(1);
-bad:
- warningx("%s: %s", errstr,
- errno == EAGAIN ? "too many processes" : strerror(errno));
- if (noexit)
- return(0);
- exit(1);
-}
-
-# else /* !HAVE_SETRESUID && !HAVE_SETREUID */
-# ifdef HAVE_SETEUID
-
-/*
- * Set real and effective uids and gids based on perm.
- * NOTE: does not support the "stay_setuid" option.
- */
-int
-set_perms(perm)
- int perm;
-{
- const char *errstr;
- int noexit;
-
- noexit = ISSET(perm, PERM_NOEXIT);
- CLR(perm, PERM_MASK);
-
- if (perm == current_perm)
- return(1);
-
- /*
- * Since we only have setuid() and seteuid() and semantics
- * for these calls differ on various systems, we set
- * real and effective uids to ROOT_UID initially to be safe.
- */
- if (seteuid(ROOT_UID)) {
- errstr = "seteuid(ROOT_UID)";
- goto bad;
- }
- if (setuid(ROOT_UID)) {
- errstr = "setuid(ROOT_UID)";
- goto bad;
- }
-
- switch (perm) {
- case PERM_ROOT:
- /* uid set above */
- (void) setegid(user_gid);
- if (current_perm == PERM_RUNAS)
- restore_groups();
- break;
-
- case PERM_USER:
- (void) setegid(user_gid);
- if (seteuid(user_uid)) {
- errstr = "seteuid(user_uid)";
- goto bad;
- }
- break;
-
- case PERM_FULL_USER:
- /* headed for exec() */
- (void) setgid(user_gid);
- if (setuid(user_uid)) {
- errstr = "setuid(user_uid)";
- goto bad;
- }
- break;
-
- case PERM_RUNAS:
- runas_setgroups();
- (void) setegid(runas_gr ?
- runas_gr->gr_gid : runas_pw->pw_gid);
- if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_FULL_RUNAS:
- /* headed for exec() */
- runas_setup();
- if (setuid(runas_pw->pw_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_SUDOERS:
- if (setegid(SUDOERS_GID))
- error(1, "unable to change to sudoers gid");
-
- /*
- * 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) && seteuid(1)) {
- errstr = "seteuid(1)";
- goto bad;
- }
- } else {
- if (seteuid(SUDOERS_UID)) {
- errstr = "seteuid(SUDOERS_UID)";
- goto bad;
- }
- }
- break;
- case PERM_TIMESTAMP:
- if (seteuid(timestamp_uid)) {
- errstr = "seteuid(timestamp_uid)";
- goto bad;
- }
- break;
- }
-
- current_perm = perm;
- return(1);
-bad:
- warningx("%s: %s", errstr,
- errno == EAGAIN ? "too many processes" : strerror(errno));
- if (noexit)
- return(0);
- exit(1);
-}
-
-# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */
-
-/*
- * 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.
- */
-int
-set_perms(perm)
- int perm;
-{
- const char *errstr;
- int noexit;
-
- noexit = ISSET(perm, PERM_NOEXIT);
- CLR(perm, PERM_MASK);
-
- if (perm == current_perm)
- return(1);
-
- switch (perm) {
- case PERM_ROOT:
- if (setuid(ROOT_UID)) {
- errstr = "setuid(ROOT_UID)";
- goto bad;
- }
- if (current_perm == PERM_RUNAS)
- restore_groups();
- break;
-
- case PERM_FULL_USER:
- (void) setgid(user_gid);
- if (setuid(user_uid)) {
- errstr = "setuid(user_uid)";
- goto bad;
- }
- break;
-
- case PERM_FULL_RUNAS:
- runas_setup();
- if (setuid(runas_pw->pw_uid)) {
- errstr = "unable to change to runas uid";
- goto bad;
- }
- break;
-
- case PERM_USER:
- case PERM_SUDOERS:
- case PERM_RUNAS:
- case PERM_TIMESTAMP:
- /* Unsupported since we can't set euid. */
- break;
- }
-
- current_perm = perm;
- return(1);
-bad:
- warningx("%s: %s", errstr,
- errno == EAGAIN ? "too many processes" : strerror(errno));
- if (noexit)
- return(0);
- exit(1);
-}
-# endif /* HAVE_SETEUID */
-# endif /* HAVE_SETREUID */
-#endif /* HAVE_SETRESUID */
-
-#ifdef HAVE_INITGROUPS
-static void
-runas_setgroups()
-{
- static int ngroups = -1;
-# ifdef HAVE_GETGROUPS
- static GETGROUPS_T *groups;
-# endif
- static struct passwd *pw;
- struct passwd *opw = pw;
-
- if (def_preserve_groups)
- return;
-
- /*
- * Use stashed copy of runas groups if available, else initgroups and stash.
- */
- pw = runas_pw ? runas_pw : sudo_user.pw;
- if (pw != opw) {
-# ifdef HAVE_SETAUTHDB
- aix_setauthdb(pw->pw_name);
-# endif
- if (initgroups(pw->pw_name, pw->pw_gid) < 0)
- log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# ifdef HAVE_GETGROUPS
- if (groups) {
- efree(groups);
- groups = NULL;
- }
- if ((ngroups = getgroups(0, NULL)) > 0) {
- groups = emalloc2(ngroups, sizeof(GETGROUPS_T));
- if (getgroups(ngroups, groups) < 0)
- log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector");
- }
-# ifdef HAVE_SETAUTHDB
- aix_restoreauthdb();
-# endif
- } else {
- if (setgroups(ngroups, groups) < 0)
- log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector");
-# endif /* HAVE_GETGROUPS */
- }
-}
-
-static void
-restore_groups()
-{
- if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0)
- log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector");
-}
-
-#else
-
-static void
-runas_setgroups()
-{
- /* STUB */
-}
-
-static void
-restore_groups()
-{
- /* STUB */
-}
-
-#endif /* HAVE_INITGROUPS */
-
-static void
-runas_setup()
-{
- gid_t gid;
-#ifdef HAVE_LOGIN_CAP_H
- int flags;
- extern login_cap_t *lc;
-#endif
-
- if (runas_pw->pw_name != NULL) {
- gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
-#ifdef HAVE_GETUSERATTR
- aix_prep_user(runas_pw->pw_name, user_ttypath);
-#endif
-#ifdef HAVE_PAM
- pam_begin_session(runas_pw);
-#endif /* HAVE_PAM */
-
-#ifdef HAVE_LOGIN_CAP_H
- if (def_use_loginclass) {
- /*
- * We only use setusercontext() to set the nice value and rlimits.
- */
- flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
- if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
- if (runas_pw->pw_uid != ROOT_UID)
- error(1, "unable to set user context");
- else
- warning("unable to set user context");
- }
- }
-#endif /* HAVE_LOGIN_CAP_H */
- /*
- * Initialize group vector
- */
- runas_setgroups();
-#ifdef HAVE_SETEUID
- if (setegid(gid))
- warning("cannot set egid to runas gid");
-#endif
- if (setgid(gid))
- warning("cannot set gid to runas gid");
- }
-}