Shell script user switch - linux

I am running a simple shell script which creates a user and then switches to it so that I can run a bunch of commands as the new user. The script below is ran as the root on a Debian 9 (Stretch) amd64 host and is not showing what I would expect. This is just a test script for me to see what's going on.
#!/bin/sh
adduser karl --gecos "First Last, RoomNumber, WorkPhone, HomePhone" --disabled-password
adduser karl sudo
echo 'karl:password123' | chpasswd
echo 'karl ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/karl
echo
sudo su - karl
whoami # prints root?
echo
echo
sudo -u karl /usr/bin/whoami # prints karl
echo
exit 0

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.

Provide password for running a script inside another script as different user

Imagine you run script as user A: sudo -u A ./script.sh
Inside that script.sh we have a line that calls another script script2.sh with a different user B: sudo -u B ./script2.sh. Now I get prompted to enter a password for user B. Is there any way to provide that password uppon call?
P.S. I know all the security breaches it can create. Please do not mention me that.
Yes you have option for that. But that password you have to provide at the time of executing the script or hard coded it in the script itself. Try with the below example:-
echo 'passwordofB' | sudo -u B -S ./script2.sh
Also you can do it like:-
sudo -u A ./script.sh passwordofB #as a command line parameter
now inside script.sh:-
echo $1 | sudo -u B -S ./script2.sh
You are executing another script sudo -u B ./script2.sh from script ./script.sh right? So change that line with echo $1 | sudo -u B -S ./script2.sh and run your first script as sudo -u A ./script.sh passwordofB where passwordofB is the password for user 'B'

correct way to rename user and remove password with ec2 user-data

I have a centos7 base ami and have successfully changed the user name using the ec2-launch user data modified from an amazon-linux script
#!/bin/bash
groupadd ec2-user
usermod -d /home/ec2-user -m -g ec2-user -l ec2-user centos
echo "" | sudo tee -a /etc/sudoers
echo "Defaults:root !requiretty" | sudo tee -a /etc/sudoers
echo "ec2-user ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers
echo "Defaults:ec2-user !requiretty" | sudo tee -a /etc/sudoers
log in works as expected and home directory has been changed, however when I use sudo it still asks for a password. As I cannot get into the file to check format I wonder if I am using the correct syntax?
How do change the user and remove the sudo password requirement in a single script?
I believe your Cloudinit userdata script is failing because it's attempting to use sudo without a tty (and the !requiretty hasn't been added yet). Since that script runs as root anyways, this should work:
#!/bin/bash
groupadd ec2-user
usermod -d /home/ec2-user -m -g ec2-user -l ec2-user centos
echo "" | tee -a /etc/sudoers
echo "Defaults:root !requiretty" | tee -a /etc/sudoers
echo "ec2-user ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers
echo "Defaults:ec2-user !requiretty" | tee -a /etc/sudoers

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

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&"

Resources