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