1290001Sglebius/* ntp_config.c
2290001Sglebius *
3290001Sglebius * This file contains the ntpd configuration code.
4290001Sglebius *
5290001Sglebius * Written By:	Sachin Kamboj
6290001Sglebius *		University of Delaware
7290001Sglebius *		Newark, DE 19711
8290001Sglebius * Some parts borrowed from the older ntp_config.c
9290001Sglebius * Copyright (c) 2006
1054359Sroberto */
11290001Sglebius
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
23290001Sglebius# include <sys/param.h>
24106163Sroberto#endif
2582498Sroberto#include <signal.h>
2682498Sroberto#ifndef SIGCHLD
2782498Sroberto# define SIGCHLD SIGCLD
2882498Sroberto#endif
29290001Sglebius#ifdef HAVE_SYS_WAIT_H
30290001Sglebius# include <sys/wait.h>
31290001Sglebius#endif
3282498Sroberto
33290001Sglebius#include <isc/net.h>
34290001Sglebius#include <isc/result.h>
3554359Sroberto
36290001Sglebius#include "ntp.h"
37290001Sglebius#include "ntpd.h"
38290001Sglebius#include "ntp_io.h"
39290001Sglebius#include "ntp_unixtime.h"
40290001Sglebius#include "ntp_refclock.h"
41290001Sglebius#include "ntp_filegen.h"
42290001Sglebius#include "ntp_stdlib.h"
43290001Sglebius#include "lib_strbuf.h"
44290001Sglebius#include "ntp_assert.h"
45290001Sglebius#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"
52290001Sglebius#include "ntp_scanner.h"
53290001Sglebius#include "ntp_parser.h"
54290001Sglebius#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
62294905Sdelphijextern int yyparse(void);
63294905Sdelphij
64290001Sglebius/* Bug 2817 */
65290001Sglebius#if defined(HAVE_SYS_MMAN_H)
66290001Sglebius# include <sys/mman.h>
67290001Sglebius#endif
6882498Sroberto
69290001Sglebius/* list of servers from command line for config_peers() */
70290001Sglebiusint	cmdline_server_count;
71290001Sglebiuschar **	cmdline_servers;
7254359Sroberto
73290001Sglebius/* Current state of memory locking:
74290001Sglebius * -1: default
75290001Sglebius *  0: memory locking disabled
76290001Sglebius *  1: Memory locking enabled
7754359Sroberto */
78290001Sglebiusint	cur_memlock = -1;
7954359Sroberto
8054359Sroberto/*
8154359Sroberto * "logconfig" building blocks
8254359Sroberto */
8354359Srobertostruct masks {
84290001Sglebius	const char * const	name;
85290001Sglebius	const u_int32		mask;
8654359Sroberto};
8754359Sroberto
8854359Srobertostatic struct masks logcfg_class[] = {
89290001Sglebius	{ "clock",	NLOG_OCLOCK },
90290001Sglebius	{ "peer",	NLOG_OPEER },
91290001Sglebius	{ "sync",	NLOG_OSYNC },
92290001Sglebius	{ "sys",	NLOG_OSYS },
93290001Sglebius	{ NULL,		0 }
9454359Sroberto};
9554359Sroberto
96290001Sglebius/* logcfg_noclass_items[] masks are complete and must not be shifted */
97290001Sglebiusstatic struct masks logcfg_noclass_items[] = {
98290001Sglebius	{ "allall",		NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
99290001Sglebius	{ "allinfo",		NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
100290001Sglebius	{ "allevents",		NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
101290001Sglebius	{ "allstatus",		NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
102290001Sglebius	{ "allstatistics",	NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
103290001Sglebius	/* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
104290001Sglebius	{ "allclock",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
105290001Sglebius	{ "allpeer",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
106290001Sglebius	{ "allsys",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
107290001Sglebius	{ "allsync",		(NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
108290001Sglebius	{ NULL,			0 }
109290001Sglebius};
110290001Sglebius
111290001Sglebius/* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
112290001Sglebiusstatic struct masks logcfg_class_items[] = {
113290001Sglebius	{ "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 },
118290001Sglebius	{ NULL,			0 }
11954359Sroberto};
12054359Sroberto
121290001Sglebiustypedef struct peer_resolved_ctx_tag {
122290001Sglebius	int		flags;
123290001Sglebius	int		host_mode;	/* T_* token identifier */
124290001Sglebius	u_short		family;
125290001Sglebius	keyid_t		keyid;
126290001Sglebius	u_char		hmode;		/* MODE_* */
127290001Sglebius	u_char		version;
128290001Sglebius	u_char		minpoll;
129290001Sglebius	u_char		maxpoll;
130290001Sglebius	u_int32		ttl;
131290001Sglebius	const char *	group;
132290001Sglebius} peer_resolved_ctx;
133290001Sglebius
134290001Sglebius/* 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
144290001Sglebius#define _UC(str)	((char *)(intptr_t)(str))
14582498Sroberto
14654359Sroberto/*
14754359Sroberto * Definitions of things either imported from or exported to outside
14854359Sroberto */
149290001Sglebiusextern int yydebug;			/* ntp_parser.c (.y) */
150290001Sglebiusconfig_tree cfgt;			/* Parser output stored here */
151290001Sglebiusstruct config_tree_tag *cfg_tree_history;	/* History of configs */
152290001Sglebiuschar	*sys_phone[MAXPHONE] = {NULL};	/* ACTS phone numbers */
153290001Sglebiuschar	default_keysdir[] = NTP_KEYSDIR;
154290001Sglebiuschar	*keysdir = default_keysdir;	/* crypto keys directory */
155290001Sglebiuschar *	saveconfigdir;
15654359Sroberto#if defined(HAVE_SCHED_SETSCHEDULER)
15754359Srobertoint	config_priority_override = 0;
15854359Srobertoint	config_priority;
15954359Sroberto#endif
16054359Sroberto
16182498Srobertoconst char *config_file;
162290001Sglebiusstatic char default_ntp_signd_socket[] =
163290001Sglebius#ifdef NTP_SIGND_PATH
164290001Sglebius					NTP_SIGND_PATH;
165290001Sglebius#else
166290001Sglebius					"";
167290001Sglebius#endif
168290001Sglebiuschar *ntp_signd_socket = default_ntp_signd_socket;
16982498Sroberto#ifdef HAVE_NETINFO
170290001Sglebiusstruct netinfo_config_state *config_netinfo = NULL;
171290001Sglebiusint check_netinfo = 1;
17282498Sroberto#endif /* HAVE_NETINFO */
17382498Sroberto#ifdef SYS_WINNT
174290001Sglebiuschar *alt_config_file;
175290001SglebiusLPTSTR temp;
176290001Sglebiuschar config_file_storage[MAX_PATH];
177290001Sglebiuschar 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      */
189290001Sglebius	char **val_list;	/* value list         */
19054359Sroberto};
19154359Sroberto#endif
19254359Sroberto
193290001Sglebiusstruct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
194290001Sglebius					     pointer info */
195290001Sglebiusint old_config_style = 1;    /* A boolean flag, which when set,
196290001Sglebius			      * indicates that the old configuration
197290001Sglebius			      * format with a newline at the end of
198290001Sglebius			      * every command is being used
199290001Sglebius			      */
200290001Sglebiusint	cryptosw;		/* crypto command called */
201290001Sglebius
202290001Sglebiusextern char *stats_drift_file;	/* name of the driftfile */
203290001Sglebius
204290001Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
20554359Sroberto/*
206290001Sglebius * backwards compatibility flags
20754359Sroberto */
208290001Sglebiusbc_entry bc_list[] = {
209290001Sglebius	{ T_Bc_bugXXXX,		1	}	/* default enabled */
210290001Sglebius};
211290001Sglebius
212290001Sglebius/*
213290001Sglebius * declare an int pointer for each flag for quick testing without
214290001Sglebius * walking bc_list.  If the pointer is consumed by libntp rather
215290001Sglebius * than ntpd, declare it in a libntp source file pointing to storage
216290001Sglebius * initialized with the appropriate value for other libntp clients, and
217290001Sglebius * redirect it to point into bc_list during ntpd startup.
218290001Sglebius */
219290001Sglebiusint *p_bcXXXX_enabled = &bc_list[0].enabled;
22054359Sroberto#endif
221290001Sglebius
222290001Sglebius/* FUNCTION PROTOTYPES */
223290001Sglebius
224290001Sglebiusstatic void init_syntax_tree(config_tree *);
225290001Sglebiusstatic void apply_enable_disable(attr_val_fifo *q, int enable);
226290001Sglebius
227290001Sglebius#ifdef FREE_CFG_T
228290001Sglebiusstatic void free_auth_node(config_tree *);
229290001Sglebiusstatic void free_all_config_trees(void);
230290001Sglebius
231290001Sglebiusstatic void free_config_access(config_tree *);
232290001Sglebiusstatic void free_config_auth(config_tree *);
233290001Sglebiusstatic void free_config_fudge(config_tree *);
234290001Sglebiusstatic void free_config_logconfig(config_tree *);
235290001Sglebiusstatic void free_config_monitor(config_tree *);
236290001Sglebiusstatic void free_config_nic_rules(config_tree *);
237290001Sglebiusstatic void free_config_other_modes(config_tree *);
238290001Sglebiusstatic void free_config_peers(config_tree *);
239290001Sglebiusstatic void free_config_phone(config_tree *);
240290001Sglebiusstatic void free_config_reset_counters(config_tree *);
241290001Sglebiusstatic void free_config_rlimit(config_tree *);
242290001Sglebiusstatic void free_config_setvar(config_tree *);
243290001Sglebiusstatic void free_config_system_opts(config_tree *);
244290001Sglebiusstatic void free_config_tinker(config_tree *);
245290001Sglebiusstatic void free_config_tos(config_tree *);
246290001Sglebiusstatic void free_config_trap(config_tree *);
247290001Sglebiusstatic void free_config_ttl(config_tree *);
248290001Sglebiusstatic void free_config_unpeers(config_tree *);
249290001Sglebiusstatic void free_config_vars(config_tree *);
250290001Sglebius
251290001Sglebius#ifdef SIM
252290001Sglebiusstatic void free_config_sim(config_tree *);
253290001Sglebius#endif
254290001Sglebiusstatic void destroy_address_fifo(address_fifo *);
255290001Sglebius#define FREE_ADDRESS_FIFO(pf)			\
256290001Sglebius	do {					\
257290001Sglebius		destroy_address_fifo(pf);	\
258290001Sglebius		(pf) = NULL;			\
259290001Sglebius	} while (0)
260290001Sglebius       void free_all_config_trees(void);	/* atexit() */
261290001Sglebiusstatic void free_config_tree(config_tree *ptree);
262290001Sglebius#endif	/* FREE_CFG_T */
263290001Sglebius
264290001Sglebiusstatic void destroy_restrict_node(restrict_node *my_node);
265290001Sglebiusstatic int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
266290001Sglebiusstatic void save_and_apply_config_tree(int/*BOOL*/ from_file);
267290001Sglebiusstatic void destroy_int_fifo(int_fifo *);
268290001Sglebius#define FREE_INT_FIFO(pf)			\
269290001Sglebius	do {					\
270290001Sglebius		destroy_int_fifo(pf);		\
271290001Sglebius		(pf) = NULL;			\
272290001Sglebius	} while (0)
273290001Sglebiusstatic void destroy_string_fifo(string_fifo *);
274290001Sglebius#define FREE_STRING_FIFO(pf)			\
275290001Sglebius	do {					\
276290001Sglebius		destroy_string_fifo(pf);		\
277290001Sglebius		(pf) = NULL;			\
278290001Sglebius	} while (0)
279290001Sglebiusstatic void destroy_attr_val_fifo(attr_val_fifo *);
280290001Sglebius#define FREE_ATTR_VAL_FIFO(pf)			\
281290001Sglebius	do {					\
282290001Sglebius		destroy_attr_val_fifo(pf);	\
283290001Sglebius		(pf) = NULL;			\
284290001Sglebius	} while (0)
285290001Sglebiusstatic void destroy_filegen_fifo(filegen_fifo *);
286290001Sglebius#define FREE_FILEGEN_FIFO(pf)			\
287290001Sglebius	do {					\
288290001Sglebius		destroy_filegen_fifo(pf);	\
289290001Sglebius		(pf) = NULL;			\
290290001Sglebius	} while (0)
291290001Sglebiusstatic void destroy_restrict_fifo(restrict_fifo *);
292290001Sglebius#define FREE_RESTRICT_FIFO(pf)			\
293290001Sglebius	do {					\
294290001Sglebius		destroy_restrict_fifo(pf);	\
295290001Sglebius		(pf) = NULL;			\
296290001Sglebius	} while (0)
297290001Sglebiusstatic void destroy_setvar_fifo(setvar_fifo *);
298290001Sglebius#define FREE_SETVAR_FIFO(pf)			\
299290001Sglebius	do {					\
300290001Sglebius		destroy_setvar_fifo(pf);	\
301290001Sglebius		(pf) = NULL;			\
302290001Sglebius	} while (0)
303290001Sglebiusstatic void destroy_addr_opts_fifo(addr_opts_fifo *);
304290001Sglebius#define FREE_ADDR_OPTS_FIFO(pf)			\
305290001Sglebius	do {					\
306290001Sglebius		destroy_addr_opts_fifo(pf);	\
307290001Sglebius		(pf) = NULL;			\
308290001Sglebius	} while (0)
309290001Sglebius
310290001Sglebiusstatic void config_logconfig(config_tree *);
311290001Sglebiusstatic void config_monitor(config_tree *);
312290001Sglebiusstatic void config_rlimit(config_tree *);
313290001Sglebiusstatic void config_system_opts(config_tree *);
314290001Sglebiusstatic void config_tinker(config_tree *);
315290001Sglebiusstatic void config_tos(config_tree *);
316290001Sglebiusstatic void config_vars(config_tree *);
317290001Sglebius
318290001Sglebius#ifdef SIM
319290001Sglebiusstatic sockaddr_u *get_next_address(address_node *addr);
320290001Sglebiusstatic void config_sim(config_tree *);
321290001Sglebiusstatic void config_ntpdsim(config_tree *);
322290001Sglebius#else	/* !SIM follows */
323290001Sglebiusstatic void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
324290001Sglebiusstatic void config_other_modes(config_tree *);
325290001Sglebiusstatic void config_auth(config_tree *);
326290001Sglebiusstatic void config_access(config_tree *);
327290001Sglebiusstatic void config_mdnstries(config_tree *);
328290001Sglebiusstatic void config_phone(config_tree *);
329290001Sglebiusstatic void config_setvar(config_tree *);
330290001Sglebiusstatic void config_ttl(config_tree *);
331290001Sglebiusstatic void config_trap(config_tree *);
332290001Sglebiusstatic void config_fudge(config_tree *);
333290001Sglebiusstatic void config_peers(config_tree *);
334290001Sglebiusstatic void config_unpeers(config_tree *);
335290001Sglebiusstatic void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
336290001Sglebiusstatic void config_reset_counters(config_tree *);
337290001Sglebiusstatic u_char get_correct_host_mode(int token);
338290001Sglebiusstatic int peerflag_bits(peer_node *);
339290001Sglebius#endif	/* !SIM */
340290001Sglebius
341290001Sglebius#ifdef WORKER
342290001Sglebiusstatic void peer_name_resolved(int, int, void *, const char *, const char *,
343290001Sglebius			const struct addrinfo *,
344290001Sglebius			const struct addrinfo *);
345290001Sglebiusstatic void unpeer_name_resolved(int, int, void *, const char *, const char *,
346290001Sglebius			  const struct addrinfo *,
347290001Sglebius			  const struct addrinfo *);
348290001Sglebiusstatic void trap_name_resolved(int, int, void *, const char *, const char *,
349290001Sglebius			const struct addrinfo *,
350290001Sglebius			const struct addrinfo *);
351290001Sglebius#endif
352290001Sglebius
353182007Srobertoenum gnn_type {
354182007Sroberto	t_UNK,		/* Unknown */
355182007Sroberto	t_REF,		/* Refclock */
356182007Sroberto	t_MSK		/* Network Mask */
357290001Sglebius};
35854359Sroberto
359290001Sglebiusstatic void ntpd_set_tod_using(const char *);
360290001Sglebiusstatic char * normal_dtoa(double);
361290001Sglebiusstatic u_int32 get_pfxmatch(const char **, struct masks *);
362290001Sglebiusstatic u_int32 get_match(const char *, struct masks *);
363290001Sglebiusstatic u_int32 get_logmask(const char *);
364290001Sglebius#ifndef SIM
365290001Sglebiusstatic int getnetnum(const char *num, sockaddr_u *addr, int complain,
366290001Sglebius		     enum gnn_type a_type);
367290001Sglebius
368290001Sglebius#endif
369290001Sglebius
370290001Sglebius
371290001Sglebius/* FUNCTIONS FOR INITIALIZATION
372290001Sglebius * ----------------------------
37354359Sroberto */
374290001Sglebius
375290001Sglebius#ifdef FREE_CFG_T
376290001Sglebiusstatic void
377290001Sglebiusfree_auth_node(
378290001Sglebius	config_tree *ptree
37954359Sroberto	)
38054359Sroberto{
381290001Sglebius	if (ptree->auth.keys) {
382290001Sglebius		free(ptree->auth.keys);
383290001Sglebius		ptree->auth.keys = NULL;
38454359Sroberto	}
385290001Sglebius
386290001Sglebius	if (ptree->auth.keysdir) {
387290001Sglebius		free(ptree->auth.keysdir);
388290001Sglebius		ptree->auth.keysdir = NULL;
389290001Sglebius	}
390290001Sglebius
391290001Sglebius	if (ptree->auth.ntp_signd_socket) {
392290001Sglebius		free(ptree->auth.ntp_signd_socket);
393290001Sglebius		ptree->auth.ntp_signd_socket = NULL;
394290001Sglebius	}
39554359Sroberto}
396290001Sglebius#endif /* DEBUG */
39754359Sroberto
398290001Sglebius
399290001Sglebiusstatic void
400290001Sglebiusinit_syntax_tree(
401290001Sglebius	config_tree *ptree
40254359Sroberto	)
40354359Sroberto{
404290001Sglebius	ZERO(*ptree);
405290001Sglebius	ptree->mdnstries = 5;
406290001Sglebius}
407290001Sglebius
408290001Sglebius
409290001Sglebius#ifdef FREE_CFG_T
410290001Sglebiusstatic void
411290001Sglebiusfree_all_config_trees(void)
412290001Sglebius{
413290001Sglebius	config_tree *ptree;
414290001Sglebius	config_tree *pnext;
415290001Sglebius
416290001Sglebius	ptree = cfg_tree_history;
417290001Sglebius
418290001Sglebius	while (ptree != NULL) {
419290001Sglebius		pnext = ptree->link;
420290001Sglebius		free_config_tree(ptree);
421290001Sglebius		ptree = pnext;
42254359Sroberto	}
42354359Sroberto}
42454359Sroberto
425290001Sglebius
426290001Sglebiusstatic void
427290001Sglebiusfree_config_tree(
428290001Sglebius	config_tree *ptree
42954359Sroberto	)
43054359Sroberto{
431290001Sglebius#if defined(_MSC_VER) && defined (_DEBUG)
432290001Sglebius	_CrtCheckMemory();
433290001Sglebius#endif
43454359Sroberto
435290001Sglebius	if (ptree->source.value.s != NULL)
436290001Sglebius		free(ptree->source.value.s);
43754359Sroberto
438290001Sglebius	free_config_other_modes(ptree);
439290001Sglebius	free_config_auth(ptree);
440290001Sglebius	free_config_tos(ptree);
441290001Sglebius	free_config_monitor(ptree);
442290001Sglebius	free_config_access(ptree);
443290001Sglebius	free_config_tinker(ptree);
444290001Sglebius	free_config_rlimit(ptree);
445290001Sglebius	free_config_system_opts(ptree);
446290001Sglebius	free_config_logconfig(ptree);
447290001Sglebius	free_config_phone(ptree);
448290001Sglebius	free_config_setvar(ptree);
449290001Sglebius	free_config_ttl(ptree);
450290001Sglebius	free_config_trap(ptree);
451290001Sglebius	free_config_fudge(ptree);
452290001Sglebius	free_config_vars(ptree);
453290001Sglebius	free_config_peers(ptree);
454290001Sglebius	free_config_unpeers(ptree);
455290001Sglebius	free_config_nic_rules(ptree);
456290001Sglebius	free_config_reset_counters(ptree);
457290001Sglebius#ifdef SIM
458290001Sglebius	free_config_sim(ptree);
459290001Sglebius#endif
460290001Sglebius	free_auth_node(ptree);
46154359Sroberto
462290001Sglebius	free(ptree);
463290001Sglebius
464290001Sglebius#if defined(_MSC_VER) && defined (_DEBUG)
465290001Sglebius	_CrtCheckMemory();
466290001Sglebius#endif
46754359Sroberto}
468290001Sglebius#endif /* FREE_CFG_T */
46954359Sroberto
47054359Sroberto
471290001Sglebius#ifdef SAVECONFIG
472290001Sglebius/* Dump all trees */
473290001Sglebiusint
474290001Sglebiusdump_all_config_trees(
475290001Sglebius	FILE *df,
476290001Sglebius	int comment
47754359Sroberto	)
47854359Sroberto{
479290001Sglebius	config_tree *	cfg_ptr;
480290001Sglebius	int		return_value;
48154359Sroberto
482290001Sglebius	return_value = 0;
483290001Sglebius	for (cfg_ptr = cfg_tree_history;
484290001Sglebius	     cfg_ptr != NULL;
485290001Sglebius	     cfg_ptr = cfg_ptr->link)
486290001Sglebius		return_value |= dump_config_tree(cfg_ptr, df, comment);
487290001Sglebius
488290001Sglebius	return return_value;
489290001Sglebius}
490290001Sglebius
491290001Sglebius
492290001Sglebius/* The config dumper */
493290001Sglebiusint
494290001Sglebiusdump_config_tree(
495290001Sglebius	config_tree *ptree,
496290001Sglebius	FILE *df,
497290001Sglebius	int comment
498290001Sglebius	)
499290001Sglebius{
500290001Sglebius	peer_node *peern;
501290001Sglebius	unpeer_node *unpeern;
502290001Sglebius	attr_val *atrv;
503290001Sglebius	address_node *addr;
504290001Sglebius	address_node *peer_addr;
505290001Sglebius	address_node *fudge_addr;
506290001Sglebius	filegen_node *fgen_node;
507290001Sglebius	restrict_node *rest_node;
508290001Sglebius	addr_opts_node *addr_opts;
509290001Sglebius	setvar_node *setv_node;
510290001Sglebius	nic_rule_node *rule_node;
511290001Sglebius	int_node *i_n;
512290001Sglebius	int_node *flags;
513290001Sglebius	int_node *counter_set;
514290001Sglebius	string_node *str_node;
515290001Sglebius
516290001Sglebius	const char *s = NULL;
517290001Sglebius	char *s1;
518290001Sglebius	char *s2;
519290001Sglebius	char timestamp[80];
520290001Sglebius	int enable;
521290001Sglebius
522290001Sglebius	DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
523290001Sglebius
524290001Sglebius	if (comment) {
525290001Sglebius		if (!strftime(timestamp, sizeof(timestamp),
526290001Sglebius			      "%Y-%m-%d %H:%M:%S",
527290001Sglebius			      localtime(&ptree->timestamp)))
528290001Sglebius			timestamp[0] = '\0';
529290001Sglebius
530290001Sglebius		fprintf(df, "# %s %s %s\n",
531290001Sglebius			timestamp,
532290001Sglebius			(CONF_SOURCE_NTPQ == ptree->source.attr)
533290001Sglebius			    ? "ntpq remote config from"
534290001Sglebius			    : "startup configuration file",
535290001Sglebius			ptree->source.value.s);
53654359Sroberto	}
53754359Sroberto
538290001Sglebius	/* For options I didn't find documentation I'll just output its name and the cor. value */
539290001Sglebius	atrv = HEAD_PFIFO(ptree->vars);
540290001Sglebius	for ( ; atrv != NULL; atrv = atrv->link) {
541290001Sglebius		switch (atrv->type) {
542290001Sglebius#ifdef DEBUG
543290001Sglebius		default:
544290001Sglebius			fprintf(df, "\n# dump error:\n"
545290001Sglebius				"# unknown vars type %d (%s) for %s\n",
546290001Sglebius				atrv->type, token_name(atrv->type),
547290001Sglebius				token_name(atrv->attr));
548290001Sglebius			break;
549290001Sglebius#endif
550290001Sglebius		case T_Double:
551290001Sglebius			fprintf(df, "%s %s\n", keyword(atrv->attr),
552290001Sglebius				normal_dtoa(atrv->value.d));
553290001Sglebius			break;
554290001Sglebius
555290001Sglebius		case T_Integer:
556290001Sglebius			fprintf(df, "%s %d\n", keyword(atrv->attr),
557290001Sglebius				atrv->value.i);
558290001Sglebius			break;
559290001Sglebius
560290001Sglebius		case T_String:
561290001Sglebius			fprintf(df, "%s \"%s\"", keyword(atrv->attr),
562290001Sglebius				atrv->value.s);
563290001Sglebius			if (T_Driftfile == atrv->attr &&
564290001Sglebius			    atrv->link != NULL &&
565290001Sglebius			    T_WanderThreshold == atrv->link->attr) {
566290001Sglebius				atrv = atrv->link;
567290001Sglebius				fprintf(df, " %s\n",
568290001Sglebius					normal_dtoa(atrv->value.d));
569290001Sglebius			} else {
570290001Sglebius				fprintf(df, "\n");
571290001Sglebius			}
572290001Sglebius			break;
573290001Sglebius		}
57454359Sroberto	}
57554359Sroberto
576290001Sglebius	atrv = HEAD_PFIFO(ptree->logconfig);
577290001Sglebius	if (atrv != NULL) {
578290001Sglebius		fprintf(df, "logconfig");
579290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link)
580290001Sglebius			fprintf(df, " %c%s", atrv->attr, atrv->value.s);
581290001Sglebius		fprintf(df, "\n");
582290001Sglebius	}
58354359Sroberto
584290001Sglebius	if (ptree->stats_dir)
585290001Sglebius		fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
58654359Sroberto
587290001Sglebius	i_n = HEAD_PFIFO(ptree->stats_list);
588290001Sglebius	if (i_n != NULL) {
589290001Sglebius		fprintf(df, "statistics");
590290001Sglebius		for ( ; i_n != NULL; i_n = i_n->link)
591290001Sglebius			fprintf(df, " %s", keyword(i_n->i));
592290001Sglebius		fprintf(df, "\n");
593290001Sglebius	}
59454359Sroberto
595290001Sglebius	fgen_node = HEAD_PFIFO(ptree->filegen_opts);
596290001Sglebius	for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
597290001Sglebius		atrv = HEAD_PFIFO(fgen_node->options);
598290001Sglebius		if (atrv != NULL) {
599290001Sglebius			fprintf(df, "filegen %s",
600290001Sglebius				keyword(fgen_node->filegen_token));
601290001Sglebius			for ( ; atrv != NULL; atrv = atrv->link) {
602290001Sglebius				switch (atrv->attr) {
603290001Sglebius#ifdef DEBUG
604290001Sglebius				default:
605290001Sglebius					fprintf(df, "\n# dump error:\n"
606290001Sglebius						"# unknown filegen option token %s\n"
607290001Sglebius						"filegen %s",
608290001Sglebius						token_name(atrv->attr),
609290001Sglebius						keyword(fgen_node->filegen_token));
610290001Sglebius					break;
611290001Sglebius#endif
612290001Sglebius				case T_File:
613290001Sglebius					fprintf(df, " file %s",
614290001Sglebius						atrv->value.s);
615290001Sglebius					break;
61654359Sroberto
617290001Sglebius				case T_Type:
618290001Sglebius					fprintf(df, " type %s",
619290001Sglebius						keyword(atrv->value.i));
620290001Sglebius					break;
62154359Sroberto
622290001Sglebius				case T_Flag:
623290001Sglebius					fprintf(df, " %s",
624290001Sglebius						keyword(atrv->value.i));
625290001Sglebius					break;
626290001Sglebius				}
627290001Sglebius			}
628290001Sglebius			fprintf(df, "\n");
629290001Sglebius		}
630290001Sglebius	}
63154359Sroberto
632290001Sglebius	atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
633290001Sglebius	if (atrv != NULL) {
634290001Sglebius		fprintf(df, "crypto");
635290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
636290001Sglebius			fprintf(df, " %s %s", keyword(atrv->attr),
637290001Sglebius				atrv->value.s);
638290001Sglebius		}
639290001Sglebius		fprintf(df, "\n");
640290001Sglebius	}
64154359Sroberto
642290001Sglebius	if (ptree->auth.revoke != 0)
643290001Sglebius		fprintf(df, "revoke %d\n", ptree->auth.revoke);
64454359Sroberto
645290001Sglebius	if (ptree->auth.keysdir != NULL)
646290001Sglebius		fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
647290001Sglebius
648290001Sglebius	if (ptree->auth.keys != NULL)
649290001Sglebius		fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
650290001Sglebius
651290001Sglebius	atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
652290001Sglebius	if (atrv != NULL) {
653290001Sglebius		fprintf(df, "trustedkey");
654290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
655290001Sglebius			if (T_Integer == atrv->type)
656290001Sglebius				fprintf(df, " %d", atrv->value.i);
657290001Sglebius			else if (T_Intrange == atrv->type)
658290001Sglebius				fprintf(df, " (%d ... %d)",
659290001Sglebius					atrv->value.r.first,
660290001Sglebius					atrv->value.r.last);
661290001Sglebius#ifdef DEBUG
662290001Sglebius			else
663290001Sglebius				fprintf(df, "\n# dump error:\n"
664290001Sglebius					"# unknown trustedkey attr type %d\n"
665290001Sglebius					"trustedkey", atrv->type);
666290001Sglebius#endif
66754359Sroberto		}
668290001Sglebius		fprintf(df, "\n");
66954359Sroberto	}
67054359Sroberto
671290001Sglebius	if (ptree->auth.control_key)
672290001Sglebius		fprintf(df, "controlkey %d\n", ptree->auth.control_key);
673260643Sdelphij
674290001Sglebius	if (ptree->auth.request_key)
675290001Sglebius		fprintf(df, "requestkey %d\n", ptree->auth.request_key);
676290001Sglebius
677290001Sglebius	/* dump enable list, then disable list */
678290001Sglebius	for (enable = 1; enable >= 0; enable--) {
679290001Sglebius		atrv = (enable)
680290001Sglebius			   ? HEAD_PFIFO(ptree->enable_opts)
681290001Sglebius			   : HEAD_PFIFO(ptree->disable_opts);
682290001Sglebius		if (atrv != NULL) {
683290001Sglebius			fprintf(df, "%s", (enable)
684290001Sglebius					? "enable"
685290001Sglebius					: "disable");
686290001Sglebius			for ( ; atrv != NULL; atrv = atrv->link)
687290001Sglebius				fprintf(df, " %s",
688290001Sglebius					keyword(atrv->value.i));
689290001Sglebius			fprintf(df, "\n");
690290001Sglebius		}
691290001Sglebius	}
692290001Sglebius
693290001Sglebius	atrv = HEAD_PFIFO(ptree->orphan_cmds);
694290001Sglebius	if (atrv != NULL) {
695290001Sglebius		fprintf(df, "tos");
696290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
697290001Sglebius			switch (atrv->type) {
698290001Sglebius#ifdef DEBUG
699290001Sglebius			default:
700290001Sglebius				fprintf(df, "\n# dump error:\n"
701290001Sglebius					"# unknown tos attr type %d %s\n"
702290001Sglebius					"tos", atrv->type,
703290001Sglebius					token_name(atrv->type));
704290001Sglebius				break;
705290001Sglebius#endif
706290001Sglebius			case T_Double:
707290001Sglebius				fprintf(df, " %s %s",
708290001Sglebius					keyword(atrv->attr),
709290001Sglebius					normal_dtoa(atrv->value.d));
710290001Sglebius				break;
711290001Sglebius			}
712290001Sglebius		}
713290001Sglebius		fprintf(df, "\n");
714290001Sglebius	}
715290001Sglebius
716290001Sglebius	atrv = HEAD_PFIFO(ptree->rlimit);
717290001Sglebius	if (atrv != NULL) {
718290001Sglebius		fprintf(df, "rlimit");
719290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
720290001Sglebius			INSIST(T_Integer == atrv->type);
721290001Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
722290001Sglebius				atrv->value.i);
723290001Sglebius		}
724290001Sglebius		fprintf(df, "\n");
725290001Sglebius	}
726290001Sglebius
727290001Sglebius	atrv = HEAD_PFIFO(ptree->tinker);
728290001Sglebius	if (atrv != NULL) {
729290001Sglebius		fprintf(df, "tinker");
730290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
731290001Sglebius			INSIST(T_Double == atrv->type);
732290001Sglebius			fprintf(df, " %s %s", keyword(atrv->attr),
733290001Sglebius				normal_dtoa(atrv->value.d));
734290001Sglebius		}
735290001Sglebius		fprintf(df, "\n");
736290001Sglebius	}
737290001Sglebius
738290001Sglebius	if (ptree->broadcastclient)
739290001Sglebius		fprintf(df, "broadcastclient\n");
740290001Sglebius
741290001Sglebius	peern = HEAD_PFIFO(ptree->peers);
742290001Sglebius	for ( ; peern != NULL; peern = peern->link) {
743290001Sglebius		addr = peern->addr;
744290001Sglebius		fprintf(df, "%s", keyword(peern->host_mode));
745290001Sglebius		switch (addr->type) {
746290001Sglebius#ifdef DEBUG
747290001Sglebius		default:
748290001Sglebius			fprintf(df, "# dump error:\n"
749290001Sglebius				"# unknown peer family %d for:\n"
750290001Sglebius				"%s", addr->type,
751290001Sglebius				keyword(peern->host_mode));
752182007Sroberto			break;
753290001Sglebius#endif
754290001Sglebius		case AF_UNSPEC:
755290001Sglebius			break;
75654359Sroberto
757290001Sglebius		case AF_INET:
758290001Sglebius			fprintf(df, " -4");
75982498Sroberto			break;
760290001Sglebius
761290001Sglebius		case AF_INET6:
762290001Sglebius			fprintf(df, " -6");
763290001Sglebius			break;
76482498Sroberto		}
765290001Sglebius		fprintf(df, " %s", addr->address);
76654359Sroberto
767290001Sglebius		if (peern->minpoll != 0)
768290001Sglebius			fprintf(df, " minpoll %u", peern->minpoll);
769290001Sglebius
770290001Sglebius		if (peern->maxpoll != 0)
771290001Sglebius			fprintf(df, " maxpoll %u", peern->maxpoll);
772290001Sglebius
773290001Sglebius		if (peern->ttl != 0) {
774290001Sglebius			if (strlen(addr->address) > 8
775290001Sglebius			    && !memcmp(addr->address, "127.127.", 8))
776290001Sglebius				fprintf(df, " mode %u", peern->ttl);
77754359Sroberto			else
778290001Sglebius				fprintf(df, " ttl %u", peern->ttl);
779290001Sglebius		}
78054359Sroberto
781290001Sglebius		if (peern->peerversion != NTP_VERSION)
782290001Sglebius			fprintf(df, " version %u", peern->peerversion);
78354359Sroberto
784290001Sglebius		if (peern->peerkey != 0)
785290001Sglebius			fprintf(df, " key %u", peern->peerkey);
786132451Sroberto
787290001Sglebius		if (peern->group != NULL)
788290001Sglebius			fprintf(df, " ident \"%s\"", peern->group);
78954359Sroberto
790290001Sglebius		atrv = HEAD_PFIFO(peern->peerflags);
791290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
792290001Sglebius			INSIST(T_Flag == atrv->attr);
793290001Sglebius			INSIST(T_Integer == atrv->type);
794290001Sglebius			fprintf(df, " %s", keyword(atrv->value.i));
795290001Sglebius		}
796290001Sglebius
797290001Sglebius		fprintf(df, "\n");
798290001Sglebius
799290001Sglebius		addr_opts = HEAD_PFIFO(ptree->fudge);
800290001Sglebius		for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
801290001Sglebius			peer_addr = peern->addr;
802290001Sglebius			fudge_addr = addr_opts->addr;
803290001Sglebius
804290001Sglebius			s1 = peer_addr->address;
805290001Sglebius			s2 = fudge_addr->address;
806290001Sglebius
807290001Sglebius			if (strcmp(s1, s2))
808290001Sglebius				continue;
809290001Sglebius
810290001Sglebius			fprintf(df, "fudge %s", s1);
811290001Sglebius
812290001Sglebius			for (atrv = HEAD_PFIFO(addr_opts->options);
813290001Sglebius			     atrv != NULL;
814290001Sglebius			     atrv = atrv->link) {
815290001Sglebius
816290001Sglebius				switch (atrv->type) {
817290001Sglebius#ifdef DEBUG
818290001Sglebius				default:
819290001Sglebius					fprintf(df, "\n# dump error:\n"
820290001Sglebius						"# unknown fudge atrv->type %d\n"
821290001Sglebius						"fudge %s", atrv->type,
822290001Sglebius						s1);
823290001Sglebius					break;
82454359Sroberto#endif
825290001Sglebius				case T_Double:
826290001Sglebius					fprintf(df, " %s %s",
827290001Sglebius						keyword(atrv->attr),
828290001Sglebius						normal_dtoa(atrv->value.d));
82954359Sroberto					break;
830290001Sglebius
831290001Sglebius				case T_Integer:
832290001Sglebius					fprintf(df, " %s %d",
833290001Sglebius						keyword(atrv->attr),
834290001Sglebius						atrv->value.i);
835290001Sglebius					break;
836290001Sglebius
837290001Sglebius				case T_String:
838290001Sglebius					fprintf(df, " %s %s",
839290001Sglebius						keyword(atrv->attr),
840290001Sglebius						atrv->value.s);
841290001Sglebius					break;
84254359Sroberto				}
843290001Sglebius			}
844290001Sglebius			fprintf(df, "\n");
845290001Sglebius		}
846290001Sglebius	}
847290001Sglebius
848290001Sglebius	addr = HEAD_PFIFO(ptree->manycastserver);
849290001Sglebius	if (addr != NULL) {
850290001Sglebius		fprintf(df, "manycastserver");
851290001Sglebius		for ( ; addr != NULL; addr = addr->link)
852290001Sglebius			fprintf(df, " %s", addr->address);
853290001Sglebius		fprintf(df, "\n");
854290001Sglebius	}
855290001Sglebius
856290001Sglebius	addr = HEAD_PFIFO(ptree->multicastclient);
857290001Sglebius	if (addr != NULL) {
858290001Sglebius		fprintf(df, "multicastclient");
859290001Sglebius		for ( ; addr != NULL; addr = addr->link)
860290001Sglebius			fprintf(df, " %s", addr->address);
861290001Sglebius		fprintf(df, "\n");
862290001Sglebius	}
863290001Sglebius
864290001Sglebius
865290001Sglebius	for (unpeern = HEAD_PFIFO(ptree->unpeers);
866290001Sglebius	     unpeern != NULL;
867290001Sglebius	     unpeern = unpeern->link)
868290001Sglebius		fprintf(df, "unpeer %s\n", unpeern->addr->address);
869290001Sglebius
870290001Sglebius	atrv = HEAD_PFIFO(ptree->mru_opts);
871290001Sglebius	if (atrv != NULL) {
872290001Sglebius		fprintf(df, "mru");
873290001Sglebius		for ( ;	atrv != NULL; atrv = atrv->link)
874290001Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
875290001Sglebius				atrv->value.i);
876290001Sglebius		fprintf(df, "\n");
877290001Sglebius	}
878290001Sglebius
879290001Sglebius	atrv = HEAD_PFIFO(ptree->discard_opts);
880290001Sglebius	if (atrv != NULL) {
881290001Sglebius		fprintf(df, "discard");
882290001Sglebius		for ( ;	atrv != NULL; atrv = atrv->link)
883290001Sglebius			fprintf(df, " %s %d", keyword(atrv->attr),
884290001Sglebius				atrv->value.i);
885290001Sglebius		fprintf(df, "\n");
886290001Sglebius	}
887290001Sglebius
888290001Sglebius
889290001Sglebius	for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
890290001Sglebius	     rest_node != NULL;
891290001Sglebius	     rest_node = rest_node->link) {
892290001Sglebius
893290001Sglebius		if (NULL == rest_node->addr) {
894290001Sglebius			s = "default";
895290001Sglebius			flags = HEAD_PFIFO(rest_node->flags);
896290001Sglebius			for ( ; flags != NULL; flags = flags->link)
897290001Sglebius				if (T_Source == flags->i) {
898290001Sglebius					s = "source";
899290001Sglebius					break;
90054359Sroberto				}
901290001Sglebius		} else {
902290001Sglebius			s = rest_node->addr->address;
903290001Sglebius		}
904290001Sglebius		fprintf(df, "restrict %s", s);
905290001Sglebius		if (rest_node->mask != NULL)
906290001Sglebius			fprintf(df, " mask %s",
907290001Sglebius				rest_node->mask->address);
908290001Sglebius		flags = HEAD_PFIFO(rest_node->flags);
909290001Sglebius		for ( ; flags != NULL; flags = flags->link)
910290001Sglebius			if (T_Source != flags->i)
911290001Sglebius				fprintf(df, " %s", keyword(flags->i));
912290001Sglebius		fprintf(df, "\n");
913290001Sglebius	}
914290001Sglebius
915290001Sglebius	rule_node = HEAD_PFIFO(ptree->nic_rules);
916290001Sglebius	for ( ; rule_node != NULL; rule_node = rule_node->link) {
917290001Sglebius		fprintf(df, "interface %s %s\n",
918290001Sglebius			keyword(rule_node->action),
919290001Sglebius			(rule_node->match_class)
920290001Sglebius			    ? keyword(rule_node->match_class)
921290001Sglebius			    : rule_node->if_name);
922290001Sglebius	}
923290001Sglebius
924290001Sglebius	str_node = HEAD_PFIFO(ptree->phone);
925290001Sglebius	if (str_node != NULL) {
926290001Sglebius		fprintf(df, "phone");
927290001Sglebius		for ( ; str_node != NULL; str_node = str_node->link)
928290001Sglebius			fprintf(df, " \"%s\"", str_node->s);
929290001Sglebius		fprintf(df, "\n");
930290001Sglebius	}
931290001Sglebius
932290001Sglebius	setv_node = HEAD_PFIFO(ptree->setvar);
933290001Sglebius	for ( ; setv_node != NULL; setv_node = setv_node->link) {
934290001Sglebius		s1 = quote_if_needed(setv_node->var);
935290001Sglebius		s2 = quote_if_needed(setv_node->val);
936290001Sglebius		fprintf(df, "setvar %s = %s", s1, s2);
937290001Sglebius		free(s1);
938290001Sglebius		free(s2);
939290001Sglebius		if (setv_node->isdefault)
940290001Sglebius			fprintf(df, " default");
941290001Sglebius		fprintf(df, "\n");
942290001Sglebius	}
943290001Sglebius
944290001Sglebius	i_n = HEAD_PFIFO(ptree->ttl);
945290001Sglebius	if (i_n != NULL) {
946290001Sglebius		fprintf(df, "ttl");
947290001Sglebius		for( ; i_n != NULL; i_n = i_n->link)
948290001Sglebius			fprintf(df, " %d", i_n->i);
949290001Sglebius		fprintf(df, "\n");
950290001Sglebius	}
951290001Sglebius
952290001Sglebius	addr_opts = HEAD_PFIFO(ptree->trap);
953290001Sglebius	for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
954290001Sglebius		addr = addr_opts->addr;
955290001Sglebius		fprintf(df, "trap %s", addr->address);
956290001Sglebius		atrv = HEAD_PFIFO(addr_opts->options);
957290001Sglebius		for ( ; atrv != NULL; atrv = atrv->link) {
958290001Sglebius			switch (atrv->attr) {
959290001Sglebius#ifdef DEBUG
960290001Sglebius			default:
961290001Sglebius				fprintf(df, "\n# dump error:\n"
962290001Sglebius					"# unknown trap token %d\n"
963290001Sglebius					"trap %s", atrv->attr,
964290001Sglebius					addr->address);
965290001Sglebius				break;
966132451Sroberto#endif
967290001Sglebius			case T_Port:
968290001Sglebius				fprintf(df, " port %d", atrv->value.i);
969182007Sroberto				break;
970182007Sroberto
971290001Sglebius			case T_Interface:
972290001Sglebius				fprintf(df, " interface %s",
973290001Sglebius					atrv->value.s);
974290001Sglebius				break;
975290001Sglebius			}
976290001Sglebius		}
977290001Sglebius		fprintf(df, "\n");
978290001Sglebius	}
97954359Sroberto
980290001Sglebius	counter_set = HEAD_PFIFO(ptree->reset_counters);
981290001Sglebius	if (counter_set != NULL) {
982290001Sglebius		fprintf(df, "reset");
983290001Sglebius		for ( ; counter_set != NULL;
984290001Sglebius		     counter_set = counter_set->link)
985290001Sglebius			fprintf(df, " %s", keyword(counter_set->i));
986290001Sglebius		fprintf(df, "\n");
987290001Sglebius	}
98854359Sroberto
989290001Sglebius	return 0;
990290001Sglebius}
991290001Sglebius#endif	/* SAVECONFIG */
99254359Sroberto
99354359Sroberto
994182007Sroberto
995290001Sglebius/* generic fifo routines for structs linked by 1st member */
996290001Sglebiusvoid *
997290001Sglebiusappend_gen_fifo(
998290001Sglebius	void *fifo,
999290001Sglebius	void *entry
1000290001Sglebius	)
1001290001Sglebius{
1002290001Sglebius	gen_fifo *pf;
1003290001Sglebius	gen_node *pe;
100454359Sroberto
1005290001Sglebius	pf = fifo;
1006290001Sglebius	pe = entry;
1007290001Sglebius	if (NULL == pf)
1008290001Sglebius		pf = emalloc_zero(sizeof(*pf));
1009290001Sglebius	else
1010290001Sglebius		CHECK_FIFO_CONSISTENCY(*pf);
1011290001Sglebius	if (pe != NULL)
1012290001Sglebius		LINK_FIFO(*pf, pe, link);
1013290001Sglebius	CHECK_FIFO_CONSISTENCY(*pf);
1014182007Sroberto
1015290001Sglebius	return pf;
1016290001Sglebius}
101754359Sroberto
1018182007Sroberto
1019290001Sglebiusvoid *
1020290001Sglebiusconcat_gen_fifos(
1021290001Sglebius	void *first,
1022290001Sglebius	void *second
1023290001Sglebius	)
1024290001Sglebius{
1025290001Sglebius	gen_fifo *pf1;
1026290001Sglebius	gen_fifo *pf2;
1027182007Sroberto
1028290001Sglebius	pf1 = first;
1029290001Sglebius	pf2 = second;
1030290001Sglebius	if (NULL == pf1)
1031290001Sglebius		return pf2;
1032290001Sglebius	if (NULL == pf2)
1033290001Sglebius		return pf1;
103454359Sroberto
1035290001Sglebius	CONCAT_FIFO(*pf1, *pf2, link);
1036290001Sglebius	free(pf2);
103754359Sroberto
1038290001Sglebius	return pf1;
1039290001Sglebius}
104054359Sroberto
104154359Sroberto
1042290001Sglebius/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
1043290001Sglebius * -----------------------------------------------
1044290001Sglebius */
104554359Sroberto
1046290001Sglebiusattr_val *
1047290001Sglebiuscreate_attr_dval(
1048290001Sglebius	int attr,
1049290001Sglebius	double value
1050290001Sglebius	)
1051290001Sglebius{
1052290001Sglebius	attr_val *my_val;
105382498Sroberto
1054290001Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1055290001Sglebius	my_val->attr = attr;
1056290001Sglebius	my_val->value.d = value;
1057290001Sglebius	my_val->type = T_Double;
105882498Sroberto
1059290001Sglebius	return my_val;
1060290001Sglebius}
106154359Sroberto
1062290001Sglebius
1063290001Sglebiusattr_val *
1064290001Sglebiuscreate_attr_ival(
1065290001Sglebius	int attr,
1066290001Sglebius	int value
1067290001Sglebius	)
1068290001Sglebius{
1069290001Sglebius	attr_val *my_val;
1070290001Sglebius
1071290001Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1072290001Sglebius	my_val->attr = attr;
1073290001Sglebius	my_val->value.i = value;
1074290001Sglebius	my_val->type = T_Integer;
1075290001Sglebius
1076290001Sglebius	return my_val;
1077290001Sglebius}
1078290001Sglebius
1079290001Sglebius
1080290001Sglebiusattr_val *
1081290001Sglebiuscreate_attr_uval(
1082290001Sglebius	int	attr,
1083290001Sglebius	u_int	value
1084290001Sglebius	)
1085290001Sglebius{
1086290001Sglebius	attr_val *my_val;
1087290001Sglebius
1088290001Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1089290001Sglebius	my_val->attr = attr;
1090290001Sglebius	my_val->value.u = value;
1091290001Sglebius	my_val->type = T_U_int;
1092290001Sglebius
1093290001Sglebius	return my_val;
1094290001Sglebius}
1095290001Sglebius
1096290001Sglebius
1097290001Sglebiusattr_val *
1098290001Sglebiuscreate_attr_rangeval(
1099290001Sglebius	int	attr,
1100290001Sglebius	int	first,
1101290001Sglebius	int	last
1102290001Sglebius	)
1103290001Sglebius{
1104290001Sglebius	attr_val *my_val;
1105290001Sglebius
1106290001Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1107290001Sglebius	my_val->attr = attr;
1108290001Sglebius	my_val->value.r.first = first;
1109290001Sglebius	my_val->value.r.last = last;
1110290001Sglebius	my_val->type = T_Intrange;
1111290001Sglebius
1112290001Sglebius	return my_val;
1113290001Sglebius}
1114290001Sglebius
1115290001Sglebius
1116290001Sglebiusattr_val *
1117290001Sglebiuscreate_attr_sval(
1118290001Sglebius	int attr,
1119290001Sglebius	const char *s
1120290001Sglebius	)
1121290001Sglebius{
1122290001Sglebius	attr_val *my_val;
1123290001Sglebius
1124290001Sglebius	my_val = emalloc_zero(sizeof(*my_val));
1125290001Sglebius	my_val->attr = attr;
1126290001Sglebius	if (NULL == s)			/* free() hates NULL */
1127290001Sglebius		s = estrdup("");
1128290001Sglebius	my_val->value.s = _UC(s);
1129290001Sglebius	my_val->type = T_String;
1130290001Sglebius
1131290001Sglebius	return my_val;
1132290001Sglebius}
1133290001Sglebius
1134290001Sglebius
1135290001Sglebiusint_node *
1136290001Sglebiuscreate_int_node(
1137290001Sglebius	int val
1138290001Sglebius	)
1139290001Sglebius{
1140290001Sglebius	int_node *i_n;
1141290001Sglebius
1142290001Sglebius	i_n = emalloc_zero(sizeof(*i_n));
1143290001Sglebius	i_n->i = val;
1144290001Sglebius
1145290001Sglebius	return i_n;
1146290001Sglebius}
1147290001Sglebius
1148290001Sglebius
1149290001Sglebiusstring_node *
1150290001Sglebiuscreate_string_node(
1151290001Sglebius	char *str
1152290001Sglebius	)
1153290001Sglebius{
1154290001Sglebius	string_node *sn;
1155290001Sglebius
1156290001Sglebius	sn = emalloc_zero(sizeof(*sn));
1157290001Sglebius	sn->s = str;
1158290001Sglebius
1159290001Sglebius	return sn;
1160290001Sglebius}
1161290001Sglebius
1162290001Sglebius
1163290001Sglebiusaddress_node *
1164290001Sglebiuscreate_address_node(
1165290001Sglebius	char *	addr,
1166290001Sglebius	int	type
1167290001Sglebius	)
1168290001Sglebius{
1169290001Sglebius	address_node *my_node;
1170290001Sglebius
1171290001Sglebius	REQUIRE(NULL != addr);
1172290001Sglebius	REQUIRE(AF_INET == type || AF_INET6 == type || AF_UNSPEC == type);
1173290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1174290001Sglebius	my_node->address = addr;
1175290001Sglebius	my_node->type = (u_short)type;
1176290001Sglebius
1177290001Sglebius	return my_node;
1178290001Sglebius}
1179290001Sglebius
1180290001Sglebius
1181290001Sglebiusvoid
1182290001Sglebiusdestroy_address_node(
1183290001Sglebius	address_node *my_node
1184290001Sglebius	)
1185290001Sglebius{
1186290001Sglebius	if (NULL == my_node)
1187290001Sglebius		return;
1188290001Sglebius	REQUIRE(NULL != my_node->address);
1189290001Sglebius
1190290001Sglebius	free(my_node->address);
1191290001Sglebius	free(my_node);
1192290001Sglebius}
1193290001Sglebius
1194290001Sglebius
1195290001Sglebiuspeer_node *
1196290001Sglebiuscreate_peer_node(
1197290001Sglebius	int		hmode,
1198290001Sglebius	address_node *	addr,
1199290001Sglebius	attr_val_fifo *	options
1200290001Sglebius	)
1201290001Sglebius{
1202290001Sglebius	peer_node *my_node;
1203290001Sglebius	attr_val *option;
1204290001Sglebius	int freenode;
1205290001Sglebius	int errflag = 0;
1206290001Sglebius
1207290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1208290001Sglebius
1209290001Sglebius	/* Initialize node values to default */
1210290001Sglebius	my_node->peerversion = NTP_VERSION;
1211290001Sglebius
1212290001Sglebius	/* Now set the node to the read values */
1213290001Sglebius	my_node->host_mode = hmode;
1214290001Sglebius	my_node->addr = addr;
1215290001Sglebius
1216290001Sglebius	/*
1217290001Sglebius	 * the options FIFO mixes items that will be saved in the
1218290001Sglebius	 * peer_node as explicit members, such as minpoll, and
1219290001Sglebius	 * those that are moved intact to the peer_node's peerflags
1220290001Sglebius	 * FIFO.  The options FIFO is consumed and reclaimed here.
1221290001Sglebius	 */
1222290001Sglebius
1223290001Sglebius	if (options != NULL)
1224290001Sglebius		CHECK_FIFO_CONSISTENCY(*options);
1225290001Sglebius	while (options != NULL) {
1226290001Sglebius		UNLINK_FIFO(option, *options, link);
1227290001Sglebius		if (NULL == option) {
1228290001Sglebius			free(options);
122954359Sroberto			break;
1230290001Sglebius		}
123154359Sroberto
1232290001Sglebius		freenode = 1;
1233290001Sglebius		/* Check the kind of option being set */
1234290001Sglebius		switch (option->attr) {
123554359Sroberto
1236290001Sglebius		case T_Flag:
1237290001Sglebius			APPEND_G_FIFO(my_node->peerflags, option);
1238290001Sglebius			freenode = 0;
1239290001Sglebius			break;
124054359Sroberto
1241290001Sglebius		case T_Minpoll:
1242290001Sglebius			if (option->value.i < NTP_MINPOLL ||
1243290001Sglebius			    option->value.i > UCHAR_MAX) {
1244290001Sglebius				msyslog(LOG_INFO,
1245290001Sglebius					"minpoll: provided value (%d) is out of range [%d-%d])",
1246290001Sglebius					option->value.i, NTP_MINPOLL,
1247290001Sglebius					UCHAR_MAX);
1248290001Sglebius				my_node->minpoll = NTP_MINPOLL;
1249290001Sglebius			} else {
1250290001Sglebius				my_node->minpoll =
1251290001Sglebius					(u_char)option->value.u;
125254359Sroberto			}
125354359Sroberto			break;
125454359Sroberto
1255290001Sglebius		case T_Maxpoll:
1256290001Sglebius			if (option->value.i < 0 ||
1257290001Sglebius			    option->value.i > NTP_MAXPOLL) {
1258290001Sglebius				msyslog(LOG_INFO,
1259290001Sglebius					"maxpoll: provided value (%d) is out of range [0-%d])",
1260290001Sglebius					option->value.i, NTP_MAXPOLL);
1261290001Sglebius				my_node->maxpoll = NTP_MAXPOLL;
1262182007Sroberto			} else {
1263290001Sglebius				my_node->maxpoll =
1264290001Sglebius					(u_char)option->value.u;
1265182007Sroberto			}
126654359Sroberto			break;
1267132451Sroberto
1268290001Sglebius		case T_Ttl:
1269290001Sglebius			if (option->value.u >= MAX_TTL) {
1270290001Sglebius				msyslog(LOG_ERR, "ttl: invalid argument");
1271290001Sglebius				errflag = 1;
1272290001Sglebius			} else {
1273290001Sglebius				my_node->ttl = (u_char)option->value.u;
1274290001Sglebius			}
1275290001Sglebius			break;
1276132451Sroberto
1277290001Sglebius		case T_Mode:
1278290001Sglebius			my_node->ttl = option->value.u;
127954359Sroberto			break;
128054359Sroberto
1281290001Sglebius		case T_Key:
1282290001Sglebius			if (option->value.u >= KEYID_T_MAX) {
1283290001Sglebius				msyslog(LOG_ERR, "key: invalid argument");
1284290001Sglebius				errflag = 1;
1285290001Sglebius			} else {
1286290001Sglebius				my_node->peerkey =
1287290001Sglebius					(keyid_t)option->value.u;
128854359Sroberto			}
1289132451Sroberto			break;
129054359Sroberto
1291290001Sglebius		case T_Version:
1292290001Sglebius			if (option->value.u >= UCHAR_MAX) {
1293290001Sglebius				msyslog(LOG_ERR, "version: invalid argument");
1294290001Sglebius				errflag = 1;
1295290001Sglebius			} else {
1296290001Sglebius				my_node->peerversion =
1297290001Sglebius					(u_char)option->value.u;
129854359Sroberto			}
129954359Sroberto			break;
130054359Sroberto
1301290001Sglebius		case T_Ident:
1302290001Sglebius			my_node->group = option->value.s;
1303290001Sglebius			break;
130482498Sroberto
1305290001Sglebius		default:
1306290001Sglebius			msyslog(LOG_ERR,
1307290001Sglebius				"Unknown peer/server option token %s",
1308290001Sglebius				token_name(option->attr));
1309290001Sglebius			errflag = 1;
1310290001Sglebius		}
1311290001Sglebius		if (freenode)
1312290001Sglebius			free(option);
1313290001Sglebius	}
1314290001Sglebius
1315290001Sglebius	/* Check if errors were reported. If yes, ignore the node */
1316290001Sglebius	if (errflag) {
1317290001Sglebius		free(my_node);
1318290001Sglebius		my_node = NULL;
1319290001Sglebius	}
1320290001Sglebius
1321290001Sglebius	return my_node;
1322290001Sglebius}
1323290001Sglebius
1324290001Sglebius
1325290001Sglebiusunpeer_node *
1326290001Sglebiuscreate_unpeer_node(
1327290001Sglebius	address_node *addr
1328290001Sglebius	)
1329290001Sglebius{
1330290001Sglebius	unpeer_node *	my_node;
1331290001Sglebius	u_int		u;
1332290001Sglebius	char *		pch;
1333290001Sglebius
1334290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1335290001Sglebius
1336290001Sglebius	/*
1337290001Sglebius	 * From the parser's perspective an association ID fits into
1338290001Sglebius	 * its generic T_String definition of a name/address "address".
1339290001Sglebius	 * We treat all valid 16-bit numbers as association IDs.
1340290001Sglebius	 */
1341290001Sglebius	pch = addr->address;
1342290001Sglebius	while (*pch && isdigit((unsigned char)*pch))
1343290001Sglebius		pch++;
1344290001Sglebius
1345290001Sglebius	if (!*pch
1346290001Sglebius	    && 1 == sscanf(addr->address, "%u", &u)
1347290001Sglebius	    && u <= ASSOCID_MAX) {
1348290001Sglebius		my_node->assocID = (associd_t)u;
1349290001Sglebius		destroy_address_node(addr);
1350290001Sglebius		my_node->addr = NULL;
1351290001Sglebius	} else {
1352290001Sglebius		my_node->assocID = 0;
1353290001Sglebius		my_node->addr = addr;
1354290001Sglebius	}
1355290001Sglebius
1356290001Sglebius	return my_node;
1357290001Sglebius}
1358290001Sglebius
1359290001Sglebiusfilegen_node *
1360290001Sglebiuscreate_filegen_node(
1361290001Sglebius	int		filegen_token,
1362290001Sglebius	attr_val_fifo *	options
1363290001Sglebius	)
1364290001Sglebius{
1365290001Sglebius	filegen_node *my_node;
1366290001Sglebius
1367290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1368290001Sglebius	my_node->filegen_token = filegen_token;
1369290001Sglebius	my_node->options = options;
1370290001Sglebius
1371290001Sglebius	return my_node;
1372290001Sglebius}
1373290001Sglebius
1374290001Sglebius
1375290001Sglebiusrestrict_node *
1376290001Sglebiuscreate_restrict_node(
1377290001Sglebius	address_node *	addr,
1378290001Sglebius	address_node *	mask,
1379290001Sglebius	int_fifo *	flags,
1380290001Sglebius	int		line_no
1381290001Sglebius	)
1382290001Sglebius{
1383290001Sglebius	restrict_node *my_node;
1384290001Sglebius
1385290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1386290001Sglebius	my_node->addr = addr;
1387290001Sglebius	my_node->mask = mask;
1388290001Sglebius	my_node->flags = flags;
1389290001Sglebius	my_node->line_no = line_no;
1390290001Sglebius
1391290001Sglebius	return my_node;
1392290001Sglebius}
1393290001Sglebius
1394290001Sglebius
1395290001Sglebiusstatic void
1396290001Sglebiusdestroy_restrict_node(
1397290001Sglebius	restrict_node *my_node
1398290001Sglebius	)
1399290001Sglebius{
1400290001Sglebius	/* With great care, free all the memory occupied by
1401290001Sglebius	 * the restrict node
1402290001Sglebius	 */
1403290001Sglebius	destroy_address_node(my_node->addr);
1404290001Sglebius	destroy_address_node(my_node->mask);
1405290001Sglebius	destroy_int_fifo(my_node->flags);
1406290001Sglebius	free(my_node);
1407290001Sglebius}
1408290001Sglebius
1409290001Sglebius
1410290001Sglebiusstatic void
1411290001Sglebiusdestroy_int_fifo(
1412290001Sglebius	int_fifo *	fifo
1413290001Sglebius	)
1414290001Sglebius{
1415290001Sglebius	int_node *	i_n;
1416290001Sglebius
1417290001Sglebius	if (fifo != NULL) {
1418290001Sglebius		for (;;) {
1419290001Sglebius			UNLINK_FIFO(i_n, *fifo, link);
1420290001Sglebius			if (i_n == NULL)
142182498Sroberto				break;
1422290001Sglebius			free(i_n);
1423290001Sglebius		}
1424290001Sglebius		free(fifo);
1425290001Sglebius	}
1426290001Sglebius}
1427132451Sroberto
1428290001Sglebius
1429290001Sglebiusstatic void
1430290001Sglebiusdestroy_string_fifo(
1431290001Sglebius	string_fifo *	fifo
1432290001Sglebius	)
1433290001Sglebius{
1434290001Sglebius	string_node *	sn;
1435290001Sglebius
1436290001Sglebius	if (fifo != NULL) {
1437290001Sglebius		for (;;) {
1438290001Sglebius			UNLINK_FIFO(sn, *fifo, link);
1439290001Sglebius			if (sn == NULL)
144082498Sroberto				break;
1441290001Sglebius			free(sn->s);
1442290001Sglebius			free(sn);
1443290001Sglebius		}
1444290001Sglebius		free(fifo);
1445290001Sglebius	}
1446290001Sglebius}
144782498Sroberto
1448290001Sglebius
1449290001Sglebiusstatic void
1450290001Sglebiusdestroy_attr_val_fifo(
1451290001Sglebius	attr_val_fifo *	av_fifo
1452290001Sglebius	)
1453290001Sglebius{
1454290001Sglebius	attr_val *	av;
1455290001Sglebius
1456290001Sglebius	if (av_fifo != NULL) {
1457290001Sglebius		for (;;) {
1458290001Sglebius			UNLINK_FIFO(av, *av_fifo, link);
1459290001Sglebius			if (av == NULL)
146082498Sroberto				break;
1461290001Sglebius			if (T_String == av->type)
1462290001Sglebius				free(av->value.s);
1463290001Sglebius			free(av);
1464290001Sglebius		}
1465290001Sglebius		free(av_fifo);
1466290001Sglebius	}
1467290001Sglebius}
146882498Sroberto
1469290001Sglebius
1470290001Sglebiusstatic void
1471290001Sglebiusdestroy_filegen_fifo(
1472290001Sglebius	filegen_fifo *	fifo
1473290001Sglebius	)
1474290001Sglebius{
1475290001Sglebius	filegen_node *	fg;
1476290001Sglebius
1477290001Sglebius	if (fifo != NULL) {
1478290001Sglebius		for (;;) {
1479290001Sglebius			UNLINK_FIFO(fg, *fifo, link);
1480290001Sglebius			if (fg == NULL)
148182498Sroberto				break;
1482290001Sglebius			destroy_attr_val_fifo(fg->options);
1483290001Sglebius			free(fg);
1484290001Sglebius		}
1485290001Sglebius		free(fifo);
1486290001Sglebius	}
1487290001Sglebius}
148882498Sroberto
1489290001Sglebius
1490290001Sglebiusstatic void
1491290001Sglebiusdestroy_restrict_fifo(
1492290001Sglebius	restrict_fifo *	fifo
1493290001Sglebius	)
1494290001Sglebius{
1495290001Sglebius	restrict_node *	rn;
1496290001Sglebius
1497290001Sglebius	if (fifo != NULL) {
1498290001Sglebius		for (;;) {
1499290001Sglebius			UNLINK_FIFO(rn, *fifo, link);
1500290001Sglebius			if (rn == NULL)
150182498Sroberto				break;
1502290001Sglebius			destroy_restrict_node(rn);
1503290001Sglebius		}
1504290001Sglebius		free(fifo);
1505290001Sglebius	}
1506290001Sglebius}
150782498Sroberto
1508290001Sglebius
1509290001Sglebiusstatic void
1510290001Sglebiusdestroy_setvar_fifo(
1511290001Sglebius	setvar_fifo *	fifo
1512290001Sglebius	)
1513290001Sglebius{
1514290001Sglebius	setvar_node *	sv;
1515290001Sglebius
1516290001Sglebius	if (fifo != NULL) {
1517290001Sglebius		for (;;) {
1518290001Sglebius			UNLINK_FIFO(sv, *fifo, link);
1519290001Sglebius			if (sv == NULL)
152082498Sroberto				break;
1521290001Sglebius			free(sv->var);
1522290001Sglebius			free(sv->val);
1523290001Sglebius			free(sv);
1524290001Sglebius		}
1525290001Sglebius		free(fifo);
1526290001Sglebius	}
1527290001Sglebius}
152882498Sroberto
1529290001Sglebius
1530290001Sglebiusstatic void
1531290001Sglebiusdestroy_addr_opts_fifo(
1532290001Sglebius	addr_opts_fifo *	fifo
1533290001Sglebius	)
1534290001Sglebius{
1535290001Sglebius	addr_opts_node *	aon;
1536290001Sglebius
1537290001Sglebius	if (fifo != NULL) {
1538290001Sglebius		for (;;) {
1539290001Sglebius			UNLINK_FIFO(aon, *fifo, link);
1540290001Sglebius			if (aon == NULL)
154182498Sroberto				break;
1542290001Sglebius			destroy_address_node(aon->addr);
1543290001Sglebius			destroy_attr_val_fifo(aon->options);
1544290001Sglebius			free(aon);
1545290001Sglebius		}
1546290001Sglebius		free(fifo);
1547290001Sglebius	}
1548290001Sglebius}
1549132451Sroberto
1550290001Sglebius
1551290001Sglebiussetvar_node *
1552290001Sglebiuscreate_setvar_node(
1553290001Sglebius	char *	var,
1554290001Sglebius	char *	val,
1555290001Sglebius	int	isdefault
1556290001Sglebius	)
1557290001Sglebius{
1558290001Sglebius	setvar_node *	my_node;
1559290001Sglebius	char *		pch;
1560290001Sglebius
1561290001Sglebius	/* do not allow = in the variable name */
1562290001Sglebius	pch = strchr(var, '=');
1563290001Sglebius	if (NULL != pch)
1564290001Sglebius		*pch = '\0';
1565290001Sglebius
1566290001Sglebius	/* Now store the string into a setvar_node */
1567290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1568290001Sglebius	my_node->var = var;
1569290001Sglebius	my_node->val = val;
1570290001Sglebius	my_node->isdefault = isdefault;
1571290001Sglebius
1572290001Sglebius	return my_node;
1573290001Sglebius}
1574290001Sglebius
1575290001Sglebius
1576290001Sglebiusnic_rule_node *
1577290001Sglebiuscreate_nic_rule_node(
1578290001Sglebius	int match_class,
1579290001Sglebius	char *if_name,	/* interface name or numeric address */
1580290001Sglebius	int action
1581290001Sglebius	)
1582290001Sglebius{
1583290001Sglebius	nic_rule_node *my_node;
1584290001Sglebius
1585290001Sglebius	REQUIRE(match_class != 0 || if_name != NULL);
1586290001Sglebius
1587290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1588290001Sglebius	my_node->match_class = match_class;
1589290001Sglebius	my_node->if_name = if_name;
1590290001Sglebius	my_node->action = action;
1591290001Sglebius
1592290001Sglebius	return my_node;
1593290001Sglebius}
1594290001Sglebius
1595290001Sglebius
1596290001Sglebiusaddr_opts_node *
1597290001Sglebiuscreate_addr_opts_node(
1598290001Sglebius	address_node *	addr,
1599290001Sglebius	attr_val_fifo *	options
1600290001Sglebius	)
1601290001Sglebius{
1602290001Sglebius	addr_opts_node *my_node;
1603290001Sglebius
1604290001Sglebius	my_node = emalloc_zero(sizeof(*my_node));
1605290001Sglebius	my_node->addr = addr;
1606290001Sglebius	my_node->options = options;
1607290001Sglebius
1608290001Sglebius	return my_node;
1609290001Sglebius}
1610290001Sglebius
1611290001Sglebius
1612290001Sglebius#ifdef SIM
1613290001Sglebiusscript_info *
1614290001Sglebiuscreate_sim_script_info(
1615290001Sglebius	double		duration,
1616290001Sglebius	attr_val_fifo *	script_queue
1617290001Sglebius	)
1618290001Sglebius{
1619290001Sglebius	script_info *my_info;
1620290001Sglebius	attr_val *my_attr_val;
1621290001Sglebius
1622290001Sglebius	my_info = emalloc_zero(sizeof(*my_info));
1623290001Sglebius
1624290001Sglebius	/* Initialize Script Info with default values*/
1625290001Sglebius	my_info->duration = duration;
1626290001Sglebius	my_info->prop_delay = NET_DLY;
1627290001Sglebius	my_info->proc_delay = PROC_DLY;
1628290001Sglebius
1629290001Sglebius	/* Traverse the script_queue and fill out non-default values */
1630290001Sglebius
1631290001Sglebius	for (my_attr_val = HEAD_PFIFO(script_queue);
1632290001Sglebius	     my_attr_val != NULL;
1633290001Sglebius	     my_attr_val = my_attr_val->link) {
1634290001Sglebius
1635290001Sglebius		/* Set the desired value */
1636290001Sglebius		switch (my_attr_val->attr) {
1637290001Sglebius
1638290001Sglebius		case T_Freq_Offset:
1639290001Sglebius			my_info->freq_offset = my_attr_val->value.d;
164054359Sroberto			break;
164154359Sroberto
1642290001Sglebius		case T_Wander:
1643290001Sglebius			my_info->wander = my_attr_val->value.d;
1644290001Sglebius			break;
1645132451Sroberto
1646290001Sglebius		case T_Jitter:
1647290001Sglebius			my_info->jitter = my_attr_val->value.d;
1648290001Sglebius			break;
1649132451Sroberto
1650290001Sglebius		case T_Prop_Delay:
1651290001Sglebius			my_info->prop_delay = my_attr_val->value.d;
1652290001Sglebius			break;
1653132451Sroberto
1654290001Sglebius		case T_Proc_Delay:
1655290001Sglebius			my_info->proc_delay = my_attr_val->value.d;
1656290001Sglebius			break;
1657182007Sroberto
1658290001Sglebius		default:
1659290001Sglebius			msyslog(LOG_ERR, "Unknown script token %d",
1660290001Sglebius				my_attr_val->attr);
1661290001Sglebius		}
1662290001Sglebius	}
1663132451Sroberto
1664290001Sglebius	return my_info;
1665290001Sglebius}
1666290001Sglebius#endif	/* SIM */
1667132451Sroberto
1668132451Sroberto
1669290001Sglebius#ifdef SIM
1670290001Sglebiusstatic sockaddr_u *
1671290001Sglebiusget_next_address(
1672290001Sglebius	address_node *addr
1673290001Sglebius	)
1674290001Sglebius{
1675290001Sglebius	const char addr_prefix[] = "192.168.0.";
1676290001Sglebius	static int curr_addr_num = 1;
1677290001Sglebius#define ADDR_LENGTH 16 + 1	/* room for 192.168.1.255 */
1678290001Sglebius	char addr_string[ADDR_LENGTH];
1679290001Sglebius	sockaddr_u *final_addr;
1680290001Sglebius	struct addrinfo *ptr;
1681290001Sglebius	int gai_err;
1682182007Sroberto
1683290001Sglebius	final_addr = emalloc(sizeof(*final_addr));
1684182007Sroberto
1685290001Sglebius	if (addr->type == T_String) {
1686290001Sglebius		snprintf(addr_string, sizeof(addr_string), "%s%d",
1687290001Sglebius			 addr_prefix, curr_addr_num++);
1688290001Sglebius		printf("Selecting ip address %s for hostname %s\n",
1689290001Sglebius		       addr_string, addr->address);
1690290001Sglebius		gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
1691290001Sglebius	} else {
1692290001Sglebius		gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
1693290001Sglebius	}
1694182007Sroberto
1695290001Sglebius	if (gai_err) {
1696290001Sglebius		fprintf(stderr, "ERROR!! Could not get a new address\n");
1697290001Sglebius		exit(1);
1698290001Sglebius	}
1699290001Sglebius	memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
1700290001Sglebius	fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
1701290001Sglebius		stoa(final_addr));
1702290001Sglebius	freeaddrinfo(ptr);
1703182007Sroberto
1704290001Sglebius	return final_addr;
1705290001Sglebius}
1706290001Sglebius#endif /* SIM */
1707290001Sglebius
1708290001Sglebius
1709290001Sglebius#ifdef SIM
1710290001Sglebiusserver_info *
1711290001Sglebiuscreate_sim_server(
1712290001Sglebius	address_node *		addr,
1713290001Sglebius	double			server_offset,
1714290001Sglebius	script_info_fifo *	script
1715290001Sglebius	)
1716290001Sglebius{
1717290001Sglebius	server_info *my_info;
1718290001Sglebius
1719290001Sglebius	my_info = emalloc_zero(sizeof(*my_info));
1720290001Sglebius	my_info->server_time = server_offset;
1721290001Sglebius	my_info->addr = get_next_address(addr);
1722290001Sglebius	my_info->script = script;
1723290001Sglebius	UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
1724290001Sglebius
1725290001Sglebius	return my_info;
1726290001Sglebius}
1727290001Sglebius#endif	/* SIM */
1728290001Sglebius
1729290001Sglebiussim_node *
1730290001Sglebiuscreate_sim_node(
1731290001Sglebius	attr_val_fifo *		init_opts,
1732290001Sglebius	server_info_fifo *	servers
1733290001Sglebius	)
1734290001Sglebius{
1735290001Sglebius	sim_node *my_node;
1736290001Sglebius
1737290001Sglebius	my_node = emalloc(sizeof(*my_node));
1738290001Sglebius	my_node->init_opts = init_opts;
1739290001Sglebius	my_node->servers = servers;
1740290001Sglebius
1741290001Sglebius	return my_node;
1742290001Sglebius}
1743290001Sglebius
1744290001Sglebius
1745290001Sglebius
1746290001Sglebius
1747290001Sglebius/* FUNCTIONS FOR PERFORMING THE CONFIGURATION
1748290001Sglebius * ------------------------------------------
1749290001Sglebius */
1750290001Sglebius
1751290001Sglebius#ifndef SIM
1752290001Sglebiusstatic void
1753290001Sglebiusconfig_other_modes(
1754290001Sglebius	config_tree *	ptree
1755290001Sglebius	)
1756290001Sglebius{
1757290001Sglebius	sockaddr_u	addr_sock;
1758290001Sglebius	address_node *	addr_node;
1759290001Sglebius
1760290001Sglebius	if (ptree->broadcastclient)
1761290001Sglebius		proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
1762290001Sglebius			     0., NULL);
1763290001Sglebius
1764290001Sglebius	addr_node = HEAD_PFIFO(ptree->manycastserver);
1765290001Sglebius	while (addr_node != NULL) {
1766290001Sglebius		ZERO_SOCK(&addr_sock);
1767290001Sglebius		AF(&addr_sock) = addr_node->type;
1768290001Sglebius		if (1 == getnetnum(addr_node->address, &addr_sock, 1,
1769290001Sglebius				   t_UNK)) {
1770290001Sglebius			proto_config(PROTO_MULTICAST_ADD,
1771290001Sglebius				     0, 0., &addr_sock);
1772290001Sglebius			sys_manycastserver = 1;
1773290001Sglebius		}
1774290001Sglebius		addr_node = addr_node->link;
1775290001Sglebius	}
1776290001Sglebius
1777290001Sglebius	/* Configure the multicast clients */
1778290001Sglebius	addr_node = HEAD_PFIFO(ptree->multicastclient);
1779290001Sglebius	if (addr_node != NULL) {
1780290001Sglebius		do {
1781290001Sglebius			ZERO_SOCK(&addr_sock);
1782290001Sglebius			AF(&addr_sock) = addr_node->type;
1783290001Sglebius			if (1 == getnetnum(addr_node->address,
1784290001Sglebius					   &addr_sock, 1, t_UNK)) {
1785290001Sglebius				proto_config(PROTO_MULTICAST_ADD, 0, 0.,
1786290001Sglebius					     &addr_sock);
1787290001Sglebius			}
1788290001Sglebius			addr_node = addr_node->link;
1789290001Sglebius		} while (addr_node != NULL);
1790290001Sglebius		proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1791290001Sglebius	}
1792290001Sglebius}
1793290001Sglebius#endif	/* !SIM */
1794290001Sglebius
1795290001Sglebius
1796290001Sglebius#ifdef FREE_CFG_T
1797290001Sglebiusstatic void
1798290001Sglebiusdestroy_address_fifo(
1799290001Sglebius	address_fifo *	pfifo
1800290001Sglebius	)
1801290001Sglebius{
1802290001Sglebius	address_node *	addr_node;
1803290001Sglebius
1804290001Sglebius	if (pfifo != NULL) {
1805290001Sglebius		for (;;) {
1806290001Sglebius			UNLINK_FIFO(addr_node, *pfifo, link);
1807290001Sglebius			if (addr_node == NULL)
1808182007Sroberto				break;
1809290001Sglebius			destroy_address_node(addr_node);
1810290001Sglebius		}
1811290001Sglebius		free(pfifo);
1812290001Sglebius	}
1813290001Sglebius}
1814182007Sroberto
1815290001Sglebius
1816290001Sglebiusstatic void
1817290001Sglebiusfree_config_other_modes(
1818290001Sglebius	config_tree *ptree
1819290001Sglebius	)
1820290001Sglebius{
1821290001Sglebius	FREE_ADDRESS_FIFO(ptree->manycastserver);
1822290001Sglebius	FREE_ADDRESS_FIFO(ptree->multicastclient);
1823290001Sglebius}
1824290001Sglebius#endif	/* FREE_CFG_T */
1825290001Sglebius
1826290001Sglebius
1827290001Sglebius#ifndef SIM
1828290001Sglebiusstatic void
1829290001Sglebiusconfig_auth(
1830290001Sglebius	config_tree *ptree
1831290001Sglebius	)
1832290001Sglebius{
1833290001Sglebius	attr_val *	my_val;
1834290001Sglebius	int		first;
1835290001Sglebius	int		last;
1836290001Sglebius	int		i;
1837290001Sglebius	int		count;
1838290001Sglebius#ifdef AUTOKEY
1839290001Sglebius	int		item;
1840290001Sglebius#endif
1841290001Sglebius
1842290001Sglebius	/* Crypto Command */
1843290001Sglebius#ifdef AUTOKEY
1844290001Sglebius# ifdef __GNUC__
1845290001Sglebius	item = -1;	/* quiet warning */
1846290001Sglebius# endif
1847290001Sglebius	my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
1848290001Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1849290001Sglebius		switch (my_val->attr) {
1850290001Sglebius
1851290001Sglebius		default:
1852290001Sglebius			INSIST(0);
1853290001Sglebius			break;
1854290001Sglebius
1855290001Sglebius		case T_Host:
1856290001Sglebius			item = CRYPTO_CONF_PRIV;
1857290001Sglebius			break;
1858290001Sglebius
1859290001Sglebius		case T_Ident:
1860290001Sglebius			item = CRYPTO_CONF_IDENT;
1861290001Sglebius			break;
1862290001Sglebius
1863290001Sglebius		case T_Pw:
1864290001Sglebius			item = CRYPTO_CONF_PW;
1865290001Sglebius			break;
1866290001Sglebius
1867290001Sglebius		case T_Randfile:
1868290001Sglebius			item = CRYPTO_CONF_RAND;
1869290001Sglebius			break;
1870290001Sglebius
1871290001Sglebius		case T_Digest:
1872290001Sglebius			item = CRYPTO_CONF_NID;
1873290001Sglebius			break;
1874290001Sglebius		}
1875290001Sglebius		crypto_config(item, my_val->value.s);
1876290001Sglebius	}
1877290001Sglebius#endif	/* AUTOKEY */
1878290001Sglebius
1879290001Sglebius	/* Keysdir Command */
1880290001Sglebius	if (ptree->auth.keysdir) {
1881290001Sglebius		if (keysdir != default_keysdir)
1882290001Sglebius			free(keysdir);
1883290001Sglebius		keysdir = estrdup(ptree->auth.keysdir);
1884290001Sglebius	}
1885290001Sglebius
1886290001Sglebius
1887290001Sglebius	/* ntp_signd_socket Command */
1888290001Sglebius	if (ptree->auth.ntp_signd_socket) {
1889290001Sglebius		if (ntp_signd_socket != default_ntp_signd_socket)
1890290001Sglebius			free(ntp_signd_socket);
1891290001Sglebius		ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
1892290001Sglebius	}
1893290001Sglebius
1894290001Sglebius#ifdef AUTOKEY
1895290001Sglebius	if (ptree->auth.cryptosw && !cryptosw) {
1896290001Sglebius		crypto_setup();
1897290001Sglebius		cryptosw = 1;
1898290001Sglebius	}
1899290001Sglebius#endif	/* AUTOKEY */
1900290001Sglebius
1901290001Sglebius	/*
1902290001Sglebius	 * Count the number of trusted keys to preallocate storage and
1903290001Sglebius	 * size the hash table.
1904290001Sglebius	 */
1905290001Sglebius	count = 0;
1906290001Sglebius	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
1907290001Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1908290001Sglebius		if (T_Integer == my_val->type) {
1909290001Sglebius			first = my_val->value.i;
1910290001Sglebius			if (first > 1 && first <= NTP_MAXKEY)
1911290001Sglebius				count++;
1912290001Sglebius		} else {
1913290001Sglebius			REQUIRE(T_Intrange == my_val->type);
1914290001Sglebius			first = my_val->value.r.first;
1915290001Sglebius			last = my_val->value.r.last;
1916290001Sglebius			if (!(first > last || first < 1 ||
1917290001Sglebius			    last > NTP_MAXKEY)) {
1918290001Sglebius				count += 1 + last - first;
1919132451Sroberto			}
1920290001Sglebius		}
1921290001Sglebius	}
1922290001Sglebius	auth_prealloc_symkeys(count);
1923290001Sglebius
1924290001Sglebius	/* Keys Command */
1925290001Sglebius	if (ptree->auth.keys)
1926290001Sglebius		getauthkeys(ptree->auth.keys);
1927290001Sglebius
1928290001Sglebius	/* Control Key Command */
1929290001Sglebius	if (ptree->auth.control_key)
1930290001Sglebius		ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
1931290001Sglebius
1932290001Sglebius	/* Requested Key Command */
1933290001Sglebius	if (ptree->auth.request_key) {
1934290001Sglebius		DPRINTF(4, ("set info_auth_keyid to %08lx\n",
1935290001Sglebius			    (u_long) ptree->auth.request_key));
1936290001Sglebius		info_auth_keyid = (keyid_t)ptree->auth.request_key;
1937290001Sglebius	}
1938290001Sglebius
1939290001Sglebius	/* Trusted Key Command */
1940290001Sglebius	my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
1941290001Sglebius	for (; my_val != NULL; my_val = my_val->link) {
1942290001Sglebius		if (T_Integer == my_val->type) {
1943290001Sglebius			first = my_val->value.i;
1944290001Sglebius			if (first >= 1 && first <= NTP_MAXKEY) {
1945290001Sglebius				authtrust(first, TRUE);
1946290001Sglebius			} else {
1947290001Sglebius				msyslog(LOG_NOTICE,
1948290001Sglebius					"Ignoring invalid trustedkey %d, min 1 max %d.",
1949290001Sglebius					first, NTP_MAXKEY);
1950290001Sglebius			}
1951290001Sglebius		} else {
1952290001Sglebius			first = my_val->value.r.first;
1953290001Sglebius			last = my_val->value.r.last;
1954290001Sglebius			if (first > last || first < 1 ||
1955290001Sglebius			    last > NTP_MAXKEY) {
1956290001Sglebius				msyslog(LOG_NOTICE,
1957290001Sglebius					"Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
1958290001Sglebius					first, last, NTP_MAXKEY);
1959290001Sglebius			} else {
1960290001Sglebius				for (i = first; i <= last; i++) {
1961290001Sglebius					authtrust(i, TRUE);
1962290001Sglebius				}
1963290001Sglebius			}
1964290001Sglebius		}
1965290001Sglebius	}
1966290001Sglebius
1967290001Sglebius#ifdef AUTOKEY
1968290001Sglebius	/* crypto revoke command */
1969290001Sglebius	if (ptree->auth.revoke)
1970290001Sglebius		sys_revoke = 1UL << ptree->auth.revoke;
1971290001Sglebius#endif	/* AUTOKEY */
1972290001Sglebius}
1973290001Sglebius#endif	/* !SIM */
1974290001Sglebius
1975290001Sglebius
1976290001Sglebius#ifdef FREE_CFG_T
1977290001Sglebiusstatic void
1978290001Sglebiusfree_config_auth(
1979290001Sglebius	config_tree *ptree
1980290001Sglebius	)
1981290001Sglebius{
1982290001Sglebius	destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
1983290001Sglebius	ptree->auth.crypto_cmd_list = NULL;
1984290001Sglebius	destroy_attr_val_fifo(ptree->auth.trusted_key_list);
1985290001Sglebius	ptree->auth.trusted_key_list = NULL;
1986290001Sglebius}
1987290001Sglebius#endif	/* FREE_CFG_T */
1988290001Sglebius
1989290001Sglebius
1990290001Sglebiusstatic void
1991290001Sglebiusconfig_tos(
1992290001Sglebius	config_tree *ptree
1993290001Sglebius	)
1994290001Sglebius{
1995290001Sglebius	attr_val *	tos;
1996290001Sglebius	int		item;
1997290001Sglebius	double		val;
1998290001Sglebius
1999290001Sglebius#ifdef __GNUC__
2000290001Sglebius	item = -1;	/* quiet warning */
2001290001Sglebius#endif
2002290001Sglebius	tos = HEAD_PFIFO(ptree->orphan_cmds);
2003290001Sglebius	for (; tos != NULL; tos = tos->link) {
2004290001Sglebius		val = tos->value.d;
2005290001Sglebius		switch(tos->attr) {
2006290001Sglebius
2007290001Sglebius		default:
2008290001Sglebius			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
2026290001Sglebius		case T_Ceiling:
2027290001Sglebius			if (val > STRATUM_UNSPEC - 1) {
2028290001Sglebius				msyslog(LOG_WARNING,
2029290001Sglebius					"Using maximum tos ceiling %d, %g requested",
2030290001Sglebius					STRATUM_UNSPEC - 1, val);
2031290001Sglebius				val = STRATUM_UNSPEC - 1;
2032132451Sroberto			}
2033290001Sglebius			item = PROTO_CEILING;
2034132451Sroberto			break;
2035132451Sroberto
2036290001Sglebius		case T_Floor:
2037290001Sglebius			item = PROTO_FLOOR;
2038290001Sglebius			break;
2039132451Sroberto
2040290001Sglebius		case T_Cohort:
2041290001Sglebius			item = PROTO_COHORT;
2042290001Sglebius			break;
2043290001Sglebius
2044290001Sglebius		case T_Orphan:
2045290001Sglebius			item = PROTO_ORPHAN;
2046290001Sglebius			break;
2047290001Sglebius
2048290001Sglebius		case T_Orphanwait:
2049290001Sglebius			item = PROTO_ORPHWAIT;
2050290001Sglebius			break;
2051290001Sglebius
2052290001Sglebius		case T_Mindist:
2053290001Sglebius			item = PROTO_MINDISP;
2054290001Sglebius			break;
2055290001Sglebius
2056290001Sglebius		case T_Maxdist:
2057290001Sglebius			item = PROTO_MAXDIST;
2058290001Sglebius			break;
2059290001Sglebius
2060290001Sglebius		case T_Minclock:
2061290001Sglebius			item = PROTO_MINCLOCK;
2062290001Sglebius			break;
2063290001Sglebius
2064290001Sglebius		case T_Maxclock:
2065290001Sglebius			item = PROTO_MAXCLOCK;
2066290001Sglebius			break;
2067290001Sglebius
2068290001Sglebius		case T_Minsane:
2069290001Sglebius			item = PROTO_MINSANE;
2070290001Sglebius			break;
2071290001Sglebius
2072290001Sglebius		case T_Beacon:
2073290001Sglebius			item = PROTO_BEACON;
2074290001Sglebius			break;
2075290001Sglebius		}
2076290001Sglebius		proto_config(item, 0, val, NULL);
2077290001Sglebius	}
2078290001Sglebius}
2079290001Sglebius
2080290001Sglebius
2081290001Sglebius#ifdef FREE_CFG_T
2082290001Sglebiusstatic void
2083290001Sglebiusfree_config_tos(
2084290001Sglebius	config_tree *ptree
2085290001Sglebius	)
2086290001Sglebius{
2087290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
2088290001Sglebius}
2089290001Sglebius#endif	/* FREE_CFG_T */
2090290001Sglebius
2091290001Sglebius
2092290001Sglebiusstatic void
2093290001Sglebiusconfig_monitor(
2094290001Sglebius	config_tree *ptree
2095290001Sglebius	)
2096290001Sglebius{
2097290001Sglebius	int_node *pfilegen_token;
2098290001Sglebius	const char *filegen_string;
2099290001Sglebius	const char *filegen_file;
2100290001Sglebius	FILEGEN *filegen;
2101290001Sglebius	filegen_node *my_node;
2102290001Sglebius	attr_val *my_opts;
2103290001Sglebius	int filegen_type;
2104290001Sglebius	int filegen_flag;
2105290001Sglebius
2106290001Sglebius	/* Set the statistics directory */
2107290001Sglebius	if (ptree->stats_dir)
2108290001Sglebius		stats_config(STATS_STATSDIR, ptree->stats_dir);
2109290001Sglebius
2110290001Sglebius	/* NOTE:
2111290001Sglebius	 * Calling filegen_get is brain dead. Doing a string
2112290001Sglebius	 * comparison to find the relavant filegen structure is
2113290001Sglebius	 * expensive.
2114290001Sglebius	 *
2115290001Sglebius	 * Through the parser, we already know which filegen is
2116290001Sglebius	 * being specified. Hence, we should either store a
2117290001Sglebius	 * pointer to the specified structure in the syntax tree
2118290001Sglebius	 * or an index into a filegen array.
2119290001Sglebius	 *
2120290001Sglebius	 * Need to change the filegen code to reflect the above.
2121290001Sglebius	 */
2122290001Sglebius
2123290001Sglebius	/* Turn on the specified statistics */
2124290001Sglebius	pfilegen_token = HEAD_PFIFO(ptree->stats_list);
2125290001Sglebius	for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
2126290001Sglebius		filegen_string = keyword(pfilegen_token->i);
2127290001Sglebius		filegen = filegen_get(filegen_string);
2128290001Sglebius		if (NULL == filegen) {
2129290001Sglebius			msyslog(LOG_ERR,
2130290001Sglebius				"stats %s unrecognized",
2131290001Sglebius				filegen_string);
2132290001Sglebius			continue;
2133290001Sglebius		}
2134290001Sglebius		DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
2135290001Sglebius			    filegen_string, filegen->dir,
2136290001Sglebius			    filegen->fname));
2137290001Sglebius		filegen_flag = filegen->flag;
2138290001Sglebius		filegen_flag |= FGEN_FLAG_ENABLED;
2139290001Sglebius		filegen_config(filegen, statsdir, filegen_string,
2140290001Sglebius			       filegen->type, filegen_flag);
2141290001Sglebius	}
2142290001Sglebius
2143290001Sglebius	/* Configure the statistics with the options */
2144290001Sglebius	my_node = HEAD_PFIFO(ptree->filegen_opts);
2145290001Sglebius	for (; my_node != NULL; my_node = my_node->link) {
2146290001Sglebius		filegen_string = keyword(my_node->filegen_token);
2147290001Sglebius		filegen = filegen_get(filegen_string);
2148290001Sglebius		if (NULL == filegen) {
2149290001Sglebius			msyslog(LOG_ERR,
2150290001Sglebius				"filegen category '%s' unrecognized",
2151290001Sglebius				filegen_string);
2152290001Sglebius			continue;
2153290001Sglebius		}
2154290001Sglebius		filegen_file = filegen_string;
2155290001Sglebius
2156290001Sglebius		/* Initialize the filegen variables to their pre-configuration states */
2157290001Sglebius		filegen_flag = filegen->flag;
2158290001Sglebius		filegen_type = filegen->type;
2159290001Sglebius
2160290001Sglebius		/* "filegen ... enabled" is the default (when filegen is used) */
2161290001Sglebius		filegen_flag |= FGEN_FLAG_ENABLED;
2162290001Sglebius
2163290001Sglebius		my_opts = HEAD_PFIFO(my_node->options);
2164290001Sglebius		for (; my_opts != NULL; my_opts = my_opts->link) {
2165290001Sglebius			switch (my_opts->attr) {
2166290001Sglebius
2167290001Sglebius			case T_File:
2168290001Sglebius				filegen_file = my_opts->value.s;
2169132451Sroberto				break;
2170132451Sroberto
2171290001Sglebius			case T_Type:
2172290001Sglebius				switch (my_opts->value.i) {
2173290001Sglebius
2174290001Sglebius				default:
2175290001Sglebius					INSIST(0);
2176290001Sglebius					break;
2177290001Sglebius
2178290001Sglebius				case T_None:
2179290001Sglebius					filegen_type = FILEGEN_NONE;
2180290001Sglebius					break;
2181290001Sglebius
2182290001Sglebius				case T_Pid:
2183290001Sglebius					filegen_type = FILEGEN_PID;
2184290001Sglebius					break;
2185290001Sglebius
2186290001Sglebius				case T_Day:
2187290001Sglebius					filegen_type = FILEGEN_DAY;
2188290001Sglebius					break;
2189290001Sglebius
2190290001Sglebius				case T_Week:
2191290001Sglebius					filegen_type = FILEGEN_WEEK;
2192290001Sglebius					break;
2193290001Sglebius
2194290001Sglebius				case T_Month:
2195290001Sglebius					filegen_type = FILEGEN_MONTH;
2196290001Sglebius					break;
2197290001Sglebius
2198290001Sglebius				case T_Year:
2199290001Sglebius					filegen_type = FILEGEN_YEAR;
2200290001Sglebius					break;
2201290001Sglebius
2202290001Sglebius				case T_Age:
2203290001Sglebius					filegen_type = FILEGEN_AGE;
2204290001Sglebius					break;
2205290001Sglebius				}
2206132451Sroberto				break;
2207132451Sroberto
2208290001Sglebius			case T_Flag:
2209290001Sglebius				switch (my_opts->value.i) {
2210290001Sglebius
2211290001Sglebius				case T_Link:
2212290001Sglebius					filegen_flag |= FGEN_FLAG_LINK;
2213290001Sglebius					break;
2214290001Sglebius
2215290001Sglebius				case T_Nolink:
2216290001Sglebius					filegen_flag &= ~FGEN_FLAG_LINK;
2217290001Sglebius					break;
2218290001Sglebius
2219290001Sglebius				case T_Enable:
2220290001Sglebius					filegen_flag |= FGEN_FLAG_ENABLED;
2221290001Sglebius					break;
2222290001Sglebius
2223290001Sglebius				case T_Disable:
2224290001Sglebius					filegen_flag &= ~FGEN_FLAG_ENABLED;
2225290001Sglebius					break;
2226290001Sglebius
2227290001Sglebius				default:
2228290001Sglebius					msyslog(LOG_ERR,
2229290001Sglebius						"Unknown filegen flag token %d",
2230290001Sglebius						my_opts->value.i);
2231290001Sglebius					exit(1);
2232290001Sglebius				}
2233132451Sroberto				break;
2234132451Sroberto
2235290001Sglebius			default:
2236132451Sroberto				msyslog(LOG_ERR,
2237290001Sglebius					"Unknown filegen option token %d",
2238290001Sglebius					my_opts->attr);
2239290001Sglebius				exit(1);
2240132451Sroberto			}
2241290001Sglebius		}
2242290001Sglebius		filegen_config(filegen, statsdir, filegen_file,
2243290001Sglebius			       filegen_type, filegen_flag);
2244290001Sglebius	}
2245290001Sglebius}
2246290001Sglebius
2247290001Sglebius
2248290001Sglebius#ifdef FREE_CFG_T
2249290001Sglebiusstatic void
2250290001Sglebiusfree_config_monitor(
2251290001Sglebius	config_tree *ptree
2252290001Sglebius	)
2253290001Sglebius{
2254290001Sglebius	if (ptree->stats_dir) {
2255290001Sglebius		free(ptree->stats_dir);
2256290001Sglebius		ptree->stats_dir = NULL;
2257290001Sglebius	}
2258290001Sglebius
2259290001Sglebius	FREE_INT_FIFO(ptree->stats_list);
2260290001Sglebius	FREE_FILEGEN_FIFO(ptree->filegen_opts);
2261290001Sglebius}
2262290001Sglebius#endif	/* FREE_CFG_T */
2263290001Sglebius
2264290001Sglebius
2265290001Sglebius#ifndef SIM
2266290001Sglebiusstatic void
2267290001Sglebiusconfig_access(
2268290001Sglebius	config_tree *ptree
2269290001Sglebius	)
2270290001Sglebius{
2271290001Sglebius	static int		warned_signd;
2272290001Sglebius	attr_val *		my_opt;
2273290001Sglebius	restrict_node *		my_node;
2274290001Sglebius	int_node *		curr_flag;
2275290001Sglebius	sockaddr_u		addr;
2276290001Sglebius	sockaddr_u		mask;
2277290001Sglebius	struct addrinfo		hints;
2278290001Sglebius	struct addrinfo *	ai_list;
2279290001Sglebius	struct addrinfo *	pai;
2280290001Sglebius	int			rc;
2281290001Sglebius	int			restrict_default;
2282290001Sglebius	u_short			flags;
2283290001Sglebius	u_short			mflags;
2284290001Sglebius	int			range_err;
2285290001Sglebius	const char *		signd_warning =
2286290001Sglebius#ifdef HAVE_NTP_SIGND
2287290001Sglebius	    "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
2288290001Sglebius#else
2289290001Sglebius	    "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
2290290001Sglebius#endif
2291290001Sglebius
2292290001Sglebius	/* Configure the mru options */
2293290001Sglebius	my_opt = HEAD_PFIFO(ptree->mru_opts);
2294290001Sglebius	for (; my_opt != NULL; my_opt = my_opt->link) {
2295290001Sglebius
2296290001Sglebius		range_err = FALSE;
2297290001Sglebius
2298290001Sglebius		switch (my_opt->attr) {
2299290001Sglebius
2300290001Sglebius		case T_Incalloc:
2301290001Sglebius			if (0 <= my_opt->value.i)
2302290001Sglebius				mru_incalloc = my_opt->value.u;
2303290001Sglebius			else
2304290001Sglebius				range_err = TRUE;
2305132451Sroberto			break;
2306132451Sroberto
2307290001Sglebius		case T_Incmem:
2308290001Sglebius			if (0 <= my_opt->value.i)
2309290001Sglebius				mru_incalloc = (my_opt->value.u * 1024U)
2310290001Sglebius						/ sizeof(mon_entry);
2311290001Sglebius			else
2312290001Sglebius				range_err = TRUE;
231382498Sroberto			break;
231482498Sroberto
2315290001Sglebius		case T_Initalloc:
2316290001Sglebius			if (0 <= my_opt->value.i)
2317290001Sglebius				mru_initalloc = my_opt->value.u;
2318290001Sglebius			else
2319290001Sglebius				range_err = TRUE;
232082498Sroberto			break;
232182498Sroberto
2322290001Sglebius		case T_Initmem:
2323290001Sglebius			if (0 <= my_opt->value.i)
2324290001Sglebius				mru_initalloc = (my_opt->value.u * 1024U)
2325290001Sglebius						 / sizeof(mon_entry);
2326290001Sglebius			else
2327290001Sglebius				range_err = TRUE;
2328290001Sglebius			break;
232954359Sroberto
2330290001Sglebius		case T_Mindepth:
2331290001Sglebius			if (0 <= my_opt->value.i)
2332290001Sglebius				mru_mindepth = my_opt->value.u;
2333290001Sglebius			else
2334290001Sglebius				range_err = TRUE;
2335290001Sglebius			break;
2336290001Sglebius
2337290001Sglebius		case T_Maxage:
2338290001Sglebius			mru_maxage = my_opt->value.i;
2339290001Sglebius			break;
2340290001Sglebius
2341290001Sglebius		case T_Maxdepth:
2342290001Sglebius			if (0 <= my_opt->value.i)
2343290001Sglebius				mru_maxdepth = my_opt->value.u;
2344290001Sglebius			else
2345290001Sglebius				mru_maxdepth = UINT_MAX;
2346290001Sglebius			break;
2347290001Sglebius
2348290001Sglebius		case T_Maxmem:
2349290001Sglebius			if (0 <= my_opt->value.i)
2350290001Sglebius				mru_maxdepth = (my_opt->value.u * 1024U) /
2351290001Sglebius					       sizeof(mon_entry);
2352290001Sglebius			else
2353290001Sglebius				mru_maxdepth = UINT_MAX;
2354290001Sglebius			break;
2355290001Sglebius
2356290001Sglebius		default:
2357290001Sglebius			msyslog(LOG_ERR,
2358290001Sglebius				"Unknown mru option %s (%d)",
2359290001Sglebius				keyword(my_opt->attr), my_opt->attr);
2360290001Sglebius			exit(1);
2361290001Sglebius		}
2362290001Sglebius		if (range_err)
2363290001Sglebius			msyslog(LOG_ERR,
2364290001Sglebius				"mru %s %d out of range, ignored.",
2365290001Sglebius				keyword(my_opt->attr), my_opt->value.i);
2366290001Sglebius	}
2367290001Sglebius
2368290001Sglebius	/* Configure the discard options */
2369290001Sglebius	my_opt = HEAD_PFIFO(ptree->discard_opts);
2370290001Sglebius	for (; my_opt != NULL; my_opt = my_opt->link) {
2371290001Sglebius
2372290001Sglebius		switch (my_opt->attr) {
2373290001Sglebius
2374290001Sglebius		case T_Average:
2375290001Sglebius			if (0 <= my_opt->value.i &&
2376290001Sglebius			    my_opt->value.i <= UCHAR_MAX)
2377290001Sglebius				ntp_minpoll = (u_char)my_opt->value.u;
2378290001Sglebius			else
237982498Sroberto				msyslog(LOG_ERR,
2380290001Sglebius					"discard average %d out of range, ignored.",
2381290001Sglebius					my_opt->value.i);
2382290001Sglebius			break;
2383290001Sglebius
2384290001Sglebius		case T_Minimum:
2385290001Sglebius			ntp_minpkt = my_opt->value.i;
2386290001Sglebius			break;
2387290001Sglebius
2388290001Sglebius		case T_Monitor:
2389290001Sglebius			mon_age = my_opt->value.i;
2390290001Sglebius			break;
2391290001Sglebius
2392290001Sglebius		default:
2393290001Sglebius			msyslog(LOG_ERR,
2394290001Sglebius				"Unknown discard option %s (%d)",
2395290001Sglebius				keyword(my_opt->attr), my_opt->attr);
2396290001Sglebius			exit(1);
2397290001Sglebius		}
2398290001Sglebius	}
2399290001Sglebius
2400290001Sglebius	/* Configure the restrict options */
2401290001Sglebius	my_node = HEAD_PFIFO(ptree->restrict_opts);
2402290001Sglebius	for (; my_node != NULL; my_node = my_node->link) {
2403290001Sglebius		/* Parse the flags */
2404290001Sglebius		flags = 0;
2405290001Sglebius		mflags = 0;
2406290001Sglebius
2407290001Sglebius		curr_flag = HEAD_PFIFO(my_node->flags);
2408290001Sglebius		for (; curr_flag != NULL; curr_flag = curr_flag->link) {
2409290001Sglebius			switch (curr_flag->i) {
2410290001Sglebius
2411290001Sglebius			default:
2412290001Sglebius				INSIST(0);
241382498Sroberto				break;
2414132451Sroberto
2415290001Sglebius			case T_Ntpport:
2416290001Sglebius				mflags |= RESM_NTPONLY;
241782498Sroberto				break;
241882498Sroberto
2419290001Sglebius			case T_Source:
2420290001Sglebius				mflags |= RESM_SOURCE;
242182498Sroberto				break;
242282498Sroberto
2423290001Sglebius			case T_Flake:
2424290001Sglebius				flags |= RES_FLAKE;
2425182007Sroberto				break;
2426182007Sroberto
2427290001Sglebius			case T_Ignore:
2428290001Sglebius				flags |= RES_IGNORE;
242982498Sroberto				break;
243082498Sroberto
2431290001Sglebius			case T_Kod:
2432290001Sglebius				flags |= RES_KOD;
243382498Sroberto				break;
243482498Sroberto
2435290001Sglebius			case T_Mssntp:
2436290001Sglebius				flags |= RES_MSSNTP;
243782498Sroberto				break;
243882498Sroberto
2439290001Sglebius			case T_Limited:
2440290001Sglebius				flags |= RES_LIMITED;
244182498Sroberto				break;
244282498Sroberto
2443290001Sglebius			case T_Lowpriotrap:
2444290001Sglebius				flags |= RES_LPTRAP;
2445132451Sroberto				break;
2446132451Sroberto
2447290001Sglebius			case T_Nomodify:
2448290001Sglebius				flags |= RES_NOMODIFY;
2449132451Sroberto				break;
2450132451Sroberto
2451290001Sglebius			case T_Nomrulist:
2452290001Sglebius				flags |= RES_NOMRULIST;
2453132451Sroberto				break;
2454132451Sroberto
2455290001Sglebius			case T_Nopeer:
2456290001Sglebius				flags |= RES_NOPEER;
245782498Sroberto				break;
245882498Sroberto
2459290001Sglebius			case T_Noquery:
2460290001Sglebius				flags |= RES_NOQUERY;
246154359Sroberto				break;
2462290001Sglebius
2463290001Sglebius			case T_Noserve:
2464290001Sglebius				flags |= RES_DONTSERVE;
2465132451Sroberto				break;
2466290001Sglebius
2467290001Sglebius			case T_Notrap:
2468290001Sglebius				flags |= RES_NOTRAP;
2469132451Sroberto				break;
2470290001Sglebius
2471290001Sglebius			case T_Notrust:
2472290001Sglebius				flags |= RES_DONTTRUST;
2473290001Sglebius				break;
2474290001Sglebius
2475290001Sglebius			case T_Version:
2476290001Sglebius				flags |= RES_VERSION;
2477290001Sglebius				break;
2478132451Sroberto			}
2479290001Sglebius		}
248054359Sroberto
2481290001Sglebius		if ((RES_MSSNTP & flags) && !warned_signd) {
2482290001Sglebius			warned_signd = 1;
2483290001Sglebius			fprintf(stderr, "%s\n", signd_warning);
2484290001Sglebius			msyslog(LOG_WARNING, "%s", signd_warning);
2485290001Sglebius		}
2486290001Sglebius
2487290001Sglebius		/* It would be swell if we could identify the line number */
2488290001Sglebius		if ((RES_KOD & flags) && !(RES_LIMITED & flags)) {
2489290001Sglebius			const char *kod_where = (my_node->addr)
2490290001Sglebius					  ? my_node->addr->address
2491290001Sglebius					  : (mflags & RESM_SOURCE)
2492290001Sglebius					    ? "source"
2493290001Sglebius					    : "default";
2494290001Sglebius			const char *kod_warn = "KOD does nothing without LIMITED.";
2495290001Sglebius
2496290001Sglebius			fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
2497290001Sglebius			msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
2498290001Sglebius		}
2499290001Sglebius
2500290001Sglebius		ZERO_SOCK(&addr);
2501290001Sglebius		ai_list = NULL;
2502290001Sglebius		pai = NULL;
2503290001Sglebius		restrict_default = 0;
2504290001Sglebius
2505290001Sglebius		if (NULL == my_node->addr) {
2506290001Sglebius			ZERO_SOCK(&mask);
2507290001Sglebius			if (!(RESM_SOURCE & mflags)) {
2508290001Sglebius				/*
2509290001Sglebius				 * The user specified a default rule
2510290001Sglebius				 * without a -4 / -6 qualifier, add to
2511290001Sglebius				 * both lists
2512290001Sglebius				 */
2513290001Sglebius				restrict_default = 1;
2514290001Sglebius			} else {
2515290001Sglebius				/* apply "restrict source ..." */
2516290001Sglebius				DPRINTF(1, ("restrict source template mflags %x flags %x\n",
2517290001Sglebius					mflags, flags));
2518290001Sglebius				hack_restrict(RESTRICT_FLAGS, NULL,
2519290001Sglebius					      NULL, mflags, flags, 0);
2520290001Sglebius				continue;
2521290001Sglebius			}
2522290001Sglebius		} else {
2523290001Sglebius			/* Resolve the specified address */
2524290001Sglebius			AF(&addr) = (u_short)my_node->addr->type;
2525290001Sglebius
2526290001Sglebius			if (getnetnum(my_node->addr->address,
2527290001Sglebius				      &addr, 1, t_UNK) != 1) {
2528290001Sglebius				/*
2529290001Sglebius				 * Attempt a blocking lookup.  This
2530290001Sglebius				 * is in violation of the nonblocking
2531290001Sglebius				 * design of ntpd's mainline code.  The
2532290001Sglebius				 * alternative of running without the
2533290001Sglebius				 * restriction until the name resolved
2534290001Sglebius				 * seems worse.
2535290001Sglebius				 * Ideally some scheme could be used for
2536290001Sglebius				 * restrict directives in the startup
2537290001Sglebius				 * ntp.conf to delay starting up the
2538290001Sglebius				 * protocol machinery until after all
2539290001Sglebius				 * restrict hosts have been resolved.
2540290001Sglebius				 */
2541290001Sglebius				ai_list = NULL;
2542290001Sglebius				ZERO(hints);
2543290001Sglebius				hints.ai_protocol = IPPROTO_UDP;
2544290001Sglebius				hints.ai_socktype = SOCK_DGRAM;
2545290001Sglebius				hints.ai_family = my_node->addr->type;
2546290001Sglebius				rc = getaddrinfo(my_node->addr->address,
2547290001Sglebius						 "ntp", &hints,
2548290001Sglebius						 &ai_list);
2549290001Sglebius				if (rc) {
2550290001Sglebius					msyslog(LOG_ERR,
2551290001Sglebius						"restrict: ignoring line %d, address/host '%s' unusable.",
2552290001Sglebius						my_node->line_no,
2553290001Sglebius						my_node->addr->address);
2554290001Sglebius					continue;
2555290001Sglebius				}
2556290001Sglebius				INSIST(ai_list != NULL);
2557290001Sglebius				pai = ai_list;
2558290001Sglebius				INSIST(pai->ai_addr != NULL);
2559290001Sglebius				INSIST(sizeof(addr) >=
2560290001Sglebius					   pai->ai_addrlen);
2561290001Sglebius				memcpy(&addr, pai->ai_addr,
2562290001Sglebius				       pai->ai_addrlen);
2563290001Sglebius				INSIST(AF_INET == AF(&addr) ||
2564290001Sglebius					   AF_INET6 == AF(&addr));
2565290001Sglebius			}
2566290001Sglebius
2567290001Sglebius			SET_HOSTMASK(&mask, AF(&addr));
2568290001Sglebius
2569290001Sglebius			/* Resolve the mask */
2570290001Sglebius			if (my_node->mask) {
2571290001Sglebius				ZERO_SOCK(&mask);
2572290001Sglebius				AF(&mask) = my_node->mask->type;
2573290001Sglebius				if (getnetnum(my_node->mask->address,
2574290001Sglebius					      &mask, 1, t_MSK) != 1) {
2575290001Sglebius					msyslog(LOG_ERR,
2576290001Sglebius						"restrict: ignoring line %d, mask '%s' unusable.",
2577290001Sglebius						my_node->line_no,
2578290001Sglebius						my_node->mask->address);
2579290001Sglebius					continue;
2580290001Sglebius				}
2581290001Sglebius			}
2582290001Sglebius		}
2583290001Sglebius
2584290001Sglebius		/* Set the flags */
2585290001Sglebius		if (restrict_default) {
2586290001Sglebius			AF(&addr) = AF_INET;
2587290001Sglebius			AF(&mask) = AF_INET;
2588290001Sglebius			hack_restrict(RESTRICT_FLAGS, &addr,
2589290001Sglebius				      &mask, mflags, flags, 0);
2590290001Sglebius			AF(&addr) = AF_INET6;
2591290001Sglebius			AF(&mask) = AF_INET6;
2592290001Sglebius		}
2593290001Sglebius
2594290001Sglebius		do {
2595290001Sglebius			hack_restrict(RESTRICT_FLAGS, &addr,
2596290001Sglebius				      &mask, mflags, flags, 0);
2597290001Sglebius			if (pai != NULL &&
2598290001Sglebius			    NULL != (pai = pai->ai_next)) {
2599290001Sglebius				INSIST(pai->ai_addr != NULL);
2600290001Sglebius				INSIST(sizeof(addr) >=
2601290001Sglebius					   pai->ai_addrlen);
2602290001Sglebius				ZERO_SOCK(&addr);
2603290001Sglebius				memcpy(&addr, pai->ai_addr,
2604290001Sglebius				       pai->ai_addrlen);
2605290001Sglebius				INSIST(AF_INET == AF(&addr) ||
2606290001Sglebius					   AF_INET6 == AF(&addr));
2607290001Sglebius				SET_HOSTMASK(&mask, AF(&addr));
2608290001Sglebius			}
2609290001Sglebius		} while (pai != NULL);
2610290001Sglebius
2611290001Sglebius		if (ai_list != NULL)
2612290001Sglebius			freeaddrinfo(ai_list);
2613290001Sglebius	}
2614290001Sglebius}
2615290001Sglebius#endif	/* !SIM */
2616290001Sglebius
2617290001Sglebius
2618290001Sglebius#ifdef FREE_CFG_T
2619290001Sglebiusstatic void
2620290001Sglebiusfree_config_access(
2621290001Sglebius	config_tree *ptree
2622290001Sglebius	)
2623290001Sglebius{
2624290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->mru_opts);
2625290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->discard_opts);
2626290001Sglebius	FREE_RESTRICT_FIFO(ptree->restrict_opts);
2627290001Sglebius}
2628290001Sglebius#endif	/* FREE_CFG_T */
2629290001Sglebius
2630290001Sglebius
2631290001Sglebiusstatic void
2632290001Sglebiusconfig_rlimit(
2633290001Sglebius	config_tree *ptree
2634290001Sglebius	)
2635290001Sglebius{
2636290001Sglebius	attr_val *	rlimit_av;
2637290001Sglebius
2638290001Sglebius	rlimit_av = HEAD_PFIFO(ptree->rlimit);
2639290001Sglebius	for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
2640290001Sglebius		switch (rlimit_av->attr) {
2641290001Sglebius
2642290001Sglebius		default:
2643290001Sglebius			INSIST(0);
2644290001Sglebius			break;
2645290001Sglebius
2646290001Sglebius		case T_Memlock:
2647290001Sglebius			/* What if we HAVE_OPT(SAVECONFIGQUIT) ? */
2648290001Sglebius			if (rlimit_av->value.i == -1) {
2649290001Sglebius# if defined(HAVE_MLOCKALL)
2650290001Sglebius				if (cur_memlock != 0) {
2651290001Sglebius					if (-1 == munlockall()) {
2652290001Sglebius						msyslog(LOG_ERR, "munlockall() failed: %m");
2653290001Sglebius					}
2654290001Sglebius				}
2655290001Sglebius				cur_memlock = 0;
2656290001Sglebius# endif /* HAVE_MLOCKALL */
2657290001Sglebius			} else if (rlimit_av->value.i >= 0) {
2658290001Sglebius#if defined(RLIMIT_MEMLOCK)
2659290001Sglebius# if defined(HAVE_MLOCKALL)
2660290001Sglebius				if (cur_memlock != 1) {
2661290001Sglebius					if (-1 == mlockall(MCL_CURRENT|MCL_FUTURE)) {
2662290001Sglebius						msyslog(LOG_ERR, "mlockall() failed: %m");
2663290001Sglebius					}
2664290001Sglebius				}
2665290001Sglebius# endif /* HAVE_MLOCKALL */
2666290001Sglebius				ntp_rlimit(RLIMIT_MEMLOCK,
2667290001Sglebius					   (rlim_t)(rlimit_av->value.i * 1024 * 1024),
2668290001Sglebius					   1024 * 1024,
2669290001Sglebius					   "MB");
2670290001Sglebius				cur_memlock = 1;
2671290001Sglebius#else
2672290001Sglebius				/* STDERR as well would be fine... */
2673290001Sglebius				msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
2674290001Sglebius#endif /* RLIMIT_MEMLOCK */
2675290001Sglebius			} else {
2676290001Sglebius				msyslog(LOG_WARNING, "'rlimit memlock' value of %d is unexpected!", rlimit_av->value.i);
2677290001Sglebius			}
2678290001Sglebius			break;
2679290001Sglebius
2680290001Sglebius		case T_Stacksize:
2681290001Sglebius#if defined(RLIMIT_STACK)
2682290001Sglebius			ntp_rlimit(RLIMIT_STACK,
2683290001Sglebius				   (rlim_t)(rlimit_av->value.i * 4096),
2684290001Sglebius				   4096,
2685290001Sglebius				   "4k");
2686290001Sglebius#else
2687290001Sglebius			/* STDERR as well would be fine... */
2688290001Sglebius			msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
2689290001Sglebius#endif /* RLIMIT_STACK */
2690290001Sglebius			break;
2691290001Sglebius
2692290001Sglebius		case T_Filenum:
2693290001Sglebius#if defined(RLIMIT_NOFILE)
2694290001Sglebius			ntp_rlimit(RLIMIT_NOFILE,
2695290001Sglebius				  (rlim_t)(rlimit_av->value.i),
2696290001Sglebius				  1,
2697290001Sglebius				  "");
2698290001Sglebius#else
2699290001Sglebius			/* STDERR as well would be fine... */
2700290001Sglebius			msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
2701290001Sglebius#endif /* RLIMIT_NOFILE */
2702290001Sglebius			break;
2703290001Sglebius
2704290001Sglebius		}
2705290001Sglebius	}
2706290001Sglebius}
2707290001Sglebius
2708290001Sglebius
2709290001Sglebiusstatic void
2710290001Sglebiusconfig_tinker(
2711290001Sglebius	config_tree *ptree
2712290001Sglebius	)
2713290001Sglebius{
2714290001Sglebius	attr_val *	tinker;
2715290001Sglebius	int		item;
2716290001Sglebius
2717290001Sglebius#ifdef __GNUC__
2718290001Sglebius	item = -1;	/* quiet warning */
2719290001Sglebius#endif
2720290001Sglebius	tinker = HEAD_PFIFO(ptree->tinker);
2721290001Sglebius	for (; tinker != NULL; tinker = tinker->link) {
2722290001Sglebius		switch (tinker->attr) {
2723290001Sglebius
2724290001Sglebius		default:
2725290001Sglebius			INSIST(0);
2726290001Sglebius			break;
2727290001Sglebius
2728290001Sglebius		case T_Allan:
2729290001Sglebius			item = LOOP_ALLAN;
2730290001Sglebius			break;
2731290001Sglebius
2732290001Sglebius		case T_Dispersion:
2733290001Sglebius			item = LOOP_PHI;
2734290001Sglebius			break;
2735290001Sglebius
2736290001Sglebius		case T_Freq:
2737290001Sglebius			item = LOOP_FREQ;
2738290001Sglebius			break;
2739290001Sglebius
2740290001Sglebius		case T_Huffpuff:
2741290001Sglebius			item = LOOP_HUFFPUFF;
2742290001Sglebius			break;
2743290001Sglebius
2744290001Sglebius		case T_Panic:
2745290001Sglebius			item = LOOP_PANIC;
2746290001Sglebius			break;
2747290001Sglebius
2748290001Sglebius		case T_Step:
2749290001Sglebius			item = LOOP_MAX;
2750290001Sglebius			break;
2751290001Sglebius
2752290001Sglebius		case T_Stepback:
2753290001Sglebius			item = LOOP_MAX_BACK;
2754290001Sglebius			break;
2755290001Sglebius
2756290001Sglebius		case T_Stepfwd:
2757290001Sglebius			item = LOOP_MAX_FWD;
2758290001Sglebius			break;
2759290001Sglebius
2760290001Sglebius		case T_Stepout:
2761290001Sglebius			item = LOOP_MINSTEP;
2762290001Sglebius			break;
2763290001Sglebius
2764290001Sglebius		case T_Tick:
2765290001Sglebius			item = LOOP_TICK;
2766290001Sglebius			break;
2767290001Sglebius		}
2768290001Sglebius		loop_config(item, tinker->value.d);
2769290001Sglebius	}
2770290001Sglebius}
2771290001Sglebius
2772290001Sglebius
2773290001Sglebius#ifdef FREE_CFG_T
2774290001Sglebiusstatic void
2775290001Sglebiusfree_config_rlimit(
2776290001Sglebius	config_tree *ptree
2777290001Sglebius	)
2778290001Sglebius{
2779290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->rlimit);
2780290001Sglebius}
2781290001Sglebius
2782290001Sglebiusstatic void
2783290001Sglebiusfree_config_tinker(
2784290001Sglebius	config_tree *ptree
2785290001Sglebius	)
2786290001Sglebius{
2787290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->tinker);
2788290001Sglebius}
2789290001Sglebius#endif	/* FREE_CFG_T */
2790290001Sglebius
2791290001Sglebius
2792290001Sglebius/*
2793290001Sglebius * config_nic_rules - apply interface listen/ignore/drop items
2794290001Sglebius */
2795290001Sglebius#ifndef SIM
2796290001Sglebiusstatic void
2797290001Sglebiusconfig_nic_rules(
2798290001Sglebius	config_tree *ptree,
2799290001Sglebius	int/*BOOL*/ input_from_file
2800290001Sglebius	)
2801290001Sglebius{
2802290001Sglebius	nic_rule_node *	curr_node;
2803290001Sglebius	sockaddr_u	addr;
2804290001Sglebius	nic_rule_match	match_type;
2805290001Sglebius	nic_rule_action	action;
2806290001Sglebius	char *		if_name;
2807290001Sglebius	char *		pchSlash;
2808290001Sglebius	int		prefixlen;
2809290001Sglebius	int		addrbits;
2810290001Sglebius
2811290001Sglebius	curr_node = HEAD_PFIFO(ptree->nic_rules);
2812290001Sglebius
2813290001Sglebius	if (curr_node != NULL
2814290001Sglebius	    && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
2815290001Sglebius		msyslog(LOG_ERR,
2816290001Sglebius			"interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
2817290001Sglebius			(input_from_file) ? ", exiting" : "");
2818290001Sglebius		if (input_from_file)
2819290001Sglebius			exit(1);
2820290001Sglebius		else
2821290001Sglebius			return;
2822290001Sglebius	}
2823290001Sglebius
2824290001Sglebius	for (; curr_node != NULL; curr_node = curr_node->link) {
2825290001Sglebius		prefixlen = -1;
2826290001Sglebius		if_name = curr_node->if_name;
2827290001Sglebius		if (if_name != NULL)
2828290001Sglebius			if_name = estrdup(if_name);
2829290001Sglebius
2830290001Sglebius		switch (curr_node->match_class) {
2831290001Sglebius
2832290001Sglebius		default:
2833290001Sglebius#ifdef __GNUC__
283454359Sroberto			/*
2835290001Sglebius			 * this assignment quiets a gcc "may be used
2836290001Sglebius			 * uninitialized" warning and is here for no
2837290001Sglebius			 * other reason.
2838132451Sroberto			 */
2839290001Sglebius			match_type = MATCH_ALL;
2840290001Sglebius#endif
2841290001Sglebius			INSIST(FALSE);
2842290001Sglebius			break;
2843132451Sroberto
2844290001Sglebius		case 0:
2845132451Sroberto			/*
2846290001Sglebius			 * 0 is out of range for valid token T_...
2847290001Sglebius			 * and in a nic_rules_node indicates the
2848290001Sglebius			 * interface descriptor is either a name or
2849290001Sglebius			 * address, stored in if_name in either case.
285054359Sroberto			 */
2851290001Sglebius			INSIST(if_name != NULL);
2852290001Sglebius			pchSlash = strchr(if_name, '/');
2853290001Sglebius			if (pchSlash != NULL)
2854290001Sglebius				*pchSlash = '\0';
2855290001Sglebius			if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
2856290001Sglebius				match_type = MATCH_IFADDR;
2857290001Sglebius				if (pchSlash != NULL
2858290001Sglebius				    && 1 == sscanf(pchSlash + 1, "%d",
2859290001Sglebius					    &prefixlen)) {
2860290001Sglebius					addrbits = 8 *
2861290001Sglebius					    SIZEOF_INADDR(AF(&addr));
2862290001Sglebius					prefixlen = max(-1, prefixlen);
2863290001Sglebius					prefixlen = min(prefixlen,
2864290001Sglebius							addrbits);
2865290001Sglebius				}
2866290001Sglebius			} else {
2867290001Sglebius				match_type = MATCH_IFNAME;
2868290001Sglebius				if (pchSlash != NULL)
2869290001Sglebius					*pchSlash = '/';
2870290001Sglebius			}
2871290001Sglebius			break;
287254359Sroberto
2873290001Sglebius		case T_All:
2874290001Sglebius			match_type = MATCH_ALL;
2875290001Sglebius			break;
287654359Sroberto
2877290001Sglebius		case T_Ipv4:
2878290001Sglebius			match_type = MATCH_IPV4;
2879290001Sglebius			break;
288054359Sroberto
2881290001Sglebius		case T_Ipv6:
2882290001Sglebius			match_type = MATCH_IPV6;
2883290001Sglebius			break;
288454359Sroberto
2885290001Sglebius		case T_Wildcard:
2886290001Sglebius			match_type = MATCH_WILDCARD;
2887290001Sglebius			break;
2888290001Sglebius		}
288954359Sroberto
2890290001Sglebius		switch (curr_node->action) {
289154359Sroberto
2892290001Sglebius		default:
2893290001Sglebius#ifdef __GNUC__
2894290001Sglebius			/*
2895290001Sglebius			 * this assignment quiets a gcc "may be used
2896290001Sglebius			 * uninitialized" warning and is here for no
2897290001Sglebius			 * other reason.
2898290001Sglebius			 */
2899290001Sglebius			action = ACTION_LISTEN;
2900290001Sglebius#endif
2901290001Sglebius			INSIST(FALSE);
2902290001Sglebius			break;
290354359Sroberto
2904290001Sglebius		case T_Listen:
2905290001Sglebius			action = ACTION_LISTEN;
2906290001Sglebius			break;
290754359Sroberto
2908290001Sglebius		case T_Ignore:
2909290001Sglebius			action = ACTION_IGNORE;
2910290001Sglebius			break;
291154359Sroberto
2912290001Sglebius		case T_Drop:
2913290001Sglebius			action = ACTION_DROP;
2914290001Sglebius			break;
2915290001Sglebius		}
291654359Sroberto
2917290001Sglebius		add_nic_rule(match_type, if_name, prefixlen,
2918290001Sglebius			     action);
2919290001Sglebius		timer_interfacetimeout(current_time + 2);
2920290001Sglebius		if (if_name != NULL)
2921290001Sglebius			free(if_name);
2922290001Sglebius	}
2923290001Sglebius}
2924290001Sglebius#endif	/* !SIM */
292582498Sroberto
292682498Sroberto
2927290001Sglebius#ifdef FREE_CFG_T
2928290001Sglebiusstatic void
2929290001Sglebiusfree_config_nic_rules(
2930290001Sglebius	config_tree *ptree
2931290001Sglebius	)
2932290001Sglebius{
2933290001Sglebius	nic_rule_node *curr_node;
293454359Sroberto
2935290001Sglebius	if (ptree->nic_rules != NULL) {
2936290001Sglebius		for (;;) {
2937290001Sglebius			UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
2938290001Sglebius			if (NULL == curr_node)
2939290001Sglebius				break;
2940290001Sglebius			free(curr_node->if_name);
2941290001Sglebius			free(curr_node);
2942290001Sglebius		}
2943290001Sglebius		free(ptree->nic_rules);
2944290001Sglebius		ptree->nic_rules = NULL;
2945290001Sglebius	}
2946290001Sglebius}
2947290001Sglebius#endif	/* FREE_CFG_T */
2948290001Sglebius
2949290001Sglebius
2950290001Sglebiusstatic void
2951290001Sglebiusapply_enable_disable(
2952290001Sglebius	attr_val_fifo *	fifo,
2953290001Sglebius	int		enable
2954290001Sglebius	)
2955290001Sglebius{
2956290001Sglebius	attr_val *curr_flag;
2957290001Sglebius	int option;
2958290001Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
2959290001Sglebius	bc_entry *pentry;
2960290001Sglebius#endif
2961290001Sglebius
2962290001Sglebius	for (curr_flag = HEAD_PFIFO(fifo);
2963290001Sglebius	     curr_flag != NULL;
2964290001Sglebius	     curr_flag = curr_flag->link) {
2965290001Sglebius
2966290001Sglebius		option = curr_flag->value.i;
2967290001Sglebius		switch (option) {
2968290001Sglebius
2969290001Sglebius		default:
2970290001Sglebius			msyslog(LOG_ERR,
2971290001Sglebius				"can not apply enable/disable token %d, unknown",
2972290001Sglebius				option);
2973290001Sglebius			break;
2974290001Sglebius
2975290001Sglebius		case T_Auth:
2976290001Sglebius			proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
2977290001Sglebius			break;
2978290001Sglebius
2979290001Sglebius		case T_Bclient:
2980290001Sglebius			proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
2981290001Sglebius			break;
2982290001Sglebius
2983290001Sglebius		case T_Calibrate:
2984290001Sglebius			proto_config(PROTO_CAL, enable, 0., NULL);
2985290001Sglebius			break;
2986290001Sglebius
2987290001Sglebius		case T_Kernel:
2988290001Sglebius			proto_config(PROTO_KERNEL, enable, 0., NULL);
2989290001Sglebius			break;
2990290001Sglebius
2991290001Sglebius		case T_Monitor:
2992290001Sglebius			proto_config(PROTO_MONITOR, enable, 0., NULL);
2993290001Sglebius			break;
2994290001Sglebius
2995301301Sdelphij		case T_Mode7:
2996301301Sdelphij			proto_config(PROTO_MODE7, enable, 0., NULL);
2997301301Sdelphij			break;
2998301301Sdelphij
2999290001Sglebius		case T_Ntp:
3000290001Sglebius			proto_config(PROTO_NTP, enable, 0., NULL);
3001290001Sglebius			break;
3002290001Sglebius
3003301301Sdelphij		case T_PCEdigest:
3004301301Sdelphij			proto_config(PROTO_PCEDIGEST, enable, 0., NULL);
3005290001Sglebius			break;
3006290001Sglebius
3007290001Sglebius		case T_Stats:
3008290001Sglebius			proto_config(PROTO_FILEGEN, enable, 0., NULL);
3009290001Sglebius			break;
3010290001Sglebius
3011294905Sdelphij		case T_UEcrypto:
3012294905Sdelphij			proto_config(PROTO_UECRYPTO, enable, 0., NULL);
3013294905Sdelphij			break;
3014294905Sdelphij
3015294905Sdelphij		case T_UEcryptonak:
3016294905Sdelphij			proto_config(PROTO_UECRYPTONAK, enable, 0., NULL);
3017294905Sdelphij			break;
3018294905Sdelphij
3019294905Sdelphij		case T_UEdigest:
3020294905Sdelphij			proto_config(PROTO_UEDIGEST, enable, 0., NULL);
3021294905Sdelphij			break;
3022294905Sdelphij
3023290001Sglebius#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3024290001Sglebius		case T_Bc_bugXXXX:
3025290001Sglebius			pentry = bc_list;
3026290001Sglebius			while (pentry->token) {
3027290001Sglebius				if (pentry->token == option)
302854359Sroberto					break;
3029290001Sglebius				pentry++;
303054359Sroberto			}
3031290001Sglebius			if (!pentry->token) {
3032290001Sglebius				msyslog(LOG_ERR,
3033290001Sglebius					"compat token %d not in bc_list[]",
3034290001Sglebius					option);
3035290001Sglebius				continue;
3036290001Sglebius			}
3037290001Sglebius			pentry->enabled = enable;
303854359Sroberto			break;
3039290001Sglebius#endif
3040290001Sglebius		}
3041290001Sglebius	}
3042290001Sglebius}
304354359Sroberto
304454359Sroberto
3045290001Sglebiusstatic void
3046290001Sglebiusconfig_system_opts(
3047290001Sglebius	config_tree *ptree
3048290001Sglebius	)
3049290001Sglebius{
3050290001Sglebius	apply_enable_disable(ptree->enable_opts, 1);
3051290001Sglebius	apply_enable_disable(ptree->disable_opts, 0);
3052290001Sglebius}
3053290001Sglebius
3054290001Sglebius
3055290001Sglebius#ifdef FREE_CFG_T
3056290001Sglebiusstatic void
3057290001Sglebiusfree_config_system_opts(
3058290001Sglebius	config_tree *ptree
3059290001Sglebius	)
3060290001Sglebius{
3061290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->enable_opts);
3062290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->disable_opts);
3063290001Sglebius}
3064290001Sglebius#endif	/* FREE_CFG_T */
3065290001Sglebius
3066290001Sglebius
3067290001Sglebiusstatic void
3068290001Sglebiusconfig_logconfig(
3069290001Sglebius	config_tree *ptree
3070290001Sglebius	)
3071290001Sglebius{
3072290001Sglebius	attr_val *	my_lc;
3073290001Sglebius
3074290001Sglebius	my_lc = HEAD_PFIFO(ptree->logconfig);
3075290001Sglebius	for (; my_lc != NULL; my_lc = my_lc->link) {
3076290001Sglebius		switch (my_lc->attr) {
3077290001Sglebius
3078290001Sglebius		case '+':
3079290001Sglebius			ntp_syslogmask |= get_logmask(my_lc->value.s);
308054359Sroberto			break;
308154359Sroberto
3082290001Sglebius		case '-':
3083290001Sglebius			ntp_syslogmask &= ~get_logmask(my_lc->value.s);
3084290001Sglebius			break;
3085132451Sroberto
3086290001Sglebius		case '=':
3087290001Sglebius			ntp_syslogmask = get_logmask(my_lc->value.s);
3088132451Sroberto			break;
3089290001Sglebius		default:
3090290001Sglebius			INSIST(0);
3091290001Sglebius			break;
3092290001Sglebius		}
3093290001Sglebius	}
3094290001Sglebius}
3095132451Sroberto
309654359Sroberto
3097290001Sglebius#ifdef FREE_CFG_T
3098290001Sglebiusstatic void
3099290001Sglebiusfree_config_logconfig(
3100290001Sglebius	config_tree *ptree
3101290001Sglebius	)
3102290001Sglebius{
3103290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->logconfig);
3104290001Sglebius}
3105290001Sglebius#endif	/* FREE_CFG_T */
3106290001Sglebius
3107290001Sglebius
3108290001Sglebius#ifndef SIM
3109290001Sglebiusstatic void
3110290001Sglebiusconfig_phone(
3111290001Sglebius	config_tree *ptree
3112290001Sglebius	)
3113290001Sglebius{
3114290001Sglebius	size_t		i;
3115290001Sglebius	string_node *	sn;
3116290001Sglebius
3117290001Sglebius	i = 0;
3118290001Sglebius	sn = HEAD_PFIFO(ptree->phone);
3119290001Sglebius	for (; sn != NULL; sn = sn->link) {
3120290001Sglebius		/* need to leave array entry for NULL terminator */
3121290001Sglebius		if (i < COUNTOF(sys_phone) - 1) {
3122290001Sglebius			sys_phone[i++] = estrdup(sn->s);
3123290001Sglebius			sys_phone[i] = NULL;
3124290001Sglebius		} else {
3125290001Sglebius			msyslog(LOG_INFO,
3126290001Sglebius				"phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
3127290001Sglebius				(COUNTOF(sys_phone) - 1), sn->s);
3128290001Sglebius		}
3129290001Sglebius	}
3130290001Sglebius}
3131290001Sglebius#endif	/* !SIM */
3132290001Sglebius
3133290001Sglebiusstatic void
3134290001Sglebiusconfig_mdnstries(
3135290001Sglebius	config_tree *ptree
3136290001Sglebius	)
3137290001Sglebius{
3138290001Sglebius#ifdef HAVE_DNSREGISTRATION
3139290001Sglebius	extern int mdnstries;
3140290001Sglebius	mdnstries = ptree->mdnstries;
3141290001Sglebius#endif  /* HAVE_DNSREGISTRATION */
3142290001Sglebius}
3143290001Sglebius
3144290001Sglebius#ifdef FREE_CFG_T
3145290001Sglebiusstatic void
3146290001Sglebiusfree_config_phone(
3147290001Sglebius	config_tree *ptree
3148290001Sglebius	)
3149290001Sglebius{
3150290001Sglebius	FREE_STRING_FIFO(ptree->phone);
3151290001Sglebius}
3152290001Sglebius#endif	/* FREE_CFG_T */
3153290001Sglebius
3154290001Sglebius
3155290001Sglebius#ifndef SIM
3156290001Sglebiusstatic void
3157290001Sglebiusconfig_setvar(
3158290001Sglebius	config_tree *ptree
3159290001Sglebius	)
3160290001Sglebius{
3161290001Sglebius	setvar_node *my_node;
3162290001Sglebius	size_t	varlen, vallen, octets;
3163290001Sglebius	char *	str;
3164290001Sglebius
3165290001Sglebius	str = NULL;
3166290001Sglebius	my_node = HEAD_PFIFO(ptree->setvar);
3167290001Sglebius	for (; my_node != NULL; my_node = my_node->link) {
3168290001Sglebius		varlen = strlen(my_node->var);
3169290001Sglebius		vallen = strlen(my_node->val);
3170290001Sglebius		octets = varlen + vallen + 1 + 1;
3171290001Sglebius		str = erealloc(str, octets);
3172290001Sglebius		snprintf(str, octets, "%s=%s", my_node->var,
3173290001Sglebius			 my_node->val);
3174290001Sglebius		set_sys_var(str, octets, (my_node->isdefault)
3175290001Sglebius						? DEF
3176290001Sglebius						: 0);
3177290001Sglebius	}
3178290001Sglebius	if (str != NULL)
3179290001Sglebius		free(str);
3180290001Sglebius}
3181290001Sglebius#endif	/* !SIM */
3182290001Sglebius
3183290001Sglebius
3184290001Sglebius#ifdef FREE_CFG_T
3185290001Sglebiusstatic void
3186290001Sglebiusfree_config_setvar(
3187290001Sglebius	config_tree *ptree
3188290001Sglebius	)
3189290001Sglebius{
3190290001Sglebius	FREE_SETVAR_FIFO(ptree->setvar);
3191290001Sglebius}
3192290001Sglebius#endif	/* FREE_CFG_T */
3193290001Sglebius
3194290001Sglebius
3195290001Sglebius#ifndef SIM
3196290001Sglebiusstatic void
3197290001Sglebiusconfig_ttl(
3198290001Sglebius	config_tree *ptree
3199290001Sglebius	)
3200290001Sglebius{
3201290001Sglebius	size_t i = 0;
3202290001Sglebius	int_node *curr_ttl;
3203290001Sglebius
3204290001Sglebius	curr_ttl = HEAD_PFIFO(ptree->ttl);
3205290001Sglebius	for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
3206290001Sglebius		if (i < COUNTOF(sys_ttl))
3207290001Sglebius			sys_ttl[i++] = (u_char)curr_ttl->i;
3208290001Sglebius		else
3209290001Sglebius			msyslog(LOG_INFO,
3210290001Sglebius				"ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
3211290001Sglebius				COUNTOF(sys_ttl), curr_ttl->i);
3212290001Sglebius	}
3213290001Sglebius	sys_ttlmax = i - 1;
3214290001Sglebius}
3215290001Sglebius#endif	/* !SIM */
3216290001Sglebius
3217290001Sglebius
3218290001Sglebius#ifdef FREE_CFG_T
3219290001Sglebiusstatic void
3220290001Sglebiusfree_config_ttl(
3221290001Sglebius	config_tree *ptree
3222290001Sglebius	)
3223290001Sglebius{
3224290001Sglebius	FREE_INT_FIFO(ptree->ttl);
3225290001Sglebius}
3226290001Sglebius#endif	/* FREE_CFG_T */
3227290001Sglebius
3228290001Sglebius
3229290001Sglebius#ifndef SIM
3230290001Sglebiusstatic void
3231290001Sglebiusconfig_trap(
3232290001Sglebius	config_tree *ptree
3233290001Sglebius	)
3234290001Sglebius{
3235290001Sglebius	addr_opts_node *curr_trap;
3236290001Sglebius	attr_val *curr_opt;
3237290001Sglebius	sockaddr_u addr_sock;
3238290001Sglebius	sockaddr_u peeraddr;
3239290001Sglebius	struct interface *localaddr;
3240290001Sglebius	struct addrinfo hints;
3241290001Sglebius	char port_text[8];
3242290001Sglebius	settrap_parms *pstp;
3243290001Sglebius	u_short port;
3244290001Sglebius	int err_flag;
3245290001Sglebius	int rc;
3246290001Sglebius
3247290001Sglebius	/* silence warning about addr_sock potentially uninitialized */
3248290001Sglebius	AF(&addr_sock) = AF_UNSPEC;
3249290001Sglebius
3250290001Sglebius	curr_trap = HEAD_PFIFO(ptree->trap);
3251290001Sglebius	for (; curr_trap != NULL; curr_trap = curr_trap->link) {
3252290001Sglebius		err_flag = 0;
3253290001Sglebius		port = 0;
3254290001Sglebius		localaddr = NULL;
3255290001Sglebius
3256290001Sglebius		curr_opt = HEAD_PFIFO(curr_trap->options);
3257290001Sglebius		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3258290001Sglebius			if (T_Port == curr_opt->attr) {
3259290001Sglebius				if (curr_opt->value.i < 1
3260290001Sglebius				    || curr_opt->value.i > USHRT_MAX) {
326154359Sroberto					msyslog(LOG_ERR,
3262290001Sglebius						"invalid port number "
3263290001Sglebius						"%d, trap ignored",
3264290001Sglebius						curr_opt->value.i);
3265290001Sglebius					err_flag = 1;
326654359Sroberto				}
3267290001Sglebius				port = (u_short)curr_opt->value.i;
326854359Sroberto			}
3269290001Sglebius			else if (T_Interface == curr_opt->attr) {
3270290001Sglebius				/* Resolve the interface address */
3271290001Sglebius				ZERO_SOCK(&addr_sock);
3272290001Sglebius				if (getnetnum(curr_opt->value.s,
3273290001Sglebius					      &addr_sock, 1, t_UNK) != 1) {
3274290001Sglebius					err_flag = 1;
3275290001Sglebius					break;
3276290001Sglebius				}
327754359Sroberto
3278290001Sglebius				localaddr = findinterface(&addr_sock);
3279290001Sglebius
3280290001Sglebius				if (NULL == localaddr) {
328154359Sroberto					msyslog(LOG_ERR,
3282290001Sglebius						"can't find interface with address %s",
3283290001Sglebius						stoa(&addr_sock));
3284290001Sglebius					err_flag = 1;
328554359Sroberto				}
328654359Sroberto			}
3287290001Sglebius		}
328854359Sroberto
3289290001Sglebius		/* Now process the trap for the specified interface
3290290001Sglebius		 * and port number
3291290001Sglebius		 */
3292290001Sglebius		if (!err_flag) {
3293290001Sglebius			if (!port)
3294290001Sglebius				port = TRAPPORT;
3295290001Sglebius			ZERO_SOCK(&peeraddr);
3296290001Sglebius			rc = getnetnum(curr_trap->addr->address,
3297290001Sglebius				       &peeraddr, 1, t_UNK);
3298290001Sglebius			if (1 != rc) {
3299290001Sglebius#ifndef WORKER
3300290001Sglebius				msyslog(LOG_ERR,
3301290001Sglebius					"trap: unable to use IP address %s.",
3302290001Sglebius					curr_trap->addr->address);
3303290001Sglebius#else	/* WORKER follows */
3304290001Sglebius				/*
3305290001Sglebius				 * save context and hand it off
3306290001Sglebius				 * for name resolution.
3307290001Sglebius				 */
3308290001Sglebius				ZERO(hints);
3309290001Sglebius				hints.ai_protocol = IPPROTO_UDP;
3310290001Sglebius				hints.ai_socktype = SOCK_DGRAM;
3311290001Sglebius				snprintf(port_text, sizeof(port_text),
3312290001Sglebius					 "%u", port);
3313290001Sglebius				hints.ai_flags = Z_AI_NUMERICSERV;
3314290001Sglebius				pstp = emalloc_zero(sizeof(*pstp));
3315290001Sglebius				if (localaddr != NULL) {
3316290001Sglebius					hints.ai_family = localaddr->family;
3317290001Sglebius					pstp->ifaddr_nonnull = 1;
3318290001Sglebius					memcpy(&pstp->ifaddr,
3319290001Sglebius					       &localaddr->sin,
3320290001Sglebius					       sizeof(pstp->ifaddr));
3321290001Sglebius				}
3322290001Sglebius				rc = getaddrinfo_sometime(
3323290001Sglebius					curr_trap->addr->address,
3324290001Sglebius					port_text, &hints,
3325290001Sglebius					INITIAL_DNS_RETRY,
3326290001Sglebius					&trap_name_resolved,
3327290001Sglebius					pstp);
3328290001Sglebius				if (!rc)
332954359Sroberto					msyslog(LOG_ERR,
3330290001Sglebius						"config_trap: getaddrinfo_sometime(%s,%s): %m",
3331290001Sglebius						curr_trap->addr->address,
3332290001Sglebius						port_text);
3333290001Sglebius#endif	/* WORKER */
3334290001Sglebius				continue;
333554359Sroberto			}
3336290001Sglebius			/* port is at same location for v4 and v6 */
3337290001Sglebius			SET_PORT(&peeraddr, port);
333854359Sroberto
3339290001Sglebius			if (NULL == localaddr)
3340290001Sglebius				localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3341290001Sglebius			else
3342290001Sglebius				AF(&peeraddr) = AF(&addr_sock);
3343290001Sglebius
3344290001Sglebius			if (!ctlsettrap(&peeraddr, localaddr, 0,
3345290001Sglebius					NTP_VERSION))
334654359Sroberto				msyslog(LOG_ERR,
3347290001Sglebius					"set trap %s -> %s failed.",
3348290001Sglebius					latoa(localaddr),
3349290001Sglebius					stoa(&peeraddr));
3350290001Sglebius		}
3351290001Sglebius	}
3352290001Sglebius}
3353290001Sglebius
3354290001Sglebius
3355290001Sglebius/*
3356290001Sglebius * trap_name_resolved()
3357290001Sglebius *
3358290001Sglebius * Callback invoked when config_trap()'s DNS lookup completes.
3359290001Sglebius */
3360290001Sglebius# ifdef WORKER
3361290001Sglebiusstatic void
3362290001Sglebiustrap_name_resolved(
3363290001Sglebius	int			rescode,
3364290001Sglebius	int			gai_errno,
3365290001Sglebius	void *			context,
3366290001Sglebius	const char *		name,
3367290001Sglebius	const char *		service,
3368290001Sglebius	const struct addrinfo *	hints,
3369290001Sglebius	const struct addrinfo *	res
3370290001Sglebius	)
3371290001Sglebius{
3372290001Sglebius	settrap_parms *pstp;
3373290001Sglebius	struct interface *localaddr;
3374290001Sglebius	sockaddr_u peeraddr;
3375290001Sglebius
3376290001Sglebius	(void)gai_errno;
3377290001Sglebius	(void)service;
3378290001Sglebius	(void)hints;
3379290001Sglebius	pstp = context;
3380290001Sglebius	if (rescode) {
3381290001Sglebius		msyslog(LOG_ERR,
3382290001Sglebius			"giving up resolving trap host %s: %s (%d)",
3383290001Sglebius			name, gai_strerror(rescode), rescode);
3384290001Sglebius		free(pstp);
3385290001Sglebius		return;
3386290001Sglebius	}
3387290001Sglebius	INSIST(sizeof(peeraddr) >= res->ai_addrlen);
3388290001Sglebius	ZERO(peeraddr);
3389290001Sglebius	memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3390290001Sglebius	localaddr = NULL;
3391290001Sglebius	if (pstp->ifaddr_nonnull)
3392290001Sglebius		localaddr = findinterface(&pstp->ifaddr);
3393290001Sglebius	if (NULL == localaddr)
3394290001Sglebius		localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3395290001Sglebius	if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
3396290001Sglebius		msyslog(LOG_ERR, "set trap %s -> %s failed.",
3397290001Sglebius			latoa(localaddr), stoa(&peeraddr));
3398290001Sglebius	free(pstp);
3399290001Sglebius}
3400290001Sglebius# endif	/* WORKER */
3401290001Sglebius#endif	/* !SIM */
3402290001Sglebius
3403290001Sglebius
3404290001Sglebius#ifdef FREE_CFG_T
3405290001Sglebiusstatic void
3406290001Sglebiusfree_config_trap(
3407290001Sglebius	config_tree *ptree
3408290001Sglebius	)
3409290001Sglebius{
3410290001Sglebius	FREE_ADDR_OPTS_FIFO(ptree->trap);
3411290001Sglebius}
3412290001Sglebius#endif	/* FREE_CFG_T */
3413290001Sglebius
3414290001Sglebius
3415290001Sglebius#ifndef SIM
3416290001Sglebiusstatic void
3417290001Sglebiusconfig_fudge(
3418290001Sglebius	config_tree *ptree
3419290001Sglebius	)
3420290001Sglebius{
3421290001Sglebius	addr_opts_node *curr_fudge;
3422290001Sglebius	attr_val *curr_opt;
3423290001Sglebius	sockaddr_u addr_sock;
3424290001Sglebius	address_node *addr_node;
3425290001Sglebius	struct refclockstat clock_stat;
3426290001Sglebius	int err_flag;
3427290001Sglebius
3428290001Sglebius	curr_fudge = HEAD_PFIFO(ptree->fudge);
3429290001Sglebius	for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
3430290001Sglebius		err_flag = 0;
3431290001Sglebius
3432290001Sglebius		/* Get the reference clock address and
3433290001Sglebius		 * ensure that it is sane
3434290001Sglebius		 */
3435290001Sglebius		addr_node = curr_fudge->addr;
3436290001Sglebius		ZERO_SOCK(&addr_sock);
3437290001Sglebius		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
3438290001Sglebius		    != 1) {
3439290001Sglebius			err_flag = 1;
3440290001Sglebius			msyslog(LOG_ERR,
3441290001Sglebius				"unrecognized fudge reference clock address %s, line ignored",
3442290001Sglebius				stoa(&addr_sock));
3443290001Sglebius		}
3444290001Sglebius
3445290001Sglebius		if (!ISREFCLOCKADR(&addr_sock)) {
3446290001Sglebius			err_flag = 1;
3447290001Sglebius			msyslog(LOG_ERR,
3448290001Sglebius				"inappropriate address %s for the fudge command, line ignored",
3449290001Sglebius				stoa(&addr_sock));
3450290001Sglebius		}
3451290001Sglebius
3452290001Sglebius		/* Parse all the options to the fudge command */
3453290001Sglebius		ZERO(clock_stat);
3454290001Sglebius		curr_opt = HEAD_PFIFO(curr_fudge->options);
3455290001Sglebius		for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3456290001Sglebius			switch (curr_opt->attr) {
3457290001Sglebius
3458290001Sglebius			case T_Time1:
3459290001Sglebius				clock_stat.haveflags |= CLK_HAVETIME1;
3460290001Sglebius				clock_stat.fudgetime1 = curr_opt->value.d;
346154359Sroberto				break;
3462290001Sglebius
3463290001Sglebius			case T_Time2:
3464290001Sglebius				clock_stat.haveflags |= CLK_HAVETIME2;
3465290001Sglebius				clock_stat.fudgetime2 = curr_opt->value.d;
3466132451Sroberto				break;
3467290001Sglebius
3468290001Sglebius			case T_Stratum:
3469290001Sglebius				clock_stat.haveflags |= CLK_HAVEVAL1;
3470290001Sglebius				clock_stat.fudgeval1 = curr_opt->value.i;
3471132451Sroberto				break;
3472290001Sglebius
3473290001Sglebius			case T_Refid:
3474290001Sglebius				clock_stat.haveflags |= CLK_HAVEVAL2;
3475290001Sglebius				clock_stat.fudgeval2 = 0;
3476290001Sglebius				memcpy(&clock_stat.fudgeval2,
3477290001Sglebius				       curr_opt->value.s,
3478290001Sglebius				       min(strlen(curr_opt->value.s), 4));
3479290001Sglebius				break;
3480290001Sglebius
3481290001Sglebius			case T_Flag1:
3482290001Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG1;
3483290001Sglebius				if (curr_opt->value.i)
3484290001Sglebius					clock_stat.flags |= CLK_FLAG1;
3485290001Sglebius				else
3486290001Sglebius					clock_stat.flags &= ~CLK_FLAG1;
3487290001Sglebius				break;
3488290001Sglebius
3489290001Sglebius			case T_Flag2:
3490290001Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG2;
3491290001Sglebius				if (curr_opt->value.i)
3492290001Sglebius					clock_stat.flags |= CLK_FLAG2;
3493290001Sglebius				else
3494290001Sglebius					clock_stat.flags &= ~CLK_FLAG2;
3495290001Sglebius				break;
3496290001Sglebius
3497290001Sglebius			case T_Flag3:
3498290001Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG3;
3499290001Sglebius				if (curr_opt->value.i)
3500290001Sglebius					clock_stat.flags |= CLK_FLAG3;
3501290001Sglebius				else
3502290001Sglebius					clock_stat.flags &= ~CLK_FLAG3;
3503290001Sglebius				break;
3504290001Sglebius
3505290001Sglebius			case T_Flag4:
3506290001Sglebius				clock_stat.haveflags |= CLK_HAVEFLAG4;
3507290001Sglebius				if (curr_opt->value.i)
3508290001Sglebius					clock_stat.flags |= CLK_FLAG4;
3509290001Sglebius				else
3510290001Sglebius					clock_stat.flags &= ~CLK_FLAG4;
3511290001Sglebius				break;
3512290001Sglebius
3513290001Sglebius			default:
3514290001Sglebius				msyslog(LOG_ERR,
3515290001Sglebius					"Unexpected fudge flag %s (%d) for %s",
3516290001Sglebius					token_name(curr_opt->attr),
3517290001Sglebius					curr_opt->attr, stoa(&addr_sock));
3518290001Sglebius				exit(curr_opt->attr ? curr_opt->attr : 1);
3519132451Sroberto			}
3520290001Sglebius		}
3521290001Sglebius# ifdef REFCLOCK
3522290001Sglebius		if (!err_flag)
3523290001Sglebius			refclock_control(&addr_sock, &clock_stat, NULL);
3524290001Sglebius# endif
3525290001Sglebius	}
3526290001Sglebius}
3527290001Sglebius#endif	/* !SIM */
3528132451Sroberto
352954359Sroberto
3530290001Sglebius#ifdef FREE_CFG_T
3531290001Sglebiusstatic void
3532290001Sglebiusfree_config_fudge(
3533290001Sglebius	config_tree *ptree
3534290001Sglebius	)
3535290001Sglebius{
3536290001Sglebius	FREE_ADDR_OPTS_FIFO(ptree->fudge);
3537290001Sglebius}
3538290001Sglebius#endif	/* FREE_CFG_T */
353954359Sroberto
354054359Sroberto
3541290001Sglebiusstatic void
3542290001Sglebiusconfig_vars(
3543290001Sglebius	config_tree *ptree
3544290001Sglebius	)
3545290001Sglebius{
3546290001Sglebius	attr_val *curr_var;
3547290001Sglebius	int len;
354854359Sroberto
3549290001Sglebius	curr_var = HEAD_PFIFO(ptree->vars);
3550290001Sglebius	for (; curr_var != NULL; curr_var = curr_var->link) {
3551290001Sglebius		/* Determine which variable to set and set it */
3552290001Sglebius		switch (curr_var->attr) {
355354359Sroberto
3554290001Sglebius		case T_Broadcastdelay:
3555290001Sglebius			proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
3556290001Sglebius			break;
355754359Sroberto
3558290001Sglebius		case T_Tick:
3559290001Sglebius			loop_config(LOOP_TICK, curr_var->value.d);
356054359Sroberto			break;
356154359Sroberto
3562290001Sglebius		case T_Driftfile:
3563290001Sglebius			if ('\0' == curr_var->value.s[0]) {
3564290001Sglebius				stats_drift_file = 0;
3565290001Sglebius				msyslog(LOG_INFO, "config: driftfile disabled");
3566290001Sglebius			} else
3567290001Sglebius				stats_config(STATS_FREQ_FILE, curr_var->value.s);
3568290001Sglebius			break;
356954359Sroberto
3570290001Sglebius		case T_Dscp:
3571290001Sglebius			/* DSCP is in the upper 6 bits of the IP TOS/DS field */
3572290001Sglebius			qos = curr_var->value.i << 2;
3573290001Sglebius			break;
357454359Sroberto
3575290001Sglebius		case T_Ident:
3576290001Sglebius			sys_ident = curr_var->value.s;
3577290001Sglebius			break;
357854359Sroberto
3579290001Sglebius		case T_WanderThreshold:		/* FALLTHROUGH */
3580290001Sglebius		case T_Nonvolatile:
3581290001Sglebius			wander_threshold = curr_var->value.d;
3582290001Sglebius			break;
358354359Sroberto
3584290001Sglebius		case T_Leapfile:
3585290001Sglebius			stats_config(STATS_LEAP_FILE, curr_var->value.s);
3586290001Sglebius			break;
358754359Sroberto
3588290001Sglebius#ifdef LEAP_SMEAR
3589290001Sglebius		case T_Leapsmearinterval:
3590290001Sglebius			leap_smear_intv = curr_var->value.i;
3591290001Sglebius			msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
3592290001Sglebius			break;
3593290001Sglebius#endif
359454359Sroberto
3595290001Sglebius		case T_Pidfile:
3596290001Sglebius			stats_config(STATS_PID_FILE, curr_var->value.s);
3597290001Sglebius			break;
359854359Sroberto
3599290001Sglebius		case T_Logfile:
3600290001Sglebius			if (-1 == change_logfile(curr_var->value.s, TRUE))
3601290001Sglebius				msyslog(LOG_ERR,
3602290001Sglebius					"Cannot open logfile %s: %m",
3603290001Sglebius					curr_var->value.s);
3604290001Sglebius			break;
360554359Sroberto
3606290001Sglebius		case T_Saveconfigdir:
3607290001Sglebius			if (saveconfigdir != NULL)
3608290001Sglebius				free(saveconfigdir);
3609290001Sglebius			len = strlen(curr_var->value.s);
3610290001Sglebius			if (0 == len) {
3611290001Sglebius				saveconfigdir = NULL;
3612290001Sglebius			} else if (DIR_SEP != curr_var->value.s[len - 1]
3613290001Sglebius#ifdef SYS_WINNT	/* slash is also a dir. sep. on Windows */
3614290001Sglebius				   && '/' != curr_var->value.s[len - 1]
3615290001Sglebius#endif
3616290001Sglebius				 ) {
3617290001Sglebius					len++;
3618290001Sglebius					saveconfigdir = emalloc(len + 1);
3619290001Sglebius					snprintf(saveconfigdir, len + 1,
3620290001Sglebius						 "%s%c",
3621290001Sglebius						 curr_var->value.s,
3622290001Sglebius						 DIR_SEP);
3623290001Sglebius			} else {
3624290001Sglebius					saveconfigdir = estrdup(
3625290001Sglebius					    curr_var->value.s);
362654359Sroberto			}
3627290001Sglebius			break;
362854359Sroberto
3629290001Sglebius		case T_Automax:
3630290001Sglebius#ifdef AUTOKEY
3631290001Sglebius			sys_automax = curr_var->value.i;
363254359Sroberto#endif
363354359Sroberto			break;
363454359Sroberto
3635290001Sglebius		default:
3636290001Sglebius			msyslog(LOG_ERR,
3637290001Sglebius				"config_vars(): unexpected token %d",
3638290001Sglebius				curr_var->attr);
3639290001Sglebius		}
3640290001Sglebius	}
3641290001Sglebius}
3642290001Sglebius
3643290001Sglebius
3644290001Sglebius#ifdef FREE_CFG_T
3645290001Sglebiusstatic void
3646290001Sglebiusfree_config_vars(
3647290001Sglebius	config_tree *ptree
3648290001Sglebius	)
3649290001Sglebius{
3650290001Sglebius	FREE_ATTR_VAL_FIFO(ptree->vars);
3651290001Sglebius}
3652290001Sglebius#endif	/* FREE_CFG_T */
3653290001Sglebius
3654290001Sglebius
3655290001Sglebius/* Define a function to check if a resolved address is sane.
3656290001Sglebius * If yes, return 1, else return 0;
3657290001Sglebius */
3658290001Sglebiusstatic int
3659290001Sglebiusis_sane_resolved_address(
3660290001Sglebius	sockaddr_u *	peeraddr,
3661290001Sglebius	int		hmode
3662290001Sglebius	)
3663290001Sglebius{
3664290001Sglebius	if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
3665290001Sglebius		msyslog(LOG_ERR,
3666290001Sglebius			"attempt to configure invalid address %s",
3667290001Sglebius			stoa(peeraddr));
3668290001Sglebius		return 0;
3669290001Sglebius	}
3670290001Sglebius	/*
3671290001Sglebius	 * Shouldn't be able to specify multicast
3672290001Sglebius	 * address for server/peer!
3673290001Sglebius	 * and unicast address for manycastclient!
3674290001Sglebius	 */
3675290001Sglebius	if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
3676290001Sglebius	    && IS_MCAST(peeraddr)) {
3677290001Sglebius		msyslog(LOG_ERR,
3678290001Sglebius			"attempt to configure invalid address %s",
3679290001Sglebius			stoa(peeraddr));
3680290001Sglebius		return 0;
3681290001Sglebius	}
3682290001Sglebius	if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
3683290001Sglebius		msyslog(LOG_ERR,
3684290001Sglebius			"attempt to configure invalid address %s",
3685290001Sglebius			stoa(peeraddr));
3686290001Sglebius		return 0;
3687290001Sglebius	}
3688290001Sglebius
3689290001Sglebius	if (IS_IPV6(peeraddr) && !ipv6_works)
3690290001Sglebius		return 0;
3691290001Sglebius
3692290001Sglebius	/* Ok, all tests succeeded, now we can return 1 */
3693290001Sglebius	return 1;
3694290001Sglebius}
3695290001Sglebius
3696290001Sglebius
3697290001Sglebius#ifndef SIM
3698290001Sglebiusstatic u_char
3699290001Sglebiusget_correct_host_mode(
3700290001Sglebius	int token
3701290001Sglebius	)
3702290001Sglebius{
3703290001Sglebius	switch (token) {
3704290001Sglebius
3705290001Sglebius	case T_Server:
3706290001Sglebius	case T_Pool:
3707290001Sglebius	case T_Manycastclient:
3708290001Sglebius		return MODE_CLIENT;
3709290001Sglebius
3710290001Sglebius	case T_Peer:
3711290001Sglebius		return MODE_ACTIVE;
3712290001Sglebius
3713290001Sglebius	case T_Broadcast:
3714290001Sglebius		return MODE_BROADCAST;
3715290001Sglebius
3716290001Sglebius	default:
3717290001Sglebius		return 0;
3718290001Sglebius	}
3719290001Sglebius}
3720290001Sglebius
3721290001Sglebius
3722290001Sglebius/*
3723290001Sglebius * peerflag_bits()	get config_peers() peerflags value from a
3724290001Sglebius *			peer_node's queue of flag attr_val entries.
3725290001Sglebius */
3726290001Sglebiusstatic int
3727290001Sglebiuspeerflag_bits(
3728290001Sglebius	peer_node *pn
3729290001Sglebius	)
3730290001Sglebius{
3731290001Sglebius	int peerflags;
3732290001Sglebius	attr_val *option;
3733290001Sglebius
3734290001Sglebius	/* translate peerflags options to bits */
3735290001Sglebius	peerflags = 0;
3736290001Sglebius	option = HEAD_PFIFO(pn->peerflags);
3737290001Sglebius	for (; option != NULL; option = option->link) {
3738290001Sglebius		switch (option->value.i) {
3739290001Sglebius
3740290001Sglebius		default:
3741290001Sglebius			INSIST(0);
374254359Sroberto			break;
374354359Sroberto
3744290001Sglebius		case T_Autokey:
3745290001Sglebius			peerflags |= FLAG_SKEY;
3746290001Sglebius			break;
374754359Sroberto
3748290001Sglebius		case T_Burst:
3749290001Sglebius			peerflags |= FLAG_BURST;
3750290001Sglebius			break;
3751290001Sglebius
3752290001Sglebius		case T_Iburst:
3753290001Sglebius			peerflags |= FLAG_IBURST;
3754290001Sglebius			break;
3755290001Sglebius
3756290001Sglebius		case T_Noselect:
3757290001Sglebius			peerflags |= FLAG_NOSELECT;
3758290001Sglebius			break;
3759290001Sglebius
3760290001Sglebius		case T_Preempt:
3761290001Sglebius			peerflags |= FLAG_PREEMPT;
3762290001Sglebius			break;
3763290001Sglebius
3764290001Sglebius		case T_Prefer:
3765290001Sglebius			peerflags |= FLAG_PREFER;
3766290001Sglebius			break;
3767290001Sglebius
3768290001Sglebius		case T_True:
3769290001Sglebius			peerflags |= FLAG_TRUE;
3770290001Sglebius			break;
3771290001Sglebius
3772290001Sglebius		case T_Xleave:
3773290001Sglebius			peerflags |= FLAG_XLEAVE;
3774290001Sglebius			break;
3775290001Sglebius		}
3776290001Sglebius	}
3777290001Sglebius
3778290001Sglebius	return peerflags;
3779290001Sglebius}
3780290001Sglebius
3781290001Sglebius
3782290001Sglebiusstatic void
3783290001Sglebiusconfig_peers(
3784290001Sglebius	config_tree *ptree
3785290001Sglebius	)
3786290001Sglebius{
3787290001Sglebius	sockaddr_u		peeraddr;
3788290001Sglebius	struct addrinfo		hints;
3789290001Sglebius	peer_node *		curr_peer;
3790290001Sglebius	peer_resolved_ctx *	ctx;
3791290001Sglebius	u_char			hmode;
3792290001Sglebius
3793290001Sglebius	/* add servers named on the command line with iburst implied */
3794290001Sglebius	for (;
3795290001Sglebius	     cmdline_server_count > 0;
3796290001Sglebius	     cmdline_server_count--, cmdline_servers++) {
3797290001Sglebius
3798290001Sglebius		ZERO_SOCK(&peeraddr);
3799290001Sglebius		/*
3800290001Sglebius		 * If we have a numeric address, we can safely
3801290001Sglebius		 * proceed in the mainline with it.  Otherwise, hand
3802290001Sglebius		 * the hostname off to the blocking child.
3803290001Sglebius		 */
3804290001Sglebius		if (is_ip_address(*cmdline_servers, AF_UNSPEC,
3805290001Sglebius				  &peeraddr)) {
3806290001Sglebius
3807290001Sglebius			SET_PORT(&peeraddr, NTP_PORT);
3808290001Sglebius			if (is_sane_resolved_address(&peeraddr,
3809290001Sglebius						     T_Server))
3810290001Sglebius				peer_config(
3811290001Sglebius					&peeraddr,
3812290001Sglebius					NULL,
3813290001Sglebius					NULL,
3814290001Sglebius					MODE_CLIENT,
3815290001Sglebius					NTP_VERSION,
3816290001Sglebius					0,
3817290001Sglebius					0,
3818290001Sglebius					FLAG_IBURST,
3819290001Sglebius					0,
3820290001Sglebius					0,
3821290001Sglebius					NULL);
3822290001Sglebius		} else {
3823290001Sglebius			/* we have a hostname to resolve */
3824290001Sglebius# ifdef WORKER
3825290001Sglebius			ctx = emalloc_zero(sizeof(*ctx));
3826290001Sglebius			ctx->family = AF_UNSPEC;
3827290001Sglebius			ctx->host_mode = T_Server;
3828290001Sglebius			ctx->hmode = MODE_CLIENT;
3829290001Sglebius			ctx->version = NTP_VERSION;
3830290001Sglebius			ctx->flags = FLAG_IBURST;
3831290001Sglebius
3832290001Sglebius			ZERO(hints);
3833290001Sglebius			hints.ai_family = (u_short)ctx->family;
3834290001Sglebius			hints.ai_socktype = SOCK_DGRAM;
3835290001Sglebius			hints.ai_protocol = IPPROTO_UDP;
3836290001Sglebius
3837310419Sdelphij			getaddrinfo_sometime_ex(*cmdline_servers,
3838290001Sglebius					     "ntp", &hints,
3839290001Sglebius					     INITIAL_DNS_RETRY,
3840290001Sglebius					     &peer_name_resolved,
3841310419Sdelphij					     (void *)ctx, DNSFLAGS);
3842290001Sglebius# else	/* !WORKER follows */
3843290001Sglebius			msyslog(LOG_ERR,
3844290001Sglebius				"hostname %s can not be used, please use IP address instead.",
3845290001Sglebius				curr_peer->addr->address);
3846290001Sglebius# endif
3847290001Sglebius		}
3848290001Sglebius	}
3849290001Sglebius
3850290001Sglebius	/* add associations from the configuration file */
3851290001Sglebius	curr_peer = HEAD_PFIFO(ptree->peers);
3852290001Sglebius	for (; curr_peer != NULL; curr_peer = curr_peer->link) {
3853290001Sglebius		ZERO_SOCK(&peeraddr);
3854290001Sglebius		/* Find the correct host-mode */
3855290001Sglebius		hmode = get_correct_host_mode(curr_peer->host_mode);
3856290001Sglebius		INSIST(hmode != 0);
3857290001Sglebius
3858290001Sglebius		if (T_Pool == curr_peer->host_mode) {
3859290001Sglebius			AF(&peeraddr) = curr_peer->addr->type;
3860290001Sglebius			peer_config(
3861290001Sglebius				&peeraddr,
3862290001Sglebius				curr_peer->addr->address,
3863290001Sglebius				NULL,
3864290001Sglebius				hmode,
3865290001Sglebius				curr_peer->peerversion,
3866290001Sglebius				curr_peer->minpoll,
3867290001Sglebius				curr_peer->maxpoll,
3868290001Sglebius				peerflag_bits(curr_peer),
3869290001Sglebius				curr_peer->ttl,
3870290001Sglebius				curr_peer->peerkey,
3871290001Sglebius				curr_peer->group);
3872290001Sglebius		/*
3873290001Sglebius		 * If we have a numeric address, we can safely
3874290001Sglebius		 * proceed in the mainline with it.  Otherwise, hand
3875290001Sglebius		 * the hostname off to the blocking child.
3876290001Sglebius		 */
3877290001Sglebius		} else if (is_ip_address(curr_peer->addr->address,
3878290001Sglebius				  curr_peer->addr->type, &peeraddr)) {
3879290001Sglebius
3880290001Sglebius			SET_PORT(&peeraddr, NTP_PORT);
3881290001Sglebius			if (is_sane_resolved_address(&peeraddr,
3882290001Sglebius			    curr_peer->host_mode))
3883290001Sglebius				peer_config(
3884290001Sglebius					&peeraddr,
3885290001Sglebius					NULL,
3886290001Sglebius					NULL,
3887290001Sglebius					hmode,
3888290001Sglebius					curr_peer->peerversion,
3889290001Sglebius					curr_peer->minpoll,
3890290001Sglebius					curr_peer->maxpoll,
3891290001Sglebius					peerflag_bits(curr_peer),
3892290001Sglebius					curr_peer->ttl,
3893290001Sglebius					curr_peer->peerkey,
3894290001Sglebius					curr_peer->group);
3895290001Sglebius		} else {
3896290001Sglebius			/* we have a hostname to resolve */
3897290001Sglebius# ifdef WORKER
3898290001Sglebius			ctx = emalloc_zero(sizeof(*ctx));
3899290001Sglebius			ctx->family = curr_peer->addr->type;
3900290001Sglebius			ctx->host_mode = curr_peer->host_mode;
3901290001Sglebius			ctx->hmode = hmode;
3902290001Sglebius			ctx->version = curr_peer->peerversion;
3903290001Sglebius			ctx->minpoll = curr_peer->minpoll;
3904290001Sglebius			ctx->maxpoll = curr_peer->maxpoll;
3905290001Sglebius			ctx->flags = peerflag_bits(curr_peer);
3906290001Sglebius			ctx->ttl = curr_peer->ttl;
3907290001Sglebius			ctx->keyid = curr_peer->peerkey;
3908290001Sglebius			ctx->group = curr_peer->group;
3909290001Sglebius
3910290001Sglebius			ZERO(hints);
3911290001Sglebius			hints.ai_family = ctx->family;
3912290001Sglebius			hints.ai_socktype = SOCK_DGRAM;
3913290001Sglebius			hints.ai_protocol = IPPROTO_UDP;
3914290001Sglebius
3915310419Sdelphij			getaddrinfo_sometime_ex(curr_peer->addr->address,
3916290001Sglebius					     "ntp", &hints,
3917290001Sglebius					     INITIAL_DNS_RETRY,
3918310419Sdelphij					     &peer_name_resolved, ctx,
3919310419Sdelphij					     DNSFLAGS);
3920290001Sglebius# else	/* !WORKER follows */
3921290001Sglebius			msyslog(LOG_ERR,
3922290001Sglebius				"hostname %s can not be used, please use IP address instead.",
3923290001Sglebius				curr_peer->addr->address);
3924290001Sglebius# endif
3925290001Sglebius		}
3926290001Sglebius	}
3927290001Sglebius}
3928290001Sglebius#endif	/* !SIM */
3929290001Sglebius
3930290001Sglebius/*
3931290001Sglebius * peer_name_resolved()
3932290001Sglebius *
3933290001Sglebius * Callback invoked when config_peers()'s DNS lookup completes.
3934290001Sglebius */
3935290001Sglebius#ifdef WORKER
3936290001Sglebiusstatic void
3937290001Sglebiuspeer_name_resolved(
3938290001Sglebius	int			rescode,
3939290001Sglebius	int			gai_errno,
3940290001Sglebius	void *			context,
3941290001Sglebius	const char *		name,
3942290001Sglebius	const char *		service,
3943290001Sglebius	const struct addrinfo *	hints,
3944290001Sglebius	const struct addrinfo *	res
3945290001Sglebius	)
3946290001Sglebius{
3947290001Sglebius	sockaddr_u		peeraddr;
3948290001Sglebius	peer_resolved_ctx *	ctx;
3949290001Sglebius	u_short			af;
3950290001Sglebius	const char *		fam_spec;
3951290001Sglebius
3952290001Sglebius	(void)gai_errno;
3953290001Sglebius	(void)service;
3954290001Sglebius	(void)hints;
3955290001Sglebius	ctx = context;
3956290001Sglebius
3957290001Sglebius	DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
3958290001Sglebius
3959290001Sglebius	if (rescode) {
3960290001Sglebius		free(ctx);
3961290001Sglebius		msyslog(LOG_ERR,
3962290001Sglebius			"giving up resolving host %s: %s (%d)",
3963290001Sglebius			name, gai_strerror(rescode), rescode);
3964290001Sglebius		return;
3965290001Sglebius	}
3966290001Sglebius
3967290001Sglebius	/* Loop to configure a single association */
3968290001Sglebius	for (; res != NULL; res = res->ai_next) {
3969290001Sglebius		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3970290001Sglebius		if (is_sane_resolved_address(&peeraddr,
3971290001Sglebius					     ctx->host_mode)) {
3972290001Sglebius			NLOG(NLOG_SYSINFO) {
3973290001Sglebius				af = ctx->family;
3974290001Sglebius				fam_spec = (AF_INET6 == af)
3975290001Sglebius					       ? "(AAAA) "
3976290001Sglebius					       : (AF_INET == af)
3977290001Sglebius						     ? "(A) "
3978290001Sglebius						     : "";
3979290001Sglebius				msyslog(LOG_INFO, "DNS %s %s-> %s",
3980290001Sglebius					name, fam_spec,
3981290001Sglebius					stoa(&peeraddr));
398254359Sroberto			}
3983290001Sglebius			peer_config(
3984290001Sglebius				&peeraddr,
3985290001Sglebius				NULL,
3986290001Sglebius				NULL,
3987290001Sglebius				ctx->hmode,
3988290001Sglebius				ctx->version,
3989290001Sglebius				ctx->minpoll,
3990290001Sglebius				ctx->maxpoll,
3991290001Sglebius				ctx->flags,
3992290001Sglebius				ctx->ttl,
3993290001Sglebius				ctx->keyid,
3994290001Sglebius				ctx->group);
399554359Sroberto			break;
3996290001Sglebius		}
3997290001Sglebius	}
3998290001Sglebius	free(ctx);
3999290001Sglebius}
4000290001Sglebius#endif	/* WORKER */
400154359Sroberto
4002290001Sglebius
4003290001Sglebius#ifdef FREE_CFG_T
4004290001Sglebiusstatic void
4005290001Sglebiusfree_config_peers(
4006290001Sglebius	config_tree *ptree
4007290001Sglebius	)
4008290001Sglebius{
4009290001Sglebius	peer_node *curr_peer;
4010290001Sglebius
4011290001Sglebius	if (ptree->peers != NULL) {
4012290001Sglebius		for (;;) {
4013290001Sglebius			UNLINK_FIFO(curr_peer, *ptree->peers, link);
4014290001Sglebius			if (NULL == curr_peer)
401554359Sroberto				break;
4016290001Sglebius			destroy_address_node(curr_peer->addr);
4017290001Sglebius			destroy_attr_val_fifo(curr_peer->peerflags);
4018290001Sglebius			free(curr_peer);
4019290001Sglebius		}
4020290001Sglebius		free(ptree->peers);
4021290001Sglebius		ptree->peers = NULL;
4022290001Sglebius	}
4023290001Sglebius}
4024290001Sglebius#endif	/* FREE_CFG_T */
4025290001Sglebius
4026290001Sglebius
4027290001Sglebius#ifndef SIM
4028290001Sglebiusstatic void
4029290001Sglebiusconfig_unpeers(
4030290001Sglebius	config_tree *ptree
4031290001Sglebius	)
4032290001Sglebius{
4033290001Sglebius	sockaddr_u		peeraddr;
4034290001Sglebius	struct addrinfo		hints;
4035290001Sglebius	unpeer_node *		curr_unpeer;
4036290001Sglebius	struct peer *		p;
4037290001Sglebius	const char *		name;
4038290001Sglebius	int			rc;
4039290001Sglebius
4040290001Sglebius	curr_unpeer = HEAD_PFIFO(ptree->unpeers);
4041290001Sglebius	for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
4042290001Sglebius		/*
4043290001Sglebius		 * Either AssocID will be zero, and we unpeer by name/
4044290001Sglebius		 * address addr, or it is nonzero and addr NULL.
4045290001Sglebius		 */
4046290001Sglebius		if (curr_unpeer->assocID) {
4047290001Sglebius			p = findpeerbyassoc(curr_unpeer->assocID);
4048290001Sglebius			if (p != NULL) {
4049290001Sglebius				msyslog(LOG_NOTICE, "unpeered %s",
4050290001Sglebius					stoa(&p->srcadr));
4051290001Sglebius				peer_clear(p, "GONE");
4052290001Sglebius				unpeer(p);
405354359Sroberto			}
405454359Sroberto
4055290001Sglebius			continue;
4056290001Sglebius		}
4057290001Sglebius
4058290001Sglebius		ZERO(peeraddr);
4059290001Sglebius		AF(&peeraddr) = curr_unpeer->addr->type;
4060290001Sglebius		name = curr_unpeer->addr->address;
4061290001Sglebius		rc = getnetnum(name, &peeraddr, 0, t_UNK);
4062290001Sglebius		/* Do we have a numeric address? */
4063290001Sglebius		if (rc > 0) {
4064290001Sglebius			DPRINTF(1, ("unpeer: searching for %s\n",
4065290001Sglebius				    stoa(&peeraddr)));
4066290001Sglebius			p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
4067290001Sglebius			if (p != NULL) {
4068290001Sglebius				msyslog(LOG_NOTICE, "unpeered %s",
4069290001Sglebius					stoa(&peeraddr));
4070290001Sglebius				peer_clear(p, "GONE");
4071290001Sglebius				unpeer(p);
407254359Sroberto			}
407354359Sroberto
4074290001Sglebius			continue;
4075290001Sglebius		}
4076290001Sglebius		/*
4077290001Sglebius		 * It's not a numeric IP address, it's a hostname.
4078290001Sglebius		 * Check for associations with a matching hostname.
4079290001Sglebius		 */
4080290001Sglebius		for (p = peer_list; p != NULL; p = p->p_link)
4081290001Sglebius			if (p->hostname != NULL)
4082290001Sglebius				if (!strcasecmp(p->hostname, name))
408354359Sroberto					break;
4084290001Sglebius		if (p != NULL) {
4085290001Sglebius			msyslog(LOG_NOTICE, "unpeered %s", name);
4086290001Sglebius			peer_clear(p, "GONE");
4087290001Sglebius			unpeer(p);
4088290001Sglebius		}
4089290001Sglebius		/* Resolve the hostname to address(es). */
4090290001Sglebius# ifdef WORKER
4091290001Sglebius		ZERO(hints);
4092290001Sglebius		hints.ai_family = curr_unpeer->addr->type;
4093290001Sglebius		hints.ai_socktype = SOCK_DGRAM;
4094290001Sglebius		hints.ai_protocol = IPPROTO_UDP;
4095290001Sglebius		getaddrinfo_sometime(name, "ntp", &hints,
4096290001Sglebius				     INITIAL_DNS_RETRY,
4097290001Sglebius				     &unpeer_name_resolved, NULL);
4098290001Sglebius# else	/* !WORKER follows */
4099290001Sglebius		msyslog(LOG_ERR,
4100290001Sglebius			"hostname %s can not be used, please use IP address instead.",
4101290001Sglebius			name);
4102290001Sglebius# endif
4103290001Sglebius	}
4104290001Sglebius}
4105290001Sglebius#endif	/* !SIM */
410654359Sroberto
410754359Sroberto
4108290001Sglebius/*
4109290001Sglebius * unpeer_name_resolved()
4110290001Sglebius *
4111290001Sglebius * Callback invoked when config_unpeers()'s DNS lookup completes.
4112290001Sglebius */
4113290001Sglebius#ifdef WORKER
4114290001Sglebiusstatic void
4115290001Sglebiusunpeer_name_resolved(
4116290001Sglebius	int			rescode,
4117290001Sglebius	int			gai_errno,
4118290001Sglebius	void *			context,
4119290001Sglebius	const char *		name,
4120290001Sglebius	const char *		service,
4121290001Sglebius	const struct addrinfo *	hints,
4122290001Sglebius	const struct addrinfo *	res
4123290001Sglebius	)
4124290001Sglebius{
4125290001Sglebius	sockaddr_u	peeraddr;
4126290001Sglebius	struct peer *	peer;
4127290001Sglebius	u_short		af;
4128290001Sglebius	const char *	fam_spec;
412954359Sroberto
4130290001Sglebius	(void)context;
4131290001Sglebius	(void)hints;
4132290001Sglebius	DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
413354359Sroberto
4134290001Sglebius	if (rescode) {
4135290001Sglebius		msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
4136290001Sglebius			name, gai_strerror(rescode), rescode);
4137290001Sglebius		return;
4138290001Sglebius	}
4139290001Sglebius	/*
4140290001Sglebius	 * Loop through the addresses found
4141290001Sglebius	 */
4142290001Sglebius	for (; res != NULL; res = res->ai_next) {
4143290001Sglebius		INSIST(res->ai_addrlen <= sizeof(peeraddr));
4144290001Sglebius		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4145290001Sglebius		DPRINTF(1, ("unpeer: searching for peer %s\n",
4146290001Sglebius			    stoa(&peeraddr)));
4147290001Sglebius		peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0);
4148290001Sglebius		if (peer != NULL) {
4149290001Sglebius			af = AF(&peeraddr);
4150290001Sglebius			fam_spec = (AF_INET6 == af)
4151290001Sglebius				       ? "(AAAA) "
4152290001Sglebius				       : (AF_INET == af)
4153290001Sglebius					     ? "(A) "
4154290001Sglebius					     : "";
4155290001Sglebius			msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
4156290001Sglebius				fam_spec, stoa(&peeraddr));
4157290001Sglebius			peer_clear(peer, "GONE");
4158290001Sglebius			unpeer(peer);
4159290001Sglebius		}
4160290001Sglebius	}
4161290001Sglebius}
4162290001Sglebius#endif	/* WORKER */
4163290001Sglebius
4164290001Sglebius
4165290001Sglebius#ifdef FREE_CFG_T
4166290001Sglebiusstatic void
4167290001Sglebiusfree_config_unpeers(
4168290001Sglebius	config_tree *ptree
4169290001Sglebius	)
4170290001Sglebius{
4171290001Sglebius	unpeer_node *curr_unpeer;
4172290001Sglebius
4173290001Sglebius	if (ptree->unpeers != NULL) {
4174290001Sglebius		for (;;) {
4175290001Sglebius			UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
4176290001Sglebius			if (NULL == curr_unpeer)
4177290001Sglebius				break;
4178290001Sglebius			destroy_address_node(curr_unpeer->addr);
4179290001Sglebius			free(curr_unpeer);
4180290001Sglebius		}
4181290001Sglebius		free(ptree->unpeers);
4182290001Sglebius	}
4183290001Sglebius}
4184290001Sglebius#endif	/* FREE_CFG_T */
4185290001Sglebius
4186290001Sglebius
4187290001Sglebius#ifndef SIM
4188290001Sglebiusstatic void
4189290001Sglebiusconfig_reset_counters(
4190290001Sglebius	config_tree *ptree
4191290001Sglebius	)
4192290001Sglebius{
4193290001Sglebius	int_node *counter_set;
4194290001Sglebius
4195290001Sglebius	for (counter_set = HEAD_PFIFO(ptree->reset_counters);
4196290001Sglebius	     counter_set != NULL;
4197290001Sglebius	     counter_set = counter_set->link) {
4198290001Sglebius		switch (counter_set->i) {
4199290001Sglebius		default:
4200290001Sglebius			DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
4201290001Sglebius				    keyword(counter_set->i), counter_set->i));
420254359Sroberto			break;
420354359Sroberto
4204290001Sglebius		case T_Allpeers:
4205290001Sglebius			peer_all_reset();
420654359Sroberto			break;
420754359Sroberto
4208290001Sglebius		case T_Auth:
4209290001Sglebius			reset_auth_stats();
4210290001Sglebius			break;
421154359Sroberto
4212290001Sglebius		case T_Ctl:
4213290001Sglebius			ctl_clr_stats();
421454359Sroberto			break;
421554359Sroberto
4216290001Sglebius		case T_Io:
4217290001Sglebius			io_clr_stats();
4218290001Sglebius			break;
421954359Sroberto
4220290001Sglebius		case T_Mem:
4221290001Sglebius			peer_clr_stats();
422254359Sroberto			break;
422354359Sroberto
4224290001Sglebius		case T_Sys:
4225290001Sglebius			proto_clr_stats();
422654359Sroberto			break;
422754359Sroberto
4228290001Sglebius		case T_Timer:
4229290001Sglebius			timer_clr_stats();
4230290001Sglebius			break;
4231290001Sglebius		}
4232290001Sglebius	}
4233290001Sglebius}
4234290001Sglebius#endif	/* !SIM */
423554359Sroberto
4236290001Sglebius
4237290001Sglebius#ifdef FREE_CFG_T
4238290001Sglebiusstatic void
4239290001Sglebiusfree_config_reset_counters(
4240290001Sglebius	config_tree *ptree
4241290001Sglebius	)
4242290001Sglebius{
4243290001Sglebius	FREE_INT_FIFO(ptree->reset_counters);
4244290001Sglebius}
4245290001Sglebius#endif	/* FREE_CFG_T */
4246290001Sglebius
4247290001Sglebius
4248290001Sglebius#ifdef SIM
4249290001Sglebiusstatic void
4250290001Sglebiusconfig_sim(
4251290001Sglebius	config_tree *ptree
4252290001Sglebius	)
4253290001Sglebius{
4254290001Sglebius	int i;
4255290001Sglebius	server_info *serv_info;
4256290001Sglebius	attr_val *init_stmt;
4257290001Sglebius	sim_node *sim_n;
4258290001Sglebius
4259290001Sglebius	/* Check if a simulate block was found in the configuration code.
4260290001Sglebius	 * If not, return an error and exit
4261290001Sglebius	 */
4262290001Sglebius	sim_n = HEAD_PFIFO(ptree->sim_details);
4263290001Sglebius	if (NULL == sim_n) {
4264290001Sglebius		fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
4265290001Sglebius		fprintf(stderr, "\tCheck your configuration file.\n");
4266290001Sglebius		exit(1);
4267290001Sglebius	}
4268290001Sglebius
4269290001Sglebius	/* Process the initialization statements
4270290001Sglebius	 * -------------------------------------
4271290001Sglebius	 */
4272290001Sglebius	init_stmt = HEAD_PFIFO(sim_n->init_opts);
4273290001Sglebius	for (; init_stmt != NULL; init_stmt = init_stmt->link) {
4274290001Sglebius		switch(init_stmt->attr) {
4275290001Sglebius
4276290001Sglebius		case T_Beep_Delay:
4277290001Sglebius			simulation.beep_delay = init_stmt->value.d;
427854359Sroberto			break;
4279132451Sroberto
4280290001Sglebius		case T_Sim_Duration:
4281290001Sglebius			simulation.end_time = init_stmt->value.d;
4282290001Sglebius			break;
4283290001Sglebius
4284290001Sglebius		default:
4285290001Sglebius			fprintf(stderr,
4286290001Sglebius				"Unknown simulator init token %d\n",
4287290001Sglebius				init_stmt->attr);
4288290001Sglebius			exit(1);
428954359Sroberto		}
429054359Sroberto	}
429182498Sroberto
4292290001Sglebius	/* Process the server list
4293290001Sglebius	 * -----------------------
4294290001Sglebius	 */
4295290001Sglebius	simulation.num_of_servers = 0;
4296290001Sglebius	serv_info = HEAD_PFIFO(sim_n->servers);
4297290001Sglebius	for (; serv_info != NULL; serv_info = serv_info->link)
4298290001Sglebius		simulation.num_of_servers++;
4299290001Sglebius	simulation.servers = eallocarray(simulation.num_of_servers,
4300290001Sglebius				     sizeof(simulation.servers[0]));
4301290001Sglebius
4302290001Sglebius	i = 0;
4303290001Sglebius	serv_info = HEAD_PFIFO(sim_n->servers);
4304290001Sglebius	for (; serv_info != NULL; serv_info = serv_info->link) {
4305290001Sglebius		if (NULL == serv_info) {
4306290001Sglebius			fprintf(stderr, "Simulator server list is corrupt\n");
4307290001Sglebius			exit(1);
4308290001Sglebius		} else {
4309290001Sglebius			simulation.servers[i] = *serv_info;
4310290001Sglebius			simulation.servers[i].link = NULL;
4311290001Sglebius			i++;
4312290001Sglebius		}
4313290001Sglebius	}
4314290001Sglebius
4315290001Sglebius	printf("Creating server associations\n");
4316290001Sglebius	create_server_associations();
4317290001Sglebius	fprintf(stderr,"\tServer associations successfully created!!\n");
4318290001Sglebius}
4319290001Sglebius
4320290001Sglebius
4321290001Sglebius#ifdef FREE_CFG_T
4322290001Sglebiusstatic void
4323290001Sglebiusfree_config_sim(
4324290001Sglebius	config_tree *ptree
4325290001Sglebius	)
4326290001Sglebius{
4327290001Sglebius	sim_node *sim_n;
4328290001Sglebius	server_info *serv_n;
4329290001Sglebius	script_info *script_n;
4330290001Sglebius
4331290001Sglebius	if (NULL == ptree->sim_details)
4332290001Sglebius		return;
4333290001Sglebius	sim_n = HEAD_PFIFO(ptree->sim_details);
4334290001Sglebius	free(ptree->sim_details);
4335290001Sglebius	ptree->sim_details = NULL;
4336290001Sglebius	if (NULL == sim_n)
4337290001Sglebius		return;
4338290001Sglebius
4339290001Sglebius	FREE_ATTR_VAL_FIFO(sim_n->init_opts);
4340290001Sglebius	for (;;) {
4341290001Sglebius		UNLINK_FIFO(serv_n, *sim_n->servers, link);
4342290001Sglebius		if (NULL == serv_n)
4343290001Sglebius			break;
4344290001Sglebius		free(serv_n->curr_script);
4345290001Sglebius		if (serv_n->script != NULL) {
4346290001Sglebius			for (;;) {
4347290001Sglebius				UNLINK_FIFO(script_n, *serv_n->script,
4348290001Sglebius					    link);
4349290001Sglebius				if (script_n == NULL)
4350290001Sglebius					break;
4351290001Sglebius				free(script_n);
4352290001Sglebius			}
4353290001Sglebius			free(serv_n->script);
4354290001Sglebius		}
4355290001Sglebius		free(serv_n);
4356290001Sglebius	}
4357290001Sglebius	free(sim_n);
4358290001Sglebius}
4359290001Sglebius#endif	/* FREE_CFG_T */
4360290001Sglebius#endif	/* SIM */
4361290001Sglebius
4362290001Sglebius
4363290001Sglebius/* Define two different config functions. One for the daemon and the other for
4364290001Sglebius * the simulator. The simulator ignores a lot of the standard ntpd configuration
4365290001Sglebius * options
4366290001Sglebius */
4367290001Sglebius#ifndef SIM
4368290001Sglebiusstatic void
4369290001Sglebiusconfig_ntpd(
4370290001Sglebius	config_tree *ptree,
4371290001Sglebius	int/*BOOL*/ input_from_files
4372290001Sglebius	)
4373290001Sglebius{
4374290001Sglebius	config_nic_rules(ptree, input_from_files);
4375290001Sglebius	config_monitor(ptree);
4376290001Sglebius	config_auth(ptree);
4377290001Sglebius	config_tos(ptree);
4378290001Sglebius	config_access(ptree);
4379290001Sglebius	config_tinker(ptree);
4380290001Sglebius	config_rlimit(ptree);
4381290001Sglebius	config_system_opts(ptree);
4382290001Sglebius	config_logconfig(ptree);
4383290001Sglebius	config_phone(ptree);
4384290001Sglebius	config_mdnstries(ptree);
4385290001Sglebius	config_setvar(ptree);
4386290001Sglebius	config_ttl(ptree);
4387290001Sglebius	config_trap(ptree);
4388290001Sglebius	config_vars(ptree);
4389290001Sglebius
4390290001Sglebius	io_open_sockets();
4391290001Sglebius
4392290001Sglebius	config_other_modes(ptree);
4393290001Sglebius	config_peers(ptree);
4394290001Sglebius	config_unpeers(ptree);
4395290001Sglebius	config_fudge(ptree);
4396290001Sglebius	config_reset_counters(ptree);
4397290001Sglebius
4398290001Sglebius#ifdef TEST_BLOCKING_WORKER
4399290001Sglebius	{
4400290001Sglebius		struct addrinfo hints;
4401290001Sglebius
4402290001Sglebius		ZERO(hints);
4403290001Sglebius		hints.ai_socktype = SOCK_STREAM;
4404290001Sglebius		hints.ai_protocol = IPPROTO_TCP;
4405290001Sglebius		getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
4406290001Sglebius				     INITIAL_DNS_RETRY,
4407290001Sglebius				     gai_test_callback, (void *)1);
4408290001Sglebius		hints.ai_family = AF_INET6;
4409290001Sglebius		getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
4410290001Sglebius				     INITIAL_DNS_RETRY,
4411290001Sglebius				     gai_test_callback, (void *)0x600);
4412290001Sglebius	}
4413290001Sglebius#endif
4414290001Sglebius}
4415290001Sglebius#endif	/* !SIM */
4416290001Sglebius
4417290001Sglebius
4418290001Sglebius#ifdef SIM
4419290001Sglebiusstatic void
4420290001Sglebiusconfig_ntpdsim(
4421290001Sglebius	config_tree *ptree
4422290001Sglebius	)
4423290001Sglebius{
4424290001Sglebius	printf("Configuring Simulator...\n");
4425290001Sglebius	printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
4426290001Sglebius
4427290001Sglebius	config_tos(ptree);
4428290001Sglebius	config_monitor(ptree);
4429290001Sglebius	config_tinker(ptree);
4430290001Sglebius	if (0)
4431290001Sglebius		config_rlimit(ptree);	/* not needed for the simulator */
4432290001Sglebius	config_system_opts(ptree);
4433290001Sglebius	config_logconfig(ptree);
4434290001Sglebius	config_vars(ptree);
4435290001Sglebius	config_sim(ptree);
4436290001Sglebius}
4437290001Sglebius#endif /* SIM */
4438290001Sglebius
4439290001Sglebius
4440290001Sglebius/*
4441290001Sglebius * config_remotely() - implements ntpd side of ntpq :config
4442290001Sglebius */
4443290001Sglebiusvoid
4444290001Sglebiusconfig_remotely(
4445290001Sglebius	sockaddr_u *	remote_addr
4446290001Sglebius	)
4447290001Sglebius{
4448290001Sglebius	char origin[128];
4449290001Sglebius
4450290001Sglebius	snprintf(origin, sizeof(origin), "remote config from %s",
4451290001Sglebius		 stoa(remote_addr));
4452290001Sglebius	lex_init_stack(origin, NULL); /* no checking needed... */
4453290001Sglebius	init_syntax_tree(&cfgt);
4454290001Sglebius	yyparse();
4455290001Sglebius	lex_drop_stack();
4456290001Sglebius
4457290001Sglebius	cfgt.source.attr = CONF_SOURCE_NTPQ;
4458290001Sglebius	cfgt.timestamp = time(NULL);
4459290001Sglebius	cfgt.source.value.s = estrdup(stoa(remote_addr));
4460290001Sglebius
4461290001Sglebius	DPRINTF(1, ("Finished Parsing!!\n"));
4462290001Sglebius
4463290001Sglebius	save_and_apply_config_tree(FALSE);
4464290001Sglebius}
4465290001Sglebius
4466290001Sglebius
4467290001Sglebius/*
4468290001Sglebius * getconfig() - process startup configuration file e.g /etc/ntp.conf
4469290001Sglebius */
4470290001Sglebiusvoid
4471290001Sglebiusgetconfig(
4472290001Sglebius	int	argc,
4473290001Sglebius	char **	argv
4474290001Sglebius	)
4475290001Sglebius{
4476290001Sglebius	char	line[256];
4477290001Sglebius
4478290001Sglebius#ifdef DEBUG
4479290001Sglebius	atexit(free_all_config_trees);
4480290001Sglebius#endif
4481290001Sglebius#ifndef SYS_WINNT
4482290001Sglebius	config_file = CONFIG_FILE;
4483290001Sglebius#else
4484290001Sglebius	temp = CONFIG_FILE;
4485290001Sglebius	if (!ExpandEnvironmentStringsA(temp, config_file_storage,
4486290001Sglebius				       sizeof(config_file_storage))) {
4487290001Sglebius		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
4488290001Sglebius		exit(1);
4489290001Sglebius	}
4490290001Sglebius	config_file = config_file_storage;
4491290001Sglebius
4492290001Sglebius	temp = ALT_CONFIG_FILE;
4493290001Sglebius	if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
4494290001Sglebius				       sizeof(alt_config_file_storage))) {
4495290001Sglebius		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
4496290001Sglebius		exit(1);
4497290001Sglebius	}
4498290001Sglebius	alt_config_file = alt_config_file_storage;
4499290001Sglebius#endif /* SYS_WINNT */
4500290001Sglebius
4501290001Sglebius	/*
4502290001Sglebius	 * install a non default variable with this daemon version
4503290001Sglebius	 */
4504290001Sglebius	snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
4505290001Sglebius	set_sys_var(line, strlen(line) + 1, RO);
4506290001Sglebius
4507290001Sglebius	/*
4508290001Sglebius	 * Set up for the first time step to install a variable showing
4509290001Sglebius	 * which syscall is being used to step.
4510290001Sglebius	 */
4511290001Sglebius	set_tod_using = &ntpd_set_tod_using;
4512290001Sglebius
4513290001Sglebius	getCmdOpts(argc, argv);
4514290001Sglebius	init_syntax_tree(&cfgt);
4515290001Sglebius	if (
4516290001Sglebius		!lex_init_stack(FindConfig(config_file), "r")
451754359Sroberto#ifdef HAVE_NETINFO
4518290001Sglebius		/* If there is no config_file, try NetInfo. */
4519290001Sglebius		&& check_netinfo && !(config_netinfo = get_netinfo_config())
4520290001Sglebius#endif /* HAVE_NETINFO */
4521290001Sglebius		) {
4522290001Sglebius		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
4523290001Sglebius#ifndef SYS_WINNT
4524290001Sglebius		io_open_sockets();
4525290001Sglebius
4526290001Sglebius		return;
4527290001Sglebius#else
4528290001Sglebius		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
4529290001Sglebius
4530290001Sglebius		if (!lex_init_stack(FindConfig(alt_config_file), "r"))  {
4531290001Sglebius			/*
4532290001Sglebius			 * Broadcast clients can sometimes run without
4533290001Sglebius			 * a configuration file.
4534290001Sglebius			 */
4535290001Sglebius			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
4536290001Sglebius			io_open_sockets();
4537290001Sglebius
4538290001Sglebius			return;
4539290001Sglebius		}
4540290001Sglebius		cfgt.source.value.s = estrdup(alt_config_file);
4541290001Sglebius#endif	/* SYS_WINNT */
4542290001Sglebius	} else
4543290001Sglebius		cfgt.source.value.s = estrdup(config_file);
4544290001Sglebius
4545290001Sglebius
4546290001Sglebius	/*** BULK OF THE PARSER ***/
4547290001Sglebius#ifdef DEBUG
4548290001Sglebius	yydebug = !!(debug >= 5);
4549290001Sglebius#endif
4550290001Sglebius	yyparse();
4551290001Sglebius	lex_drop_stack();
4552290001Sglebius
4553290001Sglebius	DPRINTF(1, ("Finished Parsing!!\n"));
4554290001Sglebius
4555290001Sglebius	cfgt.source.attr = CONF_SOURCE_FILE;
4556290001Sglebius	cfgt.timestamp = time(NULL);
4557290001Sglebius
4558290001Sglebius	save_and_apply_config_tree(TRUE);
4559290001Sglebius
4560290001Sglebius#ifdef HAVE_NETINFO
456182498Sroberto	if (config_netinfo)
456282498Sroberto		free_netinfo_config(config_netinfo);
456354359Sroberto#endif /* HAVE_NETINFO */
4564290001Sglebius}
456554359Sroberto
456682498Sroberto
4567290001Sglebiusvoid
4568290001Sglebiussave_and_apply_config_tree(int/*BOOL*/ input_from_file)
4569290001Sglebius{
4570290001Sglebius	config_tree *ptree;
4571290001Sglebius#ifndef SAVECONFIG
4572290001Sglebius	config_tree *punlinked;
4573290001Sglebius#endif
457482498Sroberto
4575290001Sglebius	/*
4576290001Sglebius	 * Keep all the configuration trees applied since startup in
4577290001Sglebius	 * a list that can be used to dump the configuration back to
4578290001Sglebius	 * a text file.
4579290001Sglebius	 */
4580290001Sglebius	ptree = emalloc(sizeof(*ptree));
4581290001Sglebius	memcpy(ptree, &cfgt, sizeof(*ptree));
4582290001Sglebius	ZERO(cfgt);
4583290001Sglebius
4584290001Sglebius	LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
4585290001Sglebius
4586290001Sglebius#ifdef SAVECONFIG
4587290001Sglebius	if (HAVE_OPT( SAVECONFIGQUIT )) {
4588290001Sglebius		FILE *dumpfile;
4589290001Sglebius		int err;
4590290001Sglebius		int dumpfailed;
4591290001Sglebius
4592290001Sglebius		dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
4593290001Sglebius		if (NULL == dumpfile) {
4594290001Sglebius			err = errno;
4595290001Sglebius			mfprintf(stderr,
4596290001Sglebius				 "can not create save file %s, error %d %m\n",
4597290001Sglebius				 OPT_ARG(SAVECONFIGQUIT), err);
4598290001Sglebius			exit(err);
459982498Sroberto		}
4600290001Sglebius
4601290001Sglebius		dumpfailed = dump_all_config_trees(dumpfile, 0);
4602290001Sglebius		if (dumpfailed)
4603290001Sglebius			fprintf(stderr,
4604290001Sglebius				"--saveconfigquit %s error %d\n",
4605290001Sglebius				OPT_ARG( SAVECONFIGQUIT ),
4606290001Sglebius				dumpfailed);
4607290001Sglebius		else
4608290001Sglebius			fprintf(stderr,
4609290001Sglebius				"configuration saved to %s\n",
4610290001Sglebius				OPT_ARG( SAVECONFIGQUIT ));
4611290001Sglebius
4612290001Sglebius		exit(dumpfailed);
461382498Sroberto	}
4614290001Sglebius#endif	/* SAVECONFIG */
461582498Sroberto
4616290001Sglebius	/* The actual configuration done depends on whether we are configuring the
4617290001Sglebius	 * simulator or the daemon. Perform a check and call the appropriate
4618290001Sglebius	 * function as needed.
4619290001Sglebius	 */
462082498Sroberto
4621290001Sglebius#ifndef SIM
4622290001Sglebius	config_ntpd(ptree, input_from_file);
4623290001Sglebius#else
4624290001Sglebius	config_ntpdsim(ptree);
4625290001Sglebius#endif
4626290001Sglebius
4627290001Sglebius	/*
4628290001Sglebius	 * With configure --disable-saveconfig, there's no use keeping
4629290001Sglebius	 * the config tree around after application, so free it.
4630290001Sglebius	 */
4631290001Sglebius#ifndef SAVECONFIG
4632290001Sglebius	UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
4633290001Sglebius		     config_tree);
4634290001Sglebius	INSIST(punlinked == ptree);
4635290001Sglebius	free_config_tree(ptree);
4636290001Sglebius#endif
4637290001Sglebius}
4638290001Sglebius
4639290001Sglebius
4640290001Sglebiusstatic void
4641290001Sglebiusntpd_set_tod_using(
4642290001Sglebius	const char *which
4643290001Sglebius	)
4644290001Sglebius{
4645290001Sglebius	char line[128];
4646290001Sglebius
4647290001Sglebius	snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
4648290001Sglebius	set_sys_var(line, strlen(line) + 1, RO);
4649290001Sglebius}
4650290001Sglebius
4651290001Sglebius
4652290001Sglebiusstatic char *
4653290001Sglebiusnormal_dtoa(
4654290001Sglebius	double d
4655290001Sglebius	)
4656290001Sglebius{
4657290001Sglebius	char *	buf;
4658290001Sglebius	char *	pch_e;
4659290001Sglebius	char *	pch_nz;
4660290001Sglebius
4661290001Sglebius	LIB_GETBUF(buf);
4662290001Sglebius	snprintf(buf, LIB_BUFLENGTH, "%g", d);
4663290001Sglebius
4664290001Sglebius	/* use lowercase 'e', strip any leading zeroes in exponent */
4665290001Sglebius	pch_e = strchr(buf, 'e');
4666290001Sglebius	if (NULL == pch_e) {
4667290001Sglebius		pch_e = strchr(buf, 'E');
4668290001Sglebius		if (NULL == pch_e)
4669290001Sglebius			return buf;
4670290001Sglebius		*pch_e = 'e';
4671290001Sglebius	}
4672290001Sglebius	pch_e++;
4673290001Sglebius	if ('-' == *pch_e)
4674290001Sglebius		pch_e++;
4675290001Sglebius	pch_nz = pch_e;
4676290001Sglebius	while ('0' == *pch_nz)
4677290001Sglebius		pch_nz++;
4678290001Sglebius	if (pch_nz == pch_e)
4679290001Sglebius		return buf;
4680290001Sglebius	strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
4681290001Sglebius
4682290001Sglebius	return buf;
4683290001Sglebius}
4684290001Sglebius
4685290001Sglebius
4686290001Sglebius/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
4687290001Sglebius * --------------------------------------------
4688290001Sglebius */
4689290001Sglebius
4690290001Sglebius
4691290001Sglebius/*
4692290001Sglebius * get_pfxmatch - find value for prefixmatch
4693290001Sglebius * and update char * accordingly
4694290001Sglebius */
4695290001Sglebiusstatic u_int32
4696290001Sglebiusget_pfxmatch(
4697290001Sglebius	const char **	pstr,
4698290001Sglebius	struct masks *	m
4699290001Sglebius	)
4700290001Sglebius{
4701290001Sglebius	while (m->name != NULL) {
4702290001Sglebius		if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
4703290001Sglebius			*pstr += strlen(m->name);
4704290001Sglebius			return m->mask;
4705290001Sglebius		} else {
4706290001Sglebius			m++;
4707132451Sroberto		}
470854359Sroberto	}
4709290001Sglebius	return 0;
471054359Sroberto}
471154359Sroberto
4712290001Sglebius/*
4713290001Sglebius * get_match - find logmask value
4714290001Sglebius */
4715290001Sglebiusstatic u_int32
4716290001Sglebiusget_match(
4717290001Sglebius	const char *	str,
4718290001Sglebius	struct masks *	m
4719290001Sglebius	)
4720290001Sglebius{
4721290001Sglebius	while (m->name != NULL) {
4722290001Sglebius		if (strcmp(str, m->name) == 0)
4723290001Sglebius			return m->mask;
4724290001Sglebius		else
4725290001Sglebius			m++;
4726290001Sglebius	}
4727290001Sglebius	return 0;
4728290001Sglebius}
472954359Sroberto
4730290001Sglebius/*
4731290001Sglebius * get_logmask - build bitmask for ntp_syslogmask
4732290001Sglebius */
4733290001Sglebiusstatic u_int32
4734290001Sglebiusget_logmask(
4735290001Sglebius	const char *	str
4736290001Sglebius	)
4737290001Sglebius{
4738290001Sglebius	const char *	t;
4739290001Sglebius	u_int32		offset;
4740290001Sglebius	u_int32		mask;
4741290001Sglebius
4742290001Sglebius	mask = get_match(str, logcfg_noclass_items);
4743290001Sglebius	if (mask != 0)
4744290001Sglebius		return mask;
4745290001Sglebius
4746290001Sglebius	t = str;
4747290001Sglebius	offset = get_pfxmatch(&t, logcfg_class);
4748290001Sglebius	mask   = get_match(t, logcfg_class_items);
4749290001Sglebius
4750290001Sglebius	if (mask)
4751290001Sglebius		return mask << offset;
4752290001Sglebius	else
4753290001Sglebius		msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
4754290001Sglebius			str);
4755290001Sglebius
4756290001Sglebius	return 0;
4757290001Sglebius}
4758290001Sglebius
4759290001Sglebius
476054359Sroberto#ifdef HAVE_NETINFO
476154359Sroberto
4762290001Sglebius/*
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 *
4767290001Sglebiusget_netinfo_config(void)
476854359Sroberto{
476954359Sroberto	ni_status status;
477054359Sroberto	void *domain;
477154359Sroberto	ni_id config_dir;
4772290001Sglebius	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
4790290001Sglebius	config = emalloc(sizeof(*config));
4791290001Sglebius	config->domain = domain;
4792290001Sglebius	config->config_dir = config_dir;
4793290001Sglebius	config->prop_index = 0;
4794290001Sglebius	config->val_index = 0;
4795290001Sglebius	config->val_list = NULL;
479654359Sroberto
479754359Sroberto	return config;
479854359Sroberto}
479954359Sroberto
480054359Sroberto
480154359Sroberto/*
480254359Sroberto * free_netinfo_config - release NetInfo configuration state
480354359Sroberto */
480454359Srobertostatic void
4805290001Sglebiusfree_netinfo_config(
4806290001Sglebius	struct netinfo_config_state *config
4807290001Sglebius	)
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	 */
4831290001Sglebius  again:
483254359Sroberto	if (!val_list) {
4833290001Sglebius		for (; prop_index < COUNTOF(keywords); prop_index++)
4834290001Sglebius		{
4835290001Sglebius			ni_namelist namelist;
483654359Sroberto			struct keyword current_prop = keywords[prop_index];
4837290001Sglebius			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			 */
4844290001Sglebius			NI_INIT(&namelist);
4845290001Sglebius			if (NI_OK == ni_lookupprop(config->domain,
4846290001Sglebius			    &config->config_dir, current_prop.text,
4847290001Sglebius			    &namelist)) {
484854359Sroberto
484954359Sroberto				/* Found the property, but it has no values */
485054359Sroberto				if (namelist.ni_namelist_len == 0) continue;
485154359Sroberto
4852290001Sglebius				config->val_list =
4853290001Sglebius				    eallocarray(
4854290001Sglebius					(namelist.ni_namelist_len + 1),
4855290001Sglebius					sizeof(char*));
4856290001Sglebius				val_list = config->val_list;
485754359Sroberto
4858290001Sglebius				for (index = 0;
4859290001Sglebius				     index < namelist.ni_namelist_len;
4860290001Sglebius				     index++) {
4861290001Sglebius					char *value;
486254359Sroberto
4863290001Sglebius					value = namelist.ni_namelist_val[index];
4864290001Sglebius					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. */
4876290001Sglebius	if (!val_list)
4877290001Sglebius		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	 */
4883290001Sglebius	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';
4901290001Sglebius				while (ISSPACE(*tokens))
4902290001Sglebius					tokens++;
4903290001Sglebius				if (ISEOL(*tokens))
4904290001Sglebius					break;
490554359Sroberto			}
490654359Sroberto		}
490754359Sroberto
4908182007Sroberto		if (ntok == MAXTOKENS) {
4909182007Sroberto			/* HMS: chomp it to lose the EOL? */
4910182007Sroberto			msyslog(LOG_ERR,
4911290001Sglebius				"gettokens_netinfo: too many tokens.  Ignoring: %s",
4912290001Sglebius				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]);
4928290001Sglebius	free(val_list);
4929290001Sglebius	val_list = config->val_list = NULL;
4930290001Sglebius	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)
4939290001Sglebius *
4940290001Sglebius * returns 1 for success, and mysteriously, 0 for most failures, and
4941290001Sglebius * -1 if the address found is IPv6 and we believe IPv6 isn't working.
494254359Sroberto */
4943290001Sglebius#ifndef SIM
494454359Srobertostatic int
494554359Srobertogetnetnum(
494654359Sroberto	const char *num,
4947290001Sglebius	sockaddr_u *addr,
4948182007Sroberto	int complain,
4949290001Sglebius	enum gnn_type a_type	/* ignored */
495054359Sroberto	)
495154359Sroberto{
4952290001Sglebius	REQUIRE(AF_UNSPEC == AF(addr) ||
4953290001Sglebius		AF_INET == AF(addr) ||
4954290001Sglebius		AF_INET6 == AF(addr));
495554359Sroberto
4956290001Sglebius	if (!is_ip_address(num, AF(addr), addr))
4957290001Sglebius		return 0;
4958182007Sroberto
4959290001Sglebius	if (IS_IPV6(addr) && !ipv6_works)
4960290001Sglebius		return -1;
496154359Sroberto
4962290001Sglebius# ifdef ISC_PLATFORM_HAVESALEN
4963290001Sglebius	addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
4964290001Sglebius# endif
4965290001Sglebius	SET_PORT(addr, NTP_PORT);
4966182007Sroberto
4967290001Sglebius	DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
4968182007Sroberto
496954359Sroberto	return 1;
497054359Sroberto}
4971290001Sglebius#endif	/* !SIM */
497254359Sroberto
4973290001Sglebius#if defined(HAVE_SETRLIMIT)
4974290001Sglebiusvoid
4975290001Sglebiusntp_rlimit(
4976290001Sglebius	int	rl_what,
4977290001Sglebius	rlim_t	rl_value,
4978290001Sglebius	int	rl_scale,
4979290001Sglebius	const char *	rl_sstr
498054359Sroberto	)
498154359Sroberto{
4982290001Sglebius	struct rlimit	rl;
498354359Sroberto
4984290001Sglebius	switch (rl_what) {
4985290001Sglebius# ifdef RLIMIT_MEMLOCK
4986290001Sglebius	    case RLIMIT_MEMLOCK:
498754359Sroberto		/*
4988290001Sglebius		 * The default RLIMIT_MEMLOCK is very low on Linux systems.
4989290001Sglebius		 * Unless we increase this limit malloc calls are likely to
4990290001Sglebius		 * fail if we drop root privilege.  To be useful the value
4991290001Sglebius		 * has to be larger than the largest ntpd resident set size.
499254359Sroberto		 */
4993290001Sglebius		DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
4994290001Sglebius			(int)(rl_value / rl_scale), rl_sstr));
4995290001Sglebius		rl.rlim_cur = rl.rlim_max = rl_value;
4996290001Sglebius		if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
4997290001Sglebius			msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
4998290001Sglebius		break;
4999290001Sglebius# endif /* RLIMIT_MEMLOCK */
5000290001Sglebius
5001290001Sglebius# ifdef RLIMIT_NOFILE
5002290001Sglebius	    case RLIMIT_NOFILE:
500354359Sroberto		/*
5004290001Sglebius		 * For large systems the default file descriptor limit may
5005290001Sglebius		 * not be enough.
500654359Sroberto		 */
5007290001Sglebius		DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
5008290001Sglebius			(int)(rl_value / rl_scale), rl_sstr));
5009290001Sglebius		rl.rlim_cur = rl.rlim_max = rl_value;
5010290001Sglebius		if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
5011290001Sglebius			msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
5012290001Sglebius		break;
5013290001Sglebius# endif /* RLIMIT_NOFILE */
501454359Sroberto
5015290001Sglebius# ifdef RLIMIT_STACK
5016290001Sglebius	    case RLIMIT_STACK:
501754359Sroberto		/*
5018290001Sglebius		 * Provide a way to set the stack limit to something
5019290001Sglebius		 * smaller, so that we don't lock a lot of unused
5020290001Sglebius		 * stack memory.
502154359Sroberto		 */
5022290001Sglebius		DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
5023290001Sglebius			    (int)(rl_value / rl_scale), rl_sstr));
5024290001Sglebius		if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
5025290001Sglebius			msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
5026290001Sglebius		} else {
5027290001Sglebius			if (rl_value > rl.rlim_max) {
5028290001Sglebius				msyslog(LOG_WARNING,
5029290001Sglebius					"ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
5030290001Sglebius					(u_long)rl.rlim_max,
5031290001Sglebius					(u_long)rl_value);
5032290001Sglebius				rl_value = rl.rlim_max;
5033290001Sglebius			}
5034290001Sglebius			rl.rlim_cur = rl_value;
5035290001Sglebius			if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
5036290001Sglebius				msyslog(LOG_ERR,
5037290001Sglebius					"ntp_rlimit: Cannot set RLIMIT_STACK: %m");
5038290001Sglebius			}
5039182007Sroberto		}
5040290001Sglebius		break;
5041290001Sglebius# endif /* RLIMIT_STACK */
5042290001Sglebius
5043290001Sglebius	    default:
5044290001Sglebius		INSIST(!"Unexpected setrlimit() case!");
5045290001Sglebius		break;
504654359Sroberto	}
504754359Sroberto}
5048290001Sglebius#endif	/* HAVE_SETRLIMIT */
5049