/*-
* Copyright (c) 1999-2004 Andrey Simonenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "config.h"
#ifndef lint
static const char rcsid[] ATTR_UNUSED =
"@(#)$Id: ipa_conf.c,v 1.3.2.8 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <ctype.h>
#include <errno.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <regex.h>
#include <stdarg.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "ipa_mod.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "parser.h"
#include "pathnames.h"
#include "ipa_ac.h"
#include "ipa_db.h"
#include "ipa_time.h"
#include "ipa_cmd.h"
#include "ipa_conf.h"
#include "ipa_ctl.h"
#include "ipa_log.h"
#include "ipa_main.h"
#include "ipa_rules.h"
#include "ipa_autorules.h"
char *ipa_conf_file = IPA_CONF_FILE; /* -f <conf-file> */
int mimic_real_config = 0; /* 1, if -tt. */
#ifdef CTL_CHECK_CREDS
static regex_t reg_acl;
static regex_t reg_ctl_acl_class;
#endif
/*
* IPA_CONF_SECT_* with 1-7 values are defined in the ipa_mod.h file.
* These are local values, modules should not use them. Even if we have
* some WITHOUT_xxx macros let's #define all SECT_xxx here, else we have
* to #ifdef too many lines in conf_sect_tbl[] and conf_param_tbl[],
* which is really not necessary.
*/
#define SECT_SUBLIMIT 8
/* Next sections can contain "exec" parameters. */
#define SECT_RESTART 9
#define SECT_REACH 10
#define SECT_EXPIRE 11
#define SECT_STARTUP 12
#define SECT_SHUTDOWN 13
#define SECT_IF_REACHED 14
#define SECT_IF_NOT_REACHED 15
#define SECT_IF_ALL_REACHED 16
#define SECT_IF_ANY_REACHED 17
#define SECT_IF_ANY_NOT_REACHED 18
#define SECT_IF_ALL_NOT_REACHED 19
#define SECT_BELOW_THRESHOLD 20
#define SECT_EQUAL_THRESHOLD 21
#define SECT_ABOVE_THRESHOLD 22
#ifdef WITH_RULES
static struct rule *currule; /* Current rule. */
#endif
static struct rulepat *currulepat; /* Current rulepat. */
static u_int rulepatno;
#ifdef WITH_AUTORULES
static struct autorule *curautorule; /* Current autorule. */
#endif
#ifdef WITH_LIMITS
static struct limit *curlimit; /* Current limit. */
static u_int limitno; /* Order number of the current limit. */
static regex_t reg_texp; /* Regular expression for +X like arguments. */
static struct limits_list *limits_list;
#endif
#ifdef WITH_SUBLIMITS
static struct sublimit *cursublimit; /* Current sublimit. */
#endif
#ifdef WITH_THRESHOLDS
static struct threshold *curthreshold; /* Current threshold. */
static u_int thresholdno; /* Order number of current threshold. */
static struct thresholds_list *thresholds_list;
static regex_t reg_thr_balance;/* Regular expression for "threshold_balance". */
#endif
static struct cmd_list *curcmdl; /* Current cmd list. */
/* Internal "null" accounting system and database. */
static struct ac_list ac_list_null = STAILQ_HEAD_INITIALIZER(ac_list_null);
static struct db_list db_list_null = STAILQ_HEAD_INITIALIZER(db_list_null);
/* Empty time interval. */
static struct tint_list tint_list_empty = STAILQ_HEAD_INITIALIZER(tint_list_empty);
static int posix_re_pattern; /* posix_re_pattern parameter. */
static int only_abs_paths; /* only_abs_paths parameter. */
struct debug_param {
const char *param_name;
int *param_value;
};
/* debug_* parameters in IPA_CONF_SECT_ROOT. */
static struct debug_param common_debug_param[] = {
#ifdef WITH_AUTORULES
{ "debug_autorule", &debug_autorule },
#endif
{ "debug_ctl", &debug_ctl, },
{ "debug_time", &debug_time },
{ "debug_worktime", &debug_worktime },
{ "debug_ac_null", &debug_ac_null },
{ "debug_db_null", &debug_db_null },
{ NULL, NULL }
};
/* debug_* parameters in IPA_CONF_SECT_GLOBAL. */
static struct debug_param global_debug_param[] = {
#ifdef WITH_LIMITS
{ "debug_limit", &global_debug_limit },
{ "debug_limit_init", &global_debug_limit_init },
#endif
#ifdef WITH_THRESHOLDS
{ "debug_threshold", &global_debug_threshold },
{ "debug_threshold_init", &global_debug_threshold_init },
#endif
{ "debug_exec", &global_debug_exec },
{ NULL, NULL }
};
struct time_param {
const char *param_name;
u_int *param_value;
};
/* *_time parameters in IPA_CONF_SECT_ROOT. */
static struct time_param common_time_param[] = {
{ "wakeup_time", &wakeup_time },
{ "freeze_time", &freeze_time },
{ "sleep_after_dump", &sleep_after_dump },
{ "sensitive_time", &sensitive_time },
{ NULL, NULL }
};
static int use_log = 1; /* 0, if -t or -x switch was used. */
static PARSING_MODE parsing_mode; /* xxx_PARSING. */
static u_int section; /* Current section ID. */
static u_int section_first; /* autorule rulepat rule */
static u_int section_top; /* autorule rulepat rule limit sublimit threshold */
static int global_section_set; /* 1, if has global{}. */
static regex_t reg_worktime;
static regex_t reg_list;
void conferrx(const char *, ...) ATTR_FORMAT(printf, 1, 2);
static void confvlogmsgx_prefix(int, const char *, const char *, va_list) ATTR_FORMAT(printf, 3, 0);
/* Macro for validating if empty TAILQ_HEAD is in consistent state. */
#define TAILQ_EMPTY_HEAD_VALID(x) \
((x)->tqh_first == NULL && (x)->tqh_last == &(x)->tqh_first)
/*
* Exported support functions for modules.
*/
static const ipa_suppfunc suppfunc = {
print_string, /* print_string */
print_bytes, /* print_bytes */
print_time, /* print_time */
print_value, /* print_value */
print_boolean, /* print_boolean */
print_space, /* print_space */
set_indent, /* set_indent */
print_param_name, /* print_param_name */
print_args, /* print_param_args */
print_param_end, /* print_param_end */
print_sect_name, /* print_sect_name */
print_args, /* print_sect_args */
print_sect_begin, /* print_sect_begin */
print_sect_end, /* print_sect_end */
open_log, /* open_log */
close_log, /* close_log */
mod_logmsg, /* logmsg */
mod_logconferr, /* logconferr */
parser_local_sym_add, /* local_sym_add */
parser_local_sym_del, /* local_sym_del */
parser_global_sym_add, /* global_sym_add */
parser_global_sym_del /* global_sym_del */
};
/*
* Log message prepending it with prefix.
* If use_log == 1 then log is used, else printf(3) is used.
* Don't use mem_* functions.
*/
static void
confvlogmsgx_prefix(int priority, const char *prefix, const char *format,
va_list ap)
{
if (use_log) {
int rv;
char *ptr;
char buf[LOG_BUF_SIZE]; /* Try to use buffer in stack. */
if ( (rv = vsnprintf(buf, sizeof buf, format, ap)) < 0) {
logmsg(IPA_LOG_ERR, "confvlogmsgx_prefix: vsnprintf failed");
goto log_unformated;
}
if (rv >= sizeof buf) {
if ( (ptr = malloc(++rv)) == NULL) {
logmsgx(IPA_LOG_ERR, "confvlogmsgx_prefix: malloc failed");
goto log_unformated;
}
if (vsnprintf(ptr, rv, format, ap) < 0) {
logmsg(IPA_LOG_ERR, "confvlogmsgx_prefix: vsnprintf failed again");
free(ptr);
goto log_unformated;
}
logmsgx(priority, "%s: %s", prefix, ptr);
free(ptr);
} else
logmsgx(priority, "%s: %s", prefix, buf);
return;
log_unformated:
logmsgx(priority, "%s: unformated message: %s",
prefix, format);
} else {
fflush(stdout);
fprintf(stderr, "%s: ", prefix);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
}
}
/*
* The wrapper for parser_vlogmsgx.
*/
static void
parser_vlogmsgx_wrapper(const char *format, va_list ap)
{
confvlogmsgx_prefix(IPA_LOG_ERR, "parsing error", format, ap);
}
/*
* The wrapper for mvlogmsgx during configuration., don't use
* mem_* functions.
*/
static void
mvlogmsgx_conf_wrapper(const char *format, va_list ap)
{
confvlogmsgx_prefix(IPA_LOG_ERR, "config error", format, ap);
}
/*
* A wrapper for logging about errors.
*/
void
conferrx(const char *format, ...)
{
va_list ap;
va_start(ap, format);
confvlogmsgx_prefix(IPA_LOG_ERR, "config error", format, ap);
va_end(ap);
}
/*
* The same as above one, but with priority argument and va_list.
*/
static void
vconferrx_priority(int priority, const char *format, va_list ap)
{
confvlogmsgx_prefix(priority, "config error", format, ap);
}
/*
* Try to find tevent with the given value of event_step,
* if such tevent does not exist, then allocate new one.
* Return NULL if new tevent can't be allocated.
*/
static struct tevent *
find_tevent(u_int event_step)
{
struct tevent *tevent;
SLIST_FOREACH(tevent, &tevents_list, link)
if (tevent->event_step == event_step)
return tevent;
if ( (tevent = mzone_alloc(tevent_mzone)) != NULL) {
tevent->event_step = event_step;
SLIST_INSERT_HEAD(&tevents_list, tevent, link);
} else
conferrx("find_tevent: mzone_alloc failed");
return tevent;
}
/*
* Register a configuration event in ac_mod module.
*/
static int
ac_mod_conf_event(const struct ac_mod *ac_mod, u_int event,
u_int no, const void *arg)
{
if (ac_mod->ipa_ac_mod->conf_event(event, no, arg) < 0) {
logconferrx("module %s: conf_event(IPA_CONF_EVENT_%s) failed",
ac_mod->mod_file, conf_event_msg[event]);
return -1;
}
return 0;
}
/*
* Register a configuration event in db_mod module.
*/
static int
db_mod_conf_event(const struct db_mod *db_mod, u_int event,
u_int no, const void *arg)
{
if (db_mod->ipa_db_mod->conf_event(event, no, arg) < 0) {
logconferrx("module %s: conf_event(IPA_CONF_EVENT_%s) failed",
db_mod->mod_file, conf_event_msg[event]);
return -1;
}
return 0;
}
/*
* Register a configuration event in each module.
*/
static int
mod_conf_event(u_int event, u_int no, const void *arg)
{
const struct ac_mod *ac_mod;
const struct db_mod *db_mod;
SLIST_FOREACH(ac_mod, &ac_mod_list, link)
if (ac_mod_conf_event(ac_mod, event, no, arg) < 0) {
logconferrx("mod_conf_event: ac_mod_conf_event failed");
return -1;
}
SLIST_FOREACH(db_mod, &db_mod_list, link)
if (db_mod_conf_event(db_mod, event, no, arg) < 0) {
logconferrx("mod_conf_event: db_mod_conf_event failed");
return -1;
}
return 0;
}
/*
* Inherit settings from rulepat from modules for rule.
*/
int
mod_conf_inherit(const struct rulepat *rulepat, const struct rule *rule)
{
const struct ac_mod *ac_mod;
const struct db_mod *db_mod;
SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
if (ac_mod->ipa_ac_mod->conf_inherit != NULL)
if (ac_mod->ipa_ac_mod->conf_inherit(rulepat->rulepatno,
rule->ruleno, rule->rule_name) < 0) {
xlogmsgx(IPA_LOG_ERR, "module %s: conf_inherit(%s, %s) failed",
ac_mod->mod_file, parser_buf_to_string(rulepat->pat),
rule->rule_name);
return -1;
}
}
SLIST_FOREACH(db_mod, &db_mod_list, link) {
if (db_mod->ipa_db_mod->conf_inherit != NULL)
if (db_mod->ipa_db_mod->conf_inherit(rulepat->rulepatno,
rule->ruleno, rule->rule_name) < 0) {
xlogmsgx(IPA_LOG_ERR, "module %s: conf_inherit(%s, %s) failed",
db_mod->mod_file, parser_buf_to_string(rulepat->pat),
rule->rule_name);
return -1;
}
}
return 0;
}
/*
* Parse the "global" section.
*/
/* ARGSUSED */
static int
parse_global(void *arg ATTR_UNUSED)
{
if (global_section_set) {
logconferrx("this section is duplicated");
return -1;
}
global_section_set = 1;
return mod_conf_event(IPA_CONF_EVENT_GLOBAL_BEGIN, 0, (void *)NULL);
}
#ifdef WITH_RULES
/*
* Parse the "rule" section.
*/
static int
parse_rule(void *arg)
{
const char *rule_name = *(char **)arg;
struct rule *rule;
if (rule_by_name(rule_name) != NULL) {
logconferrx("this section is duplicated");
return -1;
}
if ( (rule = mzone_alloc(rule_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
if ( (rule->rule_name = mem_strdup(rule_name, m_anon)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
rule->rule_info = NULL;
rule->ruleno = nstatrules++;
rule->cnt_neg = UINT64_C(0);
rule->update_tevent = rule->append_tevent = NULL;
rule->worktime = NULL;
rule->is_active = UNKNOWN_ACTIVE_FLAG;
rule->ac_list = NULL;
rule->db_list = NULL;
rule->ac_gather_add_pat = rule->ac_gather_sub_pat = NULL;
SLIST_INIT(&rule->ac_gather_rev);
rule->debug_exec = -1;
init_cmds_in_rule(rule);
#ifdef WITH_LIMITS
rule->debug_limit = rule->debug_limit_init = -1;
limits_list = &rule->limits;
STAILQ_INIT(limits_list);
limitno = 0;
#endif
#ifdef WITH_THRESHOLDS
rule->debug_threshold = rule->debug_threshold_init = -1;
thresholds_list = &rule->thresholds;
STAILQ_INIT(thresholds_list);
thresholdno = 0;
#endif
#ifdef CTL_CHECK_CREDS
rule->ctl_rule_acl = NULL;
#endif
rule->free_mask = RULE_FREE_LIMITS|RULE_FREE_THRESHOLDS;
section_first = section_top = IPA_CONF_SECT_RULE;
if (parser_local_sym_add("rule", rule->rule_name, 0) < 0)
return -1;
TAILQ_INSERT_TAIL(&rules_list, rule, list);
add_rule_to_hash(rule);
if (mod_conf_event(IPA_CONF_EVENT_RULE_BEGIN, rule->ruleno,
rule->rule_name) < 0)
return -1;
currule = rule;
return 0;
}
#endif /* WITH_RULES */
/*
* Parse the "rulepat" section.
*/
static int
parse_rulepat(void *arg)
{
char *pat = *(char **)arg;
struct rulepat *rulepat;
STAILQ_FOREACH(rulepat, &rulepats_list, link)
if (strcmp(rulepat->pat, pat) == 0) {
logconferrx("this section is duplicated");
return -1;
}
if ( (rulepat = mzone_alloc(rulepat_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(&rulepats_list, rulepat, link);
if ( (re_errcode = regcomp(&rulepat->reg, pat, REG_EXTENDED|REG_NOSUB)) != 0) {
re_form_errbuf();
logconferrx("regcomp(\"%s\"): %s", pat, re_errbuf);
return -1;
}
rulepat->pat = pat;
rulepat->rulepatno = rulepatno++;
rulepat->check_next_rulepat = -1;
rulepat->update_tevent = rulepat->append_tevent = NULL;
rulepat->worktime = NULL;
rulepat->ac_list = NULL;
rulepat->db_list = NULL;
rulepat->debug_exec = -1;
init_cmds_in_rulepat(rulepat);
#ifdef WITH_LIMITS
rulepat->debug_limit = rulepat->debug_limit_init = -1;
limits_list = &rulepat->limits;
STAILQ_INIT(limits_list);
limitno = 0;
#endif
#ifdef WITH_THRESHOLDS
rulepat->debug_threshold = rulepat->debug_threshold_init = -1;
thresholds_list = &rulepat->thresholds;
STAILQ_INIT(thresholds_list);
thresholdno = 0;
#endif
#ifdef CTL_CHECK_CREDS
rulepat->ctl_rule_acl = NULL;
#endif
section_first = section_top = IPA_CONF_SECT_RULEPAT;
if (mod_conf_event(IPA_CONF_EVENT_RULEPAT_BEGIN,
rulepat->rulepatno, rulepat->pat) < 0)
return -1;
currulepat = rulepat;
return 0;
}
/*
* Parse the "check_next_rulepat" parameter.
*/
static int
parse_check_next_rulepat(void *arg)
{
currulepat->check_next_rulepat = *(int *)arg;
return 0;
}
/*
* Parse an argument of some "debug_*" parameter.
*/
static int
check_debug_level(uint32_t level, u_int maxlevel)
{
if (level > maxlevel) {
logconferrx("too big debug level, max level is %u", maxlevel);
return -1;
}
return (int)level;
}
/*
* Parse the "debug_time" parameter.
*/
static int
parse_debug_time(void *arg)
{
return debug_time = check_debug_level(*(uint32_t *)arg, 2);
}
/*
* Parse the "debug_ac_null" parameter.
*/
static int
parse_debug_ac_null(void *arg)
{
return debug_ac_null = check_debug_level(*(uint32_t *)arg, 1);
}
/*
* Parse the "debug_db_null" parameter.
*/
static int
parse_debug_db_null(void *arg)
{
return debug_db_null = check_debug_level(*(uint32_t *)arg, 1);
}
/*
* Parse the "debug_worktime" parameter.
*/
static int
parse_debug_worktime(void *arg)
{
return debug_worktime = check_debug_level(*(uint32_t *)arg, 1);
}
/*
* Parse the "debug_exec" parameter.
*/
static int
parse_debug_exec(void *arg)
{
int level;
if ( (level = check_debug_level(*(uint32_t *)arg, 2)) < 0)
return -1;
switch (section) {
case IPA_CONF_SECT_GLOBAL:
global_debug_exec = level;
break;
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->debug_exec = level;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->debug_exec = level;
break;
#endif
default: /* IPA_CONF_SECT_RULEPAT */
currulepat->debug_exec = level;
}
return 0;
}
/*
* Parse the "update_time" parameter.
*/
static int
parse_update_time(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
struct tevent *tevent;
if (timeval == UINT64_C(0) || timeval > SECONDS_IN_DAY) {
logconferrx("argument should be greater than zero seconds and less than or equal to 1 day");
return -1;
}
if ( (tevent = find_tevent((u_int)timeval)) == NULL) {
logconferrx("find_tevent failed");
return -1;
}
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->update_tevent = tevent;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->update_tevent = tevent;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
currulepat->update_tevent = tevent;
break;
default: /* IPA_CONF_SECT_GLOBAL */
global_update_tevent = tevent;
}
return 0;
}
/*
* Parse the "freeze_time" parameter.
*/
static int
parse_freeze_time(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0) || timeval >= 5 * SECONDS_IN_MINUTE) {
logconferrx("argument should be greater than zero seconds and less than 5 minutes");
return -1;
}
freeze_time = (u_int)timeval;
return 0;
}
/*
* Parse the "append_time" parameter.
*/
static int
parse_append_time(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
struct tevent *tevent;
if (timeval == UINT64_C(0) || timeval > SECONDS_IN_DAY) {
logconferrx("argument should be greater than zero seconds and less than or equal to 1 day");
return -1;
}
if ( (tevent = find_tevent((u_int)timeval)) == NULL) {
logconferrx("find_tevent failed");
return -1;
}
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->append_tevent = tevent;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->append_tevent = tevent;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
currulepat->append_tevent = tevent;
break;
default: /* IPA_CONF_SECT_GLOBAL */
global_append_tevent = tevent;
}
return 0;
}
/*
* Parse the "wakeup_time" parameter.
*/
static int
parse_wakeup_time(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0) || timeval > SECONDS_IN_DAY) {
logconferrx("argument should be greater than zero seconds and less than or equal to 1 day");
return -1;
}
wakeup_time = (u_int)timeval;
return 0;
}
#if defined(WITH_THRESHOLDS) || defined(WITH_SUBLIMITS)
/*
* get_arg_value() + get_arg_per_cent().
*/
static int
get_value_or_per_cent(uint64_t *val_p, u_int *cnt_type_p)
{
u_int cnt_type;
uint64_t val;
if (regexec(®_bytes, parser_args, 0, (regmatch_t *)NULL, 0) == 0) {
if (get_arg_bytes(&val) < 0)
return -1;
cnt_type = IPA_CONF_TYPE_BYTES;
} else if (regexec(®_time, parser_args, 0, (regmatch_t *)NULL, 0) == 0) {
if (get_arg_time(&val) < 0)
return -1;
cnt_type = IPA_CONF_TYPE_TIME;
} else {
char *ptr;
ptr = parser_args + parser_args_len - 1;
if (*ptr == '%') {
*ptr = '\0';
cnt_type = IPA_CONF_TYPE_PER_CENT;
} else
cnt_type = IPA_CONF_TYPE_UINT64;
if (get_arg_uint64(&val) < 0)
return -1;
if (cnt_type == IPA_CONF_TYPE_PER_CENT && val > 100) {
logconferrx("per cent value should <= 100%%");
return -1;
}
}
*val_p = val;
*cnt_type_p = cnt_type;
return 0;
}
#endif /* WITH_THRESHOLDS || WITH_SUBLIMITS */
#ifdef WITH_LIMITS
/*
* Parse the "debug_limit" parameter.
*/
static int
parse_debug_limit(void *arg)
{
int level;
if ( (level = check_debug_level(*(uint32_t *)arg, 1)) < 0)
return -1;
switch (section) {
case IPA_CONF_SECT_GLOBAL:
global_debug_limit = level;
break;
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->debug_limit = level;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->debug_limit = level;
break;
#endif
default: /* IPA_CONF_SECT_RULEPAT */
currulepat->debug_limit = level;
}
return 0;
}
/*
* Parse the "debug_limit_init" parameter.
*/
static int
parse_debug_limit_init(void *arg)
{
int level;
if ( (level = check_debug_level(*(uint32_t *)arg, 1)) < 0)
return -1;
switch (section) {
case IPA_CONF_SECT_GLOBAL:
global_debug_limit_init = level;
break;
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->debug_limit_init = level;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->debug_limit_init = level;
break;
#endif
default: /* IPA_CONF_SECT_RULEPAT */
currulepat->debug_limit_init = level;
}
return 0;
}
/*
* Parse the "load_limit" parameter.
*/
static int
parse_load_limit(void *arg)
{
if (section == IPA_CONF_SECT_LIMIT)
curlimit->load_limit = *(int *)arg;
else /* IPA_CONF_SECT_GLOBAL */
global_load_limit = *(int *)arg;
return 0;
}
/*
* Parse the "limit" section.
*/
static int
parse_limit_sect(void *arg)
{
const char *limit_name = *(char **)arg;
struct limit *limit;
STAILQ_FOREACH(limit, limits_list, link)
if (strcmp(limit->limit_name, limit_name) == 0) {
logconferrx("this section is duplicated");
return -1;
}
if ( (limit = mzone_alloc(limit_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(limits_list, limit, link);
if ( (limit->limit_name = mem_strdup(limit_name, m_anon)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
limit->limit_info = NULL;
limit->limitno = limitno++;
limit->lim = limit->cnt_neg = UINT64_C(0);
limit->load_limit = -1;
limit->restart.restart.upto = limit->expire.expire.upto = TEXP_UPTO_NOTSET;
init_cmds_in_limit(limit);
limit->worktime = NULL;
limit->is_active = ACTIVE_FLAG;
limit->db_list = NULL;
#ifdef WITH_SUBLIMITS
STAILQ_INIT(&limit->sublimits);
#endif
limit->wpid.type = WPID_TYPE_LIMIT;
limit->wpid.pid = 0;
limit->wpid.u.limit = limit;
#ifdef WITH_RULES
limit->rule = currule;
#endif
if (section_top == IPA_CONF_SECT_RULE)
++nstatlimits;
section_top = IPA_CONF_SECT_LIMIT;
if (parser_local_sym_add("limit", limit->limit_name, 0) < 0)
return -1;
if (mod_conf_event(IPA_CONF_EVENT_LIMIT_BEGIN, limit->limitno,
limit->limit_name) < 0)
return -1;
curlimit = limit;
return 0;
}
/*
* Parse the "limit" parameter.
*/
static int
parse_limit_param(void *arg)
{
uint64_t *ptr = (uint64_t *)arg;
struct limit *limit;
limit = curlimit;
if (limit->lim != UINT64_C(0)) {
logconferrx("cannot redefine this parameter");
return -1;
}
if ( (limit->lim = *(ptr + 1)) == UINT64_C(0)) {
logconferrx("argument should be greater than zero");
return -1;
}
limit->cnt_type = (u_int)*ptr;
return 0;
}
#ifdef WITH_SUBLIMITS
/*
* Parse the "sublimit" section.
*/
static int
parse_sublimit(void *arg)
{
char *sublimit_name;
u_int cnt_type;
uint64_t lim;
struct sublimit *sublimit;
if (curlimit->lim == UINT64_C(0)) {
logconferrx("\"limit\" parameter in previous section should be specified before");
return -1;
}
if ( (sublimit_name = mem_strdup(*(char **)arg, m_anon)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
if (get_value_or_per_cent(&lim, &cnt_type) < 0)
return -1;
if (lim == UINT64_C(0)) {
logconferrx("argument should be greater than zero");
return -1;
}
if (cnt_type != IPA_CONF_TYPE_PER_CENT && cnt_type != curlimit->cnt_type) {
logconferrx("different arguments types for sublimit and limit");
return -1;
}
STAILQ_FOREACH(sublimit, &curlimit->sublimits, link)
if (cnt_type == IPA_CONF_TYPE_PER_CENT) {
if ((u_int)lim == sublimit->lim_per_cent) {
logconferrx("this section is duplicated");
return -1;
}
} else {
if (lim == sublimit->lim) {
logconferrx("this section is duplicated");
return -1;
}
}
if ( (sublimit = mzone_alloc(sublimit_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(&curlimit->sublimits, sublimit, link);
sublimit->sublimit_name = sublimit_name;
if (cnt_type == IPA_CONF_TYPE_PER_CENT)
sublimit->lim_per_cent = (u_int)lim;
else {
sublimit->lim = lim;
sublimit->lim_per_cent = 0;
}
sublimit->cnt_type = cnt_type;
init_cmds_in_sublimit(sublimit);
sublimit->wpid.type = WPID_TYPE_SUBLIMIT;
sublimit->wpid.pid = 0;
sublimit->wpid.u.sublimit = sublimit;
sublimit->limit = curlimit;
if (section_top == IPA_CONF_SECT_RULE)
++nstatsublimits;
section_top = SECT_SUBLIMIT;
if (parser_local_sym_add("sublimit", sublimit->sublimit_name, 0) < 0)
return -1;
cursublimit = sublimit;
return 0;
}
#endif /* WITH_SUBLIMITS */
/*
* Parse "expired time" value.
*/
static int
parse_texp(struct texp *texp, const void *arg)
{
const char *ptr = (const char *)arg;
char *endptr;
int level = 0, error = 0, overflow = 0;
uint32_t value;
texp->seconds = 0;
texp->upto = TEXP_UPTO_SIMPLE;
for (;;) {
if (*ptr == ' ')
++ptr;
if (*ptr == '+') {
texp->upto = *++ptr;
texp->side = texp->seconds > 0;
if (*++ptr == '\0')
break; /* EOL */
continue;
}
if (strto_uint32(&value, ptr, &endptr) < 0)
return -1;
ptr = endptr;
switch (*ptr) {
case 'W':
if (level > 1)
error = 1;
else {
if (value > UINT32_MAX / SECONDS_IN_WEEK)
overflow = 1;
else {
level = 2;
value *= SECONDS_IN_WEEK;
}
}
break;
case 'D':
if (level > 2)
error = 1;
else {
if (value > UINT32_MAX / SECONDS_IN_DAY)
overflow = 1;
else {
level = 3;
value *= SECONDS_IN_DAY;
}
}
break;
case 'h':
if (level > 3)
error = 1;
else {
if (value > UINT32_MAX / SECONDS_IN_HOUR)
overflow = 1;
else {
level = 4;
value *= SECONDS_IN_HOUR;
}
}
break;
case 'm':
if (level > 4)
error = 1;
else {
if (value > UINT32_MAX / SECONDS_IN_MINUTE)
overflow = 1;
else {
level = 5;
value *= SECONDS_IN_MINUTE;
}
}
break;
default: /* 's' */
if (level > 5)
error = 1;
else
level = 6;
}
if (error) {
logconferrx("wrong format of an argument");
return -1;
}
if (overflow || texp->seconds > UINT_MAX - value) {
logconferrx("too big value for u_int");
return -1;
}
texp->seconds += (u_int)value;
if (*++ptr == '\0')
break; /* EOL */
}
return 0;
}
/*
* Parse the "restart" parameter.
*/
static int
parse_restart(void *arg)
{
struct texp *texp = &curlimit->restart.restart;
if (parse_texp(texp, *(char **)arg) < 0)
return -1;
if (texp->seconds == 0 && texp->upto == TEXP_UPTO_SIMPLE) {
logconferrx("argument should be greater than zero");
return -1;
}
return 0;
}
/*
* Parse the "expire" parameter.
*/
static int
parse_expire(void *arg)
{
return parse_texp(&curlimit->expire.expire, *(char **)arg);
}
/*
* Inherit settings for a limit from the "global" section.
*/
static void
inherit_limit_from_global(struct limit *limit)
{
if (limit->load_limit < 0)
limit->load_limit = global_load_limit;
}
#endif /* WITH_LIMITS */
/*
* Parse the "exec" parameter.
*/
static int
parse_exec(void *arg)
{
char *start, *ptr, *str = *(char **)arg;
int allow_subst;
struct cmd *cmd;
switch (parser_nargs) {
case 1:
case 2:
break;
default:
logconferrx("one or two arguments are expected");
return -1;
}
/* Allocate new structure for command. */
if ( (cmd = mzone_alloc(cmd_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(&curcmdl->list, cmd, link);
/* user "..." or "..." */
if (parser_nargs == 2) {
if (*str == '\"') {
logconferrx("wrong format of an argument");
return -1;
}
ptr = str;
str = strchr(str, ' ');
*str++ = '\0';
if ( (cmd->user = mem_strdup(ptr, m_cmd)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
cmd->free_mask = CMD_FREE_STR|CMD_FREE_USER;
} else {
cmd->user = NULL;
cmd->free_mask = CMD_FREE_STR;
}
/* Check for "..." */
if (!parser_buf_is_string(str)) {
logconferrx("wrong format of an argument");
return -1;
}
/* Copy "..." */
if ( (cmd->str = parser_string_strdup(str, m_cmd)) == NULL)
return -1;
/* Validate "..." */
str = cmd->str;
if (*str == '\0') {
logconferrx("command should be a non-empty string");
return -1;
}
if (*str != '/' && only_abs_paths != 0) {
logconferrx("command should be given with absolute path");
return -1;
}
switch (section_first) {
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
#endif
case IPA_CONF_SECT_RULEPAT:
allow_subst = 1;
break;
default:
allow_subst = 0;
}
cmd->subst_per_cent = cmd->subst_rule = 0;
/* Check if a string has correct substitutions and count them. */
for (ptr = str, start = NULL, cmd->str_size = 1; *ptr != '\0'; cmd->str_size++, ++ptr)
if (allow_subst && *ptr == '%') {
if (start == NULL)
start = ptr + 1;
else {
if (ptr != start) {
/* %xxx% */
*ptr = '\0';
if (strcmp(start, "rule") != 0) {
*ptr = '%';
logconferrx("unknown substitute \"%s\" in command", start);
return -1;
}
*ptr = '%';
cmd->subst_rule++;
} else {
/* %% */
cmd->subst_per_cent++;
}
start = NULL;
}
}
if (start != NULL) {
logconferrx("unclosed substitute in command");
return -1;
}
return 0;
}
/*
* Parse the "sync_exec" parameter.
*/
static int
parse_sync_exec(void *arg)
{
curcmdl->sync_exec = *(int *)arg;
return 0;
}
#if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
/*
* Parse the "info" parameter.
*/
static int
parse_info(void *arg)
{
char *ptr, **pptr;
for (ptr = *(char **)arg; *ptr != '\0'; ++ptr)
switch (*ptr) {
case '\t':
case '\n':
logconferrx("'\\t' and '\\n' characters are not allowed here");
return -1;
}
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
pptr = &currule->rule_info;
break;
#endif
#ifdef WITH_LIMITS
case IPA_CONF_SECT_LIMIT:
pptr = &curlimit->limit_info;
break;
#endif
#ifdef WITH_THRESHOLDS
default: /* IPA_CONF_SECT_THRESHOLD */
pptr = &curthreshold->threshold_info;
break;
#endif
}
if (*pptr != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
*pptr = *(char **)arg;
return 0;
}
#endif /* WITH_RULES || WITH_ANY_LIMITS */
static const struct worktime *
parse_generic_worktime(void *arg)
{
char *ptr = *(char **)arg;
u_int wday, h1, m1, h2, m2, h2_prev, m2_prev;
struct worktime *wt;
struct tint *tint1, *tint2;
struct tint_set *set1, *set2;
struct tint_list *list;
if ( (wt = mzone_alloc(worktime_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return NULL;
}
for (wday = 0; wday < DAYS_IN_WEEK; ++wday)
wt->tint_list[wday] = &tint_list_empty;
for (; *ptr != '\0';) {
switch (*ptr) {
case 'S':
wday = 0;
break;
case 'M':
wday = 1;
break;
case 'T':
wday = 2;
break;
case 'W':
wday = 3;
break;
case 'H':
wday = 4;
break;
case 'F':
wday = 5;
break;
default: /* 'A' */
wday = 6;
}
if (wt->tint_list[wday] != &tint_list_empty) {
logconferrx("each day (currently %s) should be specified only one time",
wdays[wday]);
return NULL;
}
if ( (set1 = mem_malloc(sizeof *set1, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return NULL;
}
list = &set1->list;
STAILQ_INIT(list);
h2_prev = m2_prev = 0;
ptr += 2; /* Skip day name and one white space. */
for (;;) {
if (*ptr == '*') {
h1 = m1 = m2 = 0;
h2 = HOURS_IN_DAY;
} else {
if (isdigit(*ptr) == 0)
/* Next day in worktime. */
break;
errno = 0;
if (sscanf(ptr, "%u:%u-%u:%u", &h1, &m1, &h2, &m2) != 4) {
logconferr("sscanf(%s) failed", ptr);
return NULL;
}
if ((h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59) && !(h2 == HOURS_IN_DAY && m2 == 0)) {
logconferrx("wrong value of hours or minutes in time interval for %s",
wdays[wday]);
return NULL;
}
if (h1 == h2 && m1 == m2) {
logconferrx("zero seconds time time intervals are not allowed");
return NULL;
}
if ((h1 * MINUTES_IN_HOUR + m1) > (h2 * MINUTES_IN_HOUR + m2)) {
logconferrx("wrong time interval for %s: %02u:%02u-%02u:%02u",
wdays[wday], h1, m1, h2, m2);
return NULL;
}
if (h2_prev * MINUTES_IN_HOUR + m2_prev > h1 * MINUTES_IN_HOUR + m1) {
logconferrx("nonsuccessive time interval for %s", wdays[wday]);
return NULL;
}
}
if ( (tint1 = mzone_alloc(tint_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return NULL;
}
tint1->sec1 = h1 * SECONDS_IN_HOUR + m1 * SECONDS_IN_MINUTE;
tint1->sec2 = h2 * SECONDS_IN_HOUR + m2 * SECONDS_IN_MINUTE;
STAILQ_INSERT_TAIL(&set1->list, tint1, link);
for (; *ptr != ' '; ++ptr)
if (*ptr == '\0')
goto done;
++ptr;
h2_prev = h2;
m2_prev = m2;
}
done:
/*
* If there is already the same tint_list,
* then free memory used by just allocated one.
*/
STAILQ_FOREACH(set2, &tint_sets, link) {
tint1 = STAILQ_FIRST(&set1->list);
tint2 = STAILQ_FIRST(&set2->list);
while (tint1 != NULL && tint2 != NULL) {
if (tint1->sec1 != tint2->sec1 ||
tint1->sec2 != tint2->sec2)
break;
tint1 = STAILQ_NEXT(tint1, link);
tint2 = STAILQ_NEXT(tint2, link);
}
if (tint1 == NULL && tint2 == NULL) {
/* Duplicate tint_list was found. */
free_tint_set(set1);
set1 = set2;
break;
}
}
if (set2 == NULL)
/* New tint_list --> add it to tint_sets. */
STAILQ_INSERT_TAIL(&tint_sets, set1, link);
wt->tint_list[wday] = &set1->list;
}
return find_worktime(wt);
}
/*
* Parse the "worktime" parameter.
*/
static int
parse_worktime(void *arg)
{
const struct worktime **wtpp;
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
wtpp = &currule->worktime;
break;
#endif
#ifdef WITH_LIMITS
case IPA_CONF_SECT_LIMIT:
wtpp = &curlimit->worktime;
break;
#endif
#ifdef WITH_THRESHOLDS
case IPA_CONF_SECT_THRESHOLD:
wtpp = &curthreshold->worktime;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
wtpp = &curautorule->worktime;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
wtpp = &currulepat->worktime;
break;
default: /* IPA_CONF_SECT_GLOBAL */
wtpp = &global_worktime;
}
if (*wtpp != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
return ( (*wtpp = parse_generic_worktime(arg)) == NULL) ? -1 : 0;
}
#ifdef WITH_AUTORULES
/*
* Parse the "worktime_rule" parameter.
*/
static int
parse_worktime_rule(void *arg)
{
if (curautorule->worktime_rule != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
return ( (curautorule->worktime_rule = parse_generic_worktime(arg)) == NULL) ?
-1 : 0;
}
#endif
/*
* Check security of configuration file: absolute path, regular file,
* is owned by the user, who run ipa, writable only for the user.
*/
static int
check_conf_file(const char *fname, int ignore_non_regular)
{
struct stat statbuf;
if (lstat(fname, &statbuf) < 0) {
conferrx("lstat(%s): %s", fname, strerror(errno));
return -1;
}
if (!S_ISREG(statbuf.st_mode)) {
if (ignore_non_regular)
return 0;
conferrx("configuration file \"%s\" should be a regular file",
fname);
return -1;
}
if (statbuf.st_uid != myuid) {
conferrx("configuration file \"%s\" should be owned by the user, who run this program",
fname);
return -1;
}
if (statbuf.st_mode & (S_IWGRP|S_IWOTH)) {
conferrx("configuration file \"%s\" should not have write permissions for group or other users",
fname);
return -1;
}
return 1;
}
/*
* Check file path: non empty string and should start with '/'.
*/
static int
check_file_path(const char *fname, const char *what)
{
if (*fname == '\0') {
logconferrx("argument should be a non-empty string");
return -1;
}
if (*fname != '/') {
logconferrx("%s should be given with absolute path", what);
return -1;
}
return 0;
}
/*
* Parse the "include" parameter.
*/
static int
parse_include(void *arg)
{
char *fname = *(char **)arg;
struct parser_pbuf *pbuf;
/* Save offset of current configuration file and close it. */
if ( (parser_curpbuf->foff = ftell(parser_curpbuf->fp)) < 0) {
logconferr("ftell(%s)", parser_curpbuf->fname);
return -1;
}
if (fclose(parser_curpbuf->fp) != 0) {
logconferr("fclose(%s)", parser_curpbuf->fname);
return -1;
}
/* Validate an argument. */
if (check_file_path(fname, "file") < 0)
return -1;
/* Check security of configuration file. */
if (check_conf_file(fname, 0) < 0)
return -1;
/* Open included configuration file and put it to stack. */
if ( (pbuf = parser_new_pbuf(0)) == NULL)
return -1;
if ( (pbuf->fp = fopen(fname, "r")) == NULL) {
logconferr("fopen(%s, \"r\")", fname);
return -1;
}
pbuf->fname = fname;
pbuf->foff = 0;
return parser_push_pbuf(pbuf);
}
/*
* Parse the "include_files" parameter.
*/
static int
parse_include_files(void *arg)
{
char *dir = *(char **)arg, *pat, *fname;
int include_something;
DIR *dirp;
regex_t re;
struct stat statbuf;
struct dirent *dp;
struct parser_pbuf *pbuf, *old_curpbuf;
/* Validate an argument. */
if (check_file_path(dir, "directory") < 0)
return -1;
pat = strrchr(dir, '/');
*pat++ = '\0';
if (posix_re_pattern > 0)
if ( (re_errcode = regcomp(&re, pat, REG_EXTENDED|REG_NOSUB)) != 0) {
regerror(re_errcode, (regex_t *)NULL, re_errbuf, sizeof re_errbuf);
logconferrx("cannot compile regular expression: regcomp(\"%s\"): %s",
pat, re_errbuf);
return -1;
}
/* Check security of the given directory. */
if (lstat(dir, &statbuf) < 0) {
logconferr("lstat(%s)", dir);
return -1;
}
if (!S_ISDIR(statbuf.st_mode)) {
logconferrx("given pathname is not a directory");
return -1;
}
if (statbuf.st_uid != myuid) {
logconferrx("directory should be owned by the user, who run this program");
return -1;
}
if (statbuf.st_mode & (S_IWGRP|S_IWOTH)) {
logconferrx("directory should not have write permissions for group and other users");
return -1;
}
if ( (dirp = opendir(dir)) == NULL) {
logconferr("opendir(%s)", dir);
return -1;
}
include_something = 0;
old_curpbuf = parser_curpbuf;
for (;;) {
errno = 0;
if ( (dp = readdir(dirp)) == NULL) {
if (errno != 0) {
logconferr("readdir(%s)", dir);
return -1;
}
break;
}
if (*dp->d_name == '.')
/* Optimize and don't use strcmp(3) here for "." and "..". */
switch (*(dp->d_name + 1)) {
case '\0':
continue;
case '.':
if (*(dp->d_name + 2) == '\0')
continue;
}
if (posix_re_pattern != 1) {
if (fnmatch(pat, dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
continue;
} else {
if (regexec(&re, dp->d_name, 0, (regmatch_t *)NULL, 0) != 0)
continue;
}
if (mem_asprintf(m_parser, &fname, "%s/%s", dir, dp->d_name) < 0) {
logconferrx("mem_asprintf failed");
return -1;
}
switch (check_conf_file(fname, 1)) {
case -1:
return -1;
case 0:
mem_free(fname, m_parser);
continue;
}
if ( (pbuf = parser_new_pbuf(0)) == NULL)
return -1;
pbuf->fname = fname;
pbuf->foff = 0;
if (parser_push_pbuf(pbuf) < 0)
return -1;
include_something = 1;
}
if (posix_re_pattern > 0)
regfree(&re);
if (closedir(dirp) < 0) {
logconferr("closedir(%s)", dir);
return -1;
}
mem_free(dir, m_parser);
if (include_something) {
if ( (old_curpbuf->foff = ftell(old_curpbuf->fp)) < 0) {
logconferr("ftell(%s)", old_curpbuf->fname);
return -1;
}
if (fclose(old_curpbuf->fp) != 0) {
logconferr("fclose(%s)", old_curpbuf->fname);
return -1;
}
if ( (parser_curpbuf->fp = fopen(parser_curpbuf->fname, "r")) == NULL) {
logconferr("fopen(%s, \"r\")", parser_curpbuf->fname);
return -1;
}
}
return 0;
}
/*
* Parse the "keep_rules_order" parameter.
*/
static int
parse_keep_rules_order(void *arg)
{
keep_rules_order = *(int *)arg;
return 0;
}
/*
* Parse the "only_abs_paths" parameter.
*/
static int
parse_only_abs_paths(void *arg)
{
only_abs_paths = *(int *)arg;
return 0;
}
/*
* Get module's name from the file name "[/path/]foobar[-x.y.z][.so]".
* Return "foobar" part from the given path name.
*/
static char *
get_mod_name(char *file_name)
{
char *ptr, *ptr2, *name;
if ( (ptr = strrchr(file_name, '/')) != NULL)
++ptr; /* foobar[-x.y.z].[so] */
else
ptr = file_name;
if ( (name = mem_strdup(ptr, m_anon)) == NULL) {
logconferrx("get_mod_name: mem_strdup failed");
return NULL;
}
if ( (ptr2 = strchr(name, '.')) != NULL)
*ptr2 = '\0'; /* foobar[-x] */
if ( (ptr = strrchr(name, '-')) != NULL) {
for (ptr2 = ptr; *ptr2 != '\0'; ++ptr2)
if (isdigit(*ptr2) == 0)
break;
if (*ptr2 == '\0')
*ptr = '\0'; /* foobar */
}
return name;
}
/*
* Parse the "ac_mod" parameter.
*/
static int
parse_ac_mod(void *arg)
{
char *mod_name, *sym;
struct ac_mod *ac_mod, *ac_mod2;
struct ipa_ac_mod *ipa_ac_mod;
const struct db_mod *db_mod;
if ( (ac_mod = mem_malloc(sizeof *ac_mod, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
ac_mod->mod_file = *(char **)arg;
ac_mod->mod_ref_count = 0;
if ( (ac_mod->mod_handle = dl_open(ac_mod->mod_file)) == NULL) {
logconferrx("dl_open(%s): %s", ac_mod->mod_file, dl_error());
return -1;
}
if ( (mod_name = get_mod_name(ac_mod->mod_file)) == NULL)
return -1;
if (mem_asprintf(m_anon, &sym, "%s_ac_mod", mod_name) < 0) {
logconferrx("mem_asprintf failed");
return -1;
}
if ( (ac_mod->ipa_ac_mod = (struct ipa_ac_mod *)dl_lookup_sym(ac_mod->mod_handle, sym)) == NULL) {
logconferrx("given module is not an IPA accounting module or unknown symbol naming scheme is used");
return -1;
}
mem_free(sym, m_anon);
mem_free(mod_name, m_anon);
ipa_ac_mod = ac_mod->ipa_ac_mod;
/* Check ipa_ac_mod API version. */
if (ipa_ac_mod->api_ver != IPA_AC_MOD_API_VERSION) {
logconferrx("module %s uses ipa_ac_mod API version %u, my ipa_ac_mod API version is %u",
ac_mod->mod_file, ipa_ac_mod->api_ver, IPA_AC_MOD_API_VERSION);
return -1;
}
/* Check if module is thread-safe or vice versa. */
#ifdef WITH_PTHREAD
if (!(ipa_ac_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE)) {
logconferrx("module %s must be thread-safe", ac_mod->mod_file);
return -1;
}
#else
if (ipa_ac_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE) {
logconferrx("module %s must not be thread-safe", ac_mod->mod_file);
return -1;
}
#endif /* WITH_PTHREAD */
if (strcmp(ipa_ac_mod->ac_name, "null") == 0) {
logconferrx("module's accounting system name is \"null\", this is a name of the builtin accounting system");
return -1;
}
if ( (ac_mod2 = ac_mod_by_name(ipa_ac_mod->ac_name)) != NULL) {
conferrx("duplicated accounting system name \"%s\" in %s and %s modules",
ipa_ac_mod->ac_name, ac_mod->mod_file, ac_mod2->mod_file);
return -1;
}
if ( (ac_mod2 = ac_mod_by_prefix(ipa_ac_mod->conf_prefix)) != NULL) {
conferrx("duplicated configuration prefix \"%s\" in %s and %s modules",
ipa_ac_mod->conf_prefix, ac_mod->mod_file, ac_mod2->mod_file);
return -1;
}
if ( (db_mod = db_mod_by_prefix(ipa_ac_mod->conf_prefix)) != NULL) {
conferrx("duplicated configuration prefix \"%s\" in %s and %s modules",
ipa_ac_mod->conf_prefix, ac_mod->mod_file, db_mod->mod_file);
return -1;
}
ipa_ac_mod->suppfunc = &suppfunc;
ipa_ac_mod->memfunc = &memfunc;
ipa_ac_mod->ac_create_rule = create_rule;
ipa_ac_mod->ac_delete_rule = delete_rule;
if (init_conf_tbls(ac_mod->mod_file, 1,
ipa_ac_mod->conf_sect_tbl, &ac_mod->conf_sect_hash,
ipa_ac_mod->conf_param_tbl, &ac_mod->conf_param_hash) < 0)
return -1;
if (ipa_ac_mod->conf_init() < 0) {
conferrx("module %s: conf_init failed", ac_mod->mod_file);
return -1;
}
SLIST_INSERT_HEAD(&ac_mod_list, ac_mod, link);
++nac_mods;
return 0;
}
/*
* Parse the "db_mod" parameter.
*/
static int
parse_db_mod(void *arg)
{
char *mod_name, *sym;
struct db_mod *db_mod, *db_mod2;
struct ipa_db_mod *ipa_db_mod;
const struct ac_mod *ac_mod;
if ( (db_mod = mem_malloc(sizeof *db_mod, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
db_mod->mod_file = *(char **)arg;
if ( (db_mod->mod_handle = dl_open(db_mod->mod_file)) == NULL) {
logconferrx("dl_open(%s): %s", db_mod->mod_file, dl_error());
return -1;
}
if ( (mod_name = get_mod_name(db_mod->mod_file)) == NULL)
return -1;
if (mem_asprintf(m_anon, &sym, "%s_db_mod", mod_name) < 0) {
logconferrx("mem_asprintf failed");
return -1;
}
if ( (db_mod->ipa_db_mod = (struct ipa_db_mod *)dl_lookup_sym(db_mod->mod_handle, sym)) == NULL) {
logconferrx("given module is not an IPA database module or unknown symbol naming scheme is used");
return -1;
}
mem_free(sym, m_anon);
mem_free(mod_name, m_anon);
ipa_db_mod = db_mod->ipa_db_mod;
/* Check ipa_db_mod API version. */
if (ipa_db_mod->api_ver != IPA_DB_MOD_API_VERSION) {
logconferrx("module %s uses ipa_db_mod API version %u, my ipa_db_mod API version is %u",
db_mod->mod_file, ipa_db_mod->api_ver, IPA_DB_MOD_API_VERSION);
return -1;
}
/* Check if module is thread-safe or vice versa. */
#ifdef WITH_PTHREAD
if (!(ipa_db_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE)) {
logconferrx("module %s must be thread-safe", db_mod->mod_file);
return -1;
}
#else
if (ipa_db_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE) {
logconferrx("module %s must not be thread-safe", db_mod->mod_file);
return -1;
}
#endif /* WITH_PTHREAD */
if (strcmp(ipa_db_mod->db_name, "null") == 0) {
logconferrx("module's database name is \"null\", this is a name of the builtin database");
return -1;
}
if ( (db_mod2 = db_mod_by_name(ipa_db_mod->db_name)) != NULL) {
conferrx("duplicated database name \"%s\" in %s and %s modules",
ipa_db_mod->db_name, db_mod->mod_file, db_mod2->mod_file);
return -1;
}
if ( (db_mod2 = db_mod_by_prefix(ipa_db_mod->conf_prefix)) != NULL) {
conferrx("duplicated configuration prefix \"%s\" in %s and %s modules",
ipa_db_mod->conf_prefix, db_mod->mod_file, db_mod2->mod_file);
return -1;
}
if ( (ac_mod = ac_mod_by_prefix(ipa_db_mod->conf_prefix)) != NULL) {
conferrx("duplicated configuration prefix \"%s\" in %s and %s modules",
ipa_db_mod->conf_prefix, db_mod->mod_file, ac_mod->mod_file);
return -1;
}
ipa_db_mod->suppfunc = &suppfunc;
ipa_db_mod->memfunc = &memfunc;
if (init_conf_tbls(db_mod->mod_file, 1,
ipa_db_mod->conf_sect_tbl, &db_mod->conf_sect_hash,
ipa_db_mod->conf_param_tbl, &db_mod->conf_param_hash) < 0)
return -1;
if (ipa_db_mod->conf_init() < 0) {
conferrx("module %s: conf_init failed", db_mod->mod_file);
return -1;
}
SLIST_INSERT_HEAD(&db_mod_list, db_mod, link);
++ndb_mods;
return 0;
}
/*
* Parse the "ac_list" parameter.
*/
static int
parse_ac_list(void *arg)
{
char *ptr;
const char *ac_name;
struct ac_elem *ac1, *ac2;
struct ac_set *set1, *set2;
struct ac_list *list;
struct ac_mod *ac_mod;
const struct ac_list **listp;
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
listp = &currule->ac_list;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
listp = &curautorule->ac_list;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
listp = &currulepat->ac_list;
break;
default: /* IPA_CONF_SECT_GLOBAL */
listp = &global_ac_list;
}
if (*listp != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
set1 = NULL;
list = NULL;
for (ptr = *(char **)arg; ptr != NULL;) {
/* Get the name of the next accounting system. */
ac_name = ptr;
if ( (ptr = strchr(ptr, ' ')) != NULL)
*ptr++ = '\0';
/* Handle "null" accounting system. */
if (strcmp(ac_name, "null") == 0) {
if (list != NULL || ptr != NULL) {
logconferrx("builtin accounting system \"null\" cannot be used together with another accounting systems");
return -1;
}
*listp = &ac_list_null;
return 0;
}
if ( (ac_mod = ac_mod_by_name(ac_name)) == NULL) {
logconferrx("cannot find module with \"%s\" accounting system name", ac_name);
return -1;
}
if (set1 != NULL) {
/* We already have set for current ac_list parameter. */
STAILQ_FOREACH(ac1, list, link)
if (strcmp(ac_name, ac1->ipa_ac_mod->ac_name) == 0) {
logconferrx("duplicated accounting system \"%s\"",
ac_name);
return -1;
}
} else {
/* Create new set for ac_list parameter. */
if ( (set1 = mem_malloc(sizeof *set1, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
list = &set1->list;
STAILQ_INIT(list);
}
/* Add new ac element to ac_list. */
if ( (ac1 = mem_malloc(sizeof *ac1, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
ac1->ipa_ac_mod = ac_mod->ipa_ac_mod;
ac1->mod_file = ac_mod->mod_file;
/* Increment reference counter if needed. */
ac1->mod_ref_count = &ac_mod->mod_ref_count;
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
/* FALLTHROUGH */
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
#endif
ac_mod->mod_ref_count++;
break;
}
STAILQ_INSERT_TAIL(list, ac1, link);
}
/*
* If we already have the same ac_list (with elements exactly
* in the same order), then free memory used by just allocated
* one (mod_ref_count was updated above).
*/
SLIST_FOREACH(set2, &ac_sets, link) {
ac1 = STAILQ_FIRST(&set1->list);
ac2 = STAILQ_FIRST(&set2->list);
while (ac1 != NULL && ac2 != NULL) {
if (ac1->ipa_ac_mod != ac2->ipa_ac_mod)
break;
ac1 = STAILQ_NEXT(ac1, link);
ac2 = STAILQ_NEXT(ac2, link);
}
if (ac1 == NULL && ac2 == NULL) {
/* Duplicated ac_list was found. */
*listp = &set2->list;
free_ac_set(set1);
return 0;
}
}
/* New ac_list --> add it to ac_sets. */
*listp = list;
SLIST_INSERT_HEAD(&ac_sets, set1, link);
return 0;
}
/*
* Parse the "db_list" parameter.
*/
static int
parse_db_list(void *arg)
{
char *ptr;
const char *db_name;
struct db_elem *db1, *db2;
struct db_set *set1, *set2;
struct db_list *list;
const struct db_mod *db_mod;
const struct db_list **listp;
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
listp = &currule->db_list;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
listp = &curautorule->db_list;
break;
#endif
#ifdef WITH_LIMITS
case IPA_CONF_SECT_LIMIT:
listp = &curlimit->db_list;
break;
#endif
#ifdef WITH_THRESHOLDS
case IPA_CONF_SECT_THRESHOLD:
listp = &curthreshold->db_list;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
listp = &currulepat->db_list;
break;
default: /* IPA_CONF_SECT_GLOBAL */
listp = &global_db_list;
}
if (*listp != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
set1 = NULL;
list = NULL;
for (ptr = *(char **)arg; ptr != NULL;) {
/* Get the name of the next database. */
db_name = ptr;
if ( (ptr = strchr(ptr, ',')) != NULL)
*ptr++ = '\0';
/* Handle "null" database. */
if (strcmp(db_name, "null") == 0) {
if (list != NULL && ptr != NULL) {
logconferrx("builtin \"null\" database cannot be used together with another databases");;
return -1;
}
*listp = &db_list_null;
return 0;
}
if ( (db_mod = db_mod_by_name(db_name)) == NULL) {
logconferrx("cannot find module with \"%s\" database name", db_name);
return -1;
}
if (set1 != NULL) {
/* We already have set for current db_list parameter. */
STAILQ_FOREACH(db1, list, link)
if (strcmp(db_name, db1->ipa_db_mod->db_name) == 0) {
logconferrx("duplicated database \"%s\"",
db_name);
return -1;
}
} else {
/* Create new set for db_list parameter. */
if ( (set1 = mem_malloc(sizeof *set1, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
list = &set1->list;
STAILQ_INIT(list);
}
/* Add new db element to db_list. */
if ( (db1 = mem_malloc(sizeof *db1, m_anon)) == NULL) {
logconferrx("mem_malloc failed");
return -1;
}
db1->ipa_db_mod = db_mod->ipa_db_mod;
db1->mod_file = db_mod->mod_file;
STAILQ_INSERT_TAIL(list, db1, link);
}
/*
* If we already have the same db_list (with elements exactly
* in the same order), then free memory used by just allocated one.
*/
SLIST_FOREACH(set2, &db_sets, link) {
db1 = STAILQ_FIRST(&set1->list);
db2 = STAILQ_FIRST(&set2->list);
while (db1 != NULL && db2 != NULL) {
if (db1->ipa_db_mod != db2->ipa_db_mod)
break;
db1 = STAILQ_NEXT(db1, link);
db2 = STAILQ_NEXT(db2, link);
}
if (db1 == NULL && db2 == NULL) {
/* Duplicated db_list was found. */
*listp = &set2->list;
free_db_set(set1);
return 0;
}
}
/* New db_list --> add it to db_sets. */
*listp = list;
SLIST_INSERT_HEAD(&db_sets, set1, link);
return 0;
}
#ifdef WITH_RULES
/*
* Parse the "ac_gather_add" parameter.
*/
static int
parse_ac_gather_add(void *arg)
{
char *pat;
struct rule *rule;
rule = currule;
if (rule->ac_gather_add_pat != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
rule->ac_gather_add_pat = pat = *(char **)arg;
if ( (re_errcode = regcomp(&rule->ac_gather_add_reg, pat, REG_EXTENDED|REG_NOSUB)) != 0) {
re_form_errbuf();
logconferrx("regcomp(\"%s\"): %s", pat, re_errbuf);
return -1;
}
if (rule->ac_gather_sub_pat == NULL)
SLIST_INSERT_HEAD(&ac_gather_list, rule, ac_gather_link);
return 0;
}
/*
* Parse the "ac_gather_sub" parameter.
*/
static int
parse_ac_gather_sub(void *arg)
{
char *pat;
struct rule *rule;
rule = currule;
if (rule->ac_gather_sub_pat != NULL) {
logconferrx("cannot redefine this parameter");
return -1;
}
rule->ac_gather_sub_pat = pat = *(char **)arg;
if ( (re_errcode = regcomp(&rule->ac_gather_sub_reg, pat, REG_EXTENDED|REG_NOSUB)) != 0) {
re_form_errbuf();
logconferrx("regcomp(\"%s\"): %s", pat, re_errbuf);
return -1;
}
if (rule->ac_gather_add_pat == NULL)
SLIST_INSERT_HEAD(&ac_gather_list, rule, ac_gather_link);
return 0;
}
#endif /* WITH_RULES */
/*
* Parse "posix_re_pattern" parameter.
*/
static int
parse_posix_re_pattern(void *arg)
{
posix_re_pattern = *(int *)arg;
return 0;
}
/*
* Parse "shell_path" parameter.
*/
static int
parse_shell_path(void *arg)
{
shell_path = *(char **)arg;
if (*shell_path != '/') {
logconferrx("shell path should be absolute");
return -1;
}
return 0;
}
/*
* Parse "shell_arg1" parameter.
*/
static int
parse_shell_arg1(void *arg)
{
shell_arg1 = *(char **)arg;
return 0;
}
/*
* Parse "ctl_enable" parameter.
*/
static int
parse_ctl_enable(void *arg)
{
ctl_enable = *(int *)arg;
return 0;
}
/*
* Parse "ctl_socket_path" parameter.
*/
static int
parse_ctl_socket_path(void *arg)
{
const struct sockaddr_un addr;
ctl_socket_path = *(char **)arg;
if (*ctl_socket_path != '/') {
logconferrx("ctl socket path should be absolute");
return -1;
}
if (strlen(ctl_socket_path) + 1 > sizeof addr.sun_path) {
logconferrx("too long path for ctl socket path");
return -1;
}
return 0;
}
/*
* Parse "ctl_socket_perm" parameter.
*/
static int
parse_ctl_socket_perm(void *arg)
{
const char *ptr = *(char **)arg;
mode_t val;
val = 0;
for (; *ptr != '\0'; ++ptr)
switch (*ptr) {
case 'u':
val |= S_IWUSR;
break;
case 'g':
val |= S_IWGRP;
break;
case 'o':
#ifdef CTL_CHECK_CREDS
val |= S_IWOTH;
break;
#else
logconferrx("cannot allow to write to socket for other users");
return -1;
#endif
default:
logconferrx("wrong value");
return -1;
}
ctl_socket_perm = val | S_IRUSR;
return 0;
}
/*
* Parse "ctl_timeout" parameter.
*/
static int
parse_ctl_timeout(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0) || timeval >= UINT64_C(30)) {
logconferrx("argument should be greater than zero seconds and less than 30 seconds");
return -1;
}
ctl_timeout = (u_int)timeval;
return 0;
}
/*
* Parse "debug_ctl" parameter.
*/
static int
parse_debug_ctl(void *arg)
{
return debug_ctl = check_debug_level(*(uint32_t *)arg, 1);
}
#ifdef CTL_CHECK_CREDS
/*
* Find ctl class with the given name.
*/
static const struct ctl_acl_class *
ctl_class_by_name(const char *class_name)
{
const struct ctl_acl_class *class;
STAILQ_FOREACH(class, &ctl_acl_classes, link)
if (strcmp(class->class_name, class_name) == 0)
return class;
return NULL;
}
/*
* Parse "ctl_acl_class" parameter.
*/
static int
parse_ctl_acl_class(void *arg)
{
char *ptr, *str = *(char **)arg;
struct ctl_acl_elem *elem;
struct ctl_acl_class *class;
/* <class> [<elem1> <elem2> ...] */
if ( (ptr = strchr(str, ' ')) != NULL)
*ptr = '\0';
/* Check if we already have class with the same name. */
if (ctl_class_by_name(str) != NULL) {
logconferrx("duplicated ctl class \"%s\"", str);
return -1;
}
/* New class. */
if ( (class = mzone_alloc(ctl_acl_class_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
if ( (class->class_name = mem_strdup(str, m_ctl)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
/* Init ACL for new class. */
STAILQ_INIT(&class->list);
/* Link new class to all classes list. */
STAILQ_INSERT_TAIL(&ctl_acl_classes, class, link);
if (ptr == NULL)
/* Empty class. */
return 0;
str = ptr + 1;
do {
if ( (elem = mzone_alloc(ctl_acl_elem_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(&class->list, elem, link);
if (*str == '!') {
elem->allowed = 0;
++str;
} else
elem->allowed = 1;
ptr = str;
if ( (str = strchr(str, ' ')) != NULL)
*str++ = '\0';
if (*ptr == '%') {
/* Group. */
elem->user = NULL;
if ( (elem->group = mem_strdup(++ptr, m_ctl)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
} else {
/* User. */
elem->group = NULL;
if ( (elem->user = mem_strdup(ptr, m_ctl)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
}
} while (str != NULL);
return 0;
}
static int
parse_ctl_xxx_acl(const struct ctl_acl_class **classpp)
{
if ( (*classpp = ctl_class_by_name(parser_args)) == NULL) {
logconferrx("cannot find ctl class \"%s\"", parser_args);
return -1;
}
return 0;
}
/*
* Parse "ctl_dump_acl" parameter.
*/
/* ARGSUSED */
static int
parse_ctl_dump_acl(void *arg ATTR_UNUSED)
{
return parse_ctl_xxx_acl(&ctl_dump_acl);
}
/*
* Parse "ctl_freeze_acl" parameter.
*/
/* ARGSUSED */
static int
parse_ctl_freeze_acl(void *arg ATTR_UNUSED)
{
return parse_ctl_xxx_acl(&ctl_freeze_acl);
}
/*
* Parse "ctl_stat_acl" parameter.
*/
/* ARGSUSED */
static int
parse_ctl_stat_acl(void *arg ATTR_UNUSED)
{
return parse_ctl_xxx_acl(&ctl_stat_acl);
}
/*
* Parse "ctl_rule_acl" parameter.
*/
/* ARGSUSED */
static int
parse_ctl_rule_acl(void *arg ATTR_UNUSED)
{
const struct ctl_acl_class **classpp;
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
classpp = &currule->ctl_rule_acl;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
classpp = &curautorule->ctl_rule_acl;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
classpp = &currulepat->ctl_rule_acl;
break;
default: /* IPA_CONF_SECT_GLOBAL */
classpp = &global_ctl_rule_acl;
}
return parse_ctl_xxx_acl(classpp);
}
#endif /* CTL_CHECK_CREDS */
#ifdef WITH_THRESHOLDS
/*
* Parse "debug_threshold" parameter.
*/
static int
parse_debug_threshold(void *arg)
{
int level;
if ( (level = check_debug_level(*(uint32_t *)arg, 1)) < 0)
return -1;
switch (section) {
case IPA_CONF_SECT_GLOBAL:
global_debug_threshold = level;
break;
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->debug_threshold = level;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->debug_threshold = level;
break;
#endif
default: /* IPA_CONF_SECT_RULEPAT */
currulepat->debug_threshold = level;
}
return 0;
}
/*
* Parse "debug_threshold_init" parameter.
*/
static int
parse_debug_threshold_init(void *arg)
{
int level;
if ( (level = check_debug_level(*(uint32_t *)arg, 1)) < 0)
return -1;
switch (section) {
case IPA_CONF_SECT_GLOBAL:
global_debug_threshold_init = level;
break;
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
currule->debug_threshold_init = level;
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
curautorule->debug_threshold_init = level;
break;
#endif
default: /* IPA_CONF_SECT_RULEPAT */
currulepat->debug_threshold_init = level;
}
return 0;
}
/*
* Parse "load_threshold" parameter.
*/
static int
parse_load_threshold(void *arg)
{
if (section == IPA_CONF_SECT_THRESHOLD)
curthreshold->load_threshold = *(int *)arg;
else /* IPA_CONF_SECT_GLOBAL */
global_load_threshold = *(int *)arg;
return 0;
}
/*
* Parse "threshold" section.
*/
static int
parse_threshold_sect(void *arg)
{
const char *threshold_name = *(char **)arg;
struct threshold *threshold;
STAILQ_FOREACH(threshold, thresholds_list, link)
if (strcmp(threshold->threshold_name, threshold_name) == 0) {
logconferrx("this section is duplicated");
return -1;
}
if ( (threshold = mzone_alloc(threshold_mzone)) == NULL) {
logconferrx("mzone_alloc failed");
return -1;
}
STAILQ_INSERT_TAIL(thresholds_list, threshold, link);
if ( (threshold->threshold_name = mem_strdup(threshold_name, m_anon)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
threshold->threshold_info = NULL;
threshold->thresholdno = thresholdno++;
threshold->thr = threshold->thr_dev = threshold->cnt_neg = UINT64_C(0);
threshold->thr_dev_per_cent = 0;
threshold->cnt_slice = NULL;
threshold->cnt_slice_sign = NULL;
threshold->threshold_type = -1;
threshold->load_threshold = -1;
threshold->time_width = 0;
threshold->time_slice = NULL;
threshold->worktime = NULL;
threshold->is_active = ACTIVE_FLAG;
threshold->db_list = NULL;
threshold->below_lim = threshold->equal_lim = threshold->above_lim = 0;
init_cmds_in_threshold(threshold);
threshold->wpid.type = WPID_TYPE_THRESHOLD;
threshold->wpid.pid = 0;
threshold->wpid.u.threshold = threshold;
#ifdef WITH_RULES
threshold->rule = currule;
#endif
if (section_top == IPA_CONF_SECT_RULE)
++nstatthresholds;
section_top = IPA_CONF_SECT_THRESHOLD;
if (parser_local_sym_add("threshold", threshold->threshold_name, 0) < 0)
return -1;
if (mod_conf_event(IPA_CONF_EVENT_THRESHOLD_BEGIN,
threshold->thresholdno, threshold->threshold_name) < 0)
return -1;
curthreshold = threshold;
return 0;
}
/*
* Parse "threshold" parameter.
*/
static int
parse_threshold_param(void *arg)
{
uint64_t *ptr = (uint64_t *)arg;
if ( (curthreshold->thr = *(ptr + 1)) == UINT64_C(0)) {
logconferrx("argument should be greater than zero");
return -1;
}
curthreshold->cnt_type = (u_int)*ptr;
return 0;
}
/*
* Parse "threshold_deviation" parameter.
*/
/* ARGSUSED */
static int
parse_threshold_deviation(void *arg ATTR_UNUSED)
{
u_int cnt_type;
struct threshold *threshold;
threshold = curthreshold;
if (threshold->thr == UINT64_C(0)) {
logconferrx("\"threshold\" parameter should be specified before");
return -1;
}
if (get_value_or_per_cent(&threshold->thr_dev, &cnt_type) < 0)
return -1;
if (threshold->thr_dev == UINT64_C(0)) {
logconferrx("argument should be greater than zero");
return -1;
}
if (cnt_type == IPA_CONF_TYPE_PER_CENT)
threshold->thr_dev_per_cent = (u_int)threshold->thr_dev;
else {
if (cnt_type != threshold->cnt_type) {
logconferrx("different arguments types for \"threshold\" and \"threshold_deviation\" parameters");
return -1;
}
if (threshold->thr_dev >= threshold->thr) {
logconferrx("value of this parameter should be less than value of \"threshold\" parameter");
return -1;
}
threshold->thr_dev_per_cent = 0;
}
return 0;
}
/*
* Parse "threshold_time_width" parameter.
*/
static int
parse_threshold_time_width(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0)) {
logconferrx("argument should be greater than zero seconds");
return -1;
}
if (timeval > UINT_MAX) {
logconferrx("too big value %"PRIu64" for u_int type", timeval);
return -1;
}
if (section == IPA_CONF_SECT_THRESHOLD)
curthreshold->time_width = (u_int)timeval;
else /* IPA_CONF_SECT_GLOBAL */
global_threshold_time_width = (u_int)timeval;
return 0;
}
/*
* Parse "threshold_time_slice" parameter.
*/
static int
parse_threshold_time_slice(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
struct tevent *tevent;
if (timeval == UINT64_C(0)) {
logconferrx("argument should be greater than zero seconds");
return -1;
}
if (timeval > UINT_MAX) {
logconferrx("too big value %"PRIu64" for u_int type", timeval);
return -1;
}
if (SECONDS_IN_DAY % timeval != 0) {
logconferrx("number of seconds in one day must be divisible by the value of \"threshold_time_slice\" parameter");
return -1;
}
if ( (tevent = find_tevent((u_int)timeval)) == NULL) {
logconferrx("find_tevent failed");
return -1;
}
if (section == IPA_CONF_SECT_THRESHOLD)
curthreshold->time_slice = tevent;
else /* IPA_CONF_SECT_GLOBAL */
global_threshold_time_slice = tevent;
return 0;
}
/*
* Parse "threshold_type" parameter.
*/
static int
parse_threshold_type(void *arg)
{
uint32_t val = *(uint32_t *)arg;
if (val > THRESHOLD_JUMP_OVER_ALLBITS) {
logconferrx("incorrect value for this parameter");
return -1;
}
if (section == IPA_CONF_SECT_THRESHOLD)
curthreshold->threshold_type = (int)val;
else /* IPA_CONF_SECT_GLOBAL */
global_threshold_type = (int)val;
return 0;
}
/*
* Parse "threshold_balance" parameter.
*/
static int
parse_threshold_balance(void *arg)
{
char *ptr1 = *(char **)arg, *ptr2;
u_int i, val[3];
for (i = 0, ptr2 = ptr1; i < 3; ptr1 = ptr2, ++i) {
if (i != 2) {
ptr2 = strchr(ptr2, ':');
*ptr2 = '\0';
++ptr2;
}
if (*ptr1 != '-') {
if (strto_u_int(&val[i], ptr1, (char **)NULL) < 0)
return -1;
switch (val[i]) {
case 0:
case UINT_MAX:
logconferrx("values should be greater than zero and less than %u", UINT_MAX);
return -1;
}
} else
val[i] = UINT_MAX;
}
if (section == IPA_CONF_SECT_THRESHOLD) {
curthreshold->below_lim = curthreshold->below_cnt = val[0];
curthreshold->equal_lim = curthreshold->equal_cnt = val[1];
curthreshold->above_lim = curthreshold->above_cnt = val[2];
} else { /* IPA_CONF_SECT_GLOBAL */
global_threshold_below_lim = val[0];
global_threshold_equal_lim = val[1];
global_threshold_above_lim = val[2];
}
return 0;
}
/*
* Check if threshold's time_width and time_slice can be used together.
*/
static int
validate_threshold_times(u_int time_width, const struct tevent *time_slice)
{
if (time_width == 0 && time_slice == NULL)
return 0;
if ((time_width != 0 && time_slice == NULL) ||
(time_width == 0 && time_slice != NULL)) {
logconferrx("\"threshold_time_width\" and \"threshold_time_slice\" parameters should be defined together in one section");
return -1;
}
if (time_width < time_slice->event_step) {
logconferrx("the value of \"threshold_time_width\" parameter must be greater than the value of \"threshold_time_slice\" parameter");
return -1;
}
if (time_width % time_slice->event_step != 0) {
logconferrx("the value of \"threshold_time_width\" parameter must be divisible by the value of \"threshold_time_slice\" parameter");
return -1;
}
return 0;
}
/*
* Inherit settings for a threshold from the "global" section.
*/
static int
inherit_threshold_from_global(const char *what, const char *sect_name,
struct threshold *threshold)
{
if (threshold->load_threshold < 0)
threshold->load_threshold = global_load_threshold;
if (threshold->threshold_type < 0)
threshold->threshold_type = global_threshold_type;
if (threshold->below_lim == 0) {
threshold->below_lim = threshold->below_cnt = global_threshold_below_lim;
threshold->equal_lim = threshold->equal_cnt = global_threshold_equal_lim;
threshold->above_lim = threshold->above_cnt = global_threshold_above_lim;
}
if (threshold->time_width == 0) {
threshold->time_width = global_threshold_time_width;
threshold->time_slice = global_threshold_time_slice;
if (threshold->time_width == 0) {
conferrx("%s %s, threshold %s: \"threshold_time_width\" and \"threshold_time_slice\" parameters are not defined",
what, sect_name, threshold->threshold_name);
return -1;
}
}
return 0;
}
#endif /* WITH_THRESHOLDS */
#ifdef WITH_AUTORULES
/*
* Parse "debug_autorule" parameter.
*/
static int
parse_debug_autorule(void *arg)
{
return debug_autorule = check_debug_level(*(uint32_t *)arg, 1);
}
/*
* Parse the "autorule" section.
*/
static int
parse_autorule(void *arg)
{
const char *arule_name = *(char **)arg;
struct autorule *autorule;
for (autorule = autorules; autorule < autorules + nautorules; ++autorule)
if (strcmp(arule_name, autorule->arule_name) == 0) {
logconferrx("this section is duplicated");
return -1;
}
if (marray_alloc(autorules_marray, &nautorules, 1) < 0) {
logconferrx("marray_alloc failed");
return -1;
}
autorule = autorules + nautorules;
if ( (autorule->arule_name = mem_strdup(arule_name, m_anon)) == NULL) {
logconferrx("mem_strdup failed");
return -1;
}
autorule->aruleno = nautorules++;
autorule->update_tevent = autorule->append_tevent = NULL;
autorule->worktime = autorule->worktime_rule = NULL;
autorule->is_active = ACTIVE_FLAG;
autorule->ac_list = NULL;
autorule->db_list = NULL;
autorule->debug_exec = -1;
init_cmds_in_autorule(autorule);
#ifdef WITH_LIMITS
autorule->debug_limit = autorule->debug_limit_init = -1;
limits_list = &autorule->limits;
STAILQ_INIT(limits_list);
limitno = 0;
#endif
#ifdef WITH_THRESHOLDS
autorule->debug_threshold = autorule->debug_threshold_init = -1;
thresholds_list = &autorule->thresholds;
STAILQ_INIT(thresholds_list);
thresholdno = 0;
#endif
#ifdef CTL_CHECK_CREDS
autorule->ctl_rule_acl = NULL;
#endif
section_first = section_top = IPA_CONF_SECT_AUTORULE;
if (parser_local_sym_add("autorule", autorule->arule_name, 0) < 0)
return -1;
if (mod_conf_event(IPA_CONF_EVENT_AUTORULE_BEGIN,
autorule->aruleno, autorule->arule_name) < 0)
return -1;
curautorule = autorule;
return 0;
}
#endif /* WITH_AUTORULES */
/*
* Parse "sleep_after_dump" parameter.
*/
static int
parse_sleep_after_dump(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0) || timeval >= 5 * SECONDS_IN_MINUTE) {
logconferrx("argument should be greater than zero seconds and less than 5 minutes");
return -1;
}
sleep_after_dump = (u_int)timeval;
return 0;
}
/*
* Parse "sensitive_time" parameter.
*/
static int
parse_sensitive_time(void *arg)
{
uint64_t timeval = *(uint64_t *)arg;
if (timeval == UINT64_C(0)) {
logconferrx("argument should be greater than zero");
return -1;
}
if (timeval >= 5 * SECONDS_IN_MINUTE) {
logconferrx("argument should be less than 5 minutes");
return -1;
}
sensitive_time = (u_int)timeval;
return 0;
}
static int
set_curcmdl(void)
{
int x, *set;
#ifdef WITH_LIMITS
static void *curcmdsect;
#endif
x = section == SECT_STARTUP ? RC_STARTUP : RC_SHUTDOWN;
set = NULL;
switch (section) {
case SECT_STARTUP:
case SECT_SHUTDOWN:
switch (section_top) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
set = &currule->rc[x].set;
curcmdl = &currule->rc[x].cmdl;
# ifdef WITH_LIMITS
curcmdsect = &currule->rc[x];
# endif
break;
#endif
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
set = &curautorule->rc[x].set;
curcmdl = &curautorule->rc[x].cmdl;
# ifdef WITH_LIMITS
curcmdsect = &curautorule->rc[x];
# endif
break;
#endif
#ifdef WITH_LIMITS
case IPA_CONF_SECT_LIMIT:
set = &curlimit->rc[x].set;
curcmdl = &curlimit->rc[x].cmdl;
curcmdsect = &curlimit->rc[x];
break;
#endif
#ifdef WITH_SUBLIMITS
case SECT_SUBLIMIT:
set = &cursublimit->rc[x].set;
curcmdl = &cursublimit->rc[x].cmdl;
curcmdsect = &cursublimit->rc[x];
break;
#endif
#ifdef WITH_THRESHOLDS
case IPA_CONF_SECT_THRESHOLD:
curcmdl = &curthreshold->rc[x];
break;
#endif
case IPA_CONF_SECT_RULEPAT:
set = &currulepat->rc[x].set;
curcmdl = &currulepat->rc[x].cmdl;
#ifdef WITH_LIMITS
curcmdsect = &currulepat->rc[x];
#endif
break;
default: /* IPA_CONF_SECT_ROOT */
curcmdl = x == RC_STARTUP ? &cmds_startup : &cmds_shutdown;
}
break;
#ifdef WITH_LIMITS
case SECT_RESTART:
curcmdl = &curlimit->restart.cmdl;
break;
case SECT_REACH:
# ifdef WITH_SUBLIMITS
if (section_top == SECT_SUBLIMIT)
curcmdl = &cursublimit->reach;
else
# endif
curcmdl = &curlimit->reach;
break;
case SECT_EXPIRE:
curcmdl = &curlimit->expire.cmdl;
break;
case SECT_IF_REACHED:
curcmdl = &((struct cmds_limit *)curcmdsect)->cmdl_if_reached;
break;
case SECT_IF_NOT_REACHED:
curcmdl = &((struct cmds_limit *)curcmdsect)->cmdl_if_not_reached;
break;
case SECT_IF_ALL_REACHED:
curcmdl = &((struct cmds_rule *)curcmdsect)->cmdl_if_all_reached;
break;
case SECT_IF_ALL_NOT_REACHED:
curcmdl = &((struct cmds_rule *)curcmdsect)->cmdl_if_all_not_reached;
break;
case SECT_IF_ANY_REACHED:
curcmdl = &((struct cmds_rule *)curcmdsect)->cmdl_if_any_reached;
break;
case SECT_IF_ANY_NOT_REACHED:
curcmdl = &((struct cmds_rule *)curcmdsect)->cmdl_if_any_not_reached;
break;
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
case SECT_BELOW_THRESHOLD:
curcmdl = &curthreshold->below_threshold;
break;
case SECT_ABOVE_THRESHOLD:
curcmdl = &curthreshold->above_threshold;
break;
case SECT_EQUAL_THRESHOLD:
curcmdl = &curthreshold->equal_threshold;
break;
#endif /* WITH_THRESHOLDS */
}
if (set != NULL) {
if (*set != 0) {
logconferrx("this section is duplicated");
return -1;
}
*set = 1;
}
if (!STAILQ_EMPTY(&curcmdl->list)) {
logconferrx("this section is duplicated");
return -1;
}
return 0;
}
static const u_int sect_root[] = { IPA_CONF_SECT_ROOT, 0 };
static const u_int sect_rule[] = { IPA_CONF_SECT_RULE, 0 };
static const u_int sect_rulepat[] = { IPA_CONF_SECT_RULEPAT, 0 };
static const u_int sect_any_rule[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_RULE, IPA_CONF_SECT_AUTORULE, IPA_CONF_SECT_RULEPAT, 0 };
static const u_int sect_for_exec[] = { SECT_STARTUP, SECT_SHUTDOWN, SECT_RESTART, SECT_REACH, SECT_EXPIRE, SECT_IF_REACHED, SECT_IF_NOT_REACHED, SECT_IF_ANY_REACHED, SECT_IF_ALL_REACHED, SECT_IF_ANY_NOT_REACHED, SECT_IF_ALL_NOT_REACHED, SECT_BELOW_THRESHOLD, SECT_ABOVE_THRESHOLD, SECT_EQUAL_THRESHOLD, 0 };
#ifdef WITH_ANY_LIMITS
static const u_int sect_for_any_limit[] = { IPA_CONF_SECT_RULE, IPA_CONF_SECT_AUTORULE, IPA_CONF_SECT_RULEPAT, 0 };
#endif
#ifdef WITH_THRESHOLDS
static const u_int sect_threshold[] = { IPA_CONF_SECT_THRESHOLD, 0 };
static const u_int sect_global_threshold[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_THRESHOLD, 0 };
#endif
#ifdef WITH_LIMITS
static const u_int sect_limit[] = { IPA_CONF_SECT_LIMIT, 0 };
static const u_int sect_global_limit[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_LIMIT, 0 };
static const u_int sect_restart[] = { SECT_RESTART, 0 };
static const u_int sect_expire[] = { SECT_EXPIRE, 0 };
static const u_int sect_startup_shutdown[] = { SECT_STARTUP, SECT_SHUTDOWN, 0 };
static const u_int sect_for_reach[] = { IPA_CONF_SECT_LIMIT, SECT_SUBLIMIT, 0 };
#endif
static const u_int sect_for_startup_shutdown[] = { IPA_CONF_SECT_ROOT, IPA_CONF_SECT_RULE, IPA_CONF_SECT_AUTORULE, IPA_CONF_SECT_LIMIT, SECT_SUBLIMIT, IPA_CONF_SECT_THRESHOLD, IPA_CONF_SECT_RULEPAT, 0 };
#if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
static const u_int sect_for_info[] = { IPA_CONF_SECT_RULE, IPA_CONF_SECT_LIMIT, IPA_CONF_SECT_THRESHOLD, 0 };
#endif
static const u_int sect_for_db_list[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_RULE, IPA_CONF_SECT_AUTORULE, IPA_CONF_SECT_LIMIT, IPA_CONF_SECT_THRESHOLD, IPA_CONF_SECT_RULEPAT, 0 };
static const u_int sect_for_worktime[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_RULE, IPA_CONF_SECT_AUTORULE, IPA_CONF_SECT_LIMIT, IPA_CONF_SECT_THRESHOLD, IPA_CONF_SECT_RULEPAT, 0 };
#ifdef WITH_AUTORULES
static const u_int sect_autorule[] = { IPA_CONF_SECT_AUTORULE, 0 };
#endif
/*
* Sections in ipa.conf(5).
*/
static ipa_conf_sect conf_sect_tbl[] = {
#ifdef WITH_RULES
{ "rule", IPA_CONF_SECT_RULE, 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_rule },
#endif
{ "rulepat", IPA_CONF_SECT_RULEPAT, 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_rulepat },
{ "global", IPA_CONF_SECT_GLOBAL, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_global },
#ifdef WITH_AUTORULES
{ "autorule", IPA_CONF_SECT_AUTORULE, 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_autorule },
#endif
#ifdef WITH_LIMITS
{ "limit", IPA_CONF_SECT_LIMIT, 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_limit_sect },
{ "restart", SECT_RESTART, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_limit, NULL },
{ "reach", SECT_REACH, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_reach, NULL },
{ "expire", SECT_EXPIRE, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_limit, NULL },
# ifdef WITH_SUBLIMITS
{ "sublimit", SECT_SUBLIMIT, -1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_limit, parse_sublimit },
# endif
{ "if_reached", SECT_IF_REACHED, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
{ "if_not_reached", SECT_IF_NOT_REACHED, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
{ "if_any_reached", SECT_IF_ANY_REACHED, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
{ "if_all_reached", SECT_IF_ALL_REACHED, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
{ "if_any_not_reached", SECT_IF_ANY_NOT_REACHED,0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
{ "if_all_not_reached", SECT_IF_ALL_NOT_REACHED,0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL },
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
{ "threshold", IPA_CONF_SECT_THRESHOLD,1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_threshold_sect },
{ "below_threshold", SECT_BELOW_THRESHOLD, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_threshold, NULL },
{ "above_threshold", SECT_ABOVE_THRESHOLD, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_threshold, NULL },
{ "equal_threshold", SECT_EQUAL_THRESHOLD, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_threshold, NULL },
#endif
{ "startup", SECT_STARTUP, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_startup_shutdown, NULL },
{ "shutdown", SECT_SHUTDOWN, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_startup_shutdown, NULL },
{ NULL, 0, 0, NULL, NULL, IPA_CONF_TYPE_MISC, 0, NULL }
};
#ifdef WITH_LIMITS
#define PAT_TIME_EXP "^(\
(\\+[mhDWM] ?)?([[:digit:]]+[smhDW]( ?[[:digit:]]+[smhDW])*)?|\
([[:digit:]]+[smhDW]( ?[[:digit:]]+[smhDW])*)?( ?\\+[mhDWM])?)$"
#endif
#ifdef WITH_THRESHOLDS
#define PAT_THR_BALANCE "^(-|[[:digit:]]+):(-|[[:digit:]]+):(-|[[:digit:]]+)$"
#endif
#define PAT_WORKTIME1 "[SMTWHFA] (\\*|[[:digit:]]{1,2}:[[:digit:]]{1,2}-[[:digit:]]{1,2}:[[:digit:]]{1,2}( [[:digit:]]{1,2}:[[:digit:]]{1,2}-[[:digit:]]{1,2}:[[:digit:]]{1,2})*)"
#define PAT_WORKTIME "^"PAT_WORKTIME1"( "PAT_WORKTIME1")*$"
#define PAT_LIST "^[^ \"]+( [^ \"]+)*$"
#ifdef CTL_CHECK_CREDS
# define PAT_ACL "^[[:alnum:]]+$"
# define PAT_CTL_ACL_CLASS "^[[:alnum:]]+( !?%?[-_[:alnum:]]+)*$"
#endif
/*
* Parameters in ipa.conf(5).
*/
static ipa_conf_param conf_param_tbl[] = {
{ "update_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_any_rule, parse_update_time },
{ "append_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_any_rule, parse_append_time },
{ "wakeup_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_root, parse_wakeup_time },
{ "freeze_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_root, parse_freeze_time },
{ "sleep_after_dump", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_root, parse_sleep_after_dump },
{ "sensitive_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_root, parse_sensitive_time },
{ "exec", -1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_exec, parse_exec },
{ "sync_exec", -1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_for_exec, parse_sync_exec },
{ "ac_mod", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_ac_mod },
{ "db_mod", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_db_mod },
{ "ac_list", -1, PAT_LIST, ®_list, IPA_CONF_TYPE_MISC, sect_any_rule, parse_ac_list },
{ "db_list", -1, NULL, ®_list, IPA_CONF_TYPE_MISC, sect_for_db_list, parse_db_list },
{ "include", 1, NULL, NULL, IPA_CONF_TYPE_STRING, NULL, parse_include },
{ "include_files", 1, NULL, NULL, IPA_CONF_TYPE_STRING, NULL, parse_include_files },
#if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
{ "info", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_for_info, parse_info },
#endif
#ifdef WITH_RULES
{ "ac_gather_add", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_rule, parse_ac_gather_add },
{ "ac_gather_sub", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_rule, parse_ac_gather_sub },
#endif
#ifdef WITH_LIMITS
{ "limit", -1, NULL, NULL, IPA_CONF_TYPE_VALUE, sect_limit, parse_limit_param },
{ "restart", -1, PAT_TIME_EXP, ®_texp, IPA_CONF_TYPE_MISC, sect_restart, parse_restart },
{ "expire", -1, NULL, ®_texp, IPA_CONF_TYPE_MISC, sect_expire, parse_expire },
{ "load_limit", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_global_limit, parse_load_limit },
{ "debug_limit", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_any_rule, parse_debug_limit },
{ "debug_limit_init", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_any_rule, parse_debug_limit_init },
#endif
#ifdef WITH_THRESHOLDS
{ "threshold", -1, NULL, NULL, IPA_CONF_TYPE_VALUE, sect_threshold, parse_threshold_param },
{ "threshold_deviation",-1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_threshold, parse_threshold_deviation },
{ "threshold_time_width",-1,NULL, NULL, IPA_CONF_TYPE_TIME, sect_global_threshold, parse_threshold_time_width },
{ "threshold_time_slice",-1,NULL, NULL, IPA_CONF_TYPE_TIME, sect_global_threshold, parse_threshold_time_slice },
{ "threshold_type", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_global_threshold, parse_threshold_type },
{ "threshold_balance", 1, PAT_THR_BALANCE, ®_thr_balance, IPA_CONF_TYPE_MISC, sect_global_threshold, parse_threshold_balance },
{ "load_threshold", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_global_threshold, parse_load_threshold },
{ "debug_threshold", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_any_rule, parse_debug_threshold },
{ "debug_threshold_init",1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_any_rule, parse_debug_threshold_init },
#endif
{ "worktime", -1, PAT_WORKTIME, ®_worktime, IPA_CONF_TYPE_MISC, sect_for_worktime, parse_worktime },
#ifdef WITH_AUTORULES
{ "worktime_rule", -1, NULL, ®_worktime, IPA_CONF_TYPE_MISC, sect_autorule, parse_worktime_rule },
#endif
{ "posix_re_pattern", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_posix_re_pattern },
{ "only_abs_paths", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_only_abs_paths },
{ "keep_rules_order", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_keep_rules_order },
{ "check_next_rulepat", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_rulepat, parse_check_next_rulepat },
{ "shell_path", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_shell_path },
{ "shell_arg1", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_shell_arg1 },
{ "debug_time", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_time },
{ "debug_ac_null", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_ac_null },
{ "debug_db_null", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_db_null },
{ "debug_exec", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_any_rule, parse_debug_exec },
{ "debug_worktime", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_worktime },
{ "ctl_enable", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_ctl_enable },
{ "ctl_socket_path", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_ctl_socket_path },
{ "ctl_socket_perm", 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_ctl_socket_perm },
{ "ctl_timeout", -1, NULL, NULL, IPA_CONF_TYPE_TIME, sect_root, parse_ctl_timeout },
{ "debug_ctl", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_ctl },
#ifdef CTL_CHECK_CREDS
{ "ctl_rule_acl", 1, PAT_ACL, ®_acl, IPA_CONF_TYPE_MISC, sect_any_rule, parse_ctl_rule_acl },
{ "ctl_dump_acl", 1, NULL, ®_acl, IPA_CONF_TYPE_MISC, sect_root, parse_ctl_dump_acl },
{ "ctl_freeze_acl", 1, NULL, ®_acl, IPA_CONF_TYPE_MISC, sect_root, parse_ctl_freeze_acl },
{ "ctl_stat_acl", 1, NULL, ®_acl, IPA_CONF_TYPE_MISC, sect_root, parse_ctl_stat_acl },
{ "ctl_acl_class", -1, PAT_CTL_ACL_CLASS, ®_ctl_acl_class, IPA_CONF_TYPE_MISC, sect_root, parse_ctl_acl_class },
#endif
#ifdef WITH_AUTORULES
{ "debug_autorule", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_autorule },
#endif
{ NULL, 0, NULL, NULL, 0, 0, NULL }
};
/*
* Main function for parsing configuration file(s).
*/
int
configure(PARSING_MODE mode)
{
int real_config;
char *ptr;
const u_int *id_ptr;
const char *prefix; /* Configuration prefix. */
#ifdef WITH_RULES
const struct worktime *rule_wt;
#endif
struct rulepat *rulepat;
#ifdef WITH_RULES
struct rule *rule;
#endif
#ifdef WITH_LIMITS
struct limit *limit;
struct cmd_list *prevcmdl;
#endif
#ifdef WITH_THRESHOLDS
struct threshold *threshold;
#endif
#ifdef WITH_AUTORULES
struct autorule *autorule;
#endif
/* Stack of nested configuration sections. */
struct section_stack {
SLIST_ENTRY(section_stack) link;
u_int section; /* Section ID. */
} *section_stack_ptr;
SLIST_HEAD(, section_stack) section_stack_list = SLIST_HEAD_INITIALIZER(section_stack_list);
const struct ac_mod *ac_mod;
const struct db_mod *db_mod;
struct time_param *time_param;
struct debug_param *debug_param;
struct parser_pbuf *pbuf;
struct conf_sect_hash *conf_sect_hash;
struct conf_param_hash *conf_param_hash;
const struct conf_sect_hash *conf_sect_hash_ptr;
const struct conf_param_hash *conf_param_hash_ptr;
const ipa_conf_sect *conf_sect_tbl_ptr, *conf_sect;
const ipa_conf_param *conf_param_tbl_ptr, *conf_param;
int in_own_sect; /* 1, if in own ipa.conf(5) section. */
const struct get_arg_tbl *get_arg_ptr;
if (mode == TEST_PARSING || mode == CMD_PARSING)
use_log = real_config = 0;
else
real_config = 1;
xvlogmsgx = vconferrx_priority;
/* Set wrappers for log functions. */
mvlogmsgx = mvlogmsgx_conf_wrapper;
parser_vlogmsgx = parser_vlogmsgx_wrapper;
if (memfunc_init() < 0) {
logmsgx(IPA_LOG_ERR, "configure: memfunc_init failed");
return -1;
}
if ((m_anon = mem_type_new_local(MTYPE_NAME(anonymous), "Anonymous memory", 0)) == NULL ||
(m_tmp = mem_type_new_local(MTYPE_NAME(tmp), "Temporal memory", 0)) == NULL ||
(m_ctl = mem_type_new_local(MTYPE_NAME(ctl), "Memory for ctl", 0)) == NULL ||
(m_cmd = mem_type_new_local(MTYPE_NAME(cmd), "Memory for commands", 0)) == NULL ||
(m_parser = mem_type_new_local(MTYPE_NAME(parser), "Memory allocated by parser", MEMTYPE_FLAGS)) == NULL) {
logmsgx(IPA_LOG_ERR, "configure: mem_type_new_local failed");
return -1;
}
nac_mods = ndb_mods = 0;
global_ac_list = NULL;
global_db_list = NULL;
for (debug_param = global_debug_param; debug_param->param_name != NULL; ++debug_param)
*debug_param->param_value = -1;
SLIST_INIT(&ac_mod_list);
SLIST_INIT(&db_mod_list);
if ( (conf_sect_hentry_mzone = mzone_init(MZONE_NAME(conf_sect_hentry),
"Config sections hash entries", 0, sizeof(struct conf_sect_hentry),
CONF_SECT_HENTRY_NSIZE, CONF_SECT_HENTRY_NALLOC)) == NULL)
goto parsing_failed;
if ( (conf_param_hentry_mzone = mzone_init(MZONE_NAME(conf_param_hentry),
"Config parameters hash entries", 0, sizeof(struct conf_param_hentry),
CONF_PARAM_HENTRY_NSIZE, CONF_PARAM_HENTRY_NALLOC)) == NULL)
goto parsing_failed;
if (mode != RECONFIG_PARSING) {
init_rules_hash();
#ifdef WITH_ANY_LIMITS
init_wpid_hash();
#endif
}
if ( (rule_mzone = mzone_init(MZONE_NAME(rule), "Rules", MEMFLAG_OPTIMIZE,
sizeof(struct rule), RULE_NSIZE, RULE_NALLOC)) == NULL)
goto parsing_failed;
if ( (rulepat_mzone = mzone_init(MZONE_NAME(rulepat), "Rules patterns", 0,
sizeof(struct rulepat), RULEPAT_NSIZE, RULEPAT_NALLOC)) == NULL)
goto parsing_failed;
STAILQ_INIT(&rulepats_list);
rulepatno = 0;
#ifdef WITH_RULES
SLIST_INIT(&ac_gather_list);
#endif
nstatrules = 0;
if ( (tint_mzone = mzone_init(MZONE_NAME(tint), "Time intervals", 0,
sizeof(struct tint), TINT_NSIZE, TINT_NALLOC)) == NULL)
goto parsing_failed;
STAILQ_INIT(&tint_sets);
if ( (worktime_mzone = mzone_init(MZONE_NAME(worktime), "Worktimes", 0,
sizeof(struct worktime), WORKTIME_NSIZE, WORKTIME_NALLOC)) == NULL)
goto parsing_failed;
init_worktime_default();
SLIST_INIT(&worktimes_list);
SLIST_INSERT_HEAD(&worktimes_list, &worktime_default, link);
if ( (tevent_mzone = mzone_init(MZONE_NAME(tevent), "Time events", 0,
sizeof(struct tevent), TEVENT_NSIZE, TEVENT_NALLOC)) == NULL)
goto parsing_failed;
SLIST_INIT(&tevents_list);
if ( (cmd_mzone = mzone_init(MZONE_NAME(cmd), "Commands", MEMFLAG_OPTIMIZE,
sizeof(struct cmd), CMD_NSIZE, CMD_NALLOC)) == NULL)
goto parsing_failed;
init_cmd_list(&cmds_startup);
init_cmd_list(&cmds_shutdown);
#ifdef WITH_LIMITS
if ( (limit_mzone = mzone_init(MZONE_NAME(limit), "Limits", MEMFLAG_OPTIMIZE,
sizeof(struct limit), LIMIT_NSIZE, LIMIT_NALLOC)) == NULL)
goto parsing_failed;
global_load_limit = -1;
#endif
#ifdef WITH_SUBLIMITS
if ( (sublimit_mzone = mzone_init(MZONE_NAME(sublimit), "Sublimits", MEMFLAG_OPTIMIZE,
sizeof(struct sublimit), SUBLIMIT_NSIZE, SUBLIMIT_NALLOC)) == NULL)
goto parsing_failed;
#endif
nstatlimits = ndynlimits = nstatsublimits = ndynsublimits = 0;
#ifdef WITH_THRESHOLDS
if ( (threshold_mzone = mzone_init(MZONE_NAME(threshold), "Thresholds", MEMFLAG_OPTIMIZE,
sizeof(struct threshold), THRESHOLD_NSIZE, THRESHOLD_NALLOC)) == NULL)
goto parsing_failed;
global_threshold_type = -1;
global_load_threshold = -1;
global_threshold_time_width = 0;
global_threshold_time_slice = NULL;
global_threshold_below_lim = global_threshold_equal_lim =
global_threshold_above_lim = 0;
#endif
nstatthresholds = ndynthresholds = 0;
#ifdef WITH_AUTORULES
if ( (autorules_marray = marray_init(MARRAY_NAME(autorules), "Autorules",
0, (void *)&autorules, sizeof(struct autorule),
AUTORULE_NSIZE, AUTORULE_NALLOC)) == NULL)
goto parsing_failed;
nautorules = 0;
rules_ptr_marray = NULL;
#endif
global_update_tevent = global_append_tevent = NULL;
global_worktime = NULL;
global_section_set = 0;
only_abs_paths = keep_rules_order = posix_re_pattern = -1;
for (time_param = common_time_param; time_param->param_name != NULL; ++time_param)
*time_param->param_value = 0;
for (debug_param = common_debug_param; debug_param->param_name != NULL; ++debug_param)
*debug_param->param_value = -1;
ctl_enable = -1;
ctl_socket_path = NULL;
ctl_socket_perm = 0;
ctl_timeout = 0;
#ifdef CTL_CHECK_CREDS
if ( (ctl_acl_elem_mzone = mzone_init(MZONE_NAME(ctl_acl_elem), "ACL elements", 0,
sizeof(struct ctl_acl_elem), CTL_ACL_ELEM_NSIZE, CTL_ACL_ELEM_NALLOC)) == NULL)
goto parsing_failed;
if ( (ctl_acl_class_mzone = mzone_init(MZONE_NAME(ctl_acl_class), "ACL classes", 0,
sizeof(struct ctl_acl_class), CTL_ACL_CLASS_NSIZE, CTL_ACL_CLASS_NALLOC)) == NULL)
goto parsing_failed;
global_ctl_rule_acl = ctl_dump_acl = ctl_freeze_acl = ctl_stat_acl = NULL;
STAILQ_INIT(&ctl_acl_classes);
#endif
section = section_first = section_top = IPA_CONF_SECT_ROOT;
parsing_mode = mode;
memfunc.m_parser = m_parser;
if (real_config)
logmsgx(IPA_LOG_INFO, "use configuration file %s, parsing...", ipa_conf_file);
if (check_conf_file(ipa_conf_file, 0) < 0)
goto parsing_failed;
/* Init parser. */
if (parser_init() < 0) {
logmsgx(IPA_LOG_ERR, "configure: parser_init failed");
goto parsing_failed;
}
/* Init first pbuf. */
if ( (pbuf = parser_new_pbuf(0)) == NULL)
goto parsing_failed;
pbuf->fname = ipa_conf_file;
if ( (pbuf->fp = fopen(ipa_conf_file, "r")) == NULL) {
conferrx("fopen(%s, \"r\"): %s", ipa_conf_file, strerror(errno));
goto parsing_failed;
}
if (parser_push_pbuf(pbuf) < 0)
goto parsing_failed;
/* Needed for log messages. */
curparam = cursect = curmodfile = NULL;
if (build_conf_regexp() < 0) {
conferrx("cannot build additional regular expressions needed for parsing");
goto parsing_failed;
}
if (init_conf_tbls((char *)NULL, mode != RECONFIG_PARSING,
conf_sect_tbl, &conf_sect_hash,
conf_param_tbl, &conf_param_hash) < 0)
goto parsing_failed;
/* Set ipa.conf(5) configuration tables. */
conf_sect_tbl_ptr = conf_sect_tbl;
conf_param_tbl_ptr = conf_param_tbl;
conf_sect_hash_ptr = conf_sect_hash;
conf_param_hash_ptr = conf_param_hash;
in_own_sect = 1;
for (;;) {
switch (parser_read_string()) {
case 1:
/* Successfully read one logical line. */
break;
case 0:
/* EOF of current configuration file. */
if (fclose(parser_curpbuf->fp) != 0) {
conferrx("fclose(%s): %s", parser_curpbuf->fname, strerror(errno));
goto parsing_failed;
}
if (parser_curpbuf->fname != ipa_conf_file)
mem_free(parser_curpbuf->fname, m_parser);
parser_pop_pbuf();
if (parser_curpbuf != NULL) {
/* Init previous file for parsing. */
if ( (parser_curpbuf->fp = fopen(parser_curpbuf->fname, "r")) == NULL) {
conferrx("fopen(%s, \"r\"): %s", parser_curpbuf->fname, strerror(errno));
goto parsing_failed;
}
if (fseek(parser_curpbuf->fp, parser_curpbuf->foff, SEEK_SET) < 0) {
conferrx("fseek(%s, %ld, SEEK_SET): %s",
parser_curpbuf->fname, parser_curpbuf->foff, strerror(errno));
goto parsing_failed;
}
continue;
}
goto end_of_parsing;
default: /* -1 */
goto parsing_failed;
}
switch (parser_token_id) {
case TOKEN_ID_SECTION_BEGIN:
/* Put previous section on top of sections stack. */
if ( (section_stack_ptr = mem_malloc(sizeof *section_stack_ptr, m_anon)) == NULL) {
conferrx("configure: mem_malloc failed");
goto parsing_failed;
}
section_stack_ptr->section = section;
SLIST_INSERT_HEAD(§ion_stack_list, section_stack_ptr, link);
/* Get name of current section. */
cursect = parser_token; /* "section" or "prefix:section". */
if (in_own_sect) {
/* Previous section is not a custom section. */
if ( (ptr = strchr(cursect, ':')) != NULL) {
*ptr = '\0';
prefix = cursect;
cursect = ptr + 1; /* Fix section name. */
if ( (db_mod = db_mod_by_prefix(prefix)) != NULL) {
conf_sect_hash_ptr = db_mod->conf_sect_hash;
conf_param_hash_ptr = db_mod->conf_param_hash;
conf_sect_tbl_ptr = db_mod->ipa_db_mod->conf_sect_tbl;
conf_param_tbl_ptr = db_mod->ipa_db_mod->conf_param_tbl;
curmodfile = db_mod->mod_file;
} else if ( (ac_mod = ac_mod_by_prefix(prefix)) != NULL) {
conf_sect_hash_ptr = ac_mod->conf_sect_hash;
conf_param_hash_ptr = ac_mod->conf_param_hash;
conf_sect_tbl_ptr = ac_mod->ipa_ac_mod->conf_sect_tbl;
conf_param_tbl_ptr = ac_mod->ipa_ac_mod->conf_param_tbl;
curmodfile = ac_mod->mod_file;
db_mod = NULL;
} else {
logconferrx("cannot find module with \"%s\" configuration prefix",
prefix);
goto parsing_failed;
}
in_own_sect = 0;
}
}
/* Find ID of section. */
if ( (conf_sect = find_conf_sect(conf_sect_tbl_ptr, conf_sect_hash_ptr, cursect)) == NULL) {
logconferrx("unknown section");
goto parsing_failed;
}
/* Check if current section is used in correct place. */
if ( (id_ptr = conf_sect->sect_where) != NULL)
for (;; ++id_ptr) {
if (*id_ptr == section)
break;
if (*id_ptr == 0)
goto section_not_expected;
}
/* Check number of section's arguments. */
if (conf_sect->arg_nargs >= 0) {
if (parser_nargs != conf_sect->arg_nargs) {
logconferrx("wrong number of arguments (has %d, should have %d)",
parser_nargs, conf_sect->arg_nargs);
goto parsing_failed;
}
} else {
if (parser_nargs < -conf_sect->arg_nargs) {
logconferrx("this section should have at least %d argument%s",
-conf_sect->arg_nargs, conf_sect->arg_nargs == -1 ? "" : "s");
goto parsing_failed;
}
}
/* Validate arguments if needed. */
if (conf_sect->arg_regexp != NULL)
if (regexec(conf_sect->arg_regexp, parser_args, 0, (regmatch_t *)NULL, 0) != 0) {
logconferrx("wrong format of an argument");
goto parsing_failed;
}
section = conf_sect->sect_id;
/* Register config event in module. */
if (!in_own_sect) {
if (db_mod != NULL) {
if (db_mod_conf_event(db_mod, IPA_CONF_EVENT_CUSTOM_SECT_BEGIN, section, (void *)NULL) < 0)
goto parsing_failed;
} else {
if (ac_mod_conf_event(ac_mod, IPA_CONF_EVENT_CUSTOM_SECT_BEGIN, section, (void *)NULL) < 0)
goto parsing_failed;
}
}
/* Parse it. */
if (conf_sect->arg_type <= IPA_CONF_TYPE_MISC) {
get_arg_ptr = &get_arg_tbl[conf_sect->arg_type];
if (get_arg_ptr->reg != NULL)
if (regexec(get_arg_ptr->reg, parser_args, 0, (regmatch_t *)NULL, 0) != 0) {
logconferrx("wrong format of an argument");
goto parsing_failed;
}
if (get_arg_ptr->get_arg(get_arg_ptr->argp) < 0)
goto parsing_failed;
if (conf_sect->arg_parse != NULL)
if (conf_sect->arg_parse(get_arg_ptr->argp) < 0)
goto parsing_failed;
} else {
logconferrx("internal error: unknown type %u of function's argument",
conf_sect->arg_type);
goto parsing_failed;
}
if (in_own_sect && section >= SECT_RESTART &&
section <= SECT_ABOVE_THRESHOLD) {
/* Do additional settings for ipa.conf(5)'s sections. */
#ifdef WITH_LIMITS
switch (section) {
case SECT_IF_ALL_REACHED:
case SECT_IF_ALL_NOT_REACHED:
case SECT_IF_ANY_REACHED:
case SECT_IF_ANY_NOT_REACHED:
switch (section_top) {
case IPA_CONF_SECT_RULE:
case IPA_CONF_SECT_AUTORULE:
case IPA_CONF_SECT_RULEPAT:
break;
default:
goto section_not_expected;
}
prevcmdl = curcmdl;
break;
case SECT_IF_REACHED:
case SECT_IF_NOT_REACHED:
switch (section_top) {
case IPA_CONF_SECT_LIMIT:
case SECT_SUBLIMIT:
break;
default:
goto section_not_expected;
}
prevcmdl = curcmdl;
break;
}
#endif /* WITH_LIMITS */
if (set_curcmdl() < 0)
goto parsing_failed;
}
break;
case TOKEN_ID_PARAMETER:
curparam = parser_token; /* "param" or "prefix:param". */
if (in_own_sect) {
/* Current section is not a custom section. */
if ( (ptr = strchr(curparam, ':')) != NULL) {
*ptr = '\0';
prefix = curparam;
curparam = ptr + 1; /* Fix parameter name. */
if ( (db_mod = db_mod_by_prefix(prefix)) != NULL) {
conf_param_hash_ptr = db_mod->conf_param_hash;
conf_param_tbl_ptr = db_mod->ipa_db_mod->conf_param_tbl;
curmodfile = db_mod->mod_file;
} else if ( (ac_mod = ac_mod_by_prefix(prefix)) != NULL) {
conf_param_hash_ptr = ac_mod->conf_param_hash;
conf_param_tbl_ptr = ac_mod->ipa_ac_mod->conf_param_tbl;
curmodfile = ac_mod->mod_file;
db_mod = NULL;
} else {
logconferrx("cannot find module with \"%s\" configuration prefix",
prefix);
goto parsing_failed;
}
}
}
/* Find ID of parameter. */
if ( (conf_param = find_conf_param(conf_param_tbl_ptr, conf_param_hash_ptr, curparam)) == NULL) {
logconferrx("unknown parameter");
goto parsing_failed;
}
/* Check if parameter is used in correct place. */
if ( (id_ptr = conf_param->param_where) != NULL)
for (;; ++id_ptr) {
if (*id_ptr == section)
break;
if (*id_ptr == 0) {
logconferrx("this parameter is not expected here");
goto parsing_failed;
}
}
/* Check number of parameters's arguments. */
if (conf_param->arg_nargs >= 0) {
if (parser_nargs != conf_param->arg_nargs) {
logconferrx("wrong number of arguments (has %d, should have %d)",
parser_nargs, conf_param->arg_nargs);
goto parsing_failed;
}
} else {
if (parser_nargs < -conf_param->arg_nargs) {
logconferrx("this parameter should have at least %d argument%s",
-conf_param->arg_nargs, conf_param->arg_nargs == -1 ? "": "s");
goto parsing_failed;
}
}
/* Validate arguments if needed. */
if (conf_param->arg_regexp != NULL)
if (regexec(conf_param->arg_regexp, parser_args, 0, (regmatch_t *)NULL, 0) != 0) {
logconferrx("wrong format of an argument");
goto parsing_failed;
}
/* Parse it. */
if (conf_param->arg_type <= IPA_CONF_TYPE_MISC) {
get_arg_ptr = &get_arg_tbl[conf_param->arg_type];
if (get_arg_ptr->reg != NULL)
if (regexec(get_arg_ptr->reg, parser_args, 0, (regmatch_t *)NULL, 0) != 0) {
logconferrx("wrong format of an argument");
goto parsing_failed;
}
if (get_arg_ptr->get_arg(get_arg_ptr->argp) < 0)
goto parsing_failed;
if (conf_param->arg_parse != NULL)
if (conf_param->arg_parse(get_arg_ptr->argp) < 0)
goto parsing_failed;
curparam = NULL;
} else {
logconferrx("internal error: unknown type %u of an argument",
conf_param->arg_type);
goto parsing_failed;
}
if (curmodfile != NULL && in_own_sect) {
curmodfile = NULL; /* Was set above for logxxx() functions. */
/* Restore ipa.conf(5) parameters tables. */
conf_param_hash_ptr = conf_param_hash;
conf_param_tbl_ptr = conf_param_tbl;
}
break;
default: /* TOKEN_ID_SECTION_END */
cursect = NULL;
if (!in_own_sect) {
/* Register config event in module. */
if (db_mod != NULL) {
if (db_mod_conf_event(db_mod, IPA_CONF_EVENT_CUSTOM_SECT_END, section, (void *)NULL) < 0)
goto parsing_failed;
} else {
if (ac_mod_conf_event(ac_mod, IPA_CONF_EVENT_CUSTOM_SECT_END, section, (void *)NULL) < 0)
goto parsing_failed;
}
} else {
switch (section) {
#ifdef WITH_RULES
case IPA_CONF_SECT_RULE:
section_top = IPA_CONF_SECT_ROOT;
if (mod_conf_event(IPA_CONF_EVENT_RULE_END, currule->ruleno, (void *)NULL) < 0)
goto parsing_failed;
break;
#endif
case IPA_CONF_SECT_RULEPAT:
section_top = IPA_CONF_SECT_ROOT;
if (mod_conf_event(IPA_CONF_EVENT_RULEPAT_END, currulepat->rulepatno, (void *)NULL) < 0)
goto parsing_failed;
break;
#ifdef WITH_AUTORULES
case IPA_CONF_SECT_AUTORULE:
section_top = IPA_CONF_SECT_ROOT;
if (mod_conf_event(IPA_CONF_EVENT_AUTORULE_END, curautorule->aruleno, (void *)NULL) < 0)
goto parsing_failed;
break;
#endif
case IPA_CONF_SECT_GLOBAL:
section_top = IPA_CONF_SECT_ROOT;
#ifdef WITH_THRESHOLDS
if (validate_threshold_times(global_threshold_time_width, global_threshold_time_slice) < 0)
goto parsing_failed;
#endif
if (mod_conf_event(IPA_CONF_EVENT_GLOBAL_END, 0, (void *)NULL) < 0)
goto parsing_failed;
break;
#ifdef WITH_LIMITS
case IPA_CONF_SECT_LIMIT:
section_top = section_first;
if (curlimit->lim == UINT64_C(0)) {
logconferrx("parameter \"limit\" must be specified");
goto parsing_failed;
}
(void)parser_local_sym_del("limit");
if (mod_conf_event(IPA_CONF_EVENT_LIMIT_END, curlimit->limitno, (void *)NULL) < 0)
goto parsing_failed;
break;
# ifdef WITH_SUBLIMITS
case SECT_SUBLIMIT:
section_top = IPA_CONF_SECT_LIMIT;
(void)parser_local_sym_del("sublimit");
break;
# endif
case SECT_RESTART:
if (curlimit->restart.restart.upto == TEXP_UPTO_NOTSET) {
logconferrx("parameter \"restart\" must be specified");
goto parsing_failed;
}
break;
case SECT_EXPIRE:
if (curlimit->expire.expire.upto == TEXP_UPTO_NOTSET) {
logconferrx("parameter \"expire\" must be specified");
goto parsing_failed;
}
break;
case SECT_IF_REACHED:
case SECT_IF_NOT_REACHED:
case SECT_IF_ALL_REACHED:
case SECT_IF_ALL_NOT_REACHED:
case SECT_IF_ANY_REACHED:
case SECT_IF_ANY_NOT_REACHED:
curcmdl = prevcmdl;
break;
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
case IPA_CONF_SECT_THRESHOLD:
section_top = section_first;
if (curthreshold->thr == UINT64_C(0)) {
logconferrx("parameter \"threshold\" must be specified");
goto parsing_failed;
}
if (validate_threshold_times(curthreshold->time_width, curthreshold->time_slice) < 0)
goto parsing_failed;
(void)parser_local_sym_del("threshold");
if (mod_conf_event(IPA_CONF_EVENT_THRESHOLD_END, curthreshold->thresholdno, (void *)NULL) < 0)
goto parsing_failed;
break;
#endif /* WITH_THRESHOLDS */
}
}
section_stack_ptr = SLIST_FIRST(§ion_stack_list);
SLIST_REMOVE_HEAD(§ion_stack_list, link);
section = section_stack_ptr->section;
mem_free(section_stack_ptr, m_anon);
if (!in_own_sect && section < IPA_CONF_SECT_CUSTOM_OFFSET) {
/* We were in custom section and previous section is not a custom section. */
curmodfile = NULL;
/* Restore ipa.conf(5) configuration tables. */
conf_sect_tbl_ptr = conf_sect_tbl;
conf_param_tbl_ptr = conf_param_tbl;
conf_sect_hash_ptr = conf_sect_hash;
conf_param_hash_ptr = conf_param_hash;
in_own_sect = 1;
}
}
}
end_of_parsing:
deinit_conf_tbls(0, conf_sect_tbl, conf_sect_hash,
conf_param_tbl, conf_param_hash);
mzone_deinit(conf_sect_hentry_mzone);
mzone_deinit(conf_param_hentry_mzone);
if (parser_deinit() < 0)
goto parsing_failed;
if (mzone_is_empty(worktime_mzone)) {
mzone_deinit(worktime_mzone);
mzone_deinit(tint_mzone);
worktime_mzone = tint_mzone = NULL;
}
if (mzone_is_empty(cmd_mzone)) {
mzone_deinit(cmd_mzone);
cmd_mzone = NULL;
}
if (mzone_is_empty(rulepat_mzone)) {
mzone_deinit(rulepat_mzone);
rulepat_mzone = NULL;
}
#ifdef WITH_LIMITS
if (mzone_is_empty(limit_mzone)) {
mzone_deinit(limit_mzone);
limit_mzone = NULL;
}
#endif
#ifdef WITH_SUBLIMITS
if (mzone_is_empty(sublimit_mzone)) {
mzone_deinit(sublimit_mzone);
sublimit_mzone = NULL;
}
#endif
#ifdef WITH_THRESHOLDS
if (mzone_is_empty(threshold_mzone)) {
mzone_deinit(threshold_mzone);
threshold_mzone = NULL;
}
#endif
#ifdef CTL_CHECK_CREDS
if (mzone_is_empty(ctl_acl_elem_mzone)) {
mzone_deinit(ctl_acl_elem_mzone);
ctl_acl_elem_mzone = NULL;
}
if (mzone_is_empty(ctl_acl_class_mzone)) {
mzone_deinit(ctl_acl_class_mzone);
ctl_acl_class_mzone = NULL;
}
#endif
SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
if (mimic_real_config)
if (ac_mod->ipa_ac_mod->conf_mimic_real() < 0) {
conferrx("module %s: conf_mimic_real failed", ac_mod->mod_file);
goto parsing_failed;
}
deinit_conf_tbls(1,
ac_mod->ipa_ac_mod->conf_sect_tbl, ac_mod->conf_sect_hash,
ac_mod->ipa_ac_mod->conf_param_tbl, ac_mod->conf_param_hash);
if (ac_mod->ipa_ac_mod->conf_deinit() < 0) {
conferrx("module %s: conf_deinit failed", ac_mod->mod_file);
goto parsing_failed;
}
}
SLIST_FOREACH(db_mod, &db_mod_list, link) {
if (mimic_real_config)
if (db_mod->ipa_db_mod->conf_mimic_real() < 0) {
conferrx("module %s: conf_mimic_real failed", db_mod->mod_file);
goto parsing_failed;
}
deinit_conf_tbls(1,
db_mod->ipa_db_mod->conf_sect_tbl, db_mod->conf_sect_hash,
db_mod->ipa_db_mod->conf_param_tbl, db_mod->conf_param_hash);
if (db_mod->ipa_db_mod->conf_deinit() < 0) {
conferrx("module %s: conf_deinit failed", db_mod->mod_file);
goto parsing_failed;
}
}
if (real_config)
mimic_real_config = 1;
if (mimic_real_config || mode == CMD_PARSING) {
if (shell_path == NULL)
shell_path = shell_path_default;
if (shell_arg1 == NULL)
shell_arg1 = shell_arg1_default;
}
if (mimic_real_config) {
/* Set global parameters. */
global_section_set = 1;
if (only_abs_paths < 0)
only_abs_paths = 0;
if (keep_rules_order < 0)
keep_rules_order = 0;
if (wakeup_time == 0)
wakeup_time = WAKEUP_TIME_DEF;
if (sensitive_time == 0)
sensitive_time = SENSITIVE_TIME_DEF;
if (global_update_tevent == NULL)
if ( (global_update_tevent = find_tevent(UPDATE_TIME_DEF)) == NULL) {
conferrx("find_tevent_failed for default value of \"update_time\" parameter");
goto parsing_failed;
}
if (global_ac_list == NULL)
global_ac_list = &ac_list_null;
if (global_db_list == NULL)
global_db_list = &db_list_null;
if (global_worktime == NULL)
global_worktime = &worktime_default;
#ifdef WITH_LIMITS
if (global_load_limit < 0)
global_load_limit = 0;
#endif
#ifdef WITH_THRESHOLDS
if (global_threshold_type < 0)
global_threshold_type = 0;
if (global_load_threshold < 0)
global_load_threshold = 0;
if (global_threshold_below_lim == 0)
global_threshold_below_lim = global_threshold_equal_lim =
global_threshold_above_lim = UINT_MAX;
#endif
for (debug_param = global_debug_param; debug_param->param_name != NULL; ++debug_param)
if (*debug_param->param_value < 0)
*debug_param->param_value = 0;
if (cmds_startup.sync_exec < 0)
cmds_startup.sync_exec = 1;
if (cmds_shutdown.sync_exec < 0)
cmds_shutdown.sync_exec = 1;
/* Inherit some settings for rulepat{} from global{}. */
STAILQ_FOREACH(rulepat, &rulepats_list, link) {
if (rulepat->check_next_rulepat <= 0) {
rulepat->check_next_rulepat = 0;
if (rulepat->update_tevent == NULL)
rulepat->update_tevent = global_update_tevent;
if (rulepat->append_tevent == NULL)
rulepat->append_tevent = global_append_tevent;
if (rulepat->worktime == NULL)
rulepat->worktime = global_worktime;
if (rulepat->ac_list == NULL)
rulepat->ac_list = global_ac_list;
if (rulepat->db_list == NULL)
rulepat->db_list = global_db_list;
if (rulepat->debug_exec < 0)
rulepat->debug_exec = global_debug_exec;
#ifdef CTL_CHECK_CREDS
if (rulepat->ctl_rule_acl == NULL)
rulepat->ctl_rule_acl = global_ctl_rule_acl;
#endif
#ifdef WITH_LIMITS
if (rulepat->debug_limit < 0)
rulepat->debug_limit = global_debug_limit;
if (rulepat->debug_limit_init < 0)
rulepat->debug_limit_init = global_debug_limit_init;
STAILQ_FOREACH(limit, &rulepat->limits, link) {
inherit_limit_from_global(limit);
set_sync_exec_in_limit(limit);
}
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
if (rulepat->debug_threshold < 0)
rulepat->debug_threshold = global_debug_threshold;
if (rulepat->debug_threshold_init < 0)
rulepat->debug_threshold_init = global_debug_threshold_init;
STAILQ_FOREACH(threshold, &rulepat->thresholds, link) {
if (inherit_threshold_from_global("rulepat",
rulepat->pat, threshold) < 0)
goto parsing_failed;
set_sync_exec_in_threshold(threshold);
}
#endif /* WITH_THRESHOLDS */
}
set_sync_exec_in_rulepat(rulepat);
}
}
#ifdef WITH_AUTORULES
STAILQ_INIT(&autorules_list);
if (nautorules != 0) {
const struct ac_list *ac_list;
marray_minimize(autorules_marray);
for (autorule = autorules; autorule < autorules + nautorules; ++autorule) {
STAILQ_INSERT_TAIL(&autorules_list, autorule, link);
ac_list = autorule->ac_list != NULL ? autorule->ac_list : global_ac_list;
if (ac_list != NULL && !STAILQ_EMPTY(ac_list))
if (STAILQ_NEXT(STAILQ_FIRST(ac_list), link) != NULL) {
conferrx("autorule %s: only one accounting system can be used in autorule",
autorule->arule_name);
goto parsing_failed;
}
if (mimic_real_config) {
/* Inherit some settings for autorule{} from global{}. */
if (autorule->ac_list == NULL) {
autorule->ac_list = global_ac_list;
ac_inc_ref_count(global_ac_list);
}
if (autorule->update_tevent == NULL)
autorule->update_tevent = global_update_tevent;
if (autorule->worktime == NULL)
autorule->worktime = global_worktime;
set_sync_exec_in_autorule(autorule);
}
# ifdef WITH_LIMITS
STAILQ_FOREACH(limit, &autorule->limits, link) {
if (check_worktime_subset(autorule->worktime_rule, limit->worktime) < 0) {
conferrx("autorule %s, limit %s: limit's worktime must be a subset of autorule's worktime_rule",
autorule->arule_name, limit->limit_name);
goto parsing_failed;
}
if (mimic_real_config) {
inherit_limit_from_global(limit);
set_sync_exec_in_limit(limit);
}
}
# endif /* WITH_LIMITS */
# ifdef WITH_THRESHOLDS
STAILQ_FOREACH(threshold, &autorule->thresholds, link) {
if (check_worktime_subset(autorule->worktime_rule, threshold->worktime) < 0) {
conferrx("autorule %s, threshold %s: threshold's worktime must be a subset of autorule's worktime_rule",
autorule->arule_name, threshold->threshold_name);
goto parsing_failed;
}
if (mimic_real_config) {
if (inherit_threshold_from_global("autorule",
autorule->arule_name, threshold) < 0)
goto parsing_failed;
set_sync_exec_in_threshold(threshold);
}
}
# endif /* WITH_THRESHOLDS */
}
} else
marray_deinit(autorules_marray);
#endif /* WITH_AUTORULES */
#ifdef WITH_RULES
/* Init ac_gather_rev_mzone, needed only if there are static rules. */
if (!SLIST_EMPTY(&ac_gather_list)) {
if ( (ac_gather_rev_mzone = mzone_init(MZONE_NAME(ac_gather_rev), "Reverse ac_gather", 0,
sizeof(struct ac_gather_rev), AC_GATHER_REV_NSIZE, AC_GATHER_REV_NALLOC)) == NULL)
goto parsing_failed;
has_ac_gather = 1;
} else {
ac_gather_rev_mzone = NULL;
has_ac_gather = 0;
}
TAILQ_FOREACH(rule, &rules_list, list) {
if (init_ac_gather_rev(rule) < 0)
goto parsing_failed;
STAILQ_FOREACH(rulepat, &rulepats_list, link)
if (regexec(&rulepat->reg, rule->rule_name, 0, (regmatch_t *)NULL, 0) == 0) {
# ifdef WITH_RULES
rule_wt = rule->worktime != NULL ? rule->worktime : rulepat->worktime;
# endif
if (mimic_real_config) {
/* Inherit some settings for rule{} from rulepat{}. */
if (rule->update_tevent == NULL)
rule->update_tevent = rulepat->update_tevent;
if (rule->append_tevent == NULL)
rule->append_tevent = rulepat->append_tevent;
rule->worktime = rule_wt;
if (rule->ac_list == NULL)
if ( (rule->ac_list = rulepat->ac_list) != NULL)
ac_inc_ref_count(rule->ac_list);
if (rule->db_list == NULL)
rule->db_list = rulepat->db_list;
if (rule->debug_exec < 0)
rule->debug_exec = rulepat->debug_exec;
# ifdef WITH_LIMITS
if (rule->debug_limit < 0)
rule->debug_limit = rulepat->debug_limit;
if (rule->debug_limit_init < 0)
rule->debug_limit_init = rulepat->debug_limit_init;
# endif
# ifdef WITH_THRESHOLDS
if (rule->debug_threshold < 0)
rule->debug_threshold = rulepat->debug_threshold;
if (rule->debug_threshold_init < 0)
rule->debug_threshold_init = rulepat->debug_threshold_init;
# endif
# ifdef CTL_CHECK_CREDS
if (rule->ctl_rule_acl == NULL)
rule->ctl_rule_acl = rulepat->ctl_rule_acl;
# endif
if (mod_conf_inherit(rulepat, rule) < 0) {
conferrx("configure: mod_conf_inherit failed");
goto parsing_failed;
}
}
if (mimic_real_config || mode == CMD_PARSING) {
if (rule->rc[RC_STARTUP].set == 0 && rulepat->rc[RC_STARTUP].set != 0) {
if (copy_cmds_rule(rule, &rule->rc[RC_STARTUP], &rulepat->rc[RC_STARTUP]) < 0) {
conferrx("rule %s: cannot copy all commands from rulepat %s { startup {}}",
rule->rule_name, parser_buf_to_string(rulepat->pat));
goto parsing_failed;
}
rule->rc[RC_STARTUP].set = 1;
}
if (rule->rc[RC_SHUTDOWN].set == 0 && rulepat->rc[RC_SHUTDOWN].set != 0) {
if (copy_cmds_rule(rule, &rule->rc[RC_SHUTDOWN], &rulepat->rc[RC_SHUTDOWN]) < 0) {
conferrx("rule %s: cannot copy all commands from rulepat %s { shutdown {}}",
rule->rule_name, parser_buf_to_string(rulepat->pat));
goto parsing_failed;
}
rule->rc[RC_SHUTDOWN].set = 1;
}
#ifdef WITH_LIMITS
if (STAILQ_EMPTY(&rule->limits) && !STAILQ_EMPTY(&rulepat->limits)) {
if (copy_limits(rule, &rulepat->limits, 0) < 0) {
conferrx("rule %s: cannot copy all limits from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
goto parsing_failed;
}
rule->free_mask &= ~RULE_FREE_LIMITS;
}
#endif
#ifdef WITH_THRESHOLDS
if (STAILQ_EMPTY(&rule->thresholds) && !STAILQ_EMPTY(&rulepat->thresholds)) {
if (copy_thresholds(rule, &rulepat->thresholds, 0) < 0) {
conferrx("rule %s: cannot copy all thresholds from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
goto parsing_failed;
}
rule->free_mask &= ~RULE_FREE_THRESHOLDS;
}
#endif
}
if (rulepat->check_next_rulepat == 0)
break;
}
if (rulepat == NULL) {
# ifdef WITH_RULES
rule_wt = rule->worktime != NULL ? rule->worktime : global_worktime;
# endif
if (mimic_real_config) {
/* Inherit some settings for rule{} from global{}. */
if (rule->update_tevent == NULL)
rule->update_tevent = global_update_tevent;
if (rule->append_tevent == NULL)
rule->append_tevent = global_append_tevent;
rule->worktime = rule_wt;
if (rule->ac_list == NULL) {
rule->ac_list = global_ac_list;
ac_inc_ref_count(rule->ac_list);
}
if (rule->db_list == NULL)
rule->db_list = global_db_list;
if (rule->debug_exec < 0)
rule->debug_exec = global_debug_exec;
# ifdef WITH_LIMITS
if (rule->debug_limit < 0)
rule->debug_limit = global_debug_limit;
if (rule->debug_limit_init < 0)
rule->debug_limit_init = global_debug_limit_init;
# endif
# ifdef WITH_THRESHOLDS
if (rule->debug_threshold < 0)
rule->debug_threshold = global_debug_threshold;
if (rule->debug_threshold_init < 0)
rule->debug_threshold_init = global_debug_threshold_init;
# endif
# ifdef CTL_CHECK_CREDS
if (rule->ctl_rule_acl == NULL)
rule->ctl_rule_acl = global_ctl_rule_acl;
# endif
set_sync_exec_in_rule(rule);
}
}
# ifdef WITH_LIMITS
STAILQ_FOREACH(limit, &rule->limits, link) {
if (check_worktime_subset(rule_wt, limit->worktime) < 0) {
conferrx("rule %s, limit %s: limit's worktime must be a subset of rule's worktime",
rule->rule_name, limit->limit_name);
goto parsing_failed;
}
if (mimic_real_config) {
if (rule->free_mask & RULE_FREE_LIMITS) {
/* Limits were not copied from rulepat. */
inherit_limit_from_global(limit);
set_sync_exec_in_limit(limit);
}
if (limit->worktime == NULL)
limit->worktime = rule->worktime;
if (limit->db_list == NULL)
limit->db_list = rule->db_list;
}
}
# endif /* WITH_LIMITS */
# ifdef WITH_THRESHOLDS
STAILQ_FOREACH(threshold, &rule->thresholds, link) {
if (check_worktime_subset(rule_wt, threshold->worktime) < 0) {
conferrx("rule %s, threshold %s: threshold's worktime must be a subset of rule's worktime",
rule->rule_name, threshold->threshold_name);
goto parsing_failed;
}
if (mimic_real_config) {
if (rule->free_mask & RULE_FREE_THRESHOLDS) {
/* Thresholds were not copied from rulepat. */
if (inherit_threshold_from_global("rule",
rule->rule_name, threshold) < 0)
goto parsing_failed;
set_sync_exec_in_threshold(threshold);
}
if (threshold->worktime == NULL)
threshold->worktime = rule->worktime;
if (threshold->db_list == NULL)
threshold->db_list = rule->db_list;
}
}
# endif /* WITH_THRESHOLDS */
}
if (ac_gather_rev_mzone != NULL) {
if (mzone_is_empty(ac_gather_rev_mzone)
#ifdef WITH_AUTORULES
&& nautorules == 0
#endif
) {
mzone_deinit(ac_gather_rev_mzone);
ac_gather_rev_mzone = NULL;
}
}
#endif /* WITH_RULES */
if (real_config || mimic_real_config) {
for (debug_param = common_debug_param; debug_param->param_name != NULL; ++debug_param)
if (*debug_param->param_value < 0)
*debug_param->param_value = 0;
if (ctl_enable < 0)
ctl_enable = 0;
if (ctl_socket_path == NULL)
ctl_socket_path = ctl_socket_path_default;
if (ctl_socket_perm == 0)
ctl_socket_perm = CTL_SOCKET_PERM_DEF;
if (ctl_timeout == 0)
ctl_timeout = CTL_TIMEOUT_DEF;
}
if (real_config)
logmsgx(IPA_LOG_INFO, "loaded %u autorule(s), %u static rule(s), %u limit(s), %u sublimit(s), %u threshold(s)",
nautorules, nstatrules, nstatlimits, nstatsublimits, nstatthresholds);
mvlogmsgx = mvlogmsgx_wrapper;
xvlogmsgx = vlogmsgx;
return 0;
section_not_expected:
logconferrx("this section is not expected here");
parsing_failed:
conferrx("configuration file(s) parsing failed!");
return -1;
}
/*
* Unload all modules and free memory used by structures which
* describe loaded modules. Note that any pointer should not references
* any data in unloaded modules' memory. So, the best place when
* to call this function: after memfunc_deinit() and before checking
* amount of not freed memory.
*/
static int
unload_all_mods(void)
{
struct ac_mod *ac_mod, *ac_mod_next;
struct db_mod *db_mod, *db_mod_next;
for (ac_mod = SLIST_FIRST(&ac_mod_list); ac_mod != NULL; ac_mod = ac_mod_next) {
ac_mod_next = SLIST_NEXT(ac_mod, link);
if (dl_close(ac_mod->mod_handle) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: dl_close failed: %s",
ac_mod->mod_file, dl_error());
return -1;
}
mem_free(ac_mod->mod_file, m_parser);
mem_free(ac_mod, m_anon);
}
for (db_mod = SLIST_FIRST(&db_mod_list); db_mod != NULL; db_mod = db_mod_next) {
db_mod_next = SLIST_NEXT(db_mod, link);
if (dl_close(db_mod->mod_handle) < 0) {
logmsgx(IPA_LOG_ERR, "module %s: dl_close failed: %s",
db_mod->mod_file, dl_error());
return -1;
}
mem_free(db_mod->mod_file, m_parser);
mem_free(db_mod, m_anon);
}
return 0;
}
/*
* Free all resources allocated during work.
*/
int
free_all(void)
{
u_int n;
if (shell_path != shell_path_default)
mem_free(shell_path, m_parser);
if (shell_arg1 != shell_arg1_default)
mem_free(shell_arg1, m_parser);
free_rules();
if (!TAILQ_EMPTY(&rules_list)) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: rules_list is not empty");
return -1;
}
if (!TAILQ_EMPTY_HEAD_VALID(&rules_list)) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: empty rules_list list is in inconsistent state");
return -1;
}
if (!rules_hash_is_empty()) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: rules_hash is not empty");
return -1;
}
if ( (n = mzone_nused(rule_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: rule_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(rule_mzone);
free_rulepats();
#ifdef WITH_LIMITS
if (limit_mzone != NULL) {
if ( (n = mzone_nused(limit_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: limit_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(limit_mzone);
}
#endif
#ifdef WITH_SUBLIMITS
if (sublimit_mzone != NULL) {
if ( (n = mzone_nused(sublimit_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: sublimit_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(sublimit_mzone);
}
#endif
#ifdef WITH_THRESHOLDS
if (threshold_mzone != NULL) {
if ( (n = mzone_nused(threshold_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: threshold_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(threshold_mzone);
}
#endif
mzone_deinit(tevent_mzone);
free_cmd_list(&cmds_startup);
free_cmd_list(&cmds_shutdown);
if (cmd_mzone != NULL) {
if ( (n = mzone_nused(cmd_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: cmd_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(cmd_mzone);
}
free_worktimes();
#ifdef WITH_RULES
if (ac_gather_rev_mzone != NULL) {
if ( (n = mzone_nused(ac_gather_rev_mzone)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: free_all: ac_gather_rev_mzone is not empty: %u", n);
return -1;
}
mzone_deinit(ac_gather_rev_mzone);
}
#endif
free_ac_lists();
free_db_lists();
mem_free(tdiff_buf, m_anon);
mem_free(parser_str_buf, m_parser);
tdiff_buf = parser_str_buf = NULL;
#ifdef WITH_ANY_LIMITS
mem_free(ipa_tm_buf, m_anon);
ipa_tm_buf = NULL;
#endif
memfunc_deinit_1(0);
if (unload_all_mods() < 0) {
logmsgx(IPA_LOG_ERR, "free_all: cannot correctly unload all modules");
return -1;
}
memfunc_deinit_2(0);
return 0;
}
/*
* Reconfiguring routine.
*/
int
reconfigure(void)
{
int error = 0;
logmsgx(IPA_LOG_INFO, "deiniting old configuration...");
if (deinit_all() < 0) {
logmsgx(IPA_LOG_ERR, "reconfigure: deinit_all failed");
error = 1;
}
if (!TAILQ_EMPTY(&rules_active)) {
logmsgx(IPA_LOG_ERR, "internal error: reconfigure: rules_active is not empty");
return -1;
}
if (!TAILQ_EMPTY_HEAD_VALID(&rules_active)) {
logmsgx(IPA_LOG_ERR, "internal error: reconfigure: empty rules_active list is in inconsistent state");
return -1;
}
if (!TAILQ_EMPTY(&rules_inactive)) {
logmsgx(IPA_LOG_ERR, "internal error: reconfigure: rules_inactive is not empty");
return -1;
}
if (!TAILQ_EMPTY_HEAD_VALID(&rules_inactive)) {
logmsgx(IPA_LOG_ERR, "internal error: reconfigure: empty rules_inactive list is in inconsistent state");
return -1;
}
#ifdef WITH_ANY_LIMITS
if (!wpid_hash_is_empty()) {
logmsgx(IPA_LOG_ERR, "internal error: reconfigure: wpid_hash is not empty");
return -1;
}
#endif
if (free_all() < 0) {
logmsgx(IPA_LOG_ERR, "reconfigure: free_all failed");
error = 1;
}
if (error)
return -1;
logmsgx(IPA_LOG_INFO, "-----------------------------------------------------");
logmsgx(IPA_LOG_INFO, "rereading configuration file...");
if (configure(RECONFIG_PARSING) < 0) {
logmsgx(IPA_LOG_ERR, "reconfigure: configure failed");
return -1;
}
logmsgx(IPA_LOG_INFO, "using new configuration");
return 0;
}
static void
print_time_u_int(u_int a)
{
const uint64_t t = a;
print_time(&t);
}
static void
show_cmd_list(const struct cmd_list *cmdl, int indent)
{
const struct cmd *cmd;
if (cmdl->sync_exec >= 0) {
printf("%*s%*s%*ssync_exec = ", conf_indent, "", indent, "",
CONF_INDENT, "");
print_boolean(cmdl->sync_exec);
print_eol();
}
STAILQ_FOREACH(cmd, &cmdl->list, link) {
printf("%*s%*s%*sexec ", conf_indent, "", indent, "",
CONF_INDENT, "");
if (cmd->user != NULL)
printf("%s ", cmd->user);
print_string(cmd->str);
print_eol();
}
}
static void
show_commands(const struct cmd_list *cmd_list, const char *sect_name)
{
if (!STAILQ_EMPTY(&cmd_list->list)) {
printf("%*s%s {\n", conf_indent, "", sect_name);
show_cmd_list(cmd_list, 0);
printf("%*s}\n", conf_indent, "");
}
}
static void
show_rule_rc(const struct cmds_rule *rc)
{
int x;
for (x = 0; x < 2; ++rc, ++x)
if (rc->set != 0) {
printf("%*s%s {\n", CONF_INDENT, "",
x == RC_STARTUP ? "startup" : "shutdown");
if (!STAILQ_EMPTY(&rc->cmdl.list))
show_cmd_list(&rc->cmdl, 0);
#ifdef WITH_LIMITS
if (!STAILQ_EMPTY(&rc->cmdl_if_all_reached.list)) {
printf("%*sif_all_reached {\n", 2 * CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_all_reached, CONF_INDENT);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
if (!STAILQ_EMPTY(&rc->cmdl_if_all_not_reached.list)) {
printf("%*sif_all_not_reached {\n", 2 * CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_all_not_reached, CONF_INDENT);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
if (!STAILQ_EMPTY(&rc->cmdl_if_any_reached.list)) {
printf("%*sif_any_reached {\n", 2 * CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_any_reached, CONF_INDENT);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
if (!STAILQ_EMPTY(&rc->cmdl_if_any_not_reached.list)) {
printf("%*sif_any_not_reached {\n", 2 * CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_any_not_reached, CONF_INDENT);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
#endif /* WITH_LIMITS */
printf("%*s}\n", CONF_INDENT, "");
}
}
static void
show_generic_worktime(const struct worktime *wt, const char *param_name)
{
u_int wday;
const char *wday_char;
const struct tint *tint;
const struct tint_list *list;
if (wt == NULL)
return;
wday_char = "SMTWHFA";
printf("%*s%s =", conf_indent, "", param_name);
for (wday = 0; wday < DAYS_IN_WEEK; ++wday_char, ++wday) {
list = wt->tint_list[wday];
if (!STAILQ_EMPTY(list)) {
printf(" %c", *wday_char);
tint = STAILQ_FIRST(list);
if (tint->sec1 == 0 && tint->sec2 == SECONDS_IN_DAY)
printf(" *");
else
for (; tint != NULL; tint = STAILQ_NEXT(tint, link)) {
printf(" ");
printf(tint_to_buf(tint));
}
}
}
print_eol();
}
/*
* Output "worktime" parameter.
*/
static void
show_worktime(const struct worktime *wt)
{
show_generic_worktime(wt, "worktime");
}
static void
mod_conf_show(u_int sect_id, u_int no)
{
const struct ac_mod *ac_mod;
const struct db_mod *db_mod;
need_nl = 0;
SLIST_FOREACH(ac_mod, &ac_mod_list, link)
ac_mod->ipa_ac_mod->conf_show(sect_id, no);
if (sect_id == IPA_CONF_SECT_ROOT)
print_nl();
SLIST_FOREACH(db_mod, &db_mod_list, link)
db_mod->ipa_db_mod->conf_show(sect_id, no);
if (sect_id == IPA_CONF_SECT_ROOT)
print_nl();
}
static void
show_ac_list(const struct ac_list *list)
{
const struct ac_elem *ac;
if (list != NULL) {
printf("%*sac_list =", CONF_INDENT, "");
if (list != &ac_list_null)
STAILQ_FOREACH(ac, list, link)
printf(" %s", ac->ipa_ac_mod->ac_name);
else
printf(" null");
print_eol();
}
}
static void
show_db_list(const struct db_list *list)
{
const struct db_elem *db;
if (list != NULL) {
printf("%*sdb_list =", conf_indent, "");
if (list != &db_list_null)
STAILQ_FOREACH(db, list, link)
printf(" %s", db->ipa_db_mod->db_name);
else
printf(" null");
print_eol();
}
}
#if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
static void
print_info(const char *info)
{
if (info != NULL) {
printf("%*sinfo = ", conf_indent, "");
print_string(info);
print_eol();
}
}
#endif /* WITH_RULES || WITH_ANY_LIMITS */
#ifdef WITH_RULES
static void
show_ac_gather_xxx(const char *pat, const char *param_name)
{
if (pat != NULL) {
printf("%*s%s = ", CONF_INDENT, "", param_name);
print_string(pat);
print_eol();
}
}
#endif /* WITH_RULES */
#ifdef WITH_LIMITS
/*
* Convert expired time to human readable string.
*/
static void
print_texp(const struct texp *texp)
{
u_int t, a = texp->seconds;
if (texp->upto != TEXP_UPTO_SIMPLE && texp->side == 0)
printf(" +%c", texp->upto);
t = a / SECONDS_IN_DAY;
if (t != 0) {
printf(" %dD", t);
a -= t * SECONDS_IN_DAY;
}
if (a != 0 || (a == 0 && texp->upto == TEXP_UPTO_SIMPLE)) {
printf(" ");
print_time_u_int(a);
}
if (texp->upto != TEXP_UPTO_SIMPLE && texp->side == 1)
printf(" +%c", texp->upto);
}
static void
show_limit_rc(const struct cmds_limit *rc)
{
int x;
for (x = 0; x < 2; ++rc, ++x)
if (rc->set != 0) {
printf("%*s%s {\n", conf_indent, "", x == RC_STARTUP ? "startup" : "shutdown" );
if (!STAILQ_EMPTY(&rc->cmdl.list))
show_cmd_list(&rc->cmdl, 0);
if (!STAILQ_EMPTY(&rc->cmdl_if_reached.list)) {
printf("%*s%*sif_reached {\n", conf_indent, "", CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_reached, CONF_INDENT);
printf("%*s%*s}\n", conf_indent, "", CONF_INDENT, "");
}
if (!STAILQ_EMPTY(&rc->cmdl_if_not_reached.list)) {
printf("%*s%*sif_not_reached {\n", conf_indent, "", CONF_INDENT, "");
show_cmd_list(&rc->cmdl_if_not_reached, CONF_INDENT);
printf("%*s%*s}\n", conf_indent, "", CONF_INDENT, "");
}
printf("%*s}\n", conf_indent, "");
}
}
static void
show_reach_sect(const struct cmd_list *cmdl)
{
if (!STAILQ_EMPTY(&cmdl->list)) {
printf("%*sreach {\n", conf_indent, "");
show_cmd_list(cmdl, 0);
printf("%*s}\n", conf_indent, "");
}
}
static void
show_load_limit(int val)
{
if (val >= 0) {
printf("%*sload_limit = ", conf_indent, "");
print_boolean(val);
print_eol();
}
}
static void
show_limits(const struct limits_list *list)
{
const struct limit *limit;
#ifdef WITH_SUBLIMITS
const struct sublimit *sublimit;
#endif
STAILQ_FOREACH(limit, list, link) {
conf_indent = 2 * CONF_INDENT;
printf("%*slimit %s {\n", CONF_INDENT, "", limit->limit_name);
show_db_list(limit->db_list);
print_info(limit->limit_info);
printf("%*slimit = ", 2 * CONF_INDENT, "");
print_value(&limit->lim, limit->cnt_type);
print_eol();
show_load_limit(limit->load_limit);
show_worktime(limit->worktime);
if (limit->restart.restart.upto != TEXP_UPTO_NOTSET) {
printf("%*srestart {\n%*srestart =", 2 * CONF_INDENT, "", 3 * CONF_INDENT, "");
print_texp(&limit->restart.restart);
print_eol();
show_cmd_list(&limit->restart.cmdl, 0);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
show_reach_sect(&limit->reach);
if (limit->expire.expire.upto != TEXP_UPTO_NOTSET) {
printf("%*sexpire {\n%*sexpire =", 2 * CONF_INDENT, "", 3 * CONF_INDENT, "");
print_texp(&limit->expire.expire);
print_eol();
show_cmd_list(&limit->expire.cmdl, 0);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
mod_conf_show(IPA_CONF_SECT_LIMIT, limit->limitno);
show_limit_rc(limit->rc);
# ifdef WITH_SUBLIMITS
conf_indent = 3 * CONF_INDENT;
STAILQ_FOREACH(sublimit, &limit->sublimits, link) {
printf("%*ssublimit ", 2 * CONF_INDENT, "");
if (sublimit->lim_per_cent != 0)
printf("%u%%", sublimit->lim_per_cent);
else
print_value(&sublimit->lim, sublimit->cnt_type);
printf(" {\n");
show_reach_sect(&sublimit->reach);
show_limit_rc(sublimit->rc);
printf("%*s}\n", 2 * CONF_INDENT, "");
}
# endif /* WITH_SUBLIMITS */
printf("%*s}\n", CONF_INDENT, "");
}
}
#endif /* WITH_LIMITS */
#ifdef WITH_THRESHOLDS
static void
show_load_threshold(int val)
{
if (val >= 0) {
printf("%*sload_threshold = ", conf_indent, "");
print_boolean(val);
print_eol();
}
}
static void
show_threshold_type(int val)
{
if (val >= 0) {
printf("%*sthreshold_type = %d", conf_indent, "", val);
print_eol();
}
}
static void
show_threshold_time_width(u_int val)
{
if (val != 0) {
printf("%*sthreshold_time_width = ", conf_indent, "");
print_time_u_int(val);
print_eol();
}
}
static void
show_threshold_time_slice(const struct tevent *tevent)
{
if (tevent != NULL) {
printf("%*sthreshold_time_slice = ", conf_indent, "");
print_time_u_int(tevent->event_step);
print_eol();
}
}
static void
show_threshold_balance(u_int a, u_int b, u_int c)
{
if (a != 0) {
printf("%*sthreshold_balance = ", conf_indent, "");
if (a != UINT_MAX)
printf("%u:", a);
else
printf("-:");
if (b != UINT_MAX)
printf("%u:", b);
else
printf("-:");
if (c != UINT_MAX)
printf("%u", c);
else
printf("-");
print_eol();
}
}
static void
show_thresholds(const struct thresholds_list *list)
{
const struct threshold *threshold;
conf_indent = 2 * CONF_INDENT;
STAILQ_FOREACH(threshold, list, link) {
printf("%*sthreshold %s {\n", CONF_INDENT, "", threshold->threshold_name);
show_db_list(threshold->db_list);
print_info(threshold->threshold_info);
printf("%*sthreshold = ", 2 * CONF_INDENT, "");
print_value(&threshold->thr, threshold->cnt_type);
print_eol();
if (threshold->thr_dev != 0) {
printf("%*sthreshold_deviation = ", 2 * CONF_INDENT, "");
if (threshold->thr_dev_per_cent != 0)
printf("%u%%", threshold->thr_dev_per_cent);
else
print_value(&threshold->thr_dev, threshold->cnt_type);
print_eol();
}
show_threshold_type(threshold->threshold_type);
show_threshold_balance(threshold->below_lim,
threshold->equal_lim, threshold->above_lim);
show_load_threshold(threshold->load_threshold);
show_worktime(threshold->worktime);
show_threshold_time_width(threshold->time_width);
show_threshold_time_slice(threshold->time_slice);
mod_conf_show(IPA_CONF_SECT_THRESHOLD, threshold->thresholdno);
show_commands(&threshold->rc[RC_STARTUP], "startup");
show_commands(&threshold->rc[RC_SHUTDOWN], "shutdown");
show_commands(&threshold->below_threshold, "below_threshold");
show_commands(&threshold->equal_threshold, "equal_threshold");
show_commands(&threshold->above_threshold, "above_threshold");
printf("%*s}\n", CONF_INDENT, "");
}
}
#endif /* WITH_THRESHOLDS */
static void
show_ctl_socket_perm(void)
{
if (ctl_socket_perm != 0) {
printf("ctl_socket_perm = ");
if (ctl_socket_perm & S_IWUSR)
printf("u");
if (ctl_socket_perm & S_IWGRP)
printf("g");
#ifdef CTL_CHECK_CREDS
if (ctl_socket_perm & S_IWOTH)
printf("o");
#endif
print_eol();
}
}
#ifdef CTL_CHECK_CREDS
static void
show_ctl_xxx_acl(const struct ctl_acl_class *class, const char *param_name)
{
if (class != NULL)
printf("%*s%s = %s;\n", conf_indent, "", param_name, class->class_name);
}
static void
show_ctl_rule_acl(const struct ctl_acl_class *class)
{
show_ctl_xxx_acl(class, "ctl_rule_acl");
}
static void
show_ctl_acl_classes(void)
{
const struct ctl_acl_elem *elem;
const struct ctl_acl_class *class;
STAILQ_FOREACH(class, &ctl_acl_classes, link) {
printf("ctl_acl_class = %s", class->class_name);
STAILQ_FOREACH(elem, &class->list, link) {
if (elem->allowed)
printf(" ");
else
printf(" !");
if (elem->user != NULL)
printf("%s", elem->user);
else
printf("%%%s", elem->group);
}
print_eol();
need_nl = 1;
}
}
#endif /* CTL_CHECK_CREDS */
static void
show_update_time(const struct tevent *tevent)
{
if (tevent != NULL) {
printf("%*supdate_time = ", conf_indent, "");
print_time_u_int(tevent->event_step);
print_eol();
}
}
static void
show_append_time(const struct tevent *tevent)
{
if (tevent != NULL) {
printf("%*sappend_time = ", conf_indent, "");
print_time_u_int(tevent->event_step);
print_eol();
}
}
/*
* Main function for outputting indented configuration file.
*/
void
show_config(void)
{
#ifdef WITH_RULES
const struct rule *rule;
#endif
#ifdef WITH_AUTORULES
const struct autorule *autorule;
#endif
const struct rulepat *rulepat;
const struct ac_mod *ac_mod;
const struct db_mod *db_mod;
const struct time_param *time_param;
const struct debug_param *debug_param;
printf("\
/*\n\
* This output is not identical to the original content of the configuration\n\
* file(s), this is just how ipa(8) and IPA modules see their configurations.\n\
* Any \"include\" or \"include_files\" parameters are not printed and all\n\
* macro variables are expanded.\n\
*/\n\n");
if (mimic_real_config)
printf("/* Mimic real configuration regime. */\n\n");
conf_indent = mod_indent = 0;
SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
printf("ac_mod ");
print_string(ac_mod->mod_file);
print_eol();
need_nl = 1;
}
SLIST_FOREACH(db_mod, &db_mod_list, link) {
printf("db_mod ");
print_string(db_mod->mod_file);
print_eol();
need_nl = 1;
}
print_nl();
for (debug_param = common_debug_param; debug_param->param_name != NULL; ++debug_param)
if (*debug_param->param_value >= 0) {
printf("%s = %d;\n", debug_param->param_name, *debug_param->param_value);
need_nl = 1;
}
print_nl();
if (shell_path != NULL) {
printf("shell_path = ");
print_string(shell_path);
print_eol();
need_nl = 1;
}
if (shell_arg1 != NULL) {
printf("shell_arg1 = ");
print_string(shell_arg1);
print_eol();
need_nl = 1;
}
print_nl();
if (posix_re_pattern >= 0) {
printf("posix_re_pattern = ");
print_boolean(posix_re_pattern);
print_eol();
need_nl = 1;
}
print_nl();
for (time_param = common_time_param; time_param->param_name != NULL; ++time_param)
if (*time_param->param_value > 0) {
printf("%s = ", time_param->param_name);
print_time_u_int(*time_param->param_value);
print_eol();
need_nl = 1;
}
print_nl();
if (only_abs_paths >= 0) {
printf("only_abs_paths = ");
print_boolean(only_abs_paths);
print_eol();
need_nl = 1;
}
print_nl();
if (keep_rules_order >= 0) {
printf("keep_rules_order = ");
print_boolean(keep_rules_order);
print_eol();
need_nl = 1;
}
print_nl();
if (ctl_enable >= 0) {
printf("ctl_enable = ");
print_boolean(ctl_enable);
print_eol();
need_nl = 1;
}
if (ctl_socket_path != NULL) {
printf("ctl_socket_path = ");
print_string(ctl_socket_path);
print_eol();
need_nl = 1;
}
if (ctl_timeout != 0) {
printf("ctl_timeout = ");
print_time_u_int(ctl_timeout);
print_eol();
need_nl = 1;
}
show_ctl_socket_perm();
#ifdef CTL_CHECK_CREDS
show_ctl_acl_classes();
show_ctl_xxx_acl(ctl_dump_acl, "ctl_dump_acl");
show_ctl_xxx_acl(ctl_freeze_acl, "ctl_freeze_acl");
show_ctl_xxx_acl(ctl_stat_acl, "ctl_stat_acl");
#endif
print_nl();
mod_conf_show(IPA_CONF_SECT_ROOT, 0);
if (!STAILQ_EMPTY(&cmds_startup.list)) {
show_commands(&cmds_startup, "startup");
printf("\n");
}
if (!STAILQ_EMPTY(&cmds_shutdown.list)) {
show_commands(&cmds_shutdown, "shutdown");
printf("\n");
}
if (global_section_set) {
conf_indent = CONF_INDENT;
printf("global {\n");
show_ac_list(global_ac_list);
show_db_list(global_db_list);
show_append_time(global_append_tevent);
show_update_time(global_update_tevent);
show_worktime(global_worktime);
#ifdef WITH_LIMITS
show_load_limit(global_load_limit);
#endif
#ifdef WITH_THRESHOLDS
show_threshold_type(global_threshold_type);
show_threshold_balance(global_threshold_below_lim,
global_threshold_equal_lim, global_threshold_above_lim);
show_load_threshold(global_load_threshold);
show_threshold_time_width(global_threshold_time_width);
show_threshold_time_slice(global_threshold_time_slice);
#endif
#ifdef CTL_CHECK_CREDS
show_ctl_rule_acl(global_ctl_rule_acl);
#endif
for (debug_param = global_debug_param; debug_param->param_name != NULL; ++debug_param)
if (*debug_param->param_value >= 0) {
printf("%*s%s = %d;\n", CONF_INDENT, "", debug_param->param_name, *debug_param->param_value);
need_nl = 1;
}
mod_conf_show(IPA_CONF_SECT_GLOBAL, 0);
printf("}\n\n");
}
#ifdef WITH_AUTORULES
STAILQ_FOREACH(autorule, &autorules_list, link) {
conf_indent = CONF_INDENT;
printf("autorule %s {\n", autorule->arule_name);
show_ac_list(autorule->ac_list);
show_db_list(autorule->db_list);
show_append_time(autorule->append_tevent);
show_update_time(autorule->update_tevent);
show_worktime(autorule->worktime);
show_generic_worktime(autorule->worktime_rule, "worktime_rule");
# ifdef CTL_CHECK_CREDS
show_ctl_rule_acl(autorule->ctl_rule_acl);
# endif
mod_conf_show(IPA_CONF_SECT_AUTORULE, autorule->aruleno);
show_rule_rc(autorule->rc);
# ifdef WITH_LIMITS
if (autorule->debug_limit >= 0)
printf("%*sdebug_limit = %d;\n", CONF_INDENT, "",
autorule->debug_limit);
if (autorule->debug_limit_init >= 0)
printf("%*sdebug_limit_init = %d;\n", CONF_INDENT, "",
autorule->debug_limit_init);
show_limits(&autorule->limits);
# endif
# ifdef WITH_THRESHOLDS
if (autorule->debug_threshold >= 0)
printf("%*sdebug_threshold = %d;\n", CONF_INDENT, "",
autorule->debug_threshold);
if (autorule->debug_threshold_init >= 0)
printf("%*sdebug_threshold_init = %d;\n", CONF_INDENT, "",
autorule->debug_threshold_init);
show_thresholds(&autorule->thresholds);
# endif
printf("}\n\n");
}
#endif /* WITH_AUTORULES */
STAILQ_FOREACH(rulepat, &rulepats_list, link) {
conf_indent = CONF_INDENT;
printf("rulepat ");
print_string(rulepat->pat);
printf(" {\n");
if (rulepat->check_next_rulepat >= 0) {
printf("%*scheck_next_rulepat = ", CONF_INDENT, "");
print_boolean(rulepat->check_next_rulepat);
print_eol();
}
show_ac_list(rulepat->ac_list);
show_db_list(rulepat->db_list);
show_append_time(rulepat->append_tevent);
show_update_time(rulepat->update_tevent);
show_worktime(rulepat->worktime);
#ifdef CTL_CHECK_CREDS
show_ctl_rule_acl(rulepat->ctl_rule_acl);
#endif
mod_conf_show(IPA_CONF_SECT_RULEPAT, rulepat->rulepatno);
if (rulepat->debug_exec >= 0)
printf("%*sdebug_exec = %d;\n", CONF_INDENT, "",
rulepat->debug_exec);
show_rule_rc(rulepat->rc);
# ifdef WITH_LIMITS
if (rulepat->debug_limit >= 0)
printf("%*sdebug_limit = %d;\n", CONF_INDENT, "",
rulepat->debug_limit);
if (rulepat->debug_limit_init >= 0)
printf("%*sdebug_limit_init = %d;\n", CONF_INDENT, "",
rulepat->debug_limit_init);
show_limits(&rulepat->limits);
# endif
# ifdef WITH_THRESHOLDS
if (rulepat->debug_threshold >= 0)
printf("%*sdebug_threshold = %d;\n", CONF_INDENT, "",
rulepat->debug_threshold);
if (rulepat->debug_threshold_init >= 0)
printf("%*sdebug_threshold_init = %d;\n", CONF_INDENT, "",
rulepat->debug_threshold_init);
show_thresholds(&rulepat->thresholds);
# endif
printf("}\n\n");
}
#ifdef WITH_RULES
TAILQ_FOREACH(rule, &rules_list, list) {
conf_indent = CONF_INDENT;
printf("rule %s {\n", rule->rule_name);
show_ac_list(rule->ac_list);
show_ac_gather_xxx(rule->ac_gather_add_pat, "ac_gather_add");
show_ac_gather_xxx(rule->ac_gather_sub_pat, "ac_gather_sub");
show_db_list(rule->db_list);
print_info(rule->rule_info);
show_append_time(rule->append_tevent);
show_update_time(rule->update_tevent);
show_worktime(rule->worktime);
# ifdef CTL_CHECK_CREDS
show_ctl_rule_acl(rule->ctl_rule_acl);
# endif
mod_conf_show(IPA_CONF_SECT_RULE, rule->ruleno);
if (rule->debug_exec >= 0)
printf("%*sdebug_exec = %d;\n", CONF_INDENT, "", rule->debug_exec);
show_rule_rc(rule->rc);
# ifdef WITH_LIMITS
if (rule->debug_limit >= 0)
printf("%*sdebug_limit = %d;\n", CONF_INDENT, "", rule->debug_limit);
if (rule->debug_limit_init >= 0)
printf("%*sdebug_limit_init = %d;\n", CONF_INDENT, "", rule->debug_limit_init);
show_limits(&rule->limits);
# endif
# ifdef WITH_THRESHOLDS
if (rule->debug_threshold >= 0)
printf("%*sdebug_threshold = %d;\n", CONF_INDENT, "", rule->debug_threshold);
if (rule->debug_threshold_init >= 0)
printf("%*sdebug_threshold_init = %d;\n", CONF_INDENT, "", rule->debug_threshold_init);
show_thresholds(&rule->thresholds);
# endif
printf("}\n\n");
}
#endif /* WITH_RULES */
}
syntax highlighted by Code2HTML, v. 0.9.1