6.2. Finger: A Simple Directory Service
Finger and
WHOIS are good examples of simple directory services. Finger exists
primarily to provide read-only information about the users of a
machine (although we'll see some more creative uses shortly).
Later versions of Finger, like the GNU Finger server and its
derivatives, expanded upon this basic functionality by allowing you
to query one machine and receive information back from all of the
machines on your network.
Finger was one of the first widely deployed directory services. Once
upon a time, if you wanted to locate a user's email address at
another site, or even within your own, the finger
command was the best option. finger
harry@hogwarts.edu would tell you whether Harry's
email address was harry,
hpotter, or something more obscure (along with
listing all of the other Harrys at that school). Though it is still
in use today, Finger's popularity has waned over time as web
home pages became prevalent and the practice of freely giving out
user information became problematic.
Using the Finger protocol from Perl
provides another good example of TMTOWTDI. When I first looked on
CPAN for something to perform Finger operations, there were no
modules available for this task. If you look now, you'll find
Dennis Taylor's Net::Finger module, which he
published six months or so after my initial search. We'll see
how to use it in a moment, but in the meantime, let's pretend
it doesn't exist and take advantage of this opportunity to
learn how to use a more generic module to talk a specific protocol
when the "perfect" module doesn't exist.
The Finger protocol itself is a very simple TCP/IP-based text
protocol. Defined in RFC1288, it calls for a standard TCP connect to
port 79. The client passes a simple CRLF-terminated[1] string over the connection. This string either requests
specific user information or, if empty, asks for information about
all users of that machine. The server responds with the requested
data and closes the connection at the end of the data stream. You can
see this in action by telnet ing to the Finger
port directly on a remote machine:
[1]Carriage return + linefeed, i.e., ASCII 13 + ASCII 10.
$ telnet kantine.diku.dk 79
Trying 192.38.109.142 ...
Connected to kantine.diku.dk.
Escape character is '^]'.
cola<CR><LF>
Login: cola Name: RHS Linux User
Directory: /home/cola Shell: /bin/noshell
Never logged in.
No mail.
Plan:
Current state of the coke machine at DIKU
This file is updated every 5 seconds
At the moment, it's necessary to use correct change.
This has been the case the last 19 hours and 17 minutes
Column 1 is currently *empty*.
It's been 14 hours and 59 minutes since it became empty.
31 items were sold from this column before it became empty.
Column 2 contains some cokes.
It's been 2 days, 17 hours, and 43 minutes since it was filled.
Meanwhile, 30 items have been sold from this column.
Column 3 contains some cokes.
It's been 2 days, 17 hours, and 41 minutes since it was filled.
Meanwhile, 11 items have been sold from this column.
Column 4 contains some cokes.
It's been 5 days, 15 hours, and 28 minutes since it was filled.
Meanwhile, 26 items have been sold from this column.
Column 5 contains some cokes.
It's been 5 days, 15 hours, and 29 minutes since it was filled.
Meanwhile, 18 items have been sold from this column.
Column 6 contains some coke-lights.
It's been 5 days, 15 hours, and 30 minutes since it was filled.
Meanwhile, 16 items have been sold from this column.
Connection closed by foreign host.
$
In this example we've connected directly to kantine.diku.dk's Finger port. We
typed the user name "cola," and the server returned
information about that user.
I chose this particular host and user just to show you some of the
whimsy that accompanied the early days of the Internet. Finger
servers got pressed into service for all sorts of tasks. In this
case, anyone anywhere on the planet can see whether the soda machine
at the Department of Computer Science at the University of Copenhagen
is currently stocked. For more examples of strange devices hooked to
Finger servers, you may wish to check out Bennet Yee's
"Internet Accessible Coke Machines" and "Internet
Accessible Machines" pages; they are available online at
http://www.cs.ucsd.edu/~bsy/fun.html.
Let's take the network communication we just performed using a
telnet binary back to the world of Perl. With
Perl, we can also open up a network socket and communicate over it.
Instead of using lower-level socket commands, we'll use Jay
Roger's Net::Telnet module to introduce a
family of modules that handle generic network discussions. Other
modules in this family (some of which we use in other chapters)
include Eric Arnold's Comm.pl, Austin
Schutz's Expect.pm, and the venerable but
outdated and nonportable chat2.pl by Randal L.
Schwartz.
Net::Telnet will handle all of the connection
setup work for us and provides a clean interface for sending and
receiving data over this connection. Though we won't use them
in this example, Net::Telnet also provides some
handy pattern-scanning mechanisms that allow your program to watch
for specific responses from the other
server.
Here's a Net::Telnet version of a simple
Finger client. This code takes an argument of the form
user@finger_server. If the user name is omitted, a
list of all users considered active by the server will be returned.
If the hostname is omitted, we query the local host:
use Net::Telnet;
($username,$host) = split(/\@/,$ARGV[0]);
$host = $host ? $host : 'localhost';
# create a new connection
$cn = new Net::Telnet(Host => $host,
Port => 'finger');
# send the username down this connection
unless ($cn->print("$username")){ # could be "/W $username"
$cn->close;
die "Unable to send finger string: ".$cn->errmg."\n";
}
# grab all of the data we receive, stopping when the
# connection is dropped
while (defined $ret = $cn->get) {
$data .= $ret;
}
# close the connection
$cn->close;
# display the data we collected
print $data;
RFC1288 specifies that a /W switch can be
prepended to the username sent to the server to request it to provide
"a higher level of verbosity in the user information
output," hence the /W comment above.
If you need to connect to another TCP-based text protocol besides
Finger, you'd use very similar code. For example, to connect to
a Daytime server (which shows the local time on a machine) the code
looks very similar:
use Net::Telnet;
$host = $ARGV[0] ? $ARGV[0] : 'localhost';
$cn = new Net::Telnet(Host => $host,
Port => 'daytime');
while (defined $ret = $cn->get) {
$data .= $ret;
}
$cn->close;
print $data;
Now you have a sense of how easy it is to create generic TCP-based
network clients. If someone has taken the time to write a module
specifically designed to handle a protocol, it can be even easier. In
the case of Finger, you can use Taylor's
Net::Finger to turn the whole task into a single
function call:
use Net::Finger;
# finger( ) takes a user@host string and returns the data received
print finger($ARGV[0]);
Just to present all of the options, there's also the fallback
position of calling another executable (if it exists on the machine)
like so:
($username,$host) = split('@',$ARGV[0]);
$host = $host ? $host : 'localhost';
# location of finger executable, MacOS users can't use this method
$fingerex = ($^O eq "MSWin32") ?
$ENV{'SYSTEMROOT'}."\\System32\\finger" :
"/usr/ucb/finger"; # (could also be /usr/bin/finger)
print `$fingerex ${username}\@${host}`
Now you've seen three different methods for performing Finger
requests. The third method is probably the least ideal because it
requires spawning another process.
Net::Finger will handle simple
Finger requests; for everything else, Net::Telnet
or any of its kin should work well for you.
Copyright © 2001 O'Reilly & Associates. All rights reserved.