Execute Shell script without sudo password - shell

I have a shell script as given below.
#!/bin/bash
sudo -u testuser -H sh -c "
mkdir /usr/local/testdir;
if [ $? -eq 0 ];then
echo "Successfull";
else
echo "Unsuccessfull";
fi
"
I have given privileges to user testuser to execute shell script with sudo, but without asking password.For this I add the below line in /etc/sudoers file,
testuser ALL=(ALL) NOPASSWD: ALL
And it works fine that, I could run commands with sudo, but without asking password. But the above shell script always giving out put ass follows,
mkdir: cannot create directory `/usr/local/testdir': Permission denied
Successfull
And it is not creating directory testdir inside /usr/local. Please advice me what modification shall I need to do to work this script fine.
Thanks.

Two problems:
1.) You told:
sudo -u testuser -H ...
what's mean: run the command as testuser, and he doesn't has permissions to write into the /usr/local therefore you getting permission denied.
When you remove the -u testuser, the command will run as root (as default) (without password for the testuser) and will create the directory.
Seems, you simply misunderstand how the sudo and /etc/sudoers works. The -u user mean
-u user' The -u (user) option causes sudo to run the specified command as a user
other than root. To specify a uid instead of a user name, #uid.
When running commands as a uid, many shells require that the '#' be escaped with a
backslash ('\'). Security policies may restrict uids
to those listed in the password database. The sudoers policy allows
uids that are not in the password database as long as the targetpw
option is not set. Other security policies may not support this.
2.) second problem the Successfull message.
You're using double quotes for sh -c. The Variable expansion is done BEFORE the sh -c even starts. So use single quotes, and will get the correct Unsuccessfull message:
sudo -u testuser -H sh -c '
mkdir /usr/local/testdir
if [ $? -eq 0 ];then
echo "Successfull";
else
echo "Unsuccessfull";
fi
'
and use the next as a solution:
sudo -H sh -c '
mkdir /usr/local/testdir
if [ $? -eq 0 ];then
echo "Successfull";
else
echo "Unsuccessfull";
fi
'

Related

How can I request elevated permissions in a bash script's begin and let it go at the end?

I have a script (myscript.sh) which runs a few commands which need elevated privileges (i.e. needs to run with sudo).
Script is quite complex, but to demonstrate it is like below:
#!/bin/bash
echo "hello"
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
echo "hello3"
...
If I run it as a normal user without the required privileges:
$ ./myscript.sh
hello
must be super-user to perform this action
However if I run it with the correct privileges, it will work fine:
$ sudo ./myscript.sh
hello
hello2
hello3
Can I somehow achieve to run myscript.sh without sudo, and make the script requesting the elevated privileges only once in the beginning (and pass it back once it has finished)?
So obviously, sudo command1_which_needs_sudo will not be good, as command2 also need privileges.
How can I do this if I don't want to create another file, and due to script complexity I also don't want to do this with heredoc syntax?
If your main concern is code clarity, using wrapper functions can do a lot of good.
# call any named bash function under sudo with arbitrary arguments
run_escalated_function() {
local function_name args_q
function_name=$1; shift || return
printf -v args_q '%q ' "$#"
sudo bash -c "$(declare -f "$function_name"); $function_name $args_q"
}
privileged_bits() {
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
}
echo "hello"
run_escalated_function privileged_bits
echo "hello3"
If you want to run the script with root privileges without having to type sudo in the terminal nor having to type the password more than once then you can use:
#!/bin/bash
if [ "$EUID" -ne 0 ]
then
exec sudo -s "$0" "$#"
fi
echo "hello"
command1_which_needs_sudo
echo "hello2"
command2_which_needs_sudo
echo "hello3"
# ...
sudo -k
Update:
If your goal is to execute one part of the script with sudo rights then using a quoted here‑document is probably the easiest solution; there won't be any syntax issues because the current shell won't expand anything in it.
#!/bin/bash
echo "hello"
sudo -s var="hello2" <<'END_OF_SUDO'
command1_which_needs_sudo
echo "$var"
command2_which_needs_sudo
END_OF_SUDO
sudo -k
echo "hello3"
#...
remark: take notice that you can use external values in the here-document script by setting varname=value in the sudo command.

How to switch user when `sudo bash` script with only one login user? [duplicate]

Can I change/su user in the middle of a script?
if [ "$user" == "" ]; then
echo "Enter the table name";
read user
fi
gunzip *
chown postgres *
su postgres
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
You can, but bash won't run the subsequent commands as postgres. Instead, do:
su postgres -c 'dropdb $user'
The -c flag runs a command as the user (see man su).
You can use a here document to embed multiple su commands in your script:
if [ "$user" == "" ]; then
echo "Enter the table name";
read user
fi
gunzip *
chown postgres *
su postgres <<EOSU
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
EOSU
Not like this. su will invoke a process, which defaults to a shell. On the command line, this shell will be interactive, so you can enter commands. In the context of a script, the shell will end right away (because it has nothing to do).
With
su user -c command
command will be executed as user - if the su succeeds, which is generally only the case with password-less users or when running the script as root.
Use sudo for a better and more fine-grained approach.
Refer to answers in below question,
You can write between << EOF and EOF as mentioned in answers.
#!/bin/bash
whoami
sudo -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami
How do I use su to execute the rest of the bash script as that user?
No you can't. Or atleast... you can su but su will simply open a new shell at that point and when it's done it will continue with the rest of the script.
One way around it is to use su -c 'some command'
Another interesting idea that I heard today is to do a recursive call on the script, when you run as root and you want to run the script as another user. See the example below:
I am running script "my_script" as "root" and want the script to run as user "raamee"
#!/bin/bash
#Script name is: my_script
user=`whoami`
if [ "$user" == "root" ]; then
# As suggested by glenn jackman. Since I don't have anything to run once
# switching the user, I can modify the next line to:
# exec sudo -u raamee my_script and reuse the same process
sudo -u raamee my_script
fi
if [ "$user" == "raamee" ]; then
#put here the commands you want to perform
do_command_1
do_command_2
do_command_3
fi

Execute root command in shell script and change to normal user after a process

I am trying to create a shell script where it uses the root access to install all the dependencies and after completing it, it exits from the root command and continue executing the script as normal user.
This is the test code:
#!/bin/sh
output=$(whoami)
if [ "$(whoami)" != "root" ]
then
su -c "echo \"hi\""
echo $output
//continue doing some installtion
exit
fi
echo $output //this should show the normal username not the root name
#!/bin/sh
su -c 'echo $(whoami)'
echo $(whoami)
When you pass the command with su following with an option -c it runs as root user, so when you want to install any dependencies you can run the following command as shown in above example.

Why can't I redirect text to a text file?

I'm writing a bash shell script that has to be run with admin permissions (sudo).
I'm running the following commands
sudo -u $SUDO_USER touch /home/$SUDO_USER/.kde/share/config/kcmfonts > /dev/null
sudo -u $SUDO_USER echo "[General]\ndontChangeAASettings=true\nforceFontDPI=96" >> /home/$SUDO_USER/.kde/share/config/kcmfonts
The first command succeeds and creates the file. However the second command keeps erroring with the following:
cannot create /home/username/.kde/share/config/kcmfonts: Permission denied
I can't understand why this keeps erroring on permissions. I'm running the command as the user who invoked sudo so I should have access to write to this file. The kcmfonts file is created successfully.
Can someone help me out?
Consider doing this:
echo "some text" | sudo -u $SUDO_USER tee -a /home/$SUDO_USER/filename
The tee command can assist you with directing the output to the file. tee's -a option is for append (like >>) without it you'll clobber the file (like >).
You don't need to execute the left side with elevated privs (although it is just echo, this is a good thing to form as a habit), you only need the elevated privs for writing to the file. So with this command you're only elevating permissions for tee.
sudo -u $SUDO_USER echo "some text" >> /home/$SUDO_USER/filename
sudo executes the command echo "some text" as `$SUDO_USER".
But the redirection is done under your account, not under the $SUDO_USER account. Redirection is handled by the shell process, which is yours and is not under the control of sudo.
Try this:
sudo -u $SUDO_USER sh -c 'echo "some text" >> /home/$SUDO_USER/filename'
That way, the sh process will be executed by $SUDO_USER, and that's the process that will handle the redirection (and will write to the output file).
Depending on the complexity of the command, you may need to play some games with escaping quotation marks and other special characters. If that's too complex (which it may well be), you can create a script:
$ cat foo.sh
#!/bin/sh
echo "some text" >> /home/$SUDO_USER/filename
$ sudo -u $SUDO_USER ./foo.sh
Now it's the ./foo.sh command (which executes as /bin/sh ./foo.sh) that will run under the $SUDO_USER account, and it should have permission to write to the output file.

