[ale] utmp reading

Mark J. Reed mark_reed at sware.com
Thu Jun 6 07:29:35 EDT 1996


talking about Perl.  Little details like the programming language
you're using are good things to include when asking these
sorts of questions. :)

Looking at /usr/include/utmp.h works fine with one caveat: structure 
members are *aligned on four-byte boundaries*.
Here's the utmp.h structure definition on my system:

#define UT_NAMESIZE	8
#define UT_LINESIZE	12
#define UT_HOSTSIZE	16

struct utmp {
	short	ut_type;	        /* type of login */
	pid_t	ut_pid;		        /* pid of login-process */
	char	ut_line[UT_LINESIZE];	/* tty - "/dev/", null-term */
	char	ut_id[2];	        /* abbrev. ttyname, as 01, s1 etc. */
	time_t	ut_time;	        /* logintime */
	char	ut_user[UT_NAMESIZE];	/* username, not null-term */
	char	ut_host[UT_HOSTSIZE];	/* hostname for remote login... */
	long	ut_addr;	        /* IP addr of remote host */
};

#define ut_name ut_user

(because pid_t and time_t are both longs on my system),
which adds up to a size of 2 + 4 + 12 + 2 + 4 + 8 + 16 + 4 = 52 bytes.
But, since the structure members have to be aligned, both the "ut_type"
and "ut_id" fields end up padded with two extra bytes.  Taking that into
account, you get an unpack template of "l l a12 a4 l a8 a16 l", which
adds up to 56 bytes.  (Seems there ought to be a mechanism built-in to Perl to
take a pack or unpack template and generate the size of the packed scalar, but
I digress...)

The following Perl script dumps my utmp file successfully:

#!/usr/bin/perl
$utFile   = '/etc/utmp';	        # path to utmp file
$utFormat = 'l l a12 a4 l a8 a16 l';	# format of utmp record
$utSize   = 56;			        # size of utmp record

# list of fields in the structure in order
@utFields = ( 'ut_type', 	# type of login 
	      'ut_pid', 	# pid of login process
	      'ut_line', 	# devicename of tty without leading "/dev/"
	      'ut_id', 		# ut_line without leading "tty"
	      'ut_time', 	# login time (secs since 1970/01/01 00:00 UTC)
	      'ut_user',	# login name
              'ut_host', 	# name of remote host if remote login 
	      'ut_addr' );	# IP address of remote host if remote login

# an associative array to let me use the field name to get the field number
for ($i=0;$i<@utFields; ++$i)
{
    $utIndex{$utFields[$i]} = $i;
}
# since the C header defines a ut_name alias, might as well do likewise
$utIndex{'ut_name'} = $utIndex{'ut_user'};	

# open the file
open(UTMP,$utFile) || die "Could not open utmp file.";

# dump the contents to stdout, no formatting applied
while (read(UTMP, $utBuf, $utSize))
{
    @utStruct = unpack($utFormat, $utBuf);
    for (@utFields)
    {
        print "$_: $utStruct[$utIndex{$_}]\n";
    }
    print "\n";
}
close(UTMP);

--
Mark J. Reed                     |             http://www.sware.com
Email: mark_reed at secureware.com  |  HP Internet/System Security Lab
Voice: +1 404 648 9535           |      2957 Clairmont Rd Suite 220
Fax  : +1 404 648 9516           |        Atlanta GA 30329-1647 USA






More information about the Ale mailing list