even more pre-christmas W.I.P. Sorry for the stupid comming messages, they will get...
authorTom Kistner <tom@duncanthrax.net>
Fri, 10 Dec 2004 09:24:38 +0000 (09:24 +0000)
committerTom Kistner <tom@duncanthrax.net>
Fri, 10 Dec 2004 09:24:38 +0000 (09:24 +0000)
12 files changed:
src/OS/Makefile-Base
src/scripts/MakeLinks
src/src/acl.c
src/src/bmi_spam.c [new file with mode: 0644]
src/src/bmi_spam.h [new file with mode: 0644]
src/src/globals.c
src/src/globals.h
src/src/receive.c
src/src/spf.c [new file with mode: 0644]
src/src/spf.h [new file with mode: 0644]
src/src/srs.c [new file with mode: 0644]
src/src/srs.h [new file with mode: 0644]

index b00049e40f7ea3ca067ec585f5b68a47ff03a324..565ed1c42506bd8563deda9530a91392c23f8daf 100644 (file)
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/OS/Makefile-Base,v 1.1.2.3 2004/12/02 16:33:30 tom Exp $
+# $Cambridge: exim/src/OS/Makefile-Base,v 1.1.2.4 2004/12/10 09:24:38 tom Exp $
 
 # This file is the basis of the main makefile for Exim and friends. The
 # makefile at the top level arranges to build the main makefile by calling
@@ -284,11 +284,17 @@ convert4r4: Makefile ../src/convert4r4.src
        @echo ">>> convert4r4 script built"; echo ""
 
 
+# These are objects of optional features. They are always compiled, but
+# if the corresponding #defines are not set, they wind up empty and
+# are thrown away by the linker.
+
+OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o
+OBJ_WITH_OLD_DEMIME = demime.o
+OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o
+
 # Targets for final binaries; the main one has a build number which is
 # updated each time. We don't bother with that for the auxiliaries.
 
-OBJ_WITH_CONTENT_SCAN = demime.o malware.o mime.o regex.o spam.o spool_mbox.o
-
 OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
         directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
         filtertest.o globals.o \
@@ -297,7 +303,8 @@ OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
         rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
         route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
         store.o string.o tls.o tod.o transport.o tree.o verify.o \
-        local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN)
+        local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
+        $(OBJ_WITH_OLD_DEMIME) $(OBJ_EXPERIMENTAL) 
 
 exim:   pcre/libpcre.a lookups/lookups.a auths/auths.a \
         routers/routers.a transports/transports.a \
@@ -551,7 +558,6 @@ verify.o:        $(HDRS) verify.c
 
 # Dependencies for WITH_CONTENT_SCAN modules
 
-demime.o:        $(HDRS) demime.c
 malware.o:       $(HDRS) malware.c
 mime.o:          $(HDRS) mime.c
 regex.o:         $(HDRS) regex.c
@@ -559,6 +565,18 @@ spam.o:          $(HDRS) spam.c
 spool_mbox.o:    $(HDRS) spool_mbox.c
 
 
+# Dependencies for WITH_OLD_DEMIME modules
+
+demime.o:        $(HDRS) demime.c
+
+
+# Dependencies for EXPERIMENTAL_* modules
+
+bmi_spam.o:      $(HDRS) bmi_spam.c
+spf.o:           $(HDRS) spf.c
+srs.o:           $(HDRS) srs.c
+
+
 # The module containing tables of available lookups, routers, auths, and
 # transports must be rebuilt if any of them are. However, because the makefiles
 # for the drivers are always run, we don't actually put the dependencies here,
index 3a1192c2e422ceceac7fc9e714a52993eff78df3..ec2f93c8c23d96844f12a6d13120a24b2ffa2e07 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Cambridge: exim/src/scripts/MakeLinks,v 1.1.2.3 2004/12/02 16:33:30 tom Exp $
+# $Cambridge: exim/src/scripts/MakeLinks,v 1.1.2.4 2004/12/10 09:24:38 tom Exp $
 
 # Script to build links for all the exim source files from the system-
 # specific build directory. It should be run from within that directory.
@@ -174,28 +174,15 @@ cd ..
 # but local_scan.c does not, because its location is taken from the build-time
 # configuration. Likewise for the os.c file, which gets build dynamically.
 
-# NB: Files marked as "WITH_CONTENT_SCAN" contain only functions relating
-# to content scanning. They are always linked, but their contents compile
-# to nothing if WITH_CONTENT_SCAN is not set.
-
 ln -s ../src/dbfunctions.h     dbfunctions.h
 ln -s ../src/dbstuff.h         dbstuff.h
