Applying sudo to some commands in script - bash

I have a bash script that partially needs to be running with default user rights, but there are some parts that involve using sudo (like copying stuff into system folders) I could just run the script with sudo ./script.sh, but that messes up all file access rights, if it involves creating or modifying files in the script.
So, how can I run script using sudo for some commands? Is it possible to ask for sudo password in the beginning (when the script just starts) but still run some lines of the script as a current user?

You could add this to the top of your script:
while ! echo "$PW" | sudo -S -v > /dev/null 2>&1; do
read -s -p "password: " PW
echo
done
That ensures the sudo credentials are cached for 5 minutes. Then you could run the commands that need sudo, and just those, with sudo in front.
Edit: Incorporating mklement0's suggestion from the comments, you can shorten this to:
sudo -v || exit
The original version, which I adapted from a Python snippet I have, might be useful if you want more control over the prompt or the retry logic/limit, but this shorter one is probably what works well for most cases.

Each line of your script is a command line. So, for the lines you want, you can simply put sudo in front of those lines of your script. For example:
#!/bin/sh
ls *.h
sudo cp *.h /usr/include/
echo "done" >>log
Obviously I'm just making stuff up. But, this shows that you can use sudo selectively as part of your script.
Just like using sudo interactively, you will be prompted for your user password if you haven't done so recently.

Related

Usage of sudo in a shell script

When executing a shell script, how does sudo come into play in the following?
# script.sh
ls /root
sudo ls /root
Now, if I run $ sudo ./script.sh or $ ./script.sh what will be the difference? For example:
Do all commands that are run with sudo ./script.sh automatically prepend a "sudo" to that command?
Is the sudo ls /root line vlid? Or should the line instead of ls /root and require root invocation?
Basically, I'm trying to figure out the difference in a line-item being run as sudo, or the script itself being run as sudo.
If you have a script that requires elevated privileges for certain commands, one way to handle those commands is with sudo. Before using sudo, there are several considerations for configuring its use. For instance, if you have certain users you want to be able to run commands with sudo and further to run sudo without being prompted for a password, you need a bit of configuration first. sudo is configured through the visudo utility. For most uses of sudo you will simply need to uncomment options at the end of the file. However to allow users to run sudo without a password, you will also need to add those users to the wheel group (some distros now use a sudo group -- check). After adding users to the wheel group, to allow them to use sudo without a password, you would run visudo and uncomment the following line:
## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL
With sudo configured, then within a script, if elevated (root) privileges are needed you simply need to check whether the user UID (and/or EUID) are equal to zero indicating the user is root, if not, then you use sudo to run the command. You can structure the test in the negative or in the positive to fit your taste, e.g.
if [ "$UID" -eq 0 -o "$EUID" -eq 0 ]; then
command
else
sudo command
fi
or
if [ "$UID" -ne 0 -a "$EUID" -ne 0 ]; then
sudo command
else
command
fi
If your command is not a simple command, but instead contains redirections or pipelines, then you must run the entire command with sudo not just the first command in the list. To do so, just use sudo bash -c "your long command" to ensure elevated privileges are available to each part of a compound command that needs it. For example if you attempt:
sudo cat /etc/sudoers > sudoersbackup
The command will fail. While cat has the elevated privileges to read the file the > redirection is run as the regular user and will fail due to lack of permission. To handle that circumstance, you can do:
sudo bash -c "cat /etc/sudoers > sudoersbackup"
That ensures elevated privileges are available to the entire command.
SUDO stands for "super user do". Basically it is a keyword that when prefixed before any other command, will force that command to run with elevated privileges. Certain commands require elevated privileges. There should be a file located at /etc/sudoers which provides a list of users or user groups who have permission to execute privileged commands.
So if your shell script requires no special privileges to run (which I expect it does not), then sudo ./script.sh should be equivalent to bash script.sh or ./script.sh.

Shell script error: How would I change a permission on a file in a Shell script

