1290000Sglebius/* ntp_config.c
2290000Sglebius *
3290000Sglebius * This file contains the ntpd configuration code.
4290000Sglebius *
5290000Sglebius * Written By:	Sachin Kamboj
6290000Sglebius *		University of Delaware
7290000Sglebius *		Newark, DE 19711
8290000Sglebius * Some parts borrowed from the older ntp_config.c
9290000Sglebius * Copyright (c) 2006
1054359Sroberto */
11290000Sglebius
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
23290000Sglebius# include <sys/param.h>
24106163Sroberto#endif
2582498Sroberto#include <signal.h>
2682498Sroberto#ifndef SIGCHLD
2782498Sroberto# define SIGCHLD SIGCLD
2882498Sroberto#endif
29290000Sglebius#ifdef HAVE_SYS_WAIT_H
30290000Sglebius# include <sys/wait.h>
31290000Sglebius#endif
3282498Sroberto
33290000Sglebius#include <isc/net.h>
34290000Sglebius#include <isc/result.h>
3554359Sroberto
36290000Sglebius#include "ntp.h"
37290000Sglebius#include "ntpd.h"
38290000Sglebius#include "ntp_io.h"
39290000Sglebius#include "ntp_unixtime.h"
40290000Sglebius#include "ntp_refclock.h"
41290000Sglebius#include "ntp_filegen.h"
42290000Sglebius#include "ntp_stdlib.h"
43290000Sglebius#include "lib_strbuf.h"
44290000Sglebius#include "ntp_assert.h"
45290000Sglebius#include "ntp_random.h"
46182007Sroberto/*
47182007Sroberto * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
48182007Sroberto * so #include these later.
49182007Sroberto */
50182007Sroberto#include "ntp_config.h"
51182007Sroberto#include "ntp_cmdargs.h"
52290000Sglebius#include "ntp_scanner.h"
53290000Sglebius#include "ntp_parser.h"
54290000Sglebius#include "ntpd-opts.h"
55182007Sroberto
56310419Sdelphij#ifndef IGNORE_DNS_ERRORS
57310419Sdelphij# define DNSFLAGS 0
58310419Sdelphij#else
59310419Sdelphij# define DNSFLAGS GAIR_F_IGNDNSERR
60310419Sdelphij#endif
61310419Sdelphij
62294904Sdelphijextern int yyparse(void);
63294904Sdelphij
64290000Sglebius/* Bug 2817 */
65290000Sglebius#if defined(HAVE_SYS_MMAN_H)
66290000Sglebius# include <sys/mman.h>
67290000Sglebius#endif
6882498Sroberto
69290000Sglebius/* list of servers from command line for config_peers() */
70290000Sglebiusint	cmdline_server_count;
71290000Sglebiuschar **	cmdline_servers;
7254359Sroberto
73290000Sglebius/* Current state of memory locking:
74290000Sglebius * -1: default
75290000Sglebius *  0: memory locking disabled
76290000Sglebius *  1: Memory locking enabled
7754359Sroberto */
78290000Sglebiusint	cur_memlock = -1;
7954359Sroberto
8054359Sroberto/*
8154359Sroberto * "logconfig" building blocks
8254359Sroberto */
8354359Srobertostruct masks {
84290000Sglebius	const char * const	name;
85290000Sglebius	const u_int32		mask;
8654359Sroberto};
8754359Sroberto
8854359Srobertostatic struct masks logcfg_class[] = {
89290000Sglebius	{ "clock",	NLOG_OCLOCK },
90290000Sglebius	{ "peer",	NLOG_OPEER },
91290000Sglebius	{ "sync",	NLOG_OSYNC },
92290000Sglebius	{ "sys",	NLOG_OSYS },
93290000Sglebius	{ NULL,		0 }
9454359Sroberto};
9554359Sroberto
96290000Sglebius/* logcfg_noclass_items[] masks are complete and must not be shifted */
97290000Sglebiusstatic struct masks logcfg_noclass_items[] = {
98290000Sglebius	{ "allall",		NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
99290000Sglebius	{ "allinfo",		NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
100290000Sglebius	{ "allevents",		NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
101290000Sglebius	{ "allstatus",		NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
102290000Sglebius	{ "allstatistics",	NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
103290000Sglebius	/* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
104290000Sglebius	{ "allclock",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
105290000Sglebius	{ "allpeer",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
106290000Sglebius	{ "allsys",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
107290000Sglebius	{ "allsync",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
108290000Sglebius	{ NULL,			0 }
109290000Sglebius};
110290000Sglebius
111290000Sglebius/* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
112290000Sglebiusstatic struct masks logcfg_class_items[] = {
113290000Sglebius	{ "all",		NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST },
11454359Sroberto	{ "info",		NLOG_INFO },
11554359Sroberto	{ "events",		NLOG_EVENT },
11654359Sroberto	{ "status",		NLOG_STATUS },
11754359Sroberto	{ "statistics",		NLOG_STATIST },
118290000Sglebius	{ NULL,			0 }
11954359Sroberto};
12054359Sroberto
121290000Sglebiustypedef struct peer_resolved_ctx_tag {
122290000Sglebius	int		flags;
123290000Sglebius	int		host_mode;	/* T_* token identifier */
124290000Sglebius	u_short		family;
125290000Sglebius	keyid_t		keyid;
126290000Sglebius	u_char		hmode;		/* MODE_* */
127290000Sglebius	u_char		version;
128290000Sglebius	u_char		minpoll;
129290000Sglebius	u_char		maxpoll;
130290000Sglebius	u_int32		ttl;
131290000Sglebius	const char *	group;
132290000Sglebius} peer_resolved_ctx;
133290000Sglebius
134290000Sglebius/* Limits */
135182007Sroberto#define MAXPHONE	10	/* maximum number of phone strings */
13654359Sroberto#define MAXPPS		20	/* maximum length of PPS device string */
13754359Sroberto
13854359Sroberto/*
13954359Sroberto * Miscellaneous macros
14054359Sroberto */
14154359Sroberto#define ISEOL(c)	((c) == '#' || (c) == '\n' || (c) == '\0')
14254359Sroberto#define ISSPACE(c)	((c) == ' ' || (c) == '\t')
14354359Sroberto
144290000Sglebius#define _UC(str)	((char *)(intptr_t)(str))
14582498Sroberto
14654359Sroberto/*
14754359Sroberto * Definitions of things either imported from or exported to outside
14854359Sroberto */
149290000Sglebiusextern int yydebug;			/* ntp_parser.c (.y) */
150290000Sglebiusconfig_tree cfgt;			/* Parser output stored here */
151290000Sglebiusstruct config_tree_tag *cfg_tree_history;	/* History of configs */
152290000Sglebiuschar	*sys_phone[MAXPHONE] = {NULL};	/* ACTS phone numbers */
153290000Sglebiuschar	default_keysdir[] = NTP_KEYSDIR;
154290000Sglebiuschar	*keysdir = default_keysdir;	/* crypto keys directory */
155290000Sglebiuschar *	saveconfigdir;
15654359Sroberto#if defined(HAVE_SCHED_SETSCHEDULER)
15754359Srobertoint	config_priority_override = 0;
15854359Srobertoint	config_priority;
15954359Sroberto#endif
16054359Sroberto
16182498Srobertoconst char *config_file;
162290000Sglebiusstatic char default_ntp_signd_socket[] =
163290000Sglebius#ifdef NTP_SIGND_PATH
164290000Sglebius					NTP_SIGND_PATH;
165290000Sglebius#else
166290000Sglebius					"";
167290000Sglebius#endif
168290000Sglebiuschar *ntp_signd_socket = default_ntp_signd_socket;
16982498Sroberto#ifdef HAVE_NETINFO
170290000Sglebiusstruct netinfo_config_state *config_netinfo = NULL;
171290000Sglebiusint check_netinfo = 1;
17282498Sroberto#endif /* HAVE_NETINFO */
17382498Sroberto#ifdef SYS_WINNT
174290000Sglebiuschar *alt_config_file;
175290000SglebiusLPTSTR temp;
176290000Sglebiuschar config_file_storage[MAX_PATH];
177290000Sglebiuschar alt_config_file_storage[MAX_PATH];
17882498Sroberto#endif /* SYS_WINNT */
17954359Sroberto
18054359Sroberto#ifdef HAVE_NETINFO
18154359Sroberto/*
18254359Sroberto * NetInfo configuration state
18354359Sroberto */
18454359Srobertostruct netinfo_config_state {
18554359Sroberto	void *domain;		/* domain with config */
18654359Sroberto	ni_id config_dir;	/* ID config dir      */
18754359Sroberto	int prop_index;		/* current property   */
18854359Sroberto	int val_index;		/* current value      */
189290000Sglebius	char **val_list;	/* value list         */
19054359Sroberto};
19154359Sroberto#endif
19254359Sroberto
193290000Sglebiusstruct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
194290000Sglebius					     pointer info */
195290000Sglebiusint old_config_style = 1;    /* A boolean flag, which when set,
196290000Sglebius			      * indicates that the old configuration
197290000Sglebius			      * format with a newline at the end of
198290000Sglebius			      * every command is being used
199290000Sglebius			      */
200290000Sglebiusint	cryptosw;		/* crypto command called */
201290000Sglebius
202290000Sglebiusextern char *stats_drift_file;	/* name of the driftfile */
203290000Sglebius
204290000Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
20554359Sroberto/*
206290000Sglebius * backwards compatibility flags
20754359Sroberto */
208290000Sglebiusbc_entry bc_list[] = {
209290000Sglebius	{ T_Bc_bugXXXX,		1	}	/* default enabled */
210290000Sglebius};
211290000Sglebius
212290000Sglebius/*
213290000Sglebius * declare an int pointer for each flag for quick testing without
214290000Sglebius * walking bc_list.  If the pointer is consumed by libntp rather
215290000Sglebius * than ntpd, declare it in a libntp source file pointing to storage
216290000Sglebius * initialized with the appropriate value for other libntp clients, and
217290000Sglebius * redirect it to point into bc_list during ntpd startup.
218290000Sglebius */
219290000Sglebiusint *p_bcXXXX_enabled = &bc_list[0].enabled;
22054359Sroberto#endif
221290000Sglebius
222290000Sglebius/* FUNCTION PROTOTYPES */
223290000Sglebius
224290000Sglebiusstatic void init_syntax_tree(config_tree *);
225290000Sglebiusstatic void apply_enable_disable(attr_val_fifo *q, int enable);
226290000Sglebius
227290000Sglebius#ifdef FREE_CFG_T
228290000Sglebiusstatic void free_auth_node(config_tree *);
229290000Sglebiusstatic void free_all_config_trees(void);
230290000Sglebius
231290000Sglebiusstatic void free_config_access(config_tree *);
232290000Sglebiusstatic void free_config_auth(config_tree *);
233290000Sglebiusstatic void free_config_fudge(config_tree *);
234290000Sglebiusstatic void free_config_logconfig(config_tree *);
235290000Sglebiusstatic void free_config_monitor(config_tree *);
236290000Sglebiusstatic void free_config_nic_rules(config_tree *);
237290000Sglebiusstatic void free_config_other_modes(config_tree *);
238290000Sglebiusstatic void free_config_peers(config_tree *);
239290000Sglebiusstatic void free_config_phone(config_tree *);
240290000Sglebiusstatic void free_config_reset_counters(config_tree *);
241290000Sglebiusstatic void free_config_rlimit(config_tree *);
242290000Sglebiusstatic void free_config_setvar(config_tree *);
243290000Sglebiusstatic void free_config_system_opts(config_tree *);
244290000Sglebiusstatic void free_config_tinker(config_tree *);
245290000Sglebiusstatic void free_config_tos(config_tree *);
246290000Sglebiusstatic void free_config_trap(config_tree *);
247290000Sglebiusstatic void free_config_ttl(config_tree *);
248290000Sglebiusstatic void free_config_unpeers(config_tree *);
249290000Sglebiusstatic void free_config_vars(config_tree *);
250290000Sglebius
251290000Sglebius#ifdef SIM
252290000Sglebiusstatic void free_config_sim(config_tree *);
253290000Sglebius#endif
254290000Sglebiusstatic void destroy_address_fifo(address_fifo *);
255290000Sglebius#define FREE_ADDRESS_FIFO(pf)			\
256290000Sglebius	do {					\
257290000Sglebius		destroy_address_fifo(pf);	\
258290000Sglebius		(pf) = NULL;			\
259290000Sglebius	} while (0)
260290000Sglebius       void free_all_config_trees(void);	/* atexit() */
261290000Sglebiusstatic void free_config_tree(config_tree *ptree);
262290000Sglebius#endif	/* FREE_CFG_T */
263290000Sglebius
264290000Sglebiusstatic void destroy_restrict_node(restrict_node *my_node);
265290000Sglebiusstatic int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
266290000Sglebiusstatic void save_and_apply_config_tree(int/*BOOL*/ from_file);
267290000Sglebiusstatic void destroy_int_fifo(int_fifo *);
268290000Sglebius#define FREE_INT_FIFO(pf)			\
269290000Sglebius	do {					\
270290000Sglebius		destroy_int_fifo(pf);		\
271290000Sglebius		(pf) = NULL;			\
272290000Sglebius	} while (0)
273290000Sglebiusstatic void destroy_string_fifo(string_fifo *);
274290000Sglebius#define FREE_STRING_FIFO(pf)			\
275290000Sglebius	do {					\
276290000Sglebius		destroy_string_fifo(pf);		\
277290000Sglebius		(pf) = NULL;			\
278290000Sglebius	} while (0)
279290000Sglebiusstatic void destroy_attr_val_fifo(attr_val_fifo *);
280290000Sglebius#define FREE_ATTR_VAL_FIFO(pf)			\
281290000Sglebius	do {					\
282290000Sglebius		destroy_attr_val_fifo(pf);	\
283290000Sglebius		(pf) = NULL;			\
284290000Sglebius	} while (0)
285290000Sglebiusstatic void destroy_filegen_fifo(filegen_fifo *);
286290000Sglebius#define FREE_FILEGEN_FIFO(pf)			\
287290000Sglebius	do {					\
288290000Sglebius		destroy_filegen_fifo(pf);	\
289290000Sglebius		(pf) = NULL;			\
290290000Sglebius	} while (0)
291290000Sglebiusstatic void destroy_restrict_fifo(restrict_fifo *);
292290000Sglebius#define FREE_RESTRICT_FIFO(pf)			\
293290000Sglebius	do {					\
294290000Sglebius		destroy_restrict_fifo(pf);	\
295290000Sglebius		(pf) = NULL;			\
296290000Sglebius	} while (0)
297290000Sglebiusstatic void destroy_setvar_fifo(setvar_fifo *);
298290000Sglebius#define FREE_SETVAR_FIFO(pf)			\
299290000Sglebius	do {					\
300290000Sglebius		destroy_setvar_fifo(pf);	\
301290000Sglebius		(pf) = NULL;			\
302290000Sglebius	} while (0)
303290000Sglebiusstatic void destroy_addr_opts_fifo(addr_opts_fifo *);
304290000Sglebius#define FREE_ADDR_OPTS_FIFO(pf)			\
305290000Sglebius	do {					\
306290000Sglebius		destroy_addr_opts_fifo(pf);	\
307290000Sglebius		(pf) = NULL;			\
308290000Sglebius	} while (0)
309290000Sglebius
310290000Sglebiusstatic void config_logconfig(config_tree *);
311290000Sglebiusstatic void config_monitor(config_tree *);
312290000Sglebiusstatic void config_rlimit(config_tree *);
313290000Sglebiusstatic void config_system_opts(config_tree *);
314290000Sglebiusstatic void config_tinker(config_tree *);
315290000Sglebiusstatic void config_tos(config_tree *);
316290000Sglebiusstatic void config_vars(config_tree *);
317290000Sglebius
318290000Sglebius#ifdef SIM
319290000Sglebiusstatic sockaddr_u *get_next_address(address_node *addr);
320290000Sglebiusstatic void config_sim(config_tree *);
321290000Sglebiusstatic void config_ntpdsim(config_tree *);
322290000Sglebius#else	/* !SIM follows */
323290000Sglebiusstatic void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
324290000Sglebiusstatic void config_other_modes(config_tree *);
325290000Sglebiusstatic void config_auth(config_tree *);
326290000Sglebiusstatic void config_access(config_tree *);
327290000Sglebiusstatic void config_mdnstries(config_tree *);
328290000Sglebiusstatic void config_phone(config_tree *);
329290000Sglebiusstatic void config_setvar(config_tree *);
330290000Sglebiusstatic void config_ttl(config_tree *);
331290000Sglebiusstatic void config_trap(config_tree *);
332290000Sglebiusstatic void config_fudge(config_tree *);
333290000Sglebiusstatic void config_peers(config_tree *);
334290000Sglebiusstatic void config_unpeers(config_tree *);
335290000Sglebiusstatic void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
336290000Sglebiusstatic void config_reset_counters(config_tree *);
337290000Sglebiusstatic u_char get_correct_host_mode(int token);
338290000Sglebiusstatic int peerflag_bits(peer_node *);
339290000Sglebius#endif	/* !SIM */
340290000Sglebius
341290000Sglebius#ifdef WORKER
342290000Sglebiusstatic void peer_name_resolved(int, int, void *, const char *, const char *,
343290000Sglebius			const struct addrinfo *,
344290000Sglebius			const struct addrinfo *);
345290000Sglebiusstatic void unpeer_name_resolved(int, int, void *, const char *, const char *,
346290000Sglebius			  const struct addrinfo *,
347290000Sglebius			  const struct addrinfo *);
348290000Sglebiusstatic void trap_name_resolved(int, int, void *, const char *, const char *,
349290000Sglebius			const struct addrinfo *,
350290000Sglebius			const struct addrinfo *);
351290000Sglebius#endif
352290000Sglebius
353182007Srobertoenum gnn_type {
354182007Sroberto	t_UNK,		/* Unknown */
355182007Sroberto	t_REF,		/* Refclock */
356182007Sroberto	t_MSK		/* Network Mask */
357290000Sglebius};
35854359Sroberto
359290000Sglebiusstatic void ntpd_set_tod_using(const char *);
360290000Sglebiusstatic char * normal_dtoa(double);
361290000Sglebiusstatic u_int32 get_pfxmatch(const char **, struct masks *);
362290000Sglebiusstatic u_int32 get_match(const char *, struct masks *);
363290000Sglebiusstatic u_int32 get_logmask(const char *);
364290000Sglebius#ifndef SIM
365290000Sglebiusstatic int getnetnum(const char *num, sockaddr_u *addr, int complain,
366290000Sglebius		     enum gnn_type a_type);
367290000Sglebius
368290000Sglebius#endif
369290000Sglebius
370290000Sglebius
371290000Sglebius/* FUNCTIONS FOR INITIALIZATION
372290000Sglebius * ----------------------------
37354359Sroberto */
374290000Sglebius
375290000Sglebius#ifdef FREE_CFG_T
376290000Sglebiusstatic void
377290000Sglebiusfree_auth_node(
378290000Sglebius	config_tree *ptree
37954359Sroberto	)
38054359Sroberto{
381290000Sglebius	if (ptree->auth.keys) {
382290000Sglebius		free(ptree->auth.keys);
383290000Sglebius		ptree->auth.keys = NULL;
38454359Sroberto	}
385290000Sglebius
386290000Sglebius	if (ptree->auth.keysdir) {
387290000Sglebius		free(ptree->auth.keysdir);
388290000Sglebius		ptree->auth.keysdir = NULL;
389290000Sglebius	}
390290000Sglebius
391290000Sglebius	if (ptree->auth.ntp_signd_socket) {
392290000Sglebius		free(ptree->auth.ntp_signd_socket);
393290000Sglebius		ptree->auth.ntp_signd_socket = NULL;
394290000Sglebius	}
39554359Sroberto}
396290000Sglebius#endif /* DEBUG */
39754359Sroberto
398290000Sglebius
399290000Sglebiusstatic void
400290000Sglebiusinit_syntax_tree(
401290000Sglebius	config_tree *ptree
40254359Sroberto	)
40354359Sroberto{
404290000Sglebius	ZERO(*ptree);
405290000Sglebius	ptree->mdnstries = 5;
406290000Sglebius}
407290000Sglebius
408290000Sglebius
409290000Sglebius#ifdef FREE_CFG_T
410290000Sglebiusstatic void
411290000Sglebiusfree_all_config_trees(void)
412290000Sglebius{
413290000Sglebius	config_tree *ptree;
414290000Sglebius	config_tree *pnext;
415290000Sglebius
416290000Sglebius	ptree = cfg_tree_history;
417290000Sglebius
418290000Sglebius	while (ptree != NULL) {
419290000Sglebius		pnext = ptree->link;
420290000Sglebius		free_config_tree(ptree);
421290000Sglebius		ptree = pnext;
42254359Sroberto	}
42354359Sroberto}
42454359Sroberto
425290000Sglebius
426290000Sglebiusstatic void
427290000Sglebiusfree_config_tree(
428290000Sglebius	config_tree *ptree
42954359Sroberto	)
43054359Sroberto{
431290000Sglebius#if defined(_MSC_VER) && defined (_DEBUG)
432290000Sglebius	_CrtCheckMemory();
433290000Sglebius#endif
43454359Sroberto
435290000Sglebius	if (ptree->source.value.s != NULL)
436290000Sglebius		free(ptree->source.value.s);
43754359Sroberto
438290000Sglebius	free_config_other_modes(ptree);
439290000Sglebius	free_config_auth(ptree);
440290000Sglebius	free_config_tos(ptree);
441290000Sglebius	free_config_monitor(ptree);
442290000Sglebius	free_config_access(ptree);
443290000Sglebius	free_config_tinker(ptree);
444290000Sglebius	free_config_rlimit(ptree);
445290000Sglebius	free_config_system_opts(ptree);
446290000Sglebius	free_config_logconfig(ptree);
447290000Sglebius	free_config_phone(ptree);
448290000Sglebius	free_config_setvar(ptree);
449290000Sglebius	free_config_ttl(ptree);
450290000Sglebius	free_config_trap(ptree);
451290000Sglebius	free_config_fudge(ptree);
452290000Sglebius	free_config_vars(ptree);
453290000Sglebius	free_config_peers(ptree);
454290000Sglebius	free_config_unpeers(ptree);
455290000Sglebius	free_config_nic_rules(ptree);
456290000Sglebius	free_config_reset_counters(ptree);
457290000Sglebius#ifdef SIM
458290000Sglebius	free_config_sim(ptree);
459290000Sglebius#endif
460290000Sglebius	free_auth_node(ptree);
46154359Sroberto
462290000Sglebius	free(ptree);
463290000Sglebius
464290000Sglebius#if defined(_MSC_VER) && defined (_DEBUG)
465290000Sglebius	_CrtCheckMemory();
466290000Sglebius#endif
46754359Sroberto}
468290000Sglebius#endif /* FREE_CFG_T */
46954359Sroberto
47054359Sroberto
471290000Sglebius#ifdef SAVECONFIG
472290000Sglebius/* Dump all trees */
473290000Sglebiusint
474290000Sglebiusdump_all_config_trees(
475290000Sglebius	FILE *df,
476290000Sglebius	int comment
47754359Sroberto	)
47854359Sroberto{
479290000Sglebius	config_tree *	cfg_ptr;
480290000Sglebius	int		return_value;
48154359Sroberto
482290000Sglebius	return_value = 0;
483290000Sglebius	for (cfg_ptr = cfg_tree_history;
484290000Sglebius	     cfg_ptr != NULL;
485290000Sglebius	     cfg_ptr = cfg_ptr->link)
486290000Sglebius		return_value |= dump_config_tree(cfg_ptr, df, comment);
487290000Sglebius
488290000Sglebius	return return_value;
489290000Sglebius}
490290000Sglebius
491290000Sglebius
492290000Sglebius/* The config dumper */
493290000Sglebiusint
494290000Sglebiusdump_config_tree(
495290000Sglebius	config_tree *ptree,
496290000Sglebius	FILE *df,
497290000Sglebius	int comment
498290000Sglebius	)
499290000Sglebius{
500290000Sglebius	peer_node *peern;
501290000Sglebius	unpeer_node *unpeern;
502290000Sglebius	attr_val *atrv;
503290000Sglebius	address_node *addr;
504290000Sglebius	address_node *peer_addr;
505290000Sglebius	address_node *fudge_addr;
506290000Sglebius	filegen_node *fgen_node;
507290000Sglebius	restrict_node *rest_node;
508290000Sglebius	addr_opts_node *addr_opts;
509290000Sglebius	setvar_node *setv_node;
510290000Sglebius	nic_rule_node *rule_node;
511290000Sglebius	int_node *i_n;
512290000Sglebius	int_node *flags;
513290000Sglebius	int_node *counter_set;
514290000Sglebius	string_node *str_node;
515290000Sglebius
516290000Sglebius	const char *s = NULL;
517290000Sglebius	char *s1;
518290000Sglebius	char *s2;
519290000Sglebius	char timestamp[80];
520290000Sglebius	int enable;
521290000Sglebius
522290000Sglebius	DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
523290000Sglebius
524290000Sglebius	if (comment) {
525290000Sglebius		if (!strftime(timestamp, sizeof(timestamp),
526290000Sglebius			      "%Y-%m-%d %H:%M:%S",
527290000Sglebius			      localtime(&ptree->timestamp)))
528290000Sglebius			timestamp[0] = '\0';
529290000Sglebius
530290000Sglebius		fprintf(df, "# %s %s %s\n",
531290000Sglebius			timestamp,
532290000Sglebius			(CONF_SOURCE_NTPQ == ptree->source.attr)
533290000Sglebius			    ? "ntpq remote config from"
534290000Sglebius			    : "startup configuration file",
535290000Sglebius			ptree->source.value.s);
53654359Sroberto	}
53754359Sroberto
538290000Sglebius	/* For options I didn't find documentation I'll just output its name and the cor. value */
539290000Sglebius	atrv = HEAD_PFIFO(ptree->vars);
540290000Sglebius	for ( ; atrv != NULL; atrv = atrv->link) {
541290000Sglebius		switch (atrv->type) {
542290000Sglebius#ifdef DEBUG
543290000Sglebius		default:
544290000Sglebius			fprintf(df, "\n# dump error:\n"
545290000Sglebius				"# unknown vars type %d (%s) for %s\n",
546290000Sglebius				atrv->type, token_name(atrv->type),
547290000Sglebius				token_name(atrv->attr));
548290000Sglebius			break;
549290000Sglebius#endif
550290000Sglebius		case T_Double:
551290000Sglebius			fprintf(df, "%s %s\n", keyword(atrv->attr),
552290000Sglebius				normal_dtoa(atrv->value.d));
553290000Sglebius			break;
554290000Sglebius
555290000Sglebius		case T_Integer:
556290000Sglebius			fprintf(df, "%s %d\n", keyword(atrv->attr),
557290000Sglebius				atrv->value.i);
558290000Sglebius			break;
559290000Sglebius
560290000Sglebius		case T_String:
561290000Sglebius			fprintf(df, "%s \"%s\"", keyword(atrv->attr),
562290000Sglebius				atrv->value.s);
563290000Sglebius			if (T_Driftfile == atrv->attr &&
564290000Sglebius			    atrv->link != NULL &&
565290000Sglebius			    T_WanderThreshold == atrv->link->attr) {
566290000Sglebius				atrv = atrv->link;
567290000Sglebius				fprintf(df, " %s\n",
568290000Sglebius					normal_dtoa(atrv->value.d));
569290000Sglebius			} else {
570290000Sglebius				fprintf(df, "\n");
571290000Sglebius			}
572290000Sglebius			break;
573290000Sglebius		}
57454359Sroberto	}
57554359Sroberto
576290000Sglebius	atrv = HEAD_PFIFO(ptree->logconfig);
577290000Sglebius	if (atrv != NULL) {
578290000Sglebius		fprintf(df, "logconfig");
579290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link)
580290000Sglebius			fprintf(df, " %c%s", atrv->attr, atrv->value.s);
581290000Sglebius		fprintf(df, "\n");
582290000Sglebius	}
58354359Sroberto
584290000Sglebius	if (ptree->stats_dir)
585290000Sglebius		fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
58654359Sroberto
587290000Sglebius	i_n = HEAD_PFIFO(ptree->stats_list);
588290000Sglebius	if (i_n != NULL) {
589290000Sglebius		fprintf(df, "statistics");
590290000Sglebius		for ( ; i_n != NULL; i_n = i_n->link)
591290000Sglebius			fprintf(df, " %s", keyword(i_n->i));
592290000Sglebius		fprintf(df, "\n");
593290000Sglebius	}
59454359Sroberto
595290000Sglebius	fgen_node = HEAD_PFIFO(ptree->filegen_opts);
596290000Sglebius	for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
597290000Sglebius		atrv = HEAD_PFIFO(fgen_node->options);
598290000Sglebius		if (atrv != NULL) {
599290000Sglebius			fprintf(df, "filegen %s",
600290000Sglebius				keyword(fgen_node->filegen_token));
601290000Sglebius			for ( ; atrv != NULL; atrv = atrv->link) {
602290000Sglebius				switch (atrv->attr) {
603290000Sglebius#ifdef DEBUG
604290000Sglebius				default:
605290000Sglebius					fprintf(df, "\n# dump error:\n"
606290000Sglebius						"# unknown filegen option token %s\n"
607290000Sglebius						"filegen %s",
608290000Sglebius						token_name(atrv->attr),
609290000Sglebius						keyword(fgen_node->filegen_token));
610290000Sglebius					break;
611290000Sglebius#endif
612290000Sglebius				case T_File:
613290000Sglebius					fprintf(df, " file %s",
614290000Sglebius						atrv->value.s);
615290000Sglebius					break;
61654359Sroberto
617290000Sglebius				case T_Type:
618290000Sglebius					fprintf(df, " type %s",
619290000Sglebius						keyword(atrv->value.i));
620290000Sglebius					break;
62154359Sroberto
622290000Sglebius				case T_Flag:
623290000Sglebius					fprintf(df, " %s",
624290000Sglebius						keyword(atrv->value.i));
625290000Sglebius					break;
626290000Sglebius				}
627290000Sglebius			}
628290000Sglebius			fprintf(df, "\n");
629290000Sglebius		}
630290000Sglebius	}
63154359Sroberto
632290000Sglebius	atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
633290000Sglebius	if (atrv != NULL) {
634290000Sglebius		fprintf(df, "crypto");
635290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
636290000Sglebius			fprintf(df, " %s %s", keyword(atrv->attr),
637290000Sglebius				atrv->value.s);
638290000Sglebius		}
639290000Sglebius		fprintf(df, "\n");
640290000Sglebius	}
64154359Sroberto
642290000Sglebius	if (ptree->auth.revoke != 0)
643290000Sglebius		fprintf(df, "revoke %d\n", ptree->auth.revoke);
64454359Sroberto
645290000Sglebius	if (ptree->auth.keysdir != NULL)
646290000Sglebius		fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
647290000Sglebius
648290000Sglebius	if (ptree->auth.keys != NULL)
649290000Sglebius		fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
650290000Sglebius
651290000Sglebius	atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
652290000Sglebius	if (atrv != NULL) {
653290000Sglebius		fprintf(df, "trustedkey");
654290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
655290000Sglebius			if (T_Integer == atrv->type)
656290000Sglebius				fprintf(df, " %d", atrv->value.i);
657290000Sglebius			else if (T_Intrange == atrv->type)
658290000Sglebius				fprintf(df, " (%d ... %d)",
659290000Sglebius					atrv->value.r.first,
660290000Sglebius					atrv->value.r.last);
661290000Sglebius#ifdef DEBUG
662290000Sglebius			else
663290000Sglebius				fprintf(df, "\n# dump error:\n"
664290000Sglebius					"# unknown trustedkey attr type %d\n"
665290000Sglebius					"trustedkey", atrv->type);
666290000Sglebius#endif
66754359Sroberto		}
668290000Sglebius		fprintf(df, "\n");
66954359Sroberto	}
67054359Sroberto
671290000Sglebius	if (ptree->auth.control_key)
672290000Sglebius		fprintf(df, "controlkey %d\n", ptree->auth.control_key);
673260639Sdelphij
674290000Sglebius	if (ptree->auth.request_key)
675290000Sglebius		fprintf(df, "requestkey %d\n", ptree->auth.request_key);
676290000Sglebius
677290000Sglebius	/* dump enable list, then disable list */
678290000Sglebius	for (enable = 1; enable >= 0; enable--) {
679290000Sglebius		atrv = (enable)
680290000Sglebius			   ? HEAD_PFIFO(ptree->enable_opts)
681290000Sglebius			   : HEAD_PFIFO(ptree->disable_opts);
682290000Sglebius		if (atrv != NULL) {
683290000Sglebius			fprintf(df, "%s", (enable)
684290000Sglebius					? "enable"
685290000Sglebius					: "disable");
686290000Sglebius			for ( ; atrv != NULL; atrv = atrv->link)
687290000Sglebius				fprintf(df, " %s",
688290000Sglebius					keyword(atrv->value.i));
689290000Sglebius			fprintf(df, "\n");
690290000Sglebius		}
691290000Sglebius	}
692290000Sglebius
693290000Sglebius	atrv = HEAD_PFIFO(ptree->orphan_cmds);
694290000Sglebius	if (atrv != NULL) {
695290000Sglebius		fprintf(df, "tos");
696290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
697290000Sglebius			switch (atrv->type) {
698290000Sglebius#ifdef DEBUG
699290000Sglebius			default:
700290000Sglebius				fprintf(df, "\n# dump error:\n"
701290000Sglebius					"# unknown tos attr type %d %s\n"
702290000Sglebius					"tos", atrv->type,
703290000Sglebius					token_name(atrv->type));
704290000Sglebius				break;
705290000Sglebius#endif
706290000Sglebius			case T_Double:
707290000Sglebius				fprintf(df, " %s %s",
708290000Sglebius					keyword(atrv->attr),
709290000Sglebius					normal_dtoa(atrv->value.d));
710290000Sglebius				break;
711290000Sglebius			}
712290000Sglebius		}
713290000Sglebius		fprintf(df, "\n");
714290000Sglebius	}
715290000Sglebius
716290000Sglebius	atrv = HEAD_PFIFO(ptree->rlimit);
717290000Sglebius	if (atrv != NULL) {
718290000Sglebius		fprintf(df, "rlimit");
719290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
720290000Sglebius			INSIST(T_Integer == atrv->type);
721290000Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
722290000Sglebius				atrv->value.i);
723290000Sglebius		}
724290000Sglebius		fprintf(df, "\n");
725290000Sglebius	}
726290000Sglebius
727290000Sglebius	atrv = HEAD_PFIFO(ptree->tinker);
728290000Sglebius	if (atrv != NULL) {
729290000Sglebius		fprintf(df, "tinker");
730290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
731290000Sglebius			INSIST(T_Double == atrv->type);
732290000Sglebius			fprintf(df, " %s %s", keyword(atrv->attr),
733290000Sglebius				normal_dtoa(atrv->value.d));
734290000Sglebius		}
735290000Sglebius		fprintf(df, "\n");
736290000Sglebius	}
737290000Sglebius
738290000Sglebius	if (ptree->broadcastclient)
739290000Sglebius		fprintf(df, "broadcastclient\n");
740290000Sglebius
741290000Sglebius	peern = HEAD_PFIFO(ptree->peers);
742290000Sglebius	for ( ; peern != NULL; peern = peern->link) {
743290000Sglebius		addr = peern->addr;
744290000Sglebius		fprintf(df, "%s", keyword(peern->host_mode));
745290000Sglebius		switch (addr->type) {
746290000Sglebius#ifdef DEBUG
747290000Sglebius		default:
748290000Sglebius			fprintf(df, "# dump error:\n"
749290000Sglebius				"# unknown peer family %d for:\n"
750290000Sglebius				"%s", addr->type,
751290000Sglebius				keyword(peern->host_mode));
752182007Sroberto			break;
753290000Sglebius#endif
754290000Sglebius		case AF_UNSPEC:
755290000Sglebius			break;
75654359Sroberto
757290000Sglebius		case AF_INET:
758290000Sglebius			fprintf(df, " -4");
75982498Sroberto			break;
760290000Sglebius
761290000Sglebius		case AF_INET6:
762290000Sglebius			fprintf(df, " -6");
763290000Sglebius			break;
76482498Sroberto		}
765290000Sglebius		fprintf(df, " %s", addr->address);
76654359Sroberto
767290000Sglebius		if (peern->minpoll != 0)
768290000Sglebius			fprintf(df, " minpoll %u", peern->minpoll);
769290000Sglebius
770290000Sglebius		if (peern->maxpoll != 0)
771290000Sglebius			fprintf(df, " maxpoll %u", peern->maxpoll);
772290000Sglebius
773290000Sglebius		if (peern->ttl != 0) {
774290000Sglebius			if (strlen(addr->address) > 8
775290000Sglebius			    && !memcmp(addr->address, "127.127.", 8))
776290000Sglebius				fprintf(df, " mode %u", peern->ttl);
77754359Sroberto			else
778290000Sglebius				fprintf(df, " ttl %u", peern->ttl);
779290000Sglebius		}
78054359Sroberto
781290000Sglebius		if (peern->peerversion != NTP_VERSION)
782290000Sglebius			fprintf(df, " version %u", peern->peerversion);
78354359Sroberto
784290000Sglebius		if (peern->peerkey != 0)
785290000Sglebius			fprintf(df, " key %u", peern->peerkey);
786132451Sroberto
787290000Sglebius		if (peern->group != NULL)
788290000Sglebius			fprintf(df, " ident \"%s\"", peern->group);
78954359Sroberto
790290000Sglebius		atrv = HEAD_PFIFO(peern->peerflags);
791290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
792290000Sglebius			INSIST(T_Flag == atrv->attr);
793290000Sglebius			INSIST(T_Integer == atrv->type);
794290000Sglebius			fprintf(df, " %s", keyword(atrv->value.i));
795290000Sglebius		}
796290000Sglebius
797290000Sglebius		fprintf(df, "\n");
798290000Sglebius
799290000Sglebius		addr_opts = HEAD_PFIFO(ptree->fudge);
800290000Sglebius		for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
801290000Sglebius			peer_addr = peern->addr;
802290000Sglebius			fudge_addr = addr_opts->addr;
803290000Sglebius
804290000Sglebius			s1 = peer_addr->address;
805290000Sglebius			s2 = fudge_addr->address;
806290000Sglebius
807290000Sglebius			if (strcmp(s1, s2))
808290000Sglebius				continue;
809290000Sglebius
810290000Sglebius			fprintf(df, "fudge %s", s1);
811290000Sglebius
812290000Sglebius			for (atrv = HEAD_PFIFO(addr_opts->options);
813290000Sglebius			     atrv != NULL;
814290000Sglebius			     atrv = atrv->link) {
815290000Sglebius
816290000Sglebius				switch (atrv->type) {
817290000Sglebius#ifdef DEBUG
818290000Sglebius				default:
819290000Sglebius					fprintf(df, "\n# dump error:\n"
820290000Sglebius						"# unknown fudge atrv->type %d\n"
821290000Sglebius						"fudge %s", atrv->type,
822290000Sglebius						s1);
823290000Sglebius					break;
82454359Sroberto#endif
825290000Sglebius				case T_Double:
826290000Sglebius					fprintf(df, " %s %s",
827290000Sglebius						keyword(atrv->attr),
828290000Sglebius						normal_dtoa(atrv->value.d));
82954359Sroberto					break;
830290000Sglebius
831290000Sglebius				case T_Integer:
832290000Sglebius					fprintf(df, " %s %d",
833290000Sglebius						keyword(atrv->attr),
834290000Sglebius						atrv->value.i);
835290000Sglebius					break;
836290000Sglebius
837290000Sglebius				case T_String:
838290000Sglebius					fprintf(df, " %s %s",
839290000Sglebius						keyword(atrv->attr),
840290000Sglebius						atrv->value.s);
841290000Sglebius					break;
84254359Sroberto				}
843290000Sglebius			}
844290000Sglebius			fprintf(df, "\n");
845290000Sglebius		}
846290000Sglebius	}
847290000Sglebius
848290000Sglebius	addr = HEAD_PFIFO(ptree->manycastserver);
849290000Sglebius	if (addr != NULL) {
850290000Sglebius		fprintf(df, "manycastserver");
851290000Sglebius		for ( ; addr != NULL; addr = addr->link)
852290000Sglebius			fprintf(df, " %s", addr->address);
853290000Sglebius		fprintf(df, "\n");
854290000Sglebius	}
855290000Sglebius
856290000Sglebius	addr = HEAD_PFIFO(ptree->multicastclient);
857290000Sglebius	if (addr != NULL) {
858290000Sglebius		fprintf(df, "multicastclient");
859290000Sglebius		for ( ; addr != NULL; addr = addr->link)
860290000Sglebius			fprintf(df, " %s", addr->address);
861290000Sglebius		fprintf(df, "\n");
862290000Sglebius	}
863290000Sglebius
864290000Sglebius
865290000Sglebius	for (unpeern = HEAD_PFIFO(ptree->unpeers);
866290000Sglebius	     unpeern != NULL;
867290000Sglebius	     unpeern = unpeern->link)
868290000Sglebius		fprintf(df, "unpeer %s\n", unpeern->addr->address);
869290000Sglebius
870290000Sglebius	atrv = HEAD_PFIFO(ptree->mru_opts);
871290000Sglebius	if (atrv != NULL) {
872290000Sglebius		fprintf(df, "mru");
873290000Sglebius		for ( ;	atrv != NULL; atrv = atrv->link)
874290000Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
875290000Sglebius				atrv->value.i);
876290000Sglebius		fprintf(df, "\n");
877290000Sglebius	}
878290000Sglebius
879290000Sglebius	atrv = HEAD_PFIFO(ptree->discard_opts);
880290000Sglebius	if (atrv != NULL) {
881290000Sglebius		fprintf(df, "discard");
882290000Sglebius		for ( ;	atrv != NULL; atrv = atrv->link)
883290000Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
884290000Sglebius				atrv->value.i);
885290000Sglebius		fprintf(df, "\n");
886290000Sglebius	}
887290000Sglebius
888290000Sglebius
889290000Sglebius	for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
890290000Sglebius	     rest_node != NULL;
891290000Sglebius	     rest_node = rest_node->link) {
892290000Sglebius
893290000Sglebius		if (NULL == rest_node->addr) {
894290000Sglebius			s = "default";
895290000Sglebius			flags = HEAD_PFIFO(rest_node->flags);
896290000Sglebius			for ( ; flags != NULL; flags = flags->link)
897290000Sglebius				if (T_Source == flags->i) {
898290000Sglebius					s = "source";
899290000Sglebius					break;
90054359Sroberto				}
901290000Sglebius		} else {
902290000Sglebius			s = rest_node->addr->address;
903290000Sglebius		}
904290000Sglebius		fprintf(df, "restrict %s", s);
905290000Sglebius		if (rest_node->mask != NULL)
906290000Sglebius			fprintf(df, " mask %s",
907290000Sglebius				rest_node->mask->address);
908290000Sglebius		flags = HEAD_PFIFO(rest_node->flags);
909290000Sglebius		for ( ; flags != NULL; flags = flags->link)
910290000Sglebius			if (T_Source != flags->i)
911290000Sglebius				fprintf(df, " %s", keyword(flags->i));
912290000Sglebius		fprintf(df, "\n");
913290000Sglebius	}
914290000Sglebius
915290000Sglebius	rule_node = HEAD_PFIFO(ptree->nic_rules);
916290000Sglebius	for ( ; rule_node != NULL; rule_node = rule_node->link) {
917290000Sglebius		fprintf(df, "interface %s %s\n",
918290000Sglebius			keyword(rule_node->action),
919290000Sglebius			(rule_node->match_class)
920290000Sglebius			    ? keyword(rule_node->match_class)
921290000Sglebius			    : rule_node->if_name);
922290000Sglebius	}
923290000Sglebius
924290000Sglebius	str_node = HEAD_PFIFO(ptree->phone);
925290000Sglebius	if (str_node != NULL) {
926290000Sglebius		fprintf(df, "phone");
927290000Sglebius		for ( ; str_node != NULL; str_node = str_node->link)
928290000Sglebius			fprintf(df, " \"%s\"", str_node->s);
929290000Sglebius		fprintf(df, "\n");
930290000Sglebius	}
931290000Sglebius
932290000Sglebius	setv_node = HEAD_PFIFO(ptree->setvar);
933290000Sglebius	for ( ; setv_node != NULL; setv_node = setv_node->link) {
934290000Sglebius		s1 = quote_if_needed(setv_node->var);
935290000Sglebius		s2 = quote_if_needed(setv_node->val);
936290000Sglebius		fprintf(df, "setvar %s = %s", s1, s2);
937290000Sglebius		free(s1);
938290000Sglebius		free(s2);
939290000Sglebius		if (setv_node->isdefault)
940290000Sglebius			fprintf(df, " default");
941290000Sglebius		fprintf(df, "\n");
942290000Sglebius	}
943290000Sglebius
944290000Sglebius	i_n = HEAD_PFIFO(ptree->ttl);
945290000Sglebius	if (i_n != NULL) {
946290000Sglebius		fprintf(df, "ttl");
947290000Sglebius		for( ; i_n != NULL; i_n = i_n->link)
948290000Sglebius			fprintf(df, " %d", i_n->i);
949290000Sglebius		fprintf(df, "\n");
950290000Sglebius	}
951290000Sglebius
952290000Sglebius	addr_opts = HEAD_PFIFO(ptree->trap);
953290000Sglebius	for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
954290000Sglebius		addr = addr_opts->addr;
955290000Sglebius		fprintf(df, "trap %s", addr->address);
956290000Sglebius		atrv = HEAD_PFIFO(addr_opts->options);
957290000Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
958290000Sglebius			switch (atrv->attr) {
959290000Sglebius#ifdef DEBUG
960290000Sglebius			default:
961290000Sglebius				fprintf(df, "\n# dump error:\n"
962290000Sglebius					"# unknown trap token %d\n"
963290000Sglebius					"trap %s", atrv->attr,
964290000Sglebius					addr->address);
965290000Sglebius				break;
966132451Sroberto#endif
967290000Sglebius			case T_Port:
968290000Sglebius				fprintf(df, " port %d", atrv->value.i);
969182007Sroberto				break;
970182007Sroberto
971290000Sglebius			case T_Interface:
972290000Sglebius				fprintf(df, " interface %s",
973290000Sglebius					atrv->value.s);
974290000Sglebius				break;
975290000Sglebius			}
976290000Sglebius		}
977290000Sglebius		fprintf(df, "\n");
978290000Sglebius	}
97954359Sroberto
980290000Sglebius	counter_set = HEAD_PFIFO(ptree->reset_counters);
981290000Sglebius	if (counter_set != NULL) {
982290000Sglebius		fprintf(df, "reset");
983290000Sglebius		for ( ; counter_set != NULL;
984290000Sglebius		     counter_set = counter_set->link)
985290000Sglebius			fprintf(df, " %s", keyword(counter_set->i));
986290000Sglebius		fprintf(df, "\n");
987290000Sglebius	}
98854359Sroberto
989290000Sglebius	return 0;
990290000Sglebius}
991290000Sglebius#endif	/* SAVECONFIG */
99254359Sroberto
99354359Sroberto
994182007Sroberto
995290000Sglebius/* generic fifo routines for structs linked by 1st member */
996290000Sglebiusvoid *
997290000Sglebiusappend_gen_fifo(
998290000Sglebius	void *fifo,
999290000Sglebius	void *entry
1000290000Sglebius	)
1001290000Sglebius{
1002290000Sglebius	gen_fifo *pf;
1003290000Sglebius	gen_node *pe;
100454359Sroberto
1005290000Sglebius	pf = fifo;
1006290000Sglebius	pe = entry;
1007290000Sglebius	if (NULL == pf)
1008290000Sglebius		pf = emalloc_zero(sizeof(*pf));
1009290000Sglebius	else
1010290000Sglebius		CHECK_FIFO_CONSISTENCY(*pf);
1011290000Sglebius	if (pe != NULL)
1012290000Sglebius		LINK_FIFO(*pf, pe, link);
1013290000Sglebius	CHECK_FIFO_CONSISTENCY(*pf);
1014182007Sroberto
1015290000Sglebius	return pf;
1016290000Sglebius}
101754359Sroberto
1018182007Sroberto
1019290000Sglebiusvoid *
1020290000Sglebiusconcat_gen_fifos(
1021290000Sglebius	void *first,
1022290000Sglebius	void *second
1023290000Sglebius	)
1024290000Sglebius{
1025290000Sglebius	gen_fifo *pf1;
1026290000Sglebius	gen_fifo *pf2;
1027182007Sroberto
1028290000Sglebius	pf1 = first;
1029290000Sglebius	pf2 = second;
1030290000Sglebius	if (NULL == pf1)
1031290000Sglebius		return pf2;
1032290000Sglebius	if (NULL == pf2)
1033290000Sglebius		return pf1;
103454359Sroberto
1035290000Sglebius	CONCAT_FIFO(*pf1, *pf2, link);
1036290000Sglebius	free(pf2);
103754359Sroberto
1038290000Sglebius	return pf1;
1039290000Sglebius}
104054359Sroberto
104154359Sroberto
1042290000Sglebius/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
1043290000Sglebius * -----------------------------------------------
1044290000Sglebius */
104554359Sroberto
1046290000Sglebiusattr_val *
1047290000Sglebiuscreate_attr_dval(
1048290000Sglebius	int attr,
1049290000Sglebius	double value
1050290000Sglebius	)
1051290000Sglebius{
1052290000Sglebius	attr_val *my_val;
105382498Sroberto
1054290000Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1055290000Sglebius	my_val->attr = attr;
1056290000Sglebius	my_val->value.d = value;
1057290000Sglebius	my_val->type = T_Double;
105882498Sroberto
1059290000Sglebius	return my_val;
1060290000Sglebius}
106154359Sroberto
1062290000Sglebius
1063290000Sglebiusattr_val *
1064290000Sglebiuscreate_attr_ival(
1065290000Sglebius	int attr,
1066290000Sglebius	int value
1067290000Sglebius	)
1068290000Sglebius{
1069290000Sglebius	attr_val *my_val;
1070290000Sglebius
1071290000Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1072290000Sglebius	my_val->attr = attr;
1073290000Sglebius	my_val->value.i = value;
1074290000Sglebius	my_val->type = T_Integer;
1075290000Sglebius
1076290000Sglebius	return my_val;
1077290000Sglebius}
1078290000Sglebius
1079290000Sglebius
1080290000Sglebiusattr_val *
1081290000Sglebiuscreate_attr_uval(
1082290000Sglebius	int	attr,
1083290000Sglebius	u_int	value
1084290000Sglebius	)
1085290000Sglebius{
1086290000Sglebius	attr_val *my_val;
1087290000Sglebius
1088290000Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1089290000Sglebius	my_val->attr = attr;
1090290000Sglebius	my_val->value.u = value;
1091290000Sglebius	my_val->type = T_U_int;
1092290000Sglebius
1093290000Sglebius	return my_val;
1094290000Sglebius}
1095290000Sglebius
1096290000Sglebius
1097290000Sglebiusattr_val *
1098290000Sglebiuscreate_attr_rangeval(
1099290000Sglebius	int	attr,
1100290000Sglebius	int	first,
1101290000Sglebius	int	last
1102290000Sglebius	)
1103290000Sglebius{
1104290000Sglebius	attr_val *my_val;
1105290000Sglebius
1106290000Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1107290000Sglebius	my_val->attr = attr;
1108290000Sglebius	my_val->value.r.first = first;
1109290000Sglebius	my_val->value.r.last = last;
1110290000Sglebius	my_val->type = T_Intrange;
1111290000Sglebius
1112290000Sglebius	return my_val;
1113290000Sglebius}
1114290000Sglebius
1115290000Sglebius
1116290000Sglebiusattr_val *
1117290000Sglebiuscreate_attr_sval(
1118290000Sglebius	int attr,
1119290000Sglebius	const char *s
1120290000Sglebius	)
1121290000Sglebius{
1122290000Sglebius	attr_val *my_val;
1123290000Sglebius
1124290000Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1125290000Sglebius	my_val->attr = attr;
1126290000Sglebius	if (NULL == s)			/* free() hates NULL */
1127290000Sglebius		s = estrdup("");
1128290000Sglebius	my_val->value.s = _UC(s);
1129290000Sglebius	my_val->type = T_String;
1130290000Sglebius
1131290000Sglebius	return my_val;
1132290000Sglebius}
1133290000Sglebius
1134290000Sglebius
1135290000Sglebiusint_node *
1136290000Sglebiuscreate_int_node(
1137290000Sglebius	int val
1138290000Sglebius	)
1139290000Sglebius{
1140290000Sglebius	int_node *i_n;
1141290000Sglebius
1142290000Sglebius	i_n = emalloc_zero(sizeof(*i_n));
1143290000Sglebius	i_n->i = val;
1144290000Sglebius
1145290000Sglebius	return i_n;
1146290000Sglebius}
1147290000Sglebius
1148290000Sglebius
1149290000Sglebiusstring_node *
1150290000Sglebiuscreate_string_node(
1151290000Sglebius	char *str
1152290000Sglebius	)
1153290000Sglebius{
1154290000Sglebius	string_node *sn;
1155290000Sglebius
1156290000Sglebius	sn = emalloc_zero(sizeof(*sn));
1157290000Sglebius	sn->s = str;
1158290000Sglebius
1159290000Sglebius	return sn;
1160290000Sglebius}
1161290000Sglebius
1162290000Sglebius
1163290000Sglebiusaddress_node *
1164290000Sglebiuscreate_address_node(
1165290000Sglebius	char *	addr,
1166290000Sglebius	int	type
1167290000Sglebius	)
1168290000Sglebius{
1169290000Sglebius	address_node *my_node;
1170290000Sglebius
1171290000Sglebius	REQUIRE(NULL != addr);
1172290000Sglebius	REQUIRE(AF_INET == type || AF_INET6 == type || AF_UNSPEC == type);
1173290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1174290000Sglebius	my_node->address = addr;
1175290000Sglebius	my_node->type = (u_short)type;
1176290000Sglebius
1177290000Sglebius	return my_node;
1178290000Sglebius}
1179290000Sglebius
1180290000Sglebius
1181290000Sglebiusvoid
1182290000Sglebiusdestroy_address_node(
1183290000Sglebius	address_node *my_node
1184290000Sglebius	)
1185290000Sglebius{
1186290000Sglebius	if (NULL == my_node)
1187290000Sglebius		return;
1188290000Sglebius	REQUIRE(NULL != my_node->address);
1189290000Sglebius
1190290000Sglebius	free(my_node->address);
1191290000Sglebius	free(my_node);
1192290000Sglebius}
1193290000Sglebius
1194290000Sglebius
1195290000Sglebiuspeer_node *
1196290000Sglebiuscreate_peer_node(
1197290000Sglebius	int		hmode,
1198290000Sglebius	address_node *	addr,
1199290000Sglebius	attr_val_fifo *	options
1200290000Sglebius	)
1201290000Sglebius{
1202290000Sglebius	peer_node *my_node;
1203290000Sglebius	attr_val *option;
1204290000Sglebius	int freenode;
1205290000Sglebius	int errflag = 0;
1206290000Sglebius
1207290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1208290000Sglebius
1209290000Sglebius	/* Initialize node values to default */
1210290000Sglebius	my_node->peerversion = NTP_VERSION;
1211290000Sglebius
1212290000Sglebius	/* Now set the node to the read values */
1213290000Sglebius	my_node->host_mode = hmode;
1214290000Sglebius	my_node->addr = addr;
1215290000Sglebius
1216290000Sglebius	/*
1217290000Sglebius	 * the options FIFO mixes items that will be saved in the
1218290000Sglebius	 * peer_node as explicit members, such as minpoll, and
1219290000Sglebius	 * those that are moved intact to the peer_node's peerflags
1220290000Sglebius	 * FIFO.  The options FIFO is consumed and reclaimed here.
1221290000Sglebius	 */
1222290000Sglebius
1223290000Sglebius	if (options != NULL)
1224290000Sglebius		CHECK_FIFO_CONSISTENCY(*options);
1225290000Sglebius	while (options != NULL) {
1226290000Sglebius		UNLINK_FIFO(option, *options, link);
1227290000Sglebius		if (NULL == option) {
1228290000Sglebius			free(options);
122954359Sroberto			break;
1230290000Sglebius		}
123154359Sroberto
1232290000Sglebius		freenode = 1;
1233290000Sglebius		/* Check the kind of option being set */
1234290000Sglebius		switch (option->attr) {
123554359Sroberto
1236290000Sglebius		case T_Flag:
1237290000Sglebius			APPEND_G_FIFO(my_node->peerflags, option);
1238290000Sglebius			freenode = 0;
1239290000Sglebius			break;
124054359Sroberto
1241290000Sglebius		case T_Minpoll:
1242290000Sglebius			if (option->value.i < NTP_MINPOLL ||
1243290000Sglebius			    option->value.i > UCHAR_MAX) {
1244290000Sglebius				msyslog(LOG_INFO,
1245290000Sglebius					"minpoll: provided value (%d) is out of range [%d-%d])",
1246290000Sglebius					option->value.i, NTP_MINPOLL,
1247290000Sglebius					UCHAR_MAX);
1248290000Sglebius				my_node->minpoll = NTP_MINPOLL;
1249290000Sglebius			} else {
1250290000Sglebius				my_node->minpoll =
1251290000Sglebius					(u_char)option->value.u;
125254359Sroberto			}
125354359Sroberto			break;
125454359Sroberto
1255290000Sglebius		case T_Maxpoll:
1256290000Sglebius			if (option->value.i < 0 ||
1257290000Sglebius			    option->value.i > NTP_MAXPOLL) {
1258290000Sglebius				msyslog(LOG_INFO,
1259290000Sglebius					"maxpoll: provided value (%d) is out of range [0-%d])",
1260290000Sglebius					option->value.i, NTP_MAXPOLL);
1261290000Sglebius				my_node->maxpoll = NTP_MAXPOLL;
1262182007Sroberto			} else {
1263290000Sglebius				my_node->maxpoll =
1264290000Sglebius					(u_char)option->value.u;
1265182007Sroberto			}
126654359Sroberto			break;
1267132451Sroberto
1268290000Sglebius		case T_Ttl:
1269290000Sglebius			if (option->value.u >= MAX_TTL) {
1270290000Sglebius				msyslog(LOG_ERR, "ttl: invalid argument");
1271290000Sglebius				errflag = 1;
1272290000Sglebius			} else {
1273290000Sglebius				my_node->ttl = (u_char)option->value.u;
1274290000Sglebius			}
1275290000Sglebius			break;
1276132451Sroberto
1277290000Sglebius		case T_Mode:
1278290000Sglebius			my_node->ttl = option->value.u;
127954359Sroberto			break;
128054359Sroberto
1281290000Sglebius		case T_Key:
1282290000Sglebius			if (option->value.u >= KEYID_T_MAX) {
1283290000Sglebius				msyslog(LOG_ERR, "key: invalid argument");
1284290000Sglebius				errflag = 1;
1285290000Sglebius			} else {
1286290000Sglebius				my_node->peerkey =
1287290000Sglebius					(keyid_t)option->value.u;
128854359Sroberto			}
1289132451Sroberto			break;
129054359Sroberto
1291290000Sglebius		case T_Version:
1292290000Sglebius			if (option->value.u >= UCHAR_MAX) {
1293290000Sglebius				msyslog(LOG_ERR, "version: invalid argument");
1294290000Sglebius				errflag = 1;
1295290000Sglebius			} else {
1296290000Sglebius				my_node->peerversion =
1297290000Sglebius					(u_char)option->value.u;
129854359Sroberto			}
129954359Sroberto			break;
130054359Sroberto
1301290000Sglebius		case T_Ident:
1302290000Sglebius			my_node->group = option->value.s;
1303290000Sglebius			break;
130482498Sroberto
1305290000Sglebius		default:
1306290000Sglebius			msyslog(LOG_ERR,
1307290000Sglebius				"Unknown peer/server option token %s",
1308290000Sglebius				token_name(option->attr));
1309290000Sglebius			errflag = 1;
1310290000Sglebius		}
1311290000Sglebius		if (freenode)
1312290000Sglebius			free(option);
1313290000Sglebius	}
1314290000Sglebius
1315290000Sglebius	/* Check if errors were reported. If yes, ignore the node */
1316290000Sglebius	if (errflag) {
1317290000Sglebius		free(my_node);
1318290000Sglebius		my_node = NULL;
1319290000Sglebius	}
1320290000Sglebius
1321290000Sglebius	return my_node;
1322290000Sglebius}
1323290000Sglebius
1324290000Sglebius
1325290000Sglebiusunpeer_node *
1326290000Sglebiuscreate_unpeer_node(
1327290000Sglebius	address_node *addr
1328290000Sglebius	)
1329290000Sglebius{
1330290000Sglebius	unpeer_node *	my_node;
1331290000Sglebius	u_int		u;
1332290000Sglebius	char *		pch;
1333290000Sglebius
1334290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1335290000Sglebius
1336290000Sglebius	/*
1337290000Sglebius	 * From the parser's perspective an association ID fits into
1338290000Sglebius	 * its generic T_String definition of a name/address "address".
1339290000Sglebius	 * We treat all valid 16-bit numbers as association IDs.
1340290000Sglebius	 */
1341290000Sglebius	pch = addr->address;
1342290000Sglebius	while (*pch && isdigit((unsigned char)*pch))
1343290000Sglebius		pch++;
1344290000Sglebius
1345290000Sglebius	if (!*pch
1346290000Sglebius	    && 1 == sscanf(addr->address, "%u", &u)
1347290000Sglebius	    && u <= ASSOCID_MAX) {
1348290000Sglebius		my_node->assocID = (associd_t)u;
1349290000Sglebius		destroy_address_node(addr);
1350290000Sglebius		my_node->addr = NULL;
1351290000Sglebius	} else {
1352290000Sglebius		my_node->assocID = 0;
1353290000Sglebius		my_node->addr = addr;
1354290000Sglebius	}
1355290000Sglebius
1356290000Sglebius	return my_node;
1357290000Sglebius}
1358290000Sglebius
1359290000Sglebiusfilegen_node *
1360290000Sglebiuscreate_filegen_node(
1361290000Sglebius	int		filegen_token,
1362290000Sglebius	attr_val_fifo *	options
1363290000Sglebius	)
1364290000Sglebius{
1365290000Sglebius	filegen_node *my_node;
1366290000Sglebius
1367290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1368290000Sglebius	my_node->filegen_token = filegen_token;
1369290000Sglebius	my_node->options = options;
1370290000Sglebius
1371290000Sglebius	return my_node;
1372290000Sglebius}
1373290000Sglebius
1374290000Sglebius
1375290000Sglebiusrestrict_node *
1376290000Sglebiuscreate_restrict_node(
1377290000Sglebius	address_node *	addr,
1378290000Sglebius	address_node *	mask,
1379290000Sglebius	int_fifo *	flags,
1380290000Sglebius	int		line_no
1381290000Sglebius	)
1382290000Sglebius{
1383290000Sglebius	restrict_node *my_node;
1384290000Sglebius
1385290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1386290000Sglebius	my_node->addr = addr;
1387290000Sglebius	my_node->mask = mask;
1388290000Sglebius	my_node->flags = flags;
1389290000Sglebius	my_node->line_no = line_no;
1390290000Sglebius
1391290000Sglebius	return my_node;
1392290000Sglebius}
1393290000Sglebius
1394290000Sglebius
1395290000Sglebiusstatic void
1396290000Sglebiusdestroy_restrict_node(
1397290000Sglebius	restrict_node *my_node
1398290000Sglebius	)
1399290000Sglebius{
1400290000Sglebius	/* With great care, free all the memory occupied by
1401290000Sglebius	 * the restrict node
1402290000Sglebius	 */
1403290000Sglebius	destroy_address_node(my_node->addr);
1404290000Sglebius	destroy_address_node(my_node->mask);
1405290000Sglebius	destroy_int_fifo(my_node->flags);
1406290000Sglebius	free(my_node);
1407290000Sglebius}
1408290000Sglebius
1409290000Sglebius
1410290000Sglebiusstatic void
1411290000Sglebiusdestroy_int_fifo(
1412290000Sglebius	int_fifo *	fifo
1413290000Sglebius	)
1414290000Sglebius{
1415290000Sglebius	int_node *	i_n;
1416290000Sglebius
1417290000Sglebius	if (fifo != NULL) {
1418290000Sglebius		for (;;) {
1419290000Sglebius			UNLINK_FIFO(i_n, *fifo, link);
1420290000Sglebius			if (i_n == NULL)
142182498Sroberto				break;
1422290000Sglebius			free(i_n);
1423290000Sglebius		}
1424290000Sglebius		free(fifo);
1425290000Sglebius	}
1426290000Sglebius}
1427132451Sroberto
1428290000Sglebius
1429290000Sglebiusstatic void
1430290000Sglebiusdestroy_string_fifo(
1431290000Sglebius	string_fifo *	fifo
1432290000Sglebius	)
1433290000Sglebius{
1434290000Sglebius	string_node *	sn;
1435290000Sglebius
1436290000Sglebius	if (fifo != NULL) {
1437290000Sglebius		for (;;) {
1438290000Sglebius			UNLINK_FIFO(sn, *fifo, link);
1439290000Sglebius			if (sn == NULL)
144082498Sroberto				break;
1441290000Sglebius			free(sn->s);
1442290000Sglebius			free(sn);
1443290000Sglebius		}
1444290000Sglebius		free(fifo);
1445290000Sglebius	}
1446290000Sglebius}
144782498Sroberto
1448290000Sglebius
1449290000Sglebiusstatic void
1450290000Sglebiusdestroy_attr_val_fifo(
1451290000Sglebius	attr_val_fifo *	av_fifo
1452290000Sglebius	)
1453290000Sglebius{
1454290000Sglebius	attr_val *	av;
1455290000Sglebius
1456290000Sglebius	if (av_fifo != NULL) {
1457290000Sglebius		for (;;) {
1458290000Sglebius			UNLINK_FIFO(av, *av_fifo, link);
1459290000Sglebius			if (av == NULL)
146082498Sroberto				break;
1461290000Sglebius			if (T_String == av->type)
1462290000Sglebius				free(av->value.s);
1463290000Sglebius			free(av);
1464290000Sglebius		}
1465290000Sglebius		free(av_fifo);
1466290000Sglebius	}
1467290000Sglebius}
146882498Sroberto
1469290000Sglebius
1470290000Sglebiusstatic void
1471290000Sglebiusdestroy_filegen_fifo(
1472290000Sglebius	filegen_fifo *	fifo
1473290000Sglebius	)
1474290000Sglebius{
1475290000Sglebius	filegen_node *	fg;
1476290000Sglebius
1477290000Sglebius	if (fifo != NULL) {
1478290000Sglebius		for (;;) {
1479290000Sglebius			UNLINK_FIFO(fg, *fifo, link);
1480290000Sglebius			if (fg == NULL)
148182498Sroberto				break;
1482290000Sglebius			destroy_attr_val_fifo(fg->options);
1483290000Sglebius			free(fg);
1484290000Sglebius		}
1485290000Sglebius		free(fifo);
1486290000Sglebius	}
1487290000Sglebius}
148882498Sroberto
1489290000Sglebius
1490290000Sglebiusstatic void
1491290000Sglebiusdestroy_restrict_fifo(
1492290000Sglebius	restrict_fifo *	fifo
1493290000Sglebius	)
1494290000Sglebius{
1495290000Sglebius	restrict_node *	rn;
1496290000Sglebius
1497290000Sglebius	if (fifo != NULL) {
1498290000Sglebius		for (;;) {
1499290000Sglebius			UNLINK_FIFO(rn, *fifo, link);
1500290000Sglebius			if (rn == NULL)
150182498Sroberto				break;
1502290000Sglebius			destroy_restrict_node(rn);
1503290000Sglebius		}
1504290000Sglebius		free(fifo);
1505290000Sglebius	}
1506290000Sglebius}
150782498Sroberto
1508290000Sglebius
1509290000Sglebiusstatic void
1510290000Sglebiusdestroy_setvar_fifo(
1511290000Sglebius	setvar_fifo *	fifo
1512290000Sglebius	)
1513290000Sglebius{
1514290000Sglebius	setvar_node *	sv;
1515290000Sglebius
1516290000Sglebius	if (fifo != NULL) {
1517290000Sglebius		for (;;) {
1518290000Sglebius			UNLINK_FIFO(sv, *fifo, link);
1519290000Sglebius			if (sv == NULL)
152082498Sroberto				break;
1521290000Sglebius			free(sv->var);
1522290000Sglebius			free(sv->val);
1523290000Sglebius			free(sv);
1524290000Sglebius		}
1525290000Sglebius		free(fifo);
1526290000Sglebius	}
1527290000Sglebius}
152882498Sroberto
1529290000Sglebius
1530290000Sglebiusstatic void
1531290000Sglebiusdestroy_addr_opts_fifo(
1532290000Sglebius	addr_opts_fifo *	fifo
1533290000Sglebius	)
1534290000Sglebius{
1535290000Sglebius	addr_opts_node *	aon;
1536290000Sglebius
1537290000Sglebius	if (fifo != NULL) {
1538290000Sglebius		for (;;) {
1539290000Sglebius			UNLINK_FIFO(aon, *fifo, link);
1540290000Sglebius			if (aon == NULL)
154182498Sroberto				break;
1542290000Sglebius			destroy_address_node(aon->addr);
1543290000Sglebius			destroy_attr_val_fifo(aon->options);
1544290000Sglebius			free(aon);
1545290000Sglebius		}
1546290000Sglebius		free(fifo);
1547290000Sglebius	}
1548290000Sglebius}
1549132451Sroberto
1550290000Sglebius
1551290000Sglebiussetvar_node *
1552290000Sglebiuscreate_setvar_node(
1553290000Sglebius	char *	var,
1554290000Sglebius	char *	val,
1555290000Sglebius	int	isdefault
1556290000Sglebius	)
1557290000Sglebius{
1558290000Sglebius	setvar_node *	my_node;
1559290000Sglebius	char *		pch;
1560290000Sglebius
1561290000Sglebius	/* do not allow = in the variable name */
1562290000Sglebius	pch = strchr(var, '=');
1563290000Sglebius	if (NULL != pch)
1564290000Sglebius		*pch = '\0';
1565290000Sglebius
1566290000Sglebius	/* Now store the string into a setvar_node */
1567290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1568290000Sglebius	my_node->var = var;
1569290000Sglebius	my_node->val = val;
1570290000Sglebius	my_node->isdefault = isdefault;
1571290000Sglebius
1572290000Sglebius	return my_node;
1573290000Sglebius}
1574290000Sglebius
1575290000Sglebius
1576290000Sglebiusnic_rule_node *
1577290000Sglebiuscreate_nic_rule_node(
1578290000Sglebius	int match_class,
1579290000Sglebius	char *if_name,	/* interface name or numeric address */
1580290000Sglebius	int action
1581290000Sglebius	)
1582290000Sglebius{
1583290000Sglebius	nic_rule_node *my_node;
1584290000Sglebius
1585290000Sglebius	REQUIRE(match_class != 0 || if_name != NULL);
1586290000Sglebius
1587290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1588290000Sglebius	my_node->match_class = match_class;
1589290000Sglebius	my_node->if_name = if_name;
1590290000Sglebius	my_node->action = action;
1591290000Sglebius
1592290000Sglebius	return my_node;
1593290000Sglebius}
1594290000Sglebius
1595290000Sglebius
1596290000Sglebiusaddr_opts_node *
1597290000Sglebiuscreate_addr_opts_node(
1598290000Sglebius	address_node *	addr,
1599290000Sglebius	attr_val_fifo *	options
1600290000Sglebius	)
1601290000Sglebius{
1602290000Sglebius	addr_opts_node *my_node;
1603290000Sglebius
1604290000Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1605290000Sglebius	my_node->addr = addr;
1606290000Sglebius	my_node->options = options;
1607290000Sglebius
1608290000Sglebius	return my_node;
1609290000Sglebius}
1610290000Sglebius
1611290000Sglebius
1612290000Sglebius#ifdef SIM
1613290000Sglebiusscript_info *
1614290000Sglebiuscreate_sim_script_info(
1615290000Sglebius	double		duration,
1616290000Sglebius	attr_val_fifo *	script_queue
1617290000Sglebius	)
1618290000Sglebius{
1619290000Sglebius	script_info *my_info;
1620290000Sglebius	attr_val *my_attr_val;
1621290000Sglebius
1622290000Sglebius	my_info = emalloc_zero(sizeof(*my_info));
1623290000Sglebius
1624290000Sglebius	/* Initialize Script Info with default values*/
1625290000Sglebius	my_info->duration = duration;
1626290000Sglebius	my_info->prop_delay = NET_DLY;
1627290000Sglebius	my_info->proc_delay = PROC_DLY;
1628290000Sglebius
1629290000Sglebius	/* Traverse the script_queue and fill out non-default values */
1630290000Sglebius
1631290000Sglebius	for (my_attr_val = HEAD_PFIFO(script_queue);
1632290000Sglebius	     my_attr_val != NULL;
1633290000Sglebius	     my_attr_val = my_attr_val->link) {
1634290000Sglebius
1635290000Sglebius		/* Set the desired value */
1636290000Sglebius		switch (my_attr_val->attr) {
1637290000Sglebius
1638290000Sglebius		case T_Freq_Offset:
1639290000Sglebius			my_info->freq_offset = my_attr_val->value.d;
164054359Sroberto			break;
164154359Sroberto
1642290000Sglebius		case T_Wander:
1643290000Sglebius			my_info->wander = my_attr_val->value.d;
1644290000Sglebius			break;
1645132451Sroberto
1646290000Sglebius		case T_Jitter:
1647290000Sglebius			my_info->jitter = my_attr_val->value.d;
1648290000Sglebius			break;
1649132451Sroberto
1650290000Sglebius		case T_Prop_Delay:
1651290000Sglebius			my_info->prop_delay = my_attr_val->value.d;
1652290000Sglebius			break;
1653132451Sroberto
1654290000Sglebius		case T_Proc_Delay:
1655290000Sglebius			my_info->proc_delay = my_attr_val->value.d;
1656290000Sglebius			break;
1657182007Sroberto
1658290000Sglebius		default:
1659290000Sglebius			msyslog(LOG_ERR, "Unknown script token %d",
1660290000Sglebius				my_attr_val->attr);
1661290000Sglebius		}
1662290000Sglebius	}
1663132451Sroberto
1664290000Sglebius	return my_info;
1665290000Sglebius}
1666290000Sglebius#endif	/* SIM */
1667132451Sroberto
1668132451Sroberto
1669290000Sglebius#ifdef SIM
1670290000Sglebiusstatic sockaddr_u *
1671290000Sglebiusget_next_address(
1672290000Sglebius	address_node *addr
1673290000Sglebius	)
1674290000Sglebius{
1675290000Sglebius	const char addr_prefix[] = "192.168.0.";
1676290000Sglebius	static int curr_addr_num = 1;
1677290000Sglebius#define ADDR_LENGTH 16 + 1	/* room for 192.168.1.255 */
1678290000Sglebius	char addr_string[ADDR_LENGTH];
1679290000Sglebius	sockaddr_u *final_addr;
1680290000Sglebius	struct addrinfo *ptr;
1681290000Sglebius	int gai_err;
1682182007Sroberto
1683290000Sglebius	final_addr = emalloc(sizeof(*final_addr));
1684182007Sroberto
1685290000Sglebius	if (addr->type == T_String) {
1686290000Sglebius		snprintf(addr_string, sizeof(addr_string), "%s%d",
1687290000Sglebius			 addr_prefix, curr_addr_num++);
1688290000Sglebius		printf("Selecting ip address %s for hostname %s\n",
1689290000Sglebius		       addr_string, addr->address);
1690290000Sglebius		gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
1691290000Sglebius	} else {
1692290000Sglebius		gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
1693290000Sglebius	}
1694182007Sroberto
1695290000Sglebius	if (gai_err) {
1696290000Sglebius		fprintf(stderr, "ERROR!! Could not get a new address\n");
1697290000Sglebius		exit(1);
1698290000Sglebius	}
1699290000Sglebius	memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
1700290000Sglebius	fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
1701290000Sglebius		stoa(final_addr));
1702290000Sglebius	freeaddrinfo(ptr);
1703182007Sroberto
1704290000Sglebius	return final_addr;
1705290000Sglebius}
1706290000Sglebius#endif /* SIM */
1707290000Sglebius
1708290000Sglebius
1709290000Sglebius#ifdef SIM
1710290000Sglebiusserver_info *
1711290000Sglebiuscreate_sim_server(
1712290000Sglebius	address_node *		addr,
1713290000Sglebius	double			server_offset,
1714290000Sglebius	script_info_fifo *	script
1715290000Sglebius	)
1716290000Sglebius{
1717290000Sglebius	server_info *my_info;
1718290000Sglebius
1719290000Sglebius	my_info = emalloc_zero(sizeof(*my_info));
1720290000Sglebius	my_info->server_time = server_offset;
1721290000Sglebius	my_info->addr = get_next_address(addr);
1722290000Sglebius	my_info->script = script;
1723290000Sglebius	UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
1724290000Sglebius
1725290000Sglebius	return my_info;
1726290000Sglebius}
1727290000Sglebius#endif	/* SIM */
1728290000Sglebius
1729290000Sglebiussim_node *
1730290000Sglebiuscreate_sim_node(
1731290000Sglebius	attr_val_fifo *		init_opts,
1732290000Sglebius	server_info_fifo *	servers
1733290000Sglebius	)
1734290000Sglebius{
1735290000Sglebius	sim_node *my_node;
1736290000Sglebius
1737290000Sglebius	my_node = emalloc(sizeof(*my_node));
1738290000Sglebius	my_node->init_opts = init_opts;
1739290000Sglebius	my_node->servers = servers;
1740290000Sglebius
1741290000Sglebius	return my_node;
1742290000Sglebius}
1743290000Sglebius
1744290000Sglebius
1745290000Sglebius
1746290000Sglebius
1747290000Sglebius/* FUNCTIONS FOR PERFORMING THE CONFIGURATION
1748290000Sglebius * ------------------------------------------
1749290000Sglebius */
1750290000Sglebius
1751290000Sglebius#ifndef SIM
1752290000Sglebiusstatic void
1753290000Sglebiusconfig_other_modes(
1754290000Sglebius	config_tree *	ptree
1755290000Sglebius	)
1756290000Sglebius{
1757290000Sglebius	sockaddr_u	addr_sock;
1758290000Sglebius	address_node *	addr_node;
1759290000Sglebius
1760290000Sglebius	if (ptree->broadcastclient)
1761290000Sglebius		proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
1762290000Sglebius			     0., NULL);
1763290000Sglebius
1764290000Sglebius	addr_node = HEAD_PFIFO(ptree->manycastserver);
1765290000Sglebius	while (addr_node != NULL) {
1766290000Sglebius		ZERO_SOCK(&addr_sock);
1767290000Sglebius		AF(&addr_sock) = addr_node->type;
1768290000Sglebius		if (1 == getnetnum(addr_node->address, &addr_sock, 1,
1769290000Sglebius				   t_UNK)) {
1770290000Sglebius			proto_config(PROTO_MULTICAST_ADD,
1771290000Sglebius				     0, 0., &addr_sock);
1772290000Sglebius			sys_manycastserver = 1;
1773290000Sglebius		}
1774290000Sglebius		addr_node = addr_node->link;
1775290000Sglebius	}
1776290000Sglebius
1777290000Sglebius	/* Configure the multicast clients */
1778290000Sglebius	addr_node = HEAD_PFIFO(ptree->multicastclient);
1779290000Sglebius	if (addr_node != NULL) {
1780290000Sglebius		do {
1781290000Sglebius			ZERO_SOCK(&addr_sock);
1782290000Sglebius			AF(&addr_sock) = addr_node->type;
1783290000Sglebius			if (1 == getnetnum(addr_node->address,
1784290000Sglebius					   &addr_sock, 1, t_UNK)) {
1785290000Sglebius				proto_config(PROTO_MULTICAST_ADD, 0, 0.,
1786290000Sglebius					     &addr_sock);
1787290000Sglebius			}
1788290000Sglebius			addr_node = addr_node->link;
1789290000Sglebius		} while (addr_node != NULL);
1790290000Sglebius		proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1791290000Sglebius	}
1792290000Sglebius}
1793290000Sglebius#endif	/* !SIM */
1794290000Sglebius
1795290000Sglebius
1796290000Sglebius#ifdef FREE_CFG_T
1797290000Sglebiusstatic void
1798290000Sglebiusdestroy_address_fifo(
1799290000Sglebius	address_fifo *	pfifo
1800290000Sglebius	)
1801290000Sglebius{
1802290000Sglebius	address_node *	addr_node;
1803290000Sglebius
1804290000Sglebius	if (pfifo != NULL) {
1805290000Sglebius		for (;;) {
1806290000Sglebius			UNLINK_FIFO(addr_node, *pfifo, link);
1807290000Sglebius			if (addr_node == NULL)
1808182007Sroberto				break;
1809290000Sglebius			destroy_address_node(addr_node);
1810290000Sglebius		}
1811290000Sglebius		free(pfifo);
1812290000Sglebius	}
1813290000Sglebius}
1814182007Sroberto
1815290000Sglebius
1816290000Sglebiusstatic void
1817290000Sglebiusfree_config_other_modes(
1818290000Sglebius	config_tree *ptree
1819290000Sglebius	)
1820290000Sglebius{
1821290000Sglebius	FREE_ADDRESS_FIFO(ptree->manycastserver);
1822290000Sglebius	FREE_ADDRESS_FIFO(ptree->multicastclient);
1823290000Sglebius}
1824290000Sglebius#endif	/* FREE_CFG_T */
1825290000Sglebius
1826290000Sglebius
1827290000Sglebius#ifndef SIM
1828290000Sglebiusstatic void
1829290000Sglebiusconfig_auth(
1830290000Sglebius	config_tree *ptree
1831290000Sglebius	)
1832290000Sglebius{
1833290000Sglebius	attr_val *	my_val;
1834290000Sglebius	int		first;
1835290000Sglebius	int		last;
1836290000Sglebius	int		i;
1837290000Sglebius	int		count;
1838290000Sglebius#ifdef AUTOKEY
1839290000Sglebius	int		item;
1840290000Sglebius#endif
1841290000Sglebius
1842290000Sglebius	/* Crypto Command */
1843290000Sglebius#ifdef AUTOKEY
1844290000Sglebius# ifdef __GNUC__
1845290000Sglebius	item = -1;	/* quiet warning */
1846290000Sglebius# endif
1847290000Sglebius	my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
1848290000Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1849290000Sglebius		switch (my_val->attr) {
1850290000Sglebius
1851290000Sglebius		default:
1852290000Sglebius			INSIST(0);
1853290000Sglebius			break;
1854290000Sglebius
1855290000Sglebius		case T_Host:
1856290000Sglebius			item = CRYPTO_CONF_PRIV;
1857290000Sglebius			break;
1858290000Sglebius
1859290000Sglebius		case T_Ident:
1860290000Sglebius			item = CRYPTO_CONF_IDENT;
1861290000Sglebius			break;
1862290000Sglebius
1863290000Sglebius		case T_Pw:
1864290000Sglebius			item = CRYPTO_CONF_PW;
1865290000Sglebius			break;
1866290000Sglebius
1867290000Sglebius		case T_Randfile:
1868290000Sglebius			item = CRYPTO_CONF_RAND;
1869290000Sglebius			break;
1870290000Sglebius
1871290000Sglebius		case T_Digest:
1872290000Sglebius			item = CRYPTO_CONF_NID;
1873290000Sglebius			break;
1874290000Sglebius		}
1875290000Sglebius		crypto_config(item, my_val->value.s);
1876290000Sglebius	}
1877290000Sglebius#endif	/* AUTOKEY */
1878290000Sglebius
1879290000Sglebius	/* Keysdir Command */
1880290000Sglebius	if (ptree->auth.keysdir) {
1881290000Sglebius		if (keysdir != default_keysdir)
1882290000Sglebius			free(keysdir);
1883290000Sglebius		keysdir = estrdup(ptree->auth.keysdir);
1884290000Sglebius	}
1885290000Sglebius
1886290000Sglebius
1887290000Sglebius	/* ntp_signd_socket Command */
1888290000Sglebius	if (ptree->auth.ntp_signd_socket) {
1889290000Sglebius		if (ntp_signd_socket != default_ntp_signd_socket)
1890290000Sglebius			free(ntp_signd_socket);
1891290000Sglebius		ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
1892290000Sglebius	}
1893290000Sglebius
1894290000Sglebius#ifdef AUTOKEY
1895290000Sglebius	if (ptree->auth.cryptosw && !cryptosw) {
1896290000Sglebius		crypto_setup();
1897290000Sglebius		cryptosw = 1;
1898290000Sglebius	}
1899290000Sglebius#endif	/* AUTOKEY */
1900290000Sglebius
1901290000Sglebius	/*
1902290000Sglebius	 * Count the number of trusted keys to preallocate storage and
1903290000Sglebius	 * size the hash table.
1904290000Sglebius	 */
1905290000Sglebius	count = 0;
1906290000Sglebius	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
1907290000Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1908290000Sglebius		if (T_Integer == my_val->type) {
1909290000Sglebius			first = my_val->value.i;
1910290000Sglebius			if (first > 1 && first <= NTP_MAXKEY)
1911290000Sglebius				count++;
1912290000Sglebius		} else {
1913290000Sglebius			REQUIRE(T_Intrange == my_val->type);
1914290000Sglebius			first = my_val->value.r.first;
1915290000Sglebius			last = my_val->value.r.last;
1916290000Sglebius			if (!(first > last || first < 1 ||
1917290000Sglebius			    last > NTP_MAXKEY)) {
1918290000Sglebius				count += 1 + last - first;
1919132451Sroberto			}
1920290000Sglebius		}
1921290000Sglebius	}
1922290000Sglebius	auth_prealloc_symkeys(count);
1923290000Sglebius
1924290000Sglebius	/* Keys Command */
1925290000Sglebius	if (ptree->auth.keys)
1926290000Sglebius		getauthkeys(ptree->auth.keys);
1927290000Sglebius
1928290000Sglebius	/* Control Key Command */
1929290000Sglebius	if (ptree->auth.control_key)
1930290000Sglebius		ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
1931290000Sglebius
1932290000Sglebius	/* Requested Key Command */
1933290000Sglebius	if (ptree->auth.request_key) {
1934290000Sglebius		DPRINTF(4, ("set info_auth_keyid to %08lx\n",
1935290000Sglebius			    (u_long) ptree->auth.request_key));
1936290000Sglebius		info_auth_keyid = (keyid_t)ptree->auth.request_key;
1937290000Sglebius	}
1938290000Sglebius
1939290000Sglebius	/* Trusted Key Command */
1940290000Sglebius	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
1941290000Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1942290000Sglebius		if (T_Integer == my_val->type) {
1943290000Sglebius			first = my_val->value.i;
1944290000Sglebius			if (first >= 1 && first <= NTP_MAXKEY) {
1945290000Sglebius				authtrust(first, TRUE);
1946290000Sglebius			} else {
1947290000Sglebius				msyslog(LOG_NOTICE,
1948290000Sglebius					"Ignoring invalid trustedkey %d, min 1 max %d.",
1949290000Sglebius					first, NTP_MAXKEY);
1950290000Sglebius			}
1951290000Sglebius		} else {
1952290000Sglebius			first = my_val->value.r.first;
1953290000Sglebius			last = my_val->value.r.last;
1954290000Sglebius			if (first > last || first < 1 ||
1955290000Sglebius			    last > NTP_MAXKEY) {
1956290000Sglebius				msyslog(LOG_NOTICE,
1957290000Sglebius					"Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
1958290000Sglebius					first, last, NTP_MAXKEY);
1959290000Sglebius			} else {
1960290000Sglebius				for (i = first; i <= last; i++) {
1961290000Sglebius					authtrust(i, TRUE);
1962290000Sglebius				}
1963290000Sglebius			}
1964290000Sglebius		}
1965290000Sglebius	}
1966290000Sglebius
1967290000Sglebius#ifdef AUTOKEY
1968290000Sglebius	/* crypto revoke command */
1969290000Sglebius	if (ptree->auth.revoke)
1970290000Sglebius		sys_revoke = 1UL << ptree->auth.revoke;
1971290000Sglebius#endif	/* AUTOKEY */
1972290000Sglebius}
1973290000Sglebius#endif	/* !SIM */
1974290000Sglebius
1975290000Sglebius
1976290000Sglebius#ifdef FREE_CFG_T
1977290000Sglebiusstatic void
1978290000Sglebiusfree_config_auth(
1979290000Sglebius	config_tree *ptree
1980290000Sglebius	)
1981290000Sglebius{
1982290000Sglebius	destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
1983290000Sglebius	ptree->auth.crypto_cmd_list = NULL;
1984290000Sglebius	destroy_attr_val_fifo(ptree->auth.trusted_key_list);
1985290000Sglebius	ptree->auth.trusted_key_list = NULL;
1986290000Sglebius}
1987290000Sglebius#endif	/* FREE_CFG_T */
1988290000Sglebius
1989290000Sglebius
1990290000Sglebiusstatic void
1991290000Sglebiusconfig_tos(
1992290000Sglebius	config_tree *ptree
1993290000Sglebius	)
1994290000Sglebius{
1995290000Sglebius	attr_val *	tos;
1996290000Sglebius	int		item;
1997290000Sglebius	double		val;
1998290000Sglebius
1999290000Sglebius#ifdef __GNUC__
2000290000Sglebius	item = -1;	/* quiet warning */
2001290000Sglebius#endif
2002290000Sglebius	tos = HEAD_PFIFO(ptree->orphan_cmds);
2003290000Sglebius	for (; tos != NULL; tos = tos->link) {
2004290000Sglebius		val = tos->value.d;
2005290000Sglebius		switch(tos->attr) {
2006290000Sglebius
2007290000Sglebius		default:
2008290000Sglebius			INSIST(0);
2009132451Sroberto			break;
2010132451Sroberto
2011310419Sdelphij		case T_Bcpollbstep:
2012310419Sdelphij			if (val > 4) {
2013310419Sdelphij				msyslog(LOG_WARNING,
2014310419Sdelphij					"Using maximum bcpollbstep ceiling %d, %g requested",
2015310419Sdelphij					4, val);
2016310419Sdelphij				val = 4;
2017310419Sdelphij			} else if (val < 0) {
2018310419Sdelphij				msyslog(LOG_WARNING,
2019310419Sdelphij					"Using minimum bcpollbstep floor %d, %g requested",
2020310419Sdelphij					0, val);
2021310419Sdelphij				val = 0;
2022310419Sdelphij			}
2023310419Sdelphij			item = PROTO_BCPOLLBSTEP;
2024310419Sdelphij			break;
2025310419Sdelphij
2026290000Sglebius		case T_Ceiling:
2027290000Sglebius			if (val > STRATUM_UNSPEC - 1) {
2028290000Sglebius				msyslog(LOG_WARNING,
2029290000Sglebius					"Using maximum tos ceiling %d, %g requested",
2030290000Sglebius					STRATUM_UNSPEC - 1, val);
2031290000Sglebius				val = STRATUM_UNSPEC - 1;
2032132451Sroberto			}
2033290000Sglebius			item = PROTO_CEILING;
2034132451Sroberto			break;
2035132451Sroberto
2036290000Sglebius		case T_Floor:
2037290000Sglebius			item = PROTO_FLOOR;
2038290000Sglebius			break;
2039132451Sroberto
2040290000Sglebius		case T_Cohort:
2041290000Sglebius			item = PROTO_COHORT;
2042290000Sglebius			break;
2043290000Sglebius
2044290000Sglebius		case T_Orphan:
2045290000Sglebius			item = PROTO_ORPHAN;
2046290000Sglebius			break;
2047290000Sglebius
2048290000Sglebius		case T_Orphanwait:
2049290000Sglebius			item = PROTO_ORPHWAIT;
2050290000Sglebius			break;
2051290000Sglebius
2052290000Sglebius		case T_Mindist:
2053290000Sglebius			item = PROTO_MINDISP;
2054290000Sglebius			break;
2055290000Sglebius
2056290000Sglebius		case T_Maxdist:
2057290000Sglebius			item = PROTO_MAXDIST;
2058290000Sglebius			break;
2059290000Sglebius
2060290000Sglebius		case T_Minclock:
2061290000Sglebius			item = PROTO_MINCLOCK;
2062290000Sglebius			break;
2063290000Sglebius
2064290000Sglebius		case T_Maxclock:
2065290000Sglebius			item = PROTO_MAXCLOCK;
2066290000Sglebius			break;
2067290000Sglebius
2068290000Sglebius		case T_Minsane:
2069290000Sglebius			item = PROTO_MINSANE;
2070290000Sglebius			break;
2071290000Sglebius
2072290000Sglebius		case T_Beacon:
2073290000Sglebius			item = PROTO_BEACON;
2074290000Sglebius			break;
2075290000Sglebius		}
2076290000Sglebius		proto_config(item, 0, val, NULL);
2077290000Sglebius	}
2078290000Sglebius}
2079290000Sglebius
2080290000Sglebius
2081290000Sglebius#ifdef FREE_CFG_T
2082290000Sglebiusstatic void
2083290000Sglebiusfree_config_tos(
2084290000Sglebius	config_tree *ptree
2085290000Sglebius	)
2086290000Sglebius{
2087290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
2088290000Sglebius}
2089290000Sglebius#endif	/* FREE_CFG_T */
2090290000Sglebius
2091290000Sglebius
2092290000Sglebiusstatic void
2093290000Sglebiusconfig_monitor(
2094290000Sglebius	config_tree *ptree
2095290000Sglebius	)
2096290000Sglebius{
2097290000Sglebius	int_node *pfilegen_token;
2098290000Sglebius	const char *filegen_string;
2099290000Sglebius	const char *filegen_file;
2100290000Sglebius	FILEGEN *filegen;
2101290000Sglebius	filegen_node *my_node;
2102290000Sglebius	attr_val *my_opts;
2103290000Sglebius	int filegen_type;
2104290000Sglebius	int filegen_flag;
2105290000Sglebius
2106290000Sglebius	/* Set the statistics directory */
2107290000Sglebius	if (ptree->stats_dir)
2108290000Sglebius		stats_config(STATS_STATSDIR, ptree->stats_dir);
2109290000Sglebius
2110290000Sglebius	/* NOTE:
2111290000Sglebius	 * Calling filegen_get is brain dead. Doing a string
2112290000Sglebius	 * comparison to find the relavant filegen structure is
2113290000Sglebius	 * expensive.
2114290000Sglebius	 *
2115290000Sglebius	 * Through the parser, we already know which filegen is
2116290000Sglebius	 * being specified. Hence, we should either store a
2117290000Sglebius	 * pointer to the specified structure in the syntax tree
2118290000Sglebius	 * or an index into a filegen array.
2119290000Sglebius	 *
2120290000Sglebius	 * Need to change the filegen code to reflect the above.
2121290000Sglebius	 */
2122290000Sglebius
2123290000Sglebius	/* Turn on the specified statistics */
2124290000Sglebius	pfilegen_token = HEAD_PFIFO(ptree->stats_list);
2125290000Sglebius	for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
2126290000Sglebius		filegen_string = keyword(pfilegen_token->i);
2127290000Sglebius		filegen = filegen_get(filegen_string);
2128290000Sglebius		if (NULL == filegen) {
2129290000Sglebius			msyslog(LOG_ERR,
2130290000Sglebius				"stats %s unrecognized",
2131290000Sglebius				filegen_string);
2132290000Sglebius			continue;
2133290000Sglebius		}
2134290000Sglebius		DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
2135290000Sglebius			    filegen_string, filegen->dir,
2136290000Sglebius			    filegen->fname));
2137290000Sglebius		filegen_flag = filegen->flag;
2138290000Sglebius		filegen_flag |= FGEN_FLAG_ENABLED;
2139290000Sglebius		filegen_config(filegen, statsdir, filegen_string,
2140290000Sglebius			       filegen->type, filegen_flag);
2141290000Sglebius	}
2142290000Sglebius
2143290000Sglebius	/* Configure the statistics with the options */
2144290000Sglebius	my_node = HEAD_PFIFO(ptree->filegen_opts);
2145290000Sglebius	for (; my_node != NULL; my_node = my_node->link) {
2146290000Sglebius		filegen_string = keyword(my_node->filegen_token);
2147290000Sglebius		filegen = filegen_get(filegen_string);
2148290000Sglebius		if (NULL == filegen) {
2149290000Sglebius			msyslog(LOG_ERR,
2150290000Sglebius				"filegen category '%s' unrecognized",
2151290000Sglebius				filegen_string);
2152290000Sglebius			continue;
2153290000Sglebius		}
2154290000Sglebius		filegen_file = filegen_string;
2155290000Sglebius
2156290000Sglebius		/* Initialize the filegen variables to their pre-configuration states */
2157290000Sglebius		filegen_flag = filegen->flag;
2158290000Sglebius		filegen_type = filegen->type;
2159290000Sglebius
2160290000Sglebius		/* "filegen ... enabled" is the default (when filegen is used) */
2161290000Sglebius		filegen_flag |= FGEN_FLAG_ENABLED;
2162290000Sglebius
2163290000Sglebius		my_opts = HEAD_PFIFO(my_node->options);
2164290000Sglebius		for (; my_opts != NULL; my_opts = my_opts->link) {
2165290000Sglebius			switch (my_opts->attr) {
2166290000Sglebius
2167290000Sglebius			case T_File:
2168290000Sglebius				filegen_file = my_opts->value.s;
2169132451Sroberto				break;
2170132451Sroberto
2171290000Sglebius			case T_Type:
2172290000Sglebius				switch (my_opts->value.i) {
2173290000Sglebius
2174290000Sglebius				default:
2175290000Sglebius					INSIST(0);
2176290000Sglebius					break;
2177290000Sglebius
2178290000Sglebius				case T_None:
2179290000Sglebius					filegen_type = FILEGEN_NONE;
2180290000Sglebius					break;
2181290000Sglebius
2182290000Sglebius				case T_Pid:
2183290000Sglebius					filegen_type = FILEGEN_PID;
2184290000Sglebius					break;
2185290000Sglebius
2186290000Sglebius				case T_Day:
2187290000Sglebius					filegen_type = FILEGEN_DAY;
2188290000Sglebius					break;
2189290000Sglebius
2190290000Sglebius				case T_Week:
2191290000Sglebius					filegen_type = FILEGEN_WEEK;
2192290000Sglebius					break;
2193290000Sglebius
2194290000Sglebius				case T_Month:
2195290000Sglebius					filegen_type = FILEGEN_MONTH;
2196290000Sglebius					break;
2197290000Sglebius
2198290000Sglebius				case T_Year:
2199290000Sglebius					filegen_type = FILEGEN_YEAR;
2200290000Sglebius					break;
2201290000Sglebius
2202290000Sglebius				case T_Age:
2203290000Sglebius					filegen_type = FILEGEN_AGE;
2204290000Sglebius					break;
2205290000Sglebius				}
2206132451Sroberto				break;
2207132451Sroberto
2208290000Sglebius			case T_Flag:
2209290000Sglebius				switch (my_opts->value.i) {
2210290000Sglebius
2211290000Sglebius				case T_Link:
2212290000Sglebius					filegen_flag |= FGEN_FLAG_LINK;
2213290000Sglebius					break;
2214290000Sglebius
2215290000Sglebius				case T_Nolink:
2216290000Sglebius					filegen_flag &= ~FGEN_FLAG_LINK;
2217290000Sglebius					break;
2218290000Sglebius
2219290000Sglebius				case T_Enable:
2220290000Sglebius					filegen_flag |= FGEN_FLAG_ENABLED;
2221290000Sglebius					break;
2222290000Sglebius
2223290000Sglebius				case T_Disable:
2224290000Sglebius					filegen_flag &= ~FGEN_FLAG_ENABLED;
2225290000Sglebius					break;
2226290000Sglebius
2227290000Sglebius				default:
2228290000Sglebius					msyslog(LOG_ERR,
2229290000Sglebius						"Unknown filegen flag token %d",
2230290000Sglebius						my_opts->value.i);
2231290000Sglebius					exit(1);
2232290000Sglebius				}
2233132451Sroberto				break;
2234132451Sroberto
2235290000Sglebius			default:
2236132451Sroberto				msyslog(LOG_ERR,
2237290000Sglebius					"Unknown filegen option token %d",
2238290000Sglebius					my_opts->attr);
2239290000Sglebius				exit(1);
2240132451Sroberto			}
2241290000Sglebius		}
2242290000Sglebius		filegen_config(filegen, statsdir, filegen_file,
2243290000Sglebius			       filegen_type, filegen_flag);
2244290000Sglebius	}
2245290000Sglebius}
2246290000Sglebius
2247290000Sglebius
2248290000Sglebius#ifdef FREE_CFG_T
2249290000Sglebiusstatic void
2250290000Sglebiusfree_config_monitor(
2251290000Sglebius	config_tree *ptree
2252290000Sglebius	)
2253290000Sglebius{
2254290000Sglebius	if (ptree->stats_dir) {
2255290000Sglebius		free(ptree->stats_dir);
2256290000Sglebius		ptree->stats_dir = NULL;
2257290000Sglebius	}
2258290000Sglebius
2259290000Sglebius	FREE_INT_FIFO(ptree->stats_list);
2260290000Sglebius	FREE_FILEGEN_FIFO(ptree->filegen_opts);
2261290000Sglebius}
2262290000Sglebius#endif	/* FREE_CFG_T */
2263290000Sglebius
2264290000Sglebius
2265290000Sglebius#ifndef SIM
2266290000Sglebiusstatic void
2267290000Sglebiusconfig_access(
2268290000Sglebius	config_tree *ptree
2269290000Sglebius	)
2270290000Sglebius{
2271290000Sglebius	static int		warned_signd;
2272290000Sglebius	attr_val *		my_opt;
2273290000Sglebius	restrict_node *		my_node;
2274290000Sglebius	int_node *		curr_flag;
2275290000Sglebius	sockaddr_u		addr;
2276290000Sglebius	sockaddr_u		mask;
2277290000Sglebius	struct addrinfo		hints;
2278290000Sglebius	struct addrinfo *	ai_list;
2279290000Sglebius	struct addrinfo *	pai;
2280290000Sglebius	int			rc;
2281290000Sglebius	int			restrict_default;
2282290000Sglebius	u_short			flags;
2283290000Sglebius	u_short			mflags;
2284290000Sglebius	int			range_err;
2285290000Sglebius	const char *		signd_warning =
2286290000Sglebius#ifdef HAVE_NTP_SIGND
2287290000Sglebius	    "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
2288290000Sglebius#else
2289290000Sglebius	    "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
2290290000Sglebius#endif
2291290000Sglebius
2292290000Sglebius	/* Configure the mru options */
2293290000Sglebius	my_opt = HEAD_PFIFO(ptree->mru_opts);
2294290000Sglebius	for (; my_opt != NULL; my_opt = my_opt->link) {
2295290000Sglebius
2296290000Sglebius		range_err = FALSE;
2297290000Sglebius
2298290000Sglebius		switch (my_opt->attr) {
2299290000Sglebius
2300290000Sglebius		case T_Incalloc:
2301290000Sglebius			if (0 <= my_opt->value.i)
2302290000Sglebius				mru_incalloc = my_opt->value.u;
2303290000Sglebius			else
2304290000Sglebius				range_err = TRUE;
2305132451Sroberto			break;
2306132451Sroberto
2307290000Sglebius		case T_Incmem:
2308290000Sglebius			if (0 <= my_opt->value.i)
2309290000Sglebius				mru_incalloc = (my_opt->value.u * 1024U)
2310290000Sglebius						/ sizeof(mon_entry);
2311290000Sglebius			else
2312290000Sglebius				range_err = TRUE;
231382498Sroberto			break;
231482498Sroberto
2315290000Sglebius		case T_Initalloc:
2316290000Sglebius			if (0 <= my_opt->value.i)
2317290000Sglebius				mru_initalloc = my_opt->value.u;
2318290000Sglebius			else
2319290000Sglebius				range_err = TRUE;
232082498Sroberto			break;
232182498Sroberto
2322290000Sglebius		case T_Initmem:
2323290000Sglebius			if (0 <= my_opt->value.i)
2324290000Sglebius				mru_initalloc = (my_opt->value.u * 1024U)
2325290000Sglebius						 / sizeof(mon_entry);
2326290000Sglebius			else
2327290000Sglebius				range_err = TRUE;
2328290000Sglebius			break;
232954359Sroberto
2330290000Sglebius		case T_Mindepth:
2331290000Sglebius			if (0 <= my_opt->value.i)
2332290000Sglebius				mru_mindepth = my_opt->value.u;
2333290000Sglebius			else
2334290000Sglebius				range_err = TRUE;
2335290000Sglebius			break;
2336290000Sglebius
2337290000Sglebius		case T_Maxage:
2338290000Sglebius			mru_maxage = my_opt->value.i;
2339290000Sglebius			break;
2340290000Sglebius
2341290000Sglebius		case T_Maxdepth:
2342290000Sglebius			if (0 <= my_opt->value.i)
2343290000Sglebius				mru_maxdepth = my_opt->value.u;
2344290000Sglebius			else
2345290000Sglebius				mru_maxdepth = UINT_MAX;
2346290000Sglebius			break;
2347290000Sglebius
2348290000Sglebius		case T_Maxmem:
2349290000Sglebius			if (0 <= my_opt->value.i)
2350290000Sglebius				mru_maxdepth = (my_opt->value.u * 1024U) /
2351290000Sglebius					       sizeof(mon_entry);
2352290000Sglebius			else
2353290000Sglebius				mru_maxdepth = UINT_MAX;
2354290000Sglebius			break;
2355290000Sglebius
2356290000Sglebius		default:
2357290000Sglebius			msyslog(LOG_ERR,
2358290000Sglebius				"Unknown mru option %s (%d)",
2359290000Sglebius				keyword(my_opt->attr), my_opt->attr);
2360290000Sglebius			exit(1);
2361290000Sglebius		}
2362290000Sglebius		if (range_err)
2363290000Sglebius			msyslog(LOG_ERR,
2364290000Sglebius				"mru %s %d out of range, ignored.",
2365290000Sglebius				keyword(my_opt->attr), my_opt->value.i);
2366290000Sglebius	}
2367290000Sglebius
2368290000Sglebius	/* Configure the discard options */
2369290000Sglebius	my_opt = HEAD_PFIFO(ptree->discard_opts);
2370290000Sglebius	for (; my_opt != NULL; my_opt = my_opt->link) {
2371290000Sglebius
2372290000Sglebius		switch (my_opt->attr) {
2373290000Sglebius
2374290000Sglebius		case T_Average:
2375290000Sglebius			if (0 <= my_opt->value.i &&
2376290000Sglebius			    my_opt->value.i <= UCHAR_MAX)
2377290000Sglebius				ntp_minpoll = (u_char)my_opt->value.u;
2378290000Sglebius			else
237982498Sroberto				msyslog(LOG_ERR,
2380290000Sglebius					"discard average %d out of range, ignored.",
2381290000Sglebius					my_opt->value.i);
2382290000Sglebius			break;
2383290000Sglebius
2384290000Sglebius		case T_Minimum:
2385290000Sglebius			ntp_minpkt = my_opt->value.i;
2386290000Sglebius			break;
2387290000Sglebius
2388290000Sglebius		case T_Monitor:
2389290000Sglebius			mon_age = my_opt->value.i;
2390290000Sglebius			break;
2391290000Sglebius
2392290000Sglebius		default:
2393290000Sglebius			msyslog(LOG_ERR,
2394290000Sglebius				"Unknown discard option %s (%d)",
2395290000Sglebius				keyword(my_opt->attr), my_opt->attr);
2396290000Sglebius			exit(1);
2397290000Sglebius		}
2398290000Sglebius	}
2399290000Sglebius
2400290000Sglebius	/* Configure the restrict options */
2401290000Sglebius	my_node = HEAD_PFIFO(ptree->restrict_opts);
2402290000Sglebius	for (; my_node != NULL; my_node = my_node->link) {
2403290000Sglebius		/* Parse the flags */
2404290000Sglebius		flags = 0;
2405290000Sglebius		mflags = 0;
2406290000Sglebius
2407290000Sglebius		curr_flag = HEAD_PFIFO(my_node->flags);
2408290000Sglebius		for (; curr_flag != NULL; curr_flag = curr_flag->link) {
2409290000Sglebius			switch (curr_flag->i) {
2410290000Sglebius
2411290000Sglebius			default:
2412290000Sglebius				INSIST(0);
241382498Sroberto				break;
2414132451Sroberto
2415290000Sglebius			case T_Ntpport:
2416290000Sglebius				mflags |= RESM_NTPONLY;
241782498Sroberto				break;
241882498Sroberto
2419290000Sglebius			case T_Source:
2420290000Sglebius				mflags |= RESM_SOURCE;
242182498Sroberto				break;
242282498Sroberto
2423290000Sglebius			case T_Flake:
2424290000Sglebius				flags |= RES_FLAKE;
2425182007Sroberto				break;
2426182007Sroberto
2427290000Sglebius			case T_Ignore:
2428290000Sglebius				flags |= RES_IGNORE;
242982498Sroberto				break;
243082498Sroberto
2431290000Sglebius			case T_Kod:
2432290000Sglebius				flags |= RES_KOD;
243382498Sroberto				break;
243482498Sroberto
2435290000Sglebius			case T_Mssntp:
2436290000Sglebius				flags |= RES_MSSNTP;
243782498Sroberto				break;
243882498Sroberto
2439290000Sglebius			case T_Limited:
2440290000Sglebius				flags |= RES_LIMITED;
244182498Sroberto				break;
244282498Sroberto
2443290000Sglebius			case T_Lowpriotrap:
2444290000Sglebius				flags |= RES_LPTRAP;
2445132451Sroberto				break;
2446132451Sroberto
2447290000Sglebius			case T_Nomodify:
2448290000Sglebius				flags |= RES_NOMODIFY;
2449132451Sroberto				break;
2450132451Sroberto
2451290000Sglebius			case T_Nomrulist:
2452290000Sglebius				flags |= RES_NOMRULIST;
2453132451Sroberto				break;
2454132451Sroberto
2455290000Sglebius			case T_Nopeer:
2456290000Sglebius				flags |= RES_NOPEER;
245782498Sroberto				break;
245882498Sroberto
2459290000Sglebius			case T_Noquery:
2460290000Sglebius				flags |= RES_NOQUERY;
246154359Sroberto				break;
2462290000Sglebius
2463290000Sglebius			case T_Noserve:
2464290000Sglebius				flags |= RES_DONTSERVE;
2465132451Sroberto				break;
2466290000Sglebius
2467290000Sglebius			case T_Notrap:
2468290000Sglebius				flags |= RES_NOTRAP;
2469132451Sroberto				break;
2470290000Sglebius
2471290000Sglebius			case T_Notrust:
2472290000Sglebius				flags |= RES_DONTTRUST;
2473290000Sglebius				break;
2474290000Sglebius
2475290000Sglebius			case T_Version:
2476290000Sglebius				flags |= RES_VERSION;
2477290000Sglebius				break;
2478132451Sroberto			}
2479290000Sglebius		}
248054359Sroberto
2481290000Sglebius		if ((RES_MSSNTP & flags) && !warned_signd) {
2482290000Sglebius			warned_signd = 1;
2483290000Sglebius			fprintf(stderr, "%s\n", signd_warning);
2484290000Sglebius			msyslog(LOG_WARNING, "%s", signd_warning);
2485290000Sglebius		}
2486290000Sglebius
2487290000Sglebius		/* It would be swell if we could identify the line number */
2488290000Sglebius		if ((RES_KOD & flags) && !(RES_LIMITED & flags)) {
2489290000Sglebius			const char *kod_where = (my_node->addr)
2490290000Sglebius					  ? my_node->addr->address
2491290000Sglebius					  : (mflags & RESM_SOURCE)
2492290000Sglebius					    ? "source"
2493290000Sglebius					    : "default";
2494290000Sglebius			const char *kod_warn = "KOD does nothing without LIMITED.";
2495290000Sglebius
2496290000Sglebius			fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
2497290000Sglebius			msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
2498290000Sglebius		}
2499290000Sglebius
2500290000Sglebius		ZERO_SOCK(&addr);
2501290000Sglebius		ai_list = NULL;
2502290000Sglebius		pai = NULL;
2503290000Sglebius		restrict_default = 0;
2504290000Sglebius
2505290000Sglebius		if (NULL == my_node->addr) {
2506290000Sglebius			ZERO_SOCK(&mask);
2507290000Sglebius			if (!(RESM_SOURCE & mflags)) {
2508290000Sglebius				/*
2509290000Sglebius				 * The user specified a default rule
2510290000Sglebius				 * without a -4 / -6 qualifier, add to
2511290000Sglebius				 * both lists
2512290000Sglebius				 */
2513290000Sglebius				restrict_default = 1;
2514290000Sglebius			} else {
2515290000Sglebius				/* apply "restrict source ..." */
2516290000Sglebius				DPRINTF(1, ("restrict source template mflags %x flags %x\n",
2517290000Sglebius					mflags, flags));
2518290000Sglebius				hack_restrict(RESTRICT_FLAGS, NULL,
2519290000Sglebius					      NULL, mflags, flags, 0);
2520290000Sglebius				continue;
2521290000Sglebius			}
2522290000Sglebius		} else {
2523290000Sglebius			/* Resolve the specified address */
2524290000Sglebius			AF(&addr) = (u_short)my_node->addr->type;
2525290000Sglebius
2526290000Sglebius			if (getnetnum(my_node->addr->address,
2527290000Sglebius				      &addr, 1, t_UNK) != 1) {
2528290000Sglebius				/*
2529290000Sglebius				 * Attempt a blocking lookup.  This
2530290000Sglebius				 * is in violation of the nonblocking
2531290000Sglebius				 * design of ntpd's mainline code.  The
2532290000Sglebius				 * alternative of running without the
2533290000Sglebius				 * restriction until the name resolved
2534290000Sglebius				 * seems worse.
2535290000Sglebius				 * Ideally some scheme could be used for
2536290000Sglebius				 * restrict directives in the startup
2537290000Sglebius				 * ntp.conf to delay starting up the
2538290000Sglebius				 * protocol machinery until after all
2539290000Sglebius				 * restrict hosts have been resolved.
2540290000Sglebius				 */
2541290000Sglebius				ai_list = NULL;
2542290000Sglebius				ZERO(hints);
2543290000Sglebius				hints.ai_protocol = IPPROTO_UDP;
2544290000Sglebius				hints.ai_socktype = SOCK_DGRAM;
2545290000Sglebius				hints.ai_family = my_node->addr->type;
2546290000Sglebius				rc = getaddrinfo(my_node->addr->address,
2547290000Sglebius						 "ntp", &hints,
2548290000Sglebius						 &ai_list);
2549290000Sglebius				if (rc) {
2550290000Sglebius					msyslog(LOG_ERR,
2551290000Sglebius						"restrict: ignoring line %d, address/host '%s' unusable.",
2552290000Sglebius						my_node->line_no,
2553290000Sglebius						my_node->addr->address);
2554290000Sglebius					continue;
2555290000Sglebius				}
2556290000Sglebius				INSIST(ai_list != NULL);
2557290000Sglebius				pai = ai_list;
2558290000Sglebius				INSIST(pai->ai_addr != NULL);
2559290000Sglebius				INSIST(sizeof(addr) >=
2560290000Sglebius					   pai->ai_addrlen);
2561290000Sglebius				memcpy(&addr, pai->ai_addr,
2562290000Sglebius				       pai->ai_addrlen);
2563290000Sglebius				INSIST(AF_INET == AF(&addr) ||
2564290000Sglebius					   AF_INET6 == AF(&addr));
2565290000Sglebius			}
2566290000Sglebius
2567290000Sglebius			SET_HOSTMASK(&mask, AF(&addr));
2568290000Sglebius
2569290000Sglebius			/* Resolve the mask */
2570290000Sglebius			if (my_node->mask) {
2571290000Sglebius				ZERO_SOCK(&mask);
2572290000Sglebius				AF(&mask) = my_node->mask->type;
2573290000Sglebius				if (getnetnum(my_node->mask->address,
2574290000Sglebius					      &mask, 1, t_MSK) != 1) {
2575290000Sglebius					msyslog(LOG_ERR,
2576290000Sglebius						"restrict: ignoring line %d, mask '%s' unusable.",
2577290000Sglebius						my_node->line_no,
2578290000Sglebius						my_node->mask->address);
2579290000Sglebius					continue;
2580290000Sglebius				}
2581290000Sglebius			}
2582290000Sglebius		}
2583290000Sglebius
2584290000Sglebius		/* Set the flags */
2585290000Sglebius		if (restrict_default) {
2586290000Sglebius			AF(&addr) = AF_INET;
2587290000Sglebius			AF(&mask) = AF_INET;
2588290000Sglebius			hack_restrict(RESTRICT_FLAGS, &addr,
2589290000Sglebius				      &mask, mflags, flags, 0);
2590290000Sglebius			AF(&addr) = AF_INET6;
2591290000Sglebius			AF(&mask) = AF_INET6;
2592290000Sglebius		}
2593290000Sglebius
2594290000Sglebius		do {
2595290000Sglebius			hack_restrict(RESTRICT_FLAGS, &addr,
2596290000Sglebius				      &mask, mflags, flags, 0);
2597290000Sglebius			if (pai != NULL &&
2598290000Sglebius			    NULL != (pai = pai->ai_next)) {
2599290000Sglebius				INSIST(pai->ai_addr != NULL);
2600290000Sglebius				INSIST(sizeof(addr) >=
2601290000Sglebius					   pai->ai_addrlen);
2602290000Sglebius				ZERO_SOCK(&addr);
2603290000Sglebius				memcpy(&addr, pai->ai_addr,
2604290000Sglebius				       pai->ai_addrlen);
2605290000Sglebius				INSIST(AF_INET == AF(&addr) ||
2606290000Sglebius					   AF_INET6 == AF(&addr));
2607290000Sglebius				SET_HOSTMASK(&mask, AF(&addr));
2608290000Sglebius			}
2609290000Sglebius		} while (pai != NULL);
2610290000Sglebius
2611290000Sglebius		if (ai_list != NULL)
2612290000Sglebius			freeaddrinfo(ai_list);
2613290000Sglebius	}
2614290000Sglebius}
2615290000Sglebius#endif	/* !SIM */
2616290000Sglebius
2617290000Sglebius
2618290000Sglebius#ifdef FREE_CFG_T
2619290000Sglebiusstatic void
2620290000Sglebiusfree_config_access(
2621290000Sglebius	config_tree *ptree
2622290000Sglebius	)
2623290000Sglebius{
2624290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->mru_opts);
2625290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->discard_opts);
2626290000Sglebius	FREE_RESTRICT_FIFO(ptree->restrict_opts);
2627290000Sglebius}
2628290000Sglebius#endif	/* FREE_CFG_T */
2629290000Sglebius
2630290000Sglebius
2631290000Sglebiusstatic void
2632290000Sglebiusconfig_rlimit(
2633290000Sglebius	config_tree *ptree
2634290000Sglebius	)
2635290000Sglebius{
2636290000Sglebius	attr_val *	rlimit_av;
2637290000Sglebius
2638290000Sglebius	rlimit_av = HEAD_PFIFO(ptree->rlimit);
2639290000Sglebius	for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
2640290000Sglebius		switch (rlimit_av->attr) {
2641290000Sglebius
2642290000Sglebius		default:
2643290000Sglebius			INSIST(0);
2644290000Sglebius			break;
2645290000Sglebius
2646290000Sglebius		case T_Memlock:
2647290000Sglebius			/* What if we HAVE_OPT(SAVECONFIGQUIT) ? */
2648290000Sglebius			if (rlimit_av->value.i == -1) {
2649290000Sglebius# if defined(HAVE_MLOCKALL)
2650290000Sglebius				if (cur_memlock != 0) {
2651290000Sglebius					if (-1 == munlockall()) {
2652290000Sglebius						msyslog(LOG_ERR, "munlockall() failed: %m");
2653290000Sglebius					}
2654290000Sglebius				}
2655290000Sglebius				cur_memlock = 0;
2656290000Sglebius# endif /* HAVE_MLOCKALL */
2657290000Sglebius			} else if (rlimit_av->value.i >= 0) {
2658290000Sglebius#if defined(RLIMIT_MEMLOCK)
2659290000Sglebius# if defined(HAVE_MLOCKALL)
2660290000Sglebius				if (cur_memlock != 1) {
2661290000Sglebius					if (-1 == mlockall(MCL_CURRENT|MCL_FUTURE)) {
2662290000Sglebius						msyslog(LOG_ERR, "mlockall() failed: %m");
2663290000Sglebius					}
2664290000Sglebius				}
2665290000Sglebius# endif /* HAVE_MLOCKALL */
2666290000Sglebius				ntp_rlimit(RLIMIT_MEMLOCK,
2667290000Sglebius					   (rlim_t)(rlimit_av->value.i * 1024 * 1024),
2668290000Sglebius					   1024 * 1024,
2669290000Sglebius					   "MB");
2670290000Sglebius				cur_memlock = 1;
2671290000Sglebius#else
2672290000Sglebius				/* STDERR as well would be fine... */
2673290000Sglebius				msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
2674290000Sglebius#endif /* RLIMIT_MEMLOCK */
2675290000Sglebius			} else {
2676290000Sglebius				msyslog(LOG_WARNING, "'rlimit memlock' value of %d is unexpected!", rlimit_av->value.i);
2677290000Sglebius			}
2678290000Sglebius			break;
2679290000Sglebius
2680290000Sglebius		case T_Stacksize:
2681290000Sglebius#if defined(RLIMIT_STACK)
2682290000Sglebius			ntp_rlimit(RLIMIT_STACK,
2683290000Sglebius				   (rlim_t)(rlimit_av->value.i * 4096),
2684290000Sglebius				   4096,
2685290000Sglebius				   "4k");
2686290000Sglebius#else
2687290000Sglebius			/* STDERR as well would be fine... */
2688290000Sglebius			msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
2689290000Sglebius#endif /* RLIMIT_STACK */
2690290000Sglebius			break;
2691290000Sglebius
2692290000Sglebius		case T_Filenum:
2693290000Sglebius#if defined(RLIMIT_NOFILE)
2694290000Sglebius			ntp_rlimit(RLIMIT_NOFILE,
2695290000Sglebius				  (rlim_t)(rlimit_av->value.i),
2696290000Sglebius				  1,
2697290000Sglebius				  "");
2698290000Sglebius#else
2699290000Sglebius			/* STDERR as well would be fine... */
2700290000Sglebius			msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
2701290000Sglebius#endif /* RLIMIT_NOFILE */
2702290000Sglebius			break;
2703290000Sglebius
2704290000Sglebius		}
2705290000Sglebius	}
2706290000Sglebius}
2707290000Sglebius
2708290000Sglebius
2709290000Sglebiusstatic void
2710290000Sglebiusconfig_tinker(
2711290000Sglebius	config_tree *ptree
2712290000Sglebius	)
2713290000Sglebius{
2714290000Sglebius	attr_val *	tinker;
2715290000Sglebius	int		item;
2716290000Sglebius
2717290000Sglebius#ifdef __GNUC__
2718290000Sglebius	item = -1;	/* quiet warning */
2719290000Sglebius#endif
2720290000Sglebius	tinker = HEAD_PFIFO(ptree->tinker);
2721290000Sglebius	for (; tinker != NULL; tinker = tinker->link) {
2722290000Sglebius		switch (tinker->attr) {
2723290000Sglebius
2724290000Sglebius		default:
2725290000Sglebius			INSIST(0);
2726290000Sglebius			break;
2727290000Sglebius
2728290000Sglebius		case T_Allan:
2729290000Sglebius			item = LOOP_ALLAN;
2730290000Sglebius			break;
2731290000Sglebius
2732290000Sglebius		case T_Dispersion:
2733290000Sglebius			item = LOOP_PHI;
2734290000Sglebius			break;
2735290000Sglebius
2736290000Sglebius		case T_Freq:
2737290000Sglebius			item = LOOP_FREQ;
2738290000Sglebius			break;
2739290000Sglebius
2740290000Sglebius		case T_Huffpuff:
2741290000Sglebius			item = LOOP_HUFFPUFF;
2742290000Sglebius			break;
2743290000Sglebius
2744290000Sglebius		case T_Panic:
2745290000Sglebius			item = LOOP_PANIC;
2746290000Sglebius			break;
2747290000Sglebius
2748290000Sglebius		case T_Step:
2749290000Sglebius			item = LOOP_MAX;
2750290000Sglebius			break;
2751290000Sglebius
2752290000Sglebius		case T_Stepback:
2753290000Sglebius			item = LOOP_MAX_BACK;
2754290000Sglebius			break;
2755290000Sglebius
2756290000Sglebius		case T_Stepfwd:
2757290000Sglebius			item = LOOP_MAX_FWD;
2758290000Sglebius			break;
2759290000Sglebius
2760290000Sglebius		case T_Stepout:
2761290000Sglebius			item = LOOP_MINSTEP;
2762290000Sglebius			break;
2763290000Sglebius
2764290000Sglebius		case T_Tick:
2765290000Sglebius			item = LOOP_TICK;
2766290000Sglebius			break;
2767290000Sglebius		}
2768290000Sglebius		loop_config(item, tinker->value.d);
2769290000Sglebius	}
2770290000Sglebius}
2771290000Sglebius
2772290000Sglebius
2773290000Sglebius#ifdef FREE_CFG_T
2774290000Sglebiusstatic void
2775290000Sglebiusfree_config_rlimit(
2776290000Sglebius	config_tree *ptree
2777290000Sglebius	)
2778290000Sglebius{
2779290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->rlimit);
2780290000Sglebius}
2781290000Sglebius
2782290000Sglebiusstatic void
2783290000Sglebiusfree_config_tinker(
2784290000Sglebius	config_tree *ptree
2785290000Sglebius	)
2786290000Sglebius{
2787290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->tinker);
2788290000Sglebius}
2789290000Sglebius#endif	/* FREE_CFG_T */
2790290000Sglebius
2791290000Sglebius
2792290000Sglebius/*
2793290000Sglebius * config_nic_rules - apply interface listen/ignore/drop items
2794290000Sglebius */
2795290000Sglebius#ifndef SIM
2796290000Sglebiusstatic void
2797290000Sglebiusconfig_nic_rules(
2798290000Sglebius	config_tree *ptree,
2799290000Sglebius	int/*BOOL*/ input_from_file
2800290000Sglebius	)
2801290000Sglebius{
2802290000Sglebius	nic_rule_node *	curr_node;
2803290000Sglebius	sockaddr_u	addr;
2804290000Sglebius	nic_rule_match	match_type;
2805290000Sglebius	nic_rule_action	action;
2806290000Sglebius	char *		if_name;
2807290000Sglebius	char *		pchSlash;
2808290000Sglebius	int		prefixlen;
2809290000Sglebius	int		addrbits;
2810290000Sglebius
2811290000Sglebius	curr_node = HEAD_PFIFO(ptree->nic_rules);
2812290000Sglebius
2813290000Sglebius	if (curr_node != NULL
2814290000Sglebius	    && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
2815290000Sglebius		msyslog(LOG_ERR,
2816290000Sglebius			"interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
2817290000Sglebius			(input_from_file) ? ", exiting" : "");
2818290000Sglebius		if (input_from_file)
2819290000Sglebius			exit(1);
2820290000Sglebius		else
2821290000Sglebius			return;
2822290000Sglebius	}
2823290000Sglebius
2824290000Sglebius	for (; curr_node != NULL; curr_node = curr_node->link) {
2825290000Sglebius		prefixlen = -1;
2826290000Sglebius		if_name = curr_node->if_name;
2827290000Sglebius		if (if_name != NULL)
2828290000Sglebius			if_name = estrdup(if_name);
2829290000Sglebius
2830290000Sglebius		switch (curr_node->match_class) {
2831290000Sglebius
2832290000Sglebius		default:
2833290000Sglebius#ifdef __GNUC__
283454359Sroberto			/*
2835290000Sglebius			 * this assignment quiets a gcc "may be used
2836290000Sglebius			 * uninitialized" warning and is here for no
2837290000Sglebius			 * other reason.
2838132451Sroberto			 */
2839290000Sglebius			match_type = MATCH_ALL;
2840290000Sglebius#endif
2841290000Sglebius			INSIST(FALSE);
2842290000Sglebius			break;
2843132451Sroberto
2844290000Sglebius		case 0:
2845132451Sroberto			/*
2846290000Sglebius			 * 0 is out of range for valid token T_...
2847290000Sglebius			 * and in a nic_rules_node indicates the
2848290000Sglebius			 * interface descriptor is either a name or
2849290000Sglebius			 * address, stored in if_name in either case.
285054359Sroberto			 */
2851290000Sglebius			INSIST(if_name != NULL);
2852290000Sglebius			pchSlash = strchr(if_name, '/');
2853290000Sglebius			if (pchSlash != NULL)
2854290000Sglebius				*pchSlash = '\0';
2855290000Sglebius			if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
2856290000Sglebius				match_type = MATCH_IFADDR;
2857290000Sglebius				if (pchSlash != NULL
2858290000Sglebius				    && 1 == sscanf(pchSlash + 1, "%d",
2859290000Sglebius					    &prefixlen)) {
2860290000Sglebius					addrbits = 8 *
2861290000Sglebius					    SIZEOF_INADDR(AF(&addr));
2862290000Sglebius					prefixlen = max(-1, prefixlen);
2863290000Sglebius					prefixlen = min(prefixlen,
2864290000Sglebius							addrbits);
2865290000Sglebius				}
2866290000Sglebius			} else {
2867290000Sglebius				match_type = MATCH_IFNAME;
2868290000Sglebius				if (pchSlash != NULL)
2869290000Sglebius					*pchSlash = '/';
2870290000Sglebius			}
2871290000Sglebius			break;
287254359Sroberto
2873290000Sglebius		case T_All:
2874290000Sglebius			match_type = MATCH_ALL;
2875290000Sglebius			break;
287654359Sroberto
2877290000Sglebius		case T_Ipv4:
2878290000Sglebius			match_type = MATCH_IPV4;
2879290000Sglebius			break;
288054359Sroberto
2881290000Sglebius		case T_Ipv6:
2882290000Sglebius			match_type = MATCH_IPV6;
2883290000Sglebius			break;
288454359Sroberto
2885290000Sglebius		case T_Wildcard:
2886290000Sglebius			match_type = MATCH_WILDCARD;
2887290000Sglebius			break;
2888290000Sglebius		}
288954359Sroberto
2890290000Sglebius		switch (curr_node->action) {
289154359Sroberto
2892290000Sglebius		default:
2893290000Sglebius#ifdef __GNUC__
2894290000Sglebius			/*
2895290000Sglebius			 * this assignment quiets a gcc "may be used
2896290000Sglebius			 * uninitialized" warning and is here for no
2897290000Sglebius			 * other reason.
2898290000Sglebius			 */
2899290000Sglebius			action = ACTION_LISTEN;
2900290000Sglebius#endif
2901290000Sglebius			INSIST(FALSE);
2902290000Sglebius			break;
290354359Sroberto
2904290000Sglebius		case T_Listen:
2905290000Sglebius			action = ACTION_LISTEN;
2906290000Sglebius			break;
290754359Sroberto
2908290000Sglebius		case T_Ignore:
2909290000Sglebius			action = ACTION_IGNORE;
2910290000Sglebius			break;
291154359Sroberto
2912290000Sglebius		case T_Drop:
2913290000Sglebius			action = ACTION_DROP;
2914290000Sglebius			break;
2915290000Sglebius		}
291654359Sroberto
2917290000Sglebius		add_nic_rule(match_type, if_name, prefixlen,
2918290000Sglebius			     action);
2919290000Sglebius		timer_interfacetimeout(current_time + 2);
2920290000Sglebius		if (if_name != NULL)
2921290000Sglebius			free(if_name);
2922290000Sglebius	}
2923290000Sglebius}
2924290000Sglebius#endif	/* !SIM */
292582498Sroberto
292682498Sroberto
2927290000Sglebius#ifdef FREE_CFG_T
2928290000Sglebiusstatic void
2929290000Sglebiusfree_config_nic_rules(
2930290000Sglebius	config_tree *ptree
2931290000Sglebius	)
2932290000Sglebius{
2933290000Sglebius	nic_rule_node *curr_node;
293454359Sroberto
2935290000Sglebius	if (ptree->nic_rules != NULL) {
2936290000Sglebius		for (;;) {
2937290000Sglebius			UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
2938290000Sglebius			if (NULL == curr_node)
2939290000Sglebius				break;
2940290000Sglebius			free(curr_node->if_name);
2941290000Sglebius			free(curr_node);
2942290000Sglebius		}
2943290000Sglebius		free(ptree->nic_rules);
2944290000Sglebius		ptree->nic_rules = NULL;
2945290000Sglebius	}
2946290000Sglebius}
2947290000Sglebius#endif	/* FREE_CFG_T */
2948290000Sglebius
2949290000Sglebius
2950290000Sglebiusstatic void
2951290000Sglebiusapply_enable_disable(
2952290000Sglebius	attr_val_fifo *	fifo,
2953290000Sglebius	int		enable
2954290000Sglebius	)
2955290000Sglebius{
2956290000Sglebius	attr_val *curr_flag;
2957290000Sglebius	int option;
2958290000Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
2959290000Sglebius	bc_entry *pentry;
2960290000Sglebius#endif
2961290000Sglebius
2962290000Sglebius	for (curr_flag = HEAD_PFIFO(fifo);
2963290000Sglebius	     curr_flag != NULL;
2964290000Sglebius	     curr_flag = curr_flag->link) {
2965290000Sglebius
2966290000Sglebius		option = curr_flag->value.i;
2967290000Sglebius		switch (option) {
2968290000Sglebius
2969290000Sglebius		default:
2970290000Sglebius			msyslog(LOG_ERR,
2971290000Sglebius				"can not apply enable/disable token %d, unknown",
2972290000Sglebius				option);
2973290000Sglebius			break;
2974290000Sglebius
2975290000Sglebius		case T_Auth:
2976290000Sglebius			proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
2977290000Sglebius			break;
2978290000Sglebius
2979290000Sglebius		case T_Bclient:
2980290000Sglebius			proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
2981290000Sglebius			break;
2982290000Sglebius
2983290000Sglebius		case T_Calibrate:
2984290000Sglebius			proto_config(PROTO_CAL, enable, 0., NULL);
2985290000Sglebius			break;
2986290000Sglebius
2987290000Sglebius		case T_Kernel:
2988290000Sglebius			proto_config(PROTO_KERNEL, enable, 0., NULL);
2989290000Sglebius			break;
2990290000Sglebius
2991290000Sglebius		case T_Monitor:
2992290000Sglebius			proto_config(PROTO_MONITOR, enable, 0., NULL);
2993290000Sglebius			break;
2994290000Sglebius
2995301301Sdelphij		case T_Mode7:
2996301301Sdelphij			proto_config(PROTO_MODE7, enable, 0., NULL);
2997301301Sdelphij			break;
2998301301Sdelphij
2999290000Sglebius		case T_Ntp:
3000290000Sglebius			proto_config(PROTO_NTP, enable, 0., NULL);
3001290000Sglebius			break;
3002290000Sglebius
3003301301Sdelphij		case T_PCEdigest:
3004301301Sdelphij			proto_config(PROTO_PCEDIGEST, enable, 0., NULL);
3005290000Sglebius			break;
3006290000Sglebius
3007290000Sglebius		case T_Stats:
3008290000Sglebius			proto_config(PROTO_FILEGEN, enable, 0., NULL);
3009290000Sglebius			break;
3010290000Sglebius
3011294904Sdelphij		case T_UEcrypto:
3012294904Sdelphij			proto_config(PROTO_UECRYPTO, enable, 0., NULL);
3013294904Sdelphij			break;
3014294904Sdelphij
3015294904Sdelphij		case T_UEcryptonak:
3016294904Sdelphij			proto_config(PROTO_UECRYPTONAK, enable, 0., NULL);
3017294904Sdelphij			break;
3018294904Sdelphij
3019294904Sdelphij		case T_UEdigest:
3020294904Sdelphij			proto_config(PROTO_UEDIGEST, enable, 0., NULL);
3021294904Sdelphij			break;
3022294904Sdelphij
3023290000Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3024290000Sglebius		case T_Bc_bugXXXX:
3025290000Sglebius			pentry = bc_list;
3026290000Sglebius			while (pentry->token) {
3027290000Sglebius				if (pentry->token == option)
302854359Sroberto					break;
3029290000Sglebius				pentry++;
303054359Sroberto			}
3031290000Sglebius			if (!pentry->token) {
3032290000Sglebius				msyslog(LOG_ERR,
3033290000Sglebius					"compat token %d not in bc_list[]",
3034290000Sglebius					option);
3035290000Sglebius				continue;
3036290000Sglebius			}
3037290000Sglebius			pentry->enabled = enable;
303854359Sroberto			break;
3039290000Sglebius#endif
3040290000Sglebius		}
3041290000Sglebius	}
3042290000Sglebius}
304354359Sroberto
304454359Sroberto
3045290000Sglebiusstatic void
3046290000Sglebiusconfig_system_opts(
3047290000Sglebius	config_tree *ptree
3048290000Sglebius	)
3049290000Sglebius{
3050290000Sglebius	apply_enable_disable(ptree->enable_opts, 1);
3051290000Sglebius	apply_enable_disable(ptree->disable_opts, 0);
3052290000Sglebius}
3053290000Sglebius
3054290000Sglebius
3055290000Sglebius#ifdef FREE_CFG_T
3056290000Sglebiusstatic void
3057290000Sglebiusfree_config_system_opts(
3058290000Sglebius	config_tree *ptree
3059290000Sglebius	)
3060290000Sglebius{
3061290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->enable_opts);
3062290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->disable_opts);
3063290000Sglebius}
3064290000Sglebius#endif	/* FREE_CFG_T */
3065290000Sglebius
3066290000Sglebius
3067290000Sglebiusstatic void
3068290000Sglebiusconfig_logconfig(
3069290000Sglebius	config_tree *ptree
3070290000Sglebius	)
3071290000Sglebius{
3072290000Sglebius	attr_val *	my_lc;
3073290000Sglebius
3074290000Sglebius	my_lc = HEAD_PFIFO(ptree->logconfig);
3075290000Sglebius	for (; my_lc != NULL; my_lc = my_lc->link) {
3076290000Sglebius		switch (my_lc->attr) {
3077290000Sglebius
3078290000Sglebius		case '+':
3079290000Sglebius			ntp_syslogmask |= get_logmask(my_lc->value.s);
308054359Sroberto			break;
308154359Sroberto
3082290000Sglebius		case '-':
3083290000Sglebius			ntp_syslogmask &= ~get_logmask(my_lc->value.s);
3084290000Sglebius			break;
3085132451Sroberto
3086290000Sglebius		case '=':
3087290000Sglebius			ntp_syslogmask = get_logmask(my_lc->value.s);
3088132451Sroberto			break;
3089290000Sglebius		default:
3090290000Sglebius			INSIST(0);
3091290000Sglebius			break;
3092290000Sglebius		}
3093290000Sglebius	}
3094290000Sglebius}
3095132451Sroberto
309654359Sroberto
3097290000Sglebius#ifdef FREE_CFG_T
3098290000Sglebiusstatic void
3099290000Sglebiusfree_config_logconfig(
3100290000Sglebius	config_tree *ptree
3101290000Sglebius	)
3102290000Sglebius{
3103290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->logconfig);
3104290000Sglebius}
3105290000Sglebius#endif	/* FREE_CFG_T */
3106290000Sglebius
3107290000Sglebius
3108290000Sglebius#ifndef SIM
3109290000Sglebiusstatic void
3110290000Sglebiusconfig_phone(
3111290000Sglebius	config_tree *ptree
3112290000Sglebius	)
3113290000Sglebius{
3114290000Sglebius	size_t		i;
3115290000Sglebius	string_node *	sn;
3116290000Sglebius
3117290000Sglebius	i = 0;
3118290000Sglebius	sn = HEAD_PFIFO(ptree->phone);
3119290000Sglebius	for (; sn != NULL; sn = sn->link) {
3120290000Sglebius		/* need to leave array entry for NULL terminator */
3121290000Sglebius		if (i < COUNTOF(sys_phone) - 1) {
3122290000Sglebius			sys_phone[i++] = estrdup(sn->s);
3123290000Sglebius			sys_phone[i] = NULL;
3124290000Sglebius		} else {
3125290000Sglebius			msyslog(LOG_INFO,
3126290000Sglebius				"phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
3127290000Sglebius				(COUNTOF(sys_phone) - 1), sn->s);
3128290000Sglebius		}
3129290000Sglebius	}
3130290000Sglebius}
3131290000Sglebius#endif	/* !SIM */
3132290000Sglebius
3133290000Sglebiusstatic void
3134290000Sglebiusconfig_mdnstries(
3135290000Sglebius	config_tree *ptree
3136290000Sglebius	)
3137290000Sglebius{
3138290000Sglebius#ifdef HAVE_DNSREGISTRATION
3139290000Sglebius	extern int mdnstries;
3140290000Sglebius	mdnstries = ptree->mdnstries;
3141290000Sglebius#endif  /* HAVE_DNSREGISTRATION */
3142290000Sglebius}
3143290000Sglebius
3144290000Sglebius#ifdef FREE_CFG_T
3145290000Sglebiusstatic void
3146290000Sglebiusfree_config_phone(
3147290000Sglebius	config_tree *ptree
3148290000Sglebius	)
3149290000Sglebius{
3150290000Sglebius	FREE_STRING_FIFO(ptree->phone);
3151290000Sglebius}
3152290000Sglebius#endif	/* FREE_CFG_T */
3153290000Sglebius
3154290000Sglebius
3155290000Sglebius#ifndef SIM
3156290000Sglebiusstatic void
3157290000Sglebiusconfig_setvar(
3158290000Sglebius	config_tree *ptree
3159290000Sglebius	)
3160290000Sglebius{
3161290000Sglebius	setvar_node *my_node;
3162290000Sglebius	size_t	varlen, vallen, octets;
3163290000Sglebius	char *	str;
3164290000Sglebius
3165290000Sglebius	str = NULL;
3166290000Sglebius	my_node = HEAD_PFIFO(ptree->setvar);
3167290000Sglebius	for (; my_node != NULL; my_node = my_node->link) {
3168290000Sglebius		varlen = strlen(my_node->var);
3169290000Sglebius		vallen = strlen(my_node->val);
3170290000Sglebius		octets = varlen + vallen + 1 + 1;
3171290000Sglebius		str = erealloc(str, octets);
3172290000Sglebius		snprintf(str, octets, "%s=%s", my_node->var,
3173290000Sglebius			 my_node->val);
3174290000Sglebius		set_sys_var(str, octets, (my_node->isdefault)
3175290000Sglebius						? DEF
3176290000Sglebius						: 0);
3177290000Sglebius	}
3178290000Sglebius	if (str != NULL)
3179290000Sglebius		free(str);
3180290000Sglebius}
3181290000Sglebius#endif	/* !SIM */
3182290000Sglebius
3183290000Sglebius
3184290000Sglebius#ifdef FREE_CFG_T
3185290000Sglebiusstatic void
3186290000Sglebiusfree_config_setvar(
3187290000Sglebius	config_tree *ptree
3188290000Sglebius	)
3189290000Sglebius{
3190290000Sglebius	FREE_SETVAR_FIFO(ptree->setvar);
3191290000Sglebius}
3192290000Sglebius#endif	/* FREE_CFG_T */
3193290000Sglebius
3194290000Sglebius
3195290000Sglebius#ifndef SIM
3196290000Sglebiusstatic void
3197290000Sglebiusconfig_ttl(
3198290000Sglebius	config_tree *ptree
3199290000Sglebius	)
3200290000Sglebius{
3201290000Sglebius	size_t i = 0;
3202290000Sglebius	int_node *curr_ttl;
3203290000Sglebius
3204290000Sglebius	curr_ttl = HEAD_PFIFO(ptree->ttl);
3205290000Sglebius	for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
3206290000Sglebius		if (i < COUNTOF(sys_ttl))
3207290000Sglebius			sys_ttl[i++] = (u_char)curr_ttl->i;
3208290000Sglebius		else
3209290000Sglebius			msyslog(LOG_INFO,
3210290000Sglebius				"ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
3211290000Sglebius				COUNTOF(sys_ttl), curr_ttl->i);
3212290000Sglebius	}
3213290000Sglebius	sys_ttlmax = i - 1;
3214290000Sglebius}
3215290000Sglebius#endif	/* !SIM */
3216290000Sglebius
3217290000Sglebius
3218290000Sglebius#ifdef FREE_CFG_T
3219290000Sglebiusstatic void
3220290000Sglebiusfree_config_ttl(
3221290000Sglebius	config_tree *ptree
3222290000Sglebius	)
3223290000Sglebius{
3224290000Sglebius	FREE_INT_FIFO(ptree->ttl);
3225290000Sglebius}
3226290000Sglebius#endif	/* FREE_CFG_T */
3227290000Sglebius
3228290000Sglebius
3229290000Sglebius#ifndef SIM
3230290000Sglebiusstatic void
3231290000Sglebiusconfig_trap(
3232290000Sglebius	config_tree *ptree
3233290000Sglebius	)
3234290000Sglebius{
3235290000Sglebius	addr_opts_node *curr_trap;
3236290000Sglebius	attr_val *curr_opt;
3237290000Sglebius	sockaddr_u addr_sock;
3238290000Sglebius	sockaddr_u peeraddr;
3239290000Sglebius	struct interface *localaddr;
3240290000Sglebius	struct addrinfo hints;
3241290000Sglebius	char port_text[8];
3242290000Sglebius	settrap_parms *pstp;
3243290000Sglebius	u_short port;
3244290000Sglebius	int err_flag;
3245290000Sglebius	int rc;
3246290000Sglebius
3247290000Sglebius	/* silence warning about addr_sock potentially uninitialized */
3248290000Sglebius	AF(&addr_sock) = AF_UNSPEC;
3249290000Sglebius
3250290000Sglebius	curr_trap = HEAD_PFIFO(ptree->trap);
3251290000Sglebius	for (; curr_trap != NULL; curr_trap = curr_trap->link) {
3252290000Sglebius		err_flag = 0;
3253290000Sglebius		port = 0;
3254290000Sglebius		localaddr = NULL;
3255290000Sglebius
3256290000Sglebius		curr_opt = HEAD_PFIFO(curr_trap->options);
3257290000Sglebius		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3258290000Sglebius			if (T_Port == curr_opt->attr) {
3259290000Sglebius				if (curr_opt->value.i < 1
3260290000Sglebius				    || curr_opt->value.i > USHRT_MAX) {
326154359Sroberto					msyslog(LOG_ERR,
3262290000Sglebius						"invalid port number "
3263290000Sglebius						"%d, trap ignored",
3264290000Sglebius						curr_opt->value.i);
3265290000Sglebius					err_flag = 1;
326654359Sroberto				}
3267290000Sglebius				port = (u_short)curr_opt->value.i;
326854359Sroberto			}
3269290000Sglebius			else if (T_Interface == curr_opt->attr) {
3270290000Sglebius				/* Resolve the interface address */
3271290000Sglebius				ZERO_SOCK(&addr_sock);
3272290000Sglebius				if (getnetnum(curr_opt->value.s,
3273290000Sglebius					      &addr_sock, 1, t_UNK) != 1) {
3274290000Sglebius					err_flag = 1;
3275290000Sglebius					break;
3276290000Sglebius				}
327754359Sroberto
3278290000Sglebius				localaddr = findinterface(&addr_sock);
3279290000Sglebius
3280290000Sglebius				if (NULL == localaddr) {
328154359Sroberto					msyslog(LOG_ERR,
3282290000Sglebius						"can't find interface with address %s",
3283290000Sglebius						stoa(&addr_sock));
3284290000Sglebius					err_flag = 1;
328554359Sroberto				}
328654359Sroberto			}
3287290000Sglebius		}
328854359Sroberto
3289290000Sglebius		/* Now process the trap for the specified interface
3290290000Sglebius		 * and port number
3291290000Sglebius		 */
3292290000Sglebius		if (!err_flag) {
3293290000Sglebius			if (!port)
3294290000Sglebius				port = TRAPPORT;
3295290000Sglebius			ZERO_SOCK(&peeraddr);
3296290000Sglebius			rc = getnetnum(curr_trap->addr->address,
3297290000Sglebius				       &peeraddr, 1, t_UNK);
3298290000Sglebius			if (1 != rc) {
3299290000Sglebius#ifndef WORKER
3300290000Sglebius				msyslog(LOG_ERR,
3301290000Sglebius					"trap: unable to use IP address %s.",
3302290000Sglebius					curr_trap->addr->address);
3303290000Sglebius#else	/* WORKER follows */
3304290000Sglebius				/*
3305290000Sglebius				 * save context and hand it off
3306290000Sglebius				 * for name resolution.
3307290000Sglebius				 */
3308290000Sglebius				ZERO(hints);
3309290000Sglebius				hints.ai_protocol = IPPROTO_UDP;
3310290000Sglebius				hints.ai_socktype = SOCK_DGRAM;
3311290000Sglebius				snprintf(port_text, sizeof(port_text),
3312290000Sglebius					 "%u", port);
3313290000Sglebius				hints.ai_flags = Z_AI_NUMERICSERV;
3314290000Sglebius				pstp = emalloc_zero(sizeof(*pstp));
3315290000Sglebius				if (localaddr != NULL) {
3316290000Sglebius					hints.ai_family = localaddr->family;
3317290000Sglebius					pstp->ifaddr_nonnull = 1;
3318290000Sglebius					memcpy(&pstp->ifaddr,
3319290000Sglebius					       &localaddr->sin,
3320290000Sglebius					       sizeof(pstp->ifaddr));
3321290000Sglebius				}
3322290000Sglebius				rc = getaddrinfo_sometime(
3323290000Sglebius					curr_trap->addr->address,
3324290000Sglebius					port_text, &hints,
3325290000Sglebius					INITIAL_DNS_RETRY,
3326290000Sglebius					&trap_name_resolved,
3327290000Sglebius					pstp);
3328290000Sglebius				if (!rc)
332954359Sroberto					msyslog(LOG_ERR,
3330290000Sglebius						"config_trap: getaddrinfo_sometime(%s,%s): %m",
3331290000Sglebius						curr_trap->addr->address,
3332290000Sglebius						port_text);
3333290000Sglebius#endif	/* WORKER */
3334290000Sglebius				continue;
333554359Sroberto			}
3336290000Sglebius			/* port is at same location for v4 and v6 */
3337290000Sglebius			SET_PORT(&peeraddr, port);
333854359Sroberto
3339290000Sglebius			if (NULL == localaddr)
3340290000Sglebius				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3341290000Sglebius			else
3342290000Sglebius				AF(&peeraddr) = AF(&addr_sock);
3343290000Sglebius
3344290000Sglebius			if (!ctlsettrap(&peeraddr, localaddr, 0,
3345290000Sglebius					NTP_VERSION))
334654359Sroberto				msyslog(LOG_ERR,
3347290000Sglebius					"set trap %s -> %s failed.",
3348290000Sglebius					latoa(localaddr),
3349290000Sglebius					stoa(&peeraddr));
3350290000Sglebius		}
3351290000Sglebius	}
3352290000Sglebius}
3353290000Sglebius
3354290000Sglebius
3355290000Sglebius/*
3356290000Sglebius * trap_name_resolved()
3357290000Sglebius *
3358290000Sglebius * Callback invoked when config_trap()'s DNS lookup completes.
3359290000Sglebius */
3360290000Sglebius# ifdef WORKER
3361290000Sglebiusstatic void
3362290000Sglebiustrap_name_resolved(
3363290000Sglebius	int			rescode,
3364290000Sglebius	int			gai_errno,
3365290000Sglebius	void *			context,
3366290000Sglebius	const char *		name,
3367290000Sglebius	const char *		service,
3368290000Sglebius	const struct addrinfo *	hints,
3369290000Sglebius	const struct addrinfo *	res
3370290000Sglebius	)
3371290000Sglebius{
3372290000Sglebius	settrap_parms *pstp;
3373290000Sglebius	struct interface *localaddr;
3374290000Sglebius	sockaddr_u peeraddr;
3375290000Sglebius
3376290000Sglebius	(void)gai_errno;
3377290000Sglebius	(void)service;
3378290000Sglebius	(void)hints;
3379290000Sglebius	pstp = context;
3380290000Sglebius	if (rescode) {
3381290000Sglebius		msyslog(LOG_ERR,
3382290000Sglebius			"giving up resolving trap host %s: %s (%d)",
3383290000Sglebius			name, gai_strerror(rescode), rescode);
3384290000Sglebius		free(pstp);
3385290000Sglebius		return;
3386290000Sglebius	}
3387290000Sglebius	INSIST(sizeof(peeraddr) >= res->ai_addrlen);
3388290000Sglebius	ZERO(peeraddr);
3389290000Sglebius	memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3390290000Sglebius	localaddr = NULL;
3391290000Sglebius	if (pstp->ifaddr_nonnull)
3392290000Sglebius		localaddr = findinterface(&pstp->ifaddr);
3393290000Sglebius	if (NULL == localaddr)
3394290000Sglebius		localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3395290000Sglebius	if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
3396290000Sglebius		msyslog(LOG_ERR, "set trap %s -> %s failed.",
3397290000Sglebius			latoa(localaddr), stoa(&peeraddr));
3398290000Sglebius	free(pstp);
3399290000Sglebius}
3400290000Sglebius# endif	/* WORKER */
3401290000Sglebius#endif	/* !SIM */
3402290000Sglebius
3403290000Sglebius
3404290000Sglebius#ifdef FREE_CFG_T
3405290000Sglebiusstatic void
3406290000Sglebiusfree_config_trap(
3407290000Sglebius	config_tree *ptree
3408290000Sglebius	)
3409290000Sglebius{
3410290000Sglebius	FREE_ADDR_OPTS_FIFO(ptree->trap);
3411290000Sglebius}
3412290000Sglebius#endif	/* FREE_CFG_T */
3413290000Sglebius
3414290000Sglebius
3415290000Sglebius#ifndef SIM
3416290000Sglebiusstatic void
3417290000Sglebiusconfig_fudge(
3418290000Sglebius	config_tree *ptree
3419290000Sglebius	)
3420290000Sglebius{
3421290000Sglebius	addr_opts_node *curr_fudge;
3422290000Sglebius	attr_val *curr_opt;
3423290000Sglebius	sockaddr_u addr_sock;
3424290000Sglebius	address_node *addr_node;
3425290000Sglebius	struct refclockstat clock_stat;
3426290000Sglebius	int err_flag;
3427290000Sglebius
3428290000Sglebius	curr_fudge = HEAD_PFIFO(ptree->fudge);
3429290000Sglebius	for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
3430290000Sglebius		err_flag = 0;
3431290000Sglebius
3432290000Sglebius		/* Get the reference clock address and
3433290000Sglebius		 * ensure that it is sane
3434290000Sglebius		 */
3435290000Sglebius		addr_node = curr_fudge->addr;
3436290000Sglebius		ZERO_SOCK(&addr_sock);
3437290000Sglebius		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
3438290000Sglebius		    != 1) {
3439290000Sglebius			err_flag = 1;
3440290000Sglebius			msyslog(LOG_ERR,
3441290000Sglebius				"unrecognized fudge reference clock address %s, line ignored",
3442290000Sglebius				stoa(&addr_sock));
3443290000Sglebius		}
3444290000Sglebius
3445290000Sglebius		if (!ISREFCLOCKADR(&addr_sock)) {
3446290000Sglebius			err_flag = 1;
3447290000Sglebius			msyslog(LOG_ERR,
3448290000Sglebius				"inappropriate address %s for the fudge command, line ignored",
3449290000Sglebius				stoa(&addr_sock));
3450290000Sglebius		}
3451290000Sglebius
3452290000Sglebius		/* Parse all the options to the fudge command */
3453290000Sglebius		ZERO(clock_stat);
3454290000Sglebius		curr_opt = HEAD_PFIFO(curr_fudge->options);
3455290000Sglebius		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3456290000Sglebius			switch (curr_opt->attr) {
3457290000Sglebius
3458290000Sglebius			case T_Time1:
3459290000Sglebius				clock_stat.haveflags |= CLK_HAVETIME1;
3460290000Sglebius				clock_stat.fudgetime1 = curr_opt->value.d;
346154359Sroberto				break;
3462290000Sglebius
3463290000Sglebius			case T_Time2:
3464290000Sglebius				clock_stat.haveflags |= CLK_HAVETIME2;
3465290000Sglebius				clock_stat.fudgetime2 = curr_opt->value.d;
3466132451Sroberto				break;
3467290000Sglebius
3468290000Sglebius			case T_Stratum:
3469290000Sglebius				clock_stat.haveflags |= CLK_HAVEVAL1;
3470290000Sglebius				clock_stat.fudgeval1 = curr_opt->value.i;
3471132451Sroberto				break;
3472290000Sglebius
3473290000Sglebius			case T_Refid:
3474290000Sglebius				clock_stat.haveflags |= CLK_HAVEVAL2;
3475290000Sglebius				clock_stat.fudgeval2 = 0;
3476290000Sglebius				memcpy(&clock_stat.fudgeval2,
3477290000Sglebius				       curr_opt->value.s,
3478290000Sglebius				       min(strlen(curr_opt->value.s), 4));
3479290000Sglebius				break;
3480290000Sglebius
3481290000Sglebius			case T_Flag1:
3482290000Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG1;
3483290000Sglebius				if (curr_opt->value.i)
3484290000Sglebius					clock_stat.flags |= CLK_FLAG1;
3485290000Sglebius				else
3486290000Sglebius					clock_stat.flags &= ~CLK_FLAG1;
3487290000Sglebius				break;
3488290000Sglebius
3489290000Sglebius			case T_Flag2:
3490290000Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG2;
3491290000Sglebius				if (curr_opt->value.i)
3492290000Sglebius					clock_stat.flags |= CLK_FLAG2;
3493290000Sglebius				else
3494290000Sglebius					clock_stat.flags &= ~CLK_FLAG2;
3495290000Sglebius				break;
3496290000Sglebius
3497290000Sglebius			case T_Flag3:
3498290000Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG3;
3499290000Sglebius				if (curr_opt->value.i)
3500290000Sglebius					clock_stat.flags |= CLK_FLAG3;
3501290000Sglebius				else
3502290000Sglebius					clock_stat.flags &= ~CLK_FLAG3;
3503290000Sglebius				break;
3504290000Sglebius
3505290000Sglebius			case T_Flag4:
3506290000Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG4;
3507290000Sglebius				if (curr_opt->value.i)
3508290000Sglebius					clock_stat.flags |= CLK_FLAG4;
3509290000Sglebius				else
3510290000Sglebius					clock_stat.flags &= ~CLK_FLAG4;
3511290000Sglebius				break;
3512290000Sglebius
3513290000Sglebius			default:
3514290000Sglebius				msyslog(LOG_ERR,
3515290000Sglebius					"Unexpected fudge flag %s (%d) for %s",
3516290000Sglebius					token_name(curr_opt->attr),
3517290000Sglebius					curr_opt->attr, stoa(&addr_sock));
3518290000Sglebius				exit(curr_opt->attr ? curr_opt->attr : 1);
3519132451Sroberto			}
3520290000Sglebius		}
3521290000Sglebius# ifdef REFCLOCK
3522290000Sglebius		if (!err_flag)
3523290000Sglebius			refclock_control(&addr_sock, &clock_stat, NULL);
3524290000Sglebius# endif
3525290000Sglebius	}
3526290000Sglebius}
3527290000Sglebius#endif	/* !SIM */
3528132451Sroberto
352954359Sroberto
3530290000Sglebius#ifdef FREE_CFG_T
3531290000Sglebiusstatic void
3532290000Sglebiusfree_config_fudge(
3533290000Sglebius	config_tree *ptree
3534290000Sglebius	)
3535290000Sglebius{
3536290000Sglebius	FREE_ADDR_OPTS_FIFO(ptree->fudge);
3537290000Sglebius}
3538290000Sglebius#endif	/* FREE_CFG_T */
353954359Sroberto
354054359Sroberto
3541290000Sglebiusstatic void
3542290000Sglebiusconfig_vars(
3543290000Sglebius	config_tree *ptree
3544290000Sglebius	)
3545290000Sglebius{
3546290000Sglebius	attr_val *curr_var;
3547290000Sglebius	int len;
354854359Sroberto
3549290000Sglebius	curr_var = HEAD_PFIFO(ptree->vars);
3550290000Sglebius	for (; curr_var != NULL; curr_var = curr_var->link) {
3551290000Sglebius		/* Determine which variable to set and set it */
3552290000Sglebius		switch (curr_var->attr) {
355354359Sroberto
3554290000Sglebius		case T_Broadcastdelay:
3555290000Sglebius			proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
3556290000Sglebius			break;
355754359Sroberto
3558290000Sglebius		case T_Tick:
3559290000Sglebius			loop_config(LOOP_TICK, curr_var->value.d);
356054359Sroberto			break;
356154359Sroberto
3562290000Sglebius		case T_Driftfile:
3563290000Sglebius			if ('\0' == curr_var->value.s[0]) {
3564290000Sglebius				stats_drift_file = 0;
3565290000Sglebius				msyslog(LOG_INFO, "config: driftfile disabled");
3566290000Sglebius			} else
3567290000Sglebius				stats_config(STATS_FREQ_FILE, curr_var->value.s);
3568290000Sglebius			break;
356954359Sroberto
3570290000Sglebius		case T_Dscp:
3571290000Sglebius			/* DSCP is in the upper 6 bits of the IP TOS/DS field */
3572290000Sglebius			qos = curr_var->value.i << 2;
3573290000Sglebius			break;
357454359Sroberto
3575290000Sglebius		case T_Ident:
3576290000Sglebius			sys_ident = curr_var->value.s;
3577290000Sglebius			break;
357854359Sroberto
3579290000Sglebius		case T_WanderThreshold:		/* FALLTHROUGH */
3580290000Sglebius		case T_Nonvolatile:
3581290000Sglebius			wander_threshold = curr_var->value.d;
3582290000Sglebius			break;
358354359Sroberto
3584290000Sglebius		case T_Leapfile:
3585290000Sglebius			stats_config(STATS_LEAP_FILE, curr_var->value.s);
3586290000Sglebius			break;
358754359Sroberto
3588290000Sglebius#ifdef LEAP_SMEAR
3589290000Sglebius		case T_Leapsmearinterval:
3590290000Sglebius			leap_smear_intv = curr_var->value.i;
3591290000Sglebius			msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
3592290000Sglebius			break;
3593290000Sglebius#endif
359454359Sroberto
3595290000Sglebius		case T_Pidfile:
3596290000Sglebius			stats_config(STATS_PID_FILE, curr_var->value.s);
3597290000Sglebius			break;
359854359Sroberto
3599290000Sglebius		case T_Logfile:
3600290000Sglebius			if (-1 == change_logfile(curr_var->value.s, TRUE))
3601290000Sglebius				msyslog(LOG_ERR,
3602290000Sglebius					"Cannot open logfile %s: %m",
3603290000Sglebius					curr_var->value.s);
3604290000Sglebius			break;
360554359Sroberto
3606290000Sglebius		case T_Saveconfigdir:
3607290000Sglebius			if (saveconfigdir != NULL)
3608290000Sglebius				free(saveconfigdir);
3609290000Sglebius			len = strlen(curr_var->value.s);
3610290000Sglebius			if (0 == len) {
3611290000Sglebius				saveconfigdir = NULL;
3612290000Sglebius			} else if (DIR_SEP != curr_var->value.s[len - 1]
3613290000Sglebius#ifdef SYS_WINNT	/* slash is also a dir. sep. on Windows */
3614290000Sglebius				   && '/' != curr_var->value.s[len - 1]
3615290000Sglebius#endif
3616290000Sglebius				 ) {
3617290000Sglebius					len++;
3618290000Sglebius					saveconfigdir = emalloc(len + 1);
3619290000Sglebius					snprintf(saveconfigdir, len + 1,
3620290000Sglebius						 "%s%c",
3621290000Sglebius						 curr_var->value.s,
3622290000Sglebius						 DIR_SEP);
3623290000Sglebius			} else {
3624290000Sglebius					saveconfigdir = estrdup(
3625290000Sglebius					    curr_var->value.s);
362654359Sroberto			}
3627290000Sglebius			break;
362854359Sroberto
3629290000Sglebius		case T_Automax:
3630290000Sglebius#ifdef AUTOKEY
3631290000Sglebius			sys_automax = curr_var->value.i;
363254359Sroberto#endif
363354359Sroberto			break;
363454359Sroberto
3635290000Sglebius		default:
3636290000Sglebius			msyslog(LOG_ERR,
3637290000Sglebius				"config_vars(): unexpected token %d",
3638290000Sglebius				curr_var->attr);
3639290000Sglebius		}
3640290000Sglebius	}
3641290000Sglebius}
3642290000Sglebius
3643290000Sglebius
3644290000Sglebius#ifdef FREE_CFG_T
3645290000Sglebiusstatic void
3646290000Sglebiusfree_config_vars(
3647290000Sglebius	config_tree *ptree
3648290000Sglebius	)
3649290000Sglebius{
3650290000Sglebius	FREE_ATTR_VAL_FIFO(ptree->vars);
3651290000Sglebius}
3652290000Sglebius#endif	/* FREE_CFG_T */
3653290000Sglebius
3654290000Sglebius
3655290000Sglebius/* Define a function to check if a resolved address is sane.
3656290000Sglebius * If yes, return 1, else return 0;
3657290000Sglebius */
3658290000Sglebiusstatic int
3659290000Sglebiusis_sane_resolved_address(
3660290000Sglebius	sockaddr_u *	peeraddr,
3661290000Sglebius	int		hmode
3662290000Sglebius	)
3663290000Sglebius{
3664290000Sglebius	if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
3665290000Sglebius		msyslog(LOG_ERR,
3666290000Sglebius			"attempt to configure invalid address %s",
3667290000Sglebius			stoa(peeraddr));
3668290000Sglebius		return 0;
3669290000Sglebius	}
3670290000Sglebius	/*
3671290000Sglebius	 * Shouldn't be able to specify multicast
3672290000Sglebius	 * address for server/peer!
3673290000Sglebius	 * and unicast address for manycastclient!
3674290000Sglebius	 */
3675290000Sglebius	if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
3676290000Sglebius	    && IS_MCAST(peeraddr)) {
3677290000Sglebius		msyslog(LOG_ERR,
3678290000Sglebius			"attempt to configure invalid address %s",
3679290000Sglebius			stoa(peeraddr));
3680290000Sglebius		return 0;
3681290000Sglebius	}
3682290000Sglebius	if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
3683290000Sglebius		msyslog(LOG_ERR,
3684290000Sglebius			"attempt to configure invalid address %s",
3685290000Sglebius			stoa(peeraddr));
3686290000Sglebius		return 0;
3687290000Sglebius	}
3688290000Sglebius
3689290000Sglebius	if (IS_IPV6(peeraddr) && !ipv6_works)
3690290000Sglebius		return 0;
3691290000Sglebius
3692290000Sglebius	/* Ok, all tests succeeded, now we can return 1 */
3693290000Sglebius	return 1;
3694290000Sglebius}
3695290000Sglebius
3696290000Sglebius
3697290000Sglebius#ifndef SIM
3698290000Sglebiusstatic u_char
3699290000Sglebiusget_correct_host_mode(
3700290000Sglebius	int token
3701290000Sglebius	)
3702290000Sglebius{
3703290000Sglebius	switch (token) {
3704290000Sglebius
3705290000Sglebius	case T_Server:
3706290000Sglebius	case T_Pool:
3707290000Sglebius	case T_Manycastclient:
3708290000Sglebius		return MODE_CLIENT;
3709290000Sglebius
3710290000Sglebius	case T_Peer:
3711290000Sglebius		return MODE_ACTIVE;
3712290000Sglebius
3713290000Sglebius	case T_Broadcast:
3714290000Sglebius		return MODE_BROADCAST;
3715290000Sglebius
3716290000Sglebius	default:
3717290000Sglebius		return 0;
3718290000Sglebius	}
3719290000Sglebius}
3720290000Sglebius
3721290000Sglebius
3722290000Sglebius/*
3723290000Sglebius * peerflag_bits()	get config_peers() peerflags value from a
3724290000Sglebius *			peer_node's queue of flag attr_val entries.
3725290000Sglebius */
3726290000Sglebiusstatic int
3727290000Sglebiuspeerflag_bits(
3728290000Sglebius	peer_node *pn
3729290000Sglebius	)
3730290000Sglebius{
3731290000Sglebius	int peerflags;
3732290000Sglebius	attr_val *option;
3733290000Sglebius
3734290000Sglebius	/* translate peerflags options to bits */
3735290000Sglebius	peerflags = 0;
3736290000Sglebius	option = HEAD_PFIFO(pn->peerflags);
3737290000Sglebius	for (; option != NULL; option = option->link) {
3738290000Sglebius		switch (option->value.i) {
3739290000Sglebius
3740290000Sglebius		default:
3741290000Sglebius			INSIST(0);
374254359Sroberto			break;
374354359Sroberto
3744290000Sglebius		case T_Autokey:
3745290000Sglebius			peerflags |= FLAG_SKEY;
3746290000Sglebius			break;
374754359Sroberto
3748290000Sglebius		case T_Burst:
3749290000Sglebius			peerflags |= FLAG_BURST;
3750290000Sglebius			break;
3751290000Sglebius
3752290000Sglebius		case T_Iburst:
3753290000Sglebius			peerflags |= FLAG_IBURST;
3754290000Sglebius			break;
3755290000Sglebius
3756290000Sglebius		case T_Noselect:
3757290000Sglebius			peerflags |= FLAG_NOSELECT;
3758290000Sglebius			break;
3759290000Sglebius
3760290000Sglebius		case T_Preempt:
3761290000Sglebius			peerflags |= FLAG_PREEMPT;
3762290000Sglebius			break;
3763290000Sglebius
3764290000Sglebius		case T_Prefer:
3765290000Sglebius			peerflags |= FLAG_PREFER;
3766290000Sglebius			break;
3767290000Sglebius
3768290000Sglebius		case T_True:
3769290000Sglebius			peerflags |= FLAG_TRUE;
3770290000Sglebius			break;
3771290000Sglebius
3772290000Sglebius		case T_Xleave:
3773290000Sglebius			peerflags |= FLAG_XLEAVE;
3774290000Sglebius			break;
3775290000Sglebius		}
3776290000Sglebius	}
3777290000Sglebius
3778290000Sglebius	return peerflags;
3779290000Sglebius}
3780290000Sglebius
3781290000Sglebius
3782290000Sglebiusstatic void
3783290000Sglebiusconfig_peers(
3784290000Sglebius	config_tree *ptree
3785290000Sglebius	)
3786290000Sglebius{
3787290000Sglebius	sockaddr_u		peeraddr;
3788290000Sglebius	struct addrinfo		hints;
3789290000Sglebius	peer_node *		curr_peer;
3790290000Sglebius	peer_resolved_ctx *	ctx;
3791290000Sglebius	u_char			hmode;
3792290000Sglebius
3793290000Sglebius	/* add servers named on the command line with iburst implied */
3794290000Sglebius	for (;
3795290000Sglebius	     cmdline_server_count > 0;
3796290000Sglebius	     cmdline_server_count--, cmdline_servers++) {
3797290000Sglebius
3798290000Sglebius		ZERO_SOCK(&peeraddr);
3799290000Sglebius		/*
3800290000Sglebius		 * If we have a numeric address, we can safely
3801290000Sglebius		 * proceed in the mainline with it.  Otherwise, hand
3802290000Sglebius		 * the hostname off to the blocking child.
3803290000Sglebius		 */
3804290000Sglebius		if (is_ip_address(*cmdline_servers, AF_UNSPEC,
3805290000Sglebius				  &peeraddr)) {
3806290000Sglebius
3807290000Sglebius			SET_PORT(&peeraddr, NTP_PORT);
3808290000Sglebius			if (is_sane_resolved_address(&peeraddr,
3809290000Sglebius						     T_Server))
3810290000Sglebius				peer_config(
3811290000Sglebius					&peeraddr,
3812290000Sglebius					NULL,
3813290000Sglebius					NULL,
3814290000Sglebius					MODE_CLIENT,
3815290000Sglebius					NTP_VERSION,
3816290000Sglebius					0,
3817290000Sglebius					0,
3818290000Sglebius					FLAG_IBURST,
3819290000Sglebius					0,
3820290000Sglebius					0,
3821290000Sglebius					NULL);
3822290000Sglebius		} else {
3823290000Sglebius			/* we have a hostname to resolve */
3824290000Sglebius# ifdef WORKER
3825290000Sglebius			ctx = emalloc_zero(sizeof(*ctx));
3826290000Sglebius			ctx->family = AF_UNSPEC;
3827290000Sglebius			ctx->host_mode = T_Server;
3828290000Sglebius			ctx->hmode = MODE_CLIENT;
3829290000Sglebius			ctx->version = NTP_VERSION;
3830290000Sglebius			ctx->flags = FLAG_IBURST;
3831290000Sglebius
3832290000Sglebius			ZERO(hints);
3833290000Sglebius			hints.ai_family = (u_short)ctx->family;
3834290000Sglebius			hints.ai_socktype = SOCK_DGRAM;
3835290000Sglebius			hints.ai_protocol = IPPROTO_UDP;
3836290000Sglebius
3837310419Sdelphij			getaddrinfo_sometime_ex(*cmdline_servers,
3838290000Sglebius					     "ntp", &hints,
3839290000Sglebius					     INITIAL_DNS_RETRY,
3840290000Sglebius					     &peer_name_resolved,
3841310419Sdelphij					     (void *)ctx, DNSFLAGS);
3842290000Sglebius# else	/* !WORKER follows */
3843290000Sglebius			msyslog(LOG_ERR,
3844290000Sglebius				"hostname %s can not be used, please use IP address instead.",
3845290000Sglebius				curr_peer->addr->address);
3846290000Sglebius# endif
3847290000Sglebius		}
3848290000Sglebius	}
3849290000Sglebius
3850290000Sglebius	/* add associations from the configuration file */
3851290000Sglebius	curr_peer = HEAD_PFIFO(ptree->peers);
3852290000Sglebius	for (; curr_peer != NULL; curr_peer = curr_peer->link) {
3853290000Sglebius		ZERO_SOCK(&peeraddr);
3854290000Sglebius		/* Find the correct host-mode */
3855290000Sglebius		hmode = get_correct_host_mode(curr_peer->host_mode);
3856290000Sglebius		INSIST(hmode != 0);
3857290000Sglebius
3858290000Sglebius		if (T_Pool == curr_peer->host_mode) {
3859290000Sglebius			AF(&peeraddr) = curr_peer->addr->type;
3860290000Sglebius			peer_config(
3861290000Sglebius				&peeraddr,
3862290000Sglebius				curr_peer->addr->address,
3863290000Sglebius				NULL,
3864290000Sglebius				hmode,
3865290000Sglebius				curr_peer->peerversion,
3866290000Sglebius				curr_peer->minpoll,
3867290000Sglebius				curr_peer->maxpoll,
3868290000Sglebius				peerflag_bits(curr_peer),
3869290000Sglebius				curr_peer->ttl,
3870290000Sglebius				curr_peer->peerkey,
3871290000Sglebius				curr_peer->group);
3872290000Sglebius		/*
3873290000Sglebius		 * If we have a numeric address, we can safely
3874290000Sglebius		 * proceed in the mainline with it.  Otherwise, hand
3875290000Sglebius		 * the hostname off to the blocking child.
3876290000Sglebius		 */
3877290000Sglebius		} else if (is_ip_address(curr_peer->addr->address,
3878290000Sglebius				  curr_peer->addr->type, &peeraddr)) {
3879290000Sglebius
3880290000Sglebius			SET_PORT(&peeraddr, NTP_PORT);
3881290000Sglebius			if (is_sane_resolved_address(&peeraddr,
3882290000Sglebius			    curr_peer->host_mode))
3883290000Sglebius				peer_config(
3884290000Sglebius					&peeraddr,
3885290000Sglebius					NULL,
3886290000Sglebius					NULL,
3887290000Sglebius					hmode,
3888290000Sglebius					curr_peer->peerversion,
3889290000Sglebius					curr_peer->minpoll,
3890290000Sglebius					curr_peer->maxpoll,
3891290000Sglebius					peerflag_bits(curr_peer),
3892290000Sglebius					curr_peer->ttl,
3893290000Sglebius					curr_peer->peerkey,
3894290000Sglebius					curr_peer->group);
3895290000Sglebius		} else {
3896290000Sglebius			/* we have a hostname to resolve */
3897290000Sglebius# ifdef WORKER
3898290000Sglebius			ctx = emalloc_zero(sizeof(*ctx));
3899290000Sglebius			ctx->family = curr_peer->addr->type;
3900290000Sglebius			ctx->host_mode = curr_peer->host_mode;
3901290000Sglebius			ctx->hmode = hmode;
3902290000Sglebius			ctx->version = curr_peer->peerversion;
3903290000Sglebius			ctx->minpoll = curr_peer->minpoll;
3904290000Sglebius			ctx->maxpoll = curr_peer->maxpoll;
3905290000Sglebius			ctx->flags = peerflag_bits(curr_peer);
3906290000Sglebius			ctx->ttl = curr_peer->ttl;
3907290000Sglebius			ctx->keyid = curr_peer->peerkey;
3908290000Sglebius			ctx->group = curr_peer->group;
3909290000Sglebius
3910290000Sglebius			ZERO(hints);
3911290000Sglebius			hints.ai_family = ctx->family;
3912290000Sglebius			hints.ai_socktype = SOCK_DGRAM;
3913290000Sglebius			hints.ai_protocol = IPPROTO_UDP;
3914290000Sglebius
3915310419Sdelphij			getaddrinfo_sometime_ex(curr_peer->addr->address,
3916290000Sglebius					     "ntp", &hints,
3917290000Sglebius					     INITIAL_DNS_RETRY,
3918310419Sdelphij					     &peer_name_resolved, ctx,
3919310419Sdelphij					     DNSFLAGS);
3920290000Sglebius# else	/* !WORKER follows */
3921290000Sglebius			msyslog(LOG_ERR,
3922290000Sglebius				"hostname %s can not be used, please use IP address instead.",
3923290000Sglebius				curr_peer->addr->address);
3924290000Sglebius# endif
3925290000Sglebius		}
3926290000Sglebius	}
3927290000Sglebius}
3928290000Sglebius#endif	/* !SIM */
3929290000Sglebius
3930290000Sglebius/*
3931290000Sglebius * peer_name_resolved()
3932290000Sglebius *
3933290000Sglebius * Callback invoked when config_peers()'s DNS lookup completes.
3934290000Sglebius */
3935290000Sglebius#ifdef WORKER
3936290000Sglebiusstatic void
3937290000Sglebiuspeer_name_resolved(
3938290000Sglebius	int			rescode,
3939290000Sglebius	int			gai_errno,
3940290000Sglebius	void *			context,
3941290000Sglebius	const char *		name,
3942290000Sglebius	const char *		service,
3943290000Sglebius	const struct addrinfo *	hints,
3944290000Sglebius	const struct addrinfo *	res
3945290000Sglebius	)
3946290000Sglebius{
3947290000Sglebius	sockaddr_u		peeraddr;
3948290000Sglebius	peer_resolved_ctx *	ctx;
3949290000Sglebius	u_short			af;
3950290000Sglebius	const char *		fam_spec;
3951290000Sglebius
3952290000Sglebius	(void)gai_errno;
3953290000Sglebius	(void)service;
3954290000Sglebius	(void)hints;
3955290000Sglebius	ctx = context;
3956290000Sglebius
3957290000Sglebius	DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
3958290000Sglebius
3959290000Sglebius	if (rescode) {
3960290000Sglebius		free(ctx);
3961290000Sglebius		msyslog(LOG_ERR,
3962290000Sglebius			"giving up resolving host %s: %s (%d)",
3963290000Sglebius			name, gai_strerror(rescode), rescode);
3964290000Sglebius		return;
3965290000Sglebius	}
3966290000Sglebius
3967290000Sglebius	/* Loop to configure a single association */
3968290000Sglebius	for (; res != NULL; res = res->ai_next) {
3969290000Sglebius		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3970290000Sglebius		if (is_sane_resolved_address(&peeraddr,
3971290000Sglebius					     ctx->host_mode)) {
3972290000Sglebius			NLOG(NLOG_SYSINFO) {
3973290000Sglebius				af = ctx->family;
3974290000Sglebius				fam_spec = (AF_INET6 == af)
3975290000Sglebius					       ? "(AAAA) "
3976290000Sglebius					       : (AF_INET == af)
3977290000Sglebius						     ? "(A) "
3978290000Sglebius						     : "";
3979290000Sglebius				msyslog(LOG_INFO, "DNS %s %s-> %s",
3980290000Sglebius					name, fam_spec,
3981290000Sglebius					stoa(&peeraddr));
398254359Sroberto			}
3983290000Sglebius			peer_config(
3984290000Sglebius				&peeraddr,
3985290000Sglebius				NULL,
3986290000Sglebius				NULL,
3987290000Sglebius				ctx->hmode,
3988290000Sglebius				ctx->version,
3989290000Sglebius				ctx->minpoll,
3990290000Sglebius				ctx->maxpoll,
3991290000Sglebius				ctx->flags,
3992290000Sglebius				ctx->ttl,
3993290000Sglebius				ctx->keyid,
3994290000Sglebius				ctx->group);
399554359Sroberto			break;
3996290000Sglebius		}
3997290000Sglebius	}
3998290000Sglebius	free(ctx);
3999290000Sglebius}
4000290000Sglebius#endif	/* WORKER */
400154359Sroberto
4002290000Sglebius
4003290000Sglebius#ifdef FREE_CFG_T
4004290000Sglebiusstatic void
4005290000Sglebiusfree_config_peers(
4006290000Sglebius	config_tree *ptree
4007290000Sglebius	)
4008290000Sglebius{
4009290000Sglebius	peer_node *curr_peer;
4010290000Sglebius
4011290000Sglebius	if (ptree->peers != NULL) {
4012290000Sglebius		for (;;) {
4013290000Sglebius			UNLINK_FIFO(curr_peer, *ptree->peers, link);
4014290000Sglebius			if (NULL == curr_peer)
401554359Sroberto				break;
4016290000Sglebius			destroy_address_node(curr_peer->addr);
4017290000Sglebius			destroy_attr_val_fifo(curr_peer->peerflags);
4018290000Sglebius			free(curr_peer);
4019290000Sglebius		}
4020290000Sglebius		free(ptree->peers);
4021290000Sglebius		ptree->peers = NULL;
4022290000Sglebius	}
4023290000Sglebius}
4024290000Sglebius#endif	/* FREE_CFG_T */
4025290000Sglebius
4026290000Sglebius
4027290000Sglebius#ifndef SIM
4028290000Sglebiusstatic void
4029290000Sglebiusconfig_unpeers(
4030290000Sglebius	config_tree *ptree
4031290000Sglebius	)
4032290000Sglebius{
4033290000Sglebius	sockaddr_u		peeraddr;
4034290000Sglebius	struct addrinfo		hints;
4035290000Sglebius	unpeer_node *		curr_unpeer;
4036290000Sglebius	struct peer *		p;
4037290000Sglebius	const char *		name;
4038290000Sglebius	int			rc;
4039290000Sglebius
4040290000Sglebius	curr_unpeer = HEAD_PFIFO(ptree->unpeers);
4041290000Sglebius	for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
4042290000Sglebius		/*
4043290000Sglebius		 * Either AssocID will be zero, and we unpeer by name/
4044290000Sglebius		 * address addr, or it is nonzero and addr NULL.
4045290000Sglebius		 */
4046290000Sglebius		if (curr_unpeer->assocID) {
4047290000Sglebius			p = findpeerbyassoc(curr_unpeer->assocID);
4048290000Sglebius			if (p != NULL) {
4049290000Sglebius				msyslog(LOG_NOTICE, "unpeered %s",
4050290000Sglebius					stoa(&p->srcadr));
4051290000Sglebius				peer_clear(p, "GONE");
4052290000Sglebius				unpeer(p);
405354359Sroberto			}
405454359Sroberto
4055290000Sglebius			continue;
4056290000Sglebius		}
4057290000Sglebius
4058290000Sglebius		ZERO(peeraddr);
4059290000Sglebius		AF(&peeraddr) = curr_unpeer->addr->type;
4060290000Sglebius		name = curr_unpeer->addr->address;
4061290000Sglebius		rc = getnetnum(name, &peeraddr, 0, t_UNK);
4062290000Sglebius		/* Do we have a numeric address? */
4063290000Sglebius		if (rc > 0) {
4064290000Sglebius			DPRINTF(1, ("unpeer: searching for %s\n",
4065290000Sglebius				    stoa(&peeraddr)));
4066290000Sglebius			p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
4067290000Sglebius			if (p != NULL) {
4068290000Sglebius				msyslog(LOG_NOTICE, "unpeered %s",
4069290000Sglebius					stoa(&peeraddr));
4070290000Sglebius				peer_clear(p, "GONE");
4071290000Sglebius				unpeer(p);
407254359Sroberto			}
407354359Sroberto
4074290000Sglebius			continue;
4075290000Sglebius		}
4076290000Sglebius		/*
4077290000Sglebius		 * It's not a numeric IP address, it's a hostname.
4078290000Sglebius		 * Check for associations with a matching hostname.
4079290000Sglebius		 */
4080290000Sglebius		for (p = peer_list; p != NULL; p = p->p_link)
4081290000Sglebius			if (p->hostname != NULL)
4082290000Sglebius				if (!strcasecmp(p->hostname, name))
408354359Sroberto					break;
4084290000Sglebius		if (p != NULL) {
4085290000Sglebius			msyslog(LOG_NOTICE, "unpeered %s", name);
4086290000Sglebius			peer_clear(p, "GONE");
4087290000Sglebius			unpeer(p);
4088290000Sglebius		}
4089290000Sglebius		/* Resolve the hostname to address(es). */
4090290000Sglebius# ifdef WORKER
4091290000Sglebius		ZERO(hints);
4092290000Sglebius		hints.ai_family = curr_unpeer->addr->type;
4093290000Sglebius		hints.ai_socktype = SOCK_DGRAM;
4094290000Sglebius		hints.ai_protocol = IPPROTO_UDP;
4095290000Sglebius		getaddrinfo_sometime(name, "ntp", &hints,
4096290000Sglebius				     INITIAL_DNS_RETRY,
4097290000Sglebius				     &unpeer_name_resolved, NULL);
4098290000Sglebius# else	/* !WORKER follows */
4099290000Sglebius		msyslog(LOG_ERR,
4100290000Sglebius			"hostname %s can not be used, please use IP address instead.",
4101290000Sglebius			name);
4102290000Sglebius# endif
4103290000Sglebius	}
4104290000Sglebius}
4105290000Sglebius#endif	/* !SIM */
410654359Sroberto
410754359Sroberto
4108290000Sglebius/*
4109290000Sglebius * unpeer_name_resolved()
4110290000Sglebius *
4111290000Sglebius * Callback invoked when config_unpeers()'s DNS lookup completes.
4112290000Sglebius */
4113290000Sglebius#ifdef WORKER
4114290000Sglebiusstatic void
4115290000Sglebiusunpeer_name_resolved(
4116290000Sglebius	int			rescode,
4117290000Sglebius	int			gai_errno,
4118290000Sglebius	void *			context,
4119290000Sglebius	const char *		name,
4120290000Sglebius	const char *		service,
4121290000Sglebius	const struct addrinfo *	hints,
4122290000Sglebius	const struct addrinfo *	res
4123290000Sglebius	)
4124290000Sglebius{
4125290000Sglebius	sockaddr_u	peeraddr;
4126290000Sglebius	struct peer *	peer;
4127290000Sglebius	u_short		af;
4128290000Sglebius	const char *	fam_spec;
412954359Sroberto
4130290000Sglebius	(void)context;
4131290000Sglebius	(void)hints;
4132290000Sglebius	DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
413354359Sroberto
4134290000Sglebius	if (rescode) {
4135290000Sglebius		msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
4136290000Sglebius			name, gai_strerror(rescode), rescode);
4137290000Sglebius		return;
4138290000Sglebius	}
4139290000Sglebius	/*
4140290000Sglebius	 * Loop through the addresses found
4141290000Sglebius	 */
4142290000Sglebius	for (; res != NULL; res = res->ai_next) {
4143290000Sglebius		INSIST(res->ai_addrlen <= sizeof(peeraddr));
4144290000Sglebius		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4145290000Sglebius		DPRINTF(1, ("unpeer: searching for peer %s\n",
4146290000Sglebius			    stoa(&peeraddr)));
4147290000Sglebius		peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
4148290000Sglebius		if (peer != NULL) {
4149290000Sglebius			af = AF(&peeraddr);
4150290000Sglebius			fam_spec = (AF_INET6 == af)
4151290000Sglebius				       ? "(AAAA) "
4152290000Sglebius				       : (AF_INET == af)
4153290000Sglebius					     ? "(A) "
4154290000Sglebius					     : "";
4155290000Sglebius			msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
4156290000Sglebius				fam_spec, stoa(&peeraddr));
4157290000Sglebius			peer_clear(peer, "GONE");
4158290000Sglebius			unpeer(peer);
4159290000Sglebius		}
4160290000Sglebius	}
4161290000Sglebius}
4162290000Sglebius#endif	/* WORKER */
4163290000Sglebius
4164290000Sglebius
4165290000Sglebius#ifdef FREE_CFG_T
4166290000Sglebiusstatic void
4167290000Sglebiusfree_config_unpeers(
4168290000Sglebius	config_tree *ptree
4169290000Sglebius	)
4170290000Sglebius{
4171290000Sglebius	unpeer_node *curr_unpeer;
4172290000Sglebius
4173290000Sglebius	if (ptree->unpeers != NULL) {
4174290000Sglebius		for (;;) {
4175290000Sglebius			UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
4176290000Sglebius			if (NULL == curr_unpeer)
4177290000Sglebius				break;
4178290000Sglebius			destroy_address_node(curr_unpeer->addr);
4179290000Sglebius			free(curr_unpeer);
4180290000Sglebius		}
4181290000Sglebius		free(ptree->unpeers);
4182290000Sglebius	}
4183290000Sglebius}
4184290000Sglebius#endif	/* FREE_CFG_T */
4185290000Sglebius
4186290000Sglebius
4187290000Sglebius#ifndef SIM
4188290000Sglebiusstatic void
4189290000Sglebiusconfig_reset_counters(
4190290000Sglebius	config_tree *ptree
4191290000Sglebius	)
4192290000Sglebius{
4193290000Sglebius	int_node *counter_set;
4194290000Sglebius
4195290000Sglebius	for (counter_set = HEAD_PFIFO(ptree->reset_counters);
4196290000Sglebius	     counter_set != NULL;
4197290000Sglebius	     counter_set = counter_set->link) {
4198290000Sglebius		switch (counter_set->i) {
4199290000Sglebius		default:
4200290000Sglebius			DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
4201290000Sglebius				    keyword(counter_set->i), counter_set->i));
420254359Sroberto			break;
420354359Sroberto
4204290000Sglebius		case T_Allpeers:
4205290000Sglebius			peer_all_reset();
420654359Sroberto			break;
420754359Sroberto
4208290000Sglebius		case T_Auth:
4209290000Sglebius			reset_auth_stats();
4210290000Sglebius			break;
421154359Sroberto
4212290000Sglebius		case T_Ctl:
4213290000Sglebius			ctl_clr_stats();
421454359Sroberto			break;
421554359Sroberto
4216290000Sglebius		case T_Io:
4217290000Sglebius			io_clr_stats();
4218290000Sglebius			break;
421954359Sroberto
4220290000Sglebius		case T_Mem:
4221290000Sglebius			peer_clr_stats();
422254359Sroberto			break;
422354359Sroberto
4224290000Sglebius		case T_Sys:
4225290000Sglebius			proto_clr_stats();
422654359Sroberto			break;
422754359Sroberto
4228290000Sglebius		case T_Timer:
4229290000Sglebius			timer_clr_stats();
4230290000Sglebius			break;
4231290000Sglebius		}
4232290000Sglebius	}
4233290000Sglebius}
4234290000Sglebius#endif	/* !SIM */
423554359Sroberto
4236290000Sglebius
4237290000Sglebius#ifdef FREE_CFG_T
4238290000Sglebiusstatic void
4239290000Sglebiusfree_config_reset_counters(
4240290000Sglebius	config_tree *ptree
4241290000Sglebius	)
4242290000Sglebius{
4243290000Sglebius	FREE_INT_FIFO(ptree->reset_counters);
4244290000Sglebius}
4245290000Sglebius#endif	/* FREE_CFG_T */
4246290000Sglebius
4247290000Sglebius
4248290000Sglebius#ifdef SIM
4249290000Sglebiusstatic void
4250290000Sglebiusconfig_sim(
4251290000Sglebius	config_tree *ptree
4252290000Sglebius	)
4253290000Sglebius{
4254290000Sglebius	int i;
4255290000Sglebius	server_info *serv_info;
4256290000Sglebius	attr_val *init_stmt;
4257290000Sglebius	sim_node *sim_n;
4258290000Sglebius
4259290000Sglebius	/* Check if a simulate block was found in the configuration code.
4260290000Sglebius	 * If not, return an error and exit
4261290000Sglebius	 */
4262290000Sglebius	sim_n = HEAD_PFIFO(ptree->sim_details);
4263290000Sglebius	if (NULL == sim_n) {
4264290000Sglebius		fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
4265290000Sglebius		fprintf(stderr, "\tCheck your configuration file.\n");
4266290000Sglebius		exit(1);
4267290000Sglebius	}
4268290000Sglebius
4269290000Sglebius	/* Process the initialization statements
4270290000Sglebius	 * -------------------------------------
4271290000Sglebius	 */
4272290000Sglebius	init_stmt = HEAD_PFIFO(sim_n->init_opts);
4273290000Sglebius	for (; init_stmt != NULL; init_stmt = init_stmt->link) {
4274290000Sglebius		switch(init_stmt->attr) {
4275290000Sglebius
4276290000Sglebius		case T_Beep_Delay:
4277290000Sglebius			simulation.beep_delay = init_stmt->value.d;
427854359Sroberto			break;
4279132451Sroberto
4280290000Sglebius		case T_Sim_Duration:
4281290000Sglebius			simulation.end_time = init_stmt->value.d;
4282290000Sglebius			break;
4283290000Sglebius
4284290000Sglebius		default:
4285290000Sglebius			fprintf(stderr,
4286290000Sglebius				"Unknown simulator init token %d\n",
4287290000Sglebius				init_stmt->attr);
4288290000Sglebius			exit(1);
428954359Sroberto		}
429054359Sroberto	}
429182498Sroberto
4292290000Sglebius	/* Process the server list
4293290000Sglebius	 * -----------------------
4294290000Sglebius	 */
4295290000Sglebius	simulation.num_of_servers = 0;
4296290000Sglebius	serv_info = HEAD_PFIFO(sim_n->servers);
4297290000Sglebius	for (; serv_info != NULL; serv_info = serv_info->link)
4298290000Sglebius		simulation.num_of_servers++;
4299290000Sglebius	simulation.servers = eallocarray(simulation.num_of_servers,
4300290000Sglebius				     sizeof(simulation.servers[0]));
4301290000Sglebius
4302290000Sglebius	i = 0;
4303290000Sglebius	serv_info = HEAD_PFIFO(sim_n->servers);
4304290000Sglebius	for (; serv_info != NULL; serv_info = serv_info->link) {
4305290000Sglebius		if (NULL == serv_info) {
4306290000Sglebius			fprintf(stderr, "Simulator server list is corrupt\n");
4307290000Sglebius			exit(1);
4308290000Sglebius		} else {
4309290000Sglebius			simulation.servers[i] = *serv_info;
4310290000Sglebius			simulation.servers[i].link = NULL;
4311290000Sglebius			i++;
4312290000Sglebius		}
4313290000Sglebius	}
4314290000Sglebius
4315290000Sglebius	printf("Creating server associations\n");
4316290000Sglebius	create_server_associations();
4317290000Sglebius	fprintf(stderr,"\tServer associations successfully created!!\n");
4318290000Sglebius}
4319290000Sglebius
4320290000Sglebius
4321290000Sglebius#ifdef FREE_CFG_T
4322290000Sglebiusstatic void
4323290000Sglebiusfree_config_sim(
4324290000Sglebius	config_tree *ptree
4325290000Sglebius	)
4326290000Sglebius{
4327290000Sglebius	sim_node *sim_n;
4328290000Sglebius	server_info *serv_n;
4329290000Sglebius	script_info *script_n;
4330290000Sglebius
4331290000Sglebius	if (NULL == ptree->sim_details)
4332290000Sglebius		return;
4333290000Sglebius	sim_n = HEAD_PFIFO(ptree->sim_details);
4334290000Sglebius	free(ptree->sim_details);
4335290000Sglebius	ptree->sim_details = NULL;
4336290000Sglebius	if (NULL == sim_n)
4337290000Sglebius		return;
4338290000Sglebius
4339290000Sglebius	FREE_ATTR_VAL_FIFO(sim_n->init_opts);
4340290000Sglebius	for (;;) {
4341290000Sglebius		UNLINK_FIFO(serv_n, *sim_n->servers, link);
4342290000Sglebius		if (NULL == serv_n)
4343290000Sglebius			break;
4344290000Sglebius		free(serv_n->curr_script);
4345290000Sglebius		if (serv_n->script != NULL) {
4346290000Sglebius			for (;;) {
4347290000Sglebius				UNLINK_FIFO(script_n, *serv_n->script,
4348290000Sglebius					    link);
4349290000Sglebius				if (script_n == NULL)
4350290000Sglebius					break;
4351290000Sglebius				free(script_n);
4352290000Sglebius			}
4353290000Sglebius			free(serv_n->script);
4354290000Sglebius		}
4355290000Sglebius		free(serv_n);
4356290000Sglebius	}
4357290000Sglebius	free(sim_n);
4358290000Sglebius}
4359290000Sglebius#endif	/* FREE_CFG_T */
4360290000Sglebius#endif	/* SIM */
4361290000Sglebius
4362290000Sglebius
4363290000Sglebius/* Define two different config functions. One for the daemon and the other for
4364290000Sglebius * the simulator. The simulator ignores a lot of the standard ntpd configuration
4365290000Sglebius * options
4366290000Sglebius */
4367290000Sglebius#ifndef SIM
4368290000Sglebiusstatic void
4369290000Sglebiusconfig_ntpd(
4370290000Sglebius	config_tree *ptree,
4371290000Sglebius	int/*BOOL*/ input_from_files
4372290000Sglebius	)
4373290000Sglebius{
4374290000Sglebius	config_nic_rules(ptree, input_from_files);
4375290000Sglebius	config_monitor(ptree);
4376290000Sglebius	config_auth(ptree);
4377290000Sglebius	config_tos(ptree);
4378290000Sglebius	config_access(ptree);
4379290000Sglebius	config_tinker(ptree);
4380290000Sglebius	config_rlimit(ptree);
4381290000Sglebius	config_system_opts(ptree);
4382290000Sglebius	config_logconfig(ptree);
4383290000Sglebius	config_phone(ptree);
4384290000Sglebius	config_mdnstries(ptree);
4385290000Sglebius	config_setvar(ptree);
4386290000Sglebius	config_ttl(ptree);
4387290000Sglebius	config_trap(ptree);
4388290000Sglebius	config_vars(ptree);
4389290000Sglebius
4390290000Sglebius	io_open_sockets();
4391290000Sglebius
4392290000Sglebius	config_other_modes(ptree);
4393290000Sglebius	config_peers(ptree);
4394290000Sglebius	config_unpeers(ptree);
4395290000Sglebius	config_fudge(ptree);
4396290000Sglebius	config_reset_counters(ptree);
4397290000Sglebius
4398290000Sglebius#ifdef TEST_BLOCKING_WORKER
4399290000Sglebius	{
4400290000Sglebius		struct addrinfo hints;
4401290000Sglebius
4402290000Sglebius		ZERO(hints);
4403290000Sglebius		hints.ai_socktype = SOCK_STREAM;
4404290000Sglebius		hints.ai_protocol = IPPROTO_TCP;
4405290000Sglebius		getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
4406290000Sglebius				     INITIAL_DNS_RETRY,
4407290000Sglebius				     gai_test_callback, (void *)1);
4408290000Sglebius		hints.ai_family = AF_INET6;
4409290000Sglebius		getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
4410290000Sglebius				     INITIAL_DNS_RETRY,
4411290000Sglebius				     gai_test_callback, (void *)0x600);
4412290000Sglebius	}
4413290000Sglebius#endif
4414290000Sglebius}
4415290000Sglebius#endif	/* !SIM */
4416290000Sglebius
4417290000Sglebius
4418290000Sglebius#ifdef SIM
4419290000Sglebiusstatic void
4420290000Sglebiusconfig_ntpdsim(
4421290000Sglebius	config_tree *ptree
4422290000Sglebius	)
4423290000Sglebius{
4424290000Sglebius	printf("Configuring Simulator...\n");
4425290000Sglebius	printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
4426290000Sglebius
4427290000Sglebius	config_tos(ptree);
4428290000Sglebius	config_monitor(ptree);
4429290000Sglebius	config_tinker(ptree);
4430290000Sglebius	if (0)
4431290000Sglebius		config_rlimit(ptree);	/* not needed for the simulator */
4432290000Sglebius	config_system_opts(ptree);
4433290000Sglebius	config_logconfig(ptree);
4434290000Sglebius	config_vars(ptree);
4435290000Sglebius	config_sim(ptree);
4436290000Sglebius}
4437290000Sglebius#endif /* SIM */
4438290000Sglebius
4439290000Sglebius
4440290000Sglebius/*
4441290000Sglebius * config_remotely() - implements ntpd side of ntpq :config
4442290000Sglebius */
4443290000Sglebiusvoid
4444290000Sglebiusconfig_remotely(
4445290000Sglebius	sockaddr_u *	remote_addr
4446290000Sglebius	)
4447290000Sglebius{
4448290000Sglebius	char origin[128];
4449290000Sglebius
4450290000Sglebius	snprintf(origin, sizeof(origin), "remote config from %s",
4451290000Sglebius		 stoa(remote_addr));
4452290000Sglebius	lex_init_stack(origin, NULL); /* no checking needed... */
4453290000Sglebius	init_syntax_tree(&cfgt);
4454290000Sglebius	yyparse();
4455290000Sglebius	lex_drop_stack();
4456290000Sglebius
4457290000Sglebius	cfgt.source.attr = CONF_SOURCE_NTPQ;
4458290000Sglebius	cfgt.timestamp = time(NULL);
4459290000Sglebius	cfgt.source.value.s = estrdup(stoa(remote_addr));
4460290000Sglebius
4461290000Sglebius	DPRINTF(1, ("Finished Parsing!!\n"));
4462290000Sglebius
4463290000Sglebius	save_and_apply_config_tree(FALSE);
4464290000Sglebius}
4465290000Sglebius
4466290000Sglebius
4467290000Sglebius/*
4468290000Sglebius * getconfig() - process startup configuration file e.g /etc/ntp.conf
4469290000Sglebius */
4470290000Sglebiusvoid
4471290000Sglebiusgetconfig(
4472290000Sglebius	int	argc,
4473290000Sglebius	char **	argv
4474290000Sglebius	)
4475290000Sglebius{
4476290000Sglebius	char	line[256];
4477290000Sglebius
4478290000Sglebius#ifdef DEBUG
4479290000Sglebius	atexit(free_all_config_trees);
4480290000Sglebius#endif
4481290000Sglebius#ifndef SYS_WINNT
4482290000Sglebius	config_file = CONFIG_FILE;
4483290000Sglebius#else
4484290000Sglebius	temp = CONFIG_FILE;
4485290000Sglebius	if (!ExpandEnvironmentStringsA(temp, config_file_storage,
4486290000Sglebius				       sizeof(config_file_storage))) {
4487290000Sglebius		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
4488290000Sglebius		exit(1);
4489290000Sglebius	}
4490290000Sglebius	config_file = config_file_storage;
4491290000Sglebius
4492290000Sglebius	temp = ALT_CONFIG_FILE;
4493290000Sglebius	if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
4494290000Sglebius				       sizeof(alt_config_file_storage))) {
4495290000Sglebius		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
4496290000Sglebius		exit(1);
4497290000Sglebius	}
4498290000Sglebius	alt_config_file = alt_config_file_storage;
4499290000Sglebius#endif /* SYS_WINNT */
4500290000Sglebius
4501290000Sglebius	/*
4502290000Sglebius	 * install a non default variable with this daemon version
4503290000Sglebius	 */
4504290000Sglebius	snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
4505290000Sglebius	set_sys_var(line, strlen(line) + 1, RO);
4506290000Sglebius
4507290000Sglebius	/*
4508290000Sglebius	 * Set up for the first time step to install a variable showing
4509290000Sglebius	 * which syscall is being used to step.
4510290000Sglebius	 */
4511290000Sglebius	set_tod_using = &ntpd_set_tod_using;
4512290000Sglebius
4513290000Sglebius	getCmdOpts(argc, argv);
4514290000Sglebius	init_syntax_tree(&cfgt);
4515290000Sglebius	if (
4516290000Sglebius		!lex_init_stack(FindConfig(config_file), "r")
451754359Sroberto#ifdef HAVE_NETINFO
4518290000Sglebius		/* If there is no config_file, try NetInfo. */
4519290000Sglebius		&& check_netinfo && !(config_netinfo = get_netinfo_config())
4520290000Sglebius#endif /* HAVE_NETINFO */
4521290000Sglebius		) {
4522290000Sglebius		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
4523290000Sglebius#ifndef SYS_WINNT
4524290000Sglebius		io_open_sockets();
4525290000Sglebius
4526290000Sglebius		return;
4527290000Sglebius#else
4528290000Sglebius		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
4529290000Sglebius
4530290000Sglebius		if (!lex_init_stack(FindConfig(alt_config_file), "r"))  {
4531290000Sglebius			/*
4532290000Sglebius			 * Broadcast clients can sometimes run without
4533290000Sglebius			 * a configuration file.
4534290000Sglebius			 */
4535290000Sglebius			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
4536290000Sglebius			io_open_sockets();
4537290000Sglebius
4538290000Sglebius			return;
4539290000Sglebius		}
4540290000Sglebius		cfgt.source.value.s = estrdup(alt_config_file);
4541290000Sglebius#endif	/* SYS_WINNT */
4542290000Sglebius	} else
4543290000Sglebius		cfgt.source.value.s = estrdup(config_file);
4544290000Sglebius
4545290000Sglebius
4546290000Sglebius	/*** BULK OF THE PARSER ***/
4547290000Sglebius#ifdef DEBUG
4548290000Sglebius	yydebug = !!(debug >= 5);
4549290000Sglebius#endif
4550290000Sglebius	yyparse();
4551290000Sglebius	lex_drop_stack();
4552290000Sglebius
4553290000Sglebius	DPRINTF(1, ("Finished Parsing!!\n"));
4554290000Sglebius
4555290000Sglebius	cfgt.source.attr = CONF_SOURCE_FILE;
4556290000Sglebius	cfgt.timestamp = time(NULL);
4557290000Sglebius
4558290000Sglebius	save_and_apply_config_tree(TRUE);
4559290000Sglebius
4560290000Sglebius#ifdef HAVE_NETINFO
456182498Sroberto	if (config_netinfo)
456282498Sroberto		free_netinfo_config(config_netinfo);
456354359Sroberto#endif /* HAVE_NETINFO */
4564290000Sglebius}
456554359Sroberto
456682498Sroberto
4567290000Sglebiusvoid
4568290000Sglebiussave_and_apply_config_tree(int/*BOOL*/ input_from_file)
4569290000Sglebius{
4570290000Sglebius	config_tree *ptree;
4571290000Sglebius#ifndef SAVECONFIG
4572290000Sglebius	config_tree *punlinked;
4573290000Sglebius#endif
457482498Sroberto
4575290000Sglebius	/*
4576290000Sglebius	 * Keep all the configuration trees applied since startup in
4577290000Sglebius	 * a list that can be used to dump the configuration back to
4578290000Sglebius	 * a text file.
4579290000Sglebius	 */
4580290000Sglebius	ptree = emalloc(sizeof(*ptree));
4581290000Sglebius	memcpy(ptree, &cfgt, sizeof(*ptree));
4582290000Sglebius	ZERO(cfgt);
4583290000Sglebius
4584290000Sglebius	LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
4585290000Sglebius
4586290000Sglebius#ifdef SAVECONFIG
4587290000Sglebius	if (HAVE_OPT( SAVECONFIGQUIT )) {
4588290000Sglebius		FILE *dumpfile;
4589290000Sglebius		int err;
4590290000Sglebius		int dumpfailed;
4591290000Sglebius
4592290000Sglebius		dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
4593290000Sglebius		if (NULL == dumpfile) {
4594290000Sglebius			err = errno;
4595290000Sglebius			mfprintf(stderr,
4596290000Sglebius				 "can not create save file %s, error %d %m\n",
4597290000Sglebius				 OPT_ARG(SAVECONFIGQUIT), err);
4598290000Sglebius			exit(err);
459982498Sroberto		}
4600290000Sglebius
4601290000Sglebius		dumpfailed = dump_all_config_trees(dumpfile, 0);
4602290000Sglebius		if (dumpfailed)
4603290000Sglebius			fprintf(stderr,
4604290000Sglebius				"--saveconfigquit %s error %d\n",
4605290000Sglebius				OPT_ARG( SAVECONFIGQUIT ),
4606290000Sglebius				dumpfailed);
4607290000Sglebius		else
4608290000Sglebius			fprintf(stderr,
4609290000Sglebius				"configuration saved to %s\n",
4610290000Sglebius				OPT_ARG( SAVECONFIGQUIT ));
4611290000Sglebius
4612290000Sglebius		exit(dumpfailed);
461382498Sroberto	}
4614290000Sglebius#endif	/* SAVECONFIG */
461582498Sroberto
4616290000Sglebius	/* The actual configuration done depends on whether we are configuring the
4617290000Sglebius	 * simulator or the daemon. Perform a check and call the appropriate
4618290000Sglebius	 * function as needed.
4619290000Sglebius	 */
462082498Sroberto
4621290000Sglebius#ifndef SIM
4622290000Sglebius	config_ntpd(ptree, input_from_file);
4623290000Sglebius#else
4624290000Sglebius	config_ntpdsim(ptree);
4625290000Sglebius#endif
4626290000Sglebius
4627290000Sglebius	/*
4628290000Sglebius	 * With configure --disable-saveconfig, there's no use keeping
4629290000Sglebius	 * the config tree around after application, so free it.
4630290000Sglebius	 */
4631290000Sglebius#ifndef SAVECONFIG
4632290000Sglebius	UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
4633290000Sglebius		     config_tree);
4634290000Sglebius	INSIST(punlinked == ptree);
4635290000Sglebius	free_config_tree(ptree);
4636290000Sglebius#endif
4637290000Sglebius}
4638290000Sglebius
4639290000Sglebius
4640290000Sglebiusstatic void
4641290000Sglebiusntpd_set_tod_using(
4642290000Sglebius	const char *which
4643290000Sglebius	)
4644290000Sglebius{
4645290000Sglebius	char line[128];
4646290000Sglebius
4647290000Sglebius	snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
4648290000Sglebius	set_sys_var(line, strlen(line) + 1, RO);
4649290000Sglebius}
4650290000Sglebius
4651290000Sglebius
4652290000Sglebiusstatic char *
4653290000Sglebiusnormal_dtoa(
4654290000Sglebius	double d
4655290000Sglebius	)
4656290000Sglebius{
4657290000Sglebius	char *	buf;
4658290000Sglebius	char *	pch_e;
4659290000Sglebius	char *	pch_nz;
4660290000Sglebius
4661290000Sglebius	LIB_GETBUF(buf);
4662290000Sglebius	snprintf(buf, LIB_BUFLENGTH, "%g", d);
4663290000Sglebius
4664290000Sglebius	/* use lowercase 'e', strip any leading zeroes in exponent */
4665290000Sglebius	pch_e = strchr(buf, 'e');
4666290000Sglebius	if (NULL == pch_e) {
4667290000Sglebius		pch_e = strchr(buf, 'E');
4668290000Sglebius		if (NULL == pch_e)
4669290000Sglebius			return buf;
4670290000Sglebius		*pch_e = 'e';
4671290000Sglebius	}
4672290000Sglebius	pch_e++;
4673290000Sglebius	if ('-' == *pch_e)
4674290000Sglebius		pch_e++;
4675290000Sglebius	pch_nz = pch_e;
4676290000Sglebius	while ('0' == *pch_nz)
4677290000Sglebius		pch_nz++;
4678290000Sglebius	if (pch_nz == pch_e)
4679290000Sglebius		return buf;
4680290000Sglebius	strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
4681290000Sglebius
4682290000Sglebius	return buf;
4683290000Sglebius}
4684290000Sglebius
4685290000Sglebius
4686290000Sglebius/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
4687290000Sglebius * --------------------------------------------
4688290000Sglebius */
4689290000Sglebius
4690290000Sglebius
4691290000Sglebius/*
4692290000Sglebius * get_pfxmatch - find value for prefixmatch
4693290000Sglebius * and update char * accordingly
4694290000Sglebius */
4695290000Sglebiusstatic u_int32
4696290000Sglebiusget_pfxmatch(
4697290000Sglebius	const char **	pstr,
4698290000Sglebius	struct masks *	m
4699290000Sglebius	)
4700290000Sglebius{
4701290000Sglebius	while (m->name != NULL) {
4702290000Sglebius		if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
4703290000Sglebius			*pstr += strlen(m->name);
4704290000Sglebius			return m->mask;
4705290000Sglebius		} else {
4706290000Sglebius			m++;
4707132451Sroberto		}
470854359Sroberto	}
4709290000Sglebius	return 0;
471054359Sroberto}
471154359Sroberto
4712290000Sglebius/*
4713290000Sglebius * get_match - find logmask value
4714290000Sglebius */
4715290000Sglebiusstatic u_int32
4716290000Sglebiusget_match(
4717290000Sglebius	const char *	str,
4718290000Sglebius	struct masks *	m
4719290000Sglebius	)
4720290000Sglebius{
4721290000Sglebius	while (m->name != NULL) {
4722290000Sglebius		if (strcmp(str, m->name) == 0)
4723290000Sglebius			return m->mask;
4724290000Sglebius		else
4725290000Sglebius			m++;
4726290000Sglebius	}
4727290000Sglebius	return 0;
4728290000Sglebius}
472954359Sroberto
4730290000Sglebius/*
4731290000Sglebius * get_logmask - build bitmask for ntp_syslogmask
4732290000Sglebius */
4733290000Sglebiusstatic u_int32
4734290000Sglebiusget_logmask(
4735290000Sglebius	const char *	str
4736290000Sglebius	)
4737290000Sglebius{
4738290000Sglebius	const char *	t;
4739290000Sglebius	u_int32		offset;
4740290000Sglebius	u_int32		mask;
4741290000Sglebius
4742290000Sglebius	mask = get_match(str, logcfg_noclass_items);
4743290000Sglebius	if (mask != 0)
4744290000Sglebius		return mask;
4745290000Sglebius
4746290000Sglebius	t = str;
4747290000Sglebius	offset = get_pfxmatch(&t, logcfg_class);
4748290000Sglebius	mask   = get_match(t, logcfg_class_items);
4749290000Sglebius
4750290000Sglebius	if (mask)
4751290000Sglebius		return mask << offset;
4752290000Sglebius	else
4753290000Sglebius		msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
4754290000Sglebius			str);
4755290000Sglebius
4756290000Sglebius	return 0;
4757290000Sglebius}
4758290000Sglebius
4759290000Sglebius
476054359Sroberto#ifdef HAVE_NETINFO
476154359Sroberto
4762290000Sglebius/*
476354359Sroberto * get_netinfo_config - find the nearest NetInfo domain with an ntp
476454359Sroberto * configuration and initialize the configuration state.
476554359Sroberto */
476654359Srobertostatic struct netinfo_config_state *
4767290000Sglebiusget_netinfo_config(void)
476854359Sroberto{
476954359Sroberto	ni_status status;
477054359Sroberto	void *domain;
477154359Sroberto	ni_id config_dir;
4772290000Sglebius	struct netinfo_config_state *config;
477354359Sroberto
477454359Sroberto	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
477554359Sroberto
477654359Sroberto	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
477754359Sroberto		void *next_domain;
477854359Sroberto		if (ni_open(domain, "..", &next_domain) != NI_OK) {
477954359Sroberto			ni_free(next_domain);
478054359Sroberto			break;
478154359Sroberto		}
478254359Sroberto		ni_free(domain);
478354359Sroberto		domain = next_domain;
478454359Sroberto	}
478554359Sroberto	if (status != NI_OK) {
478654359Sroberto		ni_free(domain);
478754359Sroberto		return NULL;
478854359Sroberto	}
478954359Sroberto
4790290000Sglebius	config = emalloc(sizeof(*config));
4791290000Sglebius	config->domain = domain;
4792290000Sglebius	config->config_dir = config_dir;
4793290000Sglebius	config->prop_index = 0;
4794290000Sglebius	config->val_index = 0;
4795290000Sglebius	config->val_list = NULL;
479654359Sroberto
479754359Sroberto	return config;
479854359Sroberto}
479954359Sroberto
480054359Sroberto
480154359Sroberto/*
480254359Sroberto * free_netinfo_config - release NetInfo configuration state
480354359Sroberto */
480454359Srobertostatic void
4805290000Sglebiusfree_netinfo_config(
4806290000Sglebius	struct netinfo_config_state *config
4807290000Sglebius	)
480854359Sroberto{
480954359Sroberto	ni_free(config->domain);
481054359Sroberto	free(config);
481154359Sroberto}
481254359Sroberto
481354359Sroberto
481454359Sroberto/*
481554359Sroberto * gettokens_netinfo - return tokens from NetInfo
481654359Sroberto */
481754359Srobertostatic int
481854359Srobertogettokens_netinfo (
481954359Sroberto	struct netinfo_config_state *config,
482054359Sroberto	char **tokenlist,
482154359Sroberto	int *ntokens
482254359Sroberto	)
482354359Sroberto{
482454359Sroberto	int prop_index = config->prop_index;
482554359Sroberto	int val_index = config->val_index;
482654359Sroberto	char **val_list = config->val_list;
482754359Sroberto
482854359Sroberto	/*
482954359Sroberto	 * Iterate through each keyword and look for a property that matches it.
483054359Sroberto	 */
4831290000Sglebius  again:
483254359Sroberto	if (!val_list) {
4833290000Sglebius		for (; prop_index < COUNTOF(keywords); prop_index++)
4834290000Sglebius		{
4835290000Sglebius			ni_namelist namelist;
483654359Sroberto			struct keyword current_prop = keywords[prop_index];
4837290000Sglebius			ni_index index;
483854359Sroberto
483954359Sroberto			/*
484054359Sroberto			 * For each value associated in the property, we're going to return
484154359Sroberto			 * a separate line. We squirrel away the values in the config state
484254359Sroberto			 * so the next time through, we don't need to do this lookup.
484354359Sroberto			 */
4844290000Sglebius			NI_INIT(&namelist);
4845290000Sglebius			if (NI_OK == ni_lookupprop(config->domain,
4846290000Sglebius			    &config->config_dir, current_prop.text,
4847290000Sglebius			    &namelist)) {
484854359Sroberto
484954359Sroberto				/* Found the property, but it has no values */
485054359Sroberto				if (namelist.ni_namelist_len == 0) continue;
485154359Sroberto
4852290000Sglebius				config->val_list =
4853290000Sglebius				    eallocarray(
4854290000Sglebius					(namelist.ni_namelist_len + 1),
4855290000Sglebius					sizeof(char*));
4856290000Sglebius				val_list = config->val_list;
485754359Sroberto
4858290000Sglebius				for (index = 0;
4859290000Sglebius				     index < namelist.ni_namelist_len;
4860290000Sglebius				     index++) {
4861290000Sglebius					char *value;
486254359Sroberto
4863290000Sglebius					value = namelist.ni_namelist_val[index];
4864290000Sglebius					val_list[index] = estrdup(value);
486554359Sroberto				}
486654359Sroberto				val_list[index] = NULL;
486754359Sroberto
486854359Sroberto				break;
486954359Sroberto			}
487054359Sroberto			ni_namelist_free(&namelist);
487154359Sroberto		}
487254359Sroberto		config->prop_index = prop_index;
487354359Sroberto	}
487454359Sroberto
487554359Sroberto	/* No list; we're done here. */
4876290000Sglebius	if (!val_list)
4877290000Sglebius		return CONFIG_UNKNOWN;
487854359Sroberto
487954359Sroberto	/*
488054359Sroberto	 * We have a list of values for the current property.
488154359Sroberto	 * Iterate through them and return each in order.
488254359Sroberto	 */
4883290000Sglebius	if (val_list[val_index]) {
488454359Sroberto		int ntok = 1;
488554359Sroberto		int quoted = 0;
488654359Sroberto		char *tokens = val_list[val_index];
488754359Sroberto
488854359Sroberto		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
488954359Sroberto
489054359Sroberto		(const char*)tokenlist[0] = keywords[prop_index].text;
489154359Sroberto		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
489254359Sroberto			tokenlist[ntok] = tokens;
489354359Sroberto			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
489454359Sroberto				quoted ^= (*tokens++ == '"');
489554359Sroberto
489654359Sroberto			if (ISEOL(*tokens)) {
489754359Sroberto				*tokens = '\0';
489854359Sroberto				break;
489954359Sroberto			} else {		/* must be space */
490054359Sroberto				*tokens++ = '\0';
4901290000Sglebius				while (ISSPACE(*tokens))
4902290000Sglebius					tokens++;
4903290000Sglebius				if (ISEOL(*tokens))
4904290000Sglebius					break;
490554359Sroberto			}
490654359Sroberto		}
490754359Sroberto
4908182007Sroberto		if (ntok == MAXTOKENS) {
4909182007Sroberto			/* HMS: chomp it to lose the EOL? */
4910182007Sroberto			msyslog(LOG_ERR,
4911290000Sglebius				"gettokens_netinfo: too many tokens.  Ignoring: %s",
4912290000Sglebius				tokens);
4913182007Sroberto		} else {
4914182007Sroberto			*ntokens = ntok + 1;
4915182007Sroberto		}
4916182007Sroberto
4917182007Sroberto		config->val_index++;	/* HMS: Should this be in the 'else'? */
4918182007Sroberto
491954359Sroberto		return keywords[prop_index].keytype;
492054359Sroberto	}
492154359Sroberto
492254359Sroberto	/* We're done with the current property. */
492354359Sroberto	prop_index = ++config->prop_index;
492454359Sroberto
492554359Sroberto	/* Free val_list and reset counters. */
492654359Sroberto	for (val_index = 0; val_list[val_index]; val_index++)
492754359Sroberto		free(val_list[val_index]);
4928290000Sglebius	free(val_list);
4929290000Sglebius	val_list = config->val_list = NULL;
4930290000Sglebius	val_index = config->val_index = 0;
493154359Sroberto
493254359Sroberto	goto again;
493354359Sroberto}
493454359Sroberto#endif /* HAVE_NETINFO */
493554359Sroberto
493654359Sroberto
493754359Sroberto/*
493854359Sroberto * getnetnum - return a net number (this is crude, but careful)
4939290000Sglebius *
4940290000Sglebius * returns 1 for success, and mysteriously, 0 for most failures, and
4941290000Sglebius * -1 if the address found is IPv6 and we believe IPv6 isn't working.
494254359Sroberto */
4943290000Sglebius#ifndef SIM
494454359Srobertostatic int
494554359Srobertogetnetnum(
494654359Sroberto	const char *num,
4947290000Sglebius	sockaddr_u *addr,
4948182007Sroberto	int complain,
4949290000Sglebius	enum gnn_type a_type	/* ignored */
495054359Sroberto	)
495154359Sroberto{
4952290000Sglebius	REQUIRE(AF_UNSPEC == AF(addr) ||
4953290000Sglebius		AF_INET == AF(addr) ||
4954290000Sglebius		AF_INET6 == AF(addr));
495554359Sroberto
4956290000Sglebius	if (!is_ip_address(num, AF(addr), addr))
4957290000Sglebius		return 0;
4958182007Sroberto
4959290000Sglebius	if (IS_IPV6(addr) && !ipv6_works)
4960290000Sglebius		return -1;
496154359Sroberto
4962290000Sglebius# ifdef ISC_PLATFORM_HAVESALEN
4963290000Sglebius	addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
4964290000Sglebius# endif
4965290000Sglebius	SET_PORT(addr, NTP_PORT);
4966182007Sroberto
4967290000Sglebius	DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
4968182007Sroberto
496954359Sroberto	return 1;
497054359Sroberto}
4971290000Sglebius#endif	/* !SIM */
497254359Sroberto
4973290000Sglebius#if defined(HAVE_SETRLIMIT)
4974290000Sglebiusvoid
4975290000Sglebiusntp_rlimit(
4976290000Sglebius	int	rl_what,
4977290000Sglebius	rlim_t	rl_value,
4978290000Sglebius	int	rl_scale,
4979290000Sglebius	const char *	rl_sstr
498054359Sroberto	)
498154359Sroberto{
4982290000Sglebius	struct rlimit	rl;
498354359Sroberto
4984290000Sglebius	switch (rl_what) {
4985290000Sglebius# ifdef RLIMIT_MEMLOCK
4986290000Sglebius	    case RLIMIT_MEMLOCK:
498754359Sroberto		/*
4988290000Sglebius		 * The default RLIMIT_MEMLOCK is very low on Linux systems.
4989290000Sglebius		 * Unless we increase this limit malloc calls are likely to
4990290000Sglebius		 * fail if we drop root privilege.  To be useful the value
4991290000Sglebius		 * has to be larger than the largest ntpd resident set size.
499254359Sroberto		 */
4993290000Sglebius		DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
4994290000Sglebius			(int)(rl_value / rl_scale), rl_sstr));
4995290000Sglebius		rl.rlim_cur = rl.rlim_max = rl_value;
4996290000Sglebius		if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
4997290000Sglebius			msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
4998290000Sglebius		break;
4999290000Sglebius# endif /* RLIMIT_MEMLOCK */
5000290000Sglebius
5001290000Sglebius# ifdef RLIMIT_NOFILE
5002290000Sglebius	    case RLIMIT_NOFILE:
500354359Sroberto		/*
5004290000Sglebius		 * For large systems the default file descriptor limit may
5005290000Sglebius		 * not be enough.
500654359Sroberto		 */
5007290000Sglebius		DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
5008290000Sglebius			(int)(rl_value / rl_scale), rl_sstr));
5009290000Sglebius		rl.rlim_cur = rl.rlim_max = rl_value;
5010290000Sglebius		if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
5011290000Sglebius			msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
5012290000Sglebius		break;
5013290000Sglebius# endif /* RLIMIT_NOFILE */
501454359Sroberto
5015290000Sglebius# ifdef RLIMIT_STACK
5016290000Sglebius	    case RLIMIT_STACK:
501754359Sroberto		/*
5018290000Sglebius		 * Provide a way to set the stack limit to something
5019290000Sglebius		 * smaller, so that we don't lock a lot of unused
5020290000Sglebius		 * stack memory.
502154359Sroberto		 */
5022290000Sglebius		DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
5023290000Sglebius			    (int)(rl_value / rl_scale), rl_sstr));
5024290000Sglebius		if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
5025290000Sglebius			msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
5026290000Sglebius		} else {
5027290000Sglebius			if (rl_value > rl.rlim_max) {
5028290000Sglebius				msyslog(LOG_WARNING,
5029290000Sglebius					"ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
5030290000Sglebius					(u_long)rl.rlim_max,
5031290000Sglebius					(u_long)rl_value);
5032290000Sglebius				rl_value = rl.rlim_max;
5033290000Sglebius			}
5034290000Sglebius			rl.rlim_cur = rl_value;
5035290000Sglebius			if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
5036290000Sglebius				msyslog(LOG_ERR,
5037290000Sglebius					"ntp_rlimit: Cannot set RLIMIT_STACK: %m");
5038290000Sglebius			}
5039182007Sroberto		}
5040290000Sglebius		break;
5041290000Sglebius# endif /* RLIMIT_STACK */
5042290000Sglebius
5043290000Sglebius	    default:
5044290000Sglebius		INSIST(!"Unexpected setrlimit() case!");
5045290000Sglebius		break;
504654359Sroberto	}
504754359Sroberto}
5048290000Sglebius#endif	/* HAVE_SETRLIMIT */
5049