I'd like to remove the need for the user to type a password multiple times for a bash script that runs sudo
commands. How can I loop for password until something like sudo echo
returns 0, and then store the password in a variable to use script-wide?

- 117,780

- 173
2 Answers
It is certainly possible to remove the need to type sudo password for specific commands or even whole scripts.
Your suggested path of storing the password in a local variable in the script is rather unwise. Anyone with read rights to /proc/<pid>/environ
can read the local variables. Anyone who gains read access to a script, with hard coded credentials, could use those credentials to escalate privileges to root and own your system. On a single user system this is still unwise as there are increasing remote attacks targeting Linux users.
Without the specifics of your script I can only advise you to read Ubuntu Community Wiki - Sudoers. Then modify your sudoers file by running sudo visudo
to add the specific commands to the file.
Likely you should add two lines one to add a command alias, and the second to authorize users to run those commands.
An example of allowing specific user ie, bob, to run selected shutdown commands without a password.
Cmnd_Alias SHUTDOWN_CMDS = /sbin/poweroff, /sbin/halt, /sbin/reboot
bob ALL=(ALL) NOPASSWD: SHUTDOWN_CMDS
The following script is an example of how to include in a script the ability to install, uninstall, or edit the example lines in /etc/sudoers
.
#!/bin/bash
#Set Script Name variable
SCRIPT=`basename ${BASH_SOURCE[0]}`
#Initialize variables to default values.
OPT_i=i
OPT_u=u
OPT_e=e
OPT_m=m
#Set fonts for Help.
NORM=`tput sgr0`
BOLD=`tput bold`
REV=`tput smso`
#Help function
function HELP {
echo -e \\n"Help documentation for ${BOLD}${SCRIPT}.${NORM}"\\n
echo -e "${REV}Basic usage:${NORM} ${BOLD}$SCRIPT file.ext${NORM}"\\n
echo "Command line switches are optional. The following switches are recognized."
echo "${REV}-1${NORM} --Installs lines in /etc/sudoers to allow script to be run without entering password multiple times."
echo "${REV}-u${NORM} --Unistalls lines in /etc/sudoers."
echo "${REV}-e${NORM} --Launces visudo to edit /etc/sudoers."
echo "${REV}-m${NORM} --Launces main."
echo -e "${REV}-h${NORM} --Displays this help message. No further functions are performed."\\n
exit 1
}
#Install function
function INSTALL {
echo "launching Install"
echo -e '#script_append'\\n'Cmnd_Alias SHUTDOWN_CMDS = /sbin/poweroff, /sbin/halt, /sbin/reboot'\\n'bob ALL=(ALL) NOPASSWD: SHUTDOWN_CMDS' | sudo EDITOR='tee -a' visudo
}
#Unnstall function
function UNINSTALL {
echo "launching uninstall"
bash -c 'printf ",g/^#script_append$/d\nw\nq\n" | sudo EDITOR='ed' visudo'
bash -c 'printf ",g/^Cmnd_Alias.*reboot$/d\nw\nq\n" | sudo EDITOR='ed' visudo'
bash -c 'printf ",g/^bob ALL=(ALL) NOPASSWD: SHUTDOWN_CMDS$/d\nw\nq\n" | sudo EDITOR='ed' visudo'
}
#Main function
function MAIN {
echo "launching editor via main"
sudo visudo
}
#Check the number of arguments. If none are passed, print help and exit.
NUMARGS=$#
echo -e \\n"Number of arguments: $NUMARGS"
if [ $NUMARGS -eq 0 ]; then
HELP
fi
### Start getopts code ###
#Parse command line flags
#If an option should be followed by an argument, it should be followed by a ":".
#Notice there is no ":" after "h". The leading ":" suppresses error messages from
#getopts. This is required to get my unrecognized option code to work.
while getopts ":iuemh" FLAG; do
case "${FLAG}" in
i) #set option "i"
OPT_i=${OPTARG}
echo "-i used: $OPTARG"
if sudo grep -q '#script_append' /etc/sudoers
then
echo "Sudoers apperes to have already been installed"
exit
else
INSTALL
fi
;;
u) #set option "u"
OPT_u=$OPTARG
echo "-u used: $OPTARG"
UNINSTALL
;;
e) #set option "e"
OPT_e=$OPTARG
echo "-e used: $OPTARG"
sudo visudo
;;
m) #set option "m"
OPT_m=$OPTARG
echo "-m used: $OPTARG"
MAIN
;;
h) #show help
HELP
;;
\?) #unrecognized option - show help
echo -e \\n"Option -${BOLD}$OPTARG${NORM} not allowed."
HELP
#If you just want to display a simple error message instead of the full
#help, remove the 2 lines above and uncomment the 2 lines below.
#echo -e "Use ${BOLD}$SCRIPT -h${NORM} to see the help documentation."\\n
#exit 2
;;
esac
done
shift $((OPTIND-1)) #This tells getopts to move on to the next argument.
### End getopts code ###

- 1,969
-
I'm not storing the password into the script (which is an installer that needs to run some commands as sudo and some as user). I want to bother the user with password only once while the script runs. I tried multiple approaches with Tails OS (a supported OS) to disable password prompt but editing
/etc/sudoers.d/always-ask-password
did not fix it reliably. As for visudo, user would have to make edits themselves and I don't want that. I triedecho 'Defaults timestamp_timeout=-1' | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/always-ask-password')
but that didn't work either. – maqp Oct 28 '17 at 18:01 -
"Anyone with read rights to /proc/
/environ can read the local variables." ... this is true, but only for the variables the process started with. Modifications or additions made by the process after that are not reflected in – muru Oct 30 '17 at 10:45environ
. Local un-exported variables wouldn't even be visible in a child process'senviron
.
My current approach that seems to be working is as follows:
read_sudo_pwd() {
read -s -p "[sudo] password for $USER: " sudo_pwd
until (echo $sudo_pwd | sudo -S echo '' 2>/dev/null)
do
echo -e '\nSorry, try again.'
read -s -p "[sudo] password for $USER: " sudo_pwd
done
}
read_sudo_pwd
echo $sudo_pwd | sudo -S echo 'Hello'
echo $sudo_pwd | sudo -S echo 'World'

- 173
-
2-1 Bad design:
$PWD
is an environment variable so it's best if you don't overwrite it. Use a more descriptive, lowercase variable like$password_sudo
. – wjandrea Oct 29 '17 at 06:18
sudo /path/to/script
, IMO, any script run as root should be owned and rw only by root. Depending on what you are doing, however, you can either configure sudo to run without a password or use expect - http://www.admin-magazine.com/Articles/Automating-with-Expect-Scripts . All 3 methods are preferable to using passwords in scripts. – Panther Oct 28 '17 at 01:18