2

I'm trying to send special characters (password) which contains #?!k;|C . The password is dynamic and cannot be hardcoded in the script, so I'm passing it as variable as shown below

$ expect ./passwordlessSSH.exp $hostname "$password"

the code of this script is as below

#!/usr/bin/expect -f
 set host [lindex $argv 0]
set pass [lindex $argv 1]

spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub hdpsvcs@$host
expect {
  "yes" {
    send "yes\r"
  }
    "assword" {
    send "$pass \r"
}
exit 0

But still it is not running the script properly. I don't see any error but the variable is not passed correctly. The output is as shown below:

$ expect ./passwordlessSSH.exp $hostname "$password"

 spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub test@otesthost
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed:
"/home/test/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are     prompted now it is to install the new keys
\S
Kernel \r on an \m
test@test's password: 
$
AdminBee
  • 21,637
  • 21
  • 47
  • 71
user2925298
  • 21
  • 1
  • 2
  • IN simple words I'm not able to run below command send ";c39#?!K|;p;abc\r" and I cannot use back slashes as the password is going to be a variable – user2925298 Jul 17 '19 at 12:34
  • 1
    Make sure you write `"$pass\r"` without a space, not `"$pass \r"`. Also, add a short sleep before the send to allow the remote script to switch off echo (and flush the tty). – meuh Jul 17 '19 at 12:44
  • Hi meuh, I gave without space. Still the same issue – user2925298 Jul 17 '19 at 13:04
  • 2
    I see no evidence that the password is sent incorrectly. However, you exit right after you log in. Perhaps you want to change `exit 0` to `interact` so you can remain logged in. – glenn jackman Jul 17 '19 at 13:30
  • 1
    @meuh, a sleep should not be necessary. – glenn jackman Jul 17 '19 at 13:32

2 Answers2

3

After plenty of searching, I realized I couldn't use expect with special character unless i escaped. Convert password with special characters for use with expect script gives a short perl script that allowed me to handle special characters programatically in dynamic passwords.

#/bin/sh
pstr='$x%y!zpass' # plain, un-escaped string
estr=$(perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr}      # show escaped string

produces:

\$x\%y\!zpass

Edit: I was unable to send it to an expect script from the command line, so feel free not to accept this as the answer, but using the above did work for me by sending arguments to a bash script, that in turn invokes the expect script. Here's how I'd apply it to the OP's code.

Bash script: passwordlessSSH.sh

#/bin/sh
hostname=$1
pstr=$2 # plain, un-escaped string
estr=$(perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr}      # show escaped string
/your/script/location/passwordlessSSH.exp $hostname ${estr}

Expect Script: passwordlessSSH.exp

#!/usr/bin/expect -f
set host [lindex $argv 0]
set pass [lindex $argv 1]

spawn ssh-copy-id -i /home/hdpsvcs/.ssh/id_rsa.pub hdpsvcs@$host
expect {
  "yes" {
    send "yes\r"
   }
    "assword" {
    send "$pass \r"
}
exit 0

To execute: Just execute the bash script

./passwordlessSSH.sh $hostname "$password"

AdminBee
  • 21,637
  • 21
  • 47
  • 71
Byte
  • 31
  • 3
  • 1
    But the question isn’t about how to ``echo`` a string;  it’s about how to ``send`` it from an expect script. – Scott - Слава Україні Feb 10 '20 at 03:49
  • @Scott it looks to me as if Byte is saying that the password should be "escaped" using this method before passing it on to `expect`. Byte, correct me if I've misunderstood. It might make it more obvious if you demonstrated the OP's example of `expect ./passwordlessSSH.exp $hostname "$password"` – Jeff Schaller Feb 10 '20 at 14:29
  • 1
    @JeffSchaller: If that’s what Byte is trying to say, then I suspect that the answer is wrong. But I don’t currently have access to a system with ``expect``, so I can’t test it right now. – Scott - Слава Україні Feb 11 '20 at 23:23
  • in this example, i had to run ' set +o histexpand' from the bash prompt to use **!** in a password, else it'd attempt to read it as a bash history command. – Byte Feb 12 '20 at 19:34
0

Not sure why the respondent suggested using perl, as expect can handle this fine as an environment variable. Example:

export IN=file1
export OUT=file2
export PASS='!@#$%^&*('
expect -c '
    set timeout -1
    spawn openssl enc -d -aes-256-cbc -salt -in "$env(IN)" -out "$env(OUT)"
    match_max 100000
    expect "password:"
    send -- "$env(PASS)\r"
    expect "password:"
    send -- "$env(PASS)\r"
    expect eof
    puts "$expect_out(buffer)"' #> /dev/null 2>&1
Fmstrat
  • 330
  • 3
  • 8