Fix compile errors in clam.cxx and inoclam.cxx
[inoclam.git] / src / clam.cxx
blobb6dfc57da2e4352c9557e32163b5ac5672141633
1 /*
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
19 #include <unistd.h>
20 #include <clamav.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <libdaemon/dlog.h>
26 #include <pthread.h>
27 #include "clam.hxx"
28 #include "inoclam.hxx"
29 #include "monitor.hxx"
30 #include "signal.hxx"
31 #include "smtp.hxx"
32 #include "config.hxx"
34 #include <string>
36 /**
37 * Thread that reloads virus definitions as needed
39 void *clam_refresh(void *v)
41 unsigned int sigs;
42 int ret;
43 struct cl_stat dbstat;
45 clam *clamav;
46 clamav = (clam *) v;
48 memset(&dbstat, 0, sizeof(struct cl_stat));
49 cl_statinidir(cl_retdbdir(), &dbstat);
51 do {
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));
65 tmp_engine = NULL;
66 continue;
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));
75 cl_free(tmp_engine);
76 tmp_engine = NULL;
77 continue;
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;
84 tmp_engine = NULL;
85 daemon_log(LOG_INFO, "Virus detection engine ready.");
86 pthread_mutex_unlock(&(clamav->engine_lock));
88 cl_free(old_engine);
89 old_engine = NULL;
91 cl_statfree(&dbstat);
92 memset(&dbstat, 0, sizeof(struct cl_stat));
93 cl_statinidir(cl_retdbdir(), &dbstat);
96 sleep(5);
97 } while (!exit_now);
99 cl_statfree(&dbstat);
101 monitor_dec();
102 clamav->refresh_thread_alive = false;
103 return NULL;
107 * Load the virus definition files and prepare the engine.
109 clam::clam()
111 unsigned int sigs = 0;
112 int ret;
114 pthread_t tt;
116 engine = NULL;
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));
128 engine = NULL;
129 return;
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));
139 cl_free(engine);
140 engine = NULL;
141 return;
144 daemon_log(LOG_INFO, "Virus detection engine ready.");
145 pthread_mutex_unlock(&engine_lock);
147 refresh_thread_alive = true;
148 monitor_inc();
149 pthread_attr_init(&ta);
150 pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);
151 ret = pthread_create(&tt, &ta, clam_refresh, (void *) this);
152 if (ret) {
153 refresh_thread_alive = false;
154 monitor_dec();
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)
165 int ret;
166 struct cl_limits limits;
167 const char *virname;
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) {
184 int rc;
185 rc = unlink(filename->c_str());
186 if (rc == 0) {
187 file_removed = 1;
188 } else {
189 daemon_log(LOG_ERR, "unlink failed for '%s': %s", filename->c_str(), strerror(errno));
193 if (conf->getVirusEMailEnabled() == cfg_true) {
194 /* Sample Message:
195 * "File: <filename>\n"
196 * "Virus: <virname>\n"
197 * "Date: Thu, 28 Jun 2001 14:17:15 +0000\n"
198 * "Deleted: <Yes|No>\n"
199 * "\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");
211 std::string * vname;
212 vname = new std::string(virname);
213 smtp_body->append("Virus: ");
214 smtp_body->append(vname->c_str());
215 smtp_body->append("\n");
216 delete vname;
218 std::string * tstamp;
219 tstamp = smtp_get_timestamp();
220 if (!tstamp) {
221 return -1;
223 smtp_body->append("Date: ");
224 smtp_body->append(tstamp->c_str());
225 smtp_body->append("\n");
226 delete tstamp;
228 smtp_body->append("Deleted: ");
230 std::string * rmstatus;
232 if (file_removed == 1) {
233 rmstatus = new std::string("Yes");
234 } else {
235 rmstatus = new std::string("No");
238 smtp_body->append(rmstatus->c_str());
239 delete rmstatus;
241 smtp_body->append("\n\n");
243 std::string * banner;
244 banner = smtp_get_banner();
245 smtp_body->append(banner->c_str());
246 delete banner;
248 smtp_send(conf->getVirusEMailSubject(), smtp_body, conf);
250 delete smtp_body; /* Clean up email string */
253 return 1;
254 } else if (CL_CLEAN == ret) {
255 pthread_mutex_unlock(&engine_lock);
256 daemon_log(LOG_INFO, "%s: OK", filename->c_str());
257 return 0;
258 } else {
259 pthread_mutex_unlock(&engine_lock);
260 daemon_log(LOG_ERR, "Scan Error: %s (%s)", cl_strerror(ret), filename->c_str());
261 return -1;
266 * Free resources used by the engine.
268 clam::~clam()
270 pthread_mutex_lock(&engine_lock);
272 if (engine) {
273 cl_free(engine);
274 engine = NULL;
277 while (refresh_thread_alive) {
278 sched_yield();
279 sleep(3);
282 pthread_mutex_unlock(&engine_lock);
283 pthread_mutex_destroy(&engine_lock);
284 pthread_attr_destroy(&ta);