Helmut Grohne
Helmut Grohne

Reputation: 6778

How to drop root privileges from a POSIX shell script?

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:

Upvotes: 5

Views: 4517

Answers (2)

Charles Duffy
Charles Duffy

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

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):

  • It's a system tool which isn't going to forget about the new coffee UID introduced in Linux 3.42 (the UID for beverage drinking purposes) and which isn't going to goof by dropping user privileges before group privileges or to forget about capabilities.
  • It sets privileges to a known state: a user ID, that user's recorded group(s) from the user and group databases, no extra capabilities.
  • It records log entries.
  • And, again, it's completely standard, guaranteed to be available everywhere but on the most broken systems.

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:

  • Drop group privileges before user privileges.
  • To drop supplemental groups, set $) = "456 456" where 456 is the target GID ($) = 456 would only set the EGID without affecting the supplemental groups).
  • Check the (E)[UG]ID afterwards and abort on failure.

Upvotes: 4

Related Questions