Browse code

Implenet actions

git-svn: trunk@4526

aCaB authored on 2008/12/05 01:26:47
Showing 5 changed files
... ...
@@ -47,7 +47,7 @@
47 47
 struct smfiDesc descr = {
48 48
     "ClamAV", 		/* filter name */
49 49
     SMFI_VERSION,	/* milter version */
50
-    SMFIF_ADDHDRS|SMFIF_ADDRCPT, /* flags */
50
+    SMFIF_ADDHDRS|SMFIF_QUARANTINE, /* flags */
51 51
     clamfi_connect,	/* connection info filter */
52 52
     NULL,		/* SMTP HELO command filter */
53 53
     NULL,		/* envelope sender filter */
... ...
@@ -197,12 +197,18 @@ int main(int argc, char **argv) {
197 197
     }
198 198
 #endif
199 199
 
200
-    if(localnets_init(copt)) {
200
+    if(localnets_init(copt) || init_actions(copt)) {
201 201
 	logg_close();
202 202
 	freecfg(copt);
203 203
 	return 1;
204 204
     }
205 205
 
206
+    /* FIXME: find a place for these:
207
+     * maxthreads = cfgopt(copt, "MaxThreads")->numarg;
208
+     * logclean = cfgopt(copt, "LogClean")->numarg;
209
+     */
210
+
211
+    
206 212
     umask(0007);
207 213
     if(!(my_socket = cfgopt(copt, "MilterSocket")->strarg)) {
208 214
 	logg("!Please configure the MilterSocket directive\n");
... ...
@@ -29,6 +29,7 @@
29 29
 
30 30
 #include <libmilter/mfapi.h>
31 31
 
32
+#include "shared/cfgparser.h"
32 33
 #include "shared/output.h"
33 34
 
34 35
 #include "connpool.h"
... ...
@@ -36,6 +37,10 @@
36 36
 
37 37
 uint64_t maxfilesize;
38 38
 
39
+static sfsistat FailAction;
40
+static sfsistat (*CleanAction)(SMFICTX *ctx);
41
+static sfsistat (*InfectedAction)(SMFICTX *ctx);
42
+
39 43
 #define CLAMFIBUFSZ 1424
40 44
 
41 45
 struct CLAMFI {
... ...
@@ -65,7 +70,7 @@ static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, S
65 65
 		close(cf->alt);
66 66
 		smfi_setpriv(ctx, NULL);
67 67
 		free(cf);
68
-		return SMFIS_TEMPFAIL;
68
+		return FailAction;
69 69
 	    }
70 70
 	    len -= n;
71 71
 	    bodyp += n;
... ...
@@ -92,7 +97,7 @@ static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, S
92 92
 	    close(cf->main);
93 93
 	    smfi_setpriv(ctx, NULL);
94 94
 	    free(cf);
95
-	    return SMFIS_TEMPFAIL;
95
+	    return FailAction;
96 96
 	}
97 97
     }
98 98
     cf->totsz += len;
... ...
@@ -104,14 +109,20 @@ sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv) {
104 104
     struct CLAMFI *cf;
105 105
     sfsistat ret;
106 106
 
107
-    if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx)))
108
-	return SMFIS_CONTINUE; /* whatever */
107
+    if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) {
108
+	if(!(cf = (struct CLAMFI *)malloc(sizeof(*cf)))) {
109
+	    logg("!Failed to allocate CLAMFI struct\n");
110
+	    return FailAction;
111
+	}
112
+	cf->totsz = 0;
113
+	cf->bufsz = 0;
114
+	smfi_setpriv(ctx, (void *)cf);
109 115
 
110
-    if(!cf->totsz) {
111 116
 	if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) {
112 117
 	    logg("!Failed to initiate streaming/fdpassing\n");
118
+	    smfi_setpriv(ctx, NULL);
113 119
 	    free(cf);
114
-	    return SMFIS_TEMPFAIL;
120
+	    return FailAction;
115 121
 	}
116 122
 	if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE)
117 123
 	    return ret;
... ...
@@ -149,7 +160,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
149 149
 	    close(cf->alt);
150 150
 	    smfi_setpriv(ctx, NULL);
151 151
 	    free(cf);
152
-	    return SMFIS_TEMPFAIL;
152
+	    return FailAction;
153 153
 	}
154 154
 
155 155
 	lseek(cf->alt, 0, SEEK_SET);
