/*-
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#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 */
syntax highlighted by Code2HTML, v. 0.9.1