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