On 8.1.2013 4:33, Troy Ayers wrote:
> Could I trouble you for a sanitized version of your 
> /usr/site/dspam_train/bin/dspam_fp script?  My system is ...

I am so sorry.  I missed your original email a couple weeks ago.  I will attach 
the script we use.

The bad news is that the script relies on a slightly patched DSPAM: it causes 
DSPAM to print error messages to STDERR in addition to it's normal logging.   
The patch is only a few lines, and we've used it for many years.  However, I 
don't know if it's OK for the general community.  I'll attach that patch too.

Before invoking DSPAM for retraining, you could verify that the signature 
exists; if it does not, don't invoke DSPAM - invoke direct delivery instead.  
We implimented this for testing long ago, but we decided on the STDERR route.



Tod Sandman
Sr. Systems Administrator
Middleware Development & Integration
Rice University
Voice: 713.348.5816
#!/bin/sh
###############################################################################
#
# Project:    DSPAM
# Program:    dspam_fp - retrain/deliver a false positive from the quarantine.
# Version:    0.0
# Author:     Tod Sandman
# Start Date: 01/05/06
#
# Usage: dspam_fp [-h] [-u USER] [-d USER2] < message
#
# When dspam is invoked with the --deliver option, dspam exiting with a
# successful status does not assure the message was actually delivered.  For
# instance, if the dspam signature in the message is not found in the dspam
# database because it has expired, dspam drops the message but exits with
# "success" (it does log a warning if logging is configured).
#
# This behavior makes sense since dspam is generally receiving mail from the
# big bad world; it does not want to provide back door access for SPAM.
#
# However, when an authenticated user attempts to deliver a mis-classified
# email from his quaratntine, we really want to make sure the message is
# delivered.  We'd even prefer a duplicate delivery over a lost message.
#
# This script first tries to deliver the email via dspam as normal, but if
# successful delivery is not certain, it then tries to deliver the message
# directly without going through dspam.
#
# A user must be either passed in with the -u option, or set in the
# "EXTENSION" environemnt variable.  The -u over-rides $EXTENSION.
#
# This script is meant to be called via the DSPAM WebUI (see the DELIVER_FP
# configuration setting).  An exit value of 0 indicates the message was
# delivered; the WebUI will delete the message from the user's quarantine.
# A non-zero exit indicates the message was not delivered; the WebUI should
# not delete the message from the user's quarantine, and the user will be
# alerted.  This script should only ouput something if there were issues.
# 
###############################################################################

PATH=/bin:/usr/bin:/usr/sbin:/sbin
program=`basename $0`
nodename="`uname -n | sed 's/\..*$//'`"

dspam=/usr/bin/dspam
dspam_tmp_dir=/var/lib/dspam/tmp

## Set this IF this command is to be run as a DSPAM-trusted user:  
DSPAM_TRUSTED_USER=true

## DSPAM training options:
train_opts="--class=innocent --source=error --deliver=innocent"
if [ -n "$DSPAM_TRUSTED_USER" ]; then
  train_opts="--user USER $train_opts"
fi

## Direct delivery options for Cyrus backends:
deliver=/usr/lib/cyrus-imapd/deliver
if [ -f $deliver ]; then
  if [ -n "$DSPAM_TRUSTED_USER" ]; then
    deliver_opts=USER
  fi
else
  deliver=/usr/bin/procmail
  deliver_opts="-Y -f -"
  if [ -n "$DSPAM_TRUSTED_USER" ]; then
    deliver_opts="$deliver_opts -d USER"
  fi
fi


###############################################################################
# Procedures
###############################################################################

