1280849Scy/* ntp_config.c
2280849Scy *
3280849Scy * This file contains the ntpd configuration code.
4280849Scy *
5280849Scy * Written By:	Sachin Kamboj
6280849Scy *		University of Delaware
7280849Scy *		Newark, DE 19711
8280849Scy * Some parts borrowed from the older ntp_config.c
9280849Scy * Copyright (c) 2006
1054359Sroberto */
11280849Scy
1254359Sroberto#ifdef HAVE_CONFIG_H
1354359Sroberto# include <config.h>
1454359Sroberto#endif
1554359Sroberto
1654359Sroberto#ifdef HAVE_NETINFO
1782498Sroberto# include <netinfo/ni.h>
1854359Sroberto#endif
1954359Sroberto
2082498Sroberto#include <stdio.h>
2182498Sroberto#include <ctype.h>
22106163Sroberto#ifdef HAVE_SYS_PARAM_H
23280849Scy# include <sys/param.h>
24106163Sroberto#endif
2582498Sroberto#include <signal.h>
2682498Sroberto#ifndef SIGCHLD
2782498Sroberto# define SIGCHLD SIGCLD
2882498Sroberto#endif
29280849Scy#ifdef HAVE_SYS_WAIT_H
30280849Scy# include <sys/wait.h>
31280849Scy#endif
32358659Scy#include <time.h>
3382498Sroberto
34280849Scy#include <isc/net.h>
35280849Scy#include <isc/result.h>
3654359Sroberto
37280849Scy#include "ntp.h"
38280849Scy#include "ntpd.h"
39280849Scy#include "ntp_io.h"
40280849Scy#include "ntp_unixtime.h"
41280849Scy#include "ntp_refclock.h"
42280849Scy#include "ntp_filegen.h"
43280849Scy#include "ntp_stdlib.h"
44280849Scy#include "lib_strbuf.h"
45280849Scy#include "ntp_assert.h"
46280849Scy#include "ntp_random.h"
47182007Sroberto/*
48182007Sroberto * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
49182007Sroberto * so #include these later.
50182007Sroberto */
51182007Sroberto#include "ntp_config.h"
52182007Sroberto#include "ntp_cmdargs.h"
53280849Scy#include "ntp_scanner.h"
54280849Scy#include "ntp_parser.h"
55280849Scy#include "ntpd-opts.h"
56182007Sroberto
57309007Sdelphij#ifndef IGNORE_DNS_ERRORS
58309007Sdelphij# define DNSFLAGS 0
59309007Sdelphij#else
60309007Sdelphij# define DNSFLAGS GAIR_F_IGNDNSERR
61309007Sdelphij#endif
62309007Sdelphij
63294554Sdelphijextern int yyparse(void);
64294554Sdelphij
65289764Sglebius/* Bug 2817 */
66289764Sglebius#if defined(HAVE_SYS_MMAN_H)
67289764Sglebius# include <sys/mman.h>
68289764Sglebius#endif
6982498Sroberto
70280849Scy/* list of servers from command line for config_peers() */
71280849Scyint	cmdline_server_count;
72280849Scychar **	cmdline_servers;
7354359Sroberto
74289764Sglebius/* Current state of memory locking:
75289764Sglebius * -1: default
76289764Sglebius *  0: memory locking disabled
77289764Sglebius *  1: Memory locking enabled
78289764Sglebius */
79289764Sglebiusint	cur_memlock = -1;
8054359Sroberto
8154359Sroberto/*
8254359Sroberto * "logconfig" building blocks
8354359Sroberto */
8454359Srobertostruct masks {
85280849Scy	const char * const	name;
86280849Scy	const u_int32		mask;
8754359Sroberto};
8854359Sroberto
8954359Srobertostatic struct masks logcfg_class[] = {
90280849Scy	{ "clock",	NLOG_OCLOCK },
91280849Scy	{ "peer",	NLOG_OPEER },
92280849Scy	{ "sync",	NLOG_OSYNC },
93280849Scy	{ "sys",	NLOG_OSYS },
94280849Scy	{ NULL,		0 }
9554359Sroberto};
9654359Sroberto
97280849Scy/* logcfg_noclass_items[] masks are complete and must not be shifted */
98280849Scystatic struct masks logcfg_noclass_items[] = {
99280849Scy	{ "allall",		NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
100280849Scy	{ "allinfo",		NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
101280849Scy	{ "allevents",		NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
102280849Scy	{ "allstatus",		NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
103280849Scy	{ "allstatistics",	NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
104280849Scy	/* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
105280849Scy	{ "allclock",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
106280849Scy	{ "allpeer",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
107280849Scy	{ "allsys",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
108280849Scy	{ "allsync",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
109280849Scy	{ NULL,			0 }
110280849Scy};
111280849Scy
112280849Scy/* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
113280849Scystatic struct masks logcfg_class_items[] = {
114280849Scy	{ "all",		NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST },
11554359Sroberto	{ "info",		NLOG_INFO },
11654359Sroberto	{ "events",		NLOG_EVENT },
11754359Sroberto	{ "status",		NLOG_STATUS },
11854359Sroberto	{ "statistics",		NLOG_STATIST },
119280849Scy	{ NULL,			0 }
12054359Sroberto};
12154359Sroberto
122280849Scytypedef struct peer_resolved_ctx_tag {
123280849Scy	int		flags;
124280849Scy	int		host_mode;	/* T_* token identifier */
125280849Scy	u_short		family;
126280849Scy	keyid_t		keyid;
127280849Scy	u_char		hmode;		/* MODE_* */
128280849Scy	u_char		version;
129280849Scy	u_char		minpoll;
130280849Scy	u_char		maxpoll;
131280849Scy	u_int32		ttl;
132280849Scy	const char *	group;
133280849Scy} peer_resolved_ctx;
134280849Scy
135280849Scy/* Limits */
136182007Sroberto#define MAXPHONE	10	/* maximum number of phone strings */
13754359Sroberto#define MAXPPS		20	/* maximum length of PPS device string */
13854359Sroberto
13954359Sroberto/*
140362716Scy * Poll Skew List
141362716Scy */
142362716Scy
143362716Scystatic psl_item psl[17-3+1];	/* values for polls 3-17 */
144362716Scy				/* To simplify the runtime code we */
145362716Scy				/* don't want to have to special-case */
146362716Scy				/* dealing with a default */
147362716Scy
148362716Scy
149362716Scy/*
15054359Sroberto * Miscellaneous macros
15154359Sroberto */
15254359Sroberto#define ISEOL(c)	((c) == '#' || (c) == '\n' || (c) == '\0')
15354359Sroberto#define ISSPACE(c)	((c) == ' ' || (c) == '\t')
15454359Sroberto
155280849Scy#define _UC(str)	((char *)(intptr_t)(str))
15682498Sroberto
15754359Sroberto/*
15854359Sroberto * Definitions of things either imported from or exported to outside
15954359Sroberto */
160280849Scyextern int yydebug;			/* ntp_parser.c (.y) */
161280849Scyconfig_tree cfgt;			/* Parser output stored here */
162358659Scyconfig_tree *cfg_tree_history;		/* History of configs */
163330106Sdelphijchar *	sys_phone[MAXPHONE] = {NULL};	/* ACTS phone numbers */
164280849Scychar	default_keysdir[] = NTP_KEYSDIR;
165330106Sdelphijchar *	keysdir = default_keysdir;	/* crypto keys directory */
166280849Scychar *	saveconfigdir;
16754359Sroberto#if defined(HAVE_SCHED_SETSCHEDULER)
16854359Srobertoint	config_priority_override = 0;
16954359Srobertoint	config_priority;
17054359Sroberto#endif
17154359Sroberto
17282498Srobertoconst char *config_file;
173280849Scystatic char default_ntp_signd_socket[] =
174280849Scy#ifdef NTP_SIGND_PATH
175280849Scy					NTP_SIGND_PATH;
176280849Scy#else
177280849Scy					"";
178280849Scy#endif
179280849Scychar *ntp_signd_socket = default_ntp_signd_socket;
18082498Sroberto#ifdef HAVE_NETINFO
181280849Scystruct netinfo_config_state *config_netinfo = NULL;
182280849Scyint check_netinfo = 1;
18382498Sroberto#endif /* HAVE_NETINFO */
18482498Sroberto#ifdef SYS_WINNT
185280849Scychar *alt_config_file;
186280849ScyLPTSTR temp;
187280849Scychar config_file_storage[MAX_PATH];
188280849Scychar alt_config_file_storage[MAX_PATH];
18982498Sroberto#endif /* SYS_WINNT */
19054359Sroberto
19154359Sroberto#ifdef HAVE_NETINFO
19254359Sroberto/*
19354359Sroberto * NetInfo configuration state
19454359Sroberto */
19554359Srobertostruct netinfo_config_state {
19654359Sroberto	void *domain;		/* domain with config */
19754359Sroberto	ni_id config_dir;	/* ID config dir      */
19854359Sroberto	int prop_index;		/* current property   */
19954359Sroberto	int val_index;		/* current value      */
200280849Scy	char **val_list;	/* value list         */
20154359Sroberto};
20254359Sroberto#endif
20354359Sroberto
204280849Scystruct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
205280849Scy					     pointer info */
206280849Scyint old_config_style = 1;    /* A boolean flag, which when set,
207280849Scy			      * indicates that the old configuration
208280849Scy			      * format with a newline at the end of
209280849Scy			      * every command is being used
210280849Scy			      */
211280849Scyint	cryptosw;		/* crypto command called */
212280849Scy
213280849Scyextern char *stats_drift_file;	/* name of the driftfile */
214280849Scy
215280849Scy#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
21654359Sroberto/*
217280849Scy * backwards compatibility flags
21854359Sroberto */
219280849Scybc_entry bc_list[] = {
220280849Scy	{ T_Bc_bugXXXX,		1	}	/* default enabled */
221280849Scy};
222280849Scy
223280849Scy/*
224280849Scy * declare an int pointer for each flag for quick testing without
225280849Scy * walking bc_list.  If the pointer is consumed by libntp rather
226280849Scy * than ntpd, declare it in a libntp source file pointing to storage
227280849Scy * initialized with the appropriate value for other libntp clients, and
228280849Scy * redirect it to point into bc_list during ntpd startup.
229280849Scy */
230280849Scyint *p_bcXXXX_enabled = &bc_list[0].enabled;
23154359Sroberto#endif
232280849Scy
233280849Scy/* FUNCTION PROTOTYPES */
234280849Scy
235280849Scystatic void init_syntax_tree(config_tree *);
236280849Scystatic void apply_enable_disable(attr_val_fifo *q, int enable);
237280849Scy
238280849Scy#ifdef FREE_CFG_T
239280849Scystatic void free_auth_node(config_tree *);
240280849Scystatic void free_all_config_trees(void);
241280849Scy
242280849Scystatic void free_config_access(config_tree *);
243280849Scystatic void free_config_auth(config_tree *);
244280849Scystatic void free_config_fudge(config_tree *);
245280849Scystatic void free_config_logconfig(config_tree *);
246280849Scystatic void free_config_monitor(config_tree *);
247280849Scystatic void free_config_nic_rules(config_tree *);
248280849Scystatic void free_config_other_modes(config_tree *);
249280849Scystatic void free_config_peers(config_tree *);
250280849Scystatic void free_config_phone(config_tree *);
251280849Scystatic void free_config_reset_counters(config_tree *);
252280849Scystatic void free_config_rlimit(config_tree *);
253280849Scystatic void free_config_setvar(config_tree *);
254280849Scystatic void free_config_system_opts(config_tree *);
255280849Scystatic void free_config_tinker(config_tree *);
256280849Scystatic void free_config_tos(config_tree *);
257280849Scystatic void free_config_trap(config_tree *);
258280849Scystatic void free_config_ttl(config_tree *);
259280849Scystatic void free_config_unpeers(config_tree *);
260280849Scystatic void free_config_vars(config_tree *);
261280849Scy
262280849Scy#ifdef SIM
263280849Scystatic void free_config_sim(config_tree *);
264280849Scy#endif
265280849Scystatic void destroy_address_fifo(address_fifo *);
266280849Scy#define FREE_ADDRESS_FIFO(pf)			\
267280849Scy	do {					\
268280849Scy		destroy_address_fifo(pf);	\
269280849Scy		(pf) = NULL;			\
270280849Scy	} while (0)
271280849Scy       void free_all_config_trees(void);	/* atexit() */
272280849Scystatic void free_config_tree(config_tree *ptree);
273280849Scy#endif	/* FREE_CFG_T */
274280849Scy
275280849Scystatic void destroy_restrict_node(restrict_node *my_node);
276280849Scystatic int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
277285169Scystatic void save_and_apply_config_tree(int/*BOOL*/ from_file);
278280849Scystatic void destroy_int_fifo(int_fifo *);
279280849Scy#define FREE_INT_FIFO(pf)			\
280280849Scy	do {					\
281280849Scy		destroy_int_fifo(pf);		\
282280849Scy		(pf) = NULL;			\
283280849Scy	} while (0)
284280849Scystatic void destroy_string_fifo(string_fifo *);
285280849Scy#define FREE_STRING_FIFO(pf)			\
286280849Scy	do {					\
287280849Scy		destroy_string_fifo(pf);		\
288280849Scy		(pf) = NULL;			\
289280849Scy	} while (0)
290280849Scystatic void destroy_attr_val_fifo(attr_val_fifo *);
291280849Scy#define FREE_ATTR_VAL_FIFO(pf)			\
292280849Scy	do {					\
293280849Scy		destroy_attr_val_fifo(pf);	\
294280849Scy		(pf) = NULL;			\
295280849Scy	} while (0)
296280849Scystatic void destroy_filegen_fifo(filegen_fifo *);
297280849Scy#define FREE_FILEGEN_FIFO(pf)			\
298280849Scy	do {					\
299280849Scy		destroy_filegen_fifo(pf);	\
300280849Scy		(pf) = NULL;			\
301280849Scy	} while (0)
302280849Scystatic void destroy_restrict_fifo(restrict_fifo *);
303280849Scy#define FREE_RESTRICT_FIFO(pf)			\
304280849Scy	do {					\
305280849Scy		destroy_restrict_fifo(pf);	\
306280849Scy		(pf) = NULL;			\
307280849Scy	} while (0)
308280849Scystatic void destroy_setvar_fifo(setvar_fifo *);
309280849Scy#define FREE_SETVAR_FIFO(pf)			\
310280849Scy	do {					\
311280849Scy		destroy_setvar_fifo(pf);	\
312280849Scy		(pf) = NULL;			\
313280849Scy	} while (0)
314280849Scystatic void destroy_addr_opts_fifo(addr_opts_fifo *);
315280849Scy#define FREE_ADDR_OPTS_FIFO(pf)			\
316280849Scy	do {					\
317280849Scy		destroy_addr_opts_fifo(pf);	\
318280849Scy		(pf) = NULL;			\
319280849Scy	} while (0)
320280849Scy
321280849Scystatic void config_logconfig(config_tree *);
322280849Scystatic void config_monitor(config_tree *);
323280849Scystatic void config_rlimit(config_tree *);
324280849Scystatic void config_system_opts(config_tree *);
325280849Scystatic void config_tinker(config_tree *);
326330106Sdelphijstatic int  config_tos_clock(config_tree *);
327280849Scystatic void config_tos(config_tree *);
328280849Scystatic void config_vars(config_tree *);
329280849Scy
330280849Scy#ifdef SIM
331280849Scystatic sockaddr_u *get_next_address(address_node *addr);
332280849Scystatic void config_sim(config_tree *);
333280849Scystatic void config_ntpdsim(config_tree *);
334280849Scy#else	/* !SIM follows */
335285169Scystatic void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
336280849Scystatic void config_other_modes(config_tree *);
337280849Scystatic void config_auth(config_tree *);
338358659Scystatic void attrtopsl(int poll, attr_val *avp);
339280849Scystatic void config_access(config_tree *);
340280849Scystatic void config_mdnstries(config_tree *);
341280849Scystatic void config_phone(config_tree *);
342280849Scystatic void config_setvar(config_tree *);
343280849Scystatic void config_ttl(config_tree *);
344280849Scystatic void config_trap(config_tree *);
345280849Scystatic void config_fudge(config_tree *);
346280849Scystatic void config_peers(config_tree *);
347280849Scystatic void config_unpeers(config_tree *);
348285169Scystatic void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
349280849Scystatic void config_reset_counters(config_tree *);
350280849Scystatic u_char get_correct_host_mode(int token);
351280849Scystatic int peerflag_bits(peer_node *);
352280849Scy#endif	/* !SIM */
353280849Scy
354280849Scy#ifdef WORKER
355280849Scystatic void peer_name_resolved(int, int, void *, const char *, const char *,
356280849Scy			const struct addrinfo *,
357280849Scy			const struct addrinfo *);
358280849Scystatic void unpeer_name_resolved(int, int, void *, const char *, const char *,
359280849Scy			  const struct addrinfo *,
360280849Scy			  const struct addrinfo *);
361280849Scystatic void trap_name_resolved(int, int, void *, const char *, const char *,
362280849Scy			const struct addrinfo *,
363280849Scy			const struct addrinfo *);
364280849Scy#endif
365280849Scy
366182007Srobertoenum gnn_type {
367182007Sroberto	t_UNK,		/* Unknown */
368182007Sroberto	t_REF,		/* Refclock */
369182007Sroberto	t_MSK		/* Network Mask */
370280849Scy};
37154359Sroberto
372280849Scystatic void ntpd_set_tod_using(const char *);
373280849Scystatic char * normal_dtoa(double);
374280849Scystatic u_int32 get_pfxmatch(const char **, struct masks *);
375280849Scystatic u_int32 get_match(const char *, struct masks *);
376280849Scystatic u_int32 get_logmask(const char *);
377316068Sdelphijstatic int/*BOOL*/ is_refclk_addr(const address_node * addr);
378316068Sdelphij
379338530Sdelphijstatic void	appendstr(char *, size_t, const char *);
380316068Sdelphij
381330106Sdelphij
382280849Scy#ifndef SIM
383280849Scystatic int getnetnum(const char *num, sockaddr_u *addr, int complain,
384280849Scy		     enum gnn_type a_type);
385280849Scy
386280849Scy#endif
387280849Scy
388316068Sdelphij#if defined(__GNUC__) /* this covers CLANG, too */
389316068Sdelphijstatic void  __attribute__((noreturn,format(printf,1,2))) fatal_error(const char *fmt, ...)
390316068Sdelphij#elif defined(_MSC_VER)
391316068Sdelphijstatic void __declspec(noreturn) fatal_error(const char *fmt, ...)
392316068Sdelphij#else
393316068Sdelphijstatic void fatal_error(const char *fmt, ...)
394316068Sdelphij#endif
395316068Sdelphij{
396316068Sdelphij	va_list va;
397338530Sdelphij
398316068Sdelphij	va_start(va, fmt);
399316068Sdelphij	mvsyslog(LOG_EMERG, fmt, va);
400316068Sdelphij	va_end(va);
401316068Sdelphij	_exit(1);
402316068Sdelphij}
403280849Scy
404338530Sdelphij
405280849Scy/* FUNCTIONS FOR INITIALIZATION
406280849Scy * ----------------------------
40754359Sroberto */
408280849Scy
409280849Scy#ifdef FREE_CFG_T
410280849Scystatic void
411280849Scyfree_auth_node(
412280849Scy	config_tree *ptree
41354359Sroberto	)
41454359Sroberto{
415280849Scy	if (ptree->auth.keys) {
416280849Scy		free(ptree->auth.keys);
417280849Scy		ptree->auth.keys = NULL;
41854359Sroberto	}
419280849Scy
420280849Scy	if (ptree->auth.keysdir) {
421280849Scy		free(ptree->auth.keysdir);
422280849Scy		ptree->auth.keysdir = NULL;
423280849Scy	}
424280849Scy
425280849Scy	if (ptree->auth.ntp_signd_socket) {
426280849Scy		free(ptree->auth.ntp_signd_socket);
427280849Scy		ptree->auth.ntp_signd_socket = NULL;
428280849Scy	}
42954359Sroberto}
430280849Scy#endif /* DEBUG */
43154359Sroberto
432280849Scy
433280849Scystatic void
434280849Scyinit_syntax_tree(
435280849Scy	config_tree *ptree
43654359Sroberto	)
43754359Sroberto{
438280849Scy	ZERO(*ptree);
439280849Scy	ptree->mdnstries = 5;
440280849Scy}
441280849Scy
442280849Scy
443280849Scy#ifdef FREE_CFG_T
444280849Scystatic void
445280849Scyfree_all_config_trees(void)
446280849Scy{
447280849Scy	config_tree *ptree;
448280849Scy	config_tree *pnext;
449280849Scy
450280849Scy	ptree = cfg_tree_history;
451280849Scy
452280849Scy	while (ptree != NULL) {
453280849Scy		pnext = ptree->link;
454280849Scy		free_config_tree(ptree);
455280849Scy		ptree = pnext;
45654359Sroberto	}
45754359Sroberto}
45854359Sroberto
459280849Scy
460280849Scystatic void
461280849Scyfree_config_tree(
462280849Scy	config_tree *ptree
46354359Sroberto	)
46454359Sroberto{
465280849Scy#if defined(_MSC_VER) && defined (_DEBUG)
466280849Scy	_CrtCheckMemory();
467280849Scy#endif
46854359Sroberto
469280849Scy	if (ptree->source.value.s != NULL)
470280849Scy		free(ptree->source.value.s);
47154359Sroberto
472280849Scy	free_config_other_modes(ptree);
473280849Scy	free_config_auth(ptree);
474280849Scy	free_config_tos(ptree);
475280849Scy	free_config_monitor(ptree);
476280849Scy	free_config_access(ptree);
477280849Scy	free_config_tinker(ptree);
478280849Scy	free_config_rlimit(ptree);
479280849Scy	free_config_system_opts(ptree);
480280849Scy	free_config_logconfig(ptree);
481280849Scy	free_config_phone(ptree);
482280849Scy	free_config_setvar(ptree);
483280849Scy	free_config_ttl(ptree);
484280849Scy	free_config_trap(ptree);
485280849Scy	free_config_fudge(ptree);
486280849Scy	free_config_vars(ptree);
487280849Scy	free_config_peers(ptree);
488280849Scy	free_config_unpeers(ptree);
489280849Scy	free_config_nic_rules(ptree);
490280849Scy	free_config_reset_counters(ptree);
491280849Scy#ifdef SIM
492280849Scy	free_config_sim(ptree);
493280849Scy#endif
494280849Scy	free_auth_node(ptree);
49554359Sroberto
496280849Scy	free(ptree);
497280849Scy
498280849Scy#if defined(_MSC_VER) && defined (_DEBUG)
499280849Scy	_CrtCheckMemory();
500280849Scy#endif
50154359Sroberto}
502280849Scy#endif /* FREE_CFG_T */
50354359Sroberto
50454359Sroberto
505280849Scy#ifdef SAVECONFIG
506280849Scy/* Dump all trees */
507280849Scyint
508280849Scydump_all_config_trees(
509280849Scy	FILE *df,
510280849Scy	int comment
51154359Sroberto	)
51254359Sroberto{
513280849Scy	config_tree *	cfg_ptr;
514280849Scy	int		return_value;
515358659Scy	time_t		now = time(NULL);
516358659Scy	struct tm	tm = *localtime(&now);
51754359Sroberto
518358659Scy	fprintf(df, "#NTF:D %04d%02d%02d@%02d:%02d:%02d\n",
519358659Scy		tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
520358659Scy		tm.tm_hour, tm.tm_min, tm.tm_sec);
521358659Scy	fprintf(df, "#NTF:V %s\n", Version);
522358659Scy
523280849Scy	return_value = 0;
524280849Scy	for (cfg_ptr = cfg_tree_history;
525280849Scy	     cfg_ptr != NULL;
526280849Scy	     cfg_ptr = cfg_ptr->link)
527280849Scy		return_value |= dump_config_tree(cfg_ptr, df, comment);
528280849Scy
529280849Scy	return return_value;
530280849Scy}
531280849Scy
532280849Scy
533280849Scy/* The config dumper */
534280849Scyint
535280849Scydump_config_tree(
536280849Scy	config_tree *ptree,
537280849Scy	FILE *df,
538280849Scy	int comment
539280849Scy	)
540280849Scy{
541280849Scy	peer_node *peern;
542280849Scy	unpeer_node *unpeern;
543280849Scy	attr_val *atrv;
544280849Scy	address_node *addr;
545280849Scy	address_node *peer_addr;
546280849Scy	address_node *fudge_addr;
547280849Scy	filegen_node *fgen_node;
548280849Scy	restrict_node *rest_node;
549280849Scy	addr_opts_node *addr_opts;
550280849Scy	setvar_node *setv_node;
551280849Scy	nic_rule_node *rule_node;
552280849Scy	int_node *i_n;
553280849Scy	int_node *counter_set;
554280849Scy	string_node *str_node;
555280849Scy
556280849Scy	const char *s = NULL;
557280849Scy	char *s1;
558280849Scy	char *s2;
559280849Scy	char timestamp[80];
560280849Scy	int enable;
561280849Scy
562280849Scy	DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
563280849Scy
564280849Scy	if (comment) {
565280849Scy		if (!strftime(timestamp, sizeof(timestamp),
566280849Scy			      "%Y-%m-%d %H:%M:%S",
567280849Scy			      localtime(&ptree->timestamp)))
568280849Scy			timestamp[0] = '\0';
569280849Scy
570280849Scy		fprintf(df, "# %s %s %s\n",
571280849Scy			timestamp,
572280849Scy			(CONF_SOURCE_NTPQ == ptree->source.attr)
573280849Scy			    ? "ntpq remote config from"
574280849Scy			    : "startup configuration file",
575280849Scy			ptree->source.value.s);
57654359Sroberto	}
57754359Sroberto
578330106Sdelphij	/*
579330106Sdelphij	 * For options without documentation we just output the name
580330106Sdelphij	 * and its data value
581330106Sdelphij	 */
582280849Scy	atrv = HEAD_PFIFO(ptree->vars);
583280849Scy	for ( ; atrv != NULL; atrv = atrv->link) {
584280849Scy		switch (atrv->type) {
585280849Scy#ifdef DEBUG
586280849Scy		default:
587280849Scy			fprintf(df, "\n# dump error:\n"
588280849Scy				"# unknown vars type %d (%s) for %s\n",
589280849Scy				atrv->type, token_name(atrv->type),
590280849Scy				token_name(atrv->attr));
591280849Scy			break;
592280849Scy#endif
593280849Scy		case T_Double:
594280849Scy			fprintf(df, "%s %s\n", keyword(atrv->attr),
595280849Scy				normal_dtoa(atrv->value.d));
596280849Scy			break;
597280849Scy
598280849Scy		case T_Integer:
599280849Scy			fprintf(df, "%s %d\n", keyword(atrv->attr),
600280849Scy				atrv->value.i);
601280849Scy			break;
602280849Scy
603280849Scy		case T_String:
604280849Scy			fprintf(df, "%s \"%s\"", keyword(atrv->attr),
605280849Scy				atrv->value.s);
606280849Scy			if (T_Driftfile == atrv->attr &&
607280849Scy			    atrv->link != NULL &&
608280849Scy			    T_WanderThreshold == atrv->link->attr) {
609280849Scy				atrv = atrv->link;
610280849Scy				fprintf(df, " %s\n",
611280849Scy					normal_dtoa(atrv->value.d));
612358659Scy			} else if (T_Leapfile == atrv->attr) {
613358659Scy				fputs((atrv->flag
614358659Scy				       ? " checkhash\n"
615358659Scy				       : " ignorehash\n"),
616358659Scy				      df);
617280849Scy			} else {
618280849Scy				fprintf(df, "\n");
619280849Scy			}
620280849Scy			break;
621280849Scy		}
62254359Sroberto	}
62354359Sroberto
624280849Scy	atrv = HEAD_PFIFO(ptree->logconfig);
625280849Scy	if (atrv != NULL) {
626280849Scy		fprintf(df, "logconfig");
627280849Scy		for ( ; atrv != NULL; atrv = atrv->link)
628280849Scy			fprintf(df, " %c%s", atrv->attr, atrv->value.s);
629280849Scy		fprintf(df, "\n");
630280849Scy	}
63154359Sroberto
632280849Scy	if (ptree->stats_dir)
633280849Scy		fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
63454359Sroberto
635280849Scy	i_n = HEAD_PFIFO(ptree->stats_list);
636280849Scy	if (i_n != NULL) {
637280849Scy		fprintf(df, "statistics");
638280849Scy		for ( ; i_n != NULL; i_n = i_n->link)
639280849Scy			fprintf(df, " %s", keyword(i_n->i));
640280849Scy		fprintf(df, "\n");
641280849Scy	}
64254359Sroberto
643280849Scy	fgen_node = HEAD_PFIFO(ptree->filegen_opts);
644280849Scy	for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
645280849Scy		atrv = HEAD_PFIFO(fgen_node->options);
646280849Scy		if (atrv != NULL) {
647280849Scy			fprintf(df, "filegen %s",
648280849Scy				keyword(fgen_node->filegen_token));
649280849Scy			for ( ; atrv != NULL; atrv = atrv->link) {
650280849Scy				switch (atrv->attr) {
651280849Scy#ifdef DEBUG
652280849Scy				default:
653280849Scy					fprintf(df, "\n# dump error:\n"
654280849Scy						"# unknown filegen option token %s\n"
655280849Scy						"filegen %s",
656280849Scy						token_name(atrv->attr),
657280849Scy						keyword(fgen_node->filegen_token));
658280849Scy					break;
659280849Scy#endif
660280849Scy				case T_File:
661280849Scy					fprintf(df, " file %s",
662280849Scy						atrv->value.s);
663280849Scy					break;
66454359Sroberto
665280849Scy				case T_Type:
666280849Scy					fprintf(df, " type %s",
667280849Scy						keyword(atrv->value.i));
668280849Scy					break;
66954359Sroberto
670280849Scy				case T_Flag:
671280849Scy					fprintf(df, " %s",
672280849Scy						keyword(atrv->value.i));
673280849Scy					break;
674280849Scy				}
675280849Scy			}
676280849Scy			fprintf(df, "\n");
677280849Scy		}
678280849Scy	}
67954359Sroberto
680280849Scy	atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
681280849Scy	if (atrv != NULL) {
682280849Scy		fprintf(df, "crypto");
683280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
684280849Scy			fprintf(df, " %s %s", keyword(atrv->attr),
685280849Scy				atrv->value.s);
686280849Scy		}
687280849Scy		fprintf(df, "\n");
688280849Scy	}
68954359Sroberto
690280849Scy	if (ptree->auth.revoke != 0)
691280849Scy		fprintf(df, "revoke %d\n", ptree->auth.revoke);
69254359Sroberto
693280849Scy	if (ptree->auth.keysdir != NULL)
694280849Scy		fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
695280849Scy
696280849Scy	if (ptree->auth.keys != NULL)
697280849Scy		fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
698280849Scy
699280849Scy	atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
700280849Scy	if (atrv != NULL) {
701280849Scy		fprintf(df, "trustedkey");
702280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
703280849Scy			if (T_Integer == atrv->type)
704280849Scy				fprintf(df, " %d", atrv->value.i);
705280849Scy			else if (T_Intrange == atrv->type)
706280849Scy				fprintf(df, " (%d ... %d)",
707280849Scy					atrv->value.r.first,
708280849Scy					atrv->value.r.last);
709280849Scy#ifdef DEBUG
710280849Scy			else
711280849Scy				fprintf(df, "\n# dump error:\n"
712280849Scy					"# unknown trustedkey attr type %d\n"
713280849Scy					"trustedkey", atrv->type);
714280849Scy#endif
71554359Sroberto		}
716280849Scy		fprintf(df, "\n");
71754359Sroberto	}
71854359Sroberto
719280849Scy	if (ptree->auth.control_key)
720280849Scy		fprintf(df, "controlkey %d\n", ptree->auth.control_key);
721260637Sdelphij
722280849Scy	if (ptree->auth.request_key)
723280849Scy		fprintf(df, "requestkey %d\n", ptree->auth.request_key);
724280849Scy
725280849Scy	/* dump enable list, then disable list */
726280849Scy	for (enable = 1; enable >= 0; enable--) {
727280849Scy		atrv = (enable)
728280849Scy			   ? HEAD_PFIFO(ptree->enable_opts)
729280849Scy			   : HEAD_PFIFO(ptree->disable_opts);
730280849Scy		if (atrv != NULL) {
731280849Scy			fprintf(df, "%s", (enable)
732280849Scy					? "enable"
733280849Scy					: "disable");
734280849Scy			for ( ; atrv != NULL; atrv = atrv->link)
735280849Scy				fprintf(df, " %s",
736280849Scy					keyword(atrv->value.i));
737280849Scy			fprintf(df, "\n");
738280849Scy		}
739280849Scy	}
740280849Scy
741280849Scy	atrv = HEAD_PFIFO(ptree->orphan_cmds);
742280849Scy	if (atrv != NULL) {
743280849Scy		fprintf(df, "tos");
744280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
745280849Scy			switch (atrv->type) {
746280849Scy#ifdef DEBUG
747280849Scy			default:
748280849Scy				fprintf(df, "\n# dump error:\n"
749280849Scy					"# unknown tos attr type %d %s\n"
750280849Scy					"tos", atrv->type,
751280849Scy					token_name(atrv->type));
752280849Scy				break;
753280849Scy#endif
754330106Sdelphij			case T_Integer:
755330106Sdelphij				if (atrv->attr == T_Basedate) {
756330106Sdelphij					struct calendar jd;
757330106Sdelphij					ntpcal_rd_to_date(&jd, atrv->value.i + DAY_NTP_STARTS);
758330106Sdelphij					fprintf(df, " %s \"%04hu-%02hu-%02hu\"",
759330106Sdelphij						keyword(atrv->attr), jd.year,
760330106Sdelphij						(u_short)jd.month,
761330106Sdelphij						(u_short)jd.monthday);
762330106Sdelphij				} else {
763330106Sdelphij					fprintf(df, " %s %d",
764330106Sdelphij					keyword(atrv->attr),
765330106Sdelphij					atrv->value.i);
766330106Sdelphij				}
767330106Sdelphij				break;
768338530Sdelphij
769280849Scy			case T_Double:
770280849Scy				fprintf(df, " %s %s",
771280849Scy					keyword(atrv->attr),
772280849Scy					normal_dtoa(atrv->value.d));
773280849Scy				break;
774280849Scy			}
775280849Scy		}
776280849Scy		fprintf(df, "\n");
777280849Scy	}
778280849Scy
779280849Scy	atrv = HEAD_PFIFO(ptree->rlimit);
780280849Scy	if (atrv != NULL) {
781280849Scy		fprintf(df, "rlimit");
782280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
783280849Scy			INSIST(T_Integer == atrv->type);
784280849Scy			fprintf(df, " %s %d", keyword(atrv->attr),
785280849Scy				atrv->value.i);
786280849Scy		}
787280849Scy		fprintf(df, "\n");
788280849Scy	}
789280849Scy
790280849Scy	atrv = HEAD_PFIFO(ptree->tinker);
791280849Scy	if (atrv != NULL) {
792280849Scy		fprintf(df, "tinker");
793280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
794280849Scy			INSIST(T_Double == atrv->type);
795280849Scy			fprintf(df, " %s %s", keyword(atrv->attr),
796280849Scy				normal_dtoa(atrv->value.d));
797280849Scy		}
798280849Scy		fprintf(df, "\n");
799280849Scy	}
800280849Scy
801280849Scy	if (ptree->broadcastclient)
802280849Scy		fprintf(df, "broadcastclient\n");
803280849Scy
804280849Scy	peern = HEAD_PFIFO(ptree->peers);
805280849Scy	for ( ; peern != NULL; peern = peern->link) {
806280849Scy		addr = peern->addr;
807280849Scy		fprintf(df, "%s", keyword(peern->host_mode));
808280849Scy		switch (addr->type) {
809280849Scy#ifdef DEBUG
810280849Scy		default:
811280849Scy			fprintf(df, "# dump error:\n"
812280849Scy				"# unknown peer family %d for:\n"
813280849Scy				"%s", addr->type,
814280849Scy				keyword(peern->host_mode));
815182007Sroberto			break;
816280849Scy#endif
817280849Scy		case AF_UNSPEC:
818280849Scy			break;
81954359Sroberto
820280849Scy		case AF_INET:
821280849Scy			fprintf(df, " -4");
82282498Sroberto			break;
823280849Scy
824280849Scy		case AF_INET6:
825280849Scy			fprintf(df, " -6");
826280849Scy			break;
82782498Sroberto		}
828280849Scy		fprintf(df, " %s", addr->address);
82954359Sroberto
830280849Scy		if (peern->minpoll != 0)
831280849Scy			fprintf(df, " minpoll %u", peern->minpoll);
832280849Scy
833280849Scy		if (peern->maxpoll != 0)
834280849Scy			fprintf(df, " maxpoll %u", peern->maxpoll);
835280849Scy
836280849Scy		if (peern->ttl != 0) {
837280849Scy			if (strlen(addr->address) > 8
838280849Scy			    && !memcmp(addr->address, "127.127.", 8))
839280849Scy				fprintf(df, " mode %u", peern->ttl);
84054359Sroberto			else
841280849Scy				fprintf(df, " ttl %u", peern->ttl);
842280849Scy		}
84354359Sroberto
844280849Scy		if (peern->peerversion != NTP_VERSION)
845280849Scy			fprintf(df, " version %u", peern->peerversion);
84654359Sroberto
847280849Scy		if (peern->peerkey != 0)
848280849Scy			fprintf(df, " key %u", peern->peerkey);
849132451Sroberto
850280849Scy		if (peern->group != NULL)
851280849Scy			fprintf(df, " ident \"%s\"", peern->group);
85254359Sroberto
853280849Scy		atrv = HEAD_PFIFO(peern->peerflags);
854280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
855280849Scy			INSIST(T_Flag == atrv->attr);
856280849Scy			INSIST(T_Integer == atrv->type);
857280849Scy			fprintf(df, " %s", keyword(atrv->value.i));
858280849Scy		}
859280849Scy
860280849Scy		fprintf(df, "\n");
861280849Scy
862280849Scy		addr_opts = HEAD_PFIFO(ptree->fudge);
863280849Scy		for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
864280849Scy			peer_addr = peern->addr;
865280849Scy			fudge_addr = addr_opts->addr;
866280849Scy
867280849Scy			s1 = peer_addr->address;
868280849Scy			s2 = fudge_addr->address;
869280849Scy
870280849Scy			if (strcmp(s1, s2))
871280849Scy				continue;
872280849Scy
873280849Scy			fprintf(df, "fudge %s", s1);
874280849Scy
875280849Scy			for (atrv = HEAD_PFIFO(addr_opts->options);
876280849Scy			     atrv != NULL;
877280849Scy			     atrv = atrv->link) {
878280849Scy
879280849Scy				switch (atrv->type) {
880280849Scy#ifdef DEBUG
881280849Scy				default:
882280849Scy					fprintf(df, "\n# dump error:\n"
883280849Scy						"# unknown fudge atrv->type %d\n"
884280849Scy						"fudge %s", atrv->type,
885280849Scy						s1);
886280849Scy					break;
88754359Sroberto#endif
888280849Scy				case T_Double:
889280849Scy					fprintf(df, " %s %s",
890280849Scy						keyword(atrv->attr),
891280849Scy						normal_dtoa(atrv->value.d));
89254359Sroberto					break;
893280849Scy
894280849Scy				case T_Integer:
895280849Scy					fprintf(df, " %s %d",
896280849Scy						keyword(atrv->attr),
897280849Scy						atrv->value.i);
898280849Scy					break;
899280849Scy
900280849Scy				case T_String:
901280849Scy					fprintf(df, " %s %s",
902280849Scy						keyword(atrv->attr),
903280849Scy						atrv->value.s);
904280849Scy					break;
90554359Sroberto				}
906280849Scy			}
907280849Scy			fprintf(df, "\n");
908280849Scy		}
909280849Scy	}
910280849Scy
911280849Scy	addr = HEAD_PFIFO(ptree->manycastserver);
912280849Scy	if (addr != NULL) {
913280849Scy		fprintf(df, "manycastserver");
914280849Scy		for ( ; addr != NULL; addr = addr->link)
915280849Scy			fprintf(df, " %s", addr->address);
916280849Scy		fprintf(df, "\n");
917280849Scy	}
918280849Scy
919280849Scy	addr = HEAD_PFIFO(ptree->multicastclient);
920280849Scy	if (addr != NULL) {
921280849Scy		fprintf(df, "multicastclient");
922280849Scy		for ( ; addr != NULL; addr = addr->link)
923280849Scy			fprintf(df, " %s", addr->address);
924280849Scy		fprintf(df, "\n");
925280849Scy	}
926280849Scy
927280849Scy
928280849Scy	for (unpeern = HEAD_PFIFO(ptree->unpeers);
929280849Scy	     unpeern != NULL;
930280849Scy	     unpeern = unpeern->link)
931280849Scy		fprintf(df, "unpeer %s\n", unpeern->addr->address);
932280849Scy
933280849Scy	atrv = HEAD_PFIFO(ptree->mru_opts);
934280849Scy	if (atrv != NULL) {
935280849Scy		fprintf(df, "mru");
936280849Scy		for ( ;	atrv != NULL; atrv = atrv->link)
937280849Scy			fprintf(df, " %s %d", keyword(atrv->attr),
938280849Scy				atrv->value.i);
939280849Scy		fprintf(df, "\n");
940280849Scy	}
941280849Scy
942280849Scy	atrv = HEAD_PFIFO(ptree->discard_opts);
943280849Scy	if (atrv != NULL) {
944280849Scy		fprintf(df, "discard");
945280849Scy		for ( ;	atrv != NULL; atrv = atrv->link)
946280849Scy			fprintf(df, " %s %d", keyword(atrv->attr),
947280849Scy				atrv->value.i);
948280849Scy		fprintf(df, "\n");
949280849Scy	}
950280849Scy
951358659Scy	atrv = HEAD_PFIFO(ptree->pollskewlist);
952358659Scy	if (atrv != NULL) {
953358659Scy		fprintf(df, "pollskewlist");
954358659Scy		for ( ; atrv != NULL; atrv = atrv->link) {
955358659Scy			if (-1 == atrv->attr) {
956358659Scy				fprintf(df, " default");
957358659Scy			} else {
958358659Scy				fprintf(df, " %d", atrv->attr);
959358659Scy			}
960358659Scy			fprintf(df, " %d|%d",
961358659Scy				atrv->value.r.first, atrv->value.r.last);
962358659Scy		}
963358659Scy		fprintf(df, "\n");
964358659Scy	}
965358659Scy
966280849Scy	for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
967280849Scy	     rest_node != NULL;
968280849Scy	     rest_node = rest_node->link) {
969330106Sdelphij		int is_default = 0;
970280849Scy
971280849Scy		if (NULL == rest_node->addr) {
972280849Scy			s = "default";
973330106Sdelphij			/* Don't need to set is_default=1 here */
974358659Scy			atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
975358659Scy			for ( ; atrv != NULL; atrv = atrv->link) {
976358659Scy				if (   T_Integer == atrv->type
977358659Scy				    && T_Source == atrv->attr) {
978280849Scy					s = "source";
979280849Scy					break;
980338530Sdelphij				}
981330106Sdelphij			}
982280849Scy		} else {
983330106Sdelphij			const char *ap = rest_node->addr->address;
984330106Sdelphij			const char *mp = "";
985330106Sdelphij
986330106Sdelphij			if (rest_node->mask)
987330106Sdelphij				mp = rest_node->mask->address;
988330106Sdelphij
989330106Sdelphij			if (   rest_node->addr->type == AF_INET
990330106Sdelphij			    && !strcmp(ap, "0.0.0.0")
991330106Sdelphij			    && !strcmp(mp, "0.0.0.0")) {
992330106Sdelphij				is_default = 1;
993330106Sdelphij				s = "-4 default";
994330106Sdelphij			} else if (   rest_node->mask
995330106Sdelphij				   && rest_node->mask->type == AF_INET6
996330106Sdelphij				   && !strcmp(ap, "::")
997330106Sdelphij				   && !strcmp(mp, "::")) {
998330106Sdelphij				is_default = 1;
999330106Sdelphij				s = "-6 default";
1000330106Sdelphij			} else {
1001330106Sdelphij				s = ap;
1002330106Sdelphij			}
1003280849Scy		}
1004280849Scy		fprintf(df, "restrict %s", s);
1005330106Sdelphij		if (rest_node->mask != NULL && !is_default)
1006280849Scy			fprintf(df, " mask %s",
1007280849Scy				rest_node->mask->address);
1008330106Sdelphij		fprintf(df, " ippeerlimit %d", rest_node->ippeerlimit);
1009358659Scy		atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1010358659Scy		for ( ; atrv != NULL; atrv = atrv->link) {
1011358659Scy			if (   T_Integer == atrv->type
1012358659Scy			    && T_Source != atrv->attr) {
1013358659Scy				fprintf(df, " %s", keyword(atrv->attr));
1014358659Scy			}
1015358659Scy		}
1016358659Scy		fprintf(df, "\n");
1017358659Scy/**/
1018358659Scy#if 0
1019358659Scymsyslog(LOG_INFO, "Dumping flag_tok_fifo:");
1020358659Scyatrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1021358659Scyfor ( ; atrv != NULL; atrv = atrv->link) {
1022358659Scy	msyslog(LOG_INFO, "- flag_tok_fifo: flags: %08x", atrv->flag);
1023358659Scy	switch(atrv->type) {
1024358659Scy	    case T_Integer:
1025358659Scy		msyslog(LOG_INFO, "- T_Integer: attr <%s>/%d, value %d",
1026358659Scy			keyword(atrv->attr), atrv->attr, atrv->value.i);
1027358659Scy		break;
1028358659Scy	    default:
1029358659Scy		msyslog(LOG_INFO, "- Other: attr <%s>/%d, value ???",
1030358659Scy			keyword(atrv->attr), atrv->attr);
1031358659Scy		break;
1032358659Scy
1033280849Scy	}
1034358659Scy}
1035358659Scy#endif
1036358659Scy/**/
1037358659Scy	}
1038280849Scy
1039280849Scy	rule_node = HEAD_PFIFO(ptree->nic_rules);
1040280849Scy	for ( ; rule_node != NULL; rule_node = rule_node->link) {
1041280849Scy		fprintf(df, "interface %s %s\n",
1042280849Scy			keyword(rule_node->action),
1043280849Scy			(rule_node->match_class)
1044280849Scy			    ? keyword(rule_node->match_class)
1045280849Scy			    : rule_node->if_name);
1046280849Scy	}
1047280849Scy
1048280849Scy	str_node = HEAD_PFIFO(ptree->phone);
1049280849Scy	if (str_node != NULL) {
1050280849Scy		fprintf(df, "phone");
1051280849Scy		for ( ; str_node != NULL; str_node = str_node->link)
1052280849Scy			fprintf(df, " \"%s\"", str_node->s);
1053280849Scy		fprintf(df, "\n");
1054280849Scy	}
1055280849Scy
1056280849Scy	setv_node = HEAD_PFIFO(ptree->setvar);
1057280849Scy	for ( ; setv_node != NULL; setv_node = setv_node->link) {
1058280849Scy		s1 = quote_if_needed(setv_node->var);
1059280849Scy		s2 = quote_if_needed(setv_node->val);
1060280849Scy		fprintf(df, "setvar %s = %s", s1, s2);
1061280849Scy		free(s1);
1062280849Scy		free(s2);
1063280849Scy		if (setv_node->isdefault)
1064280849Scy			fprintf(df, " default");
1065280849Scy		fprintf(df, "\n");
1066280849Scy	}
1067280849Scy
1068280849Scy	i_n = HEAD_PFIFO(ptree->ttl);
1069280849Scy	if (i_n != NULL) {
1070280849Scy		fprintf(df, "ttl");
1071280849Scy		for( ; i_n != NULL; i_n = i_n->link)
1072280849Scy			fprintf(df, " %d", i_n->i);
1073280849Scy		fprintf(df, "\n");
1074280849Scy	}
1075280849Scy
1076280849Scy	addr_opts = HEAD_PFIFO(ptree->trap);
1077280849Scy	for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
1078280849Scy		addr = addr_opts->addr;
1079280849Scy		fprintf(df, "trap %s", addr->address);
1080280849Scy		atrv = HEAD_PFIFO(addr_opts->options);
1081280849Scy		for ( ; atrv != NULL; atrv = atrv->link) {
1082280849Scy			switch (atrv->attr) {
1083280849Scy#ifdef DEBUG
1084280849Scy			default:
1085280849Scy				fprintf(df, "\n# dump error:\n"
1086280849Scy					"# unknown trap token %d\n"
1087280849Scy					"trap %s", atrv->attr,
1088280849Scy					addr->address);
1089280849Scy				break;
1090132451Sroberto#endif
1091280849Scy			case T_Port:
1092280849Scy				fprintf(df, " port %d", atrv->value.i);
1093182007Sroberto				break;
1094182007Sroberto
1095280849Scy			case T_Interface:
1096280849Scy				fprintf(df, " interface %s",
1097280849Scy					atrv->value.s);
1098280849Scy				break;
1099280849Scy			}
1100280849Scy		}
1101280849Scy		fprintf(df, "\n");
1102280849Scy	}
110354359Sroberto
1104280849Scy	counter_set = HEAD_PFIFO(ptree->reset_counters);
1105280849Scy	if (counter_set != NULL) {
1106280849Scy		fprintf(df, "reset");
1107280849Scy		for ( ; counter_set != NULL;
1108280849Scy		     counter_set = counter_set->link)
1109280849Scy			fprintf(df, " %s", keyword(counter_set->i));
1110280849Scy		fprintf(df, "\n");
1111280849Scy	}
111254359Sroberto
1113280849Scy	return 0;
1114280849Scy}
1115280849Scy#endif	/* SAVECONFIG */
111654359Sroberto
111754359Sroberto
1118280849Scy/* generic fifo routines for structs linked by 1st member */
1119280849Scyvoid *
1120280849Scyappend_gen_fifo(
1121280849Scy	void *fifo,
1122280849Scy	void *entry
1123280849Scy	)
1124280849Scy{
1125280849Scy	gen_fifo *pf;
1126280849Scy	gen_node *pe;
112754359Sroberto
1128280849Scy	pf = fifo;
1129280849Scy	pe = entry;
1130280849Scy	if (NULL == pf)
1131280849Scy		pf = emalloc_zero(sizeof(*pf));
1132280849Scy	else
1133280849Scy		CHECK_FIFO_CONSISTENCY(*pf);
1134280849Scy	if (pe != NULL)
1135280849Scy		LINK_FIFO(*pf, pe, link);
1136280849Scy	CHECK_FIFO_CONSISTENCY(*pf);
1137182007Sroberto
1138280849Scy	return pf;
1139280849Scy}
114054359Sroberto
1141182007Sroberto
1142280849Scyvoid *
1143280849Scyconcat_gen_fifos(
1144280849Scy	void *first,
1145280849Scy	void *second
1146280849Scy	)
1147280849Scy{
1148280849Scy	gen_fifo *pf1;
1149280849Scy	gen_fifo *pf2;
1150182007Sroberto
1151280849Scy	pf1 = first;
1152280849Scy	pf2 = second;
1153280849Scy	if (NULL == pf1)
1154280849Scy		return pf2;
1155280849Scy	if (NULL == pf2)
1156280849Scy		return pf1;
115754359Sroberto
1158280849Scy	CONCAT_FIFO(*pf1, *pf2, link);
1159280849Scy	free(pf2);
116054359Sroberto
1161280849Scy	return pf1;
1162280849Scy}
116354359Sroberto
1164330106Sdelphijvoid*
1165330106Sdelphijdestroy_gen_fifo(
1166330106Sdelphij	void        *fifo,
1167330106Sdelphij	fifo_deleter func
1168330106Sdelphij	)
1169330106Sdelphij{
1170330106Sdelphij	any_node *	np  = NULL;
1171330106Sdelphij	any_node_fifo *	pf1 = fifo;
117254359Sroberto
1173330106Sdelphij	if (pf1 != NULL) {
1174330106Sdelphij		if (!func)
1175330106Sdelphij			func = free;
1176330106Sdelphij		for (;;) {
1177330106Sdelphij			UNLINK_FIFO(np, *pf1, link);
1178330106Sdelphij			if (np == NULL)
1179330106Sdelphij				break;
1180330106Sdelphij			(*func)(np);
1181330106Sdelphij		}
1182330106Sdelphij		free(pf1);
1183330106Sdelphij	}
1184330106Sdelphij	return NULL;
1185330106Sdelphij}
1186330106Sdelphij
1187280849Scy/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
1188280849Scy * -----------------------------------------------
1189280849Scy */
119054359Sroberto
1191330106Sdelphijvoid
1192330106Sdelphijdestroy_attr_val(
1193330106Sdelphij	attr_val *	av
1194330106Sdelphij	)
1195330106Sdelphij{
1196330106Sdelphij	if (av) {
1197330106Sdelphij		if (T_String == av->type)
1198330106Sdelphij			free(av->value.s);
1199330106Sdelphij		free(av);
1200330106Sdelphij	}
1201330106Sdelphij}
1202330106Sdelphij
1203280849Scyattr_val *
1204280849Scycreate_attr_dval(
1205280849Scy	int attr,
1206280849Scy	double value
1207280849Scy	)
1208280849Scy{
1209280849Scy	attr_val *my_val;
121082498Sroberto
1211280849Scy	my_val = emalloc_zero(sizeof(*my_val));
1212280849Scy	my_val->attr = attr;
1213280849Scy	my_val->value.d = value;
1214280849Scy	my_val->type = T_Double;
121582498Sroberto
1216280849Scy	return my_val;
1217280849Scy}
121854359Sroberto
1219280849Scy
1220280849Scyattr_val *
1221280849Scycreate_attr_ival(
1222280849Scy	int attr,
1223280849Scy	int value
1224280849Scy	)
1225280849Scy{
1226280849Scy	attr_val *my_val;
1227280849Scy
1228280849Scy	my_val = emalloc_zero(sizeof(*my_val));
1229280849Scy	my_val->attr = attr;
1230280849Scy	my_val->value.i = value;
1231280849Scy	my_val->type = T_Integer;
1232280849Scy
1233280849Scy	return my_val;
1234280849Scy}
1235280849Scy
1236280849Scy
1237280849Scyattr_val *
1238280849Scycreate_attr_uval(
1239280849Scy	int	attr,
1240280849Scy	u_int	value
1241280849Scy	)
1242280849Scy{
1243280849Scy	attr_val *my_val;
1244280849Scy
1245280849Scy	my_val = emalloc_zero(sizeof(*my_val));
1246280849Scy	my_val->attr = attr;
1247280849Scy	my_val->value.u = value;
1248280849Scy	my_val->type = T_U_int;
1249280849Scy
1250280849Scy	return my_val;
1251280849Scy}
1252280849Scy
1253280849Scy
1254280849Scyattr_val *
1255358659Scycreate_attr_rval(
1256280849Scy	int	attr,
1257280849Scy	int	first,
1258280849Scy	int	last
1259280849Scy	)
1260280849Scy{
1261280849Scy	attr_val *my_val;
1262280849Scy
1263280849Scy	my_val = emalloc_zero(sizeof(*my_val));
1264280849Scy	my_val->attr = attr;
1265280849Scy	my_val->value.r.first = first;
1266280849Scy	my_val->value.r.last = last;
1267280849Scy	my_val->type = T_Intrange;
1268280849Scy
1269280849Scy	return my_val;
1270280849Scy}
1271280849Scy
1272280849Scy
1273280849Scyattr_val *
1274280849Scycreate_attr_sval(
1275280849Scy	int attr,
1276280849Scy	const char *s
1277280849Scy	)
1278280849Scy{
1279280849Scy	attr_val *my_val;
1280280849Scy
1281280849Scy	my_val = emalloc_zero(sizeof(*my_val));
1282280849Scy	my_val->attr = attr;
1283280849Scy	if (NULL == s)			/* free() hates NULL */
1284280849Scy		s = estrdup("");
1285280849Scy	my_val->value.s = _UC(s);
1286280849Scy	my_val->type = T_String;
1287280849Scy
1288280849Scy	return my_val;
1289280849Scy}
1290280849Scy
1291280849Scy
1292280849Scyint_node *
1293280849Scycreate_int_node(
1294280849Scy	int val
1295280849Scy	)
1296280849Scy{
1297280849Scy	int_node *i_n;
1298280849Scy
1299280849Scy	i_n = emalloc_zero(sizeof(*i_n));
1300280849Scy	i_n->i = val;
1301280849Scy
1302280849Scy	return i_n;
1303280849Scy}
1304280849Scy
1305280849Scy
1306280849Scystring_node *
1307280849Scycreate_string_node(
1308280849Scy	char *str
1309280849Scy	)
1310280849Scy{
1311280849Scy	string_node *sn;
1312280849Scy
1313280849Scy	sn = emalloc_zero(sizeof(*sn));
1314280849Scy	sn->s = str;
1315280849Scy
1316280849Scy	return sn;
1317280849Scy}
1318280849Scy
1319280849Scy
1320280849Scyaddress_node *
1321280849Scycreate_address_node(
1322280849Scy	char *	addr,
1323280849Scy	int	type
1324280849Scy	)
1325280849Scy{
1326280849Scy	address_node *my_node;
1327280849Scy
1328289764Sglebius	REQUIRE(NULL != addr);
1329289764Sglebius	REQUIRE(AF_INET == type || AF_INET6 == type || AF_UNSPEC == type);
1330280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1331280849Scy	my_node->address = addr;
1332280849Scy	my_node->type = (u_short)type;
1333280849Scy
1334280849Scy	return my_node;
1335280849Scy}
1336280849Scy
1337280849Scy
1338280849Scyvoid
1339280849Scydestroy_address_node(
1340280849Scy	address_node *my_node
1341280849Scy	)
1342280849Scy{
1343280849Scy	if (NULL == my_node)
1344280849Scy		return;
1345289764Sglebius	REQUIRE(NULL != my_node->address);
1346280849Scy
1347280849Scy	free(my_node->address);
1348280849Scy	free(my_node);
1349280849Scy}
1350280849Scy
1351280849Scy
1352280849Scypeer_node *
1353280849Scycreate_peer_node(
1354280849Scy	int		hmode,
1355280849Scy	address_node *	addr,
1356280849Scy	attr_val_fifo *	options
1357280849Scy	)
1358280849Scy{
1359280849Scy	peer_node *my_node;
1360280849Scy	attr_val *option;
1361280849Scy	int freenode;
1362280849Scy	int errflag = 0;
1363280849Scy
1364280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1365280849Scy
1366280849Scy	/* Initialize node values to default */
1367280849Scy	my_node->peerversion = NTP_VERSION;
1368280849Scy
1369280849Scy	/* Now set the node to the read values */
1370280849Scy	my_node->host_mode = hmode;
1371280849Scy	my_node->addr = addr;
1372280849Scy
1373280849Scy	/*
1374280849Scy	 * the options FIFO mixes items that will be saved in the
1375280849Scy	 * peer_node as explicit members, such as minpoll, and
1376280849Scy	 * those that are moved intact to the peer_node's peerflags
1377280849Scy	 * FIFO.  The options FIFO is consumed and reclaimed here.
1378280849Scy	 */
1379280849Scy
1380280849Scy	if (options != NULL)
1381280849Scy		CHECK_FIFO_CONSISTENCY(*options);
1382280849Scy	while (options != NULL) {
1383280849Scy		UNLINK_FIFO(option, *options, link);
1384280849Scy		if (NULL == option) {
1385280849Scy			free(options);
138654359Sroberto			break;
1387280849Scy		}
138854359Sroberto
1389280849Scy		freenode = 1;
1390280849Scy		/* Check the kind of option being set */
1391280849Scy		switch (option->attr) {
139254359Sroberto
1393280849Scy		case T_Flag:
1394280849Scy			APPEND_G_FIFO(my_node->peerflags, option);
1395280849Scy			freenode = 0;
1396280849Scy			break;
139754359Sroberto
1398280849Scy		case T_Minpoll:
1399280849Scy			if (option->value.i < NTP_MINPOLL ||
1400280849Scy			    option->value.i > UCHAR_MAX) {
1401280849Scy				msyslog(LOG_INFO,
1402280849Scy					"minpoll: provided value (%d) is out of range [%d-%d])",
1403280849Scy					option->value.i, NTP_MINPOLL,
1404280849Scy					UCHAR_MAX);
1405280849Scy				my_node->minpoll = NTP_MINPOLL;
1406280849Scy			} else {
1407280849Scy				my_node->minpoll =
1408280849Scy					(u_char)option->value.u;
140954359Sroberto			}
141054359Sroberto			break;
141154359Sroberto
1412280849Scy		case T_Maxpoll:
1413280849Scy			if (option->value.i < 0 ||
1414280849Scy			    option->value.i > NTP_MAXPOLL) {
1415280849Scy				msyslog(LOG_INFO,
1416280849Scy					"maxpoll: provided value (%d) is out of range [0-%d])",
1417280849Scy					option->value.i, NTP_MAXPOLL);
1418280849Scy				my_node->maxpoll = NTP_MAXPOLL;
1419182007Sroberto			} else {
1420280849Scy				my_node->maxpoll =
1421280849Scy					(u_char)option->value.u;
1422182007Sroberto			}
142354359Sroberto			break;
1424132451Sroberto
1425280849Scy		case T_Ttl:
1426316068Sdelphij			if (is_refclk_addr(addr)) {
1427316068Sdelphij				msyslog(LOG_ERR, "'ttl' does not apply for refclocks");
1428316068Sdelphij				errflag = 1;
1429316068Sdelphij			} else if (option->value.u >= MAX_TTL) {
1430280849Scy				msyslog(LOG_ERR, "ttl: invalid argument");
1431280849Scy				errflag = 1;
1432280849Scy			} else {
1433280849Scy				my_node->ttl = (u_char)option->value.u;
1434280849Scy			}
1435280849Scy			break;
1436132451Sroberto
1437280849Scy		case T_Mode:
1438316068Sdelphij			if (is_refclk_addr(addr)) {
1439316068Sdelphij				my_node->ttl = option->value.u;
1440316068Sdelphij			} else {
1441316068Sdelphij				msyslog(LOG_ERR, "'mode' does not apply for network peers");
1442316068Sdelphij				errflag = 1;
1443316068Sdelphij			}
144454359Sroberto			break;
144554359Sroberto
1446280849Scy		case T_Key:
1447280849Scy			if (option->value.u >= KEYID_T_MAX) {
1448280849Scy				msyslog(LOG_ERR, "key: invalid argument");
1449280849Scy				errflag = 1;
1450280849Scy			} else {
1451280849Scy				my_node->peerkey =
1452280849Scy					(keyid_t)option->value.u;
145354359Sroberto			}
1454132451Sroberto			break;
145554359Sroberto
1456280849Scy		case T_Version:
1457280849Scy			if (option->value.u >= UCHAR_MAX) {
1458280849Scy				msyslog(LOG_ERR, "version: invalid argument");
1459280849Scy				errflag = 1;
1460280849Scy			} else {
1461280849Scy				my_node->peerversion =
1462280849Scy					(u_char)option->value.u;
146354359Sroberto			}
146454359Sroberto			break;
146554359Sroberto
1466280849Scy		case T_Ident:
1467280849Scy			my_node->group = option->value.s;
1468280849Scy			break;
146982498Sroberto
1470280849Scy		default:
1471280849Scy			msyslog(LOG_ERR,
1472280849Scy				"Unknown peer/server option token %s",
1473280849Scy				token_name(option->attr));
1474280849Scy			errflag = 1;
1475280849Scy		}
1476280849Scy		if (freenode)
1477280849Scy			free(option);
1478280849Scy	}
1479280849Scy
1480280849Scy	/* Check if errors were reported. If yes, ignore the node */
1481280849Scy	if (errflag) {
1482280849Scy		free(my_node);
1483280849Scy		my_node = NULL;
1484280849Scy	}
1485280849Scy
1486280849Scy	return my_node;
1487280849Scy}
1488280849Scy
1489280849Scy
1490280849Scyunpeer_node *
1491280849Scycreate_unpeer_node(
1492280849Scy	address_node *addr
1493280849Scy	)
1494280849Scy{
1495280849Scy	unpeer_node *	my_node;
1496316068Sdelphij	u_long		u;
1497316068Sdelphij	const u_char *	pch;
1498280849Scy
1499280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1500280849Scy
1501280849Scy	/*
1502280849Scy	 * From the parser's perspective an association ID fits into
1503280849Scy	 * its generic T_String definition of a name/address "address".
1504280849Scy	 * We treat all valid 16-bit numbers as association IDs.
1505280849Scy	 */
1506316068Sdelphij	for (u = 0, pch = (u_char*)addr->address; isdigit(*pch); ++pch) {
1507316068Sdelphij		/* accumulate with overflow retention */
1508316068Sdelphij		u = (10 * u + *pch - '0') | (u & 0xFF000000u);
1509316068Sdelphij	}
1510338530Sdelphij
1511316068Sdelphij	if (!*pch && u <= ASSOCID_MAX) {
1512280849Scy		my_node->assocID = (associd_t)u;
1513316068Sdelphij		my_node->addr = NULL;
1514280849Scy		destroy_address_node(addr);
1515280849Scy	} else {
1516280849Scy		my_node->assocID = 0;
1517280849Scy		my_node->addr = addr;
1518280849Scy	}
1519280849Scy
1520280849Scy	return my_node;
1521280849Scy}
1522280849Scy
1523280849Scyfilegen_node *
1524280849Scycreate_filegen_node(
1525280849Scy	int		filegen_token,
1526280849Scy	attr_val_fifo *	options
1527280849Scy	)
1528280849Scy{
1529280849Scy	filegen_node *my_node;
1530280849Scy
1531280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1532280849Scy	my_node->filegen_token = filegen_token;
1533280849Scy	my_node->options = options;
1534280849Scy
1535280849Scy	return my_node;
1536280849Scy}
1537280849Scy
1538280849Scy
1539280849Scyrestrict_node *
1540280849Scycreate_restrict_node(
1541280849Scy	address_node *	addr,
1542280849Scy	address_node *	mask,
1543330106Sdelphij	short		ippeerlimit,
1544358659Scy	attr_val_fifo *	flag_tok_fifo,
1545358659Scy	int		nline
1546280849Scy	)
1547280849Scy{
1548280849Scy	restrict_node *my_node;
1549280849Scy
1550280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1551280849Scy	my_node->addr = addr;
1552280849Scy	my_node->mask = mask;
1553330106Sdelphij	my_node->ippeerlimit = ippeerlimit;
1554330106Sdelphij	my_node->flag_tok_fifo = flag_tok_fifo;
1555358659Scy	my_node->line_no = nline;
1556280849Scy
1557280849Scy	return my_node;
1558280849Scy}
1559280849Scy
1560280849Scy
1561280849Scystatic void
1562280849Scydestroy_restrict_node(
1563280849Scy	restrict_node *my_node
1564280849Scy	)
1565280849Scy{
1566280849Scy	/* With great care, free all the memory occupied by
1567280849Scy	 * the restrict node
1568280849Scy	 */
1569280849Scy	destroy_address_node(my_node->addr);
1570280849Scy	destroy_address_node(my_node->mask);
1571358659Scy	destroy_attr_val_fifo(my_node->flag_tok_fifo);
1572280849Scy	free(my_node);
1573280849Scy}
1574280849Scy
1575280849Scy
1576280849Scystatic void
1577280849Scydestroy_int_fifo(
1578280849Scy	int_fifo *	fifo
1579280849Scy	)
1580280849Scy{
1581280849Scy	int_node *	i_n;
1582280849Scy
1583280849Scy	if (fifo != NULL) {
1584280849Scy		for (;;) {
1585280849Scy			UNLINK_FIFO(i_n, *fifo, link);
1586280849Scy			if (i_n == NULL)
158782498Sroberto				break;
1588280849Scy			free(i_n);
1589280849Scy		}
1590280849Scy		free(fifo);
1591280849Scy	}
1592280849Scy}
1593132451Sroberto
1594280849Scy
1595280849Scystatic void
1596280849Scydestroy_string_fifo(
1597280849Scy	string_fifo *	fifo
1598280849Scy	)
1599280849Scy{
1600280849Scy	string_node *	sn;
1601280849Scy
1602280849Scy	if (fifo != NULL) {
1603280849Scy		for (;;) {
1604280849Scy			UNLINK_FIFO(sn, *fifo, link);
1605280849Scy			if (sn == NULL)
160682498Sroberto				break;
1607280849Scy			free(sn->s);
1608280849Scy			free(sn);
1609280849Scy		}
1610280849Scy		free(fifo);
1611280849Scy	}
1612280849Scy}
161382498Sroberto
1614280849Scy
1615280849Scystatic void
1616280849Scydestroy_attr_val_fifo(
1617280849Scy	attr_val_fifo *	av_fifo
1618280849Scy	)
1619280849Scy{
1620280849Scy	attr_val *	av;
1621280849Scy
1622280849Scy	if (av_fifo != NULL) {
1623280849Scy		for (;;) {
1624280849Scy			UNLINK_FIFO(av, *av_fifo, link);
1625280849Scy			if (av == NULL)
162682498Sroberto				break;
1627330106Sdelphij			destroy_attr_val(av);
1628280849Scy		}
1629280849Scy		free(av_fifo);
1630280849Scy	}
1631280849Scy}
163282498Sroberto
1633280849Scy
1634280849Scystatic void
1635280849Scydestroy_filegen_fifo(
1636280849Scy	filegen_fifo *	fifo
1637280849Scy	)
1638280849Scy{
1639280849Scy	filegen_node *	fg;
1640280849Scy
1641280849Scy	if (fifo != NULL) {
1642280849Scy		for (;;) {
1643280849Scy			UNLINK_FIFO(fg, *fifo, link);
1644280849Scy			if (fg == NULL)
164582498Sroberto				break;
1646280849Scy			destroy_attr_val_fifo(fg->options);
1647280849Scy			free(fg);
1648280849Scy		}
1649280849Scy		free(fifo);
1650280849Scy	}
1651280849Scy}
165282498Sroberto
1653280849Scy
1654280849Scystatic void
1655280849Scydestroy_restrict_fifo(
1656280849Scy	restrict_fifo *	fifo
1657280849Scy	)
1658280849Scy{
1659280849Scy	restrict_node *	rn;
1660280849Scy
1661280849Scy	if (fifo != NULL) {
1662280849Scy		for (;;) {
1663280849Scy			UNLINK_FIFO(rn, *fifo, link);
1664280849Scy			if (rn == NULL)
166582498Sroberto				break;
1666280849Scy			destroy_restrict_node(rn);
1667280849Scy		}
1668280849Scy		free(fifo);
1669280849Scy	}
1670280849Scy}
167182498Sroberto
1672280849Scy
1673280849Scystatic void
1674280849Scydestroy_setvar_fifo(
1675280849Scy	setvar_fifo *	fifo
1676280849Scy	)
1677280849Scy{
1678280849Scy	setvar_node *	sv;
1679280849Scy
1680280849Scy	if (fifo != NULL) {
1681280849Scy		for (;;) {
1682280849Scy			UNLINK_FIFO(sv, *fifo, link);
1683280849Scy			if (sv == NULL)
168482498Sroberto				break;
1685280849Scy			free(sv->var);
1686280849Scy			free(sv->val);
1687280849Scy			free(sv);
1688280849Scy		}
1689280849Scy		free(fifo);
1690280849Scy	}
1691280849Scy}
169282498Sroberto
1693280849Scy
1694280849Scystatic void
1695280849Scydestroy_addr_opts_fifo(
1696280849Scy	addr_opts_fifo *	fifo
1697280849Scy	)
1698280849Scy{
1699280849Scy	addr_opts_node *	aon;
1700280849Scy
1701280849Scy	if (fifo != NULL) {
1702280849Scy		for (;;) {
1703280849Scy			UNLINK_FIFO(aon, *fifo, link);
1704280849Scy			if (aon == NULL)
170582498Sroberto				break;
1706280849Scy			destroy_address_node(aon->addr);
1707280849Scy			destroy_attr_val_fifo(aon->options);
1708280849Scy			free(aon);
1709280849Scy		}
1710280849Scy		free(fifo);
1711280849Scy	}
1712280849Scy}
1713132451Sroberto
1714280849Scy
1715280849Scysetvar_node *
1716280849Scycreate_setvar_node(
1717280849Scy	char *	var,
1718280849Scy	char *	val,
1719280849Scy	int	isdefault
1720280849Scy	)
1721280849Scy{
1722280849Scy	setvar_node *	my_node;
1723280849Scy	char *		pch;
1724280849Scy
1725280849Scy	/* do not allow = in the variable name */
1726280849Scy	pch = strchr(var, '=');
1727280849Scy	if (NULL != pch)
1728280849Scy		*pch = '\0';
1729280849Scy
1730280849Scy	/* Now store the string into a setvar_node */
1731280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1732280849Scy	my_node->var = var;
1733280849Scy	my_node->val = val;
1734280849Scy	my_node->isdefault = isdefault;
1735280849Scy
1736280849Scy	return my_node;
1737280849Scy}
1738280849Scy
1739280849Scy
1740280849Scynic_rule_node *
1741280849Scycreate_nic_rule_node(
1742280849Scy	int match_class,
1743280849Scy	char *if_name,	/* interface name or numeric address */
1744280849Scy	int action
1745280849Scy	)
1746280849Scy{
1747280849Scy	nic_rule_node *my_node;
1748280849Scy
1749289764Sglebius	REQUIRE(match_class != 0 || if_name != NULL);
1750280849Scy
1751280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1752280849Scy	my_node->match_class = match_class;
1753280849Scy	my_node->if_name = if_name;
1754280849Scy	my_node->action = action;
1755280849Scy
1756280849Scy	return my_node;
1757280849Scy}
1758280849Scy
1759280849Scy
1760280849Scyaddr_opts_node *
1761280849Scycreate_addr_opts_node(
1762280849Scy	address_node *	addr,
1763280849Scy	attr_val_fifo *	options
1764280849Scy	)
1765280849Scy{
1766280849Scy	addr_opts_node *my_node;
1767280849Scy
1768280849Scy	my_node = emalloc_zero(sizeof(*my_node));
1769280849Scy	my_node->addr = addr;
1770280849Scy	my_node->options = options;
1771280849Scy
1772280849Scy	return my_node;
1773280849Scy}
1774280849Scy
1775280849Scy
1776280849Scy#ifdef SIM
1777280849Scyscript_info *
1778280849Scycreate_sim_script_info(
1779280849Scy	double		duration,
1780280849Scy	attr_val_fifo *	script_queue
1781280849Scy	)
1782280849Scy{
1783280849Scy	script_info *my_info;
1784280849Scy	attr_val *my_attr_val;
1785280849Scy
1786280849Scy	my_info = emalloc_zero(sizeof(*my_info));
1787280849Scy
1788280849Scy	/* Initialize Script Info with default values*/
1789280849Scy	my_info->duration = duration;
1790280849Scy	my_info->prop_delay = NET_DLY;
1791280849Scy	my_info->proc_delay = PROC_DLY;
1792280849Scy
1793280849Scy	/* Traverse the script_queue and fill out non-default values */
1794280849Scy
1795280849Scy	for (my_attr_val = HEAD_PFIFO(script_queue);
1796280849Scy	     my_attr_val != NULL;
1797280849Scy	     my_attr_val = my_attr_val->link) {
1798280849Scy
1799280849Scy		/* Set the desired value */
1800280849Scy		switch (my_attr_val->attr) {
1801280849Scy
1802280849Scy		case T_Freq_Offset:
1803280849Scy			my_info->freq_offset = my_attr_val->value.d;
180454359Sroberto			break;
180554359Sroberto
1806280849Scy		case T_Wander:
1807280849Scy			my_info->wander = my_attr_val->value.d;
1808280849Scy			break;
1809132451Sroberto
1810280849Scy		case T_Jitter:
1811280849Scy			my_info->jitter = my_attr_val->value.d;
1812280849Scy			break;
1813132451Sroberto
1814280849Scy		case T_Prop_Delay:
1815280849Scy			my_info->prop_delay = my_attr_val->value.d;
1816280849Scy			break;
1817132451Sroberto
1818280849Scy		case T_Proc_Delay:
1819280849Scy			my_info->proc_delay = my_attr_val->value.d;
1820280849Scy			break;
1821182007Sroberto
1822280849Scy		default:
1823280849Scy			msyslog(LOG_ERR, "Unknown script token %d",
1824280849Scy				my_attr_val->attr);
1825280849Scy		}
1826280849Scy	}
1827132451Sroberto
1828280849Scy	return my_info;
1829280849Scy}
1830280849Scy#endif	/* SIM */
1831132451Sroberto
1832132451Sroberto
1833280849Scy#ifdef SIM
1834280849Scystatic sockaddr_u *
1835280849Scyget_next_address(
1836280849Scy	address_node *addr
1837280849Scy	)
1838280849Scy{
1839280849Scy	const char addr_prefix[] = "192.168.0.";
1840280849Scy	static int curr_addr_num = 1;
1841280849Scy#define ADDR_LENGTH 16 + 1	/* room for 192.168.1.255 */
1842280849Scy	char addr_string[ADDR_LENGTH];
1843280849Scy	sockaddr_u *final_addr;
1844280849Scy	struct addrinfo *ptr;
1845280849Scy	int gai_err;
1846182007Sroberto
1847280849Scy	final_addr = emalloc(sizeof(*final_addr));
1848182007Sroberto
1849280849Scy	if (addr->type == T_String) {
1850280849Scy		snprintf(addr_string, sizeof(addr_string), "%s%d",
1851280849Scy			 addr_prefix, curr_addr_num++);
1852280849Scy		printf("Selecting ip address %s for hostname %s\n",
1853280849Scy		       addr_string, addr->address);
1854280849Scy		gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
1855280849Scy	} else {
1856280849Scy		gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
1857280849Scy	}
1858182007Sroberto
1859280849Scy	if (gai_err) {
1860280849Scy		fprintf(stderr, "ERROR!! Could not get a new address\n");
1861280849Scy		exit(1);
1862280849Scy	}
1863280849Scy	memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
1864280849Scy	fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
1865280849Scy		stoa(final_addr));
1866280849Scy	freeaddrinfo(ptr);
1867182007Sroberto
1868280849Scy	return final_addr;
1869280849Scy}
1870280849Scy#endif /* SIM */
1871280849Scy
1872280849Scy
1873280849Scy#ifdef SIM
1874280849Scyserver_info *
1875280849Scycreate_sim_server(
1876280849Scy	address_node *		addr,
1877280849Scy	double			server_offset,
1878280849Scy	script_info_fifo *	script
1879280849Scy	)
1880280849Scy{
1881280849Scy	server_info *my_info;
1882280849Scy
1883280849Scy	my_info = emalloc_zero(sizeof(*my_info));
1884280849Scy	my_info->server_time = server_offset;
1885280849Scy	my_info->addr = get_next_address(addr);
1886280849Scy	my_info->script = script;
1887280849Scy	UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
1888280849Scy
1889280849Scy	return my_info;
1890280849Scy}
1891280849Scy#endif	/* SIM */
1892280849Scy
1893280849Scysim_node *
1894280849Scycreate_sim_node(
1895280849Scy	attr_val_fifo *		init_opts,
1896280849Scy	server_info_fifo *	servers
1897280849Scy	)
1898280849Scy{
1899280849Scy	sim_node *my_node;
1900280849Scy
1901280849Scy	my_node = emalloc(sizeof(*my_node));
1902280849Scy	my_node->init_opts = init_opts;
1903280849Scy	my_node->servers = servers;
1904280849Scy
1905280849Scy	return my_node;
1906280849Scy}
1907280849Scy
1908280849Scy
1909280849Scy
1910280849Scy
1911280849Scy/* FUNCTIONS FOR PERFORMING THE CONFIGURATION
1912280849Scy * ------------------------------------------
1913280849Scy */
1914280849Scy
1915280849Scy#ifndef SIM
1916280849Scystatic void
1917280849Scyconfig_other_modes(
1918280849Scy	config_tree *	ptree
1919280849Scy	)
1920280849Scy{
1921280849Scy	sockaddr_u	addr_sock;
1922280849Scy	address_node *	addr_node;
1923280849Scy
1924280849Scy	if (ptree->broadcastclient)
1925280849Scy		proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
1926280849Scy			     0., NULL);
1927280849Scy
1928280849Scy	addr_node = HEAD_PFIFO(ptree->manycastserver);
1929280849Scy	while (addr_node != NULL) {
1930280849Scy		ZERO_SOCK(&addr_sock);
1931280849Scy		AF(&addr_sock) = addr_node->type;
1932280849Scy		if (1 == getnetnum(addr_node->address, &addr_sock, 1,
1933280849Scy				   t_UNK)) {
1934280849Scy			proto_config(PROTO_MULTICAST_ADD,
1935280849Scy				     0, 0., &addr_sock);
1936280849Scy			sys_manycastserver = 1;
1937280849Scy		}
1938280849Scy		addr_node = addr_node->link;
1939280849Scy	}
1940280849Scy
1941280849Scy	/* Configure the multicast clients */
1942280849Scy	addr_node = HEAD_PFIFO(ptree->multicastclient);
1943280849Scy	if (addr_node != NULL) {
1944280849Scy		do {
1945280849Scy			ZERO_SOCK(&addr_sock);
1946280849Scy			AF(&addr_sock) = addr_node->type;
1947280849Scy			if (1 == getnetnum(addr_node->address,
1948280849Scy					   &addr_sock, 1, t_UNK)) {
1949280849Scy				proto_config(PROTO_MULTICAST_ADD, 0, 0.,
1950280849Scy					     &addr_sock);
1951280849Scy			}
1952280849Scy			addr_node = addr_node->link;
1953280849Scy		} while (addr_node != NULL);
1954280849Scy		proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1955280849Scy	}
1956280849Scy}
1957280849Scy#endif	/* !SIM */
1958280849Scy
1959280849Scy
1960280849Scy#ifdef FREE_CFG_T
1961280849Scystatic void
1962280849Scydestroy_address_fifo(
1963280849Scy	address_fifo *	pfifo
1964280849Scy	)
1965280849Scy{
1966280849Scy	address_node *	addr_node;
1967280849Scy
1968280849Scy	if (pfifo != NULL) {
1969280849Scy		for (;;) {
1970280849Scy			UNLINK_FIFO(addr_node, *pfifo, link);
1971280849Scy			if (addr_node == NULL)
1972182007Sroberto				break;
1973280849Scy			destroy_address_node(addr_node);
1974280849Scy		}
1975280849Scy		free(pfifo);
1976280849Scy	}
1977280849Scy}
1978182007Sroberto
1979280849Scy
1980280849Scystatic void
1981280849Scyfree_config_other_modes(
1982280849Scy	config_tree *ptree
1983280849Scy	)
1984280849Scy{
1985280849Scy	FREE_ADDRESS_FIFO(ptree->manycastserver);
1986280849Scy	FREE_ADDRESS_FIFO(ptree->multicastclient);
1987280849Scy}
1988280849Scy#endif	/* FREE_CFG_T */
1989280849Scy
1990280849Scy
1991280849Scy#ifndef SIM
1992280849Scystatic void
1993280849Scyconfig_auth(
1994280849Scy	config_tree *ptree
1995280849Scy	)
1996280849Scy{
1997280849Scy	attr_val *	my_val;
1998280849Scy	int		first;
1999280849Scy	int		last;
2000280849Scy	int		i;
2001280849Scy	int		count;
2002280849Scy#ifdef AUTOKEY
2003280849Scy	int		item;
2004280849Scy#endif
2005280849Scy
2006280849Scy	/* Crypto Command */
2007280849Scy#ifdef AUTOKEY
2008280849Scy	my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
2009280849Scy	for (; my_val != NULL; my_val = my_val->link) {
2010280849Scy		switch (my_val->attr) {
2011280849Scy
2012280849Scy		default:
2013316068Sdelphij			fatal_error("config_auth: attr-token=%d", my_val->attr);
2014280849Scy
2015280849Scy		case T_Host:
2016280849Scy			item = CRYPTO_CONF_PRIV;
2017280849Scy			break;
2018280849Scy
2019280849Scy		case T_Ident:
2020280849Scy			item = CRYPTO_CONF_IDENT;
2021280849Scy			break;
2022280849Scy
2023280849Scy		case T_Pw:
2024280849Scy			item = CRYPTO_CONF_PW;
2025280849Scy			break;
2026280849Scy
2027280849Scy		case T_Randfile:
2028280849Scy			item = CRYPTO_CONF_RAND;
2029280849Scy			break;
2030280849Scy
2031280849Scy		case T_Digest:
2032280849Scy			item = CRYPTO_CONF_NID;
2033280849Scy			break;
2034280849Scy		}
2035280849Scy		crypto_config(item, my_val->value.s);
2036280849Scy	}
2037280849Scy#endif	/* AUTOKEY */
2038280849Scy
2039280849Scy	/* Keysdir Command */
2040280849Scy	if (ptree->auth.keysdir) {
2041280849Scy		if (keysdir != default_keysdir)
2042280849Scy			free(keysdir);
2043280849Scy		keysdir = estrdup(ptree->auth.keysdir);
2044280849Scy	}
2045280849Scy
2046280849Scy
2047280849Scy	/* ntp_signd_socket Command */
2048280849Scy	if (ptree->auth.ntp_signd_socket) {
2049280849Scy		if (ntp_signd_socket != default_ntp_signd_socket)
2050280849Scy			free(ntp_signd_socket);
2051280849Scy		ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
2052280849Scy	}
2053280849Scy
2054280849Scy#ifdef AUTOKEY
2055280849Scy	if (ptree->auth.cryptosw && !cryptosw) {
2056280849Scy		crypto_setup();
2057280849Scy		cryptosw = 1;
2058280849Scy	}
2059280849Scy#endif	/* AUTOKEY */
2060280849Scy
2061280849Scy	/*
2062280849Scy	 * Count the number of trusted keys to preallocate storage and
2063280849Scy	 * size the hash table.
2064280849Scy	 */
2065280849Scy	count = 0;
2066280849Scy	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2067280849Scy	for (; my_val != NULL; my_val = my_val->link) {
2068280849Scy		if (T_Integer == my_val->type) {
2069280849Scy			first = my_val->value.i;
2070280849Scy			if (first > 1 && first <= NTP_MAXKEY)
2071280849Scy				count++;
2072280849Scy		} else {
2073280849Scy			REQUIRE(T_Intrange == my_val->type);
2074280849Scy			first = my_val->value.r.first;
2075280849Scy			last = my_val->value.r.last;
2076280849Scy			if (!(first > last || first < 1 ||
2077280849Scy			    last > NTP_MAXKEY)) {
2078280849Scy				count += 1 + last - first;
2079132451Sroberto			}
2080280849Scy		}
2081280849Scy	}
2082280849Scy	auth_prealloc_symkeys(count);
2083280849Scy
2084280849Scy	/* Keys Command */
2085280849Scy	if (ptree->auth.keys)
2086280849Scy		getauthkeys(ptree->auth.keys);
2087280849Scy
2088280849Scy	/* Control Key Command */
2089280849Scy	if (ptree->auth.control_key)
2090280849Scy		ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
2091280849Scy
2092280849Scy	/* Requested Key Command */
2093280849Scy	if (ptree->auth.request_key) {
2094280849Scy		DPRINTF(4, ("set info_auth_keyid to %08lx\n",
2095280849Scy			    (u_long) ptree->auth.request_key));
2096280849Scy		info_auth_keyid = (keyid_t)ptree->auth.request_key;
2097280849Scy	}
2098280849Scy
2099280849Scy	/* Trusted Key Command */
2100280849Scy	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2101280849Scy	for (; my_val != NULL; my_val = my_val->link) {
2102280849Scy		if (T_Integer == my_val->type) {
2103280849Scy			first = my_val->value.i;
2104280849Scy			if (first >= 1 && first <= NTP_MAXKEY) {
2105280849Scy				authtrust(first, TRUE);
2106280849Scy			} else {
2107280849Scy				msyslog(LOG_NOTICE,
2108280849Scy					"Ignoring invalid trustedkey %d, min 1 max %d.",
2109280849Scy					first, NTP_MAXKEY);
2110280849Scy			}
2111280849Scy		} else {
2112280849Scy			first = my_val->value.r.first;
2113280849Scy			last = my_val->value.r.last;
2114280849Scy			if (first > last || first < 1 ||
2115280849Scy			    last > NTP_MAXKEY) {
2116280849Scy				msyslog(LOG_NOTICE,
2117280849Scy					"Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
2118280849Scy					first, last, NTP_MAXKEY);
2119280849Scy			} else {
2120280849Scy				for (i = first; i <= last; i++) {
2121280849Scy					authtrust(i, TRUE);
2122280849Scy				}
2123280849Scy			}
2124280849Scy		}
2125280849Scy	}
2126280849Scy
2127280849Scy#ifdef AUTOKEY
2128280849Scy	/* crypto revoke command */
2129344884Scy	if (ptree->auth.revoke > 2 && ptree->auth.revoke < 32)
2130344884Scy		sys_revoke = (u_char)ptree->auth.revoke;
2131344884Scy	else if (ptree->auth.revoke)
2132344884Scy		msyslog(LOG_ERR,
2133344884Scy			"'revoke' value %d ignored",
2134344884Scy			ptree->auth.revoke);
2135280849Scy#endif	/* AUTOKEY */
2136280849Scy}
2137280849Scy#endif	/* !SIM */
2138280849Scy
2139280849Scy
2140280849Scy#ifdef FREE_CFG_T
2141280849Scystatic void
2142280849Scyfree_config_auth(
2143280849Scy	config_tree *ptree
2144280849Scy	)
2145280849Scy{
2146280849Scy	destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
2147280849Scy	ptree->auth.crypto_cmd_list = NULL;
2148280849Scy	destroy_attr_val_fifo(ptree->auth.trusted_key_list);
2149280849Scy	ptree->auth.trusted_key_list = NULL;
2150280849Scy}
2151280849Scy#endif	/* FREE_CFG_T */
2152280849Scy
2153280849Scy
2154330106Sdelphij/* Configure low-level clock-related parameters. Return TRUE if the
2155330106Sdelphij * clock might need adjustment like era-checking after the call, FALSE
2156330106Sdelphij * otherwise.
2157330106Sdelphij */
2158330106Sdelphijstatic int/*BOOL*/
2159330106Sdelphijconfig_tos_clock(
2160330106Sdelphij	config_tree *ptree
2161330106Sdelphij	)
2162330106Sdelphij{
2163330106Sdelphij	int		ret;
2164330106Sdelphij	attr_val *	tos;
2165330106Sdelphij
2166330106Sdelphij	ret = FALSE;
2167330106Sdelphij	tos = HEAD_PFIFO(ptree->orphan_cmds);
2168330106Sdelphij	for (; tos != NULL; tos = tos->link) {
2169330106Sdelphij		switch(tos->attr) {
2170330106Sdelphij
2171330106Sdelphij		default:
2172330106Sdelphij			break;
2173330106Sdelphij
2174330106Sdelphij		case T_Basedate:
2175330106Sdelphij			basedate_set_day(tos->value.i);
2176330106Sdelphij			ret = TRUE;
2177330106Sdelphij			break;
2178330106Sdelphij		}
2179330106Sdelphij	}
2180344884Scy
2181344884Scy	if (basedate_get_day() <= NTP_TO_UNIX_DAYS)
2182344884Scy		basedate_set_day(basedate_eval_buildstamp() - 11);
2183344884Scy
2184330106Sdelphij	return ret;
2185330106Sdelphij}
2186330106Sdelphij
2187280849Scystatic void
2188280849Scyconfig_tos(
2189280849Scy	config_tree *ptree
2190280849Scy	)
2191280849Scy{
2192280849Scy	attr_val *	tos;
2193280849Scy	int		item;
2194280849Scy	double		val;
2195280849Scy
2196316068Sdelphij	/* [Bug 2896] For the daemon to work properly it is essential
2197316068Sdelphij	 * that minsane < minclock <= maxclock.
2198316068Sdelphij	 *
2199316068Sdelphij	 * If either constraint is violated, the daemon will be or might
2200316068Sdelphij	 * become dysfunctional. Fixing the values is too fragile here,
2201316068Sdelphij	 * since three variables with interdependecies are involved. We
2202316068Sdelphij	 * just log an error but do not stop: This might be caused by
2203316068Sdelphij	 * remote config, and it might be fixed by remote config, too.
2204338530Sdelphij	 */
2205316068Sdelphij	int l_maxclock = sys_maxclock;
2206316068Sdelphij	int l_minclock = sys_minclock;
2207316068Sdelphij	int l_minsane  = sys_minsane;
2208316068Sdelphij
2209316068Sdelphij	/* -*- phase one: inspect / sanitize the values */
2210280849Scy	tos = HEAD_PFIFO(ptree->orphan_cmds);
2211280849Scy	for (; tos != NULL; tos = tos->link) {
2212330106Sdelphij		/* not all attributes are doubles (any more), so loading
2213330106Sdelphij		 * 'val' in all cases is not a good idea: It should be
2214330106Sdelphij		 * done as needed in every case processed here.
2215330106Sdelphij		 */
2216280849Scy		switch(tos->attr) {
2217280849Scy		default:
2218132451Sroberto			break;
2219132451Sroberto
2220309007Sdelphij		case T_Bcpollbstep:
2221330106Sdelphij			val = tos->value.d;
2222309007Sdelphij			if (val > 4) {
2223309007Sdelphij				msyslog(LOG_WARNING,
2224316068Sdelphij					"Using maximum bcpollbstep ceiling %d, %d requested",
2225316068Sdelphij					4, (int)val);
2226316068Sdelphij				tos->value.d = 4;
2227309007Sdelphij			} else if (val < 0) {
2228309007Sdelphij				msyslog(LOG_WARNING,
2229316068Sdelphij					"Using minimum bcpollbstep floor %d, %d requested",
2230316068Sdelphij					0, (int)val);
2231316068Sdelphij				tos->value.d = 0;
2232309007Sdelphij			}
2233309007Sdelphij			break;
2234338530Sdelphij
2235280849Scy		case T_Ceiling:
2236330106Sdelphij			val = tos->value.d;
2237280849Scy			if (val > STRATUM_UNSPEC - 1) {
2238280849Scy				msyslog(LOG_WARNING,
2239316068Sdelphij					"Using maximum tos ceiling %d, %d requested",
2240316068Sdelphij					STRATUM_UNSPEC - 1, (int)val);
2241316068Sdelphij				tos->value.d = STRATUM_UNSPEC - 1;
2242316068Sdelphij			} else if (val < 1) {
2243316068Sdelphij				msyslog(LOG_WARNING,
2244316068Sdelphij					"Using minimum tos floor %d, %d requested",
2245316068Sdelphij					1, (int)val);
2246316068Sdelphij				tos->value.d = 1;
2247132451Sroberto			}
2248316068Sdelphij			break;
2249316068Sdelphij
2250316068Sdelphij		case T_Minclock:
2251330106Sdelphij			val = tos->value.d;
2252316068Sdelphij			if ((int)tos->value.d < 1)
2253316068Sdelphij				tos->value.d = 1;
2254316068Sdelphij			l_minclock = (int)tos->value.d;
2255316068Sdelphij			break;
2256316068Sdelphij
2257316068Sdelphij		case T_Maxclock:
2258330106Sdelphij			val = tos->value.d;
2259316068Sdelphij			if ((int)tos->value.d < 1)
2260316068Sdelphij				tos->value.d = 1;
2261316068Sdelphij			l_maxclock = (int)tos->value.d;
2262316068Sdelphij			break;
2263316068Sdelphij
2264316068Sdelphij		case T_Minsane:
2265330106Sdelphij			val = tos->value.d;
2266344884Scy			if ((int)tos->value.d < 0)
2267344884Scy				tos->value.d = 0;
2268316068Sdelphij			l_minsane = (int)tos->value.d;
2269316068Sdelphij			break;
2270316068Sdelphij		}
2271316068Sdelphij	}
2272316068Sdelphij
2273316068Sdelphij	if ( ! (l_minsane < l_minclock && l_minclock <= l_maxclock)) {
2274316068Sdelphij		msyslog(LOG_ERR,
2275316068Sdelphij			"tos error: must have minsane (%d) < minclock (%d) <= maxclock (%d)"
2276316068Sdelphij			" - daemon will not operate properly!",
2277316068Sdelphij			l_minsane, l_minclock, l_maxclock);
2278316068Sdelphij	}
2279338530Sdelphij
2280316068Sdelphij	/* -*- phase two: forward the values to the protocol machinery */
2281316068Sdelphij	tos = HEAD_PFIFO(ptree->orphan_cmds);
2282316068Sdelphij	for (; tos != NULL; tos = tos->link) {
2283316068Sdelphij		switch(tos->attr) {
2284316068Sdelphij
2285316068Sdelphij		default:
2286316068Sdelphij			fatal_error("config-tos: attr-token=%d", tos->attr);
2287316068Sdelphij
2288316068Sdelphij		case T_Bcpollbstep:
2289316068Sdelphij			item = PROTO_BCPOLLBSTEP;
2290316068Sdelphij			break;
2291316068Sdelphij
2292316068Sdelphij		case T_Ceiling:
2293280849Scy			item = PROTO_CEILING;
2294132451Sroberto			break;
2295132451Sroberto
2296280849Scy		case T_Floor:
2297280849Scy			item = PROTO_FLOOR;
2298280849Scy			break;
2299132451Sroberto
2300280849Scy		case T_Cohort:
2301280849Scy			item = PROTO_COHORT;
2302280849Scy			break;
2303280849Scy
2304280849Scy		case T_Orphan:
2305280849Scy			item = PROTO_ORPHAN;
2306280849Scy			break;
2307280849Scy
2308280849Scy		case T_Orphanwait:
2309280849Scy			item = PROTO_ORPHWAIT;
2310280849Scy			break;
2311280849Scy
2312280849Scy		case T_Mindist:
2313280849Scy			item = PROTO_MINDISP;
2314280849Scy			break;
2315280849Scy
2316280849Scy		case T_Maxdist:
2317280849Scy			item = PROTO_MAXDIST;
2318280849Scy			break;
2319280849Scy
2320280849Scy		case T_Minclock:
2321280849Scy			item = PROTO_MINCLOCK;
2322280849Scy			break;
2323280849Scy
2324280849Scy		case T_Maxclock:
2325280849Scy			item = PROTO_MAXCLOCK;
2326280849Scy			break;
2327280849Scy
2328280849Scy		case T_Minsane:
2329280849Scy			item = PROTO_MINSANE;
2330280849Scy			break;
2331280849Scy
2332280849Scy		case T_Beacon:
2333280849Scy			item = PROTO_BEACON;
2334280849Scy			break;
2335330106Sdelphij
2336330106Sdelphij		case T_Basedate:
2337330106Sdelphij			continue; /* SKIP proto-config for this! */
2338280849Scy		}
2339330106Sdelphij		proto_config(item, 0, tos->value.d, NULL);
2340280849Scy	}
2341280849Scy}
2342280849Scy
2343280849Scy
2344280849Scy#ifdef FREE_CFG_T
2345280849Scystatic void
2346280849Scyfree_config_tos(
2347280849Scy	config_tree *ptree
2348280849Scy	)
2349280849Scy{
2350280849Scy	FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
2351280849Scy}
2352280849Scy#endif	/* FREE_CFG_T */
2353280849Scy
2354280849Scy
2355280849Scystatic void
2356280849Scyconfig_monitor(
2357280849Scy	config_tree *ptree
2358280849Scy	)
2359280849Scy{
2360280849Scy	int_node *pfilegen_token;
2361280849Scy	const char *filegen_string;
2362280849Scy	const char *filegen_file;
2363280849Scy	FILEGEN *filegen;
2364280849Scy	filegen_node *my_node;
2365280849Scy	attr_val *my_opts;
2366280849Scy	int filegen_type;
2367280849Scy	int filegen_flag;
2368280849Scy
2369280849Scy	/* Set the statistics directory */
2370280849Scy	if (ptree->stats_dir)
2371358659Scy	    stats_config(STATS_STATSDIR, ptree->stats_dir, 0);
2372280849Scy
2373280849Scy	/* NOTE:
2374280849Scy	 * Calling filegen_get is brain dead. Doing a string
2375280849Scy	 * comparison to find the relavant filegen structure is
2376280849Scy	 * expensive.
2377280849Scy	 *
2378280849Scy	 * Through the parser, we already know which filegen is
2379280849Scy	 * being specified. Hence, we should either store a
2380280849Scy	 * pointer to the specified structure in the syntax tree
2381280849Scy	 * or an index into a filegen array.
2382280849Scy	 *
2383280849Scy	 * Need to change the filegen code to reflect the above.
2384280849Scy	 */
2385280849Scy
2386280849Scy	/* Turn on the specified statistics */
2387280849Scy	pfilegen_token = HEAD_PFIFO(ptree->stats_list);
2388280849Scy	for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
2389280849Scy		filegen_string = keyword(pfilegen_token->i);
2390280849Scy		filegen = filegen_get(filegen_string);
2391280849Scy		if (NULL == filegen) {
2392280849Scy			msyslog(LOG_ERR,
2393280849Scy				"stats %s unrecognized",
2394280849Scy				filegen_string);
2395280849Scy			continue;
2396280849Scy		}
2397280849Scy		DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
2398280849Scy			    filegen_string, filegen->dir,
2399280849Scy			    filegen->fname));
2400280849Scy		filegen_flag = filegen->flag;
2401280849Scy		filegen_flag |= FGEN_FLAG_ENABLED;
2402280849Scy		filegen_config(filegen, statsdir, filegen_string,
2403280849Scy			       filegen->type, filegen_flag);
2404280849Scy	}
2405280849Scy
2406280849Scy	/* Configure the statistics with the options */
2407280849Scy	my_node = HEAD_PFIFO(ptree->filegen_opts);
2408280849Scy	for (; my_node != NULL; my_node = my_node->link) {
2409280849Scy		filegen_string = keyword(my_node->filegen_token);
2410280849Scy		filegen = filegen_get(filegen_string);
2411280849Scy		if (NULL == filegen) {
2412280849Scy			msyslog(LOG_ERR,
2413280849Scy				"filegen category '%s' unrecognized",
2414280849Scy				filegen_string);
2415280849Scy			continue;
2416280849Scy		}
2417280849Scy		filegen_file = filegen_string;
2418280849Scy
2419280849Scy		/* Initialize the filegen variables to their pre-configuration states */
2420280849Scy		filegen_flag = filegen->flag;
2421280849Scy		filegen_type = filegen->type;
2422280849Scy
2423280849Scy		/* "filegen ... enabled" is the default (when filegen is used) */
2424280849Scy		filegen_flag |= FGEN_FLAG_ENABLED;
2425280849Scy
2426280849Scy		my_opts = HEAD_PFIFO(my_node->options);
2427280849Scy		for (; my_opts != NULL; my_opts = my_opts->link) {
2428280849Scy			switch (my_opts->attr) {
2429280849Scy
2430280849Scy			case T_File:
2431280849Scy				filegen_file = my_opts->value.s;
2432132451Sroberto				break;
2433132451Sroberto
2434280849Scy			case T_Type:
2435280849Scy				switch (my_opts->value.i) {
2436280849Scy
2437280849Scy				default:
2438316068Sdelphij					fatal_error("config-monitor: type-token=%d", my_opts->value.i);
2439280849Scy
2440280849Scy				case T_None:
2441280849Scy					filegen_type = FILEGEN_NONE;
2442280849Scy					break;
2443280849Scy
2444280849Scy				case T_Pid:
2445280849Scy					filegen_type = FILEGEN_PID;
2446280849Scy					break;
2447280849Scy
2448280849Scy				case T_Day:
2449280849Scy					filegen_type = FILEGEN_DAY;
2450280849Scy					break;
2451280849Scy
2452280849Scy				case T_Week:
2453280849Scy					filegen_type = FILEGEN_WEEK;
2454280849Scy					break;
2455280849Scy
2456280849Scy				case T_Month:
2457280849Scy					filegen_type = FILEGEN_MONTH;
2458280849Scy					break;
2459280849Scy
2460280849Scy				case T_Year:
2461280849Scy					filegen_type = FILEGEN_YEAR;
2462280849Scy					break;
2463280849Scy
2464280849Scy				case T_Age:
2465280849Scy					filegen_type = FILEGEN_AGE;
2466280849Scy					break;
2467280849Scy				}
2468132451Sroberto				break;
2469132451Sroberto
2470280849Scy			case T_Flag:
2471280849Scy				switch (my_opts->value.i) {
2472280849Scy
2473280849Scy				case T_Link:
2474280849Scy					filegen_flag |= FGEN_FLAG_LINK;
2475280849Scy					break;
2476280849Scy
2477280849Scy				case T_Nolink:
2478280849Scy					filegen_flag &= ~FGEN_FLAG_LINK;
2479280849Scy					break;
2480280849Scy
2481280849Scy				case T_Enable:
2482280849Scy					filegen_flag |= FGEN_FLAG_ENABLED;
2483280849Scy					break;
2484280849Scy
2485280849Scy				case T_Disable:
2486280849Scy					filegen_flag &= ~FGEN_FLAG_ENABLED;
2487280849Scy					break;
2488280849Scy
2489280849Scy				default:
2490280849Scy					msyslog(LOG_ERR,
2491280849Scy						"Unknown filegen flag token %d",
2492280849Scy						my_opts->value.i);
2493280849Scy					exit(1);
2494280849Scy				}
2495132451Sroberto				break;
2496132451Sroberto
2497280849Scy			default:
2498132451Sroberto				msyslog(LOG_ERR,
2499280849Scy					"Unknown filegen option token %d",
2500280849Scy					my_opts->attr);
2501280849Scy				exit(1);
2502132451Sroberto			}
2503280849Scy		}
2504280849Scy		filegen_config(filegen, statsdir, filegen_file,
2505280849Scy			       filegen_type, filegen_flag);
2506280849Scy	}
2507280849Scy}
2508280849Scy
2509280849Scy
2510280849Scy#ifdef FREE_CFG_T
2511280849Scystatic void
2512280849Scyfree_config_monitor(
2513280849Scy	config_tree *ptree
2514280849Scy	)
2515280849Scy{
2516280849Scy	if (ptree->stats_dir) {
2517280849Scy		free(ptree->stats_dir);
2518280849Scy		ptree->stats_dir = NULL;
2519280849Scy	}
2520280849Scy
2521280849Scy	FREE_INT_FIFO(ptree->stats_list);
2522280849Scy	FREE_FILEGEN_FIFO(ptree->filegen_opts);
2523280849Scy}
2524280849Scy#endif	/* FREE_CFG_T */
2525280849Scy
2526280849Scy
2527280849Scy#ifndef SIM
2528280849Scystatic void
2529280849Scyconfig_access(
2530280849Scy	config_tree *ptree
2531280849Scy	)
2532280849Scy{
2533280849Scy	static int		warned_signd;
2534280849Scy	attr_val *		my_opt;
2535280849Scy	restrict_node *		my_node;
2536280849Scy	sockaddr_u		addr;
2537280849Scy	sockaddr_u		mask;
2538280849Scy	struct addrinfo		hints;
2539280849Scy	struct addrinfo *	ai_list;
2540280849Scy	struct addrinfo *	pai;
2541280849Scy	int			rc;
2542280849Scy	int			restrict_default;
2543330106Sdelphij	u_short			rflags;
2544280849Scy	u_short			mflags;
2545330106Sdelphij	short			ippeerlimit;
2546280849Scy	int			range_err;
2547358659Scy	psl_item		my_psl_item;
2548358659Scy	attr_val *		atrv;
2549358659Scy	attr_val *		dflt_psl_atr;
2550280849Scy	const char *		signd_warning =
2551280849Scy#ifdef HAVE_NTP_SIGND
2552280849Scy	    "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
2553280849Scy#else
2554280849Scy	    "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
2555280849Scy#endif
2556280849Scy
2557280849Scy	/* Configure the mru options */
2558280849Scy	my_opt = HEAD_PFIFO(ptree->mru_opts);
2559280849Scy	for (; my_opt != NULL; my_opt = my_opt->link) {
2560280849Scy
2561280849Scy		range_err = FALSE;
2562280849Scy
2563280849Scy		switch (my_opt->attr) {
2564280849Scy
2565280849Scy		case T_Incalloc:
2566280849Scy			if (0 <= my_opt->value.i)
2567280849Scy				mru_incalloc = my_opt->value.u;
2568280849Scy			else
2569280849Scy				range_err = TRUE;
2570132451Sroberto			break;
2571132451Sroberto
2572280849Scy		case T_Incmem:
2573280849Scy			if (0 <= my_opt->value.i)
2574280849Scy				mru_incalloc = (my_opt->value.u * 1024U)
2575280849Scy						/ sizeof(mon_entry);
2576280849Scy			else
2577280849Scy				range_err = TRUE;
257882498Sroberto			break;
257982498Sroberto
2580280849Scy		case T_Initalloc:
2581280849Scy			if (0 <= my_opt->value.i)
2582280849Scy				mru_initalloc = my_opt->value.u;
2583280849Scy			else
2584280849Scy				range_err = TRUE;
258582498Sroberto			break;
258682498Sroberto
2587280849Scy		case T_Initmem:
2588280849Scy			if (0 <= my_opt->value.i)
2589280849Scy				mru_initalloc = (my_opt->value.u * 1024U)
2590280849Scy						 / sizeof(mon_entry);
2591280849Scy			else
2592280849Scy				range_err = TRUE;
2593280849Scy			break;
259454359Sroberto
2595280849Scy		case T_Mindepth:
2596280849Scy			if (0 <= my_opt->value.i)
2597280849Scy				mru_mindepth = my_opt->value.u;
2598280849Scy			else
2599280849Scy				range_err = TRUE;
2600280849Scy			break;
2601280849Scy
2602280849Scy		case T_Maxage:
2603280849Scy			mru_maxage = my_opt->value.i;
2604280849Scy			break;
2605280849Scy
2606280849Scy		case T_Maxdepth:
2607280849Scy			if (0 <= my_opt->value.i)
2608280849Scy				mru_maxdepth = my_opt->value.u;
2609280849Scy			else
2610280849Scy				mru_maxdepth = UINT_MAX;
2611280849Scy			break;
2612280849Scy
2613280849Scy		case T_Maxmem:
2614280849Scy			if (0 <= my_opt->value.i)
2615280849Scy				mru_maxdepth = (my_opt->value.u * 1024U) /
2616280849Scy					       sizeof(mon_entry);
2617280849Scy			else
2618280849Scy				mru_maxdepth = UINT_MAX;
2619280849Scy			break;
2620280849Scy
2621280849Scy		default:
2622280849Scy			msyslog(LOG_ERR,
2623280849Scy				"Unknown mru option %s (%d)",
2624280849Scy				keyword(my_opt->attr), my_opt->attr);
2625280849Scy			exit(1);
2626280849Scy		}
2627280849Scy		if (range_err)
2628280849Scy			msyslog(LOG_ERR,
2629280849Scy				"mru %s %d out of range, ignored.",
2630280849Scy				keyword(my_opt->attr), my_opt->value.i);
2631280849Scy	}
2632280849Scy
2633280849Scy	/* Configure the discard options */
2634280849Scy	my_opt = HEAD_PFIFO(ptree->discard_opts);
2635280849Scy	for (; my_opt != NULL; my_opt = my_opt->link) {
2636280849Scy
2637280849Scy		switch (my_opt->attr) {
2638280849Scy
2639280849Scy		case T_Average:
2640280849Scy			if (0 <= my_opt->value.i &&
2641280849Scy			    my_opt->value.i <= UCHAR_MAX)
2642280849Scy				ntp_minpoll = (u_char)my_opt->value.u;
2643280849Scy			else
264482498Sroberto				msyslog(LOG_ERR,
2645280849Scy					"discard average %d out of range, ignored.",
2646280849Scy					my_opt->value.i);
2647280849Scy			break;
2648280849Scy
2649280849Scy		case T_Minimum:
2650280849Scy			ntp_minpkt = my_opt->value.i;
2651280849Scy			break;
2652280849Scy
2653280849Scy		case T_Monitor:
2654280849Scy			mon_age = my_opt->value.i;
2655280849Scy			break;
2656280849Scy
2657280849Scy		default:
2658280849Scy			msyslog(LOG_ERR,
2659280849Scy				"Unknown discard option %s (%d)",
2660280849Scy				keyword(my_opt->attr), my_opt->attr);
2661280849Scy			exit(1);
2662280849Scy		}
2663280849Scy	}
2664280849Scy
2665358659Scy	/* Configure each line of restrict options */
2666280849Scy	my_node = HEAD_PFIFO(ptree->restrict_opts);
2667330106Sdelphij
2668280849Scy	for (; my_node != NULL; my_node = my_node->link) {
2669358659Scy
2670330106Sdelphij		/* Grab the ippeerlmit */
2671330106Sdelphij		ippeerlimit = my_node->ippeerlimit;
2672330106Sdelphij
2673280849Scy		/* Parse the flags */
2674330106Sdelphij		rflags = 0;
2675280849Scy		mflags = 0;
2676280849Scy
2677358659Scy		my_opt = HEAD_PFIFO(my_node->flag_tok_fifo);
2678358659Scy		for (; my_opt != NULL; my_opt = my_opt->link) {
2679358659Scy			switch (my_opt->attr) {
2680280849Scy
2681280849Scy			default:
2682358659Scy				fatal_error("config_access: Unknown flag-type-token=%s/%d", keyword(my_opt->attr), my_opt->attr);
2683132451Sroberto
2684280849Scy			case T_Ntpport:
2685280849Scy				mflags |= RESM_NTPONLY;
268682498Sroberto				break;
268782498Sroberto
2688280849Scy			case T_Source:
2689280849Scy				mflags |= RESM_SOURCE;
269082498Sroberto				break;
269182498Sroberto
2692280849Scy			case T_Flake:
2693330106Sdelphij				rflags |= RES_FLAKE;
2694182007Sroberto				break;
2695182007Sroberto
2696280849Scy			case T_Ignore:
2697330106Sdelphij				rflags |= RES_IGNORE;
269882498Sroberto				break;
269982498Sroberto
2700280849Scy			case T_Kod:
2701330106Sdelphij				rflags |= RES_KOD;
270282498Sroberto				break;
270382498Sroberto
2704280849Scy			case T_Limited:
2705330106Sdelphij				rflags |= RES_LIMITED;
270682498Sroberto				break;
270782498Sroberto
2708280849Scy			case T_Lowpriotrap:
2709330106Sdelphij				rflags |= RES_LPTRAP;
2710132451Sroberto				break;
2711132451Sroberto
2712358659Scy			case T_Mssntp:
2713358659Scy				rflags |= RES_MSSNTP;
2714358659Scy				break;
2715358659Scy
2716280849Scy			case T_Nomodify:
2717330106Sdelphij				rflags |= RES_NOMODIFY;
2718132451Sroberto				break;
2719132451Sroberto
2720280849Scy			case T_Nomrulist:
2721330106Sdelphij				rflags |= RES_NOMRULIST;
2722132451Sroberto				break;
2723132451Sroberto
2724330106Sdelphij			case T_Noepeer:
2725330106Sdelphij				rflags |= RES_NOEPEER;
2726330106Sdelphij				break;
2727330106Sdelphij
2728280849Scy			case T_Nopeer:
2729330106Sdelphij				rflags |= RES_NOPEER;
273082498Sroberto				break;
273182498Sroberto
2732280849Scy			case T_Noquery:
2733330106Sdelphij				rflags |= RES_NOQUERY;
273454359Sroberto				break;
2735280849Scy
2736280849Scy			case T_Noserve:
2737330106Sdelphij				rflags |= RES_DONTSERVE;
2738132451Sroberto				break;
2739280849Scy
2740280849Scy			case T_Notrap:
2741330106Sdelphij				rflags |= RES_NOTRAP;
2742132451Sroberto				break;
2743280849Scy
2744280849Scy			case T_Notrust:
2745330106Sdelphij				rflags |= RES_DONTTRUST;
2746280849Scy				break;
2747280849Scy
2748358659Scy			case T_ServerresponseFuzz:
2749358659Scy				rflags |= RES_SRVRSPFUZ;
2750358659Scy				break;
2751358659Scy
2752280849Scy			case T_Version:
2753330106Sdelphij				rflags |= RES_VERSION;
2754280849Scy				break;
2755132451Sroberto			}
2756280849Scy		}
275754359Sroberto
2758330106Sdelphij		if ((RES_MSSNTP & rflags) && !warned_signd) {
2759280849Scy			warned_signd = 1;
2760280849Scy			fprintf(stderr, "%s\n", signd_warning);
2761280849Scy			msyslog(LOG_WARNING, "%s", signd_warning);
2762280849Scy		}
2763280849Scy
2764280849Scy		/* It would be swell if we could identify the line number */
2765330106Sdelphij		if ((RES_KOD & rflags) && !(RES_LIMITED & rflags)) {
2766280849Scy			const char *kod_where = (my_node->addr)
2767280849Scy					  ? my_node->addr->address
2768280849Scy					  : (mflags & RESM_SOURCE)
2769280849Scy					    ? "source"
2770280849Scy					    : "default";
2771280849Scy			const char *kod_warn = "KOD does nothing without LIMITED.";
2772280849Scy
2773280849Scy			fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
2774280849Scy			msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
2775280849Scy		}
2776280849Scy
2777280849Scy		ZERO_SOCK(&addr);
2778280849Scy		ai_list = NULL;
2779280849Scy		pai = NULL;
2780280849Scy		restrict_default = 0;
2781280849Scy
2782280849Scy		if (NULL == my_node->addr) {
2783280849Scy			ZERO_SOCK(&mask);
2784280849Scy			if (!(RESM_SOURCE & mflags)) {
2785280849Scy				/*
2786280849Scy				 * The user specified a default rule
2787280849Scy				 * without a -4 / -6 qualifier, add to
2788280849Scy				 * both lists
2789280849Scy				 */
2790280849Scy				restrict_default = 1;
2791280849Scy			} else {
2792280849Scy				/* apply "restrict source ..." */
2793330106Sdelphij				DPRINTF(1, ("restrict source template ippeerlimit %d mflags %x rflags %x\n",
2794330106Sdelphij					ippeerlimit, mflags, rflags));
2795330106Sdelphij				hack_restrict(RESTRICT_FLAGS, NULL, NULL,
2796330106Sdelphij					      ippeerlimit, mflags, rflags, 0);
2797280849Scy				continue;
2798280849Scy			}
2799280849Scy		} else {
2800280849Scy			/* Resolve the specified address */
2801280849Scy			AF(&addr) = (u_short)my_node->addr->type;
2802280849Scy
2803280849Scy			if (getnetnum(my_node->addr->address,
2804280849Scy				      &addr, 1, t_UNK) != 1) {
2805280849Scy				/*
2806280849Scy				 * Attempt a blocking lookup.  This
2807280849Scy				 * is in violation of the nonblocking
2808280849Scy				 * design of ntpd's mainline code.  The
2809280849Scy				 * alternative of running without the
2810280849Scy				 * restriction until the name resolved
2811280849Scy				 * seems worse.
2812280849Scy				 * Ideally some scheme could be used for
2813280849Scy				 * restrict directives in the startup
2814280849Scy				 * ntp.conf to delay starting up the
2815280849Scy				 * protocol machinery until after all
2816280849Scy				 * restrict hosts have been resolved.
2817280849Scy				 */
2818280849Scy				ai_list = NULL;
2819280849Scy				ZERO(hints);
2820280849Scy				hints.ai_protocol = IPPROTO_UDP;
2821280849Scy				hints.ai_socktype = SOCK_DGRAM;
2822280849Scy				hints.ai_family = my_node->addr->type;
2823280849Scy				rc = getaddrinfo(my_node->addr->address,
2824280849Scy						 "ntp", &hints,
2825280849Scy						 &ai_list);
2826280849Scy				if (rc) {
2827280849Scy					msyslog(LOG_ERR,
2828280849Scy						"restrict: ignoring line %d, address/host '%s' unusable.",
2829280849Scy						my_node->line_no,
2830280849Scy						my_node->addr->address);
2831280849Scy					continue;
2832280849Scy				}
2833280849Scy				INSIST(ai_list != NULL);
2834280849Scy				pai = ai_list;
2835280849Scy				INSIST(pai->ai_addr != NULL);
2836280849Scy				INSIST(sizeof(addr) >=
2837280849Scy					   pai->ai_addrlen);
2838280849Scy				memcpy(&addr, pai->ai_addr,
2839280849Scy				       pai->ai_addrlen);
2840280849Scy				INSIST(AF_INET == AF(&addr) ||
2841280849Scy					   AF_INET6 == AF(&addr));
2842280849Scy			}
2843280849Scy
2844280849Scy			SET_HOSTMASK(&mask, AF(&addr));
2845280849Scy
2846280849Scy			/* Resolve the mask */
2847280849Scy			if (my_node->mask) {
2848280849Scy				ZERO_SOCK(&mask);
2849280849Scy				AF(&mask) = my_node->mask->type;
2850280849Scy				if (getnetnum(my_node->mask->address,
2851280849Scy					      &mask, 1, t_MSK) != 1) {
2852280849Scy					msyslog(LOG_ERR,
2853280849Scy						"restrict: ignoring line %d, mask '%s' unusable.",
2854280849Scy						my_node->line_no,
2855280849Scy						my_node->mask->address);
2856280849Scy					continue;
2857280849Scy				}
2858280849Scy			}
2859280849Scy		}
2860280849Scy
2861280849Scy		/* Set the flags */
2862280849Scy		if (restrict_default) {
2863280849Scy			AF(&addr) = AF_INET;
2864280849Scy			AF(&mask) = AF_INET;
2865330106Sdelphij			hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2866330106Sdelphij				      ippeerlimit, mflags, rflags, 0);
2867280849Scy			AF(&addr) = AF_INET6;
2868280849Scy			AF(&mask) = AF_INET6;
2869280849Scy		}
2870280849Scy
2871280849Scy		do {
2872330106Sdelphij			hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2873330106Sdelphij				      ippeerlimit, mflags, rflags, 0);
2874280849Scy			if (pai != NULL &&
2875280849Scy			    NULL != (pai = pai->ai_next)) {
2876280849Scy				INSIST(pai->ai_addr != NULL);
2877280849Scy				INSIST(sizeof(addr) >=
2878280849Scy					   pai->ai_addrlen);
2879280849Scy				ZERO_SOCK(&addr);
2880280849Scy				memcpy(&addr, pai->ai_addr,
2881280849Scy				       pai->ai_addrlen);
2882280849Scy				INSIST(AF_INET == AF(&addr) ||
2883280849Scy					   AF_INET6 == AF(&addr));
2884280849Scy				SET_HOSTMASK(&mask, AF(&addr));
2885280849Scy			}
2886280849Scy		} while (pai != NULL);
2887280849Scy
2888280849Scy		if (ai_list != NULL)
2889280849Scy			freeaddrinfo(ai_list);
2890280849Scy	}
2891358659Scy
2892358659Scy	/* Deal with the Poll Skew List */
2893358659Scy
2894358659Scy	ZERO(psl);
2895358659Scy	ZERO(my_psl_item);
2896358659Scy
2897358659Scy	/*
2898358659Scy	 * First, find the last default pollskewlist item.
2899358659Scy	 * There should only be one of these with the current grammar,
2900358659Scy	 * but better safe than sorry.
2901358659Scy	 */
2902358659Scy	dflt_psl_atr = NULL;
2903358659Scy	atrv = HEAD_PFIFO(ptree->pollskewlist);
2904358659Scy	for ( ; atrv != NULL; atrv = atrv->link) {
2905358659Scy		switch (atrv->attr) {
2906358659Scy		case -1:	/* default */
2907358659Scy			dflt_psl_atr = atrv;
2908358659Scy			break;
2909358659Scy
2910358659Scy		case 3:		/* Fall through */
2911358659Scy		case 4:		/* Fall through */
2912358659Scy		case 5:		/* Fall through */
2913358659Scy		case 6:		/* Fall through */
2914358659Scy		case 7:		/* Fall through */
2915358659Scy		case 8:		/* Fall through */
2916358659Scy		case 9:		/* Fall through */
2917358659Scy		case 10:	/* Fall through */
2918358659Scy		case 11:	/* Fall through */
2919358659Scy		case 12:	/* Fall through */
2920358659Scy		case 13:	/* Fall through */
2921358659Scy		case 14:	/* Fall through */
2922358659Scy		case 15:	/* Fall through */
2923358659Scy		case 16:	/* Fall through */
2924358659Scy		case 17:
2925358659Scy			/* ignore */
2926358659Scy			break;
2927358659Scy
2928358659Scy		default:
2929358659Scy			msyslog(LOG_ERR,
2930358659Scy				"config_access: default PSL scan: ignoring unexpected poll value %d",
2931358659Scy				atrv->attr);
2932358659Scy			break;
2933358659Scy		}
2934358659Scy	}
2935358659Scy
2936358659Scy	/* If we have a nonzero default, initialize the PSL */
2937358659Scy	if (   dflt_psl_atr
2938358659Scy	    && (   0 != dflt_psl_atr->value.r.first
2939358659Scy		|| 0 != dflt_psl_atr->value.r.last)) {
2940358659Scy		int i;
2941358659Scy
2942358659Scy		for (i = 3; i <= 17; ++i) {
2943358659Scy			attrtopsl(i, dflt_psl_atr);
2944358659Scy		}
2945358659Scy	}
2946358659Scy
2947358659Scy	/* Finally, update the PSL with any explicit entries */
2948358659Scy	atrv = HEAD_PFIFO(ptree->pollskewlist);
2949358659Scy	for ( ; atrv != NULL; atrv = atrv->link) {
2950358659Scy		switch (atrv->attr) {
2951358659Scy		case -1:	/* default */
2952358659Scy			/* Ignore */
2953358659Scy			break;
2954358659Scy
2955358659Scy		case 3:		/* Fall through */
2956358659Scy		case 4:		/* Fall through */
2957358659Scy		case 5:		/* Fall through */
2958358659Scy		case 6:		/* Fall through */
2959358659Scy		case 7:		/* Fall through */
2960358659Scy		case 8:		/* Fall through */
2961358659Scy		case 9:		/* Fall through */
2962358659Scy		case 10:	/* Fall through */
2963358659Scy		case 11:	/* Fall through */
2964358659Scy		case 12:	/* Fall through */
2965358659Scy		case 13:	/* Fall through */
2966358659Scy		case 14:	/* Fall through */
2967358659Scy		case 15:	/* Fall through */
2968358659Scy		case 16:	/* Fall through */
2969358659Scy		case 17:
2970358659Scy			attrtopsl(atrv->attr, atrv);
2971358659Scy			break;
2972358659Scy
2973358659Scy		default:
2974358659Scy			break;	/* Ignore - we reported this above */
2975358659Scy		}
2976358659Scy	}
2977358659Scy
2978358659Scy#if 0
2979358659Scy	int p;
2980358659Scy	msyslog(LOG_INFO, "Dumping PSL:");
2981358659Scy	for (p = 3; p <= 17; ++p) {
2982358659Scy		psl_item psi;
2983358659Scy
2984358659Scy		if (0 == get_pollskew(p, &psi)) {
2985358659Scy			msyslog(LOG_INFO, "poll %d: sub %d, qty %d, msk %d",
2986358659Scy				p, psi.sub, psi.qty, psi.msk);
2987358659Scy		} else {
2988358659Scy			msyslog(LOG_ERR, "Dumping PSL: get_pollskew(%d) failed!", p);
2989358659Scy		}
2990358659Scy	}
2991358659Scy#endif
2992280849Scy}
2993358659Scy
2994358659Scy
2995358659Scyvoid
2996358659Scyattrtopsl(int poll, attr_val *avp)
2997358659Scy{
2998358659Scy
2999358659Scy	DEBUG_INSIST((poll - 3) < sizeof psl);
3000358659Scy	if (poll < 3 || poll > 17) {
3001358659Scy		msyslog(LOG_ERR, "attrtopsl(%d, ...): Poll value is out of range - ignoring", poll);
3002358659Scy	} else {
3003358659Scy		int pao = poll - 3;		/* poll array offset */
3004358659Scy		int lower = avp->value.r.first;	/* a positive number */
3005358659Scy		int upper = avp->value.r.last;
3006358659Scy		int psmax = 1 << (poll - 1);
3007358659Scy		int qmsk;
3008358659Scy
3009358659Scy		if (lower > psmax) {
3010358659Scy			msyslog(LOG_WARNING, "attrtopsl: default: poll %d lower bound reduced from %d to %d",
3011358659Scy				poll, lower, psmax);
3012358659Scy			lower = psmax;
3013358659Scy		}
3014358659Scy		if (upper > psmax) {
3015358659Scy			msyslog(LOG_WARNING, "attrtopsl: default: poll %d upper bound reduced from %d to %d",
3016358659Scy				poll, upper, psmax);
3017358659Scy			upper = psmax;
3018358659Scy		}
3019358659Scy		psl[pao].sub = lower;
3020358659Scy		psl[pao].qty = lower + upper;
3021358659Scy
3022358659Scy		qmsk = 1;
3023358659Scy		while (qmsk < (lower + upper)) {
3024358659Scy			qmsk <<= 1;
3025358659Scy			qmsk |=  1;
3026358659Scy		};
3027358659Scy		psl[pao].msk = qmsk;
3028358659Scy	}
3029358659Scy
3030358659Scy	return;
3031358659Scy}
3032280849Scy#endif	/* !SIM */
3033280849Scy
3034280849Scy
3035358659Scyint
3036358659Scyget_pollskew(
3037358659Scy	int p,
3038358659Scy	psl_item *rv
3039358659Scy	)
3040358659Scy{
3041358659Scy
3042358659Scy	DEBUG_INSIST(3 <= p && 17 >= p);
3043358659Scy	if (3 <= p && 17 >= p) {
3044358659Scy		*rv = psl[p - 3];
3045358659Scy
3046358659Scy		return 0;
3047358659Scy	} else {
3048358659Scy		msyslog(LOG_ERR, "get_pollskew(%d): poll is not between 3 and 17!", p);
3049358659Scy		return -1;
3050358659Scy	}
3051358659Scy
3052358659Scy	/* NOTREACHED */
3053358659Scy}
3054358659Scy
3055358659Scy
3056280849Scy#ifdef FREE_CFG_T
3057280849Scystatic void
3058280849Scyfree_config_access(
3059280849Scy	config_tree *ptree
3060280849Scy	)
3061280849Scy{
3062280849Scy	FREE_ATTR_VAL_FIFO(ptree->mru_opts);
3063280849Scy	FREE_ATTR_VAL_FIFO(ptree->discard_opts);
3064280849Scy	FREE_RESTRICT_FIFO(ptree->restrict_opts);
3065280849Scy}
3066280849Scy#endif	/* FREE_CFG_T */
3067280849Scy
3068280849Scy
3069280849Scystatic void
3070280849Scyconfig_rlimit(
3071280849Scy	config_tree *ptree
3072280849Scy	)
3073280849Scy{
3074280849Scy	attr_val *	rlimit_av;
3075280849Scy
3076280849Scy	rlimit_av = HEAD_PFIFO(ptree->rlimit);
3077280849Scy	for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
3078280849Scy		switch (rlimit_av->attr) {
3079280849Scy
3080280849Scy		default:
3081316068Sdelphij			fatal_error("config-rlimit: value-token=%d", rlimit_av->attr);
3082280849Scy
3083280849Scy		case T_Memlock:
3084289764Sglebius			/* What if we HAVE_OPT(SAVECONFIGQUIT) ? */
3085330106Sdelphij			if (HAVE_OPT( SAVECONFIGQUIT )) {
3086330106Sdelphij				break;
3087330106Sdelphij			}
3088289764Sglebius			if (rlimit_av->value.i == -1) {
3089289764Sglebius# if defined(HAVE_MLOCKALL)
3090289764Sglebius				if (cur_memlock != 0) {
3091289764Sglebius					if (-1 == munlockall()) {
3092289764Sglebius						msyslog(LOG_ERR, "munlockall() failed: %m");
3093289764Sglebius					}
3094289764Sglebius				}
3095289764Sglebius				cur_memlock = 0;
3096289764Sglebius# endif /* HAVE_MLOCKALL */
3097289764Sglebius			} else if (rlimit_av->value.i >= 0) {
3098280849Scy#if defined(RLIMIT_MEMLOCK)
3099289764Sglebius# if defined(HAVE_MLOCKALL)
3100289764Sglebius				if (cur_memlock != 1) {
3101289764Sglebius					if (-1 == mlockall(MCL_CURRENT|MCL_FUTURE)) {
3102289764Sglebius						msyslog(LOG_ERR, "mlockall() failed: %m");
3103289764Sglebius					}
3104289764Sglebius				}
3105289764Sglebius# endif /* HAVE_MLOCKALL */
3106280849Scy				ntp_rlimit(RLIMIT_MEMLOCK,
3107280849Scy					   (rlim_t)(rlimit_av->value.i * 1024 * 1024),
3108280849Scy					   1024 * 1024,
3109280849Scy					   "MB");
3110289764Sglebius				cur_memlock = 1;
3111280849Scy#else
3112280849Scy				/* STDERR as well would be fine... */
3113280849Scy				msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
3114280849Scy#endif /* RLIMIT_MEMLOCK */
3115280849Scy			} else {
3116289764Sglebius				msyslog(LOG_WARNING, "'rlimit memlock' value of %d is unexpected!", rlimit_av->value.i);
3117280849Scy			}
3118280849Scy			break;
3119280849Scy
3120280849Scy		case T_Stacksize:
3121280849Scy#if defined(RLIMIT_STACK)
3122280849Scy			ntp_rlimit(RLIMIT_STACK,
3123280849Scy				   (rlim_t)(rlimit_av->value.i * 4096),
3124280849Scy				   4096,
3125280849Scy				   "4k");
3126280849Scy#else
3127280849Scy			/* STDERR as well would be fine... */
3128280849Scy			msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
3129280849Scy#endif /* RLIMIT_STACK */
3130280849Scy			break;
3131280849Scy
3132280849Scy		case T_Filenum:
3133280849Scy#if defined(RLIMIT_NOFILE)
3134280849Scy			ntp_rlimit(RLIMIT_NOFILE,
3135280849Scy				  (rlim_t)(rlimit_av->value.i),
3136280849Scy				  1,
3137280849Scy				  "");
3138280849Scy#else
3139280849Scy			/* STDERR as well would be fine... */
3140280849Scy			msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
3141280849Scy#endif /* RLIMIT_NOFILE */
3142280849Scy			break;
3143280849Scy
3144280849Scy		}
3145280849Scy	}
3146280849Scy}
3147280849Scy
3148280849Scy
3149280849Scystatic void
3150280849Scyconfig_tinker(
3151280849Scy	config_tree *ptree
3152280849Scy	)
3153280849Scy{
3154280849Scy	attr_val *	tinker;
3155280849Scy	int		item;
3156280849Scy
3157280849Scy	tinker = HEAD_PFIFO(ptree->tinker);
3158280849Scy	for (; tinker != NULL; tinker = tinker->link) {
3159280849Scy		switch (tinker->attr) {
3160280849Scy
3161280849Scy		default:
3162316068Sdelphij			fatal_error("config_tinker: attr-token=%d", tinker->attr);
3163280849Scy
3164280849Scy		case T_Allan:
3165280849Scy			item = LOOP_ALLAN;
3166280849Scy			break;
3167280849Scy
3168280849Scy		case T_Dispersion:
3169280849Scy			item = LOOP_PHI;
3170280849Scy			break;
3171280849Scy
3172280849Scy		case T_Freq:
3173280849Scy			item = LOOP_FREQ;
3174280849Scy			break;
3175280849Scy
3176280849Scy		case T_Huffpuff:
3177280849Scy			item = LOOP_HUFFPUFF;
3178280849Scy			break;
3179280849Scy
3180280849Scy		case T_Panic:
3181280849Scy			item = LOOP_PANIC;
3182280849Scy			break;
3183280849Scy
3184280849Scy		case T_Step:
3185280849Scy			item = LOOP_MAX;
3186280849Scy			break;
3187280849Scy
3188282408Scy		case T_Stepback:
3189282408Scy			item = LOOP_MAX_BACK;
3190282408Scy			break;
3191282408Scy
3192282408Scy		case T_Stepfwd:
3193282408Scy			item = LOOP_MAX_FWD;
3194282408Scy			break;
3195282408Scy
3196280849Scy		case T_Stepout:
3197280849Scy			item = LOOP_MINSTEP;
3198280849Scy			break;
3199280849Scy
3200280849Scy		case T_Tick:
3201280849Scy			item = LOOP_TICK;
3202280849Scy			break;
3203280849Scy		}
3204280849Scy		loop_config(item, tinker->value.d);
3205280849Scy	}
3206280849Scy}
3207280849Scy
3208280849Scy
3209280849Scy#ifdef FREE_CFG_T
3210280849Scystatic void
3211280849Scyfree_config_rlimit(
3212280849Scy	config_tree *ptree
3213280849Scy	)
3214280849Scy{
3215280849Scy	FREE_ATTR_VAL_FIFO(ptree->rlimit);
3216280849Scy}
3217280849Scy
3218280849Scystatic void
3219280849Scyfree_config_tinker(
3220280849Scy	config_tree *ptree
3221280849Scy	)
3222280849Scy{
3223280849Scy	FREE_ATTR_VAL_FIFO(ptree->tinker);
3224280849Scy}
3225280849Scy#endif	/* FREE_CFG_T */
3226280849Scy
3227280849Scy
3228280849Scy/*
3229280849Scy * config_nic_rules - apply interface listen/ignore/drop items
3230280849Scy */
3231280849Scy#ifndef SIM
3232280849Scystatic void
3233280849Scyconfig_nic_rules(
3234285169Scy	config_tree *ptree,
3235285169Scy	int/*BOOL*/ input_from_file
3236280849Scy	)
3237280849Scy{
3238280849Scy	nic_rule_node *	curr_node;
3239280849Scy	sockaddr_u	addr;
3240280849Scy	nic_rule_match	match_type;
3241280849Scy	nic_rule_action	action;
3242280849Scy	char *		if_name;
3243280849Scy	char *		pchSlash;
3244280849Scy	int		prefixlen;
3245280849Scy	int		addrbits;
3246280849Scy
3247280849Scy	curr_node = HEAD_PFIFO(ptree->nic_rules);
3248280849Scy
3249280849Scy	if (curr_node != NULL
3250280849Scy	    && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
3251280849Scy		msyslog(LOG_ERR,
3252280849Scy			"interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
3253280849Scy			(input_from_file) ? ", exiting" : "");
3254280849Scy		if (input_from_file)
3255280849Scy			exit(1);
3256280849Scy		else
3257280849Scy			return;
3258280849Scy	}
3259280849Scy
3260280849Scy	for (; curr_node != NULL; curr_node = curr_node->link) {
3261280849Scy		prefixlen = -1;
3262280849Scy		if_name = curr_node->if_name;
3263280849Scy		if (if_name != NULL)
3264280849Scy			if_name = estrdup(if_name);
3265280849Scy
3266280849Scy		switch (curr_node->match_class) {
3267280849Scy
3268280849Scy		default:
3269316068Sdelphij			fatal_error("config_nic_rules: match-class-token=%d", curr_node->match_class);
3270132451Sroberto
3271280849Scy		case 0:
3272132451Sroberto			/*
3273280849Scy			 * 0 is out of range for valid token T_...
3274280849Scy			 * and in a nic_rules_node indicates the
3275280849Scy			 * interface descriptor is either a name or
3276280849Scy			 * address, stored in if_name in either case.
327754359Sroberto			 */
3278280849Scy			INSIST(if_name != NULL);
3279280849Scy			pchSlash = strchr(if_name, '/');
3280280849Scy			if (pchSlash != NULL)
3281280849Scy				*pchSlash = '\0';
3282280849Scy			if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
3283280849Scy				match_type = MATCH_IFADDR;
3284280849Scy				if (pchSlash != NULL
3285280849Scy				    && 1 == sscanf(pchSlash + 1, "%d",
3286280849Scy					    &prefixlen)) {
3287280849Scy					addrbits = 8 *
3288280849Scy					    SIZEOF_INADDR(AF(&addr));
3289280849Scy					prefixlen = max(-1, prefixlen);
3290280849Scy					prefixlen = min(prefixlen,
3291280849Scy							addrbits);
3292280849Scy				}
3293280849Scy			} else {
3294280849Scy				match_type = MATCH_IFNAME;
3295280849Scy				if (pchSlash != NULL)
3296280849Scy					*pchSlash = '/';
3297280849Scy			}
3298280849Scy			break;
329954359Sroberto
3300280849Scy		case T_All:
3301280849Scy			match_type = MATCH_ALL;
3302280849Scy			break;
330354359Sroberto
3304280849Scy		case T_Ipv4:
3305280849Scy			match_type = MATCH_IPV4;
3306280849Scy			break;
330754359Sroberto
3308280849Scy		case T_Ipv6:
3309280849Scy			match_type = MATCH_IPV6;
3310280849Scy			break;
331154359Sroberto
3312280849Scy		case T_Wildcard:
3313280849Scy			match_type = MATCH_WILDCARD;
3314280849Scy			break;
3315280849Scy		}
331654359Sroberto
3317280849Scy		switch (curr_node->action) {
331854359Sroberto
3319280849Scy		default:
3320316068Sdelphij			fatal_error("config_nic_rules: action-token=%d", curr_node->action);
332154359Sroberto
3322280849Scy		case T_Listen:
3323280849Scy			action = ACTION_LISTEN;
3324280849Scy			break;
332554359Sroberto
3326280849Scy		case T_Ignore:
3327280849Scy			action = ACTION_IGNORE;
3328280849Scy			break;
332954359Sroberto
3330280849Scy		case T_Drop:
3331280849Scy			action = ACTION_DROP;
3332280849Scy			break;
3333280849Scy		}
333454359Sroberto
3335280849Scy		add_nic_rule(match_type, if_name, prefixlen,
3336280849Scy			     action);
3337280849Scy		timer_interfacetimeout(current_time + 2);
3338280849Scy		if (if_name != NULL)
3339280849Scy			free(if_name);
3340280849Scy	}
3341280849Scy}
3342280849Scy#endif	/* !SIM */
334382498Sroberto
334482498Sroberto
3345280849Scy#ifdef FREE_CFG_T
3346280849Scystatic void
3347280849Scyfree_config_nic_rules(
3348280849Scy	config_tree *ptree
3349280849Scy	)
3350280849Scy{
3351280849Scy	nic_rule_node *curr_node;
335254359Sroberto
3353280849Scy	if (ptree->nic_rules != NULL) {
3354280849Scy		for (;;) {
3355280849Scy			UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
3356280849Scy			if (NULL == curr_node)
3357280849Scy				break;
3358280849Scy			free(curr_node->if_name);
3359280849Scy			free(curr_node);
3360280849Scy		}
3361280849Scy		free(ptree->nic_rules);
3362280849Scy		ptree->nic_rules = NULL;
3363280849Scy	}
3364280849Scy}
3365280849Scy#endif	/* FREE_CFG_T */
3366280849Scy
3367280849Scy
3368280849Scystatic void
3369280849Scyapply_enable_disable(
3370280849Scy	attr_val_fifo *	fifo,
3371280849Scy	int		enable
3372280849Scy	)
3373280849Scy{
3374330106Sdelphij	attr_val *curr_tok_fifo;
3375280849Scy	int option;
3376280849Scy#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3377280849Scy	bc_entry *pentry;
3378280849Scy#endif
3379280849Scy
3380330106Sdelphij	for (curr_tok_fifo = HEAD_PFIFO(fifo);
3381330106Sdelphij	     curr_tok_fifo != NULL;
3382330106Sdelphij	     curr_tok_fifo = curr_tok_fifo->link) {
3383280849Scy
3384330106Sdelphij		option = curr_tok_fifo->value.i;
3385280849Scy		switch (option) {
3386280849Scy
3387280849Scy		default:
3388280849Scy			msyslog(LOG_ERR,
3389280849Scy				"can not apply enable/disable token %d, unknown",
3390280849Scy				option);
3391280849Scy			break;
3392280849Scy
3393280849Scy		case T_Auth:
3394280849Scy			proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
3395280849Scy			break;
3396280849Scy
3397280849Scy		case T_Bclient:
3398280849Scy			proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
3399280849Scy			break;
3400280849Scy
3401280849Scy		case T_Calibrate:
3402280849Scy			proto_config(PROTO_CAL, enable, 0., NULL);
3403280849Scy			break;
3404280849Scy
3405280849Scy		case T_Kernel:
3406280849Scy			proto_config(PROTO_KERNEL, enable, 0., NULL);
3407280849Scy			break;
3408280849Scy
3409280849Scy		case T_Monitor:
3410280849Scy			proto_config(PROTO_MONITOR, enable, 0., NULL);
3411280849Scy			break;
3412280849Scy
3413301247Sdelphij		case T_Mode7:
3414301247Sdelphij			proto_config(PROTO_MODE7, enable, 0., NULL);
3415301247Sdelphij			break;
3416301247Sdelphij
3417280849Scy		case T_Ntp:
3418280849Scy			proto_config(PROTO_NTP, enable, 0., NULL);
3419280849Scy			break;
3420280849Scy
3421301247Sdelphij		case T_PCEdigest:
3422301247Sdelphij			proto_config(PROTO_PCEDIGEST, enable, 0., NULL);
3423280849Scy			break;
3424280849Scy
3425280849Scy		case T_Stats:
3426280849Scy			proto_config(PROTO_FILEGEN, enable, 0., NULL);
3427280849Scy			break;
3428280849Scy
3429294554Sdelphij		case T_UEcrypto:
3430294554Sdelphij			proto_config(PROTO_UECRYPTO, enable, 0., NULL);
3431294554Sdelphij			break;
3432294554Sdelphij
3433294554Sdelphij		case T_UEcryptonak:
3434294554Sdelphij			proto_config(PROTO_UECRYPTONAK, enable, 0., NULL);
3435294554Sdelphij			break;
3436294554Sdelphij
3437294554Sdelphij		case T_UEdigest:
3438294554Sdelphij			proto_config(PROTO_UEDIGEST, enable, 0., NULL);
3439294554Sdelphij			break;
3440294554Sdelphij
3441280849Scy#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3442280849Scy		case T_Bc_bugXXXX:
3443280849Scy			pentry = bc_list;
3444280849Scy			while (pentry->token) {
3445280849Scy				if (pentry->token == option)
344654359Sroberto					break;
3447280849Scy				pentry++;
344854359Sroberto			}
3449280849Scy			if (!pentry->token) {
3450280849Scy				msyslog(LOG_ERR,
3451280849Scy					"compat token %d not in bc_list[]",
3452280849Scy					option);
3453280849Scy				continue;
3454280849Scy			}
3455280849Scy			pentry->enabled = enable;
345654359Sroberto			break;
3457280849Scy#endif
3458280849Scy		}
3459280849Scy	}
3460280849Scy}
346154359Sroberto
346254359Sroberto
3463280849Scystatic void
3464280849Scyconfig_system_opts(
3465280849Scy	config_tree *ptree
3466280849Scy	)
3467280849Scy{
3468280849Scy	apply_enable_disable(ptree->enable_opts, 1);
3469280849Scy	apply_enable_disable(ptree->disable_opts, 0);
3470280849Scy}
3471280849Scy
3472280849Scy
3473280849Scy#ifdef FREE_CFG_T
3474280849Scystatic void
3475280849Scyfree_config_system_opts(
3476280849Scy	config_tree *ptree
3477280849Scy	)
3478280849Scy{
3479280849Scy	FREE_ATTR_VAL_FIFO(ptree->enable_opts);
3480280849Scy	FREE_ATTR_VAL_FIFO(ptree->disable_opts);
3481280849Scy}
3482280849Scy#endif	/* FREE_CFG_T */
3483280849Scy
3484280849Scy
3485280849Scystatic void
3486280849Scyconfig_logconfig(
3487280849Scy	config_tree *ptree
3488280849Scy	)
3489280849Scy{
3490280849Scy	attr_val *	my_lc;
3491280849Scy
3492280849Scy	my_lc = HEAD_PFIFO(ptree->logconfig);
3493280849Scy	for (; my_lc != NULL; my_lc = my_lc->link) {
3494280849Scy		switch (my_lc->attr) {
3495280849Scy
3496280849Scy		case '+':
3497280849Scy			ntp_syslogmask |= get_logmask(my_lc->value.s);
349854359Sroberto			break;
349954359Sroberto
3500280849Scy		case '-':
3501280849Scy			ntp_syslogmask &= ~get_logmask(my_lc->value.s);
3502280849Scy			break;
3503132451Sroberto
3504280849Scy		case '=':
3505280849Scy			ntp_syslogmask = get_logmask(my_lc->value.s);
3506132451Sroberto			break;
3507280849Scy		default:
3508316068Sdelphij			fatal_error("config-logconfig: modifier='%c'", my_lc->attr);
3509280849Scy		}
3510280849Scy	}
3511280849Scy}
3512132451Sroberto
351354359Sroberto
3514280849Scy#ifdef FREE_CFG_T
3515280849Scystatic void
3516280849Scyfree_config_logconfig(
3517280849Scy	config_tree *ptree
3518280849Scy	)
3519280849Scy{
3520280849Scy	FREE_ATTR_VAL_FIFO(ptree->logconfig);
3521280849Scy}
3522280849Scy#endif	/* FREE_CFG_T */
3523280849Scy
3524280849Scy
3525280849Scy#ifndef SIM
3526280849Scystatic void
3527280849Scyconfig_phone(
3528280849Scy	config_tree *ptree
3529280849Scy	)
3530280849Scy{
3531280849Scy	size_t		i;
3532280849Scy	string_node *	sn;
3533280849Scy
3534280849Scy	i = 0;
3535280849Scy	sn = HEAD_PFIFO(ptree->phone);
3536280849Scy	for (; sn != NULL; sn = sn->link) {
3537280849Scy		/* need to leave array entry for NULL terminator */
3538280849Scy		if (i < COUNTOF(sys_phone) - 1) {
3539280849Scy			sys_phone[i++] = estrdup(sn->s);
3540280849Scy			sys_phone[i] = NULL;
3541280849Scy		} else {
3542280849Scy			msyslog(LOG_INFO,
3543280849Scy				"phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
3544280849Scy				(COUNTOF(sys_phone) - 1), sn->s);
3545280849Scy		}
3546280849Scy	}
3547280849Scy}
3548280849Scy#endif	/* !SIM */
3549280849Scy
3550280849Scystatic void
3551280849Scyconfig_mdnstries(
3552280849Scy	config_tree *ptree
3553280849Scy	)
3554280849Scy{
3555280849Scy#ifdef HAVE_DNSREGISTRATION
3556280849Scy	extern int mdnstries;
3557280849Scy	mdnstries = ptree->mdnstries;
3558280849Scy#endif  /* HAVE_DNSREGISTRATION */
3559280849Scy}
3560280849Scy
3561280849Scy#ifdef FREE_CFG_T
3562280849Scystatic void
3563280849Scyfree_config_phone(
3564280849Scy	config_tree *ptree
3565280849Scy	)
3566280849Scy{
3567280849Scy	FREE_STRING_FIFO(ptree->phone);
3568280849Scy}
3569280849Scy#endif	/* FREE_CFG_T */
3570280849Scy
3571280849Scy
3572280849Scy#ifndef SIM
3573280849Scystatic void
3574280849Scyconfig_setvar(
3575280849Scy	config_tree *ptree
3576280849Scy	)
3577280849Scy{
3578280849Scy	setvar_node *my_node;
3579280849Scy	size_t	varlen, vallen, octets;
3580280849Scy	char *	str;
3581280849Scy
3582280849Scy	str = NULL;
3583280849Scy	my_node = HEAD_PFIFO(ptree->setvar);
3584280849Scy	for (; my_node != NULL; my_node = my_node->link) {
3585280849Scy		varlen = strlen(my_node->var);
3586280849Scy		vallen = strlen(my_node->val);
3587280849Scy		octets = varlen + vallen + 1 + 1;
3588280849Scy		str = erealloc(str, octets);
3589280849Scy		snprintf(str, octets, "%s=%s", my_node->var,
3590280849Scy			 my_node->val);
3591280849Scy		set_sys_var(str, octets, (my_node->isdefault)
3592280849Scy						? DEF
3593280849Scy						: 0);
3594280849Scy	}
3595280849Scy	if (str != NULL)
3596280849Scy		free(str);
3597280849Scy}
3598280849Scy#endif	/* !SIM */
3599280849Scy
3600280849Scy
3601280849Scy#ifdef FREE_CFG_T
3602280849Scystatic void
3603280849Scyfree_config_setvar(
3604280849Scy	config_tree *ptree
3605280849Scy	)
3606280849Scy{
3607280849Scy	FREE_SETVAR_FIFO(ptree->setvar);
3608280849Scy}
3609280849Scy#endif	/* FREE_CFG_T */
3610280849Scy
3611280849Scy
3612280849Scy#ifndef SIM
3613280849Scystatic void
3614280849Scyconfig_ttl(
3615280849Scy	config_tree *ptree
3616280849Scy	)
3617280849Scy{
3618280849Scy	size_t i = 0;
3619280849Scy	int_node *curr_ttl;
3620280849Scy
3621338530Sdelphij	/* [Bug 3465] There is a built-in default for the TTLs. We must
3622338530Sdelphij	 * overwrite 'sys_ttlmax' if we change that preset, and leave it
3623338530Sdelphij	 * alone otherwise!
3624338530Sdelphij	 */
3625280849Scy	curr_ttl = HEAD_PFIFO(ptree->ttl);
3626280849Scy	for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
3627280849Scy		if (i < COUNTOF(sys_ttl))
3628280849Scy			sys_ttl[i++] = (u_char)curr_ttl->i;
3629280849Scy		else
3630280849Scy			msyslog(LOG_INFO,
3631280849Scy				"ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
3632280849Scy				COUNTOF(sys_ttl), curr_ttl->i);
3633280849Scy	}
3634338530Sdelphij	if (0 != i) /* anything written back at all? */
3635338530Sdelphij		sys_ttlmax = i - 1;
3636280849Scy}
3637280849Scy#endif	/* !SIM */
3638280849Scy
3639280849Scy
3640280849Scy#ifdef FREE_CFG_T
3641280849Scystatic void
3642280849Scyfree_config_ttl(
3643280849Scy	config_tree *ptree
3644280849Scy	)
3645280849Scy{
3646280849Scy	FREE_INT_FIFO(ptree->ttl);
3647280849Scy}
3648280849Scy#endif	/* FREE_CFG_T */
3649280849Scy
3650280849Scy
3651280849Scy#ifndef SIM
3652280849Scystatic void
3653280849Scyconfig_trap(
3654280849Scy	config_tree *ptree
3655280849Scy	)
3656280849Scy{
3657280849Scy	addr_opts_node *curr_trap;
3658280849Scy	attr_val *curr_opt;
3659280849Scy	sockaddr_u addr_sock;
3660280849Scy	sockaddr_u peeraddr;
3661280849Scy	struct interface *localaddr;
3662280849Scy	struct addrinfo hints;
3663280849Scy	char port_text[8];
3664280849Scy	settrap_parms *pstp;
3665280849Scy	u_short port;
3666280849Scy	int err_flag;
3667280849Scy	int rc;
3668280849Scy
3669280849Scy	/* silence warning about addr_sock potentially uninitialized */
3670280849Scy	AF(&addr_sock) = AF_UNSPEC;
3671280849Scy
3672280849Scy	curr_trap = HEAD_PFIFO(ptree->trap);
3673280849Scy	for (; curr_trap != NULL; curr_trap = curr_trap->link) {
3674280849Scy		err_flag = 0;
3675280849Scy		port = 0;
3676280849Scy		localaddr = NULL;
3677280849Scy
3678280849Scy		curr_opt = HEAD_PFIFO(curr_trap->options);
3679280849Scy		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3680280849Scy			if (T_Port == curr_opt->attr) {
3681280849Scy				if (curr_opt->value.i < 1
3682280849Scy				    || curr_opt->value.i > USHRT_MAX) {
368354359Sroberto					msyslog(LOG_ERR,
3684280849Scy						"invalid port number "
3685280849Scy						"%d, trap ignored",
3686280849Scy						curr_opt->value.i);
3687280849Scy					err_flag = 1;
368854359Sroberto				}
3689280849Scy				port = (u_short)curr_opt->value.i;
369054359Sroberto			}
3691280849Scy			else if (T_Interface == curr_opt->attr) {
3692280849Scy				/* Resolve the interface address */
3693280849Scy				ZERO_SOCK(&addr_sock);
3694280849Scy				if (getnetnum(curr_opt->value.s,
3695280849Scy					      &addr_sock, 1, t_UNK) != 1) {
3696280849Scy					err_flag = 1;
3697280849Scy					break;
3698280849Scy				}
369954359Sroberto
3700280849Scy				localaddr = findinterface(&addr_sock);
3701280849Scy
3702280849Scy				if (NULL == localaddr) {
370354359Sroberto					msyslog(LOG_ERR,
3704280849Scy						"can't find interface with address %s",
3705280849Scy						stoa(&addr_sock));
3706280849Scy					err_flag = 1;
370754359Sroberto				}
370854359Sroberto			}
3709280849Scy		}
371054359Sroberto
3711280849Scy		/* Now process the trap for the specified interface
3712280849Scy		 * and port number
3713280849Scy		 */
3714280849Scy		if (!err_flag) {
3715280849Scy			if (!port)
3716280849Scy				port = TRAPPORT;
3717280849Scy			ZERO_SOCK(&peeraddr);
3718280849Scy			rc = getnetnum(curr_trap->addr->address,
3719280849Scy				       &peeraddr, 1, t_UNK);
3720280849Scy			if (1 != rc) {
3721280849Scy#ifndef WORKER
3722280849Scy				msyslog(LOG_ERR,
3723280849Scy					"trap: unable to use IP address %s.",
3724280849Scy					curr_trap->addr->address);
3725280849Scy#else	/* WORKER follows */
3726280849Scy				/*
3727280849Scy				 * save context and hand it off
3728280849Scy				 * for name resolution.
3729280849Scy				 */
3730280849Scy				ZERO(hints);
3731280849Scy				hints.ai_protocol = IPPROTO_UDP;
3732280849Scy				hints.ai_socktype = SOCK_DGRAM;
3733280849Scy				snprintf(port_text, sizeof(port_text),
3734280849Scy					 "%u", port);
3735280849Scy				hints.ai_flags = Z_AI_NUMERICSERV;
3736280849Scy				pstp = emalloc_zero(sizeof(*pstp));
3737280849Scy				if (localaddr != NULL) {
3738280849Scy					hints.ai_family = localaddr->family;
3739280849Scy					pstp->ifaddr_nonnull = 1;
3740280849Scy					memcpy(&pstp->ifaddr,
3741280849Scy					       &localaddr->sin,
3742280849Scy					       sizeof(pstp->ifaddr));
3743280849Scy				}
3744280849Scy				rc = getaddrinfo_sometime(
3745280849Scy					curr_trap->addr->address,
3746280849Scy					port_text, &hints,
3747280849Scy					INITIAL_DNS_RETRY,
3748280849Scy					&trap_name_resolved,
3749280849Scy					pstp);
3750280849Scy				if (!rc)
375154359Sroberto					msyslog(LOG_ERR,
3752280849Scy						"config_trap: getaddrinfo_sometime(%s,%s): %m",
3753280849Scy						curr_trap->addr->address,
3754280849Scy						port_text);
3755280849Scy#endif	/* WORKER */
3756280849Scy				continue;
375754359Sroberto			}
3758280849Scy			/* port is at same location for v4 and v6 */
3759280849Scy			SET_PORT(&peeraddr, port);
376054359Sroberto
3761280849Scy			if (NULL == localaddr)
3762280849Scy				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3763280849Scy			else
3764280849Scy				AF(&peeraddr) = AF(&addr_sock);
3765280849Scy
3766280849Scy			if (!ctlsettrap(&peeraddr, localaddr, 0,
3767280849Scy					NTP_VERSION))
376854359Sroberto				msyslog(LOG_ERR,
3769280849Scy					"set trap %s -> %s failed.",
3770280849Scy					latoa(localaddr),
3771280849Scy					stoa(&peeraddr));
3772280849Scy		}
3773280849Scy	}
3774280849Scy}
3775280849Scy
3776280849Scy
3777280849Scy/*
3778280849Scy * trap_name_resolved()
3779280849Scy *
3780280849Scy * Callback invoked when config_trap()'s DNS lookup completes.
3781280849Scy */
3782280849Scy# ifdef WORKER
3783280849Scystatic void
3784280849Scytrap_name_resolved(
3785280849Scy	int			rescode,
3786280849Scy	int			gai_errno,
3787280849Scy	void *			context,
3788280849Scy	const char *		name,
3789280849Scy	const char *		service,
3790280849Scy	const struct addrinfo *	hints,
3791280849Scy	const struct addrinfo *	res
3792280849Scy	)
3793280849Scy{
3794280849Scy	settrap_parms *pstp;
3795280849Scy	struct interface *localaddr;
3796280849Scy	sockaddr_u peeraddr;
3797280849Scy
3798280849Scy	(void)gai_errno;
3799280849Scy	(void)service;
3800280849Scy	(void)hints;
3801280849Scy	pstp = context;
3802280849Scy	if (rescode) {
3803280849Scy		msyslog(LOG_ERR,
3804280849Scy			"giving up resolving trap host %s: %s (%d)",
3805280849Scy			name, gai_strerror(rescode), rescode);
3806280849Scy		free(pstp);
3807280849Scy		return;
3808280849Scy	}
3809280849Scy	INSIST(sizeof(peeraddr) >= res->ai_addrlen);
3810280849Scy	ZERO(peeraddr);
3811280849Scy	memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3812280849Scy	localaddr = NULL;
3813280849Scy	if (pstp->ifaddr_nonnull)
3814280849Scy		localaddr = findinterface(&pstp->ifaddr);
3815280849Scy	if (NULL == localaddr)
3816280849Scy		localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3817280849Scy	if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
3818280849Scy		msyslog(LOG_ERR, "set trap %s -> %s failed.",
3819280849Scy			latoa(localaddr), stoa(&peeraddr));
3820280849Scy	free(pstp);
3821280849Scy}
3822280849Scy# endif	/* WORKER */
3823280849Scy#endif	/* !SIM */
3824280849Scy
3825280849Scy
3826280849Scy#ifdef FREE_CFG_T
3827280849Scystatic void
3828280849Scyfree_config_trap(
3829280849Scy	config_tree *ptree
3830280849Scy	)
3831280849Scy{
3832280849Scy	FREE_ADDR_OPTS_FIFO(ptree->trap);
3833280849Scy}
3834280849Scy#endif	/* FREE_CFG_T */
3835280849Scy
3836280849Scy
3837280849Scy#ifndef SIM
3838280849Scystatic void
3839280849Scyconfig_fudge(
3840280849Scy	config_tree *ptree
3841280849Scy	)
3842280849Scy{
3843280849Scy	addr_opts_node *curr_fudge;
3844280849Scy	attr_val *curr_opt;
3845280849Scy	sockaddr_u addr_sock;
3846280849Scy	address_node *addr_node;
3847280849Scy	struct refclockstat clock_stat;
3848280849Scy	int err_flag;
3849280849Scy
3850280849Scy	curr_fudge = HEAD_PFIFO(ptree->fudge);
3851280849Scy	for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
3852280849Scy		err_flag = 0;
3853280849Scy
3854280849Scy		/* Get the reference clock address and
3855280849Scy		 * ensure that it is sane
3856280849Scy		 */
3857280849Scy		addr_node = curr_fudge->addr;
3858280849Scy		ZERO_SOCK(&addr_sock);
3859280849Scy		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
3860280849Scy		    != 1) {
3861280849Scy			err_flag = 1;
3862280849Scy			msyslog(LOG_ERR,
3863280849Scy				"unrecognized fudge reference clock address %s, line ignored",
3864338530Sdelphij				addr_node->address);
3865338530Sdelphij		} else if (!ISREFCLOCKADR(&addr_sock)) {
3866280849Scy			err_flag = 1;
3867280849Scy			msyslog(LOG_ERR,
3868280849Scy				"inappropriate address %s for the fudge command, line ignored",
3869280849Scy				stoa(&addr_sock));
3870280849Scy		}
3871280849Scy
3872280849Scy		/* Parse all the options to the fudge command */
3873280849Scy		ZERO(clock_stat);
3874358659Scy		/* some things are not necessarily cleared by ZERO...*/
3875358659Scy		clock_stat.fudgeminjitter = 0.0;
3876358659Scy		clock_stat.fudgetime1     = 0.0;
3877358659Scy		clock_stat.fudgetime2     = 0.0;
3878358659Scy		clock_stat.p_lastcode     = NULL;
3879358659Scy		clock_stat.clockdesc      = NULL;
3880358659Scy		clock_stat.kv_list        = NULL;
3881280849Scy		curr_opt = HEAD_PFIFO(curr_fudge->options);
3882280849Scy		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3883280849Scy			switch (curr_opt->attr) {
3884280849Scy
3885280849Scy			case T_Time1:
3886280849Scy				clock_stat.haveflags |= CLK_HAVETIME1;
3887280849Scy				clock_stat.fudgetime1 = curr_opt->value.d;
388854359Sroberto				break;
3889280849Scy
3890280849Scy			case T_Time2:
3891280849Scy				clock_stat.haveflags |= CLK_HAVETIME2;
3892280849Scy				clock_stat.fudgetime2 = curr_opt->value.d;
3893132451Sroberto				break;
3894280849Scy
3895280849Scy			case T_Stratum:
3896280849Scy				clock_stat.haveflags |= CLK_HAVEVAL1;
3897280849Scy				clock_stat.fudgeval1 = curr_opt->value.i;
3898132451Sroberto				break;
3899280849Scy
3900280849Scy			case T_Refid:
3901280849Scy				clock_stat.haveflags |= CLK_HAVEVAL2;
3902358659Scy				/* strncpy() does exactly what we want here: */
3903358659Scy				strncpy((char*)&clock_stat.fudgeval2,
3904358659Scy					curr_opt->value.s, 4);
3905280849Scy				break;
3906280849Scy
3907280849Scy			case T_Flag1:
3908280849Scy				clock_stat.haveflags |= CLK_HAVEFLAG1;
3909280849Scy				if (curr_opt->value.i)
3910280849Scy					clock_stat.flags |= CLK_FLAG1;
3911280849Scy				else
3912280849Scy					clock_stat.flags &= ~CLK_FLAG1;
3913280849Scy				break;
3914280849Scy
3915280849Scy			case T_Flag2:
3916280849Scy				clock_stat.haveflags |= CLK_HAVEFLAG2;
3917280849Scy				if (curr_opt->value.i)
3918280849Scy					clock_stat.flags |= CLK_FLAG2;
3919280849Scy				else
3920280849Scy					clock_stat.flags &= ~CLK_FLAG2;
3921280849Scy				break;
3922280849Scy
3923280849Scy			case T_Flag3:
3924280849Scy				clock_stat.haveflags |= CLK_HAVEFLAG3;
3925280849Scy				if (curr_opt->value.i)
3926280849Scy					clock_stat.flags |= CLK_FLAG3;
3927280849Scy				else
3928280849Scy					clock_stat.flags &= ~CLK_FLAG3;
3929280849Scy				break;
3930280849Scy
3931280849Scy			case T_Flag4:
3932280849Scy				clock_stat.haveflags |= CLK_HAVEFLAG4;
3933280849Scy				if (curr_opt->value.i)
3934280849Scy					clock_stat.flags |= CLK_FLAG4;
3935280849Scy				else
3936280849Scy					clock_stat.flags &= ~CLK_FLAG4;
3937280849Scy				break;
3938280849Scy
3939358659Scy			case T_Minjitter:
3940358659Scy				clock_stat.haveflags |= CLK_HAVEMINJIT;
3941358659Scy				clock_stat.fudgeminjitter = curr_opt->value.d;
3942358659Scy				break;
3943358659Scy
3944280849Scy			default:
3945280849Scy				msyslog(LOG_ERR,
3946280849Scy					"Unexpected fudge flag %s (%d) for %s",
3947280849Scy					token_name(curr_opt->attr),
3948338530Sdelphij					curr_opt->attr, addr_node->address);
3949280849Scy				exit(curr_opt->attr ? curr_opt->attr : 1);
3950132451Sroberto			}
3951280849Scy		}
3952280849Scy# ifdef REFCLOCK
3953280849Scy		if (!err_flag)
3954280849Scy			refclock_control(&addr_sock, &clock_stat, NULL);
3955280849Scy# endif
3956280849Scy	}
3957280849Scy}
3958280849Scy#endif	/* !SIM */
3959132451Sroberto
396054359Sroberto
3961280849Scy#ifdef FREE_CFG_T
3962280849Scystatic void
3963280849Scyfree_config_fudge(
3964280849Scy	config_tree *ptree
3965280849Scy	)
3966280849Scy{
3967280849Scy	FREE_ADDR_OPTS_FIFO(ptree->fudge);
3968280849Scy}
3969280849Scy#endif	/* FREE_CFG_T */
397054359Sroberto
397154359Sroberto
3972280849Scystatic void
3973280849Scyconfig_vars(
3974280849Scy	config_tree *ptree
3975280849Scy	)
3976280849Scy{
3977280849Scy	attr_val *curr_var;
3978280849Scy	int len;
397954359Sroberto
3980280849Scy	curr_var = HEAD_PFIFO(ptree->vars);
3981280849Scy	for (; curr_var != NULL; curr_var = curr_var->link) {
3982280849Scy		/* Determine which variable to set and set it */
3983280849Scy		switch (curr_var->attr) {
398454359Sroberto
3985280849Scy		case T_Broadcastdelay:
3986280849Scy			proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
3987280849Scy			break;
398854359Sroberto
3989280849Scy		case T_Tick:
3990280849Scy			loop_config(LOOP_TICK, curr_var->value.d);
399154359Sroberto			break;
399254359Sroberto
3993280849Scy		case T_Driftfile:
3994280849Scy			if ('\0' == curr_var->value.s[0]) {
3995280849Scy				stats_drift_file = 0;
3996280849Scy				msyslog(LOG_INFO, "config: driftfile disabled");
3997280849Scy			} else
3998358659Scy			    stats_config(STATS_FREQ_FILE, curr_var->value.s, 0);
3999280849Scy			break;
4000280849Scy
4001285169Scy		case T_Dscp:
4002285169Scy			/* DSCP is in the upper 6 bits of the IP TOS/DS field */
4003285169Scy			qos = curr_var->value.i << 2;
4004285169Scy			break;
4005285169Scy
4006280849Scy		case T_Ident:
4007280849Scy			sys_ident = curr_var->value.s;
4008280849Scy			break;
4009280849Scy
4010280849Scy		case T_WanderThreshold:		/* FALLTHROUGH */
4011280849Scy		case T_Nonvolatile:
4012280849Scy			wander_threshold = curr_var->value.d;
4013280849Scy			break;
4014280849Scy
4015280849Scy		case T_Leapfile:
4016358659Scy		    stats_config(STATS_LEAP_FILE, curr_var->value.s, curr_var->flag);
4017280849Scy			break;
4018280849Scy
4019285169Scy#ifdef LEAP_SMEAR
4020285169Scy		case T_Leapsmearinterval:
4021285169Scy			leap_smear_intv = curr_var->value.i;
4022285169Scy			msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
4023285169Scy			break;
4024285169Scy#endif
4025285169Scy
4026280849Scy		case T_Pidfile:
4027358659Scy		    stats_config(STATS_PID_FILE, curr_var->value.s, 0);
4028280849Scy			break;
4029280849Scy
4030280849Scy		case T_Logfile:
4031280849Scy			if (-1 == change_logfile(curr_var->value.s, TRUE))
403254359Sroberto				msyslog(LOG_ERR,
4033280849Scy					"Cannot open logfile %s: %m",
4034280849Scy					curr_var->value.s);
4035280849Scy			break;
403654359Sroberto
4037280849Scy		case T_Saveconfigdir:
4038280849Scy			if (saveconfigdir != NULL)
4039280849Scy				free(saveconfigdir);
4040280849Scy			len = strlen(curr_var->value.s);
4041280849Scy			if (0 == len) {
4042280849Scy				saveconfigdir = NULL;
4043280849Scy			} else if (DIR_SEP != curr_var->value.s[len - 1]
4044280849Scy#ifdef SYS_WINNT	/* slash is also a dir. sep. on Windows */
4045280849Scy				   && '/' != curr_var->value.s[len - 1]
4046280849Scy#endif
4047280849Scy				 ) {
4048280849Scy					len++;
4049280849Scy					saveconfigdir = emalloc(len + 1);
4050280849Scy					snprintf(saveconfigdir, len + 1,
4051280849Scy						 "%s%c",
4052280849Scy						 curr_var->value.s,
4053280849Scy						 DIR_SEP);
4054280849Scy			} else {
4055280849Scy					saveconfigdir = estrdup(
4056280849Scy					    curr_var->value.s);
405754359Sroberto			}
4058280849Scy			break;
405954359Sroberto
4060280849Scy		case T_Automax:
4061280849Scy#ifdef AUTOKEY
4062344884Scy			if (curr_var->value.i > 2 && curr_var->value.i < 32)
4063344884Scy				sys_automax = (u_char)curr_var->value.i;
4064344884Scy			else
4065344884Scy				msyslog(LOG_ERR,
4066344884Scy					"'automax' value %d ignored",
4067344884Scy					curr_var->value.i);
4068280849Scy#endif
4069280849Scy			break;
407054359Sroberto
4071280849Scy		default:
4072280849Scy			msyslog(LOG_ERR,
4073280849Scy				"config_vars(): unexpected token %d",
4074280849Scy				curr_var->attr);
4075280849Scy		}
4076280849Scy	}
4077280849Scy}
407854359Sroberto
407954359Sroberto
4080280849Scy#ifdef FREE_CFG_T
4081280849Scystatic void
4082280849Scyfree_config_vars(
4083280849Scy	config_tree *ptree
4084280849Scy	)
4085280849Scy{
4086280849Scy	FREE_ATTR_VAL_FIFO(ptree->vars);
4087280849Scy}
4088280849Scy#endif	/* FREE_CFG_T */
408954359Sroberto
409054359Sroberto
4091280849Scy/* Define a function to check if a resolved address is sane.
4092280849Scy * If yes, return 1, else return 0;
4093280849Scy */
4094280849Scystatic int
4095280849Scyis_sane_resolved_address(
4096280849Scy	sockaddr_u *	peeraddr,
4097280849Scy	int		hmode
4098280849Scy	)
4099280849Scy{
4100280849Scy	if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
4101280849Scy		msyslog(LOG_ERR,
4102280849Scy			"attempt to configure invalid address %s",
4103280849Scy			stoa(peeraddr));
4104280849Scy		return 0;
4105280849Scy	}
4106280849Scy	/*
4107358659Scy	 * Shouldn't be able to specify:
4108358659Scy	 * - multicast address for server/peer!
4109358659Scy	 * - unicast address for manycastclient!
4110280849Scy	 */
4111280849Scy	if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
4112280849Scy	    && IS_MCAST(peeraddr)) {
4113280849Scy		msyslog(LOG_ERR,
4114280849Scy			"attempt to configure invalid address %s",
4115280849Scy			stoa(peeraddr));
4116280849Scy		return 0;
4117280849Scy	}
4118280849Scy	if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
4119280849Scy		msyslog(LOG_ERR,
4120280849Scy			"attempt to configure invalid address %s",
4121280849Scy			stoa(peeraddr));
4122280849Scy		return 0;
4123280849Scy	}
412454359Sroberto
4125280849Scy	if (IS_IPV6(peeraddr) && !ipv6_works)
4126280849Scy		return 0;
412754359Sroberto
4128280849Scy	/* Ok, all tests succeeded, now we can return 1 */
4129280849Scy	return 1;
4130280849Scy}
4131280849Scy
4132280849Scy
4133280849Scy#ifndef SIM
4134280849Scystatic u_char
4135280849Scyget_correct_host_mode(
4136280849Scy	int token
4137280849Scy	)
4138280849Scy{
4139280849Scy	switch (token) {
4140280849Scy
4141280849Scy	case T_Server:
4142280849Scy	case T_Pool:
4143280849Scy	case T_Manycastclient:
4144280849Scy		return MODE_CLIENT;
4145280849Scy
4146280849Scy	case T_Peer:
4147280849Scy		return MODE_ACTIVE;
4148280849Scy
4149280849Scy	case T_Broadcast:
4150280849Scy		return MODE_BROADCAST;
4151280849Scy
4152280849Scy	default:
4153280849Scy		return 0;
4154280849Scy	}
4155280849Scy}
4156280849Scy
4157280849Scy
4158280849Scy/*
4159280849Scy * peerflag_bits()	get config_peers() peerflags value from a
4160280849Scy *			peer_node's queue of flag attr_val entries.
4161280849Scy */
4162280849Scystatic int
4163280849Scypeerflag_bits(
4164280849Scy	peer_node *pn
4165280849Scy	)
4166280849Scy{
4167280849Scy	int peerflags;
4168280849Scy	attr_val *option;
4169358659Scy	int	hmode;
4170280849Scy
4171358659Scy	DEBUG_INSIST(pn);
4172280849Scy	/* translate peerflags options to bits */
4173280849Scy	peerflags = 0;
4174358659Scy	hmode = pn->host_mode;
4175280849Scy	option = HEAD_PFIFO(pn->peerflags);
4176280849Scy	for (; option != NULL; option = option->link) {
4177280849Scy		switch (option->value.i) {
4178280849Scy
4179280849Scy		default:
4180316068Sdelphij			fatal_error("peerflag_bits: option-token=%d", option->value.i);
418154359Sroberto
4182280849Scy		case T_Autokey:
4183280849Scy			peerflags |= FLAG_SKEY;
418454359Sroberto			break;
418554359Sroberto
4186280849Scy		case T_Burst:
4187280849Scy			peerflags |= FLAG_BURST;
4188280849Scy			break;
418954359Sroberto
4190280849Scy		case T_Iburst:
4191280849Scy			peerflags |= FLAG_IBURST;
4192280849Scy			break;
4193280849Scy
4194280849Scy		case T_Noselect:
4195280849Scy			peerflags |= FLAG_NOSELECT;
4196280849Scy			break;
4197280849Scy
4198280849Scy		case T_Preempt:
4199280849Scy			peerflags |= FLAG_PREEMPT;
4200280849Scy			break;
4201280849Scy
4202280849Scy		case T_Prefer:
4203280849Scy			peerflags |= FLAG_PREFER;
4204280849Scy			break;
4205280849Scy
4206280849Scy		case T_True:
4207280849Scy			peerflags |= FLAG_TRUE;
4208280849Scy			break;
4209280849Scy
4210280849Scy		case T_Xleave:
4211280849Scy			peerflags |= FLAG_XLEAVE;
4212280849Scy			break;
4213358659Scy
4214358659Scy		case T_Xmtnonce:
4215358659Scy			if (   MODE_CLIENT == hmode ) {
4216358659Scy				peerflags |= FLAG_LOOPNONCE;
4217358659Scy			}
4218358659Scy			break;
4219280849Scy		}
4220280849Scy	}
4221280849Scy
4222280849Scy	return peerflags;
4223280849Scy}
4224280849Scy
4225280849Scy
4226280849Scystatic void
4227280849Scyconfig_peers(
4228280849Scy	config_tree *ptree
4229280849Scy	)
4230280849Scy{
4231280849Scy	sockaddr_u		peeraddr;
4232280849Scy	struct addrinfo		hints;
4233280849Scy	peer_node *		curr_peer;
4234280849Scy	peer_resolved_ctx *	ctx;
4235280849Scy	u_char			hmode;
4236280849Scy
4237280849Scy	/* add servers named on the command line with iburst implied */
4238280849Scy	for (;
4239280849Scy	     cmdline_server_count > 0;
4240280849Scy	     cmdline_server_count--, cmdline_servers++) {
4241280849Scy
4242280849Scy		ZERO_SOCK(&peeraddr);
4243280849Scy		/*
4244280849Scy		 * If we have a numeric address, we can safely
4245280849Scy		 * proceed in the mainline with it.  Otherwise, hand
4246280849Scy		 * the hostname off to the blocking child.
4247330106Sdelphij		 *
4248330106Sdelphij		 * Note that if we're told to add the peer here, we
4249330106Sdelphij		 * do that regardless of ippeerlimit.
4250280849Scy		 */
4251280849Scy		if (is_ip_address(*cmdline_servers, AF_UNSPEC,
4252280849Scy				  &peeraddr)) {
4253280849Scy
4254280849Scy			SET_PORT(&peeraddr, NTP_PORT);
4255280849Scy			if (is_sane_resolved_address(&peeraddr,
4256280849Scy						     T_Server))
4257280849Scy				peer_config(
4258280849Scy					&peeraddr,
4259280849Scy					NULL,
4260280849Scy					NULL,
4261330106Sdelphij					-1,
4262280849Scy					MODE_CLIENT,
4263280849Scy					NTP_VERSION,
4264280849Scy					0,
4265280849Scy					0,
4266280849Scy					FLAG_IBURST,
4267280849Scy					0,
4268280849Scy					0,
4269280849Scy					NULL);
4270280849Scy		} else {
4271280849Scy			/* we have a hostname to resolve */
4272280849Scy# ifdef WORKER
4273280849Scy			ctx = emalloc_zero(sizeof(*ctx));
4274280849Scy			ctx->family = AF_UNSPEC;
4275280849Scy			ctx->host_mode = T_Server;
4276280849Scy			ctx->hmode = MODE_CLIENT;
4277280849Scy			ctx->version = NTP_VERSION;
4278280849Scy			ctx->flags = FLAG_IBURST;
4279280849Scy
4280280849Scy			ZERO(hints);
4281280849Scy			hints.ai_family = (u_short)ctx->family;
4282280849Scy			hints.ai_socktype = SOCK_DGRAM;
4283280849Scy			hints.ai_protocol = IPPROTO_UDP;
4284280849Scy
4285309007Sdelphij			getaddrinfo_sometime_ex(*cmdline_servers,
4286280849Scy					     "ntp", &hints,
4287280849Scy					     INITIAL_DNS_RETRY,
4288280849Scy					     &peer_name_resolved,
4289309007Sdelphij					     (void *)ctx, DNSFLAGS);
4290280849Scy# else	/* !WORKER follows */
4291280849Scy			msyslog(LOG_ERR,
4292280849Scy				"hostname %s can not be used, please use IP address instead.",
4293280849Scy				curr_peer->addr->address);
4294280849Scy# endif
4295280849Scy		}
4296280849Scy	}
4297280849Scy
4298280849Scy	/* add associations from the configuration file */
4299280849Scy	curr_peer = HEAD_PFIFO(ptree->peers);
4300280849Scy	for (; curr_peer != NULL; curr_peer = curr_peer->link) {
4301280849Scy		ZERO_SOCK(&peeraddr);
4302280849Scy		/* Find the correct host-mode */
4303280849Scy		hmode = get_correct_host_mode(curr_peer->host_mode);
4304280849Scy		INSIST(hmode != 0);
4305280849Scy
4306280849Scy		if (T_Pool == curr_peer->host_mode) {
4307280849Scy			AF(&peeraddr) = curr_peer->addr->type;
4308280849Scy			peer_config(
4309280849Scy				&peeraddr,
4310280849Scy				curr_peer->addr->address,
4311280849Scy				NULL,
4312330106Sdelphij				-1,
4313280849Scy				hmode,
4314280849Scy				curr_peer->peerversion,
4315280849Scy				curr_peer->minpoll,
4316280849Scy				curr_peer->maxpoll,
4317280849Scy				peerflag_bits(curr_peer),
4318280849Scy				curr_peer->ttl,
4319280849Scy				curr_peer->peerkey,
4320280849Scy				curr_peer->group);
4321280849Scy		/*
4322280849Scy		 * If we have a numeric address, we can safely
4323280849Scy		 * proceed in the mainline with it.  Otherwise, hand
4324280849Scy		 * the hostname off to the blocking child.
4325280849Scy		 */
4326280849Scy		} else if (is_ip_address(curr_peer->addr->address,
4327280849Scy				  curr_peer->addr->type, &peeraddr)) {
4328280849Scy
4329280849Scy			SET_PORT(&peeraddr, NTP_PORT);
4330280849Scy			if (is_sane_resolved_address(&peeraddr,
4331280849Scy			    curr_peer->host_mode))
4332280849Scy				peer_config(
4333280849Scy					&peeraddr,
4334280849Scy					NULL,
4335280849Scy					NULL,
4336330106Sdelphij					-1,
4337280849Scy					hmode,
4338280849Scy					curr_peer->peerversion,
4339280849Scy					curr_peer->minpoll,
4340280849Scy					curr_peer->maxpoll,
4341280849Scy					peerflag_bits(curr_peer),
4342280849Scy					curr_peer->ttl,
4343280849Scy					curr_peer->peerkey,
4344280849Scy					curr_peer->group);
4345280849Scy		} else {
4346280849Scy			/* we have a hostname to resolve */
4347280849Scy# ifdef WORKER
4348280849Scy			ctx = emalloc_zero(sizeof(*ctx));
4349280849Scy			ctx->family = curr_peer->addr->type;
4350280849Scy			ctx->host_mode = curr_peer->host_mode;
4351280849Scy			ctx->hmode = hmode;
4352280849Scy			ctx->version = curr_peer->peerversion;
4353280849Scy			ctx->minpoll = curr_peer->minpoll;
4354280849Scy			ctx->maxpoll = curr_peer->maxpoll;
4355280849Scy			ctx->flags = peerflag_bits(curr_peer);
4356280849Scy			ctx->ttl = curr_peer->ttl;
4357280849Scy			ctx->keyid = curr_peer->peerkey;
4358280849Scy			ctx->group = curr_peer->group;
4359280849Scy
4360280849Scy			ZERO(hints);
4361280849Scy			hints.ai_family = ctx->family;
4362280849Scy			hints.ai_socktype = SOCK_DGRAM;
4363280849Scy			hints.ai_protocol = IPPROTO_UDP;
4364280849Scy
4365309007Sdelphij			getaddrinfo_sometime_ex(curr_peer->addr->address,
4366280849Scy					     "ntp", &hints,
4367280849Scy					     INITIAL_DNS_RETRY,
4368309007Sdelphij					     &peer_name_resolved, ctx,
4369309007Sdelphij					     DNSFLAGS);
4370280849Scy# else	/* !WORKER follows */
4371280849Scy			msyslog(LOG_ERR,
4372280849Scy				"hostname %s can not be used, please use IP address instead.",
4373280849Scy				curr_peer->addr->address);
4374280849Scy# endif
4375280849Scy		}
4376280849Scy	}
4377280849Scy}
4378280849Scy#endif	/* !SIM */
4379280849Scy
4380280849Scy/*
4381280849Scy * peer_name_resolved()
4382280849Scy *
4383280849Scy * Callback invoked when config_peers()'s DNS lookup completes.
4384280849Scy */
4385280849Scy#ifdef WORKER
4386280849Scystatic void
4387280849Scypeer_name_resolved(
4388280849Scy	int			rescode,
4389280849Scy	int			gai_errno,
4390280849Scy	void *			context,
4391280849Scy	const char *		name,
4392280849Scy	const char *		service,
4393280849Scy	const struct addrinfo *	hints,
4394280849Scy	const struct addrinfo *	res
4395280849Scy	)
4396280849Scy{
4397280849Scy	sockaddr_u		peeraddr;
4398280849Scy	peer_resolved_ctx *	ctx;
4399280849Scy	u_short			af;
4400280849Scy	const char *		fam_spec;
4401280849Scy
4402280849Scy	(void)gai_errno;
4403280849Scy	(void)service;
4404280849Scy	(void)hints;
4405280849Scy	ctx = context;
4406280849Scy
4407280849Scy	DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
4408280849Scy
4409280849Scy	if (rescode) {
4410280849Scy		free(ctx);
4411280849Scy		msyslog(LOG_ERR,
4412280849Scy			"giving up resolving host %s: %s (%d)",
4413280849Scy			name, gai_strerror(rescode), rescode);
4414280849Scy		return;
4415280849Scy	}
4416280849Scy
4417280849Scy	/* Loop to configure a single association */
4418280849Scy	for (; res != NULL; res = res->ai_next) {
4419280849Scy		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4420280849Scy		if (is_sane_resolved_address(&peeraddr,
4421280849Scy					     ctx->host_mode)) {
4422280849Scy			NLOG(NLOG_SYSINFO) {
4423280849Scy				af = ctx->family;
4424280849Scy				fam_spec = (AF_INET6 == af)
4425280849Scy					       ? "(AAAA) "
4426280849Scy					       : (AF_INET == af)
4427280849Scy						     ? "(A) "
4428280849Scy						     : "";
4429280849Scy				msyslog(LOG_INFO, "DNS %s %s-> %s",
4430280849Scy					name, fam_spec,
4431280849Scy					stoa(&peeraddr));
443254359Sroberto			}
4433280849Scy			peer_config(
4434280849Scy				&peeraddr,
4435280849Scy				NULL,
4436280849Scy				NULL,
4437330106Sdelphij				-1,
4438280849Scy				ctx->hmode,
4439280849Scy				ctx->version,
4440280849Scy				ctx->minpoll,
4441280849Scy				ctx->maxpoll,
4442280849Scy				ctx->flags,
4443280849Scy				ctx->ttl,
4444280849Scy				ctx->keyid,
4445280849Scy				ctx->group);
444654359Sroberto			break;
4447280849Scy		}
4448280849Scy	}
4449280849Scy	free(ctx);
4450280849Scy}
4451280849Scy#endif	/* WORKER */
445254359Sroberto
4453280849Scy
4454280849Scy#ifdef FREE_CFG_T
4455280849Scystatic void
4456280849Scyfree_config_peers(
4457280849Scy	config_tree *ptree
4458280849Scy	)
4459280849Scy{
4460280849Scy	peer_node *curr_peer;
4461280849Scy
4462280849Scy	if (ptree->peers != NULL) {
4463280849Scy		for (;;) {
4464280849Scy			UNLINK_FIFO(curr_peer, *ptree->peers, link);
4465280849Scy			if (NULL == curr_peer)
446654359Sroberto				break;
4467280849Scy			destroy_address_node(curr_peer->addr);
4468280849Scy			destroy_attr_val_fifo(curr_peer->peerflags);
4469280849Scy			free(curr_peer);
4470280849Scy		}
4471280849Scy		free(ptree->peers);
4472280849Scy		ptree->peers = NULL;
4473280849Scy	}
4474280849Scy}
4475280849Scy#endif	/* FREE_CFG_T */
4476280849Scy
4477280849Scy
4478280849Scy#ifndef SIM
4479280849Scystatic void
4480280849Scyconfig_unpeers(
4481280849Scy	config_tree *ptree
4482280849Scy	)
4483280849Scy{
4484280849Scy	sockaddr_u		peeraddr;
4485280849Scy	struct addrinfo		hints;
4486280849Scy	unpeer_node *		curr_unpeer;
4487280849Scy	struct peer *		p;
4488280849Scy	const char *		name;
4489280849Scy	int			rc;
4490280849Scy
4491280849Scy	curr_unpeer = HEAD_PFIFO(ptree->unpeers);
4492280849Scy	for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
4493280849Scy		/*
4494316068Sdelphij		 * If we have no address attached, assume we have to
4495316068Sdelphij		 * unpeer by AssocID.
4496280849Scy		 */
4497316068Sdelphij		if (!curr_unpeer->addr) {
4498280849Scy			p = findpeerbyassoc(curr_unpeer->assocID);
4499280849Scy			if (p != NULL) {
4500280849Scy				msyslog(LOG_NOTICE, "unpeered %s",
4501280849Scy					stoa(&p->srcadr));
4502280849Scy				peer_clear(p, "GONE");
4503280849Scy				unpeer(p);
450454359Sroberto			}
4505280849Scy			continue;
4506280849Scy		}
4507280849Scy
4508280849Scy		ZERO(peeraddr);
4509280849Scy		AF(&peeraddr) = curr_unpeer->addr->type;
4510280849Scy		name = curr_unpeer->addr->address;
4511280849Scy		rc = getnetnum(name, &peeraddr, 0, t_UNK);
4512280849Scy		/* Do we have a numeric address? */
4513280849Scy		if (rc > 0) {
4514280849Scy			DPRINTF(1, ("unpeer: searching for %s\n",
4515280849Scy				    stoa(&peeraddr)));
4516330106Sdelphij			p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4517280849Scy			if (p != NULL) {
4518280849Scy				msyslog(LOG_NOTICE, "unpeered %s",
4519280849Scy					stoa(&peeraddr));
4520280849Scy				peer_clear(p, "GONE");
4521280849Scy				unpeer(p);
452254359Sroberto			}
4523280849Scy			continue;
4524280849Scy		}
4525280849Scy		/*
4526280849Scy		 * It's not a numeric IP address, it's a hostname.
4527280849Scy		 * Check for associations with a matching hostname.
4528280849Scy		 */
4529280849Scy		for (p = peer_list; p != NULL; p = p->p_link)
4530280849Scy			if (p->hostname != NULL)
4531280849Scy				if (!strcasecmp(p->hostname, name))
453254359Sroberto					break;
4533280849Scy		if (p != NULL) {
4534280849Scy			msyslog(LOG_NOTICE, "unpeered %s", name);
4535280849Scy			peer_clear(p, "GONE");
4536280849Scy			unpeer(p);
4537280849Scy		}
4538280849Scy		/* Resolve the hostname to address(es). */
4539280849Scy# ifdef WORKER
4540280849Scy		ZERO(hints);
4541280849Scy		hints.ai_family = curr_unpeer->addr->type;
4542280849Scy		hints.ai_socktype = SOCK_DGRAM;
4543280849Scy		hints.ai_protocol = IPPROTO_UDP;
4544280849Scy		getaddrinfo_sometime(name, "ntp", &hints,
4545280849Scy				     INITIAL_DNS_RETRY,
4546280849Scy				     &unpeer_name_resolved, NULL);
4547280849Scy# else	/* !WORKER follows */
4548280849Scy		msyslog(LOG_ERR,
4549280849Scy			"hostname %s can not be used, please use IP address instead.",
4550280849Scy			name);
4551280849Scy# endif
4552280849Scy	}
4553280849Scy}
4554280849Scy#endif	/* !SIM */
455554359Sroberto
455654359Sroberto
4557280849Scy/*
4558280849Scy * unpeer_name_resolved()
4559280849Scy *
4560280849Scy * Callback invoked when config_unpeers()'s DNS lookup completes.
4561280849Scy */
4562280849Scy#ifdef WORKER
4563280849Scystatic void
4564280849Scyunpeer_name_resolved(
4565280849Scy	int			rescode,
4566280849Scy	int			gai_errno,
4567280849Scy	void *			context,
4568280849Scy	const char *		name,
4569280849Scy	const char *		service,
4570280849Scy	const struct addrinfo *	hints,
4571280849Scy	const struct addrinfo *	res
4572280849Scy	)
4573280849Scy{
4574280849Scy	sockaddr_u	peeraddr;
4575280849Scy	struct peer *	peer;
4576280849Scy	u_short		af;
4577280849Scy	const char *	fam_spec;
457854359Sroberto
4579280849Scy	(void)context;
4580280849Scy	(void)hints;
4581280849Scy	DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
458254359Sroberto
4583280849Scy	if (rescode) {
4584280849Scy		msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
4585280849Scy			name, gai_strerror(rescode), rescode);
4586280849Scy		return;
4587280849Scy	}
4588280849Scy	/*
4589280849Scy	 * Loop through the addresses found
4590280849Scy	 */
4591280849Scy	for (; res != NULL; res = res->ai_next) {
4592280849Scy		INSIST(res->ai_addrlen <= sizeof(peeraddr));
4593280849Scy		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4594280849Scy		DPRINTF(1, ("unpeer: searching for peer %s\n",
4595280849Scy			    stoa(&peeraddr)));
4596330106Sdelphij		peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4597280849Scy		if (peer != NULL) {
4598280849Scy			af = AF(&peeraddr);
4599280849Scy			fam_spec = (AF_INET6 == af)
4600280849Scy				       ? "(AAAA) "
4601280849Scy				       : (AF_INET == af)
4602280849Scy					     ? "(A) "
4603280849Scy					     : "";
4604280849Scy			msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
4605280849Scy				fam_spec, stoa(&peeraddr));
4606280849Scy			peer_clear(peer, "GONE");
4607280849Scy			unpeer(peer);
4608280849Scy		}
4609280849Scy	}
4610280849Scy}
4611280849Scy#endif	/* WORKER */
4612280849Scy
4613280849Scy
4614280849Scy#ifdef FREE_CFG_T
4615280849Scystatic void
4616280849Scyfree_config_unpeers(
4617280849Scy	config_tree *ptree
4618280849Scy	)
4619280849Scy{
4620280849Scy	unpeer_node *curr_unpeer;
4621280849Scy
4622280849Scy	if (ptree->unpeers != NULL) {
4623280849Scy		for (;;) {
4624280849Scy			UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
4625280849Scy			if (NULL == curr_unpeer)
4626280849Scy				break;
4627280849Scy			destroy_address_node(curr_unpeer->addr);
4628280849Scy			free(curr_unpeer);
4629280849Scy		}
4630280849Scy		free(ptree->unpeers);
4631280849Scy	}
4632280849Scy}
4633280849Scy#endif	/* FREE_CFG_T */
4634280849Scy
4635280849Scy
4636280849Scy#ifndef SIM
4637280849Scystatic void
4638280849Scyconfig_reset_counters(
4639280849Scy	config_tree *ptree
4640280849Scy	)
4641280849Scy{
4642280849Scy	int_node *counter_set;
4643280849Scy
4644280849Scy	for (counter_set = HEAD_PFIFO(ptree->reset_counters);
4645280849Scy	     counter_set != NULL;
4646280849Scy	     counter_set = counter_set->link) {
4647280849Scy		switch (counter_set->i) {
4648280849Scy		default:
4649280849Scy			DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
4650280849Scy				    keyword(counter_set->i), counter_set->i));
465154359Sroberto			break;
465254359Sroberto
4653280849Scy		case T_Allpeers:
4654280849Scy			peer_all_reset();
465554359Sroberto			break;
465654359Sroberto
4657280849Scy		case T_Auth:
4658280849Scy			reset_auth_stats();
4659280849Scy			break;
466054359Sroberto
4661280849Scy		case T_Ctl:
4662280849Scy			ctl_clr_stats();
466354359Sroberto			break;
466454359Sroberto
4665280849Scy		case T_Io:
4666280849Scy			io_clr_stats();
4667280849Scy			break;
466854359Sroberto
4669280849Scy		case T_Mem:
4670280849Scy			peer_clr_stats();
467154359Sroberto			break;
467254359Sroberto
4673280849Scy		case T_Sys:
4674280849Scy			proto_clr_stats();
467554359Sroberto			break;
467654359Sroberto
4677280849Scy		case T_Timer:
4678280849Scy			timer_clr_stats();
4679280849Scy			break;
4680280849Scy		}
4681280849Scy	}
4682280849Scy}
4683280849Scy#endif	/* !SIM */
468454359Sroberto
4685280849Scy
4686280849Scy#ifdef FREE_CFG_T
4687280849Scystatic void
4688280849Scyfree_config_reset_counters(
4689280849Scy	config_tree *ptree
4690280849Scy	)
4691280849Scy{
4692280849Scy	FREE_INT_FIFO(ptree->reset_counters);
4693280849Scy}
4694280849Scy#endif	/* FREE_CFG_T */
4695280849Scy
4696280849Scy
4697280849Scy#ifdef SIM
4698280849Scystatic void
4699280849Scyconfig_sim(
4700280849Scy	config_tree *ptree
4701280849Scy	)
4702280849Scy{
4703280849Scy	int i;
4704280849Scy	server_info *serv_info;
4705280849Scy	attr_val *init_stmt;
4706280849Scy	sim_node *sim_n;
4707280849Scy
4708280849Scy	/* Check if a simulate block was found in the configuration code.
4709280849Scy	 * If not, return an error and exit
4710280849Scy	 */
4711280849Scy	sim_n = HEAD_PFIFO(ptree->sim_details);
4712280849Scy	if (NULL == sim_n) {
4713280849Scy		fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
4714280849Scy		fprintf(stderr, "\tCheck your configuration file.\n");
4715280849Scy		exit(1);
4716280849Scy	}
4717280849Scy
4718280849Scy	/* Process the initialization statements
4719280849Scy	 * -------------------------------------
4720280849Scy	 */
4721280849Scy	init_stmt = HEAD_PFIFO(sim_n->init_opts);
4722280849Scy	for (; init_stmt != NULL; init_stmt = init_stmt->link) {
4723280849Scy		switch(init_stmt->attr) {
4724280849Scy
4725280849Scy		case T_Beep_Delay:
4726280849Scy			simulation.beep_delay = init_stmt->value.d;
472754359Sroberto			break;
4728132451Sroberto
4729280849Scy		case T_Sim_Duration:
4730280849Scy			simulation.end_time = init_stmt->value.d;
4731280849Scy			break;
4732280849Scy
4733280849Scy		default:
4734280849Scy			fprintf(stderr,
4735280849Scy				"Unknown simulator init token %d\n",
4736280849Scy				init_stmt->attr);
4737280849Scy			exit(1);
473854359Sroberto		}
473954359Sroberto	}
474082498Sroberto
4741280849Scy	/* Process the server list
4742280849Scy	 * -----------------------
4743280849Scy	 */
4744280849Scy	simulation.num_of_servers = 0;
4745280849Scy	serv_info = HEAD_PFIFO(sim_n->servers);
4746280849Scy	for (; serv_info != NULL; serv_info = serv_info->link)
4747280849Scy		simulation.num_of_servers++;
4748285169Scy	simulation.servers = eallocarray(simulation.num_of_servers,
4749280849Scy				     sizeof(simulation.servers[0]));
4750280849Scy
4751280849Scy	i = 0;
4752280849Scy	serv_info = HEAD_PFIFO(sim_n->servers);
4753280849Scy	for (; serv_info != NULL; serv_info = serv_info->link) {
4754280849Scy		if (NULL == serv_info) {
4755280849Scy			fprintf(stderr, "Simulator server list is corrupt\n");
4756280849Scy			exit(1);
4757280849Scy		} else {
4758280849Scy			simulation.servers[i] = *serv_info;
4759280849Scy			simulation.servers[i].link = NULL;
4760280849Scy			i++;
4761280849Scy		}
4762280849Scy	}
4763280849Scy
4764280849Scy	printf("Creating server associations\n");
4765280849Scy	create_server_associations();
4766280849Scy	fprintf(stderr,"\tServer associations successfully created!!\n");
4767280849Scy}
4768280849Scy
4769280849Scy
4770280849Scy#ifdef FREE_CFG_T
4771280849Scystatic void
4772280849Scyfree_config_sim(
4773280849Scy	config_tree *ptree
4774280849Scy	)
4775280849Scy{
4776280849Scy	sim_node *sim_n;
4777280849Scy	server_info *serv_n;
4778280849Scy	script_info *script_n;
4779280849Scy
4780280849Scy	if (NULL == ptree->sim_details)
4781280849Scy		return;
4782280849Scy	sim_n = HEAD_PFIFO(ptree->sim_details);
4783280849Scy	free(ptree->sim_details);
4784280849Scy	ptree->sim_details = NULL;
4785280849Scy	if (NULL == sim_n)
4786280849Scy		return;
4787280849Scy
4788280849Scy	FREE_ATTR_VAL_FIFO(sim_n->init_opts);
4789280849Scy	for (;;) {
4790280849Scy		UNLINK_FIFO(serv_n, *sim_n->servers, link);
4791280849Scy		if (NULL == serv_n)
4792280849Scy			break;
4793280849Scy		free(serv_n->curr_script);
4794280849Scy		if (serv_n->script != NULL) {
4795280849Scy			for (;;) {
4796280849Scy				UNLINK_FIFO(script_n, *serv_n->script,
4797280849Scy					    link);
4798280849Scy				if (script_n == NULL)
4799280849Scy					break;
4800280849Scy				free(script_n);
4801280849Scy			}
4802280849Scy			free(serv_n->script);
4803280849Scy		}
4804280849Scy		free(serv_n);
4805280849Scy	}
4806280849Scy	free(sim_n);
4807280849Scy}
4808280849Scy#endif	/* FREE_CFG_T */
4809280849Scy#endif	/* SIM */
4810280849Scy
4811280849Scy
4812280849Scy/* Define two different config functions. One for the daemon and the other for
4813280849Scy * the simulator. The simulator ignores a lot of the standard ntpd configuration
4814280849Scy * options
4815280849Scy */
4816280849Scy#ifndef SIM
4817280849Scystatic void
4818280849Scyconfig_ntpd(
4819285169Scy	config_tree *ptree,
4820285169Scy	int/*BOOL*/ input_from_files
4821280849Scy	)
4822280849Scy{
4823330106Sdelphij	/* [Bug 3435] check and esure clock sanity if configured from
4824330106Sdelphij	 * file and clock sanity parameters (-> basedate) are given. Do
4825330106Sdelphij	 * this ASAP, so we don't disturb the closed loop controller.
4826330106Sdelphij	 */
4827330106Sdelphij	if (input_from_files) {
4828330106Sdelphij		if (config_tos_clock(ptree))
4829330106Sdelphij			clamp_systime();
4830330106Sdelphij	}
4831338530Sdelphij
4832285169Scy	config_nic_rules(ptree, input_from_files);
4833280849Scy	config_monitor(ptree);
4834280849Scy	config_auth(ptree);
4835280849Scy	config_tos(ptree);
4836280849Scy	config_access(ptree);
4837280849Scy	config_tinker(ptree);
4838280849Scy	config_rlimit(ptree);
4839280849Scy	config_system_opts(ptree);
4840280849Scy	config_logconfig(ptree);
4841280849Scy	config_phone(ptree);
4842280849Scy	config_mdnstries(ptree);
4843280849Scy	config_setvar(ptree);
4844280849Scy	config_ttl(ptree);
4845280849Scy	config_vars(ptree);
4846285169Scy
4847316068Sdelphij	io_open_sockets();	/* [bug 2837] dep. on config_vars() */
4848285169Scy
4849316068Sdelphij	config_trap(ptree);	/* [bug 2923] dep. on io_open_sockets() */
4850280849Scy	config_other_modes(ptree);
4851280849Scy	config_peers(ptree);
4852280849Scy	config_unpeers(ptree);
4853280849Scy	config_fudge(ptree);
4854280849Scy	config_reset_counters(ptree);
4855280849Scy
4856330106Sdelphij#ifdef DEBUG
4857330106Sdelphij	if (debug > 1) {
4858330106Sdelphij		dump_restricts();
4859330106Sdelphij	}
4860330106Sdelphij#endif
4861330106Sdelphij
4862280849Scy#ifdef TEST_BLOCKING_WORKER
4863280849Scy	{
4864280849Scy		struct addrinfo hints;
4865280849Scy
4866280849Scy		ZERO(hints);
4867280849Scy		hints.ai_socktype = SOCK_STREAM;
4868280849Scy		hints.ai_protocol = IPPROTO_TCP;
4869280849Scy		getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
4870280849Scy				     INITIAL_DNS_RETRY,
4871280849Scy				     gai_test_callback, (void *)1);
4872280849Scy		hints.ai_family = AF_INET6;
4873280849Scy		getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
4874280849Scy				     INITIAL_DNS_RETRY,
4875280849Scy				     gai_test_callback, (void *)0x600);
4876280849Scy	}
4877280849Scy#endif
4878280849Scy}
4879280849Scy#endif	/* !SIM */
4880280849Scy
4881280849Scy
4882280849Scy#ifdef SIM
4883280849Scystatic void
4884280849Scyconfig_ntpdsim(
4885280849Scy	config_tree *ptree
4886280849Scy	)
4887280849Scy{
4888280849Scy	printf("Configuring Simulator...\n");
4889280849Scy	printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
4890280849Scy
4891280849Scy	config_tos(ptree);
4892280849Scy	config_monitor(ptree);
4893280849Scy	config_tinker(ptree);
4894280849Scy	if (0)
4895280849Scy		config_rlimit(ptree);	/* not needed for the simulator */
4896280849Scy	config_system_opts(ptree);
4897280849Scy	config_logconfig(ptree);
4898280849Scy	config_vars(ptree);
4899280849Scy	config_sim(ptree);
4900280849Scy}
4901280849Scy#endif /* SIM */
4902280849Scy
4903280849Scy
4904280849Scy/*
4905280849Scy * config_remotely() - implements ntpd side of ntpq :config
4906280849Scy */
4907280849Scyvoid
4908280849Scyconfig_remotely(
4909280849Scy	sockaddr_u *	remote_addr
4910280849Scy	)
4911280849Scy{
4912280849Scy	char origin[128];
4913280849Scy
4914280849Scy	snprintf(origin, sizeof(origin), "remote config from %s",
4915280849Scy		 stoa(remote_addr));
4916285169Scy	lex_init_stack(origin, NULL); /* no checking needed... */
4917285169Scy	init_syntax_tree(&cfgt);
4918285169Scy	yyparse();
4919285169Scy	lex_drop_stack();
4920280849Scy
4921280849Scy	cfgt.source.attr = CONF_SOURCE_NTPQ;
4922280849Scy	cfgt.timestamp = time(NULL);
4923280849Scy	cfgt.source.value.s = estrdup(stoa(remote_addr));
4924280849Scy
4925280849Scy	DPRINTF(1, ("Finished Parsing!!\n"));
4926280849Scy
4927285169Scy	save_and_apply_config_tree(FALSE);
4928280849Scy}
4929280849Scy
4930280849Scy
4931280849Scy/*
4932280849Scy * getconfig() - process startup configuration file e.g /etc/ntp.conf
4933280849Scy */
4934280849Scyvoid
4935280849Scygetconfig(
4936280849Scy	int	argc,
4937280849Scy	char **	argv
4938280849Scy	)
4939280849Scy{
4940280849Scy	char	line[256];
4941280849Scy
4942280849Scy#ifdef DEBUG
4943280849Scy	atexit(free_all_config_trees);
4944280849Scy#endif
4945280849Scy#ifndef SYS_WINNT
4946280849Scy	config_file = CONFIG_FILE;
4947280849Scy#else
4948280849Scy	temp = CONFIG_FILE;
4949280849Scy	if (!ExpandEnvironmentStringsA(temp, config_file_storage,
4950280849Scy				       sizeof(config_file_storage))) {
4951280849Scy		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
4952280849Scy		exit(1);
4953280849Scy	}
4954280849Scy	config_file = config_file_storage;
4955280849Scy
4956280849Scy	temp = ALT_CONFIG_FILE;
4957280849Scy	if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
4958280849Scy				       sizeof(alt_config_file_storage))) {
4959280849Scy		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
4960280849Scy		exit(1);
4961280849Scy	}
4962280849Scy	alt_config_file = alt_config_file_storage;
4963280849Scy#endif /* SYS_WINNT */
4964280849Scy
4965280849Scy	/*
4966280849Scy	 * install a non default variable with this daemon version
4967280849Scy	 */
4968280849Scy	snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
4969280849Scy	set_sys_var(line, strlen(line) + 1, RO);
4970280849Scy
4971280849Scy	/*
4972280849Scy	 * Set up for the first time step to install a variable showing
4973280849Scy	 * which syscall is being used to step.
4974280849Scy	 */
4975280849Scy	set_tod_using = &ntpd_set_tod_using;
4976280849Scy
4977280849Scy	getCmdOpts(argc, argv);
4978280849Scy	init_syntax_tree(&cfgt);
4979280849Scy	if (
4980285169Scy		!lex_init_stack(FindConfig(config_file), "r")
498154359Sroberto#ifdef HAVE_NETINFO
4982280849Scy		/* If there is no config_file, try NetInfo. */
4983280849Scy		&& check_netinfo && !(config_netinfo = get_netinfo_config())
4984280849Scy#endif /* HAVE_NETINFO */
4985280849Scy		) {
4986280849Scy		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
4987280849Scy#ifndef SYS_WINNT
4988280849Scy		io_open_sockets();
4989280849Scy
4990280849Scy		return;
4991280849Scy#else
4992280849Scy		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
4993280849Scy
4994285169Scy		if (!lex_init_stack(FindConfig(alt_config_file), "r"))  {
4995280849Scy			/*
4996280849Scy			 * Broadcast clients can sometimes run without
4997280849Scy			 * a configuration file.
4998280849Scy			 */
4999280849Scy			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
5000280849Scy			io_open_sockets();
5001280849Scy
5002280849Scy			return;
5003280849Scy		}
5004280849Scy		cfgt.source.value.s = estrdup(alt_config_file);
5005280849Scy#endif	/* SYS_WINNT */
5006280849Scy	} else
5007280849Scy		cfgt.source.value.s = estrdup(config_file);
5008280849Scy
5009280849Scy
5010280849Scy	/*** BULK OF THE PARSER ***/
5011280849Scy#ifdef DEBUG
5012280849Scy	yydebug = !!(debug >= 5);
5013280849Scy#endif
5014285169Scy	yyparse();
5015285169Scy	lex_drop_stack();
5016280849Scy
5017280849Scy	DPRINTF(1, ("Finished Parsing!!\n"));
5018280849Scy
5019280849Scy	cfgt.source.attr = CONF_SOURCE_FILE;
5020280849Scy	cfgt.timestamp = time(NULL);
5021280849Scy
5022285169Scy	save_and_apply_config_tree(TRUE);
5023280849Scy
5024280849Scy#ifdef HAVE_NETINFO
502582498Sroberto	if (config_netinfo)
502682498Sroberto		free_netinfo_config(config_netinfo);
502754359Sroberto#endif /* HAVE_NETINFO */
5028280849Scy}
502954359Sroberto
503082498Sroberto
5031280849Scyvoid
5032285169Scysave_and_apply_config_tree(int/*BOOL*/ input_from_file)
5033280849Scy{
5034280849Scy	config_tree *ptree;
5035280849Scy#ifndef SAVECONFIG
5036280849Scy	config_tree *punlinked;
5037280849Scy#endif
503882498Sroberto
5039280849Scy	/*
5040280849Scy	 * Keep all the configuration trees applied since startup in
5041280849Scy	 * a list that can be used to dump the configuration back to
5042280849Scy	 * a text file.
5043280849Scy	 */
5044280849Scy	ptree = emalloc(sizeof(*ptree));
5045280849Scy	memcpy(ptree, &cfgt, sizeof(*ptree));
5046280849Scy	ZERO(cfgt);
5047280849Scy
5048280849Scy	LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
5049280849Scy
5050280849Scy#ifdef SAVECONFIG
5051280849Scy	if (HAVE_OPT( SAVECONFIGQUIT )) {
5052280849Scy		FILE *dumpfile;
5053280849Scy		int err;
5054280849Scy		int dumpfailed;
5055280849Scy
5056280849Scy		dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
5057280849Scy		if (NULL == dumpfile) {
5058280849Scy			err = errno;
5059280849Scy			mfprintf(stderr,
5060280849Scy				 "can not create save file %s, error %d %m\n",
5061280849Scy				 OPT_ARG(SAVECONFIGQUIT), err);
5062280849Scy			exit(err);
506382498Sroberto		}
5064280849Scy
5065280849Scy		dumpfailed = dump_all_config_trees(dumpfile, 0);
5066280849Scy		if (dumpfailed)
5067280849Scy			fprintf(stderr,
5068280849Scy				"--saveconfigquit %s error %d\n",
5069280849Scy				OPT_ARG( SAVECONFIGQUIT ),
5070280849Scy				dumpfailed);
5071280849Scy		else
5072280849Scy			fprintf(stderr,
5073280849Scy				"configuration saved to %s\n",
5074280849Scy				OPT_ARG( SAVECONFIGQUIT ));
5075280849Scy
5076280849Scy		exit(dumpfailed);
507782498Sroberto	}
5078280849Scy#endif	/* SAVECONFIG */
507982498Sroberto
5080280849Scy	/* The actual configuration done depends on whether we are configuring the
5081280849Scy	 * simulator or the daemon. Perform a check and call the appropriate
5082280849Scy	 * function as needed.
5083280849Scy	 */
508482498Sroberto
5085280849Scy#ifndef SIM
5086285169Scy	config_ntpd(ptree, input_from_file);
5087280849Scy#else
5088280849Scy	config_ntpdsim(ptree);
5089280849Scy#endif
5090280849Scy
5091280849Scy	/*
5092280849Scy	 * With configure --disable-saveconfig, there's no use keeping
5093280849Scy	 * the config tree around after application, so free it.
5094280849Scy	 */
5095280849Scy#ifndef SAVECONFIG
5096280849Scy	UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
5097280849Scy		     config_tree);
5098280849Scy	INSIST(punlinked == ptree);
5099280849Scy	free_config_tree(ptree);
5100280849Scy#endif
5101280849Scy}
5102280849Scy
5103316068Sdelphij/* Hack to disambiguate 'server' statements for refclocks and network peers.
5104316068Sdelphij * Please note the qualification 'hack'. It's just that.
5105316068Sdelphij */
5106316068Sdelphijstatic int/*BOOL*/
5107316068Sdelphijis_refclk_addr(
5108316068Sdelphij	const address_node * addr
5109316068Sdelphij	)
5110316068Sdelphij{
5111338530Sdelphij	return addr && addr->address && !strncmp(addr->address, "127.127.", 8);
5112316068Sdelphij}
5113280849Scy
5114280849Scystatic void
5115280849Scyntpd_set_tod_using(
5116280849Scy	const char *which
5117280849Scy	)
5118280849Scy{
5119280849Scy	char line[128];
5120280849Scy
5121280849Scy	snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
5122280849Scy	set_sys_var(line, strlen(line) + 1, RO);
5123280849Scy}
5124280849Scy
5125280849Scy
5126280849Scystatic char *
5127280849Scynormal_dtoa(
5128280849Scy	double d
5129280849Scy	)
5130280849Scy{
5131280849Scy	char *	buf;
5132280849Scy	char *	pch_e;
5133280849Scy	char *	pch_nz;
5134280849Scy
5135280849Scy	LIB_GETBUF(buf);
5136280849Scy	snprintf(buf, LIB_BUFLENGTH, "%g", d);
5137280849Scy
5138280849Scy	/* use lowercase 'e', strip any leading zeroes in exponent */
5139280849Scy	pch_e = strchr(buf, 'e');
5140280849Scy	if (NULL == pch_e) {
5141280849Scy		pch_e = strchr(buf, 'E');
5142280849Scy		if (NULL == pch_e)
5143280849Scy			return buf;
5144280849Scy		*pch_e = 'e';
5145280849Scy	}
5146280849Scy	pch_e++;
5147280849Scy	if ('-' == *pch_e)
5148280849Scy		pch_e++;
5149280849Scy	pch_nz = pch_e;
5150280849Scy	while ('0' == *pch_nz)
5151280849Scy		pch_nz++;
5152280849Scy	if (pch_nz == pch_e)
5153280849Scy		return buf;
5154280849Scy	strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
5155280849Scy
5156280849Scy	return buf;
5157280849Scy}
5158280849Scy
5159280849Scy
5160280849Scy/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
5161280849Scy * --------------------------------------------
5162280849Scy */
5163280849Scy
5164280849Scy
5165280849Scy/*
5166280849Scy * get_pfxmatch - find value for prefixmatch
5167280849Scy * and update char * accordingly
5168280849Scy */
5169280849Scystatic u_int32
5170280849Scyget_pfxmatch(
5171280849Scy	const char **	pstr,
5172280849Scy	struct masks *	m
5173280849Scy	)
5174280849Scy{
5175280849Scy	while (m->name != NULL) {
5176280849Scy		if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
5177280849Scy			*pstr += strlen(m->name);
5178280849Scy			return m->mask;
5179280849Scy		} else {
5180280849Scy			m++;
5181132451Sroberto		}
518254359Sroberto	}
5183280849Scy	return 0;
518454359Sroberto}
518554359Sroberto
5186280849Scy/*
5187280849Scy * get_match - find logmask value
5188280849Scy */
5189280849Scystatic u_int32
5190280849Scyget_match(
5191280849Scy	const char *	str,
5192280849Scy	struct masks *	m
5193280849Scy	)
5194280849Scy{
5195280849Scy	while (m->name != NULL) {
5196280849Scy		if (strcmp(str, m->name) == 0)
5197280849Scy			return m->mask;
5198280849Scy		else
5199280849Scy			m++;
5200280849Scy	}
5201280849Scy	return 0;
5202280849Scy}
520354359Sroberto
5204280849Scy/*
5205280849Scy * get_logmask - build bitmask for ntp_syslogmask
5206280849Scy */
5207280849Scystatic u_int32
5208280849Scyget_logmask(
5209280849Scy	const char *	str
5210280849Scy	)
5211280849Scy{
5212280849Scy	const char *	t;
5213280849Scy	u_int32		offset;
5214280849Scy	u_int32		mask;
5215280849Scy
5216280849Scy	mask = get_match(str, logcfg_noclass_items);
5217280849Scy	if (mask != 0)
5218280849Scy		return mask;
5219280849Scy
5220280849Scy	t = str;
5221280849Scy	offset = get_pfxmatch(&t, logcfg_class);
5222280849Scy	mask   = get_match(t, logcfg_class_items);
5223280849Scy
5224280849Scy	if (mask)
5225280849Scy		return mask << offset;
5226280849Scy	else
5227280849Scy		msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
5228280849Scy			str);
5229280849Scy
5230280849Scy	return 0;
5231280849Scy}
5232280849Scy
5233280849Scy
523454359Sroberto#ifdef HAVE_NETINFO
523554359Sroberto
5236280849Scy/*
523754359Sroberto * get_netinfo_config - find the nearest NetInfo domain with an ntp
523854359Sroberto * configuration and initialize the configuration state.
523954359Sroberto */
524054359Srobertostatic struct netinfo_config_state *
5241280849Scyget_netinfo_config(void)
524254359Sroberto{
524354359Sroberto	ni_status status;
524454359Sroberto	void *domain;
524554359Sroberto	ni_id config_dir;
5246280849Scy	struct netinfo_config_state *config;
524754359Sroberto
524854359Sroberto	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
524954359Sroberto
525054359Sroberto	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
525154359Sroberto		void *next_domain;
525254359Sroberto		if (ni_open(domain, "..", &next_domain) != NI_OK) {
525354359Sroberto			ni_free(next_domain);
525454359Sroberto			break;
525554359Sroberto		}
525654359Sroberto		ni_free(domain);
525754359Sroberto		domain = next_domain;
525854359Sroberto	}
525954359Sroberto	if (status != NI_OK) {
526054359Sroberto		ni_free(domain);
526154359Sroberto		return NULL;
526254359Sroberto	}
526354359Sroberto
5264280849Scy	config = emalloc(sizeof(*config));
5265280849Scy	config->domain = domain;
5266280849Scy	config->config_dir = config_dir;
5267280849Scy	config->prop_index = 0;
5268280849Scy	config->val_index = 0;
5269280849Scy	config->val_list = NULL;
527054359Sroberto
527154359Sroberto	return config;
527254359Sroberto}
527354359Sroberto
527454359Sroberto
527554359Sroberto/*
527654359Sroberto * free_netinfo_config - release NetInfo configuration state
527754359Sroberto */
527854359Srobertostatic void
5279280849Scyfree_netinfo_config(
5280280849Scy	struct netinfo_config_state *config
5281280849Scy	)
528254359Sroberto{
528354359Sroberto	ni_free(config->domain);
528454359Sroberto	free(config);
528554359Sroberto}
528654359Sroberto
528754359Sroberto
528854359Sroberto/*
528954359Sroberto * gettokens_netinfo - return tokens from NetInfo
529054359Sroberto */
529154359Srobertostatic int
529254359Srobertogettokens_netinfo (
529354359Sroberto	struct netinfo_config_state *config,
529454359Sroberto	char **tokenlist,
529554359Sroberto	int *ntokens
529654359Sroberto	)
529754359Sroberto{
529854359Sroberto	int prop_index = config->prop_index;
529954359Sroberto	int val_index = config->val_index;
530054359Sroberto	char **val_list = config->val_list;
530154359Sroberto
530254359Sroberto	/*
530354359Sroberto	 * Iterate through each keyword and look for a property that matches it.
530454359Sroberto	 */
5305280849Scy  again:
530654359Sroberto	if (!val_list) {
5307280849Scy		for (; prop_index < COUNTOF(keywords); prop_index++)
5308280849Scy		{
5309280849Scy			ni_namelist namelist;
531054359Sroberto			struct keyword current_prop = keywords[prop_index];
5311280849Scy			ni_index index;
531254359Sroberto
531354359Sroberto			/*
531454359Sroberto			 * For each value associated in the property, we're going to return
531554359Sroberto			 * a separate line. We squirrel away the values in the config state
531654359Sroberto			 * so the next time through, we don't need to do this lookup.
531754359Sroberto			 */
5318280849Scy			NI_INIT(&namelist);
5319280849Scy			if (NI_OK == ni_lookupprop(config->domain,
5320280849Scy			    &config->config_dir, current_prop.text,
5321280849Scy			    &namelist)) {
532254359Sroberto
532354359Sroberto				/* Found the property, but it has no values */
532454359Sroberto				if (namelist.ni_namelist_len == 0) continue;
532554359Sroberto
5326280849Scy				config->val_list =
5327285169Scy				    eallocarray(
5328285169Scy					(namelist.ni_namelist_len + 1),
5329285169Scy					sizeof(char*));
5330280849Scy				val_list = config->val_list;
533154359Sroberto
5332280849Scy				for (index = 0;
5333280849Scy				     index < namelist.ni_namelist_len;
5334280849Scy				     index++) {
5335280849Scy					char *value;
533654359Sroberto
5337280849Scy					value = namelist.ni_namelist_val[index];
5338280849Scy					val_list[index] = estrdup(value);
533954359Sroberto				}
534054359Sroberto				val_list[index] = NULL;
534154359Sroberto
534254359Sroberto				break;
534354359Sroberto			}
534454359Sroberto			ni_namelist_free(&namelist);
534554359Sroberto		}
534654359Sroberto		config->prop_index = prop_index;
534754359Sroberto	}
534854359Sroberto
534954359Sroberto	/* No list; we're done here. */
5350280849Scy	if (!val_list)
5351280849Scy		return CONFIG_UNKNOWN;
535254359Sroberto
535354359Sroberto	/*
535454359Sroberto	 * We have a list of values for the current property.
535554359Sroberto	 * Iterate through them and return each in order.
535654359Sroberto	 */
5357280849Scy	if (val_list[val_index]) {
535854359Sroberto		int ntok = 1;
535954359Sroberto		int quoted = 0;
536054359Sroberto		char *tokens = val_list[val_index];
536154359Sroberto
536254359Sroberto		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
536354359Sroberto
536454359Sroberto		(const char*)tokenlist[0] = keywords[prop_index].text;
536554359Sroberto		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
536654359Sroberto			tokenlist[ntok] = tokens;
536754359Sroberto			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
536854359Sroberto				quoted ^= (*tokens++ == '"');
536954359Sroberto
537054359Sroberto			if (ISEOL(*tokens)) {
537154359Sroberto				*tokens = '\0';
537254359Sroberto				break;
537354359Sroberto			} else {		/* must be space */
537454359Sroberto				*tokens++ = '\0';
5375280849Scy				while (ISSPACE(*tokens))
5376280849Scy					tokens++;
5377280849Scy				if (ISEOL(*tokens))
5378280849Scy					break;
537954359Sroberto			}
538054359Sroberto		}
538154359Sroberto
5382182007Sroberto		if (ntok == MAXTOKENS) {
5383182007Sroberto			/* HMS: chomp it to lose the EOL? */
5384182007Sroberto			msyslog(LOG_ERR,
5385280849Scy				"gettokens_netinfo: too many tokens.  Ignoring: %s",
5386280849Scy				tokens);
5387182007Sroberto		} else {
5388182007Sroberto			*ntokens = ntok + 1;
5389182007Sroberto		}
5390182007Sroberto
5391182007Sroberto		config->val_index++;	/* HMS: Should this be in the 'else'? */
5392182007Sroberto
539354359Sroberto		return keywords[prop_index].keytype;
539454359Sroberto	}
539554359Sroberto
539654359Sroberto	/* We're done with the current property. */
539754359Sroberto	prop_index = ++config->prop_index;
539854359Sroberto
539954359Sroberto	/* Free val_list and reset counters. */
540054359Sroberto	for (val_index = 0; val_list[val_index]; val_index++)
540154359Sroberto		free(val_list[val_index]);
5402280849Scy	free(val_list);
5403280849Scy	val_list = config->val_list = NULL;
5404280849Scy	val_index = config->val_index = 0;
540554359Sroberto
540654359Sroberto	goto again;
540754359Sroberto}
540854359Sroberto#endif /* HAVE_NETINFO */
540954359Sroberto
541054359Sroberto
541154359Sroberto/*
541254359Sroberto * getnetnum - return a net number (this is crude, but careful)
5413280849Scy *
5414280849Scy * returns 1 for success, and mysteriously, 0 for most failures, and
5415280849Scy * -1 if the address found is IPv6 and we believe IPv6 isn't working.
541654359Sroberto */
5417280849Scy#ifndef SIM
541854359Srobertostatic int
541954359Srobertogetnetnum(
542054359Sroberto	const char *num,
5421280849Scy	sockaddr_u *addr,
5422182007Sroberto	int complain,
5423280849Scy	enum gnn_type a_type	/* ignored */
542454359Sroberto	)
542554359Sroberto{
5426289764Sglebius	REQUIRE(AF_UNSPEC == AF(addr) ||
5427289764Sglebius		AF_INET == AF(addr) ||
5428289764Sglebius		AF_INET6 == AF(addr));
542954359Sroberto
5430280849Scy	if (!is_ip_address(num, AF(addr), addr))
5431280849Scy		return 0;
5432182007Sroberto
5433280849Scy	if (IS_IPV6(addr) && !ipv6_works)
5434280849Scy		return -1;
543554359Sroberto
5436280849Scy# ifdef ISC_PLATFORM_HAVESALEN
5437280849Scy	addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
5438280849Scy# endif
5439280849Scy	SET_PORT(addr, NTP_PORT);
5440182007Sroberto
5441280849Scy	DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
5442182007Sroberto
544354359Sroberto	return 1;
544454359Sroberto}
5445280849Scy#endif	/* !SIM */
544654359Sroberto
5447280849Scy#if defined(HAVE_SETRLIMIT)
5448280849Scyvoid
5449280849Scyntp_rlimit(
5450280849Scy	int	rl_what,
5451280849Scy	rlim_t	rl_value,
5452280849Scy	int	rl_scale,
5453280849Scy	const char *	rl_sstr
545454359Sroberto	)
545554359Sroberto{
5456280849Scy	struct rlimit	rl;
545754359Sroberto
5458280849Scy	switch (rl_what) {
5459280849Scy# ifdef RLIMIT_MEMLOCK
5460280849Scy	    case RLIMIT_MEMLOCK:
5461330106Sdelphij		if (HAVE_OPT( SAVECONFIGQUIT )) {
5462330106Sdelphij			break;
5463330106Sdelphij		}
546454359Sroberto		/*
5465280849Scy		 * The default RLIMIT_MEMLOCK is very low on Linux systems.
5466280849Scy		 * Unless we increase this limit malloc calls are likely to
5467280849Scy		 * fail if we drop root privilege.  To be useful the value
5468280849Scy		 * has to be larger than the largest ntpd resident set size.
546954359Sroberto		 */
5470280849Scy		DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
5471280849Scy			(int)(rl_value / rl_scale), rl_sstr));
5472280849Scy		rl.rlim_cur = rl.rlim_max = rl_value;
5473280849Scy		if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
5474280849Scy			msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
5475280849Scy		break;
5476280849Scy# endif /* RLIMIT_MEMLOCK */
5477280849Scy
5478280849Scy# ifdef RLIMIT_NOFILE
5479280849Scy	    case RLIMIT_NOFILE:
548054359Sroberto		/*
5481280849Scy		 * For large systems the default file descriptor limit may
5482285169Scy		 * not be enough.
548354359Sroberto		 */
5484280849Scy		DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
5485280849Scy			(int)(rl_value / rl_scale), rl_sstr));
5486280849Scy		rl.rlim_cur = rl.rlim_max = rl_value;
5487280849Scy		if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
5488280849Scy			msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
5489280849Scy		break;
5490280849Scy# endif /* RLIMIT_NOFILE */
549154359Sroberto
5492280849Scy# ifdef RLIMIT_STACK
5493280849Scy	    case RLIMIT_STACK:
549454359Sroberto		/*
5495280849Scy		 * Provide a way to set the stack limit to something
5496280849Scy		 * smaller, so that we don't lock a lot of unused
5497280849Scy		 * stack memory.
549854359Sroberto		 */
5499280849Scy		DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
5500280849Scy			    (int)(rl_value / rl_scale), rl_sstr));
5501280849Scy		if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
5502285169Scy			msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
5503280849Scy		} else {
5504280849Scy			if (rl_value > rl.rlim_max) {
5505280849Scy				msyslog(LOG_WARNING,
5506280849Scy					"ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
5507280849Scy					(u_long)rl.rlim_max,
5508280849Scy					(u_long)rl_value);
5509280849Scy				rl_value = rl.rlim_max;
5510280849Scy			}
5511285169Scy			rl.rlim_cur = rl_value;
5512280849Scy			if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
5513280849Scy				msyslog(LOG_ERR,
5514285169Scy					"ntp_rlimit: Cannot set RLIMIT_STACK: %m");
5515280849Scy			}
5516182007Sroberto		}
5517280849Scy		break;
5518280849Scy# endif /* RLIMIT_STACK */
5519280849Scy
5520280849Scy	    default:
5521316068Sdelphij		    fatal_error("ntp_rlimit: unexpected RLIMIT case: %d", rl_what);
552254359Sroberto	}
552354359Sroberto}
5524280849Scy#endif	/* HAVE_SETRLIMIT */
5525330106Sdelphij
5526330106Sdelphij
5527330106Sdelphijchar *
5528358659Scybuild_iflags(
5529358659Scy	u_int32 iflags
5530358659Scy	)
5531330106Sdelphij{
5532330106Sdelphij	static char ifs[1024];
5533330106Sdelphij
5534330106Sdelphij	ifs[0] = '\0';
5535330106Sdelphij
5536330106Sdelphij	if (iflags & INT_UP) {
5537330106Sdelphij		iflags &= ~INT_UP;
5538330106Sdelphij		appendstr(ifs, sizeof ifs, "up");
5539330106Sdelphij	}
5540330106Sdelphij
5541330106Sdelphij	if (iflags & INT_PPP) {
5542330106Sdelphij		iflags &= ~INT_PPP;
5543330106Sdelphij		appendstr(ifs, sizeof ifs, "ppp");
5544330106Sdelphij	}
5545330106Sdelphij
5546330106Sdelphij	if (iflags & INT_LOOPBACK) {
5547330106Sdelphij		iflags &= ~INT_LOOPBACK;
5548330106Sdelphij		appendstr(ifs, sizeof ifs, "loopback");
5549330106Sdelphij	}
5550330106Sdelphij
5551330106Sdelphij	if (iflags & INT_BROADCAST) {
5552330106Sdelphij		iflags &= ~INT_BROADCAST;
5553330106Sdelphij		appendstr(ifs, sizeof ifs, "broadcast");
5554330106Sdelphij	}
5555330106Sdelphij
5556330106Sdelphij	if (iflags & INT_MULTICAST) {
5557330106Sdelphij		iflags &= ~INT_MULTICAST;
5558330106Sdelphij		appendstr(ifs, sizeof ifs, "multicast");
5559330106Sdelphij	}
5560330106Sdelphij
5561330106Sdelphij	if (iflags & INT_BCASTOPEN) {
5562330106Sdelphij		iflags &= ~INT_BCASTOPEN;
5563330106Sdelphij		appendstr(ifs, sizeof ifs, "bcastopen");
5564330106Sdelphij	}
5565330106Sdelphij
5566330106Sdelphij	if (iflags & INT_MCASTOPEN) {
5567330106Sdelphij		iflags &= ~INT_MCASTOPEN;
5568330106Sdelphij		appendstr(ifs, sizeof ifs, "mcastopen");
5569330106Sdelphij	}
5570330106Sdelphij
5571330106Sdelphij	if (iflags & INT_WILDCARD) {
5572330106Sdelphij		iflags &= ~INT_WILDCARD;
5573330106Sdelphij		appendstr(ifs, sizeof ifs, "wildcard");
5574330106Sdelphij	}
5575330106Sdelphij
5576330106Sdelphij	if (iflags & INT_MCASTIF) {
5577330106Sdelphij		iflags &= ~INT_MCASTIF;
5578330106Sdelphij		appendstr(ifs, sizeof ifs, "MCASTif");
5579330106Sdelphij	}
5580330106Sdelphij
5581330106Sdelphij	if (iflags & INT_PRIVACY) {
5582330106Sdelphij		iflags &= ~INT_PRIVACY;
5583330106Sdelphij		appendstr(ifs, sizeof ifs, "IPv6privacy");
5584330106Sdelphij	}
5585330106Sdelphij
5586330106Sdelphij	if (iflags & INT_BCASTXMIT) {
5587330106Sdelphij		iflags &= ~INT_BCASTXMIT;
5588330106Sdelphij		appendstr(ifs, sizeof ifs, "bcastxmit");
5589330106Sdelphij	}
5590330106Sdelphij
5591330106Sdelphij	if (iflags) {
5592330106Sdelphij		char string[10];
5593330106Sdelphij
5594330106Sdelphij		snprintf(string, sizeof string, "%0x", iflags);
5595330106Sdelphij		appendstr(ifs, sizeof ifs, string);
5596330106Sdelphij	}
5597330106Sdelphij
5598330106Sdelphij	return ifs;
5599330106Sdelphij}
5600330106Sdelphij
5601330106Sdelphij
5602330106Sdelphijchar *
5603358659Scybuild_mflags(
5604358659Scy	u_short mflags
5605358659Scy	)
5606330106Sdelphij{
5607330106Sdelphij	static char mfs[1024];
5608330106Sdelphij
5609330106Sdelphij	mfs[0] = '\0';
5610330106Sdelphij
5611330106Sdelphij	if (mflags & RESM_NTPONLY) {
5612330106Sdelphij		mflags &= ~RESM_NTPONLY;
5613330106Sdelphij		appendstr(mfs, sizeof mfs, "ntponly");
5614330106Sdelphij	}
5615330106Sdelphij
5616330106Sdelphij	if (mflags & RESM_SOURCE) {
5617330106Sdelphij		mflags &= ~RESM_SOURCE;
5618330106Sdelphij		appendstr(mfs, sizeof mfs, "source");
5619330106Sdelphij	}
5620330106Sdelphij
5621330106Sdelphij	if (mflags) {
5622330106Sdelphij		char string[10];
5623330106Sdelphij
5624330106Sdelphij		snprintf(string, sizeof string, "%0x", mflags);
5625330106Sdelphij		appendstr(mfs, sizeof mfs, string);
5626330106Sdelphij	}
5627330106Sdelphij
5628330106Sdelphij	return mfs;
5629330106Sdelphij}
5630330106Sdelphij
5631330106Sdelphij
5632330106Sdelphijchar *
5633358659Scybuild_rflags(
5634358659Scy	u_short rflags
5635358659Scy	)
5636330106Sdelphij{
5637330106Sdelphij	static char rfs[1024];
5638330106Sdelphij
5639330106Sdelphij	rfs[0] = '\0';
5640330106Sdelphij
5641330106Sdelphij	if (rflags & RES_FLAKE) {
5642330106Sdelphij		rflags &= ~RES_FLAKE;
5643330106Sdelphij		appendstr(rfs, sizeof rfs, "flake");
5644330106Sdelphij	}
5645330106Sdelphij
5646330106Sdelphij	if (rflags & RES_IGNORE) {
5647330106Sdelphij		rflags &= ~RES_IGNORE;
5648330106Sdelphij		appendstr(rfs, sizeof rfs, "ignore");
5649330106Sdelphij	}
5650330106Sdelphij
5651330106Sdelphij	if (rflags & RES_KOD) {
5652330106Sdelphij		rflags &= ~RES_KOD;
5653330106Sdelphij		appendstr(rfs, sizeof rfs, "kod");
5654330106Sdelphij	}
5655330106Sdelphij
5656330106Sdelphij	if (rflags & RES_MSSNTP) {
5657330106Sdelphij		rflags &= ~RES_MSSNTP;
5658330106Sdelphij		appendstr(rfs, sizeof rfs, "mssntp");
5659330106Sdelphij	}
5660330106Sdelphij
5661330106Sdelphij	if (rflags & RES_LIMITED) {
5662330106Sdelphij		rflags &= ~RES_LIMITED;
5663330106Sdelphij		appendstr(rfs, sizeof rfs, "limited");
5664330106Sdelphij	}
5665330106Sdelphij
5666330106Sdelphij	if (rflags & RES_LPTRAP) {
5667330106Sdelphij		rflags &= ~RES_LPTRAP;
5668330106Sdelphij		appendstr(rfs, sizeof rfs, "lptrap");
5669330106Sdelphij	}
5670330106Sdelphij
5671330106Sdelphij	if (rflags & RES_NOMODIFY) {
5672330106Sdelphij		rflags &= ~RES_NOMODIFY;
5673330106Sdelphij		appendstr(rfs, sizeof rfs, "nomodify");
5674330106Sdelphij	}
5675330106Sdelphij
5676330106Sdelphij	if (rflags & RES_NOMRULIST) {
5677330106Sdelphij		rflags &= ~RES_NOMRULIST;
5678330106Sdelphij		appendstr(rfs, sizeof rfs, "nomrulist");
5679330106Sdelphij	}
5680330106Sdelphij
5681330106Sdelphij	if (rflags & RES_NOEPEER) {
5682330106Sdelphij		rflags &= ~RES_NOEPEER;
5683330106Sdelphij		appendstr(rfs, sizeof rfs, "noepeer");
5684330106Sdelphij	}
5685330106Sdelphij
5686330106Sdelphij	if (rflags & RES_NOPEER) {
5687330106Sdelphij		rflags &= ~RES_NOPEER;
5688330106Sdelphij		appendstr(rfs, sizeof rfs, "nopeer");
5689330106Sdelphij	}
5690330106Sdelphij
5691330106Sdelphij	if (rflags & RES_NOQUERY) {
5692330106Sdelphij		rflags &= ~RES_NOQUERY;
5693330106Sdelphij		appendstr(rfs, sizeof rfs, "noquery");
5694330106Sdelphij	}
5695330106Sdelphij
5696330106Sdelphij	if (rflags & RES_DONTSERVE) {
5697330106Sdelphij		rflags &= ~RES_DONTSERVE;
5698330106Sdelphij		appendstr(rfs, sizeof rfs, "dontserve");
5699330106Sdelphij	}
5700330106Sdelphij
5701330106Sdelphij	if (rflags & RES_NOTRAP) {
5702330106Sdelphij		rflags &= ~RES_NOTRAP;
5703330106Sdelphij		appendstr(rfs, sizeof rfs, "notrap");
5704330106Sdelphij	}
5705330106Sdelphij
5706330106Sdelphij	if (rflags & RES_DONTTRUST) {
5707330106Sdelphij		rflags &= ~RES_DONTTRUST;
5708330106Sdelphij		appendstr(rfs, sizeof rfs, "notrust");
5709330106Sdelphij	}
5710330106Sdelphij
5711358659Scy	if (rflags & RES_SRVRSPFUZ) {
5712358659Scy		rflags &= ~RES_SRVRSPFUZ;
5713358659Scy		appendstr(rfs, sizeof rfs, "srvrspfuz");
5714358659Scy	}
5715358659Scy
5716330106Sdelphij	if (rflags & RES_VERSION) {
5717330106Sdelphij		rflags &= ~RES_VERSION;
5718330106Sdelphij		appendstr(rfs, sizeof rfs, "version");
5719330106Sdelphij	}
5720330106Sdelphij
5721330106Sdelphij	if (rflags) {
5722330106Sdelphij		char string[10];
5723330106Sdelphij
5724330106Sdelphij		snprintf(string, sizeof string, "%0x", rflags);
5725330106Sdelphij		appendstr(rfs, sizeof rfs, string);
5726330106Sdelphij	}
5727330106Sdelphij
5728330106Sdelphij	if ('\0' == rfs[0]) {
5729330106Sdelphij		appendstr(rfs, sizeof rfs, "(none)");
5730330106Sdelphij	}
5731330106Sdelphij
5732330106Sdelphij	return rfs;
5733330106Sdelphij}
5734330106Sdelphij
5735330106Sdelphij
5736330106Sdelphijstatic void
5737330106Sdelphijappendstr(
5738330106Sdelphij	char *string,
5739330106Sdelphij	size_t s,
5740338530Sdelphij	const char *new
5741330106Sdelphij	)
5742330106Sdelphij{
5743330106Sdelphij	if (*string != '\0') {
5744330106Sdelphij		(void)strlcat(string, ",", s);
5745330106Sdelphij	}
5746330106Sdelphij	(void)strlcat(string, new, s);
5747330106Sdelphij
5748330106Sdelphij	return;
5749330106Sdelphij}
5750