As mentioned before, the recommended way of gaining super user privileges from the command line in macOS is the sudo
command. The name means ‘super user do’ and will perform the following command with root privileges after verifying the user running sudo
has the permission to do so.
- Part 1: Demystifying
root
- Part 2: The
sudo
Command (this post) - Part 3:
root
and Scripting - Part 4: The Authorization Database
How sudo
works
sudo
allows a user to execute a command with super user privileges, without needing to authenticate as the super user. The user has to authenticate as themself, however, and the sudo
will check whether the user is authorized to use sudo
.
For example, you want to run a command that requires super user privileges:
$ systemsetup -getremotelogin
You need administrator access to run this tool... exiting!
You can then repeat the command with sudo
to run it with temporary super user privileges.
$ sudo systemsetup -getremotelogin
Password:
Remote Login: On
On macOS, administator users are allowed to use sudo
.
A few notes on sudo
:
- you can type
sudo !!
as a short cut for ‘repeat the last command withsudo
’. More details on this in my post “On Bash History Substitution”. - the first time you run
sudo
with an account on a Mac it will show a longer dialog with a warning or ‘lecture’. (You can change the lecture.) - the system will prompt for your password when executing a command with
sudo
. However, there is a 5 minute (300 seconds) ‘grace period’ where thesudo
system caches your credentials and you do not have to re-enter the password. This grace period is limited to a given shell session, so if you open a new Terminal window, you will have to re-enter the password. - on macOS
sudo
will not work if your administrator account’s password is empty: Using the sudo command in Terminal requires an administrator password - use of
sudo
is logged. You can find the log entries in the Console.app by searching forprocess:sudo
:
armin : TTY=ttys000 ; PWD=/Users/armin ; USER=root ; COMMAND=/bin/echo "#iamroot"
- You can change the rules for who can use
sudo
in the/etc/sudoers
file, but that is a topic for another post. - on Macs with TouchID, you can modify the authorization behavior of
sudo
to include the TouchID sensor. Note this will not work when logged in overssh
for obvious reasons.
sudo
and the Environment
sudo
runs the command in the current shell environment. The user (or effective user ID) the command is run as switches to root
:
$ whoami
armin
$ sudo whoami
root
The sudo
environment changes some of the variables, while some will be passed through from your shell. To show this, create a short script:
#!/bin/bash
echo $USER
echo $HOME
echo $EUID
and run it as yourself and then with sudo
:
$ chmod +x printenvs.sh
$ ./printenvs.sh
armin
/Users/armin
501
$ sudo ./printenvs.sh
Password:
root
/Users/armin
0
Some tools might not read environment variables and determine the user environment through different means. This may lead to some tools writing data to root
’s home directory instead of the current users when running with sudo
.
The defaults
command is one example:
$ sudo defaults write com.apple.loginwindow LoginHook /path/to/script
~ $ defaults read com.apple.loginwindow LoginHook
2018-04-16 15:09:00.378 defaults[69217:3291382]
The domain/default pair of (com.apple.loginwindow, LoginHook) does not exist
~ $ sudo !!
sudo defaults read com.apple.loginwindow LoginHook
/path/to/script
~ $ sudo plutil -p /var/root/Library/Preferences/com.apple.loginwindow.plist
{
"LoginHook" => "/path/to/script"
}
Note: This form of customizing login behavior in macOS is deprecated (but still works as of 10.13). LaunchAgents are the preferred method to run scripts or processes at login. (More info here.) If you find yourself building custom LaunchAgents and LaunchDaemons frequently, you need to check out outset
.
You have to be aware that running commands with sudo
results in a different environment than when you run them directly.
root
Shells
In most cases running a single command with sudo
is sufficient. However, sometimes it can be convenient to have an interactive shell that runs with super user privileges.
There are two ways of achieving this withsudo
:
When you run sudo -s
it will invoke a new shell, running as root
. The shell that is run is the default shell of your account. So when you have bash
set as your shell (the default on macOS) you will get a bash
shell running as root
. Most other environment settings will remain the same:
$ sudo -s
Password:
# whoami
root
# echo $HOME
/Users/armin
# echo $SHELL
/bin/bash
# exit
$
Usually, the Terminal prompt is set up to change from the $
prompt to #
when you are running with super user privileges, to remind you of the power you have right now and the danger you are in.
Note: learn how to configure your shell prompt.
To leave the root
shell, just type exit.
Alternatively you can use sudo -i
to invoke a root shell. With the -i
option, the shell will be chosen from the default shell set for root
user (/bin/sh
on macOS) and will be set up as if the root
user were logging in, ignoring your settings, like profile files etc.
$ sudo -i
Mac:~ root# whoami
root
Mac:~ root# echo $HOME
/var/root
Mac:~ root# echo $SHELL
/bin/sh
Note that my custom minimal shell prompt changes when I switch to root
with sudo -i
since it creates the root
shell with the root
user’s environment.
In most cases sudo -s
should serve well. However, when you want to avoid any customization you might have set in your user environment and work in more pristine environment then it is good to know sudo -i
exists.
sudo
vs su
There is a different command which allows you to change the user: su
(short for ‘switch user’). The main difference between these tools is how they verify if you are authorized to switch.
su
will ask for credentials of the user you are switching to. So if you run su bob
you need to have Bob’s credentials.
When you run su
without a username, it assumes root
. But since logging in as root
is disabled by default on macOS, it will fail.
$ su
Password:
su: Sorry
sudo
, on the other hand, will check its configuration files to see if your account is authorized to run the command as the given user. It asks for your credentials to verify you. You do not need the credentials of the other user, whether it is root
or a different user.
Since the root
account login is usually disabled on macOS, you cannot use su root -
or su -
to get a root shell. Use sudo -s
or sudo -i
instead.
sudo
and Scripting
sudo
is very useful when working interactively in the shell. However, when you are scripting workflows then you don’t want to encounter the interactive prompt for authentication.
We will look at strategies for privilege escalation (and the opposite) in scripts in the next post.
- Part 1: Demystifying
root
- Part 2: The
sudo
Command (this post) - Part 3:
root
and Scripting - Part 4: The Authorization Database
Informative and instructional post, as usual. For those of us who (contrary to the suggestion given in Part 1) run as a standard user, the process for using sudo is slightly more complicated. One needs to either su or login to an account with administrator privileges before invoking sudo. I tend to use login, as this puts me in a shell within a shell. When I no longer need admin/super user privileges, I logout (logout or Control-D), which drops me back in to the original user shell.
I did not “recommend against the practice” as much as I doubt its efficiency in general. If that is what it takes for you to pause and and consider what this dialog is prompting for then it it’s a great solution for you! I believe most people will just enter the admin name and password with just as little consideration, though.
If the hoops you need to jump through to sudo from the CLI with a non-Admin account are too annoying you could change the sudoers file, but I guess that would defeat the purpose.
I chose the word “suggestion” fairly carefully in my note, but apparently not carefully enough; I fully understood you were saying that you personally run as Admin but acknowledged that others do not. I did not mean to infer you were criticizing those who ran as a standard user or even telling them that they shouldn’t. My post was more for completeness (especially if some of this article makes it into a future book of yours). My personal reason for sticking with a standard user account (which I adopted pre-SIP) is to prevent malware that might make its way on to my Mac from leveraging the fact that the current user has admin privileges. Post-SIP, that’s probably a pretty small security hole, but since I’m used to the workflow and the small overhead already, I keep it. As a side benefit, it also makes it clear when I am being prompted for user-level authorization (e.g., web site certificate exception) or admin-level, since the username will be filled in for the former but not for the latter. The Terminal is the only place where it is a (minor) inconvenience.