s3: libsmb: In cli_list_old_send(), push state->mask into the packet, not just mask.
[Samba.git] / source3 / modules / vfs_virusfilter_fsav.c
blob240940c75c8900405784b92d759a1d098e90fcad
1 /*
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
25 #else
26 # define VIRUSFILTER_DEFAULT_SOCKET_PATH "/tmp/.fsav-0"
27 #endif
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 {
38 /* Backpointer */
39 struct virusfilter_config *config;
41 int fsav_protocol;
42 bool scan_riskware;
43 bool stop_scan_on_first;
44 bool filter_filename;
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);
53 return 0;
56 static int virusfilter_fsav_connect(
57 struct vfs_handle_struct *handle,
58 struct virusfilter_config *config,
59 const char *svc,
60 const char *user)
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) {
68 return -1;
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);
96 return 0;
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;
104 char *reply = NULL;
105 bool ok;
106 int ret;
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");
116 if (ok) {
117 ret = strncmp(reply, "ERROR\t", 6);
118 if (ret == 0) {
119 DBG_DEBUG("fsavd: Re-using existent "
120 "connection\n");
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);
132 become_root();
133 ok = virusfilter_io_connect_path(io_h, config->socket_path);
134 unbecome_root();
136 if (!ok) {
137 DBG_ERR("fsavd: Connecting to socket failed: %s: %s\n",
138 config->socket_path, strerror(errno));
139 goto virusfilter_fsav_init_failed;
142 TALLOC_FREE(reply);
144 ok = virusfilter_io_readl(talloc_tos(), io_h, &reply);
145 if (!ok) {
146 DBG_ERR("fsavd: Reading greeting message failed: %s\n",
147 strerror(errno));
148 goto virusfilter_fsav_init_failed;
150 ret = strncmp(reply, "DBVERSION\t", 10);
151 if (ret != 0) {
152 DBG_ERR("fsavd: Invalid greeting message: %s\n",
153 reply);
154 goto virusfilter_fsav_init_failed;
157 DBG_DEBUG("fsavd: Connected\n");
159 DBG_INFO("fsavd: Configuring\n");
161 TALLOC_FREE(reply);
163 ok = virusfilter_io_writefl_readl(io_h, &reply, "PROTOCOL\t%d",
164 fsav_config->fsav_protocol);
165 if (!ok) {
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);
170 if (ret != 0) {
171 DBG_ERR("fsavd: PROTOCOL: Not accepted: %s\n",
172 reply);
173 goto virusfilter_fsav_init_failed;
176 TALLOC_FREE(reply);
178 ok = virusfilter_io_writefl_readl(io_h, &reply,
179 "CONFIGURE\tSTOPONFIRST\t%d",
180 fsav_config->stop_scan_on_first ?
181 1 : 0);
182 if (!ok) {
183 DBG_ERR("fsavd: CONFIGURE STOPONFIRST: I/O error: %s\n",
184 strerror(errno));
185 goto virusfilter_fsav_init_failed;
187 ret = strncmp(reply, "OK\t", 3);
188 if (ret != 0) {
189 DBG_ERR("fsavd: CONFIGURE STOPONFIRST: Not accepted: %s\n",
190 reply);
191 goto virusfilter_fsav_init_failed;
194 TALLOC_FREE(reply);
196 ok = virusfilter_io_writefl_readl(io_h, &reply, "CONFIGURE\tFILTER\t%d",
197 fsav_config->filter_filename ? 1 : 0);
198 if (!ok) {
199 DBG_ERR("fsavd: CONFIGURE FILTER: I/O error: %s\n",
200 strerror(errno));
201 goto virusfilter_fsav_init_failed;
203 ret = strncmp(reply, "OK\t", 3);
204 if (ret != 0) {
205 DBG_ERR("fsavd: CONFIGURE FILTER: Not accepted: %s\n",
206 reply);
207 goto virusfilter_fsav_init_failed;
210 TALLOC_FREE(reply);
212 ok = virusfilter_io_writefl_readl(io_h, &reply,
213 "CONFIGURE\tARCHIVE\t%d",
214 config->scan_archive ? 1 : 0);
215 if (!ok) {
216 DBG_ERR("fsavd: CONFIGURE ARCHIVE: I/O error: %s\n",
217 strerror(errno));
218 goto virusfilter_fsav_init_failed;
220 ret = strncmp(reply, "OK\t", 3);
221 if (ret != 0) {
222 DBG_ERR("fsavd: CONFIGURE ARCHIVE: Not accepted: %s\n",
223 reply);
224 goto virusfilter_fsav_init_failed;
227 TALLOC_FREE(reply);
229 ok = virusfilter_io_writefl_readl(io_h, &reply,
230 "CONFIGURE\tMAXARCH\t%d",
231 config->max_nested_scan_archive);
232 if (!ok) {
233 DBG_ERR("fsavd: CONFIGURE MAXARCH: I/O error: %s\n",
234 strerror(errno));
235 goto virusfilter_fsav_init_failed;
237 ret = strncmp(reply, "OK\t", 3);
238 if (ret != 0) {
239 DBG_ERR("fsavd: CONFIGURE MAXARCH: Not accepted: %s\n",
240 reply);
241 goto virusfilter_fsav_init_failed;
244 TALLOC_FREE(reply);
246 ok = virusfilter_io_writefl_readl(io_h, &reply,
247 "CONFIGURE\tMIME\t%d",
248 config->scan_mime ? 1 : 0);
249 if (!ok) {
250 DBG_ERR("fsavd: CONFIGURE MIME: I/O error: %s\n",
251 strerror(errno));
252 goto virusfilter_fsav_init_failed;
254 ret = strncmp(reply, "OK\t", 3);
255 if (ret != 0) {
256 DBG_ERR("fsavd: CONFIGURE MIME: Not accepted: %s\n",
257 reply);
258 goto virusfilter_fsav_init_failed;
261 TALLOC_FREE(reply);
263 ok = virusfilter_io_writefl_readl(io_h, &reply, "CONFIGURE\tRISKWARE\t%d",
264 fsav_config->scan_riskware ? 1 : 0);
265 if (!ok) {
266 DBG_ERR("fsavd: CONFIGURE RISKWARE: I/O error: %s\n",
267 strerror(errno));
268 goto virusfilter_fsav_init_failed;
270 ret = strncmp(reply, "OK\t", 3);
271 if (ret != 0) {
272 DBG_ERR("fsavd: CONFIGURE RISKWARE: Not accepted: %s\n",
273 reply);
274 goto virusfilter_fsav_init_failed;
277 DBG_DEBUG("fsavd: Configured\n");
279 virusfilter_fsav_init_succeed:
280 TALLOC_FREE(reply);
281 return VIRUSFILTER_RESULT_OK;
283 virusfilter_fsav_init_failed:
284 TALLOC_FREE(reply);
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,
302 char **reportp)
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;
308 char *report = NULL;
309 char *reply = NULL;
310 char *reply_token = NULL, *reply_saveptr = NULL;
311 bool ok;
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);
318 if (!ok) {
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",
323 strerror(errno));
324 goto virusfilter_fsav_scan_return;
327 TALLOC_FREE(reply);
329 for (;;) {
330 if (virusfilter_io_readl(talloc_tos(), io_h, &reply) != true) {
331 DBG_ERR("fsavd: SCANFILE: Read error: %s\n",
332 strerror(errno));
333 result = VIRUSFILTER_RESULT_ERROR;
334 report = talloc_asprintf(talloc_tos(),
335 "Scanner I/O error: %s\n",
336 strerror(errno));
337 break;
340 reply_token = strtok_r(reply, "\t", &reply_saveptr);
342 if (strcmp(reply_token, "OK") == 0) {
343 break;
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(),
363 reply_token);
364 } else {
365 report = talloc_asprintf(talloc_tos(),
366 "UNKNOWN INFECTION");
368 } else if (strcmp(reply_token, "OPEN_ARCHIVE") == 0) {
370 /* Ignore */
371 } else if (strcmp(reply_token, "CLOSE_ARCHIVE") == 0) {
373 /* Ignore */
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(),
384 reply_token);
385 } else {
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(),
398 "Scanner error: %s",
399 reply_token ? reply_token :
400 "UNKNOWN ERROR");
401 } else {
402 result = VIRUSFILTER_RESULT_ERROR;
403 DBG_ERR("fsavd: SCANFILE: Invalid reply: %s\t",
404 reply_token);
405 report = talloc_asprintf(talloc_tos(),
406 "Scanner communication error");
409 TALLOC_FREE(reply);
412 virusfilter_fsav_scan_return:
413 TALLOC_FREE(reply);
415 if (report == NULL) {
416 *reportp = talloc_asprintf(talloc_tos(), "Scanner report memory "
417 "error");
418 } else {
419 *reportp = report;
422 return result;
425 static struct virusfilter_backend_fns virusfilter_backend_fsav ={
426 .connect = virusfilter_fsav_connect,
427 .disconnect = NULL,
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) {
443 return -1;
446 backend->fns = &virusfilter_backend_fsav;
447 backend->name = "fsav";
449 config->backend = backend;
450 return 0;