Browse code

clamd: add support for on-access scanning on OS X with ClamAuth (beta)

Tomasz Kojm authored on 2012/03/03 03:49:12
Showing 7 changed files
... ...
@@ -1,3 +1,7 @@
1
+Fri Mar  2 19:48:36 CET 2012 (tk)
2
+---------------------------------
3
+ * clamd: add support for on-access scanning on OS X with ClamAuth (beta)
4
+
1 5
 Wed Feb 29 17:02:18 EET 2012 (edwin)
2 6
 ------------------------------------
3 7
  * libclamav/bytecode_api*: Fix Sparc crash (bb #4324)
... ...
@@ -12,6 +12,9 @@
12 12
 /* "build clamd" */
13 13
 #undef BUILD_CLAMD
14 14
 
15
+/* enable ClamAuth */
16
+#undef CLAMAUTH
17
+
15 18
 /* name of the clamav group */
16 19
 #undef CLAMAVGROUP
17 20
 
... ...
@@ -231,4 +231,142 @@ void *clamukoth(void *arg)
231 231
     return clamukofsth(arg);
232 232
 }
233 233
 
234
+#elif defined(CLAMAUTH)
235
+
236
+#include <stdio.h>
237
+#include <unistd.h>
238
+#include <sys/types.h>
239
+#include <sys/stat.h>
240
+#include <sys/uio.h>
241
+#include <fcntl.h>
242
+#include <signal.h>
243
+#include <pthread.h>
244
+#include <string.h>
245
+#include <errno.h>
246
+
247
+#include "libclamav/clamav.h"
248
+#include "libclamav/scanners.h"
249
+
250
+#include "shared/optparser.h"
251
+#include "shared/output.h"
252
+
253
+#include "server.h"
254
+#include "others.h"
255
+#include "scanner.h"
256
+
257
+#define SUPPORTED_PROTOCOL  2
258
+
259
+static int cauth_fd = -1;
260
+
261
+struct ClamAuthEvent {
262
+    unsigned int action;
263
+    char path[1024];
264
+    unsigned int pid;
265
+};
266
+
267
+static void cauth_exit(int sig)
268
+{
269
+    logg("*ClamAuth: cauth_exit(), signal %d\n", sig);
270
+    if(cauth_fd > 0)
271
+	close(cauth_fd);
272
+    pthread_exit(NULL);
273
+    logg("ClamAuth: stopped\n");
274
+}
275
+
276
+static int cauth_scanfile(const char *fname, int extinfo, struct thrarg *tharg)
277
+{
278
+	struct cb_context context;
279
+	const char *virname;
280
+	int ret = 0, fd;
281
+
282
+    context.filename = fname;
283
+    context.virsize = 0;
284
+
285
+    fd = open(fname, O_RDONLY);
286
+    if(fd == -1)
287
+	return -1;
288
+
289
+    if(cl_scandesc_callback(fd, &virname, NULL, tharg->engine, tharg->options, &context) == CL_VIRUS) {
290
+	if(context.virsize)
291
+	    detstats_add(virname, fname, context.virsize, context.virhash);
292
+	if(extinfo && context.virsize)
293
+	    logg("ClamAuth: %s: %s(%s:%llu) FOUND\n", fname, virname, context.virhash, context.virsize);
294
+	else
295
+	    logg("ClamAuth: %s: %s FOUND\n", fname, virname);
296
+	virusaction(fname, virname, tharg->opts);
297
+    }
298
+    close(fd);
299
+    return ret;
300
+}
301
+
302
+void *clamukoth(void *arg)
303
+{
304
+	struct thrarg *tharg = (struct thrarg *) arg;
305
+	sigset_t sigset;
306
+        struct sigaction act;
307
+	int eventcnt = 1, extinfo;
308
+	char err[128];
309
+	struct ClamAuthEvent event;
310
+
311
+    /* ignore all signals except SIGUSR1 */
312
+    sigfillset(&sigset);
313
+    sigdelset(&sigset, SIGUSR1);
314
+    /* The behavior of a process is undefined after it ignores a 
315
+     * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */
316
+    sigdelset(&sigset, SIGFPE);
317
+    sigdelset(&sigset, SIGILL);
318
+    sigdelset(&sigset, SIGSEGV);
319
+#ifdef SIGBUS    
320
+    sigdelset(&sigset, SIGBUS);
321
+#endif
322
+    pthread_sigmask(SIG_SETMASK, &sigset, NULL);
323
+    memset(&act, 0, sizeof(struct sigaction));
324
+    act.sa_handler = cauth_exit;
325
+    sigfillset(&(act.sa_mask));
326
+    sigaction(SIGUSR1, &act, NULL);
327
+    sigaction(SIGSEGV, &act, NULL);
328
+
329
+    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;
330
+
331
+    cauth_fd = open("/dev/clamauth", O_RDONLY);
332
+    if(cauth_fd == -1) {
333
+	logg("!ClamAuth: Can't open /dev/clamauth\n");
334
+	if(errno == ENOENT)
335
+	    logg("!ClamAuth: Please make sure ClamAuth.kext is loaded\n");
336
+	else if(errno == EACCES)
337
+	    logg("!ClamAuth: This application requires root privileges\n");
338
+	else
339
+	    logg("!ClamAuth: /dev/clamauth: %s\n", cli_strerror(errno, err, sizeof(err)));
340
+
341
+	return NULL;
342
+    }
343
+
344
+    while(1) {
345
+	if(read(cauth_fd, &event, sizeof(event)) > 0) {
346
+	    if(eventcnt == 1) {
347
+		if(event.action != SUPPORTED_PROTOCOL) {
348
+		    logg("!ClamAuth: Protocol version mismatch (tool: %d, driver: %d)\n", SUPPORTED_PROTOCOL, event.action);
349
+		    close(cauth_fd);
350
+		    return NULL;
351
+		}
352
+		if(strncmp(event.path, "ClamAuth", 8)) {
353
+		    logg("!ClamAuth: Invalid version event\n");
354
+		    close(cauth_fd);
355
+		    return NULL;
356
+		}
357
+		logg("ClamAuth: Driver version: %s, protocol version: %d\n", &event.path[9], event.action);
358
+	    } else {
359
+		cauth_scanfile(event.path, extinfo, tharg);
360
+	    }
361
+	    eventcnt++;
362
+	} else {
363
+	    if(errno == ENODEV) {
364
+		printf("^ClamAuth: ClamAuth module deactivated, terminating\n");
365
+		close(cauth_fd);
366
+		return NULL;
367
+	    }
368
+	}
369
+	usleep(200);
370
+    }
371
+}
234 372
 #endif
