factory.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. A Factory for SSH servers.
  5. See also L{twisted.conch.openssh_compat.factory} for OpenSSH compatibility.
  6. Maintainer: Paul Swartz
  7. """
  8. from __future__ import division, absolute_import
  9. from twisted.internet import protocol
  10. from twisted.python import log
  11. from twisted.conch import error
  12. from twisted.conch.ssh import (_kex, transport, userauth, connection)
  13. import random
  14. class SSHFactory(protocol.Factory):
  15. """
  16. A Factory for SSH servers.
  17. """
  18. protocol = transport.SSHServerTransport
  19. services = {
  20. b'ssh-userauth':userauth.SSHUserAuthServer,
  21. b'ssh-connection':connection.SSHConnection
  22. }
  23. def startFactory(self):
  24. """
  25. Check for public and private keys.
  26. """
  27. if not hasattr(self,'publicKeys'):
  28. self.publicKeys = self.getPublicKeys()
  29. if not hasattr(self,'privateKeys'):
  30. self.privateKeys = self.getPrivateKeys()
  31. if not self.publicKeys or not self.privateKeys:
  32. raise error.ConchError('no host keys, failing')
  33. if not hasattr(self,'primes'):
  34. self.primes = self.getPrimes()
  35. def buildProtocol(self, addr):
  36. """
  37. Create an instance of the server side of the SSH protocol.
  38. @type addr: L{twisted.internet.interfaces.IAddress} provider
  39. @param addr: The address at which the server will listen.
  40. @rtype: L{twisted.conch.ssh.transport.SSHServerTransport}
  41. @return: The built transport.
  42. """
  43. t = protocol.Factory.buildProtocol(self, addr)
  44. t.supportedPublicKeys = self.privateKeys.keys()
  45. if not self.primes:
  46. log.msg('disabling non-fixed-group key exchange algorithms '
  47. 'because we cannot find moduli file')
  48. t.supportedKeyExchanges = [
  49. kexAlgorithm for kexAlgorithm in t.supportedKeyExchanges
  50. if _kex.isFixedGroup(kexAlgorithm) or
  51. _kex.isEllipticCurve(kexAlgorithm)]
  52. return t
  53. def getPublicKeys(self):
  54. """
  55. Called when the factory is started to get the public portions of the
  56. servers host keys. Returns a dictionary mapping SSH key types to
  57. public key strings.
  58. @rtype: L{dict}
  59. """
  60. raise NotImplementedError('getPublicKeys unimplemented')
  61. def getPrivateKeys(self):
  62. """
  63. Called when the factory is started to get the private portions of the
  64. servers host keys. Returns a dictionary mapping SSH key types to
  65. L{twisted.conch.ssh.keys.Key} objects.
  66. @rtype: L{dict}
  67. """
  68. raise NotImplementedError('getPrivateKeys unimplemented')
  69. def getPrimes(self):
  70. """
  71. Called when the factory is started to get Diffie-Hellman generators and
  72. primes to use. Returns a dictionary mapping number of bits to lists
  73. of tuple of (generator, prime).
  74. @rtype: L{dict}
  75. """
  76. def getDHPrime(self, bits):
  77. """
  78. Return a tuple of (g, p) for a Diffe-Hellman process, with p being as
  79. close to bits bits as possible.
  80. @type bits: L{int}
  81. @rtype: L{tuple}
  82. """
  83. primesKeys = sorted(self.primes.keys(), key=lambda i: abs(i - bits))
  84. realBits = primesKeys[0]
  85. return random.choice(self.primes[realBits])
  86. def getService(self, transport, service):
  87. """
  88. Return a class to use as a service for the given transport.
  89. @type transport: L{transport.SSHServerTransport}
  90. @type service: L{bytes}
  91. @rtype: subclass of L{service.SSHService}
  92. """
  93. if service == b'ssh-userauth' or hasattr(transport, 'avatar'):
  94. return self.services[service]