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