int main(void) { int nf; Suite *s; SRunner *sr; cl_initialize_crypto(); fpu_words = get_fpu_endian(); check_version_compatible(); s = test_cl_suite(); sr = srunner_create(s); #ifdef CHECK_HAVE_LOOPS srunner_add_suite(sr, test_cli_suite()); #else printf("*** Warning ***: your check version is too old,\nseveral important tests will not execute\n"); #endif srunner_add_suite(sr, test_jsnorm_suite()); srunner_add_suite(sr, test_str_suite()); srunner_add_suite(sr, test_regex_suite()); srunner_add_suite(sr, test_disasm_suite()); srunner_add_suite(sr, test_uniq_suite()); srunner_add_suite(sr, test_matchers_suite()); srunner_add_suite(sr, test_htmlnorm_suite()); srunner_add_suite(sr, test_bytecode_suite()); srunner_set_log(sr, "test.log"); if(freopen("test-stderr.log","w+",stderr) == NULL) { fputs("Unable to redirect stderr!\n",stderr); } cl_debug(); srunner_run_all(sr, CK_NORMAL); nf = srunner_ntests_failed(sr); if (nf) printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n"); srunner_free(sr); #if HAVE_LIBXML2 xmlCleanupParser(); #endif cl_cleanup_crypto(); return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
int main(int argc, char **argv) { int ds, dms, ret; double mb, rmb; struct timeval t1, t2; #ifndef _WIN32 sigset_t sigset; #endif struct optstruct *opts; const struct optstruct *opt; if(check_flevel()) exit(2); #if !defined(_WIN32) && !defined(C_BEOS) sigemptyset(&sigset); sigaddset(&sigset, SIGXFSZ); sigprocmask(SIG_SETMASK, &sigset, NULL); #endif cl_initialize_crypto(); if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMSCAN, 0, NULL)) == NULL) { mprintf("!Can't parse command line options\n"); return 2; } if(optget(opts, "verbose")->enabled) { mprintf_verbose = 1; logg_verbose = 1; } if(optget(opts, "quiet")->enabled) mprintf_quiet = 1; if(optget(opts, "stdout")->enabled) mprintf_stdout = 1; if(optget(opts, "debug")->enabled) { #if defined(C_LINUX) /* [email protected]: create a dump if needed */ struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; if(setrlimit(RLIMIT_CORE, &rlim) < 0) perror("setrlimit"); #endif cl_debug(); /* enable debug messages */ } if (optget(opts, "gen-mdb")->enabled) { cl_always_gen_section_hash(); } if(optget(opts, "version")->enabled) { print_version(optget(opts, "database")->strarg); optfree(opts); return 0; } if(optget(opts, "help")->enabled) { optfree(opts); help(); return 0; } if(optget(opts, "recursive")->enabled) recursion = 1; if(optget(opts, "infected")->enabled) printinfected = 1; if(optget(opts, "suppress-ok-results")->enabled) printclean = 0; if(optget(opts, "bell")->enabled) bell = 1; /* initialize logger */ if((opt = optget(opts, "log"))->enabled) { logg_file = opt->strarg; if(logg("#\n-------------------------------------------------------------------------------\n\n")) { mprintf("!Problem with internal logger.\n"); optfree(opts); return 2; } } else logg_file = NULL; if(actsetup(opts)) { optfree(opts); logg_close(); exit(2); } memset(&info, 0, sizeof(struct s_info)); gettimeofday(&t1, NULL); ret = scanmanager(opts); if(!optget(opts, "no-summary")->enabled) { gettimeofday(&t2, NULL); ds = t2.tv_sec - t1.tv_sec; dms = t2.tv_usec - t1.tv_usec; ds -= (dms < 0) ? (1):(0); dms += (dms < 0) ? (1000000):(0); logg("\n----------- SCAN SUMMARY -----------\n"); logg("Known viruses: %u\n", info.sigs); logg("Engine version: %s\n", get_version()); logg("Scanned directories: %u\n", info.dirs); logg("Scanned files: %u\n", info.files); logg("Infected files: %u\n", info.ifiles); if(info.errors) logg("Total errors: %u\n", info.errors); if(notremoved) { logg("Not removed: %u\n", notremoved); } if(notmoved) { logg("Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved); } mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0; logg("Data scanned: %2.2lf MB\n", mb); rmb = info.rblocks * (CL_COUNT_PRECISION / 1024) / 1024.0; logg("Data read: %2.2lf MB (ratio %.2f:1)\n", rmb, info.rblocks ? (double)info.blocks/(double)info.rblocks : 0); logg("Time: %u.%3.3u sec (%u m %u s)\n", ds, dms/1000, ds/60, ds%60); } optfree(opts); cl_cleanup_crypto(); return ret; }
int main(int argc, char *argv[]) { FILE *f; struct cli_bc *bc; struct cli_bc_ctx *ctx; int rc, dbgargc, bc_stats=0; struct optstruct *opts; const struct optstruct *opt; unsigned funcid=0, i; struct cli_all_bc bcs; int fd = -1; unsigned tracelevel; if(check_flevel()) exit(1); opts = optparse(NULL, argc, argv, 1, OPT_CLAMBC, 0, NULL); if (!opts) { fprintf(stderr, "ERROR: Can't parse command line options\n"); exit(1); } if(optget(opts, "version")->enabled) { printf("Clam AntiVirus Bytecode Testing Tool %s\n", get_version()); cl_init(CL_INIT_DEFAULT); cli_bytecode_printversion(); optfree(opts); exit(0); } if(optget(opts, "help")->enabled || !opts->filename) { optfree(opts); help(); exit(0); } f = fopen(opts->filename[0], "r"); if (!f) { fprintf(stderr, "Unable to load %s\n", argv[1]); optfree(opts); exit(2); } bc = malloc(sizeof(*bc)); if (!bc) { fprintf(stderr, "Out of memory\n"); optfree(opts); exit(3); } if (optget(opts,"debug")->enabled) { cl_debug(); debug_flag=1; } rc = cl_init(CL_INIT_DEFAULT); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to init libclamav: %s\n", cl_strerror(rc)); optfree(opts); exit(4); } dbgargc=1; while (opts->filename[dbgargc]) dbgargc++; if (dbgargc > 1) cli_bytecode_debug(dbgargc, opts->filename); if (optget(opts, "force-interpreter")->enabled) { bcs.engine = NULL; } else { rc = cli_bytecode_init(&bcs); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to init bytecode engine: %s\n", cl_strerror(rc)); optfree(opts); exit(4); } } bcs.all_bcs = bc; bcs.count = 1; if((opt = optget(opts, "statistics"))->enabled) { while(opt) { if (!strcasecmp(opt->strarg, "bytecode")) bc_stats=1; opt = opt->nextarg; } } rc = cli_bytecode_load(bc, f, NULL, optget(opts, "trust-bytecode")->enabled, bc_stats); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to load bytecode: %s\n", cl_strerror(rc)); optfree(opts); exit(4); } fclose(f); if (bc->state == bc_skip) { fprintf(stderr,"bytecode load skipped\n"); exit(0); } if (debug_flag) printf("[clambc] Bytecode loaded\n"); if (optget(opts, "info")->enabled) { cli_bytecode_describe(bc); } else if (optget(opts, "printsrc")->enabled) { print_src(opts->filename[0]); } else if (optget(opts, "printbcir")->enabled) { cli_bytetype_describe(bc); cli_bytevalue_describe(bc, 0); cli_bytefunc_describe(bc, 0); } else { cli_ctx cctx; struct cl_engine *engine = cl_engine_new(); fmap_t *map = NULL; memset(&cctx, 0, sizeof(cctx)); if (!engine) { fprintf(stderr,"Unable to create engine\n"); optfree(opts); exit(3); } rc = cl_engine_compile(engine); if (rc) { fprintf(stderr,"Unable to compile engine: %s\n", cl_strerror(rc)); optfree(opts); exit(4); } rc = cli_bytecode_prepare2(engine, &bcs, BYTECODE_ENGINE_MASK); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to prepare bytecode: %s\n", cl_strerror(rc)); optfree(opts); exit(4); } if (debug_flag) printf("[clambc] Bytecode prepared\n"); ctx = cli_bytecode_context_alloc(); if (!ctx) { fprintf(stderr,"Out of memory\n"); exit(3); } ctx->ctx = &cctx; cctx.engine = engine; cctx.fmap = cli_calloc(sizeof(fmap_t*), engine->maxreclevel+2); if (!cctx.fmap) { fprintf(stderr,"Out of memory\n"); exit(3); } memset(&dbg_state, 0, sizeof(dbg_state)); dbg_state.file = "<libclamav>"; dbg_state.line = 0; dbg_state.col = 0; dbg_state.showline = !optget(opts, "no-trace-showsource")->enabled; tracelevel = optget(opts, "trace")->numarg; cli_bytecode_context_set_trace(ctx, tracelevel, tracehook, tracehook_op, tracehook_val, tracehook_ptr); if (opts->filename[1]) { funcid = atoi(opts->filename[1]); } cli_bytecode_context_setfuncid(ctx, bc, funcid); if (debug_flag) printf("[clambc] Running bytecode function :%u\n", funcid); if (opts->filename[1]) { i=2; while (opts->filename[i]) { rc = cli_bytecode_context_setparam_int(ctx, i-2, atoi(opts->filename[i])); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to set param %u: %s\n", i-2, cl_strerror(rc)); } i++; } } if ((opt = optget(opts,"input"))->enabled) { fd = open(opt->strarg, O_RDONLY); if (fd == -1) { fprintf(stderr, "Unable to open input file %s: %s\n", opt->strarg, strerror(errno)); optfree(opts); exit(5); } map = fmap(fd, 0, 0); if (!map) { fprintf(stderr, "Unable to map input file %s\n", opt->strarg); exit(5); } rc = cli_bytecode_context_setfile(ctx, map); if (rc != CL_SUCCESS) { fprintf(stderr, "Unable to set file %s: %s\n", opt->strarg, cl_strerror(rc)); optfree(opts); exit(5); } } /* for testing */ ctx->hooks.match_counts = deadbeefcounts; ctx->hooks.match_offsets = deadbeefcounts; rc = cli_bytecode_run(&bcs, bc, ctx); if (rc != CL_SUCCESS) { fprintf(stderr,"Unable to run bytecode: %s\n", cl_strerror(rc)); } else { uint64_t v; if (debug_flag) printf("[clambc] Bytecode run finished\n"); v = cli_bytecode_context_getresult_int(ctx); if (debug_flag) printf("[clambc] Bytecode returned: 0x%llx\n", (long long)v); } cli_bytecode_context_destroy(ctx); if (map) funmap(map); cl_engine_free(engine); free(cctx.fmap); } cli_bytecode_destroy(bc); cli_bytecode_done(&bcs); free(bc); optfree(opts); if (fd != -1) close(fd); if (debug_flag) printf("[clambc] Exiting\n"); cl_cleanup_crypto(); return 0; }
int main(int argc, char **argv) { int ds, dms, ret, infected = 0, err = 0; struct timeval t1, t2; time_t starttime; struct optstruct *opts; const struct optstruct *opt; #ifndef _WIN32 struct sigaction sigact; #endif if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMDSCAN, OPT_CLAMSCAN, NULL)) == NULL) { mprintf("!Can't parse command line options\n"); return 2; } if((clamdopts = optparse(optget(opts, "config-file")->strarg, 0, NULL, 1, OPT_CLAMD, 0, NULL)) == NULL) { logg("!Can't parse clamd configuration file %s\n", optget(opts, "config-file")->strarg); return 2; } if(optget(opts, "verbose")->enabled) { mprintf_verbose = 1; logg_verbose = 1; } if(optget(opts, "quiet")->enabled) mprintf_quiet = 1; if(optget(opts, "stdout")->enabled) mprintf_stdout = 1; if(optget(opts, "version")->enabled) { print_server_version(opts); optfree(opts); optfree(clamdopts); exit(0); } if(optget(opts, "help")->enabled) { optfree(opts); optfree(clamdopts); help(); } if(optget(opts, "infected")->enabled) printinfected = 1; /* initialize logger */ if((opt = optget(opts, "log"))->enabled) { logg_file = opt->strarg; if(logg("--------------------------------------\n")) { mprintf("!Problem with internal logger.\n"); optfree(opts); optfree(clamdopts); exit(2); } } else logg_file = NULL; if(optget(opts, "reload")->enabled) { ret = reload_clamd_database(opts); optfree(opts); optfree(clamdopts); logg_close(); exit(ret); } if(actsetup(opts)) { optfree(opts); optfree(clamdopts); logg_close(); exit(2); } #ifndef _WIN32 memset(&sigact, 0, sizeof(struct sigaction)); sigact.sa_handler = SIG_IGN; sigemptyset(&sigact.sa_mask); sigaddset(&sigact.sa_mask, SIGPIPE); sigaction(SIGPIPE, &sigact, NULL); #endif time(&starttime); /* ctime() does \n, but I need it once more */ gettimeofday(&t1, NULL); ret = client(opts, &infected, &err); optfree(clamdopts); /* TODO: Implement STATUS in clamd */ if(!optget(opts, "no-summary")->enabled) { gettimeofday(&t2, NULL); ds = t2.tv_sec - t1.tv_sec; dms = t2.tv_usec - t1.tv_usec; ds -= (dms < 0) ? (1):(0); dms += (dms < 0) ? (1000000):(0); logg("\n----------- SCAN SUMMARY -----------\n"); logg("Infected files: %d\n", infected); if(err) logg("Total errors: %d\n", err); if(notremoved) { logg("Not removed: %d\n", notremoved); } if(notmoved) { logg("Not moved: %d\n", notmoved); } logg("Time: %d.%3.3d sec (%d m %d s)\n", ds, dms/1000, ds/60, ds%60); } logg_close(); optfree(opts); cl_cleanup_crypto(); exit(ret); }
int main(int argc, char **argv) { static struct cl_engine *engine = NULL; const struct optstruct *opt; #ifndef _WIN32 struct passwd *user = NULL; struct sigaction sa; struct rlimit rlim; #endif time_t currtime; const char *dbdir, *cfgfile; char *pua_cats = NULL, *pt; int ret, tcpsock = 0, localsock = 0, min_port, max_port; unsigned int sigs = 0; int *lsockets=NULL; unsigned int nlsockets = 0; unsigned int dboptions = 0; unsigned int i; #ifdef C_LINUX STATBUF sb; #endif if(check_flevel()) exit(1); #ifndef _WIN32 memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); #endif if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMD, 0, NULL)) == NULL) { mprintf("!Can't parse command line options\n"); return 1; } if(optget(opts, "help")->enabled) { help(); optfree(opts); return 0; } if(optget(opts, "debug")->enabled) { #if defined(C_LINUX) /* [email protected]: create a dump if needed */ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; if(setrlimit(RLIMIT_CORE, &rlim) < 0) perror("setrlimit"); #endif debug_mode = 1; } /* parse the config file */ cfgfile = optget(opts, "config-file")->strarg; pt = strdup(cfgfile); if (pt == NULL) { fprintf(stderr, "ERROR: Unable to allocate memory for config file\n"); return 1; } if((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, 0, opts)) == NULL) { fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", pt); free(pt); return 1; } free(pt); if(optget(opts, "version")->enabled) { print_version(optget(opts, "DatabaseDirectory")->strarg); optfree(opts); return 0; } /* drop privileges */ #ifndef _WIN32 if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { if((user = getpwnam(opt->strarg)) == NULL) { fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg); optfree(opts); return 1; } if(optget(opts, "AllowSupplementaryGroups")->enabled) { #ifdef HAVE_INITGROUPS if(initgroups(opt->strarg, user->pw_gid)) { fprintf(stderr, "ERROR: initgroups() failed.\n"); optfree(opts); return 1; } #else mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups in %s\n", cfgfile); optfree(opts); return 1; #endif } else { #ifdef HAVE_SETGROUPS if(setgroups(1, &user->pw_gid)) { fprintf(stderr, "ERROR: setgroups() failed.\n"); optfree(opts); return 1; } #endif } if(setgid(user->pw_gid)) { fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid); optfree(opts); return 1; } if(setuid(user->pw_uid)) { fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid); optfree(opts); return 1; } } #endif /* initialize logger */ logg_lock = !optget(opts, "LogFileUnlock")->enabled; logg_time = optget(opts, "LogTime")->enabled; logok = optget(opts, "LogClean")->enabled; logg_size = optget(opts, "LogFileMaxSize")->numarg; logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled; if (logg_size) logg_rotate = optget(opts, "LogRotate")->enabled; mprintf_send_timeout = optget(opts, "SendBufTimeout")->numarg; do { /* logger initialized */ if((opt = optget(opts, "LogFile"))->enabled) { char timestr[32]; logg_file = opt->strarg; if(!cli_is_abspath(logg_file)) { fprintf(stderr, "ERROR: LogFile requires full path.\n"); ret = 1; break; } time(&currtime); if(logg("#+++ Started at %s", cli_ctime(&currtime, timestr, sizeof(timestr)))) { fprintf(stderr, "ERROR: Can't initialize the internal logger\n"); ret = 1; break; } } else { logg_file = NULL; } if (optget(opts,"DevLiblog")->enabled) cl_set_clcb_msg(msg_callback); if((ret = cl_init(CL_INIT_DEFAULT))) { logg("!Can't initialize libclamav: %s\n", cl_strerror(ret)); ret = 1; break; } if(optget(opts, "Debug")->enabled) { /* enable debug messages in libclamav */ cl_debug(); logg_verbose = 2; } #if defined(USE_SYSLOG) && !defined(C_AIX) if(optget(opts, "LogSyslog")->enabled) { int fac = LOG_LOCAL6; opt = optget(opts, "LogFacility"); if((fac = logg_facility(opt->strarg)) == -1) { logg("!LogFacility: %s: No such facility.\n", opt->strarg); ret = 1; break; } openlog("clamd", LOG_PID, fac); logg_syslog = 1; } #endif #ifdef C_LINUX procdev = 0; if(CLAMSTAT("/proc", &sb) != -1 && !sb.st_size) procdev = sb.st_dev; #endif /* check socket type */ if(optget(opts, "TCPSocket")->enabled) tcpsock = 1; if(optget(opts, "LocalSocket")->enabled) localsock = 1; if(!tcpsock && !localsock) { logg("!Please define server type (local and/or TCP).\n"); ret = 1; break; } logg("#clamd daemon %s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")\n", get_version()); #ifndef _WIN32 if(user) logg("#Running as user %s (UID %u, GID %u)\n", user->pw_name, user->pw_uid, user->pw_gid); #endif #if defined(RLIMIT_DATA) && defined(C_BSD) if (getrlimit(RLIMIT_DATA, &rlim) == 0) { /* bb #1941. * On 32-bit FreeBSD if you set ulimit -d to >2GB then mmap() will fail * too soon (after ~120 MB). * Set limit lower than 2G if on 32-bit */ uint64_t lim = rlim.rlim_cur; if (sizeof(void*) == 4 && lim > (1ULL << 31)) { rlim.rlim_cur = 1ULL << 31; if (setrlimit(RLIMIT_DATA, &rlim) < 0) logg("!setrlimit(RLIMIT_DATA) failed: %s\n", strerror(errno)); else logg("Running on 32-bit system, and RLIMIT_DATA > 2GB, lowering to 2GB!\n"); } } #endif if(logg_size) logg("#Log file size limited to %u bytes.\n", logg_size); else logg("#Log file size limit disabled.\n"); min_port = optget(opts, "StreamMinPort")->numarg; max_port = optget(opts, "StreamMaxPort")->numarg; if (min_port < 1024 || min_port > max_port || max_port > 65535) { logg("!Invalid StreamMinPort/StreamMaxPort: %d, %d\n", min_port, max_port); ret = 1; break; } if(!(engine = cl_engine_new())) { logg("!Can't initialize antivirus engine\n"); ret = 1; break; } if (optget(opts, "disable-cache")->enabled) cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1); /* load the database(s) */ dbdir = optget(opts, "DatabaseDirectory")->strarg; logg("#Reading databases from %s\n", dbdir); if(optget(opts, "DetectPUA")->enabled) { dboptions |= CL_DB_PUA; if((opt = optget(opts, "ExcludePUA"))->enabled) { dboptions |= CL_DB_PUA_EXCLUDE; i = 0; logg("#Excluded PUA categories:"); while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); cl_engine_free(engine); ret = 1; break; } logg("# %s", opt->strarg); sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } if (ret) break; logg("#\n"); pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if((opt = optget(opts, "IncludePUA"))->enabled) { if(pua_cats) { logg("!ExcludePUA and IncludePUA cannot be used at the same time\n"); free(pua_cats); ret = 1; break; } dboptions |= CL_DB_PUA_INCLUDE; i = 0; logg("#Included PUA categories:"); while(opt) { if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) { logg("!Can't allocate memory for pua_cats\n"); ret = 1; break; } logg("# %s", opt->strarg); sprintf(pua_cats + i, ".%s", opt->strarg); i += strlen(opt->strarg) + 1; pua_cats[i] = 0; opt = opt->nextarg; } if (ret) break; logg("#\n"); pua_cats[i] = '.'; pua_cats[i + 1] = 0; } if(pua_cats) { if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) { logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret)); free(pua_cats); ret = 1; break; } free(pua_cats); } } else { logg("#Not loading PUA signatures.\n"); } if (optget(opts, "StatsEnabled")->enabled) { cl_engine_stats_enable(engine); } if (optget(opts, "StatsPEDisabled")->enabled) { cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_STATS, 1); } if (optget(opts, "StatsTimeout")->enabled) { cl_engine_set_num(engine, CL_ENGINE_STATS_TIMEOUT, optget(opts, "StatsTimeout")->numarg); } if (optget(opts, "StatsHostID")->enabled) { char *p = optget(opts, "StatsHostID")->strarg; if (strcmp(p, "default")) { if (!strcmp(p, "none")) { cl_engine_set_clcb_stats_get_hostid(engine, NULL); } else if (!strcmp(p, "anonymous")) { strcpy(hostid, STATS_ANON_UUID); } else { if (strlen(p) > 36) { logg("!Invalid HostID\n"); cl_engine_set_clcb_stats_submit(engine, NULL); cl_engine_free(engine); ret = 1; break; } strcpy(hostid, p); } cl_engine_set_clcb_stats_get_hostid(engine, get_hostid); } } if(optget(opts, "OfficialDatabaseOnly")->enabled) { dboptions |= CL_DB_OFFICIAL_ONLY; logg("#Only loading official signatures.\n"); } /* set the temporary dir */ if((opt = optget(opts, "TemporaryDirectory"))->enabled) { if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) { logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret)); ret = 1; break; } } cl_engine_set_clcb_hash(engine, hash_callback); cl_engine_set_clcb_virus_found(engine, clamd_virus_found_cb); if(optget(opts, "LeaveTemporaryFiles")->enabled) cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); if(optget(opts, "ForceToDisk")->enabled) cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1); if(optget(opts, "PhishingSignatures")->enabled) dboptions |= CL_DB_PHISHING; else logg("#Not loading phishing signatures.\n"); if(optget(opts,"Bytecode")->enabled) { dboptions |= CL_DB_BYTECODE; if((opt = optget(opts,"BytecodeSecurity"))->enabled) { enum bytecode_security s; if (!strcmp(opt->strarg, "TrustSigned")) { s = CL_BYTECODE_TRUST_SIGNED; logg("#Bytecode: Security mode set to \"TrustSigned\".\n"); } else if (!strcmp(opt->strarg, "Paranoid")) { s = CL_BYTECODE_TRUST_NOTHING; logg("#Bytecode: Security mode set to \"Paranoid\".\n"); } else { logg("!Unable to parse bytecode security setting:%s\n", opt->strarg); ret = 1; break; } if ((ret = cl_engine_set_num(engine, CL_ENGINE_BYTECODE_SECURITY, s))) { logg("^Invalid bytecode security setting %s: %s\n", opt->strarg, cl_strerror(ret)); ret = 1; break; } } if((opt = optget(opts,"BytecodeUnsigned"))->enabled) { dboptions |= CL_DB_BYTECODE_UNSIGNED; logg("#Bytecode: Enabled support for unsigned bytecode.\n"); } if((opt = optget(opts,"BytecodeMode"))->enabled) { enum bytecode_mode mode; if (!strcmp(opt->strarg, "ForceJIT")) mode = CL_BYTECODE_MODE_JIT; else if(!strcmp(opt->strarg, "ForceInterpreter")) mode = CL_BYTECODE_MODE_INTERPRETER; else if(!strcmp(opt->strarg, "Test")) mode = CL_BYTECODE_MODE_TEST; else mode = CL_BYTECODE_MODE_AUTO; cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode); } if((opt = optget(opts,"BytecodeTimeout"))->enabled) { cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg); } } else { logg("#Bytecode support disabled.\n"); } if(optget(opts,"PhishingScanURLs")->enabled) dboptions |= CL_DB_PHISHING_URLS; else logg("#Disabling URL based phishing detection.\n"); if(optget(opts,"DevACOnly")->enabled) { logg("#Only using the A-C matcher.\n"); cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1); } if((opt = optget(opts, "DevACDepth"))->enabled) { cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, opt->numarg); logg("#Max A-C depth set to %u\n", (unsigned int) opt->numarg); } if((ret = cl_load(dbdir, engine, &sigs, dboptions))) { logg("!%s\n", cl_strerror(ret)); ret = 1; break; } if((ret = statinidir_th(dbdir))) { logg("!%s\n", cl_strerror(ret)); ret = 1; break; } if (optget(opts, "DisableCertCheck")->enabled) engine->dconf->pe |= PE_CONF_DISABLECERT; logg("#Loaded %u signatures.\n", sigs); if((ret = cl_engine_compile(engine)) != 0) { logg("!Database initialization error: %s\n", cl_strerror(ret)); ret = 1; break; } if(tcpsock) { opt = optget(opts, "TCPAddr"); if (opt->enabled) { int breakout = 0; while (opt && opt->strarg) { char *ipaddr = (!strcmp(opt->strarg, "all") ? NULL : opt->strarg); if (tcpserver(&lsockets, &nlsockets, ipaddr, opts) == -1) { ret = 1; breakout = 1; break; } opt = opt->nextarg; } if (breakout) break; } else { if (tcpserver(&lsockets, &nlsockets, NULL, opts) == -1) { ret = 1; break; } } } #ifndef _WIN32 if(localsock) { int *t; mode_t sock_mode, umsk = umask(0777); /* socket is created with 000 to avoid races */ t = realloc(lsockets, sizeof(int) * (nlsockets + 1)); if (!(t)) { ret = 1; break; } lsockets = t; if ((lsockets[nlsockets] = localserver(opts)) == -1) { ret = 1; umask(umsk); break; } umask(umsk); /* restore umask */ if(optget(opts, "LocalSocketGroup")->enabled) { char *gname = optget(opts, "LocalSocketGroup")->strarg, *end; gid_t sock_gid = strtol(gname, &end, 10); if(*end) { struct group *pgrp = getgrnam(gname); if(!pgrp) { logg("!Unknown group %s\n", gname); ret = 1; break; } sock_gid = pgrp->gr_gid; } if(chown(optget(opts, "LocalSocket")->strarg, -1, sock_gid)) { logg("!Failed to change socket ownership to group %s\n", gname); ret = 1; break; } } if(optget(opts, "LocalSocketMode")->enabled) { char *end; sock_mode = strtol(optget(opts, "LocalSocketMode")->strarg, &end, 8); if(*end) { logg("!Invalid LocalSocketMode %s\n", optget(opts, "LocalSocketMode")->strarg); ret = 1; break; } } else { sock_mode = 0777 /* & ~umsk*/; /* conservative default: umask was 0 in clamd < 0.96 */ } if(chmod(optget(opts, "LocalSocket")->strarg, sock_mode & 0666)) { logg("!Cannot set socket permission to %s\n", optget(opts, "LocalSocketMode")->strarg); ret = 1; break; } nlsockets++; } /* fork into background */ if(!optget(opts, "Foreground")->enabled) { #ifdef C_BSD /* workaround for OpenBSD bug, see https://wwws.clamav.net/bugzilla/show_bug.cgi?id=885 */ for(ret=0;(unsigned int)ret<nlsockets;ret++) { if (fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) | O_NONBLOCK) == -1) { logg("!fcntl for lsockets[] failed\n"); close(lsockets[ret]); ret = 1; break; } } #endif gengine = engine; atexit(free_engine); if(daemonize() == -1) { logg("!daemonize() failed: %s\n", strerror(errno)); ret = 1; break; } gengine = NULL; #ifdef C_BSD for(ret=0;(unsigned int)ret<nlsockets;ret++) { if (fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) & ~O_NONBLOCK) == -1) { logg("!fcntl for lsockets[] failed\n"); close(lsockets[ret]); ret = 1; break; } } #endif if(!debug_mode) if(chdir("/") == -1) logg("^Can't change current working directory to root\n"); } else { foreground = 1; } #endif if (nlsockets == 0) { logg("!Not listening on any interfaces\n"); ret = 1; break; } ret = recvloop_th(lsockets, nlsockets, engine, dboptions, opts); } while (0); logg("*Closing the main socket%s.\n", (nlsockets > 1) ? "s" : ""); for (i = 0; i < nlsockets; i++) { closesocket(lsockets[i]); } #ifndef _WIN32 if(nlsockets && localsock) { opt = optget(opts, "LocalSocket"); if(unlink(opt->strarg) == -1) logg("!Can't unlink the socket file %s\n", opt->strarg); else logg("Socket file removed.\n"); } #endif free(lsockets); logg_close(); optfree(opts); cl_cleanup_crypto(); return ret; }