#! /usr/local/bin/perl -w # $Id: viz.pl,v 1.1.1.1 2002/09/06 18:18:09 travcom Exp $ # (c) Travcom 2002 use strict; use integer; viz("/etc/utmp", 0); # SunOS viz("/usr/adm/wtmp", 1); # SunOS viz("/var/run/utmp", 0); # NetBSD viz("/var/log/wtmp", 1); # NetBSD viz("/var/log/wtmp.0", 1); # NetBSD sub viz() { my($fn, $wtmp) = @_; # warn and give up if we can't read this file if (!-e $fn) { warn "$fn not found: $!\n"; return; } # stat the file (possibly a symlink) my($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat($fn); # if we're on a BSD system, if (defined($blocks) and defined($blksize)) { # check for sparse files (holes); # a bug in the way zap does sign-extension leaves these. # HINT: file offsets are quad_t's! # The problem here is that PERLs stat returns longs for file size # so $size alone can't tell us how big the file is. # ask ls how big the file is: my $len = `ls -l $fn | awk -- '{ print \$5; }'`; chomp($len); if ($blocks * $blksize < $len) { print("You've probably been zapped by a script-kiddie.\n", "There are $blocks $blksize-byte blocks but ", "$len bytes in the file $fn\n"); } if ($len != $size) { print("You've probably been zapped by a script-kiddie.\n", "Your file should be $size bytes long,\n", "instead it is $len bytes long and has a hole in it.\n", "I won't bother to show you from the hole onward.\n"); } } open(UTMP, '<' . $fn) or die "could not open $fn for read: $!\n"; print "$fn:\n"; my ($recno,$offset) = (0,0); LOOP: while (read(UTMP, $_, 36)) { ++$recno; $offset = $recno * 36; # null entries are expected in utmp but not wtmp if ($wtmp and $_ eq "\0" x 36) { print "zap detected at offset $offset!\n"; } else { my($line, $name, $host, $time) = unpack("a8 a8 a16 L", $_); print "record=$recno line=$line name=$name host=$host time=" . localtime($time) . "\n"; } # print "$recno $offset $size\n"; if ($offset >= $size) { last LOOP; } } close(UTMP); } exit 0;