Samba-VirusFilter: clamav VFS and man page.
authorTrever L. Adams <trever.adams@gmail.com>
Tue, 18 Oct 2016 19:40:01 +0000 (13:40 -0600)
committerRalph Boehme <slow@samba.org>
Wed, 24 Jan 2018 14:08:59 +0000 (15:08 +0100)
Signed-off-by: Trever L. Adams <trever.adams@gmail.com>
Signed-off-by: SATOH Fumiyasu <fumiyas@osstech.co.jp>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Wed Jan 24 15:08:59 CET 2018 on sn-devel-144

docs-xml/manpages/vfs_virusfilter.8.xml
source3/modules/vfs_virusfilter.c
source3/modules/vfs_virusfilter_clamav.c [new file with mode: 0644]
source3/modules/vfs_virusfilter_common.h
source3/modules/wscript_build

index 2e70ab0b55356d107fee4d4ff5b6a319b5b51642..ee49df11575573e1fe7e5ac3adcfa5180c99a0c2 100644 (file)
@@ -46,6 +46,8 @@
                  scanner</para></listitem>
                  <listitem><para><emphasis>fsav</emphasis>, the F-Secure AV
                  scanner</para></listitem>
+                 <listitem><para><emphasis>clamav</emphasis>, the ClamAV
+                 scanner</para></listitem>
                </itemizedlist>
                </listitem>
                </varlistentry>
@@ -62,6 +64,8 @@
                <emphasis>/var/run/savdi/sssp.sock</emphasis>.</para>
                <para>For the <emphasis>fsav</emphasis> backend the default is
                <emphasis>/tmp/.fsav-0</emphasis>.</para>
+               <para>For the <emphasis>fsav</emphasis> backend the default is
+               <emphasis>/var/run/clamav/clamd.ctl</emphasis>.</para>
                </listitem>
                </varlistentry>
 
