#!/usr/bin/perl # popauthd # # by M.D. Brownsworth # # Version 2.7 # 6 Feb 02 # # Authenticates SMTP relay using POP # # Daemon runs in background looking for successful POP logins in # syslog. When one appears, if user is already in database, only # timestamp in access.info file is updated; otherwise, entry with # user's IP is added to access file, database is rehashed, and # date, userid, IP, and timestamp are added to access.info. A # companion cron script runs periodically to prune expired entries. # # Example of qpopper entry for successful login: # Mar 16 10:54:52 straylight popper[21040]: (v3.1.2) POP login by user "michelle" at (c885447-a.duckburg.or.home.com) 240.141.21.140 require 5.004; use IO::Seekable; use Fcntl qw(:DEFAULT :flock); $syslog = "/var/log/messages"; $maildir = "/etc/mail"; $access = "$maildir/access"; $makeaccess ="$maildir/makeaccess"; $pidfile = "/var/run/popauthd.pid"; open(PID,">$pidfile") or die "Can't open $pidfile: $!\n"; print PID "$$\n"; close(PID); open (SYSLOG, $syslog) or die "Can't open $syslog: $!\n"; while(1) { while() { if (/^([A-Za-z]+\s+\d+\s+\d+\:\d+\:\d+).+POP login by user \"(.+)\".+\s(\d+\.\d+\.\d+.\d+).*$/) { $date = $1; $userid = $2; $ip = $3; $timestamp = time; $dup = `grep '\\<$ip\\>' ${access}`; # Check to see if IP is already in access file if ($dup) { # Duplicate found, update timestamp on existing entry in access.info system("sed -e 's/^.*\t$userid\t$ip\t[0-9].*/$date\t$userid\t$ip\t$timestamp/' ${access}.info > ${access}.temp1"); rename("${access}.temp1","${access}.info"); } else { # No duplicate found, add new entry in access and access.info open(ACCESS, ">>$access") || die "Can't open $access: $!\n"; flock(ACCESS, LOCK_EX); # Lock in case someone is editing file print ACCESS "$ip\tRELAY\n"; flock(ACCESS, LOCK_UN); close(ACCESS); system("$makeaccess"); # Rehash access.db open(INFO, ">>${access}.info") || die "Can't open ${access}.info: $!\n"; print INFO "$date\t$userid\t$ip\t$timestamp\n"; close(INFO); } } } sleep 1; # Sleep one second SYSLOG->clearerr(); } close(SYSLOG); exit(0);