xref: /freebsd/contrib/ntp/ntpd/ntp_config.c (revision f3f38455)
1 /*
2  * ntp_config.c - read and apply configuration information
3  */
4 #ifdef HAVE_CONFIG_H
5 # include <config.h>
6 #endif
7 
8 #ifdef HAVE_NETINFO
9 # include <netinfo/ni.h>
10 #endif
11 
12 #include "ntpd.h"
13 #include "ntp_io.h"
14 #include "ntp_unixtime.h"
15 #include "ntp_refclock.h"
16 #include "ntp_filegen.h"
17 #include "ntp_stdlib.h"
18 #include <ntp_random.h>
19 #include <isc/net.h>
20 #include <isc/result.h>
21 
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef HAVE_SYS_PARAM_H
25 #include <sys/param.h>
26 #endif
27 #include <signal.h>
28 #ifndef SIGCHLD
29 # define SIGCHLD SIGCLD
30 #endif
31 #if !defined(VMS)
32 # ifdef HAVE_SYS_WAIT_H
33 #  include <sys/wait.h>
34 # endif
35 #endif /* VMS */
36 
37 #ifdef SYS_WINNT
38 # include <io.h>
39 static HANDLE ResolverThreadHandle = NULL;
40 HANDLE ResolverEventHandle;
41 #else
42 int resolver_pipe_fd[2];  /* used to let the resolver process alert the parent process */
43 #endif /* SYS_WINNT */
44 
45 /*
46  * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
47  * so #include these later.
48  */
49 
50 #include "ntp_config.h"
51 #include "ntp_cmdargs.h"
52 
53 extern int priority_done;
54 
55 /*
56  * These routines are used to read the configuration file at
57  * startup time.  An entry in the file must fit on a single line.
58  * Entries are processed as multiple tokens separated by white space
59  * Lines are considered terminated when a '#' is encountered.  Blank
60  * lines are ignored.
61  */
62 /*
63  * Translation table - keywords to function index
64  */
65 struct keyword {
66 	const char *text;
67 	int keytype;
68 };
69 
70 /*
71  * Command keywords
72  */
73 static	struct keyword keywords[] = {
74 	{ "automax",		CONFIG_AUTOMAX },
75 	{ "broadcast",		CONFIG_BROADCAST },
76 	{ "broadcastclient",	CONFIG_BROADCASTCLIENT },
77 	{ "broadcastdelay",	CONFIG_BDELAY },
78 	{ "calldelay",		CONFIG_CDELAY},
79 #ifdef OPENSSL
80 	{ "crypto",		CONFIG_CRYPTO },
81 #endif /* OPENSSL */
82 	{ "controlkey",		CONFIG_CONTROLKEY },
83 	{ "disable",		CONFIG_DISABLE },
84 	{ "driftfile",		CONFIG_DRIFTFILE },
85 	{ "enable",		CONFIG_ENABLE },
86 	{ "end",		CONFIG_END },
87 	{ "filegen",		CONFIG_FILEGEN },
88 	{ "fudge",		CONFIG_FUDGE },
89 	{ "includefile",	CONFIG_INCLUDEFILE },
90 	{ "keys",		CONFIG_KEYS },
91 	{ "keysdir",		CONFIG_KEYSDIR },
92 	{ "logconfig",		CONFIG_LOGCONFIG },
93 	{ "logfile",		CONFIG_LOGFILE },
94 	{ "manycastclient",	CONFIG_MANYCASTCLIENT },
95 	{ "manycastserver",	CONFIG_MANYCASTSERVER },
96 	{ "multicastclient",	CONFIG_MULTICASTCLIENT },
97 	{ "peer",		CONFIG_PEER },
98 	{ "phone",		CONFIG_PHONE },
99 	{ "pidfile",		CONFIG_PIDFILE },
100 	{ "discard",		CONFIG_DISCARD },
101 	{ "requestkey",		CONFIG_REQUESTKEY },
102 	{ "restrict",		CONFIG_RESTRICT },
103 	{ "revoke",		CONFIG_REVOKE },
104 	{ "server",		CONFIG_SERVER },
105 	{ "setvar",		CONFIG_SETVAR },
106 	{ "statistics",		CONFIG_STATISTICS },
107 	{ "statsdir",		CONFIG_STATSDIR },
108 	{ "tick",		CONFIG_ADJ },
109 	{ "tinker",		CONFIG_TINKER },
110 	{ "tos",		CONFIG_TOS },
111 	{ "trap",		CONFIG_TRAP },
112 	{ "trustedkey",		CONFIG_TRUSTEDKEY },
113 	{ "ttl",		CONFIG_TTL },
114 	{ "",			CONFIG_UNKNOWN }
115 };
116 
117 /*
118  * "peer", "server", "broadcast" modifier keywords
119  */
120 static	struct keyword mod_keywords[] = {
121 	{ "autokey",		CONF_MOD_SKEY },
122 	{ "burst",		CONF_MOD_BURST },
123 	{ "iburst",		CONF_MOD_IBURST },
124 	{ "key",		CONF_MOD_KEY },
125 	{ "maxpoll",		CONF_MOD_MAXPOLL },
126 	{ "minpoll",		CONF_MOD_MINPOLL },
127 	{ "mode",		CONF_MOD_MODE },    /* refclocks */
128 	{ "noselect",		CONF_MOD_NOSELECT },
129 	{ "preempt",		CONF_MOD_PREEMPT },
130 	{ "true",		CONF_MOD_TRUE },
131 	{ "prefer",		CONF_MOD_PREFER },
132 	{ "ttl",		CONF_MOD_TTL },     /* NTP peers */
133 	{ "version",		CONF_MOD_VERSION },
134 	{ "dynamic",		CONF_MOD_DYNAMIC },
135 	{ "",			CONFIG_UNKNOWN }
136 };
137 
138 /*
139  * "restrict" modifier keywords
140  */
141 static	struct keyword res_keywords[] = {
142 	{ "ignore",		CONF_RES_IGNORE },
143 	{ "limited",		CONF_RES_LIMITED },
144 	{ "kod",		CONF_RES_DEMOBILIZE },
145 	{ "lowpriotrap",	CONF_RES_LPTRAP },
146 	{ "mask",		CONF_RES_MASK },
147 	{ "nomodify",		CONF_RES_NOMODIFY },
148 	{ "nopeer",		CONF_RES_NOPEER },
149 	{ "noquery",		CONF_RES_NOQUERY },
150 	{ "noserve",		CONF_RES_NOSERVE },
151 	{ "notrap",		CONF_RES_NOTRAP },
152 	{ "notrust",		CONF_RES_NOTRUST },
153 	{ "ntpport",		CONF_RES_NTPPORT },
154 	{ "version",		CONF_RES_VERSION },
155 	{ "",			CONFIG_UNKNOWN }
156 };
157 
158 /*
159  * "trap" modifier keywords
160  */
161 static	struct keyword trap_keywords[] = {
162 	{ "port",		CONF_TRAP_PORT },
163 	{ "interface",		CONF_TRAP_INTERFACE },
164 	{ "",			CONFIG_UNKNOWN }
165 };
166 
167 /*
168  * "fudge" modifier keywords
169  */
170 static	struct keyword fudge_keywords[] = {
171 	{ "flag1",		CONF_FDG_FLAG1 },
172 	{ "flag2",		CONF_FDG_FLAG2 },
173 	{ "flag3",		CONF_FDG_FLAG3 },
174 	{ "flag4",		CONF_FDG_FLAG4 },
175 	{ "refid",		CONF_FDG_REFID }, /* this mapping should be cleaned up (endianness, \0) - kd 20041031 */
176 	{ "stratum",		CONF_FDG_STRATUM },
177 	{ "time1",		CONF_FDG_TIME1 },
178 	{ "time2",		CONF_FDG_TIME2 },
179 	{ "",			CONFIG_UNKNOWN }
180 };
181 
182 /*
183  * "filegen" modifier keywords
184  */
185 static	struct keyword filegen_keywords[] = {
186 	{ "disable",		CONF_FGEN_FLAG_DISABLE },
187 	{ "enable",		CONF_FGEN_FLAG_ENABLE },
188 	{ "file",		CONF_FGEN_FILE },
189 	{ "link",		CONF_FGEN_FLAG_LINK },
190 	{ "nolink",		CONF_FGEN_FLAG_NOLINK },
191 	{ "type",		CONF_FGEN_TYPE },
192 	{ "",			CONFIG_UNKNOWN }
193 };
194 
195 /*
196  * "type" modifier keywords
197  */
198 static	struct keyword fgen_types[] = {
199 	{ "age",		FILEGEN_AGE   },
200 	{ "day",		FILEGEN_DAY   },
201 	{ "month",		FILEGEN_MONTH },
202 	{ "none",		FILEGEN_NONE  },
203 	{ "pid",		FILEGEN_PID   },
204 	{ "week",		FILEGEN_WEEK  },
205 	{ "year",		FILEGEN_YEAR  },
206 	{ "",			CONFIG_UNKNOWN}
207 };
208 
209 /*
210  * "enable", "disable" modifier keywords
211  */
212 static struct keyword flags_keywords[] = {
213 	{ "auth",		PROTO_AUTHENTICATE },
214 	{ "bclient",		PROTO_BROADCLIENT },
215 	{ "calibrate",		PROTO_CAL },
216 	{ "kernel",		PROTO_KERNEL },
217 	{ "monitor",		PROTO_MONITOR },
218 	{ "ntp",		PROTO_NTP },
219 	{ "stats",		PROTO_FILEGEN },
220 	{ "",			CONFIG_UNKNOWN }
221 };
222 
223 /*
224  * "discard" modifier keywords
225  */
226 static struct keyword discard_keywords[] = {
227 	{ "average",		CONF_DISCARD_AVERAGE },
228 	{ "minimum",		CONF_DISCARD_MINIMUM },
229 	{ "monitor",		CONF_DISCARD_MONITOR },
230 	{ "",			CONFIG_UNKNOWN }
231 };
232 
233 /*
234  * "tinker" modifier keywords
235  */
236 static struct keyword tinker_keywords[] = {
237 	{ "step",		CONF_CLOCK_MAX },
238 	{ "panic",		CONF_CLOCK_PANIC },
239 	{ "dispersion",		CONF_CLOCK_PHI },
240 	{ "stepout",		CONF_CLOCK_MINSTEP },
241 	{ "allan",		CONF_CLOCK_ALLAN },
242 	{ "huffpuff",		CONF_CLOCK_HUFFPUFF },
243 	{ "freq",		CONF_CLOCK_FREQ },
244 	{ "",			CONFIG_UNKNOWN }
245 };
246 
247 /*
248  * "tos" modifier keywords
249  */
250 static struct keyword tos_keywords[] = {
251 	{ "minclock",		CONF_TOS_MINCLOCK },
252 	{ "maxclock",		CONF_TOS_MAXCLOCK },
253 	{ "minsane",		CONF_TOS_MINSANE },
254 	{ "floor",		CONF_TOS_FLOOR },
255 	{ "ceiling",		CONF_TOS_CEILING },
256 	{ "cohort",		CONF_TOS_COHORT },
257 	{ "mindist",		CONF_TOS_MINDISP },
258 	{ "maxdist",		CONF_TOS_MAXDIST },
259 	{ "maxhop",		CONF_TOS_MAXHOP },
260 	{ "beacon",		CONF_TOS_BEACON },
261 	{ "orphan",		CONF_TOS_ORPHAN },
262 	{ "",			CONFIG_UNKNOWN }
263 };
264 
265 #ifdef OPENSSL
266 /*
267  * "crypto" modifier keywords
268  */
269 static struct keyword crypto_keywords[] = {
270 	{ "cert",		CONF_CRYPTO_CERT },
271 	{ "gqpar",		CONF_CRYPTO_GQPAR },
272 	{ "host",		CONF_CRYPTO_RSA },
273 	{ "ident",		CONF_CRYPTO_IDENT },
274 	{ "iffpar",		CONF_CRYPTO_IFFPAR },
275 	{ "leap",		CONF_CRYPTO_LEAP },
276 	{ "mvpar",		CONF_CRYPTO_MVPAR },
277 	{ "pw",			CONF_CRYPTO_PW },
278 	{ "randfile",		CONF_CRYPTO_RAND },
279 	{ "sign",		CONF_CRYPTO_SIGN },
280 	{ "",			CONFIG_UNKNOWN }
281 };
282 #endif /* OPENSSL */
283 
284 /*
285  * Address type selection, IPv4 or IPv4.
286  * Used on various lines.
287  */
288 static struct keyword addr_type[] = {
289 	{ "-4",			CONF_ADDR_IPV4 },
290 	{ "-6",			CONF_ADDR_IPV6 },
291 	{ "",			CONFIG_UNKNOWN }
292 };
293 
294 /*
295  * "logconfig" building blocks
296  */
297 struct masks {
298 	const char	  *name;
299 	unsigned long mask;
300 };
301 
302 static struct masks logcfg_class[] = {
303 	{ "clock",		NLOG_OCLOCK },
304 	{ "peer",		NLOG_OPEER },
305 	{ "sync",		NLOG_OSYNC },
306 	{ "sys",		NLOG_OSYS },
307 	{ (char *)0,	0 }
308 };
309 
310 static struct masks logcfg_item[] = {
311 	{ "info",		NLOG_INFO },
312 	{ "allinfo",		NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
313 	{ "events",		NLOG_EVENT },
314 	{ "allevents",		NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
315 	{ "status",		NLOG_STATUS },
316 	{ "allstatus",		NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
317 	{ "statistics",		NLOG_STATIST },
318 	{ "allstatistics",	NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
319 	{ "allclock",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
320 	{ "allpeer",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
321 	{ "allsys",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
322 	{ "allsync",		(NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
323 	{ "all",		NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
324 	{ (char *)0,	0 }
325 };
326 
327 /*
328  * Limits on things
329  */
330 #define MAXTOKENS	20	/* 20 tokens on line */
331 #define MAXLINE		1024	/* maximum length of line */
332 #define MAXPHONE	10	/* maximum number of phone strings */
333 #define MAXPPS		20	/* maximum length of PPS device string */
334 #define MAXINCLUDELEVEL	5	/* maximum include file levels */
335 
336 /*
337  * Miscellaneous macros
338  */
339 #define STRSAME(s1, s2)	(*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
340 #define ISEOL(c)	((c) == '#' || (c) == '\n' || (c) == '\0')
341 #define ISSPACE(c)	((c) == ' ' || (c) == '\t')
342 #define STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
343 
344 #define KEY_TYPE_MD5	4
345 
346 /*
347  * File descriptor used by the resolver save routines, and temporary file
348  * name.
349  */
350 int call_resolver = 1;		/* ntp-genkeys sets this to 0, for example */
351 static FILE *res_fp;
352 #ifndef SYS_WINNT
353 static char res_file[20];	/* enough for /tmp/ntpXXXXXX\0 */
354 #define RES_TEMPFILE	"/tmp/ntpXXXXXX"
355 #else
356 static char res_file[MAX_PATH];
357 #endif /* SYS_WINNT */
358 
359 /*
360  * Definitions of things either imported from or exported to outside
361  */
362 
363 short default_ai_family = AF_UNSPEC;	/* Default either IPv4 or IPv6 */
364 char	*sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
365 char	*keysdir = NTP_KEYSDIR;	/* crypto keys directory */
366 #if defined(HAVE_SCHED_SETSCHEDULER)
367 int	config_priority_override = 0;
368 int	config_priority;
369 #endif
370 
371 const char *config_file;
372 #ifdef HAVE_NETINFO
373  struct netinfo_config_state *config_netinfo = NULL;
374  int check_netinfo = 1;
375 #endif /* HAVE_NETINFO */
376 #ifdef SYS_WINNT
377  char *alt_config_file;
378  LPTSTR temp;
379  char config_file_storage[MAX_PATH];
380  char alt_config_file_storage[MAX_PATH];
381 #endif /* SYS_WINNT */
382 
383 #ifdef HAVE_NETINFO
384 /*
385  * NetInfo configuration state
386  */
387 struct netinfo_config_state {
388 	void *domain;		/* domain with config */
389 	ni_id config_dir;	/* ID config dir      */
390 	int prop_index;		/* current property   */
391 	int val_index;		/* current value      */
392 	char **val_list;       	/* value list         */
393 };
394 #endif
395 
396 /*
397  * Function prototypes
398  */
399 static	unsigned long get_pfxmatch P((char **, struct masks *));
400 static	unsigned long get_match P((char *, struct masks *));
401 static	unsigned long get_logmask P((char *));
402 #ifdef HAVE_NETINFO
403 static	struct netinfo_config_state *get_netinfo_config P((void));
404 static	void free_netinfo_config P((struct netinfo_config_state *));
405 static	int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
406 #endif
407 static	int gettokens P((FILE *, char *, char **, int *));
408 static	int matchkey P((char *, struct keyword *, int));
409 enum gnn_type {
410 	t_UNK,		/* Unknown */
411 	t_REF,		/* Refclock */
412 	t_MSK		/* Network Mask */
413 	};
414 static	int getnetnum P((const char *, struct sockaddr_storage *, int,
415 			 enum gnn_type));
416 static	void save_resolve P((char *, int, int, int, int, u_int, int,
417     keyid_t, u_char *, u_char));
418 static	void do_resolve_internal P((void));
419 static	void abort_resolve P((void));
420 #if !defined(VMS) && !defined(SYS_WINNT)
421 static	RETSIGTYPE catchchild P((int));
422 #endif /* VMS */
423 
424 /*
425  * get_pfxmatch - find value for prefixmatch
426  * and update char * accordingly
427  */
428 static unsigned long
429 get_pfxmatch(
430 	char ** s,
431 	struct masks *m
432 	)
433 {
434 	while (m->name) {
435 		if (strncmp(*s, m->name, strlen(m->name)) == 0) {
436 			*s += strlen(m->name);
437 			return m->mask;
438 		} else {
439 			m++;
440 		}
441 	}
442 	return 0;
443 }
444 
445 /*
446  * get_match - find logmask value
447  */
448 static unsigned long
449 get_match(
450 	char *s,
451 	struct masks *m
452 	)
453 {
454 	while (m->name) {
455 		if (strcmp(s, m->name) == 0) {
456 			return m->mask;
457 		} else {
458 			m++;
459 		}
460 	}
461 	return 0;
462 }
463 
464 /*
465  * get_logmask - build bitmask for ntp_syslogmask
466  */
467 static unsigned long
468 get_logmask(
469 	char *s
470 	)
471 {
472 	char *t;
473 	unsigned long offset;
474 	unsigned long mask;
475 
476 	t = s;
477 	offset = get_pfxmatch(&t, logcfg_class);
478 	mask   = get_match(t, logcfg_item);
479 
480 	if (mask)
481 		return mask << offset;
482 	else
483 		msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);
484 
485 	return 0;
486 }
487 
488 
489 /*
490  * getconfig - get command line options and read the configuration file
491  */
492 void
493 getconfig(
494 	int argc,
495 	char *argv[]
496 	)
497 {
498 	register int i;
499 	int c;
500 	int errflg;
501 	int status;
502 	int istart;
503 	int peerversion;
504 	int minpoll;
505 	int maxpoll;
506 	int ttl;
507 	long stratum;
508 	unsigned long ul;
509 	keyid_t peerkey;
510 	u_char *peerkeystr;
511 	u_long fudgeflag;
512 	u_int peerflags;
513 	int hmode;
514 	struct sockaddr_storage peeraddr;
515 	struct sockaddr_storage maskaddr;
516 	FILE *fp[MAXINCLUDELEVEL+1];
517 	FILE *includefile;
518 	int includelevel = 0;
519 	char line[MAXLINE];
520 	char *(tokens[MAXTOKENS]);
521 	int ntokens = 0;
522 	int tok = CONFIG_UNKNOWN;
523 	struct interface *localaddr;
524 	struct refclockstat clock_stat;
525 	FILEGEN *filegen;
526 
527 	/*
528 	 * Initialize, initialize
529 	 */
530 	errflg = 0;
531 
532 #ifndef SYS_WINNT
533 	config_file = CONFIG_FILE;
534 #else
535 	temp = CONFIG_FILE;
536 	if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
537 		msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
538 		exit(1);
539 	}
540 	config_file = config_file_storage;
541 
542 	temp = ALT_CONFIG_FILE;
543 	if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
544 		msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
545 		exit(1);
546 	}
547 	alt_config_file = alt_config_file_storage;
548 
549 #endif /* SYS_WINNT */
550 	res_fp = NULL;
551 	ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
552 
553 	/*
554 	 * install a non default variable with this daemon version
555 	 */
556 	(void) sprintf(line, "daemon_version=\"%s\"", Version);
557 	set_sys_var(line, strlen(line)+1, RO);
558 
559 	/*
560 	 * Say how we're setting the time of day
561 	 */
562 	(void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
563 	set_sys_var(line, strlen(line)+1, RO);
564 
565 	/*
566 	 * Initialize the loop.
567 	 */
568 	loop_config(LOOP_DRIFTINIT, 0.);
569 
570 	getCmdOpts(argc, argv);
571 
572 	if (
573 	    (fp[0] = fopen(FindConfig(config_file), "r")) == NULL
574 #ifdef HAVE_NETINFO
575 	    /* If there is no config_file, try NetInfo. */
576 	    && check_netinfo && !(config_netinfo = get_netinfo_config())
577 #endif /* HAVE_NETINFO */
578 	    ) {
579 		fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
580 		msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
581 #ifdef SYS_WINNT
582 		/* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
583 
584 		if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) {
585 
586 			/*
587 			 * Broadcast clients can sometimes run without
588 			 * a configuration file.
589 			 */
590 
591 			fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
592 			msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
593 			return;
594 		}
595 #else  /* not SYS_WINNT */
596 		return;
597 #endif /* not SYS_WINNT */
598 	}
599 
600 	proto_config(PROTO_MONITOR, 0, 0., NULL);
601 
602 	for (;;) {
603 		if (tok == CONFIG_END)
604 			break;
605 		if (fp[includelevel])
606 			tok = gettokens(fp[includelevel], line, tokens, &ntokens);
607 #ifdef HAVE_NETINFO
608 		else
609 			tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
610 #endif /* HAVE_NETINFO */
611 
612 		if (tok == CONFIG_UNKNOWN) {
613 		    if (includelevel > 0) {
614 			fclose(fp[includelevel--]);
615 			continue;
616 		    } else {
617 			break;
618 		    }
619 		}
620 
621 		switch(tok) {
622 		    case CONFIG_PEER:
623 		    case CONFIG_SERVER:
624 		    case CONFIG_MANYCASTCLIENT:
625 		    case CONFIG_BROADCAST:
626 			if (tok == CONFIG_PEER)
627 			    hmode = MODE_ACTIVE;
628 			else if (tok == CONFIG_SERVER)
629 			    hmode = MODE_CLIENT;
630 			else if (tok == CONFIG_MANYCASTCLIENT)
631 			    hmode = MODE_CLIENT;
632 			else
633 			    hmode = MODE_BROADCAST;
634 
635 			if (ntokens < 2) {
636 				msyslog(LOG_ERR,
637 					"No address for %s, line ignored",
638 					tokens[0]);
639 				break;
640 			}
641 
642 			istart = 1;
643 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
644 			peeraddr.ss_family = default_ai_family;
645 			switch (matchkey(tokens[istart], addr_type, 0)) {
646 			case CONF_ADDR_IPV4:
647 				peeraddr.ss_family = AF_INET;
648 				istart++;
649 				break;
650 			case CONF_ADDR_IPV6:
651 				peeraddr.ss_family = AF_INET6;
652 				istart++;
653 				break;
654 			}
655 
656 			status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK);
657 			if (status == -1)
658 				break;		/* Found IPv6 address */
659 			if(status != 1) {
660 				errflg = -1;
661 			} else {
662 				errflg = 0;
663 
664 				if (
665 #ifdef REFCLOCK
666 					!ISREFCLOCKADR(&peeraddr) &&
667 #endif
668 					ISBADADR(&peeraddr)) {
669 					msyslog(LOG_ERR,
670 						"attempt to configure invalid address %s",
671 						stoa(&peeraddr));
672 					break;
673 				}
674 				/*
675 				 * Shouldn't be able to specify multicast
676 				 * address for server/peer!
677 				 * and unicast address for manycastclient!
678 				 */
679 				if (peeraddr.ss_family == AF_INET) {
680 					if (((tok == CONFIG_SERVER) ||
681 				     	(tok == CONFIG_PEER)) &&
682 #ifdef REFCLOCK
683 				    	!ISREFCLOCKADR(&peeraddr) &&
684 #endif
685 				    	IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
686 						msyslog(LOG_ERR,
687 							"attempt to configure invalid address %s",
688 							stoa(&peeraddr));
689 						break;
690 					}
691 					if ((tok == CONFIG_MANYCASTCLIENT) &&
692 				    	!IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
693 						msyslog(LOG_ERR,
694 							"attempt to configure invalid address %s",
695 							stoa(&peeraddr));
696 						break;
697 					}
698 				}
699 				else if(peeraddr.ss_family == AF_INET6) {
700                                 if (((tok == CONFIG_SERVER) ||
701                                      (tok == CONFIG_PEER)) &&
702 #ifdef REFCLOCK
703                                     !ISREFCLOCKADR(&peeraddr) &&
704 #endif
705                                         IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
706                                                 msyslog(LOG_ERR,
707                                                         "attempt to configure in valid address %s",
708                                                         stoa(&peeraddr));
709                                                 break;
710                                         }
711                                         if ((tok == CONFIG_MANYCASTCLIENT) &&
712                                             !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
713                                                         msyslog(LOG_ERR,
714                                                         "attempt to configure in valid address %s",
715                                                         stoa(&peeraddr));
716                                                 break;
717 					}
718 				}
719 			}
720 			if (peeraddr.ss_family == AF_INET6 &&
721 			    isc_net_probeipv6() != ISC_R_SUCCESS)
722 				break;
723 
724 			peerversion = NTP_VERSION;
725 			minpoll = NTP_MINDPOLL;
726 			maxpoll = NTP_MAXDPOLL;
727 			peerkey = 0;
728 			peerkeystr = (u_char *)"*";
729 			peerflags = 0;
730 			ttl = 0;
731 			istart++;
732 			for (i = istart; i < ntokens; i++)
733 			    switch (matchkey(tokens[i], mod_keywords, 1)) {
734 				case CONF_MOD_VERSION:
735 				    if (i >= ntokens-1) {
736 					    msyslog(LOG_ERR,
737 						    "peer/server version requires an argument");
738 					    errflg = 1;
739 					    break;
740 				    }
741 				    peerversion = atoi(tokens[++i]);
742 				    if ((u_char)peerversion > NTP_VERSION
743 					|| (u_char)peerversion < NTP_OLDVERSION) {
744 					    msyslog(LOG_ERR,
745 						    "inappropriate version number %s, line ignored",
746 						    tokens[i]);
747 					    errflg = 1;
748 				    }
749 				    break;
750 
751 				case CONF_MOD_KEY:
752 				    if (i >= ntokens-1) {
753 					    msyslog(LOG_ERR,
754 						    "key: argument required");
755 					    errflg = 1;
756 					    break;
757 				    }
758 				    peerkey = (int)atol(tokens[++i]);
759 				    peerflags |= FLAG_AUTHENABLE;
760 				    break;
761 
762 				case CONF_MOD_MINPOLL:
763 				    if (i >= ntokens-1) {
764 					    msyslog(LOG_ERR,
765 						    "minpoll: argument required");
766 					    errflg = 1;
767 					    break;
768 				    }
769 				    minpoll = atoi(tokens[++i]);
770 				    if (minpoll < NTP_MINPOLL) {
771 					    msyslog(LOG_INFO,
772 						    "minpoll: provided value (%d) is below minimum (%d)",
773 						    minpoll, NTP_MINPOLL);
774 					minpoll = NTP_MINPOLL;
775 				    }
776 				    break;
777 
778 				case CONF_MOD_MAXPOLL:
779 				    if (i >= ntokens-1) {
780 					    msyslog(LOG_ERR,
781 						    "maxpoll: argument required"
782 						    );
783 					    errflg = 1;
784 					    break;
785 				    }
786 				    maxpoll = atoi(tokens[++i]);
787 				    if (maxpoll > NTP_MAXPOLL) {
788 					    msyslog(LOG_INFO,
789 						    "maxpoll: provided value (%d) is above maximum (%d)",
790 						    maxpoll, NTP_MAXPOLL);
791 					maxpoll = NTP_MAXPOLL;
792 				    }
793 				    break;
794 
795 				case CONF_MOD_PREFER:
796 				    peerflags |= FLAG_PREFER;
797 				    break;
798 
799 				case CONF_MOD_PREEMPT:
800 				    peerflags |= FLAG_PREEMPT;
801 				    break;
802 
803 				case CONF_MOD_NOSELECT:
804 				    peerflags |= FLAG_NOSELECT;
805 				    break;
806 
807 				case CONF_MOD_TRUE:
808 				    peerflags |= FLAG_TRUE;
809 
810 				case CONF_MOD_BURST:
811 				    peerflags |= FLAG_BURST;
812 				    break;
813 
814 				case CONF_MOD_IBURST:
815 				    peerflags |= FLAG_IBURST;
816 				    break;
817 
818 				case CONF_MOD_DYNAMIC:
819 				    msyslog(LOG_WARNING,
820 				        "Warning: the \"dynamic\" keyword has been obsoleted"
821 				        " and will be removed in the next release\n");
822 				    break;
823 
824 #ifdef OPENSSL
825 				case CONF_MOD_SKEY:
826 				    peerflags |= FLAG_SKEY |
827 					FLAG_AUTHENABLE;
828 				    break;
829 #endif /* OPENSSL */
830 
831 				case CONF_MOD_TTL:
832 				    if (i >= ntokens-1) {
833 					msyslog(LOG_ERR,
834 					    "ttl: argument required");
835 				        errflg = 1;
836 				        break;
837 				    }
838 				    ttl = atoi(tokens[++i]);
839 				    if (ttl >= MAX_TTL) {
840 					msyslog(LOG_ERR,
841 					    "ttl: invalid argument");
842 					errflg = 1;
843 				    }
844 				    break;
845 
846 				case CONF_MOD_MODE:
847 				    if (i >= ntokens-1) {
848 					msyslog(LOG_ERR,
849 					    "mode: argument required");
850 					errflg = 1;
851 					break;
852 				    }
853 				    ttl = atoi(tokens[++i]);
854 				    break;
855 
856 				case CONFIG_UNKNOWN:
857 				    errflg = 1;
858 				    break;
859 			    }
860 			if (minpoll > maxpoll) {
861 				msyslog(LOG_ERR,
862 				    "config error: minpoll > maxpoll");
863 				errflg = 1;
864 			}
865 			if (errflg == 0) {
866 			    if (peer_config(&peeraddr,
867 				ANY_INTERFACE_CHOOSE(&peeraddr), hmode,
868 				peerversion, minpoll, maxpoll, peerflags,
869 				ttl, peerkey, peerkeystr) == 0) {
870 					msyslog(LOG_ERR,
871 						"configuration of %s failed",
872 						stoa(&peeraddr));
873 			    }
874 			} else if (errflg == -1) {
875 				save_resolve(tokens[istart - 1], hmode, peerversion,
876 				    minpoll, maxpoll, peerflags, ttl,
877 				    peerkey, peerkeystr, peeraddr.ss_family);
878 			}
879 			break;
880 
881 		    case CONFIG_DRIFTFILE:
882 			if (ntokens >= 2)
883 			    stats_config(STATS_FREQ_FILE, tokens[1]);
884 			else
885 			    stats_config(STATS_FREQ_FILE, (char *)0);
886 			stats_write_period = stats_write_tolerance = 0;
887 			if (ntokens >= 3)
888 			     stats_write_period = 60 * atol(tokens[2]);
889 			if (stats_write_period <= 0)
890 			     stats_write_period = 3600;
891 			if (ntokens >= 4) {
892 			     double ftemp;
893 			     sscanf(tokens[3], "%lf", &ftemp);
894 			     stats_write_tolerance = ftemp / 100;
895 			}
896 			break;
897 
898 		    case CONFIG_PIDFILE:
899 			if (ntokens >= 2)
900 			    stats_config(STATS_PID_FILE, tokens[1]);
901 			else
902 			    stats_config(STATS_PID_FILE, (char *)0);
903 			break;
904 
905 		    case CONFIG_END:
906 			for ( i = 0; i <= includelevel; i++ ) {
907 				fclose(fp[i]);
908 			}
909 			break;
910 
911 		    case CONFIG_INCLUDEFILE:
912 			if (ntokens < 2) {
913 			    msyslog(LOG_ERR, "includefile needs one argument");
914 			    break;
915 			}
916 			if (includelevel >= MAXINCLUDELEVEL) {
917 			    fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
918 			    msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
919 			    break;
920 			}
921 			includefile = fopen(FindConfig(tokens[1]), "r");
922 			if (includefile == NULL) {
923 			    fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
924 			    msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
925 			    break;
926 			}
927 			fp[++includelevel] = includefile;
928 			break;
929 
930 		    case CONFIG_LOGFILE:
931 			if (ntokens >= 2) {
932 				FILE *new_file;
933 
934 				new_file = fopen(tokens[1], "a");
935 				if (new_file != NULL) {
936 					NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
937 					    msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
938 					if (syslog_file != NULL &&
939 					    fileno(syslog_file) != fileno(new_file))
940 					    (void)fclose(syslog_file);
941 
942 					syslog_file = new_file;
943 					syslogit = 0;
944 				}
945 				else
946 				    msyslog(LOG_ERR,
947 					    "Cannot open log file %s",
948 					    tokens[1]);
949 			}
950 			else
951 			    msyslog(LOG_ERR, "logfile needs one argument");
952 			break;
953 
954 		    case CONFIG_LOGCONFIG:
955 			for (i = 1; i < ntokens; i++)
956 			{
957 				int add = 1;
958 				int equals = 0;
959 				char * s = &tokens[i][0];
960 
961 				switch (*s) {
962 				    case '+':
963 				    case '-':
964 				    case '=':
965 					add = *s == '+';
966 					equals = *s == '=';
967 					s++;
968 					break;
969 
970 				    default:
971 					break;
972 				}
973 				if (equals) {
974 					ntp_syslogmask = get_logmask(s);
975 				} else {
976 					if (add) {
977 						ntp_syslogmask |= get_logmask(s);
978 					} else {
979 						ntp_syslogmask &= ~get_logmask(s);
980 					}
981 				}
982 #ifdef DEBUG
983 				if (debug)
984 				    printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
985 #endif
986 			}
987 			break;
988 
989 		    case CONFIG_BROADCASTCLIENT:
990 			if (ntokens == 1) {
991 				proto_config(PROTO_BROADCLIENT, 1, 0., NULL);
992 			} else {
993 				proto_config(PROTO_BROADCLIENT, 2, 0., NULL);
994 			}
995 			break;
996 
997 		    case CONFIG_MULTICASTCLIENT:
998 		    case CONFIG_MANYCASTSERVER:
999 			if (ntokens > 1) {
1000 				istart = 1;
1001 				memset((char *)&peeraddr, 0, sizeof(peeraddr));
1002 				peeraddr.ss_family = default_ai_family;
1003 				switch (matchkey(tokens[istart],
1004 				    addr_type, 0)) {
1005 				case CONF_ADDR_IPV4:
1006 					peeraddr.ss_family = AF_INET;
1007 					istart++;
1008 					break;
1009 				case CONF_ADDR_IPV6:
1010 					peeraddr.ss_family = AF_INET6;
1011 					istart++;
1012 					break;
1013 				}
1014 				/*
1015 				 * Abuse maskaddr to store the prefered ip
1016 				 * version.
1017 				 */
1018 				memset((char *)&maskaddr, 0, sizeof(maskaddr));
1019 				maskaddr.ss_family = peeraddr.ss_family;
1020 
1021 				for (i = istart; i < ntokens; i++) {
1022 					memset((char *)&peeraddr, 0,
1023 					    sizeof(peeraddr));
1024 					peeraddr.ss_family = maskaddr.ss_family;
1025 					if (getnetnum(tokens[i], &peeraddr, 1,
1026 						      t_UNK)  == 1)
1027 					    proto_config(PROTO_MULTICAST_ADD,
1028 							 0, 0., &peeraddr);
1029 				}
1030 			} else
1031 			    proto_config(PROTO_MULTICAST_ADD,
1032 					 0, 0., NULL);
1033 			if (tok == CONFIG_MULTICASTCLIENT)
1034 				proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1035 			else if (tok == CONFIG_MANYCASTSERVER)
1036 				sys_manycastserver = 1;
1037 			break;
1038 
1039 		    case CONFIG_KEYS:
1040 			if (ntokens >= 2) {
1041 				getauthkeys(tokens[1]);
1042 			}
1043 			break;
1044 
1045 		    case CONFIG_KEYSDIR:
1046 			if (ntokens < 2) {
1047 			    msyslog(LOG_ERR,
1048 				"Keys directory name required");
1049 			    break;
1050 			}
1051 			keysdir = (char *)emalloc(strlen(tokens[1]) + 1);
1052 			strcpy(keysdir, tokens[1]);
1053 			break;
1054 
1055 		    case CONFIG_TINKER:
1056 			for (i = 1; i < ntokens; i++) {
1057 			    int temp;
1058 			    double ftemp;
1059 
1060 			    temp = matchkey(tokens[i++], tinker_keywords, 1);
1061 			    if (i > ntokens - 1) {
1062 				msyslog(LOG_ERR,
1063 				    "tinker: missing argument");
1064 				errflg++;
1065 				break;
1066 			    }
1067 			    sscanf(tokens[i], "%lf", &ftemp);
1068 			    switch(temp) {
1069 
1070 			    case CONF_CLOCK_MAX:
1071                                 loop_config(LOOP_MAX, ftemp);
1072 				break;
1073 
1074 			    case CONF_CLOCK_PANIC:
1075 				loop_config(LOOP_PANIC, ftemp);
1076 				break;
1077 
1078 			    case CONF_CLOCK_PHI:
1079 				loop_config(LOOP_PHI, ftemp);
1080 				break;
1081 
1082 			    case CONF_CLOCK_MINSTEP:
1083 				loop_config(LOOP_MINSTEP, ftemp);
1084 				break;
1085 
1086 			    case CONF_CLOCK_ALLAN:
1087 				loop_config(LOOP_ALLAN, ftemp);
1088 				break;
1089 
1090 			    case CONF_CLOCK_HUFFPUFF:
1091 				loop_config(LOOP_HUFFPUFF, ftemp);
1092 				break;
1093 
1094 			    case CONF_CLOCK_FREQ:
1095 				loop_config(LOOP_FREQ, ftemp);
1096 				break;
1097 			    }
1098 			}
1099 			break;
1100 
1101 		    case CONFIG_TOS:
1102 			for (i = 1; i < ntokens; i++) {
1103 			    int temp;
1104 			    double ftemp;
1105 
1106 			    temp = matchkey(tokens[i++], tos_keywords, 1);
1107 			    if (i > ntokens - 1) {
1108 				msyslog(LOG_ERR,
1109 				    "tos: missing argument");
1110 				errflg++;
1111 				break;
1112 			    }
1113 			    sscanf(tokens[i], "%lf", &ftemp);
1114 			    switch(temp) {
1115 
1116 			    case CONF_TOS_MINCLOCK:
1117 				proto_config(PROTO_MINCLOCK, 0, ftemp, NULL);
1118 				break;
1119 
1120 			    case CONF_TOS_MAXCLOCK:
1121 				proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL);
1122 				break;
1123 
1124 			    case CONF_TOS_MINSANE:
1125 				proto_config(PROTO_MINSANE, 0, ftemp, NULL);
1126 				break;
1127 
1128 			    case CONF_TOS_FLOOR:
1129 				proto_config(PROTO_FLOOR, 0, ftemp, NULL);
1130 				break;
1131 
1132 			    case CONF_TOS_CEILING:
1133 				proto_config(PROTO_CEILING, 0, ftemp, NULL);
1134 				break;
1135 
1136 			    case CONF_TOS_COHORT:
1137 				proto_config(PROTO_COHORT, 0, ftemp, NULL);
1138 				break;
1139 
1140 			    case CONF_TOS_MINDISP:
1141 				proto_config(PROTO_MINDISP, 0, ftemp, NULL);
1142 				break;
1143 
1144 			    case CONF_TOS_MAXDIST:
1145 				proto_config(PROTO_MAXDIST, 0, ftemp, NULL);
1146 				break;
1147 
1148 			    case CONF_TOS_MAXHOP:
1149 				proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
1150 				break;
1151 
1152 			    case CONF_TOS_ORPHAN:
1153 				proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
1154 				break;
1155 
1156 			    case CONF_TOS_BEACON:
1157 				proto_config(PROTO_BEACON, 0, ftemp, NULL);
1158 				break;
1159 			    }
1160 			}
1161 			break;
1162 
1163 		    case CONFIG_TTL:
1164 			for (i = 1; i < ntokens && i < MAX_TTL; i++) {
1165 			    sys_ttl[i - 1] = (u_char) atoi(tokens[i]);
1166 			    sys_ttlmax = i - 1;
1167 			}
1168 			break;
1169 
1170 		    case CONFIG_DISCARD:
1171 			for (i = 1; i < ntokens; i++) {
1172 			    int temp;
1173 
1174 			    temp = matchkey(tokens[i++],
1175 				discard_keywords, 1);
1176 			    if (i > ntokens - 1) {
1177 				msyslog(LOG_ERR,
1178 				    "discard: missing argument");
1179 				errflg++;
1180 				break;
1181 			    }
1182 			    switch(temp) {
1183 			    case CONF_DISCARD_AVERAGE:
1184 				res_avg_interval = atoi(tokens[i]);
1185 				break;
1186 
1187 			    case CONF_DISCARD_MINIMUM:
1188 				res_min_interval = atoi(tokens[i]);
1189 				break;
1190 
1191 			    case CONF_DISCARD_MONITOR:
1192 				mon_age = atoi(tokens[i]);
1193 				break;
1194 
1195 			    default:
1196 				msyslog(LOG_ERR,
1197 				    "discard: unknown keyword");
1198 				break;
1199 			    }
1200 			}
1201 			break;
1202 
1203 #ifdef OPENSSL
1204 		    case CONFIG_REVOKE:
1205 			if (ntokens >= 2)
1206 			    sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE);
1207 			break;
1208 
1209 		    case CONFIG_AUTOMAX:
1210 			if (ntokens >= 2)
1211 			    sys_automax = 1 << max(atoi(tokens[1]), 10);
1212 			break;
1213 
1214 		    case CONFIG_CRYPTO:
1215 			if (ntokens == 1) {
1216 				crypto_config(CRYPTO_CONF_NONE, NULL);
1217 				break;
1218 			}
1219 			for (i = 1; i < ntokens; i++) {
1220 			    int temp;
1221 
1222 			    temp = matchkey(tokens[i++],
1223 				 crypto_keywords, 1);
1224 			    if (i > ntokens - 1) {
1225 				msyslog(LOG_ERR,
1226 				    "crypto: missing argument");
1227 				errflg++;
1228 				break;
1229 			    }
1230 			    switch(temp) {
1231 
1232 			    case CONF_CRYPTO_CERT:
1233 				crypto_config(CRYPTO_CONF_CERT,
1234 				    tokens[i]);
1235 				break;
1236 
1237 			    case CONF_CRYPTO_RSA:
1238 				crypto_config(CRYPTO_CONF_PRIV,
1239 				    tokens[i]);
1240 				break;
1241 
1242 			    case CONF_CRYPTO_IDENT:
1243 				crypto_config(CRYPTO_CONF_IDENT,
1244 				    tokens[i]);
1245 				break;
1246 
1247 			    case CONF_CRYPTO_IFFPAR:
1248 				crypto_config(CRYPTO_CONF_IFFPAR,
1249 				    tokens[i]);
1250 				break;
1251 
1252 			    case CONF_CRYPTO_GQPAR:
1253 				crypto_config(CRYPTO_CONF_GQPAR,
1254 				    tokens[i]);
1255 				break;
1256 
1257 			    case CONF_CRYPTO_MVPAR:
1258 				crypto_config(CRYPTO_CONF_MVPAR,
1259 				    tokens[i]);
1260 				break;
1261 
1262 			    case CONF_CRYPTO_LEAP:
1263 				crypto_config(CRYPTO_CONF_LEAP,
1264 				    tokens[i]);
1265 				break;
1266 
1267 			    case CONF_CRYPTO_PW:
1268 				crypto_config(CRYPTO_CONF_PW,
1269 				    tokens[i]);
1270 				break;
1271 
1272 			    case CONF_CRYPTO_RAND:
1273 				crypto_config(CRYPTO_CONF_RAND,
1274 				    tokens[i]);
1275 				break;
1276 
1277 			    case CONF_CRYPTO_SIGN:
1278 				crypto_config(CRYPTO_CONF_SIGN,
1279 				    tokens[i]);
1280 				break;
1281 
1282 			    default:
1283 				msyslog(LOG_ERR,
1284 				    "crypto: unknown keyword");
1285 				break;
1286 			    }
1287 			}
1288 			break;
1289 #endif /* OPENSSL */
1290 
1291 		    case CONFIG_RESTRICT:
1292 			if (ntokens < 2) {
1293 				msyslog(LOG_ERR, "restrict requires an address");
1294 				break;
1295 			}
1296 			istart = 1;
1297 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1298 			peeraddr.ss_family = default_ai_family;
1299 			switch (matchkey(tokens[istart], addr_type, 0)) {
1300 			case CONF_ADDR_IPV4:
1301 				peeraddr.ss_family = AF_INET;
1302 				istart++;
1303 				break;
1304 			case CONF_ADDR_IPV6:
1305 				peeraddr.ss_family = AF_INET6;
1306 				istart++;
1307 				break;
1308 			}
1309 
1310 			/*
1311 			 * Assume default means an IPv4 address, except
1312 			 * if forced by a -4 or -6.
1313 			 */
1314 			if (STREQ(tokens[istart], "default")) {
1315 				if (peeraddr.ss_family == 0)
1316 					peeraddr.ss_family = AF_INET;
1317 			} else if (getnetnum(tokens[istart], &peeraddr, 1,
1318 					      t_UNK) != 1)
1319 				break;
1320 
1321 			/*
1322 			 * Use peerversion as flags, peerkey as mflags.  Ick.
1323 			 */
1324 			peerversion = 0;
1325 			peerkey = 0;
1326 			errflg = 0;
1327 			SET_HOSTMASK(&maskaddr, peeraddr.ss_family);
1328 			istart++;
1329 			for (i = istart; i < ntokens; i++) {
1330 				switch (matchkey(tokens[i], res_keywords, 1)) {
1331 				    case CONF_RES_MASK:
1332 					if (i >= ntokens-1) {
1333 						msyslog(LOG_ERR,
1334 							"mask keyword needs argument");
1335 						errflg++;
1336 						break;
1337 					}
1338 					i++;
1339 					if (getnetnum(tokens[i], &maskaddr, 1,
1340 						       t_MSK) != 1)
1341 					    errflg++;
1342 					break;
1343 
1344 				    case CONF_RES_IGNORE:
1345 					peerversion |= RES_IGNORE;
1346 					break;
1347 
1348 				    case CONF_RES_NOSERVE:
1349 					peerversion |= RES_DONTSERVE;
1350 					break;
1351 
1352 				    case CONF_RES_NOTRUST:
1353 					peerversion |= RES_DONTTRUST;
1354 					break;
1355 
1356 				    case CONF_RES_NOQUERY:
1357 					peerversion |= RES_NOQUERY;
1358 					break;
1359 
1360 				    case CONF_RES_NOMODIFY:
1361 					peerversion |= RES_NOMODIFY;
1362 					break;
1363 
1364 				    case CONF_RES_NOPEER:
1365 					peerversion |= RES_NOPEER;
1366 					break;
1367 
1368 				    case CONF_RES_NOTRAP:
1369 					peerversion |= RES_NOTRAP;
1370 					break;
1371 
1372 				    case CONF_RES_LPTRAP:
1373 					peerversion |= RES_LPTRAP;
1374 					break;
1375 
1376 				    case CONF_RES_NTPPORT:
1377 					peerkey |= RESM_NTPONLY;
1378 					break;
1379 
1380 				    case CONF_RES_VERSION:
1381 					peerversion |= RES_VERSION;
1382 					break;
1383 
1384 				    case CONF_RES_DEMOBILIZE:
1385 					peerversion |= RES_DEMOBILIZE;
1386 					break;
1387 
1388 				    case CONF_RES_LIMITED:
1389 					peerversion |= RES_LIMITED;
1390 					break;
1391 
1392 				    case CONFIG_UNKNOWN:
1393 					errflg++;
1394 					break;
1395 				}
1396 			}
1397 			if (SOCKNUL(&peeraddr))
1398 			    ANYSOCK(&maskaddr);
1399 			if (!errflg)
1400 			    hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
1401 					  (int)peerkey, peerversion);
1402 			break;
1403 
1404 		    case CONFIG_BDELAY:
1405 			if (ntokens >= 2) {
1406 				double tmp;
1407 
1408 				if (sscanf(tokens[1], "%lf", &tmp) != 1) {
1409 					msyslog(LOG_ERR,
1410 						"broadcastdelay value %s undecodable",
1411 						tokens[1]);
1412 				} else {
1413 					proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
1414 				}
1415 			}
1416 			break;
1417 
1418 		    case CONFIG_CDELAY:
1419                         if (ntokens >= 2) {
1420                                 u_long ui;
1421 
1422 				if (sscanf(tokens[1], "%ld", &ui) != 1)
1423 					msyslog(LOG_ERR,
1424 					    "illegal value - line ignored");
1425 				else
1426 					proto_config(PROTO_CALLDELAY, ui, 0, NULL);
1427 			}
1428 			break;
1429 
1430 		    case CONFIG_TRUSTEDKEY:
1431 			for (i = 1; i < ntokens; i++) {
1432 				keyid_t tkey;
1433 
1434 				tkey = atol(tokens[i]);
1435 				if (tkey == 0) {
1436 					msyslog(LOG_ERR,
1437 						"trusted key %s unlikely",
1438 						tokens[i]);
1439 				} else {
1440 					authtrust(tkey, 1);
1441 				}
1442 			}
1443 			break;
1444 
1445 		    case CONFIG_REQUESTKEY:
1446 			if (ntokens >= 2) {
1447 				if (!atouint(tokens[1], &ul)) {
1448 					msyslog(LOG_ERR,
1449 						"%s is undecodable as request key",
1450 						tokens[1]);
1451 				} else if (ul == 0) {
1452 					msyslog(LOG_ERR,
1453 						"%s makes a poor request keyid",
1454 						tokens[1]);
1455 				} else {
1456 #ifdef DEBUG
1457 					if (debug > 3)
1458 					    printf(
1459 						    "set info_auth_key to %08lx\n", ul);
1460 #endif
1461 					info_auth_keyid = (keyid_t)ul;
1462 				}
1463 			}
1464 			break;
1465 
1466 		    case CONFIG_CONTROLKEY:
1467 			if (ntokens >= 2) {
1468 				keyid_t ckey;
1469 
1470 				ckey = atol(tokens[1]);
1471 				if (ckey == 0) {
1472 					msyslog(LOG_ERR,
1473 						"%s makes a poor control keyid",
1474 						tokens[1]);
1475 				} else {
1476 					ctl_auth_keyid = ckey;
1477 				}
1478 			}
1479 			break;
1480 
1481 		    case CONFIG_TRAP:
1482 			if (ntokens < 2) {
1483 				msyslog(LOG_ERR,
1484 					"no address for trap command, line ignored");
1485 				break;
1486 			}
1487 			istart = 1;
1488 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1489 			peeraddr.ss_family = default_ai_family;
1490 			switch (matchkey(tokens[istart], addr_type, 0)) {
1491 			case CONF_ADDR_IPV4:
1492 				peeraddr.ss_family = AF_INET;
1493 				istart++;
1494 				break;
1495 			case CONF_ADDR_IPV6:
1496 				peeraddr.ss_family = AF_INET6;
1497 				istart++;
1498 				break;
1499 			}
1500 
1501 			if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1)
1502 			    break;
1503 
1504 			/*
1505 			 * Use peerversion for port number.  Barf.
1506 			 */
1507 			errflg = 0;
1508 			peerversion = 0;
1509 			localaddr = 0;
1510 			istart++;
1511 			for (i = istart; i < ntokens-1; i++)
1512 			    switch (matchkey(tokens[i], trap_keywords, 1)) {
1513 				case CONF_TRAP_PORT:
1514 				    if (i >= ntokens-1) {
1515 					    msyslog(LOG_ERR,
1516 						    "trap port requires an argument");
1517 					    errflg = 1;
1518 					    break;
1519 				    }
1520 				    peerversion = atoi(tokens[++i]);
1521 				    if (peerversion <= 0
1522 					|| peerversion > 32767) {
1523 					    msyslog(LOG_ERR,
1524 						    "invalid port number %s, trap ignored",
1525 						    tokens[i]);
1526 					    errflg = 1;
1527 				    }
1528 				    break;
1529 
1530 				case CONF_TRAP_INTERFACE:
1531 				    if (i >= ntokens-1) {
1532 					    msyslog(LOG_ERR,
1533 						    "trap interface requires an argument");
1534 					    errflg = 1;
1535 					    break;
1536 				    }
1537 
1538 				    memset((char *)&maskaddr, 0,
1539 					sizeof(maskaddr));
1540 				    maskaddr.ss_family = peeraddr.ss_family;
1541 				    if (getnetnum(tokens[++i],
1542 						   &maskaddr, 1, t_UNK) != 1) {
1543 					    errflg = 1;
1544 					    break;
1545 				    }
1546 
1547 				    localaddr = findinterface(&maskaddr);
1548 				    if (localaddr == NULL) {
1549 					    msyslog(LOG_ERR,
1550 						    "can't find interface with address %s",
1551 						    stoa(&maskaddr));
1552 					    errflg = 1;
1553 				    }
1554 				    break;
1555 
1556 				case CONFIG_UNKNOWN:
1557 				    errflg++;
1558 				    break;
1559 			    }
1560 
1561 			if (!errflg) {
1562 				if (peerversion != 0)
1563 				    ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion);
1564 				else
1565 				    ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);
1566 				if (localaddr == NULL)
1567 				    localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
1568 				if (!ctlsettrap(&peeraddr, localaddr, 0,
1569 						NTP_VERSION))
1570 				    msyslog(LOG_ERR,
1571 					    "can't set trap for %s, no resources",
1572 					    stoa(&peeraddr));
1573 			}
1574 			break;
1575 
1576 		    case CONFIG_FUDGE:
1577 			if (ntokens < 2) {
1578 				msyslog(LOG_ERR,
1579 					"no address for fudge command, line ignored");
1580 				break;
1581 			}
1582 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1583 			if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1)
1584 			    break;
1585 
1586 			if (!ISREFCLOCKADR(&peeraddr)) {
1587 				msyslog(LOG_ERR,
1588 					"%s is inappropriate address for the fudge command, line ignored",
1589 					stoa(&peeraddr));
1590 				break;
1591 			}
1592 
1593 			memset((void *)&clock_stat, 0, sizeof clock_stat);
1594 			fudgeflag = 0;
1595 			errflg = 0;
1596 			for (i = 2; i < ntokens-1; i++) {
1597 				switch (c = matchkey(tokens[i],
1598 				    fudge_keywords, 1)) {
1599 				    case CONF_FDG_TIME1:
1600 					if (sscanf(tokens[++i], "%lf",
1601 						   &clock_stat.fudgetime1) != 1) {
1602 						msyslog(LOG_ERR,
1603 							"fudge %s time1 value in error",
1604 							stoa(&peeraddr));
1605 						errflg = i;
1606 						break;
1607 					}
1608 					clock_stat.haveflags |= CLK_HAVETIME1;
1609 					break;
1610 
1611 				    case CONF_FDG_TIME2:
1612 					if (sscanf(tokens[++i], "%lf",
1613 						   &clock_stat.fudgetime2) != 1) {
1614 						msyslog(LOG_ERR,
1615 							"fudge %s time2 value in error",
1616 							stoa(&peeraddr));
1617 						errflg = i;
1618 						break;
1619 					}
1620 					clock_stat.haveflags |= CLK_HAVETIME2;
1621 					break;
1622 
1623 
1624 				    case CONF_FDG_STRATUM:
1625 				      if (!atoint(tokens[++i], &stratum))
1626 					{
1627 						msyslog(LOG_ERR,
1628 							"fudge %s stratum value in error",
1629 							stoa(&peeraddr));
1630 						errflg = i;
1631 						break;
1632 					}
1633 					clock_stat.fudgeval1 = stratum;
1634 					clock_stat.haveflags |= CLK_HAVEVAL1;
1635 					break;
1636 
1637 				    case CONF_FDG_REFID:
1638 					i++;
1639 					memcpy(&clock_stat.fudgeval2,
1640 					    tokens[i], min(strlen(tokens[i]),
1641 					    4));
1642 					clock_stat.haveflags |= CLK_HAVEVAL2;
1643 					break;
1644 
1645 				    case CONF_FDG_FLAG1:
1646 				    case CONF_FDG_FLAG2:
1647 				    case CONF_FDG_FLAG3:
1648 				    case CONF_FDG_FLAG4:
1649 					if (!atouint(tokens[++i], &fudgeflag)
1650 					    || fudgeflag > 1) {
1651 						msyslog(LOG_ERR,
1652 							"fudge %s flag value in error",
1653 							stoa(&peeraddr));
1654 						errflg = i;
1655 						break;
1656 					}
1657 					switch(c) {
1658 					    case CONF_FDG_FLAG1:
1659 						c = CLK_FLAG1;
1660 						clock_stat.haveflags|=CLK_HAVEFLAG1;
1661 						break;
1662 					    case CONF_FDG_FLAG2:
1663 						c = CLK_FLAG2;
1664 						clock_stat.haveflags|=CLK_HAVEFLAG2;
1665 						break;
1666 					    case CONF_FDG_FLAG3:
1667 						c = CLK_FLAG3;
1668 						clock_stat.haveflags|=CLK_HAVEFLAG3;
1669 						break;
1670 					    case CONF_FDG_FLAG4:
1671 						c = CLK_FLAG4;
1672 						clock_stat.haveflags|=CLK_HAVEFLAG4;
1673 						break;
1674 					}
1675 					if (fudgeflag == 0)
1676 					    clock_stat.flags &= ~c;
1677 					else
1678 					    clock_stat.flags |= c;
1679 					break;
1680 
1681 				    case CONFIG_UNKNOWN:
1682 					errflg = -1;
1683 					break;
1684 				}
1685 			}
1686 
1687 #ifdef REFCLOCK
1688 			/*
1689 			 * If reference clock support isn't defined the
1690 			 * fudge line will still be accepted and syntax
1691 			 * checked, but will essentially do nothing.
1692 			 */
1693 			if (!errflg) {
1694 				refclock_control(&peeraddr, &clock_stat,
1695 				    (struct refclockstat *)0);
1696 			}
1697 #endif
1698 			break;
1699 
1700 		    case CONFIG_STATSDIR:
1701 			if (ntokens >= 2)
1702 				stats_config(STATS_STATSDIR,tokens[1]);
1703 			break;
1704 
1705 		    case CONFIG_STATISTICS:
1706 			for (i = 1; i < ntokens; i++) {
1707 				filegen = filegen_get(tokens[i]);
1708 
1709 				if (filegen == NULL) {
1710 					msyslog(LOG_ERR,
1711 						"no statistics named %s available",
1712 						tokens[i]);
1713 					continue;
1714 				}
1715 #ifdef DEBUG
1716 				if (debug > 3)
1717 				    printf("enabling filegen for %s statistics \"%s%s\"\n",
1718 					   tokens[i], filegen->prefix, filegen->basename);
1719 #endif
1720 				filegen->flag |= FGEN_FLAG_ENABLED;
1721 			}
1722 			break;
1723 
1724 		    case CONFIG_FILEGEN:
1725 			if (ntokens < 2) {
1726 				msyslog(LOG_ERR,
1727 					"no id for filegen command, line ignored");
1728 				break;
1729 			}
1730 
1731 			filegen = filegen_get(tokens[1]);
1732 			if (filegen == NULL) {
1733 				msyslog(LOG_ERR,
1734 					"unknown filegen \"%s\" ignored",
1735 					tokens[1]);
1736 				break;
1737 			}
1738 			/*
1739 			 * peerversion is (ab)used for filegen file (index)
1740 			 * peerkey	   is (ab)used for filegen type
1741 			 * peerflags   is (ab)used for filegen flags
1742 			 */
1743 			peerversion = 0;
1744 			peerkey =	  filegen->type;
1745 			peerflags =   filegen->flag;
1746 			errflg = 0;
1747 
1748 			for (i = 2; i < ntokens; i++) {
1749 				switch (matchkey(tokens[i],
1750 				    filegen_keywords, 1)) {
1751 				    case CONF_FGEN_FILE:
1752 					if (i >= ntokens - 1) {
1753 						msyslog(LOG_ERR,
1754 							"filegen %s file requires argument",
1755 							tokens[1]);
1756 						errflg = i;
1757 						break;
1758 					}
1759 					peerversion = ++i;
1760 					break;
1761 				    case CONF_FGEN_TYPE:
1762 					if (i >= ntokens -1) {
1763 						msyslog(LOG_ERR,
1764 							"filegen %s type requires argument",
1765 							tokens[1]);
1766 						errflg = i;
1767 						break;
1768 					}
1769 					peerkey = matchkey(tokens[++i],
1770 					    fgen_types, 1);
1771 					if (peerkey == CONFIG_UNKNOWN) {
1772 						msyslog(LOG_ERR,
1773 							"filegen %s unknown type \"%s\"",
1774 							tokens[1], tokens[i]);
1775 						errflg = i;
1776 						break;
1777 					}
1778 					break;
1779 
1780 				    case CONF_FGEN_FLAG_LINK:
1781 					peerflags |= FGEN_FLAG_LINK;
1782 					break;
1783 
1784 				    case CONF_FGEN_FLAG_NOLINK:
1785 					peerflags &= ~FGEN_FLAG_LINK;
1786 					break;
1787 
1788 				    case CONF_FGEN_FLAG_ENABLE:
1789 					peerflags |= FGEN_FLAG_ENABLED;
1790 					break;
1791 
1792 				    case CONF_FGEN_FLAG_DISABLE:
1793 					peerflags &= ~FGEN_FLAG_ENABLED;
1794 					break;
1795 				}
1796 			}
1797 			if (!errflg)
1798 				filegen_config(filegen, tokens[peerversion],
1799 			           (u_char)peerkey, (u_char)peerflags);
1800 			break;
1801 
1802 		    case CONFIG_SETVAR:
1803 			if (ntokens < 2) {
1804 				msyslog(LOG_ERR,
1805 					"no value for setvar command - line ignored");
1806 			} else {
1807 				set_sys_var(tokens[1], strlen(tokens[1])+1,
1808 					    (u_short) (RW |
1809 					    ((((ntokens > 2)
1810 					       && !strcmp(tokens[2],
1811 							  "default")))
1812 					     ? DEF
1813 					     : 0)));
1814 			}
1815 			break;
1816 
1817 		    case CONFIG_ENABLE:
1818 			for (i = 1; i < ntokens; i++) {
1819 				int flag;
1820 
1821 				flag = matchkey(tokens[i], flags_keywords, 1);
1822 				if (flag == CONFIG_UNKNOWN) {
1823 					msyslog(LOG_ERR,
1824 						"enable unknown flag %s",
1825 						tokens[i]);
1826 					errflg = 1;
1827 					break;
1828 				}
1829 				proto_config(flag, 1, 0., NULL);
1830 			}
1831 			break;
1832 
1833 		    case CONFIG_DISABLE:
1834 			for (i = 1; i < ntokens; i++) {
1835 				int flag;
1836 
1837 				flag = matchkey(tokens[i], flags_keywords, 1);
1838 				if (flag == CONFIG_UNKNOWN) {
1839 					msyslog(LOG_ERR,
1840 						"disable unknown flag %s",
1841 						tokens[i]);
1842 					errflg = 1;
1843 					break;
1844 				}
1845 				proto_config(flag, 0, 0., NULL);
1846 			}
1847 			break;
1848 
1849 		    case CONFIG_PHONE:
1850 			for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) {
1851 				sys_phone[i - 1] =
1852 				    emalloc(strlen(tokens[i]) + 1);
1853 				strcpy(sys_phone[i - 1], tokens[i]);
1854 			}
1855 			sys_phone[i] = NULL;
1856 			break;
1857 
1858 		    case CONFIG_ADJ: {
1859 			    double ftemp;
1860 
1861 			    sscanf(tokens[1], "%lf", &ftemp);
1862 			    proto_config(PROTO_ADJ, 0, ftemp, NULL);
1863 			}
1864 			break;
1865 
1866 		}
1867 	}
1868 	if (fp[0])
1869 		(void)fclose(fp[0]);
1870 
1871 #ifdef HAVE_NETINFO
1872 	if (config_netinfo)
1873 		free_netinfo_config(config_netinfo);
1874 #endif /* HAVE_NETINFO */
1875 
1876 #if !defined(VMS) && !defined(SYS_VXWORKS)
1877 	/* find a keyid */
1878 	if (info_auth_keyid == 0)
1879 		req_keyid = 65535;
1880 	else
1881 		req_keyid = info_auth_keyid;
1882 
1883 	/* if doesn't exist, make up one at random */
1884 	if (!authhavekey(req_keyid)) {
1885 		char rankey[9];
1886 		int j;
1887 
1888 		for (i = 0; i < 8; i++)
1889 			for (j = 1; j < 100; ++j) {
1890 				rankey[i] = (char) (ntp_random() & 0xff);
1891 				if (rankey[i] != 0) break;
1892 			}
1893 		rankey[8] = 0;
1894 		authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
1895 		authtrust(req_keyid, 1);
1896 		if (!authhavekey(req_keyid)) {
1897 			msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
1898 			/* HMS: Should this be fatal? */
1899 		}
1900 	}
1901 
1902 	/* save keyid so we will accept config requests with it */
1903 	info_auth_keyid = req_keyid;
1904 #endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
1905 
1906 	if (res_fp != NULL) {
1907 		if (call_resolver) {
1908 			/*
1909 			 * Need name resolution
1910 			 */
1911 			do_resolve_internal();
1912 		}
1913 	}
1914 }
1915 
1916 
1917 #ifdef HAVE_NETINFO
1918 
1919 /*
1920  * get_netinfo_config - find the nearest NetInfo domain with an ntp
1921  * configuration and initialize the configuration state.
1922  */
1923 static struct netinfo_config_state *
1924 get_netinfo_config()
1925 {
1926 	ni_status status;
1927 	void *domain;
1928 	ni_id config_dir;
1929        	struct netinfo_config_state *config;
1930 
1931 	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
1932 
1933 	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
1934 		void *next_domain;
1935 		if (ni_open(domain, "..", &next_domain) != NI_OK) {
1936 			ni_free(next_domain);
1937 			break;
1938 		}
1939 		ni_free(domain);
1940 		domain = next_domain;
1941 	}
1942 	if (status != NI_OK) {
1943 		ni_free(domain);
1944 		return NULL;
1945 	}
1946 
1947        	config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
1948        	config->domain = domain;
1949        	config->config_dir = config_dir;
1950        	config->prop_index = 0;
1951        	config->val_index = 0;
1952        	config->val_list = NULL;
1953 
1954 	return config;
1955 }
1956 
1957 
1958 
1959 /*
1960  * free_netinfo_config - release NetInfo configuration state
1961  */
1962 static void
1963 free_netinfo_config(struct netinfo_config_state *config)
1964 {
1965 	ni_free(config->domain);
1966 	free(config);
1967 }
1968 
1969 
1970 
1971 /*
1972  * gettokens_netinfo - return tokens from NetInfo
1973  */
1974 static int
1975 gettokens_netinfo (
1976 	struct netinfo_config_state *config,
1977 	char **tokenlist,
1978 	int *ntokens
1979 	)
1980 {
1981 	int prop_index = config->prop_index;
1982 	int val_index = config->val_index;
1983 	char **val_list = config->val_list;
1984 
1985 	/*
1986 	 * Iterate through each keyword and look for a property that matches it.
1987 	 */
1988 	again:
1989 	if (!val_list) {
1990 	       	for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
1991 	       	{
1992 		       	ni_namelist namelist;
1993 			struct keyword current_prop = keywords[prop_index];
1994 
1995 			/*
1996 			 * For each value associated in the property, we're going to return
1997 			 * a separate line. We squirrel away the values in the config state
1998 			 * so the next time through, we don't need to do this lookup.
1999 			 */
2000 		       	NI_INIT(&namelist);
2001 	       		if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
2002 				ni_index index;
2003 
2004 				/* Found the property, but it has no values */
2005 				if (namelist.ni_namelist_len == 0) continue;
2006 
2007 				if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
2008 					{ msyslog(LOG_ERR, "out of memory while configuring"); break; }
2009 
2010 				for (index = 0; index < namelist.ni_namelist_len; index++) {
2011 					char *value = namelist.ni_namelist_val[index];
2012 
2013 					if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
2014 						{ msyslog(LOG_ERR, "out of memory while configuring"); break; }
2015 
2016 					strcpy(val_list[index], value);
2017 				}
2018 				val_list[index] = NULL;
2019 
2020 				break;
2021 			}
2022 			ni_namelist_free(&namelist);
2023 		}
2024 		config->prop_index = prop_index;
2025 	}
2026 
2027 	/* No list; we're done here. */
2028        	if (!val_list) return CONFIG_UNKNOWN;
2029 
2030 	/*
2031 	 * We have a list of values for the current property.
2032 	 * Iterate through them and return each in order.
2033 	 */
2034 	if (val_list[val_index])
2035 	{
2036 		int ntok = 1;
2037 		int quoted = 0;
2038 		char *tokens = val_list[val_index];
2039 
2040 		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
2041 
2042 		(const char*)tokenlist[0] = keywords[prop_index].text;
2043 		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
2044 			tokenlist[ntok] = tokens;
2045 			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
2046 				quoted ^= (*tokens++ == '"');
2047 
2048 			if (ISEOL(*tokens)) {
2049 				*tokens = '\0';
2050 				break;
2051 			} else {		/* must be space */
2052 				*tokens++ = '\0';
2053 				while (ISSPACE(*tokens)) tokens++;
2054 				if (ISEOL(*tokens)) break;
2055 			}
2056 		}
2057 
2058 		if (ntok == MAXTOKENS) {
2059 			/* HMS: chomp it to lose the EOL? */
2060 			msyslog(LOG_ERR,
2061 			    "gettokens_netinfo: too many tokens.  Ignoring: %s",
2062 			    tokens);
2063 		} else {
2064 			*ntokens = ntok + 1;
2065 		}
2066 
2067 		config->val_index++;	/* HMS: Should this be in the 'else'? */
2068 
2069 		return keywords[prop_index].keytype;
2070 	}
2071 
2072 	/* We're done with the current property. */
2073 	prop_index = ++config->prop_index;
2074 
2075 	/* Free val_list and reset counters. */
2076 	for (val_index = 0; val_list[val_index]; val_index++)
2077 		free(val_list[val_index]);
2078        	free(val_list);	val_list = config->val_list = NULL; val_index = config->val_index = 0;
2079 
2080 	goto again;
2081 }
2082 
2083 #endif /* HAVE_NETINFO */
2084 
2085 
2086 /*
2087  * gettokens - read a line and return tokens
2088  */
2089 static int
2090 gettokens (
2091 	FILE *fp,
2092 	char *line,
2093 	char **tokenlist,
2094 	int *ntokens
2095 	)
2096 {
2097 	register char *cp;
2098 	register int ntok;
2099 	register int quoted = 0;
2100 
2101 	/*
2102 	 * Find start of first token
2103 	 */
2104 	again:
2105 	while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
2106 		cp = line;
2107 		while (ISSPACE(*cp))
2108 			cp++;
2109 		if (!ISEOL(*cp))
2110 			break;
2111 	}
2112 	if (cp == NULL) {
2113 		*ntokens = 0;
2114 		return CONFIG_UNKNOWN;	/* hack.  Is recognized as EOF */
2115 	}
2116 
2117 	/*
2118 	 * Now separate out the tokens
2119 	 */
2120 	for (ntok = 0; ntok < MAXTOKENS; ntok++) {
2121 		tokenlist[ntok] = cp;
2122 		while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
2123 			quoted ^= (*cp++ == '"');
2124 
2125 		if (ISEOL(*cp)) {
2126 			*cp = '\0';
2127 			break;
2128 		} else {		/* must be space */
2129 			*cp++ = '\0';
2130 			while (ISSPACE(*cp))
2131 				cp++;
2132 			if (ISEOL(*cp))
2133 				break;
2134 		}
2135 	}
2136 
2137      /* Heiko: Remove leading and trailing quotes around tokens */
2138      {
2139             int i,j = 0;
2140 
2141 
2142 			for (i = 0; i < ntok; i++) {
2143 					/* Now check if the first char is a quote and remove that */
2144 					if ( tokenlist[ntok][0] == '"' )
2145 							tokenlist[ntok]++;
2146 
2147 					/* Now check the last char ... */
2148 					j = strlen(tokenlist[ntok])-1;
2149 					if ( tokenlist[ntok][j] == '"' )
2150 							tokenlist[ntok][j] = '\0';
2151 			}
2152 
2153     }
2154 
2155 	if (ntok == MAXTOKENS) {
2156 		--ntok;
2157 		/* HMS: chomp it to lose the EOL? */
2158 		msyslog(LOG_ERR,
2159 		    "gettokens: too many tokens on the line. Ignoring %s",
2160 		    cp);
2161 	} else {
2162 		/*
2163 		 * Return the match
2164 		 */
2165 		*ntokens = ntok + 1;
2166 		ntok = matchkey(tokenlist[0], keywords, 1);
2167 		if (ntok == CONFIG_UNKNOWN)
2168 			goto again;
2169 	}
2170 
2171 	return ntok;
2172 }
2173 
2174 
2175 
2176 /*
2177  * matchkey - match a keyword to a list
2178  */
2179 static int
2180 matchkey(
2181 	register char *word,
2182 	register struct keyword *keys,
2183 	int complain
2184 	)
2185 {
2186 	for (;;) {
2187 		if (keys->keytype == CONFIG_UNKNOWN) {
2188 			if (complain)
2189 				msyslog(LOG_ERR,
2190 				    "configure: keyword \"%s\" unknown, line ignored",
2191 				    word);
2192 			return CONFIG_UNKNOWN;
2193 		}
2194 		if (STRSAME(word, keys->text))
2195 			return keys->keytype;
2196 		keys++;
2197 	}
2198 }
2199 
2200 
2201 /*
2202  * getnetnum - return a net number (this is crude, but careful)
2203  */
2204 static int
2205 getnetnum(
2206 	const char *num,
2207 	struct sockaddr_storage *addr,
2208 	int complain,
2209 	enum gnn_type a_type
2210 	)
2211 {
2212 	struct addrinfo hints;
2213 	struct addrinfo *ptr;
2214 	int retval;
2215 
2216 #if 0
2217 	printf("getnetnum: <%s> is a %s (%d)\n",
2218 		num,
2219 		(a_type == t_UNK)
2220 		? "t_UNK"
2221 		: (a_type == t_REF)
2222 		  ? "t_REF"
2223 		  : (a_type == t_MSK)
2224 		    ? "t_MSK"
2225 		    : "???",
2226 		a_type);
2227 #endif
2228 
2229 	/* Get host address. Looking for UDP datagram connection */
2230  	memset(&hints, 0, sizeof (hints));
2231  	if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
2232 	    hints.ai_family = addr->ss_family;
2233 	else
2234 	    hints.ai_family = AF_UNSPEC;
2235 	/*
2236 	 * If we don't have an IPv6 stack, just look up IPv4 addresses
2237 	 */
2238 	if (isc_net_probeipv6() != ISC_R_SUCCESS)
2239 		hints.ai_family = AF_INET;
2240 
2241 	hints.ai_socktype = SOCK_DGRAM;
2242 
2243 	if (a_type != t_UNK) {
2244 		hints.ai_flags = AI_NUMERICHOST;
2245 	}
2246 
2247 #ifdef DEBUG
2248 	if (debug > 3)
2249 		printf("getnetnum: calling getaddrinfo(%s,...)\n", num);
2250 #endif
2251 	retval = getaddrinfo(num, "ntp", &hints, &ptr);
2252 	if (retval != 0 ||
2253 	   (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
2254 		if (complain)
2255 			msyslog(LOG_ERR,
2256 				"getaddrinfo: \"%s\" invalid host address, ignored",
2257 				num);
2258 #ifdef DEBUG
2259 		if (debug > 0)
2260 			printf(
2261 				"getaddrinfo: \"%s\" invalid host address%s.\n",
2262 				num, (complain)
2263 				? ", ignored"
2264 				: "");
2265 #endif
2266 		if (retval == 0 &&
2267 		    ptr->ai_family == AF_INET6 &&
2268 		    isc_net_probeipv6() != ISC_R_SUCCESS)
2269 		{
2270 			return -1;
2271 		}
2272 		else {
2273 			return 0;
2274 		}
2275 	}
2276 
2277 	memcpy(addr, ptr->ai_addr, ptr->ai_addrlen);
2278 #ifdef DEBUG
2279 	if (debug > 1)
2280 		printf("getnetnum given %s, got %s (%s/%d)\n",
2281 		   num, stoa(addr),
2282 			(a_type == t_UNK)
2283 			? "t_UNK"
2284 			: (a_type == t_REF)
2285 			  ? "t_REF"
2286 			  : (a_type == t_MSK)
2287 			    ? "t_MSK"
2288 			    : "???",
2289 			a_type);
2290 #endif
2291         freeaddrinfo(ptr);
2292 	return 1;
2293 }
2294 
2295 
2296 #if !defined(VMS) && !defined(SYS_WINNT)
2297 /*
2298  * catchchild - receive the resolver's exit status
2299  */
2300 static RETSIGTYPE
2301 catchchild(
2302 	int sig
2303 	)
2304 {
2305 	/*
2306 	 * We only start up one child, and if we're here
2307 	 * it should have already exited.  Hence the following
2308 	 * shouldn't hang.  If it does, please tell me.
2309 	 */
2310 #if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
2311 	(void) wait(0);
2312 #endif /* SYS_WINNT  && VXWORKS*/
2313 }
2314 #endif /* VMS */
2315 
2316 
2317 /*
2318  * save_resolve - save configuration info into a file for later name resolution
2319  */
2320 static void
2321 save_resolve(
2322 	char *name,
2323 	int mode,
2324 	int version,
2325 	int minpoll,
2326 	int maxpoll,
2327 	u_int flags,
2328 	int ttl,
2329 	keyid_t keyid,
2330 	u_char *keystr,
2331 	u_char peeraf
2332 	)
2333 {
2334 #ifndef SYS_VXWORKS
2335 	if (res_fp == NULL) {
2336 #ifndef SYS_WINNT
2337 		(void) strcpy(res_file, RES_TEMPFILE);
2338 #else
2339 		/* no /tmp directory under NT */
2340 		{
2341 			if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
2342 				msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
2343 				return;
2344 			}
2345 			(void) strcat(res_file, "ntpdXXXXXX");
2346 		}
2347 #endif /* SYS_WINNT */
2348 #ifdef HAVE_MKSTEMP
2349 		{
2350 			int fd;
2351 
2352 			res_fp = NULL;
2353 			if ((fd = mkstemp(res_file)) != -1)
2354 				res_fp = fdopen(fd, "r+");
2355 		}
2356 #else
2357 		(void) mktemp(res_file);
2358 		res_fp = fopen(res_file, "w");
2359 #endif
2360 		if (res_fp == NULL) {
2361 			msyslog(LOG_ERR, "open failed for %s: %m", res_file);
2362 			return;
2363 		}
2364 	}
2365 #ifdef DEBUG
2366 	if (debug) {
2367 		printf("resolving %s\n", name);
2368 	}
2369 #endif
2370 
2371 	(void)fprintf(res_fp, "%s %u %d %d %d %d %d %d %u %s\n", name, peeraf,
2372 	    mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2373 #ifdef DEBUG
2374 	if (debug > 1)
2375 		printf("config: %s %u %d %d %d %d %x %d %u %s\n", name, peeraf, mode,
2376 		    version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2377 #endif
2378 
2379 #else  /* SYS_VXWORKS */
2380 	/* save resolve info to a struct */
2381 #endif /* SYS_VXWORKS */
2382 }
2383 
2384 
2385 /*
2386  * abort_resolve - terminate the resolver stuff and delete the file
2387  */
2388 static void
2389 abort_resolve(void)
2390 {
2391 	/*
2392 	 * In an ideal world we would might reread the file and
2393 	 * log the hosts which aren't getting configured.  Since
2394 	 * this is too much work, however, just close and delete
2395 	 * the temp file.
2396 	 */
2397 	if (res_fp != NULL)
2398 		(void) fclose(res_fp);
2399 	res_fp = NULL;
2400 
2401 #ifndef SYS_VXWORKS		/* we don't open the file to begin with */
2402 #if !defined(VMS)
2403 	(void) unlink(res_file);
2404 #else
2405 	(void) delete(res_file);
2406 #endif /* VMS */
2407 #endif /* SYS_VXWORKS */
2408 }
2409 
2410 
2411 /*
2412  * do_resolve_internal - start up the resolver function (not program)
2413  */
2414 /*
2415  * On VMS, this routine will simply refuse to resolve anything.
2416  *
2417  * Possible implementation: keep `res_file' in memory, do async
2418  * name resolution via QIO, update from within completion AST.
2419  * I'm unlikely to find the time for doing this, though. -wjm
2420  */
2421 static void
2422 do_resolve_internal(void)
2423 {
2424 	int i;
2425 
2426 	if (res_fp == NULL) {
2427 		/* belch */
2428 		msyslog(LOG_ERR,
2429 			"do_resolve_internal: Fatal: res_fp == NULL");
2430 		exit(1);
2431 	}
2432 
2433 	/* we are done with this now */
2434 	(void) fclose(res_fp);
2435 	res_fp = NULL;
2436 
2437 #if !defined(VMS) && !defined (SYS_VXWORKS)
2438 	req_file = res_file;	/* set up pointer to res file */
2439 #ifndef SYS_WINNT
2440 	(void) signal_no_reset(SIGCHLD, catchchild);
2441 
2442 #ifndef SYS_VXWORKS
2443 	/* the parent process will write to the pipe
2444 	 * in order to wake up to child process
2445 	 * which may be waiting in a select() call
2446 	 * on the read fd */
2447 	if (pipe(resolver_pipe_fd) < 0) {
2448 		msyslog(LOG_ERR,
2449 			"unable to open resolver pipe");
2450 		exit(1);
2451 	}
2452 
2453 	i = fork();
2454 	/* Shouldn't the code below be re-ordered?
2455 	 * I.e. first check if the fork() returned an error, then
2456 	 * check whether we're parent or child.
2457 	 *     Martin Burnicki
2458 	 */
2459 	if (i == 0) {
2460 		/*
2461 		 * this used to close everything
2462 		 * I don't think this is necessary
2463 		 */
2464 		/*
2465 		 * To the unknown commenter above:
2466 		 * Well, I think it's better to clean up
2467 		 * after oneself. I have had problems with
2468 		 * refclock-io when intres was running - things
2469 		 * where fine again when ntpintres was gone.
2470 		 * So some systems react erratic at least.
2471 		 *
2472 		 *			Frank Kardel
2473 		 *
2474 		 * 94-11-16:
2475 		 * Further debugging has proven that the above is
2476 		 * absolutely harmful. The internal resolver
2477 		 * is still in the SIGIO process group and the lingering
2478 		 * async io information causes it to process requests from
2479 		 * all file decriptor causing a race between the NTP daemon
2480 		 * and the resolver. which then eats data when it wins 8-(.
2481 		 * It is absolutly necessary to kill any IO associations
2482 		 * shared with the NTP daemon.
2483 		 *
2484 		 * We also block SIGIO (currently no ports means to
2485 		 * disable the signal handle for IO).
2486 		 *
2487 		 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
2488 		 * that it is the ntp-resolver child running into trouble.
2489 		 *
2490 		 * THUS:
2491 		 */
2492 
2493 		/* This is the child process who will read the pipe,
2494 		 * so we close the write fd */
2495 		close(resolver_pipe_fd[1]);
2496 		closelog();
2497 		kill_asyncio(0);
2498 
2499 		(void) signal_no_reset(SIGCHLD, SIG_DFL);
2500 
2501 #ifdef DEBUG
2502 		if (0)
2503 		    debug = 2;
2504 #endif
2505 
2506 # ifndef LOG_DAEMON
2507 		openlog("ntpd_initres", LOG_PID);
2508 # else /* LOG_DAEMON */
2509 
2510 #  ifndef LOG_NTP
2511 #   define	LOG_NTP LOG_DAEMON
2512 #  endif
2513 		openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
2514 #ifndef SYS_CYGWIN32
2515 #  ifdef DEBUG
2516 		if (debug)
2517 		    setlogmask(LOG_UPTO(LOG_DEBUG));
2518 		else
2519 #  endif /* DEBUG */
2520 		    setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
2521 # endif /* LOG_DAEMON */
2522 #endif
2523 
2524 		ntp_intres();
2525 
2526 		/*
2527 		 * If we got here, the intres code screwed up.
2528 		 * Print something so we don't die without complaint
2529 		 */
2530 		msyslog(LOG_ERR, "call to ntp_intres lost");
2531 		abort_resolve();
2532 		exit(1);
2533 	}
2534 #else
2535 	 /* vxWorks spawns a thread... -casey */
2536 	 i = sp (ntp_intres);
2537 	 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
2538 #endif
2539 	if (i == -1) {
2540 		msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
2541 		(void) signal_no_reset(SIGCHLD, SIG_DFL);
2542 		abort_resolve();
2543 	}
2544 	else {
2545 		/* This is the parent process who will write to the pipe,
2546 		 * so we close the read fd */
2547 		close(resolver_pipe_fd[0]);
2548 	}
2549 #else /* SYS_WINNT */
2550 	{
2551 		/* NT's equivalent of fork() is _spawn(), but the start point
2552 		 * of the new process is an executable filename rather than
2553 		 * a function name as desired here.
2554 		 */
2555 		DWORD dwThreadId;
2556 		fflush(stdout);
2557 		ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
2558 		if (ResolverEventHandle == NULL) {
2559 			msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
2560 			abort_resolve();
2561 		}
2562 		ResolverThreadHandle = CreateThread(
2563 			NULL,				 /* no security attributes	*/
2564 			0,				 /* use default stack size	*/
2565 			(LPTHREAD_START_ROUTINE) ntp_intres, /* thread function		*/
2566 			NULL,				 /* argument to thread function   */
2567 			0,				 /* use default creation flags	  */
2568 			&dwThreadId);			 /* returns the thread identifier */
2569 		if (ResolverThreadHandle == NULL) {
2570 			msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
2571 			CloseHandle(ResolverEventHandle);
2572 			ResolverEventHandle = NULL;
2573 			abort_resolve();
2574 		}
2575 	}
2576 #endif /* SYS_WINNT */
2577 #else /* VMS  VX_WORKS */
2578 	msyslog(LOG_ERR,
2579 		"Name resolution not implemented for VMS - use numeric addresses");
2580 	abort_resolve();
2581 #endif /* VMS VX_WORKS */
2582 }
2583