#!/usr/bin/perl
#
#  reliably stop/start 'servicemix' service on master
#  
#  Note: - file location isn't strictly defined
#        - Linux version
#        - run from user apl:
#          sudo /opt/sarch/smix/bin/smxctl start|stop|status

use File::Basename qw(dirname);
use strict;
use warnings;

# Load configuration
my $dirname = dirname(__FILE__);
open (ICF,"$dirname/../../base/etc/install.conf") || die("Cannot read install.conf\n");
open (ECF,"$dirname/../../base/etc/env.conf")     || die("Cannot read env.conf\n");
map {$ENV{$1}=$2 if /^(\w+)=(\S+)/} grep {/^\w+=\S+/} (<ICF>,<ECF>);
close ICF;
close ECF;

# Globals
my $APL="$ENV{APL}" || "/opt/sarch";
my $APL_VAR = "$ENV{APL_VAR}" || '/var/sarch';
my $SMX_HOME = $ENV{SMX_HOME} || "/opt/apache/servicemix";
my $SMX_USER = 'smx'; # ServiceMix user

my $KEYTOOL = 'keytool';
my $KEYSTORE =  "$SMX_HOME/etc/servicemix.jks";
my $KEYSTORE_PASS = '5K0SlAVoK0qahBpfxkOnwg';
my $KEY_PASS = $KEYSTORE_PASS;
my $KEY_PROPERTIES = "CN=Unknown, OU=Stratus, O=videoNEXT Ltd, L=Chantilly, ST=VA, C=US";
my $KEY_VALID_DAYS = "3660";

my $USAGE = "Usage: keymanager <gen|export|import|clean|list> [parameters...]\n"
		 . "  gen                                           - create keystore and private key\n"
		 . "  export <certificate_file>                     - export certificate from local keystore\n"
		 . "  import <certificate_file> <certificate_alias> - import certificate into local keystore\n"
		 . "  clean                                         - delete keystore\n"
		 . "  list                                          - print keys information\n";
my $RETVAL = 0;
$| = 1;	# Disable buffering for STDOUT;

main();


#-------------------------------------------------------------------
# Routines

sub complete {
    print $RETVAL?"[  OK  ]\n" : "[  FAILED  ]\n";
}

sub printUsage {
	print $USAGE;
}

sub read_uni { # read existing UNI
	my $uni='NONE';
	if(open(NCONF,"$APL_VAR/conf/node/conf")) {
		my %ninfo=map{/(^\w+)=(.+)/} grep {/(^\w+)=(.+)/} <NCONF>;
		$uni=$ninfo{UNI} if exists $ninfo{UNI};
		close NCONF;
	}
	return $uni;
}


sub generate {

	my $keyAlias = read_uni();
	if ($keyAlias eq 'NONE') {
		print "Failed to retrieve node UNI\n";
		return;
	}

	my ($genKey, $cmd, $out) = (1, '', undef);
	if (-f $KEYSTORE) {
		# get all keys
		$cmd = "$KEYTOOL -list -keystore $KEYSTORE -storepass $KEYSTORE_PASS";
	    my @result = `$cmd 2>&1`;
		if ($? != 0) {
			print "Failed to get keys list (keystore=$KEYSTORE): $out\n";
			return;
		}

		# process output
		foreach (@result) {
			#look for PrivateKeyEntry
			if (m/^([a-z0-9]+),\s[\w\d\s,]+,\sPrivateKeyEntry,\s?$/) {
				# got PrivateKeyEntry
				my $iKeyAlias = $1;
		        if ($iKeyAlias eq lc($keyAlias)) {
					print "Valid private key $iKeyAlias is found\n";
					$genKey = 0;
				} else {
					# delete current PrivateKeyEntry (was created for different UNI)
					print "Revoke private key $iKeyAlias\n";

					$cmd = "$KEYTOOL -delete -keystore $KEYSTORE -storepass $KEYSTORE_PASS -alias $iKeyAlias";
				    $out = `$cmd 2>&1`;
					if ($? != 0) {
						print "Failed to delete key $iKeyAlias from keystore $KEYSTORE: $out\n";
						return;
					}
    			}
			}
		}
	}

	if ($genKey) {
		print "Generating new private key\n";
		my $cmd = "$KEYTOOL -genkeypair -keyalg RSA -validity $KEY_VALID_DAYS -dname \"$KEY_PROPERTIES\"  -keystore $KEYSTORE -keypass $KEY_PASS -storepass $KEYSTORE_PASS -alias $keyAlias";
    	my $out = `$cmd 2>&1`;
		if ($? != 0) {
			print $out;
			return;
		}
	}

	# set keystore permissions
	my ($name, $passwd, $uid, $gid) = getpwnam($SMX_USER);
	if (chown($uid, $gid, $KEYSTORE) != 1 || chmod(0600, $KEYSTORE) != 1) {
		print "Failed to set file $KEYSTORE permissions\n";
		return;
	}

	# export public key
	export('/home/sos/smx.cert');
}


