What is the best way for checking if the user of a script has root-like privileges?

63,136

Solution 1

Under the "Easier to Ask Forgiveness than Permission" principle:

try:
    os.rename('/etc/foo', '/etc/bar')
except IOError as e:
    if (e[0] == errno.EPERM):
       sys.exit("You need root permissions to do this, laterz!")

If you are concerned about the non-portability of os.geteuid() you probably shouldn't be mucking with /etc anyway.

Solution 2

os.geteuid gets the effective user id, which is exactly what you want, so I can't think of any better way to perform such a check. The one bit that's uncertain is that "root-like' in the title: your code checks for exactly root, no "like" about it, and indeed I wouldn't know what "root-like but not root" would mean -- so, if you mean something different than "exactly root", perhaps you can clarify, thanks!

Solution 3

You can prompt the user for sudo access:

import os, subprocess

def prompt_sudo():
    ret = 0
    if os.geteuid() != 0:
        msg = "[sudo] password for %u:"
        ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True)
    return ret

if prompt_sudo() != 0:
    # the user wasn't authenticated as a sudoer, exit?

The sudo -v switch update the user's cached credentials (see man sudo).

Solution 4

For linux:

def is_root():
    return os.geteuid() == 0

Solution 5

I like to check for sudo in the environmental variables:

if not 'SUDO_UID' in os.environ.keys():
  print "this program requires super user priv."
  sys.exit(1)
Share:
63,136

Related videos on Youtube

Paul Hoffman
Author by

Paul Hoffman

Updated on September 11, 2021

