/** * Scan email for virus. Returns 1 if virus * detected or 0 if no virus is detected. Sets * lscan.virname to virua or error output... */ int scan_clamav(char * scanpath) { sprintf(lscan.scanpath, "%s", scanpath); lscan.iNo = 0; /** lets load all our virus defs database's into memory */ lscan.root = NULL; /** without this line, the dbload will crash... */ if((lscan.i = cl_loaddbdir(cl_retdbdir(), &lscan.root, &lscan.iNo))) { sprintf(lscan.virname, "error: [%s]", cl_perror(lscan.i)); } else { if((lscan.i = cl_build(lscan.root))) { sprintf(lscan.virname, "database initialization error: [%s]", cl_perror(lscan.i)); cl_free(lscan.root); } memset(&lscan.limits, 0x0, sizeof(struct cl_limits)); lscan.limits.maxfiles = 1000; /** max files */ lscan.limits.maxfilesize = 10 * 1048576; /** maximal archived file size == 10 Mb */ lscan.limits.maxreclevel = 12; /** maximal recursion level */ lscan.limits.maxratio = 200; /** maximal compression ratio */ lscan.limits.archivememlim = 0; /** disable memory limit for bzip2 scanner */ if ((lscan.i = cl_scanfile(lscan.scanpath, (const char **)&lscan.virname, NULL, lscan.root, &lscan.limits, CL_SCAN_ARCHIVE | CL_SCAN_MAIL | CL_SCAN_OLE2 | CL_SCAN_BLOCKBROKEN | CL_SCAN_HTML | CL_SCAN_PE)) != CL_VIRUS) { if (lscan.i != CL_CLEAN) { sprintf(lscan.virname, "error: [%s]", cl_perror(lscan.i)); } else { lscan.virname = NULL; } } if (lscan.root != NULL) { cl_free(lscan.root); } memset(&lscan.limits, 0x0, sizeof(struct cl_limits)); } /** lets delete the spool message as we don't need it any more */ if (lscan.virname != NULL) { /** remove the file if we have a virus as we are going to reject it */ return(1); } else { /** else keep the file for spam filtering */ return(0); } return(1); } /** scan_clamav */
int init_virusdb() { int ret; unsigned int no = 0; virusdb = malloc(sizeof(struct virus_db)); memset(virusdb, 0, sizeof(struct virus_db)); if (!virusdb) return 0; #ifdef HAVE_LIBCLAMAV_095 if((ret = cl_init(CL_INIT_DEFAULT))) { ci_debug_printf(1, "!Can't initialize libclamav: %s\n", cl_strerror(ret)); return 0; } if(!(virusdb->db = cl_engine_new())) { ci_debug_printf(1, "Clamav DB load: Cannot create new clamav engine\n"); return 0; } if ((ret = cl_load(cl_retdbdir(), virusdb->db, &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB load: cl_load failed: %s\n", cl_strerror(ret)); #elif defined(HAVE_LIBCLAMAV_09X) if ((ret = cl_load(cl_retdbdir(), &(virusdb->db), &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB load: cl_load failed: %s\n", cl_strerror(ret)); #else if ((ret = cl_loaddbdir(cl_retdbdir(), &(virusdb->db), &no))) { ci_debug_printf(1, "cl_loaddbdir: %s\n", cl_perror(ret)); #endif return 0; } #ifdef HAVE_LIBCLAMAV_095 if ((ret = cl_engine_compile(virusdb->db))) { #else if ((ret = cl_build(virusdb->db))) { #endif ci_debug_printf(1, "Database initialization error: %s\n", cl_strerror(ret)); #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(virusdb->db); #else cl_free(virusdb->db); #endif free(virusdb); virusdb = NULL; return 0; } ci_thread_mutex_init(&db_mutex); virusdb->refcount = 1; old_virusdb = NULL; return 1; } /* Instead of using struct virus_db and refcount's someone can use the cl_dup function of clamav library, but it is undocumented so I did not use it. The following implementation we are starting to reload clamav db while threads are scanning for virus but we are not allow any child to start a new scan until we are loading DB. */ /*#define DB_NO_FULL_LOCK 1*/ #undef DB_NO_FULL_LOCK int reload_virusdb() { struct virus_db *vdb = NULL; int ret; unsigned int no = 0; ci_thread_mutex_lock(&db_mutex); if (old_virusdb) { ci_debug_printf(1, "Clamav DB reload pending, cancelling.\n"); ci_thread_mutex_unlock(&db_mutex); return 0; } #ifdef DB_NO_FULL_LOCK ci_thread_mutex_unlock(&db_mutex); #endif vdb = malloc(sizeof(struct virus_db)); if (!vdb) return 0; memset(vdb, 0, sizeof(struct virus_db)); ci_debug_printf(9, "db_reload going to load db\n"); #ifdef HAVE_LIBCLAMAV_095 if(!(vdb->db = cl_engine_new())) { ci_debug_printf(1, "Clamav DB load: Cannot create new clamav engine\n"); return 0; } if ((ret = cl_load(cl_retdbdir(), vdb->db, &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB reload: cl_load failed: %s\n", cl_strerror(ret)); #elif defined(HAVE_LIBCLAMAV_09X) if ((ret = cl_load(cl_retdbdir(), &(vdb->db), &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB reload: cl_load failed: %s\n", cl_strerror(ret)); #else if ((ret = cl_loaddbdir(cl_retdbdir(), &(vdb->db), &no))) { ci_debug_printf(1, "Clamav DB reload: cl_loaddbdir failed: %s\n", cl_perror(ret)); #endif return 0; } ci_debug_printf(9, "loaded. Going to build\n"); #ifdef HAVE_LIBCLAMAV_095 if ((ret = cl_engine_compile(vdb->db))) { #else if ((ret = cl_build(vdb->db))) { #endif ci_debug_printf(1, "Clamav DB reload: Database initialization error: %s\n", cl_strerror(ret)); #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(vdb->db); #else cl_free(vdb->db); #endif free(vdb); vdb = NULL; #ifdef DB_NO_FULL_LOCK /*no lock needed */ #else ci_thread_mutex_unlock(&db_mutex); #endif return 0; } ci_debug_printf(9, "Done releasing.....\n"); #ifdef DB_NO_FULL_LOCK ci_thread_mutex_lock(&db_mutex); #endif old_virusdb = virusdb; old_virusdb->refcount--; ci_debug_printf(9, "Old VirusDB refcount:%d\n", old_virusdb->refcount); if (old_virusdb->refcount <= 0) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } virusdb = vdb; virusdb->refcount = 1; ci_thread_mutex_unlock(&db_mutex); return 1; } CL_ENGINE *get_virusdb() { struct virus_db *vdb; ci_thread_mutex_lock(&db_mutex); vdb = virusdb; vdb->refcount++; ci_thread_mutex_unlock(&db_mutex); return vdb->db; } void release_virusdb(CL_ENGINE * db) { ci_thread_mutex_lock(&db_mutex); if (virusdb && db == virusdb->db) virusdb->refcount--; else if (old_virusdb && (db == old_virusdb->db)) { old_virusdb->refcount--; ci_debug_printf(9, "Old VirusDB refcount: %d\n", old_virusdb->refcount); if (old_virusdb->refcount <= 0) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } } else { ci_debug_printf(1, "BUG in srv_clamav service! please contact the author\n"); } ci_thread_mutex_unlock(&db_mutex); } void destroy_virusdb() { if (virusdb) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(virusdb->db); #else cl_free(virusdb->db); #endif free(virusdb); virusdb = NULL; } if (old_virusdb) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } } void set_istag(ci_service_xdata_t * srv_xdata) { char istag[SERVICE_ISTAG_SIZE + 1]; char str_version[64]; char *daily_path; char *s1, *s2; struct cl_cvd *d1; int version = 0, cfg_version = 0; struct stat daily_stat; /*instead of 128 should be strlen("/daily.inc/daily.info")+1*/ daily_path = malloc(strlen(cl_retdbdir()) + 128); if (!daily_path) /*???????? */ return; sprintf(daily_path, "%s/daily.cvd", cl_retdbdir()); if(stat(daily_path,&daily_stat) != 0){ /* if the clamav_lib_path/daily.cvd does not exists */ sprintf(daily_path, "%s/daily.cld", cl_retdbdir()); if(stat(daily_path,&daily_stat) != 0){ /* else try to use the clamav_lib_path/daily.inc/daly.info file instead" */ sprintf(daily_path, "%s/daily.inc/daily.info", cl_retdbdir()); } } if ((d1 = cl_cvdhead(daily_path))) { version = d1->version; free(d1); } free(daily_path); s1 = (char *) cl_retver(); s2 = str_version; while (*s1 != '\0' && s2 - str_version < 64) { if (*s1 != '.') { *s2 = *s1; s2++; } s1++; } *s2 = '\0'; /*cfg_version maybe must set by user when he is changing the srv_clamav configuration.... */ snprintf(istag, SERVICE_ISTAG_SIZE, "-%.3d-%s-%d%d", cfg_version, str_version, cl_retflevel(), version); istag[SERVICE_ISTAG_SIZE] = '\0'; ci_service_set_istag(srv_xdata, istag); }
static struct cl_node *reload_db(struct cl_node *root, const struct cfgstruct *copt, int do_check) { const char *dbdir; int retval; unsigned int virnum = 0; struct cfgstruct *cpt; static struct cl_stat *dbstat=NULL; if(do_check) { if(dbstat == NULL) { logg("No stats for Database check - forcing reload\n"); return root; } if(cl_statchkdir(dbstat) == 1) { logg("SelfCheck: Database modification detected. Forcing reload.\n"); return root; } else { logg("SelfCheck: Database status OK.\n"); return NULL; } } /* release old structure */ if(root) { cl_free(root); root = NULL; } if((cpt = cfgopt(copt, "DatabaseDirectory")) || (cpt = cfgopt(copt, "DataDirectory"))) { dbdir = cpt->strarg; } else { dbdir = cl_retdbdir(); } logg("Reading databases from %s\n", dbdir); if(dbstat == NULL) { dbstat = (struct cl_stat *) mmalloc(sizeof(struct cl_stat)); } else { cl_statfree(dbstat); } memset(dbstat, 0, sizeof(struct cl_stat)); cl_statinidir(dbdir, dbstat); if((retval = cl_loaddbdir(dbdir, &root, &virnum))) { logg("!reload db failed: %s\n", cl_strerror(retval)); exit(-1); } if(!root) { logg("!load db failed: %s\n", cl_strerror(retval)); exit(-1); } if((retval = cl_build(root)) != 0) { logg("!Database initialization error: can't build engine: %s\n", cl_strerror(retval)); exit(-1); } logg("Database correctly reloaded (%d viruses)\n", virnum); return root; }