I am trying to set up a cron on several AWS EC2 machines and would like to run a command on all of them at once, with the following shell script:
#!/bin/sh
cd /etc/cron.daily
touch ecs.sh
echo '#!/bin/sh' > /etc/cron.daily/ecs.sh
echo 'sudo yum update -y ecs-init' >> /etc/cron.daily/ecs.sh
echo 'sudo yum update -y' >> /etc/cron.daily/ecs.sh
sudo chmod 755 /etc/cron.daily/ecs.sh
cd ~
(crontab -u root -l; echo '0 0 * * * /etc/cron.daily/ecs.sh') | crontab -u root -
sudo yum update -y
The part that does not work is: chmod 755 /etc/cron.daily/ecs.sh
I am not sure, what am I missing.
If you can (have sufficient rights to) create a file, you do not need to sudo to change its permissions to 0755. Which would also likely prompt you to input your password and run non-interactively could be the reason why the action did not take place.
On the other hand, if the user running this did not have the necessary (write) permission, preceding lines creating the file would not happen either.
You also do not need to touch a file, because that > redirection will create it (always a new one).
You also should not cd somewhere and and continue performing actions without checking directory was changed as expected. But since on all action but the unnecessary touch you use absolute path names, you can just as well leave out both cd lines.
If you clean-up the script and it still does not perform expected action, it might be useful (assuming non-interactive execution) to save its output (redirect both standard > (or 1>) and error (2>) output to a file) and examine it for errors.

Run a command as the standard user, from a sudo elevated script

If a bash script has been executed with sudo, how can a command within the script run as the currently logged in user, instead of root and then revert to root to continue running other commands?
For example: -
#!/usr/bash
touch fileOwnedByRoot.txt
touch fileOwnedByUser.txt
touch otherRootFile.txt
If this script is run with sudo, without changing the order of commands, how can the 2nd touch command be run as the standard user?
The script is only a simple example, so using chmod to change ownership of files created is irrelevant.
The actual script I'm using is being run by an installer, so running with elevated privileges is a requirement, but specific commands must be run as the user running the installer, whose name is not known.
Use su - another_user -c "<command>" to run that specific command:
#!/bin/bash
touch /tmp/f1
su - another_user -c "touch /tmp/f2"
touch /tmp/f3
As commented by chepner below, you need to use $SUDO_USER or $SUDO_UID to get the name of the real user running the sudo command:
su - $SUDO_USER -c "touch /tmp/f2"
This way, the file will be touched by the user running the command.
You can test with:
#!/bin/bash
echo "sudo_user: $SUDO_USER"
echo "sudo_uid: $SUDO_UID"
And run the script either with ./script or sudo ./script. In the second case the values will be populated.
Don't run the script as sudo, just the commands that require elevated privileges.
#!/bin/bash
sudo touch fileOwnedByRoot.txt
touch fileOwnedByUser.txt
sudo touch otherRootFile.txt
According to the man page the environment variable SUDO_USER is set when you run sudo, so you could do something like:
#!/usr/bash
touch fileOwnedByRoot.txt
sudo ${SUDO_USER} touch fileOwnedByUser.txt
touch otherRootFile.txt
I haven't tested this, and don't know if it work differently on OSX, but it's worth a shot.

Remove sudo permissions for one command

