1 /* $Cambridge: exim/src/src/bmi_spam.c,v 1.3 2005/02/17 11:58:25 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 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
);