/* * Copyright (C) 2009 Sourcefire, Inc. * Author: Tomasz Kojm * * 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 #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "shared/optparser.h" #include "shared/misc.h" #include "libclamav/str.h" #include "libclamav/clamav.h" #include "libclamav/others.h" static struct _cfgfile { const char *name; int tool; } cfgfile[] = { { "clamd.conf", OPT_CLAMD }, { "freshclam.conf", OPT_FRESHCLAM }, { "clamav-milter.conf", OPT_MILTER }, { NULL, 0 } }; static const char *dbnames[] = { "main.cvd", "main.cld", "daily.cvd", "daily.cld", "safebrowsing.cvd", "safebrowsing.cld", NULL }; static void printopts(struct optstruct *opts, int nondef) { const struct optstruct *opt; while(opts) { if(!opts->name) { opts = opts->next; continue; } if(clam_options[opts->idx].owner & OPT_DEPRECATED) { if(opts->active) printf("*** %s is DEPRECATED ***\n", opts->name); opts = opts->next; continue; } if(nondef && (opts->numarg == clam_options[opts->idx].numarg) && ((opts->strarg == clam_options[opts->idx].strarg) || (opts->strarg && clam_options[opts->idx].strarg && !strcmp(opts->strarg, clam_options[opts->idx].strarg)))) { opts = opts->next; continue; } if(!opts->enabled) printf("%s disabled\n", opts->name); else switch(clam_options[opts->idx].argtype) { case TYPE_STRING: printf("%s = \"%s\"", opts->name, opts->strarg); opt = opts; while((opt = opt->nextarg)) printf(", \"%s\"", opt->strarg); printf("\n"); break; case TYPE_NUMBER: case TYPE_SIZE: printf("%s = \"%lld\"", opts->name, opts->numarg); opt = opts; while((opt = opt->nextarg)) printf(", \"%lld\"", opt->numarg); printf("\n"); break; case TYPE_BOOL: printf("%s = \"yes\"\n", opts->name); break; default: printf("!!! %s: UNKNOWN INTERNAL TYPE !!!\n", opts->name); } opts = opts->next; } } static int printconf(const char *name) { int i, j, tool = 0, tokens_count; char buffer[1025]; const char *tokens[128]; const struct clam_option *cpt; for(i = 0; cfgfile[i].name; i++) { if(!strcmp(name, cfgfile[i].name)) { tool = cfgfile[i].tool; break; } } if(!tool) { printf("ERROR: Unknown config file\nAvailable options:"); for(i = 0; cfgfile[i].name; i++) printf(" %s", cfgfile[i].name); printf("\n"); return 1; } printf("##\n## %s - automatically generated by clamconf "VERSION"\n##\n", name); printf("\n# Comment out or remove the line below.\nExample\n"); for(i = 0; clam_options[i].owner; i++) { cpt = &clam_options[i]; if(cpt->name && (cpt->owner & tool) && !(cpt->owner & OPT_DEPRECATED) && !(cpt->flags & 4)) { strncpy(buffer, cpt->description, 1024); buffer[1024] = 0; tokens_count = cli_strtokenize(buffer, '\n', 128, tokens); printf("\n"); for(j = 0; j < tokens_count; j++) printf("# %s\n", tokens[j]); switch(cpt->argtype) { case TYPE_STRING: if(cpt->strarg) printf("# Default: %s\n", cpt->strarg); else printf("# Default: disabled\n"); break; case TYPE_NUMBER: if(cpt->numarg != -1) printf("# Default: %lld\n", cpt->numarg); else printf("# Default: disabled\n"); break; case TYPE_SIZE: printf("# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)\n# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size\n# in bytes just don't use modifiers.\n"); if(cpt->numarg != -1) printf("# Default: %lld\n", cpt->numarg); else printf("# Default: disabled\n"); break; case TYPE_BOOL: if(cpt->numarg != -1) printf("# Default: %s\n", cpt->numarg ? "yes" : "no"); else printf("# Default: disabled\n"); break; default: printf("!!! %s: UNKNOWN INTERNAL TYPE !!!\n", cpt->name); } if(cpt->suggested && strchr(cpt->suggested, '\n')) { strncpy(buffer, cpt->suggested, 1024); buffer[1024] = 0; tokens_count = cli_strtokenize(buffer, '\n', 128, tokens); for(j = 0; j < tokens_count; j++) printf("#%s %s\n", cpt->name, tokens[j]); } else { printf("#%s %s\n", cpt->name, cpt->suggested ? cpt->suggested : "ARG"); } } } return 0; } static void help(void) { printf("\n"); printf(" Clam AntiVirus: Configuration Tool %s\n", get_version()); printf(" By The ClamAV Team: http://www.clamav.net/team\n"); printf(" (C) 2009 Sourcefire, Inc.\n\n"); printf(" --help -h Show help\n"); printf(" --version -V Show version\n"); printf(" --config-dir=DIR -c DIR Read configuration files from DIR\n"); printf(" --non-default -n Only display non-default settings\n"); printf(" --generate-config=NAME -g NAME Generate example config file\n"); printf("\n"); return; } int main(int argc, char **argv) { const char *dir; char path[512], dbdir[512], *pt; struct optstruct *opts, *toolopts; const struct optstruct *opt; unsigned int i, j; struct cl_cvd *cvd; unsigned int flevel; opts = optparse(NULL, argc, argv, 1, OPT_CLAMCONF, 0, NULL); if(!opts) { printf("ERROR: Can't parse command line options\n"); return 1; } if(optget(opts, "help")->enabled) { help(); optfree(opts); return 0; } if(optget(opts, "version")->enabled) { printf("Clam AntiVirus Configuration Tool %s\n", get_version()); optfree(opts); return 0; } if((opt = optget(opts, "generate-config"))->enabled) { printconf(opt->strarg); optfree(opts); return 0; } dbdir[0] = 0; dir = optget(opts, "config-dir")->strarg; printf("Checking configuration files in %s\n", dir); for(i = 0; cfgfile[i].name; i++) { snprintf(path, sizeof(path), "%s/%s", dir, cfgfile[i].name); path[511] = 0; if(access(path, R_OK)) { printf("\n%s not found\n", cfgfile[i].name); continue; } printf("\nConfig file: %s\n", cfgfile[i].name); for(j = 0; j < strlen(cfgfile[i].name) + 13; j++) printf("-"); printf("\n"); toolopts = optparse(path, 0, NULL, 1, cfgfile[i].tool | OPT_DEPRECATED, 0, NULL); if(!toolopts) continue; printopts(toolopts, optget(opts, "non-default")->enabled); if(cfgfile[i].tool == OPT_FRESHCLAM) { opt = optget(toolopts, "DatabaseDirectory"); strncpy(dbdir, opt->strarg, sizeof(dbdir)); dbdir[sizeof(dbdir) - 1] = 0; } optfree(toolopts); } optfree(opts); printf("\nSoftware settings\n-----------------\n"); printf("Version: %s\n", cl_retver()); if(strcmp(cl_retver(), get_version())) printf("WARNING: Version mismatch: libclamav=%s, clamconf=%s\n", cl_retver(), get_version()); cl_init(CL_INIT_DEFAULT); printf("Optional features supported: "); #ifdef USE_MPOOL printf("MEMPOOL "); #endif #ifdef SUPPORT_IPv6 printf("IPv6 "); #endif #ifdef CLAMUKO printf("CLAMUKO "); #endif #ifdef C_BIGSTACK printf("BIGSTACK "); #endif #ifdef FRESHCLAM_DNS_FIX printf("FRESHCLAM_DNS_FIX "); #endif #ifdef FPU_WORDS_BIGENDIAN printf("AUTOIT_EA06 "); #endif #ifdef HAVE_BZLIB_H printf("BZIP2 "); #endif if(have_rar) printf("RAR"); printf("\n"); if(!strlen(dbdir)) { pt = freshdbdir(); if(pt) { strncpy(dbdir, pt, sizeof(dbdir)); free(pt); } else { strncpy(dbdir, DATADIR, sizeof(dbdir)); } dbdir[sizeof(dbdir) - 1] = 0; } printf("Database directory: %s\n", dbdir); flevel = cl_retflevel(); for(i = 0; dbnames[i]; i++) { snprintf(path, sizeof(path), "%s/%s", dbdir, dbnames[i]); path[511] = 0; if(!access(path, R_OK)) { cvd = cl_cvdhead(path); if(!cvd) { printf("%s: Can't get information about the database\n", dbnames[i]); } else { printf("%s: version %u, sigs: %u, built on %s", dbnames[i], cvd->version, cvd->sigs, ctime((const time_t *) &cvd->stime)); if(cvd->fl > flevel) printf("%s: WARNING: This database requires f-level %u (current f-level: %u)\n", dbnames[i], cvd->fl, flevel); cl_cvdfree(cvd); } } } return 0; }