this is probably a really simple question. I apologize if it is a duplicate.
I want to know how to remove sudo permissions for one particular command. I've created a script that installs a bunch of .deb packages and it needs sudo to do that, but one command in it needs to run without sudo permissions, so how would I do that? I'm using Ubuntu and this is a bash script.
I'm calling my script: ROS_install
Here is part of the script:
sudo dpkg -i /home/forklift/Desktop/ROS/ros-hydro-laser-proc_0.1.3-0precise-20131015-2054-+0000_amd64.deb
sudo dpkg -i /home/forklift/Desktop/ROS/ros-hydro-urg-c_1.0.403-0precise-20131010-0128-+0000_amd64.deb
sudo rosdep init
sleep 2
rosdep update
The command "rosdep update" needs to be run without sudo permissions. I assumed that it was already, but I get a warning every time I run the script, and thus get locked out of the command after installation.
Rather than give the entire script elevated privileges, just give them to the actual commands that need them. That is, rather than
$ sudo my_script
modify my_script to use sudo only on those commands that need it. For instance, if this is your script:
command1
command2
command3
command4
command5
and command3 is the non-sudo command, modify your script to read
sudo command1
sudo command2
command3
sudo command4
sudo command5
In the process, think about whether command1 actually needs to run with sudo, or it it can run just as well without. In that way, you should be able to greatly reduce the number of commands that actually need to be run with sudo in your script.
If your command is running with full privileges, it also has the privilege to demote its own privileges, for good or for the duration of one command, by running su.
touch /privileged
su -c 'cp /privileged /tmp/not' nobody
I assume you are calling your script like:
sudo script.sh
And you do not want all of the commands within the script to run as root.
If your script is like:
apt-get install perl
apt-get install python
mv trash /home/user/
And you only want to run the first two commands as root you can specify a specific user for the third like:
su -c "mv trash /home/user/" user
Where user is the username you want to run the command as.
This will allow you to make a single sudo call at the parent level when you call the script.
If you don't want the username hardcoded, you can use a command like logname to get the username of the user that you are logged in as.
Just adding to the other answers, you can do this:
su -c "command" $SUDO_USER
Which will execute the command as the actual user who typed the sudo command
That's very useful when you are making scripts that require sudo to install something and write something in the user's $HOME

Changing to root user inside shell script

I have a shell script which needs non-root user account to run certain commands and then change the user to root to run the rest of the script. I am using SUSE11.
I have used expect to automate the password prompt. But when I use
spawn su -
and the command gets executed, the prompt comes back with root and the rest of the script does not execute.
Eg.
< non-root commands>
spawn su -
<root commands>
But after su - the prompt returns back with user as root.
How to execute the remaining of the script.
The sudo -S option does not help as it does not run sudo -S ifconfig command which I need to find the IP address of the machine.
I have already gone through these links but could not find a solution:
Change script directory to user's homedir in a shell script
Changing unix user in a shell script
sudo will work here but you need to change your script a little bit:
$ cat 1.sh
id
sudo -s <<EOF
echo Now i am root
id
echo "yes!"
EOF
$ bash 1.sh
uid=1000(igor) gid=1000(igor) groups=1000(igor),29(audio),44(video),124(fuse)
Now i am root
uid=0(root) gid=0(root) groups=0(root)
yes!
You need to run your command in <<EOF block and give the block to sudo.
If you want, you can use su, of course. But you need to run it using expect/pexpect that will enter password for you.
But even in case you could manage to enter the password automatically (or switch it off) this construction would not work:
user-command
su
root-command
In this case root-command will be executed with user, not with root privileges, because it will be executed after su will be finished (su opens a new shell, not changes uid of the current shell). You can use the same trick here of course:
su -c 'sh -s' <<EOF
# list of root commands
EOF
But now you have the same as with sudo.
There is an easy way to do it without a second script. Just put this at the start of your file:
if [ "$(whoami)" != "root" ]
then
sudo su -s "$0"
exit
fi
Then it will automatically run itself as root. Of course, this assumes that you can sudo su without having to provide a password - but that's out of scope of this answer; see one of the other questions about using sudo in shell scripts for how to do that.
Short version: create a block to enclose all commands to be run as root.
For example, I created a script to run a command from a root subdirectory, the segment goes like this:
sudo su - <<EOF
cd rootSubFolder/subfolder
./commandtoRun
EOF
Also, note that if you are changing to "root" user inside a shell script like below one, few Linux utilities like awk for data extraction or defining even a simple shell variable etc will behave weirdly.
To resolve this simply quote the whole document by using <<'EOF' in place of EOF.
sudo -i <<'EOF'
ls
echo "I am root now"
EOF
The easiest way to do that would be to create a least two scripts.
The first one should call the second one with root privileges. So every command you execute in the second script would be executed as root.
For example:
runasroot.sh
sudo su-c'./scriptname.sh'
scriptname.sh
apt-get install mysql-server-5.5
or whatever you need.

Resources