1
/* $Cambridge: exim/exim-src/src/bmi_spam.c,v 1.4 2005/06/22 15:44:37 ph10 Exp $ */
3
/*************************************************
4
* Exim - an Internet mail transport agent *
5
*************************************************/
7
/* Code for calling Brightmail AntiSpam.
8
Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
12
#ifdef EXPERIMENTAL_BRIGHTMAIL
16
uschar *bmi_current_optin = NULL;
18
uschar *bmi_process_message(header_line *header_list, int data_fd) {
19
BmiSystem *system = NULL;
20
BmiMessage *message = NULL;
22
BmiErrorLocation err_loc;
23
BmiErrorType err_type;
24
const BmiVerdict *verdict = NULL;
26
uschar data_buffer[4096];
27
uschar localhost[] = "127.0.0.1";
29
uschar *verdicts = NULL;
32
err = bmiInitSystem(BMI_VERSION, (char *)bmi_config_file, &system);
33
if (bmiErrorIsFatal(err) == BMI_TRUE) {
34
err_loc = bmiErrorGetLocation(err);
35
err_type = bmiErrorGetType(err);
36
log_write(0, LOG_PANIC,
37
"bmi error [loc %d type %d]: could not initialize Brightmail system.", (int)err_loc, (int)err_type);
41
err = bmiInitMessage(system, &message);
42
if (bmiErrorIsFatal(err) == BMI_TRUE) {
43
err_loc = bmiErrorGetLocation(err);
44
err_type = bmiErrorGetType(err);
45
log_write(0, LOG_PANIC,
46
"bmi error [loc %d type %d]: could not initialize Brightmail message.", (int)err_loc, (int)err_type);
47
bmiFreeSystem(system);
51
/* Send IP address of sending host */
52
if (sender_host_address == NULL)
53
host_address = localhost;
55
host_address = sender_host_address;
56
err = bmiProcessConnection((char *)host_address, message);
57
if (bmiErrorIsFatal(err) == BMI_TRUE) {
58
err_loc = bmiErrorGetLocation(err);
59
err_type = bmiErrorGetType(err);
60
log_write(0, LOG_PANIC,
61
"bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, (char *)host_address);
62
bmiFreeMessage(message);
63
bmiFreeSystem(system);
67
/* Send envelope sender address */
68
err = bmiProcessFROM((char *)sender_address, message);
69
if (bmiErrorIsFatal(err) == BMI_TRUE) {
70
err_loc = bmiErrorGetLocation(err);
71
err_type = bmiErrorGetType(err);
72
log_write(0, LOG_PANIC,
73
"bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, (char *)sender_address);
74
bmiFreeMessage(message);
75
bmiFreeSystem(system);
79
/* Send envelope recipients */
80
for(i=0;i<recipients_count;i++) {
81
recipient_item *r = recipients_list + i;
82
BmiOptin *optin = NULL;
84
/* create optin object if optin string is given */
85
if ((r->bmi_optin != NULL) && (Ustrlen(r->bmi_optin) > 1)) {
86
debug_printf("passing bmiOptin string: %s\n", r->bmi_optin);
88
err = bmiOptinMset(optin, r->bmi_optin, ':');
89
if (bmiErrorIsFatal(err) == BMI_TRUE) {
90
log_write(0, LOG_PANIC|LOG_MAIN,
91
"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);
98
err = bmiAccumulateTO((char *)r->address, optin, message);
103
if (bmiErrorIsFatal(err) == BMI_TRUE) {
104
err_loc = bmiErrorGetLocation(err);
105
err_type = bmiErrorGetType(err);
106
log_write(0, LOG_PANIC,
107
"bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, (char *)r->address);
108
bmiFreeMessage(message);
109
bmiFreeSystem(system);
113
err = bmiEndTO(message);
114
if (bmiErrorIsFatal(err) == BMI_TRUE) {
115
err_loc = bmiErrorGetLocation(err);
116
err_type = bmiErrorGetType(err);
117
log_write(0, LOG_PANIC,
118
"bmi error [loc %d type %d]: bmiEndTO() failed.", (int)err_loc, (int)err_type);
119
bmiFreeMessage(message);
120
bmiFreeSystem(system);
124
/* Send message headers */
125
while (header_list != NULL) {
126
/* skip deleted headers */
127
if (header_list->type == '*') {
128
header_list = header_list->next;
131
err = bmiAccumulateHeaders((const char *)header_list->text, header_list->slen, message);
132
if (bmiErrorIsFatal(err) == BMI_TRUE) {
133
err_loc = bmiErrorGetLocation(err);
134
err_type = bmiErrorGetType(err);
135
log_write(0, LOG_PANIC,
136
"bmi error [loc %d type %d]: bmiAccumulateHeaders() failed.", (int)err_loc, (int)err_type);
137
bmiFreeMessage(message);
138
bmiFreeSystem(system);
141
header_list = header_list->next;
143
err = bmiEndHeaders(message);
144
if (bmiErrorIsFatal(err) == BMI_TRUE) {
145
err_loc = bmiErrorGetLocation(err);
146
err_type = bmiErrorGetType(err);
147
log_write(0, LOG_PANIC,
148
"bmi error [loc %d type %d]: bmiEndHeaders() failed.", (int)err_loc, (int)err_type);
149
bmiFreeMessage(message);
150
bmiFreeSystem(system);
155
data_file = fdopen(data_fd,"r");
157
j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
159
err = bmiAccumulateBody((const char *)data_buffer, j, message);
160
if (bmiErrorIsFatal(err) == BMI_TRUE) {
161
err_loc = bmiErrorGetLocation(err);
162
err_type = bmiErrorGetType(err);
163
log_write(0, LOG_PANIC,
164
"bmi error [loc %d type %d]: bmiAccumulateBody() failed.", (int)err_loc, (int)err_type);
165
bmiFreeMessage(message);
166
bmiFreeSystem(system);
171
err = bmiEndBody(message);
172
if (bmiErrorIsFatal(err) == BMI_TRUE) {
173
err_loc = bmiErrorGetLocation(err);
174
err_type = bmiErrorGetType(err);
175
log_write(0, LOG_PANIC,
176
"bmi error [loc %d type %d]: bmiEndBody() failed.", (int)err_loc, (int)err_type);
177
bmiFreeMessage(message);
178
bmiFreeSystem(system);
184
err = bmiEndMessage(message);
185
if (bmiErrorIsFatal(err) == BMI_TRUE) {
186
err_loc = bmiErrorGetLocation(err);
187
err_type = bmiErrorGetType(err);
188
log_write(0, LOG_PANIC,
189
"bmi error [loc %d type %d]: bmiEndMessage() failed.", (int)err_loc, (int)err_type);
190
bmiFreeMessage(message);
191
bmiFreeSystem(system);
195
/* get store for the verdict string */
196
verdicts = store_get(1);
199
for ( err = bmiAccessFirstVerdict(message, &verdict);
201
err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
204
err = bmiCreateStrFromVerdict(verdict,&verdict_str);
205
if (!store_extend(verdicts, Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
206
/* can't allocate more store */
209
if (*verdicts != '\0')
210
Ustrcat(verdicts, US ":");
211
Ustrcat(verdicts, US verdict_str);
212
bmiFreeStr(verdict_str);
215
DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts);
217
if (Ustrlen(verdicts) == 0)
224
int bmi_get_delivery_status(uschar *base64_verdict) {
226
BmiErrorLocation err_loc;
227
BmiErrorType err_type;
228
BmiVerdict *verdict = NULL;
229
int rc = 1; /* deliver by default */
231
/* always deliver when there is no verdict */
232
if (base64_verdict == NULL)
235
/* create verdict from base64 string */
236
err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
237
if (bmiErrorIsFatal(err) == BMI_TRUE) {
238
err_loc = bmiErrorGetLocation(err);
239
err_type = bmiErrorGetType(err);
240
log_write(0, LOG_PANIC,
241
"bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
245
err = bmiVerdictError(verdict);
246
if (bmiErrorIsFatal(err) == BMI_TRUE) {
247
/* deliver normally due to error */
250
else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
251
/* deliver normally */
254
else if (bmiVerdictAccessDestination(verdict) == NULL) {
259
/* deliver to alternate location */
263
bmiFreeVerdict(verdict);
268
uschar *bmi_get_alt_location(uschar *base64_verdict) {
270
BmiErrorLocation err_loc;
271
BmiErrorType err_type;
272
BmiVerdict *verdict = NULL;
275
/* always deliver when there is no verdict */
276
if (base64_verdict == NULL)
279
/* create verdict from base64 string */
280
err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
281
if (bmiErrorIsFatal(err) == BMI_TRUE) {
282
err_loc = bmiErrorGetLocation(err);
283
err_type = bmiErrorGetType(err);
284
log_write(0, LOG_PANIC,
285
"bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
289
err = bmiVerdictError(verdict);
290
if (bmiErrorIsFatal(err) == BMI_TRUE) {
291
/* deliver normally due to error */
294
else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
295
/* deliver normally */
298
else if (bmiVerdictAccessDestination(verdict) == NULL) {
303
/* deliver to alternate location */
304
rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1);
305
Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
306
rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
309
bmiFreeVerdict(verdict);
313
uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
315
BmiErrorLocation err_loc;
316
BmiErrorType err_type;
317
BmiVerdict *verdict = NULL;
318
const BmiRecipient *recipient = NULL;
319
const char *verdict_str = NULL;
321
uschar *verdict_buffer = NULL;
324
/* return nothing if there are no verdicts available */
325
if (bmi_verdicts == NULL)
328
/* allocate room for the b64 verdict string */
329
verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1);
331
/* loop through verdicts */
332
verdict_ptr = bmi_verdicts;
333
while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
335
Ustrlen(bmi_verdicts)+1)) != NULL) {
337
/* create verdict from base64 string */
338
err = bmiCreateVerdictFromStr(verdict_str, &verdict);
339
if (bmiErrorIsFatal(err) == BMI_TRUE) {
340
err_loc = bmiErrorGetLocation(err);
341
err_type = bmiErrorGetType(err);
342
log_write(0, LOG_PANIC,
343
"bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, verdict_str);
347
/* loop through rcpts for this verdict */
348
for ( recipient = bmiVerdictAccessFirstRecipient(verdict);
350
recipient = bmiVerdictAccessNextRecipient(verdict, recipient)) {
351
uschar *rcpt_local_part;
354
/* compare address against our subject */
355
rcpt_local_part = (unsigned char *)bmiRecipientAccessAddress(recipient);
356
rcpt_domain = Ustrchr(rcpt_local_part,'@');
357
if (rcpt_domain == NULL) {
365
if ( (strcmpic(rcpt_local_part, bmi_local_part) == 0) &&
366
(strcmpic(rcpt_domain, bmi_domain) == 0) ) {
368
bmiFreeVerdict(verdict);
369
return (uschar *)verdict_str;
373
bmiFreeVerdict(verdict);
380
uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) {
382
BmiErrorLocation err_loc;
383
BmiErrorType err_type;
384
BmiVerdict *verdict = NULL;
387
/* always deliver when there is no verdict */
388
if (base64_verdict == NULL)
391
/* create verdict from base64 string */
392
err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
393
if (bmiErrorIsFatal(err) == BMI_TRUE) {
394
err_loc = bmiErrorGetLocation(err);
395
err_type = bmiErrorGetType(err);
396
log_write(0, LOG_PANIC,
397
"bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
401
/* create old tracker string from verdict */
402
err = bmiCreateOldStrFromVerdict(verdict, &rc);
403
if (bmiErrorIsFatal(err) == BMI_TRUE) {
404
err_loc = bmiErrorGetLocation(err);
405
err_type = bmiErrorGetType(err);
406
log_write(0, LOG_PANIC,
407
"bmi error [loc %d type %d]: bmiCreateOldStrFromVerdict() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
411
bmiFreeVerdict(verdict);
416
int bmi_check_rule(uschar *base64_verdict, uschar *option_list) {
418
BmiErrorLocation err_loc;
419
BmiErrorType err_type;
420
BmiVerdict *verdict = NULL;
424
uschar rule_buffer[32];
428
/* no verdict -> no rule fired */
429
if (base64_verdict == NULL)
432
/* create verdict from base64 string */
433
err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
434
if (bmiErrorIsFatal(err) == BMI_TRUE) {
435
err_loc = bmiErrorGetLocation(err);
436
err_type = bmiErrorGetType(err);
437
log_write(0, LOG_PANIC,
438
"bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
442
err = bmiVerdictError(verdict);
443
if (bmiErrorIsFatal(err) == BMI_TRUE) {
444
/* error -> no rule fired */
445
bmiFreeVerdict(verdict);
449
/* loop through numbers */
450
rule_ptr = option_list;
451
while ((rule_num = string_nextinlist(&rule_ptr, &sep,
452
rule_buffer, 32)) != NULL) {
455
/* try to translate to int */
456
(void)sscanf(rule_num, "%d", &rule_int);
458
debug_printf("checking rule #%d\n", rule_int);
459
/* check if rule fired on the message */
460
if (bmiVerdictRuleFired(verdict, rule_int) == BMI_TRUE) {
461
debug_printf("rule #%d fired\n", rule_int);
468
bmiFreeVerdict(verdict);