Sending a password over SSH or SCP with subprocess.Popen

The OpenSSH scp utility invokes the ssh program to make the SSH connection to the remote host, and the ssh process handles authentication. The ssh utility doesn't accept a password on the command line or on its standard input. I believe this is a deliberate decision on the part of the OpenSSH developers, because they feel that people should be using more secure mechanisms like key-based authentication. Any solution for invoking ssh is going to follow one of these approaches:

  1. Use an SSH key for authentication, instead of a password.
  2. Use sshpass, expect, or a similar tool to automate responding to the password prompt.
  3. Use (abuse) the SSH_ASKPASS feature to get ssh to get the password by invoking another command, described here or here, or in some of the answers here.
  4. Get the SSH server administrator to enable host-based authentication and use that. Note that host-based authentication is only suitable for certain network environments. See additional notes here and here.
  5. Write your own ssh client using perl, python, java, or your favorite language. There are ssh client libraries available for most modern programming languages, and you'd have full control over how the client gets the password.
  6. Download the ssh source code and build a modified version of ssh that works the way you want.
  7. Use a different ssh client. There are other ssh clients available, both free and commercial. One of them might suit your needs better than the OpenSSH client.

In this particular case, given that you're already invoking scp from a python script, it seems that one of these would be the most reasonable approach:

  1. Use pexpect, the python expect module, to invoke scp and feed the password to it.
  2. Use paramiko, the python ssh implementation, to do this ssh task instead of invoking an outside program.

Here's a function to ssh with a password using pexpect:

import pexpect
import tempfile

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 %s@%s %s "%s"' % (user, host, options, cmd)                                                                                                                 
    child = pexpect.spawn(ssh_cmd, timeout=timeout)  #spawnu for Python 3                                                                                                                          
    child.expect(['[pP]assword: '])                                                                                                                                                                                                                                                                                               
    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 similar should be possible using scp.


The second answer you linked suggests you use Pexpect(which is usually the right way to go about interacting with command line programs that expect input). There is a fork of it which works for python3 which you can use.