2 Samba-VirusFilter VFS modules
3 F-Secure Anti-Virus fsavd support
4 Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "vfs_virusfilter_common.h"
21 #include "vfs_virusfilter_utils.h"
23 #ifdef FSAV_DEFAULT_SOCKET_PATH
24 # define VIRUSFILTER_DEFAULT_SOCKET_PATH FSAV_DEFAULT_SOCKET_PATH
26 # define VIRUSFILTER_DEFAULT_SOCKET_PATH "/tmp/.fsav-0"
29 /* Default values for module-specific configuration variables */
30 /* 5 = F-Secure Linux 7 or later? */
32 #define VIRUSFILTER_DEFAULT_FSAV_PROTOCOL 5
33 #define VIRUSFILTER_DEFAULT_SCAN_RISKWARE false
34 #define VIRUSFILTER_DEFAULT_STOP_SCAN_ON_FIRST true
35 #define VIRUSFILTER_DEFAULT_FILTER_FILENAME false
37 struct virusfilter_fsav_config
{
39 struct virusfilter_config
*config
;
43 bool stop_scan_on_first
;
47 static void virusfilter_fsav_scan_end(struct virusfilter_config
*config
);
49 static int virusfilter_fsav_destruct_config(
50 struct virusfilter_fsav_config
*fsav_config
)
52 virusfilter_fsav_scan_end(fsav_config
->config
);
56 static int virusfilter_fsav_connect(
57 struct vfs_handle_struct
*handle
,
58 struct virusfilter_config
*config
,
62 int snum
= SNUM(handle
->conn
);
63 struct virusfilter_fsav_config
*fsav_config
= NULL
;
65 fsav_config
= talloc_zero(config
->backend
,
66 struct virusfilter_fsav_config
);
67 if (fsav_config
== NULL
) {
71 fsav_config
->config
= config
;
73 fsav_config
->fsav_protocol
= lp_parm_int(
74 snum
, "virusfilter", "fsav protocol",
75 VIRUSFILTER_DEFAULT_FSAV_PROTOCOL
);
77 fsav_config
->scan_riskware
= lp_parm_bool(
78 snum
, "virusfilter", "scan riskware",
79 VIRUSFILTER_DEFAULT_SCAN_RISKWARE
);
81 fsav_config
->stop_scan_on_first
= lp_parm_bool(
82 snum
, "virusfilter", "stop scan on first",
83 VIRUSFILTER_DEFAULT_STOP_SCAN_ON_FIRST
);
85 fsav_config
->filter_filename
= lp_parm_bool(
86 snum
, "virusfilter", "filter filename",
87 VIRUSFILTER_DEFAULT_FILTER_FILENAME
);
89 talloc_set_destructor(fsav_config
, virusfilter_fsav_destruct_config
);
91 config
->backend
->backend_private
= fsav_config
;
93 config
->block_suspected_file
= lp_parm_bool(
94 snum
, "virusfilter", "block suspected file", false);
99 static virusfilter_result
virusfilter_fsav_scan_init(
100 struct virusfilter_config
*config
)
102 struct virusfilter_fsav_config
*fsav_config
= NULL
;
103 struct virusfilter_io_handle
*io_h
= config
->io_h
;
108 fsav_config
= talloc_get_type_abort(config
->backend
->backend_private
,
109 struct virusfilter_fsav_config
);
111 if (io_h
->stream
!= NULL
) {
112 DBG_DEBUG("fsavd: Checking if connection is alive\n");
114 /* FIXME: I don't know the correct PING command format... */
115 ok
= virusfilter_io_writefl_readl(io_h
, &reply
, "PING");
117 ret
= strncmp(reply
, "ERROR\t", 6);
119 DBG_DEBUG("fsavd: Re-using existent "
121 goto virusfilter_fsav_init_succeed
;
125 DBG_DEBUG("fsavd: Closing dead connection\n");
126 virusfilter_fsav_scan_end(config
);
129 DBG_INFO("fsavd: Connecting to socket: %s\n",
130 config
->socket_path
);
133 ok
= virusfilter_io_connect_path(io_h
, config
->socket_path
);
137 DBG_ERR("fsavd: Connecting to socket failed: %s: %s\n",
138 config
->socket_path
, strerror(errno
));
139 goto virusfilter_fsav_init_failed
;
144 ok
= virusfilter_io_readl(talloc_tos(), io_h
, &reply
);
146 DBG_ERR("fsavd: Reading greeting message failed: %s\n",
148 goto virusfilter_fsav_init_failed
;
150 ret
= strncmp(reply
, "DBVERSION\t", 10);
152 DBG_ERR("fsavd: Invalid greeting message: %s\n",
154 goto virusfilter_fsav_init_failed
;
157 DBG_DEBUG("fsavd: Connected\n");
159 DBG_INFO("fsavd: Configuring\n");
163 ok
= virusfilter_io_writefl_readl(io_h
, &reply
, "PROTOCOL\t%d",
164 fsav_config
->fsav_protocol
);
166 DBG_ERR("fsavd: PROTOCOL: I/O error: %s\n", strerror(errno
));
167 goto virusfilter_fsav_init_failed
;
169 ret
= strncmp(reply
, "OK\t", 3);
171 DBG_ERR("fsavd: PROTOCOL: Not accepted: %s\n",
173 goto virusfilter_fsav_init_failed
;
178 ok
= virusfilter_io_writefl_readl(io_h
, &reply
,
179 "CONFIGURE\tSTOPONFIRST\t%d",
180 fsav_config
->stop_scan_on_first
?
183 DBG_ERR("fsavd: CONFIGURE STOPONFIRST: I/O error: %s\n",
185 goto virusfilter_fsav_init_failed
;
187 ret
= strncmp(reply
, "OK\t", 3);
189 DBG_ERR("fsavd: CONFIGURE STOPONFIRST: Not accepted: %s\n",
191 goto virusfilter_fsav_init_failed
;
196 ok
= virusfilter_io_writefl_readl(io_h
, &reply
, "CONFIGURE\tFILTER\t%d",
197 fsav_config
->filter_filename
? 1 : 0);
199 DBG_ERR("fsavd: CONFIGURE FILTER: I/O error: %s\n",
201 goto virusfilter_fsav_init_failed
;
203 ret
= strncmp(reply
, "OK\t", 3);
205 DBG_ERR("fsavd: CONFIGURE FILTER: Not accepted: %s\n",
207 goto virusfilter_fsav_init_failed
;
212 ok
= virusfilter_io_writefl_readl(io_h
, &reply
,
213 "CONFIGURE\tARCHIVE\t%d",
214 config
->scan_archive
? 1 : 0);
216 DBG_ERR("fsavd: CONFIGURE ARCHIVE: I/O error: %s\n",
218 goto virusfilter_fsav_init_failed
;
220 ret
= strncmp(reply
, "OK\t", 3);
222 DBG_ERR("fsavd: CONFIGURE ARCHIVE: Not accepted: %s\n",
224 goto virusfilter_fsav_init_failed
;
229 ok
= virusfilter_io_writefl_readl(io_h
, &reply
,
230 "CONFIGURE\tMAXARCH\t%d",
231 config
->max_nested_scan_archive
);
233 DBG_ERR("fsavd: CONFIGURE MAXARCH: I/O error: %s\n",
235 goto virusfilter_fsav_init_failed
;
237 ret
= strncmp(reply
, "OK\t", 3);
239 DBG_ERR("fsavd: CONFIGURE MAXARCH: Not accepted: %s\n",
241 goto virusfilter_fsav_init_failed
;
246 ok
= virusfilter_io_writefl_readl(io_h
, &reply
,
247 "CONFIGURE\tMIME\t%d",
248 config
->scan_mime
? 1 : 0);
250 DBG_ERR("fsavd: CONFIGURE MIME: I/O error: %s\n",
252 goto virusfilter_fsav_init_failed
;
254 ret
= strncmp(reply
, "OK\t", 3);
256 DBG_ERR("fsavd: CONFIGURE MIME: Not accepted: %s\n",
258 goto virusfilter_fsav_init_failed
;
263 ok
= virusfilter_io_writefl_readl(io_h
, &reply
, "CONFIGURE\tRISKWARE\t%d",
264 fsav_config
->scan_riskware
? 1 : 0);
266 DBG_ERR("fsavd: CONFIGURE RISKWARE: I/O error: %s\n",
268 goto virusfilter_fsav_init_failed
;
270 ret
= strncmp(reply
, "OK\t", 3);
272 DBG_ERR("fsavd: CONFIGURE RISKWARE: Not accepted: %s\n",
274 goto virusfilter_fsav_init_failed
;
277 DBG_DEBUG("fsavd: Configured\n");
279 virusfilter_fsav_init_succeed
:
281 return VIRUSFILTER_RESULT_OK
;
283 virusfilter_fsav_init_failed
:
285 virusfilter_fsav_scan_end(config
);
287 return VIRUSFILTER_RESULT_ERROR
;
290 static void virusfilter_fsav_scan_end(struct virusfilter_config
*config
)
292 struct virusfilter_io_handle
*io_h
= config
->io_h
;
294 DBG_INFO("fsavd: Disconnecting\n");
295 virusfilter_io_disconnect(io_h
);
298 static virusfilter_result
virusfilter_fsav_scan(
299 struct vfs_handle_struct
*handle
,
300 struct virusfilter_config
*config
,
301 const struct files_struct
*fsp
,
304 char *cwd_fname
= fsp
->conn
->cwd_fsp
->fsp_name
->base_name
;
305 const char *fname
= fsp
->fsp_name
->base_name
;
306 struct virusfilter_io_handle
*io_h
= config
->io_h
;
307 virusfilter_result result
= VIRUSFILTER_RESULT_CLEAN
;
310 char *reply_token
= NULL
, *reply_saveptr
= NULL
;
313 DBG_INFO("Scanning file: %s/%s\n", cwd_fname
, fname
);
315 ok
= virusfilter_io_writevl(io_h
, "SCAN\t", 5, cwd_fname
,
316 (int)strlen(cwd_fname
), "/", 1, fname
,
317 (int)strlen(fname
), NULL
);
319 DBG_ERR("fsavd: SCAN: Write error: %s\n", strerror(errno
));
320 result
= VIRUSFILTER_RESULT_ERROR
;
321 report
= talloc_asprintf(talloc_tos(),
322 "Scanner I/O error: %s\n",
324 goto virusfilter_fsav_scan_return
;
330 if (virusfilter_io_readl(talloc_tos(), io_h
, &reply
) != true) {
331 DBG_ERR("fsavd: SCANFILE: Read error: %s\n",
333 result
= VIRUSFILTER_RESULT_ERROR
;
334 report
= talloc_asprintf(talloc_tos(),
335 "Scanner I/O error: %s\n",
340 reply_token
= strtok_r(reply
, "\t", &reply_saveptr
);
342 if (strcmp(reply_token
, "OK") == 0) {
344 } else if (strcmp(reply_token
, "CLEAN") == 0) {
346 /* CLEAN\t<FILEPATH> */
347 result
= VIRUSFILTER_RESULT_CLEAN
;
348 report
= talloc_asprintf(talloc_tos(), "Clean");
349 } else if (strcmp(reply_token
, "INFECTED") == 0 ||
350 strcmp(reply_token
, "ARCHIVE_INFECTED") == 0 ||
351 strcmp(reply_token
, "MIME_INFECTED") == 0 ||
352 strcmp(reply_token
, "RISKWARE") == 0 ||
353 strcmp(reply_token
, "ARCHIVE_RISKWARE") == 0 ||
354 strcmp(reply_token
, "MIME_RISKWARE") == 0)
357 /* INFECTED\t<FILEPATH>\t<REPORT>\t<ENGINE> */
358 result
= VIRUSFILTER_RESULT_INFECTED
;
359 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
360 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
361 if (reply_token
!= NULL
) {
362 report
= talloc_strdup(talloc_tos(),
365 report
= talloc_asprintf(talloc_tos(),
366 "UNKNOWN INFECTION");
368 } else if (strcmp(reply_token
, "OPEN_ARCHIVE") == 0) {
371 } else if (strcmp(reply_token
, "CLOSE_ARCHIVE") == 0) {
374 } else if ((strcmp(reply_token
, "SUSPECTED") == 0 ||
375 strcmp(reply_token
, "ARCHIVE_SUSPECTED") == 0 ||
376 strcmp(reply_token
, "MIME_SUSPECTED") == 0) &&
377 config
->block_suspected_file
)
379 result
= VIRUSFILTER_RESULT_SUSPECTED
;
380 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
381 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
382 if (reply_token
!= NULL
) {
383 report
= talloc_strdup(talloc_tos(),
386 report
= talloc_asprintf(talloc_tos(),
387 "UNKNOWN REASON SUSPECTED");
389 } else if (strcmp(reply_token
, "SCAN_FAILURE") == 0) {
391 /* SCAN_FAILURE\t<FILEPATH>\t0x<CODE>\t<REPORT> [<ENGINE>] */
392 result
= VIRUSFILTER_RESULT_ERROR
;
393 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
394 reply_token
= strtok_r(NULL
, "\t", &reply_saveptr
);
395 DBG_ERR("fsavd: SCANFILE: Scaner error: %s\n",
396 reply_token
? reply_token
: "UNKNOWN ERROR");
397 report
= talloc_asprintf(talloc_tos(),
399 reply_token
? reply_token
:
402 result
= VIRUSFILTER_RESULT_ERROR
;
403 DBG_ERR("fsavd: SCANFILE: Invalid reply: %s\t",
405 report
= talloc_asprintf(talloc_tos(),
406 "Scanner communication error");
412 virusfilter_fsav_scan_return
:
415 if (report
== NULL
) {
416 *reportp
= talloc_asprintf(talloc_tos(), "Scanner report memory "
425 static struct virusfilter_backend_fns virusfilter_backend_fsav
={
426 .connect
= virusfilter_fsav_connect
,
428 .scan_init
= virusfilter_fsav_scan_init
,
429 .scan
= virusfilter_fsav_scan
,
430 .scan_end
= virusfilter_fsav_scan_end
,
433 int virusfilter_fsav_init(struct virusfilter_config
*config
)
435 struct virusfilter_backend
*backend
= NULL
;
437 if (config
->socket_path
== NULL
) {
438 config
->socket_path
= VIRUSFILTER_DEFAULT_SOCKET_PATH
;
441 backend
= talloc_zero(config
, struct virusfilter_backend
);
442 if (backend
== NULL
) {
446 backend
->fns
= &virusfilter_backend_fsav
;
447 backend
->name
= "fsav";
449 config
->backend
= backend
;