#!/s/std/bin/perl

# template_clean.pl
# Cleans up a Linux template so that VMs deployed from this will not
# have stale or insecure configurations

use strict;
use warnings;

use Sys::Hostname;
use File::Path qw(make_path remove_tree);

# only run this script as root
if ($<) {
  print STDERR "ERROR: Only root can do template cleanup.\n";
  exit 1;
}

# this should only be run on a template
my $host = hostname;
if ($host !~ /^template-.*\.cs\.wisc\.edu$/) {
  print STDERR "ERROR: This machine does not look like a template.\n";
  exit 2;
}

# get sysname
my @sys_commands = ('/usr/afsws/bin/sys', '/usr/bin/sys');
my $sys = '';
foreach (@sys_commands) {
  $sys = `$_` || '';
  chomp $sys;
  last if $sys;
}

if ($sys eq 'i386_rhel5') {
  print "Cleaning up 32-bit RHEL 5 template...\n";
} elsif ($sys eq 'amd64_rhel5') {
  print "Cleaning up 64-bit RHEL 5 template...\n";
} elsif ($sys eq 'amd64_rhel6') {
  print "Cleaning up 64-bit RHEL 6 template...\n";
} else {
  print STDERR "Invalid sysname $sys. Cannot clean template.\n";
  exit 3;
}

my $err = 0;
my $err_codes = [];
my $file = "";

# This may be better to do as a hash, but not when we only have 3 OS's

# SSH keys
print "\nRemoving SSH keys...\n";
my $path = ($sys eq 'amd64_rhel6') ? '/etc/ssh' : '/var/adm/openssh';
foreach my $file (glob "$path/ssh_host_*") {
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
}

# KRB keytabs
print "\nRemoving Kerberos keytabs...\n";
foreach my $file (glob "/etc/v5srvtab*") {
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
}

# CSL SSL certs
print "\nRemoving CSL SSL certificates...\n";
$err_codes = [];
remove_tree('/etc/csl/openssl', {error => \$err_codes} );
if (@$err_codes) {
  foreach my $diag (@$err_codes) {
    $err++;
    my ($file, $message) = %$diag;
    if ($file eq '') {
      warn "- ERROR: $message\n";
    } else {
      warn "- ERROR: Could not unlink $file: $message\n";
    }
  }
} else {
  print "- Successful deletion.\n";
}

# udev rule (RHEL 6 only)
if ($sys eq 'amd64_rhel6') {
  print "\nRemoving persistent network udev rule...\n";
  $file = '/etc/udev/rules.d/70-persistent-net.rules';
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
}

# RHN registration
print "\nRemoving RHN systemid file...\n";
$file = '/etc/sysconfig/rhn/systemid';
if (-e $file) {
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
} else {
  print "- No file to remove. All is well.";
}

# process accounting
print "\nRemoving process accounting files...\n";
foreach $file (glob "/var/account/*") {
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
}

# KRB credentials
print "\nRemoving old Kerberos credentials...\n";
my $krb_dir = '/var/adm/krb5/tmp';
$err_codes = [];
remove_tree(['$krb_dir/tkt', '$krb_dir/stash'], {keep_root => 1, error => \$err_codes} );
if (@$err_codes) {
  foreach my $diag (@$err_codes) {
    $err++;
    my ($file, $message) = %$diag;
    if ($file eq '') {
      warn "- ERROR: $message\n";
    } else {
      warn "- ERROR: Could not unlink $file: $message\n";
    }
  }
} else {
  print "- Successful deletion.\n";
}
foreach $file (glob "$krb_dir/krb5_* $krb_dir/host_*") {
  if (unlink $file) {
    print "- Deleted $file\n";
  } else {
    warn "- ERROR: Could not unlink $file: $!\n";
    $err++;
  }
}

# Crashdumps (/var/crash/*)
print "\nRemoving Crashdumps...\n";
$err_codes = [];
remove_tree('/var/crash', {keep_root => 1, error => \$err_codes} );
if (@$err_codes) {
  foreach my $diag (@$err_codes) {
    $err++;
    my ($file, $message) = %$diag;
    if ($file eq '') {
      warn "- ERROR: $message\n";
    } else {
      warn "- ERROR: Could not unlink $file: $message\n";
    }
  }
} else {
  print "- Successful deletion.\n";
}

# - Logs (/var/log/*)
# anything that gets logrotate'd
print "\nRemoving Logfiles...\n";
my @logs = qw(authlog btmp daemonlog lastlog messages poplog rpmpkgs syslog up2date wtmp);
foreach my $log (@logs) {
  foreach my $file (glob "/var/log/$log*") {
    if (unlink $file) {
      print "- Deleted $file\n";
    } else {
      warn "- ERROR: Could not unlink $file: $!\n";
      $err++;
    }
  }
}

# - Temp files (/var/tmp/*)
# - More temp files (stuff in /tmp?, but that's cleaned on reboot)

# at job (presumably a reboot job)
print "\nChecking/removing at jobs...\n";
my $count = 0;
foreach my $job (`/usr/bin/atq`) {
  my ($id, $date, $time, $class, $root) = split /\s+/, $job;

  my $retval = system 'atrm', $id;
  if ($retval >> 8) {
    warn "- ERROR: Could not remove at job $id.\n";
    $err++;
  } else {
    print "- Removed at job $id\n";
    $count++;
  }
}
print "- Removed $count at job(s).\n";

print "\n";

# set firstboot flag
#print "\nSetting firstboot flag...\n";
#if (open FIRSTBOOT, "> /etc/sysconfig/firstboot") {
#  print FIRSTBOOT "RUN_FIRSTBOOT=YES\n";
#  print "- Set firstboot flag\n";
#} else {
#  warn "- ERROR: Could not open firstboot file for writing: $!\n";
#  $err++;
#}
#close FIRSTBOOT;

if ($err) {
  print STDERR "WARNING: Encountered $err error(s) when cleaning this template.
Check output above before shutting down.
";
} else {
  print "This template is now clean. Shutting down in 1 minute:\n";
  print "Shutting down in 1 minute:\n";
  system "shutdown -h +1";
}
