Switching users in a shell script - shell

OS: Ubunut 14.04
I have a shell script, and I would like to run a portion of the script as a different user. I tried adding the following to my script:
echo 'user_password' | su user_name
cd ~
ls -l
But I am getting the following message:
su: must be run from a terminal
Any ideas?

Keep in mind that it is a bad security practice to store a user's password in plaintext.
If you really want to read the password from STDIN, you can use the -S option of sudo, which doesn't seem to have a counterpart in the su command.
For a better solution, that doesn't involve storing the password in plaintext, see the answers on this askubuntu thread.

Related

Remember root password throughout script using Bash

Background
I have a long bash script which setup a large environment of interconnected software, taking several hours to complete. A few of the tasks it performs need to be run as root, for which I use sudo .... The whole process is then paused until the user notices and types in the root password. I seek some way for the user to type in the root password only at the beginning of the script, and then automatically supply it when required by sudo later.
My thoughts on possible (bad) solutions
I could store the password directly in a variable and then supply it using
echo "${root_password}" | sudo -S ...
but something tells me that this is bad practice.
Another workaround would be to force the user to run the entire script as root, but wouldn't that lead to different permissions for all of the files generated without the use of sudo?
You can prompt it at the start of your script, so it is not plain text hard saved.
Example:
#!/bin/bash
read -s -p "[sudo] sudo password for $(whoami): " pass
echo $pass | sudo -S apt-get update
help read:
-r do not allow backslashes to escape any characters
-s do not echo input coming from a terminal
I suggest you figure out all of the commands you need the script to run using SUDO, ensure the script is run by a special unprivileged user (e.g. scriptuser), and then edit /etc/sudoers to permit scriptuser to run those commands with NOPASSWD
As an example:
scriptuser ALL = NOPASSWD: /bin/kill, /usr/bin/othercommand, etc.
If you know the complete commands, including arguments, that's ideal (it means that an attacker that compromises the scriptuser account can only run those specific commands as root)
Sudo has a lot of options configurable in /etc/sudoers. If you man sudoers , you should see all of them. Forewarning: This man page is very hard to understand. Find examples. Test them. Ask on StackExchange.

Login to su and take the password from the same script

I'm trying to automate the build process which is done on linux server.
to do that first i need to login to the su and then perform the tasks for stopping and starting the server. I've written shell script to do that but there are some problems I'm facing,
1) even though I'm providing password from script using expect & send it tasks for password on terminal.
2) doing echo'password' | sudo -S su takes password automatically but says wrong even if it is right.
3) and when i put the password through terminal manually using su I get logged in to the su but the rest of the commands in script does not gets executed unless i do exit.
The script I've tried is,
echo 'password\n' | sudo -S su ##it says wrong password for su
commands to be performed after logging to su
exit
I've tried expect and send too,
su expect"Password" send "password\n";
and rest of the code here
but it's not fetching password from send automatically, I've to put it manually.
I would really appreciate if someone can help me with this!!
sudo requires the password of the user calling it, not the password of the superuser (or the user specified by the -u option). That may seem backwards, but the idea is that sudo can be configured to provide fine-grained control over what you are actually allowed to run as the superuser, rather than giving you access to the superuser account itself. Also, sudo keeps a log of who does what for auditing purposes.
If you used the wrong password, use the right password instead. Like others have already commented, sudo requires your password, not root's.
Additionally, your script is wrong. The sequence su; echo hello; exit will run a root shell with su, then when that shell exits, run echo hello and exit in your current shell.
You want this instead:
sudo -S sh -c 'echo hello'
The su is completely superfluous because sudo already takes care of switching to the root user, and offers a more convenient syntax for running commands as another user to boot. The sh -c '...' isn't strictly required in this example, but will probably be useful if you have more than one command which you wish to execute using elevated privileges. (Make sure you understand the implications. A useful commandment is to try to run even less code as sudo than you currently do. Always.)

SMB Client Commands Through Shell Script

