mirror of https://github.com/Cisco-Talos/clamav
parent
0c190b52f7
commit
adc16eb592
@ -0,0 +1,249 @@ |
||||
/*
|
||||
* Copyright (C) 2007-2009 Sourcefire, Inc. |
||||
* Author: Tomasz Kojm |
||||
* Author: John Ogness <dazukocode@ogness.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||
* MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#if HAVE_CONFIG_H |
||||
#include "clamav-config.h" |
||||
#endif |
||||
|
||||
#ifdef CLAMUKO |
||||
|
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <signal.h> |
||||
#include <pthread.h> |
||||
|
||||
#include "libclamav/clamav.h" |
||||
|
||||
#include "shared/optparser.h" |
||||
#include "shared/output.h" |
||||
|
||||
#include "server.h" |
||||
#include "others.h" |
||||
#include "dazukofs.h" |
||||
#include "clamuko.h" |
||||
|
||||
static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER; |
||||
static dazukofs_handle_t shutdown_hndl; |
||||
static pthread_cond_t shutdown_cond; |
||||
|
||||
static void clamuko_exit(int sig) |
||||
{ |
||||
pthread_cond_signal(&shutdown_cond); |
||||
} |
||||
|
||||
static int setup_shutdown_handle(const char *groupname) |
||||
{ |
||||
/* is another server thread is already running? */ |
||||
if(shutdown_hndl) return -1; |
||||
|
||||
if(pthread_cond_init(&shutdown_cond, NULL)) return -1; |
||||
|
||||
/* handle used for shutdown by signal */ |
||||
shutdown_hndl = dazukofs_open(groupname, DAZUKOFS_TRACK_GROUP); |
||||
if(!shutdown_hndl) { |
||||
logg("!Clamuko: Can't register with DazukoFS\n"); |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void shutdown_clamuko(void) |
||||
{ |
||||
dazukofs_handle_t hndl = shutdown_hndl; |
||||
|
||||
/* Set shutdown_hndl before closing because the close will
|
||||
* immediately cause the scan threads to be interrupted. |
||||
* But they will only abort if shutdown_hndl is NULL. */ |
||||
shutdown_hndl = NULL; |
||||
|
||||
if(hndl) dazukofs_close(hndl, DAZUKOFS_REMOVE_GROUP); |
||||
} |
||||
|
||||
static void *clamuko_scanth(void *arg) |
||||
{ |
||||
struct thrarg *tharg = (struct thrarg *) arg; |
||||
sigset_t sigset; |
||||
short int scan; |
||||
unsigned int sizelimit = 0; |
||||
struct stat sb; |
||||
dazukofs_handle_t scan_hndl; |
||||
struct dazukofs_access acc; |
||||
const char *groupname = "ClamAV"; |
||||
int skip_scan = 0; |
||||
const char *virname; |
||||
char filename[4096]; |
||||
|
||||
/* ignore all signals */ |
||||
sigfillset(&sigset); |
||||
/* The behavior of a process is undefined after it ignores a
|
||||
* SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
||||
sigdelset(&sigset, SIGFPE); |
||||
sigdelset(&sigset, SIGILL); |
||||
sigdelset(&sigset, SIGSEGV); |
||||
#ifdef SIGBUS |
||||
sigdelset(&sigset, SIGBUS); |
||||
#endif |
||||
pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
||||
|
||||
/* register */ |
||||
scan_hndl = dazukofs_open(groupname, DAZUKOFS_TRACK_GROUP); |
||||
if(!scan_hndl) { |
||||
logg("!Clamuko: Can't register with DazukoFS\n"); |
||||
return NULL; |
||||
} else { |
||||
logg("Clamuko: Correctly registered with DazukoFS.\n"); |
||||
} |
||||
|
||||
/* access mask (not used by DazukoFS) */ |
||||
if(optget(tharg->opts, "ClamukoScanOnOpen")->enabled) |
||||
logg("!Clamuko: ClamukoScanOnOpen ignored when using DazukoFS.\n"); |
||||
if(optget(tharg->opts, "ClamukoScanOnClose")->enabled) |
||||
logg("!Clamuko: ClamukoScanOnClose ignored when using DazukoFS.\n"); |
||||
if(optget(tharg->opts, "ClamukoScanOnExec")->enabled) |
||||
logg("!Clamuko: ClamukoScanOnExec ignored when using DazukoFS.\n"); |
||||
if(optget(tharg->opts, "ClamukoIncludePath")->enabled) |
||||
logg("!Clamuko: ClamukoIncludePath ignored when using DazukoFS.\n"); |
||||
if(optget(tharg->opts, "ClamukoExcludePath")->enabled) |
||||
logg("!Clamuko: ClamukoExcludePath ignored when using DazukoFS.\n"); |
||||
|
||||
sizelimit = optget(tharg->opts, "ClamukoMaxFileSize")->numarg; |
||||
if(sizelimit) |
||||
logg("Clamuko: Max file size limited to %u bytes.\n", sizelimit); |
||||
else |
||||
logg("Clamuko: File size limit disabled.\n"); |
||||
|
||||
while(1) { |
||||
if(dazukofs_get_access(scan_hndl, &acc)) { |
||||
if(!shutdown_hndl) |
||||
break; |
||||
continue; |
||||
} |
||||
|
||||
if(!fstat(acc.fd, &sb)) { |
||||
if(S_ISDIR(sb.st_mode)) { |
||||
/* don't try to scan directories */ |
||||
skip_scan = 1; |
||||
} else if(sb.st_size > sizelimit) { |
||||
dazukofs_get_filename(&acc, filename, sizeof(filename)); |
||||
logg("*Clamuko: %s skipped (too big)\n", filename); |
||||
skip_scan = 1; |
||||
} |
||||
} |
||||
|
||||
if(skip_scan) { |
||||
acc.deny = 0; |
||||
/* reset skip flag */ |
||||
skip_scan = 0; |
||||
} else if(cl_scandesc(acc.fd, &virname, NULL, tharg->engine, |
||||
tharg->options) == CL_VIRUS) { |
||||
dazukofs_get_filename(&acc, filename, sizeof(filename)); |
||||
logg("Clamuko: %s: %s FOUND\n", filename, virname); |
||||
/* we can not perform any special action because it will
|
||||
* trigger DazukoFS recursively */ |
||||
acc.deny = 1; |
||||
} else { |
||||
acc.deny = 0; |
||||
} |
||||
|
||||
if(dazukofs_return_access(scan_hndl, &acc)) { |
||||
if(shutdown_hndl) |
||||
logg("!Clamuko: Can't return access to DazukoFS.\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
dazukofs_close(scan_hndl, 0); |
||||
|
||||
if(shutdown_hndl) |
||||
logg("!Clamuko: A scanner thread has unexpectedly shutdown.\n"); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
void *clamukofsth(void *arg) |
||||
{ |
||||
struct thrarg *tharg = (struct thrarg *) arg; |
||||
sigset_t sigset; |
||||
struct sigaction act; |
||||
pthread_t *clamuko_pids = NULL; |
||||
const char *groupname = "ClamAV"; |
||||
int count; |
||||
int started; |
||||
|
||||
/* is another server thread already working? */ |
||||
if(pthread_mutex_trylock(&running_mutex)) |
||||
return NULL; |
||||
|
||||
/* ignore all signals except SIGUSR1 */ |
||||
sigfillset(&sigset); |
||||
sigdelset(&sigset, SIGUSR1); |
||||
/* The behavior of a process is undefined after it ignores a
|
||||
* SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
||||
sigdelset(&sigset, SIGFPE); |
||||
sigdelset(&sigset, SIGILL); |
||||
sigdelset(&sigset, SIGSEGV); |
||||
#ifdef SIGBUS |
||||
sigdelset(&sigset, SIGBUS); |
||||
#endif |
||||
pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
||||
|
||||
count = optget(tharg->opts, "ClamukoScannerCount")->numarg; |
||||
if(count < 1) goto out; |
||||
|
||||
clamuko_pids = calloc(count, sizeof(pthread_t)); |
||||
if(!clamuko_pids) goto out; |
||||
|
||||
if(setup_shutdown_handle(groupname)) goto out; |
||||
|
||||
act.sa_handler = clamuko_exit; |
||||
sigfillset(&(act.sa_mask)); |
||||
sigaction(SIGUSR1, &act, NULL); |
||||
sigaction(SIGSEGV, &act, NULL); |
||||
|
||||
for(started = 0; started < count; started++) { |
||||
pthread_attr_t clamuko_attr; |
||||
|
||||
if(pthread_attr_init(&clamuko_attr)) break; |
||||
pthread_attr_setdetachstate(&clamuko_attr, PTHREAD_CREATE_JOINABLE); |
||||
if(pthread_create(&clamuko_pids[started], &clamuko_attr, |
||||
clamuko_scanth, tharg)) break; |
||||
logg("Clamuko: Started scanner thread %d.\n", started); |
||||
} |
||||
|
||||
pthread_cond_wait(&shutdown_cond, &running_mutex); |
||||
logg("Clamuko: Stop signal received.\n"); |
||||
|
||||
shutdown_clamuko(); |
||||
|
||||
for(started-- ; started >= 0; started--) { |
||||
logg("Clamuko: Waiting for scanner thread %d to finish.\n", started); |
||||
pthread_join(clamuko_pids[started], NULL); |
||||
} |
||||
|
||||
logg("Clamuko: Stopped.\n"); |
||||
out: |
||||
if(clamuko_pids) free(clamuko_pids); |
||||
pthread_mutex_unlock(&running_mutex); |
||||
return NULL; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,28 @@ |
||||
/*
|
||||
* Copyright (C) 2009 Sourcefire, Inc. |
||||
* Author: John Ogness <dazukocode@ogness.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||
* MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#ifdef CLAMUKO |
||||
|
||||
#ifndef __CLAMUKO_H |
||||
#define __CLAMUKO_H |
||||
|
||||
extern void *clamukofsth(void *arg); |
||||
|
||||
#endif |
||||
#endif |
@ -0,0 +1,238 @@ |
||||
/* userspace library to interface with dazukofs
|
||||
|
||||
Copyright (C) 2008-2009 John Ogness |
||||
Author: John Ogness <dazukocode@ogness.net> |
||||
|
||||
This library is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU Lesser General Public |
||||
License as published by the Free Software Foundation; either |
||||
version 2.1 of the License, or (at your option) any later version. |
||||
|
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU Lesser General Public |
||||
License along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
|
||||
#include "dazukofs.h" |
||||
|
||||
struct dazukofs_handle |
||||
{ |
||||
int dev_fd; |
||||
unsigned long event_id; |
||||
char *group_name; |
||||
}; |
||||
|
||||
#define DAZUKOFS_ALLOWED_GROUPCHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" |
||||
static int check_group_name(const char *gname) |
||||
{ |
||||
size_t len = strlen(gname); |
||||
const char *p; |
||||
|
||||
if (len > 20) |
||||
return -1; |
||||
|
||||
for (p = gname; *p; p++) { |
||||
if (strchr(DAZUKOFS_ALLOWED_GROUPCHARS, *p) == NULL) |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
dazukofs_handle_t dazukofs_open(const char *gname, int flags) |
||||
{ |
||||
struct dazukofs_handle *hndl = NULL; |
||||
char key[25]; |
||||
char buf[256]; |
||||
char *p; |
||||
int gid; |
||||
int fd; |
||||
|
||||
if (check_group_name(gname) != 0) |
||||
goto error_out; |
||||
|
||||
fd = open("/dev/dazukofs.ctrl", O_RDWR); |
||||
if (fd == -1) { |
||||
/* try to read at least
|
||||
* (maybe the group already exists) */ |
||||
fd = open("/dev/dazukofs.ctrl", O_RDONLY); |
||||
if (fd == -1) |
||||
goto error_out; |
||||
} else { |
||||
memset(buf, 0, sizeof(buf)); |
||||
|
||||
if (flags & DAZUKOFS_TRACK_GROUP) |
||||
snprintf(buf, sizeof(buf) - 1, "addtrack=%s", gname); |
||||
else |
||||
snprintf(buf, sizeof(buf) - 1, "add=%s", gname); |
||||
|
||||
if (write(fd, buf, strlen(buf)) == -1) |
||||
goto error_out_close; |
||||
|
||||
lseek(fd, 0, SEEK_SET); |
||||
} |
||||
|
||||
memset(buf, 0, sizeof(buf)); |
||||
if (read(fd, buf, sizeof(buf)-1) == -1) |
||||
goto error_out_close; |
||||
|
||||
memset(key, 0, sizeof(key)); |
||||
snprintf(key, sizeof(key) - 1, ":%s\n", gname); |
||||
|
||||
p = strstr(buf, key); |
||||
if (!p || p == buf) |
||||
goto error_out_close; |
||||
|
||||
p--; |
||||
gid = *p - '0'; |
||||
if (gid < 0 || gid > 9) |
||||
goto error_out_close; |
||||
|
||||
hndl = malloc(sizeof(struct dazukofs_handle)); |
||||
if (!hndl) |
||||
goto error_out_close; |
||||
memset(hndl, 0, sizeof(struct dazukofs_handle)); |
||||
|
||||
hndl->group_name = strdup(gname); |
||||
if (!hndl->group_name) |
||||
goto error_out_free; |
||||
|
||||
memset(key, 0, sizeof(key)); |
||||
snprintf(key, sizeof(key) - 1, "/dev/dazukofs.%d", gid); |
||||
|
||||
hndl->dev_fd = open(key, O_RDWR); |
||||
if (hndl->dev_fd == -1) |
||||
goto error_out_free; |
||||
|
||||
close(fd); |
||||
|
||||
return hndl; |
||||
|
||||
error_out_free: |
||||
if (hndl->group_name) |
||||
free(hndl->group_name); |
||||
free(hndl); |
||||
hndl = NULL; |
||||
error_out_close: |
||||
close(fd); |
||||
error_out: |
||||
return hndl; |
||||
} |
||||
|
||||
int dazukofs_close(dazukofs_handle_t hndl, int flags) |
||||
{ |
||||
char buf[48]; |
||||
int fd; |
||||
int ret = -1; |
||||
|
||||
if (flags & DAZUKOFS_REMOVE_GROUP) { |
||||
fd = open("/dev/dazukofs.ctrl", O_WRONLY); |
||||
if (fd == -1) |
||||
goto error_out; |
||||
|
||||
memset(buf, 0, sizeof(buf)); |
||||
snprintf(buf, sizeof(buf) - 1, "del=%s", hndl->group_name); |
||||
|
||||
if (write(fd, buf, strlen(buf)) == -1) { |
||||
close(fd); |
||||
goto error_out; |
||||
} |
||||
|
||||
close(fd); |
||||
} |
||||
|
||||
ret = close(hndl->dev_fd); |
||||
if (ret != 0) |
||||
goto error_out; |
||||
|
||||
free(hndl->group_name); |
||||
free(hndl); |
||||
|
||||
return 0; |
||||
|
||||
error_out: |
||||
return ret; |
||||
} |
||||
|
||||
int dazukofs_get_access(dazukofs_handle_t hndl, struct dazukofs_access *acc) |
||||
{ |
||||
char buf[48]; |
||||
char *p; |
||||
int err = -1; |
||||
|
||||
memset(buf, 0, sizeof(buf)); |
||||
if (read(hndl->dev_fd, buf, sizeof(buf)-1) == -1) |
||||
goto out; |
||||
|
||||
p = strstr(buf, "id="); |
||||
if (!p) |
||||
goto out; |
||||
p += 3; |
||||
hndl->event_id = strtoul(p, &p, 10); |
||||
|
||||
p = strstr(p, "fd="); |
||||
if (!p) |
||||
goto out; |
||||
p += 3; |
||||
acc->fd = (int)strtol(p, &p, 10); |
||||
|
||||
p = strstr(p, "pid="); |
||||
if (!p) |
||||
goto out; |
||||
p += 4; |
||||
acc->pid = strtoul(p, NULL, 10); |
||||
|
||||
acc->deny = 0; |
||||
|
||||
err = 0; |
||||
out: |
||||
return err; |
||||
} |
||||
|
||||
int dazukofs_return_access(dazukofs_handle_t hndl, struct dazukofs_access *acc) |
||||
{ |
||||
char buf[48]; |
||||
int err = -1; |
||||
|
||||
if (close(acc->fd) != 0) |
||||
goto out; |
||||
snprintf(buf, sizeof(buf)-1, "id=%lu r=%d", hndl->event_id, |
||||
acc->deny ? 1 : 0); |
||||
buf[sizeof(buf)-1] = 0; |
||||
|
||||
if (write(hndl->dev_fd, buf, strlen(buf)) == -1) |
||||
goto out; |
||||
lseek(hndl->dev_fd, 0, SEEK_SET); |
||||
err = 0; |
||||
out: |
||||
return err; |
||||
} |
||||
|
||||
int dazukofs_get_filename(struct dazukofs_access *acc, char *buf, size_t bufsiz) |
||||
{ |
||||
char proc[48]; |
||||
int ret; |
||||
|
||||
memset(proc, 0, sizeof(proc)); |
||||
snprintf(proc, sizeof(proc) - 1, "/proc/self/fd/%d", acc->fd); |
||||
ret = readlink(proc, buf, bufsiz - 1); |
||||
buf[bufsiz - 1] = 0; |
||||
if (ret > 0) |
||||
buf[ret] = 0; |
||||
|
||||
return ret; |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* userspace library to interface with dazukofs
|
||||
|
||||
Copyright (C) 2008 John Ogness |
||||
Author: John Ogness <dazukocode@ogness.net> |
||||
|
||||
This library is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU Lesser General Public |
||||
License as published by the Free Software Foundation; either |
||||
version 2.1 of the License, or (at your option) any later version. |
||||
|
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU Lesser General Public |
||||
License along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
*/ |
||||
|
||||
#ifndef __DAZUKOFS_H |
||||
#define __DAZUKOFS_H |
||||
|
||||
#include <stdio.h> |
||||
|
||||
/* dazukofs_open() flags */ |
||||
#define DAZUKOFS_TRACK_GROUP 1 |
||||
|
||||
/* dazukofs_close() flags */ |
||||
#define DAZUKOFS_REMOVE_GROUP 1 |
||||
|
||||
struct dazukofs_handle; |
||||
typedef struct dazukofs_handle * dazukofs_handle_t; |
||||
|
||||
struct dazukofs_access |
||||
{ |
||||
int fd; |
||||
int deny; |
||||
unsigned long pid; |
||||
}; |
||||
|
||||
dazukofs_handle_t dazukofs_open(const char *gname, int flags); |
||||
int dazukofs_get_access(dazukofs_handle_t hndl, struct dazukofs_access *acc); |
||||
int dazukofs_return_access(dazukofs_handle_t hndl, struct dazukofs_access *acc); |
||||
int dazukofs_close(dazukofs_handle_t hndl, int flags); |
||||
int dazukofs_get_filename(struct dazukofs_access *acc, char *buf, size_t bufsiz); |
||||
|
||||
#endif /* __DAZUKOFS_H */ |
Loading…
Reference in new issue