-# WITH_OLD_DEMIME
-ln -s ../src/demime.h          demime.h
-#
 ln -s ../src/exim.h            exim.h
 ln -s ../src/functions.h       functions.h
 ln -s ../src/globals.h         globals.h
 ln -s ../src/local_scan.h      local_scan.h
 ln -s ../src/macros.h          macros.h
-# WITH_CONTENT_SCAN
-ln -s ../src/mime.h            mime.h
-#
 ln -s ../src/mytypes.h         mytypes.h
 ln -s ../src/osfunctions.h     osfunctions.h
-# WITH_CONTENT_SCAN
-ln -s ../src/spam.h            spam.h
-#
 ln -s ../src/store.h           store.h
 ln -s ../src/structs.h         structs.h
 
@@ -207,9 +194,6 @@ ln -s ../src/daemon.c          daemon.c
 ln -s ../src/dbfn.c            dbfn.c
 ln -s ../src/debug.c           debug.c
 ln -s ../src/deliver.c         deliver.c
-# WITH_OLD_DEMIME
-ln -s ../src/demime.c          demime.c
-#
 ln -s ../src/directory.c       directory.c
 ln -s ../src/dns.c             dns.c
 ln -s ../src/drtables.c        drtables.c
@@ -228,13 +212,7 @@ ln -s ../src/host.c            host.c
 ln -s ../src/ip.c              ip.c
 ln -s ../src/log.c             log.c
 ln -s ../src/lss.c             lss.c
-# WITH_CONTENT_SCAN
-ln -s ../src/malware.c         malware.c
-#
 ln -s ../src/match.c           match.c
-# WITH_CONTENT_SCAN
-ln -s ../src/mime.c            mime.c
-#
 ln -s ../src/moan.c            moan.c
 ln -s ../src/parse.c           parse.c
 ln -s ../src/perl.c            perl.c
@@ -242,9 +220,6 @@ ln -s ../src/queue.c           queue.c
 ln -s ../src/rda.c             rda.c
 ln -s ../src/readconf.c        readconf.c
 ln -s ../src/receive.c         receive.c
-# WITH_CONTENT_SCAN
-ln -s ../src/regex.c           regex.c   
-#
 ln -s ../src/retry.c           retry.c
 ln -s ../src/rewrite.c         rewrite.c
 ln -s ../src/rfc2047.c         rfc2047.c
@@ -253,13 +228,7 @@ ln -s ../src/search.c          search.c
 ln -s ../src/sieve.c           sieve.c
 ln -s ../src/smtp_in.c         smtp_in.c
 ln -s ../src/smtp_out.c        smtp_out.c
-# WITH_CONTENT_SCAN
-ln -s ../src/spam.c            spam.c
-#
 ln -s ../src/spool_in.c        spool_in.c
-# WITH_CONTENT_SCAN
-ln -s ../src/spool_mbox.c      spool_mbox.c
-#
 ln -s ../src/spool_out.c       spool_out.c
 ln -s ../src/store.c           store.c
 ln -s ../src/string.c          string.c
@@ -272,4 +241,25 @@ ln -s ../src/tree.c            tree.c
 ln -s ../src/verify.c          verify.c
 ln -s ../src/version.c         version.c
 
+# WITH_CONTENT_SCAN
+ln -s ../src/spam.c            spam.c
+ln -s ../src/spam.h            spam.h
+ln -s ../src/spool_mbox.c      spool_mbox.c
+ln -s ../src/regex.c           regex.c
+ln -s ../src/mime.c            mime.c
+ln -s ../src/mime.h            mime.h
+ln -s ../src/malware.c         malware.c
+
+# WITH_OLD_DEMIME
+ln -s ../src/demime.c          demime.c
+ln -s ../src/demime.h          demime.h
+
+# EXPERIMENTAL_*
+ln -s ../src/bmi_spam.c        bmi_spam.c
+ln -s ../src/bmi_spam.h        bmi_spam.h
+ln -s ../src/spf.c             spf.c
+ln -s ../src/spf.h             spf.h
+ln -s ../src/srs.c             srs.c
+ln -s ../src/srs.h             srs.h
+
 # End of MakeLinks
index 1f80ee887e27f04865e9728c9fc651ea906bf98e..6c0a209c70667ff3ef712849aaba4e9e9c2303fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.5.2.3 2004/12/02 16:33:30 tom Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.5.2.4 2004/12/10 09:24:38 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -1577,6 +1577,18 @@ for (; cb != NULL; cb = cb->next)
 #ifdef WITH_CONTENT_SCAN
       case CONTROL_FAKEREJECT:
       fake_reject = TRUE;