I have a shell script, which I am using to access the SMB Client:
#!/bin/bash
cd /home/username
smbclient //link/to/server$ password -W domain -U username
recurse
prompt
mput baclupfiles
exit
Right now, the script runs, accesses the server, and then asks for a manual input of the commands.
Can someone show me how to get the commands recurse, prompt, mput baclupfiles and exit commands to be run by the shell script please?
I worked out a solution to this, and sharing for future references.
#!/bin/bash
cd /home/username
smbclient //link/to/server$ password -W domain -U username << SMBCLIENTCOMMANDS
recurse
prompt
mput backupfiles
exit
SMBCLIENTCOMMANDS
This will enter the commands between the two SMBCLIENTCOMMANDS statements into the smb terminal.
smbclient accepts the -c flag for this purpose.
-c|--command command string
command string is a semicolon-separated list of commands to be executed instead of
prompting from stdin.
-N is implied by -c.
This is particularly useful in scripts and for printing stdin to the server, e.g.
-c 'print -'.
For instance, you might run
$ smbclient -N \\\\Remote\\archive -c 'put /results/test-20170504.xz test-20170504.xz'
smbclient disconnects when it is finished executing the commands.
smbclient //link/to/server$ password -W domain -U username -c "recurse;prompt;mput backupfiles"
I would comment to Calchas's answer which is the correct approach-but did not directly answer OP's question-but I am new and don't have the reputation to comment.
Note that the -c listed above is semicolon separated list of commands (as documented in other answers), thus adding recurse and prompt enables the mput to copy without prompting.
You may also consider using the -A flag to use a file (or a command that decrypts a file to pass to -A) to fully automate this script
smbclient //link/to/server$ password -A ~/.smbcred -c "recurse;prompt;mput backupfiles"
Where the file format is:
username = <username>
password = <password>
domain = <domain>
workgroup = <workgroup>
workgroup is optional, as is domain, but usually needed if not using a domain\username formatted username.
I suspect this post is WAY too late to be useful to this particular need, but maybe useful to other searchers, since this thread lead me to the more elegant answer through -c and semicolons.
I would take a different approach using autofs with smb. Then you can eliminate the smbclient/ftp like approach and refactor your shell script to use other functions like rsync to move your files around. This way your credentials aren't stored in the script itself as well. You can bury them somewhere on your fs and make it read only by root an no one else.

sudo for single command in bash script

This may be a stupid question.
I have a script that I want to be portable between Mac OS X and a Linux box I use. In OS X, a command in the script requires sudo, where on the Linux box, it does not.
Long story short, how does one run one command in a script with sudo, while then removing the elevated privileges for the rest of the script?
I have tried to use
su -
and
su -c
but they both seem to error out. (They say "sorry" and move on, I assume because it is trying to run as root and root does not have a password).
I know there has to be a silly and easy way to do this, what does everyone suggest?
You can 'revoke' the sudo permission (actually: close the sudo time window early) by doing:
sudo -k
Also, you can configure sudo to only allow elevated permissions on certain commands, or even to impersonate non-root for specific commands. See man sudoers. The examples section makes it exceedingly clear that there is virtually no limit to the configurability of sudo (roles, hosts, commands, allow escaping, allow sudo target users, exceptions to allowed things, password less authorization etc etc).
Hopefully an interesting example in your context:
The user fred can run commands as any user in the DB Runas_Alias (oracle or sybase) without giving a password.
fred ALL = (DB) NOPASSWD: ALL
If you can't / don't really want to meddle with /etc/sudoers (visudo!) then I suggest using something like
{
trap "sudo -k" EXIT INT QUIT TERM
sudo ls # whatever
}
Try sudo su instead of su to change back to a regular user.
Use sudo without su:
#!/bin/bash
whoami # Runs under your regular account
sudo whoami # Runs as root
whoami # Runs under your regular account again
Here's the output when I run it:
$ ./sudotest
gordon
Password:
root
gordon

How to provide password to a command that prompts for one in bash?

