How can I launch a child process that has root privileges?
I have a python program in MacOS that can do most of its operations as a normal user. But occasionally, triggered by some user interaction, it will need root permissions to preform a task.
For security reasons, I don't want the entire GUI app to be started and left running as root. I want only a child process with a very minimal subset of functions to run as root.
For UX reasons, I don't want to have to tell the user "Sorry, please restart this app as Administrator". I want to be able to have them stay in the GUI, get presented with a pop-up that says "Uh, you need root to do that. Please enter your password."
Of course, if my unprivileged python process attempts to become root with
setuid(0)
...then I just get a permissions error
PermissionError: [Errno 1] Operation not permitted
What can I use as an alternate to setuid() so that I can launch a new child process on a MacOS system, after escalating privilege by getting authentication from the user in the GUI?
This is exactly what the MacOS Security API's
AuthorizationExecuteWithPrivileges()function was created for.You can call
AuthorizationExecuteWithPrivileges()directly with python's ctypes.For example, consider your parent script running as your normal, non-root user. If you try to just run
setuid(0), then it will fail withInstead, let's create another script named
root_child.py, which we'll execute as root withAuthorizationExecuteWithPrivileges()Child (root_child.py)
Parent (spawn_root.py)
We can execute the above
root_child.pyscript as root from our non-root scriptspawn_root.py:Example Execution
Note that, because the credential challenge for
AuthorizationExecuteWithPrivileges()comes via the GUI, you must execute this from within the GUI. If you attempt to execute the above scripts, for example, over a SSH in a tty, you'll get an error-60007, which iserrAuthorizationInteractionNotAllowedand means:However, if executed from the Terminal app in the GUI, then it prompts the user for their password.
If the user successfully enters their credentials correctly, then the
root_child.pyscript is executed with root privileges.Additional Information
Security
Note that
AuthorizationExecuteWithPrivileges()has been deprecated by apple in-favor of an alternatve that requires you to pay them money. Unfortunately, there's some misinformation out there thatAuthorizationExecuteWithPrivileges()is a huge security hole. While it's true that usingAuthorizationExecuteWithPrivileges()incorrectly can cause security issues, it is not inherently insecure to use it.Obviously, any time you run something as root, you need to be very careful!
AuthorizationExecuteWithPrivileges()is deprecated, but it can be used safely. But it can also be used unsafely!It basically boils down to: do you actually know what you're running as root? If the script you're running as root is located in a Temp dir that has world-writeable permissions (as a lot of MacOS App installers have done historically), then any malicious process could gain root access.
To execute a process as root safely:
Further Reading
AuthorizationExecuteWithPrivileges()Reference Documentation