21

The "--up" option in OpenVPN is normally used for routing etc. And so it is processed before OpenVPN drops root privileges to run as nobody. However, I am invoking shell scripts that need to run as an unprivileged user.

How do I do that? I have studied Drop Process Privileges, especially polynomial's and tylerl's answers, but I do not understand how to implement. I am working in Centos 6.5, and suid is blocked, both as "chmod u+s" and as "setuid()".

There is an OpenVPN plugin ("openvpn-down-root.so") which enables scripts invoked by the "--down" option to run as root. There could be an equivalent, such as "openvpn-up-user.so", but I have not found it.

Edit0

Per Nikola Kotur's answer, I've installed Ian Meyer's runit-rpm. Although the chpst command works in terminal, in the up script it fails with "command not found". What works is "sudo chpst" plus setting the proper display and language. Please see Why doesn't my terminal output unicode characters properly? Given that, the up script needs these four lines:

LANG="en_US.UTF-8"; export LANG
GDM_LANG="en_US.UTF-8"; export GDM_LANG
DISPLAY=:0; export DISPLAY
sudo chpst -u user -U user /home/user/unprivileged.sh &

Edit1

Per 0xC0000022L's comment, I find that "sudo -u user" works as well as "sudo chpst -u user -U user":

LANG="en_US.UTF-8"; export LANG
GDM_LANG="en_US.UTF-8"; export GDM_LANG
DISPLAY=:0; export DISPLAY
sudo -u user /home/user/unprivileged.sh &

I'll study man sudoers and update if/when I get sudo alone to work.

mirimir
  • 463
  • comment left by @user66229: "May I suggest that you surf to http://sourceforge.net/p/openvpn/mailman/ and subscribe to the lists that you find most appropriate." – slm May 30 '14 at 13:52
  • @user66229 Thank you. But I don't believe that this is an OpenVPN-specific question. Why do you believe that it is? – mirimir May 31 '14 at 11:05

5 Answers5

27

Covering only runit and sudo misses a lot. There is actually a whole family of toolsets like runit, and a wide choice of tools for doing exactly this, the very task that they were designed for:

  • Daniel J. Bernstein's daemontools has setuidgid:
    setuidgid user /home/user/unprivileged.sh
  • util-linux (installed by default on newer Debians) has setpriv:
    setpriv --reuid=user --regid=group --init-groups --inh-caps=-all /home/user/unprivileged.sh
  • Adam Sampson's freedt has setuidgid:
    setuidgid user /home/user/unprivileged.sh
  • Bruce Guenter's daemontools-encore has setuidgid:
    setuidgid user /home/user/unprivileged.sh
  • Gerrit Pape's runit has chpst:
    chpst -u user /home/user/unprivileged.sh
  • Wayne Marshall's perp has runuid:
    runuid user /home/user/unprivileged.sh
  • Laurent Bercot's s6 has s6-setuidgid:
    s6-setuidgid user /home/user/unprivileged.sh
  • my nosh has setuidgid:
    setuidgid user /home/user/unprivileged.sh

They don't mix in the different task of adding privileges, and never fall into an interactive mode.

Your tacked-on problems are little more than your forgetting to have sbin as well as bin in your PATH, by the way.

Further reading

Charles Duffy
  • 1,732
  • 15
  • 22
JdeBP
  • 68,745
8

I use runit's chpst tool for tasks like this. For example, from the up script call your unprivileged script:

chpst -u nobody /path/to/script
  • Cool :) Thank you. Is https://github.com/imeyer/runit-rpm the best way to get runit into Centos 6.5? Even with Red Hat repos, I'm not finding a package. – mirimir May 30 '14 at 10:23
  • @mirimir, yes, I use that repo when I need to build a runit package for CentOS. – Nikola Kotur Jun 02 '14 at 14:22
8

On Linux-based systems you can setpriv (from util-linux):

setpriv --reuid=1000 --regid=1000 --init-groups COMMAND [ARGUMENTS...]  # Like su/runuser/sudo
setpriv --reuid=1000 --regid=1000 --clear-groups COMMAND [ARGUMENTS...]  # Like daemontools setuid(8)

Use runuser if a PAM session is required (also from util-linux):

runuser -u USER [--] COMMAND [ARGUMENTS...]

From the su man page:

su is mostly designed for unprivileged users, the recommended solution for privileged users (e.g. scripts executed by root) is to use non-set-user-ID command runuser(1) that does not require authentication and provide separate PAM configuration. If the PAM session is not required at all then the recommend solution is to use command setpriv(1).

dcoles
  • 341
6

script which drops privileges and runs other script (but here I just made it to run itself):

#!/bin/sh

id=id -u safeuser="nobody"

if [ $id = "0" ] then # we're root. dangerous! sudo -u $safeuser "$0" # Be sure to quote "$0" else echo "I'm not root" id fi

Example:

root@n3:/tmp/x# id
uid=0(root) gid=0(root) группы=0(root)
root@n3:/tmp/x# ./drop.sh
I'm not root
uid=65534(nobody) gid=65534(nogroup) группы=65534(nogroup)
Fritz
  • 708
  • 2
  • 6
  • 16
yaroslaff
  • 106
  • While using "sudo -u user" works for some commands, it doesn't provide enough user environment for my purposes. And while "su -l user" works fine in terminal, it does nothing in scripts. I suppose that's a security feature. So it seems that I'm left with installing runit. – mirimir May 31 '14 at 02:08
  • 1
    @mirimir: why? /etc/sudoers allows to be very specific what environment variables can be conveyed to the program run by sudo and so on. man sudoers. Honestly, whoever uses sudo merely for sudo su - or to switch user context has no clue about what's behind this awesome program and how much you can lock down things for individual programs, users, hosts etc ... – 0xC0000022L Jun 01 '14 at 00:19
  • @0xC0000022L Thanks. I took another look at sudo. And yes, "sudo -u user" plus display and language also works. – mirimir Jun 01 '14 at 01:50
  • 1
    Speaking of dangerous -- you can't trust $0; the caller can set a script's $0 to literally anything they want it to be. And use more quotes. – Charles Duffy Jun 02 '17 at 00:59
  • 2
    ...if your script's $0 is /directory/name with spaces/script (and remember, users can create arbitrary symlinks in locations they own, even if they don't use exec -a somename yourscript to call yourscript with a $0 of somename), then you'd get sudo -u nobody /directory/name with spaces, with with and spaces passed as separate arguments to your command. – Charles Duffy Jun 02 '17 at 01:03
  • @Charles, if "$0" is that dangerous, it hardly matters, given that we've already established that the user is uid 0 (but it is important to be aware of this in contexts where it might matter). – Toby Speight Aug 31 '17 at 12:52
1

What about:

sudo -Eu <user> <command>

You complained about environment in a previous comment, so you might also compare the differences between the outputs:

sudo -u <user> printenv
sudo -Eu <user> printenv
thiagowfx
  • 1,249