ntp_config.c revision 106163
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>
42extern HANDLE ResolverThreadHandle;
43#endif /* SYS_WINNT */
44
45extern 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 */
94struct keyword {
95	const char *text;
96	int keytype;
97};
98
99/*
100 * Command keywords
101 */
102static	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 */
149static	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 */
170static	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 */
190static	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 */
199static	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 */
215static	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 */
228static	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 */
242static 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 */
257static 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 */
267static 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 */
282static 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 */
295struct masks {
296	const char	  *name;
297	unsigned long mask;
298};
299
300static 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
308static 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 */
348static FILE *res_fp;
349#ifndef SYS_WINNT
350static char res_file[20];	/* enough for /tmp/ntpXXXXXX\0 */
351#define RES_TEMPFILE	"/tmp/ntpXXXXXX"
352#else
353static char res_file[MAX_PATH];
354#endif /* SYS_WINNT */
355
356/*
357 * Definitions of things either imported from or exported to outside
358 */
359char const *progname;
360char	sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */
361char	pps_device[MAXPPS + 1]; /* PPS device name */
362int	pps_assert;
363int	pps_hardpps;
364#if defined(HAVE_SCHED_SETSCHEDULER)
365int	config_priority_override = 0;
366int	config_priority;
367#endif
368
369const 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 */
385struct 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 */
397static	unsigned long get_pfxmatch P((char **, struct masks *));
398static	unsigned long get_match P((char *, struct masks *));
399static	unsigned long get_logmask P((char *));
400#ifdef HAVE_NETINFO
401static	struct netinfo_config_state *get_netinfo_config P((void));
402static	void free_netinfo_config P((struct netinfo_config_state *));
403static	int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
404#endif
405static	int gettokens P((FILE *, char *, char **, int *));
406static	int matchkey P((char *, struct keyword *));
407static	int getnetnum P((const char *, struct sockaddr_in *, int));
408static	void save_resolve P((char *, int, int, int, int, u_int, int,
409    keyid_t, u_char *));
410static	void do_resolve_internal P((void));
411static	void abort_resolve P((void));
412#if !defined(VMS)
413static	RETSIGTYPE catchchild P((int));
414#endif /* VMS */
415
416/*
417 * get_pfxmatch - find value for prefixmatch
418 * and update char * accordingly
419 */
420static unsigned long
421get_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 */
440static unsigned long
441get_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 */
459static unsigned long
460get_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 */
484void
485getconfig(
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 */
1714static struct netinfo_config_state *
1715get_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 */
1753static void
1754free_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 */
1765static int
1766gettokens_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 */
1872static int
1873gettokens (
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 */
1935static int
1936matchkey(
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 */
1958static int
1959getnetnum(
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 */
2035static RETSIGTYPE
2036catchchild(
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 */
2055static void
2056save_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 */
2123static void
2124abort_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 */
2156static void
2157do_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