SSH and Windows

Peter Hansen peter at engcorp.com
Sat Aug 2 05:30:50 CEST 2003


Fazer wrote:
> 
> Peter Hansen <peter at engcorp.com> wrote in message news:<3F2069BD.1FE2EC2 at engcorp.com>...
> > Isaac Raway wrote:
> > >
> > > Hello. I'm writing a Python program that connects to servers through
> > > telnetlib to execute a few commands. I've discovered that some of the
> > > servers that I have to connect to with this program run only SSH, so I
> > > need to add support for SSH to the program. I'm looking for a library
> > > that behaves similarly to telnetlib for SSH connections. Does anyone
> > > know of one? I was going to try using pexpect to control the Windows
> > > telnet command, but pexpect only works on Unix.
> >
> > If it's just to execute a few commands, consider downloading PLink
> > (from the PuTTY site) and use it via os.system().  It works well.
> >
> > -Peter
> 
> Hmm...is there a *nix version for PLink?  I checked PuTTY's site and
> it's all for Windows.  Or maybe an alternative for PLink for *nix?

Maybe try this.  Tested (mostly) under Python 1.5.2 (as I recall, under
Linux) and Python 2.0 under Windows:

import sys
import os
import time

True, False = 1, 0

class SshException(Exception): pass

class LinuxSshSession:

    PAT_PASSWORD = '[pP]assword:'

    def __init__(self, host, user, password, timeout=30):
        self.host = host
        self.user = user
        self.password = password
        self.timeout = timeout
        self.verbose = True

    def scp(self, src, dest):
        import pexpect
        user = self.user
        host = self.host

        if self.verbose:
            sys.stdout.write('scp %(src)s %(user)s@%(host)s:%(dest)s ...' % locals())
            sys.stdout.flush()
            began = time.time()

        try:
            # use compression (not that that would help with a .tgz file
            # and make sure we don't get messed up by the known_hosts file
            child = pexpect.spawn('scp -C'
                ' -o UserKnownHostsFile=/dev/null'
                ' -o StrictHostKeyChecking=no'
                ' %(src)s %(user)s@%(host)s:%(dest)s' % locals())
            state = 'authorizing'
            while 1:
                #~ print '%s: %r///%r' % (state, child.before, child.after)
                if state == 'authorizing':
                    match = child.expect([pexpect.EOF, pexpect.TIMEOUT, self.PAT_PASSWORD],
                        timeout=self.timeout)
                    if match == 0:
                        raise SshException('failed to authenticate')
                    elif match == 1:
                        raise SshException('timeout waiting to authenticate')
                    elif match == 2:
                        child.sendline(self.password)
                        state = 'copying'

                elif state == 'copying':
                    match = child.expect([pexpect.EOF, pexpect.TIMEOUT, 'stalled', 'ETA'],
                        timeout=self.timeout)
                    if match == 0:
                        break
                    elif match == 1:
                        raise SshException('timeout waiting for response')
                    elif match == 2:
                        state = 'stalled'

                elif state == 'stalled':
                    match = child.expect([pexpect.EOF, pexpect.TIMEOUT, 'ETA'],
                        timeout=self.timeout)
                    if match == 0:
                        break
                    elif match == 1:
                        import pdb
                        pdb.set_trace()
                        raise SshException('stalled for too long, aborted copy')
                    elif match == 2:
                        state = 'copying'

        finally:
            if self.verbose:
                elapsed = time.time() - began
                try:
                    size = os.stat(src)[os.path.stat.ST_SIZE]
                    rate = size / elapsed
                    sys.stdout.write(' %.1fs (%d cps)\n' % (elapsed, rate))
                except:
                    sys.stdout.write(' %.1fs\n' % (elapsed))


    def ssh(self, cmd):
        import pexpect
        user = self.user
        host = self.host

        if self.verbose:
            sys.stdout.write('ssh -l %(user)s %(host)s \"%(cmd)s\"\n' % locals())
            sys.stdout.flush()

        # use compression
        # -o options make sure we don't get messed up by the known_hosts file
        child = pexpect.spawn('ssh -C'
            ' -o UserKnownHostsFile=/dev/null'
            ' -o StrictHostKeyChecking=no'
            ' -l %(user)s %(host)s '
            '\"%(cmd)s\"' % locals())
        state = 'authorizing'
        while 1:
            if state == 'authorizing':
                match = child.expect([pexpect.EOF, pexpect.TIMEOUT, self.PAT_PASSWORD],
                    timeout=self.timeout)
                if match == 0:
                    raise SshException('failed to authenticate')
                elif match == 1:
                    raise SshException('timeout waiting to authenticate')
                elif match == 2:
                    child.sendline(self.password)
                    state = 'running'

            elif state == 'running':
                match = child.expect([pexpect.EOF, pexpect.TIMEOUT],
                    timeout=self.timeout)
                if match == 0:
                    break
                elif match == 1:
                    raise SshException('timeout waiting to finish')

        return child.before


class WindowsSshSession:
    def __init__(self, host, user, password, timeout=30):
        self.host = host
        self.user = user
        self.password = password

    def scp(self, src, dest):
        user = self.user
        host = self.host
        password = self.password
        return os.system('pscp -pw %(password)s %(src)s %(user)s@%(host)s:%(dest)s' % locals())

    def ssh(self, cmd):
        user = self.user
        host = self.host
        password = self.password
        os.system('plink -pw %(password)s -ssh %(user)s@%(host)s "%(cmd)s"' % locals())


def SshSession(host, user, password, timeout=30):
    if sys.platform == 'win32':
        sessionClass = WindowsSshSession
    else:
        # assume we're on linux if platform is not windows
        sessionClass = LinuxSshSession
    return sessionClass(host, user, password, timeout)


-Peter




More information about the Python-list mailing list