... ...
@@ -159,7 +170,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
159 159
 	    close(cf->alt);
160 160
 	    smfi_setpriv(ctx, NULL);
161 161
 	    free(cf);
162
-	    return SMFIS_TEMPFAIL;
162
+	    return FailAction;
163 163
 	}
164 164
     } else {
165 165
 	if(cf->bufsz && nc_send(cf->alt, cf->buffer, cf->bufsz)) {
... ...
@@ -167,7 +178,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
167 167
 	    close(cf->main);
168 168
 	    smfi_setpriv(ctx, NULL);
169 169
 	    free(cf);
170
-	    return SMFIS_TEMPFAIL;
170
+	    return FailAction;
171 171
 	}
172 172
 	close(cf->alt);
173 173
     }
... ...
@@ -181,7 +192,7 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
181 181
 	logg("!No reply from clamd\n");
182 182
 	smfi_setpriv(ctx, NULL);
183 183
 	free(cf);
184
-	return SMFIS_TEMPFAIL;
184
+	return FailAction;
185 185
     }
186 186
     close(cf->main);
187 187
     smfi_setpriv(ctx, NULL);
... ...
@@ -189,12 +200,12 @@ sfsistat clamfi_eom(SMFICTX *ctx) {
189 189
 
190 190
     len = strlen(reply);
191 191
     if(len>5 && !strcmp(reply + len - 5, ": OK\n"))
192
-	ret = SMFIS_ACCEPT;
192
+	ret = CleanAction(ctx);
193 193
     else if (len>7 && !strcmp(reply + len - 7, " FOUND\n"))
194
-	ret = SMFIS_REJECT;
194
+	ret = InfectedAction(ctx);
195 195
     else {
196 196
 	logg("!Unknown reply from clamd\n");
197
-	ret = SMFIS_TEMPFAIL;
197
+	ret = FailAction;
198 198
     }
199 199
 
200 200
     free(reply);
... ...
@@ -224,15 +235,112 @@ sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) {
224 224
 	}
225 225
 	break;
226 226
     }
227
+    return SMFIS_CONTINUE;
228
+}
227 229
 
