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