10

In my Python script, I perform a few operations that need root privileges. I also create and write to files that I don't want to be owned exclusively by root but by the user who is running my script.

Usually, I run my script using sudo. Is there a way to do the above?

jww
  • 97,681
  • 90
  • 411
  • 885
Ricky Robinson
  • 21,798
  • 42
  • 129
  • 185
  • If you're running with `sudo`, you can always `chown` to the owner of the `__FILE__` after you're done – salezica Mar 29 '13 at 14:40
  • @uʍopǝpısdn Yes... but doing things like that quickly becomes racy if you're not very careful. – thejh Mar 29 '13 at 14:42
  • I didn't get it, sorry. It's root that creates all the files(consequence of `sudo`). How can I retrieve the user ID of whoever is running my script? – Ricky Robinson Mar 29 '13 at 15:49
  • Possible duplicate of [Dropping Root Permissions In Python](https://stackoverflow.com/questions/2699907/dropping-root-permissions-in-python) – jww Jul 23 '17 at 18:47

3 Answers3

13

You can switch between uid's using os.seteuid(). This differs from os.setuid() in that you can go back to getting root privileges when you need them.

For example, run the following as root:

import os

open('file1', 'wc')

# switch to userid 501
os.seteuid(501)
open('file2', 'wc')

# switch back to root
os.seteuid(0)
open('file3', 'wc')

This creates file1 and file3 as root, but file2 as the user with uid 501.

If you want to determine which user is calling your script, sudo sets two environment variables:

SUDO_USER
SUDO_UID

Respectively the username and the uid of the user who called sudo. So you could use int(os.environ['SUDO_UID']) to use with os.seteuid().

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • 1
    Beware this only works for operations in the same process. If you fork another process (i.e. by using subprocess) it inherits the ruid and runs with those privileges. – Enno Gröper Jan 07 '20 at 07:50
1

http://linux.die.net/man/8/sudo quote:
The real and effective uid and gid are set to match those of the target user

So, your only option of knowing which user to use is to read the target user from either a config file or a cmdline option, or someway of heuristical guessing.

A good idea is the so called rights shedding: Start with root privilegs, then do what you nedd them for. Then become a less privileged user.
You would use the os module for that: http://docs.python.org/2/library/os.html#os.setuid

Benjamin
  • 609
  • 3
  • 8
1

I found that using os.seteuid and os.setegid didn't actually drop the root privileges. After calling them I was still able to do things that required root privileges. The solution I found that worked was to use os.setresuid and os.setresgid instead:

sudo_uid = int(os.getenv("SUDO_UID"))
sudo_gid = int(os.getenv("SUDO_GID"))

# drop root privileges
os.setresgid(sudo_gid, sudo_gid, -1)
os.setresuid(sudo_uid, sudo_uid, -1)

subprocess.call("mkdir /foo1", shell = True) # should fail

# regain root privileges
os.setresgid(0, 0, -1)
os.setresuid(0, 0, -1)

subprocess.call("mkdir /foo2", shell = True) # should succeed
Glenn Coombs
  • 153
  • 2
  • 11
  • This is because you are forking new processes. Those new processes are inheriting the ruid. Everything would be fine for operations in the same process (like open()) – Enno Gröper Jan 07 '20 at 07:52