xref: /freebsd/contrib/ntp/ntpd/ntp_config.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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 	for (;;) {
601 		if (tok == CONFIG_END)
602 			break;
603 		if (fp[includelevel])
604 			tok = gettokens(fp[includelevel], line, tokens, &ntokens);
605 #ifdef HAVE_NETINFO
606 		else
607 			tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
608 #endif /* HAVE_NETINFO */
609 
610 		if (tok == CONFIG_UNKNOWN) {
611 		    if (includelevel > 0) {
612 			fclose(fp[includelevel--]);
613 			continue;
614 		    } else {
615 			break;
616 		    }
617 		}
618 
619 		switch(tok) {
620 		    case CONFIG_PEER:
621 		    case CONFIG_SERVER:
622 		    case CONFIG_MANYCASTCLIENT:
623 		    case CONFIG_BROADCAST:
624 			if (tok == CONFIG_PEER)
625 			    hmode = MODE_ACTIVE;
626 			else if (tok == CONFIG_SERVER)
627 			    hmode = MODE_CLIENT;
628 			else if (tok == CONFIG_MANYCASTCLIENT)
629 			    hmode = MODE_CLIENT;
630 			else
631 			    hmode = MODE_BROADCAST;
632 
633 			if (ntokens < 2) {
634 				msyslog(LOG_ERR,
635 					"No address for %s, line ignored",
636 					tokens[0]);
637 				break;
638 			}
639 
640 			istart = 1;
641 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
642 			peeraddr.ss_family = default_ai_family;
643 			switch (matchkey(tokens[istart], addr_type, 0)) {
644 			case CONF_ADDR_IPV4:
645 				peeraddr.ss_family = AF_INET;
646 				istart++;
647 				break;
648 			case CONF_ADDR_IPV6:
649 				peeraddr.ss_family = AF_INET6;
650 				istart++;
651 				break;
652 			}
653 
654 			status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK);
655 			if (status == -1)
656 				break;		/* Found IPv6 address */
657 			if(status != 1) {
658 				errflg = -1;
659 			} else {
660 				errflg = 0;
661 
662 				if (
663 #ifdef REFCLOCK
664 					!ISREFCLOCKADR(&peeraddr) &&
665 #endif
666 					ISBADADR(&peeraddr)) {
667 					msyslog(LOG_ERR,
668 						"attempt to configure invalid address %s",
669 						stoa(&peeraddr));
670 					break;
671 				}
672 				/*
673 				 * Shouldn't be able to specify multicast
674 				 * address for server/peer!
675 				 * and unicast address for manycastclient!
676 				 */
677 				if (peeraddr.ss_family == AF_INET) {
678 					if (((tok == CONFIG_SERVER) ||
679 				     	(tok == CONFIG_PEER)) &&
680 #ifdef REFCLOCK
681 				    	!ISREFCLOCKADR(&peeraddr) &&
682 #endif
683 				    	IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
684 						msyslog(LOG_ERR,
685 							"attempt to configure invalid address %s",
686 							stoa(&peeraddr));
687 						break;
688 					}
689 					if ((tok == CONFIG_MANYCASTCLIENT) &&
690 				    	!IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
691 						msyslog(LOG_ERR,
692 							"attempt to configure invalid address %s",
693 							stoa(&peeraddr));
694 						break;
695 					}
696 				}
697 				else if(peeraddr.ss_family == AF_INET6) {
698                                 if (((tok == CONFIG_SERVER) ||
699                                      (tok == CONFIG_PEER)) &&
700 #ifdef REFCLOCK
701                                     !ISREFCLOCKADR(&peeraddr) &&
702 #endif
703                                         IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
704                                                 msyslog(LOG_ERR,
705                                                         "attempt to configure in valid address %s",
706                                                         stoa(&peeraddr));
707                                                 break;
708                                         }
709                                         if ((tok == CONFIG_MANYCASTCLIENT) &&
710                                             !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
711                                                         msyslog(LOG_ERR,
712                                                         "attempt to configure in valid address %s",
713                                                         stoa(&peeraddr));
714                                                 break;
715 					}
716 				}
717 			}
718 			if (peeraddr.ss_family == AF_INET6 &&
719 			    isc_net_probeipv6() != ISC_R_SUCCESS)
720 				break;
721 
722 			peerversion = NTP_VERSION;
723 			minpoll = NTP_MINDPOLL;
724 			maxpoll = NTP_MAXDPOLL;
725 			peerkey = 0;
726 			peerkeystr = (u_char *)"*";
727 			peerflags = 0;
728 			ttl = 0;
729 			istart++;
730 			for (i = istart; i < ntokens; i++)
731 			    switch (matchkey(tokens[i], mod_keywords, 1)) {
732 				case CONF_MOD_VERSION:
733 				    if (i >= ntokens-1) {
734 					    msyslog(LOG_ERR,
735 						    "peer/server version requires an argument");
736 					    errflg = 1;
737 					    break;
738 				    }
739 				    peerversion = atoi(tokens[++i]);
740 				    if ((u_char)peerversion > NTP_VERSION
741 					|| (u_char)peerversion < NTP_OLDVERSION) {
742 					    msyslog(LOG_ERR,
743 						    "inappropriate version number %s, line ignored",
744 						    tokens[i]);
745 					    errflg = 1;
746 				    }
747 				    break;
748 
749 				case CONF_MOD_KEY:
750 				    if (i >= ntokens-1) {
751 					    msyslog(LOG_ERR,
752 						    "key: argument required");
753 					    errflg = 1;
754 					    break;
755 				    }
756 				    peerkey = (int)atol(tokens[++i]);
757 				    peerflags |= FLAG_AUTHENABLE;
758 				    break;
759 
760 				case CONF_MOD_MINPOLL:
761 				    if (i >= ntokens-1) {
762 					    msyslog(LOG_ERR,
763 						    "minpoll: argument required");
764 					    errflg = 1;
765 					    break;
766 				    }
767 				    minpoll = atoi(tokens[++i]);
768 				    if (minpoll < NTP_MINPOLL) {
769 					    msyslog(LOG_INFO,
770 						    "minpoll: provided value (%d) is below minimum (%d)",
771 						    minpoll, NTP_MINPOLL);
772 					minpoll = NTP_MINPOLL;
773 				    }
774 				    break;
775 
776 				case CONF_MOD_MAXPOLL:
777 				    if (i >= ntokens-1) {
778 					    msyslog(LOG_ERR,
779 						    "maxpoll: argument required"
780 						    );
781 					    errflg = 1;
782 					    break;
783 				    }
784 				    maxpoll = atoi(tokens[++i]);
785 				    if (maxpoll > NTP_MAXPOLL) {
786 					    msyslog(LOG_INFO,
787 						    "maxpoll: provided value (%d) is above maximum (%d)",
788 						    maxpoll, NTP_MAXPOLL);
789 					maxpoll = NTP_MAXPOLL;
790 				    }
791 				    break;
792 
793 				case CONF_MOD_PREFER:
794 				    peerflags |= FLAG_PREFER;
795 				    break;
796 
797 				case CONF_MOD_PREEMPT:
798 				    peerflags |= FLAG_PREEMPT;
799 				    break;
800 
801 				case CONF_MOD_NOSELECT:
802 				    peerflags |= FLAG_NOSELECT;
803 				    break;
804 
805 				case CONF_MOD_TRUE:
806 				    peerflags |= FLAG_TRUE;
807 
808 				case CONF_MOD_BURST:
809 				    peerflags |= FLAG_BURST;
810 				    break;
811 
812 				case CONF_MOD_IBURST:
813 				    peerflags |= FLAG_IBURST;
814 				    break;
815 
816 				case CONF_MOD_DYNAMIC:
817 				    msyslog(LOG_WARNING,
818 				        "Warning: the \"dynamic\" keyword has been obsoleted"
819 				        " and will be removed in the next release\n");
820 				    break;
821 
822 #ifdef OPENSSL
823 				case CONF_MOD_SKEY:
824 				    peerflags |= FLAG_SKEY |
825 					FLAG_AUTHENABLE;
826 				    break;
827 #endif /* OPENSSL */
828 
829 				case CONF_MOD_TTL:
830 				    if (i >= ntokens-1) {
831 					msyslog(LOG_ERR,
832 					    "ttl: argument required");
833 				        errflg = 1;
834 				        break;
835 				    }
836 				    ttl = atoi(tokens[++i]);
837 				    if (ttl >= MAX_TTL) {
838 					msyslog(LOG_ERR,
839 					    "ttl: invalid argument");
840 					errflg = 1;
841 				    }
842 				    break;
843 
844 				case CONF_MOD_MODE:
845 				    if (i >= ntokens-1) {
846 					msyslog(LOG_ERR,
847 					    "mode: argument required");
848 					errflg = 1;
849 					break;
850 				    }
851 				    ttl = atoi(tokens[++i]);
852 				    break;
853 
854 				case CONFIG_UNKNOWN:
855 				    errflg = 1;
856 				    break;
857 			    }
858 			if (minpoll > maxpoll) {
859 				msyslog(LOG_ERR,
860 				    "config error: minpoll > maxpoll");
861 				errflg = 1;
862 			}
863 			if (errflg == 0) {
864 			    if (peer_config(&peeraddr,
865 				ANY_INTERFACE_CHOOSE(&peeraddr), hmode,
866 				peerversion, minpoll, maxpoll, peerflags,
867 				ttl, peerkey, peerkeystr) == 0) {
868 					msyslog(LOG_ERR,
869 						"configuration of %s failed",
870 						stoa(&peeraddr));
871 			    }
872 			} else if (errflg == -1) {
873 				save_resolve(tokens[istart - 1], hmode, peerversion,
874 				    minpoll, maxpoll, peerflags, ttl,
875 				    peerkey, peerkeystr, peeraddr.ss_family);
876 			}
877 			break;
878 
879 		    case CONFIG_DRIFTFILE:
880 			if (ntokens >= 2)
881 			    stats_config(STATS_FREQ_FILE, tokens[1]);
882 			else
883 			    stats_config(STATS_FREQ_FILE, (char *)0);
884 			stats_write_period = stats_write_tolerance = 0;
885 			if (ntokens >= 3)
886 			     stats_write_period = 60 * atol(tokens[2]);
887 			if (stats_write_period <= 0)
888 			     stats_write_period = 3600;
889 			if (ntokens >= 4) {
890 			     double ftemp;
891 			     sscanf(tokens[3], "%lf", &ftemp);
892 			     stats_write_tolerance = ftemp / 100;
893 			}
894 			break;
895 
896 		    case CONFIG_PIDFILE:
897 			if (ntokens >= 2)
898 			    stats_config(STATS_PID_FILE, tokens[1]);
899 			else
900 			    stats_config(STATS_PID_FILE, (char *)0);
901 			break;
902 
903 		    case CONFIG_END:
904 			for ( i = 0; i <= includelevel; i++ ) {
905 				fclose(fp[i]);
906 			}
907 			break;
908 
909 		    case CONFIG_INCLUDEFILE:
910 			if (ntokens < 2) {
911 			    msyslog(LOG_ERR, "includefile needs one argument");
912 			    break;
913 			}
914 			if (includelevel >= MAXINCLUDELEVEL) {
915 			    fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
916 			    msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
917 			    break;
918 			}
919 			includefile = fopen(FindConfig(tokens[1]), "r");
920 			if (includefile == NULL) {
921 			    fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
922 			    msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
923 			    break;
924 			}
925 			fp[++includelevel] = includefile;
926 			break;
927 
928 		    case CONFIG_LOGFILE:
929 			if (ntokens >= 2) {
930 				FILE *new_file;
931 
932 				new_file = fopen(tokens[1], "a");
933 				if (new_file != NULL) {
934 					NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
935 					    msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
936 					if (syslog_file != NULL &&
937 					    fileno(syslog_file) != fileno(new_file))
938 					    (void)fclose(syslog_file);
939 
940 					syslog_file = new_file;
941 					syslogit = 0;
942 				}
943 				else
944 				    msyslog(LOG_ERR,
945 					    "Cannot open log file %s",
946 					    tokens[1]);
947 			}
948 			else
949 			    msyslog(LOG_ERR, "logfile needs one argument");
950 			break;
951 
952 		    case CONFIG_LOGCONFIG:
953 			for (i = 1; i < ntokens; i++)
954 			{
955 				int add = 1;
956 				int equals = 0;
957 				char * s = &tokens[i][0];
958 
959 				switch (*s) {
960 				    case '+':
961 				    case '-':
962 				    case '=':
963 					add = *s == '+';
964 					equals = *s == '=';
965 					s++;
966 					break;
967 
968 				    default:
969 					break;
970 				}
971 				if (equals) {
972 					ntp_syslogmask = get_logmask(s);
973 				} else {
974 					if (add) {
975 						ntp_syslogmask |= get_logmask(s);
976 					} else {
977 						ntp_syslogmask &= ~get_logmask(s);
978 					}
979 				}
980 #ifdef DEBUG
981 				if (debug)
982 				    printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
983 #endif
984 			}
985 			break;
986 
987 		    case CONFIG_BROADCASTCLIENT:
988 			if (ntokens == 1) {
989 				proto_config(PROTO_BROADCLIENT, 1, 0., NULL);
990 			} else {
991 				proto_config(PROTO_BROADCLIENT, 2, 0., NULL);
992 			}
993 			break;
994 
995 		    case CONFIG_MULTICASTCLIENT:
996 		    case CONFIG_MANYCASTSERVER:
997 			if (ntokens > 1) {
998 				istart = 1;
999 				memset((char *)&peeraddr, 0, sizeof(peeraddr));
1000 				peeraddr.ss_family = default_ai_family;
1001 				switch (matchkey(tokens[istart],
1002 				    addr_type, 0)) {
1003 				case CONF_ADDR_IPV4:
1004 					peeraddr.ss_family = AF_INET;
1005 					istart++;
1006 					break;
1007 				case CONF_ADDR_IPV6:
1008 					peeraddr.ss_family = AF_INET6;
1009 					istart++;
1010 					break;
1011 				}
1012 				/*
1013 				 * Abuse maskaddr to store the prefered ip
1014 				 * version.
1015 				 */
1016 				memset((char *)&maskaddr, 0, sizeof(maskaddr));
1017 				maskaddr.ss_family = peeraddr.ss_family;
1018 
1019 				for (i = istart; i < ntokens; i++) {
1020 					memset((char *)&peeraddr, 0,
1021 					    sizeof(peeraddr));
1022 					peeraddr.ss_family = maskaddr.ss_family;
1023 					if (getnetnum(tokens[i], &peeraddr, 1,
1024 						      t_UNK)  == 1)
1025 					    proto_config(PROTO_MULTICAST_ADD,
1026 							 0, 0., &peeraddr);
1027 				}
1028 			} else
1029 			    proto_config(PROTO_MULTICAST_ADD,
1030 					 0, 0., NULL);
1031 			if (tok == CONFIG_MULTICASTCLIENT)
1032 				proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1033 			else if (tok == CONFIG_MANYCASTSERVER)
1034 				sys_manycastserver = 1;
1035 			break;
1036 
1037 		    case CONFIG_KEYS:
1038 			if (ntokens >= 2) {
1039 				getauthkeys(tokens[1]);
1040 			}
1041 			break;
1042 
1043 		    case CONFIG_KEYSDIR:
1044 			if (ntokens < 2) {
1045 			    msyslog(LOG_ERR,
1046 				"Keys directory name required");
1047 			    break;
1048 			}
1049 			keysdir = (char *)emalloc(strlen(tokens[1]) + 1);
1050 			strcpy(keysdir, tokens[1]);
1051 			break;
1052 
1053 		    case CONFIG_TINKER:
1054 			for (i = 1; i < ntokens; i++) {
1055 			    int temp;
1056 			    double ftemp;
1057 
1058 			    temp = matchkey(tokens[i++], tinker_keywords, 1);
1059 			    if (i > ntokens - 1) {
1060 				msyslog(LOG_ERR,
1061 				    "tinker: missing argument");
1062 				errflg++;
1063 				break;
1064 			    }
1065 			    sscanf(tokens[i], "%lf", &ftemp);
1066 			    switch(temp) {
1067 
1068 			    case CONF_CLOCK_MAX:
1069                                 loop_config(LOOP_MAX, ftemp);
1070 				break;
1071 
1072 			    case CONF_CLOCK_PANIC:
1073 				loop_config(LOOP_PANIC, ftemp);
1074 				break;
1075 
1076 			    case CONF_CLOCK_PHI:
1077 				loop_config(LOOP_PHI, ftemp);
1078 				break;
1079 
1080 			    case CONF_CLOCK_MINSTEP:
1081 				loop_config(LOOP_MINSTEP, ftemp);
1082 				break;
1083 
1084 			    case CONF_CLOCK_ALLAN:
1085 				loop_config(LOOP_ALLAN, ftemp);
1086 				break;
1087 
1088 			    case CONF_CLOCK_HUFFPUFF:
1089 				loop_config(LOOP_HUFFPUFF, ftemp);
1090 				break;
1091 
1092 			    case CONF_CLOCK_FREQ:
1093 				loop_config(LOOP_FREQ, ftemp);
1094 				break;
1095 			    }
1096 			}
1097 			break;
1098 
1099 		    case CONFIG_TOS:
1100 			for (i = 1; i < ntokens; i++) {
1101 			    int temp;
1102 			    double ftemp;
1103 
1104 			    temp = matchkey(tokens[i++], tos_keywords, 1);
1105 			    if (i > ntokens - 1) {
1106 				msyslog(LOG_ERR,
1107 				    "tos: missing argument");
1108 				errflg++;
1109 				break;
1110 			    }
1111 			    sscanf(tokens[i], "%lf", &ftemp);
1112 			    switch(temp) {
1113 
1114 			    case CONF_TOS_MINCLOCK:
1115 				proto_config(PROTO_MINCLOCK, 0, ftemp, NULL);
1116 				break;
1117 
1118 			    case CONF_TOS_MAXCLOCK:
1119 				proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL);
1120 				break;
1121 
1122 			    case CONF_TOS_MINSANE:
1123 				proto_config(PROTO_MINSANE, 0, ftemp, NULL);
1124 				break;
1125 
1126 			    case CONF_TOS_FLOOR:
1127 				proto_config(PROTO_FLOOR, 0, ftemp, NULL);
1128 				break;
1129 
1130 			    case CONF_TOS_CEILING:
1131 				proto_config(PROTO_CEILING, 0, ftemp, NULL);
1132 				break;
1133 
1134 			    case CONF_TOS_COHORT:
1135 				proto_config(PROTO_COHORT, 0, ftemp, NULL);
1136 				break;
1137 
1138 			    case CONF_TOS_MINDISP:
1139 				proto_config(PROTO_MINDISP, 0, ftemp, NULL);
1140 				break;
1141 
1142 			    case CONF_TOS_MAXDIST:
1143 				proto_config(PROTO_MAXDIST, 0, ftemp, NULL);
1144 				break;
1145 
1146 			    case CONF_TOS_MAXHOP:
1147 				proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
1148 				break;
1149 
1150 			    case CONF_TOS_ORPHAN:
1151 				proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
1152 				break;
1153 
1154 			    case CONF_TOS_BEACON:
1155 				proto_config(PROTO_BEACON, 0, ftemp, NULL);
1156 				break;
1157 			    }
1158 			}
1159 			break;
1160 
1161 		    case CONFIG_TTL:
1162 			for (i = 1; i < ntokens && i < MAX_TTL; i++) {
1163 			    sys_ttl[i - 1] = (u_char) atoi(tokens[i]);
1164 			    sys_ttlmax = i - 1;
1165 			}
1166 			break;
1167 
1168 		    case CONFIG_DISCARD:
1169 			for (i = 1; i < ntokens; i++) {
1170 			    int temp;
1171 
1172 			    temp = matchkey(tokens[i++],
1173 				discard_keywords, 1);
1174 			    if (i > ntokens - 1) {
1175 				msyslog(LOG_ERR,
1176 				    "discard: missing argument");
1177 				errflg++;
1178 				break;
1179 			    }
1180 			    switch(temp) {
1181 			    case CONF_DISCARD_AVERAGE:
1182 				res_avg_interval = atoi(tokens[i]);
1183 				break;
1184 
1185 			    case CONF_DISCARD_MINIMUM:
1186 				res_min_interval = atoi(tokens[i]);
1187 				break;
1188 
1189 			    case CONF_DISCARD_MONITOR:
1190 				mon_age = atoi(tokens[i]);
1191 				break;
1192 
1193 			    default:
1194 				msyslog(LOG_ERR,
1195 				    "discard: unknown keyword");
1196 				break;
1197 			    }
1198 			}
1199 			break;
1200 
1201 #ifdef OPENSSL
1202 		    case CONFIG_REVOKE:
1203 			if (ntokens >= 2)
1204 			    sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE);
1205 			break;
1206 
1207 		    case CONFIG_AUTOMAX:
1208 			if (ntokens >= 2)
1209 			    sys_automax = 1 << max(atoi(tokens[1]), 10);
1210 			break;
1211 
1212 		    case CONFIG_CRYPTO:
1213 			if (ntokens == 1) {
1214 				crypto_config(CRYPTO_CONF_NONE, NULL);
1215 				break;
1216 			}
1217 			for (i = 1; i < ntokens; i++) {
1218 			    int temp;
1219 
1220 			    temp = matchkey(tokens[i++],
1221 				 crypto_keywords, 1);
1222 			    if (i > ntokens - 1) {
1223 				msyslog(LOG_ERR,
1224 				    "crypto: missing argument");
1225 				errflg++;
1226 				break;
1227 			    }
1228 			    switch(temp) {
1229 
1230 			    case CONF_CRYPTO_CERT:
1231 				crypto_config(CRYPTO_CONF_CERT,
1232 				    tokens[i]);
1233 				break;
1234 
1235 			    case CONF_CRYPTO_RSA:
1236 				crypto_config(CRYPTO_CONF_PRIV,
1237 				    tokens[i]);
1238 				break;
1239 
1240 			    case CONF_CRYPTO_IDENT:
1241 				crypto_config(CRYPTO_CONF_IDENT,
1242 				    tokens[i]);
1243 				break;
1244 
1245 			    case CONF_CRYPTO_IFFPAR:
1246 				crypto_config(CRYPTO_CONF_IFFPAR,
1247 				    tokens[i]);
1248 				break;
1249 
1250 			    case CONF_CRYPTO_GQPAR:
1251 				crypto_config(CRYPTO_CONF_GQPAR,
1252 				    tokens[i]);
1253 				break;
1254 
1255 			    case CONF_CRYPTO_MVPAR:
1256 				crypto_config(CRYPTO_CONF_MVPAR,
1257 				    tokens[i]);
1258 				break;
1259 
1260 			    case CONF_CRYPTO_LEAP:
1261 				crypto_config(CRYPTO_CONF_LEAP,
1262 				    tokens[i]);
1263 				break;
1264 
1265 			    case CONF_CRYPTO_PW:
1266 				crypto_config(CRYPTO_CONF_PW,
1267 				    tokens[i]);
1268 				break;
1269 
1270 			    case CONF_CRYPTO_RAND:
1271 				crypto_config(CRYPTO_CONF_RAND,
1272 				    tokens[i]);
1273 				break;
1274 
1275 			    case CONF_CRYPTO_SIGN:
1276 				crypto_config(CRYPTO_CONF_SIGN,
1277 				    tokens[i]);
1278 				break;
1279 
1280 			    default:
1281 				msyslog(LOG_ERR,
1282 				    "crypto: unknown keyword");
1283 				break;
1284 			    }
1285 			}
1286 			break;
1287 #endif /* OPENSSL */
1288 
1289 		    case CONFIG_RESTRICT:
1290 			if (ntokens < 2) {
1291 				msyslog(LOG_ERR, "restrict requires an address");
1292 				break;
1293 			}
1294 			istart = 1;
1295 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1296 			peeraddr.ss_family = default_ai_family;
1297 			switch (matchkey(tokens[istart], addr_type, 0)) {
1298 			case CONF_ADDR_IPV4:
1299 				peeraddr.ss_family = AF_INET;
1300 				istart++;
1301 				break;
1302 			case CONF_ADDR_IPV6:
1303 				peeraddr.ss_family = AF_INET6;
1304 				istart++;
1305 				break;
1306 			}
1307 
1308 			/*
1309 			 * Assume default means an IPv4 address, except
1310 			 * if forced by a -4 or -6.
1311 			 */
1312 			if (STREQ(tokens[istart], "default")) {
1313 				if (peeraddr.ss_family == 0)
1314 					peeraddr.ss_family = AF_INET;
1315 			} else if (getnetnum(tokens[istart], &peeraddr, 1,
1316 					      t_UNK) != 1)
1317 				break;
1318 
1319 			/*
1320 			 * Use peerversion as flags, peerkey as mflags.  Ick.
1321 			 */
1322 			peerversion = 0;
1323 			peerkey = 0;
1324 			errflg = 0;
1325 			SET_HOSTMASK(&maskaddr, peeraddr.ss_family);
1326 			istart++;
1327 			for (i = istart; i < ntokens; i++) {
1328 				switch (matchkey(tokens[i], res_keywords, 1)) {
1329 				    case CONF_RES_MASK:
1330 					if (i >= ntokens-1) {
1331 						msyslog(LOG_ERR,
1332 							"mask keyword needs argument");
1333 						errflg++;
1334 						break;
1335 					}
1336 					i++;
1337 					if (getnetnum(tokens[i], &maskaddr, 1,
1338 						       t_MSK) != 1)
1339 					    errflg++;
1340 					break;
1341 
1342 				    case CONF_RES_IGNORE:
1343 					peerversion |= RES_IGNORE;
1344 					break;
1345 
1346 				    case CONF_RES_NOSERVE:
1347 					peerversion |= RES_DONTSERVE;
1348 					break;
1349 
1350 				    case CONF_RES_NOTRUST:
1351 					peerversion |= RES_DONTTRUST;
1352 					break;
1353 
1354 				    case CONF_RES_NOQUERY:
1355 					peerversion |= RES_NOQUERY;
1356 					break;
1357 
1358 				    case CONF_RES_NOMODIFY:
1359 					peerversion |= RES_NOMODIFY;
1360 					break;
1361 
1362 				    case CONF_RES_NOPEER:
1363 					peerversion |= RES_NOPEER;
1364 					break;
1365 
1366 				    case CONF_RES_NOTRAP:
1367 					peerversion |= RES_NOTRAP;
1368 					break;
1369 
1370 				    case CONF_RES_LPTRAP:
1371 					peerversion |= RES_LPTRAP;
1372 					break;
1373 
1374 				    case CONF_RES_NTPPORT:
1375 					peerkey |= RESM_NTPONLY;
1376 					break;
1377 
1378 				    case CONF_RES_VERSION:
1379 					peerversion |= RES_VERSION;
1380 					break;
1381 
1382 				    case CONF_RES_DEMOBILIZE:
1383 					peerversion |= RES_DEMOBILIZE;
1384 					break;
1385 
1386 				    case CONF_RES_LIMITED:
1387 					peerversion |= RES_LIMITED;
1388 					break;
1389 
1390 				    case CONFIG_UNKNOWN:
1391 					errflg++;
1392 					break;
1393 				}
1394 			}
1395 			if (SOCKNUL(&peeraddr))
1396 			    ANYSOCK(&maskaddr);
1397 			if (!errflg)
1398 			    hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
1399 					  (int)peerkey, peerversion);
1400 			break;
1401 
1402 		    case CONFIG_BDELAY:
1403 			if (ntokens >= 2) {
1404 				double tmp;
1405 
1406 				if (sscanf(tokens[1], "%lf", &tmp) != 1) {
1407 					msyslog(LOG_ERR,
1408 						"broadcastdelay value %s undecodable",
1409 						tokens[1]);
1410 				} else {
1411 					proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
1412 				}
1413 			}
1414 			break;
1415 
1416 		    case CONFIG_CDELAY:
1417                         if (ntokens >= 2) {
1418                                 u_long ui;
1419 
1420 				if (sscanf(tokens[1], "%ld", &ui) != 1)
1421 					msyslog(LOG_ERR,
1422 					    "illegal value - line ignored");
1423 				else
1424 					proto_config(PROTO_CALLDELAY, ui, 0, NULL);
1425 			}
1426 			break;
1427 
1428 		    case CONFIG_TRUSTEDKEY:
1429 			for (i = 1; i < ntokens; i++) {
1430 				keyid_t tkey;
1431 
1432 				tkey = atol(tokens[i]);
1433 				if (tkey == 0) {
1434 					msyslog(LOG_ERR,
1435 						"trusted key %s unlikely",
1436 						tokens[i]);
1437 				} else {
1438 					authtrust(tkey, 1);
1439 				}
1440 			}
1441 			break;
1442 
1443 		    case CONFIG_REQUESTKEY:
1444 			if (ntokens >= 2) {
1445 				if (!atouint(tokens[1], &ul)) {
1446 					msyslog(LOG_ERR,
1447 						"%s is undecodable as request key",
1448 						tokens[1]);
1449 				} else if (ul == 0) {
1450 					msyslog(LOG_ERR,
1451 						"%s makes a poor request keyid",
1452 						tokens[1]);
1453 				} else {
1454 #ifdef DEBUG
1455 					if (debug > 3)
1456 					    printf(
1457 						    "set info_auth_key to %08lx\n", ul);
1458 #endif
1459 					info_auth_keyid = (keyid_t)ul;
1460 				}
1461 			}
1462 			break;
1463 
1464 		    case CONFIG_CONTROLKEY:
1465 			if (ntokens >= 2) {
1466 				keyid_t ckey;
1467 
1468 				ckey = atol(tokens[1]);
1469 				if (ckey == 0) {
1470 					msyslog(LOG_ERR,
1471 						"%s makes a poor control keyid",
1472 						tokens[1]);
1473 				} else {
1474 					ctl_auth_keyid = ckey;
1475 				}
1476 			}
1477 			break;
1478 
1479 		    case CONFIG_TRAP:
1480 			if (ntokens < 2) {
1481 				msyslog(LOG_ERR,
1482 					"no address for trap command, line ignored");
1483 				break;
1484 			}
1485 			istart = 1;
1486 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1487 			peeraddr.ss_family = default_ai_family;
1488 			switch (matchkey(tokens[istart], addr_type, 0)) {
1489 			case CONF_ADDR_IPV4:
1490 				peeraddr.ss_family = AF_INET;
1491 				istart++;
1492 				break;
1493 			case CONF_ADDR_IPV6:
1494 				peeraddr.ss_family = AF_INET6;
1495 				istart++;
1496 				break;
1497 			}
1498 
1499 			if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1)
1500 			    break;
1501 
1502 			/*
1503 			 * Use peerversion for port number.  Barf.
1504 			 */
1505 			errflg = 0;
1506 			peerversion = 0;
1507 			localaddr = 0;
1508 			istart++;
1509 			for (i = istart; i < ntokens-1; i++)
1510 			    switch (matchkey(tokens[i], trap_keywords, 1)) {
1511 				case CONF_TRAP_PORT:
1512 				    if (i >= ntokens-1) {
1513 					    msyslog(LOG_ERR,
1514 						    "trap port requires an argument");
1515 					    errflg = 1;
1516 					    break;
1517 				    }
1518 				    peerversion = atoi(tokens[++i]);
1519 				    if (peerversion <= 0
1520 					|| peerversion > 32767) {
1521 					    msyslog(LOG_ERR,
1522 						    "invalid port number %s, trap ignored",
1523 						    tokens[i]);
1524 					    errflg = 1;
1525 				    }
1526 				    break;
1527 
1528 				case CONF_TRAP_INTERFACE:
1529 				    if (i >= ntokens-1) {
1530 					    msyslog(LOG_ERR,
1531 						    "trap interface requires an argument");
1532 					    errflg = 1;
1533 					    break;
1534 				    }
1535 
1536 				    memset((char *)&maskaddr, 0,
1537 					sizeof(maskaddr));
1538 				    maskaddr.ss_family = peeraddr.ss_family;
1539 				    if (getnetnum(tokens[++i],
1540 						   &maskaddr, 1, t_UNK) != 1) {
1541 					    errflg = 1;
1542 					    break;
1543 				    }
1544 
1545 				    localaddr = findinterface(&maskaddr);
1546 				    if (localaddr == NULL) {
1547 					    msyslog(LOG_ERR,
1548 						    "can't find interface with address %s",
1549 						    stoa(&maskaddr));
1550 					    errflg = 1;
1551 				    }
1552 				    break;
1553 
1554 				case CONFIG_UNKNOWN:
1555 				    errflg++;
1556 				    break;
1557 			    }
1558 
1559 			if (!errflg) {
1560 				if (peerversion != 0)
1561 				    ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion);
1562 				else
1563 				    ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);
1564 				if (localaddr == NULL)
1565 				    localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
1566 				if (!ctlsettrap(&peeraddr, localaddr, 0,
1567 						NTP_VERSION))
1568 				    msyslog(LOG_ERR,
1569 					    "can't set trap for %s, no resources",
1570 					    stoa(&peeraddr));
1571 			}
1572 			break;
1573 
1574 		    case CONFIG_FUDGE:
1575 			if (ntokens < 2) {
1576 				msyslog(LOG_ERR,
1577 					"no address for fudge command, line ignored");
1578 				break;
1579 			}
1580 			memset((char *)&peeraddr, 0, sizeof(peeraddr));
1581 			if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1)
1582 			    break;
1583 
1584 			if (!ISREFCLOCKADR(&peeraddr)) {
1585 				msyslog(LOG_ERR,
1586 					"%s is inappropriate address for the fudge command, line ignored",
1587 					stoa(&peeraddr));
1588 				break;
1589 			}
1590 
1591 			memset((void *)&clock_stat, 0, sizeof clock_stat);
1592 			fudgeflag = 0;
1593 			errflg = 0;
1594 			for (i = 2; i < ntokens-1; i++) {
1595 				switch (c = matchkey(tokens[i],
1596 				    fudge_keywords, 1)) {
1597 				    case CONF_FDG_TIME1:
1598 					if (sscanf(tokens[++i], "%lf",
1599 						   &clock_stat.fudgetime1) != 1) {
1600 						msyslog(LOG_ERR,
1601 							"fudge %s time1 value in error",
1602 							stoa(&peeraddr));
1603 						errflg = i;
1604 						break;
1605 					}
1606 					clock_stat.haveflags |= CLK_HAVETIME1;
1607 					break;
1608 
1609 				    case CONF_FDG_TIME2:
1610 					if (sscanf(tokens[++i], "%lf",
1611 						   &clock_stat.fudgetime2) != 1) {
1612 						msyslog(LOG_ERR,
1613 							"fudge %s time2 value in error",
1614 							stoa(&peeraddr));
1615 						errflg = i;
1616 						break;
1617 					}
1618 					clock_stat.haveflags |= CLK_HAVETIME2;
1619 					break;
1620 
1621 
1622 				    case CONF_FDG_STRATUM:
1623 				      if (!atoint(tokens[++i], &stratum))
1624 					{
1625 						msyslog(LOG_ERR,
1626 							"fudge %s stratum value in error",
1627 							stoa(&peeraddr));
1628 						errflg = i;
1629 						break;
1630 					}
1631 					clock_stat.fudgeval1 = stratum;
1632 					clock_stat.haveflags |= CLK_HAVEVAL1;
1633 					break;
1634 
1635 				    case CONF_FDG_REFID:
1636 					i++;
1637 					memcpy(&clock_stat.fudgeval2,
1638 					    tokens[i], min(strlen(tokens[i]),
1639 					    4));
1640 					clock_stat.haveflags |= CLK_HAVEVAL2;
1641 					break;
1642 
1643 				    case CONF_FDG_FLAG1:
1644 				    case CONF_FDG_FLAG2:
1645 				    case CONF_FDG_FLAG3:
1646 				    case CONF_FDG_FLAG4:
1647 					if (!atouint(tokens[++i], &fudgeflag)
1648 					    || fudgeflag > 1) {
1649 						msyslog(LOG_ERR,
1650 							"fudge %s flag value in error",
1651 							stoa(&peeraddr));
1652 						errflg = i;
1653 						break;
1654 					}
1655 					switch(c) {
1656 					    case CONF_FDG_FLAG1:
1657 						c = CLK_FLAG1;
1658 						clock_stat.haveflags|=CLK_HAVEFLAG1;
1659 						break;
1660 					    case CONF_FDG_FLAG2:
1661 						c = CLK_FLAG2;
1662 						clock_stat.haveflags|=CLK_HAVEFLAG2;
1663 						break;
1664 					    case CONF_FDG_FLAG3:
1665 						c = CLK_FLAG3;
1666 						clock_stat.haveflags|=CLK_HAVEFLAG3;
1667 						break;
1668 					    case CONF_FDG_FLAG4:
1669 						c = CLK_FLAG4;
1670 						clock_stat.haveflags|=CLK_HAVEFLAG4;
1671 						break;
1672 					}
1673 					if (fudgeflag == 0)
1674 					    clock_stat.flags &= ~c;
1675 					else
1676 					    clock_stat.flags |= c;
1677 					break;
1678 
1679 				    case CONFIG_UNKNOWN:
1680 					errflg = -1;
1681 					break;
1682 				}
1683 			}
1684 
1685 #ifdef REFCLOCK
1686 			/*
1687 			 * If reference clock support isn't defined the
1688 			 * fudge line will still be accepted and syntax
1689 			 * checked, but will essentially do nothing.
1690 			 */
1691 			if (!errflg) {
1692 				refclock_control(&peeraddr, &clock_stat,
1693 				    (struct refclockstat *)0);
1694 			}
1695 #endif
1696 			break;
1697 
1698 		    case CONFIG_STATSDIR:
1699 			if (ntokens >= 2)
1700 				stats_config(STATS_STATSDIR,tokens[1]);
1701 			break;
1702 
1703 		    case CONFIG_STATISTICS:
1704 			for (i = 1; i < ntokens; i++) {
1705 				filegen = filegen_get(tokens[i]);
1706 
1707 				if (filegen == NULL) {
1708 					msyslog(LOG_ERR,
1709 						"no statistics named %s available",
1710 						tokens[i]);
1711 					continue;
1712 				}
1713 #ifdef DEBUG
1714 				if (debug > 3)
1715 				    printf("enabling filegen for %s statistics \"%s%s\"\n",
1716 					   tokens[i], filegen->prefix, filegen->basename);
1717 #endif
1718 				filegen->flag |= FGEN_FLAG_ENABLED;
1719 			}
1720 			break;
1721 
1722 		    case CONFIG_FILEGEN:
1723 			if (ntokens < 2) {
1724 				msyslog(LOG_ERR,
1725 					"no id for filegen command, line ignored");
1726 				break;
1727 			}
1728 
1729 			filegen = filegen_get(tokens[1]);
1730 			if (filegen == NULL) {
1731 				msyslog(LOG_ERR,
1732 					"unknown filegen \"%s\" ignored",
1733 					tokens[1]);
1734 				break;
1735 			}
1736 			/*
1737 			 * peerversion is (ab)used for filegen file (index)
1738 			 * peerkey	   is (ab)used for filegen type
1739 			 * peerflags   is (ab)used for filegen flags
1740 			 */
1741 			peerversion = 0;
1742 			peerkey =	  filegen->type;
1743 			peerflags =   filegen->flag;
1744 			errflg = 0;
1745 
1746 			for (i = 2; i < ntokens; i++) {
1747 				switch (matchkey(tokens[i],
1748 				    filegen_keywords, 1)) {
1749 				    case CONF_FGEN_FILE:
1750 					if (i >= ntokens - 1) {
1751 						msyslog(LOG_ERR,
1752 							"filegen %s file requires argument",
1753 							tokens[1]);
1754 						errflg = i;
1755 						break;
1756 					}
1757 					peerversion = ++i;
1758 					break;
1759 				    case CONF_FGEN_TYPE:
1760 					if (i >= ntokens -1) {
1761 						msyslog(LOG_ERR,
1762 							"filegen %s type requires argument",
1763 							tokens[1]);
1764 						errflg = i;
1765 						break;
1766 					}
1767 					peerkey = matchkey(tokens[++i],
1768 					    fgen_types, 1);
1769 					if (peerkey == CONFIG_UNKNOWN) {
1770 						msyslog(LOG_ERR,
1771 							"filegen %s unknown type \"%s\"",
1772 							tokens[1], tokens[i]);
1773 						errflg = i;
1774 						break;
1775 					}
1776 					break;
1777 
1778 				    case CONF_FGEN_FLAG_LINK:
1779 					peerflags |= FGEN_FLAG_LINK;
1780 					break;
1781 
1782 				    case CONF_FGEN_FLAG_NOLINK:
1783 					peerflags &= ~FGEN_FLAG_LINK;
1784 					break;
1785 
1786 				    case CONF_FGEN_FLAG_ENABLE:
1787 					peerflags |= FGEN_FLAG_ENABLED;
1788 					break;
1789 
1790 				    case CONF_FGEN_FLAG_DISABLE:
1791 					peerflags &= ~FGEN_FLAG_ENABLED;
1792 					break;
1793 				}
1794 			}
1795 			if (!errflg)
1796 				filegen_config(filegen, tokens[peerversion],
1797 			           (u_char)peerkey, (u_char)peerflags);
1798 			break;
1799 
1800 		    case CONFIG_SETVAR:
1801 			if (ntokens < 2) {
1802 				msyslog(LOG_ERR,
1803 					"no value for setvar command - line ignored");
1804 			} else {
1805 				set_sys_var(tokens[1], strlen(tokens[1])+1,
1806 					    (u_short) (RW |
1807 					    ((((ntokens > 2)
1808 					       && !strcmp(tokens[2],
1809 							  "default")))
1810 					     ? DEF
1811 					     : 0)));
1812 			}
1813 			break;
1814 
1815 		    case CONFIG_ENABLE:
1816 			for (i = 1; i < ntokens; i++) {
1817 				int flag;
1818 
1819 				flag = matchkey(tokens[i], flags_keywords, 1);
1820 				if (flag == CONFIG_UNKNOWN) {
1821 					msyslog(LOG_ERR,
1822 						"enable unknown flag %s",
1823 						tokens[i]);
1824 					errflg = 1;
1825 					break;
1826 				}
1827 				proto_config(flag, 1, 0., NULL);
1828 			}
1829 			break;
1830 
1831 		    case CONFIG_DISABLE:
1832 			for (i = 1; i < ntokens; i++) {
1833 				int flag;
1834 
1835 				flag = matchkey(tokens[i], flags_keywords, 1);
1836 				if (flag == CONFIG_UNKNOWN) {
1837 					msyslog(LOG_ERR,
1838 						"disable unknown flag %s",
1839 						tokens[i]);
1840 					errflg = 1;
1841 					break;
1842 				}
1843 				proto_config(flag, 0, 0., NULL);
1844 			}
1845 			break;
1846 
1847 		    case CONFIG_PHONE:
1848 			for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) {
1849 				sys_phone[i - 1] =
1850 				    emalloc(strlen(tokens[i]) + 1);
1851 				strcpy(sys_phone[i - 1], tokens[i]);
1852 			}
1853 			sys_phone[i] = NULL;
1854 			break;
1855 
1856 		    case CONFIG_ADJ: {
1857 			    double ftemp;
1858 
1859 			    sscanf(tokens[1], "%lf", &ftemp);
1860 			    proto_config(PROTO_ADJ, 0, ftemp, NULL);
1861 			}
1862 			break;
1863 
1864 		}
1865 	}
1866 	if (fp[0])
1867 		(void)fclose(fp[0]);
1868 
1869 #ifdef HAVE_NETINFO
1870 	if (config_netinfo)
1871 		free_netinfo_config(config_netinfo);
1872 #endif /* HAVE_NETINFO */
1873 
1874 #if !defined(VMS) && !defined(SYS_VXWORKS)
1875 	/* find a keyid */
1876 	if (info_auth_keyid == 0)
1877 		req_keyid = 65535;
1878 	else
1879 		req_keyid = info_auth_keyid;
1880 
1881 	/* if doesn't exist, make up one at random */
1882 	if (!authhavekey(req_keyid)) {
1883 		char rankey[9];
1884 		int j;
1885 
1886 		for (i = 0; i < 8; i++)
1887 			for (j = 1; j < 100; ++j) {
1888 				rankey[i] = (char) (ntp_random() & 0xff);
1889 				if (rankey[i] != 0) break;
1890 			}
1891 		rankey[8] = 0;
1892 		authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
1893 		authtrust(req_keyid, 1);
1894 		if (!authhavekey(req_keyid)) {
1895 			msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
1896 			/* HMS: Should this be fatal? */
1897 		}
1898 	}
1899 
1900 	/* save keyid so we will accept config requests with it */
1901 	info_auth_keyid = req_keyid;
1902 #endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
1903 
1904 	if (res_fp != NULL) {
1905 		if (call_resolver) {
1906 			/*
1907 			 * Need name resolution
1908 			 */
1909 			do_resolve_internal();
1910 		}
1911 	}
1912 }
1913 
1914 
1915 #ifdef HAVE_NETINFO
1916 
1917 /*
1918  * get_netinfo_config - find the nearest NetInfo domain with an ntp
1919  * configuration and initialize the configuration state.
1920  */
1921 static struct netinfo_config_state *
1922 get_netinfo_config()
1923 {
1924 	ni_status status;
1925 	void *domain;
1926 	ni_id config_dir;
1927        	struct netinfo_config_state *config;
1928 
1929 	if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
1930 
1931 	while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
1932 		void *next_domain;
1933 		if (ni_open(domain, "..", &next_domain) != NI_OK) {
1934 			ni_free(next_domain);
1935 			break;
1936 		}
1937 		ni_free(domain);
1938 		domain = next_domain;
1939 	}
1940 	if (status != NI_OK) {
1941 		ni_free(domain);
1942 		return NULL;
1943 	}
1944 
1945        	config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
1946        	config->domain = domain;
1947        	config->config_dir = config_dir;
1948        	config->prop_index = 0;
1949        	config->val_index = 0;
1950        	config->val_list = NULL;
1951 
1952 	return config;
1953 }
1954 
1955 
1956 
1957 /*
1958  * free_netinfo_config - release NetInfo configuration state
1959  */
1960 static void
1961 free_netinfo_config(struct netinfo_config_state *config)
1962 {
1963 	ni_free(config->domain);
1964 	free(config);
1965 }
1966 
1967 
1968 
1969 /*
1970  * gettokens_netinfo - return tokens from NetInfo
1971  */
1972 static int
1973 gettokens_netinfo (
1974 	struct netinfo_config_state *config,
1975 	char **tokenlist,
1976 	int *ntokens
1977 	)
1978 {
1979 	int prop_index = config->prop_index;
1980 	int val_index = config->val_index;
1981 	char **val_list = config->val_list;
1982 
1983 	/*
1984 	 * Iterate through each keyword and look for a property that matches it.
1985 	 */
1986 	again:
1987 	if (!val_list) {
1988 	       	for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
1989 	       	{
1990 		       	ni_namelist namelist;
1991 			struct keyword current_prop = keywords[prop_index];
1992 
1993 			/*
1994 			 * For each value associated in the property, we're going to return
1995 			 * a separate line. We squirrel away the values in the config state
1996 			 * so the next time through, we don't need to do this lookup.
1997 			 */
1998 		       	NI_INIT(&namelist);
1999 	       		if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
2000 				ni_index index;
2001 
2002 				/* Found the property, but it has no values */
2003 				if (namelist.ni_namelist_len == 0) continue;
2004 
2005 				if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
2006 					{ msyslog(LOG_ERR, "out of memory while configuring"); break; }
2007 
2008 				for (index = 0; index < namelist.ni_namelist_len; index++) {
2009 					char *value = namelist.ni_namelist_val[index];
2010 
2011 					if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
2012 						{ msyslog(LOG_ERR, "out of memory while configuring"); break; }
2013 
2014 					strcpy(val_list[index], value);
2015 				}
2016 				val_list[index] = NULL;
2017 
2018 				break;
2019 			}
2020 			ni_namelist_free(&namelist);
2021 		}
2022 		config->prop_index = prop_index;
2023 	}
2024 
2025 	/* No list; we're done here. */
2026        	if (!val_list) return CONFIG_UNKNOWN;
2027 
2028 	/*
2029 	 * We have a list of values for the current property.
2030 	 * Iterate through them and return each in order.
2031 	 */
2032 	if (val_list[val_index])
2033 	{
2034 		int ntok = 1;
2035 		int quoted = 0;
2036 		char *tokens = val_list[val_index];
2037 
2038 		msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
2039 
2040 		(const char*)tokenlist[0] = keywords[prop_index].text;
2041 		for (ntok = 1; ntok < MAXTOKENS; ntok++) {
2042 			tokenlist[ntok] = tokens;
2043 			while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
2044 				quoted ^= (*tokens++ == '"');
2045 
2046 			if (ISEOL(*tokens)) {
2047 				*tokens = '\0';
2048 				break;
2049 			} else {		/* must be space */
2050 				*tokens++ = '\0';
2051 				while (ISSPACE(*tokens)) tokens++;
2052 				if (ISEOL(*tokens)) break;
2053 			}
2054 		}
2055 
2056 		if (ntok == MAXTOKENS) {
2057 			/* HMS: chomp it to lose the EOL? */
2058 			msyslog(LOG_ERR,
2059 			    "gettokens_netinfo: too many tokens.  Ignoring: %s",
2060 			    tokens);
2061 		} else {
2062 			*ntokens = ntok + 1;
2063 		}
2064 
2065 		config->val_index++;	/* HMS: Should this be in the 'else'? */
2066 
2067 		return keywords[prop_index].keytype;
2068 	}
2069 
2070 	/* We're done with the current property. */
2071 	prop_index = ++config->prop_index;
2072 
2073 	/* Free val_list and reset counters. */
2074 	for (val_index = 0; val_list[val_index]; val_index++)
2075 		free(val_list[val_index]);
2076        	free(val_list);	val_list = config->val_list = NULL; val_index = config->val_index = 0;
2077 
2078 	goto again;
2079 }
2080 
2081 #endif /* HAVE_NETINFO */
2082 
2083 
2084 /*
2085  * gettokens - read a line and return tokens
2086  */
2087 static int
2088 gettokens (
2089 	FILE *fp,
2090 	char *line,
2091 	char **tokenlist,
2092 	int *ntokens
2093 	)
2094 {
2095 	register char *cp;
2096 	register int ntok;
2097 	register int quoted = 0;
2098 
2099 	/*
2100 	 * Find start of first token
2101 	 */
2102 	again:
2103 	while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
2104 		cp = line;
2105 		while (ISSPACE(*cp))
2106 			cp++;
2107 		if (!ISEOL(*cp))
2108 			break;
2109 	}
2110 	if (cp == NULL) {
2111 		*ntokens = 0;
2112 		return CONFIG_UNKNOWN;	/* hack.  Is recognized as EOF */
2113 	}
2114 
2115 	/*
2116 	 * Now separate out the tokens
2117 	 */
2118 	for (ntok = 0; ntok < MAXTOKENS; ntok++) {
2119 		tokenlist[ntok] = cp;
2120 		while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
2121 			quoted ^= (*cp++ == '"');
2122 
2123 		if (ISEOL(*cp)) {
2124 			*cp = '\0';
2125 			break;
2126 		} else {		/* must be space */
2127 			*cp++ = '\0';
2128 			while (ISSPACE(*cp))
2129 				cp++;
2130 			if (ISEOL(*cp))
2131 				break;
2132 		}
2133 	}
2134 
2135      /* Heiko: Remove leading and trailing quotes around tokens */
2136      {
2137             int i,j = 0;
2138 
2139 
2140 			for (i = 0; i < ntok; i++) {
2141 					/* Now check if the first char is a quote and remove that */
2142 					if ( tokenlist[ntok][0] == '"' )
2143 							tokenlist[ntok]++;
2144 
2145 					/* Now check the last char ... */
2146 					j = strlen(tokenlist[ntok])-1;
2147 					if ( tokenlist[ntok][j] == '"' )
2148 							tokenlist[ntok][j] = '\0';
2149 			}
2150 
2151     }
2152 
2153 	if (ntok == MAXTOKENS) {
2154 		--ntok;
2155 		/* HMS: chomp it to lose the EOL? */
2156 		msyslog(LOG_ERR,
2157 		    "gettokens: too many tokens on the line. Ignoring %s",
2158 		    cp);
2159 	} else {
2160 		/*
2161 		 * Return the match
2162 		 */
2163 		*ntokens = ntok + 1;
2164 		ntok = matchkey(tokenlist[0], keywords, 1);
2165 		if (ntok == CONFIG_UNKNOWN)
2166 			goto again;
2167 	}
2168 
2169 	return ntok;
2170 }
2171 
2172 
2173 
2174 /*
2175  * matchkey - match a keyword to a list
2176  */
2177 static int
2178 matchkey(
2179 	register char *word,
2180 	register struct keyword *keys,
2181 	int complain
2182 	)
2183 {
2184 	for (;;) {
2185 		if (keys->keytype == CONFIG_UNKNOWN) {
2186 			if (complain)
2187 				msyslog(LOG_ERR,
2188 				    "configure: keyword \"%s\" unknown, line ignored",
2189 				    word);
2190 			return CONFIG_UNKNOWN;
2191 		}
2192 		if (STRSAME(word, keys->text))
2193 			return keys->keytype;
2194 		keys++;
2195 	}
2196 }
2197 
2198 
2199 /*
2200  * getnetnum - return a net number (this is crude, but careful)
2201  */
2202 static int
2203 getnetnum(
2204 	const char *num,
2205 	struct sockaddr_storage *addr,
2206 	int complain,
2207 	enum gnn_type a_type
2208 	)
2209 {
2210 	struct addrinfo hints;
2211 	struct addrinfo *ptr;
2212 	int retval;
2213 
2214 #if 0
2215 	printf("getnetnum: <%s> is a %s (%d)\n",
2216 		num,
2217 		(a_type == t_UNK)
2218 		? "t_UNK"
2219 		: (a_type == t_REF)
2220 		  ? "t_REF"
2221 		  : (a_type == t_MSK)
2222 		    ? "t_MSK"
2223 		    : "???",
2224 		a_type);
2225 #endif
2226 
2227 	/* Get host address. Looking for UDP datagram connection */
2228  	memset(&hints, 0, sizeof (hints));
2229  	if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
2230 	    hints.ai_family = addr->ss_family;
2231 	else
2232 	    hints.ai_family = AF_UNSPEC;
2233 	/*
2234 	 * If we don't have an IPv6 stack, just look up IPv4 addresses
2235 	 */
2236 	if (isc_net_probeipv6() != ISC_R_SUCCESS)
2237 		hints.ai_family = AF_INET;
2238 
2239 	hints.ai_socktype = SOCK_DGRAM;
2240 
2241 	if (a_type != t_UNK) {
2242 		hints.ai_flags = AI_NUMERICHOST;
2243 	}
2244 
2245 #ifdef DEBUG
2246 	if (debug > 3)
2247 		printf("getnetnum: calling getaddrinfo(%s,...)\n", num);
2248 #endif
2249 	retval = getaddrinfo(num, "ntp", &hints, &ptr);
2250 	if (retval != 0 ||
2251 	   (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
2252 		if (complain)
2253 			msyslog(LOG_ERR,
2254 				"getaddrinfo: \"%s\" invalid host address, ignored",
2255 				num);
2256 #ifdef DEBUG
2257 		if (debug > 0)
2258 			printf(
2259 				"getaddrinfo: \"%s\" invalid host address%s.\n",
2260 				num, (complain)
2261 				? ", ignored"
2262 				: "");
2263 #endif
2264 		if (retval == 0 &&
2265 		    ptr->ai_family == AF_INET6 &&
2266 		    isc_net_probeipv6() != ISC_R_SUCCESS)
2267 		{
2268 			return -1;
2269 		}
2270 		else {
2271 			return 0;
2272 		}
2273 	}
2274 
2275 	memcpy(addr, ptr->ai_addr, ptr->ai_addrlen);
2276 #ifdef DEBUG
2277 	if (debug > 1)
2278 		printf("getnetnum given %s, got %s (%s/%d)\n",
2279 		   num, stoa(addr),
2280 			(a_type == t_UNK)
2281 			? "t_UNK"
2282 			: (a_type == t_REF)
2283 			  ? "t_REF"
2284 			  : (a_type == t_MSK)
2285 			    ? "t_MSK"
2286 			    : "???",
2287 			a_type);
2288 #endif
2289         freeaddrinfo(ptr);
2290 	return 1;
2291 }
2292 
2293 
2294 #if !defined(VMS) && !defined(SYS_WINNT)
2295 /*
2296  * catchchild - receive the resolver's exit status
2297  */
2298 static RETSIGTYPE
2299 catchchild(
2300 	int sig
2301 	)
2302 {
2303 	/*
2304 	 * We only start up one child, and if we're here
2305 	 * it should have already exited.  Hence the following
2306 	 * shouldn't hang.  If it does, please tell me.
2307 	 */
2308 #if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
2309 	(void) wait(0);
2310 #endif /* SYS_WINNT  && VXWORKS*/
2311 }
2312 #endif /* VMS */
2313 
2314 
2315 /*
2316  * save_resolve - save configuration info into a file for later name resolution
2317  */
2318 static void
2319 save_resolve(
2320 	char *name,
2321 	int mode,
2322 	int version,
2323 	int minpoll,
2324 	int maxpoll,
2325 	u_int flags,
2326 	int ttl,
2327 	keyid_t keyid,
2328 	u_char *keystr,
2329 	u_char peeraf
2330 	)
2331 {
2332 #ifndef SYS_VXWORKS
2333 	if (res_fp == NULL) {
2334 #ifndef SYS_WINNT
2335 		(void) strcpy(res_file, RES_TEMPFILE);
2336 #else
2337 		/* no /tmp directory under NT */
2338 		{
2339 			if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
2340 				msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
2341 				return;
2342 			}
2343 			(void) strcat(res_file, "ntpdXXXXXX");
2344 		}
2345 #endif /* SYS_WINNT */
2346 #ifdef HAVE_MKSTEMP
2347 		{
2348 			int fd;
2349 
2350 			res_fp = NULL;
2351 			if ((fd = mkstemp(res_file)) != -1)
2352 				res_fp = fdopen(fd, "r+");
2353 		}
2354 #else
2355 		(void) mktemp(res_file);
2356 		res_fp = fopen(res_file, "w");
2357 #endif
2358 		if (res_fp == NULL) {
2359 			msyslog(LOG_ERR, "open failed for %s: %m", res_file);
2360 			return;
2361 		}
2362 	}
2363 #ifdef DEBUG
2364 	if (debug) {
2365 		printf("resolving %s\n", name);
2366 	}
2367 #endif
2368 
2369 	(void)fprintf(res_fp, "%s %u %d %d %d %d %d %d %u %s\n", name, peeraf,
2370 	    mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2371 #ifdef DEBUG
2372 	if (debug > 1)
2373 		printf("config: %s %u %d %d %d %d %x %d %u %s\n", name, peeraf, mode,
2374 		    version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2375 #endif
2376 
2377 #else  /* SYS_VXWORKS */
2378 	/* save resolve info to a struct */
2379 #endif /* SYS_VXWORKS */
2380 }
2381 
2382 
2383 /*
2384  * abort_resolve - terminate the resolver stuff and delete the file
2385  */
2386 static void
2387 abort_resolve(void)
2388 {
2389 	/*
2390 	 * In an ideal world we would might reread the file and
2391 	 * log the hosts which aren't getting configured.  Since
2392 	 * this is too much work, however, just close and delete
2393 	 * the temp file.
2394 	 */
2395 	if (res_fp != NULL)
2396 		(void) fclose(res_fp);
2397 	res_fp = NULL;
2398 
2399 #ifndef SYS_VXWORKS		/* we don't open the file to begin with */
2400 #if !defined(VMS)
2401 	(void) unlink(res_file);
2402 #else
2403 	(void) delete(res_file);
2404 #endif /* VMS */
2405 #endif /* SYS_VXWORKS */
2406 }
2407 
2408 
2409 /*
2410  * do_resolve_internal - start up the resolver function (not program)
2411  */
2412 /*
2413  * On VMS, this routine will simply refuse to resolve anything.
2414  *
2415  * Possible implementation: keep `res_file' in memory, do async
2416  * name resolution via QIO, update from within completion AST.
2417  * I'm unlikely to find the time for doing this, though. -wjm
2418  */
2419 static void
2420 do_resolve_internal(void)
2421 {
2422 	int i;
2423 
2424 	if (res_fp == NULL) {
2425 		/* belch */
2426 		msyslog(LOG_ERR,
2427 			"do_resolve_internal: Fatal: res_fp == NULL");
2428 		exit(1);
2429 	}
2430 
2431 	/* we are done with this now */
2432 	(void) fclose(res_fp);
2433 	res_fp = NULL;
2434 
2435 #if !defined(VMS) && !defined (SYS_VXWORKS)
2436 	req_file = res_file;	/* set up pointer to res file */
2437 #ifndef SYS_WINNT
2438 	(void) signal_no_reset(SIGCHLD, catchchild);
2439 
2440 #ifndef SYS_VXWORKS
2441 	/* the parent process will write to the pipe
2442 	 * in order to wake up to child process
2443 	 * which may be waiting in a select() call
2444 	 * on the read fd */
2445 	if (pipe(resolver_pipe_fd) < 0) {
2446 		msyslog(LOG_ERR,
2447 			"unable to open resolver pipe");
2448 		exit(1);
2449 	}
2450 
2451 	i = fork();
2452 	/* Shouldn't the code below be re-ordered?
2453 	 * I.e. first check if the fork() returned an error, then
2454 	 * check whether we're parent or child.
2455 	 *     Martin Burnicki
2456 	 */
2457 	if (i == 0) {
2458 		/*
2459 		 * this used to close everything
2460 		 * I don't think this is necessary
2461 		 */
2462 		/*
2463 		 * To the unknown commenter above:
2464 		 * Well, I think it's better to clean up
2465 		 * after oneself. I have had problems with
2466 		 * refclock-io when intres was running - things
2467 		 * where fine again when ntpintres was gone.
2468 		 * So some systems react erratic at least.
2469 		 *
2470 		 *			Frank Kardel
2471 		 *
2472 		 * 94-11-16:
2473 		 * Further debugging has proven that the above is
2474 		 * absolutely harmful. The internal resolver
2475 		 * is still in the SIGIO process group and the lingering
2476 		 * async io information causes it to process requests from
2477 		 * all file decriptor causing a race between the NTP daemon
2478 		 * and the resolver. which then eats data when it wins 8-(.
2479 		 * It is absolutly necessary to kill any IO associations
2480 		 * shared with the NTP daemon.
2481 		 *
2482 		 * We also block SIGIO (currently no ports means to
2483 		 * disable the signal handle for IO).
2484 		 *
2485 		 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
2486 		 * that it is the ntp-resolver child running into trouble.
2487 		 *
2488 		 * THUS:
2489 		 */
2490 
2491 		/* This is the child process who will read the pipe,
2492 		 * so we close the write fd */
2493 		close(resolver_pipe_fd[1]);
2494 		closelog();
2495 		kill_asyncio(0);
2496 
2497 		(void) signal_no_reset(SIGCHLD, SIG_DFL);
2498 
2499 #ifdef DEBUG
2500 		if (0)
2501 		    debug = 2;
2502 #endif
2503 
2504 # ifndef LOG_DAEMON
2505 		openlog("ntpd_initres", LOG_PID);
2506 # else /* LOG_DAEMON */
2507 
2508 #  ifndef LOG_NTP
2509 #   define	LOG_NTP LOG_DAEMON
2510 #  endif
2511 		openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
2512 #ifndef SYS_CYGWIN32
2513 #  ifdef DEBUG
2514 		if (debug)
2515 		    setlogmask(LOG_UPTO(LOG_DEBUG));
2516 		else
2517 #  endif /* DEBUG */
2518 		    setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
2519 # endif /* LOG_DAEMON */
2520 #endif
2521 
2522 		ntp_intres();
2523 
2524 		/*
2525 		 * If we got here, the intres code screwed up.
2526 		 * Print something so we don't die without complaint
2527 		 */
2528 		msyslog(LOG_ERR, "call to ntp_intres lost");
2529 		abort_resolve();
2530 		exit(1);
2531 	}
2532 #else
2533 	 /* vxWorks spawns a thread... -casey */
2534 	 i = sp (ntp_intres);
2535 	 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
2536 #endif
2537 	if (i == -1) {
2538 		msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
2539 		(void) signal_no_reset(SIGCHLD, SIG_DFL);
2540 		abort_resolve();
2541 	}
2542 	else {
2543 		/* This is the parent process who will write to the pipe,
2544 		 * so we close the read fd */
2545 		close(resolver_pipe_fd[0]);
2546 	}
2547 #else /* SYS_WINNT */
2548 	{
2549 		/* NT's equivalent of fork() is _spawn(), but the start point
2550 		 * of the new process is an executable filename rather than
2551 		 * a function name as desired here.
2552 		 */
2553 		DWORD dwThreadId;
2554 		fflush(stdout);
2555 		ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
2556 		if (ResolverEventHandle == NULL) {
2557 			msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
2558 			abort_resolve();
2559 		}
2560 		ResolverThreadHandle = CreateThread(
2561 			NULL,				 /* no security attributes	*/
2562 			0,				 /* use default stack size	*/
2563 			(LPTHREAD_START_ROUTINE) ntp_intres, /* thread function		*/
2564 			NULL,				 /* argument to thread function   */
2565 			0,				 /* use default creation flags	  */
2566 			&dwThreadId);			 /* returns the thread identifier */
2567 		if (ResolverThreadHandle == NULL) {
2568 			msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
2569 			CloseHandle(ResolverEventHandle);
2570 			ResolverEventHandle = NULL;
2571 			abort_resolve();
2572 		}
2573 	}
2574 #endif /* SYS_WINNT */
2575 #else /* VMS  VX_WORKS */
2576 	msyslog(LOG_ERR,
2577 		"Name resolution not implemented for VMS - use numeric addresses");
2578 	abort_resolve();
2579 #endif /* VMS VX_WORKS */
2580 }
2581