Line data Source code
1 : /*
2 : Samba-VirusFilter VFS modules
3 : ClamAV clamd support
4 : Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : /* Default values for standard "extra" configuration variables */
21 :
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
27 :
28 : #include "modules/vfs_virusfilter_common.h"
29 : #include "modules/vfs_virusfilter_utils.h"
30 :
31 0 : static int virusfilter_clamav_connect(struct vfs_handle_struct *handle,
32 : struct virusfilter_config *config,
33 : const char *svc,
34 : const char *user)
35 : {
36 :
37 : /* To use clamd "zXXXX" commands */
38 0 : virusfilter_io_set_writel_eol(config->io_h, "\0", 1);
39 0 : virusfilter_io_set_readl_eol(config->io_h, "\0", 1);
40 :
41 0 : return 0;
42 : }
43 :
44 0 : static virusfilter_result virusfilter_clamav_scan_init(
45 : struct virusfilter_config *config)
46 : {
47 0 : struct virusfilter_io_handle *io_h = config->io_h;
48 : bool ok;
49 :
50 0 : DBG_INFO("clamd: Connecting to socket: %s\n",
51 : config->socket_path);
52 :
53 0 : become_root();
54 0 : ok = virusfilter_io_connect_path(io_h, config->socket_path);
55 0 : unbecome_root();
56 :
57 0 : if (!ok) {
58 0 : DBG_ERR("clamd: Connecting to socket failed: %s: %s\n",
59 : config->socket_path, strerror(errno));
60 0 : return VIRUSFILTER_RESULT_ERROR;
61 : }
62 :
63 0 : DBG_INFO("clamd: Connected\n");
64 :
65 0 : return VIRUSFILTER_RESULT_OK;
66 : }
67 :
68 0 : static void virusfilter_clamav_scan_end(
69 : struct virusfilter_config *config)
70 : {
71 0 : struct virusfilter_io_handle *io_h = config->io_h;
72 :
73 0 : DBG_INFO("clamd: Disconnecting\n");
74 :
75 0 : virusfilter_io_disconnect(io_h);
76 0 : }
77 :
78 0 : 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)
83 : {
84 0 : char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
85 0 : const char *fname = fsp->fsp_name->base_name;
86 0 : size_t filepath_len = strlen(cwd_fname) + 1 /* slash */ + strlen(fname);
87 0 : struct virusfilter_io_handle *io_h = config->io_h;
88 0 : virusfilter_result result = VIRUSFILTER_RESULT_CLEAN;
89 0 : char *report = NULL;
90 0 : char *reply = NULL;
91 0 : char *reply_msg = NULL;
92 : char *reply_token;
93 : bool ok;
94 :
95 0 : DBG_INFO("Scanning file: %s/%s\n", cwd_fname, fname);
96 :
97 0 : ok = virusfilter_io_writefl_readl(io_h, &reply, "zSCAN %s/%s",
98 : cwd_fname, fname);
99 0 : if (!ok) {
100 0 : DBG_ERR("clamd: zSCAN: I/O error: %s\n", strerror(errno));
101 0 : result = VIRUSFILTER_RESULT_ERROR;
102 0 : report = talloc_asprintf(talloc_tos(),
103 : "Scanner I/O error: %s\n",
104 0 : strerror(errno));
105 0 : goto virusfilter_clamav_scan_return;
106 : }
107 :
108 0 : if (reply[filepath_len] != ':' ||
109 0 : reply[filepath_len+1] != ' ')
110 : {
111 0 : DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
112 : reply);
113 0 : result = VIRUSFILTER_RESULT_ERROR;
114 0 : report = talloc_asprintf(talloc_tos(),
115 : "Scanner communication error");
116 0 : goto virusfilter_clamav_scan_return;
117 : }
118 0 : reply_msg = reply + filepath_len + 2;
119 :
120 0 : reply_token = strrchr(reply, ' ');
121 :
122 0 : if (reply_token == NULL) {
123 0 : DBG_ERR("clamd: zSCAN: Invalid reply: %s\n",
124 : reply);
125 0 : result = VIRUSFILTER_RESULT_ERROR;
126 0 : report = talloc_asprintf(talloc_tos(),
127 : "Scanner communication error");
128 0 : goto virusfilter_clamav_scan_return;
129 : }
130 0 : *reply_token = '\0';
131 0 : reply_token++;
132 :
133 0 : if (strcmp(reply_token, "OK") == 0) {
134 :
135 : /* <FILEPATH>: OK */
136 0 : result = VIRUSFILTER_RESULT_CLEAN;
137 0 : report = talloc_asprintf(talloc_tos(), "Clean");
138 0 : } else if (strcmp(reply_token, "FOUND") == 0) {
139 :
140 : /* <FILEPATH>: <REPORT> FOUND */
141 0 : result = VIRUSFILTER_RESULT_INFECTED;
142 0 : report = talloc_strdup(talloc_tos(), reply_msg);
143 0 : } else if (strcmp(reply_token, "ERROR") == 0) {
144 :
145 : /* <FILEPATH>: <REPORT> ERROR */
146 0 : DBG_ERR("clamd: zSCAN: Error: %s\n", reply_msg);
147 0 : result = VIRUSFILTER_RESULT_ERROR;
148 0 : report = talloc_asprintf(talloc_tos(),
149 : "Scanner error: %s\t", reply_msg);
150 : } else {
151 0 : DBG_ERR("clamd: zSCAN: Invalid reply: %s\n", reply_token);
152 0 : result = VIRUSFILTER_RESULT_ERROR;
153 0 : report = talloc_asprintf(talloc_tos(),
154 : "Scanner communication error");
155 : }
156 :
157 0 : virusfilter_clamav_scan_return:
158 0 : TALLOC_FREE(reply);
159 0 : if (report == NULL) {
160 0 : *reportp = talloc_asprintf(talloc_tos(),
161 : "Scanner report memory error");
162 : } else {
163 0 : *reportp = report;
164 : }
165 :
166 0 : return result;
167 : }
168 :
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,
175 : };
176 :
177 0 : int virusfilter_clamav_init(struct virusfilter_config *config)
178 : {
179 0 : struct virusfilter_backend *backend = NULL;
180 :
181 0 : if (config->socket_path == NULL) {
182 0 : config->socket_path = VIRUSFILTER_DEFAULT_SOCKET_PATH;
183 : }
184 :
185 0 : backend = talloc_zero(config, struct virusfilter_backend);
186 0 : if (backend == NULL) {
187 0 : return -1;
188 : }
189 :
190 0 : backend->fns = &virusfilter_backend_clamav;
191 0 : backend->name = "clamav";
192 :
193 0 : config->backend = backend;
194 0 : return 0;
195 : }
|