e3aaff8e |
/* |
8ca8a18e |
* Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm@clamav.net> |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 |
48b7b4a7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
e3aaff8e |
*/
|
6d6e8271 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
e3aaff8e |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
|
a889f40e |
#include "shared/cfgparser.h"
#include "shared/misc.h" |
e3aaff8e |
|
a889f40e |
#include "libclamav/str.h" |
e628b432 |
struct cfgoption cfg_options[] = { |
5174f778 |
{"LogFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"LogFileUnlock", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"LogFileMaxSize", OPT_COMPSIZE, 1048576, NULL, 0, OPT_CLAMD},
{"LogTime", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"LogClean", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"LogVerbose", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
{"LogSyslog", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM}, |
eaa9dbda |
{"LogFacility", OPT_QUOTESTR, -1, "LOG_LOCAL6", 0, OPT_CLAMD | OPT_FRESHCLAM}, |
5174f778 |
{"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
{"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"ScanPE", OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
3f97a1e7 |
{"ScanELF", OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"ScanMail", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
{"MailFollowURLs", OPT_BOOL, 0, NULL, 0, OPT_CLAMD}, |
dab42957 |
{"MailMaxRecursion", OPT_NUM, 64, NULL, 0, OPT_CLAMD}, |
af7d0dde |
{"PhishingSignatures", OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
a68507c5 |
{"PhishingScanURLs",OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
19b3e182 |
/* these are FP prone options, if default isn't used */
{"PhishingAlwaysBlockCloak", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"PhishingAlwaysBlockSSLMismatch", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"PhishingRestrictedScan", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
/* end of FP prone options */ |
47138a98 |
{"AlgorithmicDetection", OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"ScanHTML", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
{"ScanOLE2", OPT_BOOL, 1, NULL, 0, OPT_CLAMD}, |
c5107e70 |
{"ScanPDF", OPT_BOOL, 0, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"ScanArchive", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
{"ArchiveMaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
{"ArchiveMaxRecursion", OPT_NUM, 8, NULL, 0, OPT_CLAMD},
{"ArchiveMaxFiles", OPT_NUM, 1000, NULL, 0, OPT_CLAMD},
{"ArchiveMaxCompressionRatio", OPT_NUM, 250, NULL, 0, OPT_CLAMD},
{"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0, OPT_CLAMD}, |
5174f778 |
{"DatabaseDirectory", OPT_QUOTESTR, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM}, |
eaa9dbda |
{"TCPAddr", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"TCPSocket", OPT_NUM, -1, NULL, 0, OPT_CLAMD}, |
8f4dd285 |
{"LocalSocket", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"MaxConnectionQueueLength", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
{"StreamMaxLength", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
{"StreamMinPort", OPT_NUM, 1024, NULL, 0, OPT_CLAMD},
{"StreamMaxPort", OPT_NUM, 2048, NULL, 0, OPT_CLAMD},
{"MaxThreads", OPT_NUM, 10, NULL, 0, OPT_CLAMD},
{"ReadTimeout", OPT_NUM, 120, NULL, 0, OPT_CLAMD},
{"IdleTimeout", OPT_NUM, 30, NULL, 0, OPT_CLAMD},
{"MaxDirectoryRecursion", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
{"FollowDirectorySymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"FollowFileSymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"ExitOnOOM", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"Foreground", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
{"Debug", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
{"LeaveTemporaryFiles", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
{"FixStaleSocket", OPT_BOOL, 0, NULL, 0, OPT_CLAMD}, |
eaa9dbda |
{"User", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD}, |
e628b432 |
{"AllowSupplementaryGroups", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
{"SelfCheck", OPT_NUM, 1800, NULL, 0, OPT_CLAMD},
{"VirusEvent", OPT_FULLSTR, -1, NULL, 0, OPT_CLAMD}, |
b5456d64 |
{"NodalCoreAcceleration", OPT_BOOL, 0, NULL, 0, OPT_CLAMD}, |
0bbe0584 |
{"ClamukoScanOnAccess", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
{"ClamukoScanOnOpen", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
{"ClamukoScanOnClose", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
{"ClamukoScanOnExec", OPT_BOOL, -1, NULL, 0, OPT_CLAMD}, |
9373401e |
{"ClamukoIncludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD},
{"ClamukoExcludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD}, |
e628b432 |
{"ClamukoMaxFileSize", OPT_COMPSIZE, 5242880, NULL, 0, OPT_CLAMD}, |
eaa9dbda |
{"DatabaseOwner", OPT_QUOTESTR, -1, CLAMAVUSER, 0, OPT_FRESHCLAM}, |
e628b432 |
{"Checks", OPT_NUM, 12, NULL, 0, OPT_FRESHCLAM}, |
5174f778 |
{"UpdateLogFile", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
eaa9dbda |
{"DNSDatabaseInfo", OPT_QUOTESTR, -1, "current.cvd.clamav.net", 0, OPT_FRESHCLAM},
{"DatabaseMirror", OPT_QUOTESTR, -1, NULL, 1, OPT_FRESHCLAM}, |
e628b432 |
{"MaxAttempts", OPT_NUM, 3, NULL, 0, OPT_FRESHCLAM}, |
011b4f29 |
{"ScriptedUpdates", OPT_BOOL, 1, NULL, 0, OPT_FRESHCLAM}, |
eaa9dbda |
{"HTTPProxyServer", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
e628b432 |
{"HTTPProxyPort", OPT_NUM, -1, NULL, 0, OPT_FRESHCLAM}, |
eaa9dbda |
{"HTTPProxyUsername", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
{"HTTPProxyPassword", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
e628b432 |
{"HTTPUserAgent", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM}, |
8f4dd285 |
{"NotifyClamd", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
e628b432 |
{"OnUpdateExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
{"OnErrorExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
{"OnOutdatedExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM}, |
eaa9dbda |
{"LocalIPAddress", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM}, |
c27b1e2f |
{"ConnectTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM}, |
7d1c492d |
{"ReceiveTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM}, |
e628b432 |
{NULL, 0, 0, NULL, 0, 0}
};
|
fc83da82 |
static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple); |
81837459 |
struct cfgstruct *getcfg(const char *cfgfile, int verbose) |
e3aaff8e |
{ |
2e988965 |
char buff[LINE_LENGTH], *name, *arg, *c; |
e3aaff8e |
FILE *fs; |
81837459 |
int line = 0, i, found, ctype, calc, val; |
e3aaff8e |
struct cfgstruct *copt = NULL;
struct cfgoption *pt;
|
81837459 |
for(i = 0; ; i++) {
pt = &cfg_options[i];
if(!pt->name)
break;
|
52c3c225 |
if(regcfg(&copt, pt->name, pt->strarg ? strdup(pt->strarg) : NULL, pt->numarg, pt->multiple) < 0) { |
81837459 |
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
freecfg(copt);
return NULL;
}
}
|
109bde85 |
if((fs = fopen(cfgfile, "rb")) == NULL) { |
81837459 |
/* do not print error message here! */
freecfg(copt); |
e3aaff8e |
return NULL; |
81837459 |
} |
e3aaff8e |
while(fgets(buff, LINE_LENGTH, fs)) {
line++;
if(buff[0] == '#')
continue;
if(!strncmp("Example", buff, 7)) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); |
bcf3dc79 |
fclose(fs); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
|
2d70a403 |
if((name = cli_strtok(buff, 0, " \r\n"))) {
arg = cli_strtok(buff, 1, " \r\n"); |
e3aaff8e |
found = 0;
for(i = 0; ; i++) {
pt = &cfg_options[i];
if(pt->name) {
if(!strcmp(name, pt->name)) {
found = 1;
switch(pt->argtype) {
case OPT_STR: |
eaa9dbda |
/* deprecated. Use OPT_QUOTESTR instead since it behaves like this, but supports quotes to allow values to contain whitespace */ |
e3aaff8e |
if(!arg) { |
81837459 |
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name); |
81837459 |
freecfg(copt);
return NULL;
}
if(regcfg(&copt, name, arg, -1, pt->multiple) < 0) {
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
break; |
0249f9d2 |
case OPT_FULLSTR: |
81837459 |
/* an ugly hack of the above case */ |
0249f9d2 |
if(!arg) { |
81837459 |
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name); |
81837459 |
freecfg(copt); |
0249f9d2 |
return NULL;
}
free(arg);
arg = strstr(buff, " ");
arg = strdup(++arg); |
8de0d031 |
if((arg) && (c = strpbrk(arg, "\n\r"))) |
2e988965 |
*c = '\0'; |
8de0d031 |
if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) { |
81837459 |
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt);
return NULL;
} |
0249f9d2 |
break; |
5174f778 |
case OPT_QUOTESTR:
/* an ugly hack of the above case */
if(!arg) {
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
fclose(fs);
free(name);
freecfg(copt);
return NULL;
}
if((*arg == '\'') || (*arg == '"')) {
free(arg);
c = strstr(buff, " ");
arg = strdup(c+2);
if(arg) {
if((c = strchr(arg, c[1])))
*c = '\0';
else {
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s missing closing quote.\n", line, name);
fclose(fs);
free(name);
free(arg);
freecfg(copt);
return NULL;
}
}
}
if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) {
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
fclose(fs);
free(name);
free(arg);
freecfg(copt);
return NULL;
}
break; |
e3aaff8e |
case OPT_NUM: |
0deebced |
if(!arg || !isnumb(arg)) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt);
return NULL;
}
if(regcfg(&copt, name, NULL, atoi(arg), pt->multiple) < 0) {
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
fclose(fs); |
8de0d031 |
free(name); |
81837459 |
free(arg); |
8de0d031 |
freecfg(copt); |
e3aaff8e |
return NULL;
} |
2d70a403 |
free(arg); |
e3aaff8e |
break;
case OPT_COMPSIZE:
if(!arg) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
ctype = tolower(arg[strlen(arg) - 1]);
if(ctype == 'm' || ctype == 'k') { |
65d08d61 |
char *cpy = (char *) calloc(strlen(arg), 1); |
658f19f8 |
strncpy(cpy, arg, strlen(arg) - 1); |
e3aaff8e |
if(!isnumb(cpy)) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
if(ctype == 'm')
calc = atoi(cpy) * 1024 * 1024;
else
calc = atoi(cpy) * 1024;
free(cpy);
} else {
if(!isnumb(arg)) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
calc = atoi(arg);
} |
2d70a403 |
free(arg); |
81837459 |
if(regcfg(&copt, name, NULL, calc, pt->multiple) < 0) {
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
bcf3dc79 |
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
}
break; |
81837459 |
case OPT_BOOL:
if(!arg) {
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
fclose(fs); |
8de0d031 |
free(name); |
81837459 |
freecfg(copt);
return NULL;
}
if(!strcasecmp(arg, "yes") || !strcmp(arg, "1") || !strcasecmp(arg, "true")) {
val = 1;
} else if(!strcasecmp(arg, "no") || !strcmp(arg, "0") || !strcasecmp(arg, "false")) {
val = 0;
} else {
if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt);
return NULL;
}
free(arg);
if(regcfg(&copt, name, NULL, val, pt->multiple) < 0) {
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
fclose(fs); |
8de0d031 |
free(name);
free(arg); |
81837459 |
freecfg(copt);
return NULL;
} |
e3aaff8e |
break; |
2d70a403 |
default: |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype); |
8de0d031 |
fclose(fs); |
2d70a403 |
free(name);
free(arg); |
81837459 |
freecfg(copt);
return NULL; |
e3aaff8e |
}
}
} else
break; |
81837459 |
} |
e3aaff8e |
if(!found) { |
81837459 |
if(verbose) |
cc71d7c2 |
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); |
8de0d031 |
free(name); |
bcf3dc79 |
fclose(fs); |
81837459 |
freecfg(copt); |
e3aaff8e |
return NULL;
} |
52c3c225 |
free(name); |
e3aaff8e |
}
}
fclose(fs);
return copt;
}
|
9e431a95 |
void freecfg(struct cfgstruct *copt)
{
struct cfgstruct *handler;
struct cfgstruct *arg;
|
81837459 |
while(copt) { |
9e431a95 |
arg = copt->nextarg; |
5467c418 |
while(arg) { |
9e431a95 |
if(arg->strarg) {
free(arg->optname);
free(arg->strarg);
handler = arg; |
5467c418 |
arg = arg->nextarg; |
9e431a95 |
free(handler); |
5467c418 |
} else
arg = arg->nextarg; |
9e431a95 |
} |
81837459 |
if(copt->optname) |
9e431a95 |
free(copt->optname); |
81837459 |
if(copt->strarg) |
9e431a95 |
free(copt->strarg); |
81837459 |
|
9e431a95 |
handler = copt;
copt = copt->next;
free(handler);
}
return;
}
|
1095156a |
const struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname)
{
while(copt) {
if(copt->optname && !strcmp(copt->optname, optname))
return copt;
copt = copt->next;
}
return NULL;
}
static struct cfgstruct *cfgopt_i(struct cfgstruct *copt, const char *optname) |
81837459 |
{ |
797c5b1e |
while(copt) {
if(copt->optname && !strcmp(copt->optname, optname))
return copt; |
81837459 |
|
797c5b1e |
copt = copt->next; |
81837459 |
}
return NULL;
}
|
fc83da82 |
static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple) |
e3aaff8e |
{
struct cfgstruct *newnode, *pt;
|
81837459 |
|
8ca8a18e |
newnode = (struct cfgstruct *) malloc(sizeof(struct cfgstruct)); |
81837459 |
if(!newnode)
return -1;
|
52c3c225 |
newnode->optname = optname ? strdup(optname) : NULL; |
e3aaff8e |
newnode->nextarg = NULL;
newnode->next = NULL; |
81837459 |
newnode->enabled = 0;
newnode->multiple = multiple; |
e3aaff8e |
|
81837459 |
if(strarg) { |
e3aaff8e |
newnode->strarg = strarg; |
81837459 |
newnode->enabled = 1;
} else { |
e3aaff8e |
newnode->strarg = NULL;
}
|
81837459 |
newnode->numarg = numarg;
if(numarg != -1 && numarg != 0)
newnode->enabled = 1; |
e3aaff8e |
|
1095156a |
if((pt = cfgopt_i(*copt, optname))) { |
81837459 |
if(pt->multiple) { |
e3aaff8e |
|
81837459 |
if(pt->enabled) {
while(pt->nextarg)
pt = pt->nextarg; |
e3aaff8e |
|
81837459 |
pt->nextarg = newnode;
} else { |
52c3c225 |
if(pt->strarg)
free(pt->strarg); |
81837459 |
pt->strarg = newnode->strarg;
pt->numarg = newnode->numarg;
pt->enabled = newnode->enabled; |
52c3c225 |
if(newnode->optname)
free(newnode->optname); |
81837459 |
free(newnode);
}
return 3; /* registered additional argument */ |
e3aaff8e |
|
81837459 |
} else { |
52c3c225 |
if(pt->strarg)
free(pt->strarg); |
81837459 |
pt->strarg = newnode->strarg;
pt->numarg = newnode->numarg;
pt->enabled = newnode->enabled; |
52c3c225 |
if(newnode->optname)
free(newnode->optname); |
81837459 |
free(newnode);
return 2;
} |
e3aaff8e |
|
81837459 |
} else {
newnode->next = *copt;
*copt = newnode;
return 1;
} |
e3aaff8e |
} |
81837459 |
|