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