Browse code

add option LogInfected for clamav-milter

git-svn: trunk@4964

aCaB authored on 2009/03/20 03:47:01
Showing 4 changed files
... ...
@@ -1,3 +1,7 @@
1
+Thu Mar 19 19:25:08 CET 2009 (acab)
2
+-----------------------------------
3
+ * clamav-milter: add option LogInfected
4
+
1 5
 Mon Mar 16 20:12:47 CET 2009 (tk)
2 6
 ---------------------------------
3 7
  * V 0.95rc2
... ...
@@ -54,12 +54,20 @@ static char *rejectfmt = NULL;
54 54
 
55 55
 int addxvirus = 0;
56 56
 char xvirushdr[255];
57
+enum {
58
+    LOGINF_NONE,
59
+    LOGINF_BASIC,
60
+    LOGINF_FULL
61
+} loginfected;
57 62
 
58 63
 #define CLAMFIBUFSZ 1424
59 64
 
60 65
 struct CLAMFI {
61 66
     char buffer[CLAMFIBUFSZ];
62 67
     const char *virusname;
68
+    char *msg_subj;
69
+    char *msg_date;
70
+    char *msg_id;
63 71
     int local;
64 72
     int main;
65 73
     int alt;
... ...
@@ -83,11 +91,22 @@ enum CFWHAT {
83 83
 };
84 84
 
85 85
 
86
+void makesanehdr(char *hdr) {
87
+    while(*hdr) {
88
+	if(*hdr=='\'' || *hdr=='\t' || *hdr=='\r' || *hdr=='\n' || !isprint(*hdr))
89
+	    *hdr = ' ';
90
+	hdr++;
91
+    }
92
+}
93
+
86 94
 static void nullify(SMFICTX *ctx, struct CLAMFI *cf, enum CFWHAT closewhat) {
87 95
     if(closewhat & CF_MAIN || ((closewhat & CF_ANY) && cf->main >= 0))
88 96
 	close(cf->main);
89 97
     if(closewhat & CF_ALT || ((closewhat & CF_ANY) && cf->alt >= 0))
90 98
 	close(cf->alt);
99
+    if(cf->msg_subj) free(cf->msg_subj);
100
+    if(cf->msg_date) free(cf->msg_date);
101
+    if(cf->msg_id) free(cf->msg_id);
91 102
     smfi_setpriv(ctx, NULL);
92 103
     free(cf);
93 104
 }
... ...
@@ -147,6 +166,15 @@ sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv) {
147 147
     if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx)))
148 148
 	return SMFIS_CONTINUE; /* whatever */
149 149
 
