[Exim] POP/IMAP before SMTP AUTH on Exim (Exim4) HOWTO

Top Page
Delete this message
Reply to this message
Author: Eric Rutherford
Date:  
To: exim-users
Subject: [Exim] POP/IMAP before SMTP AUTH on Exim (Exim4) HOWTO
I finally got this working and it seemed to be a real pain.. all the info i
found on the net was outdated, for different software, or just
vague/incomplete

so heres what is working for me (i just set this up just now and i havent
tested it very much though so there could be some problems)

Software im using:
Debian testing branch ('sarge')
Exim4 (4.32)
imapd and ipopd from UW (2002e debian)

Basic concept:
- A script is run at all times that checks the mail.log files to see if
anyone has successfully logged in to imap or ipop, it checks once a second.
- If it finds a successful login it puts the IP/Host in /etc/relayhosts
- exim rcpt acl checks the /etc/relayhosts file before relaying


i put the script at /usr/sbin/relayd (its pasted below)
set it to have execute permission (script runs as root)

i got kinda sloppy with how its started
i just put /usr/sbin/relayd inside the startup script for exim4, i didnt put
anything in to kill it when exim is stopped though
so if you restart exim several times you will have several instances of the
script running

i made a file at /etc/relayhosts that has permission 644 root.root (this
file will contain a list of IPs, Hosts that are accepted for relaying)

change the exim4.conf
add the line:
    accept  condition     =
${lookup{$sender_host_address}lsearch{/etc/relayhosts} {1}{0}}
somewhere in the rcpt acl (i put it after accept hosts = +relay_from_hosts)
btw i left the relay_from_hosts stuff in there, i put the perminent
IPs/Hosts i want relaying from on that list
you can also put them in the file /etc/alwaysrelay


that about covers it,
save the new config
put the /usr/sbin/relayd line into your exim4 init.d script
copy the script below into /usr/sbin/relayd
then restart exim (from its init.d script) and it should all come up
do 'ps aux' to make sure exim4 and relayd are running
log in to check your mail and it should add your IP to /etc/relayhosts
after 30 minutes it is removed
you have to have LOOKUP_LSEARCH=yes in the Makefile for exim (should be on
by default)
you dont need perl built into exim for this

if your log files are different than mine (maybe you have a different
version of ipopd and imapd) just alter the commented out section of the
script to search the log a little differently for ips/hosts and you should
be able to get it working

hope this helps someone, i know it wouldve helped me if i had found
something like this a days ago




The script is as follows (/usr/sbin/relayd)
#!/usr/bin/perl

$0 = "relayd";
$maillog = "/var/log/mail.log";
$relayhosts = "/etc/relayhosts";
$alwaysrelay = "/etc/alwaysrelay";

if (! -e $maillog) { $maillog = '/var/log/mail.log.0'; }
if (! -e $maillog) { die "Cannot find the mail.log"; }

$SIG{'HUP'} = sub {
$running = 0;
};

open(ALLRELAY,"$alwaysrelay");
while(<ALLRELAY>) {
s/\n//g;
push(@ALWAYSRELAY,$_);
}
close(ALLRELAY);

&writehosts;

if (fork()) {
exit;
}


sub inittaillog {

$line = \0;
open(MS,$maillog);

   (undef,undef,undef,undef,undef,undef,undef,$size,
    undef,undef,undef,undef,undef) =stat($maillog);


    $mz = ($size - 8192);
    if ($mz > 0) {
       seek(MS,$mz,0);
    }


    while($line ne "") {
       $line = readline(*MS);
       parseline($line);
    }


}

sub taillog {
$psize = 0;
while($running) {

      (undef,undef,undef,undef,undef,undef,undef,$size,
       undef,$mtime,undef,undef,undef) =stat($maillog);
       if ($mtime > $pmtime) {
          while($line = readline(*MS)) {
             parseline($line);
          }
          $pmtime = $mtime;
       } else {
          sleep(1);
       }
       if (($psize-1) > $size) {
          last;
       } else {
          $psize = $size;
       }
   }
   close(MS);
}


sub parseline {
$line = $_[0];

my($srvlog,$data) = split(/\: /, $line);
$srvlog =~ /(\S+)$/;
my($server) = $1;
$server =~ s/\[[^\]]+\]//g;

   if ($server !~ /(ipop3d|imapd)$/) {
        return();
   }


   if ($data =~ /^login[\t\s]+[^\[]+\[(\d+\.\d+\.\d+\.\d+)/i) {
      $HOSTS{$1} = time();
   }
#   if ($data =~ /^login[\t\s]+\S+[\t\s]+\S+[\t\s]+host=(\S+)/i) {
#      $HOSTS{$1} = time();
#   }
#   if ($data =~ /^login[\t\s]+\S+[\t\s]+host=(\S+)/i) {
#      $HOSTS{$1} = time();
#   }
#   if ($data =~ /^login[\t\s]+host=(\S+)/i) {
#      $HOSTS{$1} = time();
#   }
#   if ($data =~/^login[\t\s]+host=(\S+)[\t\s]+ip=(\S+)/i) {
#      $HOSTS{$1} = time();
#      $HOSTS{$2} = time();
#   }
   &writehosts;


}

sub writehosts {
   $exptime = (time() - (60*30));
   open(RELAYHOSTS,">$relayhosts");
   foreach $host (sort keys %HOSTS) {
      if ($HOSTS{$host} > $exptime && $host ne "") {
         print RELAYHOSTS "$host\n";
      } else {
         delete $HOSTS{$host};
      }
   }
   foreach $host (sort @ALWAYSRELAY) {
      print RELAYHOSTS "$host\n";
   }
   close(RELAYHOSTS);
}



while (1) {
&inittaillog;
$running = 1;
&taillog;
}