2013-03-01 11 views
9

Sto tentando di eseguire un comando scp (copia protetta) utilizzando subprocess.Popen. Il login richiede che mando una password:Invio di una password tramite SSH o SCP con sottoprocesso.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() 

Ciò restituisce immediatamente un errore:

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

Sono certo la password è corretta. Lo posso verificare facilmente invocando manualmente scp sulla shell. Quindi, perché non funziona?

Nota, ci sono molte domande simili a questo, chiedendo circa subprocess.Popen e l'invio di una password per SSH automatizzato o login FTP:

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

La risposta (s) a queste domande don' t lavoro e/o non si applicano perché sto usando Python 3.

+0

non ho familiarità con questo codice ma si tenta di utilizzare il parametro -p? anche uno scambio di chiavi come metodo di validazione? – diego2k

+0

Con -pi significa "-p mypassword [email protected]: /foo/bar/somefile.txt" non so se lo puoi fare – diego2k

+1

@ diego2k Per quanto ne so, scp non accetta un passaggio a inserire la password sulla riga di comando (la sua pagina man non contiene nulla del genere). In generale, non è una buona pratica fornire una password sulla riga di comando perché verrà registrata in .bash_history – entropy

risposta

6

La seconda risposta che hai suggerito ti suggerisce di usare Pexpect (che di solito è il modo giusto per interagire con i programmi a riga di comando che prevedono input). C'è uno fork che funziona per python3 che puoi usare.

+1

nota: regolare [pexpect] (https://pypi.python.org/pypi/pexpect) supporta ora Python 3. – jfs

9

Ecco una funzione per ssh con una password utilizzando 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 

Qualcosa di simile dovrebbe essere possibile utilizzare scp.

+0

Grazie. Questo mi ha aiutato. Sto cercando, ma potresti dirmi cosa significa questa linea? '-q -oStrictHostKeyChecking = no -oUserKnownHostsFile =/dev/null -oPubkeyAuthentication = no' – alfonso

+1

@alfonso a queste sono le opzioni che dovresti passare a ssh sulla riga di comando o nel tuo '.ssh/config' senza' - O'. Il primo dice a ssh di non lamentarsi se l'host ha cambiato la sua chiave cos che potrebbe essere stata reinstallata dall'ultima volta che l'hai usata. Il secondo dice di usare/dev/null piuttosto che .ssh/known_hosts così di nuovo smetterà di lamentarsi se è stato reinstallato con un avviso di entrata duplicato. Gli ultimi giorni di non usare le chiavi che obbligano l'inserimento della password. – sjbx

4

Pexpect ha una libreria per esattamente questo: 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

Credo che alcune applicazioni interagiscono con l'utente che utilizza standard input e alcune applicazioni interagiscono con il morsetto. In questo caso quando scriviamo la password usando PIPE stiamo scrivendo su stdin. Ma l'applicazione SCP legge la password dal terminale. Poiché il sottoprocesso non può interagire con l'utente che usa il terminale ma può interagire solo usando stdin, non possiamo usare il modulo del sottoprocesso e dobbiamo usare pexpect per copiare il file usando scp.

Sentitevi liberi per le correzioni.

Problemi correlati