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