如何通过子进程模块调用 ssh 以便它使用 SSH_ASKPASS 变量 [英] How to call ssh by subprocess module so that it uses SSH_ASKPASS variable

查看:68
本文介绍了如何通过子进程模块调用 ssh 以便它使用 SSH_ASKPASS 变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