You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
klamav/src/klammail/cfgparser.c

306 lines
8.1 KiB

/*
* Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm@clamav.net>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "options.h"
#include "cfgparser.h"
#include "defaults.h"
#include "str.h"
#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;
}
struct cfgstruct *parsecfg(const char *cfgfile)
{
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},
{"LogClean", OPT_NOARG},
{"LogVerbose", OPT_NOARG}, /* clamd + freshclam */
{"LogSyslog", OPT_NOARG},
{"LogFacility", OPT_STR},
{"PidFile", OPT_STR},
{"TemporaryDirectory", OPT_STR},
{"MaxFileSize", OPT_COMPSIZE},
{"ScanMail", OPT_NOARG},
{"ScanOLE2", OPT_NOARG},
{"ScanArchive", OPT_NOARG},
{"ScanRAR", OPT_NOARG},
{"ArchiveMaxFileSize", OPT_COMPSIZE},
{"ArchiveMaxRecursion", OPT_NUM},
{"ArchiveMaxFiles", OPT_NUM},
{"ArchiveMaxCompressionRatio", OPT_NUM},
{"ArchiveLimitMemoryUsage", OPT_NOARG},
{"ArchiveBlockEncrypted", OPT_NOARG},
{"DataDirectory", OPT_STR}, /* obsolete */
{"DatabaseDirectory", OPT_STR}, /* clamd + freshclam */
{"TCPAddr", OPT_STR},
{"TCPSocket", OPT_NUM},
{"LocalSocket", OPT_STR},
{"MaxConnectionQueueLength", OPT_NUM},
{"StreamSaveToDisk", OPT_NOARG},
{"StreamMaxLength", OPT_COMPSIZE},
{"MaxThreads", OPT_NUM},
{"ReadTimeout", OPT_NUM},
{"MaxDirectoryRecursion", OPT_NUM},
{"FollowDirectorySymlinks", OPT_NOARG},
{"FollowFileSymlinks", OPT_NOARG},
{"Foreground", OPT_NOARG},
{"Debug", OPT_NOARG},
{"LeaveTemporaryFiles", OPT_NOARG},
{"FixStaleSocket", OPT_NOARG},
{"User", OPT_STR},
{"AllowSupplementaryGroups", OPT_NOARG},
{"SelfCheck", OPT_NUM},
{"VirusEvent", OPT_FULLSTR},
{"ClamukoScanOnLine", OPT_NOARG}, /* old name */
{"ClamukoScanOnAccess", OPT_NOARG},
{"ClamukoScanOnOpen", OPT_NOARG},
{"ClamukoScanOnClose", OPT_NOARG},
{"ClamukoScanOnExec", OPT_NOARG},
{"ClamukoIncludePath", OPT_STR},
{"ClamukoExcludePath", OPT_STR},
{"ClamukoMaxFileSize", OPT_COMPSIZE},
{"ClamukoScanArchive", OPT_NOARG},
{"DatabaseOwner", OPT_STR}, /* freshclam */
{"Checks", OPT_NUM}, /* freshclam */
{"UpdateLogFile", OPT_STR}, /* freshclam */
{"DatabaseMirror", OPT_STR}, /* freshclam */
{"MaxAttempts", OPT_NUM}, /* freshclam */
{"HTTPProxyServer", OPT_STR}, /* freshclam */
{"HTTPProxyPort", OPT_NUM}, /* freshclam */
{"HTTPProxyUsername", OPT_STR}, /* freshclam */
{"HTTPProxyPassword", OPT_STR}, /* freshclam */
{"NotifyClamd", OPT_OPTARG}, /* freshclam */
{"OnUpdateExecute", OPT_FULLSTR}, /* freshclam */
{"OnErrorExecute", OPT_FULLSTR}, /* freshclam */
{0, 0}
};
if((fs = fopen(cfgfile, "r")) == NULL) {
return NULL;
}
while(fgets(buff, LINE_LENGTH, fs)) {
line++;
if(buff[0] == '#')
continue;
if(!strncmp("Example", buff, 7)) {
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile);
return NULL;
}
if((name = cli_strtok(buff, 0, " \r\n"))) {
arg = cli_strtok(buff, 1, " \r\n");
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) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name);
return NULL;
}
copt = regcfg(copt, name, arg, 0);
break;
case OPT_FULLSTR:
if(!arg) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name);
return NULL;
}
/* FIXME: this one is an ugly hack of the above case */
free(arg);
arg = strstr(buff, " ");
arg = strdup(++arg);
copt = regcfg(copt, name, arg, 0);
break;
case OPT_NUM:
if(!arg || !isnumb(arg)) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name);
return NULL;
}
copt = regcfg(copt, name, NULL, atoi(arg));
free(arg);
break;
case OPT_COMPSIZE:
if(!arg) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name);
return NULL;
}
ctype = tolower(arg[strlen(arg) - 1]);
if(ctype == 'm' || ctype == 'k') {
char *cpy = (char *) mcalloc(strlen(arg), sizeof(char));
strncpy(cpy, arg, strlen(arg) - 1);
if(!isnumb(cpy)) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
return NULL;
}
if(ctype == 'm')
calc = atoi(cpy) * 1024 * 1024;
else
calc = atoi(cpy) * 1024;
free(cpy);
} else {
if(!isnumb(arg)) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
return NULL;
}
calc = atoi(arg);
}
copt = regcfg(copt, name, NULL, calc);
free(arg);
break;
case OPT_NOARG:
if(arg) {
fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg);
return NULL;
}
copt = regcfg(copt, name, NULL, 0);
break;
case OPT_OPTARG:
copt = regcfg(copt, name, arg, 0);
break;
default:
fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype);
free(name);
free(arg);
break;
}
}
} else
break;
}
if(!found) {
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name);
return NULL;
}
}
}
fclose(fs);
return copt;
}
void freecfg(struct cfgstruct *copt)
{
struct cfgstruct *handler;
struct cfgstruct *arg;
while (copt) {
arg = copt->nextarg;
while (arg) {
if(arg->strarg) {
free(arg->optname);
free(arg->strarg);
handler = arg;
arg=arg->nextarg;
free(handler);
}
}
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)
{
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;
}