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