2 * inoclam - Inotify+ClamAV virus scanner
3 * Copyright (C) 2007 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
19 * Tom Cort <tom.cort@state.vt.us>
20 * Matt Gagne <matt.gagne@state.vt.us>
29 #include <libdaemon/dlog.h>
32 #include "inoclam.hxx"
33 #include "monitor.hxx"
41 * Thread that reloads virus definitions as needed
43 void *clam_refresh(void *v
)
47 struct cl_stat dbstat
;
52 memset(&dbstat
, 0, sizeof(struct cl_stat
));
53 cl_statinidir(cl_retdbdir(), &dbstat
);
56 if (cl_statchkdir(&dbstat
) == 1) {
57 struct cl_engine
*tmp_engine
= NULL
;
58 struct cl_engine
*old_engine
= NULL
;
60 daemon_log(LOG_INFO
, "Reloading new virus definitions");
62 /* TODO: make options configurable. */
63 /* For example: enable/disable CL_DB_NCORE, CL_DB_PHISHING_URLS, etc. */
65 /* Load virus definition files */
66 ret
= cl_load(cl_retdbdir(), &tmp_engine
, &sigs
, CL_DB_STDOPT
);
67 if (CL_SUCCESS
!= ret
) {
68 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
73 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
75 /* prepare the detection engine */
76 ret
= cl_build(tmp_engine
);
77 if (CL_SUCCESS
!= ret
) {
78 daemon_log(LOG_ERR
, "cl_build() error: %s", cl_strerror(ret
));
84 /* Swap tmp_engine and engine, free resources from old engine */
85 pthread_mutex_lock(&(clamav
->engine_lock
));
86 old_engine
= clamav
->engine
;
87 clamav
->engine
= tmp_engine
;
89 daemon_log(LOG_INFO
, "Virus detection engine ready.");
90 pthread_mutex_unlock(&(clamav
->engine_lock
));
96 memset(&dbstat
, 0, sizeof(struct cl_stat
));
97 cl_statinidir(cl_retdbdir(), &dbstat
);
103 cl_statfree(&dbstat
);
106 clamav
->refresh_thread_alive
= false;
111 * Load the virus definition files and prepare the engine.
115 unsigned int sigs
= 0;
121 refresh_thread_alive
= false;
123 memset(&engine_lock
, '\0', sizeof(pthread_mutex_t
));
124 pthread_mutex_init(&engine_lock
, 0);
125 pthread_mutex_lock(&engine_lock
);
127 /* Load virus definition files */
128 ret
= cl_load(cl_retdbdir(), &engine
, &sigs
, CL_DB_STDOPT
);
129 if (CL_SUCCESS
!= ret
) {
130 pthread_mutex_unlock(&engine_lock
);
131 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
136 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
138 /* prepare the detection engine */
139 ret
= cl_build(engine
);
140 if (CL_SUCCESS
!= ret
) {
141 pthread_mutex_unlock(&engine_lock
);
142 daemon_log(LOG_ERR
, "cl_build() error: %s", cl_strerror(ret
));
148 daemon_log(LOG_INFO
, "Virus detection engine ready.");
149 pthread_mutex_unlock(&engine_lock
);
151 refresh_thread_alive
= true;
153 pthread_attr_init(&ta
);
154 pthread_attr_setdetachstate(&ta
, PTHREAD_CREATE_DETACHED
);
155 ret
= pthread_create(&tt
, &ta
, clam_refresh
, (void *) this);
157 refresh_thread_alive
= false;
159 daemon_log(LOG_ERR
, "Can't create clam_refresh thread: %s", strerror(errno
));
164 * Scans a file for virus.
165 * @return -1 Error || 0 No Virus || +1 Virus Found
167 int clam::clam_scan(std::string
* filename
, config
* conf
)
170 struct cl_limits limits
;
173 pthread_mutex_lock(&engine_lock
);
175 memset(&limits
, 0, sizeof(struct cl_limits
));
177 limits
.maxfilesize
= 10 * 1048576;
178 limits
.maxreclevel
= 1;
179 limits
.maxmailrec
= 1;
180 limits
.maxratio
= 200;
182 /* TODO: make options configurable. */
183 /* For example: enable/disable CL_SCAN_BLOCKENCRYPTED, CL_SCAN_BLOCKMAX, CL_SCAN_OLE2, etc. */
185 ret
= cl_scanfile(filename
->c_str(), &virname
, NULL
, engine
, &limits
, CL_SCAN_STDOPT
);
186 if (CL_VIRUS
== ret
) {
187 int file_removed
= 0;
189 pthread_mutex_unlock(&engine_lock
);
190 daemon_log(LOG_INFO
, "%s: %s FOUND", filename
->c_str(), virname
);
192 if (conf
->getVirusRemovalEnabled() == cfg_true
) {
194 rc
= unlink(filename
->c_str());
198 daemon_log(LOG_ERR
, "unlink failed for '%s': %s", filename
->c_str(), strerror(errno
));
202 if (conf
->getVirusEMailEnabled() == cfg_true
) {
204 * "File: <filename>\n"
205 * "Virus: <virname>\n"
206 * "Date: Thu, 28 Jun 2001 14:17:15 +0000\n"
207 * "Deleted: <Yes|No>\n"
209 * " (o_ Powered by: inoclam v1.0 (Bender)\n"
210 * " //\ Homepage: http://www.inoclam.org/\n"
211 * " V_/_ Author: Vermont Department of Taxes\n"
214 std::string
* smtp_body
;
215 smtp_body
= new std::string();
216 smtp_body
->append("File: ");
217 smtp_body
->append(filename
->c_str());
218 smtp_body
->append("\n");
221 vname
= new std::string(virname
);
222 smtp_body
->append("Virus: ");
223 smtp_body
->append(vname
->c_str());
224 smtp_body
->append("\n");
227 std::string
* tstamp
;
228 tstamp
= smtp_get_timestamp();
232 smtp_body
->append("Date: ");
233 smtp_body
->append(tstamp
->c_str());
234 smtp_body
->append("\n");
237 smtp_body
->append("Deleted: ");
239 std::string
* rmstatus
;
241 if (file_removed
== 1) {
242 rmstatus
= new std::string("Yes");
244 rmstatus
= new std::string("No");
247 smtp_body
->append(rmstatus
->c_str());
250 smtp_body
->append("\n\n");
252 std::string
* banner
;
253 banner
= smtp_get_banner();
254 smtp_body
->append(banner
->c_str());
257 smtp_send(conf
->getVirusEMailSubject(), smtp_body
, conf
);
259 delete smtp_body
; /* Clean up email string */
263 } else if (CL_CLEAN
== ret
) {
264 pthread_mutex_unlock(&engine_lock
);
265 daemon_log(LOG_INFO
, "%s: OK", filename
->c_str());
268 pthread_mutex_unlock(&engine_lock
);
269 daemon_log(LOG_ERR
, "Scan Error: %s (%s)", cl_strerror(ret
), filename
->c_str());
275 * Free resources used by the engine.
279 pthread_mutex_lock(&engine_lock
);
286 while (refresh_thread_alive
) {
291 pthread_mutex_unlock(&engine_lock
);
292 pthread_mutex_destroy(&engine_lock
);
293 pthread_attr_destroy(&ta
);