Added rule to logging
[clearscm.git] / maps / bin / maps
1 #!/usr/bin/perl
2
3 =pod
4
5 =head1 NAME $RCSfile: maps,v $
6
7 This script filters mail based on the files nulllist, blacklist and whitelist. 
8 Input is an email message. This script extracts the From line and then parses 
9 the email address. If the email is from a sender who should be /dev/null'ed 
10 (e.g. bounce messages from mail daemons) the message will be discarded. If the
11 sender is on the blacklist then a message is sent back informing the sender that
12 he's been blacklisted. If the sender is on the white list then the email is 
13 appended to the mail drop file. Otherwise a message is sent back informing the
14 sender that in order to successfully send email the sender must register for the
15 permission to do so, along with a URL that allows the sender to sign up.
16
17 =head1 VERSION
18
19 =over
20
21 =item Author
22
23 Andrew DeFaria <Andrew@DeFaria.com>
24
25 =item Revision
26
27 $Revision: 1.1 $
28
29 =item Created:
30
31 Fri Nov 29 14:17:21  2002
32
33 =item Modified:
34
35 $Date: 2013/06/12 14:05:47 $
36
37 =back
38
39 =head1 SYNOPSIS
40
41  Usage maps: [-u|ser <username>] [-ve|rbose] [-deb|ug] [-e|xecute]
42
43  Where:
44    -u|ser <username>: Set context to this username
45
46    -v|erbose:         Be verbose
47    -de|bug:           Output debug messages
48
49    -[no]e|xecute:     Set execute mode.
50    -f|ile <file>:     File to use as a test message
51
52 # (c) Copyright 2000-2021, Andrew@DeFaria.com, all rights reserved.
53
54 =cut 
55
56 use strict;
57 use warnings;
58
59 use Getopt::Long;
60 use Pod::Usage;
61 use Email::Valid;
62 use FindBin;
63 use File::Temp qw (tempfile);
64 use Net::Domain qw (hostdomain);
65
66 use lib "$FindBin::Bin/../lib";
67 use lib "$FindBin::Bin/../../lib";
68
69 use MAPS;
70 use MAPSLog;
71
72 use Display;
73 use Logger;
74 use Utils;
75
76 my %opts = (
77   execute => 1,
78 );
79
80 my $userid = $ENV{USER};
81
82 my $log;
83
84 # For some reason I'm not parsing messages correctly but it only seems to
85 # happen when the message is piped in from the MTA. This routine will
86 # temporarily save the messages in a file.
87 sub SaveStdin() {
88   # Generate tempfile
89   my $msgfile = tempfile ();
90
91   # Read STDIN and write it out to the tempfile
92   while (<STDIN>) {
93     print $msgfile $_;
94   } # while
95
96   # Seek to the start of the file (Note if we closed it, it would be deleted)
97   seek $msgfile, 0, 0;
98
99   # Return the filehandle
100   return $msgfile;
101 } # SaveStdin
102
103 sub ValidDomainUser($) {
104   my ($sender) = @_;
105
106   my ($username, $domainname);
107
108   if ($sender =~ /(.*)\@(.*)/) {
109     $username   = $1;
110     $domainname = $2;
111   } else {
112     return 1;
113   } # if
114
115   return 1 if $domainname ne hostdomain;
116
117   # Let BICE email come through
118   return 1 if $username eq "bice";
119
120   my $uid = getpwnam $username;
121
122   return defined $uid ? 1 : 0;
123 } # ValidDomainUser
124
125 sub ProcessMsgs ($$$) {
126   my ($msgfile, $username, $user_email) = @_;
127
128   return unless $opts{execute};
129
130   while (!eof $msgfile) {
131     my ($sender, $sender_long, $reply_to, $subject, $data) = ReadMsg ($msgfile);
132
133     my ($onlist, $rule, $sequence, $hit_count);
134
135     # Algorithm change: We now first check to see if the sender is not found
136     # in the message and skip it if so. Then we handle if we are the sender
137     # and that the from address is formatted properly. Spammers often use 
138     # the senders email address (i.e. andrew@defaria.com) as their from address
139     # so we check "Andrew DeFaria <Andrew@DeFaria.com>", which they have never
140     # forged. This catches a lot of spam actually.
141     #
142     # Next we check to see if the sender is on our whitelist. If so then we let
143     # them in. This allows us to say whitelist josephrosenberg@hotmail.com while
144     # still nulllisting all of the other hotmail.com spammers.
145     #
146     # Next we process blacklisted people as they are also of high priority.
147     #
148     # Then we process nulllist people.
149     #
150     # Finally, we handle return processing
151
152     # Discard any email with an invalid email address
153     next unless Email::Valid->address($sender);
154
155     if ($sender eq $user_email and
156             (lc ($sender_long) !~ lc ("\"$username\" <$user_email>") and
157              lc ($sender_long) !~ lc ("$username <$user_email>"))) {
158       $log->msg("Nulllisting message from sender ($sender_long) pretending to be $user_email");
159
160       Nulllist $sender;
161
162       next;
163     } # if
164
165     # Check whitelist:
166     ($onlist, $rule, $sequence, $hit_count) = OnWhitelist $sender;
167
168     if ($onlist) {
169       if (ValidDomainUser $sender) {
170         $log->msg("Whitelisting $sender - Rule: $rule:$sequence/$hit_count");
171
172         Whitelist $sender, $data, $sequence, $hit_count;
173       } else {
174         $log->msg("Sender ($sender) from this domain but user not found");
175
176         Nulllist $sender;
177       } # if
178
179       next;
180     } # if
181
182     # Check blacklist:
183     ($onlist, $rule, $sequence, $hit_count) = OnBlacklist $sender;
184
185     if ($onlist) {
186       $log->msg("Blacklisting $sender - Rule: $rule:$sequence/$hit_count");
187
188       Blacklist(
189         userid    => $userid,
190         sender    => $sender,
191         sequence  => $sequence,
192         hit_count => $hit_count,
193         data      => $data,
194       );
195
196       next;
197     } # if 
198
199     # Check nulllist:
200     ($onlist, $rule, $sequence, $hit_count) = OnNulllist $sender;
201
202     if ($onlist) {
203       $log->msg("Nulllisting $sender - Rule: $rule:$sequence/$hit_count");
204       Nulllist $sender, $sequence, $hit_count;
205       next;
206     } # if
207
208     # Return processing:
209     $log->msg("Returning message from $sender");
210
211     ReturnMsg(
212       userid   => $userid,
213       sender   => $sender,
214       reply_to => $reply_to,
215       subject  => $subject,
216       data     => $data,
217     );
218   } # while
219 } # ProcessMsgs
220
221 # Main
222 GetOptions(
223   \%opts,
224   'user=s',
225   'verbose',
226   'debug',
227   'execute!',
228 ) or pod2usage;
229
230 $log = Logger->new(
231   path        => '/var/local/log',
232   timestamped => 'yes',
233   append      => 'yes',
234 );
235
236 my $msgfile;
237
238 if ($ARGV[0] and $ARGV[0] ne "") {
239   open $msgfile, '<', $ARGV[0];
240
241   unless ($msgfile) {
242     $log->err("Unable to open file ($ARGV[0]): $!");
243     exit 1;
244   } # if
245 } else {
246   $msgfile = SaveStdin;
247 } # if 
248
249 # Get user
250 FindUser(userid => $userid);
251
252 my $user = GetUser;
253
254 ProcessMsgs $msgfile, $user->{name}, lc $user->{email};
255
256 exit 0;