Spam

© Roberto Zini, Strhold Sistemi Edp - Italy

Recently some customers of ours have been advised by their ISP that the mail server they use for handling Email message is vulnerable to SPAM and RELAY attack. What does it mean ? The following is an excerpt from the README.spam file which comes with the SCO OpenServer 5.0.5 Sendmail (you can find it under /usr/lib/mail/antispam directory - please read it carefully before proceeding with the reading) :



=== cut here ===
The sendmail.cf file has several rulesets which assist in the
prevention of spam mail.  They are:

check_rcpt: 

Purpose: Prevents your site from being used as an intermediate
site between a sender and a recipient.  Those sending spam
mail often try to use an intermediate system in an attempt to
hide the source of electronic mail.

[snip]

Result: Attempts to relay mail through this site will be
rejected and an error message will be returned to the sender.
Sites in the relays map specified by the entries in
/usr/lib/mail/antispam/relays as well as sites in the domains
served by this system will be allowed to use this site as an
intermediate relay. If there are no extra sites that will use
this one as a relay, do not add entries to the relays map.

[snip]

check_relay: 

Purpose: This ruleset prevents mail from being sent from a
pre-defined list of fully qualified domain names and/or IP
numbers, regardless of recipient.

[snip]

Result: Mail sent from the sites indicated in
/usr/lib/mail/antispam/spammers will be returned to the sender
with an error message.

check_mail: 

Purpose: This ruleset requires that the domain of the sender
specified in the "Mail From:" SMTP command resolves to a valid
fully-qualified domain name.  (It must have a DNS entry).
Additionally, the client making the connection to this SMTP
server is checked against a pre-defined list of fully qualified
domain names.

[snip]

Result: SMTP "Mail From:" commands whose argument is not a
valid fully qualified domain name (as listed by the Domain
Name Service), will cause that SMTP transaction to be terminated
with an error.  Additionally, if the "Mail From: " check
succeeds, the IP number and/or name will be checked against
the domains and IP numbers listed in /usr/lib/mail/antispam/spammers,
and the mail returned with an error message.

=== cut here ===
 

