git-svn: trunk@4891
aCaB authored on 2009/03/04 04:42:33... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Tue Mar 3 20:40:07 CET 2009 (acab) |
|
2 |
+----------------------------------- |
|
3 |
+ * clamav-milter: Allow custom rejection messages, workaround ancient |
|
4 |
+ systems without strerror_r (bb#1439), remove double syslog include |
|
5 |
+ |
|
1 | 6 |
Tue Mar 3 18:58:06 CET 2009 (tk) |
2 | 7 |
--------------------------------- |
3 | 8 |
* libclamav/unarj.c: downgrade error message (bb#1444) |
... | ... |
@@ -27,6 +27,7 @@ |
27 | 27 |
#include <string.h> |
28 | 28 |
#include <sys/types.h> |
29 | 29 |
#include <unistd.h> |
30 |
+#include <ctype.h> |
|
30 | 31 |
|
31 | 32 |
#include <libmilter/mfapi.h> |
32 | 33 |
|
... | ... |
@@ -49,6 +50,7 @@ uint64_t maxfilesize; |
49 | 49 |
static sfsistat FailAction; |
50 | 50 |
static sfsistat (*CleanAction)(SMFICTX *ctx); |
51 | 51 |
static sfsistat (*InfectedAction)(SMFICTX *ctx); |
52 |
+static char *rejectfmt = NULL; |
|
52 | 53 |
|
53 | 54 |
int addxvirus = 0; |
54 | 55 |
char xvirushdr[255]; |
... | ... |
@@ -57,6 +59,7 @@ char xvirushdr[255]; |
57 | 57 |
|
58 | 58 |
struct CLAMFI { |
59 | 59 |
char buffer[CLAMFIBUFSZ]; |
60 |
+ const char *virusname; |
|
60 | 61 |
int local; |
61 | 62 |
int main; |
62 | 63 |
int alt; |
... | ... |
@@ -236,18 +239,23 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
236 | 236 |
if(addxvirus) add_x_header(ctx, "Clean"); |
237 | 237 |
ret = CleanAction(ctx); |
238 | 238 |
} else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) { |
239 |
- if(addxvirus) { |
|
239 |
+ cf->virusname = NULL; |
|
240 |
+ if(addxvirus || rejectfmt) { |
|
240 | 241 |
char *vir; |
241 | 242 |
|
242 | 243 |
reply[len-7] = '\0'; |
243 | 244 |
vir = strrchr(reply, ' '); |
244 | 245 |
if(vir) { |
245 |
- char msg[255]; |
|
246 |
- |
|
247 | 246 |
vir++; |
248 |
- snprintf(msg, sizeof(msg), "Infected (%s)", vir); |
|
249 |
- msg[sizeof(msg)-1] = '\0'; |
|
250 |
- add_x_header(ctx, msg); |
|
247 |
+ |
|
248 |
+ if(rejectfmt) { |
|
249 |
+ cf->virusname = vir; |
|
250 |
+ } else { |
|
251 |
+ char msg[255]; |
|
252 |
+ snprintf(msg, sizeof(msg), "Infected (%s)", vir); |
|
253 |
+ msg[sizeof(msg)-1] = '\0'; |
|
254 |
+ add_x_header(ctx, msg); |
|
255 |
+ } |
|
251 | 256 |
} |
252 | 257 |
} |
253 | 258 |
ret = InfectedAction(ctx); |
... | ... |
@@ -320,6 +328,18 @@ static sfsistat action_quarantine(SMFICTX *ctx) { |
320 | 320 |
} |
321 | 321 |
return SMFIS_ACCEPT; |
322 | 322 |
} |
323 |
+static sfsistat action_reject_msg(SMFICTX *ctx) { |
|
324 |
+ struct CLAMFI *cf; |
|
325 |
+ char buf[1024]; |
|
326 |
+ |
|
327 |
+ if(!rejectfmt || !(cf = (struct CLAMFI *)smfi_getpriv(ctx))) |
|
328 |
+ return SMFIS_REJECT; |
|
329 |
+ |
|
330 |
+ snprintf(buf, sizeof(buf), rejectfmt, cf->virusname); |
|
331 |
+ buf[sizeof(buf)-1] = '\0'; |
|
332 |
+ smfi_setreply(ctx, "550", NULL, buf); |
|
333 |
+ return SMFIS_REJECT; |
|
334 |
+} |
|
323 | 335 |
|
324 | 336 |
int init_actions(struct optstruct *opts) { |
325 | 337 |
const struct optstruct *opt; |
... | ... |
@@ -336,7 +356,7 @@ int init_actions(struct optstruct *opts) { |
336 | 336 |
FailAction = SMFIS_REJECT; |
337 | 337 |
break; |
338 | 338 |
default: |
339 |
- logg("!Invalid action %s for option OnFail", opt->strarg); |
|
339 |
+ logg("!Invalid action %s for option OnFail\n", opt->strarg); |
|
340 | 340 |
return 1; |
341 | 341 |
} |
342 | 342 |
} else FailAction = SMFIS_TEMPFAIL; |
... | ... |
@@ -359,7 +379,7 @@ int init_actions(struct optstruct *opts) { |
359 | 359 |
CleanAction = action_quarantine; |
360 | 360 |
break; |
361 | 361 |
default: |
362 |
- logg("!Invalid action %s for option OnClean", opt->strarg); |
|
362 |
+ logg("!Invalid action %s for option OnClean\n", opt->strarg); |
|
363 | 363 |
return 1; |
364 | 364 |
} |
365 | 365 |
} else CleanAction = action_accept; |
... | ... |
@@ -372,15 +392,49 @@ int init_actions(struct optstruct *opts) { |
372 | 372 |
case 1: |
373 | 373 |
InfectedAction = action_defer; |
374 | 374 |
break; |
375 |
- case 2: |
|
376 |
- InfectedAction = action_reject; |
|
377 |
- break; |
|
378 | 375 |
case 3: |
379 | 376 |
InfectedAction = action_blackhole; |
380 | 377 |
break; |
381 | 378 |
case 4: |
382 | 379 |
InfectedAction = action_quarantine; |
383 | 380 |
break; |
381 |
+ case 2: |
|
382 |
+ InfectedAction = action_reject_msg; |
|
383 |
+ if((opt = optget(opts, "RejectMsg"))->enabled) { |
|
384 |
+ const char *src = opt->strarg; |
|
385 |
+ char *dst, c; |
|
386 |
+ int gotpctv = 0; |
|
387 |
+ |
|
388 |
+ rejectfmt = dst = malloc(strlen(src) * 4 + 1); |
|
389 |
+ if(!dst) { |
|
390 |
+ logg("!Failed to allocate memory for RejectMsg\n"); |
|
391 |
+ return 1; |
|
392 |
+ } |
|
393 |
+ while ((c = *src++)) { |
|
394 |
+ if(!isprint(c)) { |
|
395 |
+ logg("!RejectMsg contains non printable characters\n"); |
|
396 |
+ free(rejectfmt); |
|
397 |
+ return 1; |
|
398 |
+ } |
|
399 |
+ *dst++ = c; |
|
400 |
+ if(c == '%') { |
|
401 |
+ if(*src == 'v') { |
|
402 |
+ if(gotpctv) { |
|
403 |
+ logg("!%%v may appear at most once in RejectMsg\n"); |
|
404 |
+ free(rejectfmt); |
|
405 |
+ return 1; |
|
406 |
+ } |
|
407 |
+ gotpctv |= 1; |
|
408 |
+ src++; |
|
409 |
+ *dst++ = 's'; |
|
410 |
+ } else { |
|
411 |
+ dst[0] = dst[1] = dst[2] = '%'; |
|
412 |
+ dst += 3; |
|
413 |
+ } |
|
414 |
+ } |
|
415 |
+ } |
|
416 |
+ *dst = '\0'; |
|
417 |
+ } |
|
384 | 418 |
default: |
385 | 419 |
logg("!Invalid action %s for option OnInfected", opt->strarg); |
386 | 420 |
return 1; |
... | ... |
@@ -40,12 +40,18 @@ |
40 | 40 |
#include <netdb.h> |
41 | 41 |
#include <sys/uio.h> |
42 | 42 |
|
43 |
- |
|
44 | 43 |
#include "shared/output.h" |
45 | 44 |
#include "shared/optparser.h" |
46 | 45 |
#include "libclamav/others.h" |
47 | 46 |
#include "netcode.h" |
48 | 47 |
|
48 |
+#ifdef HAVE_STRERROR_R |
|
49 |
+#define strerror_print(msg) \ |
|
50 |
+ strerror_r(errno, er, sizeof(er)); \ |
|
51 |
+ logg(msg": %s\n", er); |
|
52 |
+#else |
|
53 |
+ logg(msg"\n"); |
|
54 |
+#endif |
|
49 | 55 |
|
50 | 56 |
enum { |
51 | 57 |
NON_SMTP, |
... | ... |
@@ -75,21 +81,18 @@ static int nc_socket(struct CP_ENTRY *cpe) { |
75 | 75 |
char er[256]; |
76 | 76 |
|
77 | 77 |
if (s == -1) { |
78 |
- strerror_r(errno, er, sizeof(er)); |
|
79 |
- logg("!Failed to create socket: %s\n", er); |
|
78 |
+ strerror_print("!Failed to create socket"); |
|
80 | 79 |
return -1; |
81 | 80 |
} |
82 | 81 |
flags = fcntl(s, F_GETFL, 0); |
83 | 82 |
if (flags == -1) { |
84 |
- strerror_r(errno, er, sizeof(er)); |
|
85 |
- logg("!fcntl_get failed: %s\n", er); |
|
83 |
+ strerror_print("!fcntl_get failed"); |
|
86 | 84 |
close(s); |
87 | 85 |
return -1; |
88 | 86 |
} |
89 | 87 |
flags |= O_NONBLOCK; |
90 | 88 |
if (fcntl(s, F_SETFL, flags) == -1) { |
91 |
- strerror_r(errno, er, sizeof(er)); |
|
92 |
- logg("!fcntl_set failed: %s\n", er); |
|
89 |
+ strerror_print("!fcntl_set failed"); |
|
93 | 90 |
close(s); |
94 | 91 |
return -1; |
95 | 92 |
} |
... | ... |
@@ -105,8 +108,7 @@ static int nc_connect(int s, struct CP_ENTRY *cpe) { |
105 | 105 |
|
106 | 106 |
if (!res) return 0; |
107 | 107 |
if (errno != EINPROGRESS) { |
108 |
- strerror_r(errno, er, sizeof(er)); |
|
109 |
- logg("*connect failed: %s\n", er); |
|
108 |
+ strerror_print("*connect failed"); |
|
110 | 109 |
close(s); |
111 | 110 |
return -1; |
112 | 111 |
} |
... | ... |
@@ -158,8 +160,7 @@ int nc_send(int s, const void *buff, size_t len) { |
158 | 158 |
continue; |
159 | 159 |
} |
160 | 160 |
if(errno != EAGAIN && errno != EWOULDBLOCK) { |
161 |
- strerror_r(errno, er, sizeof(er)); |
|
162 |
- logg("!send failed: %s\n", er); |
|
161 |
+ strerror_print("!send failed"); |
|
163 | 162 |
close(s); |
164 | 163 |
return 1; |
165 | 164 |
} |
... | ... |
@@ -219,8 +220,7 @@ int nc_sendmsg(int s, int fd) { |
219 | 219 |
|
220 | 220 |
if((ret = sendmsg(s, &msg, 0)) == -1) { |
221 | 221 |
char er[256]; |
222 |
- strerror_r(errno, er, sizeof(er)); |
|
223 |
- logg("!clamfi_eom: FD send failed (%s)\n", er); |
|
222 |
+ strerror_print("!clamfi_eom: FD send failed"); |
|
224 | 223 |
close(s); |
225 | 224 |
} |
226 | 225 |
return ret; |
... | ... |
@@ -257,8 +257,7 @@ char *nc_recv(int s) { |
257 | 257 |
res = recv(s, &buf[len], sizeof(buf) - len, 0); |
258 | 258 |
if(res==-1) { |
259 | 259 |
char er[256]; |
260 |
- strerror_r(errno, er, sizeof(er)); |
|
261 |
- logg("!recv failed after successful select: %s\n", er); |
|
260 |
+ strerror_print("!recv failed after successful select"); |
|
262 | 261 |
close(s); |
263 | 262 |
return NULL; |
264 | 263 |
} |
... | ... |
@@ -145,6 +145,12 @@ Example |
145 | 145 |
# Default Defer |
146 | 146 |
#OnFail Defer |
147 | 147 |
|
148 |
+# This option allows to set a specific rejection reason for infected messages |
|
149 |
+# and it's therefore only useful together with "OnInfected Reject" |
|
150 |
+# The string "%v", if present, will be replaced with the virus name. |
|
151 |
+# Default: MTA specific |
|
152 |
+#RejectMsg |
|
153 |
+ |
|
148 | 154 |
# If this option is set to Yes, an "X-Virus-Scanned" and an "X-Virus-Status" |
149 | 155 |
# headers will be attached to each processed message, possibly replacing |
150 | 156 |
# existing headers. |
... | ... |
@@ -373,6 +373,8 @@ const struct clam_option clam_options[] = { |
373 | 373 |
|
374 | 374 |
{ "OnFail", NULL, 0, TYPE_STRING, "^(Accept|Reject|Defer)$", -1, "Defer", 0, OPT_MILTER, "Action to be performed on error conditions (this includes failure to\nallocate data structures, no scanners available, network timeouts, unknown\nscanner replies and the like).\nThe following actions are available:\nAccept: the message is accepted for delievery;\nReject: immediately refuse delievery (a 5xx error is returned to the peer);\nDefer: return a temporary failure message (4xx) to the peer.", "Defer" }, |
375 | 375 |
|
376 |
+ { "RejectMsg", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option allows to set a specific rejection reason for infected messages\nand it's therefore only useful together with \"OnInfected Reject\"\nThe string \"%v\", if present, will be replaced with the virus name.", "MTA specific" }, |
|
377 |
+ |
|
376 | 378 |
{ "AddHeader", NULL, 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_MILTER, "If this option is set to Yes, an \"X-Virus-Scanned\" and an \"X-Virus-Status\"\nheaders will be attached to each processed message, possibly replacing\nexisting headers.", "Yes" }, |
377 | 379 |
|
378 | 380 |
{ "Chroot", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "Chroot to the specified directory.\nChrooting is performed just after reading the config file and before\ndropping privileges.", "/newroot" }, |