1 /*-
2 * Copyright (c) 1999-2004 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_conf.c,v 1.4.2.2 2012/07/09 20:28:19 simon Exp $";
32 #endif /* !lint */
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/un.h>
38
39 #include <ctype.h>
40 #include <dirent.h>
41 #include <errno.h>
42 #include <fnmatch.h>
43 #include <limits.h>
44 #include <regex.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 #include "ipa_mod.h"
51
52 #include "queue.h"
53
54 #include "dlapi.h"
55 #include "confcommon.h"
56 #include "memfunc.h"
57 #include "parser.h"
58 #include "pathnames.h"
59
60 #include "ipa_ac.h"
61 #include "ipa_db.h"
62 #include "ipa_time.h"
63
64 #include "ipa_ctl.h"
65 #include "ipa_cmd.h"
66 #include "ipa_conf.h"
67 #include "ipa_log.h"
68 #include "ipa_main.h"
69 #include "ipa_rules.h"
70 #include "ipa_autorules.h"
71
72
73 char *ipa_conf_file = IPA_CONF_FILE; /* -f conf_file */
74
75 char mimic_real_config = 0; /* Set if -tt. */
76
77 /* Give limitation on the depth of included files. */
78 #define INCLUDE_DEPTH_MAX 100
79 static unsigned int include_depth;
80
81 #ifdef CTL_CHECK_CREDS
82 static regex_t re_acl;
83 static regex_t re_ctl_acl_class;
84 #endif
85
86 /*
87 * IPA_CONF_SECT_* with 1..21 values are defined in ipa_mod.h.
88 * These are local values, modules should not use them.
89 */
90 #define SECT_SUBLIMIT 22
91
92 #ifdef WITH_RULES
93 static struct rule *currule; /* Current rule. */
94 #endif
95
96 static struct rulepat *currulepat; /* Current rulepat. */
97 static unsigned int rulepatno;
98
99 #ifdef WITH_AUTORULES
100 static struct autorule *curautorule; /* Current autorule. */
101 #endif
102
103 #ifdef WITH_LIMITS
104 static struct limit *curlimit; /* Current limit. */
105 static unsigned int limitno; /* Current limit ordinal number. */
106 static regex_t re_texp; /* Regex for PAT_TIME_EXP. */
107 static struct limits_list *limits_list;
108 #endif
109
110 #ifdef WITH_SUBLIMITS
111 static struct sublimit *cursublimit; /* Current sublimit. */
112 #endif
113
114 #ifdef WITH_THRESHOLDS
115 static struct threshold *curthreshold; /* Current threshold. */
116 static unsigned int thresholdno; /* Current threshold ordinal number. */
117 static regex_t re_thr_balance; /* Regex for "threshold_balance". */
118 static struct thresholds_list *thresholds_list;
119 #endif
120
121 static struct cmds *curcmds; /* Current commands section. */
122
123 /* Built-in "null" accounting system and database. */
124 static struct ac_list ac_list_null = STAILQ_HEAD_INITIALIZER(ac_list_null);
125 static struct db_list db_list_null = STAILQ_HEAD_INITIALIZER(db_list_null);
126
127 /* Empty time interval. */
128 static struct tint_list tint_list_empty =
129 STAILQ_HEAD_INITIALIZER(tint_list_empty);
130
131 static signed char posix_re_pattern; /* posix_re_pattern parameter. */
132 static signed char only_abs_paths; /* only_abs_paths parameter. */
133
134 struct debug_param {
135 const char *name;
136 signed char *value;
137 };
138
139 /* debug_* parameters in IPA_CONF_SECT_ROOT. */
140 static struct debug_param root_debug_param[] = {
141 #ifdef WITH_AUTORULES
142 { "debug_autorule", &debug_autorule },
143 #endif
144 { "debug_ctl", &debug_ctl },
145 { "debug_time", &debug_time },
146 { "debug_worktime", &debug_worktime },
147 { "debug_ac_null", &debug_ac_null },
148 { "debug_db_null", &debug_db_null }
149 };
150
151 #define ROOT_DEBUG_PARAM_TBL_SIZE \
152 (sizeof(root_debug_param) / sizeof(root_debug_param[0]))
153
154 /* debug_* parameters in IPA_CONF_SECT_GLOBAL. */
155 static struct debug_param global_debug_param[] = {
156 #ifdef WITH_LIMITS
157 { "debug_limit", &global_debug_limit },
158 { "debug_limit_init", &global_debug_limit_init },
159 #endif
160 #ifdef WITH_THRESHOLDS
161 { "debug_threshold", &global_debug_threshold },
162 { "debug_threshold_init", &global_debug_threshold_init },
163 #endif
164 { "debug_exec", &global_debug_exec }
165 };
166
167 #define GLOBAL_DEBUG_PARAM_TBL_SIZE \
168 (sizeof(global_debug_param) / sizeof(global_debug_param[0]))
169
170 struct time_param {
171 const char *name;
172 unsigned int *value;
173 };
174
175 /* *_time parameters in IPA_CONF_SECT_ROOT. */
176 static struct time_param root_time_param[] = {
177 { "wakeup_time", &wakeup_time },
178 { "freeze_time", &freeze_time },
179 { "sleep_after_dump", &sleep_after_dump },
180 { "sensitive_time", &sensitive_time }
181 };
182
183 #define ROOT_TIME_PARAM_TBL_SIZE \
184 (sizeof(root_time_param) / sizeof(root_time_param[0]))
185
186 static const struct {
187 const char *str;
188 int val;
189 } value_units_tbl[] = {
190 { "bytes", IPA_CONF_TYPE_BYTES },
191 { "time", IPA_CONF_TYPE_TIME },
192 { "number", IPA_CONF_TYPE_UINT64 },
193 { "any", 0 }
194 };
195
196 #define VALUE_UNITS_TBL_SIZE \
197 (sizeof(value_units_tbl) / sizeof(value_units_tbl[0]))
198
199 static char use_log; /* 0, if -t or -x switch was used. */
200
201 static PARSING_MODE parsing_mode; /* xxx_PARSING. */
202
203 static unsigned int section; /* Current section ID. */
204 static unsigned int section_first; /* root autorule rulepat rule */
205 static unsigned int section_top; /* root autorule rulepat rule limit
206 sublimit threshold */
207
208 static unsigned int section_rc; /* RC_{STARTUP,SHUTDOWN,NOTSET} */
209
210 static char global_section_set; /* Set if has global{}. */
211
212 static unsigned int conf_event_no; /* Current section ordinal number. */
213 static const void *conf_event_arg; /* Current argument for conf_event(). */
214
215 static const unsigned char conf_event_begin[] = {
216 0, /* Does not exist. */
217 0, /* Root section. */
218 IPA_CONF_EVENT_GLOBAL_BEGIN, /* global{} */
219 IPA_CONF_EVENT_RULE_BEGIN, /* rule{} */
220 IPA_CONF_EVENT_LIMIT_BEGIN, /* limit{} */
221 IPA_CONF_EVENT_THRESHOLD_BEGIN, /* threshold{} */
222 IPA_CONF_EVENT_AUTORULE_BEGIN, /* autorule{} */
223 IPA_CONF_EVENT_RULEPAT_BEGIN, /* rulepat{} */
224 IPA_CONF_EVENT_STARTUP_BEGIN, /* startup{} */
225 IPA_CONF_EVENT_SHUTDOWN_BEGIN, /* shutdown{} */
226 IPA_CONF_EVENT_RESTART_BEGIN, /* restart{} */
227 IPA_CONF_EVENT_REACH_BEGIN, /* reach{} */
228 IPA_CONF_EVENT_EXPIRE_BEGIN, /* expire{} */
229 IPA_CONF_EVENT_IF_REACHED_BEGIN, /* if_reached{} */
230 IPA_CONF_EVENT_IF_NOT_REACHED_BEGIN, /* if_not_reached{} */
231 IPA_CONF_EVENT_IF_ALL_REACHED_BEGIN, /* if_all_reached{} */
232 IPA_CONF_EVENT_IF_ANY_REACHED_BEGIN, /* if_any_reached{} */
233 IPA_CONF_EVENT_IF_ANY_NOT_REACHED_BEGIN,/* if_any_not_reached{} */
234 IPA_CONF_EVENT_IF_ALL_NOT_REACHED_BEGIN,/* if_all_not_reached{} */
235 IPA_CONF_EVENT_BELOW_THRESHOLD_BEGIN, /* below_threshold{} */
236 IPA_CONF_EVENT_EQUAL_THRESHOLD_BEGIN, /* equal_threshold{} */
237 IPA_CONF_EVENT_ABOVE_THRESHOLD_BEGIN /* above_threshold{} */
238 };
239
240 static regex_t re_worktime; /* Regexp for "worktime". */
241 static regex_t re_list; /* Regexp for any list. */
242
243 static void confvlogmsgx(int, const char *, const char *, va_list)
244 ATTR_FORMAT(printf, 3, 0);
245
246 /*
247 * Exported support functions for modules.
248 */
249 static const ipa_suppfunc suppfunc = {
250 print_string, /* print_string */
251 print_bytes, /* print_bytes */
252 print_time, /* print_time */
253 print_value, /* print_value */
254 print_boolean, /* print_boolean */
255 print_space, /* print_space */
256 mod_print_param_name, /* print_param_name */
257 mod_print_args, /* print_param_args */
258 mod_print_param_end, /* print_param_end */
259 mod_print_sect_name, /* print_sect_name */
260 mod_print_args, /* print_sect_args */
261 print_sect_begin, /* print_sect_begin */
262 mod_print_sect_end, /* print_sect_end */
263 open_log, /* open_log */
264 close_log, /* close_log */
265 mod_logmsg, /* logmsg */
266 mod_logconferr, /* logconferr */
267 parser_local_sym_add, /* local_sym_add */
268 parser_local_sym_del, /* local_sym_del */
269 parser_global_sym_add, /* global_sym_add */
270 parser_global_sym_del /* global_sym_del */
271 };
272
273 /*
274 * Log message prepending it with the prefix.
275 * If use_log is set, then log is used, else printf(3) is used.
276 * Do not use mem_*() functions in this function.
277 */
278 static void
confvlogmsgx(int priority,const char * prefix,const char * format,va_list ap)279 confvlogmsgx(int priority, const char *prefix, const char *format, va_list ap)
280 {
281 if (use_log) {
282 char buf[LOG_BUF_SIZE];
283 char *msg;
284 int rv;
285
286 rv = vsnprintf(buf, sizeof(buf), format, ap);
287 if (rv < 0) {
288 logmsg(IPA_LOG_ERR, "confvlogmsgx: vsnprintf failed");
289 goto log_unformated;
290 }
291 if (rv < sizeof(buf)) {
292 logmsgx(priority, "%s: %s", prefix, buf);
293 return;
294 }
295 msg = malloc(++rv);
296 if (msg == NULL) {
297 logmsgx(IPA_LOG_ERR, "confvlogmsgx: malloc failed");
298 goto log_unformated;
299 }
300 if (vsnprintf(msg, rv, format, ap) < 0) {
301 logmsg(IPA_LOG_ERR, "confvlogmsgx: vsnprintf failed");
302 free(msg);
303 goto log_unformated;
304 }
305 logmsgx(priority, "%s: %s", prefix, msg);
306 free(msg);
307 return;
308 log_unformated:
309 logmsgx(priority, "%s: unformated message: %s",
310 prefix, format);
311 } else {
312 fflush(stdout);
313 fprintf(stderr, "%s: ", prefix);
314 vfprintf(stderr, format, ap);
315 fprintf(stderr, "\n");
316 }
317 }
318
319 /*
320 * The wrapper for parser_vlogmsgx.
321 */
322 static void
parser_vlogmsgx_wrapper(const char * format,va_list ap)323 parser_vlogmsgx_wrapper(const char *format, va_list ap)
324 {
325 confvlogmsgx(IPA_LOG_ERR, "parsing error", format, ap);
326 }
327
328 /*
329 * Wrappers for logging about configuration errors.
330 */
331 void
vlogconfe(const char * format,va_list ap)332 vlogconfe(const char *format, va_list ap)
333 {
334 confvlogmsgx(IPA_LOG_ERR, "configuration error", format, ap);
335 }
336
337 void
logconfe(const char * format,...)338 logconfe(const char *format, ...)
339 {
340 va_list ap;
341
342 va_start(ap, format);
343 vlogconfe(format, ap);
344 va_end(ap);
345 }
346
347 /*
348 * The same as above one, but with priority argument and va_list.
349 */
350 static void
vlogconfx_priority(int priority,const char * format,va_list ap)351 vlogconfx_priority(int priority, const char *format, va_list ap)
352 {
353 confvlogmsgx(priority, "configuration error", format, ap);
354 }
355
356 /*
357 * Try to find tevent with the given value of event_step.
358 * If such tevent does not exist, then allocate new one.
359 * Return NULL if new tevent cannot be allocated.
360 */
361 static struct tevent *
find_tevent(unsigned int event_step)362 find_tevent(unsigned int event_step)
363 {
364 struct tevent *tevent;
365
366 SLIST_FOREACH(tevent, &tevents_list, link)
367 if (tevent->event_step == event_step)
368 return (tevent);
369 tevent = mzone_alloc(tevent_mzone);
370 if (tevent != NULL) {
371 tevent->event_step = event_step;
372 SLIST_INSERT_HEAD(&tevents_list, tevent, link);
373 } else
374 logconfx("find_tevent: mzone_alloc failed");
375 return (tevent);
376 }
377
378 /*
379 * Register a configuration event in ac_mod module.
380 */
381 static int
ac_mod_conf_event(const struct ac_mod * ac_mod,unsigned int event,unsigned int no,const void * arg)382 ac_mod_conf_event(const struct ac_mod *ac_mod, unsigned int event,
383 unsigned int no, const void *arg)
384 {
385 if (ac_mod->ipa_ac_mod->conf_event(event, no, arg) < 0) {
386 logconfx("module %s: conf_event(IPA_CONF_EVENT_%s) failed",
387 ac_mod->mod_file, conf_event_msg[event]);
388 return (-1);
389 }
390 return (0);
391 }
392
393 /*
394 * Register a configuration event in db_mod module.
395 */
396 static int
db_mod_conf_event(const struct db_mod * db_mod,unsigned int event,unsigned int no,const void * arg)397 db_mod_conf_event(const struct db_mod *db_mod, unsigned int event,
398 unsigned int no, const void *arg)
399 {
400 if (db_mod->ipa_db_mod->conf_event(event, no, arg) < 0) {
401 logconfx("module %s: conf_event(IPA_CONF_EVENT_%s) failed",
402 db_mod->mod_file, conf_event_msg[event]);
403 return (-1);
404 }
405 return (0);
406 }
407
408 /*
409 * Register a configuration event in each module.
410 */
411 static int
mod_conf_event(unsigned int event,unsigned int no,const void * arg)412 mod_conf_event(unsigned int event, unsigned int no, const void *arg)
413 {
414 const struct ac_mod *ac_mod;
415 const struct db_mod *db_mod;
416
417 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
418 if (ac_mod_conf_event(ac_mod, event, no, arg) < 0)
419 return (-1);
420
421 SLIST_FOREACH(db_mod, &db_mod_list, link)
422 if (db_mod_conf_event(db_mod, event, no, arg) < 0)
423 return (-1);
424
425 return (0);
426 }
427
428 /*
429 * Parse the "global" section.
430 */
431 /* ARGSUSED */
432 static int
parse_global(void * arg ATTR_UNUSED)433 parse_global(void *arg ATTR_UNUSED)
434 {
435 if (global_section_set) {
436 logconfx("this section is duplicated");
437 return (-1);
438 }
439 global_section_set = 1;
440 return (0);
441 }
442
443 #ifdef WITH_RULES
444 /*
445 * Parse the "rule" section.
446 */
447 static int
parse_rule(void * arg)448 parse_rule(void *arg)
449 {
450 const char *name;
451 struct rule *rule;
452
453 name = *(char **)arg;
454 if (conf_validate_name(name) < 0)
455 return (-1);
456 if (rule_by_name(name) != NULL) {
457 logconfx("this section is duplicated");
458 return (-1);
459 }
460
461 rule = mzone_alloc(rule_mzone);
462 if (rule == NULL) {
463 logconfx("mzone_alloc failed");
464 return (-1);
465 }
466 rule->name = mem_strdup(name, m_anon);
467 if (rule->name == NULL) {
468 logconfx("mem_strdup failed");
469 return (-1);
470 }
471 rule->info = NULL;
472 rule->no = nstatrules++;
473
474 rule->cnt = rule->cnt_neg = 0;
475
476 rule->rule_flags = RULE_FLAG_ACTIVE
477 #ifdef WITH_LIMITS
478 | RULE_FLAG_FREE_LIMITS
479 #endif
480 #ifdef WITH_THRESHOLDS
481 | RULE_FLAG_FREE_THRESHOLDS
482 #endif
483 ;
484
485 rule->update_tevent = rule->append_tevent = NULL;
486 rule->worktime = NULL;
487
488 rule->ac_list = NULL;
489 rule->db_list = NULL;
490
491 rule->acg_add_pat = rule->acg_sub_pat = NULL;
492 SLIST_INIT(&rule->acgs);
493
494 rule->debug_exec = -1;
495 rule_init_cmds(rule);
496
497 #ifdef WITH_LIMITS
498 rule->debug_limit = rule->debug_limit_init = -1;
499 limits_list = &rule->limits;
500 STAILQ_INIT(limits_list);
501 limitno = 0;
502 #endif
503
504 #ifdef WITH_THRESHOLDS
505 rule->debug_threshold = rule->debug_threshold_init = -1;
506 thresholds_list = &rule->thresholds;
507 STAILQ_INIT(thresholds_list);
508 thresholdno = 0;
509 #endif
510
511 #ifdef CTL_CHECK_CREDS
512 rule->ctl_rule_acl = NULL;
513 #endif
514
515 section_first = section_top = IPA_CONF_SECT_RULE;
516 if (parser_local_sym_add("rule", rule->name, 0) < 0)
517 return (-1);
518
519 TAILQ_INSERT_TAIL(&rules_list, rule, list);
520 rules_hash_add(rule);
521 currule = rule;
522
523 conf_event_no = rule->no;
524 conf_event_arg = rule->name;
525
526 return (0);
527 }
528 #endif /* WITH_RULES */
529
530 /*
531 * Parse the "rulepat" section.
532 */
533 static int
parse_rulepat(void * arg)534 parse_rulepat(void *arg)
535 {
536 struct rulepat *rulepat;
537 char *pat;
538 int error;
539
540 pat = *(char **)arg;
541 STAILQ_FOREACH(rulepat, &rulepats_list, link)
542 if (strcmp(rulepat->pat, pat) == 0) {
543 logconfx("this section is duplicated");
544 return (-1);
545 }
546
547 rulepat = mzone_alloc(rulepat_mzone);
548 if (rulepat == NULL) {
549 logconfx("mzone_alloc failed");
550 return (-1);
551 }
552 STAILQ_INSERT_TAIL(&rulepats_list, rulepat, link);
553
554 error = regcomp(&rulepat->re, pat, REG_EXTENDED|REG_NOSUB);
555 if (error != 0) {
556 logconfx("regcomp(\"%s\"): %s", pat, regerrbuf(error));
557 return (-1);
558 }
559
560 rulepat->pat = pat;
561 rulepat->no = rulepatno++;
562
563 rulepat->check_next = -1;
564
565 rulepat->update_tevent = rulepat->append_tevent = NULL;
566 rulepat->worktime = NULL;
567
568 rulepat->ac_list = NULL;
569 rulepat->db_list = NULL;
570
571 rulepat->debug_exec = -1;
572
573 cmds_rule_init(&rulepat->rc[RC_STARTUP]);
574 cmds_rule_init(&rulepat->rc[RC_SHUTDOWN]);
575
576 #ifdef WITH_LIMITS
577 rulepat->debug_limit = rulepat->debug_limit_init = -1;
578 limits_list = &rulepat->limits;
579 STAILQ_INIT(limits_list);
580 limitno = 0;
581 #endif
582
583 #ifdef WITH_THRESHOLDS
584 rulepat->debug_threshold = rulepat->debug_threshold_init = -1;
585 thresholds_list = &rulepat->thresholds;
586 STAILQ_INIT(thresholds_list);
587 thresholdno = 0;
588 #endif
589
590 #ifdef CTL_CHECK_CREDS
591 rulepat->ctl_rule_acl = NULL;
592 #endif
593
594 section_first = section_top = IPA_CONF_SECT_RULEPAT;
595 currulepat = rulepat;
596
597 conf_event_no = rulepat->no;
598 conf_event_arg = rulepat->pat;
599
600 return (0);
601 }
602
603 /*
604 * Parse the "check_next_rulepat" parameter.
605 */
606 static int
parse_check_next_rulepat(void * arg)607 parse_check_next_rulepat(void *arg)
608 {
609 currulepat->check_next = *(int *)arg;
610 return (0);
611 }
612
613 /*
614 * Parse an argument of some "debug_*" parameter.
615 */
616 static signed char
check_debug_level(uint32_t level,unsigned int maxlevel)617 check_debug_level(uint32_t level, unsigned int maxlevel)
618 {
619 if (level > maxlevel) {
620 logconfx("too big debug level, max level is %u", maxlevel);
621 return (-1);
622 }
623 return ((signed char)level);
624 }
625
626 /*
627 * Parse the "debug_time" parameter.
628 */
629 static int
parse_debug_time(void * arg)630 parse_debug_time(void *arg)
631 {
632 debug_time = check_debug_level(*(uint32_t *)arg, 2);
633 return (debug_time);
634 }
635
636 /*
637 * Parse the "debug_ac_null" parameter.
638 */
639 static int
parse_debug_ac_null(void * arg)640 parse_debug_ac_null(void *arg)
641 {
642 debug_ac_null = check_debug_level(*(uint32_t *)arg, 1);
643 return (debug_ac_null);
644 }
645
646 /*
647 * Parse the "debug_db_null" parameter.
648 */
649 static int
parse_debug_db_null(void * arg)650 parse_debug_db_null(void *arg)
651 {
652 debug_db_null = check_debug_level(*(uint32_t *)arg, 1);
653 return (debug_db_null);
654 }
655
656 /*
657 * Parse the "debug_worktime" parameter.
658 */
659 static int
parse_debug_worktime(void * arg)660 parse_debug_worktime(void *arg)
661 {
662 debug_worktime = check_debug_level(*(uint32_t *)arg, 1);
663 return (debug_worktime);
664 }
665
666 /*
667 * Parse the "debug_exec" parameter.
668 */
669 static int
parse_debug_exec(void * arg)670 parse_debug_exec(void *arg)
671 {
672 signed char level;
673
674 level = check_debug_level(*(uint32_t *)arg, 2);
675 if (level < 0)
676 return (-1);
677 switch (section) {
678 case IPA_CONF_SECT_GLOBAL:
679 global_debug_exec = level;
680 break;
681 #ifdef WITH_RULES
682 case IPA_CONF_SECT_RULE:
683 currule->debug_exec = level;
684 break;
685 #endif
686 #ifdef WITH_AUTORULES
687 case IPA_CONF_SECT_AUTORULE:
688 curautorule->debug_exec = level;
689 break;
690 #endif
691 case IPA_CONF_SECT_RULEPAT:
692 currulepat->debug_exec = level;
693 break;
694 }
695 return (0);
696 }
697
698 /*
699 * Parse the "update_time" parameter.
700 */
701 static int
parse_update_time(void * arg)702 parse_update_time(void *arg)
703 {
704 uint64_t timeval;
705 struct tevent *tevent;
706
707 timeval = *(uint64_t *)arg;
708 if (timeval == 0 || timeval > SECONDS_IN_DAY) {
709 logconfx("argument should be greater than zero seconds "
710 "and less than or equal to 1 day");
711 return (-1);
712 }
713 tevent = find_tevent((unsigned int)timeval);
714 if (tevent == NULL)
715 return (-1);
716 switch (section) {
717 case IPA_CONF_SECT_GLOBAL:
718 global_update_tevent = tevent;
719 break;
720 #ifdef WITH_RULES
721 case IPA_CONF_SECT_RULE:
722 currule->update_tevent = tevent;
723 break;
724 #endif
725 #ifdef WITH_AUTORULES
726 case IPA_CONF_SECT_AUTORULE:
727 curautorule->update_tevent = tevent;
728 break;
729 #endif
730 case IPA_CONF_SECT_RULEPAT:
731 currulepat->update_tevent = tevent;
732 break;
733 }
734 return (0);
735 }
736
737 /*
738 * Parse the "freeze_time" parameter.
739 */
740 static int
parse_freeze_time(void * arg)741 parse_freeze_time(void *arg)
742 {
743 uint64_t timeval;
744
745 timeval = *(uint64_t *)arg;
746 if (timeval == 0 || timeval >= 5 * SECONDS_IN_MINUTE) {
747 logconfx("argument should be greater than zero seconds "
748 "and less than 5 minutes");
749 return (-1);
750 }
751 freeze_time = (unsigned int)timeval;
752 return (0);
753 }
754
755 /*
756 * Parse the "append_time" parameter.
757 */
758 static int
parse_append_time(void * arg)759 parse_append_time(void *arg)
760 {
761 uint64_t timeval;
762 struct tevent *tevent;
763
764 timeval = *(uint64_t *)arg;
765 if (timeval == 0 || timeval > SECONDS_IN_DAY) {
766 logconfx("argument should be greater than zero seconds and "
767 "less than or equal to 1 day");
768 return (-1);
769 }
770 tevent = find_tevent((unsigned int)timeval);
771 if (tevent == NULL)
772 return (-1);
773 switch (section) {
774 case IPA_CONF_SECT_GLOBAL:
775 global_append_tevent = tevent;
776 break;
777 #ifdef WITH_RULES
778 case IPA_CONF_SECT_RULE:
779 currule->append_tevent = tevent;
780 break;
781 #endif
782 #ifdef WITH_AUTORULES
783 case IPA_CONF_SECT_AUTORULE:
784 curautorule->append_tevent = tevent;
785 break;
786 #endif
787 case IPA_CONF_SECT_RULEPAT:
788 currulepat->append_tevent = tevent;
789 break;
790 }
791 return (0);
792 }
793
794 /*
795 * Parse the "wakeup_time" parameter.
796 */
797 static int
parse_wakeup_time(void * arg)798 parse_wakeup_time(void *arg)
799 {
800 uint64_t timeval;
801
802 timeval = *(uint64_t *)arg;
803 if (timeval == 0 || timeval > SECONDS_IN_DAY) {
804 logconfx("argument should be greater than zero seconds and "
805 "less than or equal to 1 day");
806 return (-1);
807 }
808 wakeup_time = (unsigned int)timeval;
809 return (0);
810 }
811
812 /*
813 * Parse the "value_units" parameter.
814 */
815 static int
parse_value_units(void * arg)816 parse_value_units(void *arg)
817 {
818 unsigned int i;
819
820 if (value_units >= 0) {
821 logconfx("cannot re-define this parameter");
822 return (-1);
823 }
824 if (got_arg_value) {
825 logconfx("this parameter must be used before other parameters "
826 "and sections, that accept the IPA_CONF_TYPE_VALUE data "
827 "type");
828 return (-1);
829 }
830 for (i = 0; i < VALUE_UNITS_TBL_SIZE; ++i)
831 if (strcmp(*(char **)arg, value_units_tbl[i].str) == 0) {
832 value_units = value_units_tbl[i].val;
833 return (0);
834 }
835 logconfx("wrong value");
836 return (-1);
837 }
838
839 #if defined(WITH_THRESHOLDS) || defined(WITH_SUBLIMITS)
840 /*
841 * get_arg_value() plus get_arg_per_cent().
842 */
843 static int
get_value_or_per_cent(uint64_t * val_ptr,unsigned char * type_ptr)844 get_value_or_per_cent(uint64_t *val_ptr, unsigned char *type_ptr)
845 {
846 uint64_t val;
847 char *args;
848 unsigned char type;
849
850 args = parser_args;
851 if (regexec_simple(&re_bytes, args) == 0) {
852 if (get_arg_bytes(&val) < 0)
853 return (-1);
854 type = IPA_CONF_TYPE_BYTES;
855 } else if (regexec_simple(&re_time, args) == 0) {
856 if (get_arg_time(&val) < 0)
857 return (-1);
858 type = IPA_CONF_TYPE_TIME;
859 } else {
860 args += parser_args_len - 1;
861 if (*args == '%') {
862 *args = '\0';
863 type = IPA_CONF_TYPE_PER_CENT;
864 } else
865 type = IPA_CONF_TYPE_UINT64;
866 if (get_arg_uint64(&val) < 0)
867 return (-1);
868 if (type == IPA_CONF_TYPE_PER_CENT && val > 100) {
869 logconfx("per cent value should less than or "
870 "equal to 100%%");
871 return (-1);
872 }
873 }
874 *val_ptr = val;
875 *type_ptr = type;
876 return (0);
877 }
878 #endif /* WITH_THRESHOLDS || WITH_SUBLIMITS */
879
880 #ifdef WITH_LIMITS
881 /*
882 * Parse the "debug_limit" parameter.
883 */
884 static int
parse_debug_limit(void * arg)885 parse_debug_limit(void *arg)
886 {
887 signed char level;
888
889 level = check_debug_level(*(uint32_t *)arg, 1);
890 if (level < 0)
891 return (-1);
892 switch (section) {
893 case IPA_CONF_SECT_GLOBAL:
894 global_debug_limit = level;
895 break;
896 #ifdef WITH_RULES
897 case IPA_CONF_SECT_RULE:
898 currule->debug_limit = level;
899 break;
900 #endif
901 #ifdef WITH_AUTORULES
902 case IPA_CONF_SECT_AUTORULE:
903 curautorule->debug_limit = level;
904 break;
905 #endif
906 case IPA_CONF_SECT_RULEPAT:
907 currulepat->debug_limit = level;
908 break;
909 }
910 return (0);
911 }
912
913 /*
914 * Parse the "debug_limit_init" parameter.
915 */
916 static int
parse_debug_limit_init(void * arg)917 parse_debug_limit_init(void *arg)
918 {
919 signed char level;
920
921 level = check_debug_level(*(uint32_t *)arg, 1);
922 if (level < 0)
923 return (-1);
924 switch (section) {
925 case IPA_CONF_SECT_GLOBAL:
926 global_debug_limit_init = level;
927 break;
928 #ifdef WITH_RULES
929 case IPA_CONF_SECT_RULE:
930 currule->debug_limit_init = level;
931 break;
932 #endif
933 #ifdef WITH_AUTORULES
934 case IPA_CONF_SECT_AUTORULE:
935 curautorule->debug_limit_init = level;
936 break;
937 #endif
938 case IPA_CONF_SECT_RULEPAT:
939 currulepat->debug_limit_init = level;
940 break;
941 }
942 return (0);
943 }
944
945 /*
946 * Parse the "load_limit" parameter.
947 */
948 static int
parse_load_limit(void * arg)949 parse_load_limit(void *arg)
950 {
951 if (section == IPA_CONF_SECT_LIMIT)
952 curlimit->load_limit = (signed char)*(int *)arg;
953 else /* IPA_CONF_SECT_GLOBAL */
954 global_load_limit = (signed char)*(int *)arg;
955 return (0);
956 }
957
958 /*
959 * Parse the "limit" section.
960 */
961 static int
parse_limit_sect(void * arg)962 parse_limit_sect(void *arg)
963 {
964 const char *name;
965 struct limit *limit;
966
967 name = *(char **)arg;
968 if (conf_validate_name(name) < 0)
969 return (-1);
970 STAILQ_FOREACH(limit, limits_list, link)
971 if (strcmp(limit->name, name) == 0) {
972 logconfx("this section is duplicated");
973 return (-1);
974 }
975 limit = mzone_alloc(limit_mzone);
976 if (limit == NULL) {
977 logconfx("mzone_alloc failed");
978 return (-1);
979 }
980 limit->name = mem_strdup(name, m_anon);
981 if (limit->name == NULL) {
982 logconfx("mem_strdup failed");
983 return (-1);
984 }
985 limit->info = NULL;
986
987 STAILQ_INSERT_TAIL(limits_list, limit, link);
988 limit->no = limitno++;
989
990 limit->lim_flags = LIMIT_FLAG_ACTIVE;
991
992 limit->cnt_neg = 0;
993
994 limit->db_list = NULL;
995
996 #ifdef WITH_SUBLIMITS
997 STAILQ_INIT(&limit->sublimits);
998 #endif
999
1000 limit->restart.restart.upto = limit->expire.expire.upto =
1001 TEXP_UPTO_NOTSET;
1002 limit_init_cmds(limit);
1003
1004 limit->worktime = NULL;
1005
1006 limit->wpid.type = WPID_TYPE_LIMIT;
1007 limit->wpid.pid = 0;
1008 limit->wpid.u.limit = limit;
1009
1010 #ifdef WITH_RULES
1011 limit->rule = currule;
1012 #endif
1013
1014 limit->load_limit = -1;
1015
1016 if (section_top == IPA_CONF_SECT_RULE)
1017 ++nstatlimits;
1018 section_top = IPA_CONF_SECT_LIMIT;
1019
1020 if (parser_local_sym_add("limit", limit->name, 0) < 0)
1021 return (-1);
1022
1023 curlimit = limit;
1024 conf_event_no = limit->no;
1025 conf_event_arg = limit->name;
1026
1027 return (0);
1028 }
1029
1030 /*
1031 * Parse the "limit" parameter.
1032 */
1033 static int
parse_limit_param(void * arg)1034 parse_limit_param(void *arg)
1035 {
1036 struct limit *limit;
1037 uint64_t *ptr;
1038
1039 limit = curlimit;
1040 if (LIMIT_IS_SET(limit)) {
1041 logconfx("cannot re-define this parameter");
1042 return (-1);
1043 }
1044
1045 limit->lim_flags |= LIMIT_FLAG_SET;
1046 ptr = (uint64_t *)arg;
1047 limit->lim = ptr[1];
1048 limit->cnt_type = (unsigned char)ptr[0];
1049 return (0);
1050 }
1051
1052 #ifdef WITH_SUBLIMITS
1053 /*
1054 * Parse the "sublimit" section.
1055 */
1056 static int
parse_sublimit(void * arg)1057 parse_sublimit(void *arg)
1058 {
1059 uint64_t lim;
1060 struct limit *limit;
1061 struct sublimit *sublimit;
1062 char *name;
1063 unsigned char cnt_type;
1064
1065 limit = curlimit;
1066 if (LIMIT_IS_NOTSET(limit)) {
1067 logconfx("\"limit\" parameter in previous section should "
1068 "be specified before");
1069 return (-1);
1070 }
1071
1072 if (conf_validate_name(*(char **)arg) < 0)
1073 return (-1);
1074 name = mem_strdup(*(char **)arg, m_anon);
1075 if (name == NULL) {
1076 logconfx("mem_strdup failed");
1077 return (-1);
1078 }
1079
1080 if (get_value_or_per_cent(&lim, &cnt_type) < 0)
1081 return (-1);
1082 if (lim == 0) {
1083 logconfx("argument should be greater than zero");
1084 return (-1);
1085 }
1086 if (cnt_type != IPA_CONF_TYPE_PER_CENT &&
1087 cnt_type != limit->cnt_type) {
1088 logconfx("different arguments types for sublimit and limit");
1089 return (-1);
1090 }
1091
1092 STAILQ_FOREACH(sublimit, &limit->sublimits, link)
1093 if (cnt_type == IPA_CONF_TYPE_PER_CENT) {
1094 if ((unsigned int)lim == sublimit->lim_pc) {
1095 logconfx("this section is duplicated");
1096 return (-1);
1097 }
1098 } else {
1099 if (lim == sublimit->lim) {
1100 logconfx("this section is duplicated");
1101 return (-1);
1102 }
1103 }
1104
1105 sublimit = mzone_alloc(sublimit_mzone);
1106 if (sublimit == NULL) {
1107 logconfx("mzone_alloc failed");
1108 return (-1);
1109 }
1110
1111 STAILQ_INSERT_TAIL(&limit->sublimits, sublimit, link);
1112
1113 sublimit->name = name;
1114 if (cnt_type == IPA_CONF_TYPE_PER_CENT)
1115 sublimit->lim_pc = (unsigned int)lim;
1116 else {
1117 sublimit->lim = lim;
1118 sublimit->lim_pc = 0;
1119 }
1120 sublimit->cnt_type = cnt_type;
1121
1122 sublimit_init_cmds(sublimit);
1123
1124 sublimit->wpid.type = WPID_TYPE_SUBLIMIT;
1125 sublimit->wpid.pid = 0;
1126 sublimit->wpid.u.sublimit = sublimit;
1127
1128 sublimit->limit = limit;
1129
1130 if (section_top == IPA_CONF_SECT_RULE)
1131 ++nstatsublimits;
1132 section_top = SECT_SUBLIMIT;
1133
1134 if (parser_local_sym_add("sublimit", sublimit->name, 0) < 0)
1135 return (-1);
1136
1137 cursublimit = sublimit;
1138
1139 return (0);
1140 }
1141 #endif /* WITH_SUBLIMITS */
1142
1143 /*
1144 * Parse "expired time" value.
1145 */
1146 static int
parse_texp(struct texp * texp,const void * arg)1147 parse_texp(struct texp *texp, const void *arg)
1148 {
1149 const char *ptr;
1150 char *endptr;
1151 uint32_t value;
1152 char level, error, overflow;
1153
1154 ptr = (const char *)arg;
1155 level = error = overflow = 0;
1156
1157 texp->seconds = 0;
1158 texp->upto = TEXP_UPTO_SIMPLE;
1159 for (;;) {
1160 if (*ptr == ' ')
1161 ++ptr;
1162 if (*ptr == '+') {
1163 texp->upto = *++ptr;
1164 texp->side = (char)(texp->seconds > 0);
1165 if (*++ptr == '\0') {
1166 /* EOL */
1167 break;
1168 }
1169 continue;
1170 }
1171 if (strto_uint32(&value, ptr, &endptr) < 0)
1172 return (-1);
1173 ptr = endptr;
1174 switch (*ptr) {
1175 case 'W':
1176 if (level > 1)
1177 error = 1;
1178 else if (value > UINT32_MAX / SECONDS_IN_WEEK)
1179 overflow = 1;
1180 else {
1181 level = 2;
1182 value *= SECONDS_IN_WEEK;
1183 }
1184 break;
1185 case 'D':
1186 if (level > 2)
1187 error = 1;
1188 else if (value > UINT32_MAX / SECONDS_IN_DAY)
1189 overflow = 1;
1190 else {
1191 level = 3;
1192 value *= SECONDS_IN_DAY;
1193 }
1194 break;
1195 case 'h':
1196 if (level > 3)
1197 error = 1;
1198 else if (value > UINT32_MAX / SECONDS_IN_HOUR)
1199 overflow = 1;
1200 else {
1201 level = 4;
1202 value *= SECONDS_IN_HOUR;
1203 }
1204 break;
1205 case 'm':
1206 if (level > 4)
1207 error = 1;
1208 else if (value > UINT32_MAX / SECONDS_IN_MINUTE)
1209 overflow = 1;
1210 else {
1211 level = 5;
1212 value *= SECONDS_IN_MINUTE;
1213 }
1214 break;
1215 default: /* 's' */
1216 if (level > 5)
1217 error = 1;
1218 else
1219 level = 6;
1220 }
1221 if (error) {
1222 logconfx("wrong format of an argument");
1223 return (-1);
1224 }
1225 if (overflow || texp->seconds > UINT_MAX - value) {
1226 logconfx("too big value for 'unsigned int'");
1227 return (-1);
1228 }
1229 texp->seconds += (unsigned int)value;
1230 if (*++ptr == '\0') {
1231 /* EOL */
1232 break;
1233 }
1234 }
1235 return (0);
1236 }
1237
1238 /*
1239 * Parse the "restart" parameter.
1240 */
1241 static int
parse_restart(void * arg)1242 parse_restart(void *arg)
1243 {
1244 struct texp *texp;
1245
1246 texp = &curlimit->restart.restart;
1247 if (parse_texp(texp, *(char **)arg) < 0)
1248 return (-1);
1249 if (texp->seconds == 0 && texp->upto == TEXP_UPTO_SIMPLE) {
1250 logconfx("argument should be greater than zero");
1251 return (-1);
1252 }
1253 return (0);
1254 }
1255
1256 /*
1257 * Parse the "expire" parameter.
1258 */
1259 static int
parse_expire(void * arg)1260 parse_expire(void *arg)
1261 {
1262 return (parse_texp(&curlimit->expire.expire, *(char **)arg));
1263 }
1264 #endif /* WITH_LIMITS */
1265
1266 /*
1267 * Parse the "exec" parameter.
1268 */
1269 static int
parse_exec(void * arg)1270 parse_exec(void *arg)
1271 {
1272 struct cmd *cmd;
1273 char *start, *ptr, *str;
1274 int allow_subst;
1275
1276 if (parser_nargs > 2) {
1277 logconfx("one or two arguments are expected");
1278 return (-1);
1279 }
1280
1281 /* Allocate new structure for command. */
1282 cmd = mzone_alloc(cmd_mzone);
1283 if (cmd == NULL) {
1284 logconfx("mzone_alloc failed");
1285 return (-1);
1286 }
1287 STAILQ_INSERT_TAIL(&curcmds->cmd_list, cmd, link);
1288 curcmds->has_cmd = 1;
1289
1290 /* user "..." or "..." */
1291 str = *(char **)arg;
1292 if (parser_nargs == 2) {
1293 if (*str == '\"') {
1294 logconfx("wrong format of an argument");
1295 return (-1);
1296 }
1297 ptr = str;
1298 str = strchr(str, ' ');
1299 *str++ = '\0';
1300 cmd->user = mem_strdup(ptr, m_cmd);
1301 if (cmd->user == NULL) {
1302 logconfx("mem_strdup failed");
1303 return (-1);
1304 }
1305 cmd->free_mask = CMD_FREE_STR|CMD_FREE_USER;
1306 } else {
1307 cmd->user = NULL;
1308 cmd->free_mask = CMD_FREE_STR;
1309 }
1310
1311 /* Check for "..." */
1312 if (!parser_buf_is_str(str)) {
1313 logconfx("wrong format of an argument");
1314 return (-1);
1315 }
1316
1317 /* Copy "..." */
1318 cmd->str = parser_strdup(str, m_cmd);
1319 if (cmd->str == NULL)
1320 return (-1);
1321
1322 /* Validate "..." */
1323 str = cmd->str;
1324 if (*str == '\0') {
1325 logconfx("command should be a non-empty string");
1326 return (-1);
1327 }
1328 if (*str != '/' && only_abs_paths != 0) {
1329 logconfx("command should be given with absolute path");
1330 return (-1);
1331 }
1332
1333 switch (section_first) {
1334 #ifdef WITH_AUTORULES
1335 case IPA_CONF_SECT_AUTORULE:
1336 #endif
1337 case IPA_CONF_SECT_RULEPAT:
1338 allow_subst = 1;
1339 break;
1340 default:
1341 allow_subst = 0;
1342 }
1343
1344 /* Check if a string has correct substitutions and count them. */
1345 start = NULL;
1346 cmd->subst_per_cent = cmd->subst_rule = 0;
1347 cmd->str_size = 1;
1348 for (ptr = str; *ptr != '\0'; cmd->str_size++, ++ptr) {
1349 if (allow_subst && *ptr == '%') {
1350 if (start == NULL)
1351 start = ptr + 1;
1352 else if (ptr != start) {
1353 /* %xxx% */
1354 *ptr = '\0';
1355 if (strcmp(start, "rule") != 0) {
1356 logconfx("unknown substitution "
1357 "%%\"%s\"%% in a command", start);
1358 return (-1);
1359 }
1360 *ptr = '%';
1361 cmd->subst_rule++;
1362 start = NULL;
1363 } else {
1364 /* %% */
1365 cmd->subst_per_cent++;
1366 start = NULL;
1367 }
1368 }
1369 }
1370 if (start != NULL) {
1371 logconfx("not closed substitution in a command");
1372 return (-1);
1373 }
1374
1375 return (0);
1376 }
1377
1378 #ifdef WITH_RULES
1379 /*
1380 * Find the next field in a string starting from *end. If there is
1381 * a next field, then return 1 and return the start of the next field
1382 * in *beg and a pointer to the next character after the end of the
1383 * next field in *end. Otherwise return 0.
1384 */
1385 static int
next_field(char ** beg,char ** end)1386 next_field(char **beg, char **end)
1387 {
1388 char *ptr;
1389 int in_string;
1390
1391 /* Skip spaces. */
1392 for (ptr = *end;; ++ptr) {
1393 if (*ptr == '\0')
1394 return (0);
1395 if (*ptr != ' ' && *ptr != '\t')
1396 break;
1397 }
1398
1399 *beg = ptr;
1400
1401 /* Skip data. */
1402 for (in_string = 0; *ptr != '\0'; ++ptr)
1403 switch (*ptr) {
1404 case ' ':
1405 case '\t':
1406 if (!in_string)
1407 goto done;
1408 break;
1409 case '\"':
1410 in_string = !in_string;
1411 break;
1412 case '\\':
1413 if (in_string)
1414 ++ptr;
1415 }
1416 done:
1417 if (*ptr != '\0') {
1418 *ptr = '\0';
1419 *end = ptr + 1;
1420 } else
1421 *end = ptr;
1422 return (1);
1423 }
1424
1425 /*
1426 * Parse the "ictl" parameter.
1427 * Possible combinations:
1428 * "-r <rule> set ..."
1429 * "-r <rule> -l <limit> restart"
1430 * "-r <rule> -l <limit> expire"
1431 * "-r <rule> -l <limit> set ..."
1432 * "-r <rule> -t <threshold> set ..."
1433 */
1434 static int
parse_ictl(void * arg)1435 parse_ictl(void *arg)
1436 {
1437 uint64_t value[2];
1438 const char *name1;
1439 struct ictl *ictl;
1440 char *beg, *end, *cmd_str;
1441 #ifdef WITH_ANY_LIMITS
1442 char *name2;
1443 #endif
1444 unsigned int cmd, qflags, qflagset;
1445 int this_rule;
1446
1447 if (section_first != IPA_CONF_SECT_RULE &&
1448 section_first != IPA_CONF_SECT_ROOT) {
1449 logconfx("this parameter can be used only inside static "
1450 "rules and inside global startup{} section");
1451 return (-1);
1452 }
1453 if (section_rc == RC_SHUTDOWN) {
1454 logconfx("this parameter cannot be used inside "
1455 "shutdown{} section");
1456 return (-1);
1457 }
1458 if (!STAILQ_EMPTY(&curcmds->cmd_list)) {
1459 logconfx("this parameter should be used before \"exec\" "
1460 "parameters in one section");
1461 return (-1);
1462 }
1463
1464 ictl = mzone_alloc(ictl_mzone);
1465 if (ictl == NULL) {
1466 logconfx("mzone_alloc failed");
1467 return (-1);
1468 }
1469 STAILQ_INSERT_TAIL(&curcmds->ictl_list, ictl, link);
1470 curcmds->has_cmd = 1;
1471
1472 cmd_str = mem_strdup(*(char **)arg, m_ctl);
1473 if (cmd_str == NULL) {
1474 logconfx("mem_strdup failed");
1475 return (-1);
1476 }
1477
1478 /* Check "-r ..." and get rule's name. */
1479 end = *(char **)arg;
1480 if (!next_field(&beg, &end))
1481 goto short_command;
1482 if (beg[0] != '-' || beg[1] != 'r') {
1483 logconfx("command should begin with -r");
1484 return (-1);
1485 }
1486 if (beg[2] == '\0') {
1487 if (!next_field(&beg, &end))
1488 goto short_command;
1489 } else
1490 beg += 2;
1491 name1 = beg;
1492 if (conf_validate_name(name1) < 0)
1493 return (-1);
1494
1495 /* Next field can be command or "-l" or "-t" option. */
1496 if (next_field(&beg, &end) == 0)
1497 goto short_command;
1498 if (beg[0] == '-' && beg[1] == 'l') {
1499 #ifdef WITH_LIMITS
1500 qflags = CTL_CFLAG_RULE|CTL_CFLAG_LIMIT;
1501 #else
1502 logconfx("limits support was disabled");
1503 return (-1);
1504 #endif
1505 } else if (beg[0] == '-' && beg[1] == 't') {
1506 #ifdef WITH_THRESHOLDS
1507 qflags = CTL_CFLAG_RULE|CTL_CFLAG_THRESHOLD;
1508 #else
1509 logconfx("thresholds support was disabled");
1510 return (-1);
1511 #endif
1512 } else
1513 qflags = CTL_CFLAG_RULE;
1514
1515 #ifdef WITH_ANY_LIMITS
1516 if (qflags & (CTL_CFLAG_LIMIT|CTL_CFLAG_THRESHOLD)) {
1517 /* Get limit's or threshold's name. */
1518 if (beg[2] == '\0') {
1519 if (!next_field(&beg, &end))
1520 goto short_command;
1521 } else
1522 beg += 2;
1523 name2 = beg;
1524 if (conf_validate_name(name2) < 0)
1525 return (-1);
1526 /* Get command. */
1527 if (!next_field(&beg, &end))
1528 goto short_command;
1529 } else
1530 name2 = NULL;
1531 #endif
1532
1533 /* Here beg points to command. */
1534 if (strcmp(beg, "set") == 0)
1535 cmd = CTL_CMD_SET;
1536 #ifdef WITH_LIMITS
1537 else if (strcmp(beg, "restart") == 0)
1538 cmd = CTL_CMD_RESTART;
1539 else if (strcmp(beg, "expire") == 0)
1540 cmd = CTL_CMD_EXPIRE;
1541 #endif
1542 else {
1543 logconfx("unknown or unsupported command \"%s\"", beg);
1544 return (-1);
1545 }
1546
1547 if (cmd == CTL_CMD_SET) {
1548 /* Parse arguments of a "set" command. */
1549 while (next_field(&beg, &end)) {
1550 if (strcmp(beg, "counter") == 0)
1551 qflagset = CTL_CFLAG_VALUE2;
1552 #ifdef WITH_LIMITS
1553 else if (strcmp(beg, "limit") == 0) {
1554 if (!(qflags & CTL_CFLAG_LIMIT))
1555 goto wrong_keyword;
1556 qflagset = CTL_CFLAG_VALUE1;
1557 }
1558 #endif
1559 #ifdef WITH_THRESHOLDS
1560 else if (strcmp(beg, "threshold") == 0) {
1561 if (!(qflags & CTL_CFLAG_THRESHOLD))
1562 goto wrong_keyword;
1563 qflagset = CTL_CFLAG_VALUE1;
1564 }
1565 #endif
1566 else
1567 goto wrong_keyword;
1568
1569 if (qflags & qflagset)
1570 goto duped_keyword;
1571 qflags |= qflagset;
1572
1573 if (!next_field(&beg, &end))
1574 goto short_command;
1575 switch (*beg) {
1576 case '+':
1577 qflags |= qflagset == CTL_CFLAG_VALUE1 ?
1578 CTL_CFLAG_VALUE1_INC : CTL_CFLAG_VALUE2_INC;
1579 ++beg;
1580 break;
1581 case '-':
1582 qflags |= qflagset == CTL_CFLAG_VALUE1 ?
1583 CTL_CFLAG_VALUE1_DEC : CTL_CFLAG_VALUE2_DEC;
1584 ++beg;
1585 break;
1586 default:
1587 if (!(qflags &
1588 (CTL_CFLAG_LIMIT|CTL_CFLAG_THRESHOLD))) {
1589 logconfx("it is allowed only to "
1590 "increase or decrease statistics "
1591 "of a rule");
1592 return (-1);
1593 }
1594 }
1595 parser_args = beg;
1596 if (get_arg_value(value) < 0)
1597 return (-1);
1598 if (qflagset == CTL_CFLAG_VALUE2)
1599 ictl->values.value2 = value[1];
1600 #ifdef WITH_ANY_LIMITS
1601 else
1602 ictl->values.value1 = value[1];
1603 #endif
1604 }
1605 if (!(qflags & (CTL_CFLAG_VALUE1|CTL_CFLAG_VALUE2)))
1606 goto short_command;
1607 }
1608 #ifdef WITH_LIMITS
1609 else if (!(qflags & CTL_CFLAG_LIMIT)) {
1610 logconfx("command \"%s\" can be used only with limits", beg);
1611 return (-1);
1612 } else if (next_field(&beg, &end)) {
1613 logconfx("too many arguments for command \"%s\"", beg);
1614 return (-1);
1615 }
1616 #endif
1617
1618 /* At this point command was successfully parsed. */
1619 ictl->rule.name = mem_strdup(name1, m_ctl);
1620 if (ictl->rule.name == NULL) {
1621 logconfx("mem_strdup failed");
1622 return (-1);
1623 }
1624
1625 this_rule = section_first == IPA_CONF_SECT_RULE &&
1626 strcmp(currule->name, name1) == 0;
1627 if (this_rule && !(qflags & (CTL_CFLAG_LIMIT|CTL_CFLAG_THRESHOLD))) {
1628 logconfx("rule is not allowed to change own statistics");
1629 return (-1);
1630 }
1631
1632 #ifdef WITH_ANY_LIMITS
1633 if (name2 != NULL) {
1634 name2 = mem_strdup(name2, m_ctl);
1635 if (name2 == NULL) {
1636 logconfx("mem_strdup failed");
1637 return (-1);
1638 }
1639 # ifdef WITH_LIMITS
1640 if (qflags & CTL_CFLAG_LIMIT) {
1641 if (this_rule &&
1642 section_top == IPA_CONF_SECT_LIMIT &&
1643 strcmp(curlimit->name, name2) == 0) {
1644 logconfx("limit is not allowed to change "
1645 "own statistics");
1646 return (-1);
1647 }
1648 ictl->limit.name = name2;
1649 }
1650 # endif
1651 # ifdef WITH_THRESHOLDS
1652 if (qflags & CTL_CFLAG_THRESHOLD) {
1653 if (this_rule &&
1654 section_top == IPA_CONF_SECT_THRESHOLD &&
1655 strcmp(curthreshold->name, name2) == 0) {
1656 logconfx("threshold is not allowed to change "
1657 "own statistics");
1658 return (-1);
1659 }
1660 ictl->threshold.name = name2;
1661 }
1662 # endif
1663 }
1664 #endif /* WITH_ANY_LIMITS */
1665
1666 ictl->cmdq.cmd = cmd;
1667 ictl->cmdq.flags = qflags;
1668 ictl->str = cmd_str;
1669
1670 mem_free(*(char **)arg, m_parser);
1671 return (0);
1672
1673 duped_keyword:
1674 logconfx("duplicated keyword \"%s\" in a command", beg);
1675 return (-1);
1676
1677 short_command:
1678 logconfx("command is incomplete");
1679 return (-1);
1680
1681 wrong_keyword:
1682 logconfx("wrong keyword \"%s\" in a command", beg);
1683 return (-1);
1684 }
1685 #endif /* WITH_RULES */
1686
1687 /*
1688 * Parse the "sync_exec" parameter.
1689 */
1690 static int
parse_sync_exec(void * arg)1691 parse_sync_exec(void *arg)
1692 {
1693 curcmds->sync = (signed char)*(int *)arg;
1694 return (0);
1695 }
1696
1697 #if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
1698 /*
1699 * Parse the "info" parameter.
1700 */
1701 static int
parse_info(void * arg)1702 parse_info(void *arg)
1703 {
1704 char *ptr, **pptr;
1705
1706 for (ptr = *(char **)arg; *ptr != '\0'; ++ptr)
1707 switch (*ptr) {
1708 case '\t':
1709 case '\n':
1710 logconfx("'\\t' and '\\n' are not allowed");
1711 return (-1);
1712 }
1713
1714 switch (section) {
1715 #ifdef WITH_RULES
1716 case IPA_CONF_SECT_RULE:
1717 pptr = &currule->info;
1718 break;
1719 #endif
1720 #ifdef WITH_LIMITS
1721 case IPA_CONF_SECT_LIMIT:
1722 pptr = &curlimit->info;
1723 break;
1724 #endif
1725 #ifdef WITH_THRESHOLDS
1726 default: /* IPA_CONF_SECT_THRESHOLD */
1727 pptr = &curthreshold->info;
1728 break;
1729 #endif
1730 }
1731
1732 if (*pptr != NULL) {
1733 logconfx("cannot re-define this parameter");
1734 return (-1);
1735 }
1736
1737 *pptr = *(char **)arg;
1738 return (0);
1739 }
1740 #endif /* WITH_RULES || WITH_ANY_LIMITS */
1741
1742 static const char wdays_short[DAYS_IN_WEEK] = {
1743 'S', 'M', 'T', 'W', 'H', 'F', 'A'
1744 };
1745
1746 static const struct worktime *
parse_generic_worktime(void * arg)1747 parse_generic_worktime(void *arg)
1748 {
1749 struct worktime *wt;
1750 struct tint *tint1, *tint2;
1751 struct tint_set *set1, *set2;
1752 struct tint_list *list;
1753 char *ptr;
1754 unsigned int wday, h1, m1, h2, m2, h2_prev, m2_prev;
1755
1756 wt = mzone_alloc(worktime_mzone);
1757 if (wt == NULL) {
1758 logconfx("mzone_alloc failed");
1759 return (NULL);
1760 }
1761
1762 for (wday = 0; wday < DAYS_IN_WEEK; ++wday)
1763 wt->tint_list[wday] = &tint_list_empty;
1764
1765 for (ptr = *(char **)arg; *ptr != '\0';) {
1766 wday = strchr(wdays_short, *ptr) - wdays_short;
1767 if (wt->tint_list[wday] != &tint_list_empty) {
1768 logconfx("each day (currently %s) should be "
1769 "specified only one time", wdays[wday]);
1770 return (NULL);
1771 }
1772
1773 set1 = mem_malloc(sizeof(*set1), m_anon);
1774 if (set1 == NULL) {
1775 logconfx("mem_malloc failed");
1776 return (NULL);
1777 }
1778 list = &set1->list;
1779 STAILQ_INIT(list);
1780
1781 h2_prev = m2_prev = 0;
1782 ptr += 2;
1783 for (;;) {
1784 if (*ptr == '*') {
1785 h1 = m1 = m2 = 0;
1786 h2 = HOURS_IN_DAY;
1787 } else if (!isdigit((unsigned char)*ptr)) {
1788 /* Next day in worktime. */
1789 break;
1790 } else {
1791 errno = 0;
1792 if (sscanf(ptr, "%u:%u-%u:%u", &h1, &m1, &h2,
1793 &m2) != 4) {
1794 logconf("sscanf(%s) failed", ptr);
1795 return (NULL);
1796 }
1797 if ((h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59)
1798 && !(h2 == HOURS_IN_DAY && m2 == 0)) {
1799 logconfx("wrong value of hours or "
1800 "minutes in time interval for %s",
1801 wdays[wday]);
1802 return (NULL);
1803 }
1804 if (h1 == h2 && m1 == m2) {
1805 logconfx("zero seconds time intervals "
1806 "are not allowed");
1807 return (NULL);
1808 }
1809 if ((h1 * MINUTES_IN_HOUR + m1) >
1810 (h2 * MINUTES_IN_HOUR + m2)) {
1811 logconfx("wrong time interval for "
1812 "%s: %02u:%02u-%02u:%02u",
1813 wdays[wday], h1, m1, h2, m2);
1814 return (NULL);
1815 }
1816 if (h2_prev * MINUTES_IN_HOUR + m2_prev >
1817 h1 * MINUTES_IN_HOUR + m1) {
1818 logconfx("nonsuccessive time interval "
1819 "for %s", wdays[wday]);
1820 return (NULL);
1821 }
1822 }
1823
1824 tint1 = mzone_alloc(tint_mzone);
1825 if (tint1 == NULL) {
1826 logconfx("mzone_alloc failed");
1827 return (NULL);
1828 }
1829 tint1->sec1 = h1 * SECONDS_IN_HOUR +
1830 m1 * SECONDS_IN_MINUTE;
1831 tint1->sec2 = h2 * SECONDS_IN_HOUR +
1832 m2 * SECONDS_IN_MINUTE;
1833 STAILQ_INSERT_TAIL(&set1->list, tint1, link);
1834
1835 for (; *ptr != ' '; ++ptr)
1836 if (*ptr == '\0')
1837 goto done;
1838 ++ptr;
1839 h2_prev = h2;
1840 m2_prev = m2;
1841 }
1842 done:
1843 /*
1844 * If there is already the same tint_list,
1845 * then free memory used by just allocated one.
1846 */
1847 STAILQ_FOREACH(set2, &tint_sets, link) {
1848 tint1 = STAILQ_FIRST(&set1->list);
1849 tint2 = STAILQ_FIRST(&set2->list);
1850 while (tint1 != NULL && tint2 != NULL) {
1851 if (tint1->sec1 != tint2->sec1 ||
1852 tint1->sec2 != tint2->sec2)
1853 break;
1854 tint1 = STAILQ_NEXT(tint1, link);
1855 tint2 = STAILQ_NEXT(tint2, link);
1856 }
1857 if (tint1 == NULL && tint2 == NULL) {
1858 /* Duplicate tint_list was found. */
1859 free_tint_set(set1);
1860 set1 = set2;
1861 break;
1862 }
1863 }
1864 if (set2 == NULL)
1865 /* New tint_list --> add it to tint_sets. */
1866 STAILQ_INSERT_TAIL(&tint_sets, set1, link);
1867
1868 wt->tint_list[wday] = &set1->list;
1869 }
1870
1871 /*
1872 * Since "ictl" can be used before newday() is called, need to mark
1873 * worktime as active, since by default all static rules are active
1874 * on startup.
1875 */
1876 wt->wt_flags = WT_FLAG_ACTIVE;
1877
1878 return (find_worktime(wt));
1879 }
1880
1881 /*
1882 * Parse the "worktime" parameter.
1883 */
1884 static int
parse_worktime(void * arg)1885 parse_worktime(void *arg)
1886 {
1887 const struct worktime **wtpp;
1888
1889 switch (section) {
1890 #ifdef WITH_RULES
1891 case IPA_CONF_SECT_RULE:
1892 wtpp = &currule->worktime;
1893 break;
1894 #endif
1895 #ifdef WITH_LIMITS
1896 case IPA_CONF_SECT_LIMIT:
1897 wtpp = &curlimit->worktime;
1898 break;
1899 #endif
1900 #ifdef WITH_THRESHOLDS
1901 case IPA_CONF_SECT_THRESHOLD:
1902 wtpp = &curthreshold->worktime;
1903 break;
1904 #endif
1905 #ifdef WITH_AUTORULES
1906 case IPA_CONF_SECT_AUTORULE:
1907 wtpp = &curautorule->worktime;
1908 break;
1909 #endif
1910 case IPA_CONF_SECT_RULEPAT:
1911 wtpp = &currulepat->worktime;
1912 break;
1913 default: /* IPA_CONF_SECT_GLOBAL */
1914 wtpp = &global_worktime;
1915 }
1916
1917 if (*wtpp != NULL) {
1918 logconfx("cannot re-define this parameter");
1919 return (-1);
1920 }
1921
1922 *wtpp = parse_generic_worktime(arg);
1923 return (*wtpp == NULL ? -1 : 0);
1924 }
1925
1926 #ifdef WITH_AUTORULES
1927 /*
1928 * Parse the "worktime_rule" parameter.
1929 */
1930 static int
parse_worktime_rule(void * arg)1931 parse_worktime_rule(void *arg)
1932 {
1933 struct autorule *autorule;
1934
1935 autorule = curautorule;
1936 if (autorule->worktime_rule != NULL) {
1937 logconfx("cannot re-define this parameter");
1938 return (-1);
1939 }
1940 autorule->worktime_rule = parse_generic_worktime(arg);
1941 return (autorule->worktime_rule == NULL ? -1 : 0);
1942 }
1943 #endif
1944
1945 /*
1946 * Check security of a configuration file: absolute path, regular file,
1947 * is owned by the user who run ipa, writable only for the user.
1948 */
1949 static int
check_conf_file(const char * fname,int ignore_non_regular)1950 check_conf_file(const char *fname, int ignore_non_regular)
1951 {
1952 struct stat statbuf;
1953
1954 if (stat(fname, &statbuf) < 0) {
1955 logconfe("stat(%s): %s", fname, strerror(errno));
1956 return (-1);
1957 }
1958 if (!S_ISREG(statbuf.st_mode)) {
1959 if (ignore_non_regular)
1960 return (0);
1961 logconfe("configuration file \"%s\" should be a regular file",
1962 fname);
1963 return (-1);
1964 }
1965 if (statbuf.st_uid != myuid) {
1966 logconfe("configuration file \"%s\" should be owned by the "
1967 "user, who run this program", fname);
1968 return (-1);
1969 }
1970 if (statbuf.st_mode & (S_IWGRP|S_IWOTH)) {
1971 logconfe("configuration file \"%s\" should not have write "
1972 "permissions for group or other users", fname);
1973 return (-1);
1974 }
1975 return (1);
1976 }
1977
1978 /*
1979 * Check file path: non empty string and should start with '/'.
1980 */
1981 static int
check_file_path(const char * fname,const char * what)1982 check_file_path(const char *fname, const char *what)
1983 {
1984 if (*fname == '\0') {
1985 logconfx("argument should be a non-empty string");
1986 return (-1);
1987 }
1988 if (*fname != '/') {
1989 logconfx("%s should be given with absolute path", what);
1990 return (-1);
1991 }
1992 return (0);
1993 }
1994
1995 static int
check_include_depth(void)1996 check_include_depth(void)
1997 {
1998 if (include_depth > INCLUDE_DEPTH_MAX) {
1999 logconfx("too big (> %u) depth of included files",
2000 INCLUDE_DEPTH_MAX);
2001 return (-1);
2002 }
2003 return (0);
2004 }
2005
2006 /*
2007 * Parse the "include" parameter.
2008 */
2009 static int
parse_include(void * arg)2010 parse_include(void *arg)
2011 {
2012 struct parser_pb *pb;
2013 char *fname;
2014
2015 /* Save offset of current configuration file and close it. */
2016 fname = *(char **)arg;
2017 pb = parser_top_pb();
2018 pb->foff = ftell(pb->fp);
2019 if (pb->foff < 0) {
2020 logconf("ftell(%s)", pb->fname);
2021 return (-1);
2022 }
2023 if (fclose(pb->fp) != 0) {
2024 logconf("fclose(%s)", pb->fname);
2025 return (-1);
2026 }
2027
2028 /* Validate an argument. */
2029 if (check_file_path(fname, "file") < 0)
2030 return (-1);
2031
2032 /* Check security of configuration file. */
2033 if (check_conf_file(fname, 0) < 0)
2034 return (-1);
2035
2036 ++include_depth;
2037 if (check_include_depth() < 0)
2038 return (-1);
2039
2040 /* Open included configuration file and put it to stack. */
2041 pb = parser_new_pb(0);
2042 if (pb == NULL)
2043 return (-1);
2044 pb->fp = fopen(fname, "r");
2045 if (pb->fp == NULL) {
2046 logconf("fopen(%s, \"r\")", fname);
2047 return (-1);
2048 }
2049 pb->fname = fname;
2050 return (parser_push_pb(pb));
2051 }
2052
2053 /*
2054 * Parse the "include_files" parameter.
2055 */
2056 static int
parse_include_files(void * arg)2057 parse_include_files(void *arg)
2058 {
2059 struct stat statbuf;
2060 regex_t re;
2061 const struct dirent *dp;
2062 struct parser_pb *pb, *tpb;
2063 char *dir, *pat, *fname;
2064 DIR *dirp;
2065
2066 /* Validate an argument. */
2067 dir = *(char **)arg;
2068 if (check_file_path(dir, "directory") < 0)
2069 return (-1);
2070
2071 pat = strrchr(dir, '/');
2072 *pat++ = '\0';
2073 if (posix_re_pattern > 0) {
2074 int error;
2075
2076 error = regcomp(&re, pat, REG_EXTENDED|REG_NOSUB);
2077 if (error != 0) {
2078 logconfx("cannot compile regular expression: "
2079 "regcomp(\"%s\"): %s", pat, regerrbuf(error));
2080 return (-1);
2081 }
2082 }
2083
2084 /* Check security of the given directory. */
2085 if (lstat(dir, &statbuf) < 0) {
2086 logconf("lstat(%s)", dir);
2087 return (-1);
2088 }
2089 if (!S_ISDIR(statbuf.st_mode)) {
2090 logconfx("given pathname is not a directory");
2091 return (-1);
2092 }
2093 if (statbuf.st_uid != myuid) {
2094 logconfx("directory should be owned by the user, who run "
2095 "this program");
2096 return (-1);
2097 }
2098 if (statbuf.st_mode & (S_IWGRP|S_IWOTH)) {
2099 logconfx("directory should not have write permissions for "
2100 "group and other users");
2101 return (-1);
2102 }
2103
2104 /* Read directory and push pb to stack. */
2105 dirp = opendir(dir);
2106 if (dirp == NULL) {
2107 logconf("opendir(%s)", dir);
2108 return (-1);
2109 }
2110 pb = NULL;
2111 tpb = parser_top_pb();
2112 for (;;) {
2113 errno = 0;
2114 dp = readdir(dirp);
2115 if (dp == NULL) {
2116 if (errno != 0) {
2117 logconf("readdir(%s)", dir);
2118 return (-1);
2119 }
2120 break;
2121 }
2122 /* Ignore "." and ".." directories. */
2123 if (dp->d_name[0] == '.')
2124 switch (dp->d_name[1]) {
2125 case '\0':
2126 continue;
2127 case '.':
2128 if (dp->d_name[2] == '\0')
2129 continue;
2130 }
2131 if (posix_re_pattern != 1) {
2132 if (fnmatch(pat, dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
2133 continue;
2134 } else {
2135 if (regexec_simple(&re, dp->d_name) != 0)
2136 continue;
2137 }
2138 if (mem_asprintf(m_parser, &fname, "%s/%s", dir,
2139 dp->d_name) < 0) {
2140 logconfx("mem_asprintf failed");
2141 return (-1);
2142 }
2143 switch (check_conf_file(fname, 1)) {
2144 case -1:
2145 return (-1);
2146 case 0:
2147 mem_free(fname, m_parser);
2148 continue;
2149 }
2150 pb = parser_new_pb(0);
2151 if (pb == NULL)
2152 return (-1);
2153 pb->fname = fname;
2154 pb->foff = 0;
2155 if (parser_push_pb(pb) < 0)
2156 return (-1);
2157 }
2158 if (posix_re_pattern > 0)
2159 regfree(&re);
2160 if (closedir(dirp) < 0) {
2161 logconf("closedir(%s)", dir);
2162 return (-1);
2163 }
2164 mem_free(dir, m_parser);
2165 if (pb != NULL) {
2166 tpb->foff = ftell(tpb->fp);
2167 if (tpb->foff < 0) {
2168 logconf("ftell(%s)", tpb->fname);
2169 return (-1);
2170 }
2171 if (fclose(tpb->fp) != 0) {
2172 logconf("fclose(%s)", tpb->fname);
2173 return (-1);
2174 }
2175 ++include_depth;
2176 if (check_include_depth() < 0)
2177 return (-1);
2178 pb->fp = fopen(pb->fname, "r");
2179 if (pb->fp == NULL) {
2180 logconf("fopen(%s, \"r\")", pb->fname);
2181 return (-1);
2182 }
2183 }
2184 return (0);
2185 }
2186
2187 /*
2188 * Parse the "keep_rules_order" parameter.
2189 */
2190 static int
parse_keep_rules_order(void * arg)2191 parse_keep_rules_order(void *arg)
2192 {
2193 keep_rules_order = (signed char)*(int *)arg;
2194 return (0);
2195 }
2196
2197 /*
2198 * Parse the "only_abs_paths" parameter.
2199 */
2200 static int
parse_only_abs_paths(void * arg)2201 parse_only_abs_paths(void *arg)
2202 {
2203 only_abs_paths = (signed char)*(int *)arg;
2204 return (0);
2205 }
2206
2207 /*
2208 * Parse the "ac_mod" parameter.
2209 */
2210 static int
parse_ac_mod(void * arg)2211 parse_ac_mod(void *arg)
2212 {
2213 const struct ac_mod *ac_mod2;
2214 struct ipa_ac_mod *ipa_ac_mod;
2215 struct ac_mod *ac_mod;
2216 char *mod_name, *sym;
2217
2218 ac_mod = mem_malloc(sizeof(*ac_mod), m_anon);
2219 if (ac_mod == NULL) {
2220 logconfx("mem_malloc failed");
2221 return (-1);
2222 }
2223 ac_mod->mod_file = *(char **)arg;
2224 ac_mod->mod_ref_count = 0;
2225 ac_mod->mod_handle = dl_open(ac_mod->mod_file);
2226 if (ac_mod->mod_handle == NULL) {
2227 logconfx("dl_open(%s): %s", ac_mod->mod_file, dl_error());
2228 return (-1);
2229 }
2230 mod_name = get_mod_name(ac_mod->mod_file);
2231 if (mod_name == NULL)
2232 return (-1);
2233 if (mem_asprintf(m_anon, &sym, "%s_ac_mod", mod_name) < 0) {
2234 logconfx("mem_asprintf failed");
2235 return (-1);
2236 }
2237 ac_mod->ipa_ac_mod =
2238 (struct ipa_ac_mod *)dl_lookup_sym(ac_mod->mod_handle, sym);
2239 if (ac_mod->ipa_ac_mod == NULL) {
2240 logconfx("given module is not an IPA accounting module "
2241 "or unknown symbol naming scheme is used");
2242 return (-1);
2243 }
2244 mem_free(sym, m_anon);
2245 mem_free(mod_name, m_anon);
2246 ipa_ac_mod = ac_mod->ipa_ac_mod;
2247
2248 /* Check ipa_ac_mod API version. */
2249 if (ipa_ac_mod->api_ver != IPA_AC_MOD_API_VERSION) {
2250 logconfx("module %s uses ipa_ac_mod API version %u, "
2251 "my ipa_ac_mod API version is %u", ac_mod->mod_file,
2252 ipa_ac_mod->api_ver, IPA_AC_MOD_API_VERSION);
2253 return (-1);
2254 }
2255
2256 /* Check if module is thread-safe or vice versa. */
2257 #ifdef WITH_PTHREAD
2258 if (!(ipa_ac_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE)) {
2259 logconfx("module %s must be thread-safe", ac_mod->mod_file);
2260 return (-1);
2261 }
2262 #else
2263 if (ipa_ac_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE) {
2264 logconfx("module %s must not be thread-safe",
2265 ac_mod->mod_file);
2266 return (-1);
2267 }
2268 #endif /* WITH_PTHREAD */
2269
2270 if (strcmp(ipa_ac_mod->ac_name, "null") == 0) {
2271 logconfx("module's accounting system name is \"null\", "
2272 "this is a name of the built-in accounting system");
2273 return (-1);
2274 }
2275
2276 ac_mod2 = ac_mod_by_name(ipa_ac_mod->ac_name);
2277 if (ac_mod2 != NULL) {
2278 logconfx("duplicated accounting system name \"%s\" in %s and "
2279 "%s modules", ipa_ac_mod->ac_name, ac_mod->mod_file,
2280 ac_mod2->mod_file);
2281 return (-1);
2282 }
2283 if (ipa_ac_mod->conf_prefix != NULL) {
2284 const struct db_mod *db_mod;
2285
2286 ac_mod2 = ac_mod_by_prefix(ipa_ac_mod->conf_prefix);
2287 if (ac_mod2 != NULL) {
2288 logconfx("duplicated configuration prefix \"%s\" in "
2289 "%s and %s modules", ipa_ac_mod->conf_prefix,
2290 ac_mod->mod_file, ac_mod2->mod_file);
2291 return (-1);
2292 }
2293 db_mod = db_mod_by_prefix(ipa_ac_mod->conf_prefix);
2294 if (db_mod != NULL) {
2295 logconfx("duplicated configuration prefix \"%s\" in "
2296 "%s and %s modules", ipa_ac_mod->conf_prefix,
2297 ac_mod->mod_file, db_mod->mod_file);
2298 return (-1);
2299 }
2300 }
2301
2302 ipa_ac_mod->suppfunc = &suppfunc;
2303 ipa_ac_mod->memfunc = &memfunc;
2304 ipa_ac_mod->ac_create_rule = create_rule;
2305 ipa_ac_mod->ac_delete_rule = delete_rule;
2306
2307 if (init_conf_tbls(ac_mod->mod_file, 1,
2308 ipa_ac_mod->conf_sect_tbl, &ac_mod->conf_sect_hash,
2309 ipa_ac_mod->conf_param_tbl, &ac_mod->conf_param_hash) < 0)
2310 return (-1);
2311
2312 if (ipa_ac_mod->conf_init() < 0) {
2313 logconfx("module %s: conf_init failed", ac_mod->mod_file);
2314 return (-1);
2315 }
2316
2317 SLIST_INSERT_HEAD(&ac_mod_list, ac_mod, link);
2318 ++nac_mods;
2319 return (0);
2320 }
2321
2322 /*
2323 * Parse the "db_mod" parameter.
2324 */
2325 static int
parse_db_mod(void * arg)2326 parse_db_mod(void *arg)
2327 {
2328 const struct db_mod *db_mod2;
2329 struct ipa_db_mod *ipa_db_mod;
2330 struct db_mod *db_mod;
2331 char *mod_name, *sym;
2332
2333 db_mod = mem_malloc(sizeof(*db_mod), m_anon);
2334 if (db_mod == NULL) {
2335 logconfx("mem_malloc failed");
2336 return (-1);
2337 }
2338 db_mod->mod_file = *(char **)arg;
2339 db_mod->mod_handle = dl_open(db_mod->mod_file);
2340 if (db_mod->mod_handle == NULL) {
2341 logconfx("dl_open(%s): %s", db_mod->mod_file, dl_error());
2342 return (-1);
2343 }
2344 mod_name = get_mod_name(db_mod->mod_file);
2345 if (mod_name == NULL)
2346 return (-1);
2347 if (mem_asprintf(m_anon, &sym, "%s_db_mod", mod_name) < 0) {
2348 logconfx("mem_asprintf failed");
2349 return (-1);
2350 }
2351 db_mod->ipa_db_mod =
2352 (struct ipa_db_mod *)dl_lookup_sym(db_mod->mod_handle, sym);
2353 if (db_mod->ipa_db_mod == NULL) {
2354 logconfx("given module is not an IPA database module or "
2355 "unknown symbol naming scheme is used");
2356 return (-1);
2357 }
2358 mem_free(sym, m_anon);
2359 mem_free(mod_name, m_anon);
2360 ipa_db_mod = db_mod->ipa_db_mod;
2361
2362 /* Check ipa_db_mod API version. */
2363 if (ipa_db_mod->api_ver != IPA_DB_MOD_API_VERSION) {
2364 logconfx("module %s uses ipa_db_mod API version %u, "
2365 "my ipa_db_mod API version is %u", db_mod->mod_file,
2366 ipa_db_mod->api_ver, IPA_DB_MOD_API_VERSION);
2367 return (-1);
2368 }
2369
2370 /* Check if module is thread-safe or vice versa. */
2371 #ifdef WITH_PTHREAD
2372 if (!(ipa_db_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE)) {
2373 logconfx("module %s must be thread-safe", db_mod->mod_file);
2374 return (-1);
2375 }
2376 #else
2377 if (ipa_db_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE) {
2378 logconfx("module %s must not be thread-safe",
2379 db_mod->mod_file);
2380 return (-1);
2381 }
2382 #endif /* WITH_PTHREAD */
2383
2384 if (strcmp(ipa_db_mod->db_name, "null") == 0) {
2385 logconfx("module's database name is \"null\","
2386 "this is a name of the built-in database");
2387 return (-1);
2388 }
2389
2390 db_mod2 = db_mod_by_name(ipa_db_mod->db_name);
2391 if (db_mod2 != NULL) {
2392 logconfx("duplicated database name \"%s\" in %s and %s modules",
2393 ipa_db_mod->db_name, db_mod->mod_file, db_mod2->mod_file);
2394 return (-1);
2395 }
2396 if (ipa_db_mod->conf_prefix != NULL) {
2397 const struct ac_mod *ac_mod;
2398
2399 db_mod2 = db_mod_by_prefix(ipa_db_mod->conf_prefix);
2400 if (db_mod2 != NULL) {
2401 logconfx("duplicated configuration prefix \"%s\" in "
2402 "%s and %s modules", ipa_db_mod->conf_prefix,
2403 db_mod->mod_file, db_mod2->mod_file);
2404 return (-1);
2405 }
2406 ac_mod = ac_mod_by_prefix(ipa_db_mod->conf_prefix);
2407 if (ac_mod != NULL) {
2408 logconfx("duplicated configuration prefix \"%s\" in "
2409 "%s and %s modules", ipa_db_mod->conf_prefix,
2410 db_mod->mod_file, ac_mod->mod_file);
2411 return (-1);
2412 }
2413 }
2414
2415 ipa_db_mod->suppfunc = &suppfunc;
2416 ipa_db_mod->memfunc = &memfunc;
2417
2418 if (init_conf_tbls(db_mod->mod_file, 1,
2419 ipa_db_mod->conf_sect_tbl, &db_mod->conf_sect_hash,
2420 ipa_db_mod->conf_param_tbl, &db_mod->conf_param_hash) < 0)
2421 return (-1);
2422
2423 if (ipa_db_mod->conf_init() < 0) {
2424 logconfx("module %s: conf_init failed", db_mod->mod_file);
2425 return (-1);
2426 }
2427
2428 SLIST_INSERT_HEAD(&db_mod_list, db_mod, link);
2429 ++ndb_mods;
2430 return (0);
2431 }
2432
2433 /*
2434 * Parse the "ac_list" parameter.
2435 */
2436 static int
parse_ac_list(void * arg)2437 parse_ac_list(void *arg)
2438 {
2439 const struct ac_list **list_ptr;
2440 const char *ac_name;
2441 struct ac_elem *ac1, *ac2;
2442 struct ac_set *set1, *set2;
2443 struct ac_list *list;
2444 struct ac_mod *ac_mod;
2445 char *ptr;
2446
2447 switch (section) {
2448 #ifdef WITH_RULES
2449 case IPA_CONF_SECT_RULE:
2450 list_ptr = &currule->ac_list;
2451 break;
2452 #endif
2453 #ifdef WITH_AUTORULES
2454 case IPA_CONF_SECT_AUTORULE:
2455 list_ptr = &curautorule->ac_list;
2456 break;
2457 #endif
2458 case IPA_CONF_SECT_RULEPAT:
2459 list_ptr = &currulepat->ac_list;
2460 break;
2461 default: /* IPA_CONF_SECT_GLOBAL */
2462 list_ptr = &global_ac_list;
2463 }
2464
2465 if (*list_ptr != NULL) {
2466 logconfx("cannot re-define this parameter");
2467 return (-1);
2468 }
2469
2470 set1 = NULL;
2471 list = NULL;
2472
2473 for (ptr = *(char **)arg; ptr != NULL;) {
2474 /* Get the name of the next accounting system. */
2475 ac_name = ptr;
2476 ptr = strchr(ptr, ' ');
2477 if (ptr != NULL)
2478 *ptr++ = '\0';
2479
2480 /* Handle "null" accounting system. */
2481 if (strcmp(ac_name, "null") == 0) {
2482 if (list != NULL || ptr != NULL) {
2483 logconfx("built-in accounting system \"null\" "
2484 "cannot be used together with another "
2485 "accounting systems");
2486 return (-1);
2487 }
2488 *list_ptr = &ac_list_null;
2489 return (0);
2490 }
2491
2492 ac_mod = ac_mod_by_name(ac_name);
2493 if (ac_mod == NULL) {
2494 logconfx("cannot find module with \"%s\" "
2495 "accounting system name", ac_name);
2496 return (-1);
2497 }
2498
2499 if (set1 != NULL) {
2500 /* We already have set for current ac_list parameter. */
2501 STAILQ_FOREACH(ac1, list, link)
2502 if (strcmp(ac_name,
2503 ac1->ipa_ac_mod->ac_name) == 0) {
2504 logconfx("duplicated accounting system "
2505 "\"%s\"", ac_name);
2506 return (-1);
2507 }
2508 } else {
2509 /* Create new set for ac_list parameter. */
2510 set1 = mem_malloc(sizeof(*set1), m_anon);
2511 if (set1 == NULL) {
2512 logconfx("mem_malloc failed");
2513 return (-1);
2514 }
2515 list = &set1->list;
2516 STAILQ_INIT(list);
2517 }
2518
2519 /* Add new ac element to ac_list. */
2520 ac1 = mem_malloc(sizeof(*ac1), m_anon);
2521 if (ac1 == NULL) {
2522 logconfx("mem_malloc failed");
2523 return (-1);
2524 }
2525 ac1->ipa_ac_mod = ac_mod->ipa_ac_mod;
2526 ac1->mod_file = ac_mod->mod_file;
2527
2528 /* Increase reference counter if needed. */
2529 ac1->mod_ref_count = &ac_mod->mod_ref_count;
2530 switch (section) {
2531 #ifdef WITH_RULES
2532 case IPA_CONF_SECT_RULE:
2533 /* FALLTHROUGH */
2534 #endif
2535 #ifdef WITH_AUTORULES
2536 case IPA_CONF_SECT_AUTORULE:
2537 #endif
2538 ac_mod->mod_ref_count++;
2539 break;
2540 }
2541
2542 STAILQ_INSERT_TAIL(list, ac1, link);
2543 }
2544
2545 /*
2546 * If we already have the same ac_list (with elements exactly
2547 * in the same order), then free memory used by just allocated
2548 * one (mod_ref_count was updated above).
2549 */
2550 SLIST_FOREACH(set2, &ac_sets, link) {
2551 ac1 = STAILQ_FIRST(&set1->list);
2552 ac2 = STAILQ_FIRST(&set2->list);
2553 while (ac1 != NULL && ac2 != NULL) {
2554 if (ac1->ipa_ac_mod != ac2->ipa_ac_mod)
2555 break;
2556 ac1 = STAILQ_NEXT(ac1, link);
2557 ac2 = STAILQ_NEXT(ac2, link);
2558 }
2559 if (ac1 == NULL && ac2 == NULL) {
2560 /* Duplicated ac_list was found. */
2561 *list_ptr = &set2->list;
2562 free_ac_set(set1);
2563 return (0);
2564 }
2565 }
2566
2567 /* New ac_list --> add it to ac_sets. */
2568 *list_ptr = list;
2569 SLIST_INSERT_HEAD(&ac_sets, set1, link);
2570 return (0);
2571 }
2572
2573 /*
2574 * Parse the "db_list" parameter.
2575 */
2576 static int
parse_db_list(void * arg)2577 parse_db_list(void *arg)
2578 {
2579 const struct db_list **list_ptr;
2580 const struct db_mod *db_mod;
2581 const char *db_name;
2582 struct db_elem *db1, *db2;
2583 struct db_set *set1, *set2;
2584 struct db_list *list;
2585 char *ptr;
2586
2587 switch (section) {
2588 #ifdef WITH_RULES
2589 case IPA_CONF_SECT_RULE:
2590 list_ptr = &currule->db_list;
2591 break;
2592 #endif
2593 #ifdef WITH_AUTORULES
2594 case IPA_CONF_SECT_AUTORULE:
2595 list_ptr = &curautorule->db_list;
2596 break;
2597 #endif
2598 #ifdef WITH_LIMITS
2599 case IPA_CONF_SECT_LIMIT:
2600 list_ptr = &curlimit->db_list;
2601 break;
2602 #endif
2603 #ifdef WITH_THRESHOLDS
2604 case IPA_CONF_SECT_THRESHOLD:
2605 list_ptr = &curthreshold->db_list;
2606 break;
2607 #endif
2608 case IPA_CONF_SECT_RULEPAT:
2609 list_ptr = &currulepat->db_list;
2610 break;
2611 default: /* IPA_CONF_SECT_GLOBAL */
2612 list_ptr = &global_db_list;
2613 }
2614
2615 if (*list_ptr != NULL) {
2616 logconfx("cannot re-define this parameter");
2617 return (-1);
2618 }
2619
2620 set1 = NULL;
2621 list = NULL;
2622
2623 for (ptr = *(char **)arg; ptr != NULL;) {
2624 /* Get the name of the next database. */
2625 db_name = ptr;
2626 ptr = strchr(ptr, ' ');
2627 if (ptr != NULL)
2628 *ptr++ = '\0';
2629
2630 /* Handle "null" database. */
2631 if (strcmp(db_name, "null") == 0) {
2632 if (list != NULL || ptr != NULL) {
2633 logconfx("built-in \"null\" database cannot "
2634 "be used together with another databases");
2635 return (-1);
2636 }
2637 *list_ptr = &db_list_null;
2638 return (0);
2639 }
2640
2641 db_mod = db_mod_by_name(db_name);
2642 if (db_mod == NULL) {
2643 logconfx("cannot find module with \"%s\" database "
2644 "name", db_name);
2645 return (-1);
2646 }
2647
2648 if (set1 != NULL) {
2649 /* We already have set for current db_list parameter. */
2650 STAILQ_FOREACH(db1, list, link)
2651 if (strcmp(db_name,
2652 db1->ipa_db_mod->db_name) == 0) {
2653 logconfx("duplicated database \"%s\"",
2654 db_name);
2655 return (-1);
2656 }
2657 } else {
2658 /* Create new set for db_list parameter. */
2659 set1 = mem_malloc(sizeof(*set1), m_anon);
2660 if (set1 == NULL) {
2661 logconfx("mem_malloc failed");
2662 return (-1);
2663 }
2664 list = &set1->list;
2665 STAILQ_INIT(list);
2666 }
2667
2668 /* Add new db element to db_list. */
2669 db1 = mem_malloc(sizeof(*db1), m_anon);
2670 if (db1 == NULL) {
2671 logconfx("mem_malloc failed");
2672 return (-1);
2673 }
2674 db1->ipa_db_mod = db_mod->ipa_db_mod;
2675 db1->mod_file = db_mod->mod_file;
2676
2677 STAILQ_INSERT_TAIL(list, db1, link);
2678 }
2679
2680 /*
2681 * If we already have the same db_list (with elements exactly
2682 * in the same order), then free memory used by just allocated one.
2683 */
2684 SLIST_FOREACH(set2, &db_sets, link) {
2685 db1 = STAILQ_FIRST(&set1->list);
2686 db2 = STAILQ_FIRST(&set2->list);
2687 while (db1 != NULL && db2 != NULL) {
2688 if (db1->ipa_db_mod != db2->ipa_db_mod)
2689 break;
2690 db1 = STAILQ_NEXT(db1, link);
2691 db2 = STAILQ_NEXT(db2, link);
2692 }
2693 if (db1 == NULL && db2 == NULL) {
2694 /* Duplicated db_list was found. */
2695 *list_ptr = &set2->list;
2696 free_db_set(set1);
2697 return (0);
2698 }
2699 }
2700
2701 /* New db_list --> add it to db_sets. */
2702 *list_ptr = list;
2703 SLIST_INSERT_HEAD(&db_sets, set1, link);
2704 return (0);
2705 }
2706
2707 #ifdef WITH_RULES
2708 /*
2709 * Parse the "ac_gather_add" parameter.
2710 */
2711 static int
parse_ac_gather_add(void * arg)2712 parse_ac_gather_add(void *arg)
2713 {
2714 struct rule *rule;
2715 char *pat;
2716 int error;
2717
2718 rule = currule;
2719 if (rule->acg_add_pat != NULL) {
2720 logconfx("cannot re-define this parameter");
2721 return (-1);
2722 }
2723
2724 rule->acg_add_pat = pat = *(char **)arg;
2725 error = regcomp(&rule->acg_add_re, pat, REG_EXTENDED|REG_NOSUB);
2726 if (error != 0) {
2727 logconfx("regcomp(\"%s\"): %s", pat, regerrbuf(error));
2728 return (-1);
2729 }
2730
2731 if (rule->acg_sub_pat == NULL)
2732 SLIST_INSERT_HEAD(&acg_list, rule, acg_link);
2733 return (0);
2734 }
2735
2736 /*
2737 * Parse the "ac_gather_sub" parameter.
2738 */
2739 static int
parse_ac_gather_sub(void * arg)2740 parse_ac_gather_sub(void *arg)
2741 {
2742 struct rule *rule;
2743 char *pat;
2744 int error;
2745
2746 rule = currule;
2747 if (rule->acg_sub_pat != NULL) {
2748 logconfx("cannot re-define this parameter");
2749 return (-1);
2750 }
2751
2752 rule->acg_sub_pat = pat = *(char **)arg;
2753 error = regcomp(&rule->acg_sub_re, pat, REG_EXTENDED|REG_NOSUB);
2754 if (error != 0) {
2755 logconfx("regcomp(\"%s\"): %s", pat, regerrbuf(error));
2756 return (-1);
2757 }
2758
2759 if (rule->acg_add_pat == NULL)
2760 SLIST_INSERT_HEAD(&acg_list, rule, acg_link);
2761 return (0);
2762 }
2763 #endif /* WITH_RULES */
2764
2765 /*
2766 * Parse "posix_re_pattern" parameter.
2767 */
2768 static int
parse_posix_re_pattern(void * arg)2769 parse_posix_re_pattern(void *arg)
2770 {
2771 posix_re_pattern = (signed char)*(int *)arg;
2772 return (0);
2773 }
2774
2775 /*
2776 * Parse "shell_path" parameter.
2777 */
2778 static int
parse_shell_path(void * arg)2779 parse_shell_path(void *arg)
2780 {
2781 shell_path = *(char **)arg;
2782 if (*shell_path != '/') {
2783 logconfx("shell path should be absolute");
2784 return (-1);
2785 }
2786 return (0);
2787 }
2788
2789 /*
2790 * Parse "shell_arg1" parameter.
2791 */
2792 static int
parse_shell_arg1(void * arg)2793 parse_shell_arg1(void *arg)
2794 {
2795 shell_arg1 = *(char **)arg;
2796 return (0);
2797 }
2798
2799 /*
2800 * Parse "ctl_enable" parameter.
2801 */
2802 static int
parse_ctl_enable(void * arg)2803 parse_ctl_enable(void *arg)
2804 {
2805 ctl_enable = (signed char)*(int *)arg;
2806 return (0);
2807 }
2808
2809 /*
2810 * Parse "ctl_socket_path" parameter.
2811 */
2812 static int
parse_ctl_socket_path(void * arg)2813 parse_ctl_socket_path(void *arg)
2814 {
2815 struct sockaddr_un addr;
2816
2817 ctl_socket_path = *(char **)arg;
2818 if (*ctl_socket_path != '/') {
2819 logconfx("control socket path should be absolute");
2820 return (-1);
2821 }
2822 if (strlen(ctl_socket_path) + 1 > sizeof(addr.sun_path)) {
2823 logconfx("too long path (> %lu) for control socket path",
2824 (unsigned long)sizeof(addr.sun_path) - 1);
2825 return (-1);
2826 }
2827 return (0);
2828 }
2829
2830 /*
2831 * Parse "ctl_socket_perm" parameter.
2832 */
2833 static int
parse_ctl_socket_perm(void * arg)2834 parse_ctl_socket_perm(void *arg)
2835 {
2836 const char *ptr;
2837 mode_t val;
2838 int error;
2839
2840 ptr = *(char **)arg;
2841 val = 0;
2842 error = 0;
2843 for (; *ptr != '\0'; ++ptr)
2844 switch (*ptr) {
2845 case 'u':
2846 if (!(val & S_IWUSR))
2847 val |= S_IWUSR;
2848 else
2849 error = 1;
2850 break;
2851 case 'g':
2852 if (!(val & S_IWGRP))
2853 val |= S_IWGRP;
2854 else
2855 error = 1;
2856 break;
2857 case 'o':
2858 #ifdef CTL_CHECK_CREDS
2859 if (!(val & S_IWOTH))
2860 val |= S_IWOTH;
2861 else
2862 error = 1;
2863 break;
2864 #else
2865 logconfx("cannot allow to write to socket for "
2866 "other users because messages credentials are "
2867 "disabled");
2868 return (-1);
2869 #endif
2870 default:
2871 error = 1;
2872 }
2873 if (error) {
2874 logconfx("wrong value");
2875 return (-1);
2876 }
2877 ctl_socket_perm = val | S_IRUSR;
2878 return (0);
2879 }
2880
2881 /*
2882 * Parse "ctl_timeout" parameter.
2883 */
2884 static int
parse_ctl_timeout(void * arg)2885 parse_ctl_timeout(void *arg)
2886 {
2887 uint64_t timeval;
2888
2889 timeval = *(uint64_t *)arg;
2890 if (timeval == 0 || timeval >= 30) {
2891 logconfx("argument should be greater than zero seconds and "
2892 "less than 30 seconds");
2893 return (-1);
2894 }
2895 ctl_timeout = (unsigned int)timeval;
2896 return (0);
2897 }
2898
2899 /*
2900 * Parse "ctl_query_max_size" parameter.
2901 */
2902 static int
parse_ctl_query_max_size(void * arg)2903 parse_ctl_query_max_size(void *arg)
2904 {
2905 uint64_t val;
2906
2907 val = *(uint64_t *)arg;
2908 if (val > 10 * MBYTE) {
2909 logconfx("too big value (> 10M)");
2910 return (-1);
2911 }
2912 ctl_query_max_size = (size_t)val;
2913 return (0);
2914 }
2915
2916 /*
2917 * Parse "debug_ctl" parameter.
2918 */
2919 static int
parse_debug_ctl(void * arg)2920 parse_debug_ctl(void *arg)
2921 {
2922 debug_ctl = check_debug_level(*(uint32_t *)arg, 1);
2923 return (debug_ctl);
2924 }
2925
2926 #ifdef CTL_CHECK_CREDS
2927 /*
2928 * Find ctl class with the given name.
2929 */
2930 static const struct ctl_acl_class *
ctl_class_by_name(const char * class_name)2931 ctl_class_by_name(const char *class_name)
2932 {
2933 const struct ctl_acl_class *cl;
2934
2935 STAILQ_FOREACH(cl, &ctl_acl_classes, link)
2936 if (strcmp(cl->class_name, class_name) == 0)
2937 return (cl);
2938 return (NULL);
2939 }
2940
2941 /*
2942 * Parse "ctl_acl_class" parameter.
2943 */
2944 static int
parse_ctl_acl_class(void * arg)2945 parse_ctl_acl_class(void *arg)
2946 {
2947 struct ctl_acl_elem *elem;
2948 struct ctl_acl_class *class;
2949 char *ptr, *str;
2950
2951 /* class [elem1 elem2 ...] */
2952 str = *(char **)arg;
2953 ptr = strchr(str, ' ');
2954 if (ptr != NULL)
2955 *ptr = '\0';
2956
2957 /* Check if we already have class with the same name. */
2958 if (ctl_class_by_name(str) != NULL) {
2959 logconfx("duplicated ctl class \"%s\"", str);
2960 return (-1);
2961 }
2962
2963 /* New class. */
2964 class = mzone_alloc(ctl_acl_class_mzone);
2965 if (class == NULL) {
2966 logconfx("mzone_alloc failed");
2967 return (-1);
2968 }
2969 class->class_name = mem_strdup(str, m_ctl);
2970 if (class->class_name == NULL) {
2971 logconfx("mem_strdup failed");
2972 return (-1);
2973 }
2974
2975 /* Initialize ACL for new class. */
2976 STAILQ_INIT(&class->list);
2977
2978 /* Link new class to all classes list. */
2979 STAILQ_INSERT_TAIL(&ctl_acl_classes, class, link);
2980
2981 if (ptr == NULL)
2982 /* Empty class. */
2983 return (0);
2984
2985 str = ptr + 1;
2986
2987 do {
2988 elem = mzone_alloc(ctl_acl_elem_mzone);
2989 if (elem == NULL) {
2990 logconfx("mzone_alloc failed");
2991 return (-1);
2992 }
2993 STAILQ_INSERT_TAIL(&class->list, elem, link);
2994
2995 if (*str == '!') {
2996 elem->allowed = 0;
2997 ++str;
2998 } else
2999 elem->allowed = 1;
3000
3001 ptr = str;
3002 str = strchr(str, ' ');
3003 if (str != NULL)
3004 *str++ = '\0';
3005 if (*ptr == '%') {
3006 /* Group. */
3007 elem->user = NULL;
3008 elem->group = mem_strdup(++ptr, m_ctl);
3009 if (elem->group == NULL) {
3010 logconfx("mem_strdup failed");
3011 return (-1);
3012 }
3013 } else {
3014 /* User. */
3015 elem->user = mem_strdup(ptr, m_ctl);
3016 if (elem->user == NULL) {
3017 logconfx("mem_strdup failed");
3018 return (-1);
3019 }
3020 elem->group = NULL;
3021 }
3022 } while (str != NULL);
3023
3024 return (0);
3025 }
3026
3027 static int
parse_ctl_xxx_acl(const struct ctl_acl_class ** classpp)3028 parse_ctl_xxx_acl(const struct ctl_acl_class **classpp)
3029 {
3030 *classpp = ctl_class_by_name(parser_args);
3031 if (*classpp == NULL) {
3032 logconfx("cannot find ctl class \"%s\"", parser_args);
3033 return (-1);
3034 }
3035 return (0);
3036 }
3037
3038 /*
3039 * Parse "ctl_dump_acl" parameter.
3040 */
3041 /* ARGSUSED */
3042 static int
parse_ctl_dump_acl(void * arg ATTR_UNUSED)3043 parse_ctl_dump_acl(void *arg ATTR_UNUSED)
3044 {
3045 return (parse_ctl_xxx_acl(&ctl_dump_acl));
3046 }
3047
3048 /*
3049 * Parse "ctl_freeze_acl" parameter.
3050 */
3051 /* ARGSUSED */
3052 static int
parse_ctl_freeze_acl(void * arg ATTR_UNUSED)3053 parse_ctl_freeze_acl(void *arg ATTR_UNUSED)
3054 {
3055 return (parse_ctl_xxx_acl(&ctl_freeze_acl));
3056 }
3057
3058 /*
3059 * Parse "ctl_stat_acl" parameter.
3060 */
3061 /* ARGSUSED */
3062 static int
parse_ctl_stat_acl(void * arg ATTR_UNUSED)3063 parse_ctl_stat_acl(void *arg ATTR_UNUSED)
3064 {
3065 return (parse_ctl_xxx_acl(&ctl_stat_acl));
3066 }
3067
3068 /*
3069 * Parse "ctl_rule_acl" parameter.
3070 */
3071 /* ARGSUSED */
3072 static int
parse_ctl_rule_acl(void * arg ATTR_UNUSED)3073 parse_ctl_rule_acl(void *arg ATTR_UNUSED)
3074 {
3075 const struct ctl_acl_class **classpp;
3076
3077 switch (section) {
3078 #ifdef WITH_RULES
3079 case IPA_CONF_SECT_RULE:
3080 classpp = &currule->ctl_rule_acl;
3081 break;
3082 #endif
3083 #ifdef WITH_AUTORULES
3084 case IPA_CONF_SECT_AUTORULE:
3085 classpp = &curautorule->ctl_rule_acl;
3086 break;
3087 #endif
3088 case IPA_CONF_SECT_RULEPAT:
3089 classpp = &currulepat->ctl_rule_acl;
3090 break;
3091 default: /* IPA_CONF_SECT_GLOBAL */
3092 classpp = &global_ctl_rule_acl;
3093 }
3094
3095 return (parse_ctl_xxx_acl(classpp));
3096 }
3097
3098 #endif /* CTL_CHECK_CREDS */
3099
3100 #ifdef WITH_THRESHOLDS
3101 /*
3102 * Parse "debug_threshold" parameter.
3103 */
3104 static int
parse_debug_threshold(void * arg)3105 parse_debug_threshold(void *arg)
3106 {
3107 signed char level;
3108
3109 level = check_debug_level(*(uint32_t *)arg, 1);
3110 if (level < 0)
3111 return (-1);
3112
3113 switch (section) {
3114 case IPA_CONF_SECT_GLOBAL:
3115 global_debug_threshold = level;
3116 break;
3117 #ifdef WITH_RULES
3118 case IPA_CONF_SECT_RULE:
3119 currule->debug_threshold = level;
3120 break;
3121 #endif
3122 #ifdef WITH_AUTORULES
3123 case IPA_CONF_SECT_AUTORULE:
3124 curautorule->debug_threshold = level;
3125 break;
3126 #endif
3127 case IPA_CONF_SECT_RULEPAT:
3128 currulepat->debug_threshold = level;
3129 break;
3130 }
3131
3132 return (0);
3133 }
3134
3135 /*
3136 * Parse "debug_threshold_init" parameter.
3137 */
3138 static int
parse_debug_threshold_init(void * arg)3139 parse_debug_threshold_init(void *arg)
3140 {
3141 signed char level;
3142
3143 level = check_debug_level(*(uint32_t *)arg, 1);
3144 if (level < 0)
3145 return (-1);
3146
3147 switch (section) {
3148 case IPA_CONF_SECT_GLOBAL:
3149 global_debug_threshold_init = level;
3150 break;
3151 #ifdef WITH_RULES
3152 case IPA_CONF_SECT_RULE:
3153 currule->debug_threshold_init = level;
3154 break;
3155 #endif
3156 #ifdef WITH_AUTORULES
3157 case IPA_CONF_SECT_AUTORULE:
3158 curautorule->debug_threshold_init = level;
3159 break;
3160 #endif
3161 case IPA_CONF_SECT_RULEPAT:
3162 currulepat->debug_threshold_init = level;
3163 break;
3164 }
3165
3166 return (0);
3167 }
3168
3169 /*
3170 * Parse "load_threshold" parameter.
3171 */
3172 static int
parse_load_threshold(void * arg)3173 parse_load_threshold(void *arg)
3174 {
3175 if (section == IPA_CONF_SECT_THRESHOLD)
3176 curthreshold->load_thr = (char)*(int *)arg;
3177 else /* IPA_CONF_SECT_GLOBAL */
3178 global_load_threshold = (char)*(int *)arg;
3179 return (0);
3180 }
3181
3182 /*
3183 * Parse "threshold" section.
3184 */
3185 static int
parse_threshold_sect(void * arg)3186 parse_threshold_sect(void *arg)
3187 {
3188 const char *name;
3189 struct threshold *threshold;
3190
3191 name = *(char **)arg;
3192 if (conf_validate_name(name) < 0)
3193 return (-1);
3194 STAILQ_FOREACH(threshold, thresholds_list, link)
3195 if (strcmp(threshold->name, name) == 0) {
3196 logconfx("this section is duplicated");
3197 return (-1);
3198 }
3199 threshold = mzone_alloc(threshold_mzone);
3200 if (threshold == NULL) {
3201 logconfx("mzone_alloc failed");
3202 return (-1);
3203 }
3204 threshold->name = mem_strdup(name, m_anon);
3205 if (threshold->name == NULL) {
3206 logconfx("mem_strdup failed");
3207 return (-1);
3208 }
3209 STAILQ_INSERT_TAIL(thresholds_list, threshold, link);
3210 threshold->no = thresholdno++;
3211
3212 threshold->thr_flags = THRESHOLD_FLAG_ACTIVE;
3213
3214 threshold->cnt_neg = 0;
3215 threshold->cnt_slice = NULL;
3216 threshold->cnt_slice_sign = NULL;
3217
3218 threshold->time_width = 0;
3219 threshold->time_slice = NULL;
3220 threshold->worktime = NULL;
3221
3222 threshold->db_list = NULL;
3223
3224 threshold->below_lim = threshold->equal_lim = threshold->above_lim = 0;
3225
3226 threshold_init_cmds(threshold);
3227
3228 threshold->wpid.type = WPID_TYPE_THRESHOLD;
3229 threshold->wpid.pid = 0;
3230 threshold->wpid.u.threshold = threshold;
3231
3232 #ifdef WITH_RULES
3233 threshold->rule = currule;
3234 #endif
3235
3236 threshold->thr = threshold->thr_dev = 0;
3237 threshold->thr_dev_pc = 0;
3238
3239 threshold->info = NULL;
3240
3241 threshold->load_thr = -1;
3242 threshold->thr_type = -1;
3243
3244 if (section_top == IPA_CONF_SECT_RULE)
3245 ++nstatthresholds;
3246 section_top = IPA_CONF_SECT_THRESHOLD;
3247
3248 if (parser_local_sym_add("threshold", threshold->name, 0) < 0)
3249 return (-1);
3250
3251 curthreshold = threshold;
3252 conf_event_no = threshold->no;
3253 conf_event_arg = threshold->name;
3254
3255 return (0);
3256 }
3257
3258 /*
3259 * Parse "threshold" parameter.
3260 */
3261 static int
parse_threshold_param(void * arg)3262 parse_threshold_param(void *arg)
3263 {
3264 uint64_t *ptr;
3265
3266 if (THRESHOLD_IS_SET(curthreshold)) {
3267 logconfx("cannot re-define this parameter");
3268 return (-1);
3269 }
3270 curthreshold->thr_flags |= THRESHOLD_FLAG_SET;
3271
3272 ptr = (uint64_t *)arg;
3273 curthreshold->thr = *(ptr + 1);
3274 curthreshold->cnt_type = (unsigned char)*ptr;
3275 return (0);
3276 }
3277
3278 /*
3279 * Parse "threshold_deviation" parameter.
3280 */
3281 /* ARGSUSED */
3282 static int
parse_threshold_deviation(void * arg ATTR_UNUSED)3283 parse_threshold_deviation(void *arg ATTR_UNUSED)
3284 {
3285 uint64_t thr_dev;
3286 struct threshold *threshold;
3287 unsigned char cnt_type;
3288
3289 threshold = curthreshold;
3290 if (THRESHOLD_IS_NOTSET(threshold)) {
3291 logconfx("parameter \"threshold\" should be specified before");
3292 return (-1);
3293 }
3294
3295 if (get_value_or_per_cent(&thr_dev, &cnt_type) < 0)
3296 return (-1);
3297 if (thr_dev == 0) {
3298 logconfx("argument should be greater than zero");
3299 return (-1);
3300 }
3301 if (cnt_type == IPA_CONF_TYPE_PER_CENT)
3302 threshold->thr_dev_pc = (unsigned int)thr_dev;
3303 else {
3304 if (cnt_type != threshold->cnt_type) {
3305 logconfx("different arguments types for \"threshold\" "
3306 "and \"threshold_deviation\" parameters");
3307 return (-1);
3308 }
3309 threshold->thr_dev_pc = 0;
3310 }
3311 threshold->thr_dev = thr_dev;
3312
3313 return (0);
3314 }
3315
3316 /*
3317 * Parse "threshold_time_width" parameter.
3318 */
3319 static int
parse_threshold_time_width(void * arg)3320 parse_threshold_time_width(void *arg)
3321 {
3322 uint64_t timeval;
3323
3324 timeval = *(uint64_t *)arg;
3325 if (timeval == 0) {
3326 logconfx("argument should be greater than zero seconds");
3327 return (-1);
3328 }
3329 if (timeval > UINT_MAX) {
3330 logconfx("too big value %"PRIu64" for 'unsigned int' type",
3331 timeval);
3332 return (-1);
3333 }
3334
3335 if (section == IPA_CONF_SECT_THRESHOLD)
3336 curthreshold->time_width = (unsigned int)timeval;
3337 else /* IPA_CONF_SECT_GLOBAL */
3338 global_threshold_time_width = (unsigned int)timeval;
3339
3340 return (0);
3341 }
3342
3343 /*
3344 * Parse "threshold_time_slice" parameter.
3345 */
3346 static int
parse_threshold_time_slice(void * arg)3347 parse_threshold_time_slice(void *arg)
3348 {
3349 uint64_t timeval;
3350 struct tevent *tevent;
3351
3352 timeval = *(uint64_t *)arg;
3353 if (timeval == 0) {
3354 logconfx("argument should be greater than zero seconds");
3355 return (-1);
3356 }
3357 if (timeval > UINT_MAX) {
3358 logconfx("too big value %"PRIu64" for 'unsigned int' type",
3359 timeval);
3360 return (-1);
3361 }
3362 if (SECONDS_IN_DAY % timeval != 0) {
3363 logconfx("number of seconds in one day must be divisible "
3364 "by the value of \"threshold_time_slice\" parameter");
3365 return (-1);
3366 }
3367
3368 tevent = find_tevent((unsigned int)timeval);
3369 if (tevent == NULL)
3370 return (-1);
3371
3372 if (section == IPA_CONF_SECT_THRESHOLD)
3373 curthreshold->time_slice = tevent;
3374 else /* IPA_CONF_SECT_GLOBAL */
3375 global_threshold_time_slice = tevent;
3376
3377 return (0);
3378 }
3379
3380 /*
3381 * Parse "threshold_type" parameter.
3382 */
3383 static int
parse_threshold_type(void * arg)3384 parse_threshold_type(void *arg)
3385 {
3386 uint32_t val;
3387
3388 val = *(uint32_t *)arg;
3389 if (val > THRESHOLD_JUMP_OVER_ALLBITS) {
3390 logconfx("incorrect value for this parameter");
3391 return (-1);
3392 }
3393
3394 if (section == IPA_CONF_SECT_THRESHOLD)
3395 curthreshold->thr_type = (char)val;
3396 else /* IPA_CONF_SECT_GLOBAL */
3397 global_threshold_type = (char)val;
3398
3399 return (0);
3400 }
3401
3402 /*
3403 * Parse "threshold_balance" parameter.
3404 */
3405 static int
parse_threshold_balance(void * arg)3406 parse_threshold_balance(void *arg)
3407 {
3408 char *ptr1, *ptr2;
3409 unsigned int i, val[3];
3410
3411 ptr1 = *(char **)arg;
3412 for (i = 0, ptr2 = ptr1; i < 3; ptr1 = ptr2, ++i) {
3413 if (i != 2) {
3414 ptr2 = strchr(ptr2, ':');
3415 *ptr2 = '\0';
3416 ++ptr2;
3417 }
3418 if (*ptr1 != '-') {
3419 if (strto_u_int(&val[i], ptr1, (char **)NULL) < 0)
3420 return (-1);
3421 switch (val[i]) {
3422 case 0:
3423 case UINT_MAX:
3424 logconfx("values should be greater than zero "
3425 "and less than %u", UINT_MAX);
3426 return (-1);
3427 }
3428 } else
3429 val[i] = UINT_MAX;
3430 }
3431
3432 if (section == IPA_CONF_SECT_THRESHOLD) {
3433 curthreshold->below_lim = curthreshold->below_cnt = val[0];
3434 curthreshold->equal_lim = curthreshold->equal_cnt = val[1];
3435 curthreshold->above_lim = curthreshold->above_cnt = val[2];
3436 } else { /* IPA_CONF_SECT_GLOBAL */
3437 global_threshold_below_lim = val[0];
3438 global_threshold_equal_lim = val[1];
3439 global_threshold_above_lim = val[2];
3440 }
3441
3442 return (0);
3443 }
3444
3445 /*
3446 * Check if threshold's time_width and time_slice can be used together.
3447 */
3448 static int
check_threshold_times(unsigned int time_width,const struct tevent * time_slice,int must_exist)3449 check_threshold_times(unsigned int time_width,
3450 const struct tevent *time_slice, int must_exist)
3451 {
3452 if (time_width == 0 && time_slice == NULL) {
3453 if (must_exist && global_threshold_time_width == 0) {
3454 logconfx("parameter \"threshold_time_width\" is not "
3455 "defined neigher in this threshold{} section nor "
3456 "in the global{} section");
3457 return (-1);
3458 }
3459 return (0);
3460 }
3461
3462 if ((time_width != 0 && time_slice == NULL) ||
3463 (time_width == 0 && time_slice != NULL)) {
3464 logconfx("parameters \"threshold_time_width\" and "
3465 "\"threshold_time_slice\" should be defined together "
3466 "in one section");
3467 return (-1);
3468 }
3469
3470 if (time_width < time_slice->event_step) {
3471 logconfx("the value of \"threshold_time_width\" parameter must "
3472 "be greater than the value of \"threshold_time_slice\" "
3473 "parameter");
3474 return (-1);
3475 }
3476
3477 if (time_width % time_slice->event_step != 0) {
3478 logconfx("the value of \"threshold_time_width\" parameter must "
3479 "be divisible by the value of \"threshold_time_slice\" "
3480 "parameter");
3481 return (-1);
3482 }
3483
3484 return (0);
3485 }
3486 #endif /* WITH_THRESHOLDS */
3487
3488 #ifdef WITH_AUTORULES
3489 /*
3490 * Parse "debug_autorule" parameter.
3491 */
3492 static int
parse_debug_autorule(void * arg)3493 parse_debug_autorule(void *arg)
3494 {
3495 debug_autorule = check_debug_level(*(uint32_t *)arg, 1);
3496 return (debug_autorule);
3497 }
3498
3499 /*
3500 * Parse the "autorule" section.
3501 */
3502 static int
parse_autorule(void * arg)3503 parse_autorule(void *arg)
3504 {
3505 const char *name;
3506 struct autorule *autorule;
3507
3508 name = *(char **)arg;
3509 if (conf_validate_name(name) < 0)
3510 return (-1);
3511 if (autorule_by_name(name) != NULL) {
3512 logconfx("this section is duplicated");
3513 return (-1);
3514 }
3515 if (marray_alloc(autorules_marray, &nautorules, 1) < 0) {
3516 logconfx("marray_alloc failed");
3517 return (-1);
3518 }
3519 autorule = autorules + nautorules;
3520
3521 autorule->name = mem_strdup(name, m_anon);
3522 if (autorule->name == NULL) {
3523 logconfx("mem_strdup failed");
3524 return (-1);
3525 }
3526 autorule->no = nautorules++;
3527
3528 autorule->arule_flags = AUTORULE_FLAG_ACTIVE;
3529
3530 autorule->update_tevent = autorule->append_tevent = NULL;
3531 autorule->worktime = autorule->worktime_rule = NULL;
3532
3533 autorule->ac_list = NULL;
3534 autorule->db_list = NULL;
3535
3536 autorule->debug_exec = -1;
3537
3538 #ifdef WITH_LIMITS
3539 autorule->debug_limit = autorule->debug_limit_init = -1;
3540 limits_list = &autorule->limits;
3541 STAILQ_INIT(limits_list);
3542 limitno = 0;
3543 #endif
3544
3545 #ifdef WITH_THRESHOLDS
3546 autorule->debug_threshold = autorule->debug_threshold_init = -1;
3547 thresholds_list = &autorule->thresholds;
3548 STAILQ_INIT(thresholds_list);
3549 thresholdno = 0;
3550 #endif
3551
3552 #ifdef CTL_CHECK_CREDS
3553 autorule->ctl_rule_acl = NULL;
3554 #endif
3555
3556 autorule->nrules = 0;
3557
3558 cmds_rule_init(&autorule->rc[RC_STARTUP]);
3559 cmds_rule_init(&autorule->rc[RC_SHUTDOWN]);
3560
3561 section_first = section_top = IPA_CONF_SECT_AUTORULE;
3562
3563 if (parser_local_sym_add("autorule", autorule->name, 0) < 0)
3564 return (-1);
3565
3566 curautorule = autorule;
3567 conf_event_no = autorule->no;
3568 conf_event_arg = autorule->name;
3569
3570 return (0);
3571 }
3572
3573 #endif /* WITH_AUTORULES */
3574
3575 /*
3576 * Parse "sleep_after_dump" parameter.
3577 */
3578 static int
parse_sleep_after_dump(void * arg)3579 parse_sleep_after_dump(void *arg)
3580 {
3581 uint64_t timeval;
3582
3583 timeval = *(uint64_t *)arg;
3584 if (timeval == 0 || timeval >= 5 * SECONDS_IN_MINUTE) {
3585 logconfx("argument should be greater than zero seconds and "
3586 "less than 5 minutes");
3587 return (-1);
3588 }
3589 sleep_after_dump = (unsigned int)timeval;
3590 return (0);
3591 }
3592
3593 /*
3594 * Parse "sensitive_time" parameter.
3595 */
3596 static int
parse_sensitive_time(void * arg)3597 parse_sensitive_time(void *arg)
3598 {
3599 uint64_t timeval;
3600
3601 timeval = *(uint64_t *)arg;
3602 if (timeval == 0) {
3603 logconfx("argument should be greater than zero");
3604 return (-1);
3605 }
3606 if (timeval >= 5 * SECONDS_IN_MINUTE) {
3607 logconfx("argument should be less than 5 minutes");
3608 return (-1);
3609 }
3610 sensitive_time = (unsigned int)timeval;
3611 return (0);
3612 }
3613
3614 /*
3615 * Log information about chain of included files.
3616 */
3617 static void
log_include_history(void)3618 log_include_history(void)
3619 {
3620 const struct parser_pb *pb;
3621 const char *fname;
3622
3623 pb = parser_top_pb();
3624 if (pb != NULL) {
3625 fname = pb->fname;
3626 while ((pb = parser_top_pb()) != NULL) {
3627 if (fname != pb->fname) {
3628 fname = pb->fname;
3629 logconfe("included from %s:%u",
3630 fname, pb->lineno);
3631 }
3632 (void)parser_pop_pb();
3633 }
3634 }
3635 }
3636
3637 static int
set_curcmdl(void)3638 set_curcmdl(void)
3639 {
3640 #ifdef WITH_LIMITS
3641 static void *ptr;
3642 #endif
3643 unsigned int x;
3644
3645 switch (section) {
3646 case IPA_CONF_SECT_STARTUP:
3647 case IPA_CONF_SECT_SHUTDOWN:
3648 x = section_rc;
3649 switch (section_top) {
3650 #ifdef WITH_RULES
3651 case IPA_CONF_SECT_RULE:
3652 curcmds = &currule->rc[x].cmds;
3653 # ifdef WITH_LIMITS
3654 ptr = &currule->rc[x];
3655 # endif
3656 break;
3657 #endif
3658 #ifdef WITH_AUTORULES
3659 case IPA_CONF_SECT_AUTORULE:
3660 curcmds = &curautorule->rc[x].cmds;
3661 # ifdef WITH_LIMITS
3662 ptr = &curautorule->rc[x];
3663 # endif
3664 break;
3665 #endif
3666 #ifdef WITH_LIMITS
3667 case IPA_CONF_SECT_LIMIT:
3668 curcmds = &curlimit->rc[x].cmds;
3669 ptr = &curlimit->rc[x];
3670 break;
3671 #endif
3672 #ifdef WITH_SUBLIMITS
3673 case SECT_SUBLIMIT:
3674 curcmds = &cursublimit->rc[x].cmds;
3675 ptr = &cursublimit->rc[x];
3676 break;
3677 #endif
3678 #ifdef WITH_THRESHOLDS
3679 case IPA_CONF_SECT_THRESHOLD:
3680 curcmds = &curthreshold->rc[x];
3681 break;
3682 #endif
3683 case IPA_CONF_SECT_RULEPAT:
3684 curcmds = &currulepat->rc[x].cmds;
3685 #ifdef WITH_LIMITS
3686 ptr = &currulepat->rc[x];
3687 #endif
3688 break;
3689 default: /* IPA_CONF_SECT_ROOT */
3690 curcmds = &cmds_global[x];
3691 }
3692 break;
3693 #ifdef WITH_LIMITS
3694 case IPA_CONF_SECT_RESTART:
3695 curcmds = &curlimit->restart.cmds;
3696 break;
3697 case IPA_CONF_SECT_REACH:
3698 # ifdef WITH_SUBLIMITS
3699 if (section_top == SECT_SUBLIMIT)
3700 curcmds = &cursublimit->reach;
3701 else
3702 # endif
3703 curcmds = &curlimit->reach;
3704 break;
3705 case IPA_CONF_SECT_EXPIRE:
3706 curcmds = &curlimit->expire.cmds;
3707 break;
3708 case IPA_CONF_SECT_IF_REACHED:
3709 curcmds = &((struct cmds_limit *)ptr)->cmds_reached;
3710 break;
3711 case IPA_CONF_SECT_IF_NOT_REACHED:
3712 curcmds = &((struct cmds_limit *)ptr)->cmds_not_reached;
3713 break;
3714 case IPA_CONF_SECT_IF_ALL_REACHED:
3715 curcmds = &((struct cmds_rule *)ptr)->cmds_all_reached;
3716 break;
3717 case IPA_CONF_SECT_IF_ALL_NOT_REACHED:
3718 curcmds = &((struct cmds_rule *)ptr)->cmds_all_not_reached;
3719 break;
3720 case IPA_CONF_SECT_IF_ANY_REACHED:
3721 curcmds = &((struct cmds_rule *)ptr)->cmds_any_reached;
3722 break;
3723 case IPA_CONF_SECT_IF_ANY_NOT_REACHED:
3724 curcmds = &((struct cmds_rule *)ptr)->cmds_any_not_reached;
3725 break;
3726 #endif /* WITH_LIMITS */
3727 #ifdef WITH_THRESHOLDS
3728 case IPA_CONF_SECT_BELOW_THRESHOLD:
3729 curcmds = &curthreshold->below_thr;
3730 break;
3731 case IPA_CONF_SECT_ABOVE_THRESHOLD:
3732 curcmds = &curthreshold->above_thr;
3733 break;
3734 case IPA_CONF_SECT_EQUAL_THRESHOLD:
3735 curcmds = &curthreshold->equal_thr;
3736 break;
3737 #endif /* WITH_THRESHOLDS */
3738 }
3739
3740 if (curcmds->sect_set) {
3741 logconfx("this section is duplicated");
3742 return (-1);
3743 }
3744 curcmds->sect_set = 1;
3745
3746 return (0);
3747 }
3748
3749 static int
set_global_params(void)3750 set_global_params(void)
3751 {
3752 unsigned int i;
3753
3754 global_section_set = 1;
3755 if (only_abs_paths < 0)
3756 only_abs_paths = 0;
3757 if (keep_rules_order < 0)
3758 keep_rules_order = 0;
3759 if (wakeup_time == 0)
3760 wakeup_time = WAKEUP_TIME_DEF;
3761 if (sensitive_time == 0)
3762 sensitive_time = SENSITIVE_TIME_DEF;
3763 if (global_update_tevent == NULL) {
3764 global_update_tevent = find_tevent(UPDATE_TIME_DEF);
3765 if (global_update_tevent == NULL) {
3766 logconfe("find_tevent failed for default value of"
3767 "\"update_time\" parameter");
3768 return (-1);
3769 }
3770 }
3771 if (global_ac_list == NULL)
3772 global_ac_list = &ac_list_null;
3773 if (global_db_list == NULL)
3774 global_db_list = &db_list_null;
3775 if (global_worktime == NULL)
3776 global_worktime = &worktime_default;
3777 #ifdef WITH_LIMITS
3778 if (global_load_limit < 0)
3779 global_load_limit = 0;
3780 #endif
3781 #ifdef WITH_THRESHOLDS
3782 if (global_threshold_type < 0)
3783 global_threshold_type = 0;
3784 if (global_load_threshold < 0)
3785 global_load_threshold = 0;
3786 if (global_threshold_below_lim == 0)
3787 global_threshold_below_lim = global_threshold_equal_lim =
3788 global_threshold_above_lim = UINT_MAX;
3789 #endif
3790 for (i = 0; i < GLOBAL_DEBUG_PARAM_TBL_SIZE; ++i)
3791 if (*global_debug_param[i].value < 0)
3792 *global_debug_param[i].value = 0;
3793 for (i = 0; i < ROOT_DEBUG_PARAM_TBL_SIZE; ++i)
3794 if (*root_debug_param[i].value < 0)
3795 *root_debug_param[i].value = 0;
3796
3797 if (shell_path == NULL)
3798 shell_path = shell_path_default;
3799 if (shell_arg1 == NULL)
3800 shell_arg1 = shell_arg1_default;
3801 if (cmds_global[RC_STARTUP].sync < 0)
3802 cmds_global[RC_STARTUP].sync = 1;
3803 if (cmds_global[RC_SHUTDOWN].sync < 0)
3804 cmds_global[RC_SHUTDOWN].sync = 1;
3805 if (value_units < 0)
3806 value_units = 0;
3807
3808 if (ctl_enable < 0)
3809 ctl_enable = 0;
3810 if (ctl_socket_path == NULL)
3811 ctl_socket_path = ctl_socket_path_default;
3812 if (ctl_socket_perm == 0)
3813 ctl_socket_perm = CTL_SOCKET_PERM_DEF;
3814 if (ctl_timeout == 0)
3815 ctl_timeout = CTL_TIMEOUT_DEF;
3816 if (ctl_query_max_size == 0)
3817 ctl_query_max_size = CTL_QUERY_MAX_SIZE;
3818
3819 return (0);
3820 }
3821
3822 static const unsigned int sect_root[] = { IPA_CONF_SECT_ROOT, 0 };
3823 #ifdef WITH_RULES
3824 static const unsigned int sect_rule[] = { IPA_CONF_SECT_RULE, 0 };
3825 #endif
3826 static const unsigned int sect_rulepat[] = { IPA_CONF_SECT_RULEPAT, 0 };
3827 static const unsigned int sect_any_rule[] = { IPA_CONF_SECT_GLOBAL,
3828 #ifdef WITH_RULES
3829 IPA_CONF_SECT_RULE,
3830 #endif
3831 #ifdef WITH_AUTORULES
3832 IPA_CONF_SECT_AUTORULE,
3833 #endif
3834 IPA_CONF_SECT_RULEPAT, 0
3835 };
3836 static const unsigned int sect_for_exec[] = { IPA_CONF_SECT_STARTUP,
3837 IPA_CONF_SECT_SHUTDOWN,
3838 #ifdef WITH_LIMITS
3839 IPA_CONF_SECT_RESTART, IPA_CONF_SECT_REACH, IPA_CONF_SECT_EXPIRE,
3840 IPA_CONF_SECT_IF_REACHED, IPA_CONF_SECT_IF_NOT_REACHED,
3841 IPA_CONF_SECT_IF_ANY_REACHED, IPA_CONF_SECT_IF_ANY_NOT_REACHED,
3842 IPA_CONF_SECT_IF_ALL_REACHED, IPA_CONF_SECT_IF_ALL_NOT_REACHED,
3843 #endif
3844 #ifdef WITH_THRESHOLDS
3845 IPA_CONF_SECT_BELOW_THRESHOLD, IPA_CONF_SECT_ABOVE_THRESHOLD,
3846 IPA_CONF_SECT_EQUAL_THRESHOLD,
3847 #endif
3848 0
3849 };
3850 #ifdef WITH_ANY_LIMITS
3851 static const unsigned int sect_for_any_limit[] = {
3852 # ifdef WITH_RULES
3853 IPA_CONF_SECT_RULE,
3854 # endif
3855 # ifdef WITH_AUTORULES
3856 IPA_CONF_SECT_AUTORULE,
3857 # endif
3858 IPA_CONF_SECT_RULEPAT, 0
3859 };
3860 #endif
3861 #ifdef WITH_THRESHOLDS
3862 static const unsigned int sect_threshold[] = { IPA_CONF_SECT_THRESHOLD, 0 };
3863 static const unsigned int sect_global_threshold[] = { IPA_CONF_SECT_GLOBAL,
3864 IPA_CONF_SECT_THRESHOLD, 0
3865 };
3866 #endif
3867 #ifdef WITH_LIMITS
3868 static const unsigned int sect_limit[] = { IPA_CONF_SECT_LIMIT, 0 };
3869 static const unsigned int sect_global_limit[] = { IPA_CONF_SECT_GLOBAL,
3870 IPA_CONF_SECT_LIMIT, 0
3871 };
3872 static const unsigned int sect_restart[] = { IPA_CONF_SECT_RESTART, 0 };
3873 static const unsigned int sect_expire[] = { IPA_CONF_SECT_EXPIRE, 0 };
3874 static const unsigned int sect_startup_shutdown[] = { IPA_CONF_SECT_STARTUP,
3875 IPA_CONF_SECT_SHUTDOWN, 0
3876 };
3877 static const unsigned int sect_for_reach[] = { IPA_CONF_SECT_LIMIT,
3878 # ifdef WITH_SUBLIMITS
3879 SECT_SUBLIMIT,
3880 # endif
3881 0
3882 };
3883 #endif /* WITH_LIMITS */
3884 static const unsigned int sect_for_startup_shutdown[] = { IPA_CONF_SECT_ROOT,
3885 #ifdef WITH_RULES
3886 IPA_CONF_SECT_RULE,
3887 #endif
3888 #ifdef WITH_AUTORULES
3889 IPA_CONF_SECT_AUTORULE,
3890 #endif
3891 #ifdef WITH_LIMITS
3892 IPA_CONF_SECT_LIMIT,
3893 #endif
3894 #ifdef WITH_SUBLIMITS
3895 SECT_SUBLIMIT,
3896 #endif
3897 #ifdef WITH_THRESHOLDS
3898 IPA_CONF_SECT_THRESHOLD,
3899 #endif
3900 IPA_CONF_SECT_RULEPAT, 0
3901 };
3902 #if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
3903 static const unsigned int sect_for_info[] = {
3904 # ifdef WITH_RULES
3905 IPA_CONF_SECT_RULE,
3906 # endif
3907 # ifdef WITH_LIMITS
3908 IPA_CONF_SECT_LIMIT,
3909 # endif
3910 # ifdef WITH_THRESHOLDS
3911 IPA_CONF_SECT_THRESHOLD,
3912 #endif
3913 0
3914 };
3915 #endif
3916 static const unsigned int sect_for_db_list[] = { IPA_CONF_SECT_GLOBAL,
3917 #ifdef WITH_RULES
3918 IPA_CONF_SECT_RULE,
3919 #endif
3920 #ifdef WITH_AUTORULES
3921 IPA_CONF_SECT_AUTORULE,
3922 #endif
3923 #ifdef WITH_LIMITS
3924 IPA_CONF_SECT_LIMIT,
3925 #endif
3926 #ifdef WITH_THRESHOLDS
3927 IPA_CONF_SECT_THRESHOLD,
3928 #endif
3929 IPA_CONF_SECT_RULEPAT, 0
3930 };
3931 static const unsigned int sect_for_worktime[] = { IPA_CONF_SECT_GLOBAL,
3932 #ifdef WITH_RULES
3933 IPA_CONF_SECT_RULE,
3934 #endif
3935 #ifdef WITH_AUTORULES
3936 IPA_CONF_SECT_AUTORULE,
3937 #endif
3938 #ifdef WITH_LIMITS
3939 IPA_CONF_SECT_LIMIT,
3940 #endif
3941 #ifdef WITH_THRESHOLDS
3942 IPA_CONF_SECT_THRESHOLD,
3943 #endif
3944 IPA_CONF_SECT_RULEPAT, 0
3945 };
3946 #ifdef WITH_AUTORULES
3947 static const unsigned int sect_autorule[] = { IPA_CONF_SECT_AUTORULE, 0 };
3948 #endif
3949
3950 /*
3951 * Sections in ipa.conf.
3952 */
3953 static ipa_conf_sect conf_sect_tbl[] = {
3954 #ifdef WITH_RULES
3955 { "rule", IPA_CONF_SECT_RULE, 1, NULL, NULL,
3956 IPA_CONF_TYPE_MISC, sect_root, parse_rule
3957 },
3958 #endif
3959 { "rulepat", IPA_CONF_SECT_RULEPAT, 1, NULL, NULL,
3960 IPA_CONF_TYPE_STRING, sect_root, parse_rulepat
3961 },
3962 { "global", IPA_CONF_SECT_GLOBAL, 0, NULL, NULL,
3963 IPA_CONF_TYPE_MISC, sect_root, parse_global
3964 },
3965 #ifdef WITH_AUTORULES
3966 { "autorule", IPA_CONF_SECT_AUTORULE, 1, NULL, NULL,
3967 IPA_CONF_TYPE_MISC, sect_root, parse_autorule
3968 },
3969 #endif
3970 #ifdef WITH_LIMITS
3971 { "limit", IPA_CONF_SECT_LIMIT, 1, NULL, NULL,
3972 IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_limit_sect
3973 },
3974 { "restart", IPA_CONF_SECT_RESTART, 0, NULL, NULL,
3975 IPA_CONF_TYPE_MISC, sect_limit, NULL
3976 },
3977 { "reach", IPA_CONF_SECT_REACH, 0, NULL, NULL,
3978 IPA_CONF_TYPE_MISC, sect_for_reach, NULL
3979 },
3980 { "expire", IPA_CONF_SECT_EXPIRE, 0, NULL, NULL,
3981 IPA_CONF_TYPE_MISC, sect_limit, NULL
3982 },
3983 # ifdef WITH_SUBLIMITS
3984 { "sublimit", SECT_SUBLIMIT, -1, NULL, NULL,
3985 IPA_CONF_TYPE_MISC, sect_limit, parse_sublimit
3986 },
3987 # endif
3988 { "if_reached", IPA_CONF_SECT_IF_REACHED, 0, NULL, NULL,
3989 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
3990 },
3991 { "if_not_reached", IPA_CONF_SECT_IF_NOT_REACHED, 0, NULL, NULL,
3992 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
3993 },
3994 { "if_any_reached", IPA_CONF_SECT_IF_ANY_REACHED, 0, NULL, NULL,
3995 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
3996 },
3997 { "if_all_reached", IPA_CONF_SECT_IF_ALL_REACHED, 0, NULL, NULL,
3998 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
3999 },
4000 { "if_any_not_reached", IPA_CONF_SECT_IF_ANY_NOT_REACHED, 0, NULL, NULL,
4001 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
4002 },
4003 { "if_all_not_reached", IPA_CONF_SECT_IF_ALL_NOT_REACHED, 0, NULL, NULL,
4004 IPA_CONF_TYPE_MISC, sect_startup_shutdown, NULL
4005 },
4006 #endif /* WITH_LIMITS */
4007 #ifdef WITH_THRESHOLDS
4008 { "threshold", IPA_CONF_SECT_THRESHOLD, 1, NULL, NULL,
4009 IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_threshold_sect
4010 },
4011 { "below_threshold", IPA_CONF_SECT_BELOW_THRESHOLD, 0, NULL, NULL,
4012 IPA_CONF_TYPE_MISC, sect_threshold, NULL
4013 },
4014 { "above_threshold", IPA_CONF_SECT_ABOVE_THRESHOLD, 0, NULL, NULL,
4015 IPA_CONF_TYPE_MISC, sect_threshold, NULL
4016 },
4017 { "equal_threshold", IPA_CONF_SECT_EQUAL_THRESHOLD, 0, NULL, NULL,
4018 IPA_CONF_TYPE_MISC, sect_threshold, NULL
4019 },
4020 #endif
4021 { "startup", IPA_CONF_SECT_STARTUP, 0, NULL, NULL,
4022 IPA_CONF_TYPE_MISC, sect_for_startup_shutdown, NULL
4023 },
4024 { "shutdown", IPA_CONF_SECT_SHUTDOWN, 0, NULL, NULL,
4025 IPA_CONF_TYPE_MISC, sect_for_startup_shutdown, NULL
4026 },
4027 { NULL, 0, 0, NULL, NULL,
4028 IPA_CONF_TYPE_MISC, NULL, NULL
4029 }
4030 };
4031
4032 #ifdef WITH_LIMITS
4033 #define PAT_TIME_EXP "\
4034 ^((\\+[mhDWM] ?)?([[:digit:]]+[smhDW]( ?[[:digit:]]+[smhDW])*)?|\
4035 ([[:digit:]]+[smhDW]( ?[[:digit:]]+[smhDW])*)?( ?\\+[mhDWM])?)$"
4036 #endif
4037
4038 #ifdef WITH_THRESHOLDS
4039 #define PAT_THR_BALANCE "\
4040 ^(-|[[:digit:]]+):(-|[[:digit:]]+):(-|[[:digit:]]+)$"
4041 #endif
4042
4043 #define PAT_WORKTIME1 "\
4044 [SMTWHFA] (\\*|[[:digit:]]{1,2}:[[:digit:]]{1,2}-\
4045 [[:digit:]]{1,2}:[[:digit:]]{1,2}( [[:digit:]]{1,2}:[[:digit:]]{1,2}-\
4046 [[:digit:]]{1,2}:[[:digit:]]{1,2})*)"
4047 #define PAT_WORKTIME "^"PAT_WORKTIME1"( "PAT_WORKTIME1")*$"
4048 #define PAT_LIST "^[^ \"]+( [^ \"]+)*$"
4049
4050 #ifdef CTL_CHECK_CREDS
4051 # define PAT_ACL "^[[:alnum:]]+$"
4052 # define PAT_CTL_ACL_CLASS "^[[:alnum:]]+( !?%?[-_[:alnum:]]+)*$"
4053 #endif
4054
4055 /*
4056 * Parameters in ipa.conf.
4057 */
4058 static ipa_conf_param conf_param_tbl[] = {
4059 { "update_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4060 sect_any_rule, parse_update_time
4061 },
4062 { "append_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4063 sect_any_rule, parse_append_time
4064 },
4065 { "wakeup_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4066 sect_root, parse_wakeup_time
4067 },
4068 { "freeze_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4069 sect_root, parse_freeze_time
4070 },
4071 { "sleep_after_dump", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4072 sect_root, parse_sleep_after_dump
4073 },
4074 { "sensitive_time", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4075 sect_root, parse_sensitive_time
4076 },
4077 { "exec", -1, NULL, NULL, IPA_CONF_TYPE_MISC,
4078 sect_for_exec, parse_exec
4079 },
4080 { "sync_exec", -1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4081 sect_for_exec, parse_sync_exec
4082 },
4083 { "ac_mod", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4084 sect_root, parse_ac_mod
4085 },
4086 { "db_mod", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4087 sect_root, parse_db_mod
4088 },
4089 { "ac_list", -1, PAT_LIST, &re_list, IPA_CONF_TYPE_MISC,
4090 sect_any_rule, parse_ac_list
4091 },
4092 { "db_list", -1, NULL, &re_list, IPA_CONF_TYPE_MISC,
4093 sect_for_db_list, parse_db_list
4094 },
4095 { "include", 1, NULL, NULL,IPA_CONF_TYPE_STRING,
4096 NULL, parse_include
4097 },
4098 { "include_files", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4099 NULL, parse_include_files
4100 },
4101 { "value_units", 1, NULL, NULL, IPA_CONF_TYPE_MISC,
4102 sect_root, parse_value_units
4103 },
4104 #if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
4105 { "info", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4106 sect_for_info, parse_info
4107 },
4108 #endif
4109 #ifdef WITH_RULES
4110 { "ac_gather_add", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4111 sect_rule, parse_ac_gather_add
4112 },
4113 { "ac_gather_sub", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4114 sect_rule, parse_ac_gather_sub
4115 },
4116 { "ictl", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4117 sect_for_exec, parse_ictl
4118 },
4119 #endif
4120 #ifdef WITH_LIMITS
4121 { "limit", -1, NULL, NULL, IPA_CONF_TYPE_VALUE,
4122 sect_limit, parse_limit_param
4123 },
4124 { "restart", -1, PAT_TIME_EXP, &re_texp, IPA_CONF_TYPE_MISC,
4125 sect_restart, parse_restart
4126 },
4127 { "expire", -1, NULL, &re_texp, IPA_CONF_TYPE_MISC,
4128 sect_expire, parse_expire
4129 },
4130 { "load_limit", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4131 sect_global_limit, parse_load_limit
4132 },
4133 { "debug_limit", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4134 sect_any_rule, parse_debug_limit
4135 },
4136 { "debug_limit_init", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4137 sect_any_rule, parse_debug_limit_init
4138 },
4139 #endif
4140 #ifdef WITH_THRESHOLDS
4141 { "threshold", -1, NULL, NULL, IPA_CONF_TYPE_VALUE,
4142 sect_threshold, parse_threshold_param
4143 },
4144 { "threshold_deviation", -1, NULL, NULL, IPA_CONF_TYPE_MISC,
4145 sect_threshold, parse_threshold_deviation
4146 },
4147 { "threshold_time_width", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4148 sect_global_threshold, parse_threshold_time_width
4149 },
4150 { "threshold_time_slice", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4151 sect_global_threshold, parse_threshold_time_slice
4152 },
4153 { "threshold_type", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4154 sect_global_threshold, parse_threshold_type
4155 },
4156 { "threshold_balance", 1, PAT_THR_BALANCE, &re_thr_balance,
4157 IPA_CONF_TYPE_MISC, sect_global_threshold, parse_threshold_balance
4158 },
4159 { "load_threshold", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4160 sect_global_threshold, parse_load_threshold
4161 },
4162 { "debug_threshold", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4163 sect_any_rule, parse_debug_threshold
4164 },
4165 { "debug_threshold_init", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4166 sect_any_rule, parse_debug_threshold_init
4167 },
4168 #endif
4169 { "worktime", -1, PAT_WORKTIME, &re_worktime, IPA_CONF_TYPE_MISC,
4170 sect_for_worktime, parse_worktime
4171 },
4172 { "posix_re_pattern", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4173 sect_root, parse_posix_re_pattern
4174 },
4175 { "only_abs_paths", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4176 sect_root, parse_only_abs_paths
4177 },
4178 { "keep_rules_order", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4179 sect_root, parse_keep_rules_order
4180 },
4181 { "check_next_rulepat", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4182 sect_rulepat, parse_check_next_rulepat
4183 },
4184 { "shell_path", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4185 sect_root, parse_shell_path
4186 },
4187 { "shell_arg1", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4188 sect_root, parse_shell_arg1
4189 },
4190 { "debug_time", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4191 sect_root, parse_debug_time
4192 },
4193 { "debug_ac_null", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4194 sect_root, parse_debug_ac_null
4195 },
4196 { "debug_db_null", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4197 sect_root, parse_debug_db_null
4198 },
4199 { "debug_exec", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4200 sect_any_rule, parse_debug_exec
4201 },
4202 { "debug_worktime", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4203 sect_root, parse_debug_worktime
4204 },
4205 { "ctl_enable", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN,
4206 sect_root, parse_ctl_enable
4207 },
4208 { "ctl_socket_path", 1, NULL, NULL, IPA_CONF_TYPE_STRING,
4209 sect_root, parse_ctl_socket_path
4210 },
4211 { "ctl_socket_perm", 1, NULL, NULL, IPA_CONF_TYPE_MISC,
4212 sect_root, parse_ctl_socket_perm
4213 },
4214 { "ctl_timeout", -1, NULL, NULL, IPA_CONF_TYPE_TIME,
4215 sect_root, parse_ctl_timeout
4216 },
4217 { "ctl_query_max_size", -1, NULL, NULL, IPA_CONF_TYPE_BYTES,
4218 sect_root, parse_ctl_query_max_size
4219 },
4220 { "debug_ctl", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4221 sect_root, parse_debug_ctl
4222 },
4223 #ifdef CTL_CHECK_CREDS
4224 { "ctl_rule_acl", 1, PAT_ACL, &re_acl, IPA_CONF_TYPE_MISC,
4225 sect_any_rule, parse_ctl_rule_acl
4226 },
4227 { "ctl_dump_acl", 1, NULL, &re_acl, IPA_CONF_TYPE_MISC,
4228 sect_root, parse_ctl_dump_acl
4229 },
4230 { "ctl_freeze_acl", 1, NULL, &re_acl, IPA_CONF_TYPE_MISC,
4231 sect_root, parse_ctl_freeze_acl
4232 },
4233 { "ctl_stat_acl", 1, NULL, &re_acl, IPA_CONF_TYPE_MISC,
4234 sect_root, parse_ctl_stat_acl
4235 },
4236 { "ctl_acl_class", -1, PAT_CTL_ACL_CLASS, &re_ctl_acl_class,
4237 IPA_CONF_TYPE_MISC, sect_root, parse_ctl_acl_class
4238 },
4239 #endif
4240 #ifdef WITH_AUTORULES
4241 { "worktime_rule", -1, NULL, &re_worktime, IPA_CONF_TYPE_MISC,
4242 sect_autorule, parse_worktime_rule
4243 },
4244 { "debug_autorule", 1, NULL, NULL, IPA_CONF_TYPE_UINT32,
4245 sect_root, parse_debug_autorule
4246 },
4247 #endif
4248 { NULL, 0, NULL, NULL, IPA_CONF_TYPE_MISC,
4249 NULL, NULL
4250 }
4251 };
4252
4253 /* Module which own current custom section. */
4254 static const struct ac_mod *cur_ac_mod;
4255 static const struct db_mod *cur_db_mod;
4256
4257 /* Hash tables for ipa.conf configuration. */
4258 static struct conf_sect_hash *conf_sect_hash;
4259 static struct conf_param_hash *conf_param_hash;
4260
4261 /* Pointers to configuration tables. */
4262 static const ipa_conf_sect *conf_sect_tbl_ptr;
4263 static const ipa_conf_param *conf_param_tbl_ptr;
4264 static const struct conf_sect_hash *conf_sect_hash_ptr;
4265 static const struct conf_param_hash *conf_param_hash_ptr;
4266
4267 /* Set if in own ipa.conf section. */
4268 static char in_own_sect;
4269
4270 #ifdef WITH_LIMITS
4271 /* Previous commands section. */
4272 static struct cmds *prevcmds;
4273 #endif
4274
4275 /* Stack of nested configuration sections. */
4276 struct sect_stack {
4277 SLIST_ENTRY(sect_stack) link;
4278 unsigned int section;
4279 };
4280
4281 SLIST_HEAD(EMPTY, sect_stack) sect_stack_list =
4282 SLIST_HEAD_INITIALIZER(sect_stack_list);
4283
4284 static int
init_config_data(PARSING_MODE mode)4285 init_config_data(PARSING_MODE mode)
4286 {
4287 unsigned int i;
4288
4289 if ((m_anon = mem_type_new_local(MTYPE_NAME(anonymous),
4290 "Anonymous memory", 0)) == NULL ||
4291 (m_tmp = mem_type_new_local(MTYPE_NAME(tmp),
4292 "Temporal memory", 0)) == NULL ||
4293 (m_ctl = mem_type_new_local(MTYPE_NAME(ctl),
4294 "Memory for ctl", 0)) == NULL ||
4295 (m_cmd = mem_type_new_local(MTYPE_NAME(cmd),
4296 "Memory for commands", 0)) == NULL ||
4297 (m_parser = mem_type_new_local(MTYPE_NAME(parser),
4298 "Memory allocated by parser", MEMTYPE_FLAGS)) == NULL)
4299 return (-1);
4300
4301 nac_mods = ndb_mods = 0;
4302
4303 value_units = -1;
4304 got_arg_value = 0;
4305
4306 global_ac_list = NULL;
4307 global_db_list = NULL;
4308
4309 SLIST_INIT(&ac_mod_list);
4310 SLIST_INIT(&db_mod_list);
4311
4312 SLIST_INIT(&ac_sets);
4313 SLIST_INIT(&db_sets);
4314
4315 conf_sect_he_mzone = mzone_init(MZONE_NAME(conf_sect_he),
4316 "Config sections hash entries", 0, sizeof(struct conf_sect_he),
4317 CONF_SECT_HE_NSIZE, CONF_SECT_HE_NALLOC);
4318 if (conf_sect_he_mzone == NULL)
4319 return (-1);
4320
4321 conf_param_he_mzone = mzone_init(MZONE_NAME(conf_param_he),
4322 "Config parameters hash entries", 0, sizeof(struct conf_param_he),
4323 CONF_PARAM_HE_NSIZE, CONF_PARAM_HE_NALLOC);
4324 if (conf_param_he_mzone == NULL)
4325 return (-1);
4326
4327 if (mode != RECONFIG_PARSING) {
4328 rules_hash_init();
4329 #ifdef WITH_ANY_LIMITS
4330 wpid_hash_init();
4331 #endif
4332 }
4333
4334 rule_mzone = mzone_init(MZONE_NAME(rule), "Rules", MEMFLAG_OPTIMIZE,
4335 sizeof(struct rule), RULE_NSIZE, RULE_NALLOC);
4336 if (rule_mzone == NULL)
4337 return (-1);
4338
4339 rulepat_mzone = mzone_init(MZONE_NAME(rulepat), "Rules patterns",
4340 0, sizeof(struct rulepat), RULEPAT_NSIZE, RULEPAT_NALLOC);
4341 if (rulepat_mzone == NULL)
4342 return (-1);
4343 STAILQ_INIT(&rulepats_list);
4344 rulepatno = 0;
4345
4346 #ifdef WITH_RULES
4347 SLIST_INIT(&acg_list);
4348 #endif
4349
4350 tint_mzone = mzone_init(MZONE_NAME(tint), "Time intervals", 0,
4351 sizeof(struct tint), TINT_NSIZE, TINT_NALLOC);
4352 if (tint_mzone == NULL)
4353 return (-1);
4354 STAILQ_INIT(&tint_sets);
4355
4356 worktime_mzone = mzone_init(MZONE_NAME(worktime), "Worktimes", 0,
4357 sizeof(struct worktime), WORKTIME_NSIZE, WORKTIME_NALLOC);
4358 if (worktime_mzone == NULL)
4359 return (-1);
4360 init_worktime_default();
4361 SLIST_INIT(&worktimes_list);
4362 SLIST_INSERT_HEAD(&worktimes_list, &worktime_default, link);
4363
4364 tevent_mzone = mzone_init(MZONE_NAME(tevent), "Time events", 0,
4365 sizeof(struct tevent), TEVENT_NSIZE, TEVENT_NALLOC);
4366 if (tevent_mzone == NULL)
4367 return (-1);
4368 SLIST_INIT(&tevents_list);
4369
4370 cmd_mzone = mzone_init(MZONE_NAME(cmd), "Commands", 0,
4371 sizeof(struct cmd), CMD_NSIZE, CMD_NALLOC);
4372 if (cmd_mzone == NULL)
4373 return (-1);
4374
4375 #ifdef WITH_RULES
4376 acg_mzone = NULL;
4377 ictl_mzone = mzone_init(MZONE_NAME(ictl), "Ictl", 0,
4378 sizeof(struct ictl), CMD_NSIZE, CMD_NALLOC);
4379 if (ictl_mzone == NULL)
4380 return (-1);
4381 #endif
4382
4383 cmds_init(&cmds_global[RC_STARTUP]);
4384 cmds_init(&cmds_global[RC_SHUTDOWN]);
4385
4386 #ifdef WITH_LIMITS
4387 limit_mzone = mzone_init(MZONE_NAME(limit), "Limits", MEMFLAG_OPTIMIZE,
4388 sizeof(struct limit), LIMIT_NSIZE, LIMIT_NALLOC);
4389 if (limit_mzone == NULL)
4390 return (-1);
4391 global_load_limit = -1;
4392 #endif
4393
4394 #ifdef WITH_SUBLIMITS
4395 sublimit_mzone = mzone_init(MZONE_NAME(sublimit), "Sublimits", 0,
4396 sizeof(struct sublimit), SUBLIMIT_NSIZE, SUBLIMIT_NALLOC);
4397 if (sublimit_mzone == NULL)
4398 return (-1);
4399 #endif
4400
4401 nautorules = nstatrules = ndynrules = nstatlimits = ndynlimits =
4402 nstatsublimits = ndynsublimits = 0;
4403
4404 #ifdef WITH_THRESHOLDS
4405 threshold_mzone = mzone_init(MZONE_NAME(threshold), "Thresholds",
4406 MEMFLAG_OPTIMIZE, sizeof(struct threshold), THRESHOLD_NSIZE,
4407 THRESHOLD_NALLOC);
4408 if (threshold_mzone == NULL)
4409 return (-1);
4410 global_threshold_type = -1;
4411 global_load_threshold = -1;
4412 global_threshold_time_width = 0;
4413 global_threshold_time_slice = NULL;
4414 global_threshold_below_lim = global_threshold_equal_lim =
4415 global_threshold_above_lim = 0;
4416 #endif
4417 nstatthresholds = ndynthresholds = 0;
4418
4419 #ifdef WITH_AUTORULES
4420 autorules_marray = marray_init(MARRAY_NAME(autorules), "Autorules", 0,
4421 (void *)&autorules, sizeof(struct autorule), AUTORULE_NSIZE,
4422 AUTORULE_NALLOC);
4423 if (autorules_marray == NULL)
4424 return (-1);
4425 rules_ptr_marray = NULL;
4426 #endif
4427
4428 global_update_tevent = global_append_tevent = NULL;
4429 global_worktime = NULL;
4430 global_section_set = 0;
4431 only_abs_paths = keep_rules_order = posix_re_pattern = -1;
4432
4433 for (i = 0; i < GLOBAL_DEBUG_PARAM_TBL_SIZE; ++i)
4434 *global_debug_param[i].value = -1;
4435 for (i = 0; i < ROOT_DEBUG_PARAM_TBL_SIZE; ++i)
4436 *root_debug_param[i].value = -1;
4437 for (i = 0; i < ROOT_TIME_PARAM_TBL_SIZE; ++i)
4438 *root_time_param[i].value = 0;
4439
4440 ctl_enable = -1;
4441 ctl_socket_path = NULL;
4442 ctl_socket_perm = 0;
4443 ctl_timeout = 0;
4444 #ifdef CTL_CHECK_CREDS
4445 ctl_acl_elem_mzone = mzone_init(MZONE_NAME(ctl_acl_elem),
4446 "ACL elements", 0, sizeof(struct ctl_acl_elem), CTL_ACL_ELEM_NSIZE,
4447 CTL_ACL_ELEM_NALLOC);
4448 if (ctl_acl_elem_mzone == NULL)
4449 return (-1);
4450 ctl_acl_class_mzone = mzone_init(MZONE_NAME(ctl_acl_class),
4451 "ACL classes", 0, sizeof(struct ctl_acl_class), CTL_ACL_CLASS_NSIZE,
4452 CTL_ACL_CLASS_NALLOC);
4453 if (ctl_acl_class_mzone == NULL)
4454 return (-1);
4455 global_ctl_rule_acl = ctl_dump_acl = ctl_freeze_acl =
4456 ctl_stat_acl = NULL;
4457 STAILQ_INIT(&ctl_acl_classes);
4458 #endif
4459
4460 if (build_conf_re() < 0)
4461 return (-1);
4462 if (init_conf_tbls((char *)NULL, mode != RECONFIG_PARSING,
4463 conf_sect_tbl, &conf_sect_hash, conf_param_tbl,
4464 &conf_param_hash) < 0)
4465 return (-1);
4466
4467 return (0);
4468 }
4469
4470 /*
4471 * Deinitialize not needed configuration data structures.
4472 */
4473 static void
deinit_config_data(void)4474 deinit_config_data(void)
4475 {
4476 deinit_conf_tbls(0, conf_sect_tbl, conf_sect_hash,
4477 conf_param_tbl, conf_param_hash);
4478
4479 mzone_deinit(conf_sect_he_mzone);
4480 mzone_deinit(conf_param_he_mzone);
4481
4482 if (mzone_is_empty(worktime_mzone)) {
4483 mzone_deinit(worktime_mzone);
4484 mzone_deinit(tint_mzone);
4485 worktime_mzone = tint_mzone = NULL;
4486 }
4487
4488 if (mzone_is_empty(cmd_mzone)) {
4489 mzone_deinit(cmd_mzone);
4490 cmd_mzone = NULL;
4491 }
4492 #ifdef WITH_RULES
4493 if (mzone_is_empty(ictl_mzone)) {
4494 mzone_deinit(ictl_mzone);
4495 ictl_mzone = NULL;
4496 }
4497 #endif
4498 if (mzone_is_empty(rulepat_mzone)) {
4499 mzone_deinit(rulepat_mzone);
4500 rulepat_mzone = NULL;
4501 }
4502 #ifdef WITH_LIMITS
4503 if (mzone_is_empty(limit_mzone)) {
4504 mzone_deinit(limit_mzone);
4505 limit_mzone = NULL;
4506 }
4507 #endif
4508 #ifdef WITH_SUBLIMITS
4509 if (mzone_is_empty(sublimit_mzone)) {
4510 mzone_deinit(sublimit_mzone);
4511 sublimit_mzone = NULL;
4512 }
4513 #endif
4514 #ifdef WITH_THRESHOLDS
4515 if (mzone_is_empty(threshold_mzone)) {
4516 mzone_deinit(threshold_mzone);
4517 threshold_mzone = NULL;
4518 }
4519 #endif
4520
4521 #ifdef CTL_CHECK_CREDS
4522 if (mzone_is_empty(ctl_acl_elem_mzone)) {
4523 mzone_deinit(ctl_acl_elem_mzone);
4524 ctl_acl_elem_mzone = NULL;
4525 }
4526 if (mzone_is_empty(ctl_acl_class_mzone)) {
4527 mzone_deinit(ctl_acl_class_mzone);
4528 ctl_acl_class_mzone = NULL;
4529 }
4530 #endif
4531 }
4532
4533 static int
token_section_begin(void)4534 token_section_begin(void)
4535 {
4536 const unsigned int *id;
4537 const char *prefix;
4538 const ipa_conf_sect *conf_sect;
4539 const struct get_arg *get_arg;
4540 struct sect_stack *sect_stack;
4541 struct ac_mod *ac_mod;
4542 struct db_mod *db_mod;
4543 char *ptr;
4544 int nargs;
4545
4546 /* Put previous section on top of sections stack. */
4547 sect_stack = mem_malloc(sizeof(*sect_stack), m_anon);
4548 if (sect_stack == NULL) {
4549 logconfe("token_section_begin: mem_malloc failed");
4550 return (-1);
4551 }
4552 sect_stack->section = section;
4553 SLIST_INSERT_HEAD(§_stack_list, sect_stack, link);
4554
4555 /* Get name of current section: "section" or "prefix:section". */
4556 cursect = parser_token;
4557 if (in_own_sect && (ptr = strchr(cursect, ':')) != NULL) {
4558 /*
4559 * Previous section is not a custom section and
4560 * new custom section appears.
4561 */
4562 *ptr = '\0';
4563 prefix = cursect;
4564 cursect = ptr + 1;
4565 if ((db_mod = db_mod_by_prefix(prefix)) != NULL) {
4566 conf_sect_hash_ptr = db_mod->conf_sect_hash;
4567 conf_param_hash_ptr = db_mod->conf_param_hash;
4568 conf_sect_tbl_ptr = db_mod->ipa_db_mod->conf_sect_tbl;
4569 conf_param_tbl_ptr = db_mod->ipa_db_mod->conf_param_tbl;
4570 curmodfile = db_mod->mod_file;
4571 cur_db_mod = db_mod;
4572 } else if ((ac_mod = ac_mod_by_prefix(prefix)) != NULL) {
4573 conf_sect_hash_ptr = ac_mod->conf_sect_hash;
4574 conf_param_hash_ptr = ac_mod->conf_param_hash;
4575 conf_sect_tbl_ptr = ac_mod->ipa_ac_mod->conf_sect_tbl;
4576 conf_param_tbl_ptr = ac_mod->ipa_ac_mod->conf_param_tbl;
4577 curmodfile = ac_mod->mod_file;
4578 cur_ac_mod = ac_mod;
4579 cur_db_mod = NULL;
4580 } else {
4581 logconfx("cannot find module with \"%s\" "
4582 "configuration prefix", prefix);
4583 return (-1);
4584 }
4585 in_own_sect = 0;
4586 }
4587
4588 /* Find section. */
4589 conf_sect = find_conf_sect(conf_sect_tbl_ptr, conf_sect_hash_ptr,
4590 cursect);
4591 if (conf_sect == NULL) {
4592 logconfx("unknown section");
4593 return (-1);
4594 }
4595
4596 /* Validate type of argument. */
4597 if (conf_sect->arg_type > IPA_CONF_TYPE_MISC) {
4598 logconfx("internal error: unknown type %u of function's "
4599 "argument", conf_sect->arg_type);
4600 return (-1);
4601 }
4602
4603 /* Check whether current section is used in correct place. */
4604 id = conf_sect->sect_where;
4605 if (id != NULL)
4606 for (;; ++id) {
4607 if (*id == section)
4608 break;
4609 if (*id == 0)
4610 goto not_expected;
4611 }
4612
4613 /* Check number of section's arguments. */
4614 nargs = conf_sect->arg_nargs;
4615 if (nargs >= 0) {
4616 if (parser_nargs != nargs) {
4617 logconfx("wrong number of arguments (has %d, "
4618 "should have %d)", parser_nargs, nargs);
4619 return (-1);
4620 }
4621 } else {
4622 nargs = -nargs;
4623 if (parser_nargs < nargs) {
4624 logconfx("this section should have at "
4625 "least %d argument%s", nargs,
4626 plural_form((unsigned int)nargs));
4627 return (-1);
4628 }
4629 }
4630
4631 /* Validate arguments if needed. */
4632 if (conf_sect->arg_regexp != NULL)
4633 if (regexec_simple(conf_sect->arg_regexp, parser_args) != 0) {
4634 logconfx("wrong format of an argument");
4635 return (-1);
4636 }
4637
4638 section = conf_sect->sect_id;
4639 if (!in_own_sect) {
4640 /* Register configuration event in module for its section. */
4641 if (cur_db_mod != NULL) {
4642 if (db_mod_conf_event(cur_db_mod,
4643 IPA_CONF_EVENT_CUSTOM_SECT_BEGIN, section,
4644 (void *)NULL) < 0)
4645 return (-1);
4646 } else {
4647 if (ac_mod_conf_event(cur_ac_mod,
4648 IPA_CONF_EVENT_CUSTOM_SECT_BEGIN, section,
4649 (void *)NULL) < 0)
4650 return (-1);
4651 }
4652 }
4653
4654 /* Parse it. */
4655 conf_event_no = 0;
4656 conf_event_arg = NULL;
4657 get_arg = &get_arg_tbl[conf_sect->arg_type];
4658 if (get_arg->reg != NULL)
4659 if (regexec_simple(get_arg->reg, parser_args) != 0) {
4660 logconfx("wrong format of an argument");
4661 return (-1);
4662 }
4663 if (get_arg->parse(get_arg->argp) < 0)
4664 return (-1);
4665 if (conf_sect->arg_parse != NULL)
4666 if (conf_sect->arg_parse(get_arg->argp) < 0)
4667 return (-1);
4668
4669 if (in_own_sect && section != SECT_SUBLIMIT) {
4670 /*
4671 * Register configuration event in all modules for
4672 * ipa.conf's section.
4673 */
4674 if (mod_conf_event(conf_event_begin[section], conf_event_no,
4675 conf_event_arg) < 0)
4676 return (-1);
4677 }
4678
4679 if (in_own_sect && section >= IPA_CONF_SECT_RESTART &&
4680 section <= IPA_CONF_SECT_ABOVE_THRESHOLD) {
4681 /* Do additional settings for ipa.conf's sections. */
4682 switch (section) {
4683 case IPA_CONF_SECT_STARTUP:
4684 section_rc = RC_STARTUP;
4685 break;
4686 case IPA_CONF_SECT_SHUTDOWN:
4687 section_rc = RC_SHUTDOWN;
4688 break;
4689 #ifdef WITH_LIMITS
4690 case IPA_CONF_SECT_IF_ALL_REACHED:
4691 case IPA_CONF_SECT_IF_ALL_NOT_REACHED:
4692 case IPA_CONF_SECT_IF_ANY_REACHED:
4693 case IPA_CONF_SECT_IF_ANY_NOT_REACHED:
4694 switch (section_top) {
4695 # ifdef WITH_RULES
4696 case IPA_CONF_SECT_RULE:
4697 # endif
4698 # ifdef WITH_AUTORULES
4699 case IPA_CONF_SECT_AUTORULE:
4700 # endif
4701 case IPA_CONF_SECT_RULEPAT:
4702 break;
4703 default:
4704 goto not_expected;
4705 }
4706 prevcmds = curcmds;
4707 break;
4708 case IPA_CONF_SECT_IF_REACHED:
4709 case IPA_CONF_SECT_IF_NOT_REACHED:
4710 switch (section_top) {
4711 case IPA_CONF_SECT_LIMIT:
4712 # ifdef WITH_SUBLIMITS
4713 case SECT_SUBLIMIT:
4714 # endif
4715 break;
4716 default:
4717 goto not_expected;
4718 }
4719 prevcmds = curcmds;
4720 break;
4721 #endif /* WITH_LIMITS */
4722 }
4723 if (set_curcmdl() < 0)
4724 return (-1);
4725 }
4726
4727 return (0);
4728
4729 not_expected:
4730 logconfx("this section is not expected here");
4731 return (-1);
4732 }
4733
4734 static int
token_parameter(void)4735 token_parameter(void)
4736 {
4737 const unsigned int *id;
4738 const char *prefix;
4739 const ipa_conf_param *conf_param;
4740 const struct get_arg *get_arg;
4741 const struct ac_mod *ac_mod;
4742 const struct db_mod *db_mod;
4743 char *ptr;
4744 int nargs;
4745
4746 /* Get name of current parameter: "parameter" or "prefix:parameter". */
4747 curparam = parser_token;
4748 if (in_own_sect && (ptr = strchr(curparam, ':')) != NULL) {
4749 /*
4750 * Current section is not a custom section
4751 * and custom parameter appears.
4752 */
4753 *ptr = '\0';
4754 prefix = curparam;
4755 curparam = ptr + 1;
4756 if ((db_mod = db_mod_by_prefix(prefix)) != NULL) {
4757 conf_param_hash_ptr = db_mod->conf_param_hash;
4758 conf_param_tbl_ptr = db_mod->ipa_db_mod->conf_param_tbl;
4759 curmodfile = db_mod->mod_file;
4760 } else if ((ac_mod = ac_mod_by_prefix(prefix)) != NULL) {
4761 conf_param_hash_ptr = ac_mod->conf_param_hash;
4762 conf_param_tbl_ptr = ac_mod->ipa_ac_mod->conf_param_tbl;
4763 curmodfile = ac_mod->mod_file;
4764 db_mod = NULL;
4765 } else {
4766 logconfx("cannot find module with \"%s\" "
4767 "configuration prefix", prefix);
4768 return (-1);
4769 }
4770 }
4771
4772 /* Find parameter. */
4773 conf_param = find_conf_param(conf_param_tbl_ptr, conf_param_hash_ptr,
4774 curparam);
4775 if (conf_param == NULL) {
4776 logconfx("unknown parameter");
4777 return (-1);
4778 }
4779
4780 /* Validate type of argument. */
4781 if (conf_param->arg_type > IPA_CONF_TYPE_MISC) {
4782 logconfx("internal error: unknown type %u of an argument",
4783 conf_param->arg_type);
4784 return (-1);
4785 }
4786
4787 /* Check whether parameter is used in correct place. */
4788 id = conf_param->param_where;
4789 if (id != NULL)
4790 for (;; ++id) {
4791 if (*id == section)
4792 break;
4793 if (*id == 0) {
4794 logconfx("this parameter is not expected here");
4795 return (-1);
4796 }
4797 }
4798
4799 /* Check number of parameter's arguments. */
4800 nargs = conf_param->arg_nargs;
4801 if (nargs >= 0) {
4802 if (parser_nargs != nargs) {
4803 logconfx("wrong number of arguments (has %d, "
4804 "should have %d)", parser_nargs, nargs);
4805 return (-1);
4806 }
4807 } else {
4808 nargs = -nargs;
4809 if (parser_nargs < nargs) {
4810 logconfx("this parameter should have at "
4811 "least %d argument%s", nargs,
4812 plural_form((unsigned int)nargs));
4813 return (-1);
4814 }
4815 }
4816
4817 /* Validate arguments if needed. */
4818 if (conf_param->arg_regexp != NULL)
4819 if (regexec_simple(conf_param->arg_regexp, parser_args) != 0) {
4820 logconfx("wrong format of an argument");
4821 return (-1);
4822 }
4823
4824 /* Parse it. */
4825 get_arg = &get_arg_tbl[conf_param->arg_type];
4826 if (get_arg->reg != NULL)
4827 if (regexec_simple(get_arg->reg, parser_args) != 0) {
4828 logconfx("wrong format of an argument");
4829 return (-1);
4830 }
4831 if (get_arg->parse(get_arg->argp) < 0)
4832 return (-1);
4833 if (conf_param->arg_parse != NULL)
4834 if (conf_param->arg_parse(get_arg->argp) < 0)
4835 return (-1);
4836
4837 curparam = NULL;
4838 if (curmodfile != NULL && in_own_sect) {
4839 /* Restore ipa.conf parameters tables. */
4840 curmodfile = NULL;
4841 conf_param_hash_ptr = conf_param_hash;
4842 conf_param_tbl_ptr = conf_param_tbl;
4843 }
4844
4845 return (0);
4846 }
4847
4848 static int
token_section_end(void)4849 token_section_end(void)
4850 {
4851 struct sect_stack *sect_stack;
4852
4853 cursect = NULL;
4854 if (!in_own_sect) {
4855 /* Register configuration event in module for its section. */
4856 if (cur_db_mod != NULL) {
4857 if (db_mod_conf_event(cur_db_mod,
4858 IPA_CONF_EVENT_CUSTOM_SECT_END, section,
4859 (void *)NULL) < 0)
4860 return (-1);
4861 } else {
4862 if (ac_mod_conf_event(cur_ac_mod,
4863 IPA_CONF_EVENT_CUSTOM_SECT_END, section,
4864 (void *)NULL) < 0)
4865 return (-1);
4866 }
4867 } else {
4868 /*
4869 * Register configuration event in all modules for
4870 * ipa.conf's section.
4871 */
4872 if (mod_conf_event(conf_event_begin[section] + 1,
4873 conf_event_no, conf_event_arg) < 0)
4874 return (-1);
4875 switch (section) {
4876 #ifdef WITH_RULES
4877 case IPA_CONF_SECT_RULE:
4878 #endif
4879 #ifdef WITH_AUTORULES
4880 case IPA_CONF_SECT_AUTORULE:
4881 #endif
4882 case IPA_CONF_SECT_RULEPAT:
4883 section_top = IPA_CONF_SECT_ROOT;
4884 break;
4885 case IPA_CONF_SECT_GLOBAL:
4886 section_top = IPA_CONF_SECT_ROOT;
4887 #ifdef WITH_THRESHOLDS
4888 if (check_threshold_times(global_threshold_time_width,
4889 global_threshold_time_slice, 0) < 0)
4890 return (-1);
4891 #endif
4892 break;
4893 #ifdef WITH_LIMITS
4894 case IPA_CONF_SECT_LIMIT:
4895 section_top = section_first;
4896 if (LIMIT_IS_NOTSET(curlimit)) {
4897 logconfx("parameter \"limit\" is absent");
4898 return (-1);
4899 }
4900 if (curlimit->lim == 0 &&
4901 curlimit->expire.expire.upto == TEXP_UPTO_SIMPLE &&
4902 curlimit->expire.expire.seconds == 0) {
4903 logconfx("\"limit\" parameter cannot be equal "
4904 "to zero, since \"expire\" parameter is "
4905 "equal to 0s");
4906 return (-1);
4907 }
4908 (void)parser_local_sym_del("limit");
4909 break;
4910 # ifdef WITH_SUBLIMITS
4911 case SECT_SUBLIMIT:
4912 section_top = IPA_CONF_SECT_LIMIT;
4913 (void)parser_local_sym_del("sublimit");
4914 break;
4915 # endif
4916 case IPA_CONF_SECT_IF_REACHED:
4917 case IPA_CONF_SECT_IF_NOT_REACHED:
4918 case IPA_CONF_SECT_IF_ALL_REACHED:
4919 case IPA_CONF_SECT_IF_ALL_NOT_REACHED:
4920 case IPA_CONF_SECT_IF_ANY_REACHED:
4921 case IPA_CONF_SECT_IF_ANY_NOT_REACHED:
4922 curcmds = prevcmds;
4923 break;
4924 #endif /* WITH_LIMITS */
4925 #ifdef WITH_THRESHOLDS
4926 case IPA_CONF_SECT_THRESHOLD:
4927 section_top = section_first;
4928 if (THRESHOLD_IS_NOTSET(curthreshold)) {
4929 logconfx("parameter \"threshold\" is absent");
4930 return (-1);
4931 }
4932 if (check_threshold_times(curthreshold->time_width,
4933 curthreshold->time_slice, 1) < 0)
4934 return (-1);
4935 (void)parser_local_sym_del("threshold");
4936 break;
4937 #endif /* WITH_THRESHOLDS */
4938 case IPA_CONF_SECT_STARTUP:
4939 case IPA_CONF_SECT_SHUTDOWN:
4940 section_rc = RC_NOTSET;
4941 break;
4942 }
4943 }
4944
4945 sect_stack = SLIST_FIRST(§_stack_list);
4946 SLIST_REMOVE_HEAD(§_stack_list, link);
4947 section = sect_stack->section;
4948 mem_free(sect_stack, m_anon);
4949 if (!in_own_sect && section < IPA_CONF_SECT_CUSTOM_OFFSET) {
4950 /*
4951 * We were in custom section and previous section
4952 * is not a custom section. Restore ipa.conf tables.
4953 */
4954 curmodfile = NULL;
4955 conf_sect_tbl_ptr = conf_sect_tbl;
4956 conf_param_tbl_ptr = conf_param_tbl;
4957 conf_sect_hash_ptr = conf_sect_hash;
4958 conf_param_hash_ptr = conf_param_hash;
4959 in_own_sect = 1;
4960 }
4961
4962 return (0);
4963 }
4964
4965 static int
deinit_config_mods(void)4966 deinit_config_mods(void)
4967 {
4968 const struct ipa_ac_mod *ipa_ac_mod;
4969 const struct ipa_db_mod *ipa_db_mod;
4970 const struct ac_mod *ac_mod;
4971 const struct db_mod *db_mod;
4972
4973 SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
4974 ipa_ac_mod = ac_mod->ipa_ac_mod;
4975 if (mimic_real_config)
4976 if (ipa_ac_mod->conf_mimic_real() < 0) {
4977 logconfe("module %s: conf_mimic_real failed",
4978 ac_mod->mod_file);
4979 return (-1);
4980 }
4981 deinit_conf_tbls(1,
4982 ipa_ac_mod->conf_sect_tbl, ac_mod->conf_sect_hash,
4983 ipa_ac_mod->conf_param_tbl, ac_mod->conf_param_hash);
4984 if (ipa_ac_mod->conf_deinit() < 0) {
4985 logconfe("module %s: conf_deinit failed",
4986 ac_mod->mod_file);
4987 return (-1);
4988 }
4989 }
4990
4991 SLIST_FOREACH(db_mod, &db_mod_list, link) {
4992 ipa_db_mod = db_mod->ipa_db_mod;
4993 if (mimic_real_config)
4994 if (ipa_db_mod->conf_mimic_real() < 0) {
4995 logconfe("module %s: conf_mimic_real failed",
4996 db_mod->mod_file);
4997 return (-1);
4998 }
4999 deinit_conf_tbls(1,
5000 ipa_db_mod->conf_sect_tbl, db_mod->conf_sect_hash,
5001 ipa_db_mod->conf_param_tbl, db_mod->conf_param_hash);
5002 if (ipa_db_mod->conf_deinit() < 0) {
5003 logconfe("module %s: conf_deinit failed",
5004 db_mod->mod_file);
5005 return (-1);
5006 }
5007 }
5008 return (0);
5009 }
5010
5011 /*
5012 * Main function for parsing configuration file(s).
5013 */
5014 int
configure(PARSING_MODE mode)5015 configure(PARSING_MODE mode)
5016 {
5017 struct parser_pb *pb;
5018
5019 switch (mode) {
5020 case TEST_PARSING:
5021 case CMD_PARSING:
5022 use_log = 0;
5023 break;
5024 default:
5025 use_log = 1;
5026 }
5027
5028 /* Set wrappers for log functions during configuration. */
5029 xvlogmsgx = vlogconfx_priority;
5030 mvlogmsgx = vlogconfe;
5031 parser_vlogmsgx = parser_vlogmsgx_wrapper;
5032
5033 if (memfunc_init() < 0)
5034 goto failed;
5035
5036 if (init_config_data(mode) < 0)
5037 goto failed;
5038
5039 section = section_first = section_top = IPA_CONF_SECT_ROOT;
5040 section_rc = RC_NOTSET;
5041 parsing_mode = mode;
5042 memfunc.m_parser = m_parser;
5043
5044 if (mode != TEST_PARSING && mode != CMD_PARSING)
5045 logmsgx(IPA_LOG_INFO, "use configuration file %s, parsing...",
5046 ipa_conf_file);
5047
5048 if (check_conf_file(ipa_conf_file, 0) < 0)
5049 goto failed;
5050
5051 /* Initialize parser and first pb. */
5052 if (parser_init() < 0)
5053 goto failed;
5054 pb = parser_new_pb(0);
5055 if (pb == NULL)
5056 goto failed;
5057 pb->fname = ipa_conf_file;
5058 pb->fp = fopen(ipa_conf_file, "r");
5059 if (pb->fp == NULL) {
5060 logconfe("fopen(%s, \"r\"): %s", ipa_conf_file,
5061 strerror(errno));
5062 goto failed;
5063 }
5064 if (parser_push_pb(pb) < 0)
5065 goto failed;
5066 include_depth = 1;
5067
5068 /* Needed for log messages. */
5069 curparam = cursect = curmodfile = NULL;
5070
5071 /* Set ipa.conf configuration tables. */
5072 conf_sect_tbl_ptr = conf_sect_tbl;
5073 conf_param_tbl_ptr = conf_param_tbl;
5074 conf_sect_hash_ptr = conf_sect_hash;
5075 conf_param_hash_ptr = conf_param_hash;
5076 in_own_sect = 1;
5077
5078 for (;;) {
5079 switch (parser_read_string()) {
5080 case 1:
5081 /* Successfully read one logical line. */
5082 break;
5083 case 0:
5084 /* EOF of current configuration file. */
5085 --include_depth;
5086 pb = parser_top_pb();
5087 if (fclose(pb->fp) != 0) {
5088 logconfe("fclose(%s): %s", pb->fname,
5089 strerror(errno));
5090 goto failed;
5091 }
5092 if (pb->fname != ipa_conf_file)
5093 mem_free(pb->fname, m_parser);
5094 pb = parser_pop_pb();
5095 if (pb == NULL)
5096 goto end_of_parsing;
5097 /* Initialize previous file for parsing. */
5098 pb->fp = fopen(pb->fname, "r");
5099 if (pb->fp == NULL) {
5100 logconfe("fopen(%s, \"r\"): %s", pb->fname,
5101 strerror(errno));
5102 goto failed;
5103 }
5104 if (fseek(pb->fp, pb->foff, SEEK_SET) < 0) {
5105 logconfe("fseek(%s, %ld, SEEK_SET): %s",
5106 pb->fname, pb->foff, strerror(errno));
5107 goto failed;
5108 }
5109 continue;
5110 default: /* -1 */
5111 goto failed;
5112 }
5113 switch (parser_token_id) {
5114 case TOKEN_ID_SECTION_BEGIN:
5115 if (token_section_begin() < 0)
5116 goto failed;
5117 break;
5118 case TOKEN_ID_SECTION_END:
5119 if (token_section_end() < 0)
5120 goto failed;
5121 break;
5122 case TOKEN_ID_PARAMETER:
5123 if (token_parameter() < 0)
5124 goto failed;
5125 break;
5126 }
5127 }
5128
5129 end_of_parsing:
5130 if (deinit_config_mods() < 0)
5131 goto failed;
5132
5133 if (parser_deinit() < 0)
5134 goto failed;
5135
5136 deinit_config_data();
5137
5138 if (mode != TEST_PARSING)
5139 mimic_real_config = 1;
5140
5141 if (mimic_real_config) {
5142 if (set_global_params() < 0)
5143 goto failed;
5144 rulepats_inherit();
5145 }
5146
5147 #ifdef WITH_AUTORULES
5148 STAILQ_INIT(&autorules_list);
5149 if (nautorules != 0) {
5150 if (autorules_inherit() < 0)
5151 goto failed;
5152 } else
5153 marray_deinit(autorules_marray);
5154 #endif
5155
5156 #ifdef WITH_RULES
5157 if (mimic_real_config) {
5158 if (rules_inherit() < 0)
5159 goto failed;
5160 if (setup_all_ictl() < 0)
5161 goto failed;
5162 }
5163 #endif
5164
5165 /* Set wrappers for log functions after configuration. */
5166 mvlogmsgx = mvlogmsgx_wrapper;
5167 xvlogmsgx = vlogmsgx;
5168 return (0);
5169
5170 failed:
5171 log_include_history();
5172 logconfe("configuration file parsing failed!");
5173 return (-1);
5174 }
5175
5176 /*
5177 * Unload all modules and free memory used by structures which
5178 * describe loaded modules. Note that any pointer should not
5179 * references any data in unloaded modules' memory. So, the best
5180 * place when to call this function: after memfunc_deinit_1() and
5181 * before memfunc_deinit_2().
5182 */
5183 int
unload_all_mods(void)5184 unload_all_mods(void)
5185 {
5186 struct ac_mod *ac_mod, *ac_mod_next;
5187 struct db_mod *db_mod, *db_mod_next;
5188 int rv;
5189
5190 rv = 0;
5191 SLIST_FOREACH_SAFE(ac_mod, &ac_mod_list, link, ac_mod_next) {
5192 if (dl_close(ac_mod->mod_handle) < 0) {
5193 logmsgx(IPA_LOG_ERR, "module %s: dl_close failed: %s",
5194 ac_mod->mod_file, dl_error());
5195 rv = -1;
5196 }
5197 mem_free(ac_mod->mod_file, m_parser);
5198 mem_free(ac_mod, m_anon);
5199 }
5200
5201 SLIST_FOREACH_SAFE(db_mod, &db_mod_list, link, db_mod_next) {
5202 if (dl_close(db_mod->mod_handle) < 0) {
5203 logmsgx(IPA_LOG_ERR, "module %s: dl_close failed: %s",
5204 db_mod->mod_file, dl_error());
5205 rv = -1;
5206 }
5207 mem_free(db_mod->mod_file, m_parser);
5208 mem_free(db_mod, m_anon);
5209 }
5210
5211 return (rv);
5212 }
5213
5214 static void
print_time_u_int(unsigned int a)5215 print_time_u_int(unsigned int a)
5216 {
5217 const uint64_t t = a;
5218
5219 print_time(&t);
5220 }
5221
5222 /*
5223 * Table of sections names, only used entries are defined.
5224 */
5225 static const char *const sect_name_tbl[] = {
5226 NULL, /* 0 | undefined */
5227 NULL, /* 1 | IPA_CONF_SECT_ROOT */
5228 NULL, /* 2 | IPA_CONF_SECT_GLOBAL */
5229 NULL, /* 3 | IPA_CONF_SECT_RULE */
5230 NULL, /* 4 | IPA_CONF_SECT_LIMIT */
5231 NULL, /* 5 | IPA_CONF_SECT_THRESHOLD */
5232 NULL, /* 6 | IPA_CONF_SECT_AUTORULE */
5233 NULL, /* 7 | IPA_CONF_SECT_RULEPAT */
5234 "restart", /* 8 | IPA_CONF_SECT_RESTART */
5235 "reach", /* 9 | IPA_CONF_SECT_REACH */
5236 "expire", /* 10 | IPA_CONF_SECT_EXPIRE */
5237 "startup", /* 11 | IPA_CONF_SECT_STARTUP */
5238 "shutdown", /* 12 | IPA_CONF_SECT_SHUTDOWN */
5239 "if_reached", /* 13 | IPA_CONF_SECT_IF_REACHED */
5240 "if_not_reached", /* 14 | IPA_CONF_SECT_IF_NOT_REACHED */
5241 "if_all_reached", /* 15 | IPA_CONF_SECT_IF_ALL_REACHED */
5242 "if_any_reached", /* 16 | IPA_CONF_SECT_IF_ANY_REACHED */
5243 "if_all_not_reached", /* 17 | IPA_CONF_SECT_IF_ALL_NOT_REACHED*/
5244 "if_any_not_reached", /* 18 | IPA_CONF_SECT_IF_ANY_NOT_REACHED*/
5245 "below_threshold", /* 19 | IPA_CONF_SECT_BELOW_THRESHOLD */
5246 "equal_threshold", /* 20 | IPA_CONF_SECT_EQUAL_THRESHOLD */
5247 "above_threshold" /* 21 | IPA_CONF_SECT_ABOVE_THRESHOLD */
5248 };
5249
5250 static char sect_is_visible; /* Set if section is visible for
5251 modules. */
5252
5253 /*
5254 * Call conf_show() for all modules if current section is
5255 * visible for modules.
5256 */
5257 static void
mod_conf_show(unsigned int sect_id,unsigned int no)5258 mod_conf_show(unsigned int sect_id, unsigned int no)
5259 {
5260 if (sect_is_visible) {
5261 const struct ac_mod *ac_mod;
5262 const struct db_mod *db_mod;
5263
5264 need_nl = 0;
5265 SLIST_FOREACH(ac_mod, &ac_mod_list, link)
5266 ac_mod->ipa_ac_mod->conf_show(sect_id, no);
5267 if (sect_id == IPA_CONF_SECT_ROOT)
5268 print_nl_cond();
5269 SLIST_FOREACH(db_mod, &db_mod_list, link)
5270 db_mod->ipa_db_mod->conf_show(sect_id, no);
5271 if (sect_id == IPA_CONF_SECT_ROOT)
5272 print_nl_cond();
5273 }
5274 }
5275
5276 static void
show_cmds(const struct cmds * cmds)5277 show_cmds(const struct cmds *cmds)
5278 {
5279 #ifdef WITH_RULES
5280 const struct ictl_list *ictl_list;
5281 const struct ictl *ictl;
5282 #endif
5283 const struct cmd_list *cmd_list;
5284 const struct cmd *cmd;
5285
5286 if (cmds->sync >= 0) {
5287 print_param_name("sync_exec");
5288 print_boolean(cmds->sync);
5289 print_param_end();
5290 }
5291
5292 #ifdef WITH_RULES
5293 ictl_list = &cmds->ictl_list;
5294 STAILQ_FOREACH(ictl, ictl_list, link) {
5295 print_param_name0("ictl");
5296 printf("\"%s\"", ictl->str);
5297 print_param_end();
5298 }
5299 #endif
5300
5301 cmd_list = &cmds->cmd_list;
5302 STAILQ_FOREACH(cmd, cmd_list, link) {
5303 print_param_name0("exec");
5304 if (cmd->user != NULL)
5305 printf("%s ", cmd->user);
5306 print_string(cmd->str);
5307 print_param_end();
5308 }
5309 }
5310
5311 static void
show_commands(unsigned int sect_id,const struct cmds * cmds)5312 show_commands(unsigned int sect_id, const struct cmds *cmds)
5313 {
5314 if (cmds->sect_set) {
5315 print_sect_name(sect_name_tbl[sect_id]);
5316 print_sect_begin();
5317 show_cmds(cmds);
5318 mod_conf_show(sect_id, 0);
5319 print_sect_end();
5320 }
5321 }
5322
5323 static void
show_rule_rc(const struct cmds_rule * rc)5324 show_rule_rc(const struct cmds_rule *rc)
5325 {
5326 unsigned int x, sect_id;
5327
5328 sect_id = IPA_CONF_SECT_STARTUP;
5329 for (x = 0; x < 2; ++rc, ++x) {
5330 if (rc->cmds.sect_set) {
5331 print_sect_name(rc_sect_name[x]);
5332 print_sect_begin();
5333 show_cmds(&rc->cmds);
5334 mod_conf_show(sect_id, 0);
5335 #ifdef WITH_LIMITS
5336 show_commands(IPA_CONF_SECT_IF_ALL_REACHED,
5337 &rc->cmds_all_reached);
5338 show_commands(IPA_CONF_SECT_IF_ALL_NOT_REACHED,
5339 &rc->cmds_all_not_reached);
5340 show_commands(IPA_CONF_SECT_IF_ANY_REACHED,
5341 &rc->cmds_any_reached);
5342 show_commands(IPA_CONF_SECT_IF_ANY_NOT_REACHED,
5343 &rc->cmds_any_not_reached);
5344 #endif
5345 print_sect_end();
5346 }
5347 sect_id = IPA_CONF_SECT_SHUTDOWN;
5348 }
5349 }
5350
5351 static void
show_debug_exec(signed char val)5352 show_debug_exec(signed char val)
5353 {
5354 if (val >= 0) {
5355 print_param_name("debug_exec");
5356 printf("%d", val);
5357 print_param_end();
5358 }
5359 }
5360
5361 static void
show_worktime_generic(const struct worktime * wt,const char * param_name)5362 show_worktime_generic(const struct worktime *wt, const char *param_name)
5363 {
5364 const struct tint_list *list;
5365 const struct tint *tint;
5366 unsigned int wday;
5367
5368 if (wt == NULL)
5369 return;
5370
5371 print_param_name(param_name);
5372 for (wday = 0; wday < DAYS_IN_WEEK; ++wday) {
5373 list = wt->tint_list[wday];
5374 if (!STAILQ_EMPTY(list)) {
5375 if (wday > 0)
5376 printf(" ");
5377 printf("%c", wdays_short[wday]);
5378 tint = STAILQ_FIRST(list);
5379 if (tint->sec1 == 0 && tint->sec2 == SECONDS_IN_DAY)
5380 printf(" *");
5381 else
5382 for (; tint != NULL;
5383 tint = STAILQ_NEXT(tint, link))
5384 printf(" %s", tint_str(tint));
5385 }
5386 }
5387 print_param_end();
5388 }
5389
5390 static void
show_worktime(const struct worktime * wt)5391 show_worktime(const struct worktime *wt)
5392 {
5393 show_worktime_generic(wt, "worktime");
5394 }
5395
5396 static void
show_ac_list(const struct ac_list * list)5397 show_ac_list(const struct ac_list *list)
5398 {
5399 if (list != NULL) {
5400 print_param_name("ac_list");
5401 if (list != &ac_list_null) {
5402 const struct ac_elem *ac;
5403
5404 for (ac = STAILQ_FIRST(list);;) {
5405 printf("%s", ac->ipa_ac_mod->ac_name);
5406 ac = STAILQ_NEXT(ac, link);
5407 if (ac == NULL)
5408 break;
5409 printf(" ");
5410 }
5411 } else
5412 printf("null");
5413 print_param_end();
5414 }
5415 }
5416
5417 static void
show_db_list(const struct db_list * list)5418 show_db_list(const struct db_list *list)
5419 {
5420 if (list != NULL) {
5421 print_param_name("db_list");
5422 if (list != &db_list_null) {
5423 const struct db_elem *db;
5424
5425 for (db = STAILQ_FIRST(list);;) {
5426 printf("%s", db->ipa_db_mod->db_name);
5427 db = STAILQ_NEXT(db, link);
5428 if (db == NULL)
5429 break;
5430 printf(" ");
5431 }
5432 } else
5433 printf("null");
5434 print_param_end();
5435 }
5436 }
5437
5438 #if defined(WITH_RULES) || defined(WITH_ANY_LIMITS)
5439 static void
print_info(const char * info)5440 print_info(const char *info)
5441 {
5442 if (info != NULL) {
5443 print_param_name("info");
5444 print_string(info);
5445 print_param_end();
5446 }
5447 }
5448 #endif /* WITH_RULES || WITH_ANY_LIMITS */
5449
5450 #ifdef WITH_RULES
5451 static void
show_ac_gather_xxx(const char * pat,const char * param_name)5452 show_ac_gather_xxx(const char *pat, const char *param_name)
5453 {
5454 if (pat != NULL) {
5455 print_param_name(param_name);
5456 print_string(pat);
5457 print_param_end();
5458 }
5459 }
5460 #endif /* WITH_RULES */
5461
5462 #ifdef WITH_LIMITS
5463 /*
5464 * Convert expired time to human readable string.
5465 */
5466 static void
print_texp(const struct texp * texp)5467 print_texp(const struct texp *texp)
5468 {
5469 unsigned int t, a;
5470 int need_space;
5471
5472 a = texp->seconds;
5473 if (texp->upto != TEXP_UPTO_SIMPLE && texp->side == 0) {
5474 printf("+%c", texp->upto);
5475 need_space = 1;
5476 } else
5477 need_space = 0;
5478 t = a / SECONDS_IN_DAY;
5479 if (t != 0) {
5480 if (need_space)
5481 printf(" ");
5482 else
5483 need_space = 1;
5484 printf("%uD", t);
5485 a -= t * SECONDS_IN_DAY;
5486 }
5487 if (a != 0 || (a == 0 && t == 0 && texp->upto == TEXP_UPTO_SIMPLE)) {
5488 if (need_space)
5489 printf(" ");
5490 else
5491 need_space = 1;
5492 print_time_u_int(a);
5493 }
5494 if (texp->upto != TEXP_UPTO_SIMPLE && texp->side == 1) {
5495 if (need_space)
5496 printf(" ");
5497 printf("+%c", texp->upto);
5498 }
5499 }
5500
5501 static void
show_limit_rc(const struct cmds_limit * rc)5502 show_limit_rc(const struct cmds_limit *rc)
5503 {
5504 unsigned int x, sect_id;
5505
5506 sect_id = IPA_CONF_SECT_STARTUP;
5507 for (x = 0; x < 2; ++rc, ++x) {
5508 if (rc->cmds.sect_set) {
5509 print_sect_name(rc_sect_name[x]);
5510 print_sect_begin();
5511 show_cmds(&rc->cmds);
5512 mod_conf_show(sect_id, 0);
5513 show_commands(IPA_CONF_SECT_IF_REACHED,
5514 &rc->cmds_reached);
5515 show_commands(IPA_CONF_SECT_IF_NOT_REACHED,
5516 &rc->cmds_not_reached);
5517 print_sect_end();
5518 }
5519 sect_id = IPA_CONF_SECT_SHUTDOWN;
5520 }
5521 }
5522
5523 static void
show_load_limit(signed char val)5524 show_load_limit(signed char val)
5525 {
5526 if (val >= 0) {
5527 print_param_name("load_limit");
5528 print_boolean(val);
5529 print_param_end();
5530 }
5531 }
5532
5533 static void
show_debug_limit(signed char val1,signed char val2)5534 show_debug_limit(signed char val1, signed char val2)
5535 {
5536 if (val1 >= 0) {
5537 print_param_name("debug_limit");
5538 printf("%d", val1);
5539 print_param_end();
5540 }
5541 if (val2 >= 0) {
5542 print_param_name("debug_limit_init");
5543 printf("%d", val2);
5544 print_param_end();
5545 }
5546 }
5547
5548 static void
show_limits(const struct limits_list * list)5549 show_limits(const struct limits_list *list)
5550 {
5551 const struct limit *limit;
5552 #ifdef WITH_SUBLIMITS
5553 const struct sublimit *sublimit;
5554 #endif
5555
5556 STAILQ_FOREACH(limit, list, link) {
5557 print_sect_name("limit");
5558 printf("%s ", limit->name);
5559 print_sect_begin();
5560 show_db_list(limit->db_list);
5561 print_info(limit->info);
5562 print_param_name("limit");
5563 print_value(&limit->lim, limit->cnt_type);
5564 print_param_end();
5565 show_load_limit(limit->load_limit);
5566 show_worktime(limit->worktime);
5567 mod_conf_show(IPA_CONF_SECT_LIMIT, limit->no);
5568 if (limit->restart.cmds.sect_set) {
5569 print_sect_name("restart");
5570 print_sect_begin();
5571 if (limit->restart.restart.upto != TEXP_UPTO_NOTSET) {
5572 print_param_name("restart");
5573 print_texp(&limit->restart.restart);
5574 print_param_end();
5575 }
5576 show_cmds(&limit->restart.cmds);
5577 mod_conf_show(IPA_CONF_SECT_RESTART, 0);
5578 print_sect_end();
5579 }
5580 show_commands(IPA_CONF_SECT_REACH, &limit->reach);
5581 if (limit->expire.cmds.sect_set) {
5582 print_sect_name("expire");
5583 print_sect_begin();
5584 if (limit->expire.expire.upto != TEXP_UPTO_NOTSET) {
5585 print_param_name("expire");
5586 print_texp(&limit->expire.expire);
5587 print_param_end();
5588 }
5589 show_cmds(&limit->expire.cmds);
5590 mod_conf_show(IPA_CONF_SECT_EXPIRE, 0);
5591 print_sect_end();
5592 }
5593 show_limit_rc(limit->rc);
5594 # ifdef WITH_SUBLIMITS
5595 sect_is_visible = 0;
5596 STAILQ_FOREACH(sublimit, &limit->sublimits, link) {
5597 print_sect_name("sublimit");
5598 if (sublimit->lim_pc != 0)
5599 printf("%u%%", sublimit->lim_pc);
5600 else
5601 print_value(&sublimit->lim, sublimit->cnt_type);
5602 printf(" ");
5603 print_sect_begin();
5604 show_commands(IPA_CONF_SECT_REACH, &sublimit->reach);
5605 show_limit_rc(sublimit->rc);
5606 print_sect_end();
5607 }
5608 sect_is_visible = 1;
5609 # endif /* WITH_SUBLIMITS */
5610 print_sect_end();
5611 }
5612 }
5613 #endif /* WITH_LIMITS */
5614
5615 #ifdef WITH_THRESHOLDS
5616 static void
show_load_threshold(signed char val)5617 show_load_threshold(signed char val)
5618 {
5619 if (val >= 0) {
5620 print_param_name("load_threshold");
5621 print_boolean(val);
5622 print_param_end();
5623 }
5624 }
5625
5626 static void
show_threshold_type(signed char val)5627 show_threshold_type(signed char val)
5628 {
5629 if (val >= 0) {
5630 print_param_name("threshold_type");
5631 printf("%d", val);
5632 print_param_end();
5633 }
5634 }
5635
5636 static void
show_threshold_time_width(unsigned int val)5637 show_threshold_time_width(unsigned int val)
5638 {
5639 if (val != 0) {
5640 print_param_name("threshold_time_width");
5641 print_time_u_int(val);
5642 print_param_end();
5643 }
5644 }
5645
5646 static void
show_threshold_time_slice(const struct tevent * tevent)5647 show_threshold_time_slice(const struct tevent *tevent)
5648 {
5649 if (tevent != NULL) {
5650 print_param_name("threshold_time_slice");
5651 print_time_u_int(tevent->event_step);
5652 print_param_end();
5653 }
5654 }
5655
5656 static void
show_threshold_balance(unsigned int a,unsigned int b,unsigned int c)5657 show_threshold_balance(unsigned int a, unsigned int b, unsigned int c)
5658 {
5659 if (a != 0) {
5660 print_param_name("threshold_balance");
5661 if (a != UINT_MAX)
5662 printf("%u:", a);
5663 else
5664 printf("-:");
5665 if (b != UINT_MAX)
5666 printf("%u:", b);
5667 else
5668 printf("-:");
5669 if (c != UINT_MAX)
5670 printf("%u", c);
5671 else
5672 printf("-");
5673 print_param_end();
5674 }
5675 }
5676
5677 static void
show_debug_threshold(signed char val1,signed char val2)5678 show_debug_threshold(signed char val1, signed char val2)
5679 {
5680 if (val1 >= 0) {
5681 print_param_name("debug_threshold");
5682 printf("%d", val1);
5683 print_param_end();
5684 }
5685 if (val2 >= 0) {
5686 print_param_name("debug_threshold_init");
5687 printf("%d", val2);
5688 print_param_end();
5689 }
5690 }
5691
5692 static void
show_thresholds(const struct thresholds_list * list)5693 show_thresholds(const struct thresholds_list *list)
5694 {
5695 const struct threshold *threshold;
5696
5697 STAILQ_FOREACH(threshold, list, link) {
5698 print_sect_name("threshold");
5699 printf("%s ", threshold->name);
5700 print_sect_begin();
5701 show_db_list(threshold->db_list);
5702 print_info(threshold->info);
5703 print_param_name("threshold");
5704 print_value(&threshold->thr, threshold->cnt_type);
5705 print_param_end();
5706 if (threshold->thr_dev != 0) {
5707 print_param_name("threshold_deviation");
5708 if (threshold->thr_dev_pc != 0)
5709 printf("%u%%", threshold->thr_dev_pc);
5710 else
5711 print_value(&threshold->thr_dev,
5712 threshold->cnt_type);
5713 print_param_end();
5714 }
5715 show_threshold_type(threshold->thr_type);
5716 show_threshold_balance(threshold->below_lim,
5717 threshold->equal_lim, threshold->above_lim);
5718 show_load_threshold(threshold->load_thr);
5719 show_worktime(threshold->worktime);
5720 show_threshold_time_width(threshold->time_width);
5721 show_threshold_time_slice(threshold->time_slice);
5722 mod_conf_show(IPA_CONF_SECT_THRESHOLD, threshold->no);
5723 show_commands(IPA_CONF_SECT_STARTUP,
5724 &threshold->rc[RC_STARTUP]);
5725 show_commands(IPA_CONF_SECT_SHUTDOWN,
5726 &threshold->rc[RC_SHUTDOWN]);
5727 show_commands(IPA_CONF_SECT_BELOW_THRESHOLD,
5728 &threshold->below_thr);
5729 show_commands(IPA_CONF_SECT_EQUAL_THRESHOLD,
5730 &threshold->equal_thr);
5731 show_commands(IPA_CONF_SECT_ABOVE_THRESHOLD,
5732 &threshold->above_thr);
5733 print_sect_end();
5734 }
5735 }
5736 #endif /* WITH_THRESHOLDS */
5737
5738 static void
show_ctl_socket_perm(void)5739 show_ctl_socket_perm(void)
5740 {
5741 if (ctl_socket_perm != 0) {
5742 print_param_name("ctl_socket_perm");
5743 if (ctl_socket_perm & S_IWUSR)
5744 printf("u");
5745 if (ctl_socket_perm & S_IWGRP)
5746 printf("g");
5747 #ifdef CTL_CHECK_CREDS
5748 if (ctl_socket_perm & S_IWOTH)
5749 printf("o");
5750 #endif
5751 print_param_end();
5752 need_nl = 1;
5753 }
5754 }
5755
5756 #ifdef CTL_CHECK_CREDS
5757 static void
show_ctl_xxx_acl(const struct ctl_acl_class * class,const char * param_name)5758 show_ctl_xxx_acl(const struct ctl_acl_class *class, const char *param_name)
5759 {
5760 if (class != NULL) {
5761 print_param_name(param_name);
5762 printf("%s", class->class_name);
5763 print_param_end();
5764 }
5765 }
5766
5767 static void
show_ctl_rule_acl(const struct ctl_acl_class * class)5768 show_ctl_rule_acl(const struct ctl_acl_class *class)
5769 {
5770 show_ctl_xxx_acl(class, "ctl_rule_acl");
5771 }
5772
5773 static void
show_ctl_acl_classes(void)5774 show_ctl_acl_classes(void)
5775 {
5776 const struct ctl_acl_class *class;
5777 const struct ctl_acl_elem *elem;
5778
5779 STAILQ_FOREACH(class, &ctl_acl_classes, link) {
5780 print_param_name("ctl_acl_class");
5781 printf("%s", class->class_name);
5782 STAILQ_FOREACH(elem, &class->list, link) {
5783 printf(elem->allowed ? " " : " !");
5784 if (elem->user != NULL)
5785 printf("%s", elem->user);
5786 else
5787 printf("%%%s", elem->group);
5788 }
5789 print_param_end();
5790 need_nl = 1;
5791 }
5792 }
5793 #endif /* CTL_CHECK_CREDS */
5794
5795 static void
show_update_time(const struct tevent * tevent)5796 show_update_time(const struct tevent *tevent)
5797 {
5798 if (tevent != NULL) {
5799 print_param_name("update_time");
5800 print_time_u_int(tevent->event_step);
5801 print_param_end();
5802 }
5803 }
5804
5805 static void
show_append_time(const struct tevent * tevent)5806 show_append_time(const struct tevent *tevent)
5807 {
5808 if (tevent != NULL) {
5809 print_param_name("append_time");
5810 print_time_u_int(tevent->event_step);
5811 print_param_end();
5812 }
5813 }
5814
5815 /*
5816 * Main function for outputting configuration.
5817 */
5818 void
show_config(void)5819 show_config(void)
5820 {
5821 #ifdef WITH_RULES
5822 const struct rule *rule;
5823 #endif
5824 #ifdef WITH_AUTORULES
5825 const struct autorule *autorule;
5826 #endif
5827 const struct rulepat *rulepat;
5828 const struct ac_mod *ac_mod;
5829 const struct db_mod *db_mod;
5830 const struct time_param *time_param;
5831 const struct debug_param *debug_param;
5832 uint64_t val;
5833 unsigned int i;
5834
5835 printf(
5836 "/*\n\
5837 * This output is not identical to the original content of the configuration\n\
5838 * file(s), this is just how ipa(8) and IPA modules see their configurations.\n\
5839 * Any \"include\" or \"include_files\" parameters are not printed and all\n\
5840 * macro variables are expanded.\n\
5841 */\n\n");
5842
5843 if (mimic_real_config)
5844 printf("/* Mimic real configuration regime (" IPA_NAME "-"
5845 PACKAGE_VERSION "). */\n\n");
5846
5847 sect_is_visible = 1;
5848
5849 SLIST_FOREACH(ac_mod, &ac_mod_list, link) {
5850 print_param_name0("ac_mod");
5851 print_string(ac_mod->mod_file);
5852 print_param_end();
5853 need_nl = 1;
5854 }
5855 SLIST_FOREACH(db_mod, &db_mod_list, link) {
5856 print_param_name0("db_mod");
5857 print_string(db_mod->mod_file);
5858 print_param_end();
5859 need_nl = 1;
5860 }
5861 print_nl_cond();
5862
5863 for (i = 0; i < ROOT_DEBUG_PARAM_TBL_SIZE; ++i) {
5864 debug_param = &root_debug_param[i];
5865 if (*debug_param->value >= 0) {
5866 print_param_name(debug_param->name);
5867 printf("%d", *debug_param->value);
5868 print_param_end();
5869 need_nl = 1;
5870 }
5871 }
5872 print_nl_cond();
5873
5874 if (shell_path != NULL) {
5875 print_param_name("shell_path");
5876 print_string(shell_path);
5877 print_param_end();
5878 need_nl = 1;
5879 }
5880 if (shell_arg1 != NULL) {
5881 print_param_name("shell_arg1");
5882 print_string(shell_arg1);
5883 print_param_end();
5884 need_nl = 1;
5885 }
5886 print_nl_cond();
5887
5888 if (posix_re_pattern >= 0) {
5889 print_param_name("posix_re_pattern");
5890 print_boolean(posix_re_pattern);
5891 print_param_end();
5892 need_nl = 1;
5893 }
5894 print_nl_cond();
5895
5896 for (i = 0; i < ROOT_TIME_PARAM_TBL_SIZE; ++i) {
5897 time_param = &root_time_param[i];
5898 if (*time_param->value > 0) {
5899 print_param_name(time_param->name);
5900 print_time_u_int(*time_param->value);
5901 print_param_end();
5902 need_nl = 1;
5903 }
5904 }
5905 print_nl_cond();
5906
5907 if (only_abs_paths >= 0) {
5908 print_param_name("only_abs_paths");
5909 print_boolean(only_abs_paths);
5910 print_param_end();
5911 need_nl = 1;
5912 }
5913 print_nl_cond();
5914
5915 if (keep_rules_order >= 0) {
5916 print_param_name("keep_rules_order");
5917 print_boolean(keep_rules_order);
5918 print_param_end();
5919 need_nl = 1;
5920 }
5921 print_nl_cond();
5922
5923 if (ctl_enable >= 0) {
5924 print_param_name("ctl_enable");
5925 print_boolean(ctl_enable);
5926 print_param_end();
5927 need_nl = 1;
5928 }
5929 if (ctl_socket_path != NULL) {
5930 print_param_name("ctl_socket_path");
5931 print_string(ctl_socket_path);
5932 print_param_end();
5933 need_nl = 1;
5934 }
5935 if (ctl_timeout != 0) {
5936 print_param_name("ctl_timeout");
5937 print_time_u_int(ctl_timeout);
5938 print_param_end();
5939 need_nl = 1;
5940 }
5941 if (ctl_query_max_size != 0) {
5942 print_param_name("ctl_query_max_size");
5943 val = (uint64_t)ctl_query_max_size;
5944 print_bytes(&val);
5945 print_param_end();
5946 need_nl = 1;
5947 }
5948 show_ctl_socket_perm();
5949 #ifdef CTL_CHECK_CREDS
5950 show_ctl_acl_classes();
5951 show_ctl_xxx_acl(ctl_dump_acl, "ctl_dump_acl");
5952 show_ctl_xxx_acl(ctl_freeze_acl, "ctl_freeze_acl");
5953 show_ctl_xxx_acl(ctl_stat_acl, "ctl_stat_acl");
5954 #endif
5955 print_nl_cond();
5956
5957 if (value_units >= 0) {
5958 print_param_name("value_units");
5959 for (i = 0; i < VALUE_UNITS_TBL_SIZE; ++i)
5960 if (value_units == value_units_tbl[i].val) {
5961 printf("%s", value_units_tbl[i].str);
5962 break;
5963 }
5964 print_param_end();
5965 print_nl();
5966 }
5967
5968 mod_conf_show(IPA_CONF_SECT_ROOT, 0);
5969
5970 if (cmds_global[RC_STARTUP].sect_set) {
5971 show_commands(IPA_CONF_SECT_STARTUP,
5972 &cmds_global[RC_STARTUP]);
5973 print_nl();
5974 }
5975 if (cmds_global[RC_SHUTDOWN].sect_set) {
5976 show_commands(IPA_CONF_SECT_SHUTDOWN,
5977 &cmds_global[RC_SHUTDOWN]);
5978 print_nl();
5979 }
5980
5981 if (global_section_set) {
5982 print_sect_name("global");
5983 print_sect_begin();
5984 show_ac_list(global_ac_list);
5985 show_db_list(global_db_list);
5986 show_append_time(global_append_tevent);
5987 show_update_time(global_update_tevent);
5988 show_worktime(global_worktime);
5989 #ifdef WITH_LIMITS
5990 show_load_limit(global_load_limit);
5991 #endif
5992 #ifdef WITH_THRESHOLDS
5993 show_threshold_type(global_threshold_type);
5994 show_threshold_balance(global_threshold_below_lim,
5995 global_threshold_equal_lim, global_threshold_above_lim);
5996 show_load_threshold(global_load_threshold);
5997 show_threshold_time_width(global_threshold_time_width);
5998 show_threshold_time_slice(global_threshold_time_slice);
5999 #endif
6000 #ifdef CTL_CHECK_CREDS
6001 show_ctl_rule_acl(global_ctl_rule_acl);
6002 #endif
6003 for (i = 0; i < GLOBAL_DEBUG_PARAM_TBL_SIZE; ++i) {
6004 debug_param = &global_debug_param[i];
6005 if (*debug_param->value >= 0) {
6006 print_param_name(debug_param->name);
6007 printf("%d", *debug_param->value);
6008 print_param_end();
6009 need_nl = 1;
6010 }
6011 }
6012 mod_conf_show(IPA_CONF_SECT_GLOBAL, 0);
6013 print_sect_end();
6014 print_nl();
6015 }
6016
6017 #ifdef WITH_AUTORULES
6018 STAILQ_FOREACH(autorule, &autorules_list, link) {
6019 print_sect_name("autorule");
6020 printf("%s ", autorule->name);
6021 print_sect_begin();
6022 show_ac_list(autorule->ac_list);
6023 show_db_list(autorule->db_list);
6024 show_append_time(autorule->append_tevent);
6025 show_update_time(autorule->update_tevent);
6026 show_worktime(autorule->worktime);
6027 show_worktime_generic(autorule->worktime_rule, "worktime_rule");
6028 # ifdef CTL_CHECK_CREDS
6029 show_ctl_rule_acl(autorule->ctl_rule_acl);
6030 # endif
6031 mod_conf_show(IPA_CONF_SECT_AUTORULE, autorule->no);
6032 show_debug_exec(autorule->debug_exec);
6033 show_rule_rc(autorule->rc);
6034 # ifdef WITH_LIMITS
6035 show_debug_limit(autorule->debug_limit,
6036 autorule->debug_limit_init);
6037 show_limits(&autorule->limits);
6038 # endif
6039 # ifdef WITH_THRESHOLDS
6040 show_debug_threshold(autorule->debug_threshold,
6041 autorule->debug_threshold_init);
6042 show_thresholds(&autorule->thresholds);
6043 # endif
6044 print_sect_end();
6045 print_nl();
6046 }
6047 #endif /* WITH_AUTORULES */
6048
6049 STAILQ_FOREACH(rulepat, &rulepats_list, link) {
6050 print_sect_name("rulepat");
6051 print_string(rulepat->pat);
6052 printf(" ");
6053 print_sect_begin();
6054 if (rulepat->check_next >= 0) {
6055 print_param_name("check_next_rulepat");
6056 print_boolean(rulepat->check_next);
6057 print_param_end();
6058 }
6059 show_ac_list(rulepat->ac_list);
6060 show_db_list(rulepat->db_list);
6061 show_append_time(rulepat->append_tevent);
6062 show_update_time(rulepat->update_tevent);
6063 show_worktime(rulepat->worktime);
6064 #ifdef CTL_CHECK_CREDS
6065 show_ctl_rule_acl(rulepat->ctl_rule_acl);
6066 #endif
6067 mod_conf_show(IPA_CONF_SECT_RULEPAT, rulepat->no);
6068 show_debug_exec(rulepat->debug_exec);
6069 show_rule_rc(rulepat->rc);
6070 # ifdef WITH_LIMITS
6071 show_debug_limit(rulepat->debug_limit,
6072 rulepat->debug_limit_init);
6073 show_limits(&rulepat->limits);
6074 # endif
6075 # ifdef WITH_THRESHOLDS
6076 show_debug_threshold(rulepat->debug_threshold,
6077 rulepat->debug_threshold_init);
6078 show_thresholds(&rulepat->thresholds);
6079 # endif
6080 print_sect_end();
6081 print_nl();
6082 }
6083
6084 #ifdef WITH_RULES
6085 TAILQ_FOREACH(rule, &rules_list, list) {
6086 print_sect_name("rule");
6087 printf("%s ", rule->name);
6088 print_sect_begin();
6089 show_ac_list(rule->ac_list);
6090 show_ac_gather_xxx(rule->acg_add_pat, "ac_gather_add");
6091 show_ac_gather_xxx(rule->acg_sub_pat, "ac_gather_sub");
6092 show_db_list(rule->db_list);
6093 print_info(rule->info);
6094 show_append_time(rule->append_tevent);
6095 show_update_time(rule->update_tevent);
6096 show_worktime(rule->worktime);
6097 # ifdef CTL_CHECK_CREDS
6098 show_ctl_rule_acl(rule->ctl_rule_acl);
6099 # endif
6100 mod_conf_show(IPA_CONF_SECT_RULE, rule->no);
6101 show_debug_exec(rule->debug_exec);
6102 show_rule_rc(rule->rc);
6103 # ifdef WITH_LIMITS
6104 show_debug_limit(rule->debug_limit,
6105 rule->debug_limit_init);
6106 show_limits(&rule->limits);
6107 # endif
6108 # ifdef WITH_THRESHOLDS
6109 show_debug_threshold(rule->debug_threshold,
6110 rule->debug_threshold_init);
6111 show_thresholds(&rule->thresholds);
6112 # endif
6113 print_sect_end();
6114 print_nl();
6115 }
6116 #endif /* WITH_RULES */
6117 }
6118