Reputation: 6778
What portable options do exist to drop root privileges and execute a given command as a different user from a shell script?
After doing a bit of research, here are a few non-options:
su $USER -c "$COMMAND"
uses the PAM stack and creates a new cgroup (when run under systemd). It also fails in user namespaces, because the audit call returns -EPERM on older versions of Linux.sudo -u $USER $COMMAND
is not installed by default on many systems.start-stop-daemon --pidfile /dev/null --start --chuid $USER --startas /bin/sh -- -c "$COMMAND"
is very hard to use and only available on Debian systems.chpst -u $USER $COMMAND
is missing on many systems.runuser -u $USER -- $COMMAND
works where su
doesn't, but requires recent util-linux.Upvotes: 5
Views: 4517
Reputation: 295383
For folks who are reading this in a context where the relevant meaning of "POSIX shell script" is "POSIX sh script, being run on an arbitrary Linux system", as opposed to "sh script, run on a system guaranteed to have only tools guaranteed by POSIX", there are more options available.
Borrowing from an excellent answer to the UNIX & Linux question How do I drop root privileges in shell scripts:
Modern util-linux
has setpriv
, which can be used in the manner of:
setpriv --reuid=user --regid=group --init-groups --inh-caps=-all yourcommand
The excellent article by @JdeBP Don't Abuse su
For Dropping Privileges is also worth reading.
Upvotes: 4
Reputation: 107759
If it's POSIX you want, then su
is your only option (unless you want to write a C program). su
has several advantages (or not, depending on your requirements):
Now in practice some systems aren't POSIX — like this older Linux where it fails in user namespaces. Them's the breaks.
If you want something that's reasonably portable in practice (on non-embedded platforms) and that gives you a greater decree of control, use Perl (or Python, a bit less commonly installed). For preference, use a solid module: Privilege::Drop.
perl -e 'use Privileges::Drop; drop_uid_gid(123, 456); exec("/path/to/command", "--option", "an argument")'
Privilege::Drop
takes care of doing things right (dropping supplemental groups, checking for errors). It might not be complete, however; for example it isn't aware of capabilities.
If you must do it by hand, take care of several things:
$) = "456 456"
where 456 is the target GID ($) = 456
would only set the EGID without affecting the supplemental groups).Upvotes: 4