Subversion Repositories vsftpd-clamav

Rev

Rev 1 | Rev 3 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 madcat 1
Add support for scanning uploaded files with clamav. Not all features are
2
implemented (ex. file inclusion/exclusion for scanning). Every uploaded file is
3
saved in random named file, and moved to destination file after scanning. Side
4
effects: when uploaded *new* file was infected, 0-size file left.
5
 
6
Written by Marek Marczykowski <m.marczykowski@fiok.pl>
7
 
8
Downloaded from: http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/packages/vsftpd/vsftpd-clamav.patch
9
 
10
diff -Naru vsftpd-2.2.2.orig/Makefile vsftpd-2.2.2/Makefile
11
--- vsftpd-2.2.2.orig/Makefile  2009-05-22 21:44:52.000000000 +0200
12
+++ vsftpd-2.2.2/Makefile       2010-04-29 19:46:54.435448038 +0200
13
@@ -14,7 +14,7 @@
14
     banner.o filestr.o parseconf.o secutil.o \
15
     ascii.o oneprocess.o twoprocess.o privops.o standalone.o hash.o \
16
     tcpwrap.o ipaddrparse.o access.o features.o readwrite.o opts.o \
17
-    ssl.o sslslave.o ptracesandbox.o ftppolicy.o sysutil.o sysdeputil.o
18
+    ssl.o sslslave.o ptracesandbox.o ftppolicy.o sysutil.o sysdeputil.o clamav.o
19
 
20
 
21
 .c.o:
