105

$ whoami
admin
$ sudo -S -u otheruser whoami
otheruser
$ sudo -S -u otheruser /bin/bash -l -c 'echo $HOME'
/home/admin

Why isn't $HOME being set to /home/otheruser even though bash is invoked as a login shell?

Specifically, /home/otheruser/.bashrc isn't being sourced. Also, /home/otheruser/.profile isn't being sourced. - (/home/otheruser/.bash_profile doesn't exist)

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
user80551
  • 1,619
  • 4
  • 16
  • 21

3 Answers3

147

To invoke a login shell using sudo just use -i. When command is not specified you'll get a login shell prompt, otherwise you'll get the output of your command.

Example (login shell):

sudo -i

Example (with a specified user):

sudo -i -u user

Example (with a command):

sudo -i -u user whoami

Example (print user's $HOME):

sudo -i -u user echo \$HOME

Note: The backslash character ensures that the dollar sign reaches the target user's shell and is not interpreted in the calling user's shell.

I have just checked the last example with strace which tells you exactly what's happening. The output bellow shows that the shell is being called with --login and with the specified command, just as in your explicit call to bash, but in addition sudo can do its own work like setting the $HOME.

# strace -f -e process sudo -S -i -u user echo \$HOME
execve("/usr/bin/sudo", ["sudo", "-S", "-i", "-u", "user", "echo", "$HOME"], [/* 42 vars */]) = 0
...
[pid 12270] execve("/bin/bash", ["-bash", "--login", "-c", "echo \\$HOME"], [/* 16 vars */]) = 0
...

I noticed that you are using -S and I don't think it is generally a good technique. If you want to run commands as a different user without performing authentication from the keyboard, you might want to use SSH instead. It works for localhost as well as for other hosts and provides public key authentication that works without any interactive input.

ssh user@localhost echo \$HOME

Note: You don't need any special options with SSH as the SSH server always creates a login shell to be accessed by the SSH client.

  • 3
    sudo -i -u user echo \$HOME doesn't work for me. Output: $HOME. strace gives the same output as yours. What's the issue? – John_West Nov 23 '15 at 11:12
  • No idea, it still works for me, I'd need to see it or maybe even touch the system. – Pavel Šimerda Jan 20 '16 at 19:02
  • While sudo -i should be a login shell it is different from what sudo su - does on Arch linux. A clear sign the former does not do a login is that it does not display the last login time but that the latter does (and it does a lot more, like have a lot of envvars ready). – karatedog Oct 21 '21 at 13:22
  • @John_West Because $HOME is expanded before it's sent to sudo. echo '$HOME' works, though. – Martin Braun Aug 26 '23 at 15:20
14

You're giving Bash too much credit. All "login shell" means to Bash is what files are sourced at startup and shutdown. The $HOME variable doesn't figure into it.

The Bash docs explain some more what login shell means: https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html#Bash-Startup-Files

In fact, Bash doesn't do anything to set $HOME at all. $HOME is set by whatever invokes the shell (login, ssh, etc.), and the shell inherits it. Whatever started your shell as admin set $HOME and then exec-ed bash, sudo by design doesn't alter the environment unless asked or configured to do so, so bash as otheruser inherited it from your shell.

If you want sudo to handle more of the environment in the way you're expecting, look at the -i switch for sudo. Try:

sudo -S -u otheruser -i /bin/bash -l -c 'echo $HOME'

The man page for sudo describes it in more detail, though not really well, I think: http://linux.die.net/man/8/sudo

mdahlman
  • 103
Jeff Snider
  • 241
  • 1
  • 3
  • 5
    $HOME isn't set by bash - Thanks, I didn't know that. – user80551 Jan 02 '15 at 08:11
  • Look for strace in my answer. It shows that you don't need to build /bin/bash -l -c 'echo $HOME' command line yourself when using -i. – Pavel Šimerda Jan 02 '15 at 09:46
  • 1
    That sudo syntax threw an error on my machine. (su uses the -c option, but I don't think sudo does.) I had better luck with: HomeDir=$( sudo -u "$1" -H -s echo "\$HOME" ) – palswim Oct 13 '16 at 20:21
  • yeah, @palswim is right. Not sure about -S (I didn't need it, so I left it out), but -c doesn't work here, you need -s instead. – polynomial_donut Jan 07 '19 at 23:34
1
sudo -u www-data bash -i -c "env"

Notice the -i flag, telling bash to run interactively.

This command will execute an interactive bash shell for user www-data, within which shell (as an example) the env command is executed.

This works even if user www-data has a nologin shell as their default shell.

Abdull
  • 853