1 /*-
2 * Copyright (c) 2003 Andrey Simonenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include "config.h"
28
29 #ifndef lint
30 static const char rcsid[] ATTR_UNUSED =
31 "@(#)$Id: ipa_ac.c,v 1.2 2011/01/23 18:42:34 simon Exp $";
32 #endif /* !lint */
33
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "ipa_mod.h"
40
41 #include "queue.h"
42
43 #include "dlapi.h"
44 #include "confcommon.h"
45 #include "memfunc.h"
46 #include "parser.h"
47
48 #include "ipa_ac.h"
49 #include "ipa_db.h"
50 #include "ipa_ctl.h"
51 #include "ipa_cmd.h"
52 #include "ipa_time.h"
53
54 #include "ipa_conf.h"
55 #include "ipa_log.h"
56 #include "ipa_main.h"
57 #include "ipa_rules.h"
58 #include "ipa_autorules.h"
59
60 unsigned int nac_mods; /* Number of ac_mods. */
61
62 signed char debug_ac_null; /* debug_ac_null parameter. */
63
64 const struct ac_list *global_ac_list; /* global { ac_list } */
65
66 /*
67 * List of all used "ac_list" parameters. If some rules use the same
68 * "ac_list" parameter, then they share the same struct ac_list{}.
69 */
70 struct ac_sets ac_sets;
71
72 /* List of all accounting modules. */
73 struct ac_mod_list ac_mod_list;
74
75 /*
76 * Find an accounting module by configuration prefix.
77 */
78 struct ac_mod *
ac_mod_by_prefix(const char * prefix)79 ac_mod_by_prefix(const char *prefix)
80 {
81 struct ac_mod *ac_mod;
82
83 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
84 if (ac_mod->ipa_ac_mod->conf_prefix != NULL &&
85 strcmp(ac_mod->ipa_ac_mod->conf_prefix, prefix) == 0)
86 break;
87 return (ac_mod);
88 }
89
90 /*
91 * Find an accounting module by a name.
92 */
93 struct ac_mod *
ac_mod_by_name(const char * name)94 ac_mod_by_name(const char *name)
95 {
96 struct ac_mod *ac_mod;
97
98 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
99 if (strcmp(ac_mod->ipa_ac_mod->ac_name, name) == 0)
100 break;
101 return (ac_mod);
102 }
103
104 /*
105 * Increase ref_count for all accounting modules
106 * in the given ac_list.
107 */
108 void
ac_inc_ref_count(const struct ac_list * list)109 ac_inc_ref_count(const struct ac_list *list)
110 {
111 const struct ac_elem *ac;
112
113 STAILQ_FOREACH(ac, list, link)
114 (*ac->mod_ref_count)++;
115 }
116
117 /*
118 * Decrease ref_count for all accounting modules
119 * in the given ac_list.
120 */
121 int
ac_dec_ref_count(const struct ac_list * list)122 ac_dec_ref_count(const struct ac_list *list)
123 {
124 const struct ac_elem *ac;
125
126 STAILQ_FOREACH(ac, list, link) {
127 if (*ac->mod_ref_count == 0) {
128 logmsgx(IPA_LOG_INFO, "internal error: "
129 "ac_dec_ref_count: mod_ref_count is zero for "
130 "module %s", ac->mod_file);
131 return (-1);
132 }
133 (*ac->mod_ref_count)--;
134 }
135 return (0);
136 }
137
138 /*
139 * Release memory held by ac_set, including struct ac_set{}.
140 */
141 void
free_ac_set(struct ac_set * set)142 free_ac_set(struct ac_set *set)
143 {
144 struct ac_elem *ac, *ac_next;
145
146 STAILQ_FOREACH_SAFE(ac, &set->list, link, ac_next)
147 mem_free(ac, m_anon);
148 mem_free(set, m_anon);
149 }
150
151 /*
152 * Release memory held by all ac_set.
153 */
154 void
free_ac_lists(void)155 free_ac_lists(void)
156 {
157 struct ac_set *set, *set_next;
158
159 SLIST_FOREACH_SAFE(set, &ac_sets, link, set_next)
160 free_ac_set(set);
161 }
162
163 /*
164 * Pre-initialize all ac_mods.
165 */
166 int
pre_init_ac_mods(void)167 pre_init_ac_mods(void)
168 {
169 const struct ac_mod *ac_mod;
170
171 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
172 if (ac_mod->ipa_ac_mod->ac_pre_init() < 0) {
173 logmsgx(IPA_LOG_ERR, "module %s: ac_pre_init failed",
174 ac_mod->mod_file);
175 return (-1);
176 }
177 return (0);
178 }
179
180 /*
181 * Initialize all ac_mods.
182 */
183 int
init_ac_mods(void)184 init_ac_mods(void)
185 {
186 const struct ac_mod *ac_mod;
187
188 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
189 if (ac_mod->ipa_ac_mod->ac_init() < 0) {
190 logmsgx(IPA_LOG_ERR, "module %s: ac_init failed",
191 ac_mod->mod_file);
192 return (-1);
193 }
194 return (0);
195 }
196
197 /*
198 * Deinitialize all ac_mods.
199 */
200 int
deinit_ac_mods(void)201 deinit_ac_mods(void)
202 {
203 const struct ac_mod *ac_mod;
204 int rv;
205
206 rv = 0;
207 SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
208 if (ac_mod->mod_ref_count != 0) {
209 logmsgx(IPA_LOG_ERR, "internal error: deinit_ac_mods: "
210 "mod_ref_count is %u for module %s!",
211 ac_mod->mod_ref_count, ac_mod->mod_file);
212 rv = -1;
213 }
214 if (ac_mod->ipa_ac_mod->ac_deinit() < 0) {
215 logmsgx(IPA_LOG_ERR, "module %s: ac_deinit failed",
216 ac_mod->mod_file);
217 rv = -1;
218 }
219 }
220 return (rv);
221 }
222
223 #ifdef WITH_RULES
224 /*
225 * Initialize one static rule in accounting systems.
226 */
227 int
ac_init_statrule(const struct rule * rule)228 ac_init_statrule(const struct rule *rule)
229 {
230 if (!STAILQ_EMPTY(rule->ac_list)) {
231 const struct ac_elem *ac;
232
233 STAILQ_FOREACH(ac, rule->ac_list, link) {
234 if (ac->ipa_ac_mod->ac_init_statrule == NULL) {
235 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
236 "ac_init_statrule: module does not support "
237 "static rules", ac->mod_file, rule->name);
238 return (-1);
239 }
240 if (ac->ipa_ac_mod->ac_init_statrule(rule->no,
241 rule->name) < 0) {
242 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
243 "ac_init_statrule failed", ac->mod_file,
244 rule->name);
245 return (-1);
246 }
247 }
248 } else {
249 if (debug_ac_null && rule->acg_add_pat == NULL &&
250 rule->acg_sub_pat == NULL)
251 logdbg("rule %s: uses \"null\" accounting system",
252 rule->name);
253 }
254 return (0);
255 }
256 #endif /* WITH_RULES */
257
258 /*
259 * Deinitialize one rule in accounting systems, which it uses.
260 */
261 int
ac_deinit_rule(const struct rule * rule)262 ac_deinit_rule(const struct rule *rule)
263 {
264 const struct ac_elem *ac;
265 int rv;
266
267 rv = 0;
268 STAILQ_FOREACH(ac, rule->ac_list, link)
269 if (ac->ipa_ac_mod->ac_deinit_rule(rule->no) < 0) {
270 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
271 "ac_deinit_rule failed", ac->mod_file, rule->name);
272 rv = -1;
273 }
274 return (rv);
275 }
276
277 /*
278 * Call ac_get_stat for all used accounting modules, if ref_count of
279 * a module is greater than zero.
280 */
281 int
ac_get_stat(void)282 ac_get_stat(void)
283 {
284 const struct ac_mod *ac_mod;
285
286 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
287 if (ac_mod->mod_ref_count != 0 &&
288 ac_mod->ipa_ac_mod->ac_get_stat != NULL &&
289 ac_mod->ipa_ac_mod->ac_get_stat(&curdate) < 0) {
290 logmsgx(IPA_LOG_ERR, "module %s: ac_get_stat failed",
291 ac_mod->mod_file);
292 return (-1);
293 }
294 return (0);
295 }
296
297 /*
298 * Set a rule active/inactive in accounting systems it uses.
299 */
300 int
ac_set_rule_active(const struct rule * rule,int active)301 ac_set_rule_active(const struct rule *rule, int active)
302 {
303 const struct ac_elem *ac;
304
305 STAILQ_FOREACH(ac, rule->ac_list, link) {
306 if (ac->ipa_ac_mod->ac_set_rule_active != NULL &&
307 ac->ipa_ac_mod->ac_set_rule_active(rule->no, active) < 0) {
308 logmsgx(IPA_LOG_ERR, "module %s: rule %s: "
309 "ac_set_rule_active(%d) failed", ac->mod_file,
310 rule->name, active);
311 return (-1);
312 }
313 /* Increase/decrease reference counter. */
314 *ac->mod_ref_count += active ? 1 : -1;
315 }
316 return (0);
317 }
318
319 #ifdef WITH_LIMITS
320 /*
321 * Register limit event for one limit.
322 */
323 int
ac_limit_event(const struct rule * rule,const struct limit * limit,unsigned int event)324 ac_limit_event(const struct rule *rule, const struct limit *limit,
325 unsigned int event)
326 {
327 const struct ac_elem *ac;
328 int rv;
329
330 rv = 0;
331 STAILQ_FOREACH(ac, rule->ac_list, link)
332 if (ac->ipa_ac_mod->ac_limit_event != NULL &&
333 ac->ipa_ac_mod->ac_limit_event(rule->no, limit->no,
334 event) < 0) {
335 logmsgx(IPA_LOG_ERR, "module %s: rule %s, limit %s: "
336 "ac_limit_event(EVENT_%s) failed", ac->mod_file,
337 rule->name, limit->name, limit_event_msg[event]);
338 rv = -1;
339 }
340 return (rv);
341 }
342
343 /*
344 * Set a limit active/inactive in accounting systems it uses.
345 */
346 int
ac_set_limit_active(const struct rule * rule,const struct limit * limit,int active)347 ac_set_limit_active(const struct rule *rule, const struct limit *limit,
348 int active)
349 {
350 const struct ac_elem *ac;
351
352 /* Limit shares the same ac_list with its rule. */
353 STAILQ_FOREACH(ac, rule->ac_list, link)
354 if (ac->ipa_ac_mod->ac_set_limit_active != NULL &&
355 ac->ipa_ac_mod->ac_set_limit_active(rule->no, limit->no,
356 active) < 0) {
357 logmsgx(IPA_LOG_ERR, "module %s: rule %s, limit %s: "
358 "ac_set_limit_active(%d) failed", ac->mod_file,
359 rule->name, limit->name, active);
360 return (-1);
361 }
362 return (0);
363 }
364 #endif /* WITH_LIMITS */
365
366 #ifdef WITH_THRESHOLDS
367 /*
368 * Register limit event for one threshold.
369 */
370 int
ac_threshold_event(const struct rule * rule,const struct threshold * threshold,unsigned int event)371 ac_threshold_event(const struct rule *rule,
372 const struct threshold *threshold, unsigned int event)
373 {
374 const struct ac_elem *ac;
375 int rv;
376
377 rv = 0;
378 STAILQ_FOREACH(ac, rule->ac_list, link)
379 if (ac->ipa_ac_mod->ac_threshold_event != NULL &&
380 ac->ipa_ac_mod->ac_threshold_event(rule->no,
381 threshold->no, event) < 0) {
382 logmsgx(IPA_LOG_ERR, "module %s: rule %s, threshold "
383 "%s: ac_threshold_event(EVENT_%s) failed",
384 ac->mod_file, rule->name, threshold->name,
385 threshold_event_msg[event]);
386 rv = -1;
387 }
388 return (rv);
389 }
390
391 /*
392 * Set a threshold active/inactive in accounting systems it uses.
393 */
394 int
ac_set_threshold_active(const struct rule * rule,const struct threshold * threshold,int active)395 ac_set_threshold_active(const struct rule *rule,
396 const struct threshold *threshold, int active)
397 {
398 const struct ac_elem *ac;
399
400 /* Threshold shares the same ac_list with its rule. */
401 STAILQ_FOREACH(ac, rule->ac_list, link)
402 if (ac->ipa_ac_mod->ac_set_threshold_active != NULL &&
403 ac->ipa_ac_mod->ac_set_threshold_active(rule->no,
404 threshold->no, active) < 0) {
405 logmsgx(IPA_LOG_ERR, "module %s: rule %s, threshold "
406 "%s: ac_set_threshold_active(%d) failed",
407 ac->mod_file, rule->name, threshold->name, active);
408 return (-1);
409 }
410 return (0);
411 }
412 #endif /* WITH_THRESHOLDS */
413
414 #ifdef WITH_AUTORULES
415 /*
416 * Initialize one autorule in accounting system, which it uses.
417 */
418 int
ac_init_autorule(const struct autorule * autorule)419 ac_init_autorule(const struct autorule *autorule)
420 {
421 if (!STAILQ_EMPTY(autorule->ac_list)) {
422 const struct ac_elem *ac;
423
424 /* Any autorule can use only one accounting system. */
425 ac = STAILQ_FIRST(autorule->ac_list);
426 if (ac->ipa_ac_mod->ac_init_autorule == NULL) {
427 logmsgx(IPA_LOG_ERR, "module %s: autorule %s: "
428 "ac_init_autorule: module does not support "
429 "dynamic rules", ac->mod_file, autorule->name);
430 return (-1);
431 }
432 if (ac->ipa_ac_mod->ac_init_autorule(autorule->no,
433 autorule->name) < 0) {
434 logmsgx(IPA_LOG_ERR, "module %s: autorule %s: "
435 "ac_init_autorule failed", ac->mod_file,
436 autorule->name);
437 return (-1);
438 }
439 } else if (debug_ac_null)
440 logdbg("autorule %s: uses \"null\" accounting system",
441 autorule->name);
442 return (0);
443 }
444
445 /*
446 * Deinitialize one autorule in accounting system, which it uses.
447 */
448 int
ac_deinit_autorule(const struct autorule * autorule)449 ac_deinit_autorule(const struct autorule *autorule)
450 {
451 const struct ac_elem *ac;
452
453 STAILQ_FOREACH(ac, autorule->ac_list, link)
454 if (ac->ipa_ac_mod->ac_deinit_autorule != NULL &&
455 ac->ipa_ac_mod->ac_deinit_autorule(autorule->no) < 0) {
456 logmsgx(IPA_LOG_ERR, "module %s: autorule %s: "
457 "ac_deinit_autorule failed", ac->mod_file,
458 autorule->name);
459 return (-1);
460 }
461 return (0);
462 }
463
464 /*
465 * Initialize one dynamic rule in accounting systems.
466 */
467 int
ac_init_dynrule(const struct autorule * autorule,const struct rule * rule)468 ac_init_dynrule(const struct autorule *autorule, const struct rule *rule)
469 {
470 const struct ac_elem *ac;
471
472 /* Any dynamic rule can use only one accounting system. */
473 ac = STAILQ_FIRST(rule->ac_list);
474 if (ac != NULL && ac->ipa_ac_mod->ac_init_dynrule(autorule->no,
475 rule->no, rule->name) < 0) {
476 logmsgx(IPA_LOG_ERR, "module %s: autorule %s, rule %s: "
477 "ac_dyninit_rule failed", ac->mod_file, autorule->name,
478 rule->name);
479 return (-1);
480 }
481 return (0);
482 }
483
484 int
ac_set_autorule_active(const struct autorule * autorule,int active)485 ac_set_autorule_active(const struct autorule *autorule, int active)
486 {
487 const struct ac_elem *ac;
488
489 STAILQ_FOREACH(ac, autorule->ac_list, link) {
490 if (ac->ipa_ac_mod->ac_set_autorule_active != NULL &&
491 ac->ipa_ac_mod->ac_set_autorule_active(autorule->no,
492 active) < 0) {
493 logmsgx(IPA_LOG_ERR, "module %s: autorule %s: "
494 "ac_set_autorule_active(%d) failed",
495 ac->mod_file, autorule->name, active);
496 return (-1);
497 }
498 /* Increase/decrease reference counter. */
499 *ac->mod_ref_count += active ? 1 : -1;
500 }
501 return (0);
502 }
503 #endif /* WITH_AUTORULES */
504