#!/usr/bin/perl -w
#
# module EliminateExpired.pl
#
# parameter: cert for CRL  class1 or class3
#
# Eliminates certificate-records from file index.txt for CRL, which
# are revoked at least for 100 days and their expirationdate also older than 100 days
# puts the resulting file of kept records in place of the original index.txt
#
# if a certificate is revoked, it remains at index.txt
#	max{expirationDate,revokationDate} + 100 days
#
# this has to be proofed against the parameters of the openssl - config files
# for next update of the CRL
#
# also $fileNameStart has to be checked agains the config files
# /etc/ssl/CA for class1
# /etc/ssl/class3 for class3
#

use strict;
use warnings;

use POSIX;
use open qw< :encoding(UTF-8) >;

#
# initializing
#

my $debuglvl = 0;
my $cert     = "";

# Counters

my $countInput              = 0;
my $countOutput             = 0;
my $countRevokedUnexpired   = 0;
my $countRevokedExpired     = 0;
my $countUnrevokedUnexpired = 0;
my $countUnrevokedExpired   = 0;
my $countEliminated         = 0;

# Filenames

my $filenameInput      = undef;
my $filenameOutput     = undef;
my $filenameEliminated = undef;
my $filenameSave       = undef;
my $filenameTemp       = undef;
my $fileNameStart      = undef;

#
# Date handling
#

my $actualDate = time();
my $actualDateS = strftime( "%Y-%m-%d", gmtime($actualDate) );

my $eliminationDateLimit =
  $actualDate - 100 * 24 * 60 * 60;    #subtract 100 days from current time
my $eliminationDateLimitS =
  strftime( "%Y-%m-%d", gmtime($eliminationDateLimit) );
my $eliminateDate =
    substr( $eliminationDateLimitS, 2, 2 )
  . substr( $eliminationDateLimitS, 5, 2 )
  . substr( $eliminationDateLimitS, 8, 2 );

#
#Logging functions:
#

my $lastdate = "";

sub SysLog($) {
	return if ( not defined( $_[0] ) );
	my $timestamp = strftime( "%Y-%m-%d %H:%M:%S", gmtime );
	my $currdate = substr( $timestamp, 0, 10 );
	if ( $lastdate ne $currdate ) {
		close LOG if ( $lastdate ne "" );
		$lastdate = $currdate;
		open LOG, ">>logfile$lastdate.txt";
	}
	print LOG "$timestamp $_[0]";
	print "$timestamp $_[0]" if ( $debuglvl > 0 );
	flush LOG;
}

#
# Handling filenames and parameters
#
# getParameters allowed: class1, class3, test
# getFilename returns te next valid name of a specific file
# selectFilenames depending on given arguments

sub getParameters () {
	if ( not defined $ARGV[0] ) {
		$cert = "test";
	}
	else {
		$cert = $ARGV[0];
	}
	if (    ( $cert ne "test" )
		and ( $cert ne "class1" )
		and ( $cert ne "class3" ) )
	{
		dieOut(
"no valid parameter $cert  allowed are 'class1', 'class3' and 'test'\n"
		);
	}
}

sub getFilename($$) {
	my $name     = $_[0];
	my $qualif   = $_[1];
	my $namepart = $name . $qualif;

	if ( -f $fileNameStart . $namepart . $actualDateS ) {
		while ( -f $fileNameStart . $namepart . $actualDateS ) {
			$namepart .= $qualif;
		}
	}

	return $namepart . $actualDateS;
}

sub SelectFilenames {

	if ( $cert eq "class1" ) {
		$fileNameStart = "/etc/ssl/CA/";
	}
	else {
		if ( $cert eq "class3" ) {
			$fileNameStart = "/etc/ssl/class3/";
		}
		else {
			$fileNameStart = "/home/GuKKDevel/bug-1306/tmp/";
		}
	}
	$filenameInput      = $fileNameStart . "index.txt";
	$filenameOutput     = $fileNameStart . getFilename( "index.", "kept." );
	$filenameEliminated = $fileNameStart . getFilename( "index.", "elim." );
	$filenameSave       = $fileNameStart . getFilename( "index.", "save." );
	$filenameTemp       = $fileNameStart . "index.temp";

	SysLog("File to read from -> $filenameInput\n");
	SysLog("File to write kept lines -> $filenameOutput\n");
	SysLog("File to save the removed lines -> $filenameEliminated\n");

}

#
# Pre-/Post-processing
#
# StartStopDemon stopping and starting the signer-demon
# dieOut Start the signer-demon before die
# preProcessing stopping the signer-demon
# postProcessing renaming the kept-file as new index.txt-file

my $restartDemon = 0;