22
diff -Naru vsftpd-2.2.2.orig/clamav.c vsftpd-2.2.2/clamav.c
23
--- vsftpd-2.2.2.orig/clamav.c  1970-01-01 01:00:00.000000000 +0100
24
+++ vsftpd-2.2.2/clamav.c       2010-04-29 19:46:54.435448038 +0200
25
@@ -0,0 +1,221 @@
26
+#include <sys/types.h>
27
+#include <regex.h>
28
+#include <sys/socket.h>
29
+#include <linux/un.h>
30
+#include <arpa/inet.h>
31
+#include <netdb.h>
32
+#include <sys/socket.h>
33
+#include <stdio.h>
34
+#include "clamav.h"
35
+#include "tunables.h"
36
+#include "utility.h"
37
+#include "sysutil.h"
38
+#include "logging.h"
39
+#include "sysstr.h"
40
+
41
+regex_t av_include_files_regex, av_exclude_files_regex;
42
+
43
+int av_init() {
44
+       int ret;
45
+
46
+       if (tunable_av_enable) {
47
+               if (tunable_av_include_files) {
48
+                       if ((ret=regcomp(&av_include_files_regex, tunable_av_include_files, REG_NOSUB)) != 0)
49
+                               die("regex compilation failed for AvIncludeFiles");
50
+               }
51
+               if (tunable_av_exclude_files) {
52
+                       if ((ret=regcomp(&av_exclude_files_regex, tunable_av_exclude_files, REG_NOSUB)) != 0)
53
+                               die("regex compilation failed for AvExcludeFiles");
54
+               }
55
+       }
56
+       return 0;
57
+}
58
+
59
+int av_will_scan(const char *filename) {
60
+       if (!tunable_av_enable)
61
+               return 0;
62
+       if (tunable_av_include_files && (regexec(&av_include_files_regex, filename, 0, 0, 0)!=0))
63
+               return 0;
64
+       if (tunable_av_exclude_files && (regexec(&av_exclude_files_regex, filename, 0, 0, 0)==0))
65
+               return 0;
66
+       return 1;
67
+}
68
+
69
+int av_init_scanner (struct vsf_session* p_sess) {
70
+       struct mystr debug_str = INIT_MYSTR;
71
+
72
+       if (p_sess->clamd_sock < 0) {
73
+               
74
+               /* connect to clamd through local unix socket */
75
+               if (tunable_av_clamd_socket) {
76
+                       struct sockaddr_un server_local;
77
+
78
+                       vsf_sysutil_memclr((char*)&server_local, sizeof(server_local));
79
+
80
+                       server_local.sun_family = AF_UNIX;
81
+                       vsf_sysutil_strcpy(server_local.sun_path, tunable_av_clamd_socket, sizeof(server_local.sun_path));
82
+                       if ((p_sess->clamd_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
83
+                               str_alloc_text(&debug_str, "av: error opening unix socket");
84
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
85
+                               p_sess->clamd_sock = -2;
86
+                               return 0;
87
+                       }
88
+
89
+                       if (connect(p_sess->clamd_sock, (struct sockaddr *)&server_local, sizeof(struct sockaddr_un)) < 0) {
90
+                               str_alloc_text(&debug_str, "av: error connecting to clamd");
91
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
92
+                               p_sess->clamd_sock = -2;
93
+                               return 0;
94
+                       }
95
+
96
+               } else if (tunable_av_clamd_host) {
97
+                       struct sockaddr_in server_inet;
98
+                       struct hostent *he;
99
+
100
+                       vsf_sysutil_memclr((char*)&server_inet, sizeof(server_inet));
101
+
102
+                       /* Remote Socket */
103
+                       server_inet.sin_family = AF_INET;
104
+                       server_inet.sin_port = htons(tunable_av_clamd_port);
105
+
106
+                       if ((p_sess->clamd_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
107
+                               str_alloc_text(&debug_str, "av: error opening inet socket");
108
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
109
+                               p_sess->clamd_sock = -2;
110
+                               return 0;
111
+                       }
112
+
113
+                       if ((he = gethostbyname(tunable_av_clamd_host)) == 0) {
114
+                               str_alloc_text(&debug_str, "av: unable to locate clamd host");
115
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
116
+                               vsf_sysutil_close_failok(p_sess->clamd_sock);
117
+                               p_sess->clamd_sock = -2;
118
+                               return 0;
119
+                       }
120
+
121
+                       server_inet.sin_addr = *(struct in_addr *) he->h_addr_list[0];
122
+
123
+                       if (connect(p_sess->clamd_sock, (struct sockaddr *)&server_inet, sizeof(struct sockaddr_in)) < 0) {
124
+                               str_alloc_text(&debug_str, "av: error connecting to clamd host");
125
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
126
+                               vsf_sysutil_close_failok(p_sess->clamd_sock);
127
+                               p_sess->clamd_sock = -2;
128
+                               return 0;
129
+                       }
130
+               }
131
+
132
+               if (vsf_sysutil_write(p_sess->clamd_sock, "nIDSESSION\n", 11) <= 0) {
133
+                       str_alloc_text(&debug_str, "av: error starting clamd session");
134
+                       vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
135
+                       vsf_sysutil_close_failok(p_sess->clamd_sock);
136
+                       p_sess->clamd_sock = -2;
137
+                       return 0;
138
+               }
139
+       }
140
+
141
+       return 1;
142
+}
143
+
144
+int av_scan_file(struct vsf_session* p_sess, struct mystr *filename, struct mystr *virname) {
145
+       struct mystr cwd = INIT_MYSTR;
146
+       struct mystr clamcmd = INIT_MYSTR;
147
+       struct mystr response = INIT_MYSTR;
148
+       char recv_buff[4096];
149
+       int recv_count;
150
+       struct str_locate_result locate_res;
151
+       struct mystr debug_str = INIT_MYSTR;
152
+       int retry = 0;
153
+
154
+init_scan:
155
+       if (av_init_scanner(p_sess)) {
156
+
157
+               str_alloc_text(&clamcmd, "nSCAN ");
158
+               if (!str_isempty(&p_sess->chroot_str)) {
159
+                       str_append_str(&clamcmd, &p_sess->chroot_str);
160
+               }
161
+               if (str_get_char_at(filename, 0) != '/') {
162
+                       str_getcwd(&cwd);
163
+                       str_append_str(&clamcmd, &cwd);
164
+               }
165
+               if (str_get_char_at(&clamcmd, str_getlen(&clamcmd) - 1) != '/') { 
166
+                       str_append_char(&clamcmd, '/');
167
+               }
168
+               str_append_str(&clamcmd, filename);
169
+               str_append_char(&clamcmd, '\n');
170
+
171
+//             sprintf(recv_buff, "sockfd: %d", p_sess->clamd_sock);
172
+//             str_alloc_text(&debug_str, recv_buff);
173
+//             vsf_log_line(p_sess, kVSFLogEntryDebug, &p_sess->chroot_str);
174
+//             vsf_log_line(p_sess, kVSFLogEntryDebug, &clamcmd);
175
+
176
+               if (vsf_sysutil_write(p_sess->clamd_sock, str_getbuf(&clamcmd), str_getlen(&clamcmd)) <= 0) {
177
+                       str_alloc_text(&debug_str, "av: failed to scan file");
178
+                       vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
179
+                       vsf_sysutil_close_failok(p_sess->clamd_sock);
180
+                       p_sess->clamd_sock = -2;
181
+                       return 2;
182
+               }
183
+
184
+               str_free(&clamcmd);
185
+
186
+               /* receive and interpret answer */
187
+               while ((recv_count=vsf_sysutil_read(p_sess->clamd_sock, recv_buff, 4095)) > 0) {
188
+                       recv_buff[recv_count]=0;
189
+                       str_append_text(&response, recv_buff);
190
+                       if (recv_buff[recv_count-1] == '\n')
191
+                               break;
192
+               }
193
+               if (recv_count < 0 || str_getlen(&response) == 0) {
194
+                       if (!retry) {
195
+                               retry = 1;
196
+                               vsf_sysutil_close_failok(p_sess->clamd_sock);
197
+                               p_sess->clamd_sock = -2;
198
+                               goto init_scan;
199
+                       } else {
200
+                               str_alloc_text(&debug_str, "av: failed to scan file (read failed)");
201
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
202
+                               vsf_sysutil_close(p_sess->clamd_sock);
203
+                               p_sess->clamd_sock = -2;
204
+                               return 2;
205
+                       }
206
+               }
207
+               
208
+               if (str_equal_text(&response, "COMMAND READ TIMED OUT\n")) {
209
+                       if (!retry) {
210
+                               retry = 1;
211
+                               vsf_sysutil_close_failok(p_sess->clamd_sock);
212
+                               p_sess->clamd_sock = -2;
213
+                               goto init_scan;
214
+                       } else {
215
+                               str_alloc_text(&debug_str, "av: got: ");
216
+                               str_append_str(&debug_str, &response);
217
+                               vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
218
+                               return 2;
219
+                       }
220
+               }
221
+
222
+
223
+
224
+               locate_res = str_locate_text(&response, " FOUND\n");
225
+               /* virus found */
226
+               if (locate_res.found) {
227
+                       str_trunc(&response, locate_res.index);
228
+                       str_split_text_reverse(&response, virname, ": ");
229
+                       return 1;
230
+               }
231
+               locate_res = str_locate_text(&response, " ERROR\n");
232
+               if (locate_res.found) {
233
+                       str_alloc_text(&debug_str, "av: got: ");
234
+                       str_append_str(&debug_str, &response);
235
+                       vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
236
+                       return 2;
237
+               }
238
+               return 0;
239
+       }
240
+
241
+       return 2;
242
+}
243
+
244
+
245
+
246
+
247
diff -Naru vsftpd-2.2.2.orig/clamav.h vsftpd-2.2.2/clamav.h
248
--- vsftpd-2.2.2.orig/clamav.h  1970-01-01 01:00:00.000000000 +0100
249
+++ vsftpd-2.2.2/clamav.h       2010-04-29 19:46:54.435448038 +0200
250
@@ -0,0 +1,12 @@
251
+#ifndef _CLAMAV_H
252
+#define _CLAMAV_H
253
+
254
+#include "str.h"
255
+#include "session.h"
256
+
257
+extern int av_init();
258
+extern int av_will_scan(const char *filename);
259
+extern int av_init_scanner (struct vsf_session* p_sess);
260
+extern int av_scan_file(struct vsf_session* p_sess, struct mystr *filename, struct mystr *virname);
261
+
262
+#endif
263
diff -Naru vsftpd-2.2.2.orig/main.c vsftpd-2.2.2/main.c
264
--- vsftpd-2.2.2.orig/main.c    2009-07-18 07:55:53.000000000 +0200
265
+++ vsftpd-2.2.2/main.c 2010-04-29 19:46:54.435448038 +0200
2 madcat 266
@@ -66,7 +66,9 @@
1 madcat 267
     /* Secure connection state */
268
     0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1,
269
     /* Login fails */
270
-    0
271
+    0,
272
+       /* av */
273
+       -1, INIT_MYSTR
274
   };
275
   int config_loaded = 0;
276
   int i;
277
diff -Naru vsftpd-2.2.2.orig/parseconf.c vsftpd-2.2.2/parseconf.c
278
--- vsftpd-2.2.2.orig/parseconf.c       2009-08-07 20:46:40.000000000 +0200
279
+++ vsftpd-2.2.2/parseconf.c    2010-04-29 19:46:54.435448038 +0200
2 madcat 280
@@ -101,6 +101,7 @@
1 madcat 281
   { "delete_failed_uploads", &tunable_delete_failed_uploads },
282
   { "implicit_ssl", &tunable_implicit_ssl },
283
   { "sandbox", &tunable_sandbox },
284
+  { "av_enable", &tunable_av_enable },
285
   { "require_ssl_reuse", &tunable_require_ssl_reuse },
286
   { "isolate", &tunable_isolate },
287
   { "isolate_network", &tunable_isolate_network },
2 madcat 288
@@ -136,6 +137,7 @@
1 madcat 289
   { "delay_successful_login", &tunable_delay_successful_login },
290
   { "max_login_fails", &tunable_max_login_fails },
291
   { "chown_upload_mode", &tunable_chown_upload_mode },
292
+  { "av_clamd_port", &tunable_av_clamd_port },
293
   { 0, 0 }
294
 };
