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