/*-
* Copyright (c) 2003-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_autorules.c,v 1.2.2.3 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <regex.h>
#include "ipa_mod.h"
#include "ipa_log.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "parser.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_main.h"
#include "ipa_rules.h"
#include "ipa_autorules.h"
u_int nautorules; /* Number of autorules. */
u_int ndynrules; /* Number of dynamic rules. */
#ifdef WITH_AUTORULES
int debug_autorule; /* debug_autorule parameter. */
struct autorule *autorules; /* Array of autorules. */
ipa_marray *autorules_marray; /* Marray of autorules. */
struct autorules_list autorules_list; /* List of all autorules. */
#define AUTORULE(i) &autorules[i] /* Pointer to autorule by number. */
static struct rule **rules_ptr; /* Array of pointers to rules. */
ipa_marray *rules_ptr_marray; /* Marray for array of pointers to rules. */
#define RULE(i) rules_ptr[i] /* Pointer to rule by number. */
u_int autorules_active_check_sec; /* Time when to check active autorules. */
u_int autorules_inactive_check_sec; /* Time when to check inactive autorules. */
static struct autorules_queue autorules_active; /* Active rules queue. */
static struct autorules_queue autorules_inactive; /* Inactive rules queue. */
/*
* Set autorule active or inactive in modules it uses.
*/
static int
mod_set_autorule_active(struct autorule *autorule, int active)
{
if (autorule->is_active == active) {
logmsgx(IPA_LOG_ERR, "internal error: mod_set_autorule_active(%s, %d): autorule is already %s",
autorule->arule_name, active, active_msg[active]);
return -1;
}
if (debug_worktime)
logmsgx(IPA_LOG_INFO, "autorule %s: set autorule %s",
autorule->arule_name, active_msg[active]);
autorule->is_active = active;
if (ac_set_autorule_active(autorule, active) < 0) {
logmsgx(IPA_LOG_INFO, "autorule %s: mod_set_autorule_active: ac_set_autorule_active failed",
autorule->arule_name);
return -1;
}
return 0;
}
static void
show_inactive_autorules(void)
{
const struct autorule *autorule;
logmsgx(IPA_LOG_INFO, "inactive autorules after sorting:");
TAILQ_FOREACH(autorule, &autorules_inactive, queue)
logmsgx(IPA_LOG_INFO, " active %s, autorule %s",
sec_to_buf(autorule->worktime->active_sec), autorule->arule_name);
}
/*
* Move am autorule from the active autorules queue to the inactive
* autorules queue.
*/
static int
set_autorule_inactive(struct autorule *autorule1)
{
struct autorule *autorule2;
/* Inform modules that autorule becomes inactive. */
if (mod_set_autorule_active(autorule1, INACTIVE_FLAG) < 0)
return -1;
/* Remove the autorule from the active autorules queue. */
TAILQ_REMOVE(&autorules_active, autorule1, queue);
/* Add the autorule to the inactive autorules queue, keep that queue sorted. */
TAILQ_FOREACH(autorule2, &autorules_inactive, queue)
if (autorule1->worktime->active_sec < autorule2->worktime->active_sec) {
TAILQ_INSERT_BEFORE(autorule2, autorule1, queue);
goto out;
}
TAILQ_INSERT_TAIL(&autorules_inactive, autorule1, queue);
out:
if (debug_worktime)
show_inactive_autorules();
autorules_inactive_check_sec = TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
return 0;
}
/*
* Move an autorule from the inactive autorules queue to the
* active autorules queue.
*/
static int
set_autorule_active(struct autorule *autorule)
{
/* Inform modules that autorule becomes active. */
if (mod_set_autorule_active(autorule, ACTIVE_FLAG) < 0)
return -1;
/* Remove the autorule from the inactive autorules queue. */
TAILQ_REMOVE(&autorules_inactive, autorule, queue);
/* Add the rule to the active autorules queue. */
TAILQ_INSERT_TAIL(&autorules_active, autorule, queue);
/* Get new value of autorules_inactive_check_sec. */
autorules_inactive_check_sec = TAILQ_EMPTY(&autorules_inactive) ?
SECONDS_IN_WEEK : TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
/* Check if rules_active_check_sec should be modified. */
if (autorules_active_check_sec > autorule->update_tevent->event_sec)
autorules_active_check_sec = autorule->update_tevent->event_sec;
if (autorules_active_check_sec > autorule->worktime->inactive_sec)
autorules_active_check_sec = autorule->worktime->inactive_sec;
return 0;
}
/*
* Sort inactive autorules.
*/
static void
sort_inactive_autorules(void)
{
struct autorule *autorule1, *autorule1_next, *autorule2;
if (TAILQ_EMPTY(&autorules_inactive))
autorules_inactive_check_sec = SECONDS_IN_WEEK;
else {
autorule1 = TAILQ_FIRST(&autorules_inactive);
TAILQ_INIT(&autorules_inactive);
for (; autorule1 != NULL; autorule1 = autorule1_next) {
autorule1_next = TAILQ_NEXT(autorule1, queue);
if (autorule1->worktime->active_sec != SECONDS_IN_WEEK) {
/* Will be active in current day. */
TAILQ_FOREACH(autorule2, &autorules_inactive, queue)
if (autorule1->worktime->active_sec <= autorule2->worktime->active_sec) {
TAILQ_INSERT_BEFORE(autorule2, autorule1, queue);
goto next;
}
}
TAILQ_INSERT_TAIL(&autorules_inactive, autorule1, queue);
next:
;
}
autorules_inactive_check_sec = TAILQ_FIRST(&autorules_inactive)->worktime->active_sec;
}
if (debug_worktime)
show_inactive_autorules();
}
/*
* Make initialization for all autorules.
*/
int
init_autorules(void)
{
struct rule *rule;
struct autorule *autorule;
/* Init autorules queues. */
TAILQ_INIT(&autorules_inactive);
TAILQ_INIT(&autorules_active);
/* Flush number of dynamic rules. */
ndynrules = 0;
if (nautorules != 0) {
/* Init each autorule in accounting modules. */
STAILQ_FOREACH(autorule, &autorules_list, link) {
if (ac_init_autorule(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "autorule %s: init_autorules: ac_init_autorule failed",
autorule->arule_name);
return -1;
}
TAILQ_INSERT_TAIL(&autorules_active, autorule, queue);
}
/* Create rules_ptr_marray. */
if ( (rules_ptr_marray = marray_init(MARRAY_NAME(rules_ptr),
"Pointers to rules", 0, (void *)&rules_ptr, sizeof(struct rule *),
nstatrules + RULE_NSIZE, RULE_NALLOC)) == NULL) {
logmsgx(IPA_LOG_ERR, "init_autorules: marray_init failed");
return -1;
}
/* Mark entries in rules_ptr for static rules as used. */
TAILQ_FOREACH(rule, &rules_list, list)
if (marray_alloc(rules_ptr_marray, &rule->ruleno, 1) < 0) {
logmsgx(IPA_LOG_ERR, "init_autorules: marray_alloc failed");
return -1;
}
}
return 0;
}
/*
* Deinit one autorule.
*/
static int
deinit_autorule(struct autorule *autorule)
{
int error = 0;
/* Deinit in modules. */
if (ac_deinit_autorule(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "autorule %s: deinit_autorule: ac_deinit_autorule failed",
autorule->arule_name);
error = -1;
}
/* Decrement ref_count for accounting systems. */
if (IS_ACTIVE(autorule))
if (ac_dec_ref_count(autorule->ac_list) < 0) {
logmsgx(IPA_LOG_ERR, "autorule %s: deinit_autorule: ac_dec_ref_count failed",
autorule->arule_name);
error = -1;
}
/* And free all memory used by a autorule. */
mem_free(autorule->arule_name, m_anon);
free_cmds_rule(&autorule->rc[RC_STARTUP]);
free_cmds_rule(&autorule->rc[RC_SHUTDOWN]);
#ifdef WITH_LIMITS
free_limits(RULE_FREE_LIMITS, &autorule->limits, 0);
#endif
#ifdef WITH_THRESHOLDS
free_thresholds(RULE_FREE_THRESHOLDS, &autorule->thresholds, 0);
#endif
return error;
}
/*
* Make deinitialization for all autorules.
*/
int
deinit_autorules(void)
{
int error;
u_int n;
struct autorule *autorule;
error = 0;
if (nautorules != 0) {
STAILQ_FOREACH(autorule, &autorules_list, link)
if (deinit_autorule(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "deinit_autorules: deinit_autorule failed");
error = -1;
}
marray_deinit(autorules_marray);
if (ndynrules != 0) {
logmsgx(IPA_LOG_ERR, "internal error: deinit_autorules: ndynrules is not zero: %u", ndynrules);
error = -1;
}
if (rules_ptr_marray != NULL) {
if ( (n = marray_nused(rules_ptr_marray)) != 0) {
logmsgx(IPA_LOG_ERR, "internal error: deinit_autorules: rules_ptr_marray is not empty: %u", n);
error = -1;
}
marray_deinit(rules_ptr_marray);
}
}
return error;
}
/*
* Inherit settings for dynamic rule.
*/
static int
dyn_rule_inherit(const struct autorule *autorule, struct rule *rule)
{
struct rulepat *rulepat;
#ifdef WITH_LIMITS
struct limit *limit;
#endif
#ifdef WITH_THRESHOLDS
struct threshold *threshold;
#endif
/* Inherit settings from autorule{}. */
/* Dynamic rule always inherits non-NULL update_tevent from autorule. */
rule->update_tevent = autorule->update_tevent;
rule->append_tevent = autorule->append_tevent;
rule->worktime = autorule->worktime_rule;
/* Dynamic rule always inherits non-NULL ac_list from autorule. */
rule->ac_list = autorule->ac_list;
ac_inc_ref_count(rule->ac_list);
rule->db_list = autorule->db_list;
#ifdef WITH_RULES
/* Dynamic rules can't have ac_gather_* parameters. */
rule->ac_gather_add_pat = rule->ac_gather_sub_pat = NULL;
SLIST_INIT(&rule->ac_gather_rev);
#endif
rule->debug_exec = autorule->debug_exec;
init_cmds_in_rule(rule);
#ifdef WITH_LIMITS
rule->debug_limit = autorule->debug_limit;
rule->debug_limit_init = autorule->debug_limit_init;
STAILQ_INIT(&rule->limits);
#endif
#ifdef WITH_THRESHOLDS
rule->debug_threshold = autorule->debug_threshold;
rule->debug_threshold_init = autorule->debug_threshold_init;
STAILQ_INIT(&rule->thresholds);
#endif
/*
* free_mask is always zero for dynamic rules, since copy_limits()
* and copy_thresholds() always are called for dynamic rules.
*/
rule->free_mask = 0;
#ifdef CTL_CHECK_CREDS
rule->ctl_rule_acl = autorule->ctl_rule_acl;
#endif
/* Add rule to rules list. */
TAILQ_INSERT_TAIL(&rules_list, rule, list);
/*
* At this point everything is ready in rule for possible
* deinit_dyn_rule() invocation.
*/
/* Inherit other settings from autorule, and we can fail here. */
if (autorule->rc[RC_STARTUP].set != 0) {
if (copy_cmds_rule(rule, &rule->rc[RC_STARTUP], &autorule->rc[RC_STARTUP]) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all commands from autorule %s { startup {}}",
rule->rule_name, autorule->arule_name);
return -1;
}
rule->rc[RC_STARTUP].set = 1;
}
if (autorule->rc[RC_SHUTDOWN].set != 0) {
if (copy_cmds_rule(rule, &rule->rc[RC_SHUTDOWN], &autorule->rc[RC_SHUTDOWN]) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all commands from autorule %s { shutdown {}}",
rule->rule_name, autorule->arule_name);
return -1;
}
rule->rc[RC_SHUTDOWN].set = 1;
}
#ifdef WITH_LIMITS
if (!STAILQ_EMPTY(&autorule->limits))
if (copy_limits(rule, &autorule->limits, 1) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all limits from autorule %s",
rule->rule_name, autorule->arule_name);
return -1;
}
#endif
#ifdef WITH_THRESHOLDS
if (!STAILQ_EMPTY(&autorule->thresholds))
if (copy_thresholds(rule, &autorule->thresholds, 1) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule: cannot copy all thresholds from autorule %s",
rule->rule_name, autorule->arule_name);
return -1;
}
#endif
STAILQ_FOREACH(rulepat, &rulepats_list, link)
if (regexec(&rulepat->reg, rule->rule_name, 0, (regmatch_t *)NULL, 0) == 0) {
/* Inherit some settings for dynamic rule from rulepat{}. */
if (rule->append_tevent == NULL)
rule->append_tevent = rulepat->append_tevent;
if (rule->worktime == NULL)
rule->worktime = rulepat->worktime;
if (rule->db_list == NULL)
rule->db_list = rulepat->db_list;
if (rule->debug_exec < 0)
rule->debug_exec = rulepat->debug_exec;
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) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all commands from rulepat %s { startup {}}",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -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) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all commands from rulepat %s { shutdown {}}",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -1;
}
#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;
if (STAILQ_EMPTY(&rule->limits) && !STAILQ_EMPTY(&rulepat->limits))
if (copy_limits(rule, &rulepat->limits, 1) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all limits from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -1;
}
#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;
if (STAILQ_EMPTY(&rule->thresholds) && !STAILQ_EMPTY(&rulepat->thresholds))
if (copy_thresholds(rule, &rulepat->thresholds, 1) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: cannot copy all thresholds from rulepat %s",
rule->rule_name, parser_buf_to_string(rulepat->pat));
return -1;
}
#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) {
logmsgx(IPA_LOG_ERR, "rule %s: dyn_rule_inherit: mod_conf_inherit failed",
rule->rule_name);
return -1;
}
if (rulepat->check_next_rulepat == 0)
break;
}
if (rulepat == NULL) {
/* Inherit some settings for dynamic rule from global{}. */
if (rule->append_tevent == NULL)
rule->append_tevent = global_append_tevent;
if (rule->worktime == NULL)
rule->worktime = global_worktime;
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)
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
}
#ifdef WITH_LIMITS
STAILQ_FOREACH(limit, &rule->limits, link) {
if (check_worktime_subset(rule->worktime, limit->worktime) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s, limit %s: dyn_rule_inherit: limit's worktime must be a subset of rule's worktime",
rule->rule_name, limit->limit_name);
return -1;
}
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->worktime, threshold->worktime) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: dyn_rule_inherit: threshold's worktime must be a subset of rule's worktime",
rule->rule_name, threshold->threshold_name);
return -1;
}
if (threshold->worktime == NULL)
threshold->worktime = rule->worktime;
if (threshold->db_list == NULL)
threshold->db_list = rule->db_list;
}
#endif /* WITH_THRESHOLDS */
return 0;
}
/*
* Deinit one dynamic rule.
*/
int
deinit_dyn_rule(struct rule *rule)
{
/* Mark rule as unused. */
marray_free(rules_ptr_marray, rule->ruleno);
/* Decrement number of dynamic rules. */
--ndynrules;
if (deinit_rule(rule) < 0) {
logmsgx(IPA_LOG_ERR, "deinit_dyn_rule: deinit_rule failed");
return -1;
}
return 0;
}
/*
* Init one dynamic rule.
*/
static int
init_dyn_rule(const struct autorule *autorule, struct rule *rule)
{
rule->newstat = 0;
if (rule->append_tevent == NULL)
rule->append_sec = SECONDS_IN_WEEK;
if (ac_init_dynrule(autorule, rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: init_dyn_rule: ac_init_dynrule failed",
rule->rule_name);
return -1;
}
if (db_init_dynrule(autorule, rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: init_dyn_rule: db_init_dynrule failed",
rule->rule_name);
return -1;
}
return 0;
}
/*
* Create a dynamic rule from the autorule, this function is invoked
* from the ipa_ac_mod's ac_get_stat() function.
*/
int
create_rule(const char *mod_name, u_int autoruleno,
const char *rule_name, const char *rule_info)
{
u_int ruleno;
struct rule *rule;
struct autorule *autorule;
#ifdef WITH_LIMITS
struct limit *limit;
#endif
#ifdef WITH_THRESHOLDS
struct threshold *threshold;
#endif
/* Validate aruleno. */
if (autoruleno >= nautorules) {
logmsgx(IPA_LOG_ERR, "create_rule: module %s tries to create dynamic rule from autorule with number %u and such autorule does not exist",
mod_name, autoruleno);
goto failed;
}
autorule = AUTORULE(autoruleno);
if (debug_autorule)
logmsgx(IPA_LOG_INFO, "create_rule: module %s creates rule %s from autorule %s",
mod_name, rule_name, autorule->arule_name);
/* Check if there is already rule with the given name. */
if ( (rule = rule_by_name(rule_name)) != NULL) {
logmsgx(IPA_LOG_WARNING, "autorule %s: create_rule: module %s is trying to create duplicated rule %s",
autorule->arule_name, mod_name, rule_name);
return -2;
}
/* Find first unused ruleno. */
if (marray_alloc(rules_ptr_marray, &ruleno, 0) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: marray_alloc failed",
rule_name);
goto failed;
}
/* Create rule. */
if ( (rule = mzone_alloc(rule_mzone)) == NULL) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: mzone_alloc failed",
rule_name);
marray_free(rules_ptr_marray, ruleno);
goto failed;
}
/* Copy rule_name. */
if ( (rule->rule_name = mem_strdup(rule_name, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: mem_strdup for rule_name failed",
rule_name);
mzone_free(rule_mzone, rule);
marray_free(rules_ptr_marray, ruleno);
goto failed;
}
RULE(ruleno) = rule;
rule->ruleno = ruleno;
++ndynrules;
/* Add rule to rules hash. */
add_rule_to_hash(rule);
rule->rule_info = NULL;
/*
* Flush negative counter, positive counter we will flush
* in db_append_rule().
*/
rule->cnt_neg = UINT64_C(0);
/* By default any new rule is active. */
rule->is_active = ACTIVE_FLAG;
queue_active_rule(rule);
/* Inherit settings for dynamic rule. */
if (dyn_rule_inherit(autorule, rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: cannot inherit all settings for dynamic rule",
rule_name);
goto failed_deinit;
}
#ifdef WITH_RULES
if (has_ac_gather)
if (init_ac_gather_rev(rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: init_ac_gather_rev failed",
rule_name);
goto failed_deinit;
}
#endif
/* Copy rule_info if it exist. */
if (rule_info != NULL)
if ( (rule->rule_info = mem_strdup(rule_info, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: mem_strdup for rule_info failed",
rule_name);
goto failed_deinit;
}
if (init_dyn_rule(autorule, rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: init_dyn_rule failed",
rule_name);
goto failed_deinit;
}
#ifdef WITH_LIMITS
if (init_limits(rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: init_limits failed",
rule_name);
goto failed_deinit;
}
#endif
#ifdef WITH_THRESHOLDS
if (init_thresholds(rule) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: init_thresholds failed",
rule_name);
goto failed_deinit;
}
#endif
if (run_rule_cmds(rule, RC_STARTUP) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: run_rule_cmds failed",
rule_name);
goto failed_deinit;
}
/*
* By default any new rule is active as its limits and thresholds
* are. First ac_get_rule_stat() for the new rule returns statistics,
* mark rule inactive even if newday_flag is set on.
*/
#ifdef WITH_LIMITS
STAILQ_FOREACH(limit, &rule->limits, link)
if (IS_INACTIVE(limit->worktime))
if (set_limit_inactive(rule, limit) < 0) {
logmsgx(IPA_LOG_ERR, "create_rule: set_limit_inactive failed");
goto failed_deinit;
}
#endif
#ifdef WITH_THRESHOLDS
STAILQ_FOREACH(threshold, &rule->thresholds, link)
if (IS_INACTIVE(threshold->worktime))
if (set_threshold_inactive(rule, threshold) < 0) {
logmsgx(IPA_LOG_ERR, "create_rule: set_threshold_inactive failed");
goto failed_deinit;
}
#endif
if (IS_INACTIVE(rule->worktime)) {
if (set_rule_inactive(rule) < 0) {
logmsgx(IPA_LOG_ERR, "create_rule: set_rule_inactive failed");
goto failed_deinit;
}
} else {
/* If a rule is active, then check it immediately. */
rule->check_sec = 0;
if (db_append_rule(rule, &uint64_zero, 1) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: create_rule: db_append_rule failed",
rule_name);
goto failed_deinit;
}
}
if (debug_autorule)
logmsgx(IPA_LOG_INFO, "create_rule: dynamic rule %s with number %u has been created",
rule_name, ruleno);
return 0;
failed_deinit:
if (deinit_dyn_rule(rule) < 0)
logmsgx(IPA_LOG_ERR, "create_rule: deinit_dyn_rule failed");
free_rule(rule);
failed:
return -1;
}
/*
* Delete a dynamic rule previously created from an autorule,
* this function is invoked from the ipa_ac_mod.
*/
int
delete_rule(const char *mod_name, u_int ruleno)
{
int error;
struct rule *rule;
/* Validate ruleno. */
if (ruleno < nstatrules) {
logmsgx(IPA_LOG_ERR, "delete_rule: module %s tries to delete rule with number %u and this rule is not dynamic",
mod_name, ruleno);
goto failed;
}
if (!marray_check_index(rules_ptr_marray, ruleno)) {
logmsgx(IPA_LOG_ERR, "delete_rule: module %s tries to delete rule with number %u and this rule does not exist",
mod_name, ruleno);
goto failed;
}
rule = RULE(ruleno);
if (debug_autorule)
logmsgx(IPA_LOG_INFO, "delete_rule: module %s tries to delete rule %s with number %u",
mod_name, rule->rule_name, ruleno);
error = 0;
if (run_rule_cmds(rule, RC_SHUTDOWN) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s: delete_rule: run_rule_cmds failed",
rule->rule_name);
error = 1;
}
if (deinit_dyn_rule(rule) < 0) {
logmsgx(IPA_LOG_ERR, "delete_rule: deinit_dyn_rule failed");
error = 1;
}
free_rule(rule);
if (debug_autorule)
logmsgx(IPA_LOG_INFO, "delete_rule: rule with number %u has been deleted",
ruleno);
if (error)
goto failed;
return 0;
failed:
return -1;
}
/*
* This function is called from newday().
*/
int
autorules_newday(void)
{
struct autorule *autorule;
autorules_active_check_sec = SECONDS_IN_WEEK; /* Hint. */
STAILQ_FOREACH(autorule, &autorules_list, link) {
if (IS_INACTIVE(autorule->worktime)) {
if (IS_ACTIVE(autorule))
if (set_autorule_inactive(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "autorules_newday: set_autorule_inactive failed");
return -1;
}
} else {
if (IS_INACTIVE(autorule))
if (set_autorule_active(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "autorules_newday: set_autorule_active failed");
return -1;
}
if (autorules_active_check_sec > autorule->update_tevent->event_sec)
autorules_active_check_sec = autorule->update_tevent->event_sec;
if (autorules_active_check_sec > autorule->worktime->inactive_sec)
autorules_active_check_sec = autorule->worktime->inactive_sec;
}
}
sort_inactive_autorules();
return 0;
}
/*
* Check if time to make some autorule active come. This function
* is called when autorules_inactive_check_sec <= cursec.
*/
int
check_inactive_autorules(void)
{
struct autorule *autorule, *autorule_next;
for (autorule = TAILQ_FIRST(&autorules_inactive); autorule != NULL; autorule = autorule_next) {
if (autorule->worktime->inactive_sec <= cursec) {
/* It's time to make autorule active. */
autorule_next = TAILQ_NEXT(autorule, queue);
if (set_autorule_active(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "check_inactive_autorules: set_autorule_active failed");
return -1;
}
} else {
/* Set next time of invocation of this function. */
autorules_inactive_check_sec = autorule->worktime->active_sec;
return 0;
}
}
/* No more inactive autorules. */
autorules_inactive_check_sec = SECONDS_IN_WEEK;
return 0;
}
/*
* This function is called from do_ac() and it is very simple,
* since usually there are not a lot of autorules. This function
* is called when autorules_active_check_sec <= cursec.
*/
int
check_active_autorules(void)
{
struct autorule *autorule;
autorules_active_check_sec = SECONDS_IN_WEEK; /* Hint. */
TAILQ_FOREACH(autorule, &autorules_active, queue) {
if (IS_INACTIVE(autorule->worktime)) {
/* Autorule became inactive. */
if (!newday_flag)
if (set_autorule_inactive(autorule) < 0) {
logmsgx(IPA_LOG_ERR, "check_active_autorules: set_autorule_inactive failed");
return -1;
}
} else {
/* Autorule is still active. */
if (autorules_active_check_sec > autorule->worktime->inactive_sec)
autorules_active_check_sec = autorule->worktime->inactive_sec;
if (autorules_active_check_sec > autorule->update_tevent->event_sec)
autorules_active_check_sec = autorule->update_tevent->event_sec;
}
}
return 0;
}
void
init_cmds_in_autorule(struct autorule *autorule)
{
init_cmds_rule(&autorule->rc[RC_STARTUP]);
init_cmds_rule(&autorule->rc[RC_SHUTDOWN]);
}
void
set_sync_exec_in_autorule(struct autorule *autorule)
{
set_sync_exec_cmds_rule(&autorule->rc[RC_STARTUP]);
set_sync_exec_cmds_rule(&autorule->rc[RC_SHUTDOWN]);
}
#else /* !WITH_AUTORULES */
/* ARGSUSED3 */
int
create_rule(const char *mod_name, u_int autoruleno,
const char *rule_name, const char *rule_info ATTR_UNUSED)
{
logmsgx(IPA_LOG_WARNING, "create_rule: module %s tries to create rule %s from autorule %u",
mod_name, rule_name, autoruleno);
logmsgx(IPA_LOG_WARNING, "create_rule: autorules support was removed");
return -1;
}
int
delete_rule(const char *mod_name, u_int ruleno)
{
logmsgx(IPA_LOG_ERR, "delete_rule: module %s tries to delete rule %u",
mod_name, ruleno);
logmsgx(IPA_LOG_ERR, "delete_rule: autorules support was removed");
return -1;
}
#endif /* WITH_AUTORULES */
syntax highlighted by Code2HTML, v. 0.9.1