Pass a password to ssh in pure bash - linux

I want to pass a password to ssh using a bash script (Yes, I know that there are ssh keys that I could use, but this is not what I intend).
I found some solutions that were using expect but since it is not a standard bash tool I am wondering if I can do this using pipes.
Can someone explain to me, why exactly something like this:
echo "password\n" | ssh somehost.com
or
ssh somehost.com <(echo "password\n")
doesn't work? Is there any possibility to make it work? Maybe executing ssh as a different process, obtaining its PID and then sending a string directly to it?

You can not specify the password from the command line but you can do either using ssh keys or using sshpass as suggested by John C. or using a expect script.
To use sshpass, you need to install it first. Then
sshpass -f <(printf '%s\n' your_password) ssh user#hostname
instead of using sshpass -p your_password. As mentioned by Charles Duffy in the comments, it is safer to supply the password from a file or from a variable instead of from command line.
BTW, a little explanation for the <(command) syntax. The shell executes the command inside the parentheses and replaces the whole thing with a file descriptor, which is connected to the command's stdout. You can find more from this answer https://unix.stackexchange.com/questions/156084/why-does-process-substitution-result-in-a-file-called-dev-fd-63-which-is-a-pipe

Since there were no exact answers to my question, I made some investigation why my code doesn't work when there are other solutions that works, and decided to post what I found to complete the subject.
As it turns out:
"ssh uses direct TTY access to make sure that the password is indeed
issued by an interactive keyboard user." sshpass manpage
which answers the question, why the pipes don't work in this case. The obvious solution was to create conditions so that ssh "thought" that it is run in the regular terminal and since it may be accomplished by simple posix functions, it is beyond what simple bash offers.

Related

How can I ingore whitespaces inside an echo command when usual methods don't seem to work

Hi I'm pretty new to linux/bash in general and I'm having a some trouble making a script for my coworker. Idea of this script is to help automate coworkers IP table entries (don't use IP tables myself so no idea how it works, just working as per his instructions). Program is going to ask a few questions, form an entry and then add it to a file on a different host. After the file is written it will also run
"systemctl reload iptables.service" and "systemctl status iptables". I tested that pwd was atleast working where I was planning to put these.
The code worked fine with a single word in place of table_entry variable, I was able to write something to a file in my host computer with a different user.
Problem is that the "table_entry" variable is going to have whitespaces in it and the sudo su -c command gets the second word as input (atleast that's what I think is happening) and I get an error sudo: INPUT: command not found. the "INPUT" coming from my case sentence
I tried to put the "table_entry" variable in "{$table_entry}" , "$table_entry" and {$table_entry} forms but they didn't work.
I removed some of the code to make it more readable (mostly case sentences for variables and asking for host and username).
#!/bin/bash
echo -e "Which ports?
1. INPUT
2. OUTPUT
3. Forward"
read opt_ch
case $opt_ch in
1) chain="INPUT" ;;
2) chain="OUTPUT" ;;
3) chain="FORWARD" ;;
*) echo -e "Wrong Option Selected!!!"
esac
table_entry="-A $chain "#-s $ip_source -d $ip_dest
ssh -t user#host "sudo table_entry=$table_entry su -c 'echo $table_entry >> /home/user/y.txt'"
#^ this line will later also include the systemctl commands separated with ";" ^
I tested few different methods how to do this script overall, heredoc(didn't get input to work very well), Ansible(Didn't really seem like a great tool for this job), Python(can't install new modules to the enviroment). So this is the best solution I came up with bearing my limited skillset.
Edit: I also realise this is propably not the smartest way to do this script, but it's the only one I have gotten to work this far, that can also ask for a password from the user when doing su command. I'm not knowledgeable in transferring passwords safely in linux enviroment or in general, so I like to let linux handle the passwords for me.
This a problem with dealing with nested quoting - which is really quite the annoying problem to solve.
This case seems like you could do this with quotes inside the string - your example would become
ssh -t user#host "sudo table_entry='$table_entry' su -c 'echo \"$table_entry\" >> /home/user/y.txt'"
It seems to me the table_entry='$table_entry' is redundant though, this should work:
ssh -t user#host "sudo su -c 'echo \"$table_entry\" >> /home/user/y.txt'"
Your comment (denoted with #) is getting concatenated with the table_entry string you're trying to form. Try adding a space like this:
table_entry="-A $chain " #-s $ip_source -d $ip_dest
Then table_entry gets assigned correctly. I was using KWrite to edit your bash script, and it does text highlighting that quickly showed me the problem.

Provide commands automatically to ftp in bash script

I am trying to create a bash script with ftp.
If I use terminal and put the commands below one bye one, it works like a charm.
$ ftp 192.168.1.4 2121
Connected to 192.168.1.4.
220 SwiFTP 1.7.11 ready
Name (192.168.1.4:user):
331 Send password
Password:
230 Access granted
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd Study/Math
ftp> put ~/Documents/Math/lesson.pdf lesson.pdf
I am trying to automate this command with a bash script:
#!/bin/bash
ftp 192.168.1.4 2121
cd Study/Math
put ~/Documents/Math/lesson.pdf lesson.pdf
It is not working. I know here ftp is a independent tool and I have to put those command while the ftp program is running. I searched internet tried various techniques (like printf, expect, etc...) but it did not worked. I also tried to use some scripts from internet to automate this process, but nothing helped. I am a newbie in bash scripting and these stuffs. Can you guys help me to solve this Problem?
Thanks in advance...
First, don't do this if you have any other option. It's a fairly standard idiom, but it's really broken in a lot of ways. If you're very sure that it won't ever do anything unpredictable, and that when it does it will be ok anyway, then sure, but in general...
use something besides ftp. For example, scp works quite well and has a checkable return code that is actually useful.
use a more granular programming language with modules. Don't get me wrong, I love bash and will always use it first when I can, but pumping a stream of commands into an ftp like a fire-and-forget UDP torpedo without any easy way of checking that each worked is just bad habit. Try Perl, or Python, or any other damned thing that lets you check a return code on each command and react accordingly. :)
if you MUST use bash (and yes, I have done it), and if it's important enough to check (what isn't?), then think about how you're going to do that. Maybe you can just pull lesson.pdf back to a local testme.pdf and cmp them to make sure it's good, which seems pretty easy. For any more complex script, you might need to run the ftp as a coprocesses and feed it commands one at a time, then read back it's output and parse for return codes, because ftp generally only reports errors there...and watch out for "500 bytes sent", which isn't a 500 error.
Either way, good luck. In many ways, simple is still best.
You might be interested in what is known as a heredoc
#!/usr/bin/env bash
ftp -n 92.168.1.4 2121 <<EOF
cd Study/Math
put ~/Documents/Math/lesson.pdf lesson.pdf
EOF
Since the ftp program reads its input from /dev/stdin, you can use a heredoc to define what should be passed from /dev/stdin
Okay, after User123 gave me a link, I finally solved my problem. So, I am giving my working script.
#!/bin/sh
HOST='192.168.1.4 2121'
USER='username_of_ftp'
PASSWD='password_of_ftp'
/usr/bin/ftp -n $HOST <<END_SCRIPT
user ${USER} ${PASSWD}
cd Study/Math
put ~/Documents/Math/lesson.pdf lesson.pdf
quit
END_SCRIPT
exit 0
While the ftp approach you're working with might be OK for your purposes, it's not going to behave properly if the server doesn't respond as expected.
As has already been suggested, use something other than ftp if at all possible. Scp or rsync using key authentication will work better, be more convenient since it won't break every time you change your password, and be more secure.

In bash, how do I input a password for a background process command?

I'm trying to do an rsync backup from dreamhost to another host, here's the command i'd like to use:
nohup rsync -e "/usr/bin/ssh" --bwlimit=2000 -av username#server.dreamhost.com:remote_directory local_directory&
I'd like the process to keep running in the background and even when I disconnect. Problem is, I don't know how to put in the password when it's a background process. How do I do this?
Usually this is done by not requiring a password at all. Instead, consider configuring SSH to use a public key. There are several resources online (such as this one from dreamhost) that can help you do that.
I would use a key. If you need to protect the key with a password or you cannot use a key for whatever reason, then use expect to pass the password:
rsync_auto.sh:
#/bin/bash
expect <<<EOF
spawn nohup rsync -e "/usr/bin/ssh" --bwlimit=2000 -av username#server.dreamhost.com:remote_directory
expect "password:"
send "your_password\r"
expect eof
EOF
!!!Make sure that nobody except you can access the file!!!:
chmod 500 rsync_auto.sh
A little bit more elaborated way might be to store the password in a keyring application, like gnome-keyring instead of storing them in a plain file. I've found this article if you are interested.

to transfer files in linux fedora 12 by giving password at command prompt

I am fully aware that this question has been asked many times but I cant able to find any solution which satisy my requirement.
Task -> I need to transfer files from machine A to machineB and remotely execute scripts on Machine B. Due to my limitation I cant able to use keygen, expect utility or any other utility which requires to install packages. To Transfer the file I need to give password and I want to give password in Url. as this will run inside bash script and requires no user interference .
My investigation- I thought of using scp but realise, its not possible to give password at command prompt. So i wondering , if there is any other alternative from rsync .
below is the small attempt
#!/bin/bash
PATH=/usr/bin:/usr/sbin:/bin:/sbin
USER="bob"
RSYNC_PASSWORD="blue"
MACHINE_B="192.168.200.2"
if ping -c 1 -W 1 $MACHINE_B
then
echo "There is machine b as well"
echo " cheking to transfer file to machine b"
rsync lol.sh 192.168.200.2:/home/bob/
fi
Thanks and regards,
Sam
I have tried various option mentioned above ,, but unfortunately none of them works in my case. But I would like to thanks everyone for helping me and surely I have learned few new things specially rsync.
In my case, I have to rely on ssh keys to make it work.
From the rsync man page:
Some modules on the remote daemon may require authentication. If so, you will receive a password prompt when you connect. You can avoid the password
prompt by setting the environment variable RSYNC_PASSWORD to the password you want to use or using the --password-file option. This may be useful
when scripting rsync.

iLO3: Multiple SSH commands

is there a way to run multiple commands in HPs integrated Lights-Out 3 system via SSH? I can login to iLO and run a command line by line, but I need to create a small shell-script, to connect to iLO and to run some commands one by one.
This is the line I use, to get information about the iLO-version:
/usr/bin/ssh -i dsa_key administrator#<iLO-IP> "version"
Now, how can I do something like this?
/usr/bin/ssh -i dsa_key administrator#<iLO-IP> "version" "show /map1 license" "start /system1"
This doesn't work, because iLO thinks it's all one command. But I need something to login into iLO, run these commands and then exit from iLO. It takes too much time to run them one after the other because every login into iLO-SSH takes ~5-6 seconds (5 commands = 5*5 seconds...).
I've also tried to seperate the commands directly in iLO after manual login but there is no way to use multiple commands in one line. Seems like one command is finished by pressing return.
iLO-SSH Version is: SM-CLP Version 1.0
The following solutions did NOT work:
/usr/bin/ssh -i dsa_key administrator#<iLO-IP> "version; show /map1 license; start /system1"
/usr/bin/ssh -i dsa_key administrator#<iLO-IP> "version && show /map1 license && start /system1"
This Python module is for HP iLO Management. check it out
http://pypi.python.org/pypi/python-hpilo/
Try putting your commands in a file (named theFile in this example):
version
show /map1 license
start /system1
Then:
ssh -i dsa_key administrator#iLO-IP < theFile
Semicolons and such won't work because you're using the iLO shell on the other side, not a normal *nix shell. So above I redirect the file, with newlines intact, as if you were typing all that into the session by hand. I hope it works.
You are trying to treat iLO like it's a normal shell, but its really HP's dopy interface.
That being said, the easiest way is to put all the commands in a file and then pipe it to ssh (sending all of the newline characters):
echo -e "version\nshow /map1 license\nstart /system1" | /usr/bin/ssh -i dsa_key administrator#<iLO-IP>
That's a messy workaround, but would you might fancy using expect? Your script in expect would look something like that:
# Make an ssh connection
spawn ssh -i dsa_key administrator#<iLO-IP>
# Wait for command prompt to appear
expect "$"
# Send your first command
send "version\r"
# Wait for command prompt to appear
expect "$"
# Send your second command
send "show /map1 license\r"
# Etc...
On the bright side, it's guaranteed to work. On the darker side, it's a pretty clumsy workaround, very prone to breaking if something goes not the way it should (for example, command prompt character would appear in version output, or something like that).
I'm on the same case and wish to avoid to run a lot of plink commands. So I've seen you can add a file with the -m option but apparently it executes just one command at time :-(
plink -ssh Administrator#AddressIP -pw password -m test.txt
What's the purpose of the file ? Is there a special format for this file ?
My current text file looks like below:
set /map1/oemhp_dircfg1 oemhp_usercntxt1=CN=TEST
set /map1/oemhp_dircfg1 oemhp_usercntxt2=CN=TEST2
...
Is there a solution to execute these two commands ?
I had similar issues and ended up using the "RIBCL over HTTPS" interface to the iLO. This has advantages in that it is much more responsive than logging in/out over ssh.
Using curl or another command-line HTTP client try:
USERNAME=<YOUR_ILO_USERNAME>
PASSWORD=<YOUR_ILO_PASSWORD>
ILO_URL=https://<YOUR_ILO_IP>/ribcl
curl -k -X POST -d "<RIBCL VERSION=\"2.0\">
<LOGIN USER_LOGIN=\"${USERNAME}\" PASSWORD=\"${PASSWORD}\">
<RIB_INFO MODE="READ">
<GET_FW_VERSION/>
<GET_ALL_LICENSES/>
</RIB_INFO>
<SERVER_INFO MODE=\"write\">
<SET_HOST_POWER HOST_POWER=\"Yes\">
</SERVER_INFO>
</LOGIN>
</RIBCL>" ${ILO_URL}
The formatting isn't exactly the same, but if you have the ability to access the iLO via HTTPS instead of only ssh, this may give you some flexibility.
More details on the various RIBCL commands and options may be found at HP iLO 3 Scripting Guide (PDF).

Resources