如何通过子进程模块调用ssh,以便它使用SSH_ASKPASS变量

时间:2009-11-24 01:45:36

标签: python ssh subprocess

我正在编写一个使用SSH命令的GUI。我尝试使用子进程模块来调用ssh并设置SSH_ASKPASS环境变量,以便我的应用程序可以弹出一个窗口,询问SSH密码。但是我无法使用给定的SSH_ASKPASS命令使ssh读取密码:它总是在终端窗口中提示它,无论我如何设置DISPLAY,SSH_ASKPASS,TERM环境变量或如何管道标准输入/输出。如何确保ssh与当前TTY分离并使用给定程序读取密码?

我的测试代码是:

#!/usr/bin/env python

import os
import subprocess

env = dict(os.environ)
env['DISPLAY'] = ':9999' # Fake value (trying in OS X and Windows)
del env['TERM']
env['SSH_ASKPASS'] = '/opt/local/libexec/git-core/git-gui--askpass'

p = subprocess.Popen(['ssh', '-T', '-v', 'user@myhost.com'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    env=env
)
p.communicate()

3 个答案:

答案 0 :(得分:15)

SSH仅在进程与TTY分离时才使用SSH_ASKPASS变量(stdin重定向和设置环境变量是不够的)。要从控制台分离进程,它应该fork并调用os.setsid()。所以我发现的第一个解决方案是:

# Detach process
pid = os.fork()
if pid == 0:
    # Ensure that process is detached from TTY
    os.setsid()

    # call ssh from here
else:
    print "Waiting for ssh (pid %d)" % pid
    os.waitpid(pid, 0)    
    print "Done"

使用子进程模块还有一种优雅的方法:在preexec_fn参数中,我们可以传递在执行外部命令之前在子进程中调用的Python函数。因此问题的解决方案是一个额外的路线:

env = {'SSH_ASKPASS':'/path/to/myprog', 'DISPLAY':':9999'}
p = subprocess.Popen(['ssh', '-T', '-v', 'user@myhost.com'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    env=env,
    preexec_fn=os.setsid
)

答案 1 :(得分:4)

您的问题是SSH检测到您的TTY并直接与它进行对话(如手册页中明确指出的那样)。您可以尝试在没有终端的情况下运行ssh - 手册页建议可能需要将stdin重定向到/dev/null以使ssh认为它没有终端。

您也可以使用pexcept,知道可以使用SSH - 例如usage

正确的方式(TM)做你想做的事情是:

  1. 使用专门用于在python中使用SSH的库(例如twisted conchparamiko
  2. 使用公钥和私钥,以便不需要密码

答案 2 :(得分:1)

如果您想快速而肮脏地将其用于个人用途,您可以在终端中启用无密码登录:

ssh-keygen -t rsa # generate a keypair (if you haven't done this already)
ssh-copy-id user@other_machine # copy your public key to the other machine

然后你可以通过创建一个脚本(记住用可标记的可执行文件,例如chmod 755 my_script.sh)来获取ssh命令(子进程似乎不能直接接受ssh命令),例如: :

#!/bin/bash
ssh user@other_machine ls

并从您的程序中调用它:

import subprocess
response = subprocess.call("./my_script.sh")
print(response)

对于需要在其他人的机器上部署的应用程序的生产使用,我会使用abyx使用SSH库的方法。比搞乱一些环境变量要简单得多。