1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 from twisted.internet import defer, protocol, reactor
6 from twisted.conch import error
7 from twisted.conch.ssh import transport
8 from twisted.python import log
12 class SSHClientFactory(protocol.ClientFactory):
14 def __init__(self, d, options, verifyHostKey, userAuthObject):
16 self.options = options
17 self.verifyHostKey = verifyHostKey
18 self.userAuthObject = userAuthObject
21 def clientConnectionLost(self, connector, reason):
22 if self.options['reconnect']:
26 def clientConnectionFailed(self, connector, reason):
29 d, self.d = self.d, None
33 def buildProtocol(self, addr):
34 trans = SSHClientTransport(self)
35 if self.options['ciphers']:
36 trans.supportedCiphers = self.options['ciphers']
37 if self.options['macs']:
38 trans.supportedMACs = self.options['macs']
39 if self.options['compress']:
40 trans.supportedCompressions[0:1] = ['zlib']
41 if self.options['host-key-algorithms']:
42 trans.supportedPublicKeys = self.options['host-key-algorithms']
47 class SSHClientTransport(transport.SSHClientTransport):
49 def __init__(self, factory):
50 self.factory = factory
51 self.unixServer = None
54 def connectionLost(self, reason):
56 d = self.unixServer.stopListening()
57 self.unixServer = None
59 d = defer.succeed(None)
60 d.addCallback(lambda x:
61 transport.SSHClientTransport.connectionLost(self, reason))
64 def receiveError(self, code, desc):
65 if self.factory.d is None:
67 d, self.factory.d = self.factory.d, None
68 d.errback(error.ConchError(desc, code))
71 def sendDisconnect(self, code, reason):
72 if self.factory.d is None:
74 d, self.factory.d = self.factory.d, None
75 transport.SSHClientTransport.sendDisconnect(self, code, reason)
76 d.errback(error.ConchError(reason, code))
79 def receiveDebug(self, alwaysDisplay, message, lang):
80 log.msg('Received Debug Message: %s' % message)
81 if alwaysDisplay: # XXX what should happen here?
85 def verifyHostKey(self, pubKey, fingerprint):
86 return self.factory.verifyHostKey(self, self.transport.getPeer().host, pubKey,
90 def setService(self, service):
91 log.msg('setting client server to %s' % service)
92 transport.SSHClientTransport.setService(self, service)
93 if service.name != 'ssh-userauth' and self.factory.d is not None:
94 d, self.factory.d = self.factory.d, None
98 def connectionSecure(self):
99 self.requestService(self.factory.userAuthObject)
103 def connect(host, port, options, verifyHostKey, userAuthObject):
105 factory = SSHClientFactory(d, options, verifyHostKey, userAuthObject)
106 reactor.connectTCP(host, port, factory)