I have the following expect script on a Solaris 11.4 server. As Solaris 11 does not ship with ssh-copy-id or ssh-pass. I want to create a script to automate copying my ssh key to 100+ servers. After a bit of Google expect seems to be only option - unless someone knows better ?
I can get the script to copy the key onto the target server, but what I require is the script not to copy if they key is already installed.
The only way I can check for this is if the ssh login goes straight on without asking for a password. My issue is how do I test for an empty prompt ? .
If the key is not installed I get password prompt - then I can use expect to complete the password and copy the key. I've tried testing for "" (empty) but that seems to match everything. Any advise greatly appreciated.
#!/usr/bin/expect
set timeout 1200
set user [lindex $argv 0]
set host [lindex $argv 1]
set pass [lindex $argv 2]
set sshkeyfile [open ~/.ssh/id_rsa.pub r]
set sshid [read $sshkeyfile]
close $sshkeyfile
spawn ssh $user@$host "mkdir -m 700 ~/.ssh ; echo \" $sshid\" >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"
expect {
"continue" { send "Yes\n" ; exp_continue }
"Password" { send "$pass\r"; interact}
"" { send "exit\n" ; exit 0 } # Exit if not asked for "continue/Password"
}
How about this: ssh without the command; if the password is seen, set a boolean variable; when you hit the shell prompt, if the variable is true, append to the authorized_keys
#!/usr/bin/expect
set timeout 1200
lassign $argv user host pass
set sshkeyfile [open ~/.ssh/id_rsa.pub r]
set sshid [read -nonewline $sshkeyfile]
close $sshkeyfile
set sentPassword false
set prompt {\$ $} ;# shell prompt ends with "dollar space"
spawn ssh $user@$host
expect {
"continue" {
send "Yes\r"
exp_continue
}
"Password" {
set sentPassword true
send "$pass\r"
exp_continue
}
-re $prompt
}
if {$sentPassword} {
send "mkdir -p -m 700 ~/.ssh ; echo \"$sshid\" >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys\r"
expect -re $prompt
}
send "exit\r"
expect eof
other changes:
lassign
to handle the command line arguments in one commandread -nonewline
to omit the trailing newline from the public keymkdir -p
to prevent error message if the directory already exists.