Kaynağa Gözat

new package: pb4sd 1.0 (POP-before-SMTP Daemon)

Ralf S. Engelschall 24 yıl önce
ebeveyn
işleme
83023f8ead
3 değiştirilmiş dosya ile 396 ekleme ve 0 silme
  1. 268 0
      pb4sd/pb4sd
  2. 81 0
      pb4sd/pb4sd.spec
  3. 47 0
      pb4sd/rc.pb4sd

+ 268 - 0
pb4sd/pb4sd

@@ -0,0 +1,268 @@
+#!/usr/bin/perl 
+##
+##  pb4sd -- POP-before-SMTP Daemon
+##  Copyright (c) 2001 Ralf S. Engelschall <rse@engelschall.com> 
+##
+##  This program is derived from Bennett Todd <bet@rahul.net>'s 
+##  pop-before-smtp 1.28 (http://people.oven.com/bet/pop-before-smtp/)
+##
+
+use File::Tail;
+use DB_File;
+use Net::Netmask;
+use Date::Parse;
+use Getopt::Long;
+use Fcntl ':flock';
+use POSIX qw(getpid setsid);
+use IO;
+
+#   logfile parsing patters
+my $pattern = {
+    #   QPopper 4.0.x (OpenPKG)
+    'qpopper' => 
+        '^(... .. ..:..:..) (?:<\S+>|\S+) (?:/\S+?)?q?popper\S*\[\d+\]: ' .
+        '\([^)]*\) POP login by user "[^"]+" at \([^)]+\) (\d+.\d+.\d+.\d+)$',
+    #   Qpopper 3.x
+    'popper3' => 
+        '^(\w{3} \w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}) \[\d+\] ' .
+        ' Stats:\s+\w+ \d \d \d \d [\w\.]+ (\d+\.\d+\.\d+\.\d+)',
+    #   UW ipop3d/imapd
+    'ipop3d' =>
+        '^(... .. ..:..:..) \S+ (?:ipop3d|imapd)\[\d+\]: ' .
+        '(?:Login|Authenticated|Auth) user=\S+ host=(?:\S+)?\[(\d+\.\d+\.\d+\.\d+)\](?: nmsgs=\d+/\d+)?$',
+    #   GNU pop3d
+    'popd3d' => 
+        '^(... .. ..:..:..) \S+ gnu-pop3d\[\d+\]: ' .
+        'User .* logged in with mailbox .* from (\d+\.\d+\.\d+\.\d+)$',
+    #   Cyrus
+    'cyrus' => 
+        '^(... .. ..:..:..) \S+ (?:pop3d|imapd)\[\d+\]: ' .
+        'login: \S*\[(\d+\.\d+\.\d+\.\d+)\] \S+ \S+',
+    #   Courier-IMAP
+    'courier' => 
+        '^(... .. ..:..:..) \S+ imaplogin: ' .
+        'LOGIN, user=\S+, ip=\[(\d+\.\d+\.\d+\.\d+)\]$',
+    #   Qmail pop3d
+    'pop3d' => 
+        '^(... .. ..:..:..) \S+ vpopmail\[\d+\]: ' .
+        'vchkpw: login \[\S+\] from (\d+\.\d+\.\d+\.\d+)$',
+    #   cucipop
+    'cucipop' => 
+        '^(... .. ..:..:..) \S+ cucipop\[\d+\]: \S+ ' .
+        '(\d+\.\d+\.\d+\.\d+) \d+, \d+ \(\d+\), \d+ \(\d+\)',
+    #   popa3d 
+    'popa3d' => 
+        '^(... .. ..:..:..) \S+ popa3d\[\d+\]: Authentication passed for \S+ -- \[(\d+.\d+.\d+.\d+)\]$',
+};
+
+#   parameters and their defaults
+my $daemon     = 0;
+my $infile     = 'qpopper.log';
+my $dbfile     = 'qpopper';
+my $popserver  = 'qpopper';
+my @exclude    = ();
+my $grace      = 1800;
+my $logfile    = 'pb4s.log';
+my $pidfile    = 'pb4s.pid';
+
+#   option parsing
+GetOptions(
+    "daemon!"      => \$daemon,
+    "infile=s"     => \$infile,
+    "dbfile=s"     => \$dbfile,
+    "popserver=s"  => \$popserver,
+    "exclude=s@"   => \@exclude,
+    "grace=i"      => \$grace,
+    "logfile=s"    => \$logfile,
+    "pidfile=s"    => \$pidfile,
+) or die "Usage: p4bs [--daemon]\n" .
+         "            [--infile=filename]\n" .
+         "            [--dbfile=filename]\n" .
+         "            [--popserver=type]\n" .
+         "            [--exclude=a.b.c.d/x]\n" .
+         "            [--grace=seconds]\n" .
+         "            [--logfile=filename]\n" .
+         "            [--pidfile=filename]\n";
+
+#   make sure filenames are specified as absolute paths
+die "--infile requires absolute filename" if ($infile !~ m|^/|);
+
+#   make sure it is a known pop server
+die "unknown pop server '$popserver'" if (not defined($pattern->{$popserver}));
+
+#   make sure input logfile exists
+die "logfile '$infile' not found" if (not -f $infile);
+
+#   create tail object
+my $lf = File::Tail->new(
+    name        => $infile,
+    maxinterval => 2,
+    interval    => 1,
+    adjustafter => 3,
+    resetafter  => 30
+) || die "unable to create tail object for '$infile'";
+
+#   create network block
+my $nt = {};
+foreach my $exclude (@exclude) {
+    my $nb = new Net::Netmask ($exclude) || die;
+    $nb->storeNetblock($nt);
+}
+
+#   create DB hash file
+my %db;
+my $dbh = tie %db, 'DB_File', $dbfile, O_CREAT|O_RDWR, 0666, $DB_HASH
+    || die "cannot open DB file '$dbfile': $!\n";
+
+#   create DB hash file descriptor
+my $fd = $dbh->fd;
+open(DB_FH, "+<&=$fd") || die "cannot open '$dbfile' filehandle: $!\n";
+
+#   delete database
+flock(DB_FH, LOCK_EX) || die "(exclusive) lock failed: $!\n";
+foreach $k (keys(%db)) {
+    delete $db{$k}; 
+}
+flock(DB_FH, LOCK_UN) or die "unlock failed: $!\n";
+
+#   open logfile
+my $log = new IO::File ">>$logfile" || die;
+$log->autoflush(1);
+
+#   establish signal handlers
+$SIG{__DIE__} = sub {
+    $log->print("[".localtime(time())."] DIE error=".join(" ", @_)."\n");
+    die @_;
+};
+
+#   start/stop logging
+$log->print("[".localtime(time())."] STARTUP\n");
+$SIG{'QUIT'} = $SIG{'INT'} = $SIG{'TERM'} = sub {
+    $log->print("[".localtime(time())."] SHUTDOWN\n");
+    exit(0);
+};
+
+#   optionally daemonize
+if ($daemon) {
+    my ($pid, $sess_id, $i);
+
+    #   fork and exit parent 
+    if ($pid = fork()) { 
+        exit(0); 
+    }
+
+    #   detach from the terminal
+    $sess_id = POSIX::setsid();
+
+    #   prevent possibility of acquiring a controling terminal
+    $SIG{'HUP'} = 'IGNORE'; 
+    if ($pid = fork()) {
+        exit(0);
+    }
+
+    #   create pidfile
+    open(PID, ">$pidfile") || die;
+    printf(PID "%d\n", POSIX::getpid());
+    close(PID);
+
+    #   change working directory
+    chdir("/");
+
+    #   clear file creation mask
+    umask(0);
+
+    #   close stdio file descriptors
+    close(STDIN);
+    close(STDOUT);
+    close(STDERR);
+
+    #   re-open stdio file descriptors to /dev/null
+    open(STDIN,  "+>/dev/null");
+    open(STDOUT, "+>&STDIN");
+    open(STDERR, "+>&STDIN");
+}
+
+my $t = {}; # ip to expire table
+my $q = []; # ip/expire stack
+while (1) {
+    my $line = $lf->read();
+    my $now = time();
+    if ($line =~ m/$pattern->{$popserver}/o) {
+        my ($timestamp, $ipaddr) = ($1, $2);
+
+        #   log recognition of entry
+        $log->print("[".localtime($now)."] SEE client=".$ipaddr.
+                    " login=".localtime(str2time($timestamp))."\n");
+
+        #   calculate expire time
+        my $expire = str2time($timestamp) || next;
+        $expire += $grace;
+
+        #   skip if grace period is already expired or ip is excluded
+        next if ($expire < $now);
+        next if (findNetblock($ipaddr, $nt));
+
+        #   push ip/expire onto stack
+        push @{$q}, [$ipaddr, $expire];
+
+        #   remember ip
+        my $already_enabled = exists($t->{$ipaddr});
+        $t->{$ipaddr} = $expire;
+
+        #   skip if ip was already enabled
+        next if $already_enabled;
+
+        #   lock database
+        flock(DB_FH, LOCK_EX);
+
+        #   add entry to database
+        $db{$ipaddr} = "OK";
+        $log->print("[".localtime($now)."] ADD client=".$ipaddr." logout=".localtime($expire)."\n");
+
+        #   purge expired database entries
+        while ($q->[0][1] < $now) {
+            if ($q->[0][1] == $t->{$q->[0][0]}) {
+                $log->print("[".localtime($now)."] DEL client=".$q->[0][0]." logout=".localtime($q->[0][1])."\n");
+                delete $t->{$q->[0][0]};
+                delete $db{$q->[0][0]};
+            }
+            shift @q;
+        }
+
+        #   synchronize database
+        $dbh->sync();
+
+        #   unlock database
+        flock(DB_FH, LOCK_UN);
+    }
+}
+
+__DATA__
+
+=pod
+
+=head1 NAME
+
+pb4sd -- POP-before-SMTP Daemon
+
+=head1 SYNOPSIS
+
+B<p4bsd>
+[--daemon]
+[--infile=filename]
+[--dbfile=filename]
+[--popserver=type]
+[--exclude=a.b.c.d/x]
+[--grace=seconds]
+[--logfile=filename]
+[--pidfile=filename]
+
+=head1 DESCRIPTION
+
+B<pb4sd> is a little daemon program which watches a POP/IMAP server's
+logfile for successful client authentications and writes the
+corresponding IP addresses into a Berkeley-DB hash file. This hash file
+then can be used by the MTA to allow relaying access.
+
+=cut
+

