su commands in a script executed as root seem inconsistent - linux

I'm trying to understand how to run commands from my user account in a script with root privileges. I've got this test script and the output is confusing me.
~$ cat test.sh
output:
#!/usr/bin/bash
su -c "whoami" user
su -c "echo $HOME" user
~$ sudo ./test.sh
output:
user
/root
Why does the first 'su' command seem to run as 'user' but the second seems to run as 'root'?

Double quotes expand shell variables. Try
echo su -c "echo $HOME" user
to see what I mean. It's the shell running the script that expands $HOME, which runs as root (from sudo ./test.sh). So what ends up being run is su -c 'echo /root' user.
You want
su -c 'echo $HOME' user
Here we pass echo $HOME unexpanded to su -c.

Related

Unix: 'su user' not working and remains root inside SSH if condition [duplicate]

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.

Stop being root in the middle of a script that was run with sudo

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

Multiple commands in sudo over ssh in shell script

My script is as below.
#!/bin/bash
version = 1.1
echo "Enter username"
read UserName
ssh -t $UserName#server bash -c " '
./runSomeScript
echo "Entering Sudo"
sudo -s -u user1 -c "cd random; ./randomscrip xx-$version-yy"
'"
But this is not working.
Basically i want to do a ssh to a account. And then runSomeScript
Then do a sudo with user as user1 and then run commands cd random and ./randomscrip (with xx-Version-yy as argument) as the sudo user only.
But the commands inside sudo are not working.
Your quoting is a little careless. You're using double-quotes for the first and third levels of quoting, and the shell can't tell one from the other. Do something like this instead:
sudoScript="cd random; ./randomscrip xx-${version}-yy"
sshScript='
./runSomeScript
echo "Entering Sudo"
sudo -s -u user1 bash -c '"'${sudoScript}'"'
'
ssh -t ${UserName}#server "${sshScript}"
But beware that if you embed any single-quotes, it will still go wrong unless you add a layer of shell-quoting.
Finally, remove the spaces around = when you assign to version.

change user in linux script

User x run a script. Now I want to change the user in the script to User y.
#!/bin/sh
whoami
echo password | su y
whoami
But I get this:
x
su: must be run from a terminal
x
Thanks for your help.
This is working for me inside a bash script:
whoami;
sudo su $user << BASH
whoami;
BASH
Su cannot be ran in a Bash script. You can use sudo -u <user> <command> && however.
you can do:
su - $USER -l -m -c $CMD
-l provide an environment similar to the login env
-m preserves the current environment
-c runs the command
e.g. I use this to run nohup commands also
su - $USER -l -m -c "nohup $RUN_CMD > "$LOG" 2>&1 >> /dev/null&"

Bash: executing commands from within a chroot and switch user

Im writing a script that should do this...
chroot /chroot_dir/ su -
./startup.sh (This should run within the su environment)
I have tried this approach:
chroot /chroot_dir /bin/bash -c " su -; ./startup.sh"
This tries to execute the user switching and the script as a string command to bash...however what it does, is it "stops" after
"su -" and doesnt execute the script.
However, once I leave the "su -" environment, it does try to run startup.sh but of course, it cant find it.
Basically I need to nest the "startup.sh" to be run inside the "su -" environment...
try
chroot /chroot_dir /bin/bash -c "su - -c ./startup.sh"
chroot /chroot_dir /bin/bash -x <<'EOF'
su -
./startup.sh
EOF
basic option:
cat << EOF | chroot /chroot_dir
touch aaaaa
touch bbbbb
EOF
option with different shell (eg. if using bash but in chrooted enviroment it doesn't exists)
cat << EOF | chroot /chroot_dir /bin/sh
touch aaaaa
touch bbbbb
EOF

Resources