sub startStopDemon($) {
	if ( $_[0] eq "Stop" ) {
		# Stop demon
		SysLog("Stopping signer-demon\n");
		system("service commmodule-signer stop");
		if ($!) {
			 die("$0: Couldn't stop signer"); 
		}
		SysLog("Signer-demon stopped");
		$restartDemon = 1;
	}
	else {
		# Start demon
		SysLog("Restarting signer-demon\n");
		system("service commmodule-signer start");
		if ($!) {
			 die("$0: Couldn't start signer"); 
		}
		SysLog("Signer-demon started");

	}
}

sub dieOut ($) {

	SysLog( $_[0] );

	if ($restartDemon) {
		startStopDemon("Start");
	}
	die( $_[0] );
}

sub preProcessing () {
	SysLog("\n");
	SysLog("Start Pre-prossessing\n");
	startStopDemon("Stop");
	SysLog("End Pre-processing\n");
	SysLog("\n");
}

sub postProcessing () {
	SysLog("\n");
	SysLog("Start Post-processing\n");

	SysLog("Copying $filenameOutput to \n");
	SysLog("$filenameTemp\n");

	system("cp $filenameOutput $filenameTemp");
	if ($!) {
		dieOut("$0: can' t copy $filenameOutput to $filenameTemp: $! \n ");
	}
	SysLog(" Copying done \n ");

	SysLog(" Copying $filenameInput to \n ");
	SysLog("$filenameSave \n ");

	system(" cp $filenameInput $filenameSave ");
	if ($!) {
		dieOut("$0 : can't copy $filenameInput to $filenameSave \n ");
	}
	SysLog(" Copying done \n ");

	SysLog(" Renaming $filenameTemp to \n ");
	SysLog("$filenameInput \n ");

	# now the index.txt file will be replaced
	# whilst Error server-demon MUST BE NOT RESTARTED
	$restartDemon = 0;

	system(" mv $filenameTemp $filenameInput ");
	if ($!) {
		dieOut("$0 : can't replace $filenameInput by $filenameTemp \n ");
	}
	SysLog(" Renaming done \n ");

	# restart demon

	$restartDemon = 1;
	startStopDemon(" Start ");

	SysLog(" End Post-processing \n ");
	SysLog(" \n ");
}

#
# start of the main structure
#
# open the neccessary files
#

SysLog(" Start of program \n ");
SysLog(" Reading the parameters \n ");
getParameters();
SysLog(
	" Remove all revoked certificates, issued by $cert -certificate, expired
			  and revoked before
			: $eliminationDateLimitS \n "
);
preProcessing();
SysLog(" Allocating files \n ");
SelectFilenames();

my $fileInput = undef;
open( $fileInput, " < ", "$filenameInput " )
  || dieOut("$0 : can't open $filenameInput for reading : $! \n ");

my $fileOutput = undef;
open( $fileOutput, " > ", "$filenameOutput " )
  || dieOut("$0 : can't open $filenameOutput for writing : $! \n ");

my $fileEliminated = undef;
open( $fileEliminated, " > ", "$filenameEliminated " )
  || dieOut("$0 : can't open $filenameEliminated for writing : $! \n ");

SysLog(" Start reading \n ");

while (<$fileInput>) {

	my $record         = $_;
	my @field          = split /\s+/, $record;
	my $flag           = $field[0];
	my $expirationDate = $field[1];
	$countInput++;

	if ( $flag ne " R " ) {

		# certificate is unrevoked
		print $fileOutput $record;
		$countOutput++;

		if ( $expirationDate lt $eliminateDate ) {
			$countUnrevokedExpired++;
		}
		else {
			$countUnrevokedUnexpired++;
		}
	}
	else {
		# certificate is revoked
		my $revokationDate = $field[2];
		if (    $expirationDate lt $eliminateDate
			and $revokationDate lt $eliminateDate )
		{
			print $fileEliminated $record;
			$countEliminated++;
			$countRevokedExpired++;
		}
		else {
			print $fileOutput $record;
			$countOutput++;
			$countRevokedUnexpired++;
		}
	}
}
if ($!) {
	dieOut(" unexpected error while reading from $fileInput: $! ");
}
SysLog(" End reading \n ");
SysLog(" Closing files \n ");
close $fileInput;
close $fileOutput;
close $fileEliminated;

postProcessing();

SysLog(" \n ");
SysLog(" STATISTICS \n ");
SysLog(" Read lines : $countInput \n ");
SysLog(" Kept lines : $countOutput \n ");
SysLog(" unrevoked and unexpired : $countUnrevokedUnexpired \n ");
SysLog(" unrevoked but expired : $countUnrevokedExpired \n ");
SysLog(" revoked but unexpired : $countRevokedUnexpired \n ");
SysLog(" Eliminated            : $countEliminated \n ");
SysLog(" revoked and expired : $countRevokedExpired \n ");
SysLog(" End of program \n ");
