#!/usr/bin/perl # $Id: pbs.pl,v 1.13 2005/12/18 03:31:46 jcs Exp $ # vim:ts=4 # # pbs.pl # pop/imap-before-smtp for postfix and popa3d/dovecot/other # # Copyright (c) 2004-2005 joshua stein # # 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. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # 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. # # # for popa3d, apply http://jcs.org/patches/popa3d-logging.diff to your popa3d # source tree, recompile, reinstall, and restart popa3d, ensure authentication # entries are showing up in /var/log/messages # # for dovecot, make sure logging is turned on and showing up in # /var/log/dovecot # # create a pbs user # echo "# 1" > /etc/postfix/pop-before-smtp # echo "127.0.0.1 OK" >> /etc/postfix/pop-before-smtp # postmap /etc/postfix/pop-before-smtp # chown pbs:pbs /etc/postfix/pop-before-smtp* # # add "check_client_access hash:/etc/postfix/pop-before-smtp" to the # smtpd_recipient_restrictions setting in postfix # # run: # sudo -u pbs perl ~pbs/pbs.pl & # at startup # # run: # perl ~pbs/pbs.pl -p # in the pbs user's crontab every so often to purge old entries # use Fcntl ':flock'; # where our db will be my $dbfile = "/etc/postfix/pop-before-smtp"; # where the pop/imap log is my $poplog = "/var/log/maillog"; # my $poplog = "/var/log/dovecot"; # maximum seconds an entry can live (6 hours) my $maxlife = (60 * 60 * 6); # make sure we can find tail and postmap $ENV{"PATH"} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"; $|++; if ($ARGV[0] eq "-p") { # purge old entries from the database my @newfile; open(PBSDB, "<" . $dbfile) or die "can't read " . $dbfile . ": " . $!; while (my $line = ) { if ($line =~ /# (\d+)\n$/) { my $timestamp = $1; chop(my $ip = ); if ((time() - $timestamp) > $maxlife) { # delete this entry } else { push @newfile, "# " . $timestamp; push @newfile, $ip; } } } close(PBSDB); # rewrite the db open(DB, ">" . $dbfile) or die "can't rewrite " . $dbfile . ": " . $!; flock(DB, LOCK_EX); for ($x = 0; $x <= $#newfile; $x++) { print DB $newfile[$x] . "\n"; } flock(DB, LOCK_UN); close(DB); # regenerate db system("postmap", "hash:" . $dbfile); exit; } elsif ($ARGV[0]) { die "usage: " . $0 . " [-p]\n"; } # else, run as a daemon while (1) { open(TAIL, "tail -n0 -f " . $poplog . " |") or die "can't run tail: " . $!; while (my $line = ) { if (($line =~ /popa3d.*: Authentication passed .* \[(.+)\]/) or ($line =~ /^dovecot:.*imap-login: Login: .*rip=(.+?), lip=/)) { my $ip = $1; if ($ip !~ /^\d+\.\d+\.\d+\.\d+$/) { next; } # see if the db has this ip already my $query = `postmap -q $ip $dbfile`; if ($query =~ /OK/) { # exists already next; } # else add it open(DB, ">>" . $dbfile) or die "can't append to " . $dbfile . ": " . $!; flock(DB, LOCK_EX); # just incase seek(DB, 0, 2); # add print DB "# " . time() . "\n"; print DB $ip . " OK\n"; close(DB); flock(DB, LOCK_UN); # regen system("postmap", "hash:" . $dbfile); # verbosity print "added " . $ip . "\n"; } } # we should never get here close(TAIL); sleep 1; }