18

The problem
In a bash script, I am using the command...

sudo -u node bash

.. to switch from root to a non-sudo user, and this is failing.

The context
I am writing a provision.sh script for Vagrant, to set up a server running Ubuntu 16.04.3 with all the packages required to deliver an app with Meteor 1.6.

One required step is to install nvm as a non-root user. After nvm is installed, you need to log out and log back in again in order to activate nvm. I therefore create a non-sudo user named meteor, and want to switch to that when I download and install nvm.

Subsequently, I want to switch back to being root and log in gain immediately as meteor, in order to start using nvm to install Node.js.

You'll find a heavily commented script below. Vagrant runs this script each time I call vagrant reload --provision.

What command should I be using instead of sudo -u node bash?


echo "# whoami" && whoami && echo "^^^^ root expected"
echo "As root, create non-sudo user meteor:"
pass=$(perl -e 'print crypt($ARGV[0], "password")' $password)
useradd -m -p $pass meteor
echo "User meteor created. ls -al /home/meteor:"
ls -al /home/meteor
echo "Install curl as root:"
apt-get install -y curl
echo "Trying sudo -u meteor bash"
sudo -u meteor bash #### THIS IS THE LINE THAT FAILS ###

echo "$ whoami" && whoami && echo "^^^^^^ meteor expected"
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash
echo "ls -al /home/meteor/.nvm # should be populated"
ls -al /home/meteor/.nvm

echo "ls -al /root/.nvm # should not exist"
ls -al /root/.nvm

echo "command -v nvm will fail silently until we log out and back in again"
#command -v nvm
exit

#### Because the script is still running as root, it halts here ####

echo "# whoami" && whoami && echo "^^^^ should be root"
sudo -u meteor bash
echo "$ whoami" && whoami && echo "^^^^^^ should be meteor"
echo "command -v nvm should work now"
command -v nvm
2
  • You'll have to extract the parts into another script and call sudo on that, or call each command with sudo (in this case that's only the bash after the curl). sudo -u meteor bash simply starts bash as meteor, it can't simply take over the rest of the script.
    – muru
    Nov 20, 2017 at 16:08
  • Related, maybe a duplicate? Best practices on using sudo in a bash script
    – wjandrea
    Nov 22, 2017 at 20:59

3 Answers 3

19

If you start your script with root permissions but need to run certain commands as a specific non-root user you can use sudo with the -u option to either run a single command with e.g.

sudo -u USERNAME whoami # outputs USERNAME's user name

or start a subshell and run your commands in it, e.g.:

sudo -u USERNAME bash -c 'whoami;echo $USER' # outputs USERNAME's user name twice

The line in your script doesn't fail actually, you just run only bash as user meteor, and as bash has nothing to do it just exits and the original root shell runs the rest of the script. What you actually want to do (I suppose) is:

…
echo "Trying sudo -u meteor bash"
sudo -u meteor bash -c '\
  echo "$ whoami" && whoami && echo "^^^^^^ meteor expected"
  curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh |\
  bash
'
echo "ls -al /home/meteor/.nvm # should be populated"
…

Another way to achieve the same is a here document:

…
echo "Trying sudo -u meteor bash"
sudo -u meteor bash <<EOF
  echo "$ whoami" && whoami && echo "^^^^^^ meteor expected"
  curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh |\
  bash
EOF
echo "ls -al /home/meteor/.nvm # should be populated"
…
1
  • sudo -u does affect the environment (i.e. available variables), though. This is important in some cases, for example with gsettings.
    – caw
    Jun 15, 2021 at 4:39
1

If you're in a container environment, the gosu project could be of interest. It is intended to solve the issue that su and sudo have very strange and often annoying TTY and signal-forwarding behavior.

A few nice alternatives are mentioned in the gosu project's README.md:

  1. chroot --userspec may already be installed
  2. su-exec https://github.com/ncopa/su-exec
  3. setpriv from the (Debian) util-linux package https://manpages.debian.org/buster/util-linux/setpriv.1.en.html
0
#! /bin/bash
#  (GPL3+) Alberto Salvia Novella (es20490446e)


execute () {
    function="${1}"
    command="${2}"
    error=$(eval "${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo "${function}: $error"
        exit 1
    fi
}


executeAsNonAdmin () {
    function="${1}"
    command="${2}"

    eval setPasswordAsker="SUDO_ASKPASS=/usr/libexec/openssh/ssh-askpass"
    run="runuser ${SUDO_USER} --session-command=\"${setPasswordAsker}\" --command=\"${command}\""
    execute "${function}" "${run}"
}


executeAsNonAdmin "" "${@}"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.