295
 
2 madcat 296
@@ -178,6 +180,10 @@
1 madcat 297
   { "dsa_private_key_file", &tunable_dsa_private_key_file },
298
   { "ca_certs_file", &tunable_ca_certs_file },
299
   { "cmds_denied", &tunable_cmds_denied },
300
+  { "av_clamd_socket", &tunable_av_clamd_socket },
301
+  { "av_clamd_host", &tunable_av_clamd_host },
302
+  { "av_include_files", &tunable_av_include_files },
303
+  { "av_exclude_files", &tunable_av_exclude_files },
304
   { 0, 0 }
305
 };
306
 
307
diff -Naru vsftpd-2.2.2.orig/postlogin.c vsftpd-2.2.2/postlogin.c
308
--- vsftpd-2.2.2.orig/postlogin.c       2009-11-07 05:55:12.000000000 +0100
309
+++ vsftpd-2.2.2/postlogin.c    2010-04-29 19:46:54.438781445 +0200
310
@@ -27,6 +27,7 @@
311
 #include "ssl.h"
312
 #include "vsftpver.h"
313
 #include "opts.h"
314
+#include "clamav.h"
315
 
316
 /* Private local functions */
317
 static void handle_pwd(struct vsf_session* p_sess);
2 madcat 318
@@ -993,12 +994,15 @@
1 madcat 319
   static struct vsf_sysutil_statbuf* s_p_statbuf;