+      if (*p == '/')
+        { 
+        uschar *pp = p + 1;
+        while (*pp != 0) pp++; 
+        fake_reject_text = expand_string(string_copyn(p+1, pp-p));
+        p = pp;
+        }
+       else
+        {
+        /* Explicitly reset to default string */
+        fake_reject_text = US"Your message has been rejected but is being kept for evaluation.\nIf it was a legit message, it may still be delivered to the target recipient(s).";
+        }
       break;
 #endif
 
diff --git a/src/src/bmi_spam.c b/src/src/bmi_spam.c
new file mode 100644 (file)
index 0000000..90bbc97
--- /dev/null
@@ -0,0 +1,472 @@
+/* $Cambridge: exim/src/src/bmi_spam.c,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+/* Code for calling Brightmail AntiSpam.
+   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
+   License: GPL */
+
+#include "exim.h"
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+
+#include "bmi_spam.h"
+
+uschar *bmi_current_optin = NULL;
+
+uschar *bmi_process_message(header_line *header_list, int data_fd) {
+  BmiSystem *system = NULL;
+  BmiMessage *message = NULL;
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  const BmiVerdict *verdict = NULL;
+  FILE *data_file;
+  uschar data_buffer[4096];
+  uschar localhost[] = "127.0.0.1";
+  uschar *host_address;
+  uschar *verdicts = NULL;
+  int i,j;
+  
+  err = bmiInitSystem(BMI_VERSION, (char *)bmi_config_file, &system);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: could not initialize Brightmail system.", (int)err_loc, (int)err_type);
+    return NULL;
+  }
+
+  err = bmiInitMessage(system, &message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: could not initialize Brightmail message.", (int)err_loc, (int)err_type);
+    bmiFreeSystem(system);
+    return NULL;
+  }
+
+  /* Send IP address of sending host */
+  if (sender_host_address == NULL)
+    host_address = localhost;
+  else
+    host_address = sender_host_address;
+  err = bmiProcessConnection((char *)host_address, message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, (char *)host_address);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+
+  /* Send envelope sender address */
+  err = bmiProcessFROM((char *)sender_address, message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, (char *)sender_address);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+
+  /* Send envelope recipients */
+  for(i=0;i<recipients_count;i++) {
+    recipient_item *r = recipients_list + i;
+    BmiOptin *optin = NULL;
+    
+    /* create optin object if optin string is given */
+    if ((r->bmi_optin != NULL) && (Ustrlen(r->bmi_optin) > 1)) {
+      debug_printf("passing bmiOptin string: %s\n", r->bmi_optin);
+      bmiOptinInit(&optin);
+      err = bmiOptinMset(optin, r->bmi_optin, ':');
+      if (bmiErrorIsFatal(err) == BMI_TRUE) {
+        log_write(0, LOG_PANIC|LOG_MAIN,
+                   "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, (char *)r->address, (char *)r->bmi_optin);
+        if (optin != NULL)
+          bmiOptinFree(optin);
+        optin = NULL;
+      };
+    };
+    
+    err = bmiAccumulateTO((char *)r->address, optin, message);
+    
+    if (optin != NULL)
+      bmiOptinFree(optin);
+    
+    if (bmiErrorIsFatal(err) == BMI_TRUE) {
+      err_loc = bmiErrorGetLocation(err);
+      err_type = bmiErrorGetType(err);
+      log_write(0, LOG_PANIC,
+                 "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, (char *)r->address);
+      bmiFreeMessage(message);
+      bmiFreeSystem(system);
+      return NULL;
+    };
+  };
+  err = bmiEndTO(message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiEndTO() failed.", (int)err_loc, (int)err_type);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+  
+  /* Send message headers */
+  while (header_list != NULL) {
+    /* skip deleted headers */
+    if (header_list->type == '*') {
+      header_list = header_list->next;
+      continue;
+    };
+    err = bmiAccumulateHeaders((const char *)header_list->text, header_list->slen, message);
+    if (bmiErrorIsFatal(err) == BMI_TRUE) {
+      err_loc = bmiErrorGetLocation(err);
+      err_type = bmiErrorGetType(err);
+      log_write(0, LOG_PANIC,
+                 "bmi error [loc %d type %d]: bmiAccumulateHeaders() failed.", (int)err_loc, (int)err_type);
+      bmiFreeMessage(message);
+      bmiFreeSystem(system);
+      return NULL;
+    };
+    header_list = header_list->next;
+  };
+  err = bmiEndHeaders(message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiEndHeaders() failed.", (int)err_loc, (int)err_type);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+  
+  /* Send body */
+  data_file = fdopen(data_fd,"r");
+  do {
+    j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
+    if (j > 0) {
+      err = bmiAccumulateBody((const char *)data_buffer, j, message);
+      if (bmiErrorIsFatal(err) == BMI_TRUE) {
+        err_loc = bmiErrorGetLocation(err);
+        err_type = bmiErrorGetType(err);
+        log_write(0, LOG_PANIC,
+                   "bmi error [loc %d type %d]: bmiAccumulateBody() failed.", (int)err_loc, (int)err_type);
+        bmiFreeMessage(message);
+        bmiFreeSystem(system);
+        return NULL;
+      };
+    };
+  } while (j > 0);
+  err = bmiEndBody(message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiEndBody() failed.", (int)err_loc, (int)err_type);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+  
+  
+  /* End message */
+  err = bmiEndMessage(message);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiEndMessage() failed.", (int)err_loc, (int)err_type);
+    bmiFreeMessage(message);
+    bmiFreeSystem(system);
+    return NULL;
+  };
+  
+  /* get store for the verdict string */
+  verdicts = store_get(1);
+  *verdicts = '\0';
+  
+  for ( err = bmiAccessFirstVerdict(message, &verdict);
+        verdict != NULL;
+        err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
+    char *verdict_str;
+
+    err = bmiCreateStrFromVerdict(verdict,&verdict_str);
+    if (!store_extend(verdicts, Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
+      /* can't allocate more store */
+      return NULL;
+    };
+    if (*verdicts != '\0')
+      Ustrcat(verdicts, US ":");
+    Ustrcat(verdicts, US verdict_str);
+    bmiFreeStr(verdict_str);
+  };
+
+  DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts);
+
+  if (Ustrlen(verdicts) == 0)
+    return NULL;
+  else
+    return verdicts;
+}
+
+
+int bmi_get_delivery_status(uschar *base64_verdict) {
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  BmiVerdict *verdict = NULL;
+  int rc = 1;   /* deliver by default */
+  
+  /* always deliver when there is no verdict */
+  if (base64_verdict == NULL)
+    return 1;
+
+  /* create verdict from base64 string */
+  err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
+    return 1;
+  };
+
+  err = bmiVerdictError(verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    /* deliver normally due to error */
+    rc = 1;
+  }
+  else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
+    /* deliver normally */
+    rc = 1;    
+  }
+  else if (bmiVerdictAccessDestination(verdict) == NULL) {
+    /* do not deliver */
+    rc = 0;
+  }
+  else {
+    /* deliver to alternate location */
+    rc = 1;
+  };
+  
+  bmiFreeVerdict(verdict);
+  return rc;
+}
+
+
+uschar *bmi_get_alt_location(uschar *base64_verdict) {
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  BmiVerdict *verdict = NULL;
+  uschar *rc = NULL;
+  
+  /* always deliver when there is no verdict */
+  if (base64_verdict == NULL)
+    return NULL;
+
+  /* create verdict from base64 string */
+  err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
+    return NULL;
+  };
+  
+  err = bmiVerdictError(verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    /* deliver normally due to error */
+    rc = NULL;
+  }
+  else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
+    /* deliver normally */
+    rc = NULL; 
+  }
+  else if (bmiVerdictAccessDestination(verdict) == NULL) {
+    /* do not deliver */
+    rc = NULL;
+  }
+  else {
+    /* deliver to alternate location */
+    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1);
+    Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
+    rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
+  };
+  
+  bmiFreeVerdict(verdict);
+  return rc;
+}
+
+uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  BmiVerdict *verdict = NULL;
+  const BmiRecipient *recipient = NULL;
+  const char *verdict_str = NULL;
+  uschar *verdict_ptr;
+  uschar *verdict_buffer = NULL;
+  int sep = 0;
+  
+  /* return nothing if there are no verdicts available */
+  if (bmi_verdicts == NULL)
+    return NULL;
+  
+  /* allocate room for the b64 verdict string */
+  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1);
+  
+  /* loop through verdicts */
+  verdict_ptr = bmi_verdicts;
+  while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
+                                          verdict_buffer,
+                                          Ustrlen(bmi_verdicts)+1)) != NULL) {
+    
+    /* create verdict from base64 string */
+    err = bmiCreateVerdictFromStr(verdict_str, &verdict);
+    if (bmiErrorIsFatal(err) == BMI_TRUE) {
+      err_loc = bmiErrorGetLocation(err);
+      err_type = bmiErrorGetType(err);
+      log_write(0, LOG_PANIC,
+                 "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, verdict_str);
+      return NULL;
+    };
+    
+    /* loop through rcpts for this verdict */
+    for ( recipient = bmiVerdictAccessFirstRecipient(verdict);
+          recipient != NULL;
+          recipient = bmiVerdictAccessNextRecipient(verdict, recipient)) {
+      uschar *rcpt_local_part;
+      uschar *rcpt_domain;
+      
+      /* compare address against our subject */
+      rcpt_local_part = (unsigned char *)bmiRecipientAccessAddress(recipient);
+      rcpt_domain = Ustrchr(rcpt_local_part,'@');
+      if (rcpt_domain == NULL) {
+        rcpt_domain = US"";
+      }
+      else {
+        *rcpt_domain = '\0';
+        rcpt_domain++;
+      };
+
+      if ( (strcmpic(rcpt_local_part, bmi_local_part) == 0) &&
+           (strcmpic(rcpt_domain, bmi_domain) == 0) ) {
+        /* found verdict */
+        bmiFreeVerdict(verdict);
+        return (uschar *)verdict_str;
+      };   
+    };
+  
+    bmiFreeVerdict(verdict);
+  };
+  
+  return NULL;
+}
+
+
+uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) {
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  BmiVerdict *verdict = NULL;
+  uschar *rc = NULL;
+  
+  /* always deliver when there is no verdict */
+  if (base64_verdict == NULL)
+    return NULL;
+
+  /* create verdict from base64 string */
+  err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
+    return NULL;
+  };
+  
+  /* create old tracker string from verdict */
+  err = bmiCreateOldStrFromVerdict(verdict, &rc);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiCreateOldStrFromVerdict() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
+    return NULL;
+  };
+  
+  bmiFreeVerdict(verdict);
+  return rc;
+}
+
+
+int bmi_check_rule(uschar *base64_verdict, uschar *option_list) {
+  BmiError err;
+  BmiErrorLocation err_loc;
+  BmiErrorType err_type;
+  BmiVerdict *verdict = NULL;
+  int rc = 0;
+  uschar *rule_num;
+  uschar *rule_ptr;
+  uschar rule_buffer[32];
+  int sep = 0;
+  
+  
+  /* no verdict -> no rule fired */
+  if (base64_verdict == NULL)
+    return 0;
+  
+  /* create verdict from base64 string */
+  err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    err_loc = bmiErrorGetLocation(err);
+    err_type = bmiErrorGetType(err);
+    log_write(0, LOG_PANIC,
+               "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
+    return 0;
+  };
+  
+  err = bmiVerdictError(verdict);
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
+    /* error -> no rule fired */
+    bmiFreeVerdict(verdict);
+    return 0;
+  }
+  
+  /* loop through numbers */
+  rule_ptr = option_list;
+  while ((rule_num = string_nextinlist(&rule_ptr, &sep,
+                                       rule_buffer, 32)) != NULL) {
+    int rule_int = -1;
+    
+    /* try to translate to int */
+    sscanf(rule_num, "%d", &rule_int);
+    if (rule_int > 0) {
+      debug_printf("checking rule #%d\n", rule_int);
+      /* check if rule fired on the message */
+      if (bmiVerdictRuleFired(verdict, rule_int) == BMI_TRUE) {
+        debug_printf("rule #%d fired\n", rule_int);
+        rc = 1;
+        break;
+      };
+    };
+  };
+
+  bmiFreeVerdict(verdict);
+  return rc;
+};
+
+#endif
diff --git a/src/src/bmi_spam.h b/src/src/bmi_spam.h
new file mode 100644 (file)
index 0000000..5fca7c6
--- /dev/null
@@ -0,0 +1,24 @@
+/* $Cambridge: exim/src/src/bmi_spam.h,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+/* Code for calling Brightmail AntiSpam.
+   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
+   License: GPL */
+
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+
+#include <bmi_api.h>
+
+extern uschar *bmi_process_message(header_line *, int);
+extern uschar *bmi_get_base64_verdict(uschar *, uschar *);
+extern uschar *bmi_get_base64_tracker_verdict(uschar *);
+extern int bmi_get_delivery_status(uschar *);
+extern uschar *bmi_get_alt_location(uschar *);
+extern int bmi_check_rule(uschar *,uschar *);
+
+extern uschar *bmi_current_optin;
+
+#endif
index da57ba5e29dc8f145fccea450855ff54594c314b..4566947f5c7d1046fe19faa66b04a89e640dbfde 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.6.2.3 2004/12/02 09:15:11 tom Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.6.2.4 2004/12/10 09:24:38 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -492,6 +492,7 @@ uschar *extra_local_interfaces = NULL;
 
 #ifdef WITH_CONTENT_SCAN
 BOOL    fake_reject            = FALSE;
