What is the best way for checking if the user of a script has root-like privileges?
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)
Related videos on Youtube
Paul Hoffman
Updated on September 11, 2021Comments
-
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 almost 14 yearsI 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 almost 14 years@Stan: then EAFP would indeed be better
-
Jim Dennis almost 14 yearsThe 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 almost 14 yearsThis 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̲̳̳ almost 14 yearsThis may actually be worse depending on the situation. Hmm but Florian has a point.
-
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̲̳̳ 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 almost 14 yearsUsing 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 almost 14 yearsAgreed about apt-get, see below.
-
Paul Hoffman almost 14 yearsI 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 over 9 yearsWouldn't it make more sense to edit this into your other answer?
-
Montana Burr about 9 yearsI 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 about 9 yearsBad code. The error thrown here is
TypeError
, since if you're not running as root,os.getenv("SUDO_USER")
returnNone
which is of typeNoneType
, and you cannot concatenatestr
andNoneType
. If you want to useos.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 about 9 yearsNot 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 withoutsudo
. -
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 about 9 yearsThanks 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 about 8 yearsA 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 aroot
orsudo
which is what generally your script needs to know. -
keithpjolley almost 5 yearsSometimes 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 over 4 yearsThis is simple and neat. Thanks!
-
aster94 about 4 yearsactually I upvoted for the "Easier to Ask Forgiveness than Permission" principle
-
Mateo de Mayo almost 4 yearsJust 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 almost 3 yearsBased on "Flat is better than nested", wouldn't it be better to use
PermissionError
rather thanIOError
and checking the error code, at least in Python 3.x? -
Brōtsyorfuzthrāx over 2 yearsNice.
os.environ.keys()
has other information in it I wanted, too! -
buhtz over 2 yearsThis does not work for
root
. -
mike rodent over 2 yearsThis 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 ofSUDO_UID
? -
mike rodent over 2 yearsAm 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 about 2 yearsThere is no need for
.keys()
, just useif not 'SUDO_UID' in os.environ:
-- Thanks!