As you can see (and here I'm assuming a basic knowledge of the email delivery subsystem), version 8.8.8 of Sendmail (the one which comes with SCO OpenServer 5.0.5) offers a robust set of electronic "countermeasures" (rulesets) specifically designed to prevent an "incorrect" usage of your email server.

However, the above check_relay method assumes that you know the IP address of the machines allowed to relay messages through your site; this is reasonable on a local LAN (where you have a single machine which acts as an Email SMTP/POP3/IMAP4 server for a number of machines with well known - and fixed - IP addresses ), or when you system hosts a number or remote machines (eg, connected with PPP/SLIP) for which you know the set of IP addresses assigned to them. But what when you have (eg) remote agents or people 'on-the-road' which connect to your Email server by using an IP address dynamically assigned by an external ISP (ie, not you) ? How do you know in advance the IP numbers to insert in the relays file?

Being myself rather ignorant in Sendmail administration (take a look at the /usr/lib/sendmail.cf file and you'll know ;-), and due to a lack of info about this issue, I managed to solve to above problem in 2 different ways.

1) Your remote hosts are able to check for emails BEFORE sending new ones

Leroy Janda implemented a shell script with which you can examine the syslog file (or whatever file you instructed the POP3 daemon to write info in) and search for any occurence of the "Ending request for 'user' at ('machine') 'ip_address'" message (let's say every 15 to 30 seconds).

This message comes from the POP3 server and it's simply telling you that a remote machine (whose name is 'machine', with an internet address set to 'ip_address') has got in touch with your server to see if there were email messages for remote user 'user'.

The script could compare the 'user' info against a pre-compiled list of remote users allowed to do mail relaying; it it finds a match, it extracts the ip_address from the log file, inserts it in the relays file and recompiles it in order to make the change affective.

The script also uses a 'cache' directory under which it stores the previously assigned IP address; if the actual IP address has not changed from the old one, it does not get changed in the relays file.

Note: the POP3 check is activated every 15 seconds (by default). You can check this delay by modifying a shell variable inside the script; set it to a reasonable value which avoids a multiple line matches during the check (eg, a remote hosts which checks incoming email too frequently).

2) Remote hosts are UNABLE to check for emails before sending new ones

I've notice this behavior with Micro$oft Outlook Express; if the remote use wrote an 'off-line' message, the software tries to deliver the message BEFORE seeking for new ones. This is also due to the fact that, opposed to any Netscape incantations, Outlook lacks of separate 'Get Msg' and 'New Msg' icons but it offers a single 'Send/Receive' options which works as explained before. Of course, if there aren't 'off-line' messages ready to be delivered, Outlook simply checks for received ones.

I know that most users fire up the Internet connection by using either a browser (Explorer/Netscape ...) or their Email program (Outlook, Messenger Mailbox ...); if this is your case, you can instruct 'em to FIRST access a specified URL which contains a simple CGI shell script which grabs the remote IP address, check for the user name and insert the former in the relays file. As an example, you could put the following URL in the user 'Home Page':

http://your_web_server_here/cgi/spamscript?user-password

checkspam is the name of the CGI script which gets the remote user information by scanning the above parameters; here 'user' is the remote user account name and 'password' is a plain unencrypted password which could be different from the account/POP3 one (the adminstrator could set it accordignly to his/her needs).

As an example, remote user 'fred' could have the following URL inserted in his (her ? ;-) bookmark :

http://webserver.foo.com/cgi/spamscript?fred-mypassword

spamscript would extract 'fred' from the input parameters, it would also extract the 'mypassword' item and would check 'em against a simple ASCII file, written by using the 'user password' syntax (one entry for each line).

Since security is a goal in WEB server administration, and since most CGI scripts are executed with 'nouser' permissions, I've prepared a little shell script which acts like a 'daemon', receiving incoming validation requests from the above one. This script runs with 'root' authorizations so that it could access user protected files; it is the above daemon which actually performs the check.

The CGI one simply builds a simple ASCII file and puts it under a 'spool' dir which gets regularly scanned by the 'spam' daemon; it checks the net provided user-password items against the stored one and, if the check succeeds, is 'signals' the script in order to visually inform the remote user that his/her remote machine name has been inserted in the relays file.

The URL access has to be done only ONCE per connection; during the remote connection lifetime, the remote site will be allowed to relay messages 'thru our server, while assuring protection against other unwanted hosts.

And, as for method #1, even this script uses a directory cache to speed up operations.

=========== SOLUTION #1 ===========

I've modified Leroy's script to add some unimplemented features such as IP cache and debugging. The modified script follows :

=== cut here ===

#!/bin/sh
#
########################################################################
# Buildmap 1.2 
#
# Originally written by Janda Le Roi and modified by 
# R.Zini ([email protected]) - Strhold Sistemi Edp (RE - Italy)
########################################################################

#
# BuildMap log file
#

ALOG=/usr/adm/bmap.log

#
# Popper log file
#

PFILE=/usr/adm/mail

#
# Tmp files
#

TMPF=/tmp/_spam$$
TMPF1=/tmp/__spam$$

#
# Antispam dir
#

ADIR=/usr/lib/mail/antispam

#
# Relays file (change it for debugging purposes)
#

ARELAYS=$ADIR/my_relays

#
# Directory which contains the last assigned IP address 
# (cache dir)
#

RDIR=$ADIR/bmap_cache

#
# List of remote users allowed to relay
#

RUSER=$ADIR/allowed_users

#
# File which holds the current process ID
#

PROGPID=/etc/buildmap.pid

#
# Queue scan delay time
#

SCANWAIT=15

#
# Default debug level (0=no debug, 1=debug)
#

DEBUG=1

#
# Debug routine
#

my_debug()
{
        if [ $DEBUG -gt 0 ]
        then
                echo `date` " $*" >> $ALOG
        fi
}

#
# Exit flag
#

FORCE_EXIT=0

#
# Clean exit procedure
#

my_exit()
{
        trap '' 2 3 15
        FORCE_EXIT=1
}


#
# Do the trick
#

checklog()
{

   #
   # Has the log file increased in size ?
   #

   TLINES=`cat $PFILE | wc -l`
   if [ $TLINES -le $NLINES ]
   then
        return
   fi
 
   #
   # Debug
   #

   cd $ADIR
   cp $ARELAYS $ARELAYS.old
   touch $TMPF

   #
   # Build the tmp file
   #

   X=`expr $TLINES - $NLINES` 

   #
   # The $TMPF file will hold the user-ip_address entries
   #
   # Bug: it could happen then, from time to time, 
   # the $TMPF might contain more than one occurrence
   # of the given pattern (eg, when a remote host
   # checks for incoming messages very frequently or
   # when there is a password mismatch).
   #
   # As an example, consider the following situation:
   #
   # Servicing request from "machine" at xyz.YYY.ZZZ.KKK
   # ERR Password supplied for "fred" is incorrect.
   # Servicing request from "machine" at xyz.YYY.ZZZ.KKK
   # ERR Password supplied for "fred" is incorrect.
   # Ending request from "fred" at (machine) xyz.YYY.ZZZ.KKK
   # Ending request from "fred" at (machine) xyz.YYY.ZZZ.KKK
   # Servicing request from "machine" at xyz.YYY.ZZZ.KKK
   # Ending request from "fred" at (machine) xyz.YYY.ZZZ.KKK
   #
   # The above command could lead to a file which contains 3
   # occurrences of the 'fred-xyz.YYY.ZZZ.KKK' pair, thus
   # fooling the rest of the script. In order to avoid it,
   # we use the 'sort | uniq' pipe.
   #

   tail -$X $PFILE | grep "Ending request" | \
        awk '{ printf "%s-%s\n",$10,$13 }' | \
        sed 's/\"//g' | sort | uniq > $TMPF

   #
   # Any matches ?
   #

   if [ ! -s $TMPF ]
   then
        rm $TMPF
        return
   fi

   #
   # For each POP3 user detected ...
   #

   for x in `cat $TMPF | awk -F- '{ print $1 }'`
   do
      my_debug "checking for user $x ..." 

      #
      # We use the '^name$' form of grep in order to avoid
      # similar name matches (eg, fred could match fred itself
      # but also frederick).
      # 

      grep -q \^$x\$ $RUSER

      if [ $? -eq 0 ]
      then

        #
        # Good one
        #

        my_debug "user $x matches a database entry"

        #
        # Grab the actual IP address
        #
        # Again, we could face another problem; let's suppose
        # that some remote hosts are checking their incoming messages
        # by using the same account name (fred). Also, suppose they check for
        # messages at different times (they should be unable to check for
        # the same user simultaneously - popper should be able to prevent
        # this), but close enaugh to 'fool' our check (remember that
        # this script wakes up every 15 seconds - let's suppose that
        # the following scenario happens in less than 15 seconds).
        #
        # We could end up with the following TMPF file :
        #
        # Ending request from "fred" at (machine1) xyz.YYY.ZZZ.001
        # Ending request from "fred" at (machine2) xyz.YYY.ZZZ.002
        # Ending request from "fred" at (machine3) xyz.YYY.ZZZ.003
        #
        # The following grep(C) for user "fred" will give 3 different
        # IP addresses; how could we handle this situation ? We
        # only consider the *LAST* occurrence of the IP address, thus
        # checking for the xyz.YYY.ZZZ.003 one (sorry for the first two).
        # We could also check for all of 'em but only the last one will
        # be inserted in the $RELAYS map (the first two will be overwritten
        # by the last one); so consider only the last occurrence.
        #

        NEWIP=`grep $x $TMPF | awk -F- '{ print $2 }' | tail -1`

        #
        # This is the actual IP address; has it changed since
        # last check ?
        #

        if [ ! -f $RDIR/$x ]
        then
                #
                # First assigned IP address
                #
                my_debug "first IP address for $x - $NEWIP"
                echo $NEWIP > $RDIR/$x
                echo "$NEWIP\t\tOK" >> $ARELAYS
        else

                IPDATA=$NEWIP

                #
                # Last assigned IP address
                #

                unset OLDIP
                OLDIP=`cat $RDIR/$x`

                my_debug "The cached file contains : `cat $RDIR/$x`"

                my_debug "$x already in cache ($NEWIP-$OLDIP)"

                if [ "$OLDIP" != "$NEWIP" ]
                then

                  #
                  # Substitute the OLD IP address with the
                  # new one in $ARELAYS
                  #

                  my_debug "user $x changed from $OLDIP to $NEWIP" 
                  NEWIP=`echo $NEWIP | sed 's/\./\\\./g'`
                  OLDIP=`echo $OLDIP | sed 's/\./\\\./g'`
                  cat $ARELAYS | sed '1,$s/$OLDIP/$NEWIP/g' > $TMPF1
                  cp $TMPF1 $ARELAYS
                  rm $TMPF1 1>/dev/null 2>&1
                fi

                # 
                # Update the $ARELAYS table
                #

                echo $IPDATA > $RDIR/$x
        fi
      fi
   done

   rm -f $TMPF

   #
   # Has $ARELAYS changed since last check ?
   #

   diff $ARELAYS $ARELAYS.old 1>/dev/null
   if [ $? != 0 ]
   then
     my_debug "Making RELAY map" 
     rm $ARELAYS.db
     makemap hash $ARELAYS <$ARELAYS
   fi
}

#
# Main
#

if [ ! -d $RDIR ]
then
        mkdir $RDIR
fi

#
# If the relays file does no exist, create a new one
#

if [ ! -f $ARELAYS ]
then
        touch $ARELAYS
fi

#
# Check for the allowed users file
#

if [ ! -f $RUSER ]
then
        echo "$RUSER file MISSING ! Exiting ..." 
        exit 1
fi

#
# Is another daemon already running ?
#

if [ -f $PROGPID ]
then
        
        #
        # Perhaps we've had either a panic or a power failure 
        #

        TPID=`cat $PROGPID`
        if [ `ps -p$TPID | wc -l` -gt 1 ]
        then
                echo "Another instance of the daemon is running."
                echo "Exiting ..."
                exit 1
        else
                echo "The $PROGPID file is still effective but the daemon"
                echo "is not active. Starting a new instance of the daemon ..."
                echo $$ > $PROGPID
        fi
else
        logger "BuildMap : activated"
        my_debug "BuildMap : activated"
        echo $$ > $PROGPID
fi

#
# Prepare to handle SIGQUIT and SIGTERM signals
#

trap my_exit 3 15

#
# Main loop
#

while [ $FORCE_EXIT -eq 0 ]
do
        NLINES=`cat $PFILE | wc -l`
        sleep $SCANWAIT
        checklog
done    

#
# Clean exit
#

rm $PROGPID

my_debug "Program terminated at user request"

logger "BuildMap : Program terminated at user request"

#
# Bye
#

exit 0


=== cut here ===
 

=========== SOLUTION #2 ===========

Following you can find the CGI script which gets accessed (via WEB) by remote users in order to perform mail relaying.

=== cut here ===


#!/bin/ksh
#
# Program :     Spamcheck 
# Release :     0.1
# Last Upd:     29/06/1999
##########################
# History :
# 
# The following script builds a request file which is made up
# of the followin 3 items :
#
# username password IP_address
#
# 'username' is the remote user account name, 'password' is
# a plain-text (not encrypted) password choosen by the administrator
# (it could be different from the account one) and 'IP_address'
# is the remote IP address as 'derived' by the script itself
# (see below). This request file will be placed in a spool dir which
# gets scanned by the spamdaemon.sh (see below); if the remote
# username matches against a list of allowed user, the CGI script
# is signaled with SIGUSR2 (OK) while if the match is not found,
# the script is signaled with SUGUSR1 (BAD).
#
##########################

#
# Bad matching
# 
bad_ans()
{
        trap '' 16
        echo "<FONT COLOR='FF0000'>"
        echo "<H3>You're not allowed to do mail relaying !</H3>"
        echo "</FONT></CENTER></BODY></HTML>"
        exit 0
}

#
# Good match
# 
good_ans()
{
        trap '' 17
        echo "<FONT COLOR='FFFFFF'>"
        echo "<H3>You're allowed to do mail relaying !</H3>"
        echo "</FONT></CENTER></BODY></HTML>"
        exit 0
}

#
# Request file
#

REQFILE=/tmp/spam_req-$$

#
# We wait up to $MAXDELAY seconds for the server to respond
#

MAXDELAY=30

#
# Signal trapping
#

trap bad_ans 16
trap good_ans 17

#
# HTML header
#

cat <<EOF
Content-type: text/html

<HTML>
<HEAD>
<TITLE>Spamcheck</TITLE>
<BODY BGCOLOR="000000">
<CENTER>
<FONT COLOR="FFFFFF">
<H2>Your username is being checked; please wait ...</H2>
<CENTER>
</FONT>
EOF

#
# This script gets executed with the following parameters :
#
#       username-password
#
#

TMP=$1
if [ "X$TMP" = "X" ]
then
        echo "<FONT COLOR='FF0000'>"
        echo "<H3>You did not specify enaugh information to proceed !</H3>"
        echo "</FONT></BODY></HTML>"
        exit 0
fi
        
USER=`echo $TMP | awk -F- '{ print $1 }'`
PASSWD=`echo $TMP | awk -F- '{ print $2 }'`

#
# Check for USER and PASSWD
#

if [ "X$USER" = "X" -o "X$PASSWD" = "X" ]
then
        echo "<FONT COLOR='FF0000'>"
        echo "<H3>Incorrect username/password specified !</H3>"
        echo "</FONT></BODY></HTML>"
        exit 0
fi

#
# Let's check the user against the database file
#

USER=`echo $USER | tr "[:upper:]" "[:lower:]"`
PASSWD=`echo $PASSWD | tr "[:upper:]" "[:lower:]"`

#
# Since most WEB server execute under 'nouser' privileges,
# we pass the above info to the spamdaemon.sh server which
# will run under 'root'. If a match is found, we'll be
# signalled with SIGUSR2; alternatively, we'll be
# signalled with SIGUSR1.
#
# 21/07/1999
############
#
# Problem: I've noticed that the script is sometimes unable to
# correctly handle the above signals so I changed the
# notification mechanism to a more primitive one. If the
# server places a file with the name $REQFILE.ok then our
# request has been accepted while if the find ends with *.no
# that our request has not been accepted.
#

echo "$USER $PASSWD $REMOTE_ADDR" > $REQFILE

#
# Wait
#

while [ $MAXDELAY -gt 0 ]
do
        MAXDELAY=`expr $MAXDELAY - 1`

        #
        # Check out the response file
        #

        if [ -f $REQFILE.ok ]
        then
                good_ans
        else if [ -f $REQFILE.no ]
             then
                bad_ans
             fi
        fi
        sleep 1
done

echo "<FONT COLOR='FF0000'>"
echo "<H3>The remote server did not respond; please contact Tech Support !</H3>"

#
# Goodbye
#

echo "</FONT></BODY></HTML>"
exit 0

=== cut here ===
 

And here's the spamdaemon.sh script.

=== cut here ===

#!/bin/sh
#
########################################################################
# Name          : SpamDaemon 
# Release       : 1.2 
# Author        : R. Zini (Strhold Sistemi Edp)
########################################################################
#
# Notes         : 29/06/1999
#
# You must have SendMail 8.8.8 (or higher) for the program
# to work (eg, the one included with SCO OS 5.0.5). Also,
# in the /usr/lib/sendmail.cf file, you have to un-comment
# the check_mail and check_rcpt macro in order for these
# antiSPAM feature to be active.
#
# I'm also assuming that your relays file has been correctly
# built with the necessary local and remote fixed IP address
# (machines allowed to relay messages).
#
# For additional info, see /usr/lib/mail/antispam/README.spam.
#
# This program works along with its WEB counterpart in order to
# authorize remote internet user to use our Email server
# for message relaying . Every 15 seconds it scans the /tmp
# area in order to find files whose name is spam_req-xyzx
# (where xyzx is the PID of the requesting WEB program). The
# above file contains the following info
#
# username password ip_address
#
# Where 'username' is the account (login) name of the remote
# user, 'password' in the plain (not encrypted) password
# choosen by the administrator (not the account one) inserted
# in the $RUSER file and ip_address is the remote machine
# IP_address as recognized by the WEB program. 
#
# If there is a match for username and password in the $RUSER
# file, the ip_address is inserted in the relays file, thus
# making the remote user able to use our email server for
# mail relaying. Also, the WEB program is signalled with a
# SIGUSR2 signal in order to inform it (and the requesting
# user) that everything went fine.
#
# Alternatively (username and/or password does not match)
# the remote WEB program is signalled with a SIGUSR1 signal
# in order to inform the remote user that the request
# failed.
#
# Please notice that the program uses a cache directory
# ($RDIR) to keep track of the last assigned IP address and
# that the relays file gets rebuilt only if a change has
# been noticed since the last check.
#
# 30/06/1999
############
#
# This program is now able to trap SIGINT (2) signals in order
# to toggle its internal debug level (0-1).
#
# The program tyerminates upon the reception of the SIGTERM (15)
# and SIGQUIT (3) signals.
#
########################################################################
#
# 20/07/1999
############
#
# I've noticed that, for reasons unknown to me, the signal (kill)
# method does not work any longer (the CGI script does not handle
# the above signals). So, if there's a match, the request file
# (/tmp/spam_req-$$) is changed to spam_req-$$.ok; alternatively
# the name is changed to spam_req-$$.no .
#
########################################################################

#
# AntiSpam log file
#

ALOG=/usr/adm/spam.log

#
# Tmp files
#

TMPF=/tmp/_spam$$
TMPF1=/tmp/__spam$$

#
# Antispam dir
#

ADIR=/usr/lib/mail/antispam

#
# Directory which contains the last assigned IP address 
# (cache dir)
#

RDIR=$ADIR/remdir

#
# List of remote users allowed to relay messages here in
# the form :
#
# username1 password1 ip_address1
# username2 password2 ip_address2
# username3 password3 ip_address3
#
# Please notice that comments (#) are not allowed in this file
# (mainly because I'm lazy ;-)
#

REMUSER=$ADIR/remusers

#
# Program PID file
#

PROGPID=/etc/spamdaemon.pid

#
# Reply filename
#

ANSFILE=/tmp/spam_req

#
# Queue scan delay time
#

SCANWAIT=15

#
# Default debug level (0=no debug, 1=debug)
#

DEBUG=1

#
# Debug routine
#

my_debug()
{
        if [ $DEBUG -gt 0 ]
        then
                echo `date` " $*" >> $ALOG
        fi
}

#
# Debug catcher
#

my_debugtoggle()
{
        trap my_debugtoggle 2
        if [ $DEBUG -eq 0 ]
        then
                DEBUG=1
                my_debug "toggling debug level to 1"
        else
                my_debug "toggling debug level to 0"
                DEBUG=0
        fi
}

#
# Exit flag
#

FORCE_EXIT=0

#
# Clean exit procedure
#

my_exit()
{
        trap '' 2 3 15
        FORCE_EXIT=1
}

#
# Do the trick
#

checkfiles()
{

   #
   # Just to be sure, delete temporary *.ok and *.no files
   #

   rm /tmp/spam_req-*.ok 1>/dev/null 2>&1
   rm /tmp/spam_req-*.no 1>/dev/null 2>&1

   #
   # Retrieve the list of request files
   #

   REQFILES=`ls /tmp/spam_req-*`
   if [ "X$REQFILES" = "X" ]
   then
        return
   fi
        
   #
   # We've got some of 'em
   #

   cd $ADIR
   cp relays relays.old
   touch $TMPF

   #
   # For each file ...
   #

   for XF in $REQFILES
   do

   my_debug "Processing file $XF" 

   #
   # Retrieve the username, password and IP_address
   #

   R_USER=`cat $XF | awk '{ print $1 }'`
   R_PWD=`cat $XF | awk '{ print $2 }'`
   R_IP=`cat $XF | awk '{ print $3 }'`

   #
   # Retrieve the PID of the invoking process
   #

   R_PID=`echo $XF | awk -F- '{ print $2 }'`
   TMP=`grep "^$R_USER" $REMUSER`

   my_debug "checking for user $R_USER ..."

   # 
   # Do we have a match ?
   #

   if [ "X$TMP" != "X" ]
   then

        #
        # Check the password
        #

        T_PWD=`echo $TMP | awk '{ print $2 }'`
        if [ $R_PWD = $T_PWD ]
        then

           #
           # Good one !
           #

           my_debug "good password for user $R_USER ..."

           NEWIP=$R_IP

           #
           # This is the actual IP address; has it changed since
           # last check ?
           #

           if [ ! -f $RDIR/$R_USER ]
           then
                #
                # First assigned IP address
                #
                my_debug "first IP address for $R_USER - $NEWIP" 
                echo $NEWIP > $RDIR/$R_USER
                echo "$NEWIP\t\tOK" >> relays
           else
                #
                # Last assigned IP address
                #
                OLDIP=`cat $RDIR/$R_USER`
                if [ "$OLDIP" != "$NEWIP" ]
                then

                  #
                  # Substitute the OLD IP address with the
                  # new one in relays
                  #

                  my_debug "user $R_USER changed from $OLDIP to $NEWIP" 

                  #
                  # OK; the IP is in the cache. Let's check
                  # it against the relays file (just to be sure)
                  #

                  grep -q ${OLDIP} relays
                  if [ $? -eq 0 ]
                  then
                        MYSED=/tmp/mysed$$
                        echo "1,\$s/${OLDIP}/${NEWIP}/g" > $MYSED
                        sed -f $MYSED < relays > $TMPF1
                        cp $TMPF1 relays
                        rm $TMPF1 $MYSED 1>/dev/null 2>&1
                  else
                        my_debug "user $R_USER ($NEWIP) cache incoherency !"
                        echo "$NEWIP\t\tOK" >> relays
                  fi

                fi
                echo $R_IP > $RDIR/$R_USER
           fi   # Cache check

           #
           # Inform the remote process that we're ready to
           # process incoming messages
           #

           kill -17 $R_PID
           mv $ANSFILE-$R_PID $ANSFILE-$R_PID.ok

         else
                #
                # Password does not match
                #

                my_debug "password does not match for user $R_USER"
                kill -16 $R_PID
                mv $ANSFILE-$R_PID $ANSFILE-$R_PID.no
         fi     
   else
                #
                # Username does not match
                #

                my_debug "no matches for user $R_USER"
                kill -16 $R_PID
                mv $ANSFILE-$R_PID $ANSFILE-$R_PID.no
   fi           

   #
   # Delete the request file
   #

   rm $XF

   done

   rm -f $TMPF

   #
   # Has relays changed since last check ?
   #

   diff relays relays.old 1>/dev/null
   if [ $? != 0 ]
   then
     my_debug "Making RELAY map" 
     rm relays.db
     makemap hash relays <relays
   fi
}

######
# Main
######

#
# Create the 'cache' directory 
#

if [ ! -d $RDIR ]
then
        mkdir $RDIR
fi

#
# Is another daemon already running ?
#

if [ -f $PROGPID ]
then
        
        #
        # Perhaps we've had either a panic or a power failure 
        #

        TPID=`cat $PROGPID`
        if [ `ps -p$TPID | wc -l` -gt 1 ]
        then
                echo "Another instance of the daemon is running."
                echo "Exiting ..."
                exit 1
        else
                echo "The $PROGPID file is still effective but the daemon"
                echo "is not active. Starting a new instance of the daemon ..."
                echo $$ > $PROGPID
        fi
else
        logger "SpamDaemon : activated"
        echo $$ > $PROGPID
fi

#
# Prepare to handle SIGHUP signals
#

trap my_debugtoggle 2

#
# Prepare to handle SIGQUIT and SIGTERM signals
#

trap my_exit 3 15

#
# Use the relays.pattern file
#

cd $ADIR
cp relays.pattern relays
makemap hash relays <relays

#
# Main loop
#

while [ $FORCE_EXIT -eq 0 ]
do
        sleep $SCANWAIT
        checkfiles
done    

#
# Clean exit
#

rm $PROGPID

my_debug "Program terminated at user request"

logger "SpamDaemon : Program terminated at user request"

#
# Bye
#

exit 0

=== cut here ===
 

I've noticed that the CGI script may be fooled if the remote browser uses a WEB Proxy Server to access our WEB server. Thus acting, the CGI script will extract the IP address of the Proxy Server instead of the remote PC one, thus causing subsequent mail messages posted by the remote PC to fail. So, remote PC users are required not to use any WEB Proxy Server during the 'authentication' phase; they can however re-use it after they've been acknowledged by the server.

Hope it helps !


Publish your articles, comments, book reviews or opinions here!

© July 1999Roberto Zini, Strhold Sistemi Edp - Italy



Got something to add? Send me email.





(OLDER) <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

-> -> Roberto Zini: Spam




Increase ad revenue 50-250% with Ezoic


More Articles by © Roberto Zini



Kerio Connect Mailserver

Kerio Samepage

Kerio Control Firewall

Have you tried Searching this site?

Unix/Linux/Mac OS X support by phone, email or on-site: Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.

Contact us