#!/usr/bin/perl

##
## cache_clean.pl -- cleans mod_authn_myproxy cache
##
##  $Id: cache_clean.pl 137 2006-08-01 21:49:21Z alamber3 $
##
##  See http://myproxy.ncsa.uiuc.edu/apache
##

use warnings;
use strict;

use Fcntl;
use Switch;

use Date::Parse;
use Getopt::Long;

my @dirs;
my $verbose = '';

GetOptions( 'dir=s' => \@dirs, 'verbose!' => \$verbose );

die("usage: $0 --dir directory1 [--dir directory2...] [--verbose]")
  if ( scalar(@dirs) == 0 );

scan($_) foreach (@dirs);

sub scan {
    my $dir = shift;

    return undef unless opendir( DIR, $dir );

    while ( my $file = readdir(DIR) ) {
        if ( $file =~ m/-user$/ ) {
            next unless get_lock_nb("$dir/$file");
            process_file("$dir/$file");
            release_lock("$dir/$file");
        }
    }
}

sub get_lock_nb {
    return undef
      unless
      sysopen( LOCK, sprintf( "%s-lock", $_[0] ), O_CREAT | O_EXCL, 0600 );
    close(LOCK);
    return 1;
}

sub release_lock {
    return unlink( sprintf( "%s-lock", $_[0] ) );
}

sub unserialize_cache_record {
    return undef unless open( CACHE_FILE, '<', $_[0] );

    my $should_abort = undef;

    my %cache_rec;
    my %cert_rec;
    $cache_rec{cert} = \%cert_rec;

    while (<CACHE_FILE>) {
        chomp;
        my ( $key, $value ) = split( /=/, $_, 2 );

        switch ($key) {
            case 'version' {
                $should_abort = 1 if ( $value ne '1' );
            }
            case 'user' {
                $cache_rec{user} = $value;
            }
            case 'salt' {
                $cache_rec{salt} = $value;
            }
            case 'passphrase_hash' {
                $cache_rec{passphrase_hash} = $value;
            }
            case 'myproxy_server' {
                $cache_rec{myproxy_server} = $value;
            }
            case 'myproxy_port' {
                $cache_rec{myproxy_port} = $value;
            }
            case 'requested_lifetime' {
                $cache_rec{requested_lifetime} = $value;
            }
            case 'cert_file' {
                $cache_rec{cert}{file} = $value;
            }
            case 'cert_identity' {
                $cache_rec{cert}{identity} = $value;
            }
            case 'cert_good_till' {
                $cache_rec{cert}{good_till} = str2time($value);
            }
            else {
                $should_abort = 1;
            }
        }
    }
    close(CACHE_FILE);

    if ($should_abort) {
        return undef;
    }
    else {
        return %cache_rec;
    }
}

sub process_file {
    my ($cache_file) = @_;
    my %cache_rec;

    unless ( %cache_rec = unserialize_cache_record($cache_file) ) {

        # destroy invalid entry
        unlink($cache_file);
        return;
    }

    if ( $cache_rec{cert}{good_till} < time ) {
        unlink( $cache_rec{cert}{file} );
        unlink($cache_file);
        verbose("$cache_file has expired");
    }
    else {
        verbose("$cache_file has not expired");
    }
}

sub verbose($) {
    print STDERR $_[0] . "\n" if $verbose;
}
