... | ... |
@@ -1,3 +1,7 @@ |
1 |
+Sat Jun 18 17:44:42 CEST 2011 (acab) |
|
2 |
+------------------------------------ |
|
3 |
+ * clamav-milter: add config option "SupportMultipleRecipients" (bb#2879) |
|
4 |
+ |
|
1 | 5 |
Thu Jun 9 08:22:31 CEST 2011 (acab) |
2 | 6 |
------------------------------------ |
3 | 7 |
* libclamav/mew.c: harden boundary check on e8/e9 fixup |
... | ... |
@@ -241,6 +241,8 @@ int main(int argc, char **argv) { |
241 | 241 |
addxvirus = 2; |
242 | 242 |
} |
243 | 243 |
} |
244 |
+ |
|
245 |
+ multircpt = optget(opts, "SupportMultipleRecipients")->enabled; |
|
244 | 246 |
|
245 | 247 |
if(!(my_socket = optget(opts, "MilterSocket")->strarg)) { |
246 | 248 |
logg("!Please configure the MilterSocket directive\n"); |
... | ... |
@@ -58,6 +58,7 @@ static char *rejectfmt = NULL; |
58 | 58 |
int addxvirus = 0; /* 0 - don't add | 1 - replace | 2 - add */ |
59 | 59 |
char xvirushdr[255]; |
60 | 60 |
char *viraction = NULL; |
61 |
+int multircpt = 1; |
|
61 | 62 |
|
62 | 63 |
#define LOGINF_NONE 0 |
63 | 64 |
#define LOGINF_BASIC 1 |
... | ... |
@@ -75,6 +76,7 @@ struct CLAMFI { |
75 | 75 |
char *msg_subj; |
76 | 76 |
char *msg_date; |
77 | 77 |
char *msg_id; |
78 |
+ char **recipients; |
|
78 | 79 |
int local; |
79 | 80 |
int main; |
80 | 81 |
int alt; |
... | ... |
@@ -84,6 +86,7 @@ struct CLAMFI { |
84 | 84 |
unsigned int gotbody; |
85 | 85 |
unsigned int scanned_count; |
86 | 86 |
unsigned int status_count; |
87 |
+ unsigned int nrecipients; |
|
87 | 88 |
uint32_t sendme; |
88 | 89 |
char buffer[CLAMFIBUFSZ]; |
89 | 90 |
}; |
... | ... |
@@ -137,6 +140,13 @@ static void nullify(SMFICTX *ctx, struct CLAMFI *cf, enum CFWHAT closewhat) { |
137 | 137 |
if(cf->msg_subj) free(cf->msg_subj); |
138 | 138 |
if(cf->msg_date) free(cf->msg_date); |
139 | 139 |
if(cf->msg_id) free(cf->msg_id); |
140 |
+ if(multircpt && cf->nrecipients) { |
|
141 |
+ while(cf->nrecipients) { |
|
142 |
+ cf->nrecipients--; |
|
143 |
+ free(cf->recipients[cf->nrecipients]); |
|
144 |
+ } |
|
145 |
+ free(cf->recipients); |
|
146 |
+ } |
|
140 | 147 |
smfi_setpriv(ctx, NULL); |
141 | 148 |
free(cf); |
142 | 149 |
} |
... | ... |
@@ -273,6 +283,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
273 | 273 |
struct CLAMFI *cf; |
274 | 274 |
char *reply; |
275 | 275 |
int len, ret; |
276 |
+ unsigned int crcpt; |
|
276 | 277 |
|
277 | 278 |
if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) |
278 | 279 |
return SMFIS_CONTINUE; /* whatever */ |
... | ... |
@@ -322,15 +333,25 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
322 | 322 |
if(loginfected & LOGCLN_FULL) { |
323 | 323 |
const char *id = smfi_getsymval(ctx, "{i}"); |
324 | 324 |
const char *from = smfi_getsymval(ctx, "{mail_addr}"); |
325 |
- const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); |
|
326 | 325 |
const char *msg_subj = makesanehdr(cf->msg_subj); |
327 | 326 |
const char *msg_date = makesanehdr(cf->msg_date); |
328 | 327 |
const char *msg_id = makesanehdr(cf->msg_id); |
329 |
- logg("~Clean message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s'\n", id, from, to, msg_subj, msg_id, msg_date); |
|
328 |
+ if(multircpt && cf->nrecipients) { |
|
329 |
+ for(crcpt = 0; crcpt < cf->nrecipients; crcpt++) |
|
330 |
+ logg("~Clean message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s'\n", id, from, cf->recipients[crcpt], msg_subj, msg_id, msg_date); |
|
331 |
+ } else { |
|
332 |
+ const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); |
|
333 |
+ logg("~Clean message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s'\n", id, from, to ? to : HDR_UNAVAIL, msg_subj, msg_id, msg_date); |
|
334 |
+ } |
|
330 | 335 |
} else if(loginfected & LOGCLN_BASIC) { |
331 | 336 |
const char *from = smfi_getsymval(ctx, "{mail_addr}"); |
332 |
- const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); |
|
333 |
- logg("~Clean message from <%s> to <%s>\n", from, to); |
|
337 |
+ if(multircpt && cf->nrecipients) { |
|
338 |
+ for(crcpt = 0; crcpt < cf->nrecipients; crcpt++) |
|
339 |
+ logg("~Clean message from <%s> to <%s>\n", from, cf->recipients[crcpt]); |
|
340 |
+ } else { |
|
341 |
+ const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); |
|
342 |
+ logg("~Clean message from <%s> to <%s>\n", from, to ? to : HDR_UNAVAIL); |
|
343 |
+ } |
|
334 | 344 |
} |
335 | 345 |
ret = CleanAction(ctx); |
336 | 346 |
} else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) { |
... | ... |
@@ -341,6 +362,8 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
341 | 341 |
reply[len-7] = '\0'; |
342 | 342 |
vir = strrchr(reply, ' '); |
343 | 343 |
if(vir) { |
344 |
+ unsigned int have_multi = (multircpt != 0 && cf->nrecipients); |
|
345 |
+ unsigned int lst_rcpt = (have_multi * (cf->nrecipients - 1)) + 1; |
|
344 | 346 |
vir++; |
345 | 347 |
|
346 | 348 |
if(rejectfmt) |
... | ... |
@@ -353,76 +376,78 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
353 | 353 |
add_x_header(ctx, msg, cf->scanned_count, cf->status_count); |
354 | 354 |
} |
355 | 355 |
|
356 |
- if(loginfected || viraction) { |
|
357 |
- const char *from = smfi_getsymval(ctx, "{mail_addr}"); |
|
358 |
- const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); |
|
356 |
+ for(crcpt = 0; crcpt < lst_rcpt; crcpt++) { |
|
357 |
+ if(loginfected || viraction) { |
|
358 |
+ const char *from = smfi_getsymval(ctx, "{mail_addr}"); |
|
359 |
+ const char *to = have_multi ? cf->recipients[crcpt] : smfi_getsymval(ctx, "{rcpt_addr}"); |
|
359 | 360 |
|
360 |
- if(!from) from = HDR_UNAVAIL; |
|
361 |
- if(!to) to = HDR_UNAVAIL; |
|
362 |
- if((loginfected & LOGINF_FULL) || viraction) { |
|
363 |
- const char *id = smfi_getsymval(ctx, "{i}"); |
|
364 |
- const char *msg_subj = makesanehdr(cf->msg_subj); |
|
365 |
- const char *msg_date = makesanehdr(cf->msg_date); |
|
366 |
- const char *msg_id = makesanehdr(cf->msg_id); |
|
361 |
+ if(!from) from = HDR_UNAVAIL; |
|
362 |
+ if(!to) to = HDR_UNAVAIL; |
|
363 |
+ if((loginfected & LOGINF_FULL) || viraction) { |
|
364 |
+ const char *id = smfi_getsymval(ctx, "{i}"); |
|
365 |
+ const char *msg_subj = makesanehdr(cf->msg_subj); |
|
366 |
+ const char *msg_date = makesanehdr(cf->msg_date); |
|
367 |
+ const char *msg_id = makesanehdr(cf->msg_id); |
|
367 | 368 |
|
368 |
- if(!id) id = HDR_UNAVAIL; |
|
369 |
+ if(!id) id = HDR_UNAVAIL; |
|
369 | 370 |
|
370 |
- if(loginfected & LOGINF_FULL) |
|
371 |
- logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id, from, to, msg_subj, msg_id, msg_date, vir); |
|
372 |
- |
|
373 |
- if(viraction) { |
|
374 |
- char er[256]; |
|
375 |
- char *e_id = strdup(id); |
|
376 |
- char *e_from = strdup(from); |
|
377 |
- char *e_to = strdup(to); |
|
378 |
- char *e_msg_subj = strdup(msg_subj); |
|
379 |
- char *e_msg_date = strdup(msg_date); |
|
380 |
- char *e_msg_id = strdup(msg_id); |
|
381 |
- pid_t pid; |
|
382 |
- |
|
383 |
- logg("*VirusEvent: about to execute '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'\n", viraction, vir, e_id, e_from, e_to, e_msg_subj, e_msg_id, e_msg_date); |
|
384 |
- |
|
385 |
- pthread_mutex_lock(&virusaction_lock); |
|
386 |
- pid = fork(); |
|
387 |
- if(!pid) { |
|
388 |
- char * args[9]; /* avoid element is not computable at load time warns */ |
|
389 |
- args[0]= viraction; |
|
390 |
- args[1] = vir; |
|
391 |
- args[2] = e_id; |
|
392 |
- args[3] = e_from; |
|
393 |
- args[4] = e_to; |
|
394 |
- args[5] = e_msg_subj; |
|
395 |
- args[6] = e_msg_id; |
|
396 |
- args[7] = e_msg_date; |
|
397 |
- args[8] = NULL; |
|
398 |
- exit(execvp(viraction, args)); |
|
399 |
- } else if(pid > 0) { |
|
400 |
- int wret; |
|
401 |
- pthread_mutex_unlock(&virusaction_lock); |
|
402 |
- while((wret = waitpid(pid, &ret, 0)) == -1 && errno == EINTR); |
|
403 |
- if(wret<0) |
|
404 |
- logg("!VirusEvent: waitpid() failed: %s\n", cli_strerror(errno, er, sizeof(er))); |
|
405 |
- else { |
|
406 |
- if(WIFEXITED(ret)) |
|
407 |
- logg("*VirusEvent: child exited with code %d\n", WEXITSTATUS(ret)); |
|
408 |
- else if(WIFSIGNALED(ret)) |
|
409 |
- logg("*VirusEvent: child killed by signal %d\n", WTERMSIG(ret)); |
|
410 |
- else |
|
411 |
- logg("*VirusEvent: child lost\n"); |
|
371 |
+ if(loginfected & LOGINF_FULL) |
|
372 |
+ logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id, from, to, msg_subj, msg_id, msg_date, vir); |
|
373 |
+ |
|
374 |
+ if(viraction) { |
|
375 |
+ char er[256]; |
|
376 |
+ char *e_id = strdup(id); |
|
377 |
+ char *e_from = strdup(from); |
|
378 |
+ char *e_to = strdup(to); |
|
379 |
+ char *e_msg_subj = strdup(msg_subj); |
|
380 |
+ char *e_msg_date = strdup(msg_date); |
|
381 |
+ char *e_msg_id = strdup(msg_id); |
|
382 |
+ pid_t pid; |
|
383 |
+ |
|
384 |
+ logg("*VirusEvent: about to execute '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'\n", viraction, vir, e_id, e_from, e_to, e_msg_subj, e_msg_id, e_msg_date); |
|
385 |
+ |
|
386 |
+ pthread_mutex_lock(&virusaction_lock); |
|
387 |
+ pid = fork(); |
|
388 |
+ if(!pid) { |
|
389 |
+ char * args[9]; /* avoid element is not computable at load time warns */ |
|
390 |
+ args[0]= viraction; |
|
391 |
+ args[1] = vir; |
|
392 |
+ args[2] = e_id; |
|
393 |
+ args[3] = e_from; |
|
394 |
+ args[4] = e_to; |
|
395 |
+ args[5] = e_msg_subj; |
|
396 |
+ args[6] = e_msg_id; |
|
397 |
+ args[7] = e_msg_date; |
|
398 |
+ args[8] = NULL; |
|
399 |
+ exit(execvp(viraction, args)); |
|
400 |
+ } else if(pid > 0) { |
|
401 |
+ int wret; |
|
402 |
+ pthread_mutex_unlock(&virusaction_lock); |
|
403 |
+ while((wret = waitpid(pid, &ret, 0)) == -1 && errno == EINTR); |
|
404 |
+ if(wret<0) |
|
405 |
+ logg("!VirusEvent: waitpid() failed: %s\n", cli_strerror(errno, er, sizeof(er))); |
|
406 |
+ else { |
|
407 |
+ if(WIFEXITED(ret)) |
|
408 |
+ logg("*VirusEvent: child exited with code %d\n", WEXITSTATUS(ret)); |
|
409 |
+ else if(WIFSIGNALED(ret)) |
|
410 |
+ logg("*VirusEvent: child killed by signal %d\n", WTERMSIG(ret)); |
|
411 |
+ else |
|
412 |
+ logg("*VirusEvent: child lost\n"); |
|
413 |
+ } |
|
414 |
+ } else { |
|
415 |
+ logg("!VirusEvent: fork failed: %s\n", cli_strerror(errno, er, sizeof(er))); |
|
412 | 416 |
} |
413 |
- } else { |
|
414 |
- logg("!VirusEvent: fork failed: %s\n", cli_strerror(errno, er, sizeof(er))); |
|
417 |
+ free(e_id); |
|
418 |
+ free(e_from); |
|
419 |
+ free(e_to); |
|
420 |
+ free(e_msg_subj); |
|
421 |
+ free(e_msg_date); |
|
422 |
+ free(e_msg_id); |
|
415 | 423 |
} |
416 |
- free(e_id); |
|
417 |
- free(e_from); |
|
418 |
- free(e_to); |
|
419 |
- free(e_msg_subj); |
|
420 |
- free(e_msg_date); |
|
421 |
- free(e_msg_id); |
|
422 | 424 |
} |
425 |
+ if(loginfected & LOGINF_BASIC) |
|
426 |
+ logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir); |
|
423 | 427 |
} |
424 |
- if(loginfected & LOGINF_BASIC) |
|
425 |
- logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir); |
|
426 | 428 |
} |
427 | 429 |
} |
428 | 430 |
} |
... | ... |
@@ -665,6 +690,10 @@ sfsistat clamfi_envfrom(SMFICTX *ctx, char **argv) { |
665 | 665 |
cf->all_whitelisted = 1; |
666 | 666 |
cf->gotbody = 0; |
667 | 667 |
cf->msg_subj = cf->msg_date = cf->msg_id = NULL; |
668 |
+ if(multircpt) { |
|
669 |
+ cf->recipients = NULL; |
|
670 |
+ cf->nrecipients = 0; |
|
671 |
+ } |
|
668 | 672 |
if(addxvirus==1) { |
669 | 673 |
cf->scanned_count = 0; |
670 | 674 |
cf->status_count = 0; |
... | ... |
@@ -683,6 +712,24 @@ sfsistat clamfi_envrcpt(SMFICTX *ctx, char **argv) { |
683 | 683 |
|
684 | 684 |
if(cf->all_whitelisted) |
685 | 685 |
cf->all_whitelisted &= whitelisted(argv[0], 0); |
686 |
+ |
|
687 |
+ if(multircpt) { |
|
688 |
+ void *new_rcpt = realloc(cf->recipients, (cf->nrecipients + 1) * sizeof(*(cf->recipients))); |
|
689 |
+ unsigned int rcpt_cnt; |
|
690 |
+ if(!new_rcpt) { |
|
691 |
+ logg("!Failed to allocate array for new recipient\n"); |
|
692 |
+ nullify(ctx, cf, CF_ANY); |
|
693 |
+ return FailAction; |
|
694 |
+ } |
|
695 |
+ cf->recipients = new_rcpt; |
|
696 |
+ rcpt_cnt = cf->nrecipients++; |
|
697 |
+ if(!(cf->recipients[rcpt_cnt] = strdup(argv[0]))) { |
|
698 |
+ logg("!Failed to allocate space for new recipient\n"); |
|
699 |
+ nullify(ctx, cf, CF_ANY); |
|
700 |
+ return FailAction; |
|
701 |
+ } |
|
702 |
+ } |
|
703 |
+ |
|
686 | 704 |
return SMFIS_CONTINUE; |
687 | 705 |
} |
688 | 706 |
|
... | ... |
@@ -228,6 +228,17 @@ See LogInfected for possible values and caveats. |
228 | 228 |
Useful in debugging but drastically increases the log size. |
229 | 229 |
.br |
230 | 230 |
Default: disabled |
231 |
+.TP |
|
232 |
+\fBSupportMultipleRecipients BOOL\fR |
|
233 |
+This option affects the behaviour of LogInfected, LogClean and VirusAction when a message with multiple recipients is scanned: |
|
234 |
+.br |
|
235 |
+If SupportMultipleRecipients is off (the default) then one single log entry is generated for the message and, in case the message is determined to be malicious, the command indicated by VirusAction is executed just once. In both cases only the last recipient is reported. |
|
236 |
+.br |
|
237 |
+If SupportMultipleRecipients is on then one line is logged for each recipient and the command indicated by VirusAction is also executed once for each recipient. |
|
238 |
+.br |
|
239 |
+Note: although it's probably a good idea to enable this option, the default value is currently set to off for legacy reasons. |
|
240 |
+.br |
|
241 |
+Default: no |
|
231 | 242 |
.SH "NOTES" |
232 | 243 |
.LP |
233 | 244 |
All options expressing a size are limited to max 4GB. Values in excess will be resetted to the maximum. |
... | ... |
@@ -271,3 +271,18 @@ Example |
271 | 271 |
# Default: disabled |
272 | 272 |
#LogClean Basic |
273 | 273 |
|
274 |
+# This option affects the behaviour of LogInfected, LogClean and VirusAction |
|
275 |
+# when a message with multiple recipients is scanned: |
|
276 |
+# If SupportMultipleRecipients is off (the default) |
|
277 |
+# then one single log entry is generated for the message and, in case the |
|
278 |
+# message is determined to be malicious, the command indicated by VirusAction |
|
279 |
+# is executed just once. In both cases only the last recipient is reported. |
|
280 |
+# If SupportMultipleRecipients is on: |
|
281 |
+# then one line is logged for each recipient and the command indicated |
|
282 |
+# by VirusAction is also executed once for each recipient. |
|
283 |
+# |
|
284 |
+# Note: although it's probably a good idea to enable this option, the default value |
|
285 |
+# is currently set to off for legacy reasons. |
|
286 |
+# Default: no |
|
287 |
+#SupportMultipleRecipients yes |
|
288 |
+ |
... | ... |
@@ -462,6 +462,8 @@ const struct clam_option __clam_options[] = { |
462 | 462 |
|
463 | 463 |
{ "LogClean", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option allows to tune what is logged when no threat is found in a scanned message.\nSee LogInfected for possible values and caveats.\nUseful in debugging but drastically increases the log size.", "Basic" }, |
464 | 464 |
|
465 |
+ { "SupportMultipleRecipients", NULL, 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_MILTER, "This option affects the behaviour of LogInfected, LogClean and VirusAction\nwhen a message with multiple recipients is scanned:\nIf SupportMultipleRecipients is off (the default)\nthen one single log entry is generated for the message and, in case the\nmessage is determined to be malicious, the command indicated by VirusAction\nis executed just once. In both cases only the last recipient is reported.\nIf SupportMultipleRecipients is on:\nthen one line is logged for each recipient and the command indicated\nby VirusAction is also executed once for each recipient.\n\nNote: although it's probably a good idea to enable this option, the default value\nis currently set to off for legacy reasons.", "yes" }, |
|
466 |
+ |
|
465 | 467 |
/* Deprecated milter options */ |
466 | 468 |
|
467 | 469 |
{ "ArchiveBlockEncrypted", NULL, 0, TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", "" }, |