A couple of weeks ago, there was a question posed on Reddit, where almost all of the responses were dangerously incomplete, or simply wrong. That question was
What’s the difference between
sudo -i
andsu -
?
Let’s fix that now.
Table of contents
- Table of contents
- Some misconceptions
- Who’s password gets used?
- PAM vs /etc/shadow
- Running a command vs becoming a user
- Becoming users other than root
- What was nailed in the Reddit conversation
- Some history
- Real world differences
- Why is sudo su - a bad habit?
- Why is sudo su an even worse habit?
- Updating OpenSUSE to use the origin credentials
Some misconceptions
Who’s password gets used?
After a bit of fumbling, most threads landed on:
su
uses the destination user’s password.sudo
defaults to using the origin user’s password, but can be configured differently.
Excellent… Or is it?
PAM vs /etc/shadow
One myth that came up, but seems to be deleted/edited now, is that sudo
uses PAM, while su
re-implements the authentication against /etc/shadow
.
Both use PAM:
Above: PAM config for both utilities in Fedora 39.
These configurations define how authentication works for each utility, so it’s possible to change how su
authenticates the user (including which password is used). Although I don’t recommend it (Spoiler: That’s what sudo is for.)
Above: PAM config for su in Fedora 39.
Note that while the following PAM config controls how authentication works for sudo, there will rarely be a need to touch this. Instead you’ll want to change /etc/sudoers
or /etc/sudoers.d
.
Above: PAM config for sudo in Fedora 39.
I also did the same checks on Debian, Ubuntu and OpenSUSE. Only OpenSUSE was ambiguous (there’s likely an easy way to tell, but I didn’t see value in pursuing it further.)
The myth that su
uses /etc/shadow has been popping up from time-to-time for many years, and I suspect that it might have been true at some point. But it certainly hasn’t been true for a very long time. Here’s a couple of screenshots from Fedora Core 2 (from 2004):
Above: PAM config files for both su and sudo on Fedora Core 2.
This is what the su
config looks like.
Running a command vs becoming a user
Many commenters stated that sudo
runs a command with escalated privileges, while su
becomes the user.
In reality, both commands can be used to run a command with escalated privileges:
Above: Both commands being used to escalate privileges for a single command.
And both commands can be used to become a different user:
Becoming users other than root
There were a whole heap of combinations of ideas around which utility could become a different user directly, and which couldn’t.
Both can become a specific non-root user:
Above: Both commands being used to become another user.
Both commands can run a command as a specific user:
Above: Both commands being used to run whoami as anotheruser.
What was nailed in the Reddit conversation
Environment variables setup
While both sudo -i
and su -
perform a login shell to give you the full environment of the destination user, they do it a little differently:
Above: How many environment variables are available via each method.
Here is the key in the su
man page:
-, -l, --login
Start the shell as a login shell with an environment similar to a real login:
• clears all the environment variables except TERM and variables specified by
--whitelist-environment
• initializes the environment variables HOME, SHELL, USER, LOGNAME, and PATH
• changes to the target user’s home directory
• sets argv[0] of the shell to '-' in order to make the shell a login shell
Specifically:
• clears all the environment variables except TERM and variables specified by
--whitelist-environment
Meanwhile from the sudo
man page:
-i, -‐login
Run the shell specified by the target user’s password database entry as a login shell. This
means that login‐specific resource files such as .profile, .bash_profile, or .login will be
read by the shell. If a command is specified, it is passed to the shell as a simple command
using the -c option. The command and any args are concatenated, separated by spaces, after
escaping each character (including white space) with a backslash (‘\’) except for alphanu‐
merics, underscores, hyphens, and dollar signs. If no command is specified, an interactive
shell is executed. sudo attempts to change to that user’s home directory before running the
shell. The command is run with an environment similar to the one a user would receive at
log in. Most shells behave differently when a command is specified as compared to an inter‐
active session; consult the shell’s manual for details. The Command environment section in
the sudoers(5) manual documents how the -i option affects the environment in which a command
is run when the sudoers policy is in use.
Notice that there is no mention of clearing existing environment variables.
Some history
su
su
has been around for as long as I can remember. In the 90s, it seemed magical to be able to switch to another user without having to log out and in again. You needed to know the password of the account that you want to switch to, but that was well worth the time saving of not having to log out and in again.
Since then, it hasn’t changed a lot from a user perspective. If there’s any truth to the idea of it reading /etc/shadow directly in the past, I’m guessing that authentication via PAM probably has.
A result of needing the destination user’s password, is that if you needed root access on a machine, you needed to have the root password. On single-user systems, this wasn’t a big deal. But on multi-user systems, this means everyone who needs root access would need to have the root password. If there was a need to change the password (eg after an employee leaves), then the password needed to be changed, and everyone would have a new password to remember. It also meant that there were many potential places for the root password to get leaked. - Only one person needed to make a mistake for it to be exposed. Basically, it was a security nightmare.
Enter sudo
sudo
came in to address this in a couple of ways:
- Use the origin user’s password instead of the destination user’s password, and only allow specific users to use sudo.
- Encourage only escalating privileges when needed, rather than switching user for the entire time.
At this point, the root account’s password can now be disabled, and you never need to log in to anything using the root account. - In the early days of Ubuntu, this was one of selling points of it compared to other distros. There was a lot of FUD surrounding it, because people were so used to using the root account. But as we all got used to it, it slowly became the norm, and we are in a better place now because of it.
Real world differences
So far, the only differences between the two utilities are:
- Using the destination account’s credentials vs using the origin account’s credentials, by default.
- Which environment variables get created when simulating a login shell.
While PAM configuration can be changed to influence authentication behaviour, you shouldn’t do so unless there is a good reason (Eg you want to add support for Google Authenticator, or Yubikey.) Therefore we can assume that those bullets won’t change much.
Meanwhile, we’ve yet to explore the sudoers config.
sudoers
/etc/sudoers
and /etc/sudoers.d
is where the magic happens that really sets the two utilities apart.
For personal desktop use, you probably don’t need to change the defaults, and so barely look at these files, if ever. But when you need to restrict access in a multi-user environment, or you need to track command-line usage for compliance with regulations, this configuration is so, so important.
You can specify things like:
- Who can escalate privileges, or change to different accounts.
- What accounts they can change to, or not change to.
- What they can run, or not run.
- How long their authentication is valid before they have to enter it again.
You need to take some care when editing these files, but you can help yourself with a tool like visudo
, which wraps your text editor in a sanity check, and rolls-back the changes if you’ve created a breaking change.
Current intention
su
- Ideal in scripts that run in non-interactively, like service management. These have mostly been taken over by systemd now.sudo
- Ideal for anything user-facing.
In general, the use-cases that make sense for a user to use su
in any capacity, are now very rare. If you catch yourself wanting to use it over sudo
, it’s worth asking your self why; you’re probably doing something wrong.
In fact, if a system requires you to know the passwords for multiple accounts, take that as an indication that you’re probably doing something wrong. Especially if you have multiple people using the same account. If you can get that root account disabled, you’ll have removed a big attack surface.
Why is sudo su - a bad habit?
It’s an extra process, more typing, and it’s duplicating common functionality (Ie sudo -i
or su -
do almost identical jobs.) But most of the time, it probably doesn’t matter on a modern system.
However, it does come into play when you are obligated to lock down how people get what access to what stuff, and to track everything that they do. When I was involved in such an operation, and a user used sudo -i
, we could be certain that the appropriate tracking was being used. But if they loaded up a shell via any other method, we couldn’t be certain.
We had a few weeks of cat & mouse while we patched the holes, and tried to find the short-comings of the permissions that we had granted users. Ie Why did they want a shell? And why didn’t they want to use -i
? - Sometimes it was just education. Sometimes they were doing something they weren’t supposed to be doing, but unaware that it was a problem.
If your use case will work with sudo -i
, you should be using that.
Why is sudo su an even worse habit?
Again, sudo su
uses a whole heap of extra resources used when there are simpler options available.
While writing this section, I originally dove into what each command was doing compared to what you need. But that turned into a series of rabbit holes of nuanced use-cases vs security vs assumptions that needed to be verified. This might warrant its own dedicated blog post in the future. But for now:
If your use case will work with sudo -i
, you should be using that.
Updating OpenSUSE to use the origin credentials
Throughout this post, you may have noticed that I’m on a system that uses the destination user’s password rather the origin’s:
Above: Sudo asking for the password of root rather than the origin account.
Above: Sudo asking for the password of anotheruser rather than the origin account.
That’s sudo’s default configuration on OpenSUSE.
Let’s fix that.
Steps
Add any user that you want to be able to sudo, to the wheel
group. You can do it like this:
$ sudo gpasswd -a `whoami` wheel
Adding user ksandom to group wheel
Now we need to edit the /etc/sudoers
file. We can do that with the visudo
command.
Find the lines that look like this:
Defaults targetpw # ask for the password of the target user i.e. root
ALL ALL=(ALL) ALL # WARNING! Only use this together with 'Defaults targetpw'!
and comment them out to look like this:
#Defaults targetpw # ask for the password of the target user i.e. root
#ALL ALL=(ALL) ALL # WARNING! Only use this together with 'Defaults targetpw'!
Now find this line:
# %wheel ALL=(ALL:ALL) ALL
And uncomment it like this:
%wheel ALL=(ALL:ALL) ALL
Save, and exit. If you’re using vim, you can exit and save like this:
:wq
You might need to log out, and log back in again to get the groups applying. So you can test it first like this:
Above: Triggering a fresh login shell to make sure that the groups are applied.
And then test sudo:
Above: Sudo is now working using the origin password.
Notice that it is now asking for my password, instead of root’s password.
Log out, and back in again to get the behaviour across all shells.
Tip
It’s worth having an extra shell running as root while you make these changes, so that if you make a mistake, you can run visudo again to restore the previous configuration while you figure out the problem. visudo
protects against configuration failures. But it doesn’t protect against permissions failures.