diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 09:44:07 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 09:44:07 +0000 |
commit | 39ce00b8d520cbecbd6af87257e8fb11df0ec273 (patch) | |
tree | 4c21a2674c19e5c44be3b3550b476b9e63d8ae3d /src/bmi_spam.c | |
parent | Initial commit. (diff) | |
download | exim4-upstream/4.94.2.tar.xz exim4-upstream/4.94.2.zip |
Adding upstream version 4.94.2.upstream/4.94.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/bmi_spam.c')
-rw-r--r-- | src/bmi_spam.c | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/bmi_spam.c b/src/bmi_spam.c new file mode 100644 index 0000000..6651de5 --- /dev/null +++ b/src/bmi_spam.c @@ -0,0 +1,473 @@ +/************************************************* +* 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, CS 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(CS 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, CS host_address); + bmiFreeMessage(message); + bmiFreeSystem(system); + return NULL; + }; + + /* Send envelope sender address */ + err = bmiProcessFROM(CS 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, CS 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, CS r->address, CS r->bmi_optin); + if (optin != NULL) + bmiOptinFree(optin); + optin = NULL; + }; + }; + + err = bmiAccumulateTO(CS 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, CS 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(CCS 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(CCS 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. Since we are processing message data, assume that + the verdict is tainted. XXX this should use a growable-string */ + + verdicts = store_get(1, TRUE); + *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, TRUE, + 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, TRUE); + 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, TRUE); + + /* loop through verdicts */ + verdict_ptr = bmi_verdicts; + while ((verdict_str = CCS 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 = US 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 US 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 */ + (void)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 |