#!/usr/bin/perl # # Copyright (c) 2006 Jason L. Wright (jason@thought.net) # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # # external mail validator for use with greyscanner. Uses sendmail-isms # (/etc/mail/local-host-names and /etc/mail/aliases) and the password # file to validate local usernames and domains. # use Email::Valid; use Sys::Hostname; use Sys::Syslog qw(:DEFAULT setlogsock); # by default, sendmail accepts mail for gethostname() $LOCALHOST=hostname; # sendmail style domain list (one per line, comments lines start with '#') $DOMAINS_FILE='/etc/mail/local-host-names'; # sendmail aliases file $ALIAS_FILE='/etc/mail/aliases'; sub build_domainlist { my $d; if (-f $DOMAINS_FILE) { open(F, $DOMAINS_FILE) || die "$DOMAINS_FILE"; while () { chomp; next if (/$\#/); $d = $_; $d =~ tr/A-Z/a-z/; $domains{$d} = 1; } close(F); } $domains{$LOCALHOST} = 1; } sub build_userlist { my $name, $foo; # load in /etc/passwd while (($name, $foo) = getpwent()) { $name =~ tr/A-Z/a-z/; $users{$name} = 1; } endpwent(); # aliases are kinda like users if (-f $ALIAS_FILE) { open(F, $ALIAS_FILE) || die "$ALIAS_FILE"; while () { chomp; next if (/$\#/); ($name, $foo) = split(':', $_, 2); next if ($name eq ""); $name =~ tr/A-Z/a-z/; $users{$name} = 1; } close(F); } } build_domainlist(); build_userlist(); setlogsock('unix'); openlog("greyrcpt", 'pid', 'mail') || die "can't openlog"; while ($to = shift) { syslog('debug', "checking... $to"); unless (($addr = Email::Valid->address(-address => "$to", -fudge => 1, -local_rules => 1))) { # No need to go further, the email address is borked. syslog('info', "$to: addr check fail: $Email::Valid::Details\n"); exit(1); } # at this point we should have user@domain.com style address ($user, $domain) = split('\@', $addr); $domain =~ tr/A-Z/a-z/; $user =~ tr/A-Z/a-z/; # verify the domain is one we care about unless ($domains{$domain}) { # not on this machine, sorry... syslog('info', "$to: to invalid domain\n"); exit(1); } # now verify the user is one we care about unless ($users{$user}) { syslog('info', "$to: to invalid user\n"); exit(1); } syslog('debug', "$to: pass\n"); } exit(0);