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(&sect_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(&sect_stack_list);
4946 	SLIST_REMOVE_HEAD(&sect_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