Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources]

David Ascher, Alex Martelli, Anna Ravenscroft

نسخه متنی -صفحه : 394/ 304
نمايش فراداده

Recipe 15.9. Performing Remote Logins Using telnetlib

Credit: Jeff Bauer

Problem

You need to send commands to one or more logins that can be on a local machine, or a remote machine, and the Telnet protocol is acceptable.

Solution

Telnet is one of the oldest protocols in the TCP/IP stack, but it may still be serviceable (at least within an intranet that is well protected against sniffing and spoofing attacks). In any case, Python's standard module telnetlib supports Telnet quite well:

# auto_telnet.py - remote control via telnet
import os, sys, telnetlib
from getpass import getpass
class AutoTelnet(object):
def _ _init_ _(self, user_list, cmd_list, **kw):
# optional parameters are host, timeout in seconds, command
# prompt to expect from the host on successful logins:
self.host = kw.get('host', 'localhost')
self.timeout = kw.get('timeout', 600)
self.command_prompt = kw.get('command_prompt', "$ ")
# collect passwords for each user, interactively
self.passwd = {  }
for user in user_list:
self.passwd[user] = getpass("Enter user '%s' password: " % user)
# instantiate Telnet proxy
self.telnet = telnetlib.Telnet( )
for user in user_list:
# login with given host and user, and act appropriately
self.telnet.open(self.host)
ok = self.action(user, cmd_list)
if not ok:
print "Unable to process:", user
self.telnet.close( )
def action(self, user, cmd_list):
# wait for a login prompt
t = self.telnet
t.write("\n")
login_prompt = "login: "
response = t.read_until(login_prompt, 5)
if login_prompt in response:
print response
else:
return 0
# supply user and password for login
t.write("%s\n" % user)
password_prompt = "Password:"
response = t.read_until(password_prompt, 3)
if password_prompt in response:
print response
else:
return 0
t.write("%s\n" % self.passwd[user])
# wait for command prompt to indicate successful login
response = t.read_until(self.command_prompt, 5)
if self.command_prompt not in response:
return 0
# send each command and wait for command prompt after each
for cmd in cmd_list:
t.write("%s\n" % cmd)
response = t.read_until(self.command_prompt, self.timeout)
if self.command_prompt not in response:
return 0
print response
return 1
if _ _name_ _ == '_ _main_ _':
# code which runs as a main script, only
basename = os.path.splitext(os.path.basename(sys.argv[0]))[0]
logname = os.environ.get("LOGNAME", os.environ.get("USERNAME"))
host = 'localhost'
import getopt
optlist, user_list = getopt.getopt(sys.argv[1:], 'c:f:h:')
usage = ""
usage: %s [-h host] [-f cmdfile] [-c "command"] user1 user2 ...
-c  command
-f  command file
-h  host  (default: '%s')
Example:  %s -c "echo $HOME" %s
"" % (basename, host, basename, logname)
if len(sys.argv) < 2:
print usage
sys.exit(1)
cmd_list = [  ]
for opt, optarg in optlist:
if opt == '-f':
for r in open(optarg):
if r.rstrip( ):
cmd_list.append(r)
elif opt == '-c':
command = optarg
if command[0] == '"' and command[-1] == '"':
command = command[1:-1]
cmd_list.append(command)
elif opt == '-h':
host = optarg
autoTelnet = AutoTelnet(user_list, cmd_list, host=host)

Discussion

Python's telnetlib lets you easily automate access to Telnet servers, even from non-Unix machines. As a flexible alternative to the popen functions, which only run commands locally as the user that's running the script, telnetlib, which can work across an intranet and can login and run commands as different users, is a handy technique to have in your system administration toolbox.

Production code generally has to be made more robust, but this recipe should be enough to get you started in the right direction. The recipe's AutoTelnet class instantiates a single telnetlib.Telnet object and uses that single object in a loop over a list of users. For each user, the recipe calls the open method of the Telnet instance to open the connection to the specified host, runs a series of commands in AutoTelnet's action method, and finally calls the close method of the Telnet instance to terminate the connection.

AutoTelnet's action method is where the action is. All operations depend on two methods of the Telnet instance. The write method takes a single string argument and writes it to the connection. The read_until method takes two arguments, a string to wait for and a timeout in seconds, and returns a string with all the characters received from the connection until the timeout elapsed or the waited-for string occurred. action's code uses these two methods to wait for a login prompt and send the username; wait for a password prompt and send the password; and then, repeatedly, wait for a command prompt (typically from a Unix shell at the other end of the connection) and send the commands in the list sequentially (waiting for a command prompt again after sending each one).

One warning (which applies to any use of Telnet and some other old protocols): except when transmitting completely public data, not protected by passwords that might be of interest to intruders of ill will, do not run Telnet (or non-anonymous FTP, for that matter) on networks on which you are not completely sure that nobody is packet-sniffing, since these protocols date from an older, more trusting age. These protocols let passwords and everything else travel in the clear, open to any snooper. This issue is not Python specific; it applies to any implementation of these protocols, since it depends on the definition of the protocols themselves. Whether or not you use Python, be advised: if there is any risk that someone might be packet-sniffing, use SSH instead, as shown next in Recipe 15.10 so that no password ever travels on the network in the clear, and so that the connection stream itself gets encrypted.

See Also

Documentation on the standard library module telnetlib in the Library Reference; Recipe 15.10.