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

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.

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.

Providing password using a variable to become a sudo user in Jenkins

I have a jenkins job, which has its own set of build servers. The process which i follow is building applications on the jenkins build server and then I use "send files or execute commands over ssh" to copy my build and deploy the same using a shell script.
As a part of the deployment commands, I have quite a few steps to be done, like mkdir, tar -xzvf etc.I want to execute these deployment steps with a specific user "K". But when i type the sudo su - k command, the jenkins job fails because i am unable to feed the password to it.
#!/bin/bash
sudo su - K << \EOF
cd /DIR1/DIR2;
cp ~/MY_APP.war .
mkdir DIR 3
tar -xzvf MY_APP.war
EOF
To handle that, I used a PASSWORD parameter and made the build as parameterized, so that i can use the same PASSWORD in the shell script.
I have tried to use Expect, but looks like commands like cd, tar -xzvf are not working inside it and even if they work they will not be executed with the K as a user since the terminal may expire(please correct if wrong).
export $PASSWORD
/usr/bin/expect << EOD
spawn sudo su - k
expect "password for K"
send -- "$PASSWORD"
cd /DIR1/DIR2;
cp ~/MY_APP.war .
mkdir DIR 3
tar -xzvf MY_APP.war
EOD
Note: I do not have the root access to the servers and hence cannot tweak the host key files. Is there a work around for this problem?
Even if you get it working, having passwords in scripts or on the command line probably is not ideal from a security standpoint. Two things I would suggest :
1) Use a public SSH key owned by the user on your initiating system as an authorized key on the remote system to allow logging as the intended user on the remote system without a password. You should have all you need to do that (no root access required, only to the users you already use on each system).
2) Set-up the "sudoers" file on the remote system so that the user you log in as is allowed to perform the commands you need as the required user. You would need the system administrator help for that.
Like so:
SUDO_PASSWORD=TheSudoPassword
...
ssh kilroy#somehost "echo $SUDO_PASSWORD | sudo -S some_root_command"
Later
How can i use this in the 1st snippet?
Write a file:
deploy.sh
#!/bin/sh
cd /DIR1/DIR2
cp ~/MY_APP.war .
mkdir DIR 3
tar -xzvf MY_APP.war
Then:
chmod +x deploy.sh
scp deploy.sh kilroy#somehost:~
ssh kilroy#somehost "echo $SUDO_PASSWORD | sudo -S ./deploy.sh"

Moving files owned by a different user with Sudo and wildcard

I have a user named cam. Cam stores a bunch of files. Now I want to move those files so I tried the following...
sudo mv /home/cam/DCS-*.jpg /home/cam/cam/
But when I run this command I get...
mv: cannot stat ‘/home/cam/DCS-*.jpg’: No such file or directory
But if I runt the command like...
sudo mv /home/cam/DCS-934L2015110711425501.jpg /home/cam/cam/
It works fine. WTF am I missing
if I do a sudo ls /home/cam I see everything but without sudo I don't have permissions to see anything.
When this command is executed:
sudo mv /home/cam/DCS-*.jpg /home/cam/cam/
The * is expanded by the shell according to the permissions of the current user. As the current user cannot see those files (ls /home/cam has no permission), the shell cannot expand the parameter list.
shouldn't sudo have permissions regardless?
No. With sudo, the mv command will be executed as root, but the parameter list expansion happens before execution is passed to sudo mv.
To have the * expansion happen with root permission (so that the content of the directory will be visible), you can wrap the command in its own shell like this:
sudo sh -c 'mv /home/cam/DCS-*.jpg /home/cam/cam/'

Use sudo to change file in root directory [duplicate]

This question already has answers here:
How do I use sudo to redirect output to a location I don't have permission to write to? [closed]
(15 answers)
Closed 6 months ago.
I'm trying to write a script to configure resolv.conf and /etc/network/interfaces automatically. I'm running the commands as "sudo", but I'm getting "Permission denied" errors.
sudo apt-get --assume-yes install vsftpd
sudo "nameserver 8.8.8.8" >> /etc/resolv.conf
sudo python setinterfaces.py
sudo chattr +i /etc/network/interfaces
sudo apt-get --assume-yes install lamp-server^
Lines 2 and 3 get permission denied errors, but lines 1 and 5 did run. setinterfaces.py is supposed to overwrite /etc/network/interfaces'.setinterfaces.pyworks when pointed at the home folder but not theinterfaces` file.
Any idea? Do I have to be changing ownership? Ideally I'd like this to be a one command script, where I can just call it and it will run. I'm writing this script for people who are not experienced in *nix.
The sudo command executes the command you give it under the root account. In its simplest form, the syntax is:
sudo command args...
For example:
sudo whoami
prints root.
If you type, as you did in your question:
sudo "nameserver 8.8.8.8" >> /etc/resolv.conf
then it's not going to work; it will try to execute a command named "nameserver 8.8.8.8", which doesn't exist. The problem there is that you're missing the echo command.
This:
sudo "echo nameserver 8.8.8.8" >> /etc/resolv.conf
still won't work because there's no command called "echo nameserver 8.8.8.8". That entire string is passed to sudo as a single argument. It needs to see the command and each of its arguments as a separate argument.
So this:
sudo echo nameserver 8.8.8.8 >> /etc/resolv.conf
is getting closer -- but it still won't work. It executes the echo command as root -- but echo requires no special privileges, so there's no point in executing it as root. The >> /etc/resolv.conf redirection is executed by your shell, which is running as you, not as root. Since you don't have permission to write to /etc/resolv.conf, the command fails. The sudo command never sees the redirection.
You need the redirection to be executed under the root account, which means that you need a shell process running as root. So the solution is:
sudo sh -c 'echo nameserver 8.8.8.8 >> /etc/resolv.conf'
This launches a shell as a root process. That shell executes the command line echo nameserver 8.8.8.8 >> /etc/resolv.conf. Since you have a root shell executing both the echo and the output redirection, it should work.
(I suggest grabbing a copy of your /etc/resolv.conf file before doing this, just to make sure you can recover if you accidentally clobber it.)
Second line would be like this,
sudo sh -c "echo 'nameserver 8.8.8.8' >> /etc/resolv.conf"

Applying sudo to some commands in script

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.

Resources