I'm working on a script that will shred a usb drive and install Kali linux with encrypted persistent data.
#! /bin/bash
cd ~/Documents/Other/ISOs/Kali
echo "/dev/sdx x=?"
read x
echo "how many passes to wipe? 1 will be sufficient."
read n
echo "sd$x will be wiped $n times."
read -p "do you want to continue? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
exit 1
fi
echo "Your role in the installation process is not over. You will be prompted to type YES and a passphrase."
sudo shred -vz --iterations=$n /dev/sd$x
echo "Wiped. Installing Kali"
sudo dd if=kali-linux-2.0-amd64.iso of=/dev/sd$x bs=512k
echo "Installed. Making persistence."
y=3
sudo parted /dev/sd$x mkpart primary 3.5GiB 100%
x=$x$y
sudo cryptsetup --verbose --verify-passphrase luksFormat /dev/sd$x
sudo cryptsetup luksOpen /dev/sd$x my_usb
sudo mkfs.ext3 -L persistence /dev/mapper/my_usb
sudo e2label /dev/mapper/my_usb persistence
sudo mkdir -p /mnt/my_usb
sudo mount /dev/mapper/my_usb /mnt/my_usb
sudo -i
echo "/ union" > /mnt/my_usb/persistence.conf
umount /dev/mapper/my_usb
cryptsetup luksClose /dev/mapper/my_usb
echo "Persistence complete. Installation complete."
It works nearly perfectly. These commands individually entered into the terminal will create the desired effect, but the problem comes in at line 37:
sudo echo "/ union" > /mnt/my_usb/persistence.conf
That command won't work unless I'm logged in as root user. To solve this I tried adding the sudo -i command before, but once I do that all of the following commands are skipped.
It's okay if the solution suggested requires me to type in the password. I don't want the password stored in the script, that's just wreckless.
Side note, I didn't make a generic form for this question because I want other people to be able use this if they like it.
The problem is that the echo runs with root privilege but the redirection happens in the original shell as the non-root user. Instead, try running an explicit sh under sudo and do the redirection in there
sudo /bin/sh -c 'echo "/ union" > /mnt/my_usb/persistence.conf'
The problem is that when you type in the following command:
sudo echo "/ union" > /mnt/my_usb/persistence.conf
Only the "echo" will be run as root through sudo, but the redirection to the file using > will still be executed as the "normal" user, because it is not a command but something performed directly by the shell.
My usual solution is to use teeso that it runs as a command and not as a shell built-in operation, like this:
echo "/ union" | sudo tee /mnt/my_usb/persistence.conf >/dev/null
Now the tee command will be run as root through sudo and will be allowed to write to the file. >/dev/null is just added to keep the output of the script clean. If you ever want to append instead of overwrite (e.g. you would be using >>normally), then use tee -a.
Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 1 year ago.
The community reviewed whether to reopen this question 3 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I've been given sudo access on one of our development RedHat linux boxes, and I seem to find myself quite often needing to redirect output to a location I don't normally have write access to.
The trouble is, this contrived example doesn't work:
sudo ls -hal /root/ > /root/test.out
I just receive the response:
-bash: /root/test.out: Permission denied
How can I get this to work?
Your command does not work because the redirection is performed by your shell which does not have the permission to write to /root/test.out. The redirection of the output is not performed by sudo.
There are multiple solutions:
Run a shell with sudo and give the command to it by using the -c option:
sudo sh -c 'ls -hal /root/ > /root/test.out'
Create a script with your commands and run that script with sudo:
#!/bin/sh
ls -hal /root/ > /root/test.out
Run sudo ls.sh. See Steve Bennett's answer if you don't want to create a temporary file.
Launch a shell with sudo -s then run your commands:
[nobody#so]$ sudo -s
[root#so]# ls -hal /root/ > /root/test.out
[root#so]# ^D
[nobody#so]$
Use sudo tee (if you have to escape a lot when using the -c option):
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
The redirect to /dev/null is needed to stop tee from outputting to the screen. To append instead of overwriting the output file
(>>), use tee -a or tee --append (the last one is specific to GNU coreutils).
Thanks go to Jd, Adam J. Forster and Johnathan for the second, third and fourth solutions.
Someone here has just suggested sudoing tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
This could also be used to redirect any command, to a directory that you do not have access to. It works because the tee program is effectively an "echo to a file" program, and the redirect to /dev/null is to stop it also outputting to the screen to keep it the same as the original contrived example above.
A trick I figured out myself was
sudo ls -hal /root/ | sudo dd of=/root/test.out
The problem is that the command gets run under sudo, but the redirection gets run under your user. This is done by the shell and there is very little you can do about it.
sudo command > /some/file.log
`-----v-----'`-------v-------'
command redirection
The usual ways of bypassing this are:
Wrap the commands in a script which you call under sudo.
If the commands and/or log file changes, you can make the
script take these as arguments. For example:
sudo log_script command /log/file.txt
Call a shell and pass the command line as a parameter with -c
This is especially useful for one off compound commands.
For example:
sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
Arrange a pipe/subshell with required rights (i.e. sudo)
# Read and append to a file
cat ./'file1.txt' | sudo tee -a '/log/file.txt' > '/dev/null';
# Store both stdout and stderr streams in a file
{ command1 arg; command2 arg; } |& sudo tee -a '/log/file.txt' > '/dev/null';
Yet another variation on the theme:
sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF
Or of course:
echo 'ls -hal /root/ > /root/test.out' | sudo bash
They have the (tiny) advantage that you don't need to remember any arguments to sudo or sh/bash
Clarifying a bit on why the tee option is preferable
Assuming you have appropriate permission to execute the command that creates the output, if you pipe the output of your command to tee, you only need to elevate tee's privledges with sudo and direct tee to write (or append) to the file in question.
in the example given in the question that would mean:
ls -hal /root/ | sudo tee /root/test.out
for a couple more practical examples:
# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts
# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4
In each of these examples you are taking the output of a non-privileged command and writing to a file that is usually only writable by root, which is the origin of your question.
It is a good idea to do it this way because the command that generates the output is not executed with elevated privileges. It doesn't seem to matter here with echo but when the source command is a script that you don't completely trust, it is crucial.
Note you can use the -a option to tee to append append (like >>) to the target file rather than overwrite it (like >).
Make sudo run a shell, like this:
sudo sh -c "echo foo > ~root/out"
The way I would go about this issue is:
If you need to write/replace the file:
echo "some text" | sudo tee /path/to/file
If you need to append to the file:
echo "some text" | sudo tee -a /path/to/file
Don't mean to beat a dead horse, but there are too many answers here that use tee, which means you have to redirect stdout to /dev/null unless you want to see a copy on the screen.
A simpler solution is to just use cat like this:
sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"
Notice how the redirection is put inside quotes so that it is evaluated by a shell started by sudo instead of the one running it.
How about writing a script?
Filename: myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
Then use sudo to run the script:
sudo ./myscript
Whenever I have to do something like this I just become root:
# sudo -s
# ls -hal /root/ > /root/test.out
# exit
It's probably not the best way, but it works.
I would do it this way:
sudo su -c 'ls -hal /root/ > /root/test.out'
This is based on the answer involving tee. To make things easier I wrote a small script (I call it suwrite) and put it in /usr/local/bin/ with +x permission:
#! /bin/sh
if [ $# = 0 ] ; then
echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
exit 1
fi
for arg in "$#" ; do
if [ ${arg#/dev/} != ${arg} ] ; then
echo "Found dangerous argument ‘$arg’. Will exit."
exit 2
fi
done
sudo tee "$#" > /dev/null
As shown in the USAGE in the code, all you have to do is to pipe the output to this script followed by the desired superuser-accessible filename and it will automatically prompt you for your password if needed (since it includes sudo).
echo test | suwrite /root/test.txt
Note that since this is a simple wrapper for tee, it will also accept tee's -a option to append, and also supports writing to multiple files at the same time.
echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt
It also has some simplistic protection against writing to /dev/ devices which was a concern mentioned in one of the comments on this page.
sudo at now
at> echo test > /tmp/test.out
at> <EOT>
job 1 at Thu Sep 21 10:49:00 2017
Maybe you been given sudo access to only some programs/paths? Then there is no way to do what you want. (unless you will hack it somehow)
If it is not the case then maybe you can write bash script:
cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out
Press ctrl + d :
chmod a+x myscript.sh
sudo myscript.sh
Hope it help.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 1 year ago.
The community reviewed whether to reopen this question 3 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I've been given sudo access on one of our development RedHat linux boxes, and I seem to find myself quite often needing to redirect output to a location I don't normally have write access to.
The trouble is, this contrived example doesn't work:
sudo ls -hal /root/ > /root/test.out
I just receive the response:
-bash: /root/test.out: Permission denied
How can I get this to work?
Your command does not work because the redirection is performed by your shell which does not have the permission to write to /root/test.out. The redirection of the output is not performed by sudo.
There are multiple solutions:
Run a shell with sudo and give the command to it by using the -c option:
sudo sh -c 'ls -hal /root/ > /root/test.out'
Create a script with your commands and run that script with sudo:
#!/bin/sh
ls -hal /root/ > /root/test.out
Run sudo ls.sh. See Steve Bennett's answer if you don't want to create a temporary file.
Launch a shell with sudo -s then run your commands:
[nobody#so]$ sudo -s
[root#so]# ls -hal /root/ > /root/test.out
[root#so]# ^D
[nobody#so]$
Use sudo tee (if you have to escape a lot when using the -c option):
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
The redirect to /dev/null is needed to stop tee from outputting to the screen. To append instead of overwriting the output file
(>>), use tee -a or tee --append (the last one is specific to GNU coreutils).
Thanks go to Jd, Adam J. Forster and Johnathan for the second, third and fourth solutions.
Someone here has just suggested sudoing tee:
sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
This could also be used to redirect any command, to a directory that you do not have access to. It works because the tee program is effectively an "echo to a file" program, and the redirect to /dev/null is to stop it also outputting to the screen to keep it the same as the original contrived example above.
A trick I figured out myself was
sudo ls -hal /root/ | sudo dd of=/root/test.out
The problem is that the command gets run under sudo, but the redirection gets run under your user. This is done by the shell and there is very little you can do about it.
sudo command > /some/file.log
`-----v-----'`-------v-------'
command redirection
The usual ways of bypassing this are:
Wrap the commands in a script which you call under sudo.
If the commands and/or log file changes, you can make the
script take these as arguments. For example:
sudo log_script command /log/file.txt
Call a shell and pass the command line as a parameter with -c
This is especially useful for one off compound commands.
For example:
sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
Arrange a pipe/subshell with required rights (i.e. sudo)
# Read and append to a file
cat ./'file1.txt' | sudo tee -a '/log/file.txt' > '/dev/null';
# Store both stdout and stderr streams in a file
{ command1 arg; command2 arg; } |& sudo tee -a '/log/file.txt' > '/dev/null';
Yet another variation on the theme:
sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF
Or of course:
echo 'ls -hal /root/ > /root/test.out' | sudo bash
They have the (tiny) advantage that you don't need to remember any arguments to sudo or sh/bash
Clarifying a bit on why the tee option is preferable
Assuming you have appropriate permission to execute the command that creates the output, if you pipe the output of your command to tee, you only need to elevate tee's privledges with sudo and direct tee to write (or append) to the file in question.
in the example given in the question that would mean:
ls -hal /root/ | sudo tee /root/test.out
for a couple more practical examples:
# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts
# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4
In each of these examples you are taking the output of a non-privileged command and writing to a file that is usually only writable by root, which is the origin of your question.
It is a good idea to do it this way because the command that generates the output is not executed with elevated privileges. It doesn't seem to matter here with echo but when the source command is a script that you don't completely trust, it is crucial.
Note you can use the -a option to tee to append append (like >>) to the target file rather than overwrite it (like >).
Make sudo run a shell, like this:
sudo sh -c "echo foo > ~root/out"
The way I would go about this issue is:
If you need to write/replace the file:
echo "some text" | sudo tee /path/to/file
If you need to append to the file:
echo "some text" | sudo tee -a /path/to/file
Don't mean to beat a dead horse, but there are too many answers here that use tee, which means you have to redirect stdout to /dev/null unless you want to see a copy on the screen.
A simpler solution is to just use cat like this:
sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"
Notice how the redirection is put inside quotes so that it is evaluated by a shell started by sudo instead of the one running it.
How about writing a script?
Filename: myscript
#!/bin/sh
/bin/ls -lah /root > /root/test.out
# end script
Then use sudo to run the script:
sudo ./myscript
Whenever I have to do something like this I just become root:
# sudo -s
# ls -hal /root/ > /root/test.out
# exit
It's probably not the best way, but it works.
I would do it this way:
sudo su -c 'ls -hal /root/ > /root/test.out'
This is based on the answer involving tee. To make things easier I wrote a small script (I call it suwrite) and put it in /usr/local/bin/ with +x permission:
#! /bin/sh
if [ $# = 0 ] ; then
echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
exit 1
fi
for arg in "$#" ; do
if [ ${arg#/dev/} != ${arg} ] ; then
echo "Found dangerous argument ‘$arg’. Will exit."
exit 2
fi
done
sudo tee "$#" > /dev/null
As shown in the USAGE in the code, all you have to do is to pipe the output to this script followed by the desired superuser-accessible filename and it will automatically prompt you for your password if needed (since it includes sudo).
echo test | suwrite /root/test.txt
Note that since this is a simple wrapper for tee, it will also accept tee's -a option to append, and also supports writing to multiple files at the same time.
echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt
It also has some simplistic protection against writing to /dev/ devices which was a concern mentioned in one of the comments on this page.
sudo at now
at> echo test > /tmp/test.out
at> <EOT>
job 1 at Thu Sep 21 10:49:00 2017
Maybe you been given sudo access to only some programs/paths? Then there is no way to do what you want. (unless you will hack it somehow)
If it is not the case then maybe you can write bash script:
cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out
Press ctrl + d :
chmod a+x myscript.sh
sudo myscript.sh
Hope it help.
I've written a script that takes, as an argument, a string that is a concatenation of a username and a project. The script is supposed to switch (su) to the username, cd to a specific directory based upon the project string.
I basically want to do:
su $USERNAME;
cd /home/$USERNAME/$PROJECT;
svn update;
The problem is that once I do an su... it just waits there. Which makes sense since the flow of execution has passed to switching to the user. Once I exit, then the rest of the things execute but it doesn't work as desired.
I prepended su to the svn command but the command failed (i.e. it didn't update svn in the directory desired).
How do I write a script that allows the user to switch user and invoke svn (among other things)?
Much simpler: use sudo to run a shell and use a heredoc to feed it commands.
#!/usr/bin/env bash
whoami
sudo -i -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami
(answer originally on SuperUser)
The trick is to use "sudo" command instead of "su"
You may need to add this
username1 ALL=(username2) NOPASSWD: /path/to/svn
to your /etc/sudoers file
and change your script to:
sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update"
Where username2 is the user you want to run the SVN command as and username1 is the user running the script.
If you need multiple users to run this script, use a %groupname instead of the username1
You need to execute all the different-user commands as their own script. If it's just one, or a few commands, then inline should work. If it's lots of commands then it's probably best to move them to their own file.
su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME"
Here is yet another approach, which was more convenient in my case (I just wanted to drop root privileges and do the rest of my script from restricted user): you can make the script restart itself from the correct user. This approach is more readable than using sudo or su -c with a "nested script". Let's suppose it is started as root initially. Then the code will look like this:
#!/bin/bash
if [ $UID -eq 0 ]; then
user=$1
dir=$2
shift 2 # if you need some other parameters
cd "$dir"
exec su "$user" "$0" -- "$#"
# nothing will be executed beyond that line,
# because exec replaces running process with the new one
fi
echo "This will be run from user $UID"
...
Use a script like the following to execute the rest or part of the script under another user:
#!/bin/sh
id
exec sudo -u transmission /bin/sh - << eof
id
eof
Use sudo instead
EDIT: As Douglas pointed out, you can not use cd in sudo since it is not an external command. You have to run the commands in a subshell to make the cd work.
sudo -u $USERNAME -H sh -c "cd ~/$PROJECT; svn update"
sudo -u $USERNAME -H cd ~/$PROJECT
sudo -u $USERNAME svn update
You may be asked to input that user's password, but only once.
It's not possible to change user within a shell script. Workarounds using sudo described in other answers are probably your best bet.
If you're mad enough to run perl scripts as root, you can do this with the $< $( $> $) variables which hold real/effective uid/gid, e.g.:
#!/usr/bin/perl -w
$user = shift;
if (!$<) {
$> = getpwnam $user;
$) = getgrnam $user;
} else {
die 'must be root to change uid';
}
system('whoami');
This worked for me
I split out my "provisioning" from my "startup".
# Configure everything else ready to run
config.vm.provision :shell, path: "provision.sh"
config.vm.provision :shell, path: "start_env.sh", run: "always"
then in my start_env.sh
#!/usr/bin/env bash
echo "Starting Server Env"
#java -jar /usr/lib/node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-2.40.0.jar &
#(cd /vagrant_projects/myproj && sudo -u vagrant -H sh -c "nohup npm install 0<&- &>/dev/null &;bower install 0<&- &>/dev/null &")
cd /vagrant_projects/myproj
nohup grunt connect:server:keepalive 0<&- &>/dev/null &
nohup apimocker -c /vagrant_projects/myproj/mock_api_data/config.json 0<&- &>/dev/null &
Inspired by the idea from #MarSoft but I changed the lines like the following:
USERNAME='desireduser'
COMMAND=$0
COMMANDARGS="$(printf " %q" "${#}")"
if [ $(whoami) != "$USERNAME" ]; then
exec sudo -E su $USERNAME -c "/usr/bin/bash -l $COMMAND $COMMANDARGS"
exit
fi
I have used sudo to allow a password less execution of the script. If you want to enter a password for the user, remove the sudo. If you do not need the environment variables, remove -E from sudo.
The /usr/bin/bash -l ensures, that the profile.d scripts are executed for an initialized environment.
I have a bash script that makes a backup of my data files (~50GB). The script is basically something like this:
sudo tar /backup/mydata1 into old-backup-1.tar
sudo tar /backup/mydata2 into old-backup-2.tar
sudo rsync /mydata1 to /backup/mydata1
sudo rsync /mydata2 to /backup/mydata2
(I use sudo because some of the files are owned by root).
The problem is that after every command (because it takes a long time) I loose root privileges and if I'm not present at the computer then the su prompt gets timed out and the script ends in the middle of the job.
Is there a way to retain su privileges during the entire script? What is the best way to approach this situation? I prefer to run the script under my user.
With a second shell:
sudo bash -c "command1; command2; command3; command4"
Perhaps like this:
#!/bin/bash -eu
exec sudo /bin/bash <<'EOF'
echo I am $UID
whoami
#^the script
EOF
Alternatively, you could put something like:
if ! [ $(id -u) -eq 0 ]; then
exec sudo "$0" "$#"
fi
at the top.
There is a list of commands that only succeed when they are prefaced with sudo.
There is another list of commands that only succeed when the user runs them without sudo.
I want to execute all of these commands from the same script.
I'd like to avoid having to do the following:
#!/usr/bin/env bash
sudo sudo_command_one;
sudo sudo_command_two;
sudo sudo_command_three;
non_sudo_command;
sudo sudo_command_four;
The reason for this, is because sudo has a time-out, and these commands will likely take a long time. I don't want to be burdened with having to re-type the sudo password occasionally. I could perhaps extend the time-out of sudo indefinitely, but that is also something I would prefer to avoid if there is an easier way.
Therefore, I'm going to run the script like this:
sudo ./script
But this will prevent the non-sudo commands from working.
What are the missing commands I need:
#!/usr/bin/env bash
sudo_command_one;
sudo_command_two;
sudo_command_three;
[turn sudo off for a moment]
non_sudo_command;
[ok, turn sudo back on]
sudo_command_four;
Unfortunately, the order of the commands cannot be rearranged so that I run all the sudo commands first, followed by all the non-sudo commands(or vice versa).
In a script run by sudo, use:
su -c "shell command; shell command" $SUDO_USER
within that script to execute commands as the normal user who invoked sudo.
This works because sudo sets the environment variable SUDO_USER to the original username.
If you have a bunch of commands to run as the original user, you could use a hereis document.
Here is an example script file as proof of concept:
myscript.sh
#!/bin/bash
echo "Part 1"
echo "now running as:"
whoami
echo "SUDO_USER is:"
echo $SUDO_USER
su $SUDO_USER <<EOF
echo "Part 2"
echo "now running as:"
whoami
echo "SUDO_USER is:"
env | grep ^SUDO_USER
sleep 5
EOF
echo "Part 3"
echo "now running as:"
whoami
echo "SUDO_USER is:"
echo $SUDO_USER
And here's the output on sudo ./myscript.sh
Part 1
now running as:
root
SUDO_USER is:
paul
Part 2
now running as:
paul
SUDO_USER is:
SUDO_USER=paul
Part 3
now running as:
root
SUDO_USER is:
paul
Warning: This technique doesn't work so well with nested sudo. If sudo is nested twice, e.g.
sudo su
echo $SUDO_USER
---> me
sudo su
echo $SUDO_USER
---> root
SUDO_USER will return root, not the original username. su $SUDO_USER would then keep running as root. Be careful to avoid that scenario, and it should work ok.
Here is how I would run it in a script.
#! /bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root";
exit 1;
else
NON_ROOT_USER=$(who am i | awk '{print $1}');
echo "root ran this echo.";
sudo -u $NON_ROOT_USER echo "$NON_ROOT_USER ran this echo.";
fi
sudo ./script.sh