+ 81 - 0
pb4sd/pb4sd.spec

@@ -0,0 +1,81 @@
+##
+##  pb4sd.spec -- OpenPKG RPM Specification
+##  Copyright (c) 2000-2001 Cable & Wireless Deutschland GmbH
+##  Copyright (c) 2000-2001 The OpenPKG Project <http://www.openpkg.org/>
+##  Copyright (c) 2000-2001 Ralf S. Engelschall <rse@engelschall.com>
+##
+##  Permission to use, copy, modify, and distribute this software for
+##  any purpose with or without fee is hereby granted, provided that
+##  the above copyright notice and this permission notice appear in all
+##  copies.
+##
+##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+##  CONTRIBUTORS 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. 
+##  
+
+#   package information
+Name:         pb4sd
+Summary:      POP-before-SMTP Daemon
+URL:          -
+Vendor:       Cable & Wireless DE
+Packager:     The OpenPKG Project
+Distribution: OpenPKG [EXP]
+Group:        Mail
+License:      PD
+Version:      1.0
+Release:      20011228
+
+#   list of sources
+Source0:      pb4sd
+Source1:      rc.pb4sd
+
+#   build information
+Prefix:       %{l_prefix}
+BuildRoot:    %{l_buildroot}
+BuildPreReq:  OpenPKG, openpkg >= 20011227, perl, perl-db
+PreReq:       OpenPKG, openpkg >= 20011227, perl, perl-db, POP
+AutoReq:      no
+AutoReqProv:  no
+
+%description
+    pb4sd is a little daemon program which watches a POP/IMAP server's
+    logfile for successful client authentications and writes the
+    corresponding IP addresses into a Berkeley-DB hash file. This hash
+    file then can be used by the MTA to allow relaying access.
+
+%prep
+
+%build
+
+%install
+    rm -rf $RPM_BUILD_ROOT
+    %{l_shtool} mkdir -f -p -m 755 \
+        $RPM_BUILD_ROOT%{l_prefix}/sbin \
+        $RPM_BUILD_ROOT%{l_prefix}/man/man8 \
+        $RPM_BUILD_ROOT%{l_prefix}/etc/rc.d \
+        $RPM_BUILD_ROOT%{l_prefix}/var/pb4sd
+    %{l_shtool} install -c -m 755 \
+        -e 's;/usr/bin/perl;%{l_prefix}/bin/perl;g' \
+        %{SOURCE pb4sd} $RPM_BUILD_ROOT%{l_prefix}/sbin/
+    %{l_prefix}/bin/pod2man \
+        %{SOURCE pb4sd} >$RPM_BUILD_ROOT%{l_prefix}/man/man8/pb4sd.8
+    %{l_shtool} install -c -m 755 \
+        -e 's;@l_prefix@;%{l_prefix};g' \
+        %{SOURCE rc.pb4sd} $RPM_BUILD_ROOT%{l_prefix}/etc/rc.d/
+    %{l_rpmtool} files -v -ofiles -r$RPM_BUILD_ROOT %{l_files_std}
+
+%files -f files
+
+%clean
+    rm -rf $RPM_BUILD_ROOT
+

