4

我正在编写一个 GUI 程序来为一群害怕使用命令行的用户生成和监视 SSH 隧道。

不幸的是,有问题的服务器非常严格。通过 RSA SecurID 令牌进行的双因素身份验证是唯一官方认可的打开 SSH 连接的方式。不允许使用无密码 RSA 公钥/私钥身份验证。

因此,我的程序有必要从文本输入框中读取密码并将其发送给子 SSH 进程。不幸的是,ssh我们竭尽全力确保密码仅来自真正的键盘。

我强烈不喜欢使用第三方模块。我知道 paramiko 和 pexpect (它们都被提出来作为类似问题的可能解决方案),但是试图向我的用户解释如何从源代码安装 Python 模块太让人头疼了。

那么:如何使用标准 pythonsubprocess模块向 ssh 子进程发送密码?有什么办法可以让子进程误以为我在使用 TTY?是否可以使用 SSH_ASKPASS 从我的程序中读取?

其他标准库模块(例如,模块的低级命令os)也是允许的。

4

1 回答 1

5

最后,我能够使用 pty 模块通过伪终端控制 ssh。我在 中编写了一个解决方案pexpect,然后通过查看 pexpect 源代码并从这个 StackOverflow 答案中获得一些帮助,我能够弄清楚该怎么做。这是相关代码的摘录(作为对象方法的一部分执行;因此引用self)。

command = [
        '/usr/bin/ssh',
        '{0}@{1}'.format(username, hostname),
        '-L', '{0}:localhost:{1}'.format(local_port, foreign_port),
        '-o', 'NumberOfPasswordPrompts=1',
        'sleep {0}'.format(SLEEP_TIME),
]

# PID = 0 for child, and the PID of the child for the parent    
self.pid, child_fd = pty.fork()

if not self.pid: # Child process
    # Replace child process with our SSH process
    os.execv(command[0], command)

while True:
    output = os.read(child_fd, 1024).strip()
    lower = output.lower()
    # Write the password
    if lower.endswith('password:'):
        os.write(child_fd, self.password_var.get() + '\n')
        break
    elif 'are you sure you want to continue connecting' in lower:
        # Adding key to known_hosts
        os.write(child_fd, 'yes\n')
    elif 'company privacy warning' in lower:
        pass # This is an understood message
    else:
        tkMessageBox.showerror("SSH Connection Failed",
            "Encountered unrecognized message when spawning "
            "the SSH tunnel: '{0}'".format(output))
        self.disconnect()
于 2012-10-30T23:08:24.933 回答