smbd: replace CHECK_WRITE() macro with calls to check_any_access_fsp()
[Samba.git] / source3 / modules / vfs_virusfilter_clamav.c
blobfb93caeded6663e1477e4c8d24c2e4c4466b7342
1 /*
2 Samba-VirusFilter VFS modules
3 ClamAV clamd 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 /* Default values for standard "extra" configuration variables */
22 #ifdef CLAMAV_DEFAULT_SOCKET_PATH
23 # define VIRUSFILTER_DEFAULT_SOCKET_PATH CLAMAV_DEFAULT_SOCKET_PATH
24 #else
25 # define VIRUSFILTER_DEFAULT_SOCKET_PATH "/var/run/clamav/clamd.ctl"
26 #endif
28 #include "modules/vfs_virusfilter_common.h"
29 #include "modules/vfs_virusfilter_utils.h"
31 static int virusfilter_clamav_connect(struct vfs_handle_struct *handle,
32 struct virusfilter_config *config,
33 const char *svc,
34 const char *user)
37 /* To use clamd "zXXXX" commands */
38 virusfilter_io_set_writel_eol(config->io_h, "\0", 1);
39 virusfilter_io_set_readl_eol(config->io_h, "\0", 1);
41 return 0;
44 static virusfilter_result virusfilter_clamav_scan_init(
45 struct virusfilter_config *config)
47 struct virusfilter_io_handle *io_h = config->io_h;
48 bool ok;
50 DBG_INFO("clamd: Connecting to socket: %s\n",
51 config->socket_path);
53 become_root();
54 ok = virusfilter_io_connect_path(io_h, config->socket_path);
55 unbecome_root();
57 if (!ok) {
58 DBG_ERR("clamd: Connecting to socket failed: %s: %s\n",
59 config->socket_path, strerror(errno));
60 return VIRUSFILTER_RESULT_ERROR;
63 DBG_INFO("clamd: Connected\n");
65 return VIRUSFILTER_RESULT_OK;
68 static void virusfilter_clamav_scan_end(
69 struct virusfilter_config *config)
71 struct virusfilter_io_handle *io_h = config->io_h;
73 DBG_INFO("clamd: Disconnecting\n");
75 virusfilter_io_disconnect(io_h);
78 static virusfilter_result virusfilter_clamav_scan(
79 struct vfs_handle_struct *handle,
80 struct virusfilter_config *config,
81 const struct files_struct *fsp,
82 char **reportp)
84 char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
85 const char *fname = fsp->fsp_name->base_name;
86 size_t filepath_len = strlen(cwd_fname) + 1 /* slash */ + strlen(fname);
87 struct virusfilter_io_handle *io_h = config->io_h;
88 virusfilter_result result = VIRUSFILTER_RESULT_CLEAN;
89 char *report = NULL;
90 char *reply = NULL;
91 char *reply_msg = NULL;
92 char *reply_token;
93 bool ok;
95 DBG_INFO("Scanning file: %s/%s\n", cwd_fname, fname);
97 ok = virusfilter_io_writefl_readl(io_h, &reply, "zSCAN %s/%s",
98 cwd_fname, fname);
99 if (!ok) {
100 DBG_ERR("clamd: zSCAN: I/O error: %s\n", strerror(errno));
101 result = VIRUSFILTER_RESULT_ERROR;
102 report = talloc_asprintf(talloc_tos(),
103 "Scanner I/O error: %s\n",
104 strerror(errno));
105 goto virusfilter_clamav_scan_return;
108 if (reply[filepath_len] != ':' ||
109 reply[filepath_len+1] != ' ')
111 DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
112 reply);
113 result = VIRUSFILTER_RESULT_ERROR;
114 report = talloc_asprintf(talloc_tos(),
115 "Scanner communication error");
116 goto virusfilter_clamav_scan_return;
118 reply_msg = reply + filepath_len + 2;
120 reply_token = strrchr(reply, ' ');
122 if (reply_token == NULL) {
123 DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
124 reply);
125 result = VIRUSFILTER_RESULT_ERROR;
126 report = talloc_asprintf(talloc_tos(),
127 "Scanner communication error");
128 goto virusfilter_clamav_scan_return;
130 *reply_token = '\0';
131 reply_token++;
133 if (strcmp(reply_token, "OK") == 0) {
135 /* <FILEPATH>: OK */
136 result = VIRUSFILTER_RESULT_CLEAN;
137 report = talloc_asprintf(talloc_tos(), "Clean");
138 } else if (strcmp(reply_token, "FOUND") == 0) {
140 /* <FILEPATH>: <REPORT> FOUND */
141 result = VIRUSFILTER_RESULT_INFECTED;
142 report = talloc_strdup(talloc_tos(), reply_msg);
143 } else if (strcmp(reply_token, "ERROR") == 0) {
145 /* <FILEPATH>: <REPORT> ERROR */
146 DBG_ERR("clamd: zSCAN: Error: %s\n", reply_msg);
147 result = VIRUSFILTER_RESULT_ERROR;
148 report = talloc_asprintf(talloc_tos(),
149 "Scanner error: %s\t", reply_msg);
150 } else {
151 DBG_ERR("clamd: zSCAN: Invalid reply: %s\n", reply_token);
152 result = VIRUSFILTER_RESULT_ERROR;
153 report = talloc_asprintf(talloc_tos(),
154 "Scanner communication error");
157 virusfilter_clamav_scan_return:
158 TALLOC_FREE(reply);
159 if (report == NULL) {
160 *reportp = talloc_asprintf(talloc_tos(),
161 "Scanner report memory error");
162 } else {
163 *reportp = report;
166 return result;
169 static struct virusfilter_backend_fns virusfilter_backend_clamav = {
170 .connect = virusfilter_clamav_connect,
171 .disconnect = NULL,
172 .scan_init = virusfilter_clamav_scan_init,
173 .scan = virusfilter_clamav_scan,
174 .scan_end = virusfilter_clamav_scan_end,
177 int virusfilter_clamav_init(struct virusfilter_config *config)
179 struct virusfilter_backend *backend = NULL;
181 if (config->socket_path == NULL) {
182 config->socket_path = VIRUSFILTER_DEFAULT_SOCKET_PATH;
185 backend = talloc_zero(config, struct virusfilter_backend);
186 if (backend == NULL) {
187 return -1;
190 backend->fns = &virusfilter_backend_clamav;
191 backend->name = "clamav";
193 config->backend = backend;
194 return 0;