Skip to content

Instantly share code, notes, and snippets.

@virtuald
Created December 20, 2014 19:49
Show Gist options
  • Select an option

  • Save virtuald/54c8657a9ea834fb7fdd to your computer and use it in GitHub Desktop.

Select an option

Save virtuald/54c8657a9ea834fb7fdd to your computer and use it in GitHub Desktop.

Revisions

  1. virtuald created this gist Dec 20, 2014.
    97 changes: 97 additions & 0 deletions sshpass.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,97 @@
    #!/usr/bin/env python3

    import os
    import sys

    _b = sys.version_info[0] < 3 and (lambda x:x) or (lambda x:x.encode('utf-8'))

    def ssh_exec_pass(password, args, capture_output=False):
    '''
    Wrapper around openssh that allows you to send a password to
    ssh/sftp/scp et al similar to sshpass.
    Not super robust, but works well enough for most purposes. Typical
    usage might be::
    ssh_exec_pass('p@ssw0rd', ['ssh', '[email protected]', 'echo hi!'])
    :param args: A list of args. arg[0] must be the command to run.
    :param capture_output: If True, suppresses output to stdout and stores
    it in a buffer that is returned
    :returns: (retval, output)
    *nix only, tested on linux and OSX. Python 2.7 and 3.3+ compatible.
    '''

    import pty, select

    # create pipe for stdout
    stdout_fd, w1_fd = os.pipe()
    stderr_fd, w2_fd = os.pipe()

    pid, pty_fd = pty.fork()
    if not pid:
    # in child
    os.close(stdout_fd)
    os.close(stderr_fd)
    os.dup2(w1_fd, 1) # replace stdout on child
    os.dup2(w2_fd, 2) # replace stderr on child
    os.close(w1_fd)
    os.close(w2_fd)

    os.execvp(args[0], args)

    os.close(w1_fd)
    os.close(w2_fd)

    output = bytearray()
    rd_fds = [stdout_fd, stderr_fd, pty_fd]

    def _read(fd):
    if fd not in rd_ready:
    return
    try:
    data = os.read(fd, 1024)
    except (OSError, IOError):
    data = None
    if not data:
    rd_fds.remove(fd) # EOF

    return data

    # Read data, etc
    try:
    while rd_fds:

    rd_ready, _, _ = select.select(rd_fds, [], [], 0.04)

    if rd_ready:

    # Deal with prompts from pty
    data = _read(pty_fd)
    if data is not None:
    if b'assword:' in data:
    os.write(pty_fd, _b(password + '\n'))
    elif b're you sure you want to continue connecting' in data:
    os.write(pty_fd, b'yes\n')

    # Deal with stdout
    data = _read(stdout_fd)
    if data is not None:
    if capture_output:
    output.extend(data)
    else:
    sys.stdout.write(data.decode('utf-8', 'ignore'))

    data = _read(stderr_fd)
    if data is not None:
    sys.stderr.write(data.decode('utf-8', 'ignore'))
    finally:
    os.close(pty_fd)

    pid, retval = os.waitpid(pid, 0)
    return retval, output

    if __name__ == '__main__':
    retval, _ = ssh_exec_pass(sys.argv[1], sys.argv[2:], False)
    exit(retval)