320
   static struct mystr s_filename;
321
   struct mystr* p_filename;
322
+  struct mystr tmp_filename = INIT_MYSTR;
323
   struct vsf_transfer_ret trans_ret;
324
   int new_file_fd;
325
+  int av_orig_file_fd = -1;
326
   int remote_fd;
327
   int success = 0;
328
   int created = 0;
329
   int do_truncate = 0;
330
+  int do_av = 0;
331
   filesize_t offset = p_sess->restart_pos;
332
   p_sess->restart_pos = 0;
333
   if (!data_transfer_checks_ok(p_sess))
2 madcat 334
@@ -1012,6 +1016,7 @@
1 madcat 335
     get_unique_filename(&s_filename, p_filename);
336
     p_filename = &s_filename;
337
   }
338
+
339
   vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
340
   str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
341
   prepend_path_to_filename(&p_sess->log_str);
2 madcat 342
@@ -1043,6 +1048,24 @@
1 madcat 343
     return;
344
   }
345
   created = 1;
346
+
347
+  if (av_will_scan(str_getbuf(p_filename))) {
348
+       do_av = 1;
349
+       str_copy(&tmp_filename, p_filename);
350
+       str_append_text(&tmp_filename, ".XXXXXX");
351
+       av_orig_file_fd = new_file_fd;
352
+       /* FIXME: various permissions issues... ex. writable file in non-writable directory */
353
+       new_file_fd = mkstemp(str_getbuf(&tmp_filename));
354
+       if (vsf_sysutil_retval_is_error(new_file_fd))
355
+       {
356
+         vsf_sysutil_close(av_orig_file_fd);
357
+         vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create temp file.");
358
+         return;
359
+       }
360
+       /* mkstemp creates file with 0600 */
361
+       vsf_sysutil_fchmod(new_file_fd, 0666 &(~vsf_sysutil_get_umask()));
362
+  }
363
+
364
   vsf_sysutil_fstat(new_file_fd, &s_p_statbuf);