150
+    if(loginfected == LOGINF_FULL) {
151
+	if(headerf && !strcasecmp(headerf, "Subject") && !cf->msg_subj)
152
+	    cf->msg_subj = strdup(headerv);
153
+	if(headerf && !strcasecmp(headerf, "Date") && !cf->msg_date)
154
+	    cf->msg_date = strdup(headerv);
155
+	if(headerf && !strcasecmp(headerf, "Message-ID") && !cf->msg_id)
156
+	    cf->msg_id = strdup(headerv);
157
+    }
158
+
150 159
     if(!cf->totsz) {
151 160
 	if(cf->all_whitelisted) {
152 161
 	    logg("*Skipping scan (all destinations whitelisted)\n");
... ...
@@ -239,7 +267,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
239 239
 	ret = CleanAction(ctx);
240 240
     } else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) {
241 241
 	cf->virusname = NULL;
242
-	if(addxvirus || rejectfmt) {
242
+	if(loginfected || addxvirus || rejectfmt) {
243 243
 	    char *vir;
244 244
 
245 245
 	    reply[len-7] = '\0';
... ...
@@ -247,14 +275,31 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
247 247
 	    if(vir) {
248 248
 		vir++;
249 249
 
250
-		if(rejectfmt) {
250
+		if(rejectfmt)
251 251
 		    cf->virusname = vir;
252
-		} else {
252
+
253
+		if(addxvirus) {
253 254
 		    char msg[255];
254 255
 		    snprintf(msg, sizeof(msg), "Infected (%s)", vir);
255 256
 		    msg[sizeof(msg)-1] = '\0';
256 257
 		    add_x_header(ctx, msg);
257 258
 		}
259
+
260
+		if(loginfected) {
261
+		    const char *from = smfi_getsymval(ctx, "{mail_addr}"), *to = smfi_getsymval(ctx, "{rcpt_addr}");
262
+		    
263
+		    if(!from) from = "UNKNOWN";
264
+		    if(!to) to = "UNKNOWN";
265
+		    
266
+		    if(loginfected == LOGINF_FULL) {
267
+			const char *id = smfi_getsymval(ctx, "{i}");
268
+
269
+			makesanehdr(cf->msg_subj);
270
+			makesanehdr(cf->msg_date);
271
+			makesanehdr(cf->msg_id);
272
+			logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id ? id : "UNKNOWN", from, to, cf->msg_subj, cf->msg_id, cf->msg_date, vir);
273
+		    } else logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir);
274
+		}
258 275
 	    }
259 276
 	}
260 277
 	ret = InfectedAction(ctx);
... ...
@@ -345,6 +390,17 @@ static sfsistat action_reject_msg(SMFICTX *ctx) {
345 345
 int init_actions(struct optstruct *opts) {
346 346
     const struct optstruct *opt;
347 347
 
348
+    if(!(opt = optget(opts, "LogInfected"))->enabled || !strcasecmp(opt->strarg, "Off"))
349
+	loginfected = LOGINF_NONE;
350
+    else if(!strcasecmp(opt->strarg, "Basic"))
351
+	loginfected = LOGINF_BASIC;
352
+    else if(!strcasecmp(opt->strarg, "Full"))
353
+	loginfected = LOGINF_FULL;
354
+    else {
355
+	logg("!Invalid setting %s for option LogInfected\n", opt->strarg);
356
+	return 1;
357
+    }
358
+
348 359
     if((opt = optget(opts, "OnFail"))->enabled) {
349 360
 	switch(parse_action(opt->strarg)) {
350 361
 	case 0:
... ...
@@ -462,6 +518,7 @@ sfsistat clamfi_envfrom(SMFICTX *ctx, char **argv) {
462 462
     cf->bufsz = 0;
463 463
     cf->main = cf->alt = -1;
464 464
     cf->all_whitelisted = 1;
465
+    cf->msg_subj = cf->msg_date = cf->msg_id = NULL;
465 466
     smfi_setpriv(ctx, (void *)cf);
466 467
 
467 468
     return SMFIS_CONTINUE;
... ...
@@ -474,7 +531,8 @@ sfsistat clamfi_envrcpt(SMFICTX *ctx, char **argv) {
474 474
     if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx)))
475 475
 	return SMFIS_CONTINUE; /* whatever */
476 476
 
477
-    cf->all_whitelisted &= whitelisted(argv[0], 0);
477
+    if(cf->all_whitelisted)
478
+	cf->all_whitelisted &= whitelisted(argv[0], 0);
478 479
     return SMFIS_CONTINUE;
479 480
 }
480 481
 
... ...
@@ -206,13 +206,21 @@ Example
206 206
 # Default: no
207 207
 #LogVerbose yes
208 208
 
209
+# This option allows to tune what is logged when a message is infected.
210
+# Possible values are Off (the default - nothing is logged),
211
+# Basic (minimal info logged), Full (verbose info logged)
212
+#
213
+# Default: disabled
214
+#LogInfected Basic
215
+
209 216
 
210 217
 ##
211 218
 ## Limits
212 219
 ##
213 220
 
214 221
 # Messages larger than this value won't be scanned.
215
-# Make sure this value is lower than StreamMaxLength in clamd.conf
222
+# Make sure this value is lower or equal than StreamMaxLength in clamd.conf
223
+#
216 224
 # Default: 25M
217 225
 #MaxFileSize 10M
218 226
 
... ...
@@ -384,6 +384,8 @@ const struct clam_option clam_options[] = {
384 384
 
385 385
     { "Whitelist", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned.  Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be whitelisted.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/whitelisted_addresses" },
386 386
 
387
+    { "LogInfected", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option allows to tune what is logged when a message is infected.\nPossible values are Off (the default - nothing is logged),\nBasic (minimal info logged), Full (verbose info logged)", "Basic" },
388
+
387 389
     /* Deprecated milter options */
388 390
 
389 391
     { "ArchiveBlockEncrypted", NULL, 0, TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", "" },