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