-1

I made some scripts containing some functions which by design needs sudo permission. I have added those path in .bashrc for Linux and .bash_profile for MacOS so that it can be called from anywhere.

But I do not want the user to type sudo each time they want to call those script functions. Is there any way I can imply sudo in a way that whenever these functions are called, terminal would assume its being called from root user?

I think I should just add sudo -i at the beginning of the script or maybe each function? Or is there any other alternative way of implying sudo? Also, would be great to know if you think it would be terrible or dangerous to imply sudo and if it is not recommended.

An example of dangerous-function script that contains some functions which, I am trying to accomplish without specifying sudo

#!/bin/bash
start-one()
{
    ## do dangerous stuff with sudo
    systemctl start dangerous.service
}

start-two()
{
    systemctl start dangerous1.service
}

start-launchwizard()
{
    systemctl start dangerous2.service
}

## Calling functions one by one...
"$@"

I dont want to call them by sudo dangerous-function start-one I just want to call them with dangerous-function start-one but still get the same result as the previous one.

  • Why can't you execute the script like $ sudo ./script.sh? – 0xSheepdog Apr 6 at 6:36
  • @0xSheepdog Thank you. I have updated the question. I dont know, just want to try I guess. – Rakib Fiha Apr 6 at 6:38
  • 1
    Why don't you just add sudo to the function? start_one() { sudo systemctl ... ? – glenn jackman Apr 6 at 11:24
  • Sorry for late reply, because if I want to make a systemd service for my script, including sudo within the script becomes weird – Rakib Fiha Apr 7 at 3:44
5

The "$@" will expand to the list of command line arguments, individually quoted. This means that if you call your script with

./script.sh start-one

it will run start-one at that point (which is your function). It also means that invoking it as

./script.sh ls

it would run ls.

Allowing a user to invoke the script using sudo (or using sudo inside the script) would allow them to run any command as root, if they had sudo access. You do not want this.

Instead, you would need to carefully validate the command line arguments. Maybe something like

foo_func () {
    # stuff
    printf 'foo:\t%s\n' "$@"
}

bar_func () {
    # stuff
    printf 'bar:\t%s\n' "$@"
}

arg=$1
shift

case $arg in
    foo)
        foo_func "$@" ;;
    bar)
        bar_func "$@" ;;
    *)
        printf 'invalid sub-command: %s\n' "$arg" >&2
        exit 1
esac

Testing:

$ sh script.sh bar 1 2 3
bar:    1
bar:    2
bar:    3
$ sh script.sh baz
invalid sub-command: baz

This would be safer to use with sudo, but you would still not want to execute anything that the user gives you within your various functions directly without sanitising the input. The script above does this by restricting the user to a particular set of sub-commands, and each function that handles a sub-command does not execute, eval, or source its arguments.

Let me say that again with other words: The script does not, and should not, try to execute the user input as code in any way. It should not try to figure out whether an argument corresponds to a function in the current environment that it can execute (functions may have been put there by the calling environment) and it should not execute scripts whose pathnames were given on the command line etc.

If a script is performing administrative tasks, I would be expecting to have to run it with sudo, and I would not want the script itself to ask me for my password, especially not if it's a script that I may want to run non-interactively (e.g. from a cron job). That is, a script performing administrative tasks requiring root privileges should (IMHO) be able to assume it's running with the correct privileges from the start.

If you want to test this in the script, you could do so with

if [ "$( id -u )" -ne 0 ]; then
    echo 'please run this script as root' >&2
    exit 1
fi

It then moves the decision of how to run the script with root privileges to the user of the script.

  • Wow, this was explained so perfectly. I will implement this case statement to avoid inputting invalid commands. Also, I was feeling the same way as you about implying sudo, and giving prompt to user if run without sudo would be much better, but I think I will still try to imply sudo after I sanitize the input from user. :) – Rakib Fiha Apr 6 at 7:57
  • @RakibFiha Note that you can't easily use sudo with functions (if you need to do that). See e.g. Executing a Bash Script Function with Sudo – Kusalananda Apr 6 at 8:43
  • Thank you very much. Now I am trying to figure out how can I check if the parameter passed exists as a function from an array as Im trying to implement your case statement. – Rakib Fiha Apr 6 at 9:47
  • @RakibFiha Note that you don't need to do that as you can simple switch through the valid cases, and output an error when none matches. The point is that you don't use the string given to you by the user as something you can call. Instead you use that string to figure out if it's a sting that is valid. It's very much like testing the command line options (-h, -a etc.) to see whether a given option is valid or not. – Kusalananda Apr 6 at 9:51
  • the case statement is working like a charm now, but I wanted to make a hash table because now my number of functions are increasing and did not want to write case statement for every single function one by one. For some reason case statement is worked only for the first object of the array. Thank you again. Learnt alot from this. – Rakib Fiha Apr 7 at 3:50
1

You can add your script in /etc/sudoers (preferably using `visudo) so that it is accessible to the user.

user ALL= /path/to/script

Then the user will able to execute path/to/script without sudo.

  • Note that since the script simply executes "$@", this would allow the user to execute anything with root privileges, e.g. sudo /path/to/script reboot. – Kusalananda Apr 6 at 7:16
  • @Kusalananda wow, thank you for pointing that out. I thought $@ was only passing the functions within the script. How can I avoid that? – Rakib Fiha Apr 6 at 7:24
  • 4
    Adding a script to sudoers doesn't make it magically run without needing sudo. It simply tells the sudo command it's allowed to let the user run that script. You still need to invoke sudo. – roaima Apr 6 at 7:42

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.