Can I run 'su' in the middle of a bash script?

Can I change/su user in the middle of a script?
if [ "$user" == "" ]; then
echo "Enter the table name";
read user
fi
gunzip *
chown postgres *
su postgres
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
You can, but bash won't run the subsequent commands as postgres. Instead, do:
su postgres -c 'dropdb $user'
The -c flag runs a command as the user (see man su).
You can use a here document to embed multiple su commands in your script:
if [ "$user" == "" ]; then
echo "Enter the table name";
read user
fi
gunzip *
chown postgres *
su postgres <<EOSU
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
EOSU
Not like this. su will invoke a process, which defaults to a shell. On the command line, this shell will be interactive, so you can enter commands. In the context of a script, the shell will end right away (because it has nothing to do).
With
su user -c command
command will be executed as user - if the su succeeds, which is generally only the case with password-less users or when running the script as root.
Use sudo for a better and more fine-grained approach.
Refer to answers in below question,
You can write between << EOF and EOF as mentioned in answers.
#!/bin/bash
whoami
sudo -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami
How do I use su to execute the rest of the bash script as that user?
No you can't. Or atleast... you can su but su will simply open a new shell at that point and when it's done it will continue with the rest of the script.
One way around it is to use su -c 'some command'
Another interesting idea that I heard today is to do a recursive call on the script, when you run as root and you want to run the script as another user. See the example below:
I am running script "my_script" as "root" and want the script to run as user "raamee"
#!/bin/bash
#Script name is: my_script
user=`whoami`
if [ "$user" == "root" ]; then
# As suggested by glenn jackman. Since I don't have anything to run once
# switching the user, I can modify the next line to:
# exec sudo -u raamee my_script and reuse the same process
sudo -u raamee my_script
fi
if [ "$user" == "raamee" ]; then
#put here the commands you want to perform
do_command_1
do_command_2
do_command_3
fi

Resources