[Twisted-Python] How to switch users in SSH session.
Paul_S_Johnson at mnb.uscourts.gov
Paul_S_Johnson at mnb.uscourts.gov
Thu Sep 27 14:00:14 MDT 2007
After much wrangling and a small miracle I have managed to write an object
that fetches the output of three commands in the order given through an
SSH connection. How come I cannot switch users? Some of the information I
need can only be fetched through a root account and security is such that
I cannot log in remotely from a root account but must switch once logged
in from an account with less than root privileges.
Here's the line that instaniates my SSH object (also repeated at the end
of my code):
myssh = SSH("my.host.com", "myusername", "mypasswd", ["id; su - root;
myrootpasswd; id", "pwd", "ls -l"])
The last argument above is a list of three commands. Inside one command
";" separates the piece parts.
I am not even able to su to accounts that don't require a password.
###========= CODE STARTS ================###
from twisted.conch import error
from twisted.conch.ssh import transport, connection, keys, userauth,
channel, common
from twisted.internet import defer, protocol, reactor
import sys, getpass, os, string
class ClientCommandTransport(transport.SSHClientTransport):
def __init__(self, username, password, cmds, caller):
self.username = username
self.password = password
self.cmds = cmds
self.caller = caller
def verifyHostKey(self, pubKey, fingerprint):
# in a real app, you should verify that the fingerprint matches
# the one you expected to get from this server
return defer.succeed(True)
def connectionSecure(self):
self.requestService(PasswordAuth(self.username, self.password,
ClientConnection(self.cmds, self.caller)))
class PasswordAuth(userauth.SSHUserAuthClient):
def __init__(self, user, password, connection):
userauth.SSHUserAuthClient.__init__(self, user, connection)
self.password = password
def getPassword(self, prompt=None):
return defer.succeed(self.password)
class ClientConnection(connection.SSHConnection):
def __init__(self, cmds, caller, *args, **kwargs):
connection.SSHConnection.__init__(self)
self.cmds = cmds
self.caller = caller
#======================
def serviceStarted(self):
self.d = defer.Deferred()
self.d.addCallback(self._cbFirst)
self.d.addErrback(self._ebFirst)
self.openChannel(CommandChannel(self.cmds[0], lastcmd=0,
conn=self))
def _cbFirst(self, result):
#print 'CALLBACK Result 1:', result
self.caller.responses.append(result.rstrip())
self.d = defer.Deferred()
self.d.addCallback(self._cbSecond)
self.d.addErrback(self._ebSecond)
self.openChannel(CommandChannel(self.cmds[1], lastcmd=0,
conn=self))
def _ebFirst(self, f):
self.caller.responses.append(None)
print "Error 1"
self.d = defer.Deferred()
self.d.addCallback(self._cbSecond)
self.d.addErrback(self._ebSecond)
self.openChannel(CommandChannel(self.cmds[1], lastcmd=0,
conn=self))
#log.err()
def _cbSecond(self, result):
#print 'CALLBACK Result 2:', result
self.caller.responses.append(result.rstrip())
self.d = defer.Deferred()
self.d.addCallback(self._cbThird)
self.d.addErrback(self._ebThird)
self.openChannel(CommandChannel(self.cmds[2], lastcmd=1,
conn=self))
def _ebSecond(self, f):
self.caller.responses.append(None)
self.d = defer.Deferred()
self.d.addCallback(self._cbThird)
self.d.addErrback(self._ebThird)
self.openChannel(CommandChannel(self.cmds[2], lastcmd=1,
conn=self))
#log.err()
def _cbThird(self, result):
self.caller.responses.append(result.rstrip())
#print 'CALLBACK Result 3:', result
reactor.stop()
def _ebThird(self, f):
self.caller.responses.append(None)
log.err()
reactor.stop()
#======================
class CommandChannel(channel.SSHChannel):
name = 'session'
def __init__(self, command, lastcmd, *args, **kwargs):
channel.SSHChannel.__init__(self, *args, **kwargs)
self.command = command
self.lastcmd = lastcmd
self.data = ""
def channelOpen(self, data):
self.conn.sendRequest(self, 'exec', common.NS(self.command),
wantReply=True).addCallback(self._gotResponse)
def _gotResponse(self, _):
#print "RESPONSE"
self.conn.sendEOF(self)
def dataReceived(self, data):
#print "Data Received:", data
self.data += data
def closed(self):
self.conn.d.callback(self.data)
self.loseConnection()
## if self.lastcmd:
## print "closing reactor."
## reactor.stop()
class ClientCommandFactory(protocol.ClientFactory):
def __init__(self, username, password, cmds, caller):
self.username = username
self.password = password
self.cmds = cmds
self.caller = caller
def buildProtocol(self, addr):
protocol = ClientCommandTransport(self.username, self.password,
self.cmds, self.caller)
return protocol
class SSH():
""" Contains a SSH connection, runs commands, and stores results. """
def __init__(self, host, username, password, cmds):
self.host = host
self.username = username
self.password = password
self.cmds = cmds
self.responses = []
self.run_commands()
def run_commands(self):
factory = ClientCommandFactory(self.username, self.password,
self.cmds, self)
reactor.connectTCP(self.host, 22, factory)
reactor.run()
myssh = SSH("my.host.com", "myacct", "mypasswd", ["id; su - root;
myrootpasswd; id", "pwd", "ls -l"])
print "=" * 25
for i, response in enumerate(myssh.responses):
print i, response
print "=" * 25
print "\nDone."
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20070927/1ab7670f/attachment.html>
More information about the Twisted-Python
mailing list