7

我使用以下语法将公钥复制到主机,以便之后能够登录到主机而无需密码查询:

ssh-copy-id $hostname 

其中$hostname是带有用户名的系统主机名,例如root@123.456.789.100. 但是,此命令需要至少一个密码查询,有时还需要一个额外的交互类型:

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)?

我试图用 解决我的问题expect,这就是我目前所拥有的(包含所有评论和建议):

#!/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"
  }

}

只要它正确地“捕捉”了第一个交互,而不是第二个交互,这就是有效的。似乎正在使用正确的密码(fg4,57e4h),但是当我尝试登录主机时,仍然要求我输入密码。我还检查了没有进入.ssh/authorized_hosts。使用的密码也绝对正确,因为我可以将其复制并粘贴到登录。该脚本不会产生任何错误,但会产生以下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's password: 
expect: does "XXX's 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's password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "XXX's password: "
send: sending "fg4,57e4h\r" to { exp6 }

虽然我既不是 tcl 也不是期望专家,但似乎期望将正确的字符串(即密码)发送到ssh-copy-id命令。但是,仍然存在问题,因为上述期望命令没有将公钥复制到主机。

4

5 回答 5

4

在正常情况下,SSH 工具链从终端询问密码,而不是从标准输入。您可以提供自定义 SSH_ASKPASS 程序来推送您的密码。

创建一个简单的脚本 askpass.sh:

#!/bin/sh
echo $PASSWORD

然后将其配置为在 ssh 中使用:

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

最后运行 ssh-copy-id (没有期望):

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

setsid 从终端分离(ssh 会恐慌并寻找 askpass 程序) ssh 也检查 DISPLAY(它认为你的 askpass 是一个 GUI)

请注意,这种方法可能存在隐藏的安全漏洞。

于 2013-10-24T17:23:27.093 回答
3

这应该可以解决您的问题。

#!/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
    }
}
于 2016-05-12T16:27:32.450 回答
1

您看到的错误是由于spawn未使用 shell 执行命令所致。如果你想要 shell 控制字符,你需要生成一个 shell:

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

但是,我想ssh-copy-id会问你同样的问题,所以这应该是一个替代品:

spawn ssh-copy-id $hostname

如果您可能会或可能不会看到“继续连接”提示,您需要一个嵌套的期望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"
    }
}
于 2013-10-16T12:42:23.340 回答
1

我想分享我的 tcl/expect 脚本。它工作得很好。

#!/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
于 2017-12-22T10:37:46.917 回答
0

如果您的方法expect失败,您仍然可以尝试 sshpass

于 2013-10-24T21:23:54.213 回答