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