index 338b4fc899c4c9911fd911597f81a7e3acc2da31..9b29923110ddc6f12de2d85a53d95a97bbfd7b19 100644 (file)
@@ -448,6 +448,9 @@ static int virusfilter_vfs_connect(
        case VIRUSFILTER_SCANNER_FSAV:
                ret = virusfilter_fsav_init(config);
                break;
+       case VIRUSFILTER_SCANNER_CLAMAV:
+               ret = virusfilter_clamav_init(config);
+               break;
        default:
                DBG_ERR("Unhandled scanner %d\n", backend);
                return -1;
diff --git a/source3/modules/vfs_virusfilter_clamav.c b/source3/modules/vfs_virusfilter_clamav.c
new file mode 100644 (file)
index 0000000..d0e1fc0
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+   Samba-VirusFilter VFS modules
+   ClamAV clamd support
+   Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Default values for standard "extra" configuration variables */
+
+#ifdef CLAMAV_DEFAULT_SOCKET_PATH
+#  define VIRUSFILTER_DEFAULT_SOCKET_PATH      CLAMAV_DEFAULT_SOCKET_PATH
+#else
+#  define VIRUSFILTER_DEFAULT_SOCKET_PATH      "/var/run/clamav/clamd.ctl"
+#endif
+
+#include "modules/vfs_virusfilter_common.h"
+#include "modules/vfs_virusfilter_utils.h"
+
+static int virusfilter_clamav_connect(struct vfs_handle_struct *handle,
+                                     struct virusfilter_config *config,
+                                     const char *svc,
+                                     const char *user)
+{
+
+       /* To use clamd "zXXXX" commands */
+       virusfilter_io_set_writel_eol(config->io_h, "\0", 1);
+       virusfilter_io_set_readl_eol(config->io_h, "\0", 1);
+
+       return 0;
+}
+
+static virusfilter_result virusfilter_clamav_scan_init(
+       struct virusfilter_config *config)
+{
+       struct virusfilter_io_handle *io_h = config->io_h;
+       bool ok;
+
+       DBG_INFO("clamd: Connecting to socket: %s\n",
+                config->socket_path);
+
+       become_root();
+       ok = virusfilter_io_connect_path(io_h, config->socket_path);
+       unbecome_root();
+
+       if (!ok) {
+               DBG_ERR("clamd: Connecting to socket failed: %s: %s\n",
+                       config->socket_path, strerror(errno));
+               return VIRUSFILTER_RESULT_ERROR;
+       }
+
+       DBG_INFO("clamd: Connected\n");
+
+       return VIRUSFILTER_RESULT_OK;
+}
+
+static void virusfilter_clamav_scan_end(
+       struct virusfilter_config *config)
+{
+       struct virusfilter_io_handle *io_h = config->io_h;
+
+       DBG_INFO("clamd: Disconnecting\n");
+
+       virusfilter_io_disconnect(io_h);
+}
+
+static virusfilter_result virusfilter_clamav_scan(
+       struct vfs_handle_struct *handle,
+       struct virusfilter_config *config,
+       const struct files_struct *fsp,
+       char **reportp)
+{
+       char *cwd_fname = fsp->conn->cwd_fname->base_name;
+       const char *fname = fsp->fsp_name->base_name;
+       size_t filepath_len = strlen(cwd_fname) + 1 /* slash */ + strlen(fname);
+       struct virusfilter_io_handle *io_h = config->io_h;
+       virusfilter_result result = VIRUSFILTER_RESULT_CLEAN;
+       char *report = NULL;
+       char *reply = NULL;
+       char *reply_msg = NULL;
+       char *reply_token;
+       bool ok;
+
+       DBG_INFO("Scanning file: %s/%s\n", cwd_fname, fname);
+
+       ok = virusfilter_io_writefl_readl(io_h, &reply, "zSCAN %s/%s",
+                                         cwd_fname, fname);
+       if (!ok) {
+               DBG_ERR("clamd: zSCAN: I/O error: %s\n", strerror(errno));
+               result = VIRUSFILTER_RESULT_ERROR;
+               report = talloc_asprintf(talloc_tos(),
+                                        "Scanner I/O error: %s\n",
+                                        strerror(errno));
+               goto virusfilter_clamav_scan_return;
+       }
+
+       if (reply[filepath_len] != ':' ||
+           reply[filepath_len+1] != ' ')
+       {
+               DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
+                       reply);
+               result = VIRUSFILTER_RESULT_ERROR;
+               report = talloc_asprintf(talloc_tos(),
+                                        "Scanner communication error");
+               goto virusfilter_clamav_scan_return;
+       }
+       reply_msg = reply + filepath_len + 2;
+
+       reply_token = strrchr(reply, ' ');
+
+       if (reply_token == NULL) {
+               DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
+                       reply);
+               result = VIRUSFILTER_RESULT_ERROR;
+               report = talloc_asprintf(talloc_tos(),
+                                        "Scanner communication error");
+               goto virusfilter_clamav_scan_return;
+       }
+       *reply_token = '\0';
+       reply_token++;
+
+       if (strcmp(reply_token, "OK") == 0) {
+
+               /* <FILEPATH>: OK */
+               result = VIRUSFILTER_RESULT_CLEAN;
+               report = talloc_asprintf(talloc_tos(), "Clean");
+       } else if (strcmp(reply_token, "FOUND") == 0) {
+
+               /* <FILEPATH>: <REPORT> FOUND */
+               result = VIRUSFILTER_RESULT_INFECTED;
+               report = talloc_strdup(talloc_tos(), reply_msg);
+       } else if (strcmp(reply_token, "ERROR") == 0) {
+
+               /* <FILEPATH>: <REPORT> ERROR */
+               DBG_ERR("clamd: zSCAN: Error: %s\n", reply_msg);
+               result = VIRUSFILTER_RESULT_ERROR;
+               report = talloc_asprintf(talloc_tos(),
+                                        "Scanner error: %s\t", reply_msg);
+       } else {
+               DBG_ERR("clamd: zSCAN: Invalid reply: %s\n", reply_token);
+               result = VIRUSFILTER_RESULT_ERROR;
+               report = talloc_asprintf(talloc_tos(),
+                                        "Scanner communication error");
+       }
+
+virusfilter_clamav_scan_return:
+       TALLOC_FREE(reply);
+       if (report == NULL) {
+               *reportp = talloc_asprintf(talloc_tos(),
+                                          "Scanner report memory error");
+       } else {
+               *reportp = report;
+       }
+
+       return result;
+}
+
+static struct virusfilter_backend_fns virusfilter_backend_clamav = {
+       .connect = virusfilter_clamav_connect,
+       .disconnect = NULL,
+       .scan_init = virusfilter_clamav_scan_init,
+       .scan = virusfilter_clamav_scan,
+       .scan_end = virusfilter_clamav_scan_end,
+};
+
+int virusfilter_clamav_init(struct virusfilter_config *config)
+{
+       struct virusfilter_backend *backend = NULL;
+
+       if (config->socket_path == NULL) {
+               config->socket_path = VIRUSFILTER_DEFAULT_SOCKET_PATH;
+       }
+
+       backend = talloc_zero(config, struct virusfilter_backend);
+       if (backend == NULL) {
+               return -1;
+       }
+
+       backend->fns = &virusfilter_backend_clamav;
+       backend->name = "clamav";
+
+       config->backend = backend;
+       return 0;
+}
index a28ce2978fa94abf1d8de5505e59eb667856a4be..f71b0b949a7e122f68fa8db07a1bf231a7c13f0c 100644 (file)
@@ -148,5 +148,6 @@ struct virusfilter_backend {
 
 int virusfilter_sophos_init(struct virusfilter_config *config);
 int virusfilter_fsav_init(struct virusfilter_config *config);
+int virusfilter_clamav_init(struct virusfilter_config *config);
 
 #endif /* _VIRUSFILTER_COMMON_H */
index f63c00a9955901f7978a102e4094cc63f5eb2dc9..5c5298904708baf6f25ef288bdb8de6dcddd6901 100644 (file)
@@ -516,6 +516,7 @@ bld.SAMBA3_MODULE('vfs_virusfilter',
                  vfs_virusfilter.c
                  vfs_virusfilter_sophos.c
                  vfs_virusfilter_fsav.c
+                 vfs_virusfilter_clamav.c
                  ''',
                  deps='samba-util VFS_VIRUSFILTER_UTILS',
                  init_function='',