/*- * Copyright (c) 2003 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_ac.c,v 1.1.4.1 2007/05/11 16:29:59 simon Exp $"; #endif /* !lint */ #include #include #include #include #include "ipa_mod.h" #include "dlapi.h" #include "confcommon.h" #include "memfunc.h" #include "parser.h" #include "ipa_ac.h" #include "ipa_db.h" #include "ipa_cmd.h" #include "ipa_ctl.h" #include "ipa_time.h" #include "ipa_conf.h" #include "ipa_log.h" #include "ipa_main.h" #include "ipa_rules.h" #include "ipa_autorules.h" u_int nac_mods; /* Number of ac_mods. */ int debug_ac_null; /* debug_ac_null parameter. */ const struct ac_list *global_ac_list; /* global { ac_list } */ /* * ac_sets is the list of all used "ac_list" parameters. * If some rules use the same "ac_list" parameter, then * they share the same struct ac_list{}. */ struct ac_sets ac_sets = SLIST_HEAD_INITIALIZER(ac_sets); /* * List of all accounting modules. */ struct ac_mod_list ac_mod_list; /* * Find an accounting module by configuration prefix. */ struct ac_mod * ac_mod_by_prefix(const char *prefix) { struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) if (strcmp(ac_mod->ipa_ac_mod->conf_prefix, prefix) == 0) break; return ac_mod; } /* * Find an accounting module by a name. */ struct ac_mod * ac_mod_by_name(const char *name) { struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) if (strcmp(ac_mod->ipa_ac_mod->ac_name, name) == 0) return ac_mod; return NULL; } /* * Increment ref_count for all accounting modules * in the given ac_list. */ void ac_inc_ref_count(const struct ac_list *list) { const struct ac_elem *ac; STAILQ_FOREACH(ac, list, link) (*ac->mod_ref_count)++; } /* * Decrement ref_count for all accounting modules * in the given ac_list. */ int ac_dec_ref_count(const struct ac_list *list) { const struct ac_elem *ac; STAILQ_FOREACH(ac, list, link) { if (*ac->mod_ref_count == 0) { logmsgx(IPA_LOG_INFO, "internal error: ac_dec_ref_count: mod_ref_count is zero for module %s", ac->mod_file); return -1; } (*ac->mod_ref_count)--; } return 0; } /* * Release memory held by ac_set, including struct ac_set{}. */ void free_ac_set(struct ac_set *set) { struct ac_elem *ac, *ac_next; for (ac = STAILQ_FIRST(&set->list); ac != NULL; ac = ac_next) { ac_next = STAILQ_NEXT(ac, link); mem_free(ac, m_anon); } mem_free(set, m_anon); } /* * Release memory held by all ac_set. */ void free_ac_lists(void) { struct ac_set *set; while ( (set = SLIST_FIRST(&ac_sets)) != NULL) { SLIST_REMOVE_HEAD(&ac_sets, link); free_ac_set(set); } } /* * Pre-init all ac_mods. */ int pre_init_ac_mods(void) { const struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) if (ac_mod->ipa_ac_mod->ac_pre_init() < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_pre_init failed", ac_mod->mod_file); return -1; } return 0; } /* * Init all ac_mods. */ int init_ac_mods(void) { const struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) if (ac_mod->ipa_ac_mod->ac_init() < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_init failed", ac_mod->mod_file); return -1; } return 0; } /* * Deinit all ac_mods. */ int deinit_ac_mods(void) { int error = 0; const struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) { if (ac_mod->mod_ref_count != 0) { logmsgx(IPA_LOG_ERR, "internal error: deinit_ac_mods: mod_ref_count is %u for module %s!", ac_mod->mod_ref_count, ac_mod->mod_file); error = -1; } if (ac_mod->ipa_ac_mod->ac_deinit() < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_deinit failed", ac_mod->mod_file); error = -1; } } return error; } #ifdef WITH_RULES /* * Init one static rule in accounting systems. */ int ac_init_statrule(const struct rule *rule) { const struct ac_elem *ac; if (!STAILQ_EMPTY(rule->ac_list)) STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_init_statrule != NULL) { if (ac->ipa_ac_mod->ac_init_statrule(rule->ruleno, rule->rule_name) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_init_statrule(%s) failed", ac->mod_file, rule->rule_name); return -1; } } else { logmsgx(IPA_LOG_ERR, "module %s: ac_init_statrule(%s): module does not support static rules", ac->mod_file, rule->rule_name); return -1; } else if (rule->ac_gather_add_pat == NULL && rule->ac_gather_sub_pat == NULL) { if (debug_ac_null) logmsgx(IPA_LOG_INFO, "rule %s: this rule uses builtin \"null\" accounting system", rule->rule_name); } return 0; } #endif /* WITH_RULES */ /* * Deinit one rule in accounting systems, which it uses. */ int ac_deinit_rule(const struct rule *rule) { int error = 0; const struct ac_elem *ac; STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_deinit_rule(rule->ruleno) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_deinit_rule(%s) failed", ac->mod_file, rule->rule_name); error = -1; } return error; } /* * Call ac_get_stat for all used accounting modules, if ref_count of * a module is greater than zero. */ int ac_get_stat(void) { const struct ac_mod *ac_mod; SLIST_FOREACH(ac_mod, &ac_mod_list, link) if (ac_mod->mod_ref_count > 0 && ac_mod->ipa_ac_mod->ac_get_stat != NULL) if (ac_mod->ipa_ac_mod->ac_get_stat() < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_get_stat failed", ac_mod->mod_file); return -1; } return 0; } /* * Set a rule active/inactive in accounting systems it uses. */ int ac_set_rule_active(const struct rule *rule, int active) { const struct ac_elem *ac; STAILQ_FOREACH(ac, rule->ac_list, link) { if (ac->ipa_ac_mod->ac_set_rule_active != NULL) if (ac->ipa_ac_mod->ac_set_rule_active(rule->ruleno, active) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_set_rule_active(%s, %d) failed", ac->mod_file, rule->rule_name, active); return -1; } /* Increment/decrement reference counter. */ *ac->mod_ref_count += active ? 1 : -1; } return 0; } #ifdef WITH_LIMITS /* * Register limit event for one limit. */ int ac_limit_event(const struct rule *rule, const struct limit *limit, u_int event) { int error = 0; const struct ac_elem *ac; STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_limit_event != NULL) if (ac->ipa_ac_mod->ac_limit_event(rule->ruleno, limit->limitno, event) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_limit_event(%s, %s, LIMIT_EVENT_%s) failed", ac->mod_file, rule->rule_name, limit->limit_name, limit_event_msg[event]); error = -1; } return error; } /* * Set a limit active/inactive in accounting systems it uses. */ int ac_set_limit_active(const struct rule *rule, const struct limit *limit, int active) { const struct ac_elem *ac; /* Limit shares the same ac_list with its rule. */ STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_set_limit_active != NULL) if (ac->ipa_ac_mod->ac_set_limit_active(rule->ruleno, limit->limitno, active) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_set_limit_active(%s, %s, %d) failed", ac->mod_file, rule->rule_name, limit->limit_name, active); return -1; } return 0; } #endif /* WITH_LIMITS */ #ifdef WITH_THRESHOLDS /* * Register limit event for one threshold. */ int ac_threshold_event(const struct rule *rule, const struct threshold *threshold, u_int event) { int error = 0; const struct ac_elem *ac; STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_threshold_event != NULL) if (ac->ipa_ac_mod->ac_threshold_event(rule->ruleno, threshold->thresholdno, event) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_threshold_event(%s, %s, THRESHOLD_EVENT_%s) failed", ac->mod_file, rule->rule_name, threshold->threshold_name, threshold_event_msg[event]); error = -1; } return error; } /* * Set a threshold active/inactive in accounting systems it uses. */ int ac_set_threshold_active(const struct rule *rule, const struct threshold *threshold, int active) { const struct ac_elem *ac; /* Threshold shares the same ac_list with its rule. */ STAILQ_FOREACH(ac, rule->ac_list, link) if (ac->ipa_ac_mod->ac_set_threshold_active != NULL) if (ac->ipa_ac_mod->ac_set_threshold_active(rule->ruleno, threshold->thresholdno, active) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_set_threshold_active(%s, %s, %d) failed", ac->mod_file, rule->rule_name, threshold->threshold_name, active); return -1; } return 0; } #endif /* WITH_THRESHOLDS */ #ifdef WITH_AUTORULES /* * Init one autorule in accounting system, which it uses. */ int ac_init_autorule(const struct autorule *autorule) { const struct ac_elem *ac; /* Any autorule can use only one accounting system. */ if (!STAILQ_EMPTY(autorule->ac_list)) { ac = STAILQ_FIRST(autorule->ac_list); if (ac->ipa_ac_mod->ac_init_autorule != NULL) { if (ac->ipa_ac_mod->ac_init_autorule(autorule->aruleno, autorule->arule_name) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_init_autorule(%s) failed", ac->mod_file, autorule->arule_name); return -1; } } else { logmsgx(IPA_LOG_ERR, "module %s: ac_init_autorule(%s): module does not support dynamic rules", autorule->arule_name, ac->mod_file); return -1; } } else { if (debug_ac_null) logmsgx(IPA_LOG_INFO, "autorule %s: this autorule uses builtin \"null\" accounting system", autorule->arule_name); } return 0; } /* * Deinit one autorule in accounting system, which it uses. */ int ac_deinit_autorule(const struct autorule *autorule) { const struct ac_elem *ac; STAILQ_FOREACH(ac, autorule->ac_list, link) if (ac->ipa_ac_mod->ac_deinit_autorule != NULL) if (ac->ipa_ac_mod->ac_deinit_autorule(autorule->aruleno) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_deinit_autorule(%s) failed", ac->mod_file, autorule->arule_name); return -1; } return 0; } /* * Init one dynamic rule in accounting systems. */ int ac_init_dynrule(const struct autorule *autorule, const struct rule *rule) { const struct ac_elem *ac; /* Any autorule can use only one accounting system. */ if (!STAILQ_EMPTY(rule->ac_list)) { ac = STAILQ_FIRST(rule->ac_list); if (ac->ipa_ac_mod->ac_init_dynrule(autorule->aruleno, rule->ruleno, rule->rule_name) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_dyninit_rule(%s, %s) failed", ac->mod_file, autorule->arule_name, rule->rule_name); return -1; } } return 0; } int ac_set_autorule_active(const struct autorule *autorule, int active) { const struct ac_elem *ac; STAILQ_FOREACH(ac, autorule->ac_list, link) { if (ac->ipa_ac_mod->ac_set_autorule_active != NULL) if (ac->ipa_ac_mod->ac_set_autorule_active(autorule->aruleno, active) < 0) { logmsgx(IPA_LOG_ERR, "module %s: ac_set_autorule_active(%s, %d) failed", ac->mod_file, autorule->arule_name, active); return -1; } /* Increment/decrement reference counter. */ *ac->mod_ref_count += active ? 1 : -1; } return 0; } #endif /* WITH_AUTORULES */