[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