... ...
@@ -709,7 +709,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
709 709
 	unsigned int selfchk;
710 710
 	threadpool_t *thr_pool;
711 711
 
712
-#ifdef CLAMUKO
712
+#if defined(CLAMUKO) || defined(CLAMAUTH)
713 713
 	pthread_t clamuko_pid;
714 714
 	pthread_attr_t clamuko_attr;
715 715
 	struct thrarg *tharg = NULL; /* shut up gcc */
... ...
@@ -1005,7 +1005,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1005 1005
     acceptdata.max_queue = max_queue;
1006 1006
 
1007 1007
     if(optget(opts, "ClamukoScanOnAccess")->enabled)
1008
-#ifdef CLAMUKO
1008
+#if defined(CLAMUKO) || defined(CLAMAUTH)
1009 1009
     {
1010 1010
         do {
1011 1011
 	    if(pthread_attr_init(&clamuko_attr)) break;
... ...
@@ -1284,8 +1284,8 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1284 1284
 	pthread_mutex_lock(&reload_mutex);
1285 1285
 	if(reload) {
1286 1286
 	    pthread_mutex_unlock(&reload_mutex);
1287
-#ifdef CLAMUKO
1288
-	    if(optget(opts, "ClamukoScanOnAccess")->enabled && tharg) {
1287
+#if defined(CLAMUKO) || defined(CLAMAUTH)
1288
+	    if((optget(opts, "ClamukoScanOnAccess")->enabled || optget(opts, "ClamAuth")->enabled) && tharg) {
1289 1289
 		logg("Stopping and restarting Clamuko.\n");
1290 1290
 		pthread_kill(clamuko_pid, SIGUSR1);
1291 1291
 		pthread_join(clamuko_pid, NULL);
... ...
@@ -1303,8 +1303,8 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1303 1303
 	    reload = 0;
1304 1304
 	    time(&reloaded_time);
1305 1305
 	    pthread_mutex_unlock(&reload_mutex);
1306
-#ifdef CLAMUKO
1307
-	    if(optget(opts, "ClamukoScanOnAccess")->enabled && tharg) {
1306
+#if defined(CLAMUKO) || defined(CLAMAUTH)
1307
+	    if((optget(opts, "ClamukoScanOnAccess")->enabled || optget(opts, "ClamAuth")->enabled) && tharg) {
1308 1308
 		tharg->engine = engine;
1309 1309
 		pthread_create(&clamuko_pid, &clamuko_attr, clamukoth, tharg);
1310 1310
 	    }
... ...
@@ -1330,8 +1330,8 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1330 1330
      */
1331 1331
     logg("*Waiting for all threads to finish\n");
1332 1332
     thrmgr_destroy(thr_pool);
1333
-#ifdef CLAMUKO
1334
-    if(optget(opts, "ClamukoScanOnAccess")->enabled) {
1333
+#if defined(CLAMUKO) || defined(CLAMAUTH)
1334
+    if(optget(opts, "ClamukoScanOnAccess")->enabled || optget(opts, "ClamAuth")->enabled) {
1335 1335
 	logg("Stopping Clamuko.\n");
1336 1336
 	pthread_kill(clamuko_pid, SIGUSR1);
1337 1337
 	pthread_join(clamuko_pid, NULL);
... ...
@@ -16941,6 +16941,9 @@ $as_echo "#define C_DARWIN 1" >>confdefs.h
16941 16941
 
16942 16942
 $as_echo "#define BIND_8_COMPAT 1" >>confdefs.h
16943 16943
 
16944
+
16945
+$as_echo "#define CLAMAUTH 1" >>confdefs.h
16946
+
16944 16947
     use_netinfo="yes"
16945 16948
     ;;
16946 16949
 os2*)
... ...
@@ -1044,6 +1044,7 @@ darwin*)
1044 1044
     AC_DEFINE([C_BSD],1,[os is bsd flavor])
1045 1045
     AC_DEFINE([C_DARWIN],1,[os is darwin])
1046 1046
     AC_DEFINE([BIND_8_COMPAT],1,[enable bind8 compatibility])
1047
+    AC_DEFINE([CLAMAUTH],1,[enable ClamAuth])
1047 1048
     use_netinfo="yes"
1048 1049
     ;;
1049 1050
 os2*)
... ...
@@ -325,6 +325,8 @@ const struct clam_option __clam_options[] = {
325 325
 
326 326
     { "MaxFiles", "max-files", 0, TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXFILES, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Number of files to be scanned within an archive, a document, or any other\ncontainer file.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "10000" },
327 327
 
328
+    { "ClamAuth", NULL, 0, TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "This option enables on-access scanning with ClamAuth on OS X (BETA).", "no" },
329
+
328 330
     { "ClamukoScanOnAccess", NULL, 0, TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "This option enables Clamuko. Dazuko needs to be already configured and\nrunning.", "no" },
329 331
 
330 332
     { "ClamukoScannerCount", NULL, 0, TYPE_NUMBER, MATCH_NUMBER, 3, NULL, 0, OPT_CLAMD, "The number of scanner threads that will be started (DazukoFS only).\nHaving multiple scanner threads allows Clamuko to serve multiple\nprocesses simultaneously. This is particularly beneficial on SMP machines.", "3" },