I'm writing a UNIX shell function that is going to execute a command that will prompt the user for a password. I want to hard-code the password into the script and provide it to the command. I've tried piping the password into the command like this:
function() {
echo "password" | command
}
This may not work for some commands as the command may flush the input buffer before prompting for the password.
I've also tried redirecting standard input to a file containing the password like this, but that doesn't work either:
function() {
echo "password" > pass.tmp
command < pass.tmp
rm pass.tmp
}
I know that some commands allow for the password to be provided as an argument, but I'd rather go through standard input.
I'm looking for a quick and dirty way of piping a password into a command in bash.
How to use autoexpect to pipe a password into a command:
These steps are illustrated with an Ubuntu 12.10 desktop. The exact commands for your distribution may be slightly different.
This is dangerous because you risk exposing whatever password you use to anyone who can read the autoexpect script file.
DO NOT expose your root password or power user passwords by piping them through expect like this. Root kits WILL find this in an instant and your box is owned.
EXPECT spawns a process, reads text that comes in then sends text predefined in the script file.
Make sure you have expect and autoexpect installed:
sudo apt-get install expect
sudo apt-get install expect-dev
Read up on it:
man expect
man autoexpect
Go to your home directory:
cd /home/el
User el cannot chown a file to root and must enter a password:
touch testfile.txt
sudo chown root:root testfile.txt
[enter password to authorize the changing of the owner]
This is the password entry we want to automate. Restart the terminal to ensure that sudo asks us for the password again. Go to /home/el again and do this:
touch myfile.txt
autoexpect -f my_test_expect.exp sudo chown root:root myfile.txt
[enter password which authorizes the chown to root]
autoexpect done, file is my_test_expect.exp
You have created my_test_expect.exp file. Your super secret password is stored plaintext in this file. This should make you VERY uncomfortable. Mitigate some discomfort by restricting permissions and ownership as much as possible:
sudo chown el my_test_expect.exp //make el the owner.
sudo chmod 700 my_test_expect.exp //make file only readable by el.
You see these sorts of commands at the bottom of my_test_expect.exp:
set timeout -1
spawn sudo chown root:root myfile.txt
match_max 100000
expect -exact "\[sudo\] password for el: "
send -- "YourPasswordStoredInPlaintext\r"
expect eof
You will need to verify that the above expect commands are appropriate. If the autoexpect script is being overly sensitive or not sensitive enough then it will hang. In this case it's acceptable because the expect is waiting for text that will always arrive.
Run the expect script as user el:
expect my_test_expect.exp
spawn sudo chown root:root myfile.txt
[sudo] password for el:
The password contained in my_test_expect.exp was piped into a chown to root by user el. To see if the password was accepted, look at myfile.txt:
ls -l
-rw-r--r-- 1 root root 0 Dec 2 14:48 myfile.txt
It worked because it is root, and el never entered a password. If you expose your root, sudo, or power user password with this script, then acquiring root on your box will be easy. Such is the penalty for a security system that lets everybody in no questions asked.
Take a look at autoexpect (decent tutorial HERE). It's about as quick-and-dirty as you can get without resorting to trickery.
You can use the -S flag to read from std input. Find below an example:
function shutd()
{
echo "mySuperSecurePassword" | sudo -S shutdown -h now
}
Secure commands will not allow this, and rightly so, I'm afraid - it's a security hole you could drive a truck through.
If your command does not allow it using input redirection, or a command-line parameter, or a configuration file, then you're going to have to resort to serious trickery.
Some applications will actually open up /dev/tty to ensure you will have a hard time defeating security. You can get around them by temporarily taking over /dev/tty (creating your own as a pipe, for example) but this requires serious privileges and even it can be defeated.
with read
Here's an example that uses read to get the password and store it in the variable pass. Then, 7z uses the password to create an encrypted archive:
read -s -p "Enter password: " pass && 7z a archive.zip a_file -p"$pass"; unset pass
But be aware that the password can easily be sniffed.
Programs that prompt for passwords usually set the tty into "raw" mode, and read input directly from the tty. If you spawn the subprocess in a pty you can make that work. That is what Expect does...
Simply use :
echo "password" | sudo -S mount -t vfat /dev/sda1 /media/usb/;
if [ $? -eq 0 ]; then
echo -e '[ ok ] Usb key mounted'
else
echo -e '[warn] The USB key is not mounted'
fi
This code is working for me, and its in /etc/init.d/myscriptbash.sh
That's a really insecure idea, but:
Using the passwd command from within a shell script

Resources