xref: /freebsd/contrib/ntp/ntpd/ntp_config.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /* ntp_config.c
2  *
3  * This file contains the ntpd configuration code.
4  *
5  * Written By:	Sachin Kamboj
6  *		University of Delaware
7  *		Newark, DE 19711
8  * Some parts borrowed from the older ntp_config.c
9  * Copyright (c) 2006
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15 
16 #ifdef HAVE_NETINFO
17 # include <netinfo/ni.h>
18 #endif
19 
20 #include <stdio.h>
21 #include <ctype.h>
22 #ifdef HAVE_SYS_PARAM_H
23 # include <sys/param.h>
24 #endif
25 #include <signal.h>
26 #ifndef SIGCHLD
27 # define SIGCHLD SIGCLD
28 #endif
29 #ifdef HAVE_SYS_WAIT_H
30 # include <sys/wait.h>
31 #endif
32 #include <time.h>
33 
34 #include <isc/net.h>
35 #include <isc/result.h>
36 
37 #include "ntp.h"
38 #include "ntpd.h"
39 #include "ntp_io.h"
40 #include "ntp_unixtime.h"
41 #include "ntp_refclock.h"
42 #include "ntp_clockdev.h"
43 #include "ntp_filegen.h"
44 #include "ntp_stdlib.h"
45 #include "lib_strbuf.h"
46 #include "ntp_assert.h"
47 #include "ntp_random.h"
48 /*
49  * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
50  * so #include these later.
51  */
52 #include "ntp_config.h"
53 #include "ntp_cmdargs.h"
54 #include "ntp_scanner.h"
55 #include "ntp_parser.h"
56 #include "ntpd-opts.h"
57 
58 #ifndef IGNORE_DNS_ERRORS
59 # define DNSFLAGS 0
60 #else
61 # define DNSFLAGS GAIR_F_IGNDNSERR
62 #endif
63 
64 extern int yyparse(void);
65 
66 /* Bug 2817 */
67 #if defined(HAVE_SYS_MMAN_H)
68 # include <sys/mman.h>
69 #endif
70 
71 /* list of servers from command line for config_peers() */
72 int	cmdline_server_count;
73 char **	cmdline_servers;
74 
75 /* Current state of memory locking:
76  * -1: default
77  *  0: memory locking disabled
78  *  1: Memory locking enabled
79  */
80 int	cur_memlock = -1;
81 
82 /*
83  * "logconfig" building blocks
84  */
85 struct masks {
86 	const char * const	name;
87 	const u_int32		mask;
88 };
89 
90 static struct masks logcfg_class[] = {
91 	{ "clock",	NLOG_OCLOCK },
92 	{ "peer",	NLOG_OPEER },
93 	{ "sync",	NLOG_OSYNC },
94 	{ "sys",	NLOG_OSYS },
95 	{ NULL,		0 }
96 };
97 
98 /* logcfg_noclass_items[] masks are complete and must not be shifted */
99 static struct masks logcfg_noclass_items[] = {
100 	{ "allall",		NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
101 	{ "allinfo",		NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
102 	{ "allevents",		NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
103 	{ "allstatus",		NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
104 	{ "allstatistics",	NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
105 	/* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
106 	{ "allclock",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
107 	{ "allpeer",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
108 	{ "allsys",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
109 	{ "allsync",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
110 	{ NULL,			0 }
111 };
112 
113 /* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
114 static struct masks logcfg_class_items[] = {
115 	{ "all",		NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST },
116 	{ "info",		NLOG_INFO },
117 	{ "events",		NLOG_EVENT },
118 	{ "status",		NLOG_STATUS },
119 	{ "statistics",		NLOG_STATIST },
120 	{ NULL,			0 }
121 };
122 
123 typedef struct peer_resolved_ctx_tag {
124 	int		flags;
125 	int		host_mode;	/* T_* token identifier */
126 	u_short		family;
127 	keyid_t		keyid;
128 	u_char		hmode;		/* MODE_* */
129 	u_char		version;
130 	u_char		minpoll;
131 	u_char		maxpoll;
132 	u_int32		ttl;
133 	const char *	group;
134 	int		was_initializing;
135 } peer_resolved_ctx;
136 
137 /* Limits */
138 #define MAXPHONE	10	/* maximum number of phone strings */
139 #define MAXPPS		20	/* maximum length of PPS device string */
140 
141 /*
142  * Poll Skew List
143  */
144 
145 static psl_item psl[17-3+1];	/* values for polls 3-17 */
146 				/* To simplify the runtime code we */
147 				/* don't want to have to special-case */
148 				/* dealing with a default */
149 
150 
151 /*
152  * Miscellaneous macros
153  */
154 #define ISEOL(c)	((c) == '#' || (c) == '\n' || (c) == '\0')
155 #define ISSPACE(c)	((c) == ' ' || (c) == '\t')
156 
157 #define _UC(str)	((char *)(intptr_t)(str))
158 
159 /*
160  * Definitions of things either imported from or exported to outside
161  */
162 extern int yydebug;			/* ntp_parser.c (.y) */
163 config_tree cfgt;			/* Parser output stored here */
164 config_tree *cfg_tree_history;		/* History of configs */
165 char *	sys_phone[MAXPHONE] = {NULL};	/* ACTS phone numbers */
166 char	default_keysdir[] = NTP_KEYSDIR;
167 char *	keysdir = default_keysdir;	/* crypto keys directory */
168 char *	saveconfigdir;
169 #if defined(HAVE_SCHED_SETSCHEDULER)
170 int	config_priority_override = 0;
171 int	config_priority;
172 #endif
173 
174 const char *config_file;
175 static char default_ntp_signd_socket[] =
176 #ifdef NTP_SIGND_PATH
177 					NTP_SIGND_PATH;
178 #else
179 					"";
180 #endif
181 char *ntp_signd_socket = default_ntp_signd_socket;
182 #ifdef HAVE_NETINFO
183 struct netinfo_config_state *config_netinfo = NULL;
184 int check_netinfo = 1;
185 #endif /* HAVE_NETINFO */
186 #ifdef SYS_WINNT
187 char *alt_config_file;
188 LPTSTR temp;
189 char config_file_storage[MAX_PATH];
190 char alt_config_file_storage[MAX_PATH];
191 #endif /* SYS_WINNT */
192 
193 #ifdef HAVE_NETINFO
194 /*
195  * NetInfo configuration state
196  */
197 struct netinfo_config_state {
198 	void *domain;		/* domain with config */
199 	ni_id config_dir;	/* ID config dir      */
200 	int prop_index;		/* current property   */
201 	int val_index;		/* current value      */
202 	char **val_list;	/* value list         */
203 };
204 #endif
205 
206 struct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
207 					     pointer info */
208 int old_config_style = 1;    /* A boolean flag, which when set,
209 			      * indicates that the old configuration
210 			      * format with a newline at the end of
211 			      * every command is being used
212 			      */
213 int	cryptosw;		/* crypto command called */
214 
215 extern char *stats_drift_file;	/* name of the driftfile */
216 
217 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
218 /*
219  * backwards compatibility flags
220  */
221 bc_entry bc_list[] = {
222 	{ T_Bc_bugXXXX,		1	}	/* default enabled */
223 };
224 
225 /*
226  * declare an int pointer for each flag for quick testing without
227  * walking bc_list.  If the pointer is consumed by libntp rather
228  * than ntpd, declare it in a libntp source file pointing to storage
229  * initialized with the appropriate value for other libntp clients, and
230  * redirect it to point into bc_list during ntpd startup.
231  */
232 int *p_bcXXXX_enabled = &bc_list[0].enabled;
233 #endif
234 
235 /* FUNCTION PROTOTYPES */
236 
237 static void init_syntax_tree(config_tree *);
238 static void apply_enable_disable(attr_val_fifo *q, int enable);
239 
240 #ifdef FREE_CFG_T
241 static void free_auth_node(config_tree *);
242 static void free_all_config_trees(void);
243 
244 static void free_config_access(config_tree *);
245 static void free_config_auth(config_tree *);
246 static void free_config_fudge(config_tree *);
247 static void free_config_device(config_tree *);
248 static void free_config_logconfig(config_tree *);
249 static void free_config_monitor(config_tree *);
250 static void free_config_nic_rules(config_tree *);
251 static void free_config_other_modes(config_tree *);
252 static void free_config_phone(config_tree *);
253 static void free_config_reset_counters(config_tree *);
254 static void free_config_rlimit(config_tree *);
255 static void free_config_setvar(config_tree *);
256 static void free_config_system_opts(config_tree *);
257 static void free_config_tinker(config_tree *);
258 static void free_config_tos(config_tree *);
259 static void free_config_trap(config_tree *);
260 static void free_config_ttl(config_tree *);
261 static void free_config_vars(config_tree *);
262 
263 #ifdef SIM
264 static void free_config_sim(config_tree *);
265 #else	/* !SIM follows */
266 static void free_config_peers(config_tree *);
267 static void free_config_unpeers(config_tree *);
268 static int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
269 #endif	/* !SIM */
270 static void destroy_address_fifo(address_fifo *);
271 #define FREE_ADDRESS_FIFO(pf)			\
272 	do {					\
273 		destroy_address_fifo(pf);	\
274 		(pf) = NULL;			\
275 	} while (0)
276        void free_all_config_trees(void);	/* atexit() */
277 static void free_config_tree(config_tree *ptree);
278 #endif	/* FREE_CFG_T */
279 
280 static void destroy_restrict_node(restrict_node *my_node);
281 static void save_and_apply_config_tree(int/*BOOL*/ from_file);
282 static void destroy_int_fifo(int_fifo *);
283 #define FREE_INT_FIFO(pf)			\
284 	do {					\
285 		destroy_int_fifo(pf);		\
286 		(pf) = NULL;			\
287 	} while (0)
288 static void destroy_string_fifo(string_fifo *);
289 #define FREE_STRING_FIFO(pf)			\
290 	do {					\
291 		destroy_string_fifo(pf);		\
292 		(pf) = NULL;			\
293 	} while (0)
294 static void destroy_attr_val_fifo(attr_val_fifo *);
295 #define FREE_ATTR_VAL_FIFO(pf)			\
296 	do {					\
297 		destroy_attr_val_fifo(pf);	\
298 		(pf) = NULL;			\
299 	} while (0)
300 static void destroy_filegen_fifo(filegen_fifo *);
301 #define FREE_FILEGEN_FIFO(pf)			\
302 	do {					\
303 		destroy_filegen_fifo(pf);	\
304 		(pf) = NULL;			\
305 	} while (0)
306 static void destroy_restrict_fifo(restrict_fifo *);
307 #define FREE_RESTRICT_FIFO(pf)			\
308 	do {					\
309 		destroy_restrict_fifo(pf);	\
310 		(pf) = NULL;			\
311 	} while (0)
312 static void destroy_setvar_fifo(setvar_fifo *);
313 #define FREE_SETVAR_FIFO(pf)			\
314 	do {					\
315 		destroy_setvar_fifo(pf);	\
316 		(pf) = NULL;			\
317 	} while (0)
318 static void destroy_addr_opts_fifo(addr_opts_fifo *);
319 #define FREE_ADDR_OPTS_FIFO(pf)			\
320 	do {					\
321 		destroy_addr_opts_fifo(pf);	\
322 		(pf) = NULL;			\
323 	} while (0)
324 
325 static void config_logconfig(config_tree *);
326 static void config_monitor(config_tree *);
327 static void config_rlimit(config_tree *);
328 static void config_system_opts(config_tree *);
329 static void config_tinker(config_tree *);
330 static void config_tos(config_tree *);
331 static void config_vars(config_tree *);
332 
333 #ifdef SIM
334 static sockaddr_u *get_next_address(address_node *addr);
335 static void config_sim(config_tree *);
336 static void config_ntpdsim(config_tree *);
337 #else	/* !SIM follows */
338 static void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
339 static void config_other_modes(config_tree *);
340 static void config_auth(config_tree *);
341 static void attrtopsl(int poll, attr_val *avp);
342 static void config_access(config_tree *);
343 static void config_mdnstries(config_tree *);
344 static void config_phone(config_tree *);
345 static void config_setvar(config_tree *);
346 static int  config_tos_clock(config_tree *);
347 static void config_ttl(config_tree *);
348 static void config_trap(config_tree *);
349 static void config_fudge(config_tree *);
350 static void config_device(config_tree *);
351 static void config_peers(config_tree *);
352 static void config_unpeers(config_tree *);
353 static void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
354 static void config_reset_counters(config_tree *);
355 static u_char get_correct_host_mode(int token);
356 static int peerflag_bits(peer_node *);
357 
358 #ifdef WORKER
359 static void peer_name_resolved(int, int, void *, const char *, const char *,
360 			const struct addrinfo *,
361 			const struct addrinfo *);
362 static void unpeer_name_resolved(int, int, void *, const char *, const char *,
363 			  const struct addrinfo *,
364 			  const struct addrinfo *);
365 static void trap_name_resolved(int, int, void *, const char *, const char *,
366 			const struct addrinfo *,
367 			const struct addrinfo *);
368 #endif	/* WORKER */
369 #endif	/* !SIM */
370 
371 enum gnn_type {
372 	t_UNK,		/* Unknown */
373 	t_REF,		/* Refclock */
374 	t_MSK		/* Network Mask */
375 };
376 
377 static void ntpd_set_tod_using(const char *);
378 static char * normal_dtoa(double);
379 static u_int32 get_pfxmatch(const char **, struct masks *);
380 static u_int32 get_match(const char *, struct masks *);
381 static u_int32 get_logmask(const char *);
382 static int/*BOOL*/ is_refclk_addr(const address_node * addr);
383 
384 static void	appendstr(char *, size_t, const char *);
385 
386 
387 #ifndef SIM
388 static int getnetnum(const char *num, sockaddr_u *addr, int complain,
389 		     enum gnn_type a_type);
390 
391 #endif
392 
393 #if defined(__GNUC__) /* this covers CLANG, too */
394 static void  __attribute__((__noreturn__,format(printf,1,2))) fatal_error(const char *fmt, ...)
395 #elif defined(_MSC_VER)
396 static void __declspec(noreturn) fatal_error(const char *fmt, ...)
397 #else
398 static void fatal_error(const char *fmt, ...)
399 #endif
400 {
401 	va_list va;
402 
403 	va_start(va, fmt);
404 	mvsyslog(LOG_EMERG, fmt, va);
405 	va_end(va);
406 	_exit(1);
407 }
408 
409 
410 /* FUNCTIONS FOR INITIALIZATION
411  * ----------------------------
412  */
413 
414 #ifdef FREE_CFG_T
415 static void
416 free_auth_node(
417 	config_tree *ptree
418 	)
419 {
420 	if (ptree->auth.keys) {
421 		free(ptree->auth.keys);
422 		ptree->auth.keys = NULL;
423 	}
424 
425 	if (ptree->auth.keysdir) {
426 		free(ptree->auth.keysdir);
427 		ptree->auth.keysdir = NULL;
428 	}
429 
430 	if (ptree->auth.ntp_signd_socket) {
431 		free(ptree->auth.ntp_signd_socket);
432 		ptree->auth.ntp_signd_socket = NULL;
433 	}
434 }
435 #endif /* DEBUG */
436 
437 
438 static void
439 init_syntax_tree(
440 	config_tree *ptree
441 	)
442 {
443 	ZERO(*ptree);
444 	ptree->mdnstries = 5;
445 }
446 
447 
448 #ifdef FREE_CFG_T
449 static void
450 free_all_config_trees(void)
451 {
452 	config_tree *ptree;
453 	config_tree *pnext;
454 
455 	ptree = cfg_tree_history;
456 
457 	while (ptree != NULL) {
458 		pnext = ptree->link;
459 		free_config_tree(ptree);
460 		ptree = pnext;
461 	}
462 }
463 
464 
465 static void
466 free_config_tree(
467 	config_tree *ptree
468 	)
469 {
470 #if defined(_MSC_VER) && defined (_DEBUG)
471 	_CrtCheckMemory();
472 #endif
473 
474 	if (ptree->source.value.s != NULL)
475 		free(ptree->source.value.s);
476 
477 	free_config_other_modes(ptree);
478 	free_config_auth(ptree);
479 	free_config_tos(ptree);
480 	free_config_monitor(ptree);
481 	free_config_access(ptree);
482 	free_config_tinker(ptree);
483 	free_config_rlimit(ptree);
484 	free_config_system_opts(ptree);
485 	free_config_logconfig(ptree);
486 	free_config_phone(ptree);
487 	free_config_setvar(ptree);
488 	free_config_ttl(ptree);
489 	free_config_trap(ptree);
490 	free_config_fudge(ptree);
491 	free_config_device(ptree);
492 	free_config_vars(ptree);
493 	free_config_nic_rules(ptree);
494 	free_config_reset_counters(ptree);
495 #ifdef SIM
496 	free_config_sim(ptree);
497 #else	/* !SIM follows */
498 	free_config_peers(ptree);
499 	free_config_unpeers(ptree);
500 #endif	/* !SIM */
501 	free_auth_node(ptree);
502 
503 	free(ptree);
504 
505 #if defined(_MSC_VER) && defined (_DEBUG)
506 	_CrtCheckMemory();
507 #endif
508 }
509 #endif /* FREE_CFG_T */
510 
511 
512 #ifdef SAVECONFIG
513 /* Dump all trees */
514 int
515 dump_all_config_trees(
516 	FILE *df,
517 	int comment
518 	)
519 {
520 	config_tree *	cfg_ptr;
521 	int		return_value;
522 	time_t		now = time(NULL);
523 	struct tm	tm = *localtime(&now);
524 
525 	fprintf(df, "#NTF:D %04d%02d%02d@%02d:%02d:%02d\n",
526 		tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
527 		tm.tm_hour, tm.tm_min, tm.tm_sec);
528 	fprintf(df, "#NTF:V %s\n", Version);
529 
530 	return_value = 0;
531 	for (cfg_ptr = cfg_tree_history;
532 	     cfg_ptr != NULL;
533 	     cfg_ptr = cfg_ptr->link)
534 		return_value |= dump_config_tree(cfg_ptr, df, comment);
535 
536 	return return_value;
537 }
538 
539 
540 /* The config dumper */
541 int
542 dump_config_tree(
543 	config_tree *ptree,
544 	FILE *df,
545 	int comment
546 	)
547 {
548 	peer_node *peern;
549 	unpeer_node *unpeern;
550 	attr_val *atrv;
551 	address_node *addr;
552 	address_node *peer_addr;
553 	address_node *fudge_addr;
554 	filegen_node *fgen_node;
555 	restrict_node *rest_node;
556 	addr_opts_node *addr_opts;
557 	setvar_node *setv_node;
558 	nic_rule_node *rule_node;
559 	int_node *i_n;
560 	int_node *counter_set;
561 	string_node *str_node;
562 
563 	const char *s = NULL;
564 	char *s1;
565 	char *s2;
566 	char timestamp[80];
567 	int enable;
568 
569 	DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
570 
571 	if (comment) {
572 		if (!strftime(timestamp, sizeof(timestamp),
573 			      "%Y-%m-%d %H:%M:%S",
574 			      localtime(&ptree->timestamp)))
575 			timestamp[0] = '\0';
576 
577 		fprintf(df, "# %s %s %s\n",
578 			timestamp,
579 			(CONF_SOURCE_NTPQ == ptree->source.attr)
580 			    ? "ntpq remote config from"
581 			    : "startup configuration file",
582 			ptree->source.value.s);
583 	}
584 
585 	/*
586 	 * For options without documentation we just output the name
587 	 * and its data value
588 	 */
589 	atrv = HEAD_PFIFO(ptree->vars);
590 	for ( ; atrv != NULL; atrv = atrv->link) {
591 		switch (atrv->type) {
592 #ifdef DEBUG
593 		default:
594 			fprintf(df, "\n# dump error:\n"
595 				"# unknown vars type %d (%s) for %s\n",
596 				atrv->type, token_name(atrv->type),
597 				token_name(atrv->attr));
598 			break;
599 #endif
600 		case T_Double:
601 			fprintf(df, "%s %s\n", keyword(atrv->attr),
602 				normal_dtoa(atrv->value.d));
603 			break;
604 
605 		case T_Integer:
606 			fprintf(df, "%s %d\n", keyword(atrv->attr),
607 				atrv->value.i);
608 			break;
609 
610 		case T_String:
611 			fprintf(df, "%s \"%s\"", keyword(atrv->attr),
612 				atrv->value.s);
613 			if (T_Driftfile == atrv->attr &&
614 			    atrv->link != NULL &&
615 			    T_WanderThreshold == atrv->link->attr) {
616 				atrv = atrv->link;
617 				fprintf(df, " %s\n",
618 					normal_dtoa(atrv->value.d));
619 			} else if (T_Leapfile == atrv->attr) {
620 				fputs((atrv->flag
621 				       ? " checkhash\n"
622 				       : " ignorehash\n"),
623 				      df);
624 			} else {
625 				fprintf(df, "\n");
626 			}
627 			break;
628 		}
629 	}
630 
631 	atrv = HEAD_PFIFO(ptree->logconfig);
632 	if (atrv != NULL) {
633 		fprintf(df, "logconfig");
634 		for ( ; atrv != NULL; atrv = atrv->link)
635 			fprintf(df, " %c%s", atrv->attr, atrv->value.s);
636 		fprintf(df, "\n");
637 	}
638 
639 	if (ptree->stats_dir)
640 		fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
641 
642 	i_n = HEAD_PFIFO(ptree->stats_list);
643 	if (i_n != NULL) {
644 		fprintf(df, "statistics");
645 		for ( ; i_n != NULL; i_n = i_n->link)
646 			fprintf(df, " %s", keyword(i_n->i));
647 		fprintf(df, "\n");
648 	}
649 
650 	fgen_node = HEAD_PFIFO(ptree->filegen_opts);
651 	for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
652 		atrv = HEAD_PFIFO(fgen_node->options);
653 		if (atrv != NULL) {
654 			fprintf(df, "filegen %s",
655 				keyword(fgen_node->filegen_token));
656 			for ( ; atrv != NULL; atrv = atrv->link) {
657 				switch (atrv->attr) {
658 #ifdef DEBUG
659 				default:
660 					fprintf(df, "\n# dump error:\n"
661 						"# unknown filegen option token %s\n"
662 						"filegen %s",
663 						token_name(atrv->attr),
664 						keyword(fgen_node->filegen_token));
665 					break;
666 #endif
667 				case T_File:
668 					fprintf(df, " file %s",
669 						atrv->value.s);
670 					break;
671 
672 				case T_Type:
673 					fprintf(df, " type %s",
674 						keyword(atrv->value.i));
675 					break;
676 
677 				case T_Flag:
678 					fprintf(df, " %s",
679 						keyword(atrv->value.i));
680 					break;
681 				}
682 			}
683 			fprintf(df, "\n");
684 		}
685 	}
686 
687 	atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
688 	if (atrv != NULL) {
689 		fprintf(df, "crypto");
690 		for ( ; atrv != NULL; atrv = atrv->link) {
691 			fprintf(df, " %s %s", keyword(atrv->attr),
692 				atrv->value.s);
693 		}
694 		fprintf(df, "\n");
695 	}
696 
697 	if (ptree->auth.revoke != 0)
698 		fprintf(df, "revoke %d\n", ptree->auth.revoke);
699 
700 	if (ptree->auth.keysdir != NULL)
701 		fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
702 
703 	if (ptree->auth.keys != NULL)
704 		fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
705 
706 	atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
707 	if (atrv != NULL) {
708 		fprintf(df, "trustedkey");
709 		for ( ; atrv != NULL; atrv = atrv->link) {
710 			if (T_Integer == atrv->type)
711 				fprintf(df, " %d", atrv->value.i);
712 			else if (T_Intrange == atrv->type)
713 				fprintf(df, " (%d ... %d)",
714 					atrv->value.r.first,
715 					atrv->value.r.last);
716 #ifdef DEBUG
717 			else
718 				fprintf(df, "\n# dump error:\n"
719 					"# unknown trustedkey attr type %d\n"
720 					"trustedkey", atrv->type);
721 #endif
722 		}
723 		fprintf(df, "\n");
724 	}
725 
726 	if (ptree->auth.control_key)
727 		fprintf(df, "controlkey %d\n", ptree->auth.control_key);
728 
729 	if (ptree->auth.request_key)
730 		fprintf(df, "requestkey %d\n", ptree->auth.request_key);
731 
732 	/* dump enable list, then disable list */
733 	for (enable = 1; enable >= 0; enable--) {
734 		atrv = (enable)
735 			   ? HEAD_PFIFO(ptree->enable_opts)
736 			   : HEAD_PFIFO(ptree->disable_opts);
737 		if (atrv != NULL) {
738 			fprintf(df, "%s", (enable)
739 					? "enable"
740 					: "disable");
741 			for ( ; atrv != NULL; atrv = atrv->link)
742 				fprintf(df, " %s",
743 					keyword(atrv->value.i));
744 			fprintf(df, "\n");
745 		}
746 	}
747 
748 	atrv = HEAD_PFIFO(ptree->orphan_cmds);
749 	if (atrv != NULL) {
750 		fprintf(df, "tos");
751 		for ( ; atrv != NULL; atrv = atrv->link) {
752 			switch (atrv->type) {
753 #ifdef DEBUG
754 			default:
755 				fprintf(df, "\n# dump error:\n"
756 					"# unknown tos attr type %d %s\n"
757 					"tos", atrv->type,
758 					token_name(atrv->type));
759 				break;
760 #endif
761 			case T_Integer:
762 				if (atrv->attr == T_Basedate) {
763 					struct calendar jd;
764 					ntpcal_rd_to_date(&jd, atrv->value.i + DAY_NTP_STARTS);
765 					fprintf(df, " %s \"%04hu-%02hu-%02hu\"",
766 						keyword(atrv->attr), jd.year,
767 						(u_short)jd.month,
768 						(u_short)jd.monthday);
769 				} else {
770 					fprintf(df, " %s %d",
771 					keyword(atrv->attr),
772 					atrv->value.i);
773 				}
774 				break;
775 
776 			case T_Double:
777 				fprintf(df, " %s %s",
778 					keyword(atrv->attr),
779 					normal_dtoa(atrv->value.d));
780 				break;
781 			}
782 		}
783 		fprintf(df, "\n");
784 	}
785 
786 	atrv = HEAD_PFIFO(ptree->rlimit);
787 	if (atrv != NULL) {
788 		fprintf(df, "rlimit");
789 		for ( ; atrv != NULL; atrv = atrv->link) {
790 			INSIST(T_Integer == atrv->type);
791 			fprintf(df, " %s %d", keyword(atrv->attr),
792 				atrv->value.i);
793 		}
794 		fprintf(df, "\n");
795 	}
796 
797 	atrv = HEAD_PFIFO(ptree->tinker);
798 	if (atrv != NULL) {
799 		fprintf(df, "tinker");
800 		for ( ; atrv != NULL; atrv = atrv->link) {
801 			INSIST(T_Double == atrv->type);
802 			fprintf(df, " %s %s", keyword(atrv->attr),
803 				normal_dtoa(atrv->value.d));
804 		}
805 		fprintf(df, "\n");
806 	}
807 
808 	if (ptree->broadcastclient)
809 		fprintf(df, "broadcastclient\n");
810 
811 	peern = HEAD_PFIFO(ptree->peers);
812 	for ( ; peern != NULL; peern = peern->link) {
813 		addr = peern->addr;
814 		fprintf(df, "%s", keyword(peern->host_mode));
815 		switch (addr->type) {
816 #ifdef DEBUG
817 		default:
818 			fprintf(df, "# dump error:\n"
819 				"# unknown peer family %d for:\n"
820 				"%s", addr->type,
821 				keyword(peern->host_mode));
822 			break;
823 #endif
824 		case AF_UNSPEC:
825 			break;
826 
827 		case AF_INET:
828 			fprintf(df, " -4");
829 			break;
830 
831 		case AF_INET6:
832 			fprintf(df, " -6");
833 			break;
834 		}
835 		fprintf(df, " %s", addr->address);
836 
837 		if (peern->minpoll != 0)
838 			fprintf(df, " minpoll %u", peern->minpoll);
839 
840 		if (peern->maxpoll != 0)
841 			fprintf(df, " maxpoll %u", peern->maxpoll);
842 
843 		if (peern->ttl != 0) {
844 			if (strlen(addr->address) > 8
845 			    && !memcmp(addr->address, "127.127.", 8))
846 				fprintf(df, " mode %u", peern->ttl);
847 			else
848 				fprintf(df, " ttl %u", peern->ttl);
849 		}
850 
851 		if (peern->peerversion != NTP_VERSION)
852 			fprintf(df, " version %u", peern->peerversion);
853 
854 		if (peern->peerkey != 0)
855 			fprintf(df, " key %u", peern->peerkey);
856 
857 		if (peern->group != NULL)
858 			fprintf(df, " ident \"%s\"", peern->group);
859 
860 		atrv = HEAD_PFIFO(peern->peerflags);
861 		for ( ; atrv != NULL; atrv = atrv->link) {
862 			INSIST(T_Flag == atrv->attr);
863 			INSIST(T_Integer == atrv->type);
864 			fprintf(df, " %s", keyword(atrv->value.i));
865 		}
866 
867 		fprintf(df, "\n");
868 
869 		addr_opts = HEAD_PFIFO(ptree->fudge);
870 		for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
871 			peer_addr = peern->addr;
872 			fudge_addr = addr_opts->addr;
873 
874 			s1 = peer_addr->address;
875 			s2 = fudge_addr->address;
876 
877 			if (strcmp(s1, s2))
878 				continue;
879 
880 			fprintf(df, "fudge %s", s1);
881 
882 			for (atrv = HEAD_PFIFO(addr_opts->options);
883 			     atrv != NULL;
884 			     atrv = atrv->link) {
885 
886 				switch (atrv->type) {
887 #ifdef DEBUG
888 				default:
889 					fprintf(df, "\n# dump error:\n"
890 						"# unknown fudge atrv->type %d\n"
891 						"fudge %s", atrv->type,
892 						s1);
893 					break;
894 #endif
895 				case T_Double:
896 					fprintf(df, " %s %s",
897 						keyword(atrv->attr),
898 						normal_dtoa(atrv->value.d));
899 					break;
900 
901 				case T_Integer:
902 					fprintf(df, " %s %d",
903 						keyword(atrv->attr),
904 						atrv->value.i);
905 					break;
906 
907 				case T_String:
908 					fprintf(df, " %s %s",
909 						keyword(atrv->attr),
910 						atrv->value.s);
911 					break;
912 				}
913 			}
914 			fprintf(df, "\n");
915 		}
916 
917 		addr_opts = HEAD_PFIFO(ptree->device);
918 		for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
919 			peer_addr = peern->addr;
920 			fudge_addr = addr_opts->addr;
921 
922 			s1 = peer_addr->address;
923 			s2 = fudge_addr->address;
924 
925 			if (strcmp(s1, s2))
926 				continue;
927 
928 			fprintf(df, "device %s", s1);
929 
930 			for (atrv = HEAD_PFIFO(addr_opts->options);
931 			     atrv != NULL;
932 			     atrv = atrv->link) {
933 
934 				switch (atrv->type) {
935 #ifdef DEBUG
936 				default:
937 					fprintf(df, "\n# dump error:\n"
938 						"# unknown device atrv->type %d\n"
939 						"device %s", atrv->type,
940 						s1);
941 					break;
942 #endif
943 				case T_String:
944 					fprintf(df, " %s %s",
945 						keyword(atrv->attr),
946 						atrv->value.s);
947 					break;
948 				}
949 			}
950 			fprintf(df, "\n");
951 		}
952 	}
953 
954 	addr = HEAD_PFIFO(ptree->manycastserver);
955 	if (addr != NULL) {
956 		fprintf(df, "manycastserver");
957 		for ( ; addr != NULL; addr = addr->link)
958 			fprintf(df, " %s", addr->address);
959 		fprintf(df, "\n");
960 	}
961 
962 	addr = HEAD_PFIFO(ptree->multicastclient);
963 	if (addr != NULL) {
964 		fprintf(df, "multicastclient");
965 		for ( ; addr != NULL; addr = addr->link)
966 			fprintf(df, " %s", addr->address);
967 		fprintf(df, "\n");
968 	}
969 
970 
971 	for (unpeern = HEAD_PFIFO(ptree->unpeers);
972 	     unpeern != NULL;
973 	     unpeern = unpeern->link)
974 		fprintf(df, "unpeer %s\n", unpeern->addr->address);
975 
976 	atrv = HEAD_PFIFO(ptree->mru_opts);
977 	if (atrv != NULL) {
978 		fprintf(df, "mru");
979 		for ( ;	atrv != NULL; atrv = atrv->link)
980 			fprintf(df, " %s %d", keyword(atrv->attr),
981 				atrv->value.i);
982 		fprintf(df, "\n");
983 	}
984 
985 	atrv = HEAD_PFIFO(ptree->discard_opts);
986 	if (atrv != NULL) {
987 		fprintf(df, "discard");
988 		for ( ;	atrv != NULL; atrv = atrv->link)
989 			fprintf(df, " %s %d", keyword(atrv->attr),
990 				atrv->value.i);
991 		fprintf(df, "\n");
992 	}
993 
994 	atrv = HEAD_PFIFO(ptree->pollskewlist);
995 	if (atrv != NULL) {
996 		fprintf(df, "pollskewlist");
997 		for ( ; atrv != NULL; atrv = atrv->link) {
998 			if (-1 == atrv->attr) {
999 				fprintf(df, " default");
1000 			} else {
1001 				fprintf(df, " %d", atrv->attr);
1002 			}
1003 			fprintf(df, " %d|%d",
1004 				atrv->value.r.first, atrv->value.r.last);
1005 		}
1006 		fprintf(df, "\n");
1007 	}
1008 
1009 	for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
1010 	     rest_node != NULL;
1011 	     rest_node = rest_node->link) {
1012 		int is_default = 0;
1013 
1014 		if (NULL == rest_node->addr) {
1015 			s = "default";
1016 			/* Don't need to set is_default=1 here */
1017 			atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1018 			for ( ; atrv != NULL; atrv = atrv->link) {
1019 				if (   T_Integer == atrv->type
1020 				    && T_Source == atrv->attr) {
1021 					s = "source";
1022 					break;
1023 				}
1024 			}
1025 		} else {
1026 			const char *ap = rest_node->addr->address;
1027 			const char *mp = "";
1028 
1029 			if (rest_node->mask)
1030 				mp = rest_node->mask->address;
1031 
1032 			if (   rest_node->addr->type == AF_INET
1033 			    && !strcmp(ap, "0.0.0.0")
1034 			    && !strcmp(mp, "0.0.0.0")) {
1035 				is_default = 1;
1036 				s = "-4 default";
1037 			} else if (   rest_node->mask
1038 				   && rest_node->mask->type == AF_INET6
1039 				   && !strcmp(ap, "::")
1040 				   && !strcmp(mp, "::")) {
1041 				is_default = 1;
1042 				s = "-6 default";
1043 			} else {
1044 				s = ap;
1045 			}
1046 		}
1047 		fprintf(df, "restrict %s", s);
1048 		if (rest_node->mask != NULL && !is_default)
1049 			fprintf(df, " mask %s",
1050 				rest_node->mask->address);
1051 		fprintf(df, " ippeerlimit %d", rest_node->ippeerlimit);
1052 		atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1053 		for ( ; atrv != NULL; atrv = atrv->link) {
1054 			if (   T_Integer == atrv->type
1055 			    && T_Source != atrv->attr) {
1056 				fprintf(df, " %s", keyword(atrv->attr));
1057 			}
1058 		}
1059 		fprintf(df, "\n");
1060 /**/
1061 #if 0
1062 msyslog(LOG_INFO, "Dumping flag_tok_fifo:");
1063 atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1064 for ( ; atrv != NULL; atrv = atrv->link) {
1065 	msyslog(LOG_INFO, "- flag_tok_fifo: flags: %08x", atrv->flag);
1066 	switch(atrv->type) {
1067 	    case T_Integer:
1068 		msyslog(LOG_INFO, "- T_Integer: attr <%s>/%d, value %d",
1069 			keyword(atrv->attr), atrv->attr, atrv->value.i);
1070 		break;
1071 	    default:
1072 		msyslog(LOG_INFO, "- Other: attr <%s>/%d, value ???",
1073 			keyword(atrv->attr), atrv->attr);
1074 		break;
1075 
1076 	}
1077 }
1078 #endif
1079 /**/
1080 	}
1081 
1082 	rule_node = HEAD_PFIFO(ptree->nic_rules);
1083 	for ( ; rule_node != NULL; rule_node = rule_node->link) {
1084 		fprintf(df, "interface %s %s\n",
1085 			keyword(rule_node->action),
1086 			(rule_node->match_class)
1087 			    ? keyword(rule_node->match_class)
1088 			    : rule_node->if_name);
1089 	}
1090 
1091 	str_node = HEAD_PFIFO(ptree->phone);
1092 	if (str_node != NULL) {
1093 		fprintf(df, "phone");
1094 		for ( ; str_node != NULL; str_node = str_node->link)
1095 			fprintf(df, " \"%s\"", str_node->s);
1096 		fprintf(df, "\n");
1097 	}
1098 
1099 	setv_node = HEAD_PFIFO(ptree->setvar);
1100 	for ( ; setv_node != NULL; setv_node = setv_node->link) {
1101 		s1 = quote_if_needed(setv_node->var);
1102 		s2 = quote_if_needed(setv_node->val);
1103 		fprintf(df, "setvar %s = %s", s1, s2);
1104 		free(s1);
1105 		free(s2);
1106 		if (setv_node->isdefault)
1107 			fprintf(df, " default");
1108 		fprintf(df, "\n");
1109 	}
1110 
1111 	i_n = HEAD_PFIFO(ptree->ttl);
1112 	if (i_n != NULL) {
1113 		fprintf(df, "ttl");
1114 		for( ; i_n != NULL; i_n = i_n->link)
1115 			fprintf(df, " %d", i_n->i);
1116 		fprintf(df, "\n");
1117 	}
1118 
1119 	addr_opts = HEAD_PFIFO(ptree->trap);
1120 	for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
1121 		addr = addr_opts->addr;
1122 		fprintf(df, "trap %s", addr->address);
1123 		atrv = HEAD_PFIFO(addr_opts->options);
1124 		for ( ; atrv != NULL; atrv = atrv->link) {
1125 			switch (atrv->attr) {
1126 #ifdef DEBUG
1127 			default:
1128 				fprintf(df, "\n# dump error:\n"
1129 					"# unknown trap token %d\n"
1130 					"trap %s", atrv->attr,
1131 					addr->address);
1132 				break;
1133 #endif
1134 			case T_Port:
1135 				fprintf(df, " port %d", atrv->value.i);
1136 				break;
1137 
1138 			case T_Interface:
1139 				fprintf(df, " interface %s",
1140 					atrv->value.s);
1141 				break;
1142 			}
1143 		}
1144 		fprintf(df, "\n");
1145 	}
1146 
1147 	counter_set = HEAD_PFIFO(ptree->reset_counters);
1148 	if (counter_set != NULL) {
1149 		fprintf(df, "reset");
1150 		for ( ; counter_set != NULL;
1151 		     counter_set = counter_set->link)
1152 			fprintf(df, " %s", keyword(counter_set->i));
1153 		fprintf(df, "\n");
1154 	}
1155 
1156 	return 0;
1157 }
1158 #endif	/* SAVECONFIG */
1159 
1160 
1161 /* generic fifo routines for structs linked by 1st member */
1162 void *
1163 append_gen_fifo(
1164 	void *fifo,
1165 	void *entry
1166 	)
1167 {
1168 	gen_fifo *pf;
1169 	gen_node *pe;
1170 
1171 	pf = fifo;
1172 	pe = entry;
1173 	if (NULL == pf)
1174 		pf = emalloc_zero(sizeof(*pf));
1175 	else
1176 		CHECK_FIFO_CONSISTENCY(*pf);
1177 	if (pe != NULL)
1178 		LINK_FIFO(*pf, pe, link);
1179 	CHECK_FIFO_CONSISTENCY(*pf);
1180 
1181 	return pf;
1182 }
1183 
1184 
1185 void *
1186 concat_gen_fifos(
1187 	void *first,
1188 	void *second
1189 	)
1190 {
1191 	gen_fifo *pf1;
1192 	gen_fifo *pf2;
1193 
1194 	pf1 = first;
1195 	pf2 = second;
1196 	if (NULL == pf1)
1197 		return pf2;
1198 	if (NULL == pf2)
1199 		return pf1;
1200 
1201 	CONCAT_FIFO(*pf1, *pf2, link);
1202 	free(pf2);
1203 
1204 	return pf1;
1205 }
1206 
1207 void*
1208 destroy_gen_fifo(
1209 	void        *fifo,
1210 	fifo_deleter func
1211 	)
1212 {
1213 	any_node *	np  = NULL;
1214 	any_node_fifo *	pf1 = fifo;
1215 
1216 	if (pf1 != NULL) {
1217 		if (!func)
1218 			func = free;
1219 		for (;;) {
1220 			UNLINK_FIFO(np, *pf1, link);
1221 			if (np == NULL)
1222 				break;
1223 			(*func)(np);
1224 		}
1225 		free(pf1);
1226 	}
1227 	return NULL;
1228 }
1229 
1230 /* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
1231  * -----------------------------------------------
1232  */
1233 
1234 void
1235 destroy_attr_val(
1236 	attr_val *	av
1237 	)
1238 {
1239 	if (av) {
1240 		if (T_String == av->type)
1241 			free(av->value.s);
1242 		free(av);
1243 	}
1244 }
1245 
1246 attr_val *
1247 create_attr_dval(
1248 	int attr,
1249 	double value
1250 	)
1251 {
1252 	attr_val *my_val;
1253 
1254 	my_val = emalloc_zero(sizeof(*my_val));
1255 	my_val->attr = attr;
1256 	my_val->value.d = value;
1257 	my_val->type = T_Double;
1258 
1259 	return my_val;
1260 }
1261 
1262 
1263 attr_val *
1264 create_attr_ival(
1265 	int attr,
1266 	int value
1267 	)
1268 {
1269 	attr_val *my_val;
1270 
1271 	my_val = emalloc_zero(sizeof(*my_val));
1272 	my_val->attr = attr;
1273 	my_val->value.i = value;
1274 	my_val->type = T_Integer;
1275 
1276 	return my_val;
1277 }
1278 
1279 
1280 attr_val *
1281 create_attr_uval(
1282 	int	attr,
1283 	u_int	value
1284 	)
1285 {
1286 	attr_val *my_val;
1287 
1288 	my_val = emalloc_zero(sizeof(*my_val));
1289 	my_val->attr = attr;
1290 	my_val->value.u = value;
1291 	my_val->type = T_U_int;
1292 
1293 	return my_val;
1294 }
1295 
1296 
1297 attr_val *
1298 create_attr_rval(
1299 	int	attr,
1300 	int	first,
1301 	int	last
1302 	)
1303 {
1304 	attr_val *my_val;
1305 
1306 	my_val = emalloc_zero(sizeof(*my_val));
1307 	my_val->attr = attr;
1308 	my_val->value.r.first = first;
1309 	my_val->value.r.last = last;
1310 	my_val->type = T_Intrange;
1311 
1312 	return my_val;
1313 }
1314 
1315 
1316 attr_val *
1317 create_attr_sval(
1318 	int attr,
1319 	const char *s
1320 	)
1321 {
1322 	attr_val *my_val;
1323 
1324 	my_val = emalloc_zero(sizeof(*my_val));
1325 	my_val->attr = attr;
1326 	if (NULL == s)			/* free() hates NULL */
1327 		s = estrdup("");
1328 	my_val->value.s = _UC(s);
1329 	my_val->type = T_String;
1330 
1331 	return my_val;
1332 }
1333 
1334 
1335 int_node *
1336 create_int_node(
1337 	int val
1338 	)
1339 {
1340 	int_node *i_n;
1341 
1342 	i_n = emalloc_zero(sizeof(*i_n));
1343 	i_n->i = val;
1344 
1345 	return i_n;
1346 }
1347 
1348 
1349 string_node *
1350 create_string_node(
1351 	char *str
1352 	)
1353 {
1354 	string_node *sn;
1355 
1356 	sn = emalloc_zero(sizeof(*sn));
1357 	sn->s = str;
1358 
1359 	return sn;
1360 }
1361 
1362 
1363 address_node *
1364 create_address_node(
1365 	char *	addr,
1366 	int	type
1367 	)
1368 {
1369 	address_node *my_node;
1370 
1371 	REQUIRE(NULL != addr);
1372 	REQUIRE(AF_INET == type || AF_INET6 == type || AF_UNSPEC == type);
1373 	my_node = emalloc_zero(sizeof(*my_node));
1374 	my_node->address = addr;
1375 	my_node->type = (u_short)type;
1376 
1377 	return my_node;
1378 }
1379 
1380 
1381 void
1382 destroy_address_node(
1383 	address_node *my_node
1384 	)
1385 {
1386 	if (NULL == my_node)
1387 		return;
1388 	REQUIRE(NULL != my_node->address);
1389 
1390 	free(my_node->address);
1391 	free(my_node);
1392 }
1393 
1394 
1395 peer_node *
1396 create_peer_node(
1397 	int		hmode,
1398 	address_node *	addr,
1399 	attr_val_fifo *	options
1400 	)
1401 {
1402 	peer_node *my_node;
1403 	attr_val *option;
1404 	int freenode;
1405 	int errflag = 0;
1406 
1407 	my_node = emalloc_zero(sizeof(*my_node));
1408 
1409 	/* Initialize node values to default */
1410 	my_node->peerversion = NTP_VERSION;
1411 
1412 	/* Now set the node to the read values */
1413 	my_node->host_mode = hmode;
1414 	my_node->addr = addr;
1415 
1416 	/*
1417 	 * the options FIFO mixes items that will be saved in the
1418 	 * peer_node as explicit members, such as minpoll, and
1419 	 * those that are moved intact to the peer_node's peerflags
1420 	 * FIFO.  The options FIFO is consumed and reclaimed here.
1421 	 */
1422 
1423 	if (options != NULL)
1424 		CHECK_FIFO_CONSISTENCY(*options);
1425 	while (options != NULL) {
1426 		UNLINK_FIFO(option, *options, link);
1427 		if (NULL == option) {
1428 			free(options);
1429 			break;
1430 		}
1431 
1432 		freenode = 1;
1433 		/* Check the kind of option being set */
1434 		switch (option->attr) {
1435 
1436 		case T_Flag:
1437 			APPEND_G_FIFO(my_node->peerflags, option);
1438 			freenode = 0;
1439 			break;
1440 
1441 		case T_Minpoll:
1442 			if (option->value.i < NTP_MINPOLL ||
1443 			    option->value.i > UCHAR_MAX) {
1444 				msyslog(LOG_INFO,
1445 					"minpoll: provided value (%d) is out of range [%d-%d])",
1446 					option->value.i, NTP_MINPOLL,
1447 					UCHAR_MAX);
1448 				my_node->minpoll = NTP_MINPOLL;
1449 			} else {
1450 				my_node->minpoll =
1451 					(u_char)option->value.u;
1452 			}
1453 			break;
1454 
1455 		case T_Maxpoll:
1456 			if (option->value.i < 0 ||
1457 			    option->value.i > NTP_MAXPOLL) {
1458 				msyslog(LOG_INFO,
1459 					"maxpoll: provided value (%d) is out of range [0-%d])",
1460 					option->value.i, NTP_MAXPOLL);
1461 				my_node->maxpoll = NTP_MAXPOLL;
1462 			} else {
1463 				my_node->maxpoll =
1464 					(u_char)option->value.u;
1465 			}
1466 			break;
1467 
1468 		case T_Ttl:
1469 			if (is_refclk_addr(addr)) {
1470 				msyslog(LOG_ERR, "'ttl' does not apply for refclocks");
1471 				errflag = 1;
1472 			} else if (option->value.u >= MAX_TTL) {
1473 				msyslog(LOG_ERR, "ttl: invalid argument");
1474 				errflag = 1;
1475 			} else {
1476 				my_node->ttl = (u_char)option->value.u;
1477 			}
1478 			break;
1479 
1480 		case T_Mode:
1481 			if (is_refclk_addr(addr)) {
1482 				my_node->ttl = option->value.u;
1483 			} else {
1484 				msyslog(LOG_ERR, "'mode' does not apply for network peers");
1485 				errflag = 1;
1486 			}
1487 			break;
1488 
1489 		case T_Key:
1490 			if (option->value.u >= KEYID_T_MAX) {
1491 				msyslog(LOG_ERR, "key: invalid argument");
1492 				errflag = 1;
1493 			} else {
1494 				my_node->peerkey =
1495 					(keyid_t)option->value.u;
1496 			}
1497 			break;
1498 
1499 		case T_Version:
1500 			if (option->value.u >= UCHAR_MAX) {
1501 				msyslog(LOG_ERR, "version: invalid argument");
1502 				errflag = 1;
1503 			} else {
1504 				my_node->peerversion =
1505 					(u_char)option->value.u;
1506 			}
1507 			break;
1508 
1509 		case T_Ident:
1510 			my_node->group = option->value.s;
1511 			break;
1512 
1513 		default:
1514 			msyslog(LOG_ERR,
1515 				"Unknown peer/server option token %s",
1516 				token_name(option->attr));
1517 			errflag = 1;
1518 		}
1519 		if (freenode)
1520 			free(option);
1521 	}
1522 
1523 	/* Check if errors were reported. If yes, ignore the node */
1524 	if (errflag) {
1525 		free(my_node);
1526 		my_node = NULL;
1527 	}
1528 
1529 	return my_node;
1530 }
1531 
1532 
1533 unpeer_node *
1534 create_unpeer_node(
1535 	address_node *addr
1536 	)
1537 {
1538 	unpeer_node *	my_node;
1539 	u_long		u;
1540 	const u_char *	pch;
1541 
1542 	my_node = emalloc_zero(sizeof(*my_node));
1543 
1544 	/*
1545 	 * From the parser's perspective an association ID fits into
1546 	 * its generic T_String definition of a name/address "address".
1547 	 * We treat all valid 16-bit numbers as association IDs.
1548 	 */
1549 	for (u = 0, pch = (u_char*)addr->address; isdigit(*pch); ++pch) {
1550 		/* accumulate with overflow retention */
1551 		u = (10 * u + *pch - '0') | (u & 0xFF000000u);
1552 	}
1553 
1554 	if (!*pch && u <= ASSOCID_MAX) {
1555 		my_node->assocID = (associd_t)u;
1556 		my_node->addr = NULL;
1557 		destroy_address_node(addr);
1558 	} else {
1559 		my_node->assocID = 0;
1560 		my_node->addr = addr;
1561 	}
1562 
1563 	return my_node;
1564 }
1565 
1566 filegen_node *
1567 create_filegen_node(
1568 	int		filegen_token,
1569 	attr_val_fifo *	options
1570 	)
1571 {
1572 	filegen_node *my_node;
1573 
1574 	my_node = emalloc_zero(sizeof(*my_node));
1575 	my_node->filegen_token = filegen_token;
1576 	my_node->options = options;
1577 
1578 	return my_node;
1579 }
1580 
1581 
1582 restrict_node *
1583 create_restrict_node(
1584 	address_node *	addr,
1585 	address_node *	mask,
1586 	short		ippeerlimit,
1587 	attr_val_fifo *	flag_tok_fifo,
1588 	int		nline
1589 	)
1590 {
1591 	restrict_node *my_node;
1592 
1593 	my_node = emalloc_zero(sizeof(*my_node));
1594 	my_node->addr = addr;
1595 	my_node->mask = mask;
1596 	my_node->ippeerlimit = ippeerlimit;
1597 	my_node->flag_tok_fifo = flag_tok_fifo;
1598 	my_node->line_no = nline;
1599 
1600 	return my_node;
1601 }
1602 
1603 
1604 static void
1605 destroy_restrict_node(
1606 	restrict_node *my_node
1607 	)
1608 {
1609 	/* With great care, free all the memory occupied by
1610 	 * the restrict node
1611 	 */
1612 	destroy_address_node(my_node->addr);
1613 	destroy_address_node(my_node->mask);
1614 	destroy_attr_val_fifo(my_node->flag_tok_fifo);
1615 	free(my_node);
1616 }
1617 
1618 
1619 static void
1620 destroy_int_fifo(
1621 	int_fifo *	fifo
1622 	)
1623 {
1624 	int_node *	i_n;
1625 
1626 	if (fifo != NULL) {
1627 		for (;;) {
1628 			UNLINK_FIFO(i_n, *fifo, link);
1629 			if (i_n == NULL)
1630 				break;
1631 			free(i_n);
1632 		}
1633 		free(fifo);
1634 	}
1635 }
1636 
1637 
1638 static void
1639 destroy_string_fifo(
1640 	string_fifo *	fifo
1641 	)
1642 {
1643 	string_node *	sn;
1644 
1645 	if (fifo != NULL) {
1646 		for (;;) {
1647 			UNLINK_FIFO(sn, *fifo, link);
1648 			if (sn == NULL)
1649 				break;
1650 			free(sn->s);
1651 			free(sn);
1652 		}
1653 		free(fifo);
1654 	}
1655 }
1656 
1657 
1658 static void
1659 destroy_attr_val_fifo(
1660 	attr_val_fifo *	av_fifo
1661 	)
1662 {
1663 	attr_val *	av;
1664 
1665 	if (av_fifo != NULL) {
1666 		for (;;) {
1667 			UNLINK_FIFO(av, *av_fifo, link);
1668 			if (av == NULL)
1669 				break;
1670 			destroy_attr_val(av);
1671 		}
1672 		free(av_fifo);
1673 	}
1674 }
1675 
1676 
1677 static void
1678 destroy_filegen_fifo(
1679 	filegen_fifo *	fifo
1680 	)
1681 {
1682 	filegen_node *	fg;
1683 
1684 	if (fifo != NULL) {
1685 		for (;;) {
1686 			UNLINK_FIFO(fg, *fifo, link);
1687 			if (fg == NULL)
1688 				break;
1689 			destroy_attr_val_fifo(fg->options);
1690 			free(fg);
1691 		}
1692 		free(fifo);
1693 	}
1694 }
1695 
1696 
1697 static void
1698 destroy_restrict_fifo(
1699 	restrict_fifo *	fifo
1700 	)
1701 {
1702 	restrict_node *	rn;
1703 
1704 	if (fifo != NULL) {
1705 		for (;;) {
1706 			UNLINK_FIFO(rn, *fifo, link);
1707 			if (rn == NULL)
1708 				break;
1709 			destroy_restrict_node(rn);
1710 		}
1711 		free(fifo);
1712 	}
1713 }
1714 
1715 
1716 static void
1717 destroy_setvar_fifo(
1718 	setvar_fifo *	fifo
1719 	)
1720 {
1721 	setvar_node *	sv;
1722 
1723 	if (fifo != NULL) {
1724 		for (;;) {
1725 			UNLINK_FIFO(sv, *fifo, link);
1726 			if (sv == NULL)
1727 				break;
1728 			free(sv->var);
1729 			free(sv->val);
1730 			free(sv);
1731 		}
1732 		free(fifo);
1733 	}
1734 }
1735 
1736 
1737 static void
1738 destroy_addr_opts_fifo(
1739 	addr_opts_fifo *	fifo
1740 	)
1741 {
1742 	addr_opts_node *	aon;
1743 
1744 	if (fifo != NULL) {
1745 		for (;;) {
1746 			UNLINK_FIFO(aon, *fifo, link);
1747 			if (aon == NULL)
1748 				break;
1749 			destroy_address_node(aon->addr);
1750 			destroy_attr_val_fifo(aon->options);
1751 			free(aon);
1752 		}
1753 		free(fifo);
1754 	}
1755 }
1756 
1757 
1758 setvar_node *
1759 create_setvar_node(
1760 	char *	var,
1761 	char *	val,
1762 	int	isdefault
1763 	)
1764 {
1765 	setvar_node *	my_node;
1766 	char *		pch;
1767 
1768 	/* do not allow = in the variable name */
1769 	pch = strchr(var, '=');
1770 	if (NULL != pch)
1771 		*pch = '\0';
1772 
1773 	/* Now store the string into a setvar_node */
1774 	my_node = emalloc_zero(sizeof(*my_node));
1775 	my_node->var = var;
1776 	my_node->val = val;
1777 	my_node->isdefault = isdefault;
1778 
1779 	return my_node;
1780 }
1781 
1782 
1783 nic_rule_node *
1784 create_nic_rule_node(
1785 	int match_class,
1786 	char *if_name,	/* interface name or numeric address */
1787 	int action
1788 	)
1789 {
1790 	nic_rule_node *my_node;
1791 
1792 	REQUIRE(match_class != 0 || if_name != NULL);
1793 
1794 	my_node = emalloc_zero(sizeof(*my_node));
1795 	my_node->match_class = match_class;
1796 	my_node->if_name = if_name;
1797 	my_node->action = action;
1798 
1799 	return my_node;
1800 }
1801 
1802 
1803 addr_opts_node *
1804 create_addr_opts_node(
1805 	address_node *	addr,
1806 	attr_val_fifo *	options
1807 	)
1808 {
1809 	addr_opts_node *my_node;
1810 
1811 	my_node = emalloc_zero(sizeof(*my_node));
1812 	my_node->addr = addr;
1813 	my_node->options = options;
1814 
1815 	return my_node;
1816 }
1817 
1818 
1819 #ifdef SIM
1820 script_info *
1821 create_sim_script_info(
1822 	double		duration,
1823 	attr_val_fifo *	script_queue
1824 	)
1825 {
1826 	script_info *my_info;
1827 	attr_val *my_attr_val;
1828 
1829 	my_info = emalloc_zero(sizeof(*my_info));
1830 
1831 	/* Initialize Script Info with default values*/
1832 	my_info->duration = duration;
1833 	my_info->prop_delay = NET_DLY;
1834 	my_info->proc_delay = PROC_DLY;
1835 
1836 	/* Traverse the script_queue and fill out non-default values */
1837 
1838 	for (my_attr_val = HEAD_PFIFO(script_queue);
1839 	     my_attr_val != NULL;
1840 	     my_attr_val = my_attr_val->link) {
1841 
1842 		/* Set the desired value */
1843 		switch (my_attr_val->attr) {
1844 
1845 		case T_Freq_Offset:
1846 			my_info->freq_offset = my_attr_val->value.d;
1847 			break;
1848 
1849 		case T_Wander:
1850 			my_info->wander = my_attr_val->value.d;
1851 			break;
1852 
1853 		case T_Jitter:
1854 			my_info->jitter = my_attr_val->value.d;
1855 			break;
1856 
1857 		case T_Prop_Delay:
1858 			my_info->prop_delay = my_attr_val->value.d;
1859 			break;
1860 
1861 		case T_Proc_Delay:
1862 			my_info->proc_delay = my_attr_val->value.d;
1863 			break;
1864 
1865 		default:
1866 			msyslog(LOG_ERR, "Unknown script token %d",
1867 				my_attr_val->attr);
1868 		}
1869 	}
1870 
1871 	return my_info;
1872 }
1873 #endif	/* SIM */
1874 
1875 
1876 #ifdef SIM
1877 static sockaddr_u *
1878 get_next_address(
1879 	address_node *addr
1880 	)
1881 {
1882 	const char addr_prefix[] = "192.168.0.";
1883 	static int curr_addr_num = 1;
1884 #define ADDR_LENGTH 16 + 1	/* room for 192.168.1.255 */
1885 	char addr_string[ADDR_LENGTH];
1886 	sockaddr_u *final_addr;
1887 	struct addrinfo *ptr;
1888 	int gai_err;
1889 
1890 	final_addr = emalloc(sizeof(*final_addr));
1891 
1892 	if (addr->type == T_String) {
1893 		snprintf(addr_string, sizeof(addr_string), "%s%d",
1894 			 addr_prefix, curr_addr_num++);
1895 		printf("Selecting ip address %s for hostname %s\n",
1896 		       addr_string, addr->address);
1897 		gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
1898 	} else {
1899 		gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
1900 	}
1901 
1902 	if (gai_err) {
1903 		fprintf(stderr, "ERROR!! Could not get a new address\n");
1904 		exit(1);
1905 	}
1906 	memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
1907 	fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
1908 		stoa(final_addr));
1909 	freeaddrinfo(ptr);
1910 
1911 	return final_addr;
1912 }
1913 #endif /* SIM */
1914 
1915 
1916 #ifdef SIM
1917 server_info *
1918 create_sim_server(
1919 	address_node *		addr,
1920 	double			server_offset,
1921 	script_info_fifo *	script
1922 	)
1923 {
1924 	server_info *my_info;
1925 
1926 	my_info = emalloc_zero(sizeof(*my_info));
1927 	my_info->server_time = server_offset;
1928 	my_info->addr = get_next_address(addr);
1929 	my_info->script = script;
1930 	UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
1931 
1932 	return my_info;
1933 }
1934 #endif	/* SIM */
1935 
1936 sim_node *
1937 create_sim_node(
1938 	attr_val_fifo *		init_opts,
1939 	server_info_fifo *	servers
1940 	)
1941 {
1942 	sim_node *my_node;
1943 
1944 	my_node = emalloc(sizeof(*my_node));
1945 	my_node->init_opts = init_opts;
1946 	my_node->servers = servers;
1947 
1948 	return my_node;
1949 }
1950 
1951 
1952 
1953 
1954 /* FUNCTIONS FOR PERFORMING THE CONFIGURATION
1955  * ------------------------------------------
1956  */
1957 
1958 #ifndef SIM
1959 static void
1960 config_other_modes(
1961 	config_tree *	ptree
1962 	)
1963 {
1964 	sockaddr_u	addr_sock;
1965 	address_node *	addr_node;
1966 
1967 	if (ptree->broadcastclient)
1968 		proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
1969 			     0., NULL);
1970 
1971 	addr_node = HEAD_PFIFO(ptree->manycastserver);
1972 	while (addr_node != NULL) {
1973 		ZERO_SOCK(&addr_sock);
1974 		AF(&addr_sock) = addr_node->type;
1975 		if (1 == getnetnum(addr_node->address, &addr_sock, 1,
1976 				   t_UNK)) {
1977 			proto_config(PROTO_MULTICAST_ADD,
1978 				     0, 0., &addr_sock);
1979 			sys_manycastserver = 1;
1980 		}
1981 		addr_node = addr_node->link;
1982 	}
1983 
1984 	/* Configure the multicast clients */
1985 	addr_node = HEAD_PFIFO(ptree->multicastclient);
1986 	if (addr_node != NULL) {
1987 		do {
1988 			ZERO_SOCK(&addr_sock);
1989 			AF(&addr_sock) = addr_node->type;
1990 			if (1 == getnetnum(addr_node->address,
1991 					   &addr_sock, 1, t_UNK)) {
1992 				proto_config(PROTO_MULTICAST_ADD, 0, 0.,
1993 					     &addr_sock);
1994 			}
1995 			addr_node = addr_node->link;
1996 		} while (addr_node != NULL);
1997 		proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1998 	}
1999 }
2000 #endif	/* !SIM */
2001 
2002 
2003 #ifdef FREE_CFG_T
2004 static void
2005 destroy_address_fifo(
2006 	address_fifo *	pfifo
2007 	)
2008 {
2009 	address_node *	addr_node;
2010 
2011 	if (pfifo != NULL) {
2012 		for (;;) {
2013 			UNLINK_FIFO(addr_node, *pfifo, link);
2014 			if (addr_node == NULL)
2015 				break;
2016 			destroy_address_node(addr_node);
2017 		}
2018 		free(pfifo);
2019 	}
2020 }
2021 
2022 
2023 static void
2024 free_config_other_modes(
2025 	config_tree *ptree
2026 	)
2027 {
2028 	FREE_ADDRESS_FIFO(ptree->manycastserver);
2029 	FREE_ADDRESS_FIFO(ptree->multicastclient);
2030 }
2031 #endif	/* FREE_CFG_T */
2032 
2033 
2034 #ifndef SIM
2035 static void
2036 config_auth(
2037 	config_tree *ptree
2038 	)
2039 {
2040 	attr_val *	my_val;
2041 	int		first;
2042 	int		last;
2043 	int		i;
2044 	int		count;
2045 #ifdef AUTOKEY
2046 	int		item;
2047 #endif
2048 
2049 	/* Crypto Command */
2050 #ifdef AUTOKEY
2051 	my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
2052 	for (; my_val != NULL; my_val = my_val->link) {
2053 		switch (my_val->attr) {
2054 
2055 		default:
2056 			fatal_error("config_auth: attr-token=%d", my_val->attr);
2057 
2058 		case T_Host:
2059 			item = CRYPTO_CONF_PRIV;
2060 			break;
2061 
2062 		case T_Ident:
2063 			item = CRYPTO_CONF_IDENT;
2064 			break;
2065 
2066 		case T_Pw:
2067 			item = CRYPTO_CONF_PW;
2068 			break;
2069 
2070 		case T_Randfile:
2071 			item = CRYPTO_CONF_RAND;
2072 			break;
2073 
2074 		case T_Digest:
2075 			item = CRYPTO_CONF_NID;
2076 			break;
2077 		}
2078 		crypto_config(item, my_val->value.s);
2079 	}
2080 #endif	/* AUTOKEY */
2081 
2082 	/* Keysdir Command */
2083 	if (ptree->auth.keysdir) {
2084 		if (keysdir != default_keysdir)
2085 			free(keysdir);
2086 		keysdir = estrdup(ptree->auth.keysdir);
2087 	}
2088 
2089 
2090 	/* ntp_signd_socket Command */
2091 	if (ptree->auth.ntp_signd_socket) {
2092 		if (ntp_signd_socket != default_ntp_signd_socket)
2093 			free(ntp_signd_socket);
2094 		ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
2095 	}
2096 
2097 #ifdef AUTOKEY
2098 	if (ptree->auth.cryptosw && !cryptosw) {
2099 		crypto_setup();
2100 		cryptosw = 1;
2101 	}
2102 #endif	/* AUTOKEY */
2103 
2104 	/*
2105 	 * Count the number of trusted keys to preallocate storage and
2106 	 * size the hash table.
2107 	 */
2108 	count = 0;
2109 	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2110 	for (; my_val != NULL; my_val = my_val->link) {
2111 		if (T_Integer == my_val->type) {
2112 			first = my_val->value.i;
2113 			if (first > 1 && first <= NTP_MAXKEY)
2114 				count++;
2115 		} else {
2116 			REQUIRE(T_Intrange == my_val->type);
2117 			first = my_val->value.r.first;
2118 			last = my_val->value.r.last;
2119 			if (!(first > last || first < 1 ||
2120 			    last > NTP_MAXKEY)) {
2121 				count += 1 + last - first;
2122 			}
2123 		}
2124 	}
2125 	auth_prealloc_symkeys(count);
2126 
2127 	/* Keys Command */
2128 	if (ptree->auth.keys)
2129 		getauthkeys(ptree->auth.keys);
2130 
2131 	/* Control Key Command */
2132 	if (ptree->auth.control_key)
2133 		ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
2134 
2135 	/* Requested Key Command */
2136 	if (ptree->auth.request_key) {
2137 		DPRINTF(4, ("set info_auth_keyid to %08lx\n",
2138 			    (u_long) ptree->auth.request_key));
2139 		info_auth_keyid = (keyid_t)ptree->auth.request_key;
2140 	}
2141 
2142 	/* Trusted Key Command */
2143 	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2144 	for (; my_val != NULL; my_val = my_val->link) {
2145 		if (T_Integer == my_val->type) {
2146 			first = my_val->value.i;
2147 			if (first >= 1 && first <= NTP_MAXKEY) {
2148 				authtrust(first, TRUE);
2149 			} else {
2150 				msyslog(LOG_NOTICE,
2151 					"Ignoring invalid trustedkey %d, min 1 max %d.",
2152 					first, NTP_MAXKEY);
2153 			}
2154 		} else {
2155 			first = my_val->value.r.first;
2156 			last = my_val->value.r.last;
2157 			if (first > last || first < 1 ||
2158 			    last > NTP_MAXKEY) {
2159 				msyslog(LOG_NOTICE,
2160 					"Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
2161 					first, last, NTP_MAXKEY);
2162 			} else {
2163 				for (i = first; i <= last; i++) {
2164 					authtrust(i, TRUE);
2165 				}
2166 			}
2167 		}
2168 	}
2169 
2170 #ifdef AUTOKEY
2171 	/* crypto revoke command */
2172 	if (ptree->auth.revoke > 2 && ptree->auth.revoke < 32)
2173 		sys_revoke = (u_char)ptree->auth.revoke;
2174 	else if (ptree->auth.revoke)
2175 		msyslog(LOG_ERR,
2176 			"'revoke' value %d ignored",
2177 			ptree->auth.revoke);
2178 #endif	/* AUTOKEY */
2179 }
2180 #endif	/* !SIM */
2181 
2182 
2183 #ifdef FREE_CFG_T
2184 static void
2185 free_config_auth(
2186 	config_tree *ptree
2187 	)
2188 {
2189 	destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
2190 	ptree->auth.crypto_cmd_list = NULL;
2191 	destroy_attr_val_fifo(ptree->auth.trusted_key_list);
2192 	ptree->auth.trusted_key_list = NULL;
2193 }
2194 #endif	/* FREE_CFG_T */
2195 
2196 #ifndef SIM
2197 /* Configure low-level clock-related parameters. Return TRUE if the
2198  * clock might need adjustment like era-checking after the call, FALSE
2199  * otherwise.
2200  */
2201 static int/*BOOL*/
2202 config_tos_clock(
2203 	config_tree *ptree
2204 	)
2205 {
2206 	int		ret;
2207 	attr_val *	tos;
2208 
2209 	ret = FALSE;
2210 	tos = HEAD_PFIFO(ptree->orphan_cmds);
2211 	for (; tos != NULL; tos = tos->link) {
2212 		switch(tos->attr) {
2213 
2214 		default:
2215 			break;
2216 
2217 		case T_Basedate:
2218 			basedate_set_day(tos->value.i);
2219 			ret = TRUE;
2220 			break;
2221 		}
2222 	}
2223 
2224 	if (basedate_get_day() <= NTP_TO_UNIX_DAYS)
2225 		basedate_set_day(basedate_eval_buildstamp() - 11);
2226 
2227 	return ret;
2228 }
2229 #endif	/* SIM */
2230 
2231 static void
2232 config_tos(
2233 	config_tree *ptree
2234 	)
2235 {
2236 	char const	improper_operation_msg[] =
2237 				" - daemon will not operate properly!";
2238 	attr_val *	tos;
2239 	int		item;
2240 	double		val;
2241 
2242 	/* [Bug 2896] For the daemon to work properly it is essential
2243 	 * that minsane < minclock <= maxclock.
2244 	 *
2245 	 * If either constraint is violated, the daemon will be or might
2246 	 * become dysfunctional. Fixing the values is too fragile here,
2247 	 * since three variables with interdependecies are involved. We
2248 	 * just log an error but do not stop: This might be caused by
2249 	 * remote config, and it might be fixed by remote config, too.
2250 	 */
2251 	int l_maxclock	= sys_maxclock;
2252 	int l_minclock	= sys_minclock;
2253 	int l_minsane	= sys_minsane;
2254 	int l_floor	= sys_floor;
2255 	int l_ceiling	= sys_ceiling;
2256 
2257 	/* -*- phase one: inspect / sanitize the values */
2258 	tos = HEAD_PFIFO(ptree->orphan_cmds);
2259 	for (; tos != NULL; tos = tos->link) {
2260 		/* not all attributes are doubles (any more), so loading
2261 		 * 'val' in all cases is not a good idea: It should be
2262 		 * done as needed in every case processed here.
2263 		 */
2264 		switch(tos->attr) {
2265 		default:
2266 			break;
2267 
2268 		case T_Bcpollbstep:
2269 			val = tos->value.d;
2270 			if (val > 4) {
2271 				msyslog(LOG_WARNING,
2272 					"Using maximum tos bcpollbstep %d, %d requested",
2273 					4, (int)val);
2274 				tos->value.d = 4;
2275 			} else if (val < 0) {
2276 				msyslog(LOG_WARNING,
2277 					"Using minimum tos bcpollbstep %d, %d requested",
2278 					0, (int)val);
2279 				tos->value.d = 0;
2280 			}
2281 			break;
2282 
2283 		case T_Floor:
2284 			l_floor = (int)tos->value.d;
2285 			if (l_floor > STRATUM_UNSPEC - 1) {
2286 				msyslog(LOG_WARNING,
2287 					"Using maximum tos floor %d, %d requested",
2288 					STRATUM_UNSPEC - 1, l_floor);
2289 				tos->value.d = STRATUM_UNSPEC - 1;
2290 			}
2291 			else if (l_floor < 0) {
2292 				msyslog(LOG_WARNING,
2293 					"Using minimum tos floor %d, %d requested",
2294 					0, l_floor);
2295 				tos->value.d = 0;
2296 			}
2297 			l_floor = (int)tos->value.d;
2298 			break;
2299 
2300 		case T_Ceiling:
2301 			l_ceiling = (int)tos->value.d;
2302 			if (l_ceiling > STRATUM_UNSPEC - 1) {
2303 				msyslog(LOG_WARNING,
2304 					"Using maximum tos ceiling %d, %d requested",
2305 					STRATUM_UNSPEC - 1, l_ceiling);
2306 				tos->value.d = STRATUM_UNSPEC - 1;
2307 			}
2308 			else if (l_ceiling < 0) {
2309 				msyslog(LOG_WARNING,
2310 					"Using minimum tos ceiling %d, %d requested",
2311 					0, l_ceiling);
2312 				tos->value.d = 0;
2313 			}
2314 			l_ceiling = (int)tos->value.d;
2315 			break;
2316 
2317 		case T_Minclock:
2318 			val = tos->value.d;
2319 			if ((int)tos->value.d < 1)
2320 				tos->value.d = 1;
2321 			l_minclock = (int)tos->value.d;
2322 			break;
2323 
2324 		case T_Maxclock:
2325 			val = tos->value.d;
2326 			if ((int)tos->value.d < 1)
2327 				tos->value.d = 1;
2328 			l_maxclock = (int)tos->value.d;
2329 			break;
2330 
2331 		case T_Minsane:
2332 			val = tos->value.d;
2333 			if ((int)tos->value.d < 0)
2334 				tos->value.d = 0;
2335 			l_minsane = (int)tos->value.d;
2336 			break;
2337 		}
2338 	}
2339 
2340 	if ( ! (l_minsane < l_minclock && l_minclock <= l_maxclock)) {
2341 		msyslog(LOG_ERR, "Must have tos "
2342 			"minsane (%d) < minclock (%d) <= maxclock (%d)%s",
2343 			l_minsane, l_minclock, l_maxclock,
2344 			improper_operation_msg);
2345 	}
2346 
2347 	if (l_floor > l_ceiling) {
2348 		msyslog(LOG_ERR, "Must have tos "
2349 			"floor (%d) <= ceiling (%d)%s",
2350 			l_floor, l_ceiling, improper_operation_msg);
2351 	}
2352 
2353 	/* -*- phase two: forward the values to the protocol machinery */
2354 	tos = HEAD_PFIFO(ptree->orphan_cmds);
2355 	for (; tos != NULL; tos = tos->link) {
2356 		switch(tos->attr) {
2357 
2358 		default:
2359 			fatal_error("config-tos: attr-token=%d", tos->attr);
2360 
2361 		case T_Bcpollbstep:
2362 			item = PROTO_BCPOLLBSTEP;
2363 			break;
2364 
2365 		case T_Ceiling:
2366 			item = PROTO_CEILING;
2367 			break;
2368 
2369 		case T_Floor:
2370 			item = PROTO_FLOOR;
2371 			break;
2372 
2373 		case T_Cohort:
2374 			item = PROTO_COHORT;
2375 			break;
2376 
2377 		case T_Orphan:
2378 			item = PROTO_ORPHAN;
2379 			break;
2380 
2381 		case T_Orphanwait:
2382 			item = PROTO_ORPHWAIT;
2383 			break;
2384 
2385 		case T_Mindist:
2386 			item = PROTO_MINDISP;
2387 			break;
2388 
2389 		case T_Maxdist:
2390 			item = PROTO_MAXDIST;
2391 			break;
2392 
2393 		case T_Minclock:
2394 			item = PROTO_MINCLOCK;
2395 			break;
2396 
2397 		case T_Maxclock:
2398 			item = PROTO_MAXCLOCK;
2399 			break;
2400 
2401 		case T_Minsane:
2402 			item = PROTO_MINSANE;
2403 			break;
2404 
2405 		case T_Beacon:
2406 			item = PROTO_BEACON;
2407 			break;
2408 
2409 		case T_Basedate:
2410 			continue; /* SKIP proto-config for this! */
2411 		}
2412 		proto_config(item, 0, tos->value.d, NULL);
2413 	}
2414 }
2415 
2416 
2417 #ifdef FREE_CFG_T
2418 static void
2419 free_config_tos(
2420 	config_tree *ptree
2421 	)
2422 {
2423 	FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
2424 }
2425 #endif	/* FREE_CFG_T */
2426 
2427 
2428 static void
2429 config_monitor(
2430 	config_tree *ptree
2431 	)
2432 {
2433 	int_node *pfilegen_token;
2434 	const char *filegen_string;
2435 	const char *filegen_file;
2436 	FILEGEN *filegen;
2437 	filegen_node *my_node;
2438 	attr_val *my_opts;
2439 	int filegen_type;
2440 	int filegen_flag;
2441 
2442 	/* Set the statistics directory */
2443 	if (ptree->stats_dir)
2444 	    stats_config(STATS_STATSDIR, ptree->stats_dir, 0);
2445 
2446 	/* NOTE:
2447 	 * Calling filegen_get is brain dead. Doing a string
2448 	 * comparison to find the relavant filegen structure is
2449 	 * expensive.
2450 	 *
2451 	 * Through the parser, we already know which filegen is
2452 	 * being specified. Hence, we should either store a
2453 	 * pointer to the specified structure in the syntax tree
2454 	 * or an index into a filegen array.
2455 	 *
2456 	 * Need to change the filegen code to reflect the above.
2457 	 */
2458 
2459 	/* Turn on the specified statistics */
2460 	pfilegen_token = HEAD_PFIFO(ptree->stats_list);
2461 	for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
2462 		filegen_string = keyword(pfilegen_token->i);
2463 		filegen = filegen_get(filegen_string);
2464 		if (NULL == filegen) {
2465 			msyslog(LOG_ERR,
2466 				"stats %s unrecognized",
2467 				filegen_string);
2468 			continue;
2469 		}
2470 		DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
2471 			    filegen_string, filegen->dir,
2472 			    filegen->fname));
2473 		filegen_flag = filegen->flag;
2474 		filegen_flag |= FGEN_FLAG_ENABLED;
2475 		filegen_config(filegen, statsdir, filegen_string,
2476 			       filegen->type, filegen_flag);
2477 	}
2478 
2479 	/* Configure the statistics with the options */
2480 	my_node = HEAD_PFIFO(ptree->filegen_opts);
2481 	for (; my_node != NULL; my_node = my_node->link) {
2482 		filegen_string = keyword(my_node->filegen_token);
2483 		filegen = filegen_get(filegen_string);
2484 		if (NULL == filegen) {
2485 			msyslog(LOG_ERR,
2486 				"filegen category '%s' unrecognized",
2487 				filegen_string);
2488 			continue;
2489 		}
2490 		filegen_file = filegen_string;
2491 
2492 		/* Initialize the filegen variables to their pre-configuration states */
2493 		filegen_flag = filegen->flag;
2494 		filegen_type = filegen->type;
2495 
2496 		/* "filegen ... enabled" is the default (when filegen is used) */
2497 		filegen_flag |= FGEN_FLAG_ENABLED;
2498 
2499 		my_opts = HEAD_PFIFO(my_node->options);
2500 		for (; my_opts != NULL; my_opts = my_opts->link) {
2501 			switch (my_opts->attr) {
2502 
2503 			case T_File:
2504 				filegen_file = my_opts->value.s;
2505 				break;
2506 
2507 			case T_Type:
2508 				switch (my_opts->value.i) {
2509 
2510 				default:
2511 					fatal_error("config-monitor: type-token=%d", my_opts->value.i);
2512 
2513 				case T_None:
2514 					filegen_type = FILEGEN_NONE;
2515 					break;
2516 
2517 				case T_Pid:
2518 					filegen_type = FILEGEN_PID;
2519 					break;
2520 
2521 				case T_Day:
2522 					filegen_type = FILEGEN_DAY;
2523 					break;
2524 
2525 				case T_Week:
2526 					filegen_type = FILEGEN_WEEK;
2527 					break;
2528 
2529 				case T_Month:
2530 					filegen_type = FILEGEN_MONTH;
2531 					break;
2532 
2533 				case T_Year:
2534 					filegen_type = FILEGEN_YEAR;
2535 					break;
2536 
2537 				case T_Age:
2538 					filegen_type = FILEGEN_AGE;
2539 					break;
2540 				}
2541 				break;
2542 
2543 			case T_Flag:
2544 				switch (my_opts->value.i) {
2545 
2546 				case T_Link:
2547 					filegen_flag |= FGEN_FLAG_LINK;
2548 					break;
2549 
2550 				case T_Nolink:
2551 					filegen_flag &= ~FGEN_FLAG_LINK;
2552 					break;
2553 
2554 				case T_Enable:
2555 					filegen_flag |= FGEN_FLAG_ENABLED;
2556 					break;
2557 
2558 				case T_Disable:
2559 					filegen_flag &= ~FGEN_FLAG_ENABLED;
2560 					break;
2561 
2562 				default:
2563 					msyslog(LOG_ERR,
2564 						"Unknown filegen flag token %d",
2565 						my_opts->value.i);
2566 					exit(1);
2567 				}
2568 				break;
2569 
2570 			default:
2571 				msyslog(LOG_ERR,
2572 					"Unknown filegen option token %d",
2573 					my_opts->attr);
2574 				exit(1);
2575 			}
2576 		}
2577 		filegen_config(filegen, statsdir, filegen_file,
2578 			       filegen_type, filegen_flag);
2579 	}
2580 }
2581 
2582 
2583 #ifdef FREE_CFG_T
2584 static void
2585 free_config_monitor(
2586 	config_tree *ptree
2587 	)
2588 {
2589 	if (ptree->stats_dir) {
2590 		free(ptree->stats_dir);
2591 		ptree->stats_dir = NULL;
2592 	}
2593 
2594 	FREE_INT_FIFO(ptree->stats_list);
2595 	FREE_FILEGEN_FIFO(ptree->filegen_opts);
2596 }
2597 #endif	/* FREE_CFG_T */
2598 
2599 
2600 #ifndef SIM
2601 static void
2602 config_access(
2603 	config_tree *ptree
2604 	)
2605 {
2606 	static int		warned_signd;
2607 	attr_val *		my_opt;
2608 	restrict_node *		my_node;
2609 	sockaddr_u		addr;
2610 	sockaddr_u		mask;
2611 	struct addrinfo		hints;
2612 	struct addrinfo *	ai_list;
2613 	struct addrinfo *	pai;
2614 	int			rc;
2615 	int			restrict_default;
2616 	u_short			rflags;
2617 	u_short			mflags;
2618 	short			ippeerlimit;
2619 	int			range_err;
2620 	psl_item		my_psl_item;
2621 	attr_val *		atrv;
2622 	attr_val *		dflt_psl_atr;
2623 	const char *		signd_warning =
2624 #ifdef HAVE_NTP_SIGND
2625 	    "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
2626 #else
2627 	    "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
2628 #endif
2629 
2630 	/* Configure the mru options */
2631 	my_opt = HEAD_PFIFO(ptree->mru_opts);
2632 	for (; my_opt != NULL; my_opt = my_opt->link) {
2633 
2634 		range_err = FALSE;
2635 
2636 		switch (my_opt->attr) {
2637 
2638 		case T_Incalloc:
2639 			if (0 <= my_opt->value.i)
2640 				mru_incalloc = my_opt->value.u;
2641 			else
2642 				range_err = TRUE;
2643 			break;
2644 
2645 		case T_Incmem:
2646 			if (0 <= my_opt->value.i)
2647 				mru_incalloc = (my_opt->value.u * 1024U)
2648 						/ sizeof(mon_entry);
2649 			else
2650 				range_err = TRUE;
2651 			break;
2652 
2653 		case T_Initalloc:
2654 			if (0 <= my_opt->value.i)
2655 				mru_initalloc = my_opt->value.u;
2656 			else
2657 				range_err = TRUE;
2658 			break;
2659 
2660 		case T_Initmem:
2661 			if (0 <= my_opt->value.i)
2662 				mru_initalloc = (my_opt->value.u * 1024U)
2663 						 / sizeof(mon_entry);
2664 			else
2665 				range_err = TRUE;
2666 			break;
2667 
2668 		case T_Mindepth:
2669 			if (0 <= my_opt->value.i)
2670 				mru_mindepth = my_opt->value.u;
2671 			else
2672 				range_err = TRUE;
2673 			break;
2674 
2675 		case T_Maxage:
2676 			mru_maxage = my_opt->value.i;
2677 			break;
2678 
2679 		case T_Maxdepth:
2680 			if (0 <= my_opt->value.i)
2681 				mru_maxdepth = my_opt->value.u;
2682 			else
2683 				mru_maxdepth = UINT_MAX;
2684 			break;
2685 
2686 		case T_Maxmem:
2687 			if (0 <= my_opt->value.i)
2688 				mru_maxdepth = (my_opt->value.u * 1024U) /
2689 					       sizeof(mon_entry);
2690 			else
2691 				mru_maxdepth = UINT_MAX;
2692 			break;
2693 
2694 		default:
2695 			msyslog(LOG_ERR,
2696 				"Unknown mru option %s (%d)",
2697 				keyword(my_opt->attr), my_opt->attr);
2698 			exit(1);
2699 		}
2700 		if (range_err)
2701 			msyslog(LOG_ERR,
2702 				"mru %s %d out of range, ignored.",
2703 				keyword(my_opt->attr), my_opt->value.i);
2704 	}
2705 
2706 	/* Configure the discard options */
2707 	my_opt = HEAD_PFIFO(ptree->discard_opts);
2708 	for (; my_opt != NULL; my_opt = my_opt->link) {
2709 
2710 		switch (my_opt->attr) {
2711 
2712 		case T_Average:
2713 			if (0 <= my_opt->value.i &&
2714 			    my_opt->value.i <= UCHAR_MAX)
2715 				ntp_minpoll = (u_char)my_opt->value.u;
2716 			else
2717 				msyslog(LOG_ERR,
2718 					"discard average %d out of range, ignored.",
2719 					my_opt->value.i);
2720 			break;
2721 
2722 		case T_Minimum:
2723 			ntp_minpkt = my_opt->value.i;
2724 			break;
2725 
2726 		case T_Monitor:
2727 			mon_age = my_opt->value.i;
2728 			break;
2729 
2730 		default:
2731 			msyslog(LOG_ERR,
2732 				"Unknown discard option %s (%d)",
2733 				keyword(my_opt->attr), my_opt->attr);
2734 			exit(1);
2735 		}
2736 	}
2737 
2738 	/* Configure each line of restrict options */
2739 	my_node = HEAD_PFIFO(ptree->restrict_opts);
2740 
2741 	for (; my_node != NULL; my_node = my_node->link) {
2742 
2743 		/* Grab the ippeerlmit */
2744 		ippeerlimit = my_node->ippeerlimit;
2745 
2746 		/* Parse the flags */
2747 		rflags = 0;
2748 		mflags = 0;
2749 
2750 		my_opt = HEAD_PFIFO(my_node->flag_tok_fifo);
2751 		for (; my_opt != NULL; my_opt = my_opt->link) {
2752 			switch (my_opt->attr) {
2753 
2754 			default:
2755 				fatal_error("config_access: Unknown flag-type-token=%s/%d", keyword(my_opt->attr), my_opt->attr);
2756 
2757 			case T_Ntpport:
2758 				mflags |= RESM_NTPONLY;
2759 				break;
2760 
2761 			case T_Source:
2762 				mflags |= RESM_SOURCE;
2763 				break;
2764 
2765 			case T_Flake:
2766 				rflags |= RES_FLAKE;
2767 				break;
2768 
2769 			case T_Ignore:
2770 				rflags |= RES_IGNORE;
2771 				break;
2772 
2773 			case T_Kod:
2774 				rflags |= RES_KOD;
2775 				break;
2776 
2777 			case T_Limited:
2778 				rflags |= RES_LIMITED;
2779 				break;
2780 
2781 			case T_Lowpriotrap:
2782 				rflags |= RES_LPTRAP;
2783 				break;
2784 
2785 			case T_Mssntp:
2786 				rflags |= RES_MSSNTP;
2787 				break;
2788 
2789 			case T_Nomodify:
2790 				rflags |= RES_NOMODIFY;
2791 				break;
2792 
2793 			case T_Nomrulist:
2794 				rflags |= RES_NOMRULIST;
2795 				break;
2796 
2797 			case T_Noepeer:
2798 				rflags |= RES_NOEPEER;
2799 				break;
2800 
2801 			case T_Nopeer:
2802 				rflags |= RES_NOPEER;
2803 				break;
2804 
2805 			case T_Noquery:
2806 				rflags |= RES_NOQUERY;
2807 				break;
2808 
2809 			case T_Noserve:
2810 				rflags |= RES_DONTSERVE;
2811 				break;
2812 
2813 			case T_Notrap:
2814 				rflags |= RES_NOTRAP;
2815 				break;
2816 
2817 			case T_Notrust:
2818 				rflags |= RES_DONTTRUST;
2819 				break;
2820 
2821 			case T_ServerresponseFuzz:
2822 				rflags |= RES_SRVRSPFUZ;
2823 				break;
2824 
2825 			case T_Version:
2826 				rflags |= RES_VERSION;
2827 				break;
2828 			}
2829 		}
2830 
2831 		if ((RES_MSSNTP & rflags) && !warned_signd) {
2832 			warned_signd = 1;
2833 			fprintf(stderr, "%s\n", signd_warning);
2834 			msyslog(LOG_WARNING, "%s", signd_warning);
2835 		}
2836 
2837 		/* It would be swell if we could identify the line number */
2838 		if ((RES_KOD & rflags) && !(RES_LIMITED & rflags)) {
2839 			const char *kod_where = (my_node->addr)
2840 					  ? my_node->addr->address
2841 					  : (mflags & RESM_SOURCE)
2842 					    ? "source"
2843 					    : "default";
2844 			const char *kod_warn = "KOD does nothing without LIMITED.";
2845 
2846 			fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
2847 			msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
2848 		}
2849 
2850 		ZERO_SOCK(&addr);
2851 		ai_list = NULL;
2852 		pai = NULL;
2853 		restrict_default = 0;
2854 
2855 		if (NULL == my_node->addr) {
2856 			ZERO_SOCK(&mask);
2857 			if (!(RESM_SOURCE & mflags)) {
2858 				/*
2859 				 * The user specified a default rule
2860 				 * without a -4 / -6 qualifier, add to
2861 				 * both lists
2862 				 */
2863 				restrict_default = 1;
2864 			} else {
2865 				/* apply "restrict source ..." */
2866 				DPRINTF(1, ("restrict source template ippeerlimit %d mflags %x rflags %x\n",
2867 					ippeerlimit, mflags, rflags));
2868 				hack_restrict(RESTRICT_FLAGS, NULL, NULL,
2869 					      ippeerlimit, mflags, rflags, 0);
2870 				continue;
2871 			}
2872 		} else {
2873 			/* Resolve the specified address */
2874 			AF(&addr) = (u_short)my_node->addr->type;
2875 
2876 			if (getnetnum(my_node->addr->address,
2877 				      &addr, 1, t_UNK) != 1) {
2878 				/*
2879 				 * Attempt a blocking lookup.  This
2880 				 * is in violation of the nonblocking
2881 				 * design of ntpd's mainline code.  The
2882 				 * alternative of running without the
2883 				 * restriction until the name resolved
2884 				 * seems worse.
2885 				 * Ideally some scheme could be used for
2886 				 * restrict directives in the startup
2887 				 * ntp.conf to delay starting up the
2888 				 * protocol machinery until after all
2889 				 * restrict hosts have been resolved.
2890 				 */
2891 				ai_list = NULL;
2892 				ZERO(hints);
2893 				hints.ai_protocol = IPPROTO_UDP;
2894 				hints.ai_socktype = SOCK_DGRAM;
2895 				hints.ai_family = my_node->addr->type;
2896 				rc = getaddrinfo(my_node->addr->address,
2897 						 "ntp", &hints,
2898 						 &ai_list);
2899 				if (rc) {
2900 					msyslog(LOG_ERR,
2901 						"restrict: ignoring line %d, address/host '%s' unusable.",
2902 						my_node->line_no,
2903 						my_node->addr->address);
2904 					continue;
2905 				}
2906 				INSIST(ai_list != NULL);
2907 				pai = ai_list;
2908 				INSIST(pai->ai_addr != NULL);
2909 				INSIST(sizeof(addr) >=
2910 					   pai->ai_addrlen);
2911 				memcpy(&addr, pai->ai_addr,
2912 				       pai->ai_addrlen);
2913 				INSIST(AF_INET == AF(&addr) ||
2914 					   AF_INET6 == AF(&addr));
2915 			}
2916 
2917 			SET_HOSTMASK(&mask, AF(&addr));
2918 
2919 			/* Resolve the mask */
2920 			if (my_node->mask) {
2921 				ZERO_SOCK(&mask);
2922 				AF(&mask) = my_node->mask->type;
2923 				if (getnetnum(my_node->mask->address,
2924 					      &mask, 1, t_MSK) != 1) {
2925 					msyslog(LOG_ERR,
2926 						"restrict: ignoring line %d, mask '%s' unusable.",
2927 						my_node->line_no,
2928 						my_node->mask->address);
2929 					continue;
2930 				}
2931 			}
2932 		}
2933 
2934 		/* Set the flags */
2935 		if (restrict_default) {
2936 			AF(&addr) = AF_INET;
2937 			AF(&mask) = AF_INET;
2938 			hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2939 				      ippeerlimit, mflags, rflags, 0);
2940 			AF(&addr) = AF_INET6;
2941 			AF(&mask) = AF_INET6;
2942 		}
2943 
2944 		do {
2945 			hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2946 				      ippeerlimit, mflags, rflags, 0);
2947 			if (pai != NULL &&
2948 			    NULL != (pai = pai->ai_next)) {
2949 				INSIST(pai->ai_addr != NULL);
2950 				INSIST(sizeof(addr) >=
2951 					   pai->ai_addrlen);
2952 				ZERO_SOCK(&addr);
2953 				memcpy(&addr, pai->ai_addr,
2954 				       pai->ai_addrlen);
2955 				INSIST(AF_INET == AF(&addr) ||
2956 					   AF_INET6 == AF(&addr));
2957 				SET_HOSTMASK(&mask, AF(&addr));
2958 			}
2959 		} while (pai != NULL);
2960 
2961 		if (ai_list != NULL)
2962 			freeaddrinfo(ai_list);
2963 	}
2964 
2965 	/* Deal with the Poll Skew List */
2966 
2967 	ZERO(psl);
2968 	ZERO(my_psl_item);
2969 
2970 	/*
2971 	 * First, find the last default pollskewlist item.
2972 	 * There should only be one of these with the current grammar,
2973 	 * but better safe than sorry.
2974 	 */
2975 	dflt_psl_atr = NULL;
2976 	atrv = HEAD_PFIFO(ptree->pollskewlist);
2977 	for ( ; atrv != NULL; atrv = atrv->link) {
2978 		switch (atrv->attr) {
2979 		case -1:	/* default */
2980 			dflt_psl_atr = atrv;
2981 			break;
2982 
2983 		case 3:		/* Fall through */
2984 		case 4:		/* Fall through */
2985 		case 5:		/* Fall through */
2986 		case 6:		/* Fall through */
2987 		case 7:		/* Fall through */
2988 		case 8:		/* Fall through */
2989 		case 9:		/* Fall through */
2990 		case 10:	/* Fall through */
2991 		case 11:	/* Fall through */
2992 		case 12:	/* Fall through */
2993 		case 13:	/* Fall through */
2994 		case 14:	/* Fall through */
2995 		case 15:	/* Fall through */
2996 		case 16:	/* Fall through */
2997 		case 17:
2998 			/* ignore */
2999 			break;
3000 
3001 		default:
3002 			msyslog(LOG_ERR,
3003 				"config_access: default PSL scan: ignoring unexpected poll value %d",
3004 				atrv->attr);
3005 			break;
3006 		}
3007 	}
3008 
3009 	/* If we have a nonzero default, initialize the PSL */
3010 	if (   dflt_psl_atr
3011 	    && (   0 != dflt_psl_atr->value.r.first
3012 		|| 0 != dflt_psl_atr->value.r.last)) {
3013 		int i;
3014 
3015 		for (i = 3; i <= 17; ++i) {
3016 			attrtopsl(i, dflt_psl_atr);
3017 		}
3018 	}
3019 
3020 	/* Finally, update the PSL with any explicit entries */
3021 	atrv = HEAD_PFIFO(ptree->pollskewlist);
3022 	for ( ; atrv != NULL; atrv = atrv->link) {
3023 		switch (atrv->attr) {
3024 		case -1:	/* default */
3025 			/* Ignore */
3026 			break;
3027 
3028 		case 3:		/* Fall through */
3029 		case 4:		/* Fall through */
3030 		case 5:		/* Fall through */
3031 		case 6:		/* Fall through */
3032 		case 7:		/* Fall through */
3033 		case 8:		/* Fall through */
3034 		case 9:		/* Fall through */
3035 		case 10:	/* Fall through */
3036 		case 11:	/* Fall through */
3037 		case 12:	/* Fall through */
3038 		case 13:	/* Fall through */
3039 		case 14:	/* Fall through */
3040 		case 15:	/* Fall through */
3041 		case 16:	/* Fall through */
3042 		case 17:
3043 			attrtopsl(atrv->attr, atrv);
3044 			break;
3045 
3046 		default:
3047 			break;	/* Ignore - we reported this above */
3048 		}
3049 	}
3050 
3051 #if 0
3052 	int p;
3053 	msyslog(LOG_INFO, "Dumping PSL:");
3054 	for (p = 3; p <= 17; ++p) {
3055 		psl_item psi;
3056 
3057 		if (0 == get_pollskew(p, &psi)) {
3058 			msyslog(LOG_INFO, "poll %d: sub %d, qty %d, msk %d",
3059 				p, psi.sub, psi.qty, psi.msk);
3060 		} else {
3061 			msyslog(LOG_ERR, "Dumping PSL: get_pollskew(%d) failed!", p);
3062 		}
3063 	}
3064 #endif
3065 }
3066 
3067 
3068 void
3069 attrtopsl(int poll, attr_val *avp)
3070 {
3071 
3072 	DEBUG_INSIST((poll - 3) < sizeof psl);
3073 	if (poll < 3 || poll > 17) {
3074 		msyslog(LOG_ERR, "attrtopsl(%d, ...): Poll value is out of range - ignoring", poll);
3075 	} else {
3076 		int pao = poll - 3;		/* poll array offset */
3077 		int lower = avp->value.r.first;	/* a positive number */
3078 		int upper = avp->value.r.last;
3079 		int psmax = 1 << (poll - 1);
3080 		int qmsk;
3081 
3082 		if (lower > psmax) {
3083 			msyslog(LOG_WARNING, "attrtopsl: default: poll %d lower bound reduced from %d to %d",
3084 				poll, lower, psmax);
3085 			lower = psmax;
3086 		}
3087 		if (upper > psmax) {
3088 			msyslog(LOG_WARNING, "attrtopsl: default: poll %d upper bound reduced from %d to %d",
3089 				poll, upper, psmax);
3090 			upper = psmax;
3091 		}
3092 		psl[pao].sub = lower;
3093 		psl[pao].qty = lower + upper;
3094 
3095 		qmsk = 1;
3096 		while (qmsk < (lower + upper)) {
3097 			qmsk <<= 1;
3098 			qmsk |=  1;
3099 		};
3100 		psl[pao].msk = qmsk;
3101 	}
3102 
3103 	return;
3104 }
3105 #endif	/* !SIM */
3106 
3107 
3108 int
3109 get_pollskew(
3110 	int p,
3111 	psl_item *rv
3112 	)
3113 {
3114 
3115 #ifdef DISABLE_BUG3767_FIX
3116 	DEBUG_INSIST(3 <= p && 17 >= p);
3117 #endif
3118 	if (3 <= p && 17 >= p) {
3119 		*rv = psl[p - 3];
3120 
3121 		return 0;
3122 	} else {
3123 		msyslog(LOG_ERR, "get_pollskew(%d): poll is not between 3 and 17!", p);
3124 		return -1;
3125 	}
3126 
3127 	/* NOTREACHED */
3128 }
3129 
3130 
3131 #ifdef FREE_CFG_T
3132 static void
3133 free_config_access(
3134 	config_tree *ptree
3135 	)
3136 {
3137 	FREE_ATTR_VAL_FIFO(ptree->mru_opts);
3138 	FREE_ATTR_VAL_FIFO(ptree->discard_opts);
3139 	FREE_RESTRICT_FIFO(ptree->restrict_opts);
3140 }
3141 #endif	/* FREE_CFG_T */
3142 
3143 
3144 static void
3145 config_rlimit(
3146 	config_tree *ptree
3147 	)
3148 {
3149 	attr_val *	rlimit_av;
3150 
3151 	rlimit_av = HEAD_PFIFO(ptree->rlimit);
3152 	for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
3153 		switch (rlimit_av->attr) {
3154 
3155 		default:
3156 			fatal_error("config-rlimit: value-token=%d", rlimit_av->attr);
3157 
3158 		case T_Memlock:
3159 			/* What if we HAVE_OPT(SAVECONFIGQUIT) ? */
3160 			if (HAVE_OPT( SAVECONFIGQUIT )) {
3161 				break;
3162 			}
3163 			if (rlimit_av->value.i == -1) {
3164 # if defined(HAVE_MLOCKALL)
3165 				if (cur_memlock != 0) {
3166 					if (-1 == munlockall()) {
3167 						msyslog(LOG_ERR, "munlockall() failed: %m");
3168 					}
3169 				}
3170 				cur_memlock = 0;
3171 # endif /* HAVE_MLOCKALL */
3172 			} else if (rlimit_av->value.i >= 0) {
3173 #if defined(RLIMIT_MEMLOCK)
3174 # if defined(HAVE_MLOCKALL)
3175 				if (cur_memlock != 1) {
3176 					if (-1 == mlockall(MCL_CURRENT|MCL_FUTURE)) {
3177 						msyslog(LOG_ERR, "mlockall() failed: %m");
3178 					}
3179 				}
3180 # endif /* HAVE_MLOCKALL */
3181 				ntp_rlimit(RLIMIT_MEMLOCK,
3182 					   (rlim_t)(rlimit_av->value.i * 1024 * 1024),
3183 					   1024 * 1024,
3184 					   "MB");
3185 				cur_memlock = 1;
3186 #else
3187 				/* STDERR as well would be fine... */
3188 				msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
3189 #endif /* RLIMIT_MEMLOCK */
3190 			} else {
3191 				msyslog(LOG_WARNING, "'rlimit memlock' value of %d is unexpected!", rlimit_av->value.i);
3192 			}
3193 			break;
3194 
3195 		case T_Stacksize:
3196 #if defined(RLIMIT_STACK)
3197 			ntp_rlimit(RLIMIT_STACK,
3198 				   (rlim_t)(rlimit_av->value.i * 4096),
3199 				   4096,
3200 				   "4k");
3201 #else
3202 			/* STDERR as well would be fine... */
3203 			msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
3204 #endif /* RLIMIT_STACK */
3205 			break;
3206 
3207 		case T_Filenum:
3208 #if defined(RLIMIT_NOFILE)
3209 			ntp_rlimit(RLIMIT_NOFILE,
3210 				  (rlim_t)(rlimit_av->value.i),
3211 				  1,
3212 				  "");
3213 #else
3214 			/* STDERR as well would be fine... */
3215 			msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
3216 #endif /* RLIMIT_NOFILE */
3217 			break;
3218 
3219 		}
3220 	}
3221 }
3222 
3223 
3224 static void
3225 config_tinker(
3226 	config_tree *ptree
3227 	)
3228 {
3229 	attr_val *	tinker;
3230 	int		item;
3231 
3232 	tinker = HEAD_PFIFO(ptree->tinker);
3233 	for (; tinker != NULL; tinker = tinker->link) {
3234 		switch (tinker->attr) {
3235 
3236 		default:
3237 			fatal_error("config_tinker: attr-token=%d", tinker->attr);
3238 
3239 		case T_Allan:
3240 			item = LOOP_ALLAN;
3241 			break;
3242 
3243 		case T_Dispersion:
3244 			item = LOOP_PHI;
3245 			break;
3246 
3247 		case T_Freq:
3248 			item = LOOP_FREQ;
3249 			break;
3250 
3251 		case T_Huffpuff:
3252 			item = LOOP_HUFFPUFF;
3253 			break;
3254 
3255 		case T_Panic:
3256 			item = LOOP_PANIC;
3257 			break;
3258 
3259 		case T_Step:
3260 			item = LOOP_MAX;
3261 			break;
3262 
3263 		case T_Stepback:
3264 			item = LOOP_MAX_BACK;
3265 			break;
3266 
3267 		case T_Stepfwd:
3268 			item = LOOP_MAX_FWD;
3269 			break;
3270 
3271 		case T_Stepout:
3272 			item = LOOP_MINSTEP;
3273 			break;
3274 
3275 		case T_Tick:
3276 			item = LOOP_TICK;
3277 			break;
3278 		}
3279 		loop_config(item, tinker->value.d);
3280 	}
3281 }
3282 
3283 
3284 #ifdef FREE_CFG_T
3285 static void
3286 free_config_rlimit(
3287 	config_tree *ptree
3288 	)
3289 {
3290 	FREE_ATTR_VAL_FIFO(ptree->rlimit);
3291 }
3292 
3293 static void
3294 free_config_tinker(
3295 	config_tree *ptree
3296 	)
3297 {
3298 	FREE_ATTR_VAL_FIFO(ptree->tinker);
3299 }
3300 #endif	/* FREE_CFG_T */
3301 
3302 
3303 /*
3304  * config_nic_rules - apply interface listen/ignore/drop items
3305  */
3306 #ifndef SIM
3307 static void
3308 config_nic_rules(
3309 	config_tree *ptree,
3310 	int/*BOOL*/ input_from_file
3311 	)
3312 {
3313 	nic_rule_node *	curr_node;
3314 	sockaddr_u	addr;
3315 	nic_rule_match	match_type;
3316 	nic_rule_action	action;
3317 	char *		if_name;
3318 	char *		pchSlash;
3319 	int		prefixlen;
3320 	int		addrbits;
3321 
3322 	curr_node = HEAD_PFIFO(ptree->nic_rules);
3323 
3324 	if (curr_node != NULL
3325 	    && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
3326 		msyslog(LOG_ERR,
3327 			"interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
3328 			(input_from_file) ? ", exiting" : "");
3329 		if (input_from_file)
3330 			exit(1);
3331 		else
3332 			return;
3333 	}
3334 
3335 	for (; curr_node != NULL; curr_node = curr_node->link) {
3336 		prefixlen = -1;
3337 		if_name = curr_node->if_name;
3338 		if (if_name != NULL)
3339 			if_name = estrdup(if_name);
3340 
3341 		switch (curr_node->match_class) {
3342 
3343 		default:
3344 			fatal_error("config_nic_rules: match-class-token=%d", curr_node->match_class);
3345 
3346 		case 0:
3347 			/*
3348 			 * 0 is out of range for valid token T_...
3349 			 * and in a nic_rules_node indicates the
3350 			 * interface descriptor is either a name or
3351 			 * address, stored in if_name in either case.
3352 			 */
3353 			INSIST(if_name != NULL);
3354 			pchSlash = strchr(if_name, '/');
3355 			if (pchSlash != NULL)
3356 				*pchSlash = '\0';
3357 			if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
3358 				match_type = MATCH_IFADDR;
3359 				if (pchSlash != NULL
3360 				    && 1 == sscanf(pchSlash + 1, "%d",
3361 					    &prefixlen)) {
3362 					addrbits = 8 *
3363 					    SIZEOF_INADDR(AF(&addr));
3364 					prefixlen = max(-1, prefixlen);
3365 					prefixlen = min(prefixlen,
3366 							addrbits);
3367 				}
3368 			} else {
3369 				match_type = MATCH_IFNAME;
3370 				if (pchSlash != NULL)
3371 					*pchSlash = '/';
3372 			}
3373 			break;
3374 
3375 		case T_All:
3376 			match_type = MATCH_ALL;
3377 			break;
3378 
3379 		case T_Ipv4:
3380 			match_type = MATCH_IPV4;
3381 			break;
3382 
3383 		case T_Ipv6:
3384 			match_type = MATCH_IPV6;
3385 			break;
3386 
3387 		case T_Wildcard:
3388 			match_type = MATCH_WILDCARD;
3389 			break;
3390 		}
3391 
3392 		switch (curr_node->action) {
3393 
3394 		default:
3395 			fatal_error("config_nic_rules: action-token=%d", curr_node->action);
3396 
3397 		case T_Listen:
3398 			action = ACTION_LISTEN;
3399 			break;
3400 
3401 		case T_Ignore:
3402 			action = ACTION_IGNORE;
3403 			break;
3404 
3405 		case T_Drop:
3406 			action = ACTION_DROP;
3407 			break;
3408 		}
3409 
3410 		add_nic_rule(match_type, if_name, prefixlen,
3411 			     action);
3412 		timer_interfacetimeout(current_time + 2);
3413 		if (if_name != NULL)
3414 			free(if_name);
3415 	}
3416 }
3417 #endif	/* !SIM */
3418 
3419 
3420 #ifdef FREE_CFG_T
3421 static void
3422 free_config_nic_rules(
3423 	config_tree *ptree
3424 	)
3425 {
3426 	nic_rule_node *curr_node;
3427 
3428 	if (ptree->nic_rules != NULL) {
3429 		for (;;) {
3430 			UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
3431 			if (NULL == curr_node)
3432 				break;
3433 			free(curr_node->if_name);
3434 			free(curr_node);
3435 		}
3436 		free(ptree->nic_rules);
3437 		ptree->nic_rules = NULL;
3438 	}
3439 }
3440 #endif	/* FREE_CFG_T */
3441 
3442 
3443 static void
3444 apply_enable_disable(
3445 	attr_val_fifo *	fifo,
3446 	int		enable
3447 	)
3448 {
3449 	attr_val *curr_tok_fifo;
3450 	int option;
3451 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3452 	bc_entry *pentry;
3453 #endif
3454 
3455 	for (curr_tok_fifo = HEAD_PFIFO(fifo);
3456 	     curr_tok_fifo != NULL;
3457 	     curr_tok_fifo = curr_tok_fifo->link) {
3458 
3459 		option = curr_tok_fifo->value.i;
3460 		switch (option) {
3461 
3462 		default:
3463 			msyslog(LOG_ERR,
3464 				"can not apply enable/disable token %d, unknown",
3465 				option);
3466 			break;
3467 
3468 		case T_Auth:
3469 			proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
3470 			break;
3471 
3472 		case T_Bclient:
3473 			proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
3474 			break;
3475 
3476 		case T_Calibrate:
3477 			proto_config(PROTO_CAL, enable, 0., NULL);
3478 			break;
3479 
3480 		case T_Kernel:
3481 			proto_config(PROTO_KERNEL, enable, 0., NULL);
3482 			break;
3483 
3484 		case T_Monitor:
3485 			proto_config(PROTO_MONITOR, enable, 0., NULL);
3486 			break;
3487 
3488 		case T_Mode7:
3489 			proto_config(PROTO_MODE7, enable, 0., NULL);
3490 			break;
3491 
3492 		case T_Ntp:
3493 			proto_config(PROTO_NTP, enable, 0., NULL);
3494 			break;
3495 
3496 		case T_PCEdigest:
3497 			proto_config(PROTO_PCEDIGEST, enable, 0., NULL);
3498 			break;
3499 
3500 		case T_Stats:
3501 			proto_config(PROTO_FILEGEN, enable, 0., NULL);
3502 			break;
3503 
3504 		case T_UEcrypto:
3505 			proto_config(PROTO_UECRYPTO, enable, 0., NULL);
3506 			break;
3507 
3508 		case T_UEcryptonak:
3509 			proto_config(PROTO_UECRYPTONAK, enable, 0., NULL);
3510 			break;
3511 
3512 		case T_UEdigest:
3513 			proto_config(PROTO_UEDIGEST, enable, 0., NULL);
3514 			break;
3515 
3516 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3517 		case T_Bc_bugXXXX:
3518 			pentry = bc_list;
3519 			while (pentry->token) {
3520 				if (pentry->token == option)
3521 					break;
3522 				pentry++;
3523 			}
3524 			if (!pentry->token) {
3525 				msyslog(LOG_ERR,
3526 					"compat token %d not in bc_list[]",
3527 					option);
3528 				continue;
3529 			}
3530 			pentry->enabled = enable;
3531 			break;
3532 #endif
3533 		}
3534 	}
3535 }
3536 
3537 
3538 static void
3539 config_system_opts(
3540 	config_tree *ptree
3541 	)
3542 {
3543 	apply_enable_disable(ptree->enable_opts, 1);
3544 	apply_enable_disable(ptree->disable_opts, 0);
3545 }
3546 
3547 
3548 #ifdef FREE_CFG_T
3549 static void
3550 free_config_system_opts(
3551 	config_tree *ptree
3552 	)
3553 {
3554 	FREE_ATTR_VAL_FIFO(ptree->enable_opts);
3555 	FREE_ATTR_VAL_FIFO(ptree->disable_opts);
3556 }
3557 #endif	/* FREE_CFG_T */
3558 
3559 
3560 static void
3561 config_logconfig(
3562 	config_tree *ptree
3563 	)
3564 {
3565 	attr_val *	my_lc;
3566 
3567 	my_lc = HEAD_PFIFO(ptree->logconfig);
3568 	for (; my_lc != NULL; my_lc = my_lc->link) {
3569 		switch (my_lc->attr) {
3570 
3571 		case '+':
3572 			ntp_syslogmask |= get_logmask(my_lc->value.s);
3573 			break;
3574 
3575 		case '-':
3576 			ntp_syslogmask &= ~get_logmask(my_lc->value.s);
3577 			break;
3578 
3579 		case '=':
3580 			ntp_syslogmask = get_logmask(my_lc->value.s);
3581 			break;
3582 		default:
3583 			fatal_error("config-logconfig: modifier='%c'", my_lc->attr);
3584 		}
3585 	}
3586 }
3587 
3588 
3589 #ifdef FREE_CFG_T
3590 static void
3591 free_config_logconfig(
3592 	config_tree *ptree
3593 	)
3594 {
3595 	FREE_ATTR_VAL_FIFO(ptree->logconfig);
3596 }
3597 #endif	/* FREE_CFG_T */
3598 
3599 
3600 #ifndef SIM
3601 static void
3602 config_phone(
3603 	config_tree *ptree
3604 	)
3605 {
3606 	size_t		i;
3607 	string_node *	sn;
3608 
3609 	i = 0;
3610 	sn = HEAD_PFIFO(ptree->phone);
3611 	for (; sn != NULL; sn = sn->link) {
3612 		/* need to leave array entry for NULL terminator */
3613 		if (i < COUNTOF(sys_phone) - 1) {
3614 			sys_phone[i++] = estrdup(sn->s);
3615 			sys_phone[i] = NULL;
3616 		} else {
3617 			msyslog(LOG_INFO,
3618 				"phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
3619 				(COUNTOF(sys_phone) - 1), sn->s);
3620 		}
3621 	}
3622 }
3623 
3624 static void
3625 config_mdnstries(
3626 	config_tree *ptree
3627 	)
3628 {
3629 #ifdef HAVE_DNSREGISTRATION
3630 	extern int mdnstries;
3631 	mdnstries = ptree->mdnstries;
3632 #endif  /* HAVE_DNSREGISTRATION */
3633 }
3634 #endif	/* !SIM */
3635 
3636 #ifdef FREE_CFG_T
3637 static void
3638 free_config_phone(
3639 	config_tree *ptree
3640 	)
3641 {
3642 	FREE_STRING_FIFO(ptree->phone);
3643 }
3644 #endif	/* FREE_CFG_T */
3645 
3646 
3647 #ifndef SIM
3648 static void
3649 config_setvar(
3650 	config_tree *ptree
3651 	)
3652 {
3653 	setvar_node *my_node;
3654 	size_t	varlen, vallen, octets;
3655 	char *	str;
3656 
3657 	str = NULL;
3658 	my_node = HEAD_PFIFO(ptree->setvar);
3659 	for (; my_node != NULL; my_node = my_node->link) {
3660 		varlen = strlen(my_node->var);
3661 		vallen = strlen(my_node->val);
3662 		octets = varlen + vallen + 1 + 1;
3663 		str = erealloc(str, octets);
3664 		snprintf(str, octets, "%s=%s", my_node->var,
3665 			 my_node->val);
3666 		set_sys_var(str, octets, (my_node->isdefault)
3667 						? DEF
3668 						: 0);
3669 	}
3670 	if (str != NULL)
3671 		free(str);
3672 }
3673 #endif	/* !SIM */
3674 
3675 
3676 #ifdef FREE_CFG_T
3677 static void
3678 free_config_setvar(
3679 	config_tree *ptree
3680 	)
3681 {
3682 	FREE_SETVAR_FIFO(ptree->setvar);
3683 }
3684 #endif	/* FREE_CFG_T */
3685 
3686 
3687 #ifndef SIM
3688 static void
3689 config_ttl(
3690 	config_tree *ptree
3691 	)
3692 {
3693 	size_t i = 0;
3694 	int_node *curr_ttl;
3695 
3696 	/* [Bug 3465] There is a built-in default for the TTLs. We must
3697 	 * overwrite 'sys_ttlmax' if we change that preset, and leave it
3698 	 * alone otherwise!
3699 	 */
3700 	curr_ttl = HEAD_PFIFO(ptree->ttl);
3701 	for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
3702 		if (i < COUNTOF(sys_ttl))
3703 			sys_ttl[i++] = (u_char)curr_ttl->i;
3704 		else
3705 			msyslog(LOG_INFO,
3706 				"ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
3707 				COUNTOF(sys_ttl), curr_ttl->i);
3708 	}
3709 	if (0 != i) /* anything written back at all? */
3710 		sys_ttlmax = i - 1;
3711 }
3712 #endif	/* !SIM */
3713 
3714 
3715 #ifdef FREE_CFG_T
3716 static void
3717 free_config_ttl(
3718 	config_tree *ptree
3719 	)
3720 {
3721 	FREE_INT_FIFO(ptree->ttl);
3722 }
3723 #endif	/* FREE_CFG_T */
3724 
3725 
3726 #ifndef SIM
3727 static void
3728 config_trap(
3729 	config_tree *ptree
3730 	)
3731 {
3732 	addr_opts_node *curr_trap;
3733 	attr_val *curr_opt;
3734 	sockaddr_u addr_sock;
3735 	sockaddr_u peeraddr;
3736 	struct interface *localaddr;
3737 	struct addrinfo hints;
3738 	char port_text[8];
3739 	settrap_parms *pstp;
3740 	u_short port;
3741 	int err_flag;
3742 	int rc;
3743 
3744 	/* silence warning about addr_sock potentially uninitialized */
3745 	AF(&addr_sock) = AF_UNSPEC;
3746 
3747 	curr_trap = HEAD_PFIFO(ptree->trap);
3748 	for (; curr_trap != NULL; curr_trap = curr_trap->link) {
3749 		err_flag = 0;
3750 		port = 0;
3751 		localaddr = NULL;
3752 
3753 		curr_opt = HEAD_PFIFO(curr_trap->options);
3754 		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3755 			if (T_Port == curr_opt->attr) {
3756 				if (curr_opt->value.i < 1
3757 				    || curr_opt->value.i > USHRT_MAX) {
3758 					msyslog(LOG_ERR,
3759 						"invalid port number "
3760 						"%d, trap ignored",
3761 						curr_opt->value.i);
3762 					err_flag = 1;
3763 				}
3764 				port = (u_short)curr_opt->value.i;
3765 			}
3766 			else if (T_Interface == curr_opt->attr) {
3767 				/* Resolve the interface address */
3768 				ZERO_SOCK(&addr_sock);
3769 				if (getnetnum(curr_opt->value.s,
3770 					      &addr_sock, 1, t_UNK) != 1) {
3771 					err_flag = 1;
3772 					break;
3773 				}
3774 
3775 				localaddr = findinterface(&addr_sock);
3776 
3777 				if (NULL == localaddr) {
3778 					msyslog(LOG_ERR,
3779 						"can't find interface with address %s",
3780 						stoa(&addr_sock));
3781 					err_flag = 1;
3782 				}
3783 			}
3784 		}
3785 
3786 		/* Now process the trap for the specified interface
3787 		 * and port number
3788 		 */
3789 		if (!err_flag) {
3790 			if (!port)
3791 				port = TRAPPORT;
3792 			ZERO_SOCK(&peeraddr);
3793 			rc = getnetnum(curr_trap->addr->address,
3794 				       &peeraddr, 1, t_UNK);
3795 			if (1 != rc) {
3796 #ifndef WORKER
3797 				msyslog(LOG_ERR,
3798 					"trap: unable to use IP address %s.",
3799 					curr_trap->addr->address);
3800 #else	/* WORKER follows */
3801 				/*
3802 				 * save context and hand it off
3803 				 * for name resolution.
3804 				 */
3805 				ZERO(hints);
3806 				hints.ai_protocol = IPPROTO_UDP;
3807 				hints.ai_socktype = SOCK_DGRAM;
3808 				snprintf(port_text, sizeof(port_text),
3809 					 "%u", port);
3810 				hints.ai_flags = Z_AI_NUMERICSERV;
3811 				pstp = emalloc_zero(sizeof(*pstp));
3812 				if (localaddr != NULL) {
3813 					hints.ai_family = localaddr->family;
3814 					pstp->ifaddr_nonnull = 1;
3815 					memcpy(&pstp->ifaddr,
3816 					       &localaddr->sin,
3817 					       sizeof(pstp->ifaddr));
3818 				}
3819 				rc = getaddrinfo_sometime(
3820 					curr_trap->addr->address,
3821 					port_text, &hints,
3822 					INITIAL_DNS_RETRY,
3823 					&trap_name_resolved,
3824 					pstp);
3825 				if (!rc)
3826 					msyslog(LOG_ERR,
3827 						"config_trap: getaddrinfo_sometime(%s,%s): %m",
3828 						curr_trap->addr->address,
3829 						port_text);
3830 #endif	/* WORKER */
3831 				continue;
3832 			}
3833 			/* port is at same location for v4 and v6 */
3834 			SET_PORT(&peeraddr, port);
3835 
3836 			if (NULL == localaddr)
3837 				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3838 			else
3839 				AF(&peeraddr) = AF(&addr_sock);
3840 
3841 			if (!ctlsettrap(&peeraddr, localaddr, 0,
3842 					NTP_VERSION))
3843 				msyslog(LOG_ERR,
3844 					"set trap %s -> %s failed.",
3845 					latoa(localaddr),
3846 					stoa(&peeraddr));
3847 		}
3848 	}
3849 }
3850 
3851 
3852 /*
3853  * trap_name_resolved()
3854  *
3855  * Callback invoked when config_trap()'s DNS lookup completes.
3856  */
3857 # ifdef WORKER
3858 static void
3859 trap_name_resolved(
3860 	int			rescode,
3861 	int			gai_errno,
3862 	void *			context,
3863 	const char *		name,
3864 	const char *		service,
3865 	const struct addrinfo *	hints,
3866 	const struct addrinfo *	res
3867 	)
3868 {
3869 	settrap_parms *pstp;
3870 	struct interface *localaddr;
3871 	sockaddr_u peeraddr;
3872 
3873 	(void)gai_errno;
3874 	(void)service;
3875 	(void)hints;
3876 	pstp = context;
3877 	if (rescode) {
3878 		msyslog(LOG_ERR,
3879 			"giving up resolving trap host %s: %s (%d)",
3880 			name, gai_strerror(rescode), rescode);
3881 		free(pstp);
3882 		return;
3883 	}
3884 	INSIST(sizeof(peeraddr) >= res->ai_addrlen);
3885 	ZERO(peeraddr);
3886 	memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3887 	localaddr = NULL;
3888 	if (pstp->ifaddr_nonnull)
3889 		localaddr = findinterface(&pstp->ifaddr);
3890 	if (NULL == localaddr)
3891 		localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3892 	if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
3893 		msyslog(LOG_ERR, "set trap %s -> %s failed.",
3894 			latoa(localaddr), stoa(&peeraddr));
3895 	free(pstp);
3896 }
3897 # endif	/* WORKER */
3898 #endif	/* !SIM */
3899 
3900 
3901 #ifdef FREE_CFG_T
3902 static void
3903 free_config_trap(
3904 	config_tree *ptree
3905 	)
3906 {
3907 	FREE_ADDR_OPTS_FIFO(ptree->trap);
3908 }
3909 #endif	/* FREE_CFG_T */
3910 
3911 
3912 #ifndef SIM
3913 static void
3914 config_fudge(
3915 	config_tree *ptree
3916 	)
3917 {
3918 	addr_opts_node *curr_fudge;
3919 	attr_val *curr_opt;
3920 	sockaddr_u addr_sock;
3921 	address_node *addr_node;
3922 	struct refclockstat clock_stat;
3923 	char refid_str[5];
3924 	int err_flag;
3925 
3926 	curr_fudge = HEAD_PFIFO(ptree->fudge);
3927 	for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
3928 		err_flag = 0;
3929 
3930 		/* Get the reference clock address and
3931 		 * ensure that it is sane
3932 		 */
3933 		addr_node = curr_fudge->addr;
3934 		ZERO_SOCK(&addr_sock);
3935 		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
3936 		    != 1) {
3937 			err_flag = 1;
3938 			msyslog(LOG_ERR,
3939 				"unrecognized fudge reference clock address %s, line ignored",
3940 				addr_node->address);
3941 		} else if (!ISREFCLOCKADR(&addr_sock)) {
3942 			err_flag = 1;
3943 			msyslog(LOG_ERR,
3944 				"inappropriate address %s for the fudge command, line ignored",
3945 				stoa(&addr_sock));
3946 		}
3947 
3948 		/* Parse all the options to the fudge command */
3949 		ZERO(clock_stat);
3950 		/* some things are not necessarily cleared by ZERO...*/
3951 		clock_stat.fudgeminjitter = 0.0;
3952 		clock_stat.fudgetime1     = 0.0;
3953 		clock_stat.fudgetime2     = 0.0;
3954 		clock_stat.p_lastcode     = NULL;
3955 		clock_stat.clockdesc      = NULL;
3956 		clock_stat.kv_list        = NULL;
3957 		curr_opt = HEAD_PFIFO(curr_fudge->options);
3958 		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3959 			switch (curr_opt->attr) {
3960 
3961 			case T_Time1:
3962 				clock_stat.haveflags |= CLK_HAVETIME1;
3963 				clock_stat.fudgetime1 = curr_opt->value.d;
3964 				break;
3965 
3966 			case T_Time2:
3967 				clock_stat.haveflags |= CLK_HAVETIME2;
3968 				clock_stat.fudgetime2 = curr_opt->value.d;
3969 				break;
3970 
3971 			case T_Stratum:
3972 				clock_stat.haveflags |= CLK_HAVEVAL1;
3973 				clock_stat.fudgeval1 = curr_opt->value.i;
3974 				break;
3975 
3976 			case T_Refid:
3977 				clock_stat.haveflags |= CLK_HAVEVAL2;
3978 				/* strncpy() does exactly what we want here: */
3979 				strncpy(refid_str, curr_opt->value.s,
3980 					sizeof refid_str - 1);
3981 				memcpy(&clock_stat.fudgeval2, refid_str,
3982 				       sizeof clock_stat.fudgeval2);
3983 				break;
3984 
3985 			case T_Flag1:
3986 				clock_stat.haveflags |= CLK_HAVEFLAG1;
3987 				if (curr_opt->value.i)
3988 					clock_stat.flags |= CLK_FLAG1;
3989 				else
3990 					clock_stat.flags &= ~CLK_FLAG1;
3991 				break;
3992 
3993 			case T_Flag2:
3994 				clock_stat.haveflags |= CLK_HAVEFLAG2;
3995 				if (curr_opt->value.i)
3996 					clock_stat.flags |= CLK_FLAG2;
3997 				else
3998 					clock_stat.flags &= ~CLK_FLAG2;
3999 				break;
4000 
4001 			case T_Flag3:
4002 				clock_stat.haveflags |= CLK_HAVEFLAG3;
4003 				if (curr_opt->value.i)
4004 					clock_stat.flags |= CLK_FLAG3;
4005 				else
4006 					clock_stat.flags &= ~CLK_FLAG3;
4007 				break;
4008 
4009 			case T_Flag4:
4010 				clock_stat.haveflags |= CLK_HAVEFLAG4;
4011 				if (curr_opt->value.i)
4012 					clock_stat.flags |= CLK_FLAG4;
4013 				else
4014 					clock_stat.flags &= ~CLK_FLAG4;
4015 				break;
4016 
4017 			case T_Minjitter:
4018 				clock_stat.haveflags |= CLK_HAVEMINJIT;
4019 				clock_stat.fudgeminjitter = curr_opt->value.d;
4020 				break;
4021 
4022 			default:
4023 				msyslog(LOG_ERR,
4024 					"Unexpected fudge flag %s (%d) for %s",
4025 					token_name(curr_opt->attr),
4026 					curr_opt->attr, addr_node->address);
4027 				exit(curr_opt->attr ? curr_opt->attr : 1);
4028 			}
4029 		}
4030 # ifdef REFCLOCK
4031 		if (!err_flag)
4032 			refclock_control(&addr_sock, &clock_stat, NULL);
4033 # endif
4034 	}
4035 }
4036 #endif	/* !SIM */
4037 
4038 #ifndef SIM
4039 static void
4040 config_device(
4041 	config_tree *ptree
4042 	)
4043 {
4044 	addr_opts_node *curr_device;
4045 	attr_val *curr_opt;
4046 	sockaddr_u addr_sock;
4047 	address_node *addr_node;
4048 	char *ttyName, *ppsName;
4049 
4050 	curr_device = HEAD_PFIFO(ptree->device);
4051 	for (; curr_device != NULL; curr_device = curr_device->link) {
4052 		/* Get the reference clock address and
4053 		 * ensure that it is sane
4054 		 */
4055 		addr_node = curr_device->addr;
4056 		ZERO_SOCK(&addr_sock);
4057 		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
4058 		    != 1) {
4059 			msyslog(LOG_ERR,
4060 				"unrecognized device reference clock address %s, line ignored",
4061 				addr_node->address);
4062 			continue;
4063 		}
4064 		if (!ISREFCLOCKADR(&addr_sock)) {
4065 			msyslog(LOG_ERR,
4066 				"inappropriate address %s for the device command, line ignored",
4067 				stoa(&addr_sock));
4068 			continue;
4069 		}
4070 
4071 		ppsName = ttyName = NULL;
4072 		curr_opt = HEAD_PFIFO(curr_device->options);
4073 		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
4074 			switch (curr_opt->attr) {
4075 
4076 			case T_TimeData:
4077 				ttyName = curr_opt->value.s;
4078 				break;
4079 
4080 			case T_PpsData:
4081 				ppsName = curr_opt->value.s;
4082 				break;
4083 
4084 			default:
4085 				msyslog(LOG_ERR,
4086 					"Unexpected device spec %s (%d) for %s",
4087 					token_name(curr_opt->attr),
4088 					curr_opt->attr, addr_node->address);
4089 				exit(curr_opt->attr ? curr_opt->attr : 1);
4090 			}
4091 		}
4092 # ifdef REFCLOCK
4093 		clockdev_update(&addr_sock, ttyName, ppsName);
4094 # endif
4095 	}
4096 }
4097 #endif	/* !SIM */
4098 
4099 
4100 #ifdef FREE_CFG_T
4101 static void
4102 free_config_fudge(
4103 	config_tree *ptree
4104 	)
4105 {
4106 	FREE_ADDR_OPTS_FIFO(ptree->fudge);
4107 }
4108 
4109 static void
4110 free_config_device(
4111 	config_tree *ptree
4112 	)
4113 {
4114 	FREE_ADDR_OPTS_FIFO(ptree->device);
4115 }
4116 #endif	/* FREE_CFG_T */
4117 
4118 
4119 static void
4120 config_vars(
4121 	config_tree *ptree
4122 	)
4123 {
4124 	attr_val *curr_var;
4125 	int len;
4126 
4127 	curr_var = HEAD_PFIFO(ptree->vars);
4128 	for (; curr_var != NULL; curr_var = curr_var->link) {
4129 		/* Determine which variable to set and set it */
4130 		switch (curr_var->attr) {
4131 
4132 		case T_Broadcastdelay:
4133 			proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
4134 			break;
4135 
4136 		case T_Tick:
4137 			loop_config(LOOP_TICK, curr_var->value.d);
4138 			break;
4139 
4140 		case T_Driftfile:
4141 			if ('\0' == curr_var->value.s[0])
4142 				msyslog(LOG_INFO, "config: driftfile disabled");
4143 			stats_config(STATS_FREQ_FILE, curr_var->value.s, 0);
4144 			break;
4145 
4146 		case T_Dscp:
4147 			/* DSCP is in the upper 6 bits of the IP TOS/DS field */
4148 			qos = curr_var->value.i << 2;
4149 			break;
4150 
4151 		case T_Ident:
4152 			sys_ident = curr_var->value.s;
4153 			break;
4154 
4155 		case T_WanderThreshold:		/* FALLTHROUGH */
4156 		case T_Nonvolatile:
4157 			wander_threshold = curr_var->value.d;
4158 			break;
4159 
4160 		case T_Leapfile:
4161 		    stats_config(STATS_LEAP_FILE, curr_var->value.s, curr_var->flag);
4162 			break;
4163 
4164 #ifdef LEAP_SMEAR
4165 		case T_Leapsmearinterval:
4166 			leap_smear_intv = curr_var->value.i;
4167 			msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
4168 			break;
4169 #endif
4170 
4171 		case T_Pidfile:
4172 		    stats_config(STATS_PID_FILE, curr_var->value.s, 0);
4173 			break;
4174 
4175 		case T_Logfile:
4176 			if (-1 == change_logfile(curr_var->value.s, TRUE))
4177 				msyslog(LOG_ERR,
4178 					"Cannot open logfile %s: %m",
4179 					curr_var->value.s);
4180 			break;
4181 
4182 		case T_Saveconfigdir:
4183 			if (saveconfigdir != NULL)
4184 				free(saveconfigdir);
4185 			len = strlen(curr_var->value.s);
4186 			if (0 == len) {
4187 				saveconfigdir = NULL;
4188 			} else if (DIR_SEP != curr_var->value.s[len - 1]
4189 #ifdef SYS_WINNT	/* slash is also a dir. sep. on Windows */
4190 				   && '/' != curr_var->value.s[len - 1]
4191 #endif
4192 				 ) {
4193 					len++;
4194 					saveconfigdir = emalloc(len + 1);
4195 					snprintf(saveconfigdir, len + 1,
4196 						 "%s%c",
4197 						 curr_var->value.s,
4198 						 DIR_SEP);
4199 			} else {
4200 					saveconfigdir = estrdup(
4201 					    curr_var->value.s);
4202 			}
4203 			break;
4204 
4205 		case T_Automax:
4206 #ifdef AUTOKEY
4207 			if (curr_var->value.i > 2 && curr_var->value.i < 32)
4208 				sys_automax = (u_char)curr_var->value.i;
4209 			else
4210 				msyslog(LOG_ERR,
4211 					"'automax' value %d ignored",
4212 					curr_var->value.i);
4213 #endif
4214 			break;
4215 
4216 		default:
4217 			msyslog(LOG_ERR,
4218 				"config_vars(): unexpected token %d",
4219 				curr_var->attr);
4220 		}
4221 	}
4222 }
4223 
4224 
4225 #ifdef FREE_CFG_T
4226 static void
4227 free_config_vars(
4228 	config_tree *ptree
4229 	)
4230 {
4231 	FREE_ATTR_VAL_FIFO(ptree->vars);
4232 }
4233 #endif	/* FREE_CFG_T */
4234 
4235 
4236 #ifndef SIM
4237 /* Define a function to check if a resolved address is sane.
4238  * If yes, return 1, else return 0;
4239  */
4240 static int
4241 is_sane_resolved_address(
4242 	sockaddr_u *	peeraddr,
4243 	int		hmode
4244 	)
4245 {
4246 	if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
4247 		msyslog(LOG_ERR,
4248 			"attempt to configure invalid address %s",
4249 			stoa(peeraddr));
4250 		return 0;
4251 	}
4252 	/*
4253 	 * Shouldn't be able to specify:
4254 	 * - multicast address for server/peer!
4255 	 * - unicast address for manycastclient!
4256 	 */
4257 	if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
4258 	    && IS_MCAST(peeraddr)) {
4259 		msyslog(LOG_ERR,
4260 			"attempt to configure invalid address %s",
4261 			stoa(peeraddr));
4262 		return 0;
4263 	}
4264 	if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
4265 		msyslog(LOG_ERR,
4266 			"attempt to configure invalid address %s",
4267 			stoa(peeraddr));
4268 		return 0;
4269 	}
4270 
4271 	if (IS_IPV6(peeraddr) && !ipv6_works)
4272 		return 0;
4273 
4274 	/* Ok, all tests succeeded, now we can return 1 */
4275 	return 1;
4276 }
4277 
4278 
4279 static u_char
4280 get_correct_host_mode(
4281 	int token
4282 	)
4283 {
4284 	switch (token) {
4285 
4286 	case T_Server:
4287 	case T_Pool:
4288 	case T_Manycastclient:
4289 		return MODE_CLIENT;
4290 
4291 	case T_Peer:
4292 		return MODE_ACTIVE;
4293 
4294 	case T_Broadcast:
4295 		return MODE_BROADCAST;
4296 
4297 	default:
4298 		return 0;
4299 	}
4300 }
4301 
4302 
4303 /*
4304  * peerflag_bits()	get config_peers() peerflags value from a
4305  *			peer_node's queue of flag attr_val entries.
4306  */
4307 static int
4308 peerflag_bits(
4309 	peer_node *pn
4310 	)
4311 {
4312 	int peerflags;
4313 	attr_val *option;
4314 	int	hmode;
4315 
4316 	DEBUG_INSIST(pn);
4317 	/* translate peerflags options to bits */
4318 	peerflags = 0;
4319 	hmode = pn->host_mode;
4320 	option = HEAD_PFIFO(pn->peerflags);
4321 	for (; option != NULL; option = option->link) {
4322 		switch (option->value.i) {
4323 
4324 		default:
4325 			fatal_error("peerflag_bits: option-token=%d", option->value.i);
4326 
4327 		case T_Autokey:
4328 			peerflags |= FLAG_SKEY;
4329 			break;
4330 
4331 		case T_Burst:
4332 			peerflags |= FLAG_BURST;
4333 			break;
4334 
4335 		case T_Iburst:
4336 			peerflags |= FLAG_IBURST;
4337 			break;
4338 
4339 		case T_Noselect:
4340 			peerflags |= FLAG_NOSELECT;
4341 			break;
4342 
4343 		case T_Preempt:
4344 			peerflags |= FLAG_PREEMPT;
4345 			break;
4346 
4347 		case T_Prefer:
4348 			peerflags |= FLAG_PREFER;
4349 			break;
4350 
4351 		case T_True:
4352 			peerflags |= FLAG_TRUE;
4353 			break;
4354 
4355 		case T_Xleave:
4356 			peerflags |= FLAG_XLEAVE;
4357 			break;
4358 
4359 		case T_Xmtnonce:
4360 			if (   MODE_CLIENT == hmode ) {
4361 				peerflags |= FLAG_LOOPNONCE;
4362 			}
4363 			break;
4364 		}
4365 	}
4366 
4367 	return peerflags;
4368 }
4369 
4370 
4371 static void
4372 config_peers(
4373 	config_tree *ptree
4374 	)
4375 {
4376 	sockaddr_u		peeraddr;
4377 	struct addrinfo		hints;
4378 	peer_node *		curr_peer;
4379 	peer_resolved_ctx *	ctx;
4380 	u_char			hmode;
4381 
4382 	/* add servers named on the command line with iburst implied */
4383 	for (;
4384 	     cmdline_server_count > 0;
4385 	     cmdline_server_count--, cmdline_servers++) {
4386 
4387 		ZERO_SOCK(&peeraddr);
4388 		/*
4389 		 * If we have a numeric address, we can safely
4390 		 * proceed in the mainline with it.  Otherwise, hand
4391 		 * the hostname off to the blocking child.
4392 		 *
4393 		 * Note that if we're told to add the peer here, we
4394 		 * do that regardless of ippeerlimit.
4395 		 */
4396 		if (is_ip_address(*cmdline_servers, AF_UNSPEC,
4397 				  &peeraddr)) {
4398 
4399 			SET_PORT(&peeraddr, NTP_PORT);
4400 			if (is_sane_resolved_address(&peeraddr,
4401 						     T_Server))
4402 				peer_config(
4403 					&peeraddr,
4404 					NULL,
4405 					NULL,
4406 					-1,
4407 					MODE_CLIENT,
4408 					NTP_VERSION,
4409 					0,
4410 					0,
4411 					FLAG_IBURST,
4412 					0,
4413 					0,
4414 					NULL);
4415 		} else {
4416 			/* we have a hostname to resolve */
4417 # ifdef WORKER
4418 			ctx = emalloc_zero(sizeof(*ctx));
4419 			ctx->family = AF_UNSPEC;
4420 			ctx->host_mode = T_Server;
4421 			ctx->hmode = MODE_CLIENT;
4422 			ctx->version = NTP_VERSION;
4423 			ctx->flags = FLAG_IBURST;
4424 			ctx->was_initializing = initializing;
4425 
4426 			ZERO(hints);
4427 			hints.ai_family = (u_short)ctx->family;
4428 			hints.ai_socktype = SOCK_DGRAM;
4429 			hints.ai_protocol = IPPROTO_UDP;
4430 
4431 			getaddrinfo_sometime_ex(*cmdline_servers,
4432 					     "ntp", &hints,
4433 					     INITIAL_DNS_RETRY,
4434 					     &peer_name_resolved,
4435 					     (void *)ctx, DNSFLAGS);
4436 # else	/* !WORKER follows */
4437 			msyslog(LOG_ERR,
4438 				"hostname %s can not be used, please use IP address instead.",
4439 				curr_peer->addr->address);
4440 # endif
4441 		}
4442 	}
4443 
4444 	/* add associations from the configuration file */
4445 	curr_peer = HEAD_PFIFO(ptree->peers);
4446 	for (; curr_peer != NULL; curr_peer = curr_peer->link) {
4447 		ZERO_SOCK(&peeraddr);
4448 		/* Find the correct host-mode */
4449 		hmode = get_correct_host_mode(curr_peer->host_mode);
4450 		INSIST(hmode != 0);
4451 
4452 		if (T_Pool == curr_peer->host_mode) {
4453 			AF(&peeraddr) = curr_peer->addr->type;
4454 			peer_config(
4455 				&peeraddr,
4456 				curr_peer->addr->address,
4457 				NULL,
4458 				-1,
4459 				hmode,
4460 				curr_peer->peerversion,
4461 				curr_peer->minpoll,
4462 				curr_peer->maxpoll,
4463 				peerflag_bits(curr_peer),
4464 				curr_peer->ttl,
4465 				curr_peer->peerkey,
4466 				curr_peer->group);
4467 		/*
4468 		 * If we have a numeric address, we can safely
4469 		 * proceed in the mainline with it.  Otherwise, hand
4470 		 * the hostname off to the blocking child.
4471 		 */
4472 		} else if (is_ip_address(curr_peer->addr->address,
4473 				  curr_peer->addr->type, &peeraddr)) {
4474 
4475 			SET_PORT(&peeraddr, NTP_PORT);
4476 			if (is_sane_resolved_address(&peeraddr,
4477 			    curr_peer->host_mode))
4478 				peer_config(
4479 					&peeraddr,
4480 					NULL,
4481 					NULL,
4482 					-1,
4483 					hmode,
4484 					curr_peer->peerversion,
4485 					curr_peer->minpoll,
4486 					curr_peer->maxpoll,
4487 					peerflag_bits(curr_peer),
4488 					curr_peer->ttl,
4489 					curr_peer->peerkey,
4490 					curr_peer->group);
4491 		} else {
4492 			/* we have a hostname to resolve */
4493 # ifdef WORKER
4494 			ctx = emalloc_zero(sizeof(*ctx));
4495 			ctx->family = curr_peer->addr->type;
4496 			ctx->host_mode = curr_peer->host_mode;
4497 			ctx->hmode = hmode;
4498 			ctx->version = curr_peer->peerversion;
4499 			ctx->minpoll = curr_peer->minpoll;
4500 			ctx->maxpoll = curr_peer->maxpoll;
4501 			ctx->flags = peerflag_bits(curr_peer);
4502 			ctx->ttl = curr_peer->ttl;
4503 			ctx->keyid = curr_peer->peerkey;
4504 			ctx->group = curr_peer->group;
4505 			ctx->was_initializing = initializing;
4506 
4507 			ZERO(hints);
4508 			hints.ai_family = ctx->family;
4509 			hints.ai_socktype = SOCK_DGRAM;
4510 			hints.ai_protocol = IPPROTO_UDP;
4511 
4512 			getaddrinfo_sometime_ex(curr_peer->addr->address,
4513 					     "ntp", &hints,
4514 					     INITIAL_DNS_RETRY,
4515 					     &peer_name_resolved, ctx,
4516 					     DNSFLAGS);
4517 # else	/* !WORKER follows */
4518 			msyslog(LOG_ERR,
4519 				"hostname %s can not be used, please use IP address instead.",
4520 				curr_peer->addr->address);
4521 # endif
4522 		}
4523 	}
4524 }
4525 
4526 
4527 /*
4528  * peer_name_resolved()
4529  *
4530  * Callback invoked when config_peers()'s DNS lookup completes.
4531  */
4532 #ifdef WORKER
4533 static void
4534 peer_name_resolved(
4535 	int			rescode,
4536 	int			gai_errno,
4537 	void *			context,
4538 	const char *		name,
4539 	const char *		service,
4540 	const struct addrinfo *	hints,
4541 	const struct addrinfo *	res
4542 	)
4543 {
4544 	sockaddr_u		peeraddr;
4545 	peer_resolved_ctx *	ctx;
4546 	u_short			af;
4547 	const char *		fam_spec;
4548 
4549 	(void)gai_errno;
4550 	(void)service;
4551 	(void)hints;
4552 	ctx = context;
4553 
4554 	DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
4555 
4556 	if (rescode) {
4557 		free(ctx);
4558 		msyslog(LOG_ERR,
4559 			"giving up resolving host %s: %s (%d)",
4560 			name, gai_strerror(rescode), rescode);
4561 		return;
4562 	}
4563 
4564 	/* Loop to configure a single association */
4565 	for (; res != NULL; res = res->ai_next) {
4566 		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4567 		if (is_sane_resolved_address(&peeraddr,
4568 					     ctx->host_mode)) {
4569 			NLOG(NLOG_SYSINFO) {
4570 				af = ctx->family;
4571 				fam_spec = (AF_INET6 == af)
4572 					       ? "(AAAA) "
4573 					       : (AF_INET == af)
4574 						     ? "(A) "
4575 						     : "";
4576 				msyslog(LOG_INFO, "DNS %s %s-> %s",
4577 					name, fam_spec,
4578 					stoa(&peeraddr));
4579 			}
4580 
4581 			/*
4582 			 * peer_clear needs to know if this association was specified
4583 			 * in the startup configuration file to set the next poll time.
4584 			 */
4585 			if (ctx->was_initializing) {
4586 				INSIST(!initializing);
4587 				initializing = TRUE;
4588 			}
4589 
4590 			peer_config(
4591 				&peeraddr,
4592 				NULL,
4593 				NULL,
4594 				-1,
4595 				ctx->hmode,
4596 				ctx->version,
4597 				ctx->minpoll,
4598 				ctx->maxpoll,
4599 				ctx->flags,
4600 				ctx->ttl,
4601 				ctx->keyid,
4602 				ctx->group);
4603 
4604 			if (ctx->was_initializing) {
4605 				initializing = FALSE;
4606 			}
4607 
4608 			break;
4609 		}
4610 	}
4611 	free(ctx);
4612 }
4613 #endif	/* WORKER */
4614 
4615 
4616 #ifdef FREE_CFG_T
4617 static void
4618 free_config_peers(
4619 	config_tree *ptree
4620 	)
4621 {
4622 	peer_node *curr_peer;
4623 
4624 	if (ptree->peers != NULL) {
4625 		for (;;) {
4626 			UNLINK_FIFO(curr_peer, *ptree->peers, link);
4627 			if (NULL == curr_peer)
4628 				break;
4629 			destroy_address_node(curr_peer->addr);
4630 			destroy_attr_val_fifo(curr_peer->peerflags);
4631 			free(curr_peer);
4632 		}
4633 		free(ptree->peers);
4634 		ptree->peers = NULL;
4635 	}
4636 }
4637 #endif	/* FREE_CFG_T */
4638 
4639 
4640 static void
4641 config_unpeers(
4642 	config_tree *ptree
4643 	)
4644 {
4645 	sockaddr_u		peeraddr;
4646 	struct addrinfo		hints;
4647 	unpeer_node *		curr_unpeer;
4648 	struct peer *		p;
4649 	const char *		name;
4650 	int			rc;
4651 
4652 	curr_unpeer = HEAD_PFIFO(ptree->unpeers);
4653 	for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
4654 		/*
4655 		 * If we have no address attached, assume we have to
4656 		 * unpeer by AssocID.
4657 		 */
4658 		if (!curr_unpeer->addr) {
4659 			p = findpeerbyassoc(curr_unpeer->assocID);
4660 			if (p != NULL) {
4661 				msyslog(LOG_NOTICE, "unpeered %s",
4662 					stoa(&p->srcadr));
4663 				peer_clear(p, "GONE");
4664 				unpeer(p);
4665 			}
4666 			continue;
4667 		}
4668 
4669 		ZERO(peeraddr);
4670 		AF(&peeraddr) = curr_unpeer->addr->type;
4671 		name = curr_unpeer->addr->address;
4672 		rc = getnetnum(name, &peeraddr, 0, t_UNK);
4673 		/* Do we have a numeric address? */
4674 		if (rc > 0) {
4675 			DPRINTF(1, ("unpeer: searching for %s\n",
4676 				    stoa(&peeraddr)));
4677 			p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4678 			if (p != NULL) {
4679 				msyslog(LOG_NOTICE, "unpeered %s",
4680 					stoa(&peeraddr));
4681 				peer_clear(p, "GONE");
4682 				unpeer(p);
4683 			}
4684 			continue;
4685 		}
4686 		/*
4687 		 * It's not a numeric IP address, it's a hostname.
4688 		 * Check for associations with a matching hostname.
4689 		 */
4690 		for (p = peer_list; p != NULL; p = p->p_link)
4691 			if (p->hostname != NULL)
4692 				if (!strcasecmp(p->hostname, name))
4693 					break;
4694 		if (p != NULL) {
4695 			msyslog(LOG_NOTICE, "unpeered %s", name);
4696 			peer_clear(p, "GONE");
4697 			unpeer(p);
4698 		}
4699 		/* Resolve the hostname to address(es). */
4700 # ifdef WORKER
4701 		ZERO(hints);
4702 		hints.ai_family = curr_unpeer->addr->type;
4703 		hints.ai_socktype = SOCK_DGRAM;
4704 		hints.ai_protocol = IPPROTO_UDP;
4705 		getaddrinfo_sometime(name, "ntp", &hints,
4706 				     INITIAL_DNS_RETRY,
4707 				     &unpeer_name_resolved, NULL);
4708 # else	/* !WORKER follows */
4709 		msyslog(LOG_ERR,
4710 			"hostname %s can not be used, please use IP address instead.",
4711 			name);
4712 # endif
4713 	}
4714 }
4715 
4716 
4717 /*
4718  * unpeer_name_resolved()
4719  *
4720  * Callback invoked when config_unpeers()'s DNS lookup completes.
4721  */
4722 #ifdef WORKER
4723 static void
4724 unpeer_name_resolved(
4725 	int			rescode,
4726 	int			gai_errno,
4727 	void *			context,
4728 	const char *		name,
4729 	const char *		service,
4730 	const struct addrinfo *	hints,
4731 	const struct addrinfo *	res
4732 	)
4733 {
4734 	sockaddr_u	peeraddr;
4735 	struct peer *	peer;
4736 	u_short		af;
4737 	const char *	fam_spec;
4738 
4739 	(void)context;
4740 	(void)hints;
4741 	DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
4742 
4743 	if (rescode) {
4744 		msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
4745 			name, gai_strerror(rescode), rescode);
4746 		return;
4747 	}
4748 	/*
4749 	 * Loop through the addresses found
4750 	 */
4751 	for (; res != NULL; res = res->ai_next) {
4752 		INSIST(res->ai_addrlen <= sizeof(peeraddr));
4753 		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4754 		DPRINTF(1, ("unpeer: searching for peer %s\n",
4755 			    stoa(&peeraddr)));
4756 		peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4757 		if (peer != NULL) {
4758 			af = AF(&peeraddr);
4759 			fam_spec = (AF_INET6 == af)
4760 				       ? "(AAAA) "
4761 				       : (AF_INET == af)
4762 					     ? "(A) "
4763 					     : "";
4764 			msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
4765 				fam_spec, stoa(&peeraddr));
4766 			peer_clear(peer, "GONE");
4767 			unpeer(peer);
4768 		}
4769 	}
4770 }
4771 #endif	/* WORKER */
4772 
4773 
4774 #ifdef FREE_CFG_T
4775 static void
4776 free_config_unpeers(
4777 	config_tree *ptree
4778 	)
4779 {
4780 	unpeer_node *curr_unpeer;
4781 
4782 	if (ptree->unpeers != NULL) {
4783 		for (;;) {
4784 			UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
4785 			if (NULL == curr_unpeer)
4786 				break;
4787 			destroy_address_node(curr_unpeer->addr);
4788 			free(curr_unpeer);
4789 		}
4790 		free(ptree->unpeers);
4791 	}
4792 }
4793 #endif	/* FREE_CFG_T */
4794 #endif	/* !SIM */
4795 
4796 
4797 #ifndef SIM
4798 static void
4799 config_reset_counters(
4800 	config_tree *ptree
4801 	)
4802 {
4803 	int_node *counter_set;
4804 
4805 	for (counter_set = HEAD_PFIFO(ptree->reset_counters);
4806 	     counter_set != NULL;
4807 	     counter_set = counter_set->link) {
4808 		switch (counter_set->i) {
4809 		default:
4810 			DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
4811 				    keyword(counter_set->i), counter_set->i));
4812 			break;
4813 
4814 		case T_Allpeers:
4815 			peer_all_reset();
4816 			break;
4817 
4818 		case T_Auth:
4819 			reset_auth_stats();
4820 			break;
4821 
4822 		case T_Ctl:
4823 			ctl_clr_stats();
4824 			break;
4825 
4826 		case T_Io:
4827 			io_clr_stats();
4828 			break;
4829 
4830 		case T_Mem:
4831 			peer_clr_stats();
4832 			break;
4833 
4834 		case T_Sys:
4835 			proto_clr_stats();
4836 			break;
4837 
4838 		case T_Timer:
4839 			timer_clr_stats();
4840 			break;
4841 		}
4842 	}
4843 }
4844 #endif	/* !SIM */
4845 
4846 
4847 #ifdef FREE_CFG_T
4848 static void
4849 free_config_reset_counters(
4850 	config_tree *ptree
4851 	)
4852 {
4853 	FREE_INT_FIFO(ptree->reset_counters);
4854 }
4855 #endif	/* FREE_CFG_T */
4856 
4857 
4858 #ifdef SIM
4859 static void
4860 config_sim(
4861 	config_tree *ptree
4862 	)
4863 {
4864 	int i;
4865 	server_info *serv_info;
4866 	attr_val *init_stmt;
4867 	sim_node *sim_n;
4868 
4869 	/* Check if a simulate block was found in the configuration code.
4870 	 * If not, return an error and exit
4871 	 */
4872 	sim_n = HEAD_PFIFO(ptree->sim_details);
4873 	if (NULL == sim_n) {
4874 		fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
4875 		fprintf(stderr, "\tCheck your configuration file.\n");
4876 		exit(1);
4877 	}
4878 
4879 	/* Process the initialization statements
4880 	 * -------------------------------------
4881 	 */
4882 	init_stmt = HEAD_PFIFO(sim_n->init_opts);
4883 	for (; init_stmt != NULL; init_stmt = init_stmt->link) {
4884 		switch(init_stmt->attr) {
4885 
4886 		case T_Beep_Delay:
4887 			simulation.beep_delay = init_stmt->value.d;
4888 			break;
4889 
4890 		case T_Sim_Duration:
4891 			simulation.end_time = init_stmt->value.d;
4892 			break;
4893 
4894 		default:
4895 			fprintf(stderr,
4896 				"Unknown simulator init token %d\n",
4897 				init_stmt->attr);
4898 			exit(1);
4899 		}
4900 	}
4901 
4902 	/* Process the server list
4903 	 * -----------------------
4904 	 */
4905 	simulation.num_of_servers = 0;
4906 	serv_info = HEAD_PFIFO(sim_n->servers);
4907 	for (; serv_info != NULL; serv_info = serv_info->link)
4908 		simulation.num_of_servers++;
4909 	simulation.servers = eallocarray(simulation.num_of_servers,
4910 				     sizeof(simulation.servers[0]));
4911 
4912 	i = 0;
4913 	serv_info = HEAD_PFIFO(sim_n->servers);
4914 	for (; serv_info != NULL; serv_info = serv_info->link) {
4915 		if (NULL == serv_info) {
4916 			fprintf(stderr, "Simulator server list is corrupt\n");
4917 			exit(1);
4918 		} else {
4919 			simulation.servers[i] = *serv_info;
4920 			simulation.servers[i].link = NULL;
4921 			i++;
4922 		}
4923 	}
4924 
4925 	printf("Creating server associations\n");
4926 	create_server_associations();
4927 	fprintf(stderr,"\tServer associations successfully created!!\n");
4928 }
4929 
4930 
4931 #ifdef FREE_CFG_T
4932 static void
4933 free_config_sim(
4934 	config_tree *ptree
4935 	)
4936 {
4937 	sim_node *sim_n;
4938 	server_info *serv_n;
4939 	script_info *script_n;
4940 
4941 	if (NULL == ptree->sim_details)
4942 		return;
4943 	sim_n = HEAD_PFIFO(ptree->sim_details);
4944 	free(ptree->sim_details);
4945 	ptree->sim_details = NULL;
4946 	if (NULL == sim_n)
4947 		return;
4948 
4949 	FREE_ATTR_VAL_FIFO(sim_n->init_opts);
4950 	for (;;) {
4951 		UNLINK_FIFO(serv_n, *sim_n->servers, link);
4952 		if (NULL == serv_n)
4953 			break;
4954 		free(serv_n->curr_script);
4955 		if (serv_n->script != NULL) {
4956 			for (;;) {
4957 				UNLINK_FIFO(script_n, *serv_n->script,
4958 					    link);
4959 				if (script_n == NULL)
4960 					break;
4961 				free(script_n);
4962 			}
4963 			free(serv_n->script);
4964 		}
4965 		free(serv_n);
4966 	}
4967 	free(sim_n);
4968 }
4969 #endif	/* FREE_CFG_T */
4970 #endif	/* SIM */
4971 
4972 
4973 /* Define two different config functions. One for the daemon and the other for
4974  * the simulator. The simulator ignores a lot of the standard ntpd configuration
4975  * options
4976  */
4977 #ifndef SIM
4978 static void
4979 config_ntpd(
4980 	config_tree *ptree,
4981 	int/*BOOL*/ input_from_files
4982 	)
4983 {
4984 	/* [Bug 3435] check and esure clock sanity if configured from
4985 	 * file and clock sanity parameters (-> basedate) are given. Do
4986 	 * this ASAP, so we don't disturb the closed loop controller.
4987 	 */
4988 	if (input_from_files) {
4989 		if (config_tos_clock(ptree))
4990 			clamp_systime();
4991 	}
4992 
4993 	config_nic_rules(ptree, input_from_files);
4994 	config_monitor(ptree);
4995 	config_auth(ptree);
4996 	config_tos(ptree);
4997 	config_access(ptree);
4998 	config_tinker(ptree);
4999 	config_rlimit(ptree);
5000 	config_system_opts(ptree);
5001 	config_logconfig(ptree);
5002 	config_phone(ptree);
5003 	config_mdnstries(ptree);
5004 	config_setvar(ptree);
5005 	config_ttl(ptree);
5006 	config_vars(ptree);
5007 
5008 	io_open_sockets();	/* [bug 2837] dep. on config_vars() */
5009 
5010 	config_trap(ptree);	/* [bug 2923] dep. on io_open_sockets() */
5011 	config_other_modes(ptree);
5012 	config_device(ptree);
5013 	config_peers(ptree);
5014 	config_unpeers(ptree);
5015 	config_fudge(ptree);
5016 	config_reset_counters(ptree);
5017 
5018 #ifdef DEBUG
5019 	if (debug > 1) {
5020 		dump_restricts();
5021 	}
5022 #endif
5023 
5024 #ifdef TEST_BLOCKING_WORKER
5025 	{
5026 		struct addrinfo hints;
5027 
5028 		ZERO(hints);
5029 		hints.ai_socktype = SOCK_STREAM;
5030 		hints.ai_protocol = IPPROTO_TCP;
5031 		getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
5032 				     INITIAL_DNS_RETRY,
5033 				     gai_test_callback, (void *)1);
5034 		hints.ai_family = AF_INET6;
5035 		getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
5036 				     INITIAL_DNS_RETRY,
5037 				     gai_test_callback, (void *)0x600);
5038 	}
5039 #endif
5040 }
5041 #endif	/* !SIM */
5042 
5043 
5044 #ifdef SIM
5045 static void
5046 config_ntpdsim(
5047 	config_tree *ptree
5048 	)
5049 {
5050 	printf("Configuring Simulator...\n");
5051 	printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
5052 
5053 	config_tos(ptree);
5054 	config_monitor(ptree);
5055 	config_tinker(ptree);
5056 	if (0)
5057 		config_rlimit(ptree);	/* not needed for the simulator */
5058 	config_system_opts(ptree);
5059 	config_logconfig(ptree);
5060 	config_vars(ptree);
5061 	config_sim(ptree);
5062 }
5063 #endif /* SIM */
5064 
5065 
5066 /*
5067  * config_remotely() - implements ntpd side of ntpq :config
5068  */
5069 void
5070 config_remotely(
5071 	sockaddr_u *	remote_addr
5072 	)
5073 {
5074 	char origin[128];
5075 
5076 	snprintf(origin, sizeof(origin), "remote config from %s",
5077 		 stoa(remote_addr));
5078 	lex_init_stack(origin, NULL); /* no checking needed... */
5079 	init_syntax_tree(&cfgt);
5080 	yyparse();
5081 	lex_drop_stack();
5082 
5083 	cfgt.source.attr = CONF_SOURCE_NTPQ;
5084 	cfgt.timestamp = time(NULL);
5085 	cfgt.source.value.s = estrdup(stoa(remote_addr));
5086 
5087 	DPRINTF(1, ("Finished Parsing!!\n"));
5088 
5089 	save_and_apply_config_tree(FALSE);
5090 }
5091 
5092 
5093 /*
5094  * getconfig() - process startup configuration file e.g /etc/ntp.conf
5095  */
5096 void
5097 getconfig(
5098 	int	argc,
5099 	char **	argv
5100 	)
5101 {
5102 	char	line[256];
5103 
5104 #ifdef DEBUG
5105 	atexit(free_all_config_trees);
5106 #endif
5107 #ifndef SYS_WINNT
5108 	config_file = CONFIG_FILE;
5109 #else
5110 	temp = CONFIG_FILE;
5111 	if (!ExpandEnvironmentStringsA(temp, config_file_storage,
5112 				       sizeof(config_file_storage))) {
5113 		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
5114 		exit(1);
5115 	}
5116 	config_file = config_file_storage;
5117 
5118 	temp = ALT_CONFIG_FILE;
5119 	if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
5120 				       sizeof(alt_config_file_storage))) {
5121 		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
5122 		exit(1);
5123 	}
5124 	alt_config_file = alt_config_file_storage;
5125 #endif /* SYS_WINNT */
5126 
5127 	/*
5128 	 * install a non default variable with this daemon version
5129 	 */
5130 	snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
5131 	set_sys_var(line, strlen(line) + 1, RO);
5132 
5133 	/*
5134 	 * Set up for the first time step to install a variable showing
5135 	 * which syscall is being used to step.
5136 	 */
5137 	set_tod_using = &ntpd_set_tod_using;
5138 
5139 	getCmdOpts(argc, argv);
5140 	init_syntax_tree(&cfgt);
5141 	if (
5142 		!lex_init_stack(FindConfig(config_file), "r")
5143 #ifdef HAVE_NETINFO
5144 		/* If there is no config_file, try NetInfo. */
5145 		&& check_netinfo && !(config_netinfo = get_netinfo_config())
5146 #endif /* HAVE_NETINFO */
5147 		) {
5148 		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
5149 #ifndef SYS_WINNT
5150 		io_open_sockets();
5151 
5152 		return;
5153 #else
5154 		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
5155 
5156 		if (!lex_init_stack(FindConfig(alt_config_file), "r"))  {
5157 			/*
5158 			 * Broadcast clients can sometimes run without
5159 			 * a configuration file.
5160 			 */
5161 			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
5162 			io_open_sockets();
5163 
5164 			return;
5165 		}
5166 		cfgt.source.value.s = estrdup(alt_config_file);
5167 #endif	/* SYS_WINNT */
5168 	} else
5169 		cfgt.source.value.s = estrdup(config_file);
5170 
5171 
5172 	/*** BULK OF THE PARSER ***/
5173 #ifdef DEBUG
5174 	yydebug = !!(debug >= 5);
5175 #endif
5176 	yyparse();
5177 	lex_drop_stack();
5178 
5179 	DPRINTF(1, ("Finished Parsing!!\n"));
5180 
5181 	cfgt.source.attr = CONF_SOURCE_FILE;
5182 	cfgt.timestamp = time(NULL);
5183 
5184 	save_and_apply_config_tree(TRUE);
5185 
5186 #ifdef HAVE_NETINFO
5187 	if (config_netinfo)
5188 		free_netinfo_config(config_netinfo);
5189 #endif /* HAVE_NETINFO */
5190 }
5191 
5192 
5193 void
5194 save_and_apply_config_tree(int/*BOOL*/ input_from_file)
5195 {
5196 	config_tree *ptree;
5197 #ifndef SAVECONFIG
5198 	config_tree *punlinked;
5199 #endif
5200 
5201 	/*
5202 	 * Keep all the configuration trees applied since startup in
5203 	 * a list that can be used to dump the configuration back to
5204 	 * a text file.
5205 	 */
5206 	ptree = emalloc(sizeof(*ptree));
5207 	memcpy(ptree, &cfgt, sizeof(*ptree));
5208 	ZERO(cfgt);
5209 
5210 	LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
5211 
5212 #ifdef SAVECONFIG
5213 	if (HAVE_OPT( SAVECONFIGQUIT )) {
5214 		FILE *dumpfile;
5215 		int err;
5216 		int dumpfailed;
5217 
5218 		dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
5219 		if (NULL == dumpfile) {
5220 			err = errno;
5221 			mfprintf(stderr,
5222 				 "can not create save file %s, error %d %m\n",
5223 				 OPT_ARG(SAVECONFIGQUIT), err);
5224 			exit(err);
5225 		}
5226 
5227 		dumpfailed = dump_all_config_trees(dumpfile, 0);
5228 		if (dumpfailed)
5229 			fprintf(stderr,
5230 				"--saveconfigquit %s error %d\n",
5231 				OPT_ARG( SAVECONFIGQUIT ),
5232 				dumpfailed);
5233 		else
5234 			fprintf(stderr,
5235 				"configuration saved to %s\n",
5236 				OPT_ARG( SAVECONFIGQUIT ));
5237 
5238 		exit(dumpfailed);
5239 	}
5240 #endif	/* SAVECONFIG */
5241 
5242 	/* The actual configuration done depends on whether we are configuring the
5243 	 * simulator or the daemon. Perform a check and call the appropriate
5244 	 * function as needed.
5245 	 */
5246 
5247 #ifndef SIM
5248 	config_ntpd(ptree, input_from_file);
5249 #else
5250 	config_ntpdsim(ptree);
5251 #endif
5252 
5253 	/*
5254 	 * With configure --disable-saveconfig, there's no use keeping
5255 	 * the config tree around after application, so free it.
5256 	 */
5257 #ifndef SAVECONFIG
5258 	UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
5259 		     config_tree);
5260 	INSIST(punlinked == ptree);
5261 	free_config_tree(ptree);
5262 #endif
5263 }
5264 
5265 /* Hack to disambiguate 'server' statements for refclocks and network peers.
5266  * Please note the qualification 'hack'. It's just that.
5267  */
5268 static int/*BOOL*/
5269 is_refclk_addr(
5270 	const address_node * addr
5271 	)
5272 {
5273 	return addr && addr->address && !strncmp(addr->address, "127.127.", 8);
5274 }
5275 
5276 static void
5277 ntpd_set_tod_using(
5278 	const char *which
5279 	)
5280 {
5281 	char line[128];
5282 
5283 	snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
5284 	set_sys_var(line, strlen(line) + 1, RO);
5285 }
5286 
5287 
5288 static char *
5289 normal_dtoa(
5290 	double d
5291 	)
5292 {
5293 	char *	buf;
5294 	char *	pch_e;
5295 	char *	pch_nz;
5296 
5297 	LIB_GETBUF(buf);
5298 	snprintf(buf, LIB_BUFLENGTH, "%g", d);
5299 
5300 	/* use lowercase 'e', strip any leading zeroes in exponent */
5301 	pch_e = strchr(buf, 'e');
5302 	if (NULL == pch_e) {
5303 		pch_e = strchr(buf, 'E');
5304 		if (NULL == pch_e)
5305 			return buf;
5306 		*pch_e = 'e';
5307 	}
5308 	pch_e++;
5309 	if ('-' == *pch_e)
5310 		pch_e++;
5311 	pch_nz = pch_e;
5312 	while ('0' == *pch_nz)
5313 		pch_nz++;
5314 	if (pch_nz == pch_e)
5315 		return buf;
5316 	strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
5317 
5318 	return buf;
5319 }
5320 
5321 
5322 /* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
5323  * --------------------------------------------
5324  */
5325 
5326 
5327 /*
5328  * get_pfxmatch - find value for prefixmatch
5329  * and update char * accordingly
5330  */
5331 static u_int32
5332 get_pfxmatch(
5333 	const char **	pstr,
5334 	struct masks *	m
5335 	)
5336 {
5337 	while (m->name != NULL) {
5338 		if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
5339 			*pstr += strlen(m->name);
5340 			return m->mask;
5341 		} else {
5342 			m++;
5343 		}
5344 	}
5345 	return 0;
5346 }
5347 
5348 /*
5349  * get_match - find logmask value
5350  */
5351 static u_int32
5352 get_match(
5353 	const char *	str,
5354 	struct masks *	m
5355 	)
5356 {
5357 	while (m->name != NULL) {
5358 		if (strcmp(str, m->name) == 0)
5359 			return m->mask;
5360 		else
5361 			m++;
5362 	}
5363 	return 0;
5364 }
5365 
5366 /*
5367  * get_logmask - build bitmask for ntp_syslogmask
5368  */
5369 static u_int32
5370 get_logmask(
5371 	const char *	str
5372 	)
5373 {
5374 	const char *	t;
5375 	u_int32		offset;
5376 	u_int32		mask;
5377 
5378 	mask = get_match(str, logcfg_noclass_items);
5379 	if (mask != 0)
5380 		return mask;
5381 
5382 	t = str;
5383 	offset = get_pfxmatch(&t, logcfg_class);
5384 	mask   = get_match(t, logcfg_class_items);
5385 
5386 	if (mask)
5387 		return mask << offset;
5388 	else
5389 		msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
5390 			str);
5391 
5392 	return 0;
5393 }
5394 
5395 
5396 #ifdef HAVE_NETINFO
5397 
5398 /*
5399  * get_netinfo_config - find the nearest NetInfo domain with an ntp
5400  * configuration and initialize the configuration state.
5401  */
5402 static struct netinfo_config_state *
5403 get_netinfo_config(void)
5404 {
5405 	ni_status status;
5406 	void *domain;
5407 	ni_id config_dir;
5408 	struct netinfo_config_state *config;
5409 
5410 	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
5411 
5412 	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
5413 		void *next_domain;
5414 		if (ni_open(domain, "..", &next_domain) != NI_OK) {
5415 			ni_free(next_domain);
5416 			break;
5417 		}
5418 		ni_free(domain);
5419 		domain = next_domain;
5420 	}
5421 	if (status != NI_OK) {
5422 		ni_free(domain);
5423 		return NULL;
5424 	}
5425 
5426 	config = emalloc(sizeof(*config));
5427 	config->domain = domain;
5428 	config->config_dir = config_dir;
5429 	config->prop_index = 0;
5430 	config->val_index = 0;
5431 	config->val_list = NULL;
5432 
5433 	return config;
5434 }
5435 
5436 
5437 /*
5438  * free_netinfo_config - release NetInfo configuration state
5439  */
5440 static void
5441 free_netinfo_config(
5442 	struct netinfo_config_state *config
5443 	)
5444 {
5445 	ni_free(config->domain);
5446 	free(config);
5447 }
5448 
5449 
5450 /*
5451  * gettokens_netinfo - return tokens from NetInfo
5452  */
5453 static int
5454 gettokens_netinfo (
5455 	struct netinfo_config_state *config,
5456 	char **tokenlist,
5457 	int *ntokens
5458 	)
5459 {
5460 	int prop_index = config->prop_index;
5461 	int val_index = config->val_index;
5462 	char **val_list = config->val_list;
5463 
5464 	/*
5465 	 * Iterate through each keyword and look for a property that matches it.
5466 	 */
5467   again:
5468 	if (!val_list) {
5469 		for (; prop_index < COUNTOF(keywords); prop_index++)
5470 		{
5471 			ni_namelist namelist;
5472 			struct keyword current_prop = keywords[prop_index];
5473 			ni_index index;
5474 
5475 			/*
5476 			 * For each value associated in the property, we're going to return
5477 			 * a separate line. We squirrel away the values in the config state
5478 			 * so the next time through, we don't need to do this lookup.
5479 			 */
5480 			NI_INIT(&namelist);
5481 			if (NI_OK == ni_lookupprop(config->domain,
5482 			    &config->config_dir, current_prop.text,
5483 			    &namelist)) {
5484 
5485 				/* Found the property, but it has no values */
5486 				if (namelist.ni_namelist_len == 0) continue;
5487 
5488 				config->val_list =
5489 				    eallocarray(
5490 					(namelist.ni_namelist_len + 1),
5491 					sizeof(char*));
5492 				val_list = config->val_list;
5493 
5494 				for (index = 0;
5495 				     index < namelist.ni_namelist_len;
5496 				     index++) {
5497 					char *value;
5498 
5499 					value = namelist.ni_namelist_val[index];
5500 					val_list[index] = estrdup(value);
5501 				}
5502 				val_list[index] = NULL;
5503 
5504 				break;
5505 			}
5506 			ni_namelist_free(&namelist);
5507 		}
5508 		config->prop_index = prop_index;
5509 	}
5510 
5511 	/* No list; we're done here. */
5512 	if (!val_list)
5513 		return CONFIG_UNKNOWN;
5514 
5515 	/*
5516 	 * We have a list of values for the current property.
5517 	 * Iterate through them and return each in order.
5518 	 */
5519 	if (val_list[val_index]) {
5520 		int ntok = 1;
5521 		int quoted = 0;
5522 		char *tokens = val_list[val_index];
5523 
5524 		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
5525 
5526 		(const char*)tokenlist[0] = keywords[prop_index].text;
5527 		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
5528 			tokenlist[ntok] = tokens;
5529 			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
5530 				quoted ^= (*tokens++ == '"');
5531 
5532 			if (ISEOL(*tokens)) {
5533 				*tokens = '\0';
5534 				break;
5535 			} else {		/* must be space */
5536 				*tokens++ = '\0';
5537 				while (ISSPACE(*tokens))
5538 					tokens++;
5539 				if (ISEOL(*tokens))
5540 					break;
5541 			}
5542 		}
5543 
5544 		if (ntok == MAXTOKENS) {
5545 			/* HMS: chomp it to lose the EOL? */
5546 			msyslog(LOG_ERR,
5547 				"gettokens_netinfo: too many tokens.  Ignoring: %s",
5548 				tokens);
5549 		} else {
5550 			*ntokens = ntok + 1;
5551 		}
5552 
5553 		config->val_index++;	/* HMS: Should this be in the 'else'? */
5554 
5555 		return keywords[prop_index].keytype;
5556 	}
5557 
5558 	/* We're done with the current property. */
5559 	prop_index = ++config->prop_index;
5560 
5561 	/* Free val_list and reset counters. */
5562 	for (val_index = 0; val_list[val_index]; val_index++)
5563 		free(val_list[val_index]);
5564 	free(val_list);
5565 	val_list = config->val_list = NULL;
5566 	val_index = config->val_index = 0;
5567 
5568 	goto again;
5569 }
5570 #endif /* HAVE_NETINFO */
5571 
5572 
5573 /*
5574  * getnetnum - return a net number (this is crude, but careful)
5575  *
5576  * returns 1 for success, and mysteriously, 0 for most failures, and
5577  * -1 if the address found is IPv6 and we believe IPv6 isn't working.
5578  */
5579 #ifndef SIM
5580 static int
5581 getnetnum(
5582 	const char *num,
5583 	sockaddr_u *addr,
5584 	int complain,
5585 	enum gnn_type a_type	/* ignored */
5586 	)
5587 {
5588 	REQUIRE(AF_UNSPEC == AF(addr) ||
5589 		AF_INET == AF(addr) ||
5590 		AF_INET6 == AF(addr));
5591 
5592 	if (!is_ip_address(num, AF(addr), addr))
5593 		return 0;
5594 
5595 	if (IS_IPV6(addr) && !ipv6_works)
5596 		return -1;
5597 
5598 # ifdef ISC_PLATFORM_HAVESALEN
5599 	addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
5600 # endif
5601 	SET_PORT(addr, NTP_PORT);
5602 
5603 	DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
5604 
5605 	return 1;
5606 }
5607 #endif	/* !SIM */
5608 
5609 #if defined(HAVE_SETRLIMIT)
5610 void
5611 ntp_rlimit(
5612 	int	rl_what,
5613 	rlim_t	rl_value,
5614 	int	rl_scale,
5615 	const char *	rl_sstr
5616 	)
5617 {
5618 	struct rlimit	rl;
5619 
5620 	switch (rl_what) {
5621 # ifdef RLIMIT_MEMLOCK
5622 	    case RLIMIT_MEMLOCK:
5623 		if (HAVE_OPT( SAVECONFIGQUIT )) {
5624 			break;
5625 		}
5626 		/*
5627 		 * The default RLIMIT_MEMLOCK is very low on Linux systems.
5628 		 * Unless we increase this limit malloc calls are likely to
5629 		 * fail if we drop root privilege.  To be useful the value
5630 		 * has to be larger than the largest ntpd resident set size.
5631 		 */
5632 		DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
5633 			(int)(rl_value / rl_scale), rl_sstr));
5634 		rl.rlim_cur = rl.rlim_max = rl_value;
5635 		if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
5636 			msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
5637 		break;
5638 # endif /* RLIMIT_MEMLOCK */
5639 
5640 # ifdef RLIMIT_NOFILE
5641 	    case RLIMIT_NOFILE:
5642 		/*
5643 		 * For large systems the default file descriptor limit may
5644 		 * not be enough.
5645 		 */
5646 		DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
5647 			(int)(rl_value / rl_scale), rl_sstr));
5648 		rl.rlim_cur = rl.rlim_max = rl_value;
5649 		if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
5650 			msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
5651 		break;
5652 # endif /* RLIMIT_NOFILE */
5653 
5654 # ifdef RLIMIT_STACK
5655 	    case RLIMIT_STACK:
5656 		/*
5657 		 * Provide a way to set the stack limit to something
5658 		 * smaller, so that we don't lock a lot of unused
5659 		 * stack memory.
5660 		 */
5661 		DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
5662 			    (int)(rl_value / rl_scale), rl_sstr));
5663 		if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
5664 			msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
5665 		} else {
5666 			if (rl_value > rl.rlim_max) {
5667 				msyslog(LOG_WARNING,
5668 					"ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
5669 					(u_long)rl.rlim_max,
5670 					(u_long)rl_value);
5671 				rl_value = rl.rlim_max;
5672 			}
5673 			rl.rlim_cur = rl_value;
5674 			if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
5675 				msyslog(LOG_ERR,
5676 					"ntp_rlimit: Cannot set RLIMIT_STACK: %m");
5677 			}
5678 		}
5679 		break;
5680 # endif /* RLIMIT_STACK */
5681 
5682 	    default:
5683 		    fatal_error("ntp_rlimit: unexpected RLIMIT case: %d", rl_what);
5684 	}
5685 }
5686 #endif	/* HAVE_SETRLIMIT */
5687 
5688 
5689 char *
5690 build_iflags(
5691 	u_int32 iflags
5692 	)
5693 {
5694 	static char ifs[1024];
5695 
5696 	ifs[0] = '\0';
5697 
5698 	if (iflags & INT_UP) {
5699 		iflags &= ~INT_UP;
5700 		appendstr(ifs, sizeof ifs, "up");
5701 	}
5702 
5703 	if (iflags & INT_PPP) {
5704 		iflags &= ~INT_PPP;
5705 		appendstr(ifs, sizeof ifs, "ppp");
5706 	}
5707 
5708 	if (iflags & INT_LOOPBACK) {
5709 		iflags &= ~INT_LOOPBACK;
5710 		appendstr(ifs, sizeof ifs, "loopback");
5711 	}
5712 
5713 	if (iflags & INT_BROADCAST) {
5714 		iflags &= ~INT_BROADCAST;
5715 		appendstr(ifs, sizeof ifs, "broadcast");
5716 	}
5717 
5718 	if (iflags & INT_MULTICAST) {
5719 		iflags &= ~INT_MULTICAST;
5720 		appendstr(ifs, sizeof ifs, "multicast");
5721 	}
5722 
5723 	if (iflags & INT_BCASTOPEN) {
5724 		iflags &= ~INT_BCASTOPEN;
5725 		appendstr(ifs, sizeof ifs, "bcastopen");
5726 	}
5727 
5728 	if (iflags & INT_MCASTOPEN) {
5729 		iflags &= ~INT_MCASTOPEN;
5730 		appendstr(ifs, sizeof ifs, "mcastopen");
5731 	}
5732 
5733 	if (iflags & INT_WILDCARD) {
5734 		iflags &= ~INT_WILDCARD;
5735 		appendstr(ifs, sizeof ifs, "wildcard");
5736 	}
5737 
5738 	if (iflags & INT_MCASTIF) {
5739 		iflags &= ~INT_MCASTIF;
5740 		appendstr(ifs, sizeof ifs, "MCASTif");
5741 	}
5742 
5743 	if (iflags & INT_PRIVACY) {
5744 		iflags &= ~INT_PRIVACY;
5745 		appendstr(ifs, sizeof ifs, "IPv6privacy");
5746 	}
5747 
5748 	if (iflags & INT_BCASTXMIT) {
5749 		iflags &= ~INT_BCASTXMIT;
5750 		appendstr(ifs, sizeof ifs, "bcastxmit");
5751 	}
5752 
5753 	if (iflags) {
5754 		char string[10];
5755 
5756 		snprintf(string, sizeof string, "%0x", iflags);
5757 		appendstr(ifs, sizeof ifs, string);
5758 	}
5759 
5760 	return ifs;
5761 }
5762 
5763 
5764 char *
5765 build_mflags(
5766 	u_short mflags
5767 	)
5768 {
5769 	static char mfs[1024];
5770 
5771 	mfs[0] = '\0';
5772 
5773 	if (mflags & RESM_NTPONLY) {
5774 		mflags &= ~RESM_NTPONLY;
5775 		appendstr(mfs, sizeof mfs, "ntponly");
5776 	}
5777 
5778 	if (mflags & RESM_SOURCE) {
5779 		mflags &= ~RESM_SOURCE;
5780 		appendstr(mfs, sizeof mfs, "source");
5781 	}
5782 
5783 	if (mflags) {
5784 		char string[10];
5785 
5786 		snprintf(string, sizeof string, "%0x", mflags);
5787 		appendstr(mfs, sizeof mfs, string);
5788 	}
5789 
5790 	return mfs;
5791 }
5792 
5793 
5794 char *
5795 build_rflags(
5796 	u_short rflags
5797 	)
5798 {
5799 	static char rfs[1024];
5800 
5801 	rfs[0] = '\0';
5802 
5803 	if (rflags & RES_FLAKE) {
5804 		rflags &= ~RES_FLAKE;
5805 		appendstr(rfs, sizeof rfs, "flake");
5806 	}
5807 
5808 	if (rflags & RES_IGNORE) {
5809 		rflags &= ~RES_IGNORE;
5810 		appendstr(rfs, sizeof rfs, "ignore");
5811 	}
5812 
5813 	if (rflags & RES_KOD) {
5814 		rflags &= ~RES_KOD;
5815 		appendstr(rfs, sizeof rfs, "kod");
5816 	}
5817 
5818 	if (rflags & RES_MSSNTP) {
5819 		rflags &= ~RES_MSSNTP;
5820 		appendstr(rfs, sizeof rfs, "mssntp");
5821 	}
5822 
5823 	if (rflags & RES_LIMITED) {
5824 		rflags &= ~RES_LIMITED;
5825 		appendstr(rfs, sizeof rfs, "limited");
5826 	}
5827 
5828 	if (rflags & RES_LPTRAP) {
5829 		rflags &= ~RES_LPTRAP;
5830 		appendstr(rfs, sizeof rfs, "lptrap");
5831 	}
5832 
5833 	if (rflags & RES_NOMODIFY) {
5834 		rflags &= ~RES_NOMODIFY;
5835 		appendstr(rfs, sizeof rfs, "nomodify");
5836 	}
5837 
5838 	if (rflags & RES_NOMRULIST) {
5839 		rflags &= ~RES_NOMRULIST;
5840 		appendstr(rfs, sizeof rfs, "nomrulist");
5841 	}
5842 
5843 	if (rflags & RES_NOEPEER) {
5844 		rflags &= ~RES_NOEPEER;
5845 		appendstr(rfs, sizeof rfs, "noepeer");
5846 	}
5847 
5848 	if (rflags & RES_NOPEER) {
5849 		rflags &= ~RES_NOPEER;
5850 		appendstr(rfs, sizeof rfs, "nopeer");
5851 	}
5852 
5853 	if (rflags & RES_NOQUERY) {
5854 		rflags &= ~RES_NOQUERY;
5855 		appendstr(rfs, sizeof rfs, "noquery");
5856 	}
5857 
5858 	if (rflags & RES_DONTSERVE) {
5859 		rflags &= ~RES_DONTSERVE;
5860 		appendstr(rfs, sizeof rfs, "dontserve");
5861 	}
5862 
5863 	if (rflags & RES_NOTRAP) {
5864 		rflags &= ~RES_NOTRAP;
5865 		appendstr(rfs, sizeof rfs, "notrap");
5866 	}
5867 
5868 	if (rflags & RES_DONTTRUST) {
5869 		rflags &= ~RES_DONTTRUST;
5870 		appendstr(rfs, sizeof rfs, "notrust");
5871 	}
5872 
5873 	if (rflags & RES_SRVRSPFUZ) {
5874 		rflags &= ~RES_SRVRSPFUZ;
5875 		appendstr(rfs, sizeof rfs, "srvrspfuz");
5876 	}
5877 
5878 	if (rflags & RES_VERSION) {
5879 		rflags &= ~RES_VERSION;
5880 		appendstr(rfs, sizeof rfs, "version");
5881 	}
5882 
5883 	if (rflags) {
5884 		char string[10];
5885 
5886 		snprintf(string, sizeof string, "%0x", rflags);
5887 		appendstr(rfs, sizeof rfs, string);
5888 	}
5889 
5890 	if ('\0' == rfs[0]) {
5891 		appendstr(rfs, sizeof rfs, "(none)");
5892 	}
5893 
5894 	return rfs;
5895 }
5896 
5897 
5898 static void
5899 appendstr(
5900 	char *string,
5901 	size_t s,
5902 	const char *new
5903 	)
5904 {
5905 	if (*string != '\0') {
5906 		(void)strlcat(string, ",", s);
5907 	}
5908 	(void)strlcat(string, new, s);
5909 
5910 	return;
5911 }
5912