#!/usr/bin/perl =pod =head1 NAME $RCSfile: maps,v $ This script filters mail based on the files nulllist, blacklist and whitelist. Input is an email message. This script extracts the From line and then parses the email address. If the email is from a sender who should be /dev/null'ed (e.g. bounce messages from mail daemons) the message will be discarded. If the sender is on the blacklist then a message is sent back informing the sender that he's been blacklisted. If the sender is on the white list then the email is appended to the mail drop file. Otherwise a message is sent back informing the sender that in order to successfully send email the sender must register for the permission to do so, along with a URL that allows the sender to sign up. =head1 VERSION =over =item Author Andrew DeFaria =item Revision $Revision: 1.1 $ =item Created: Fri Nov 29 14:17:21 2002 =item Modified: $Date: 2013/06/12 14:05:47 $ =back =head1 SYNOPSIS Usage maps: [-u|ser ] [-ve|rbose] [-deb|ug] [-e|xecute] Where: -u|ser : Set context to this username -v|erbose: Be verbose -de|bug: Output debug messages -[no]e|xecute: Set execute mode. -f|ile : File to use as a test message # (c) Copyright 2000-2021, Andrew@DeFaria.com, all rights reserved. =cut use strict; use warnings; use Getopt::Long; use Pod::Usage; use Email::Valid; use FindBin; use File::Temp qw (tempfile); use Net::Domain qw (hostdomain); use lib "$FindBin::Bin/../lib"; use lib "$FindBin::Bin/../../lib"; use MAPS; use MAPSLog; use Display; use Logger; use Utils; my %opts = ( execute => 1, ); my $userid = $ENV{USER}; my $log; # For some reason I'm not parsing messages correctly but it only seems to # happen when the message is piped in from the MTA. This routine will # temporarily save the messages in a file. sub SaveStdin() { # Generate tempfile my $msgfile = tempfile (); # Read STDIN and write it out to the tempfile while () { print $msgfile $_; } # while # Seek to the start of the file (Note if we closed it, it would be deleted) seek $msgfile, 0, 0; # Return the filehandle return $msgfile; } # SaveStdin sub ValidDomainUser($) { my ($sender) = @_; my ($username, $domainname); if ($sender =~ /(.*)\@(.*)/) { $username = $1; $domainname = $2; } else { return 1; } # if return 1 if $domainname ne hostdomain; # Let BICE email come through return 1 if $username eq "bice"; my $uid = getpwnam $username; return defined $uid ? 1 : 0; } # ValidDomainUser sub formatRule($) { my ($rec) = @_; return "$rec->{pattern}\@$rec->{domain}:$rec->{sequence}/$rec->{hit_count} $rec->{comment}"; } # formatRule sub ProcessMsgs ($$$) { my ($msgfile, $username, $user_email) = @_; return unless $opts{execute}; while (!eof $msgfile) { my %msgInfo = ReadMsg $msgfile; my ($onlist, $rec, $sequence, $hit_count); # Algorithm change: We now first check to see if the sender is not found # in the message and skip it if so. Then we handle if we are the sender # and that the from address is formatted properly. Spammers often use # the senders email address (i.e. andrew@defaria.com) as their from address # so we check "Andrew DeFaria ", which they have never # forged. This catches a lot of spam actually. # # Next we check to see if the sender is on our whitelist. If so then we let # them in. This allows us to say whitelist josephrosenberg@hotmail.com while # still nulllisting all of the other hotmail.com spammers. # # Next we process blacklisted people as they are also of high priority. # # Then we process nulllist people. # # Finally, we handle return processing # Discard any email with an invalid email address next unless Email::Valid->address($msgInfo{sender}); if ($msgInfo{sender} eq $user_email and (lc ($msgInfo{sender_long}) !~ lc ("\"$username\" <$user_email>") and lc ($msgInfo{sender_long}) !~ lc ("$username <$user_email>"))) { $log->msg("Nulllisting message from sender ($msgInfo{sender_long}) pretending to be $user_email - Subject: $msgInfo{subject}"); next; } # if # Discard messges coming from andrew@clearscm.com because I don't send from # that email address if (lc $msgInfo{to} eq 'andrew@clearscm.com') { $log->msg("Nulllisting message from Andrew\@ClearSCM.com since I don't send from that email address - Subject: $msgInfo{subject}"); next; } # if # Check whitelist: ($onlist, $rec) = OnWhitelist $msgInfo{sender}; if ($onlist) { if (ValidDomainUser $msgInfo{sender}) { $log->msg("Whitelisting $msgInfo{sender} - Rule: " . formatRule($rec) . " - Subject: $msgInfo{subject}"); Whitelist $msgInfo{sender}, $msgInfo{data}, $rec->{sequence}, $rec->{hit_count}; } else { $log->msg("Sender ($msgInfo{sender}) from this domain but user not found - Subject: $msgInfo{subject}"); Nulllist $msgInfo{sender}; } # if next; } # if # Check blacklist: ($onlist, $rec) = OnBlacklist $msgInfo{sender}; if ($onlist) { $log->msg("Blacklisting $msgInfo{sender} - Rule: " . formatRule($rec) . " - Subject: $msgInfo{subject}"); Blacklist( userid => $userid, sender => $msgInfo{sender}, sequence => $rec->{sequence}, hit_count => $rec->{hit_count}, data => $msgInfo{data}, ); next; } # if # Check nulllist: ($onlist, $rec) = OnNulllist $msgInfo{sender}; if ($onlist) { $log->msg("Nulllisting $msgInfo{sender} - Rule: " . formatRule($rec) . " - Subject: $msgInfo{subject}"); Nulllist $msgInfo{sender}, $rec->{sequence}, $rec->{hit_count}; next; } # if # Return processing: $log->msg("Returning message from $msgInfo{sender} - Subject: $msgInfo{subject}"); ReturnMsg( userid => $userid, sender => $msgInfo{sender}, reply_to => $msgInfo{reply_to}, subject => $msgInfo{subject}, data => $msgInfo{data}, ); } # while } # ProcessMsgs # Main GetOptions( \%opts, 'user=s', 'verbose', 'debug', 'execute!', ) or pod2usage; $log = Logger->new( path => '/var/local/log', timestamped => 'yes', append => 'yes', ); my $msgfile; if ($ARGV[0] and $ARGV[0] ne '') { open $msgfile, '<', $ARGV[0]; unless ($msgfile) { $log->err("Unable to open file ($ARGV[0]): $!"); exit 1; } # if } else { $msgfile = SaveStdin; } # if # Get user FindUser(userid => $userid); my $user = GetUser; ProcessMsgs $msgfile, $user->{name}, lc $user->{email}; exit 0;