• Uncategorized

About linux : Use-Expect-in-a-Bash-script-to-provide-a-password-to-an-SSH-command

Question Detail

I’m trying to use expect in a Bash script to provide the SSH password. Providing the password works, but I don’t end up in the SSH session as I should. It goes back strait to Bash.

My script:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no [email protected]$myhost.example.com'
expect "password"
send "$PWD\n"
EOD
echo "you're out"

The output of my script:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no [email protected]$myhost.example.com
[email protected]$myhost.example.com's password: you're out

I would like to have my SSH session and, only when I exit it, to go back to my Bash script.

The reason why I am using Bash before expect is because I have to use a menu. I can choose which unit/device to connect to.

To those who want to reply that I should use SSH keys, please abstain.

Question Answer

Mixing Bash and Expect is not a good way to achieve the desired effect. I’d try to use only Expect:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no [email protected]$myhost.example.com

# Use the correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Sample solution for bash could be:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no [email protected]$myhost.example.com; interact }'

This will wait for Enter and then return to (for a moment) the interactive session.

The easiest way is to use sshpass. This is available in Ubuntu/Debian repositories and you don’t have to deal with integrating expect with Bash.

An example:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh [email protected] ls -l /tmp

The above command can be easily integrated with a Bash script.

Note: Please read the Security Considerations section in man sshpass for a full understanding of the security implications.

Add the ‘interact’ Expect command just before your EOD:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no [email protected]$myhost.example.com
expect "password"
send -- "$PWD\r"
interact
EOD
echo "you're out"

This should let you interact with the remote machine until you log out. Then you’ll be back in Bash.

After looking for an answer for the question for months, I finally find a really best solution: writing a simple script.

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "assword:"   # matches both 'Password' and 'password'
send -- "$password\r"; # -- for passwords starting with -, see https://stackoverflow.com/a/21280372/4575793
interact

Put it to /usr/bin/exp, then you can use:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

Done!

A simple Expect script:

File Remotelogin.exp

    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh [email protected]$ip
    expect "password"
    send "$password\r"
    interact

Example:

./Remotelogin.exp <ip> <user name> <password>

Also make sure to use

send -- "$PWD\r"

instead, as passwords starting with a dash (-) will fail otherwise.

The above won’t interpret a string starting with a dash as an option to the send command.

Use the helper tool fd0ssh (from hxtools, source for ubuntu, source for openSUSE, not pmt). It works without having to expect a particular prompt from the ssh program.

It is also “much safer than passing the password on the command line as sshpass does” ( – comment by Charles Duffy).

Another way that I found useful to use a small Expect script from a Bash script is as follows.

...
Bash script start
Bash commands
...
expect - <<EOF
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
More Bash commands
...

This works because ...If the string "-" is supplied as a filename, standard input is read instead...

sshpass is broken if you try to use it inside a Sublime Text build target, inside a Makefile. Instead of sshpass, you can use passh

With sshpass you would do:

sshpass -p pa$$word ssh [email protected]

With passh you would do:

passh -p pa$$word ssh [email protected]

Note: Do not forget to use -o StrictHostKeyChecking=no. Otherwise, the connection will hang on the first time you use it. For example:

passh -p pa$$word ssh -o StrictHostKeyChecking=no [email protected]

References:

  1. Send command for password doesn’t work using Expect script in SSH connection
  2. How can I disable strict host key checking in ssh?
  3. How to disable SSH host key checking
  4. scp without known_hosts check
  5. pam_mount and sshfs with password authentication

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.