123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- TAP plugin for creating telnet- and ssh-accessible manhole servers.
- @author: Jp Calderone
- """
- from zope.interface import implementer
- from twisted.application import service, strports
- from twisted.conch import manhole, manhole_ssh, telnet
- from twisted.conch.insults import insults
- from twisted.conch.ssh import keys
- from twisted.cred import checkers, portal
- from twisted.internet import protocol
- from twisted.python import filepath, usage
- class makeTelnetProtocol:
- def __init__(self, portal):
- self.portal = portal
- def __call__(self):
- auth = telnet.AuthenticatingTelnetProtocol
- args = (self.portal,)
- return telnet.TelnetTransport(auth, *args)
- class chainedProtocolFactory:
- def __init__(self, namespace):
- self.namespace = namespace
- def __call__(self):
- return insults.ServerProtocol(manhole.ColoredManhole, self.namespace)
- @implementer(portal.IRealm)
- class _StupidRealm:
- def __init__(self, proto, *a, **kw):
- self.protocolFactory = proto
- self.protocolArgs = a
- self.protocolKwArgs = kw
- def requestAvatar(self, avatarId, *interfaces):
- if telnet.ITelnetProtocol in interfaces:
- return (
- telnet.ITelnetProtocol,
- self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs),
- lambda: None,
- )
- raise NotImplementedError()
- class Options(usage.Options):
- optParameters = [
- [
- "telnetPort",
- "t",
- None,
- (
- "strports description of the address on which to listen for telnet "
- "connections"
- ),
- ],
- [
- "sshPort",
- "s",
- None,
- (
- "strports description of the address on which to listen for ssh "
- "connections"
- ),
- ],
- [
- "passwd",
- "p",
- "/etc/passwd",
- "name of a passwd(5)-format username/password file",
- ],
- [
- "sshKeyDir",
- None,
- "<USER DATA DIR>",
- "Directory where the autogenerated SSH key is kept.",
- ],
- ["sshKeyName", None, "server.key", "Filename of the autogenerated SSH key."],
- ["sshKeySize", None, 4096, "Size of the automatically generated SSH key."],
- ]
- def __init__(self):
- usage.Options.__init__(self)
- self["namespace"] = None
- def postOptions(self):
- if self["telnetPort"] is None and self["sshPort"] is None:
- raise usage.UsageError(
- "At least one of --telnetPort and --sshPort must be specified"
- )
- def makeService(options):
- """
- Create a manhole server service.
- @type options: L{dict}
- @param options: A mapping describing the configuration of
- the desired service. Recognized key/value pairs are::
- "telnetPort": strports description of the address on which
- to listen for telnet connections. If None,
- no telnet service will be started.
- "sshPort": strports description of the address on which to
- listen for ssh connections. If None, no ssh
- service will be started.
- "namespace": dictionary containing desired initial locals
- for manhole connections. If None, an empty
- dictionary will be used.
- "passwd": Name of a passwd(5)-format username/password file.
- "sshKeyDir": The folder that the SSH server key will be kept in.
- "sshKeyName": The filename of the key.
- "sshKeySize": The size of the key, in bits. Default is 4096.
- @rtype: L{twisted.application.service.IService}
- @return: A manhole service.
- """
- svc = service.MultiService()
- namespace = options["namespace"]
- if namespace is None:
- namespace = {}
- checker = checkers.FilePasswordDB(options["passwd"])
- if options["telnetPort"]:
- telnetRealm = _StupidRealm(
- telnet.TelnetBootstrapProtocol,
- insults.ServerProtocol,
- manhole.ColoredManhole,
- namespace,
- )
- telnetPortal = portal.Portal(telnetRealm, [checker])
- telnetFactory = protocol.ServerFactory()
- telnetFactory.protocol = makeTelnetProtocol(telnetPortal)
- telnetService = strports.service(options["telnetPort"], telnetFactory)
- telnetService.setServiceParent(svc)
- if options["sshPort"]:
- sshRealm = manhole_ssh.TerminalRealm()
- sshRealm.chainedProtocolFactory = chainedProtocolFactory(namespace)
- sshPortal = portal.Portal(sshRealm, [checker])
- sshFactory = manhole_ssh.ConchFactory(sshPortal)
- if options["sshKeyDir"] != "<USER DATA DIR>":
- keyDir = options["sshKeyDir"]
- else:
- from twisted.python._appdirs import getDataDirectory
- keyDir = getDataDirectory()
- keyLocation = filepath.FilePath(keyDir).child(options["sshKeyName"])
- sshKey = keys._getPersistentRSAKey(keyLocation, int(options["sshKeySize"]))
- sshFactory.publicKeys[b"ssh-rsa"] = sshKey
- sshFactory.privateKeys[b"ssh-rsa"] = sshKey
- sshService = strports.service(options["sshPort"], sshFactory)
- sshService.setServiceParent(svc)
- return svc
|