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