Comments

  • Paul Hoffman
    Paul Hoffman over 2 years

    I have a Python script that will be doing a lot of things that would require root-level privileges, such as moving files in /etc, installing with apt-get, and so on. I currently have:

    if os.geteuid() != 0:
        exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
    

    Is this the best way to do the check? Are there other best practices?

  • Taylor Buchanan
    Taylor Buchanan almost 14 years
    I am assuming Paul is worried about different systems using different uids for administrators. Normally id(root) == 0, but it is not a must and on some systems it's really not equal.
  • msw
    msw almost 14 years
    @Stan: then EAFP would indeed be better
  • Jim Dennis
    Jim Dennis almost 14 years
    The assumption that effective UID == 0 means "root" is pretty deeply ingrained into UNIX code (including throughout most UNIX-like kernel sources). Technically under Linux that assumption is NOT necessarily correct. The Linux "capabilities" model allows the system to run with more fine-grained controls delegated via process inheritance (lcap2 wrappers) or potentially through extended filesystem attributes. Also SELinux features could play havoc with such assumptions. For 99% of the systems out there, geteuid() == 0 is sufficient; for the rest try: ... except: is your friend.
  • Florian Diesch
    Florian Diesch almost 14 years
    This is the most portable way and even works under a bit more exotic circumstances, like with SELinux limiting root privileges.
  • L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
    L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ almost 14 years
    This may actually be worse depending on the situation. Hmm but Florian has a point.
  • msw
    msw almost 14 years
    @Longpoke - are you referring to the situation where a user may have rename permissions in /etc but - say lack the ability to remove a file from that path? If that is what you mean, then trying to determine what capabilities the user does have in advance is a fool's errand. Better to structure your code for "transactional" semantics where A and B can be rolled-back if C fails.
  • L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
    L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ almost 14 years
    @msw: I initially thought, "you should just check if you're root or not and exit", to avoid any transactional consequence, but SELinux, ACLs, and capabilities definately break that, so I guess the only way to really do it right is what you suggested.
  • Paul Hoffman
    Paul Hoffman almost 14 years
    Using try/except is fine for os.rename, but isn't flexible enough for the other thing I mentioned, "installing with apt-get". I fully agree that euid could fail on permissions-based systems, which is why I asked the question in the first place. However, I don't think that try/except covers all the issues either.
  • msw
    msw almost 14 years
    Agreed about apt-get, see below.
  • Paul Hoffman
    Paul Hoffman almost 14 years
    I can only mark one answer as "the correct one", but your addition below (and other riffs on it that I can think of) nail it. Yes, I should be checking for errno.EPERM on each action.
  • jpmc26
    jpmc26 over 9 years
    Wouldn't it make more sense to edit this into your other answer?
  • Montana Burr
    Montana Burr about 9 years
    I know this is old, but in the end, you don't exactly need root privileges, just enough privileges to get the job done. Running as root is simply the easiest way to escalate privileges beyond what Linux and Linux-based OSs give to administrators.
  • Or B
    Or B about 9 years
    Bad code. The error thrown here is TypeError, since if you're not running as root, os.getenv("SUDO_USER") return None which is of type NoneType, and you cannot concatenate str and NoneType. If you want to use os.getenv("SUDO_USER") to solve the problem, you should do it like this: if os.getenv("SUDO_USER") == None: print "This program need 'sudo'"; exit()
  • Or B
    Or B about 9 years
    Not working for me running Python 2.7.3 on Linux. It throws OSError: [Errno 2] No such file or directory, doesn't matter if I run it with or without sudo.
  • msw
    msw about 9 years
    @OrB That probably means that there is no such file or directory for whatever it is you are trying to do. Please phrase your issue in the form of a new question because your one sentence complaint here doesn't afford enough information to even guess what you are trying to accomplish nor why it has nothing to do with this answer.
  • Cediddi
    Cediddi about 9 years
    Thanks for update, This code will only test sudo, not root access. Because it doesn't check for root, if you log in as root (or you wrote a cronjob like me) you still need to call the script with sudo, because sudo doesn't ask password on root, I was able fix my cronjob with just calling my python script with sudo.
  • Prahlad Yeri
    Prahlad Yeri about 8 years
    A bit late to the party, but this is indeed very useful! When combined with something like os.getenv('HOME'), this will tell you whether the current user is a root or sudo which is what generally your script needs to know.
  • keithpjolley
    keithpjolley almost 5 years
    Sometimes you need to know if all the parts of the task are going to be successful before you start making changes. I don't want to do steps 1, 2, and 3 just to find out I can't do step 4 and hope I can back out what's been done.
  • blueren
    blueren over 4 years
    This is simple and neat. Thanks!
  • aster94
    aster94 about 4 years
    actually I upvoted for the "Easier to Ask Forgiveness than Permission" principle
  • Mateo de Mayo
    Mateo de Mayo almost 4 years
    Just to clarify, this lets you check if the user has root privileges in a literal sense, but it will not give the instance of the program you are running root acccess if it didn't have it at launch. You could try something like this for that.
  • dericke
    dericke almost 3 years
    Based on "Flat is better than nested", wouldn't it be better to use PermissionError rather than IOError and checking the error code, at least in Python 3.x?
  • Brōtsyorfuzthrāx
    Brōtsyorfuzthrāx over 2 years
    Nice. os.environ.keys() has other information in it I wanted, too!
  • buhtz
    buhtz over 2 years
    This does not work for root.
  • mike rodent
    mike rodent over 2 years
    This answers the question since we're looking for "root-like" privileges, but why do you need the second part of the if in this case? Isn't it sufficient to check for the existence of SUDO_UID?
  • mike rodent
    mike rodent over 2 years
    Am I completely mad, or couldn't this do severe damage to your system, i.e. if you turn out to be root, and renaming /etc/foo causes severe problems!? Mightn't it be better to see if you can create a dir in /etc: mkdir /etc/my_extremely_silly_and_implausible_directory (and then delete it). I appreciate that having a directory in /etc called "foo" which does something crucial would be the height of silliness and implausibility... but you never know what people get up to!
  • kol
    kol about 2 years
    There is no need for .keys(), just use if not 'SUDO_UID' in os.environ: -- Thanks!