/*- * 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 #include #include #include #include #include #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 */