Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Privilege escalation from Python like from systemd
When you try to do a privileged systemd operation without the privilege, you get an escalation prompt:
$ systemctl stop docker
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to stop 'docker.service'.
Authenticating as: [MY USER NAME]
Password:
I've seen some other programs do this as well (don't recall which), so it seems like not a systemd-specific thing.
I want to write a Python program that occasionally does privileged things. Most of the time it does not do privileged things, so I don't want to tell users to run my program with sudo. Instead I want to ask for the escalation as needed, like systemctl
does.
Is it possible in Python?
1 answer
Generallly (assuming no exploit is found) it's not possible to escalate the privileges of an already running process, except via code that itself has kernel level access (running in ring 0 - this is presumably how systemd
is able to do it). But from your own Python program running in user-land (as a script being interpreted by the python
executable), you can only do this by starting a new process.
Fortunately, it's easy enough in Python to start new processes using the subprocess
standard library. We can also use os.geteuid
to determine Python's "effective user id" - i.e., 0
when the script is running as root, and nonzero otherwise. This allows us to create a script that spawns itself via sudo
when not already running as root, and proceeds normally when it is. Something like:
#!/usr/bin/env python
# (or whatever other shebang is appropriate)
import os, sys, subprocess
# actual code to run as root, when this file is run as a script
def main():
...
if __name__ == '__main__':
if os.geteuid() == 0:
sys.exit(main())
else:
# assuming our script has chmod+x
sys.exit(subprocess.call(['sudo', *sys.argv]))
Of course, the sudoers file can also be modified to allow running the script as root without a password. But for the use case of a script that only occasionally expects escalated privileges, it might be better to ask each time (the user likely wants a warning!) - and to defer the subprocess logic until it's actually necessary. This is tricky to set up; it may be easier to put the root-requiring logic in a separate script file (and perhaps use the standard output and/or error code of the root process to communicate back to the main program).
References:
-
Elevate privileges of running process on Stack Overflow
-
Write to a file with sudo privileges in Python on Stack Overflow
-
How do I sudo a command in a script without being asked for a password? on Ask Ubuntu
0 comment threads