Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dumping out /var/log/lastlog file?

1,509 views
Skip to first unread message

Mike Pelley

unread,
Oct 4, 2006, 7:46:22 PM10/4/06
to
Folks - A friend asked me to dump out all logins from his
/var/log/lastlog file on a Red Hat box. It's been some time since I've
done any Linux administration and can't remember how to process the
binary file (and Google is making me go blind ;-)

Thanks
Mike

Kevin Lacquement

unread,
Oct 6, 2006, 9:32:45 AM10/6/06
to
Mike Pelley <mike@_remove-this_pelleys.com> writes:

Use the ''lastlog'' command. Flags at ''man lastlog''

>
> Thanks
> Mike

No problem
Kevin

Mike Pelley

unread,
Oct 6, 2006, 11:38:02 AM10/6/06
to
I need to go longer than the lastlog will provide. wtmp was overwritten
(not by hacking but by log control). I have a script in perl that is
the start of the process (see below) but the info isn't quite. I think
that it is related to the byte offset. The script was taken from
Solaris and the Linux lastlog file format differes.

Suggestions?


#/usr/bin/perl

# A lastlog record format for use by pack and unpack.

$lastlog_t = "L A12 A16"; # (Your machine's may differ.)

# Find the length of the fixed-length record.

$LEN = length(pack($lastlog_t, 0, '', ''));

# Open the database of last logins. Fixed length records.

open(LASTLOG, "/var/log/lastlog")
|| die "Can't open lastlog file: $!\n";

# Open the database of accounts. Variable length records.

open(PASSWD, "/etc/passwd")
|| die "Can't open passwd file: $!\n";

# So we can look up month names later.

@month = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

# Now we iterate through variable length records by using
# the <> input symbol. In this particular database, the
# delimiter just happens to be \n. How lucky can you get?

while ($varrec = <PASSWD>) {

# And the field delimiter happens to be a colon. Amazing!

($login, $pass, $uid, $gid, $gcos) = split(/:/, $varrec);

# Extract name from gcos field portably.

$fullname = $gcos;
$fullname =~ s/^[^,]*-(.*)\(.*/$1/ || $fullname =~ s/,.*//;
if ($fullname =~ /&/) { # You don't want to know.
$name = $login;
substr($name,0,1) =~ tr/a-z/A-Z/;
$fullname =~ s/&/$name/;
}

# Now we random access the lastlog database. It's keyed
# by position based on the user id we want to look up.
# Note that we multiply by the record length, since Unix
# always wants byte offsets.

seek(LASTLOG, $uid * $LEN, 0);
read(LASTLOG, $lastlog, $LEN);

# Now that we've fetched the lastlog record, we can
# break it out into its fields. Note that variable-
# length fields above are separated with the split
# operator, while these fixed-length fields are separated
# using unpack.

($time, $line, $host) = unpack($lastlog_t, $lastlog);

# Now remember it so we can sort easily.

push(@records, "$time:$login:$uid:$fullname");
}

# Now sort the records, oldest first. See the
# "numerically" subroutine below.

@records = sort numerically @records;

foreach $record (@records) {
($time,$login,$uid,$fullname) = split(/:/, $record);

# Break out the login time, stored as seconds since
# January 1, 1970, into normal date numbers.

if ($time) {
($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
$year += 1900;
$date = "$mday $month[$mon] $year";
}
else {
$date = "Never";
}

# Write using the format below.

write;
}

sub numerically { $a <=> $b; }

format top =
Uid Login Full Name Last Login

.

format STDOUT =
@>>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @||||||||||
$uid, $login, $fullname, $date
.

0 new messages