echo "root" when using $USER - bash

I'd like to understand bash better and when variables are evaluated.
When using sudo the user environment that can be checked out using env is exchanged with the root environment. Hence env and sudo env yield different results.
Now if I am doing sudo echo "I am $USER"! the result is I am my-username!
instead of I am root!, presumably because the $USER variable is looked up before the sudo command is excuted.
How can I use that same command so that I am root! is printed? Do I need some switches or change the string somehow?

In the command sudo echo "$USER", bash evaluates $USER first and then executes the command. In that case your username is printed.
If you want to print the root username, the parameter expansion must be done as the root user. It can be done using bash -c command:
sudo bash -c 'echo "$USER"'

Related

Run a subshell as root

Consider you have a Linux/UNIX machine with Bash. You have a file secret.txt that only root can read. You want to use a command that takes a string as an argument, say,
sample-command <string>
Log in as a root user and run the command using the first line of the text file:
root ~ $ sample-command $(sed '1!d' secret.txt)
Can this be done by non-root, sudoer users?
Note. sudo sh -c "<command>" doesn't help since subshells don't carry over the root/sudo privilege. For example,
sarah ~ $ sudo sh -c "echo $(whoami)"
gives you sarah, not root.
Expansions like command substitution will be processed by the shell before executing the actual command line:
sudo sh -c "echo $(whoami)"
foouser
Here the shell will first run whoami, as the current user, replace the expansion by it's result and then execute
sudo sh -c "echo foouser"
Expansions doesn't happen within single quotes:
sudo sh -c 'echo "$(whoami)"'
root
In this example $(whoami) won't get processed by calling shell because it appears within single quotes. $(whoami) will therefore get expanded by subshell before calling echo.

Why sudo -H needs an extra command?

I found this related question What does sudo -H do?
that demonstrates the usage of -H with
sudo -H bash -c 'echo $HOME $USER'
But I don't understand is why is bash necessary, because the echo command can stand on its own, but running
sudo -H echo $HOME $USER
will display instead current user variables (and not root's).
So why is (in this case) bash needed for the commands ran as sudo arguments to take in the -H flag?
This is also true if one specifies another user, like sudo -H -u anotheruser echo $HOME $USER.
When you run the command:
sudo -H echo $HOME $USER
the variables $HOME and $USER are evaluated by the current shell. They are replaced with their values and the command line adjusted this way is passed to sudo.
F.e. if your username is foo and your home is /home/foo, the command above is the same thing as:
sudo -H echo /home/foo foo
It's not necessarily bash that is required to get what you want. It's required a way to evaluate the environment variables by the command that is executed by sudo, not by the current shell.
When you run:
sudo -H bash -c 'echo $HOME $USER'
the $HOME and $USER environment variables are not evaluated by the current shell, because they are enclosed in single quotes.
sudo receives the command line as it is written here (it's fourth argument is the string echo $HOME $USER as a single word). It then launches bash with two arguments: -c and the string mentioned above.
bash interprets -c as "execute a command" that is provided as the next argument. It then tries to run echo $HOME $USER (notice that the variables are not enclosed in quotes here) and, before running echo it replaces $HOME and $USER with their values (that belong to the new user now).
Running bash (or any other shell) is needed to do the variables expansion in the execution environment of the new user.
$HOME and $USER are expanded by the shell before sudo even runs. You need bash -c to add a layer of indirection, so that the shell run by sudo does the expansion.

where did my environment variable go?

I am trying to use an environment variable in a bash script that needs to run as sudo with source.
I have the following file (my_file.sh)
echo "this is DOMAIN = $DOMAIN"
I have the DOMAIN environment variable in my session..
and now I need to run
sudo -E bash -c "source ./my_file.sh"
but the output does not display the value for $DOMAIN. instead it is empty.
if I change the command to be
sudo -E bash -c "echo $DOMAIN"
I see the correct value..
what am I doing wrong?
With the command line:
sudo -E bash -c "source ./my_file.sh"
you are running a script that may refer to environment variables that would need to be exported from a parent shell to be visible.
On the other hand:
sudo -E bash -c "echo $DOMAIN"
expands the value of $DOMAIN in the parent shell, not inside your sudo line.
To demonstrate this, try your "working" solution with single quotes:
sudo -E bash -c 'echo $DOMAIN'
And to make things go, try exporting the variable:
export DOMAIN
sudo -E bash -c "source ./my_file.sh"
Or alternately, pass $DOMAIN on the command line:
sudo -E bash -c "source ./my_file.sh $DOMAIN"
And have your script refer to $1.

Want to find status of sudo su - in multiple servers

I have a bash script, hostlist file and an expect script:
Below is the bash script to take inputs from hostlist file and keep looping ssh for multiple servers.
for x in $(cat hostlist); do
./sudoscript.exp $x
done
Below is the expect cum bash script I want to tun and collect outputs of sudo su - command. I just need to get outputs as '0 or non zero values in a file for successful run/execution of 'sudo su - '. I just need to simulate the execution and check if the command runs successfully or not with out actually changing user to admin by doing sudo su -.
#!/bin/bash
#!/usr/bin/expect
spawn ssh [lindex $argv 0]
expect "$"
send "sudo su -\r" exit ; echo $server:$? >> output
Can someone please suggest to complete the script above.
What exactly are you trying to do?
Maybe you're trying to see if it is possible to become root without a password? If that's the case, try:
for x in $(cat hostlist); do
echo $x
ssh $x sudo -l |egrep -w 'NOPASSWD:.*(ALL|/su)'
echo
done
sudo -l will list what you can run. It requires your password unless you have one or more commands that do not require your password (ssh won't run interactively when called with a command and without the -t flag. This is intentional since we don't want that).
The egrep command limits the results to just what can be done without a password as well as either ALL commands or else su itself. (Note, this won't find su if it's in an alias.)

How to define environment variable in input command of su

This command has an empty output.
su user -c "ABC=abc;echo $ABC"
Any idea, how can I define a variable in the input command?
Change your quotes to single quotes. The double quotes allow the variable to be substituted in the current environment where it's not set yet. To see the difference, try your version with $USER and compare it to this one:
su user -c 'ABC=abc; echo $ABC; echo $USER'
If using a bourne shell variant:
ABC=abc su user -c 'echo $ABC'
If not, use env.
env ABC=abc su user -c 'echo $ABC'

Resources