xref: /freebsd/contrib/ntp/ntpd/ntp_config.c (revision c0b746e5e8d9479f05b3749cbf1f73b8928719bd)
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>
37 extern 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  */
181 struct keyword {
182 	const char *text;
183 	int keytype;
184 };
185 
186 /*
187  * Command keywords
188  */
189 static	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  */
228 static	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  */
245 static	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  */
263 static	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  */
273 static	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  */
289 static	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  */
302 static	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  */
316 static 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  */
329 static 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  */
339 struct masks {
340 	const char	  *name;
341 	unsigned long mask;
342 };
343 
344 static 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 
352 static 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  */
391 static FILE *res_fp;
392 #ifndef SYS_WINNT
393 static char res_file[20];	/* enough for /tmp/ntpXXXXXX\0 */
394 #define RES_TEMPFILE	"/tmp/ntpXXXXXX"
395 #else
396 static char res_file[MAX_PATH];
397 #endif /* SYS_WINNT */
398 
399 /*
400  * Definitions of things either imported from or exported to outside
401  */
402 char const *progname;
403 char	sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */
404 char	pps_device[MAXPPS + 1]; /* PPS device name */
405 int	pps_assert = 1;
406 int	pps_hardpps;
407 int	listen_to_virtual_ips = 0;
408 #if defined(HAVE_SCHED_SETSCHEDULER)
409 int	config_priority_override = 0;
410 int	config_priority;
411 #endif
412 
413 static 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  */
419 struct 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  */
431 static	unsigned long get_pfxmatch P((char **, struct masks *));
432 static	unsigned long get_match P((char *, struct masks *));
433 static	unsigned long get_logmask P((char *));
434 #ifdef HAVE_NETINFO
435 static	struct netinfo_config_state *get_netinfo_config P((void));
436 static	void free_netinfo_config P((struct netinfo_config_state *));
437 static	int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
438 #endif
439 static	int gettokens P((FILE *, char *, char **, int *));
440 static	int matchkey P((char *, struct keyword *));
441 static	int getnetnum P((const char *, struct sockaddr_in *, int));
442 static	void save_resolve P((char *, int, int, int, int, int, int, u_long));
443 static	void do_resolve_internal P((void));
444 static	void abort_resolve P((void));
445 #if !defined(VMS)
446 static	RETSIGTYPE catchchild P((int));
447 #endif /* VMS */
448 
449 /*
450  * get_pfxmatch - find value for prefixmatch
451  * and update char * accordingly
452  */
453 static unsigned long
454 get_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  */
473 static unsigned long
474 get_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  */
492 static unsigned long
493 get_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  */
516 void
517 getstartup(
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  */
630 void
631 getconfig(
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  */
1820 static struct netinfo_config_state *
1821 get_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  */
1859 static void
1860 free_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  */
1871 static int
1872 gettokens_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  */
1978 static int
1979 gettokens (
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  */
2041 static int
2042 matchkey(
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  */
2064 static int
2065 getnetnum(
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  */
2141 static RETSIGTYPE
2142 catchchild(
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  */
2161 static void
2162 save_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  */
2222 static void
2223 abort_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  */
2257 static void
2258 do_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