How to Execute Script as Root Without Password in macOS

automationmacospermissionrootscript

I have a script, let's call it on-event.sh, that's going to be run at specific times, such as when a particular application launches or quits. The script itself will run as the current user (not root) since I'll be using BetterTouchTool to execute it.

However, on-event.sh needs to somehow trigger the execution of another script that must run as root, which I'll call run-as-root.sh. run-as-root.sh will execute some commands to load or unload specific third party launch daemons (not my own), hence the need to run as root. Since it'll all be happening in the background, it needs to happen without requiring user intervention, so it can't use sudo or AppleScript's with administrator privileges. Because of the obvious security implications, I only want it to be possible to execute run-as-root.sh as root and not any arbitrary script or terminal command.

One option I'm already aware of is I could create a launch daemon that opens a socket, waits for a connection, and then executes run-as-root.sh, and have on-event.sh connect to that socket. But that's a more heavy weight solution and I'm hoping for an easier way to do this.

How can I set it up so this is possible?

Best Answer

You can use sudo to allow a user to run specific commands as root, without the need for a password.

To allow user bribri to run launchctl, run sudo visudo -f /etc/sudoers.d/launchctl and add

bribri ALL = (root) NOPASSWD: /bin/launchctl

then save and exit. Afterwards, the user can run

sudo launchctl ...

without getting prompted for a password.

The caveat here is that this gives the user the rights to start/stop/load/unload any LaunchAgents/Daemons. To avoid this, a shell script could be used to wrap the launchctl call, but this brings a bunch of security risks. To at least reduce them

  • put the script into a dedicated directory,
  • make sure both the directory and the script are owned by root and chmoded to 0700,
  • keep the script as short as possible (include only things which must be run as root),
  • use absolute paths for all commands called in the script,
  • avoid to rely on any environment variables.