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."