How to use "wait" to copy the public key to the host?

I use the following syntax to copy the public key to the host so that I can subsequently log into the host without asking for a password:

ssh-copy-id $hostname 

in which $hostname is the host name of the system with the username, for example. root@123.456.789.100 . However, this command requires at least one password request, and sometimes an additional interaction of the type:

 The authenticity of host 'xxx (xxx)' can't be established. RSA key fingerprint is xxx. Are you sure you want to continue connecting (yes/no)? 

I tried to solve my problem with expect , and here is what I still have (with all comments and suggestions):

 #!/usr/bin/expect set timeout 9 set hostname [lindex $argv 0] spawn ssh-copy-id $hostname expect { timeout { send_user "\nFailed to get password prompt\n"; exit 1 } eof { send_user "\nSSH failure for $hostname\n"; exit 1 } "*re you sure you want to continue connecting" { send "yes\r" exp_continue } "*assword*" { send "fg4,57e4h\r" } } 

This works because it “catches” the first interaction correctly, but not the second. It seems that the correct password is used (fg4,57e4h), but when I try to enter the host machine, they still ask me for the password. I also checked that the entry in .ssh/authorized_hosts not done. The password used is also absolutely right, because I can just copy and paste it to enter the system. The script does not generate any errors, but produces the following output exp_internal 1 :

  ./expect_keygen XXX spawn ssh-copy-id XXX parent: waiting for sync byte parent: telling child to go ahead parent: now unsynchronized from child spawn: returns {3602} expect: does "" (spawn_id exp6) match glob pattern "*re you sure you want to continue connecting"? no "*assword*"? no XXX password: expect: does "XXX password: " (spawn_id exp6) match glob pattern "*re you sure you want to continue connecting"? no "*assword*"? yes expect: set expect_out(0,string) "XXX password: " expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) "XXX password: " send: sending "fg4,57e4h\r" to { exp6 } 

Although I am not an expert and I do not expect it, it seems that it expects to send the correct line (i.e. password) to the ssh-copy-id command. However, there should be a problem since the above wait command does not copy the public key to the host.

+7
ssh tcl expect
source share
5 answers

I would like to share my tcl / expect script. It works quite well.

 #!/usr/bin/env tclsh package require Expect set prompt {[$❯#] } set keyfile "~/.ssh/id_rsa.pub" set needcopy 0 if {![file exists $keyfile]} { spawn ssh-keygen interact } spawn ssh $argv expect { {continue connecting (yes/no)?} { send "yes\r" exp_continue } {[Pp]ass*: } { set needcopy 1 interact "\r" { send "\r" exp_continue } } $prompt } if {$needcopy} { set fd [open $keyfile] gets $fd pubkey close $fd send " mkdir -p ~/.ssh\r" expect $prompt send " cat >> ~/.ssh/authorized_keys <<EOF\r$pubkey\rEOF\r" expect $prompt } interact 
0
source share

Under normal circumstances, the SSH toolchain requests a password from the terminal, not from stdin. You can provide the SSH_ASKPASS user program to click on your password.

Create a simple askpass.sh script:

 #!/bin/sh echo $PASSWORD 

then configure it for use in ssh:

 chmod a+x askpass.sh export SSH_ASKPASS=askpass.sh 

finally run ssh-copy-id (without waiting):

 export DISPLAY=:0 PASSWORD=mySecurePassword setsid ssh-copy-id -o StrictHostKeyChecking=no hishost.thatwas.secure.com 

setsid is detached from the terminal (then ssh will panic and look for the askpass program) DISPLAY is also checked by ssh (it thinks your request is a graphical interface)

Please note that with this approach there may be hidden security vulnerabilities.

+4
source share

This should solve your problem.

 #!/usr/bin/expect set timeout 9 set hostname [lindex $argv 0] spawn ssh-copy-id $hostname expect { timeout { send_user "\nFailed to get password prompt\n"; exit 1 } eof { send_user "\nSSH failure for $hostname\n"; exit 1 } "*re you sure you want to continue connecting" { send "yes\r" exp_continue } "*assword*" { send "fg4,57e4h\r" interact exit 0 } } 
+2
source share

The errors you see arise from spawn without using the shell to execute the command. If you need shell control characters, you need to create a shell:

 spawn sh -c "cat $home/.ssh/id_rsa.pub | ssh $hostname 'cat >> $home/.ssh/authorized_keys'" 

However, I think ssh-copy-id will ask you the same questions, so this should be a replacement:

 spawn ssh-copy-id $hostname 

If you can see or not see the “continue connection” prompt, you will need the nested expected option with exp_continue

 spawn ssh-copy-id $hostname expect { timeout { send_user "\nFailed to get password prompt\n"; exit 1 } eof { send_user "\nSSH failure for $hostname\n"; exit 1 } "*re you sure you want to continue connecting" { send "yes\r" exp_continue } "*assword*" { send "mysecretpassword\r" } } 
+1
source share

If your approach with expect fails, you can still try sshpass .

0
source share

All Articles