| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
""" |
|---|
| 5 |
TAP plugin for creating telnet- and ssh-accessible manhole servers. |
|---|
| 6 |
|
|---|
| 7 |
@author: Jp Calderone |
|---|
| 8 |
""" |
|---|
| 9 |
|
|---|
| 10 |
from zope.interface import implements |
|---|
| 11 |
|
|---|
| 12 |
from twisted.internet import protocol |
|---|
| 13 |
from twisted.application import service, strports |
|---|
| 14 |
from twisted.conch.ssh import session |
|---|
| 15 |
from twisted.conch import interfaces as iconch |
|---|
| 16 |
from twisted.cred import portal, checkers |
|---|
| 17 |
from twisted.python import usage |
|---|
| 18 |
|
|---|
| 19 |
from twisted.conch.insults import insults |
|---|
| 20 |
from twisted.conch import manhole, manhole_ssh, telnet |
|---|
| 21 |
|
|---|
| 22 |
class makeTelnetProtocol: |
|---|
| 23 |
def __init__(self, portal): |
|---|
| 24 |
self.portal = portal |
|---|
| 25 |
|
|---|
| 26 |
def __call__(self): |
|---|
| 27 |
auth = telnet.AuthenticatingTelnetProtocol |
|---|
| 28 |
args = (self.portal,) |
|---|
| 29 |
return telnet.TelnetTransport(auth, *args) |
|---|
| 30 |
|
|---|
| 31 |
class chainedProtocolFactory: |
|---|
| 32 |
def __init__(self, namespace): |
|---|
| 33 |
self.namespace = namespace |
|---|
| 34 |
|
|---|
| 35 |
def __call__(self): |
|---|
| 36 |
return insults.ServerProtocol(manhole.ColoredManhole, self.namespace) |
|---|
| 37 |
|
|---|
| 38 |
class _StupidRealm: |
|---|
| 39 |
implements(portal.IRealm) |
|---|
| 40 |
|
|---|
| 41 |
def __init__(self, proto, *a, **kw): |
|---|
| 42 |
self.protocolFactory = proto |
|---|
| 43 |
self.protocolArgs = a |
|---|
| 44 |
self.protocolKwArgs = kw |
|---|
| 45 |
|
|---|
| 46 |
def requestAvatar(self, avatarId, *interfaces): |
|---|
| 47 |
if telnet.ITelnetProtocol in interfaces: |
|---|
| 48 |
return (telnet.ITelnetProtocol, |
|---|
| 49 |
self.protocolFactory(*self.protocolArgs, **self.protocolKwArgs), |
|---|
| 50 |
lambda: None) |
|---|
| 51 |
raise NotImplementedError() |
|---|
| 52 |
|
|---|
| 53 |
class Options(usage.Options): |
|---|
| 54 |
optParameters = [ |
|---|
| 55 |
["telnetPort", "t", None, "strports description of the address on which to listen for telnet connections"], |
|---|
| 56 |
["sshPort", "s", None, "strports description of the address on which to listen for ssh connections"], |
|---|
| 57 |
["passwd", "p", "/etc/passwd", "name of a passwd(5)-format username/password file"]] |
|---|
| 58 |
|
|---|
| 59 |
def __init__(self): |
|---|
| 60 |
usage.Options.__init__(self) |
|---|
| 61 |
self.users = [] |
|---|
| 62 |
self['namespace'] = None |
|---|
| 63 |
|
|---|
| 64 |
def opt_user(self, name): |
|---|
| 65 |
self.users.append(name) |
|---|
| 66 |
|
|---|
| 67 |
def postOptions(self): |
|---|
| 68 |
if self['telnetPort'] is None and self['sshPort'] is None: |
|---|
| 69 |
raise usage.UsageError("At least one of --telnetPort and --sshPort must be specified") |
|---|
| 70 |
|
|---|
| 71 |
def makeService(options): |
|---|
| 72 |
"""Create a manhole server service. |
|---|
| 73 |
|
|---|
| 74 |
@type options: C{dict} |
|---|
| 75 |
@param options: A mapping describing the configuration of |
|---|
| 76 |
the desired service. Recognized key/value pairs are:: |
|---|
| 77 |
|
|---|
| 78 |
"telnetPort": strports description of the address on which |
|---|
| 79 |
to listen for telnet connections. If None, |
|---|
| 80 |
no telnet service will be started. |
|---|
| 81 |
|
|---|
| 82 |
"sshPort": strports description of the address on which to |
|---|
| 83 |
listen for ssh connections. If None, no ssh |
|---|
| 84 |
service will be started. |
|---|
| 85 |
|
|---|
| 86 |
"namespace": dictionary containing desired initial locals |
|---|
| 87 |
for manhole connections. If None, an empty |
|---|
| 88 |
dictionary will be used. |
|---|
| 89 |
|
|---|
| 90 |
"passwd": Name of a passwd(5)-format username/password file. |
|---|
| 91 |
|
|---|
| 92 |
@rtype: L{twisted.application.service.IService} |
|---|
| 93 |
@return: A manhole service. |
|---|
| 94 |
""" |
|---|
| 95 |
|
|---|
| 96 |
svc = service.MultiService() |
|---|
| 97 |
|
|---|
| 98 |
namespace = options['namespace'] |
|---|
| 99 |
if namespace is None: |
|---|
| 100 |
namespace = {} |
|---|
| 101 |
|
|---|
| 102 |
checker = checkers.FilePasswordDB(options['passwd']) |
|---|
| 103 |
|
|---|
| 104 |
if options['telnetPort']: |
|---|
| 105 |
telnetRealm = _StupidRealm(telnet.TelnetBootstrapProtocol, |
|---|
| 106 |
insults.ServerProtocol, |
|---|
| 107 |
manhole.ColoredManhole, |
|---|
| 108 |
namespace) |
|---|
| 109 |
|
|---|
| 110 |
telnetPortal = portal.Portal(telnetRealm, [checker]) |
|---|
| 111 |
|
|---|
| 112 |
telnetFactory = protocol.ServerFactory() |
|---|
| 113 |
telnetFactory.protocol = makeTelnetProtocol(telnetPortal) |
|---|
| 114 |
telnetService = strports.service(options['telnetPort'], |
|---|
| 115 |
telnetFactory) |
|---|
| 116 |
telnetService.setServiceParent(svc) |
|---|
| 117 |
|
|---|
| 118 |
if options['sshPort']: |
|---|
| 119 |
sshRealm = manhole_ssh.TerminalRealm() |
|---|
| 120 |
sshRealm.chainedProtocolFactory = chainedProtocolFactory(namespace) |
|---|
| 121 |
|
|---|
| 122 |
sshPortal = portal.Portal(sshRealm, [checker]) |
|---|
| 123 |
sshFactory = manhole_ssh.ConchFactory(sshPortal) |
|---|
| 124 |
sshService = strports.service(options['sshPort'], |
|---|
| 125 |
sshFactory) |
|---|
| 126 |
sshService.setServiceParent(svc) |
|---|
| 127 |
|
|---|
| 128 |
return svc |
|---|