2013-03-01 32 views
9

Tôi đang cố chạy lệnh scp (bản sao bảo mật) bằng cách sử dụng subprocess.Popen. Đăng nhập yêu cầu tôi gửi mật khẩu:Gửi mật khẩu qua SSH hoặc SCP với tiến trình con.Popen

from subprocess import Popen, PIPE 

proc = Popen(['scp', "[email protected]:/foo/bar/somefile.txt", "."], stdin = PIPE) 
proc.stdin.write(b'mypassword') 
proc.stdin.flush() 

này ngay lập tức trả về một lỗi:

[email protected]'s password: 
Permission denied, please try again. 

Tôi nhất định mật khẩu là chính xác. Tôi dễ dàng xác minh nó bằng cách thủ công gọi scp trên vỏ. Vậy tại sao điều này không hiệu quả?

Lưu ý, có rất nhiều câu hỏi tương tự như sau, hỏi về subprocess.Popen và gửi một mật khẩu cho SSH tự động hoặc FTP đăng nhập:

How can I set a users password in linux from a python script?
Use subprocess to send a password

Câu trả lời (s) cho những câu hỏi don' t làm việc và/hoặc không áp dụng vì tôi đang sử dụng Python 3.

+0

Tôi không quen với mã này nhưng bạn cố gắng sử dụng tham số -p? cũng là một trao đổi quan trọng như một phương pháp xác nhận? – diego2k

+0

Với -pi có nghĩa là "-p mypassword [email protected]: /foo/bar/somefile.txt" tôi không biết nếu bạn có thể làm điều đó – diego2k

+1

@ diego2k Theo như tôi biết, scp không chấp nhận chuyển sang nhập mật khẩu qua dòng lệnh (trang của nó không chứa gì cả). Nói chung nó không phải là thực hành tốt để cung cấp một mật khẩu trên dòng lệnh bởi vì đó sẽ được ghi lại trong .bash_history – entropy

Trả lời

6

Câu trả lời thứ hai mà bạn liên kết đề nghị bạn sử dụng Pexpect (thường là cách phù hợp để tương tác với các chương trình dòng lệnh mong đợi đầu vào). Có một fork của nó mà làm việc cho python3 mà bạn có thể sử dụng.

+1

lưu ý: thông thường [pexpect] (https://pypi.python.org/pypi/pexpect) hỗ trợ Python 3 ngay bây giờ. – jfs

9

Dưới đây là một chức năng để ssh với một mật khẩu sử dụng pexpect:

def ssh(host, cmd, user, password, timeout=30, bg_run=False):                         
    """SSH'es to a host using the supplied credentials and executes a command.                         
    Throws an exception if the command doesn't return 0.                              
    bgrun: run command in the background"""                                  

    fname = tempfile.mktemp()                                     
    fout = open(fname, 'w')                                      

    options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'                   
    if bg_run:                                       
     options += ' -f'                                      
    ssh_cmd = 'ssh %[email protected]%s %s "%s"' % (user, host, options, cmd)                             
    child = pexpect.spawn(ssh_cmd, timeout=timeout)                                
    child.expect(['password: '])                                                                        
    child.sendline(password)                                     
    child.logfile = fout                                      
    child.expect(pexpect.EOF)                                     
    child.close()                                        
    fout.close()                                        

    fin = open(fname, 'r')                                      
    stdout = fin.read()                                       
    fin.close()                                         

    if 0 != child.exitstatus:                                     
     raise Exception(stdout)                                     

    return stdout 

Something tương tự ta có thể sử dụng scp.

+0

Cảm ơn. Điều này đã giúp tôi. Tôi đang tìm kiếm nó, nhưng bạn có thể cho tôi biết dòng này có nghĩa là gì không? '-q -oStrictHostKeyChecking = no -oUserKnownHostsFile =/dev/null -oPubkeyAuthentication = no' – alfonso

+1

@alfonso đây là các tùy chọn bạn sẽ chuyển tới ssh trên dòng lệnh hoặc trong '.ssh/config' không có' - o'. Việc đầu tiên nói với ssh không phàn nàn nếu host đã thay đổi cos chính của nó, nó có thể đã được cài đặt lại kể từ lần cuối bạn sử dụng nó. Điều thứ hai nói để sử dụng/dev/null thay vì .ssh/known_hosts, do đó một lần nữa nó sẽ dừng nó phàn nàn nếu nó được cài đặt lại với một cảnh báo mục trùng lặp. Những ngày cuối cùng không sử dụng các phím buộc nhập mật khẩu. – sjbx

4

Pexpect có một thư viện cho chính xác này: pxssh

http://pexpect.readthedocs.org/en/stable/api/pxssh.html

import pxssh 
import getpass 
try: 
    s = pxssh.pxssh() 
    hostname = raw_input('hostname: ') 
    username = raw_input('username: ') 
    password = getpass.getpass('password: ') 
    s.login(hostname, username, password) 
    s.sendline('uptime') # run a command 
    s.prompt()    # match the prompt 
    print(s.before)  # print everything before the prompt. 
    s.logout() 
except pxssh.ExceptionPxssh as e: 
    print("pxssh failed on login.") 
    print(e) 
1

Tôi đoán một số ứng dụng tương tác với người dùng sử dụng thiết bị nhập chuẩn và một số ứng dụng tương tác sử dụng thiết bị đầu cuối. Trong trường hợp này, khi chúng ta viết mật khẩu bằng cách sử dụng PIPE, chúng ta sẽ ghi vào stdin. Nhưng ứng dụng SCP đọc mật khẩu từ thiết bị đầu cuối. Vì subprocess không thể tương tác với người dùng bằng terminal nhưng chỉ có thể tương tác bằng stdin, chúng ta không thể sử dụng module subprocess và chúng ta phải sử dụng pexpect để copy file bằng scp.

Hãy thoải mái chỉnh sửa.

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