2009-11-24 6 views
8

SSH 명령을 사용하는 GUI를 작성하고 있습니다. 서브 프로세스 모듈을 사용하여 ssh를 호출하고 SSH_ASKPASS 환경 변수를 설정하여 응용 프로그램이 SSH 암호를 묻는 창을 팝업 할 수 있도록했습니다. 그러나 ssh는 주어진 SSH_ASKPASS 명령을 사용하여 암호를 읽을 수 없습니다. DISPLAY, SSH_ASKPASS, TERM 환경 변수를 설정하는 방법이나 표준 입력/출력을 파이프하는 방법에 관계없이 항상 터미널 창에서 암호를 묻습니다. ssh가 현재 TTY에서 분리되었는지 확인하고 주어진 프로그램을 사용하여 암호를 읽을 수 있습니까?서브 프로세스 모듈에서 ssh를 호출하여 SSH_ASKPASS 변수를 사용하는 방법

내 테스트 코드이었다 :

#!/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 redirecting and set 환경 변수가 충분하지 않음). 콘솔에서 프로세스를 분리하려면 fork하고 os.setsid()를 호출해야합니다. 그래서 내가 찾은 최초의 솔루션이었다 : 우리가 외부 명령을 실행하기 전에 하위 프로세스에서 호출되는 파이썬 함수를 전달할 수 preexec_fn 인수에 :

는 서브 프로세스 모듈을 사용하여이 작업을 수행하는 우아한 방법이
# 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" 

. 당신이 당신의 자신의 개인적인 사용을 위해 그 일의 신속하고 더러운 방법을 원하는 경우

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. 사용 (예를 twisted conch 또는 paramiko에 대한) 파이썬에서
  2. 사용하여 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

, 당신은 터미널에서이 작업을 수행하여이 두 시스템 간의 암호없이 로그인을 활성화 할 수 있습니다 : 그래서 질문에 대한 솔루션은 하나 개의 추가 라인이다 :

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 

이 그럼 당신은 ssh를 얻을 수있는 스크립트를 작성하여 (직접 SSH를 받아 들일 수없는 것 서브 프로세스 명령)을 통해 이동 명령을 당신이 원하는 것들로, 같은 (그것을 실행, 예 chmod 755 my_script.sh 표시하는 기억) 예 :

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

및 프로그램에서 호출 :

내가 SSH 라이브러리를 사용 abyx의 접근 방식을 가고 싶어 다른 사람의 컴퓨터에 배포 할 필요가 애플 리케이션의 생산 사용을 위해
import subprocess 
response = subprocess.call("./my_script.sh") 
print(response) 

. 일부 환경 변수를 사용하는 것보다 훨씬 간단합니다.