/***************************************************************************
*
* Copyright (c) 1999 Balázs Scheidler
* Copyright (c) 1999-2001 BalaBit IT Ltd.
*
* 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.
*
* Inspired by nsyslog, originally written by Darren Reed.
*
* $Id: cfgfile.c,v 1.40.4.4 2007/02/02 08:58:30 bazsi Exp $
*
***************************************************************************/
#include "cfgfile.h"
#include "nscache.h"
#include <string.h>
#include <assert.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#define CLASS_DEFINE
#include "cfgfile.h.x"
#undef CLASS_DEFINE
struct syslog_config *configuration;
void add_dest_group(struct log_dest_group *grp)
{
grp->next_dest_group = configuration->destinations;
configuration->destinations = grp;
}
void add_source_group(struct log_source_group *grp)
{
grp->next_source_group = configuration->sources;
configuration->sources = grp;
}
void add_filter_rule(struct log_filter *filter)
{
filter->next_filter = configuration->filters;
if (filter->next_filter)
filter->next_filter->prev_filter = filter;
filter->prev_filter = NULL;
configuration->filters = filter;
}
void add_log_connection(struct log_connection *conn)
{
conn->next = NULL;
if (configuration->last_connection) {
configuration->last_connection->next = conn;
}
else {
configuration->connections = conn;
}
configuration->last_connection = conn;
}
void cfg_set_owner(char *uid)
{
struct passwd *pwd;
pwd = getpwnam(uid);
if (pwd)
configuration->uid = pwd->pw_uid;
else
configuration->uid = atoi(uid);
}
void cfg_set_group(char *gid)
{
struct group *grp;
grp = getgrnam(gid);
if (grp)
configuration->gid = grp->gr_gid;
else
configuration->gid = atoi(gid);
}
void cfg_set_perm(int perm)
{
configuration->perm = perm;
}
void cfg_set_dir_owner(char *uid)
{
struct passwd *pwd;
pwd = getpwnam(uid);
if (pwd)
configuration->dir_uid = pwd->pw_uid;
else
configuration->dir_uid = atoi(uid);
}
void cfg_set_dir_group(char *gid)
{
struct group *grp;
grp = getgrnam(gid);
if (grp)
configuration->dir_gid = grp->gr_gid;
else
configuration->dir_gid = atoi(gid);
}
void cfg_set_dir_perm(int perm)
{
configuration->dir_perm = perm;
}
void cfg_set_bad_hostname(char *bad_hostname)
{
configuration->bad_hostname = (UINT8 *) bad_hostname;
}
struct persistent_info *
make_persistent_info(struct ol_string *name,
struct ol_object *o,
void (*kill)(struct ol_string *name, struct ol_object *obj))
{
NEW(persistent_info, self);
self->name = name;
self->o = o;
self->kill = kill;
return self;
}
struct persistent_info *
find_persistent_info(struct persistent_config *c, UINT32 length, const char *name)
{
struct persistent_info *p;
for (p = c->nodes; p; p = p->next) {
if (p->name->length == length &&
memcmp(p->name->data, name, length) == 0) {
return p;
}
}
return NULL;
}
void add_persistent_info(struct persistent_config *c,
struct persistent_info *node)
{
struct persistent_info *p;
p = find_persistent_info(c, node->name->length, (char *) node->name->data);
if (p) {
werror("You have a fatal error in your configuration, conflicting persistent names for one or more sources/destinations, name='%S'\n", node->name);
}
else {
node->next = c->nodes;
c->nodes = node;
}
}
void kill_persistent_config(struct persistent_config *persistent)
{
struct persistent_info *p;
for (p = persistent->nodes; p; p = p->next) {
if (p->kill)
(p->kill)(p->name, p->o);
}
persistent->nodes = NULL;
}
struct persistent_config *
make_persistent_config(void)
{
NEW(persistent_config, persistent);
return persistent;
}
/* cfgfile */
#define RESOLVE_VAR(s, first, next, i) \
do \
{ \
for (s = first; s; s = s->next) { \
if (i->name->length == s->name->length && \
strncmp((char *) i->name->data, (char *) s->name->data, i->name->length) == 0) { \
i->ref = (struct ol_object *) s; \
break; \
} \
} \
if (i->ref == NULL) { \
werror("unresolved reference: %S\n", i->name); \
return 0; \
} \
} while (0)
static int do_init_config(struct syslog_config *self, struct persistent_config *p)
{
struct log_source_group *s;
struct log_filter *f;
struct log_dest_group *d;
struct log_connection *c;
struct log_endpoint_info *i;
struct log_handler *center;
int res, n;
gc_idle_threshold = self->gc_idle_threshold;
gc_busy_threshold = self->gc_busy_threshold;
center = make_log_center(self->connections);
if (self->dns_cache)
self->cache = nscache_new(self->dns_cache_size,
self->dns_cache_expire,
self->dns_cache_expire_failed);
else
self->cache = NULL;
for (s = self->sources; s; s = s->next_source_group) {
res = LOG_HANDLER_INIT(s, self, p);
append_log_handler(s, center);
if (res & ST_FAIL)
return 0;
}
for (d = self->destinations; d; d = d->next_dest_group) {
res = LOG_HANDLER_INIT(d, self, p);
if (res & ST_FAIL)
return 0;
}
if (!self->internal) {
werror("Warning: No source refers to internal messages, they'll go to /dev/null\n");
}
for (c = self->connections, n = 0; c; c = c->next, n++) {
if (!c->sources && !(c->flags & LOG_CONN_CATCHALL)) {
werror("Warning: connection %i doesn't have any sources\n", n);
}
for (i = c->sources; i; i = i->next) {
RESOLVE_VAR(s, self->sources, next_source_group, i);
}
for (i = c->filters; i; i = i->next) {
RESOLVE_VAR(f, self->filters, next_filter, i);
}
for (i = c->destinations; i; i = i->next) {
RESOLVE_VAR(d, self->destinations, next_dest_group, i);
}
}
return 1;
}
static int do_destroy_config(struct syslog_config *self, struct persistent_config *persistent)
{
struct log_dest_group *d;
struct log_source_group *s;
self->living = 1;
for (s = self->sources; s; s = s->next_source_group) {
if (s->super.super.destroy)
LOG_HANDLER_DESTROY(s, self, persistent);
}
for (d = self->destinations; d; d = d->next_dest_group) {
if (d->super.destroy)
LOG_HANDLER_DESTROY(d, self, persistent);
}
KILL_RESOURCE_LIST(self->resources);
if (self->dns_cache && self->cache) {
nscache_free(self->cache);
self->cache = NULL;
}
return 0;
}
extern FILE *yyin;
extern int yyparse();
extern void lex_init(FILE *);
extern int yydebug;
extern int linenum;
struct syslog_config *make_syslog_config(const char *name, struct io_backend *backend)
{
FILE *cfg;
int res;
NEW(syslog_config, self);
configuration = self;
self->init = do_init_config;
self->destroy = do_destroy_config;
self->backend = backend;
self->living = 1;
self->sync_freq = 0;
self->mark_freq = 1200; /* 20 minutes */
self->stats_freq = 600;
self->chain_hostnames = 1;
self->use_fqdn = 0;
self->use_dns = 1;
self->time_reopen = 60;
self->time_reap = 60;
self->log_fifo_size = 1000;
self->gc_idle_threshold = 100;
self->gc_busy_threshold = 3000;
self->uid = 0;
self->gid = 0;
self->perm = 0600;
self->dir_uid = 0;
self->dir_gid = 0;
self->dir_perm = 0700;
self->dns_cache = 1;
self->dns_cache_size = 1007;
self->dns_cache_expire = 3600;
self->dns_cache_expire_failed = 60;
self->log_msg_size = 2048;
self->bad_hostname = NULL;
self->sanitize_filenames = 1;
if ((cfg = fopen(name, "r")) != NULL) {
lex_init(cfg);
res = yyparse();
fclose(cfg);
if (!res) {
/* successfully parsed */
self->resources = empty_resource_list();
return self;
}
}
else {
werror("Cannot open configuration file %z for reading\n", name);
}
KILL(self);
configuration = NULL;
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1