Viewing file: manhole_ssh.py (3.9 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# -*- test-case-name: twisted.conch.test.test_manhole -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details.
""" insults/SSH integration support.
@author: Jp Calderone """
from zope.interface import implementer
from twisted.conch import avatar, interfaces as iconch, error as econch from twisted.conch.ssh import factory, session from twisted.python import components
from twisted.conch.insults import insults
class _Glue: """ A feeble class for making one attribute look like another.
This should be replaced with a real class at some point, probably. Try not to write new code that uses it. """ def __init__(self, **kw): self.__dict__.update(kw)
def __getattr__(self, name): raise AttributeError(self.name, "has no attribute", name)
class TerminalSessionTransport: def __init__(self, proto, chainedProtocol, avatar, width, height): self.proto = proto self.avatar = avatar self.chainedProtocol = chainedProtocol
protoSession = self.proto.session
self.proto.makeConnection( _Glue(write=self.chainedProtocol.dataReceived, loseConnection=lambda: avatar.conn.sendClose(protoSession), name="SSH Proto Transport"))
def loseConnection(): self.proto.loseConnection()
self.chainedProtocol.makeConnection( _Glue(write=self.proto.write, loseConnection=loseConnection, name="Chained Proto Transport"))
# XXX TODO # chainedProtocol is supposed to be an ITerminalTransport, # maybe. That means perhaps its terminalProtocol attribute is # an ITerminalProtocol, it could be. So calling terminalSize # on that should do the right thing But it'd be nice to clean # this bit up. self.chainedProtocol.terminalProtocol.terminalSize(width, height)
@implementer(iconch.ISession) class TerminalSession(components.Adapter): transportFactory = TerminalSessionTransport chainedProtocolFactory = insults.ServerProtocol
def getPty(self, term, windowSize, attrs): self.height, self.width = windowSize[:2]
def openShell(self, proto): self.transportFactory( proto, self.chainedProtocolFactory(), iconch.IConchUser(self.original), self.width, self.height)
def execCommand(self, proto, cmd): raise econch.ConchError("Cannot execute commands")
def closed(self): pass
class TerminalUser(avatar.ConchUser, components.Adapter): def __init__(self, original, avatarId): components.Adapter.__init__(self, original) avatar.ConchUser.__init__(self) self.channelLookup[b'session'] = session.SSHSession
class TerminalRealm: userFactory = TerminalUser sessionFactory = TerminalSession
transportFactory = TerminalSessionTransport chainedProtocolFactory = insults.ServerProtocol
def _getAvatar(self, avatarId): comp = components.Componentized() user = self.userFactory(comp, avatarId) sess = self.sessionFactory(comp)
sess.transportFactory = self.transportFactory sess.chainedProtocolFactory = self.chainedProtocolFactory
comp.setComponent(iconch.IConchUser, user) comp.setComponent(iconch.ISession, sess)
return user
def __init__(self, transportFactory=None): if transportFactory is not None: self.transportFactory = transportFactory
def requestAvatar(self, avatarId, mind, *interfaces): for i in interfaces: if i is iconch.IConchUser: return (iconch.IConchUser, self._getAvatar(avatarId), lambda: None) raise NotImplementedError()
class ConchFactory(factory.SSHFactory): publicKeys = {} privateKeys = {}
def __init__(self, portal): self.portal = portal
|