+uschar *fake_reject_text       = US"Your message has been rejected but is being kept for evaluation.\nIf it was a legit message, it may still be delivered to the target recipient(s).";
 #endif
 int     filter_n[FILTER_VARIABLE_COUNT];
 BOOL    filter_running         = FALSE;
index 727be71c517b7e4c1dd8b4cf10c49cca7436eb44..2b36a8aa7156dd772b46c298810af73442ff7bf0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.6.2.2 2004/12/02 09:15:11 tom Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.6.2.3 2004/12/10 09:24:38 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -285,6 +285,7 @@ extern uschar *extra_local_interfaces; /* Local, non-listen interfaces */
 
 #ifdef WITH_CONTENT_SCAN
 extern BOOL    fake_reject;            /* TRUE if fake reject is to be given */
+extern uschar *fake_reject_text;       /* Option for the fakereject control statement: can contain user defined message. Default is in globals.c. */
 #endif
 extern int     filter_n[FILTER_VARIABLE_COUNT]; /* filter variables */
 extern BOOL    filter_running;         /* TRUE while running a filter */
index abde1ce9a6425e431105f096ff0129a28cd6971f..dfe14076f315ee6e12b92f015aefb8c514da68c2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/receive.c,v 1.4.2.2 2004/12/02 16:33:30 tom Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.4.2.3 2004/12/10 09:24:38 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -3385,11 +3385,7 @@ if (smtp_input)
       smtp_printf("250 OK id=%s\r\n", message_id);
 #else      
         if (fake_reject)