+ 47 - 0
pb4sd/rc.pb4sd

@@ -0,0 +1,47 @@
+#!@l_prefix@/lib/openpkg/bash @l_prefix@/etc/rc
+##
+##  rc.pb4sd -- Run-Commands for PB4SD
+##
+
+%config
+    pb4sd_enable="yes"
+    pb4sd_dbfile="@l_prefix@/var/pb4sd/pb4sd.db"
+    pb4sd_logfile="@l_prefix@/var/pb4sd/pb4sd.log"
+    pb4sd_pidfile="@l_prefix@/var/pb4sd/pb4sd.pid"
+    pb4sd_grace="3600"
+    pb4sd_exclude="127.0.0.0/8"
+    pb4sd_log_prolog="true"
+    pb4sd_log_epilog="true"
+    pb4sd_log_numfiles="10"
+    pb4sd_log_minsize="1M"
+    pb4sd_log_complevel="9"
+
+%start -p 200 -u root
+    opServiceEnabled pb4sd || exit 0
+    pb4sd_popserver="${pop_type:-qpopper}"
+    pb4sd_infile="${pop_logfile:-@l_prefix@/var/qpopper/qpopper.log}"
+    @l_prefix@/sbin/pb4sd \
+        --daemon \
+        --popserver="${pb4sd_popserver}" \
+        --infile="${pb4sd_infile}" \
+        --dbfile="${pb4sd_dbfile}" \
+        --logfile="${pb4sd_logfile}" \
+        --pidfile="${pb4sd_pidfile}" \
+        --grace="${pb4sd_grace}" \
+        --exclude="${pb4sd_exclude}"
+
+%stop -p 200 -u root
+    opServiceEnabled pb4sd || exit 0
+    if [ -f $pb4sd_logfile ]; then
+        kill -TERM `cat ${pb4sd_logfile}`
+    fi
+
+%daily -u root
+    opServiceEnabled pb4sd || exit 0
+    shtool rotate -f \
+        -n${pb4sd_log_numfiles} -s${pb4sd_log_minsize} -d \
+        -z${pb4sd_log_complevel} -o@l_fsusr@ -o@l_fsgrp@ -m644 \
+        -P "${pb4sd_log_prolog}" \
+        -E "${pb4sd_log_epilog}" \
+        ${pb4sd_logfile}
+