5

I am trying to make sure when a script is run it is run as a specific user without having to su to that user before the script is run. Also the script is run with a couple of flags for example

./myscript.sh -e dev -v 1.9

I have tried the following

[ `whoami` = myuser ] || exec sudo -S su - myuser -c "bash `pwd`/`basename $0` $@"

But the -v flag which is supposed to be an input to my script is being fed as input to su. So it complains of an invalid option, is there a way to correct the above?

NB: The person running the script has sudo privileges.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
PDStat
  • 153
  • 3
    The [ and ] must have spaces after and before them, respectively. Why do you need sudo su? Is not sudo enough? Do you really need to start an interactive or login shell? And if the user has sudo access, why use -S (used for passing a password over standard input)? Related: Is there ever a good reason to run sudo su? – Kusalananda Jun 10 '19 at 08:36
  • The spaces was a typo. And I've found with just sudo su it asks for password input whereas -S doesn't – PDStat Jun 10 '19 at 08:40
  • No, it still asks for one with -S, that just allows you to do something like echo password | sudo -S command. If it didn't ask for a password, that's because you've recently run another sudo command so it still remembers the password. Run sudo -k to forget it and try again and it will ask for a password. – terdon Jun 10 '19 at 08:45
  • As per my comment to terdon it looks like the sudoers file is set to not require a password prompt for su. That isn't the case however for doing an su from a script, it still prompts unless I use -S – PDStat Jun 10 '19 at 08:59
  • @PDStat su does not use sudoers. – Kusalananda Jun 10 '19 at 09:00
  • 1
    @Kusalananda no, but you can set up su to be run with sudo su without needing a password through sudoers. That said, I have absolutely no idea how or why the -S flag could possibly be relevant. – terdon Jun 10 '19 at 09:03
  • It looks like su changes its behavior if given the -- "end of options" marker. See, for instance, su - myuser -c 'echo "$@"; echo "$0"; echo "$USER";' -- sh a --foo -X, and observe that 1) it doesn't work without the --, giving the error you mentioned; 2) the shell gets the arguments correctly, including $0. I cannot explain it right now, though. – fra-san Jun 10 '19 at 13:25

3 Answers3

6

The current user is already in the variable $USER. So all you need is:

[ "$USER" = "myuser" ] || sudo -u myuser $0 "$@"

There is no need for sudo su, sudo can do everything you require. You also don't need pwd or basename, the $0 variable already has the full path to the script.

Your original command was starting a login shell (su -). If that's really needed (which seems strange), you can do:

[ "$USER" = "myuser" ] || sudo -iu myuser $0 "$@"
terdon
  • 242,166
  • Doing just sudo -u myuser will ask for the password. I don't wish for this to happen – PDStat Jun 10 '19 at 08:51
  • @PDStat How do you wish to provide the password (which has to be provided)? – Kusalananda Jun 10 '19 at 08:53
  • 1
    @PDStat there is no option of sudo or su that will let you do this without a password. Your approach also asks for a password. If it didn't that's because your user had already authenticated. Try running sudo -k and then your command again and you'll see it will ask for a password. If you really need to do it without a password, you will need to set that up in the sudoers file. – terdon Jun 10 '19 at 08:53
  • It looks like the sudoers files is already set like that as I can do sudo -k followed by sudo su - myuser without the prompt for a password. That's not the case however from a script without the -S flag. – PDStat Jun 10 '19 at 08:58
  • 1
    @PDStat that... makes no sense to me. I believe you, I just don't have any idea how that could possibly happen. I cannot imagine how the -S would ever be relevant. – terdon Jun 10 '19 at 09:05
3

There are two problems with your script:

1) You forgot the spaces in the test command [`whoami` = myuser]

2) Due to the expansion of the variable "$@" in two steps the quoting is lost.

The following seems to work on my system:

[ `whoami` = myuser ] || exec sudo -S -u myuser bash -- "$0" "$@"
user000001
  • 3,635
3

If the whole script would need to be run by a specific user, then I would leave it up to the user running the script to arrange with changing into the correct user identity in any way that they see fit (whether through su, sudo, or some other means).

This would simplify your script and would make it easier to use. In particular, it would avoid having to "correct" for the inability of the user to assume the right identity. Personally, I would treat this as an error in its invocation, similar to failing to use the correct command line options.

The script could still check to make sure that it's being run by the correct user, obviously:

if [ "$USER" != "correctuser" ]; then
    echo 'Must be run by "correctuser"' >&2
    exit 1
fi

An ordinary user would then run the script using

sudo -u correctuser ./script.sh -e dev -v 1.9

while the root user may want to do

su correctuser -c ./script.sh -e dev -v 1.9
Kusalananda
  • 333,661