#!/usr/bin/perl -w 
#
# nrpep (Netsaint Remote Plugin Executor/Perl)
# --------------------------------------------
# A program designed to replace netsaint_statd and nrpe.  Uses the design
# of nrpe, but implemented in perl and uses inetd/tcpwrappers for access
# control and to manage the sockets.
#
# Written by Adam Jacob
# Copyright 1999 Adam Jacob
# Covered under the terms of the GNU Public License Version 2.0 or greater
#

# Perl libs and such the program needs
use strict;
use vars qw($opt_d $opt_c $version %commands $key $cipher);
use Getopt::Std;
use Crypt::TripleDES;

# Global Variables
$version = "0.2-fbsd";

# Get the command line arguments
getopts('d:c:');

# Open a log
if ($opt_d) {
        open(LOG,">>$opt_d") or die "Cannot open $opt_d for logging";
	print LOG "\n\nNRPEP\n";
}

# Check for the proper command line arguments, if we fail, print out an
# error message and die.
&Check_Command($opt_c);

# Grab the configuration file, and parse it for all the variables we
# will need.
%commands = Get_Configs($opt_c);
if ($opt_d) {print LOG Dumper(%commands);}

# Now that I have a set of commands, go into recieve mode
&Recieve;

$opt_d && close(LOG);
exit 0;

######################################################################################

sub Recieve {
	my $line;
	my $commandentered;
	my $returncode;
	my $plaintext;
	my $cipher;

# Set the buffer settings on STDOUT to flush right away, so I actually
# can communicate with the outside world...
	$| = 1;
# Banner me, baby.
	print "nrpep - $version\n";
# Loop on stdin untill you recieve exit
	while (<STDIN>) {
# Strip the \r\n from input
		$_ =~ s/(\r|\n)//g;
# Start a new cipher with the proper key;
		$cipher = new Crypt::TripleDES;
# Decrypt the command
		$opt_d && print LOG "Decrypting $_\n"; 
		$commandentered = $cipher->decrypt3(pack("H*", $_), $key);
		$opt_d && print LOG " ... got $commandentered\n";
		$commandentered =~ s/\s+$//;
# If the command entered looks like one in the config file, execute it and
# print it's return code
		if ($commands{$commandentered}) {
			undef($plaintext);
			$plaintext = "OP: " . `$commands{$commandentered}`;
			$plaintext = $plaintext . "RC: $?\n";
			$plaintext = unpack("H*", $cipher->encrypt3($plaintext, $key));
			print ($plaintext, "\r\n");
		} elsif ($commandentered eq "exit") {
# If you get an exit on the socket, die.
			exit 0 
		} else {
# If you don't know what the hell they are talking about.
 			$plaintext = "OP: Unknown Command\r\nRC:512\r\n";
			$plaintext = unpack("H*", $cipher->encrypt3($plaintext, $key));
			print ($plaintext, "\r\n");
		}
	}
}

#################################################################################

sub Check_Command {
# If I don't have a config file given, barf the mini-howto
	unless ($opt_c) {
		print <<USAGE;
Minimum arguments not supplied!

NRPEP - Version $version
Copyright (c) 1999 Adam Jacob

Usage: nrpep -c <config file> 

-c <command> = The config file to read on startup.  Required. 
USAGE
		exit 1;
	}
}

###################################################################################

sub Get_Configs {
	my $opt_c = $_[0];

	my %commands;

# Open the config file...
	open(FILE, "$opt_c") || die "Cannot open file at $opt_c";
	foreach my $line (<FILE>) {
		chomp($line);
# Ignore comments and blank lines
		unless ($line =~ /^#/ or $line =~ /^\s*$/) {
# If it's a command line, grab the command name and toss it in a name value
# hash.  The value is the command to execute.
			if (my ($command,$plugin) = $line =~ /^\s*command\[(.+)\]=(.*)$/) {
				$commands{$command} = $plugin;
				$opt_d && print LOG "Got command '$command' = $plugin\n";
# If it's the secret, we want it!
			} elsif ($line =~ /secret=(.+)/) {
				$key = $1;
			}
		}
	}
	close(FILE);

	return %commands;
}
