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