b151ef55 |
/* |
50099661 |
* Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm@clamav.net> |
b151ef55 |
*
* 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.
*/
|
8b242bb9 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
b151ef55 |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "options.h" |
36f2038b |
#include "cfgparser.h" |
b151ef55 |
#include "defaults.h" |
e8217f5a |
#include "str.h" |
36f2038b |
#include "memory.h" |
d2f07436 |
#include "misc.h" |
b151ef55 |
|
819c7c41 |
struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
b151ef55 |
{ |
e82a5185 |
char buff[LINE_LENGTH], *name, *arg, *c; |
b151ef55 |
FILE *fs;
int line = 0, i, found, ctype, calc;
struct cfgstruct *copt = NULL;
struct cfgoption *pt;
struct cfgoption cfg_options[] = { |
e82a5185 |
{"LogFile", OPT_FULLSTR}, |
b151ef55 |
{"LogFileUnlock", OPT_NOARG},
{"LogFileMaxSize", OPT_COMPSIZE},
{"LogTime", OPT_NOARG}, |
50099661 |
{"LogClean", OPT_NOARG}, |
0d98d74c |
{"LogVerbose", OPT_NOARG}, /* clamd + freshclam */ |
b151ef55 |
{"LogSyslog", OPT_NOARG}, |
096e5bbd |
{"LogFacility", OPT_STR}, |
e82a5185 |
{"PidFile", OPT_FULLSTR},
{"TemporaryDirectory", OPT_FULLSTR}, |
511eef51 |
{"DisableDefaultScanOptions", OPT_NOARG}, |
c2484690 |
{"ScanPE", OPT_NOARG}, |
f8355d13 |
{"DetectBrokenExecutables", OPT_NOARG}, |
b151ef55 |
{"ScanMail", OPT_NOARG}, |
94da957a |
{"MailFollowURLs", OPT_NOARG}, |
2fe19b26 |
{"ScanHTML", OPT_NOARG}, |
90e447be |
{"ScanOLE2", OPT_NOARG}, |
b151ef55 |
{"ScanArchive", OPT_NOARG}, |
4cd4319e |
{"ScanRAR", OPT_NOARG}, |
b151ef55 |
{"ArchiveMaxFileSize", OPT_COMPSIZE},
{"ArchiveMaxRecursion", OPT_NUM},
{"ArchiveMaxFiles", OPT_NUM}, |
cf899a29 |
{"ArchiveMaxCompressionRatio", OPT_NUM}, |
b151ef55 |
{"ArchiveLimitMemoryUsage", OPT_NOARG}, |
8373a9b0 |
{"ArchiveBlockEncrypted", OPT_NOARG}, |
728f8802 |
{"ArchiveBlockMax", OPT_NOARG}, |
e82a5185 |
{"DataDirectory", OPT_FULLSTR}, /* obsolete */
{"DatabaseDirectory", OPT_FULLSTR}, /* clamd + freshclam */ |
4cd4319e |
{"TCPAddr", OPT_STR}, |
b151ef55 |
{"TCPSocket", OPT_NUM}, |
e82a5185 |
{"LocalSocket", OPT_FULLSTR}, |
b151ef55 |
{"MaxConnectionQueueLength", OPT_NUM},
{"StreamMaxLength", OPT_COMPSIZE}, |
166069c2 |
{"StreamMinPort", OPT_NUM},
{"StreamMaxPort", OPT_NUM}, |
b151ef55 |
{"MaxThreads", OPT_NUM}, |
3520af97 |
{"ReadTimeout", OPT_NUM}, |
a0231a19 |
{"IdleTimeout", OPT_NUM}, |
b151ef55 |
{"MaxDirectoryRecursion", OPT_NUM},
{"FollowDirectorySymlinks", OPT_NOARG},
{"FollowFileSymlinks", OPT_NOARG}, |
df4a42fe |
{"ExitOnOOM", OPT_NOARG}, |
55ae06a5 |
{"Foreground", OPT_NOARG}, /* clamd + freshclam */ |
c72178a4 |
{"Debug", OPT_NOARG}, |
3506c157 |
{"LeaveTemporaryFiles", OPT_NOARG}, |
c6259ac5 |
{"FixStaleSocket", OPT_NOARG}, |
b151ef55 |
{"User", OPT_STR},
{"AllowSupplementaryGroups", OPT_NOARG},
{"SelfCheck", OPT_NUM}, |
c72178a4 |
{"VirusEvent", OPT_FULLSTR}, |
b5ad6489 |
{"ClamukoScanOnLine", OPT_NOARG}, /* old name */
{"ClamukoScanOnAccess", OPT_NOARG}, |
b151ef55 |
{"ClamukoScanOnOpen", OPT_NOARG},
{"ClamukoScanOnClose", OPT_NOARG},
{"ClamukoScanOnExec", OPT_NOARG},
{"ClamukoIncludePath", OPT_STR},
{"ClamukoExcludePath", OPT_STR},
{"ClamukoMaxFileSize", OPT_COMPSIZE},
{"ClamukoScanArchive", OPT_NOARG}, |
0d98d74c |
{"DatabaseOwner", OPT_STR}, /* freshclam */
{"Checks", OPT_NUM}, /* freshclam */ |
e82a5185 |
{"UpdateLogFile", OPT_FULLSTR}, /* freshclam */ |
881069d7 |
{"DNSDatabaseInfo", OPT_STR}, /* freshclam */ |
0d98d74c |
{"DatabaseMirror", OPT_STR}, /* freshclam */
{"MaxAttempts", OPT_NUM}, /* freshclam */
{"HTTPProxyServer", OPT_STR}, /* freshclam */ |
d11fb38a |
{"HTTPProxyPort", OPT_NUM}, /* freshclam */ |
819bbe1f |
{"HTTPProxyUsername", OPT_STR}, /* freshclam */ |
0d98d74c |
{"HTTPProxyPassword", OPT_STR}, /* freshclam */
{"NotifyClamd", OPT_OPTARG}, /* freshclam */
{"OnUpdateExecute", OPT_FULLSTR}, /* freshclam */
{"OnErrorExecute", OPT_FULLSTR}, /* freshclam */ |
d18eac06 |
{"OnOutdatedExecute", OPT_FULLSTR}, /* freshclam */ |
0539b2a8 |
{"LocalIPAddress", OPT_STR}, /* freshclam */ |
d18eac06 |
{0, 0}, |
b151ef55 |
};
|
25133aef |
if((fs = fopen(cfgfile, "r")) == NULL) |
b151ef55 |
return NULL;
while(fgets(buff, LINE_LENGTH, fs)) {
line++;
if(buff[0] == '#')
continue;
if(!strncmp("Example", buff, 7)) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
|
e8217f5a |
if((name = cli_strtok(buff, 0, " \r\n"))) {
arg = cli_strtok(buff, 1, " \r\n"); |
b151ef55 |
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) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
copt = regcfg(copt, name, arg, 0);
break; |
c72178a4 |
case OPT_FULLSTR:
if(!arg) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
25133aef |
fclose(fs); |
c72178a4 |
return NULL;
} |
8a05efc5 |
/* FIXME: this one is an ugly hack of the above case */ |
c72178a4 |
free(arg);
arg = strstr(buff, " ");
arg = strdup(++arg); |
e82a5185 |
if((c = strpbrk(arg, "\n\r")))
*c = '\0'; |
c72178a4 |
copt = regcfg(copt, name, arg, 0);
break; |
b151ef55 |
case OPT_NUM: |
f5101389 |
if(!arg || !isnumb(arg)) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
copt = regcfg(copt, name, NULL, atoi(arg)); |
e8217f5a |
free(arg); |
b151ef55 |
break;
case OPT_COMPSIZE:
if(!arg) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
ctype = tolower(arg[strlen(arg) - 1]);
if(ctype == 'm' || ctype == 'k') { |
36f2038b |
char *cpy = (char *) mcalloc(strlen(arg), sizeof(char)); |
7cc3891c |
strncpy(cpy, arg, strlen(arg) - 1); |
b151ef55 |
if(!isnumb(cpy)) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
if(ctype == 'm')
calc = atoi(cpy) * 1024 * 1024;
else
calc = atoi(cpy) * 1024;
free(cpy);
} else {
if(!isnumb(arg)) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
calc = atoi(arg);
}
copt = regcfg(copt, name, NULL, calc); |
e8217f5a |
free(arg); |
b151ef55 |
break;
case OPT_NOARG:
if(arg) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
copt = regcfg(copt, name, NULL, 0);
break;
case OPT_OPTARG:
copt = regcfg(copt, name, arg, 0);
break; |
e8217f5a |
default: |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype); |
e8217f5a |
free(name);
free(arg);
break; |
b151ef55 |
}
}
} else
break;
}
if(!found) { |
819c7c41 |
if(messages)
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); |
25133aef |
fclose(fs); |
b151ef55 |
return NULL;
}
}
}
fclose(fs);
return copt;
}
|
9c1c9007 |
void freecfg(struct cfgstruct *copt)
{
struct cfgstruct *handler;
struct cfgstruct *arg;
while (copt) {
arg = copt->nextarg; |
2fa47b44 |
while(arg) { |
9c1c9007 |
if(arg->strarg) {
free(arg->optname);
free(arg->strarg);
handler = arg; |
2fa47b44 |
arg = arg->nextarg; |
9c1c9007 |
free(handler); |
2fa47b44 |
} else
arg = arg->nextarg; |
9c1c9007 |
}
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) |
b151ef55 |
{
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;
} |