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