365
   if (vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
366
   {
2 madcat 367
@@ -1068,6 +1091,8 @@
1 madcat 368
   if (tunable_lock_upload_files)
369
   {
370
     vsf_sysutil_lock_file_write(new_file_fd);
371
+       if (do_av)
372
+               vsf_sysutil_lock_file_write(av_orig_file_fd);
373
   }
374
   /* Must truncate the file AFTER locking it! */
375
   if (do_truncate)
2 madcat 376
@@ -1075,6 +1100,22 @@
1 madcat 377
     vsf_sysutil_ftruncate(new_file_fd);
378
     vsf_sysutil_lseek_to(new_file_fd, 0);
379
   }
380
+  if (do_av && (is_append || offset != 0)) {
381
+       char buf[4096];
382
+       int count;
383
+
384
+       /* copy original file */
385
+       vsf_sysutil_lseek_to(av_orig_file_fd, 0);
386
+       while ((count=vsf_sysutil_read(av_orig_file_fd, buf, 4096)) > 0) {
387
+         if (vsf_sysutil_write_loop(new_file_fd, buf, count) < 0) {
388
+               vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not copy temp file.");
389
+               vsf_sysutil_close(new_file_fd);
390
+               vsf_sysutil_close(av_orig_file_fd);
391
+               vsf_sysutil_unlink(str_getbuf(&tmp_filename));
392
+               return;
393
+         }
394
+       }
395
+  }
396
   if (!is_append && offset != 0)
397
   {
398
     /* XXX - warning, allows seek past end of file! Check for seek > size? */
2 madcat 399
@@ -1098,6 +1139,7 @@
1 madcat 400
   }
401
   if (vsf_sysutil_retval_is_error(remote_fd))
402
   {
403
+       vsf_sysutil_unlink(str_getbuf(&tmp_filename));
404
     goto port_pasv_cleanup_out;
405
   }
406
   if (tunable_ascii_upload_enable && p_sess->is_ascii)
2 madcat 407
@@ -1118,7 +1160,6 @@
1 madcat 408
   if (trans_ret.retval == 0)
409
   {
410
     success = 1;
411
-    vsf_log_do_log(p_sess, 1);
412
   }
413
   if (trans_ret.retval == -1)
414
   {
2 madcat 415
@@ -1130,7 +1171,43 @@
1 madcat 416
   }
417
   else
418
   {
419
-    vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete.");
420
+       if (do_av) {
421
+         struct mystr virname = INIT_MYSTR;
422
+         struct mystr resp_str = INIT_MYSTR;
423
+
424
+         switch (av_scan_file(p_sess, &tmp_filename, &virname)) {
425
+               case 1:
426
+                 str_alloc_text(&resp_str, "Virus found: ");
427
+                 str_append_str(&resp_str, &virname);
428
+                 vsf_log_line(p_sess, kVSFLogEntryUpload, &resp_str);
429
+                 vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, str_getbuf(&resp_str));
430
+                 str_free(&resp_str);
431
+
432
+                 str_unlink(&tmp_filename);
433
+                 break;
434
+               case 2:
435
+                 vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure scanning file.");
436
+                 str_unlink(&tmp_filename);
437
+                 break;
438
+               default:
439
+                 /* FIXME: race condition */
440
+                 if (vsf_sysutil_rename(str_getbuf(&tmp_filename), str_getbuf(p_filename)) < 0) {
441
+                       vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file .");
442
+                       str_unlink(&tmp_filename);
443
+                 } 
444
+                 else 
445
+                 {
446
+                       vsf_log_do_log(p_sess, 1);
447
+                       vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK.");
448
+                 }
449
+                 break;
450
+         }
451
+       } 
452
+       else 
453
+       {
454
+         vsf_log_do_log(p_sess, 1);
455
+         vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK.");
456
+       }
457
   }
