<br><tt><font size=2>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.</font></tt>
<br>
<br><tt><font size=2>Here's the line that instaniates my SSH object (also
repeated at the end of my code):</font></tt>
<br>
<br><tt><font size=2>myssh = SSH("my.host.com", "myusername",
"mypasswd", ["id; su - root; myrootpasswd; id", "pwd",
"ls -l"])</font></tt>
<br>
<br><tt><font size=2>The last argument above is a list of three commands.
Inside one command ";" separates the piece parts.</font></tt>
<br><tt><font size=2>I am not even able to su to accounts that don't require
a password.</font></tt>
<br>
<br><tt><font size=2>###========= CODE STARTS ================###</font></tt>
<br><tt><font size=2>from twisted.conch import error</font></tt>
<br><tt><font size=2>from twisted.conch.ssh import transport, connection,
keys, userauth, channel, common</font></tt>
<br><tt><font size=2>from twisted.internet import defer, protocol, reactor</font></tt>
<br><tt><font size=2>import sys, getpass, os, string</font></tt>
<br>
<br><tt><font size=2>class ClientCommandTransport(transport.SSHClientTransport):</font></tt>
<br><tt><font size=2> def __init__(self, username, password,
cmds, caller):</font></tt>
<br><tt><font size=2> self.username = username</font></tt>
<br><tt><font size=2> self.password = password</font></tt>
<br><tt><font size=2> self.cmds = cmds</font></tt>
<br><tt><font size=2> self.caller = caller</font></tt>
<br><tt><font size=2> </font></tt>
<br><tt><font size=2> def verifyHostKey(self, pubKey, fingerprint):</font></tt>
<br><tt><font size=2> # in a real app, you should
verify that the fingerprint matches</font></tt>
<br><tt><font size=2> # the one you expected
to get from this server</font></tt>
<br><tt><font size=2> return defer.succeed(True)</font></tt>
<br>
<br><tt><font size=2> def connectionSecure(self):</font></tt>
<br><tt><font size=2> self.requestService(PasswordAuth(self.username,
self.password, ClientConnection(self.cmds, self.caller)))</font></tt>
<br>
<br><tt><font size=2>class PasswordAuth(userauth.SSHUserAuthClient):</font></tt>
<br><tt><font size=2> def __init__(self, user, password, connection):</font></tt>
<br><tt><font size=2> userauth.SSHUserAuthClient.__init__(self,
user, connection)</font></tt>
<br><tt><font size=2> self.password = password</font></tt>
<br><tt><font size=2> </font></tt>
<br><tt><font size=2> def getPassword(self, prompt=None):</font></tt>
<br><tt><font size=2> return defer.succeed(self.password)</font></tt>
<br>
<br><tt><font size=2>class ClientConnection(connection.SSHConnection):</font></tt>
<br><tt><font size=2> def __init__(self, cmds, caller, *args,
**kwargs):</font></tt>
<br><tt><font size=2> connection.SSHConnection.__init__(self)</font></tt>
<br><tt><font size=2> self.cmds = cmds</font></tt>
<br><tt><font size=2> self.caller = caller</font></tt>
<br>
<br><tt><font size=2> #======================</font></tt>
<br><tt><font size=2> def serviceStarted(self):</font></tt>
<br><tt><font size=2> self.d = defer.Deferred()</font></tt>
<br><tt><font size=2> self.d.addCallback(self._cbFirst)</font></tt>
<br><tt><font size=2> self.d.addErrback(self._ebFirst)</font></tt>
<br><tt><font size=2> self.openChannel(CommandChannel(self.cmds[0],
lastcmd=0, conn=self))</font></tt>
<br>
<br><tt><font size=2> def _cbFirst(self, result):</font></tt>
<br><tt><font size=2> #print 'CALLBACK Result
1:', result</font></tt>
<br><tt><font size=2> self.caller.responses.append(result.rstrip())</font></tt>
<br><tt><font size=2> self.d = defer.Deferred()</font></tt>
<br><tt><font size=2> self.d.addCallback(self._cbSecond)</font></tt>
<br><tt><font size=2> self.d.addErrback(self._ebSecond)</font></tt>
<br><tt><font size=2> self.openChannel(CommandChannel(self.cmds[1],
lastcmd=0, conn=self))</font></tt>
<br>
<br><tt><font size=2> def _ebFirst(self, f):</font></tt>
<br><tt><font size=2> self.caller.responses.append(None)</font></tt>
<br><tt><font size=2> print "Error 1"</font></tt>
<br><tt><font size=2> self.d = defer.Deferred()</font></tt>
<br><tt><font size=2> self.d.addCallback(self._cbSecond)</font></tt>
<br><tt><font size=2> self.d.addErrback(self._ebSecond)</font></tt>
<br><tt><font size=2> self.openChannel(CommandChannel(self.cmds[1],
lastcmd=0, conn=self))</font></tt>
<br><tt><font size=2> #log.err()</font></tt>
<br>
<br><tt><font size=2> def _cbSecond(self, result):</font></tt>
<br><tt><font size=2> #print 'CALLBACK Result
2:', result</font></tt>
<br><tt><font size=2> self.caller.responses.append(result.rstrip())</font></tt>
<br><tt><font size=2> self.d = defer.Deferred()</font></tt>
<br><tt><font size=2> self.d.addCallback(self._cbThird)</font></tt>
<br><tt><font size=2> self.d.addErrback(self._ebThird)</font></tt>
<br><tt><font size=2> self.openChannel(CommandChannel(self.cmds[2],
lastcmd=1, conn=self))</font></tt>
<br>
<br><tt><font size=2> def _ebSecond(self, f):</font></tt>
<br><tt><font size=2> self.caller.responses.append(None)</font></tt>
<br><tt><font size=2> self.d = defer.Deferred()</font></tt>
<br><tt><font size=2> self.d.addCallback(self._cbThird)</font></tt>
<br><tt><font size=2> self.d.addErrback(self._ebThird)</font></tt>
<br><tt><font size=2> self.openChannel(CommandChannel(self.cmds[2],
lastcmd=1, conn=self))</font></tt>
<br><tt><font size=2> #log.err()</font></tt>
<br>
<br><tt><font size=2> def _cbThird(self, result):</font></tt>
<br><tt><font size=2> self.caller.responses.append(result.rstrip())</font></tt>
<br><tt><font size=2> #print 'CALLBACK Result
3:', result</font></tt>
<br><tt><font size=2> reactor.stop()</font></tt>
<br>
<br><tt><font size=2> def _ebThird(self, f):</font></tt>
<br><tt><font size=2> self.caller.responses.append(None)</font></tt>
<br><tt><font size=2> log.err()</font></tt>
<br><tt><font size=2> reactor.stop()</font></tt>
<br><tt><font size=2> #======================</font></tt>
<br>
<br><tt><font size=2>class CommandChannel(channel.SSHChannel):</font></tt>
<br><tt><font size=2> name = 'session'</font></tt>
<br><tt><font size=2> </font></tt>
<br><tt><font size=2> def __init__(self, command, lastcmd,
*args, **kwargs):</font></tt>
<br><tt><font size=2> channel.SSHChannel.__init__(self,
*args, **kwargs)</font></tt>
<br><tt><font size=2> self.command = command</font></tt>
<br><tt><font size=2> self.lastcmd = lastcmd</font></tt>
<br><tt><font size=2> self.data = ""</font></tt>
<br>
<br><tt><font size=2> def channelOpen(self, data):</font></tt>
<br><tt><font size=2> self.conn.sendRequest(self,
'exec', common.NS(self.command), wantReply=True).addCallback(self._gotResponse)</font></tt>
<br>
<br><tt><font size=2> def _gotResponse(self, _):</font></tt>
<br><tt><font size=2> #print "RESPONSE"</font></tt>
<br><tt><font size=2> self.conn.sendEOF(self)</font></tt>
<br>
<br><tt><font size=2> def dataReceived(self, data):</font></tt>
<br><tt><font size=2> #print "Data Received:",
data</font></tt>
<br><tt><font size=2> self.data += data</font></tt>
<br>
<br><tt><font size=2> def closed(self):</font></tt>
<br><tt><font size=2> self.conn.d.callback(self.data)</font></tt>
<br><tt><font size=2> self.loseConnection()</font></tt>
<br><tt><font size=2> ##
if self.lastcmd:</font></tt>
<br><tt><font size=2> ##
print "closing reactor."</font></tt>
<br><tt><font size=2> ##
reactor.stop()</font></tt>
<br>
<br><tt><font size=2>class ClientCommandFactory(protocol.ClientFactory):</font></tt>
<br><tt><font size=2> def __init__(self, username, password,
cmds, caller):</font></tt>
<br><tt><font size=2> self.username = username</font></tt>
<br><tt><font size=2> self.password = password</font></tt>
<br><tt><font size=2> self.cmds = cmds</font></tt>
<br><tt><font size=2> self.caller = caller</font></tt>
<br>
<br><tt><font size=2> def buildProtocol(self, addr):</font></tt>
<br><tt><font size=2> protocol = ClientCommandTransport(self.username,
self.password, self.cmds, self.caller)</font></tt>
<br><tt><font size=2> return protocol</font></tt>
<br>
<br><tt><font size=2> </font></tt>
<br><tt><font size=2>class SSH():</font></tt>
<br><tt><font size=2> """ Contains a SSH connection,
runs commands, and stores results. """</font></tt>
<br><tt><font size=2> def __init__(self, host, username, password,
cmds):</font></tt>
<br><tt><font size=2> self.host = host</font></tt>
<br><tt><font size=2> self.username = username</font></tt>
<br><tt><font size=2> self.password = password</font></tt>
<br><tt><font size=2> self.cmds = cmds</font></tt>
<br><tt><font size=2> self.responses = []</font></tt>
<br><tt><font size=2> self.run_commands()</font></tt>
<br>
<br><tt><font size=2> def run_commands(self):</font></tt>
<br><tt><font size=2> factory = ClientCommandFactory(self.username,
self.password, self.cmds, self)</font></tt>
<br><tt><font size=2> reactor.connectTCP(self.host,
22, factory)</font></tt>
<br><tt><font size=2> reactor.run()</font></tt>
<br>
<br><tt><font size=2>myssh = SSH("my.host.com", "myacct",
"mypasswd", ["id; su - root; myrootpasswd; id", "pwd",
"ls -l"])</font></tt>
<br>
<br><tt><font size=2>print "=" * 25</font></tt>
<br><tt><font size=2>for i, response in enumerate(myssh.responses):</font></tt>
<br><tt><font size=2> print i, response</font></tt>
<br><tt><font size=2> print "=" * 25</font></tt>
<br>
<br><tt><font size=2>print "\nDone."</font></tt>