-          {
-            smtp_printf("550-FAKE_REJECT id=%s\r\n", message_id);
-            smtp_printf("550-Your message has been rejected but is being kept for evaluation.\r\n");
-            smtp_printf("550 If it was a legit message, it may still be delivered to the target recipient(s).\r\n");
-          }
+          smtp_respond(550,TRUE,fake_reject_text);
         else  
           smtp_printf("250 OK id=%s\r\n", message_id);      
 #endif     
@@ -3403,11 +3399,7 @@ if (smtp_input)
     else if (smtp_reply[0] != 0)
       {
         if (fake_reject && (smtp_reply[0] == '2'))
-        {
-          smtp_printf("550-FAKE_REJECT id=%s\r\n", message_id);
-          smtp_printf("550-Your message has been rejected but is being kept for evaluation.\r\n");
-          smtp_printf("550 If it was a legit message, it may still be delivered to the target recipient(s).\r\n");
-        }
+          smtp_respond(550,TRUE,fake_reject_text);
         else 
           smtp_printf("%.1024s\r\n", smtp_reply);
       };
diff --git a/src/src/spf.c b/src/src/spf.c
new file mode 100644 (file)
index 0000000..7b5edb9
--- /dev/null
@@ -0,0 +1,131 @@
+/* $Cambridge: exim/src/src/spf.c,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+/* Experimental SPF support.
+   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
+   License: GPL */
+   
+/* Code for calling spf checks via libspf-alt. Called from acl.c. */
+
+#include "exim.h"
+#ifdef EXPERIMENTAL_SPF
+
+#include "spf.h"
+
+SPF_config_t        spfcid = NULL;
+SPF_dns_config_t    spfdcid_resolv = NULL;
+SPF_dns_config_t    spfdcid = NULL;
+
+
+/* spf_init sets up a context that can be re-used for several
+   messages on the same SMTP connection (that come from the
+   same host with the same HELO string) */
+   
+int spf_init(uschar *spf_helo_domain, uschar *spf_remote_addr) {
+  uschar *p;
+  
+  /* paranoia */
+  spfcid = NULL;
+  spfdcid_resolv = NULL;
+  spfdcid = NULL;
+  
+  spfcid = SPF_create_config();
+  if ( spfcid == NULL ) {
+    debug_printf("spf: SPF_create_config() failed.\n");
+         return 0;
+  }
+
+  /* set up resolver */
+  spfdcid_resolv = SPF_dns_create_config_resolv(NULL, 0);
+  spfdcid = SPF_dns_create_config_cache(spfdcid_resolv, 8, 0);
+
+  if (spfdcid == NULL) {
+    debug_printf("spf: SPF_dns_create_config_cache() failed.\n");
+    spfcid = NULL;
+    spfdcid_resolv = NULL;
+         return 0;
+  }
+
+  if (SPF_set_ip_str(spfcid, spf_remote_addr)) {
+    debug_printf("spf: SPF_set_ip_str() failed.\n");
+    spfcid = NULL;
+    spfdcid_resolv = NULL;
+         return 0;
+  }
+
+  if (SPF_set_helo_dom(spfcid, spf_helo_domain)) {
+    debug_printf("spf: SPF_set_helo_dom() failed.\n");
+    spfcid = NULL;
+    spfdcid_resolv = NULL;
+         return 0;
+  }
+  
+  return 1;
+}
+
+
+/* spf_process adds the envelope sender address to the existing
+   context (if any), retrieves the result, sets up expansion
+   strings and evaluates the condition outcome. */
+
+int spf_process(uschar **listptr, uschar *spf_envelope_sender) {
+  int sep = 0;
+  uschar *list = *listptr;
+  uschar *spf_result_id;
+  uschar spf_result_id_buffer[128];
+  SPF_output_t spf_output;
+  int rc = SPF_RESULT_ERROR;
+  if (!(spfcid && spfdcid)) {
+    /* no global context, assume temp error and skip to evaluation */
+    rc = SPF_RESULT_ERROR;
+    goto SPF_EVALUATE;
+  };
+
+  if (SPF_set_env_from(spfcid, spf_envelope_sender)) {
+    /* Invalid sender address. This should be a real rare occurence */
+    rc = SPF_RESULT_ERROR;
+    goto SPF_EVALUATE;
+  } 
+
+  /* get SPF result */
+  spf_output = SPF_result(spfcid, spfdcid);
+
+  /* set up expansion items */
+  spf_header_comment     = spf_output.header_comment ? (uschar *)spf_output.header_comment : NULL;
+  spf_received           = spf_output.received_spf ? (uschar *)spf_output.received_spf : NULL;
+  spf_result             = (uschar *)SPF_strresult(spf_output.result);
+  spf_smtp_comment       = spf_output.smtp_comment ? (uschar *)spf_output.smtp_comment : NULL;
+
+  rc = spf_output.result;
+
+  /* We got a result. Now see if we should return OK or FAIL for it */
+  SPF_EVALUATE:
+  debug_printf("SPF result is %s (%d)\n", SPF_strresult(rc), rc);
+  while ((spf_result_id = string_nextinlist(&list, &sep,
+                                     spf_result_id_buffer,
+                                     sizeof(spf_result_id_buffer))) != NULL) {
+    int negate = 0;
+    int result = 0;
+
+    /* Check for negation */
+    if (spf_result_id[0] == '!') {
+      negate = 1;
+      spf_result_id++;
+    };
+
+    /* Check the result identifier */
+    result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name);
+    if (!negate && result==0) return OK;
+    if (negate && result!=0) return OK;
+  };
+
+  /* no match */
+  return FAIL;
+}
+
+#endif
+
diff --git a/src/src/spf.h b/src/src/spf.h
new file mode 100644 (file)
index 0000000..337c84d
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Cambridge: exim/src/src/spf.h,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+/* Experimental SPF support.
+   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
+   License: GPL */
+
+#ifdef EXPERIMENTAL_SPF
+
+#include <spf2/spf.h>
+#include <spf2/spf_dns_resolv.h>
+#include <spf2/spf_dns_cache.h>
+
+typedef struct spf_result_id {
+  uschar *name;
+  int    value;
+} spf_result_id;
+
+/* must be kept in numeric order */
+static spf_result_id spf_result_id_list[] = {
+  { US"pass", 0 },
+  { US"fail", 1 },
+  { US"softfail", 2 },
+  { US"neutral", 3 },
+  { US"err_perm", 4 },
+  { US"err_temp", 5 },
+  { US"none", 6 }
+};
+
+static int spf_result_id_list_size = sizeof(spf_result_id_list)/sizeof(spf_result_id);
+
+/* prototypes */
+int spf_init(uschar *,uschar *);
+int spf_process(uschar **, uschar *);
+
+#endif
diff --git a/src/src/srs.c b/src/src/srs.c
new file mode 100644 (file)
index 0000000..dd462c8
--- /dev/null
@@ -0,0 +1,206 @@
+/* $Cambridge: exim/src/src/srs.c,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* SRS - Sender rewriting scheme support
+  ©2004 Miles Wilton <miles@mirtol.com>
+  License: GPL */
+
+#include "exim.h"
+#ifdef EXPERIMENTAL_SRS
+
+#include <srs_alt.h>
+#include "srs.h"
+
+srs_t    *srs                   = NULL;
+uschar   *srs_db_forward        = NULL;
+uschar   *srs_db_reverse        = NULL;
+
+
+/* srs_init just initialises libsrs and creates (if necessary)
+   an srs object to use for all srs calls in this instance */
+   
+int eximsrs_init()
+{
+  int co;
+  uschar *list = srs_config;
+  char secret_buf[SRS_MAX_SECRET_LENGTH];
+  char *secret;
+  char sbuf[4];
+  char *sbufp;
+  int hashlen, maxage;
+
+  
+  if(!srs)
+  {
+    // Check config
+    if(!srs_config)
+    {
+      log_write(0, LOG_MAIN | LOG_PANIC,
+          "SRS Configuration Error");
+      return DEFER;
+    }
+    
+    // Get config
+    co = 0;
+    if((secret = string_nextinlist(&list, &co, secret_buf,
+                                   SRS_MAX_SECRET_LENGTH)) == NULL)
+    {
+      log_write(0, LOG_MAIN | LOG_PANIC,
+          "SRS Configuration Error: No secret specified");
+      return DEFER;
+    }
+    
+    if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) == NULL)
+      maxage = 31;
+    else
+      maxage = atoi(sbuf);
+    if(maxage < 0 || maxage > 365)
+    {
+      log_write(0, LOG_MAIN | LOG_PANIC,
+          "SRS Configuration Error: Invalid maximum timestamp age");
+      return DEFER;
+    }
+
+    if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) == NULL)
+      hashlen = 6;
+    else
+      hashlen = atoi(sbuf);
+    if(hashlen < 1 || hashlen > 20)
+    {
+      log_write(0, LOG_MAIN | LOG_PANIC,
+          "SRS Configuration Error: Invalid hash length");
+      return DEFER;
+    }
+    
+    
+    if((srs = srs_open(secret, strnlen(secret, SRS_MAX_SECRET_LENGTH),
+                      maxage, hashlen, hashlen)) == NULL)
+    {
+      log_write(0, LOG_MAIN | LOG_PANIC,
+          "Failed to allocate SRS memory");
+      return DEFER;
+    }
+
+
+    if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
+      srs_set_option(srs, SRS_OPTION_USETIMESTAMP, atoi(sbuf));
+    
+    if((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))) != NULL)
+      srs_set_option(srs, SRS_OPTION_USEHASH, atoi(sbuf));
+
+    DEBUG(D_any)
+      debug_printf("SRS initialized\n");
+  }
+
+  return OK;
+}
+
+
+int eximsrs_done()
+{
+  if(srs)
+    srs_close(srs);
+  
+  srs = NULL;
+
+  return OK;
+}
+
+
+int eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
+{
+  char res[512];
+  int n;
+
+  if((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
+  {
+    DEBUG(D_any)
+      debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
+    return DEFER;
+  }
+
+  *result = string_copy(res);
+  return OK;
+}
+
+
+int eximsrs_reverse(uschar **result, uschar *address)
+{
+  char res[512];
+  int n;
+
+  if((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
+  {
+    DEBUG(D_any)
+      debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
+    if(n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
+      return DECLINE;
+    if(n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
+      return FAIL;
+    return DEFER;
+  }
+
+  *result = string_copy(res);
+  return OK;
+}
+
+
+int eximsrs_db_set(BOOL reverse, uschar *srs_db)
+{
+  if(reverse)
+    srs_db_reverse = string_copy(srs_db);
+  else
+    srs_db_forward = string_copy(srs_db);
+    
+  if(srs_set_db_functions(srs, eximsrs_db_insert, eximsrs_db_lookup) * SRS_RESULT_FAIL)
+    return DEFER;
+  
+  return OK;
+}
+
+
+srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
+{
+  uschar *res;
+  char buf[64];
+
+  srs_db_address = string_copyn(data, data_len);
+  if(srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
+    return DEFER;
+  
+  srs_db_key = string_copyn(buf, 16);
+  
+  if((res = expand_string(srs_db_forward)) == NULL)
+    return SRS_RESULT_DBERROR;
+  
+  if(result_len < 17)
+    return SRS_RESULT_DBERROR;
+    
+  strncpy(result, srs_db_key, result_len);
+
+  return SRS_RESULT_OK;
+}
+
+
+srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
+{
+  uschar *res;
+
+  srs_db_key = string_copyn(data, data_len);
+  if((res = expand_string(srs_db_reverse)) == NULL)
+    return SRS_RESULT_DBERROR;
+  
+  if(Ustrlen(res) >= result_len)
+    return SRS_RESULT_ADDRESSTOOLONG;
+    
+  strncpy(result, res, result_len);
+
+  return SRS_RESULT_OK;
+}
+
+
+#endif
+
diff --git a/src/src/srs.h b/src/src/srs.h
new file mode 100644 (file)
index 0000000..38c1afd
--- /dev/null
@@ -0,0 +1,31 @@
+/* $Cambridge: exim/src/src/srs.h,v 1.1.2.1 2004/12/10 09:24:38 tom Exp $ */
+
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* SRS - Sender rewriting scheme support
+  ©2004 Miles Wilton <miles@mirtol.com>
+  License: GPL */
+
+#ifndef __SRS_H__
+
+#define __SRS_H__ 1
+
+#ifdef EXPERIMENTAL_SRS
+
+#include "mytypes.h"
+#include <srs_alt.h>
+
+int eximsrs_init();
+int eximsrs_done();
+int eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain);
+int eximsrs_reverse(uschar **result, uschar *address);
+int eximsrs_db(BOOL reverse, uschar *srs_db);
+
+srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len);
+srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len);
+
+#endif
+
+#endif