#!/usr/bin/perl -w

#################################################################
# Change the parameters here
#################################################################
$LOWUID=100;             # don't look at accounts with uid below this
                         # they're special system accounts
$HOME="/home";           # where are the home dirs
$PASS="/etc/passwd";     # where is the password file
$SHADOW="/etc/shadow";   # where is the password shadow file
$MAIL="/var/spool/mail"; # where are the mail spool files
$OLD=30;                 # how many days of no activity before an account is old
$BIGACCOUNT=10000;       # How many KB of disk space before an account is too huge
$MAXDEPTH=8;          # Max depth of directories to seach for files.

#################################################################
# Nothing to change below here
#################################################################

#
# Read /etc/shadow if it exists.
if (! -f $SHADOW) {
	print "No shadow password file.  Testing without it.\n";
	$shadow = 0;
}
else {
	$shadow = 1;
	open(SH, $SHADOW) || die "Unable to open password shadow file $SHADOW\n";
	while ($line = <SH>) {
		chomp($line);
		local($junk); # make the -w not error the variable junk
		($name, $password, $junk) = split(":", $line);
		$password{$name} = $password;
	}
}
	
#
# Open and read in the password file
local($name, $password, $uid, $gid, $longname, $home, $shell);
open(PW, $PASS) || die "Unable to open password file $PASS\n";
while ($line = <PW>) {
	chomp($line);
	$shell="";

	# split the password entry, and correct if they
	# don't have a longname
	($name, $password, $uid, $gid, $longname, $home, $shell) = split(":", $line);
	if ($shell eq "") {
		print "Found it $name\n";
		$home=$longname;
		$shell=$home;
	}
	$users{$name} = 1;

	# Check some obvious stuff
	if ($uid < $LOWUID) {
		next;
	}
	print "Checking $name\n";
	if ($uid == 0 || $gid == 0) {
		print "    $name has $uid and gid $gid!\n";
	}
	if ($password eq "") {
		print "    $name has no password!\n";
	}
	if ($shadow == 1 && !defined($password{$name})) {
		print "    $name has no entry in shadow password file $SHADOW!\n";
	}
	if ($shell ne "/bin/bash" && $shell ne "/bin/csh" && 
		$shell ne "/bin/tcsh") {
		print "    $name is disabled with shell $shell\n";
	}
	if (! -d $home) {
		print "    $name has home dir $home which is not really a directory.\n";
	}
	else {
		if (defined($homes{$home})) {
			print "    $name shares a home dir with $homes{$home}.\n";
		}
		else {
			#
			# Scan the users home directory looking for 
			# files owned by someone else, and checking
			# the amount of scace used.
			#
	
			$homes{$home} = $name;
			# Checks the total space used by a subdir, and the access time of
			# the newest file in that dir.
			$latest = $filesize = $badowner = 0;
			open(FIND, "find $home -maxdepth $MAXDEPTH -printf \"%p-XQC-%k-XQC-%u-XQC-%C@\n\" |") 
				|| die "Unable to open find";
			while ($line = <FIND>) {
				# get a file and it's info
				#
				chomp($line);
				($filename, $size, $owner, $date) = split("-XQC-", $line);
				if ($latest < $date) {
					$latest = $date;
				}
				if ($name ne $owner && $badowner == 0) {
					print "    $name has a file ($filename) owned by $owner.\n";
					$badowner = 1;
				}
				if ($name ne $owner && $badowner == 1) {
					print "    $name has more files not owned by $name.\n";
					$badowner = 2;
				}
				$filesize += $size;
			}
			$old = (time() - $latest) / 24 / 60 / 60;
			if ($old > $OLD) {
				print "    $name has not changed a file in $old days.\n";
			}
			if ($filesize > $BIGACCOUNT) {
				print "    $name uses $filesize KB of disk space\n";
			}
		}
	}
}

#
# Check $HOME for files not owned by any valid user
#
$homes = `echo $HOME/*`;
chomp($homes);
for $home (sort split(/ /, $homes)) {
	if (!defined($homes{$home})) {
		print "File $home is in the home dirs but not the home dir for any user!\n";
	}
}

#
# Check for files in the mail spool directory that do not
# corespond to valid users
#
$mails = `cd $MAIL; echo *`;
chomp($mails);
for $mail (sort split(/ /, $mails)) {
	if (!defined($users{$mail})) {
		print "File $MAIL/$mail is in the mail spool directory but not associated with a valid user!\n";
	}
}

#
# Check the entries from $SHADOW (stored in %password) to see if they
# also exist in $PASS (stored in %users).
#
for $user (sort keys %password) {
	if (!defined($users{$user})) {
		print "$user appears in $SHADOW but not $PASS!\n";
	}
}