Usage ()
{
  echo "
NAME
  $program - retrain/deliver a false positive from the quarantine

USAGE
  $program [-h] [-u <username>] [-d <delivery_user>] 

DESCRITION
  $program is used to re-train and deliver false positives from
  the DSPAM quarantine.  Since user authentication to the DSPAM
  WebUI is required, extra care can be taken to assure the email
  is successfully delivered to the end user.

OPTIONS
  -h: Help.
  -u: Specify a user.  If not provided, the value of \$EXTENSION
      is used.
  -d: Specify a user for use when direct delivery is required. This
      is only needed if the user for direct delivery is different
      than the user for delivery via DSPAM.

EXAMPLES
  % $program -u joebob

"
  exit 0
}

## Routine to log a message via logger.
Log ()
{
  if [ $# -gt 1 ]; then p=$1; shift;
  else p=mail.notice; fi
  logger -p $p "${program}[$$]: $@"
}

## Print a message to STDERR.
Warn () { echo "${program}: $@" >&2; }

## Print a message to STDERR and pass it to logger.
WarnLog () { Warn "$@"; Log mail.err "$@"; }

## Call WarnLog and exit:
Error () { WarnLog "$@"; exit 1; }

## Run the specified DSPAM command.
Dspam ()
{
  my_command=$1         ## The command to run
  my_tmpfile=$2         ## The file to read; may be empty (read STDIN)

  ## Run the command, saving its STDOUT/STDERR and its exit status:
  my_out="`sed '1{/^From /d;}' $my_tmpfile | $my_command 2>&1`"; my_result=$?

  ## We'll assume trouble if DSPAM outputs something, or exits non-zero.
  if [ \( $my_result -ne 0 \) -o \( -n "$my_out" \) ]; then
    WarnLog "Command \"$my_command\" FAILED:"
    [ $my_result -eq 0 ] || WarnLog "Command exit failure code: $my_result"
    [ -z "$my_out" ] || WarnLog "Command output: $my_out"
    return 1
  fi

  ## If DSPAM exits 0 and does not say anything, we'll assume all is OK.
  return 0
}


###############################################################################
# End of procedures
###############################################################################

while [ $# -gt 0 ]; do
  case $1 in
    -u)  shift; user=$1;;
    -u*) user=`echo $1 | sed 's/^-u\(.*\)$/\1/'`;;
    -h)  Usage; exit 0;;
    -d)  shift; deliver_to=$1;;
    -d*) deliver_to=`echo $1 | sed 's/^-d\(.*\)$/\1/'`;;
    *)  Error "Unknown option \"$1\"";;
  esac; [ $# -gt 0 ] && shift
done


[ -z "$user" ] && user=$EXTENSION
[ -z "$user" ] && Error "Bad configuration: failed to determine user!"
[ -z "$deliver_to" ] && deliver_to=$user

## Now that we've figured out the user, substitute it in here:
train_opts=`echo $train_opts | sed "s/USER/$user/g"`
deliver_opts=`echo $deliver_opts | sed "s/USER/$deliver_to/g"`

## We want to copy the message (STDIN) so that in case DSPAM fails, we
## can try another way.  And we can leave the message behind if worse
## comes to worst.

tmpfile="$dspam_tmp_dir/$user.${program}.$$"
out=`touch $tmpfile 2>&1`; result=$?
if [ $result -ne 0 ]; then
  WarnLog "Failure creating tmpfile: $out"
  WarnLog "Attempting quarantine delivery/retrain for user $user without a 
tmpfile."
  tmpfile=""
else
  cat - > $tmpfile; result=$?
  if [ $result -ne 0 ]; then
    WarnLog "Failure writing tmpfile \"$tmpfile\"!"
    WarnLog "Not ok: delivery of false positive failed for user $user!"
    exit 3      ## There's nothing we can do now!
  fi
fi


## Try to retrain/deliver via DSPAM:

if [ ! -x $dspam ]; then
  WarnLog "Bad configuration: dspam command \"$dspam\" not found!"
else
  Log "Invoking dspam for FP re-classification for user $user."
  Log "$dspam $train_opts"
  Dspam "$dspam $train_opts" $tmpfile; result=$?
  if [ $result -eq 0 ]; then
    Log "Ok: re-classification and delivery of message from quarantine 
succeeded for $user."
    [ -n "$tmpfile" ] && rm $tmpfile
    exit 0
  elif [ -z "$tmpfile" ]; then
    WarnLog "Not ok: delivery of false positive failed for user $user!"
    exit 4      ## Nothing we can do now - we already read STDIN!
  fi
fi


## Attempt direct delivery without DSPAM:

if [ ! -x $deliver ]; then
  WarnLog "Bad configuration: deliver command \"$deliver\" not found!"
  [ -n "$tmpfile" ] && WarnLog "Message saved as $tmpfile; it has NOT been 
delivered!!!"
  exit 5
fi

Log "Attempting direct delivery via $deliver!"
Log "$deliver $deliver_opts"

## We trust deliver's return value a little more than dspam's, but we can't
## be certain if deliver exits successfully but outputs something.

out="`sed '1{/^From /d;}' $my_tmpfile | $deliver $deliver_opts 2>&1`"; result=$?

if [ $result -eq 0 ]; then
  if [ -z "$out" ]; then
    Log "Ok: direct delivery of message from quarantine for $deliver_to 
succeeded."
    [ -n "$tmpfile" ] && rm $tmpfile
  else
    WarnLog "Not sure if direct delivery of message from quarantine for 
$deliver_to succeeded."
    WarnLog "Delivery command exited successfully, but output the following: 
$out"
    [ -n "$tmpfile" ] && WarnLog "Message saved as $tmpfile just in case."
  fi
  exit 0
else
  WarnLog "Direct delivery of false positive failed for user ${deliver_to}: 
$out"
  [ -n "$tmpfile" ] && WarnLog "Message saved as $tmpfile; it has NOT been 
delivered!!!"
  exit 5
fi

diff -Npru dspam-3.10.2-2.orig/src/error.c dspam-3.10.2-2/src/error.c
--- dspam-3.10.2-2.orig/src/error.c     2012-04-11 13:48:33.000000000 -0500
+++ dspam-3.10.2-2/src/error.c  2012-12-12 18:32:47.000000000 -0600
@@ -65,12 +65,12 @@ pthread_mutex_t  __syslog_lock;
 #endif
 
 #ifndef _WIN32
+#define LOG_STDERR
 void
 LOG(int priority, const char *err, ... )
 {
-#if defined(USE_SYSLOG) || defined(LOGFILE)
+#if defined(USE_SYSLOG) || defined(LOGFILE) || defined(LOG_STDERR)
   va_list ap;
-  va_start (ap, err);
 #endif
 #ifdef LOGFILE
   char date[128];
@@ -85,13 +85,20 @@ LOG(int priority, const char *err, ... )
 
 #ifdef USE_SYSLOG
   openlog ("dspam", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_MAIL);
+  va_start (ap, err);
   vsyslog (priority, err, ap);
   closelog ();
+  va_end (ap); /* sandmant */
 #endif
 
-#ifdef LOGFILE
+#if defined(LOGFILE) || defined(LOG_STDERR)
   char err_text[256];
+  va_start (ap, err);
   vsnprintf(err_text, sizeof(err_text), err, ap);
+  va_end (ap);
+#endif
+
+#ifdef LOGFILE
   file = fopen(LOGFILE, "a");
   if (file) {
     fprintf(file, "%ld: [%s] %s\n", (long) getpid(), format_date_r(date), 
err_text);
@@ -102,8 +109,8 @@ LOG(int priority, const char *err, ... )
   }
 #endif
 
-#if defined(USE_SYSLOG) || defined(LOGFILE)
-  va_end (ap);
+#ifdef LOG_STDERR
+    fprintf(stderr, "%s\n", err_text);
 #endif
 
 #ifdef DAEMON
------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. ON SALE this month only -- learn more at:
http://p.sf.net/sfu/learnnow-d2d
_______________________________________________
Dspam-devel mailing list
Dspam-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dspam-devel

Reply via email to