如何通过子进程模块调用 ssh 以便它使用 SSH_ASKPASS 变量 [英] How to call ssh by subprocess module so that it uses SSH_ASKPASS variable
问题描述
我正在编写一个使用 SSH 命令的 GUI.我尝试使用 subprocess 模块调用 ssh 并设置 SSH_ASKPASS 环境变量,以便我的应用程序可以弹出一个窗口,要求输入 SSH 密码.但是,我无法使用给定的 SSH_ASKPASS 命令让 ssh 读取密码:它总是在终端窗口中提示它,无论我如何设置 DISPLAY、SSH_ASKPASS、TERM 环境变量或我如何通过管道传输标准输入/输出.如何确保 ssh 与当前 TTY 分离并使用给定程序读取密码?
I am writing a GUI which uses SSH commands. I tried to use the subprocess module to call ssh and set the SSH_ASKPASS environment variable so that my application can pop up a window asking for the SSH password. However I cannot make ssh read the password using the given SSH_ASKPASS command: it always prompts it in the terminal window, regardless how I set the DISPLAY, SSH_ASKPASS, TERM environment variables or how I pipe the standard input/output. How can I make sure that ssh is detached from the current TTY and use the given program to read password?
我的测试代码是:
#!/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()
推荐答案
SSH 仅在进程确实与 TTY 分离时才使用 SSH_ASKPASS 变量(stdin 重定向和设置环境变量还不够).要将进程与控制台分离,它应该派生并调用 os.setsid().所以我找到的第一个解决方案是:
SSH uses the SSH_ASKPASS variable only if the process is really detached from TTY (stdin redirecting and setting environment variables is not enough). To detach a process from console it should fork and call os.setsid(). So the first solution I found was:
# 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"
还有一种使用 subprocess 模块的优雅方法:在 preexec_fn 参数中,我们可以传递一个 Python 函数,该函数在执行外部命令之前在子进程中调用.所以这个问题的解决方案是额外的一行:
There is also an elegant way to do this using the subprocess module: in the preexec_fn argument we can pass a Python function that is called in the subprocess before executing the external command. So the solution for the question is one extra line:
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
)
这篇关于如何通过子进程模块调用 ssh 以便它使用 SSH_ASKPASS 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!