sub export {
	my $certificateFile = shift;
	if (-f $certificateFile) {
		if (! unlink($certificateFile)) {
			print "Failed to delete existig certificate file $certificateFile\n";
			return;
		}
	}

	my $keyAlias = read_uni();
	if ($keyAlias eq 'NONE') {
		print "Failed to retrieve node UNI\n";
		return;
	}

	my $cmd = "$KEYTOOL -export -keystore $KEYSTORE -storepass $KEYSTORE_PASS -alias $keyAlias -file $certificateFile";
    my $out = `$cmd 2>&1`;
	if ($? != 0) {
		print $out;
		return;
	}

	if (chmod(0644, $certificateFile) != 1) {
		print "Failed to set permissions to file $certificateFile\n";
	} else {
		$RETVAL = 1;
	}
}


sub exportCommand {
	if ($#ARGV < 1) {
		printUsage;
	} else {
		export($ARGV[1]);
	}
}


sub import {
	if ($#ARGV < 2) {
		printUsage;
		return;
	}

	my ($certFile, $certAlias) = ($ARGV[1], $ARGV[2]);
	if (! -f $certFile) {
		print "File $certFile not found\n";
		return;
	}

	if (!-f $KEYSTORE) {
		print "Keystore file $KEYSTORE is missing\n";
		return;
	}

	my $cmd = "$KEYTOOL -list -keystore $KEYSTORE -storepass $KEYSTORE_PASS -alias $certAlias";
    my $out = `$cmd 2>&1`;
	if ($? == 0) {
		$cmd = "$KEYTOOL -delete -keystore $KEYSTORE -storepass $KEYSTORE_PASS -alias $certAlias";		
	    $out = `$cmd 2>&1`;
		if ($? != 0) {
			print "Failed to delete key $certAlias from keystore: $out\n";
			return;
		}	
	}

	$cmd = "$KEYTOOL -import -keystore $KEYSTORE -storepass $KEYSTORE_PASS -noprompt -alias $certAlias -file $certFile";
    $out = `$cmd 2>&1`;
	if ($? == 0) {
		$RETVAL = 1;
	} else {
		print $out;
	}
}


sub clean {
	unlink $KEYSTORE, "/home/sos/smx*.cert", "/home/sos/.ssh/smx*.cert";
	$RETVAL = 1;
}


sub listkeys {
	my $cmd = "$KEYTOOL -list -keystore $KEYSTORE -storepass $KEYSTORE_PASS";
    my $out = `$cmd 2>&1`;
	if ($? == 0) {
		$RETVAL = 1;
	}
	print "$out\n";
}


sub main {
	my $CMD = $ARGV[0];
    die $USAGE unless defined $CMD;
    die "ServiceMix is not installed!\n" unless -d $SMX_HOME;
    die "ServiceMix user is not defined\n" unless $SMX_USER;
    for($CMD) {
        /^gen$/  && do { generate; complete; last };
        /^export$/  && do { exportCommand; complete; last };
        /^import$/   && do { import; complete; last };
        /^list$/   && do { listkeys; last };
        /^clean$/   && do { clean; complete; last };
        /^--help$/ && do { printUsage; last };
	die $USAGE;
    }

    exit 1 - $RETVAL;
}
