Put DPC's mkcdb script (with tabs removed) into the util directory, and
[exim.git] / src / src / bmi_spam.c
CommitLineData
8e669ac1 1/* $Cambridge: exim/src/src/bmi_spam.c,v 1.3 2005/02/17 11:58:25 ph10 Exp $ */
8523533c
TK
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
8e669ac1 6
8523533c
TK
7/* Code for calling Brightmail AntiSpam.
8 Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
9 License: GPL */
10
11#include "exim.h"
12#ifdef EXPERIMENTAL_BRIGHTMAIL
13
14#include "bmi_spam.h"
15
16uschar *bmi_current_optin = NULL;
17
18uschar *bmi_process_message(header_line *header_list, int data_fd) {
19 BmiSystem *system = NULL;
20 BmiMessage *message = NULL;
21 BmiError err;
22 BmiErrorLocation err_loc;
23 BmiErrorType err_type;
24 const BmiVerdict *verdict = NULL;
25 FILE *data_file;
26 uschar data_buffer[4096];
27 uschar localhost[] = "127.0.0.1";
28 uschar *host_address;
29 uschar *verdicts = NULL;
30 int i,j;
8e669ac1 31
8523533c
TK
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);
38 return NULL;
39 }
40
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);
48 return NULL;
49 }
50
51 /* Send IP address of sending host */
52 if (sender_host_address == NULL)
53 host_address = localhost;
54 else
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);
64 return NULL;
65 };
66
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);
76 return NULL;
77 };
78
79 /* Send envelope recipients */
80 for(i=0;i<recipients_count;i++) {
81 recipient_item *r = recipients_list + i;
82 BmiOptin *optin = NULL;
8e669ac1 83
8523533c
TK
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);
87 bmiOptinInit(&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);
92 if (optin != NULL)
93 bmiOptinFree(optin);
94 optin = NULL;
95 };
96 };
8e669ac1 97
8523533c 98 err = bmiAccumulateTO((char *)r->address, optin, message);
8e669ac1 99
8523533c
TK
100 if (optin != NULL)
101 bmiOptinFree(optin);
8e669ac1 102
8523533c
TK
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);
110 return NULL;
111 };
112 };
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);
121 return NULL;
122 };
8e669ac1 123
8523533c
TK
124 /* Send message headers */
125 while (header_list != NULL) {
126 /* skip deleted headers */
127 if (header_list->type == '*') {
128 header_list = header_list->next;
129 continue;
130 };
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);
139 return NULL;
140 };
141 header_list = header_list->next;
142 };
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);
151 return NULL;
152 };
8e669ac1 153
8523533c
TK
154 /* Send body */
155 data_file = fdopen(data_fd,"r");
156 do {
157 j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
158 if (j > 0) {
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);
167 return NULL;
168 };
169 };
170 } while (j > 0);
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);
179 return NULL;
180 };
8e669ac1
PH
181
182
8523533c
TK
183 /* End message */
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);
192 return NULL;
193 };
8e669ac1 194
8523533c
TK
195 /* get store for the verdict string */
196 verdicts = store_get(1);
197 *verdicts = '\0';
8e669ac1 198
8523533c
TK
199 for ( err = bmiAccessFirstVerdict(message, &verdict);
200 verdict != NULL;
201 err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
202 char *verdict_str;
203
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 */
207 return NULL;
208 };
209 if (*verdicts != '\0')
210 Ustrcat(verdicts, US ":");
211 Ustrcat(verdicts, US verdict_str);
212 bmiFreeStr(verdict_str);
213 };
214
215 DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts);
216
217 if (Ustrlen(verdicts) == 0)
218 return NULL;
219 else
220 return verdicts;
221}
222
223
224int bmi_get_delivery_status(uschar *base64_verdict) {
225 BmiError err;
226 BmiErrorLocation err_loc;
227 BmiErrorType err_type;
228 BmiVerdict *verdict = NULL;
229 int rc = 1; /* deliver by default */
8e669ac1 230
8523533c
TK
231 /* always deliver when there is no verdict */
232 if (base64_verdict == NULL)
233 return 1;
234
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);
242 return 1;
243 };
244
245 err = bmiVerdictError(verdict);
246 if (bmiErrorIsFatal(err) == BMI_TRUE) {
247 /* deliver normally due to error */
248 rc = 1;
249 }
250 else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
251 /* deliver normally */
8e669ac1 252 rc = 1;
8523533c
TK
253 }
254 else if (bmiVerdictAccessDestination(verdict) == NULL) {
255 /* do not deliver */
256 rc = 0;
257 }
258 else {
259 /* deliver to alternate location */
260 rc = 1;
261 };
8e669ac1 262
8523533c
TK
263 bmiFreeVerdict(verdict);
264 return rc;
265}
266
267
268uschar *bmi_get_alt_location(uschar *base64_verdict) {
269 BmiError err;
270 BmiErrorLocation err_loc;
271 BmiErrorType err_type;
272 BmiVerdict *verdict = NULL;
273 uschar *rc = NULL;
8e669ac1 274
8523533c
TK
275 /* always deliver when there is no verdict */
276 if (base64_verdict == NULL)
277 return NULL;
278
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);
286 return NULL;
287 };
8e669ac1 288
8523533c
TK
289 err = bmiVerdictError(verdict);
290 if (bmiErrorIsFatal(err) == BMI_TRUE) {
291 /* deliver normally due to error */
292 rc = NULL;
293 }
294 else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
295 /* deliver normally */
8e669ac1 296 rc = NULL;
8523533c
TK
297 }
298 else if (bmiVerdictAccessDestination(verdict) == NULL) {
299 /* do not deliver */
300 rc = NULL;
301 }
302 else {
303 /* deliver to alternate location */
304 rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1);
305 Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
306 rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
307 };
8e669ac1 308
8523533c
TK
309 bmiFreeVerdict(verdict);
310 return rc;
311}
312
313uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
314 BmiError err;
315 BmiErrorLocation err_loc;
316 BmiErrorType err_type;
317 BmiVerdict *verdict = NULL;
318 const BmiRecipient *recipient = NULL;
319 const char *verdict_str = NULL;
320 uschar *verdict_ptr;
321 uschar *verdict_buffer = NULL;
322 int sep = 0;
8e669ac1 323
8523533c
TK
324 /* return nothing if there are no verdicts available */
325 if (bmi_verdicts == NULL)
326 return NULL;
8e669ac1 327
8523533c
TK
328 /* allocate room for the b64 verdict string */
329 verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1);
8e669ac1 330
8523533c
TK
331 /* loop through verdicts */
332 verdict_ptr = bmi_verdicts;
333 while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
334 verdict_buffer,
335 Ustrlen(bmi_verdicts)+1)) != NULL) {
8e669ac1 336
8523533c
TK
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);
344 return NULL;
345 };
8e669ac1 346
8523533c
TK
347 /* loop through rcpts for this verdict */
348 for ( recipient = bmiVerdictAccessFirstRecipient(verdict);
349 recipient != NULL;
350 recipient = bmiVerdictAccessNextRecipient(verdict, recipient)) {
351 uschar *rcpt_local_part;
352 uschar *rcpt_domain;
8e669ac1 353
8523533c
TK
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) {
358 rcpt_domain = US"";
359 }
360 else {
361 *rcpt_domain = '\0';
362 rcpt_domain++;
363 };
364
365 if ( (strcmpic(rcpt_local_part, bmi_local_part) == 0) &&
366 (strcmpic(rcpt_domain, bmi_domain) == 0) ) {
367 /* found verdict */
368 bmiFreeVerdict(verdict);
369 return (uschar *)verdict_str;
8e669ac1 370 };
8523533c 371 };
8e669ac1 372
8523533c
TK
373 bmiFreeVerdict(verdict);
374 };
8e669ac1 375
8523533c
TK
376 return NULL;
377}
378
379
380uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) {
381 BmiError err;
382 BmiErrorLocation err_loc;
383 BmiErrorType err_type;
384 BmiVerdict *verdict = NULL;
385 uschar *rc = NULL;
8e669ac1 386
8523533c
TK
387 /* always deliver when there is no verdict */
388 if (base64_verdict == NULL)
389 return NULL;
390
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);
398 return NULL;
399 };
8e669ac1 400
8523533c
TK
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);
408 return NULL;
409 };
8e669ac1 410
8523533c
TK
411 bmiFreeVerdict(verdict);
412 return rc;
413}
414
415
416int bmi_check_rule(uschar *base64_verdict, uschar *option_list) {
417 BmiError err;
418 BmiErrorLocation err_loc;
419 BmiErrorType err_type;
420 BmiVerdict *verdict = NULL;
421 int rc = 0;
422 uschar *rule_num;
423 uschar *rule_ptr;
424 uschar rule_buffer[32];
425 int sep = 0;
8e669ac1
PH
426
427
8523533c
TK
428 /* no verdict -> no rule fired */
429 if (base64_verdict == NULL)
430 return 0;
8e669ac1 431
8523533c
TK
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);
439 return 0;
440 };
8e669ac1 441
8523533c
TK
442 err = bmiVerdictError(verdict);
443 if (bmiErrorIsFatal(err) == BMI_TRUE) {
444 /* error -> no rule fired */
445 bmiFreeVerdict(verdict);
446 return 0;
447 }
8e669ac1 448
8523533c
TK
449 /* loop through numbers */
450 rule_ptr = option_list;
451 while ((rule_num = string_nextinlist(&rule_ptr, &sep,
452 rule_buffer, 32)) != NULL) {
453 int rule_int = -1;
8e669ac1 454
8523533c
TK
455 /* try to translate to int */
456 sscanf(rule_num, "%d", &rule_int);
457 if (rule_int > 0) {
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);
462 rc = 1;
463 break;
464 };
465 };
466 };
467
468 bmiFreeVerdict(verdict);
469 return rc;
470};
471
472#endif