e3aaff8e |
/* |
ee039e40 |
* Copyright (C) 2002 - 2004 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
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
|
6d6e8271 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
e3aaff8e |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "options.h" |
afb48b28 |
#include "cfgparser.h" |
e3aaff8e |
#include "defaults.h" |
2d70a403 |
#include "str.h" |
afb48b28 |
#include "memory.h"
static int isnumb(const char *str)
{
int i;
for(i = 0; i < strlen(str); i++)
if(!isdigit(str[i]))
return 0;
return 1;
} |
e3aaff8e |
|
cc71d7c2 |
struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
e3aaff8e |
{
char buff[LINE_LENGTH], *name, *arg;
FILE *fs;
int line = 0, i, found, ctype, calc;
struct cfgstruct *copt = NULL;
struct cfgoption *pt;
struct cfgoption cfg_options[] = {
{"LogFile", OPT_STR},
{"LogFileUnlock", OPT_NOARG},
{"LogFileMaxSize", OPT_COMPSIZE},
{"LogTime", OPT_NOARG}, |
ee039e40 |
{"LogClean", OPT_NOARG}, |
95d401c4 |
{"LogVerbose", OPT_NOARG}, /* clamd + freshclam */ |
e3aaff8e |
{"LogSyslog", OPT_NOARG}, |
c695dab4 |
{"LogFacility", OPT_STR}, |
e3aaff8e |
{"PidFile", OPT_STR}, |
ee039e40 |
{"TemporaryDirectory", OPT_STR}, |
e3aaff8e |
{"MaxFileSize", OPT_COMPSIZE}, |
a9082ea2 |
{"ScanPE", OPT_NOARG}, |
20c3d44d |
{"DetectBrokenExecutables", OPT_NOARG}, |
e3aaff8e |
{"ScanMail", OPT_NOARG}, |
a36e6e5c |
{"MailFollowURLs", OPT_NOARG}, |
888f5794 |
{"ScanHTML", OPT_NOARG}, |
e8c9ccdb |
{"ScanOLE2", OPT_NOARG}, |
e3aaff8e |
{"ScanArchive", OPT_NOARG}, |
8139fd99 |
{"ScanRAR", OPT_NOARG}, |
e3aaff8e |
{"ArchiveMaxFileSize", OPT_COMPSIZE},
{"ArchiveMaxRecursion", OPT_NUM},
{"ArchiveMaxFiles", OPT_NUM}, |
a6945b5d |
{"ArchiveMaxCompressionRatio", OPT_NUM}, |
e3aaff8e |
{"ArchiveLimitMemoryUsage", OPT_NOARG}, |
5484e03c |
{"ArchiveBlockEncrypted", OPT_NOARG}, |
d272908a |
{"ArchiveBlockMax", OPT_NOARG}, |
95d401c4 |
{"DataDirectory", OPT_STR}, /* obsolete */
{"DatabaseDirectory", OPT_STR}, /* clamd + freshclam */ |
8139fd99 |
{"TCPAddr", OPT_STR}, |
e3aaff8e |
{"TCPSocket", OPT_NUM},
{"LocalSocket", OPT_STR},
{"MaxConnectionQueueLength", OPT_NUM},
{"StreamMaxLength", OPT_COMPSIZE},
{"MaxThreads", OPT_NUM}, |
7390dfcd |
{"ReadTimeout", OPT_NUM}, |
e3aaff8e |
{"MaxDirectoryRecursion", OPT_NUM},
{"FollowDirectorySymlinks", OPT_NOARG},
{"FollowFileSymlinks", OPT_NOARG},
{"Foreground", OPT_NOARG}, |
0249f9d2 |
{"Debug", OPT_NOARG}, |
590135f9 |
{"LeaveTemporaryFiles", OPT_NOARG}, |
049a18b9 |
{"FixStaleSocket", OPT_NOARG}, |
e3aaff8e |
{"User", OPT_STR},
{"AllowSupplementaryGroups", OPT_NOARG},
{"SelfCheck", OPT_NUM}, |
0249f9d2 |
{"VirusEvent", OPT_FULLSTR}, |
2b278a02 |
{"ClamukoScanOnLine", OPT_NOARG}, /* old name */
{"ClamukoScanOnAccess", OPT_NOARG}, |
e3aaff8e |
{"ClamukoScanOnOpen", OPT_NOARG},
{"ClamukoScanOnClose", OPT_NOARG},
{"ClamukoScanOnExec", OPT_NOARG},
{"ClamukoIncludePath", OPT_STR},
{"ClamukoExcludePath", OPT_STR},
{"ClamukoMaxFileSize", OPT_COMPSIZE},
{"ClamukoScanArchive", OPT_NOARG}, |
95d401c4 |
{"DatabaseOwner", OPT_STR}, /* freshclam */
{"Checks", OPT_NUM}, /* freshclam */
{"UpdateLogFile", OPT_STR}, /* freshclam */ |
3e92581e |
{"DNSDatabaseInfo", OPT_STR}, /* freshclam */ |
95d401c4 |
{"DatabaseMirror", OPT_STR}, /* freshclam */
{"MaxAttempts", OPT_NUM}, /* freshclam */
{"HTTPProxyServer", OPT_STR}, /* freshclam */ |
8105f365 |
{"HTTPProxyPort", OPT_NUM}, /* freshclam */ |
a7d9bef2 |
{"HTTPProxyUsername", OPT_STR}, /* freshclam */ |
95d401c4 |
{"HTTPProxyPassword", OPT_STR}, /* freshclam */
{"NotifyClamd", OPT_OPTARG}, /* freshclam */
{"OnUpdateExecute", OPT_FULLSTR}, /* freshclam */
{"OnErrorExecute", OPT_FULLSTR}, /* freshclam */ |
e3aaff8e |
{0, 0}
};
|
bcf3dc79 |
if((fs = fopen(cfgfile, "r")) == NULL) |
e3aaff8e |
return NULL;
while(fgets(buff, LINE_LENGTH, fs)) {
line++;
if(buff[0] == '#')
continue;
if(!strncmp("Example", buff, 7)) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); |
bcf3dc79 |
fclose(fs); |
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:
if(!arg) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
copt = regcfg(copt, name, arg, 0);
break; |
0249f9d2 |
case OPT_FULLSTR:
if(!arg) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
0249f9d2 |
return NULL;
} |
bf5a1ce7 |
/* FIXME: this one is an ugly hack of the above case */ |
0249f9d2 |
free(arg);
arg = strstr(buff, " ");
arg = strdup(++arg);
copt = regcfg(copt, name, arg, 0);
break; |
e3aaff8e |
case OPT_NUM: |
0deebced |
if(!arg || !isnumb(arg)) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
copt = regcfg(copt, name, NULL, atoi(arg)); |
2d70a403 |
free(arg); |
e3aaff8e |
break;
case OPT_COMPSIZE:
if(!arg) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
ctype = tolower(arg[strlen(arg) - 1]);
if(ctype == 'm' || ctype == 'k') { |
afb48b28 |
char *cpy = (char *) mcalloc(strlen(arg), sizeof(char)); |
658f19f8 |
strncpy(cpy, arg, strlen(arg) - 1); |
e3aaff8e |
if(!isnumb(cpy)) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
if(ctype == 'm')
calc = atoi(cpy) * 1024 * 1024;
else
calc = atoi(cpy) * 1024;
free(cpy);
} else {
if(!isnumb(arg)) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
calc = atoi(arg);
}
copt = regcfg(copt, name, NULL, calc); |
2d70a403 |
free(arg); |
e3aaff8e |
break;
case OPT_NOARG:
if(arg) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
copt = regcfg(copt, name, NULL, 0);
break;
case OPT_OPTARG:
copt = regcfg(copt, name, arg, 0);
break; |
2d70a403 |
default: |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype); |
2d70a403 |
free(name);
free(arg);
break; |
e3aaff8e |
}
}
} else
break;
}
if(!found) { |
cc71d7c2 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); |
bcf3dc79 |
fclose(fs); |
e3aaff8e |
return NULL;
}
}
}
fclose(fs);
return copt;
}
|
9e431a95 |
void freecfg(struct cfgstruct *copt)
{
struct cfgstruct *handler;
struct cfgstruct *arg;
while (copt) {
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 |
}
if(copt->optname) {
free(copt->optname);
}
if(copt->strarg) {
free(copt->strarg);
}
handler = copt;
copt = copt->next;
free(handler);
}
return;
}
struct cfgstruct *regcfg(struct cfgstruct *copt, char *optname, char *strarg, int numarg) |
e3aaff8e |
{
struct cfgstruct *newnode, *pt;
newnode = (struct cfgstruct *) mmalloc(sizeof(struct cfgstruct));
newnode->optname = optname;
newnode->nextarg = NULL;
newnode->next = NULL;
if(strarg)
newnode->strarg = strarg;
else {
newnode->strarg = NULL;
newnode->numarg = numarg;
}
if((pt = cfgopt(copt, optname))) {
while(pt->nextarg)
pt = pt->nextarg;
pt->nextarg = newnode;
return copt;
} else {
newnode->next = copt;
return newnode;
}
}
struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname)
{
struct cfgstruct *handler;
handler = (struct cfgstruct *) copt;
while(1) {
if(handler) {
if(handler->optname)
if(!strcmp(handler->optname, optname))
return handler;
} else break;
handler = handler->next;
}
return NULL;
} |