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