/*- * Copyright (c) 2005 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: ipastat_rules.c,v 1.1.4.2 2007/05/11 16:29:59 simon Exp $"; #endif /* !lint */ #include #include #include #include #include #include "ipa_mod.h" #include "dlapi.h" #include "confcommon.h" #include "memfunc.h" #include "parser.h" #include "ipastat_log.h" #include "ipastat_conf.h" #include "ipastat_main.h" #include "ipastat_rules.h" #include "ipastat_st.h" #ifndef RULES_HASH_BUCKETS # define RULES_HASH_BUCKETS 128 /* Must be power of 2. */ #endif int dynamic_rules = -1; /* dynamic_rules parameter. */ struct opt_rule *cur_opt_rule = NULL; /* Current optional rule. */ ipa_mzone *rule_mzone; /* Mzone for all struct rule{}. */ ipa_mzone *rulepat_mzone; /* Mzone for all struct rulepat{}. */ struct rules_list rules_list = STAILQ_HEAD_INITIALIZER(rules_list); /* List of all rules. */ struct rulepats_list rulepats_list = STAILQ_HEAD_INITIALIZER(rulepats_list); /* List of rulepats. */ u_int nrules = 0; /* Number of rules. */ struct opt_rules_list opt_rules_list = STAILQ_HEAD_INITIALIZER(opt_rules_list); SLIST_HEAD(rules_hash, rule); static struct rules_hash rules_hash[RULES_HASH_BUCKETS]; /* * Init one rule. */ static int init_rule(const struct opt_rule *opt_rule) { struct rule *rule; rule = opt_rule->rule; if (!rule->inited) { rule->inited = 1; /* Init in modules. */ if (st_init_rule(rule) < 0) { logmsgx(IPA_LOG_ERR, "rule %s: init_rule: st_init_rule failed", rule->rule_name); return -1; } } return 0; } /* * Init rules and limits or thresholds. */ int init_rules(void) { const struct opt_rule *opt_rule; STAILQ_FOREACH(opt_rule, &opt_rules_list, link) { if (init_rule(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "init_rules: init_rule failed"); return -1; } #ifdef WITH_LIMITS if (has_opt_limits) if (init_limits(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "init_rules: init_limits failed"); return -1; } #endif #ifdef WITH_THRESHOLDS if (has_opt_thresholds) if (init_thresholds(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "init_rules: init_thresholds failed"); return -1; } #endif } return 0; } /* * Release memory used by one rule. */ static void free_rule(struct rule *rule) { #ifdef WITH_LIMITS free_limits(&rule->limits); #endif #ifdef WITH_THRESHOLDS free_thresholds(&rule->thresholds); #endif if (rule->free_mask & RULE_FREE_NAME) mem_free(rule->rule_name, m_anon); mem_free(rule->rule_info, m_result); mzone_free(rule_mzone, rule); } /* * Call free_rule() for each rule. */ void free_rules(void) { struct rule *rule, *rule_next; for (rule = STAILQ_FIRST(&rules_list); rule != NULL; rule = rule_next) { rule_next = STAILQ_NEXT(rule, list); free_rule(rule); } STAILQ_INIT(&rules_list); } /* * Deinit one rule. */ static int deinit_rule(const struct opt_rule *opt_rule) { int error = 0; struct rule *rule; rule = opt_rule->rule; if (rule->inited) { rule->inited = 0; /* Deinit in modules. */ if (st_deinit_rule(rule) < 0) { logmsgx(IPA_LOG_ERR, "rule %s: deinit_rule: st_deinit_rule failed", rule->rule_name); error = -1; } } return error; } /* * Deinit previously inited rules, limits or thresholds. */ int deinit_rules(void) { int error = 0; struct opt_rule *opt_rule; STAILQ_FOREACH(opt_rule, &opt_rules_list, link) { if (deinit_rule(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_rule failed"); error = -1; } #ifdef WITH_LIMITS if (has_opt_limits) if (deinit_limits(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_limits failed"); error = -1; } #endif #ifdef WITH_THRESHOLDS if (has_opt_thresholds) if (deinit_thresholds(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "deinit_rules: deinit_thresholds failed"); error = -1; } #endif } return error; } /* * Return hash_value for the given rule_name; */ static u_int get_rule_hash_value(const char *rule_name) { u_int hash_value; for (hash_value = 0; *rule_name != '\0'; ++rule_name) hash_value += (u_char)*rule_name; return hash_value; } #define get_rules_bucket(x) ((x) & (RULES_HASH_BUCKETS - 1)) /* * Add rule to rules_hash. */ void add_rule_to_hash(struct rule *rule) { rule->hash_value = get_rule_hash_value(rule->rule_name); SLIST_INSERT_HEAD(&rules_hash[get_rules_bucket(rule->hash_value)], rule, hlink); } void init_rules_hash(void) { struct rules_hash *hash; for (hash = rules_hash; hash < rules_hash + RULES_HASH_BUCKETS; ++hash) SLIST_INIT(hash); } /* * Return pointer to rule with the given name. */ struct rule * rule_by_name(const char *rule_name) { u_int hash_value; struct rule *rule; const struct rules_hash *hash; hash_value = get_rule_hash_value(rule_name); hash = &rules_hash[get_rules_bucket(hash_value)]; SLIST_FOREACH(rule, hash, hlink) if (rule->hash_value == hash_value && strcmp(rule->rule_name, rule_name) == 0) return rule; return NULL; } struct rule * alloc_rule(void) { struct rule *rule; if ( (rule = mzone_alloc(rule_mzone)) == NULL) { xlogmsgx(IPA_LOG_ERR, "alloc_rule: mzone_alloc failed"); return NULL; } rule->rule_info = NULL; rule->ruleno = nrules++; rule->st_list = NULL; #ifdef WITH_LIMITS STAILQ_INIT(&rule->limits); #endif #ifdef WITH_THRESHOLDS STAILQ_INIT(&rule->thresholds); #endif rule->inited = 0; STAILQ_INSERT_TAIL(&rules_list, rule, list); return rule; } /* * Add one optional rule given in the -q -r option. */ int add_opt_rule(const char *rule_name) { struct opt_rule *opt_rule; if ( (opt_rule = mem_malloc(sizeof *opt_rule, m_anon)) == NULL) { logmsgx(IPA_LOG_ERR, "add_opt_rule: mem_malloc failed"); return -1; } opt_rule->rule_name = rule_name; opt_rule->opt_st = cur_opt_st; opt_rule->type = OPT_RULE_RULE; opt_rule->data = NULL; #ifdef WITH_LIMITS STAILQ_INIT(&opt_rule->opt_limits); #endif #ifdef WITH_THRESHOLDS STAILQ_INIT(&opt_rule->opt_thresholds); #endif STAILQ_INSERT_TAIL(&opt_rules_list, opt_rule, link); cur_opt_rule = opt_rule; return 0; } /* * Parse all rules, limits and thresholds names given in the * command line. */ int parse_opt_rules(void) { struct rule *rule; struct opt_rule *opt_rule; const struct rulepat *rulepat; STAILQ_FOREACH(opt_rule, &opt_rules_list, link) { if ( (rule = rule_by_name(opt_rule->rule_name)) == NULL) { /* This rule is not given in configuration file. */ if (!dynamic_rules) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: unknown rule %s", opt_rule->rule_name); return -1; } if ( (rule = alloc_rule()) == NULL) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: alloc_rule failed"); return -1; } rule->rule_name = (char *)opt_rule->rule_name; rule->free_mask = 0; add_rule_to_hash(rule); } if (opt_rule->opt_st != NULL) rule->st_list = opt_rule->opt_st->st_list; STAILQ_FOREACH(rulepat, &rulepats_list, link) if (regexec(&rulepat->reg, rule->rule_name, 0, (regmatch_t *)NULL, 0) == 0) { /* Inherit some settings for rule{} from rulepat{}. */ if (rule->st_list == NULL) rule->st_list = rulepat->st_list; #ifdef WITH_LIMITS if (STAILQ_EMPTY(&rule->limits) && !STAILQ_EMPTY(&rulepat->limits)) if (copy_limits(rule, &rulepat->limits) < 0) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: rule %s: cannot copy all limits from rulepat %s", rule->rule_name, parser_buf_to_string(rulepat->pat)); return -1; } #endif #ifdef WITH_THRESHOLDS if (STAILQ_EMPTY(&rule->thresholds) && !STAILQ_EMPTY(&rulepat->thresholds)) if (copy_thresholds(rule, &rulepat->thresholds) < 0) { logmsgx(IPA_LOG_ERR, "parse_opt_rule: rule %s: cannot copy all thresholds from rulepat %s", rule->rule_name, parser_buf_to_string(rulepat->pat)); return -1; } #endif if (mod_conf_inherit(rulepat, rule) < 0) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: mod_conf_inherit failed"); return -1; } if (rulepat->check_next_rulepat == 0) break; } if (rulepat == NULL) { /* Inherit some settings for rule{} from global{}. */ if (rule->st_list == NULL) rule->st_list = global_st_list; } opt_rule->rule = rule; #ifdef WITH_LIMITS if (parse_opt_limits(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: parse_opt_limits failed"); return -1; } #endif #ifdef WITH_THRESHOLDS if (parse_opt_thresholds(opt_rule) < 0) { logmsgx(IPA_LOG_ERR, "parse_opt_rules: parse_opt_thresholds failed"); return -1; } #endif } return 0; } /* * Release memory used by all opt_rule structures. */ void free_opt_rules(void) { struct opt_rule *opt_rule, *opt_rule_next; for (opt_rule = STAILQ_FIRST(&opt_rules_list); opt_rule != NULL; opt_rule = opt_rule_next) { opt_rule_next = STAILQ_NEXT(opt_rule, link); #ifdef WITH_LIMITS free_opt_limits(&opt_rule->opt_limits); #endif #ifdef WITH_THRESHOLDS free_opt_thresholds(&opt_rule->opt_thresholds); #endif mem_free(opt_rule, m_anon); } } /* * Release memory used by all rulepats. */ void free_rulepats(void) { struct rulepat *rulepat; STAILQ_FOREACH(rulepat, &rulepats_list, link) { mem_free(rulepat->pat, m_parser); regfree(&rulepat->reg); #ifdef WITH_LIMITS free_limits(&rulepat->limits); #endif #ifdef WITH_THRESHOLDS free_thresholds(&rulepat->thresholds); #endif } mzone_deinit(rulepat_mzone); }