Use source with script that contains sudo command - linux

I have a script that copies files between servers. I am using the lsof command to make sure that the file is not being written to before being moved. The user running the script and the user writing to the file are different, so I need to sudo to the file owner. Here is the relevant line in the sudoers file :
userA ALL=(userB:userB) NOPASSWD: ALL
In the main script (ran as userA), I have tried calling sudo then the subscript containing the lsof command:
sudo su - userB -c 'source ./getOpenFiles.sh'
getOpenFiles.sh has this one line:
#!/bin/bash
lsofResult=$(/usr/sbin/lsof "${sourcePath}")
I have also tried calling the subscript:
source ./getOpenFiles.sh
Then have the first line of the subscript be the sudo:
#!/bin/bash
sudo su - banjobs
lsofResult=$(/usr/sbin/lsof "${sourcePath}")`.
Neither solution is working.

What you actually want is something more like:
lsofResult=$(sudo -u banjobs lsof "${sourcePath}")
Let's go over why the other approaches didn't work one-at-a-time:
Running source under sudo su -c
sudo su - userB -c 'source ./getOpenFiles.sh'
...uses sudo to run su, which runs sh -c 'source ./getOpenFiles.sh'. This doesn't work for several independent reasons:
sh -c 'source ./getOpenFiles.sh' relies on the source keyword being available in /bin/sh, but this is a bash extension.
Even if your /bin/sh is provided by bash, this still defeats the purpose of using source: By starting a new copy of /bin/sh and sourcing your script into that, you're defining the variable in the new shell, not in the original shell that started sudo su.
Running sudo su - banjobs, followed by lsofResult=$(/usr/sbin/lsof "${sourcePath}")
...means that lsofResult=$(...) doesn't run until after sudo su - banjobs exits. If sudo su - banjobs has exited, then the current user isn't banjobs any more, so the sudo command has no effect whatsoever on the lsof.
Demonstrating, in detail, how to test this (for folks who don't have a banoff or userB account on their system):
# place relevant contents in sourceme.bash
# switching from lsof to fuser for this test since OS X lsof does not accept a directory
# as an argument.
cat >sourceme.bash <<'EOF'
lsofResult=$(sudo -u root fuser "${sourcePath}" 2>&1)
EOF
# set sourcePath in the outer shell
sourcePath=$PWD
source sourceme.bash
declare -p lsofResult
...yields, on my system, output akin to the following:
declare -- lsofResult="/Users/chaduffy/tmp: 17165c 17686c 17687c 17688c 17689c 17690c"
...showing that the code in question did in fact work as described.

Related

Difference between sudo -s and sudo su in mac os

Both sudo -s and sudo su makes user root. is there any some difference?
With sudo -s
with sudo su
From man sudo:
-s, --shell
Run the shell specified by the SHELL environment variable if it is set or the shell specified by the invoking user's password
database entry. If a command is specified, it is passed to the shell for execution via the shell's -c option. If no command is
specified, an interactive shell is executed.
So -s keeps your current shell (bash in this case), while omitting it uses the shell of the root user (sh). Myself, I prefer sudo -Es to keep both my shell and environment variables.

change user and run ssh instruction in 1 line

I'm trying to change my user to one that doesn't need password to run ssh instructions and then do exactly that, run an ssh instruction. What I have now is:
sudo su - testUser ssh testUser#server2 'cat /home/randomUser/hola.txt'
But I'm getting the answer:
/usr/bin/ssh: /usr/bin/ssh: cannot execute binary file
if I put the instructions in a different file called testit like this:
ssh testUser#server2
cat /home/randomUser/hola.txt
and I run:
sudo su - testUser < testit
it works!, but I need to use the one line instruction, someone know what should I change to make it work?
sudo su - testUser
why don't you use just sudo -u testUser as it is supposed to be used?
But anyway, manual pages for the tools you are using is a good start. For sudo:
sudo [...] [command]
This looks good and fits into your example.
For su:
su [options] [username]
Ola ... su does not have any argument command, unless you provide also -c switch, which is written also in the manual page. And it is [option], so it should come in front of [username]! Something like this should do the job:
sudo su -l -c "ssh testUser#server2 'cat /home/randomUser/hola.txt'" testUser
but as I already mentioned, it can be significantly simplified by using sudo only:
sudo -i -u testUser "ssh testUser#server2 'cat /home/randomUser/hola.txt'"

shell script giving "sudo: no tty present and no askpass program specified" when trying to execute sudo command [duplicate]

This question already has answers here:
How to fix 'sudo: no tty present and no askpass program specified' error?
(30 answers)
Closed 6 years ago.
I have a shell script which creates a user and executes another script as that user
sudo useradd -m devops
sudo passwd devops
sudo adduser devops sudo
su - devops -c "sh /path/to/myscript.sh"
This script creates the user,sets the password and adds user to sudo group as expected.
myscript.sh contains commands which uses sudo previlages. (sudo apt-get update, sudo apt-get install software-properties-common etc.). And other commands like ssh-keygen,curl and wget.
All commands except the one's with sudo are executed correctly and producing results as excepted.
But commands having sudo fails by giving the error "no tty present and no askpass program specified"
Why does this happen in this case and how can I overcome this?
I have seen similiar questions but will be thankful if I get a clear explanation in this context,thank you.
Try to replace this:
su - devops -c "sh /path/to/myscript.sh"
with this:
sudo -u devops -H sh -c "sh /path/to/myscript.sh"
The -c option of su doesn't support interactive mode:
-c, --command COMMAND Specify a command that will be invoked by
the shell using its -c.
The executed command will have no controlling terminal. This option
cannot be used to execute interractive programs which need a
controlling TTY.
(man su)
By the way, I wouldn't use sudo within a script everywhere. The script might simply require root permissions. Within the script you might drop privileges where necessary by means of the above-mentioned sudo command.

su command in shell script

I have a script which copies a file, then untar and install it (agent-service) on multiple systems (IPs are read from systems.txt file). In the script, I wanted to start the agent-service as user "test". However after the script execution, when I check the target system, the agent-service is shown as running as "root" user. What could be wrong here? Am I not using su command correct within the script?
~]# ps -ef | grep agent-service
root 23511 15196 0 02:12 pts/3 00:00:00 agent-service
Script>
#!/bin/bash
export AGENT=linux-5.8.1.tar.gz
while read host; do
scp $AGENT root#$host:/opt
ssh -n root#$host 'cd /opt/linux;
tar zxvf linux-5.8.1.tar.gz;
mkdir /opt/hyperic;
useradd -m test;
chown -R test:test /opt/linux;
su - test;
/opt/linux/agent-service start'
done < systems.txt
Using su as you do here spawns a new shell that has nothing to do thus exits immediately.
Either pass the command to su:
su - test -c /opt/linux/agent-service start
Or use sudo in a similar manner:
sudo -u test /opt/linux/agent-service start

Why this linux command can affect the environment variables?

When I changed my current user to admin using
sudo su admin
I found that the environment variable changed too. What I intend to do is to change my user to admin with the env not changed.
Then I found a command as follows:
sudo bash -c "su - admin"
This command does indeed what I want, but I googled about bash -c, with no clue to why this command can do that for me. Could anyone give me a clear explanation? Thanks a lot.
first you should read the sudo manpage and set theses options in the /etc/sudoers file or you can do it interactively (see second below).
default sudoers file may not preserve the existing $USER environment unless you set the config options to do so. You'll want to read up on env_reset because depending on your OS distribution the sudo config will be different in most cases.
I dont mean to be terse but I am on a mobile device..
I do not recommend using sudo su .. for anything. whomever is sharing sudo su with the public is a newb, and you can accomplish the same cleaner with just sudo.
with your example whats happining is you are starting a subshell owned by the original user ("not admin") . you are starting the subshell with -c "string" sudo has the equivelant of the shell's -c using -s which either reads the shell from the arg passed to -s or the shell defined in the passwd file.
second you should use:
$ sudo -u admin -E -s
much cleaner right ? :)
-u sets the user, obviously
-s we just explained
-E preserves the orig user env
see for yourself just
$ echo $HOME # should show the original users /home/orig_user
$ env
your original env is preserved with none of that sudo su ugliness.
if you were interested in simulating a users login without preserving the env..
$ sudo -u user -i
or for root:
Might require -E depending on distro sudoers file
$ sudo -s
or
$ sudo -i
-i simulates the login and uses the users env.
hopefully this helps and someone will kindly format it to be more readable since im on my mobile.
bash with -c argument defines below.
-c string
If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
Thanks & Regards,
Alok

Resources