Browse code

bb#2879

aCaB authored on 2011/06/19 00:45:44
Showing 7 changed files
... ...
@@ -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
 
... ...
@@ -27,6 +27,7 @@
27 27
 extern uint64_t maxfilesize;
28 28
 extern int addxvirus;
29 29
 extern char xvirushdr[255];
30
+extern int multircpt;
30 31
 
31 32
 
32 33
 sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len);
... ...
@@ -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, "", "" },