458
   check_abor(p_sess);
459
 port_pasv_cleanup_out:
2 madcat 460
@@ -1138,9 +1215,15 @@
1 madcat 461
   pasv_cleanup(p_sess);
462
   if (tunable_delete_failed_uploads && created && !success)
463
   {
464
-    str_unlink(p_filename);
465
+       if (do_av) {
466
+         str_unlink(&tmp_filename);
467
+       } else {
468
+         str_unlink(p_filename);
469
+       }
470
   }
471
   vsf_sysutil_close(new_file_fd);
472
+  if (do_av)
473
+       vsf_sysutil_close(av_orig_file_fd);
474
 }
475
 
476
 static void
477
diff -Naru vsftpd-2.2.2.orig/secutil.c vsftpd-2.2.2/secutil.c
478
--- vsftpd-2.2.2.orig/secutil.c 2009-05-27 08:20:36.000000000 +0200
479
+++ vsftpd-2.2.2/secutil.c      2010-04-29 19:46:54.438781445 +0200
480
@@ -34,6 +34,7 @@
481
     if (p_dir_str == 0 || str_isempty(p_dir_str))
482
     {
483
       str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user));
484
+         str_copy(p_dir_str, &dir_str);
485
     }
486
     else
487
     {
488
diff -Naru vsftpd-2.2.2.orig/session.h vsftpd-2.2.2/session.h
489
--- vsftpd-2.2.2.orig/session.h 2008-02-12 03:39:38.000000000 +0100
490
+++ vsftpd-2.2.2/session.h      2010-04-29 19:46:54.438781445 +0200
2 madcat 491
@@ -97,6 +97,10 @@
1 madcat 492
   int ssl_slave_fd;
493
   int ssl_consumer_fd;
494
   unsigned int login_fails;
495
+
496
+  /* data for av scanner */
497
+  int clamd_sock;
498
+  struct mystr chroot_str;
499
 };
500
 
501
 #endif /* VSF_SESSION_H */
