From d2bf0b73d2ac72332258e31190bcc481317ac792 Mon Sep 17 00:00:00 2001 From: Tom Kistner Date: Fri, 10 Dec 2004 09:24:38 +0000 Subject: [PATCH] even more pre-christmas W.I.P. Sorry for the stupid comming messages, they will get better when the changes are less numerous :) --- src/OS/Makefile-Base | 28 ++- src/scripts/MakeLinks | 54 ++--- src/src/acl.c | 14 +- src/src/bmi_spam.c | 472 ++++++++++++++++++++++++++++++++++++++++++ src/src/bmi_spam.h | 24 +++ src/src/globals.c | 3 +- src/src/globals.h | 3 +- src/src/receive.c | 14 +- src/src/spf.c | 131 ++++++++++++ src/src/spf.h | 39 ++++ src/src/srs.c | 206 ++++++++++++++++++ src/src/srs.h | 31 +++ 12 files changed, 968 insertions(+), 51 deletions(-) create mode 100644 src/src/bmi_spam.c create mode 100644 src/src/bmi_spam.h create mode 100644 src/src/spf.c create mode 100644 src/src/spf.h create mode 100644 src/src/srs.c create mode 100644 src/src/srs.h diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index b00049e40..565ed1c42 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -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, diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 3a1192c2e..ec2f93c8c 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -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 diff --git a/src/src/acl.c b/src/src/acl.c index 1f80ee887..6c0a209c7 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -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 index 000000000..90bbc975e --- /dev/null +++ b/src/src/bmi_spam.c @@ -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 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;ibmi_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 index 000000000..5fca7c6c9 --- /dev/null +++ b/src/src/bmi_spam.h @@ -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 2004 + License: GPL */ + +#ifdef EXPERIMENTAL_BRIGHTMAIL + +#include + +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 diff --git a/src/src/globals.c b/src/src/globals.c index da57ba5e2..4566947f5 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -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; diff --git a/src/src/globals.h b/src/src/globals.h index 727be71c5..2b36a8aa7 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -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 */ diff --git a/src/src/receive.c b/src/src/receive.c index abde1ce9a..dfe14076f 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -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 index 000000000..7b5edb9b9 --- /dev/null +++ b/src/src/spf.c @@ -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 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 index 000000000..337c84de0 --- /dev/null +++ b/src/src/spf.h @@ -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 2004 + License: GPL */ + +#ifdef EXPERIMENTAL_SPF + +#include +#include +#include + +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 index 000000000..dd462c8c9 --- /dev/null +++ b/src/src/srs.c @@ -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 + License: GPL */ + +#include "exim.h" +#ifdef EXPERIMENTAL_SRS + +#include +#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 index 000000000..38c1afdf5 --- /dev/null +++ b/src/src/srs.h @@ -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 + License: GPL */ + +#ifndef __SRS_H__ + +#define __SRS_H__ 1 + +#ifdef EXPERIMENTAL_SRS + +#include "mytypes.h" +#include + +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 -- 2.30.2