2009-11-24 8 views
8

SSHコマンドを使用するGUIを作成しています。サブプロセスモジュールを使用してsshを呼び出し、SSH_ASKPASS環境変数を設定して、アプリケーションがSSHパスワードを要求するウィンドウをポップアップできるようにしました。 SSH_ASKPASSコマンドを使用してsshにパスワードを読み取らせることはできません。DISPLAY、SSH_ASKPASS、TERM環境変数の設定方法や標準入出力のパイプ設定に関係なく、ターミナルウィンドウで常にプロンプ​​トを表示します。 sshが現在のTTYから切り離されていることを確認して、指定されたプログラムを使用してパスワードを読み取るにはどうすればよいですか?SSH_ASKPASS変数を使用するようにサブプロセスモジュールでsshを呼び出す方法

私のテストコードはでした:

#!/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', '[email protected]'], 
    stdin=subprocess.PIPE, 
    stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE, 
    env=env 
) 
p.communicate() 
+0

SSHは、それを呼び出したサブプロセスであなたにプロンプ​​トを表示するので、 'Popen()'に 'p.stdin 'を使ってパスワードを送信するよう指示します。write() 'を実行するか、まったく単純化して、Paramikoのようなあなたのためにすでに書かれているSSHのやりとりのために何かを使用してください。 – jathanism

+0

答えをありがとう。私はp.stdin.write()とp.communicate()を使ってパスワードを送信しようとしましたが、SSHはまだ実際のTTYを使ってパスワードを読み取っていました...そしてもう一つの問題は、SSHがパスワードを要求すると(これはSSHセッションの後半に出てくる異なる文字列で行うことができます) – gyim

+0

自分でSSHプロセスにパスワードを「書き込む」ことがわかっているので、使用するオプションで自分の答えを更新しました'pexcpet'は、これでうまくいくでしょう。 – abyx

答えて

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" 

は、subprocessモジュールを使用してこれを行うためのエレガントな方法もあります:preexec_fnに引数に我々は外部コマンドを実行する前に、サブプロセスで呼び出されるPython関数を渡すことができます。そこで問題のためのソリューションは、1つの余分ラインです:

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

これはまさに私が後にしていることです。あなたは私の英雄です。 – Ishpeck

4

あなたの問題は、(明らかに、マンページに記載されているよう)SSHは、あなたのTTYと直接に交渉を検出していることです。 sshがターミナルを持っていないと思うように、stdinから/dev/nullにリダイレクトする必要があるかもしれないことをマンページで示唆しています。

これにはpexceptを使用することもできます。SSHで動作することが知られています(例:usage)。あなたが何をしようとして行うには

右ウェイ(TM)は、いずれかです:

  1. は使用
  2. (例twisted conchまたはparamikoのために)特にPythonでSSHを使用するためのライブラリを使用します公開鍵と秘密鍵を使用してパスワードが不要になるようにします。
+0

コードでわかるように、私は標準入力のリダイレクトを行い、データを送信しないので、stdinを/ dev/nullにリダイレクトしたのと全く同じです。または私は間違っていますか? この問題は、完全なssh実装を使用せずに解決できると確信しています。例えば、git-gui(tcl/tkで書かれています)は端末から実行できます。バックグラウンドでsshを実行し、独自のプログラム(git-gui-askpass)でパスワードを尋ねます。 – gyim

+0

Popenを呼び出した直後にstdinをクローズして、コードが/ dev/nullの動作をエミュレートするようにしました。成功しない場合:( – gyim

+0

+1、PKIの場合はプログラムで処理するほうがはるかに簡単です – JimB

1

あなたがあなた自身の個人的な使用のためにそれを行うための迅速かつ汚いやり方をしたい場合、あなたはターミナルでこれを行うことによって、これらの2台のマシン間でパスワードなしログインを可能にすることができます:

ssh-keygen -t rsa # generate a keypair (if you haven't done this already) 
ssh-copy-id [email protected]_machine # copy your public key to the other machine 

その後、あなたは、このような、あなたが欲しいものを(例えばchmod 755 my_script.sh、実行可能にマークすることを忘れないでください)スクリプトを作成することによって、(サブプロセスは、sshがコマンドを直接受け入れるように見えることはできません)sshが通過するコマンドを取得することができますとして:

#!/bin/bash 
ssh [email protected]_machine ls 

し、プログラムからそれを呼び出す:私はSSHライブラリを使用してのabyxのアプローチで行くと思います他の人のマシン上に展開する必要があるアプリケーションの生産・使用のために

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

。いくつかの環境変数を混乱させるよりもずっと簡単です。

関連する問題