502
diff -Naru vsftpd-2.2.2.orig/tunables.c vsftpd-2.2.2/tunables.c
503
--- vsftpd-2.2.2.orig/tunables.c        2009-07-15 22:08:27.000000000 +0200
504
+++ vsftpd-2.2.2/tunables.c     2010-04-29 19:48:44.265437093 +0200
2 madcat 505
@@ -88,6 +88,8 @@
506
 int tunable_ftp_enable;
507
 int tunable_http_enable;
1 madcat 508
 
509
+int tunable_av_enable;
510
+
511
 unsigned int tunable_accept_timeout;
512
 unsigned int tunable_connect_timeout;
513
 unsigned int tunable_local_umask;
2 madcat 514
@@ -108,6 +110,7 @@
1 madcat 515
 unsigned int tunable_delay_successful_login;
516
 unsigned int tunable_max_login_fails;
517
 unsigned int tunable_chown_upload_mode;
518
+unsigned int tunable_av_clamd_port;
519
 
520
 const char* tunable_secure_chroot_dir;
521
 const char* tunable_ftp_username;
2 madcat 522
@@ -142,6 +145,11 @@
1 madcat 523
 const char* tunable_dsa_private_key_file;
524
 const char* tunable_ca_certs_file;
525
 
526
+const char* tunable_av_clamd_socket;
527
+const char* tunable_av_clamd_host;
528
+const char* tunable_av_include_files;
529
+const char* tunable_av_exclude_files;
530
+
531
 static void install_str_setting(const char* p_value, const char** p_storage);
532
 
533
 void
2 madcat 534
@@ -223,9 +231,10 @@
1 madcat 535
   tunable_sandbox = 0;
536
   tunable_require_ssl_reuse = 1;
537
   tunable_isolate = 1;
538
-  tunable_isolate_network = 1;
539
+  tunable_isolate_network = 0;
540
   tunable_ftp_enable = 1;
541
   tunable_http_enable = 0;
542
+  tunable_av_enable = 0;
543
 
544
   tunable_accept_timeout = 60;
545
   tunable_connect_timeout = 60;
2 madcat 546
@@ -251,6 +260,7 @@
1 madcat 547
   tunable_max_login_fails = 3;
548
   /* -rw------- */
549
   tunable_chown_upload_mode = 0600;
550
+  tunable_av_clamd_port = 3310;
551
 
2 madcat 552
   install_str_setting("/var/run/vsftpd/empty", &tunable_secure_chroot_dir);
1 madcat 553
   install_str_setting("ftp", &tunable_ftp_username);
2 madcat 554
@@ -286,6 +296,11 @@
1 madcat 555
   install_str_setting(0, &tunable_rsa_private_key_file);
556
   install_str_setting(0, &tunable_dsa_private_key_file);
557
   install_str_setting(0, &tunable_ca_certs_file);
558
+
559
+  install_str_setting(0, &tunable_av_clamd_socket);
560
+  install_str_setting("127.0.0.1", &tunable_av_clamd_host);
561
+  install_str_setting(0, &tunable_av_include_files);
562
+  install_str_setting(0, &tunable_av_exclude_files);
563
 }
564
 
565
 void
566
diff -Naru vsftpd-2.2.2.orig/tunables.h vsftpd-2.2.2/tunables.h
567
--- vsftpd-2.2.2.orig/tunables.h        2009-07-07 03:37:28.000000000 +0200
568
+++ vsftpd-2.2.2/tunables.h     2010-04-29 19:46:54.438781445 +0200
2 madcat 569
@@ -84,6 +84,7 @@
1 madcat 570
 extern int tunable_implicit_ssl;              /* Use implicit SSL protocol */
571
 extern int tunable_sandbox;                   /* Deploy ptrace sandbox */
572
 extern int tunable_require_ssl_reuse;         /* Require re-used data conn */
573
+extern int tunable_av_enable;                 /* Scan av incomming files */
574
 extern int tunable_isolate;                   /* Use container clone() flags */
