Home > database >  How to use expect to provide required string when logging into remote computer
How to use expect to provide required string when logging into remote computer

Time:12-12

I am trying to log into a remote computer that requires a passphrase even though I have ssh set up with private/public keys. I cannot be made a sudden. Here is the script I use to do this.

⌂107% [:~/bin] develop( 1/-1) ± cat _script
#!/bin/bash
#
#  provide the info to remote-host from this script
#
function _ssh() {
USER=$1
HOST=$2
PSWD=$3

/usr/local/bin/expect<<EOD
   set timeout 30
   log_user 1
   set send_slow {1 .01}
   log_file ~/log/ssh_tmp.log

   send_log "Connecting to $HOST using $USER user\n"
   eval spawn ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=30 "$USER\@$HOST"
   expect {
      timeout {send_user "timeout while connecting to $HOST\n"; exit }
      "*No route to host*" { send_user "$HOST not reachable\n"; exit }
      "*assword: " { send -s $PSWD\r }
      }
   expect {
      timeout { send_user "timeout waiting for prompt\n"; exit }
      "*]#"  { send_user "Login successful to $HOST\n" }
      }
   send "\hostname\r"
   expect {
      "[*~]$"  { send "exit\r" }
      }
   send_user "Disconnected\n"
   close
EOD
}

_ssh remote-userid remote-host 'required-passphrase'

Here is the response I get:

⌂77% [:~/bin] develop( 1/-1) 11s ± _script
spawn ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=30 useid@remote-host
Warning: Permanently added 'remote-host,128.255.155.99' (ECDSA) to the list of known hosts.
--------------------------------------------------------------------------------
This is a private computing facility. Access to this service is limited to those
who have been granted access by the operating service provider on behalf of the
contracting authority and use is restricted to the purposes for which access was
granted. All access and usage are governed by the terms and conditions of access
agreed to by all registered users and are thus subject to the provisions of the
Computer Misuse Act, 1990 under which unauthorised use is a criminal offence.

If you are not authorised to use this service you must disconnect immediately.
--------------------------------------------------------------------------------

userid@remote-host's password: 

Welcome to remote-host-name

Website: https://remote-host/

Documentation: https://remote-host/en/master/

Last login: Sat Dec 10 10:16:03 2021 from my-ip
[userid@remote-host ~]$ ls      (I entered this, when the [userid@remote-host ~]$ appeared)
timeout waiting for prompt

It appears to log me in and show me the prompt, but is it expecting something else? How do I handle this?

CodePudding user response:

Just what it says: "timeout waiting for prompt"

   expect {
      timeout { send_user "timeout waiting for prompt\n"; exit }
      "*]#"  { send_user "Login successful to $HOST\n" }
      }

Change the prompt pattern to -re {\][$#] $} to match a close bracket followed by either # (root) or $ (you), followed by a space at the end.

Since you'll expect the prompt in several places, store it in a variable

   set prompt {\][$#] $}
   expect {
      timeout { send_user "timeout waiting for prompt\n"; exit }
      -re prompt
   }
   send_user "Login successful to $HOST\n"

Adding an expect program into a bash script, use a quoted here-doc and pass the shell variables to expect through the environment: this is important because you don't want the shell to expand your expect variables and you don't want to have to start escaping thing.

function _ssh() {
export USER=$1
export HOST=$2
export PSWD=$3

/usr/local/bin/expect << 'EOD'
...
   send_log "Connecting to $env(HOST) using $env(USER) user\n"

spawn does not need eval:

  spawn ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=30 "$env(USER)@$env(HOST)"

Change close to expect eof to allow the ssh connection to end gracefully.


Lastly, your expect code is doing all the interaction with the ssh process. You won't be able to type at the remote prompt unless you instruct expect to cede control of the ssh process to the user. You use the interact command to do that.

CodePudding user response:

I suggest:

function _ssh() {
  local user="$1"
  local host="$2"
  declare -x SSHPASS="$3"

  sshpass -e ssh "$user@$host"
}
  • Related