2009-11-24 28 views
8

Tôi đang viết một GUI sử dụng các lệnh SSH. Tôi đã cố gắng sử dụng mô-đun subprocess để gọi ssh và thiết lập biến môi trường SSH_ASKPASS để ứng dụng của tôi có thể bật lên một cửa sổ yêu cầu mật khẩu SSH. Tuy nhiên tôi không thể làm cho ssh đọc mật khẩu bằng cách sử dụng lệnh SSH_ASKPASS đã cho: nó luôn nhắc nó trong cửa sổ đầu cuối, bất kể tôi đặt các biến môi trường DISPLAY, SSH_ASKPASS, TERM như thế nào hoặc cách đầu vào/đầu ra tiêu chuẩn. Làm thế nào tôi có thể chắc chắn rằng ssh được tách ra khỏi TTY hiện tại và sử dụng chương trình đã cho để đọc mật khẩu?Làm thế nào để gọi ssh bằng mô-đun subprocess để nó sử dụng biến SSH_ASKPASS

mã kiểm tra của tôi là:

#!/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 sẽ luôn nhắc bạn trong tiến trình con gọi nó, vì vậy những gì bạn cần làm là cho 'Popen()' gửi mật khẩu bằng cách sử dụng 'p.stdin.write() 'hoặc đơn giản hóa toàn bộ điều damn và sử dụng một cái gì đó cho tương tác SSH đã được viết cho bạn như Paramiko. – jathanism

+0

Cảm ơn câu trả lời. Tôi đã thử gửi mật khẩu bằng cách sử dụng p.stdin.write() và p.communicate(), buth ssh vẫn sử dụng TTY thực để đọc mật khẩu ... Và một vấn đề khác là nó không dễ phát hiện khi SSH yêu cầu mật khẩu (nó có thể làm điều đó với các chuỗi khác nhau, có thể xuất hiện sau trong phiên SSH, v.v.) – gyim

+0

Thấy rằng bạn sẵn sàng 'viết' mật khẩu cho quy trình SSH, tôi đã cập nhật câu trả lời của mình với tùy chọn để sử dụng 'pexcpet', mà sẽ làm việc cho điều đó. – abyx

Trả lời

15

SSH chỉ sử dụng biến SSH_ASKPASS nếu quá trình này thực sự tách rời khỏi TTY (chuyển hướng stdin và đặt) biến môi trường ting là không đủ). Để tách một tiến trình khỏi giao diện điều khiển, nó nên dùng fork và gọi os.setsid(). Vì vậy, giải pháp đầu tiên tôi thấy được:

# 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" 

Ngoài ra còn có một cách thanh lịch để làm điều này bằng cách sử dụng mô-đun subprocess: trong đối số preexec_fn chúng ta có thể vượt qua một hàm Python đó được gọi là trong tiến trình con trước khi thực hiện các lệnh bên ngoài . Vì vậy, các giải pháp cho vấn đề là một dòng thêm:

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

Đây chính xác là những gì tôi đang theo dõi Bạn là anh hùng của tôi, thưa bạn. – Ishpeck

4

Vấn đề của bạn là SSH phát hiện TTY và nói chuyện với nó trực tiếp của bạn (như được nêu rõ trong con người-page). Bạn có thể thử và chạy ssh mà không có một thiết bị đầu cuối - trang người đàn ông cho thấy nó có thể là cần thiết để chuyển hướng stdin đến /dev/null cho ssh để nghĩ rằng nó không có thiết bị đầu cuối.

Bạn cũng có thể sử dụng pexcept cho việc này, nó được biết là làm việc với SSH - ví dụ usage.

Các Way Right (TM) để làm những gì bạn đang cố gắng làm là một trong hai:

  1. Sử dụng một thư viện đặc biệt cho sử dụng SSH trong python (ví dụ twisted conch hay paramiko)
  2. Sử dụng các khóa công khai và riêng tư để mật khẩu sẽ không cần thiết
+0

Như bạn có thể thấy trong mã, tôi _am_ chuyển hướng đầu vào tiêu chuẩn và tôi không gửi dữ liệu đến nó, vì vậy nó hoàn toàn giống như tôi đã chuyển hướng stdin đến/dev/null. Hoặc là tôi sai? Tôi khá chắc chắn rằng vấn đề này có thể được giải quyết mà không cần sử dụng thực thi ssh đầy đủ: ví dụ, git-gui (viết bằng tcl/tk) có thể được chạy từ thiết bị đầu cuối. Nó chạy ssh ở chế độ nền và yêu cầu mật khẩu bằng chương trình riêng của nó (git-gui - askpass). – gyim

+0

Tôi cũng đã cố gắng đóng stdin ngay lập tức sau khi gọi Popen để đảm bảo rằng mã mô phỏng hành vi/dev/null. Không thành công: ( – gyim

+0

+1 cho PKI, dễ dàng hơn để xử lý theo chương trình – JimB

1

Nếu bạn muốn một cách nhanh chóng và dơ bẩn để làm việc đó để sử dụng cá nhân của riêng bạn, bạn có thể kích hoạt tính năng mật mã đăng nhập giữa hai máy này bằng cách làm này trong terminal của bạn :

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 

Sau đó, bạn có thể nhận được ssh lệnh phải đi qua (subprocess dường như không thể chấp nhận ssh lệnh trực tiếp) bằng cách tạo ra một kịch bản (nhớ để đánh dấu nó thực thi, ví dụ chmod 755 my_script.sh) với những điều bạn muốn, chẳng hạn như:

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

và gọi nó là từ chương trình của bạn:

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

Đối với sản xuất sử dụng các ứng dụng mà cần phải được triển khai trên máy của người khác Tôi muốn đi với cách tiếp cận abyx của của việc sử dụng một thư viện SSH. Đơn giản hơn nhiều so với rối tung với một số biến môi trường.

Các vấn đề liên quan