575
 extern int tunable_isolate_network;           /* Use CLONE_NEWNET */
2 madcat 576
 extern int tunable_ftp_enable;                /* Allow FTP protocol */
577
@@ -110,6 +111,7 @@
1 madcat 578
 extern unsigned int tunable_delay_successful_login;
579
 extern unsigned int tunable_max_login_fails;
580
 extern unsigned int tunable_chown_upload_mode;
581
+extern unsigned int tunable_av_clamd_port;
582
 
583
 /* String defines */
584
 extern const char* tunable_secure_chroot_dir;
2 madcat 585
@@ -144,6 +146,10 @@
1 madcat 586
 extern const char* tunable_dsa_private_key_file;
587
 extern const char* tunable_ca_certs_file;
588
 extern const char* tunable_cmds_denied;
589
+extern const char* tunable_av_clamd_socket;
590
+extern const char* tunable_av_clamd_host;
591
+extern const char* tunable_av_include_files;
592
+extern const char* tunable_av_exclude_files;
593
 
594
 #endif /* VSF_TUNABLES_H */
595
 
596
diff -Naru vsftpd-2.2.2.orig/twoprocess.c vsftpd-2.2.2/twoprocess.c
597
--- vsftpd-2.2.2.orig/twoprocess.c      2009-07-18 07:56:44.000000000 +0200
598
+++ vsftpd-2.2.2/twoprocess.c   2010-04-29 19:46:54.438781445 +0200
2 madcat 599
@@ -430,6 +430,13 @@
1 madcat 600
                         p_user_str, p_orig_user_str);
601
     vsf_secutil_change_credentials(p_user_str, &userdir_str, &chroot_str,
602
                                    0, secutil_option);
603
+
604
+       if (do_chroot) {
605
+               str_copy(&p_sess->chroot_str, &userdir_str);
606
+       } else {
607
+               str_empty(&p_sess->chroot_str);
608
+       }
609
+
610
     if (!str_isempty(&chdir_str))
611
     {
612
       (void) str_chdir(&chdir_str);
613
diff -Naru vsftpd-2.2.2.orig/vsftpd.conf.5 vsftpd-2.2.2/vsftpd.conf.5
614
--- vsftpd-2.2.2.orig/vsftpd.conf.5     2009-10-19 04:46:30.000000000 +0200
615
+++ vsftpd-2.2.2/vsftpd.conf.5  2010-04-29 19:46:54.438781445 +0200
616
@@ -105,6 +105,11 @@
617
 
618
 Default: NO
619
 .TP
620
+.B av_enable
621
+If enabled, all uploaded files are scanned with clamav (through clamd).
622
+
623
+Default: NO
624
+.TP
625
 .B background
626
 When enabled, and vsftpd is started in "listen" mode, vsftpd will background
627
 the listener process. i.e. control will immediately be returned to the shell
628
@@ -643,6 +648,11 @@
629
 
630
 Default: 077
631
 .TP
632
+.B av_clamd_port
633
+Port number where clamd listen on.
634
+
635
+Default: 3310
636
+.TP
637
 .B chown_upload_mode
638
 The file mode to force for chown()ed anonymous uploads. (Added in v2.0.6).
639
 
640
@@ -758,6 +768,18 @@
641
 
642
 Default: (none)
643
 .TP
644
+.B av_clamd_host
645
+IP where clamd listen. It must be on the same host (or have access to same
646
+filesystem).
647
+
648
+Default: 127.0.0.1
649
+.TP
650
+.B av_clamd_socket
651
+UNIX socket of clamd. Warning: When using chroot you should use TCP instead of
652
+UNIX socket.
653
+
654
+Default: (none)
655
+.TP
656
 .B banned_email_file
657
 This option is the name of a file containing a list of anonymous e-mail
658
 passwords which are not permitted. This file is consulted if the option