2 * inoclam - Inotify+ClamAV virus scanner
3 * Copyright (C) 2007, 2008 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. */
61 /* Load virus definition files */
62 ret
= cl_load(cl_retdbdir(), &tmp_engine
, &sigs
, CL_DB_STDOPT
);
63 if (CL_SUCCESS
!= ret
) {
64 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
69 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
71 /* prepare the detection engine */
72 ret
= cl_build(tmp_engine
);
73 if (CL_SUCCESS
!= ret
) {
74 daemon_log(LOG_ERR
, "cl_build() error: %s", cl_strerror(ret
));
80 /* Swap tmp_engine and engine, free resources from old engine */
81 pthread_mutex_lock(&(clamav
->engine_lock
));
82 old_engine
= clamav
->engine
;
83 clamav
->engine
= tmp_engine
;
85 daemon_log(LOG_INFO
, "Virus detection engine ready.");
86 pthread_mutex_unlock(&(clamav
->engine_lock
));
92 memset(&dbstat
, 0, sizeof(struct cl_stat
));
93 cl_statinidir(cl_retdbdir(), &dbstat
);
102 clamav
->refresh_thread_alive
= false;
107 * Load the virus definition files and prepare the engine.
111 unsigned int sigs
= 0;
117 refresh_thread_alive
= false;
119 memset(&engine_lock
, '\0', sizeof(pthread_mutex_t
));
120 pthread_mutex_init(&engine_lock
, 0);
121 pthread_mutex_lock(&engine_lock
);
123 /* Load virus definition files */
124 ret
= cl_load(cl_retdbdir(), &engine
, &sigs
, CL_DB_STDOPT
);
125 if (CL_SUCCESS
!= ret
) {
126 pthread_mutex_unlock(&engine_lock
);
127 daemon_log(LOG_ERR
, "cl_load() error: %s", cl_strerror(ret
));
132 daemon_log(LOG_INFO
, "Virus definitions loaded (%d signatures).", sigs
);
134 /* prepare the detection engine */
135 ret
= cl_build(engine
);
136 if (CL_SUCCESS
!= ret
) {
137 pthread_mutex_unlock(&engine_lock
);
138 daemon_log(LOG_ERR
, "cl_build() error: %s", cl_strerror(ret
));
144 daemon_log(LOG_INFO
, "Virus detection engine ready.");
145 pthread_mutex_unlock(&engine_lock
);
147 refresh_thread_alive
= true;
149 pthread_attr_init(&ta
);
150 pthread_attr_setdetachstate(&ta
, PTHREAD_CREATE_DETACHED
);
151 ret
= pthread_create(&tt
, &ta
, clam_refresh
, (void *) this);
153 refresh_thread_alive
= false;
155 daemon_log(LOG_ERR
, "Can't create clam_refresh thread: %s", strerror(errno
));
160 * Scans a file for virus.
161 * @return -1 Error || 0 No Virus || +1 Virus Found
163 int clam::clam_scan(std::string
* filename
, config
* conf
)
166 struct cl_limits limits
;
169 pthread_mutex_lock(&engine_lock
);
171 memset(&limits
, 0, sizeof(struct cl_limits
));
173 /* TODO: make options configurable. */
174 /* For example: enable/disable CL_SCAN_BLOCKENCRYPTED, CL_SCAN_BLOCKMAX, CL_SCAN_OLE2, etc. */
176 ret
= cl_scanfile(filename
->c_str(), &virname
, NULL
, engine
, &limits
, CL_SCAN_STDOPT
);
177 if (CL_VIRUS
== ret
) {
178 int file_removed
= 0;
180 pthread_mutex_unlock(&engine_lock
);
181 daemon_log(LOG_INFO
, "%s: %s FOUND", filename
->c_str(), virname
);
183 if (conf
->getVirusRemovalEnabled() == cfg_true
) {
185 rc
= unlink(filename
->c_str());
189 daemon_log(LOG_ERR
, "unlink failed for '%s': %s", filename
->c_str(), strerror(errno
));
193 if (conf
->getVirusEMailEnabled() == cfg_true
) {
195 * "File: <filename>\n"
196 * "Virus: <virname>\n"
197 * "Date: Thu, 28 Jun 2001 14:17:15 +0000\n"
198 * "Deleted: <Yes|No>\n"
200 * " (o_ Powered by: inoclam v1.0 (Bender)\n"
201 * " //\ Homepage: http://www.inoclam.org/\n"
202 * " V_/_ Author: Vermont Department of Taxes\n"
205 std::string
* smtp_body
;
206 smtp_body
= new std::string();
207 smtp_body
->append("File: ");
208 smtp_body
->append(filename
->c_str());
209 smtp_body
->append("\n");
212 vname
= new std::string(virname
);
213 smtp_body
->append("Virus: ");
214 smtp_body
->append(vname
->c_str());
215 smtp_body
->append("\n");
218 std::string
* tstamp
;
219 tstamp
= smtp_get_timestamp();
223 smtp_body
->append("Date: ");
224 smtp_body
->append(tstamp
->c_str());
225 smtp_body
->append("\n");
228 smtp_body
->append("Deleted: ");
230 std::string
* rmstatus
;
232 if (file_removed
== 1) {
233 rmstatus
= new std::string("Yes");
235 rmstatus
= new std::string("No");
238 smtp_body
->append(rmstatus
->c_str());
241 smtp_body
->append("\n\n");
243 std::string
* banner
;
244 banner
= smtp_get_banner();
245 smtp_body
->append(banner
->c_str());
248 smtp_send(conf
->getVirusEMailSubject(), smtp_body
, conf
);
250 delete smtp_body
; /* Clean up email string */
254 } else if (CL_CLEAN
== ret
) {
255 pthread_mutex_unlock(&engine_lock
);
256 daemon_log(LOG_INFO
, "%s: OK", filename
->c_str());
259 pthread_mutex_unlock(&engine_lock
);
260 daemon_log(LOG_ERR
, "Scan Error: %s (%s)", cl_strerror(ret
), filename
->c_str());
266 * Free resources used by the engine.
270 pthread_mutex_lock(&engine_lock
);
277 while (refresh_thread_alive
) {
282 pthread_mutex_unlock(&engine_lock
);
283 pthread_mutex_destroy(&engine_lock
);
284 pthread_attr_destroy(&ta
);