What it means to become another user on Unix
Ignoring things like SELinux for the moment, the basic security state of Unix system calls has always been that root is allowed to become any other UID at will, but no one else is allowed to change their UID or other security attributes (setuid programs then provide an escape hatch from this). But what does it mean to become another user on Unix, beyond just setting your UID? In fact there are a whole series of things that it can mean, some of which you do not necessarily want.
Let's make a list:
- switching to the user's UID. This is the basic prerequisite of what
it means to become another user on Unix, and is done by
- switching your groups to the user's groups, which is done with a
- setting some environment variables like
$SHELLto values appropriate for the new user.
(Most but not all versions of
sudo this. Versions of
suthat do not change
$HOMEcan be exciting, especially when combined with shells that read initialization files from
- clearing various environment variables; in the extreme case, you will
clear all environment variables and give yourself a new set of safe
values for things like
$PATHand so on.
(Aggressively scrubbing the environment is generally the default for
sudo. In general there are any number of environment variables that are very dangerous to leave intact, such as all of the
LD_*variables that influence the behavior of the dynamic loader.)
- running the user's shell, either interactively or with
-c ...to execute commands.
sunormally always runs the user's shell;
sudowill often run commands directly without starting the user's shell.)
- changing to the user's home directory.
- running the user's shell as a login shell.
- allocating a new pseudo-tty as the user and attaching the user's shell
and so on to it as a new session. This is generally the domain
of things that are making real login sessions, like
sshd, instead of programs that just become the user.
(Note that this list is not in the order that your code wants to
actually do these operations. For example, you want to set groups
before changing to the other UID because the moment you
setuid() to a
non-root user you lose the power to set your own groups list.)
Many things that become another user deliberately run the the target
user's shell even when they just want to run a command. This is done
partly so that the user's shell can do any special initialization that,
eg, may augment its
$PATH and partly so that users with restricted
shells can't escape them in various clever ways. However, not everything
does this and sometimes running the user's shell is inconvenient.
There are a surprising number of cases where you want basically the
first two only; you want to run a command as a user but in a way
such that their environment (their shell, their shell initialization,
and so on) is ignored. It's possible to do this with standard
sudo by carefully reading their manpages
and picking exactly the right options, but I find it easier to have
a very basic
runas program sitting around.
runas only works for root, so it can completely ignore authentication
and similar issues.)