git-svn: trunk@4527
aCaB authored on 2008/12/05 01:26:52... | ... |
@@ -47,7 +47,7 @@ |
47 | 47 |
struct smfiDesc descr = { |
48 | 48 |
"ClamAV", /* filter name */ |
49 | 49 |
SMFI_VERSION, /* milter version */ |
50 |
- SMFIF_ADDHDRS|SMFIF_QUARANTINE, /* flags */ |
|
50 |
+ SMFIF_CHGHDRS|SMFIF_QUARANTINE, /* flags */ |
|
51 | 51 |
clamfi_connect, /* connection info filter */ |
52 | 52 |
NULL, /* SMTP HELO command filter */ |
53 | 53 |
NULL, /* envelope sender filter */ |
... | ... |
@@ -203,11 +203,27 @@ int main(int argc, char **argv) { |
203 | 203 |
return 1; |
204 | 204 |
} |
205 | 205 |
|
206 |
+ |
|
206 | 207 |
/* FIXME: find a place for these: |
207 | 208 |
* maxthreads = cfgopt(copt, "MaxThreads")->numarg; |
208 | 209 |
* logclean = cfgopt(copt, "LogClean")->numarg; |
209 | 210 |
*/ |
210 | 211 |
|
212 |
+ if(cfgopt(copt, "AddHeader")->enabled) { |
|
213 |
+ char myname[255]; |
|
214 |
+ |
|
215 |
+ if(!gethostname(myname, sizeof(myname))) { |
|
216 |
+ char mydomain[255]; |
|
217 |
+ |
|
218 |
+ myname[sizeof(myname)-1] = '\0'; |
|
219 |
+ snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname); |
|
220 |
+ xvirushdr[sizeof(xvirushdr)-1] = '\0'; |
|
221 |
+ } else { |
|
222 |
+ snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version()); |
|
223 |
+ xvirushdr[sizeof(xvirushdr)-1] = '\0'; |
|
224 |
+ } |
|
225 |
+ addxvirus = 1; |
|
226 |
+ } |
|
211 | 227 |
|
212 | 228 |
umask(0007); |
213 | 229 |
if(!(my_socket = cfgopt(copt, "MilterSocket")->strarg)) { |
... | ... |
@@ -22,6 +22,7 @@ |
22 | 22 |
#include "clamav-config.h" |
23 | 23 |
#endif |
24 | 24 |
|
25 |
+#include <stdio.h> |
|
25 | 26 |
#include <stdlib.h> |
26 | 27 |
#include <string.h> |
27 | 28 |
#include <sys/types.h> |
... | ... |
@@ -35,12 +36,21 @@ |
35 | 35 |
#include "connpool.h" |
36 | 36 |
#include "netcode.h" |
37 | 37 |
|
38 |
+#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) |
|
39 |
+#define _UNUSED_ __attribute__ ((__unused__)) |
|
40 |
+#else |
|
41 |
+#define _UNUSED_ |
|
42 |
+#endif |
|
43 |
+ |
|
38 | 44 |
uint64_t maxfilesize; |
39 | 45 |
|
40 | 46 |
static sfsistat FailAction; |
41 | 47 |
static sfsistat (*CleanAction)(SMFICTX *ctx); |
42 | 48 |
static sfsistat (*InfectedAction)(SMFICTX *ctx); |
43 | 49 |
|
50 |
+int addxvirus = 0; |
|
51 |
+char xvirushdr[255]; |
|
52 |
+ |
|
44 | 53 |
#define CLAMFIBUFSZ 1424 |
45 | 54 |
|
46 | 55 |
struct CLAMFI { |
... | ... |
@@ -53,9 +63,15 @@ struct CLAMFI { |
53 | 53 |
}; |
54 | 54 |
|
55 | 55 |
|
56 |
+void add_x_header(SMFICTX *ctx, char *st) { |
|
57 |
+ smfi_chgheader(ctx, "X-Virus-Scanned", 1, xvirushdr); |
|
58 |
+ smfi_chgheader(ctx, "X-Virus-Status", 1, st); |
|
59 |
+} |
|
60 |
+ |
|
61 |
+ |
|
56 | 62 |
static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, SMFICTX *ctx) { |
57 | 63 |
if(cf->totsz >= maxfilesize) |
58 |
- return SMFIS_CONTINUE; /* FIXME: SMFIS_SKIP needs negotiation (only for _body() */ |
|
64 |
+ return SMFIS_CONTINUE; |
|
59 | 65 |
|
60 | 66 |
if(cf->totsz + len > maxfilesize) |
61 | 67 |
len = maxfilesize - cf->totsz; |
... | ... |
@@ -126,7 +142,9 @@ sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv) { |
126 | 126 |
} |
127 | 127 |
if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) |
128 | 128 |
return ret; |
129 |
+ |
|
129 | 130 |
} |
131 |
+ |
|
130 | 132 |
if((ret = sendchunk(cf, (unsigned char *)headerf, strlen(headerf), ctx)) != SMFIS_CONTINUE) |
131 | 133 |
return ret; |
132 | 134 |
if((ret = sendchunk(cf, (unsigned char *)": ", 2, ctx)) != SMFIS_CONTINUE) |
... | ... |
@@ -199,11 +217,29 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
199 | 199 |
free(cf); |
200 | 200 |
|
201 | 201 |
len = strlen(reply); |
202 |
- if(len>5 && !strcmp(reply + len - 5, ": OK\n")) |
|
202 |
+ if(len>5 && !strcmp(reply + len - 5, ": OK\n")) { |
|
203 |
+ if(addxvirus) add_x_header(ctx, "Clean"); |
|
203 | 204 |
ret = CleanAction(ctx); |
204 |
- else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) |
|
205 |
+ } else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) { |
|
206 |
+ logg("^%s\n", reply); |
|
207 |
+ if(addxvirus) { |
|
208 |
+ char *vir; |
|
209 |
+ |
|
210 |
+ reply[len-7] = '\0'; |
|
211 |
+ vir = strrchr(reply, ' '); |
|
212 |
+ logg("^%s\n", reply); |
|
213 |
+ if(vir) { |
|
214 |
+ char msg[255]; |
|
215 |
+ |
|
216 |
+ vir++; |
|
217 |
+ logg("^v: >%s<\n", vir); |
|
218 |
+ snprintf(msg, sizeof(msg), "Infected (%s)", vir); |
|
219 |
+ msg[sizeof(msg)-1] = '\0'; |
|
220 |
+ add_x_header(ctx, msg); |
|
221 |
+ } |
|
222 |
+ } |
|
205 | 223 |
ret = InfectedAction(ctx); |
206 |
- else { |
|
224 |
+ } else { |
|
207 | 225 |
logg("!Unknown reply from clamd\n"); |
208 | 226 |
ret = FailAction; |
209 | 227 |
} |
... | ... |
@@ -213,9 +249,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
213 | 213 |
} |
214 | 214 |
|
215 | 215 |
|
216 |
-sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { |
|
217 |
- struct CLAMFI *cf; |
|
218 |
- |
|
216 |
+sfsistat clamfi_connect(_UNUSED_ SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { |
|
219 | 217 |
while(1) { |
220 | 218 |
/* Postfix doesn't seem to honor passing a NULL hostaddr and hostname |
221 | 219 |
set to "localhost" for non-smtp messages (they still appear as SMTP |
... | ... |
@@ -255,16 +289,16 @@ static int parse_action(char *action) { |
255 | 255 |
} |
256 | 256 |
|
257 | 257 |
|
258 |
-static sfsistat action_accept(SMFICTX *ctx) { |
|
258 |
+static sfsistat action_accept(_UNUSED_ SMFICTX *ctx) { |
|
259 | 259 |
return SMFIS_ACCEPT; |
260 | 260 |
} |
261 |
-static sfsistat action_defer(SMFICTX *ctx) { |
|
261 |
+static sfsistat action_defer(_UNUSED_ SMFICTX *ctx) { |
|
262 | 262 |
return SMFIS_TEMPFAIL; |
263 | 263 |
} |
264 |
-static sfsistat action_reject(SMFICTX *ctx) { |
|
264 |
+static sfsistat action_reject(_UNUSED_ SMFICTX *ctx) { |
|
265 | 265 |
return SMFIS_REJECT; |
266 | 266 |
} |
267 |
-static sfsistat action_blackhole(SMFICTX *ctx) { |
|
267 |
+static sfsistat action_blackhole(_UNUSED_ SMFICTX *ctx) { |
|
268 | 268 |
return SMFIS_DISCARD; |
269 | 269 |
} |
270 | 270 |
static sfsistat action_quarantine(SMFICTX *ctx) { |
... | ... |
@@ -4,7 +4,10 @@ |
4 | 4 |
#include "shared/cfgparser.h" |
5 | 5 |
#include <libmilter/mfapi.h> |
6 | 6 |
|
7 |
-uint64_t maxfilesize; |
|
7 |
+extern uint64_t maxfilesize; |
|
8 |
+extern int addxvirus; |
|
9 |
+extern char xvirushdr[255]; |
|
10 |
+ |
|
8 | 11 |
|
9 | 12 |
sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len); |
10 | 13 |
sfsistat clamfi_eom(SMFICTX *ctx); |
... | ... |
@@ -107,6 +107,8 @@ Example |
107 | 107 |
# Like accept but the message is sent to oblivion |
108 | 108 |
# - Quarantine (not available for OnFail) |
109 | 109 |
# Like accept but message is quarantined instead of being deilievered |
110 |
+# In sendmail the quarantine queue can be examined via mailq -qQ |
|
111 |
+# For Postfix this causes the message to be accepted but placed on hold |
|
110 | 112 |
# |
111 | 113 |
# Action to be performed on clean messages (mostly useful for testing) |
112 | 114 |
# Default Accept |
... | ... |
@@ -122,6 +124,13 @@ Example |
122 | 122 |
# Default Defer |
123 | 123 |
#OnFail Defer |
124 | 124 |
|
125 |
+# If this option is set to Yes, an "X-Virus-Scanned" and an "X-Virus-Status" |
|
126 |
+# headers will be attached to each processed message, possibly replacing |
|
127 |
+# existing headers. |
|
128 |
+# Default: No |
|
129 |
+#AddHeader Yes |
|
130 |
+ |
|
131 |
+ |
|
125 | 132 |
## |
126 | 133 |
## Logging options |
127 | 134 |
## |
... | ... |
@@ -250,9 +259,9 @@ Example |
250 | 250 |
#--server |
251 | 251 |
|
252 | 252 |
#Reworked |
253 |
-#-A --advisory |
|
254 |
-#-d --dont-scan-on-error |
|
255 |
-#-n --noxheader |
|
256 |
-#-N --noreject |
|
257 |
-#-Q --quarantine |
|
258 |
-#-U, --quarantine-dir |
|
253 |
+##-A --advisory |
|
254 |
+##-d --dont-scan-on-error |
|
255 |
+##-n --noxheader |
|
256 |
+##-N --noreject |
|
257 |
+##-Q --quarantine |
|
258 |
+##-U, --quarantine-dir |
... | ... |
@@ -142,14 +142,14 @@ struct cfgoption cfg_options[] = { |
142 | 142 |
{"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_DEPRECATED}, |
143 | 143 |
{"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_DEPRECATED }, |
144 | 144 |
|
145 |
- |
|
146 | 145 |
/* Milter specific options */ |
147 | 146 |
{"ClamdSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER}, |
148 | 147 |
{"MilterSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER}, |
149 | 148 |
{"LocalNet", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER}, |
150 |
- {"ActionClean", OPT_QUOTESTR, -1, "Accept", 1, OPT_MILTER}, |
|
151 |
- {"ActionInfected", OPT_QUOTESTR, -1, "Quarantine", 1, OPT_MILTER}, |
|
152 |
- {"ActionFail", OPT_QUOTESTR, -1, "Defer", 1, OPT_MILTER}, |
|
149 |
+ {"OnClean", OPT_QUOTESTR, -1, "Accept", 0, OPT_MILTER}, |
|
150 |
+ {"OnInfected", OPT_QUOTESTR, -1, "Quarantine", 0, OPT_MILTER}, |
|
151 |
+ {"OnFail", OPT_QUOTESTR, -1, "Defer", 0, OPT_MILTER}, |
|
152 |
+ {"AddHeader", OPT_BOOL, 0, NULL, 0, OPT_MILTER}, |
|
153 | 153 |
|
154 | 154 |
/* Deprecated milter options */ |
155 | 155 |
{"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_MILTER | OPT_DEPRECATED}, |