git-svn: trunk@4964
aCaB authored on 2009/03/20 03:47:01... | ... |
@@ -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, "", "" }, |