228
-    if(!(cf = (struct CLAMFI *)malloc(sizeof(*cf)))) {
229
-	logg("!Failed to allocate CLAMFI struct\n");
230
+
231
+static int parse_action(char *action) {
232
+    if(!strcasecmp(action, "Accept"))
233
+	return 0;
234
+    if(!strcasecmp(action, "Defer"))
235
+	return 1;
236
+    if(!strcasecmp(action, "Reject"))
237
+	return 2;
238
+    if(!strcasecmp(action, "Blackhole"))
239
+	return 3;
240
+    if(!strcasecmp(action, "Quarantine"))
241
+	return 4;
242
+    logg("!Unknown action %s\n", action);
243
+    return -1;
244
+}
245
+
246
+
247
+static sfsistat action_accept(SMFICTX *ctx) {
248
+    return SMFIS_ACCEPT;
249
+}
250
+static sfsistat action_defer(SMFICTX *ctx) {
251
+    return SMFIS_TEMPFAIL;
252
+}
253
+static sfsistat action_reject(SMFICTX *ctx) {
254
+    return SMFIS_REJECT;
255
+}
256
+static sfsistat action_blackhole(SMFICTX *ctx)  {
257
+    return SMFIS_DISCARD;
258
+}
259
+static sfsistat action_quarantine(SMFICTX *ctx) {
260
+    if(smfi_quarantine(ctx, "quarantined by clamav-milter") != MI_SUCCESS) {
261
+	logg("^Failed to quarantine message\n");
230 262
 	return SMFIS_TEMPFAIL;
231 263
     }
232
-    cf->totsz = 0;
233
-    cf->bufsz = 0;
234
-    smfi_setpriv(ctx, (void *)cf);
235
-    return SMFIS_CONTINUE;
264
+    return SMFIS_ACCEPT;
265
+}
266
+
267
+int init_actions(struct cfgstruct *copt) {
268
+    const struct cfgstruct *cpt;
269
+
270
+    if((cpt = cfgopt(copt, "OnFail"))->enabled) {
271
+	switch(parse_action(cpt->strarg)) {
272
+	case 0:
273
+	    FailAction = SMFIS_ACCEPT;
274
+	    break;
275
+	case 1:
276
+	    FailAction = SMFIS_TEMPFAIL;
277
+	    break;
278
+	case 2:
279
+	    FailAction = SMFIS_REJECT;
280
+	    break;
281
+	default:
282
+	    logg("!Invalid action %s for option OnFail", cpt->strarg);
283
+	    return 1;
284
+	}
285
+    } else FailAction = SMFIS_TEMPFAIL;
286
+
287
+    if((cpt = cfgopt(copt, "OnClean"))->enabled) {
288
+	switch(parse_action(cpt->strarg)) {
289
+	case 0:
290
+	    CleanAction = action_accept;
291
+	    break;
292
+	case 1:
293
+	    CleanAction = action_defer;
294
+	    break;
295
+	case 2:
296
+	    CleanAction = action_reject;
297
+	    break;
298
+	case 3:
299
+	    CleanAction = action_blackhole;
300
+	    break;
301
+	case 4:
302
+	    CleanAction = action_quarantine;
303
+	    break;
304
+	default:
305
+	    logg("!Invalid action %s for option OnClean", cpt->strarg);
306
+	    return 1;
307
+	}
308
+    } else CleanAction = action_accept;
309
+
310
+    if((cpt = cfgopt(copt, "OnInfected"))->enabled) {
311
+	switch(parse_action(cpt->strarg)) {
312
+	case 0:
313
+	    InfectedAction = action_accept;
314
+	    break;
315
+	case 1:
316
+	    InfectedAction = action_defer;
317
+	    break;
318
+	case 2:
319
+	    InfectedAction = action_reject;
320
+	    break;
321
+	case 3:
322
+	    InfectedAction = action_blackhole;
323
+	    break;
324
+	case 4:
325
+	    InfectedAction = action_quarantine;
326
+	    break;
327
+	default:
328
+	    logg("!Invalid action %s for option OnInfected", cpt->strarg);
329
+	    return 1;
330
+	}
331
+    } else InfectedAction = action_quarantine;
332
+    return 0;
236 333
 }
237 334
 
238 335
 /*
... ...
@@ -1,6 +1,7 @@
1 1
 #ifndef _CLAMFI_H
2 2
 #define _CLAMFI_H
3 3
 
4
+#include "shared/cfgparser.h"
4 5
 #include <libmilter/mfapi.h>
5 6
 
6 7
 uint64_t maxfilesize;
... ...
@@ -9,4 +10,6 @@ sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len);
9 9
 sfsistat clamfi_eom(SMFICTX *ctx);
10 10
 sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv);
11 11
 sfsistat clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr);
12
+int init_actions(struct cfgstruct *copt);
13
+
12 14
 #endif
... ...
@@ -91,6 +91,38 @@ Example
91 91
 
92 92
 
93 93
 ##
94
+## Actions
95
+##
96
+
97
+# The following group of options controls the delievery process under
98
+# different circumstances.
99
+# The following actions are available:
100
+# - Accept
101
+#   The message is accepted for delievery
102
+# - Reject
103
+#   Immediately refuse delievery (a 5xx error is returned to the peer)
104
+# - Defer
105
+#   Return a temporary failure message (4xx) to the peer
106
+# - Blackhole (not available for OnFail)
107
+#   Like accept but the message is sent to oblivion
108
+# - Quarantine (not available for OnFail)
109
+#   Like accept but message is quarantined instead of being deilievered
110
+# 
111
+# Action to be performed on clean messages (mostly useful for testing)
112
+# Default Accept
113
+#OnClean Accept
114
+
115
+# Action to be performed on infected messages
116
+# Default: Quarantine
117
+#OnInfected Quarantine
118
+
119
+# Action to be performed on error conditions (this includes failure to
120
+# allocate data structures, no scanners available, network timeouts,
121
+# unknown scanner replies and the like)
122
+# Default Defer
123
+#OnFail Defer
124
+
125
+##
94 126
 ## Logging options
95 127
 ##
96 128
 
... ...
@@ -183,7 +215,7 @@ Example
183 183
 #-C --chroot
184 184
 #-D --debug
185 185
 #-i --pidfile
186
-#-I --ignore
186
+##-I --ignore
187 187
 #-W --whitelist-file
188 188
 
189 189
 #Deprecated switches
... ...
@@ -147,6 +147,9 @@ struct cfgoption cfg_options[] = {
147 147
     {"ClamdSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
148 148
     {"MilterSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
149 149
     {"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},
150 153
 
151 154
     /* Deprecated milter options */
152 155
     {"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_MILTER | OPT_DEPRECATED},