Chapter 16 ■ telnet and SSh
300
The fact that Telnet is ignorant of authentication has an important consequence: you cannot give any arguments
to the Telnet command itself to be preauthenticated to the remote system, nor avoid the login and password prompts
that will pop up when you first connect. If you are going to use plain Telnet, somehow you are going to have to watch
the incoming text for those two prompts (or however many prompts the remote system supplies) and then respond by
typing the correct replies.
Obviously, if systems vary in what username and password prompts they present, then you can hardly expect
standardization in the error messages or responses that are printed when your password fails. That is why Telnet is so
hard to script and program from a language like Python. Unless you know every single error message that the remote
system could print in response to your login and password—which might not just be its “bad password” message but
also things like “cannot spawn shell: out of memory,” “home directory not mounted,” and “quota exceeded: confining
you to a restricted shell”—your script will sometimes run into situations where it is waiting to see either a command
prompt or a particular error message, and it will instead simply wait forever without seeing anything in the inbound
character stream that it recognizes.
Therefore, if you are using Telnet, you are playing a purely textual game. You watch for text to arrive and then try
to reply with something intelligible to the remote system. To help you with this, the Python telnetlib provides not
only basic methods for sending and receiving data but also a few routines that will watch and wait for a particular
string to arrive from the remote system. In this respect, telnetlib is a little bit like the third-party Python pexpect
library that I mentioned earlier in this chapter, and therefore it is a bit like the venerable Unix expect command. In
fact, one of these telnetlib routines is, in honor of its predecessor, named expect().
Listing 16-2 connects to a host, automates the entire back-and-forth login conversation itself, and then runs a
simple command so that you can see its output. This is what it looks like, minimally, to automate a Telnet conversation.
Listing 16-2. Logging Into a Remote Host Using Telnet
#!/usr/bin/env python3
Foundations of Python Network Programming, Third Edition
https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter16/telnet_login.py
Connect to localhost, watch for a login prompt, and try logging in
import argparse, getpass, telnetlib
def main(hostname, username, password):
t = telnetlib.Telnet(hostname)
t.set_debuglevel(1) # uncomment to get debug messages
t.read_until(b'login:')
t.write(username.encode('utf-8'))
t.write(b'\r')
t.read_until(b'assword:') # first letter might be 'p' or 'P'
t.write(password.encode('utf-8'))
t.write(b'\r')
n, match, previous_text = t.expect([br'Login incorrect', br'\$'], 10)
if n == 0:
print('Username and password failed - giving up')
else:
t.write(b'exec uptime\r')
print(t.read_all().decode('utf-8')) # read until socket closes
if name == 'main':
parser = argparse.ArgumentParser(description='Use Telnet to log in')
parser.add_argument('hostname', help='Remote host to telnet to')
parser.add_argument('username', help='Remote username')