#!/usr/bin/perl

use strict;

use lib '/etc/openvpn';

use vars qw(%RAD_REQUEST %RAD_REPLY %RAD_CHECK);
use Data::Dumper;
use File::Basename;

use NVPNLog;
use NVPNApi;

# setting up syslog
nvpn_log_init;

# Original request from radius
#my %RAD_REQUEST;
# Hash returned to NAS.
#my %RAD_REPLY;
# Check items
#my %RAD_CHECK;

use constant RLM_MODULE_REJECT   => 0; #  /* immediately reject the request */
use constant RLM_MODULE_FAIL     => 1; #  /* module failed, don't reply */
use constant RLM_MODULE_OK       => 2; #  /* the module is OK, continue */
use constant RLM_MODULE_HANDLED  => 3; #  /* the module handled the request, so stop. */
use constant RLM_MODULE_INVALID  => 4; #  /* the module considers the request invalid. */
use constant RLM_MODULE_USERLOCK => 5; #  /* reject the request (user is locked out) */
use constant RLM_MODULE_NOTFOUND => 6; #  /* user not found */
use constant RLM_MODULE_NOOP     => 7; #  /* module succeeded without doing anything */
use constant RLM_MODULE_UPDATED  => 8; #  /* OK (pairs modified) */
use constant RLM_MODULE_NUMCODES => 9; #  /* How many return codes there are */

my %sessions = ();

sub authorize
{
	#&log_request_attributes;

	if (exists($RAD_REQUEST{'User-Password'}))
	{
		$RAD_CHECK{'Auth-Type'} = 'PAP';
		return RLM_MODULE_OK;
	}
	else # chap, mschapv1, mschapv2
	{ 
		$RAD_CHECK{'Cleartext-Password'} = nvpn_get_password($RAD_REQUEST{'User-Name'});
		return RLM_MODULE_UPDATED;
	}
}

# Function to handle authenticate
sub authenticate
{
	#&log_request_attributes;
	my $ret = RLM_MODULE_REJECT;

	if (exists($RAD_REQUEST{'User-Password'})) {
		$ret = nvpn_validate_user($RAD_REQUEST{'User-Name'}, $RAD_REQUEST{'User-Password'}, $RAD_REQUEST{'NAS-IP-Address'}, $RAD_REQUEST{'NAS-Identifier'});
	} else {
		$ret = nvpn_validate_chap_user($RAD_REQUEST{'User-Name'}, $RAD_REQUEST{'NAS-IP-Address'}, $RAD_REQUEST{'NAS-Identifier'});
	}

	if ($ret == FAILURE) {
		$RAD_REPLY{'Reply-Message'} = "Denied access by rlm_perl function";
		return RLM_MODULE_REJECT;
	} else {
		$RAD_CHECK{'Auth-Type'} = 'Accept';
		return RLM_MODULE_OK;
	}
}

# Function to handle preacct
sub preacct
{
	# &log_request_attributes;
	return RLM_MODULE_OK;
}

# Function to handle accounting
sub accounting
{
	#&log_request_attributes;

	# if NAS is socks, no need to setup NAT, just allow user to use service
	return RLM_MODULE_OK if ($RAD_REQUEST{'NAS-Identifier'} eq "socks");
	return RLM_MODULE_OK if ($RAD_REQUEST{'NAS-Identifier'} eq "strongswan");

	if ($RAD_REQUEST{'Acct-Status-Type'} eq "Start") {
		&log_request_attributes;
		&radiusd::radlog(0,"rlm_perl::accounting - point to do clientconnect [".$RAD_REQUEST{'User-Name'}.", ".$RAD_REQUEST{'Framed-IP-Address'}.", ".$RAD_REQUEST{'NAS-IP-Address'}."]");
		nvpn_handle_connect($RAD_REQUEST{'User-Name'}, $RAD_REQUEST{'Framed-IP-Address'}, $RAD_REQUEST{'NAS-IP-Address'}, "1.2.3.4", $RAD_REQUEST{'NAS-Identifier'});
	}

	if ($RAD_REQUEST{'Acct-Status-Type'} eq "Stop") {
		&radiusd::radlog(0,"rlm_perl::accounting - point to do clientdisconnect [".$RAD_REQUEST{'User-Name'}.", ".$RAD_REQUEST{'Framed-IP-Address'}.", ".$RAD_REQUEST{'NAS-IP-Address'}."]");
		nvpn_handle_disconnect($RAD_REQUEST{'User-Name'}, $RAD_REQUEST{'Framed-IP-Address'}, $RAD_REQUEST{'NAS-IP-Address'}, $RAD_REQUEST{'NAS-Identifier'});
        }

	return RLM_MODULE_OK;
}

# Function to handle checksimul
sub checksimul
{
	# &log_request_attributes;
	return RLM_MODULE_OK;
}

# Function to handle pre_proxy
sub pre_proxy
{
	# &log_request_attributes;
	return RLM_MODULE_OK;
}

# Function to handle post_proxy
sub post_proxy
{
	# &log_request_attributes;
	return RLM_MODULE_OK;
}

# Function to handle post_auth
sub post_auth
{
	# &log_request_attributes;
	return RLM_MODULE_OK;
}

# Function to handle xlat
sub xlat
{
	# &log_request_attributes;

	my ($filename,$a,$b,$c,$d) = @_;
	&radiusd::radlog(1, "From xlat $filename ");
	&radiusd::radlog(1,"From xlat $a $b $c $d ");
	local *FH;
	open FH, $filename or die "open '$filename' $!";
	local($/) = undef;
	my $sub = <FH>;
	close FH;
	my $eval = qq{ sub handler{ $sub;} };
	eval $eval;
	eval {main->handler;};
}

# Function to handle detach
sub detach
{
	# &log_request_attributes;
	&radiusd::radlog(0,"rlm_perl::Detaching. Reloading. Done.");
}

sub log_request_attributes {
	# This shouldn't be done in production environments!
	# This is only meant for debugging!
	for (keys %RAD_REQUEST) {
		&radiusd::radlog(1, "RAD_REQUEST: $_ = $RAD_REQUEST{$_}");
	}
}

