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