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