Commit e80918dd authored by Nigel Kukard's avatar Nigel Kukard
Browse files

* Backported support for reverse DNS policies

parent 6f5e4099
......@@ -36,6 +36,8 @@ use cbp::logging;
use cbp::dblayer;
use cbp::system;
use Data::Dumper;
# Database handle
my $dbh = undef;
......@@ -75,10 +77,12 @@ sub Error
# Hash - indexed by policy priority, the value is an array of policy ID's
sub getPolicy
{
my ($server,$sourceIP,$emailFrom,$emailTo,$saslUsername) = @_;
my ($server,$sessionData) = @_;
my $log = defined($server->{'config'}{'logging'}{'policies'});
$server->log(LOG_DEBUG,"[POLICIES] Going to resolve session data into policy: ".Dumper($sessionData)) if ($log);
# Start with blank policy list
my %matchedPolicies = ();
......@@ -139,7 +143,7 @@ sub getPolicy
my $history = {}; # Used to track depth & loops
foreach my $item (@rawSources) {
# Process item
my $res = policySourceItemMatches($server,$debugTxt,$history,$item,$sourceIP,$emailFrom,$saslUsername);
my $res = policySourceItemMatches($server,$debugTxt,$history,$item,$sessionData);
# Check for error
if ($res < 0) {
$server->log(LOG_WARN,"[POLICIES] $debugTxt: Error while processing source item '$item', skipping...");
......@@ -180,7 +184,7 @@ sub getPolicy
my $history = {}; # Used to track depth & loops
foreach my $item (@rawDestinations) {
# Process item
my $res = policyDestinationItemMatches($server,$debugTxt,{},$item,$emailTo);
my $res = policyDestinationItemMatches($server,$debugTxt,$history,$item,$sessionData);
# Check for error
if ($res < 0) {
$server->log(LOG_WARN,"[POLICIES] $debugTxt: Error while processing destination item '$item', skipping...");
......@@ -255,7 +259,7 @@ sub getGroupMembers
# Check if this source item matches, this function automagically resolves groups aswell
sub policySourceItemMatches
{
my ($server,$debugTxt,$history,$rawItem,$sourceIP,$emailFrom,$saslUsername) = @_;
my ($server,$debugTxt,$history,$rawItem,$sessionData) = @_;
my $log = defined($server->{'config'}{'logging'}{'policies'});
......@@ -292,7 +296,7 @@ sub policySourceItemMatches
if (@{$groupMembers} > 0) {
foreach my $gmember (@{$groupMembers}) {
# Process this group member
my $res = policySourceItemMatches($server,"$debugTxt=>(group:$item)",$history,$gmember,$sourceIP,$emailFrom,$saslUsername);
my $res = policySourceItemMatches($server,"$debugTxt=>(group:$item)",$history,$gmember,$sessionData);
# Check for hard error
if ($res < 0) {
return $res;
......@@ -313,19 +317,24 @@ sub policySourceItemMatches
# Match IP
if ($item =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\/\d{1,2})$/) {
$res = ipMatches($sourceIP,$item);
$res = ipMatches($sessionData->{'ClientAddress'},$item);
$server->log(LOG_DEBUG,"[POLICIES] $debugTxt: - Resolved source '$item' to a IP/CIDR specification, match = $res") if ($log);
# Match SASL user, must be above email addy to match SASL usernames in the same format as email addies
} elsif ($item =~ /^\$\S+$/) {
$res = saslUsernameMatches($saslUsername,$item);
$res = saslUsernameMatches($sessionData->{'SASLUsername'},$item);
$server->log(LOG_DEBUG,"[POLICIES] $debugTxt: - Resolved source '$item' to a SASL user specification, match = $res") if ($log);
# Match email addy
} elsif ($item =~ /^\S*@\S+$/) {
$res = emailAddressMatches($emailFrom,$item);
$res = emailAddressMatches($sessionData->{'Sender'},$item);
$server->log(LOG_DEBUG,"[POLICIES] $debugTxt: - Resolved source '$item' to a email address specification, match = $res") if ($log);
# Match domain name (for reverse dns)
} elsif ($item =~ /^(?:[a-z0-9\-_\*]+\.)+[a-z0-9]+$/i) {
$res = reverseDNSMatches($sessionData->{'ClientReverseName'},$item);
$server->log(LOG_DEBUG,"[POLICIES] $debugTxt: - Resolved source '$item' to a reverse dns specification, match = $res") if ($log);
# Not valid
} else {
$server->log(LOG_WARN,"[POLICIES] $debugTxt: - Source '".$item."' is not a valid specification");
......@@ -344,7 +353,7 @@ sub policySourceItemMatches
# Check if this destination item matches, this function automagically resolves groups aswell
sub policyDestinationItemMatches
{
my ($server,$debugTxt,$history,$rawItem,$emailTo) = @_;
my ($server,$debugTxt,$history,$rawItem,$sessionData) = @_;
my $log = defined($server->{'config'}{'logging'}{'policies'});
......@@ -381,7 +390,7 @@ sub policyDestinationItemMatches
if (@{$groupMembers} > 0) {
foreach my $gmember (@{$groupMembers}) {
# Process this group member
my $res = policyDestinationItemMatches($server,"$debugTxt=>(group:$item)",$history,$gmember,$emailTo);
my $res = policyDestinationItemMatches($server,"$debugTxt=>(group:$item)",$history,$gmember,$sessionData);
# Check for hard error
if ($res < 0) {
return $res;
......@@ -402,7 +411,7 @@ sub policyDestinationItemMatches
# Match email addy
if ($item =~ /^!?\S*@\S+$/) {
$res = emailAddressMatches($emailTo,$item);
$res = emailAddressMatches($sessionData->{'Recipient'},$item);
$server->log(LOG_DEBUG,"[POLICIES] $debugTxt: - Resolved destination '$item' to a email address specification, match = $res") if ($log);
} else {
......@@ -496,6 +505,40 @@ sub saslUsernameMatches
}
# Check if first arg lies within the scope of second arg reverse dns specification
sub reverseDNSMatches
{
my ($reverseDNSMatches,$template) = @_;
my $match = 0;
my $partial = 0;
# Check if we have a . at the beginning of the line to match partials
if ($template =~ /^\./) {
$partial = 1;
}
# Replace all .'s with \.'s
$template =~ s/\./\\./g;
# Change *'s into a proper regex expression
$template =~ s/\*/[a-z0-9\-_\.]*/g;
# Check for partial match
if ($partial) {
if ($reverseDNSMatches =~ /$template$/i) {
$match = 1;
}
# Check for exact match
} else {
if ($reverseDNSMatches =~ /^$template$/i) {
$match = 1;
}
}
return $match;
}
# Encode policy data into session recipient data
sub encodePolicyData
{
......
......@@ -203,8 +203,10 @@ sub getSessionDataFromRequest
if ($request->{'protocol_state'} eq 'RCPT') {
$server->log(LOG_DEBUG,"[TRACKING] Protocol state is 'RCPT', resolving policy...") if ($log);
$sessionData->{'Recipient'} = $request->{'recipient'};
# Get policy
my $policy = getPolicy($server,$request->{'client_address'},$request->{'sender'},$request->{'recipient'},$request->{'sasl_username'});
my $policy = getPolicy($server,$sessionData);
if (ref $policy ne "HASH") {
return -1;
}
......@@ -212,7 +214,6 @@ sub getSessionDataFromRequest
$server->log(LOG_DEBUG,"[TRACKING] Policy resolved into: ".Dumper($policy)) if ($log);
$sessionData->{'Policy'} = $policy;
$sessionData->{'Recipient'} = $request->{'recipient'};
# If we in end of message, load policy from data
} elsif ($request->{'protocol_state'} eq 'END-OF-MESSAGE') {
......@@ -231,6 +232,7 @@ sub getSessionDataFromRequest
# Check for HTTP protocol transport
} elsif ($request->{'_protocol_transport'} eq "HTTP") {
$sessionData->{'ClientAddress'} = $request->{'client_address'};
$sessionData->{'ClientReverseName'} = $request->{'client_reverse_name'} if (defined($request->{'client_reverse_name'}));
$sessionData->{'Helo'} = $request->{'helo_name'} if (defined($request->{'helo_name'}));
$sessionData->{'Sender'} = $request->{'sender'};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment