2 * inoclam - Inotify+ClamAV virus scanner
3 * Copyright (C) 2007, 2008, 2009 Vermont Department of Taxes
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <libdaemon/dlog.h>
28 #include "inoclam.hxx"
29 #include "monitor.hxx"
37 * Thread that reloads virus definitions as needed
39 void *clam_refresh(void *v
)
43 struct cl_stat dbstat
;
48 memset(&dbstat
, 0, sizeof(struct cl_stat
));
49 cl_statinidir(cl_retdbdir(), &dbstat
);
52 if (cl_statchkdir(&dbstat
) == 1) {
53 struct cl_engine
*tmp_engine
= NULL
;
54 struct cl_engine
*old_engine
= NULL
;
56 daemon_log(LOG_INFO
, "Reloading new virus definitions");
58 /* TODO: make options configurable. */
59 /* For example: enable/disable CL_DB_NCORE, CL_DB_PHISHING_URLS, etc. */
62 /* prepare the detection engine */
63 tmp_engine
= cl_engine_new();
64 if (NULL
== tmp_engine
) {
65 daemon_log(LOG_ERR
, "cl_engine_new() error.");
69 /* Load virus definition files */
70 ret
= cl_load(cl_retdbdir(), tmp_engine
, &sigs
, CL_DB_STDOPT
);
71 if (CL_SUCCESS
!= ret
) {
72 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
73 cl_engine_free(tmp_engine
);
78 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
80 ret
= cl_engine_compile(tmp_engine
);
81 if (CL_SUCCESS
!= ret
) {
82 daemon_log(LOG_ERR
, "cl_engine_compile() error: %s", cl_strerror(ret
));
86 daemon_log(LOG_INFO
, "Virus detection engine ready.");
88 /* Swap tmp_engine and engine, free resources from old engine */
89 pthread_mutex_lock(&(clamav
->engine_lock
));
90 old_engine
= clamav
->engine
;
91 clamav
->engine
= tmp_engine
;
93 daemon_log(LOG_INFO
, "Virus detection engine ready.");
94 pthread_mutex_unlock(&(clamav
->engine_lock
));
96 cl_engine_free(old_engine
);
100 memset(&dbstat
, 0, sizeof(struct cl_stat
));
101 cl_statinidir(cl_retdbdir(), &dbstat
);
107 cl_statfree(&dbstat
);
110 clamav
->refresh_thread_alive
= false;
115 * Load the virus definition files and prepare the engine.
119 unsigned int sigs
= 0;
125 refresh_thread_alive
= false;
127 memset(&engine_lock
, '\0', sizeof(pthread_mutex_t
));
128 pthread_mutex_init(&engine_lock
, 0);
129 pthread_mutex_lock(&engine_lock
);
131 /* Initialize libclamav */
132 ret
= cl_init(CL_INIT_DEFAULT
);
133 if (CL_SUCCESS
!= ret
) {
134 pthread_mutex_unlock(&engine_lock
);
135 daemon_log(LOG_ERR
, "cl_init() error: %s", cl_strerror(ret
));
140 /* prepare the detection engine */
141 engine
= cl_engine_new();
142 if (NULL
== engine
) {
143 pthread_mutex_unlock(&engine_lock
);
144 daemon_log(LOG_ERR
, "cl_engine_new() error.");
148 /* Load virus definition files */
149 ret
= cl_load(cl_retdbdir(), engine
, &sigs
, CL_DB_STDOPT
);
150 if (CL_SUCCESS
!= ret
) {
151 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
152 cl_engine_free(engine
);
157 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
159 ret
= cl_engine_compile(engine
);
160 if (CL_SUCCESS
!= ret
) {
161 daemon_log(LOG_ERR
, "cl_engine_compile() error: %s", cl_strerror(ret
));
162 cl_engine_free(engine
);
167 daemon_log(LOG_INFO
, "Virus detection engine ready.");
168 pthread_mutex_unlock(&engine_lock
);
170 refresh_thread_alive
= true;
172 pthread_attr_init(&ta
);
173 pthread_attr_setdetachstate(&ta
, PTHREAD_CREATE_DETACHED
);
174 ret
= pthread_create(&tt
, &ta
, clam_refresh
, (void *) this);
176 refresh_thread_alive
= false;
178 daemon_log(LOG_ERR
, "Can't create clam_refresh thread: %s", strerror(errno
));
183 * Scans a file for virus.
184 * @return -1 Error || 0 No Virus || +1 Virus Found
186 int clam::clam_scan(std::string
* filename
, config
* conf
)
191 pthread_mutex_lock(&engine_lock
);
193 /* TODO: make options configurable. */
194 /* For example: enable/disable CL_SCAN_BLOCKENCRYPTED, CL_SCAN_BLOCKMAX, CL_SCAN_OLE2, etc. */
196 daemon_log(LOG_INFO
, "About to scan '%s'", filename
->c_str());
198 ret
= cl_scanfile(filename
->c_str(), &virname
, NULL
, engine
, CL_SCAN_STDOPT
);
199 if (CL_VIRUS
== ret
) {
200 int file_removed
= 0;
202 pthread_mutex_unlock(&engine_lock
);
203 daemon_log(LOG_INFO
, "%s: %s FOUND", filename
->c_str(), virname
);
205 if (conf
->getVirusRemovalEnabled() == cfg_true
) {
207 rc
= unlink(filename
->c_str());
211 daemon_log(LOG_ERR
, "unlink failed for '%s': %s", filename
->c_str(), strerror(errno
));
215 if (conf
->getVirusEMailEnabled() == cfg_true
) {
217 * "File: <filename>\n"
218 * "Virus: <virname>\n"
219 * "Date: Thu, 28 Jun 2001 14:17:15 +0000\n"
220 * "Deleted: <Yes|No>\n"
222 * " (o_ Powered by: inoclam v1.0 (Bender)\n"
223 * " //\ Homepage: http://www.inoclam.org/\n"
224 * " V_/_ Author: Vermont Department of Taxes\n"
227 std::string
* smtp_body
;
228 smtp_body
= new std::string();
229 smtp_body
->append("File: ");
230 smtp_body
->append(filename
->c_str());
231 smtp_body
->append("\n");
234 vname
= new std::string(virname
);
235 smtp_body
->append("Virus: ");
236 smtp_body
->append(vname
->c_str());
237 smtp_body
->append("\n");
240 std::string
* tstamp
;
241 tstamp
= smtp_get_timestamp();
245 smtp_body
->append("Date: ");
246 smtp_body
->append(tstamp
->c_str());
247 smtp_body
->append("\n");
250 smtp_body
->append("Deleted: ");
252 std::string
* rmstatus
;
254 if (file_removed
== 1) {
255 rmstatus
= new std::string("Yes");
257 rmstatus
= new std::string("No");
260 smtp_body
->append(rmstatus
->c_str());
263 smtp_body
->append("\n\n");
265 std::string
* banner
;
266 banner
= smtp_get_banner();
267 smtp_body
->append(banner
->c_str());
270 smtp_send(conf
->getVirusEMailSubject(), smtp_body
, conf
);
272 delete smtp_body
; /* Clean up email string */
276 } else if (CL_CLEAN
== ret
) {
277 pthread_mutex_unlock(&engine_lock
);
278 daemon_log(LOG_INFO
, "%s: OK", filename
->c_str());
281 pthread_mutex_unlock(&engine_lock
);
282 daemon_log(LOG_ERR
, "Scan Error: %s (%s)", cl_strerror(ret
), filename
->c_str());
288 * Free resources used by the engine.
292 pthread_mutex_lock(&engine_lock
);
295 cl_engine_free(engine
);
299 while (refresh_thread_alive
) {
304 pthread_mutex_unlock(&engine_lock
);
305 pthread_mutex_destroy(&engine_lock
);
306 pthread_attr_destroy(&ta
);