Difference between sudo -i and sudo su
Based on the descriptions from the man pages for su
and sudo
I would assume the following things.
- Since
sudo -iu <user>
means a login shell this would be equivalent to ansu - <user>
orsu -l <user>
. - An
su
without any arguments changes your effective user ID but you're still using your original<user>
environment and awho am i
will report you're still<user>
.
excerpt sudo man page
-i [command]
The -i (simulate initial login) option runs the shell specified in
the passwd(5) entry of the target user as a login shell. This means
that login-specific resource files such as .profile or .login will
be read by the shell. If a command is specified, it is passed to
the shell for execution. Otherwise, an interactive shell is
executed. sudo attempts to change to that user's home directory
before running the shell. It also initializes the environment,
leaving DISPLAY and TERM unchanged, setting HOME, MAIL, SHELL,
USER, LOGNAME, and PATH, as well as the contents of
/etc/environment on Linux and AIX systems. All other environment
variables are removed.
Example
I have a user account, saml
with a UID of 500.
$ egrep "Uid|Gid" /proc/$$/task/$$/status
Uid: 500 500 500 500
Gid: 501 501 501 501
In the above output, the 1st column is my real UID (uid) and the 2nd is my effective UID (euid).
Becoming root via (su)
$ su
Now I'm root, but I still maintain my environment and my real UID is still 500
. Notice that my euid is now 0 (root).
$ egrep "Uid|Gid" /proc/$(pgrep su -n)/task/$(pgrep su -n)/status
Uid: 500 0 0 0
Gid: 501 501 501 501
However my environment is still saml
's. Here's one of he environment variables, $LOGNAME
.
$ env | grep LOGNAME
LOGNAME=saml
Becoming root via (su -) or (sudo -i)
$ su -
With an su -
or sudo -i
not only do I change my effective UID to a new user, but I also source their files as if it was a login, and my environment now becomes identical as if I were them directly logging in.
$ egrep "Uid|Gid" /proc/$(pgrep su -n)/task/$(pgrep su -n)/status
Uid: 500 0 0 0
Gid: 501 501 501 501
However my environment is now root
's. Same variable, $LOGNAME
, now it's set with root
.
$ env | grep LOGNAME
LOGNAME=root
So then what's the difference?
Well let's try the above with sudo -i
and find out.
$ sudo -i
Now let's look at the same info:
$ egrep "Uid|Gid" /proc/$(pgrep su -n)/task/$(pgrep su -n)/status
Uid: 0 0 0 0
Gid: 501 501 501 501
Well one major thing is my effective ID and real ID are both 0 (root
) with this approach. The environment variable $LOGNAME
is as if we logged in as root
.
$ env | grep LOGNAME
LOGNAME=root
Comparing environments
If we count the number of lines in say the 3 methods, perhaps there is some additional info to be had.
$ env > /tmp/<method used to become root>
We are left with these 3 files:
- -rw-r--r-- 1 root root 1999 Nov 2 06:43 sudo_root.txt
- -rw-r--r-- 1 root root 1970 Nov 2 06:44 sudash_root.txt
- -rw-r--r-- 1 root root 4859 Nov 2 06:44 su_root.txt
Already we can see that something is up with just a plain su
. The env. is over 2x the size of the others.
Number of lines in each:
$ wc -l su*
28 sudash_root.txt
32 sudo_root.txt
92 su_root.txt
There's really no need to look further at the su_root.txt
file. This file contains a much of user's environment that ran the su
command. So let's look at the other 2 files.
They're virtually identical except for a few cosmetic variables, such as $LANG
being slightly different. The one smoking gun in the list is the $PATH
.
sudo
PATH=/usr/lib64/ccache:/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/brlcad/bin:/root/bin
su -
PATH=/usr/lib64/qt-3.3/bin:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/brlcad/bin:/root/bin
As you can see sudo -i
gives us some additional protection by stripping out suspicious paths, but it also keeps our $DISPLAY
and $TERM
intact in case we were displaying a GUI to different location.
Take aways?
- So the big take away is that the method used to become root
sudo -i
is advantages over the others because you use your own password to do so, protecting root's password from needing to be given out. - There is logging when you became
root
, vs. mysteriously some one becomingroot
viasu
orsu -
. sudo -i
gives you a better user experience over eithersu
's because it protects your$DISPLAY
and$TERM
.sudo -i
provides some protection to the system when user's becomeroot
, by limiting the environment which they are given.
What about sudo su
, you didn't even discuss it?
I intentionally avoided bringing that into the discussion even though the OP asked about it because doing so would only of confused the issue, IMO. When you run sudo su
the sudo
command masks the effects of the su
and so much of the environment that you'd get from a regular su
is lost. Sudo is doing its job and providing a limited and protected environment regardless of whether it's sudo su
or sudo -i
.
Example
Here's the result of the sudo su
environment being dumped:
ls -l /tmp/sudosu_root.txt
-rw-r--r-- 1 root root 1933 Nov 2 14:48 /tmp/sudosu_root.txt
And the number of lines:
$ wc -l /tmp/sudosu_root.txt
31 /tmp/sudosu_root.txt
These are the only variables that differ between a sudo su -
and a sudo -i
:
$ sdiff /tmp/sudosu_root.txt /tmp/sudo_root.txt | grep ' |'
USERNAME=saml | USERNAME=root
PATH=/usr/lib64/ccache:/sbin:/bin:/usr/sbin:/usr/bin:/usr/brl | PATH=/usr/lib64/ccache:/usr/local/sbin:/sbin:/bin:/usr/sbin:/
MAIL=/var/spool/mail/saml | MAIL=/var/spool/mail/root
PWD=/home/saml/tst | PWD=/root
SUDO_COMMAND=/bin/su | SUDO_COMMAND=/bin/bash
XAUTHORITY=/root/.xauthYFtlL3 | XAUTHORITY=/var/run/gdm/auth-for-saml-iZePuv/datab
So as you can see there really isn't much of a difference between them. Slightly different $PATH
, the $SUDO_COMMAND
, and the $MAIL
and $USERNAME
are the only differences.
References
- Real and Effective IDs
I think @slm misread the question, so providing another answer.
He did hit on the main point, about one being a login shell and the other not.
When running sudo -i
the shell will become a login shell, and so it will read things like ~/.profile
where as a non-login shell will only read ~/.bashrc
.
When chaining sudo
with su
(as in sudo su
), neither the sudo
nor the su
invoke a login shell. The equivalent to sudo -i
when using su
would instead be sudo su -l
.
I personally consider sudo su
to be along the lines of "useless use of cat" examples. You can get the same behavior with sudo -s
.
There are basically 5 common ways of invoking a root shell via sudo
sudo su
- non-login shell
- sets
HOME
to/root
- Prunes the environment
sudo -i
- login shell
- sets
HOME
to/root
- Prunes the environment
sudo su -l
- login shell
- sets
HOME
to/root
- Prunes the environment
When invoking a shell, this is equivalent to
sudo -i
sudo -s
- non-login shell
- sets
HOME
to/root
- Prunes the environment
When invoking a shell, this is equivalent to
sudo su
sudo -Es
- non-login shell
- Leaves
HOME
alone - Leaves the environment alone (except for
$PATH
and$LD_LIBRARY_PATH
iirc)
Note, that these rules only apply when using them to gain a shell. There is a difference between sudo -s somecommand
and sudo su -c somecommand
.
The second one preserves the current directory (pwd) but the first command drops the user to the root's home directory.