Obfuscate RCS ID matching so that CVS doesn't expand it.
[netbsd-mini2440.git] / dist / ntp / ntpd / ntp_config.c
blobdd1dc45f2d65e3b79a21c5a4afaa680f56b4cbac
1 /* $NetBSD: ntp_config.c,v 1.9 2007/01/06 19:45:22 kardel Exp $ */
3 /*
4 * ntp_config.c - read and apply configuration information
5 */
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
10 #ifdef HAVE_NETINFO
11 # include <netinfo/ni.h>
12 #endif
14 #include "ntpd.h"
15 #include "ntp_io.h"
16 #include "ntp_unixtime.h"
17 #include "ntp_refclock.h"
18 #include "ntp_filegen.h"
19 #include "ntp_stdlib.h"
20 #include <ntp_random.h>
21 #include <isc/net.h>
22 #include <isc/result.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #ifdef HAVE_SYS_PARAM_H
27 #include <sys/param.h>
28 #endif
29 #include <signal.h>
30 #ifndef SIGCHLD
31 # define SIGCHLD SIGCLD
32 #endif
33 #if !defined(VMS)
34 # ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
36 # endif
37 #endif /* VMS */
39 #ifdef SYS_WINNT
40 # include <io.h>
41 static HANDLE ResolverThreadHandle = NULL;
42 HANDLE ResolverEventHandle;
43 #else
44 int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */
45 #endif /* SYS_WINNT */
48 * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
49 * so #include these later.
52 #include "ntp_config.h"
53 #include "ntp_cmdargs.h"
55 extern int priority_done;
58 * These routines are used to read the configuration file at
59 * startup time. An entry in the file must fit on a single line.
60 * Entries are processed as multiple tokens separated by white space
61 * Lines are considered terminated when a '#' is encountered. Blank
62 * lines are ignored.
65 * Translation table - keywords to function index
67 struct keyword {
68 const char *text;
69 int keytype;
73 * Command keywords
75 static struct keyword keywords[] = {
76 { "automax", CONFIG_AUTOMAX },
77 { "broadcast", CONFIG_BROADCAST },
78 { "broadcastclient", CONFIG_BROADCASTCLIENT },
79 { "broadcastdelay", CONFIG_BDELAY },
80 { "calldelay", CONFIG_CDELAY},
81 #ifdef OPENSSL
82 { "crypto", CONFIG_CRYPTO },
83 #endif /* OPENSSL */
84 { "controlkey", CONFIG_CONTROLKEY },
85 { "disable", CONFIG_DISABLE },
86 { "driftfile", CONFIG_DRIFTFILE },
87 { "enable", CONFIG_ENABLE },
88 { "end", CONFIG_END },
89 { "filegen", CONFIG_FILEGEN },
90 { "fudge", CONFIG_FUDGE },
91 { "includefile", CONFIG_INCLUDEFILE },
92 { "keys", CONFIG_KEYS },
93 { "keysdir", CONFIG_KEYSDIR },
94 { "logconfig", CONFIG_LOGCONFIG },
95 { "logfile", CONFIG_LOGFILE },
96 { "manycastclient", CONFIG_MANYCASTCLIENT },
97 { "manycastserver", CONFIG_MANYCASTSERVER },
98 { "multicastclient", CONFIG_MULTICASTCLIENT },
99 { "peer", CONFIG_PEER },
100 { "phone", CONFIG_PHONE },
101 { "pidfile", CONFIG_PIDFILE },
102 { "discard", CONFIG_DISCARD },
103 { "requestkey", CONFIG_REQUESTKEY },
104 { "restrict", CONFIG_RESTRICT },
105 { "revoke", CONFIG_REVOKE },
106 { "server", CONFIG_SERVER },
107 { "setvar", CONFIG_SETVAR },
108 { "statistics", CONFIG_STATISTICS },
109 { "statsdir", CONFIG_STATSDIR },
110 { "tick", CONFIG_ADJ },
111 { "tinker", CONFIG_TINKER },
112 { "tos", CONFIG_TOS },
113 { "trap", CONFIG_TRAP },
114 { "trustedkey", CONFIG_TRUSTEDKEY },
115 { "ttl", CONFIG_TTL },
116 { "", CONFIG_UNKNOWN }
120 * "peer", "server", "broadcast" modifier keywords
122 static struct keyword mod_keywords[] = {
123 { "autokey", CONF_MOD_SKEY },
124 { "burst", CONF_MOD_BURST },
125 { "iburst", CONF_MOD_IBURST },
126 { "key", CONF_MOD_KEY },
127 { "maxpoll", CONF_MOD_MAXPOLL },
128 { "minpoll", CONF_MOD_MINPOLL },
129 { "mode", CONF_MOD_MODE }, /* refclocks */
130 { "noselect", CONF_MOD_NOSELECT },
131 { "preempt", CONF_MOD_PREEMPT },
132 { "true", CONF_MOD_TRUE },
133 { "prefer", CONF_MOD_PREFER },
134 { "ttl", CONF_MOD_TTL }, /* NTP peers */
135 { "version", CONF_MOD_VERSION },
136 { "dynamic", CONF_MOD_DYNAMIC },
137 { "", CONFIG_UNKNOWN }
141 * "restrict" modifier keywords
143 static struct keyword res_keywords[] = {
144 { "ignore", CONF_RES_IGNORE },
145 { "limited", CONF_RES_LIMITED },
146 { "kod", CONF_RES_DEMOBILIZE },
147 { "lowpriotrap", CONF_RES_LPTRAP },
148 { "mask", CONF_RES_MASK },
149 { "nomodify", CONF_RES_NOMODIFY },
150 { "nopeer", CONF_RES_NOPEER },
151 { "noquery", CONF_RES_NOQUERY },
152 { "noserve", CONF_RES_NOSERVE },
153 { "notrap", CONF_RES_NOTRAP },
154 { "notrust", CONF_RES_NOTRUST },
155 { "ntpport", CONF_RES_NTPPORT },
156 { "version", CONF_RES_VERSION },
157 { "", CONFIG_UNKNOWN }
161 * "trap" modifier keywords
163 static struct keyword trap_keywords[] = {
164 { "port", CONF_TRAP_PORT },
165 { "interface", CONF_TRAP_INTERFACE },
166 { "", CONFIG_UNKNOWN }
170 * "fudge" modifier keywords
172 static struct keyword fudge_keywords[] = {
173 { "flag1", CONF_FDG_FLAG1 },
174 { "flag2", CONF_FDG_FLAG2 },
175 { "flag3", CONF_FDG_FLAG3 },
176 { "flag4", CONF_FDG_FLAG4 },
177 { "refid", CONF_FDG_REFID }, /* this mapping should be cleaned up (endianness, \0) - kd 20041031 */
178 { "stratum", CONF_FDG_STRATUM },
179 { "time1", CONF_FDG_TIME1 },
180 { "time2", CONF_FDG_TIME2 },
181 { "", CONFIG_UNKNOWN }
185 * "filegen" modifier keywords
187 static struct keyword filegen_keywords[] = {
188 { "disable", CONF_FGEN_FLAG_DISABLE },
189 { "enable", CONF_FGEN_FLAG_ENABLE },
190 { "file", CONF_FGEN_FILE },
191 { "link", CONF_FGEN_FLAG_LINK },
192 { "nolink", CONF_FGEN_FLAG_NOLINK },
193 { "type", CONF_FGEN_TYPE },
194 { "", CONFIG_UNKNOWN }
198 * "type" modifier keywords
200 static struct keyword fgen_types[] = {
201 { "age", FILEGEN_AGE },
202 { "day", FILEGEN_DAY },
203 { "month", FILEGEN_MONTH },
204 { "none", FILEGEN_NONE },
205 { "pid", FILEGEN_PID },
206 { "week", FILEGEN_WEEK },
207 { "year", FILEGEN_YEAR },
208 { "", CONFIG_UNKNOWN}
212 * "enable", "disable" modifier keywords
214 static struct keyword flags_keywords[] = {
215 { "auth", PROTO_AUTHENTICATE },
216 { "bclient", PROTO_BROADCLIENT },
217 { "calibrate", PROTO_CAL },
218 { "kernel", PROTO_KERNEL },
219 { "monitor", PROTO_MONITOR },
220 { "ntp", PROTO_NTP },
221 { "stats", PROTO_FILEGEN },
222 { "", CONFIG_UNKNOWN }
226 * "discard" modifier keywords
228 static struct keyword discard_keywords[] = {
229 { "average", CONF_DISCARD_AVERAGE },
230 { "minimum", CONF_DISCARD_MINIMUM },
231 { "monitor", CONF_DISCARD_MONITOR },
232 { "", CONFIG_UNKNOWN }
236 * "tinker" modifier keywords
238 static struct keyword tinker_keywords[] = {
239 { "step", CONF_CLOCK_MAX },
240 { "panic", CONF_CLOCK_PANIC },
241 { "dispersion", CONF_CLOCK_PHI },
242 { "stepout", CONF_CLOCK_MINSTEP },
243 { "allan", CONF_CLOCK_ALLAN },
244 { "huffpuff", CONF_CLOCK_HUFFPUFF },
245 { "freq", CONF_CLOCK_FREQ },
246 { "", CONFIG_UNKNOWN }
250 * "tos" modifier keywords
252 static struct keyword tos_keywords[] = {
253 { "minclock", CONF_TOS_MINCLOCK },
254 { "maxclock", CONF_TOS_MAXCLOCK },
255 { "minsane", CONF_TOS_MINSANE },
256 { "floor", CONF_TOS_FLOOR },
257 { "ceiling", CONF_TOS_CEILING },
258 { "cohort", CONF_TOS_COHORT },
259 { "mindist", CONF_TOS_MINDISP },
260 { "maxdist", CONF_TOS_MAXDIST },
261 { "maxhop", CONF_TOS_MAXHOP },
262 { "beacon", CONF_TOS_BEACON },
263 { "orphan", CONF_TOS_ORPHAN },
264 { "", CONFIG_UNKNOWN }
267 #ifdef OPENSSL
269 * "crypto" modifier keywords
271 static struct keyword crypto_keywords[] = {
272 { "cert", CONF_CRYPTO_CERT },
273 { "gqpar", CONF_CRYPTO_GQPAR },
274 { "host", CONF_CRYPTO_RSA },
275 { "ident", CONF_CRYPTO_IDENT },
276 { "iffpar", CONF_CRYPTO_IFFPAR },
277 { "leap", CONF_CRYPTO_LEAP },
278 { "mvpar", CONF_CRYPTO_MVPAR },
279 { "pw", CONF_CRYPTO_PW },
280 { "randfile", CONF_CRYPTO_RAND },
281 { "sign", CONF_CRYPTO_SIGN },
282 { "", CONFIG_UNKNOWN }
284 #endif /* OPENSSL */
287 * Address type selection, IPv4 or IPv4.
288 * Used on various lines.
290 static struct keyword addr_type[] = {
291 { "-4", CONF_ADDR_IPV4 },
292 { "-6", CONF_ADDR_IPV6 },
293 { "", CONFIG_UNKNOWN }
297 * "logconfig" building blocks
299 struct masks {
300 const char *name;
301 unsigned long mask;
304 static struct masks logcfg_class[] = {
305 { "clock", NLOG_OCLOCK },
306 { "peer", NLOG_OPEER },
307 { "sync", NLOG_OSYNC },
308 { "sys", NLOG_OSYS },
309 { (char *)0, 0 }
312 static struct masks logcfg_item[] = {
313 { "info", NLOG_INFO },
314 { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
315 { "events", NLOG_EVENT },
316 { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
317 { "status", NLOG_STATUS },
318 { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
319 { "statistics", NLOG_STATIST },
320 { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
321 { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
322 { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
323 { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
324 { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
325 { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
326 { (char *)0, 0 }
330 * Limits on things
332 #define MAXTOKENS 20 /* 20 tokens on line */
333 #define MAXLINE 1024 /* maximum length of line */
334 #define MAXPHONE 10 /* maximum number of phone strings */
335 #define MAXPPS 20 /* maximum length of PPS device string */
336 #define MAXINCLUDELEVEL 5 /* maximum include file levels */
339 * Miscellaneous macros
341 #define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
342 #define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
343 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
344 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
346 #define KEY_TYPE_MD5 4
349 * File descriptor used by the resolver save routines, and temporary file
350 * name.
352 int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */
353 static FILE *res_fp;
354 #ifndef SYS_WINNT
355 static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */
356 #define RES_TEMPFILE "/tmp/ntpXXXXXX"
357 #else
358 static char res_file[MAX_PATH];
359 #endif /* SYS_WINNT */
362 * Definitions of things either imported from or exported to outside
365 short default_ai_family = AF_UNSPEC; /* Default either IPv4 or IPv6 */
366 char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
367 char *keysdir = NTP_KEYSDIR; /* crypto keys directory */
368 #if defined(HAVE_SCHED_SETSCHEDULER)
369 int config_priority_override = 0;
370 int config_priority;
371 #endif
373 const char *config_file;
374 #ifdef HAVE_NETINFO
375 struct netinfo_config_state *config_netinfo = NULL;
376 int check_netinfo = 1;
377 #endif /* HAVE_NETINFO */
378 #ifdef SYS_WINNT
379 char *alt_config_file;
380 LPTSTR temp;
381 char config_file_storage[MAX_PATH];
382 char alt_config_file_storage[MAX_PATH];
383 #endif /* SYS_WINNT */
385 #ifdef HAVE_NETINFO
387 * NetInfo configuration state
389 struct netinfo_config_state {
390 void *domain; /* domain with config */
391 ni_id config_dir; /* ID config dir */
392 int prop_index; /* current property */
393 int val_index; /* current value */
394 char **val_list; /* value list */
396 #endif
399 * Function prototypes
401 static unsigned long get_pfxmatch P((char **, struct masks *));
402 static unsigned long get_match P((char *, struct masks *));
403 static unsigned long get_logmask P((char *));
404 #ifdef HAVE_NETINFO
405 static struct netinfo_config_state *get_netinfo_config P((void));
406 static void free_netinfo_config P((struct netinfo_config_state *));
407 static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
408 #endif
409 static int gettokens P((FILE *, char *, char **, int *));
410 static int matchkey P((char *, struct keyword *, int));
411 enum gnn_type {
412 t_UNK, /* Unknown */
413 t_REF, /* Refclock */
414 t_MSK /* Network Mask */
416 static int getnetnum P((const char *, struct sockaddr_storage *, int,
417 enum gnn_type));
418 static void save_resolve P((char *, int, int, int, int, u_int, int,
419 keyid_t, u_char *));
420 static void do_resolve_internal P((void));
421 static void abort_resolve P((void));
422 #if !defined(VMS) && !defined(SYS_WINNT)
423 static RETSIGTYPE catchchild P((int));
424 #endif /* VMS */
427 * get_pfxmatch - find value for prefixmatch
428 * and update char * accordingly
430 static unsigned long
431 get_pfxmatch(
432 char ** s,
433 struct masks *m
436 while (m->name) {
437 if (strncmp(*s, m->name, strlen(m->name)) == 0) {
438 *s += strlen(m->name);
439 return m->mask;
440 } else {
441 m++;
444 return 0;
448 * get_match - find logmask value
450 static unsigned long
451 get_match(
452 char *s,
453 struct masks *m
456 while (m->name) {
457 if (strcmp(s, m->name) == 0) {
458 return m->mask;
459 } else {
460 m++;
463 return 0;
467 * get_logmask - build bitmask for ntp_syslogmask
469 static unsigned long
470 get_logmask(
471 char *s
474 char *t;
475 unsigned long offset;
476 unsigned long mask;
478 t = s;
479 offset = get_pfxmatch(&t, logcfg_class);
480 mask = get_match(t, logcfg_item);
482 if (mask)
483 return mask << offset;
484 else
485 msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);
487 return 0;
492 * getconfig - get command line options and read the configuration file
494 void
495 getconfig(
496 int argc,
497 char *argv[]
500 register int i;
501 int c;
502 int errflg;
503 int status;
504 int istart;
505 int peerversion;
506 int minpoll;
507 int maxpoll;
508 int ttl;
509 long stratum;
510 unsigned long ul;
511 keyid_t peerkey;
512 u_char *peerkeystr;
513 u_long fudgeflag;
514 u_int peerflags;
515 int hmode;
516 struct sockaddr_storage peeraddr;
517 struct sockaddr_storage maskaddr;
518 FILE *fp[MAXINCLUDELEVEL+1];
519 FILE *includefile;
520 int includelevel = 0;
521 char line[MAXLINE];
522 char *(tokens[MAXTOKENS]);
523 int ntokens = 0;
524 int tok = CONFIG_UNKNOWN;
525 struct interface *localaddr;
526 struct refclockstat clock_stat;
527 FILEGEN *filegen;
530 * Initialize, initialize
532 errflg = 0;
534 #ifndef SYS_WINNT
535 config_file = CONFIG_FILE;
536 #else
537 temp = CONFIG_FILE;
538 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
539 msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
540 exit(1);
542 config_file = config_file_storage;
544 temp = ALT_CONFIG_FILE;
545 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
546 msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
547 exit(1);
549 alt_config_file = alt_config_file_storage;
551 #endif /* SYS_WINNT */
552 res_fp = NULL;
553 ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
556 * install a non default variable with this daemon version
558 (void) sprintf(line, "daemon_version=\"%s\"", Version);
559 set_sys_var(line, strlen(line)+1, RO);
562 * Say how we're setting the time of day
564 (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
565 set_sys_var(line, strlen(line)+1, RO);
568 * Initialize the loop.
570 loop_config(LOOP_DRIFTINIT, 0.);
572 getCmdOpts(argc, argv);
574 if (
575 (fp[0] = fopen(FindConfig(config_file), "r")) == NULL
576 #ifdef HAVE_NETINFO
577 /* If there is no config_file, try NetInfo. */
578 && check_netinfo && !(config_netinfo = get_netinfo_config())
579 #endif /* HAVE_NETINFO */
581 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
582 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
583 #ifdef SYS_WINNT
584 /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
586 if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) {
589 * Broadcast clients can sometimes run without
590 * a configuration file.
593 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
594 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
595 return;
597 #else /* not SYS_WINNT */
598 return;
599 #endif /* not SYS_WINNT */
602 for (;;) {
603 if (tok == CONFIG_END)
604 break;
605 if (fp[includelevel])
606 tok = gettokens(fp[includelevel], line, tokens, &ntokens);
607 #ifdef HAVE_NETINFO
608 else
609 tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
610 #endif /* HAVE_NETINFO */
612 if (tok == CONFIG_UNKNOWN) {
613 if (includelevel > 0) {
614 fclose(fp[includelevel--]);
615 continue;
616 } else {
617 break;
621 switch(tok) {
622 case CONFIG_PEER:
623 case CONFIG_SERVER:
624 case CONFIG_MANYCASTCLIENT:
625 case CONFIG_BROADCAST:
626 if (tok == CONFIG_PEER)
627 hmode = MODE_ACTIVE;
628 else if (tok == CONFIG_SERVER)
629 hmode = MODE_CLIENT;
630 else if (tok == CONFIG_MANYCASTCLIENT)
631 hmode = MODE_CLIENT;
632 else
633 hmode = MODE_BROADCAST;
635 if (ntokens < 2) {
636 msyslog(LOG_ERR,
637 "No address for %s, line ignored",
638 tokens[0]);
639 break;
642 istart = 1;
643 memset((char *)&peeraddr, 0, sizeof(peeraddr));
644 peeraddr.ss_family = default_ai_family;
645 switch (matchkey(tokens[istart], addr_type, 0)) {
646 case CONF_ADDR_IPV4:
647 peeraddr.ss_family = AF_INET;
648 istart++;
649 break;
650 case CONF_ADDR_IPV6:
651 peeraddr.ss_family = AF_INET6;
652 istart++;
653 break;
656 status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK);
657 if (status == -1)
658 break; /* Found IPv6 address */
659 if(status != 1) {
660 errflg = -1;
661 } else {
662 errflg = 0;
664 if (
665 #ifdef REFCLOCK
666 !ISREFCLOCKADR(&peeraddr) &&
667 #endif
668 ISBADADR(&peeraddr)) {
669 msyslog(LOG_ERR,
670 "attempt to configure invalid address %s",
671 stoa(&peeraddr));
672 break;
675 * Shouldn't be able to specify multicast
676 * address for server/peer!
677 * and unicast address for manycastclient!
679 if (peeraddr.ss_family == AF_INET) {
680 if (((tok == CONFIG_SERVER) ||
681 (tok == CONFIG_PEER)) &&
682 #ifdef REFCLOCK
683 !ISREFCLOCKADR(&peeraddr) &&
684 #endif
685 IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
686 msyslog(LOG_ERR,
687 "attempt to configure invalid address %s",
688 stoa(&peeraddr));
689 break;
691 if ((tok == CONFIG_MANYCASTCLIENT) &&
692 !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
693 msyslog(LOG_ERR,
694 "attempt to configure invalid address %s",
695 stoa(&peeraddr));
696 break;
699 else if(peeraddr.ss_family == AF_INET6) {
700 if (((tok == CONFIG_SERVER) ||
701 (tok == CONFIG_PEER)) &&
702 #ifdef REFCLOCK
703 !ISREFCLOCKADR(&peeraddr) &&
704 #endif
705 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
706 msyslog(LOG_ERR,
707 "attempt to configure in valid address %s",
708 stoa(&peeraddr));
709 break;
711 if ((tok == CONFIG_MANYCASTCLIENT) &&
712 !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
713 msyslog(LOG_ERR,
714 "attempt to configure in valid address %s",
715 stoa(&peeraddr));
716 break;
720 if (peeraddr.ss_family == AF_INET6 &&
721 isc_net_probeipv6() != ISC_R_SUCCESS)
722 break;
724 peerversion = NTP_VERSION;
725 minpoll = NTP_MINDPOLL;
726 maxpoll = NTP_MAXDPOLL;
727 peerkey = 0;
728 peerkeystr = (u_char *)"*";
729 peerflags = 0;
730 ttl = 0;
731 istart++;
732 for (i = istart; i < ntokens; i++)
733 switch (matchkey(tokens[i], mod_keywords, 1)) {
734 case CONF_MOD_VERSION:
735 if (i >= ntokens-1) {
736 msyslog(LOG_ERR,
737 "peer/server version requires an argument");
738 errflg = 1;
739 break;
741 peerversion = atoi(tokens[++i]);
742 if ((u_char)peerversion > NTP_VERSION
743 || (u_char)peerversion < NTP_OLDVERSION) {
744 msyslog(LOG_ERR,
745 "inappropriate version number %s, line ignored",
746 tokens[i]);
747 errflg = 1;
749 break;
751 case CONF_MOD_KEY:
752 if (i >= ntokens-1) {
753 msyslog(LOG_ERR,
754 "key: argument required");
755 errflg = 1;
756 break;
758 peerkey = (int)atol(tokens[++i]);
759 peerflags |= FLAG_AUTHENABLE;
760 break;
762 case CONF_MOD_MINPOLL:
763 if (i >= ntokens-1) {
764 msyslog(LOG_ERR,
765 "minpoll: argument required");
766 errflg = 1;
767 break;
769 minpoll = atoi(tokens[++i]);
770 if (minpoll < NTP_MINPOLL) {
771 msyslog(LOG_INFO,
772 "minpoll: provided value (%d) is below minimum (%d)",
773 minpoll, NTP_MINPOLL);
774 minpoll = NTP_MINPOLL;
776 break;
778 case CONF_MOD_MAXPOLL:
779 if (i >= ntokens-1) {
780 msyslog(LOG_ERR,
781 "maxpoll: argument required"
783 errflg = 1;
784 break;
786 maxpoll = atoi(tokens[++i]);
787 if (maxpoll > NTP_MAXPOLL) {
788 msyslog(LOG_INFO,
789 "maxpoll: provided value (%d) is above maximum (%d)",
790 maxpoll, NTP_MAXPOLL);
791 maxpoll = NTP_MAXPOLL;
793 break;
795 case CONF_MOD_PREFER:
796 peerflags |= FLAG_PREFER;
797 break;
799 case CONF_MOD_PREEMPT:
800 peerflags |= FLAG_PREEMPT;
801 break;
803 case CONF_MOD_NOSELECT:
804 peerflags |= FLAG_NOSELECT;
805 break;
807 case CONF_MOD_TRUE:
808 peerflags |= FLAG_TRUE;
810 case CONF_MOD_BURST:
811 peerflags |= FLAG_BURST;
812 break;
814 case CONF_MOD_IBURST:
815 peerflags |= FLAG_IBURST;
816 break;
818 case CONF_MOD_DYNAMIC:
819 msyslog(LOG_WARNING,
820 "Warning: the \"dynamic\" keyword has been obsoleted"
821 " and will be removed in the next release\n");
822 break;
824 #ifdef OPENSSL
825 case CONF_MOD_SKEY:
826 peerflags |= FLAG_SKEY |
827 FLAG_AUTHENABLE;
828 break;
829 #endif /* OPENSSL */
831 case CONF_MOD_TTL:
832 if (i >= ntokens-1) {
833 msyslog(LOG_ERR,
834 "ttl: argument required");
835 errflg = 1;
836 break;
838 ttl = atoi(tokens[++i]);
839 if (ttl >= MAX_TTL) {
840 msyslog(LOG_ERR,
841 "ttl: invalid argument");
842 errflg = 1;
844 break;
846 case CONF_MOD_MODE:
847 if (i >= ntokens-1) {
848 msyslog(LOG_ERR,
849 "mode: argument required");
850 errflg = 1;
851 break;
853 ttl = atoi(tokens[++i]);
854 break;
856 case CONFIG_UNKNOWN:
857 errflg = 1;
858 break;
860 if (minpoll > maxpoll) {
861 msyslog(LOG_ERR,
862 "config error: minpoll > maxpoll");
863 errflg = 1;
865 if (errflg == 0) {
866 if (peer_config(&peeraddr,
867 ANY_INTERFACE_CHOOSE(&peeraddr), hmode,
868 peerversion, minpoll, maxpoll, peerflags,
869 ttl, peerkey, peerkeystr) == 0) {
870 msyslog(LOG_ERR,
871 "configuration of %s failed",
872 stoa(&peeraddr));
874 } else if (errflg == -1) {
875 save_resolve(tokens[1], hmode, peerversion,
876 minpoll, maxpoll, peerflags, ttl,
877 peerkey, peerkeystr);
879 break;
881 case CONFIG_DRIFTFILE:
882 if (ntokens >= 2)
883 stats_config(STATS_FREQ_FILE, tokens[1]);
884 else
885 stats_config(STATS_FREQ_FILE, (char *)0);
886 stats_write_period = stats_write_tolerance = 0;
887 if (ntokens >= 3)
888 stats_write_period = 60 * atol(tokens[2]);
889 if (stats_write_period <= 0)
890 stats_write_period = 3600;
891 if (ntokens >= 4) {
892 double ftemp;
893 sscanf(tokens[3], "%lf", &ftemp);
894 stats_write_tolerance = ftemp / 100;
896 break;
898 case CONFIG_PIDFILE:
899 if (ntokens >= 2)
900 stats_config(STATS_PID_FILE, tokens[1]);
901 else
902 stats_config(STATS_PID_FILE, (char *)0);
903 break;
905 case CONFIG_END:
906 for ( i = 0; i <= includelevel; i++ ) {
907 fclose(fp[i]);
909 break;
911 case CONFIG_INCLUDEFILE:
912 if (ntokens < 2) {
913 msyslog(LOG_ERR, "includefile needs one argument");
914 break;
916 if (includelevel >= MAXINCLUDELEVEL) {
917 fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
918 msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
919 break;
921 includefile = fopen(FindConfig(tokens[1]), "r");
922 if (includefile == NULL) {
923 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
924 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
925 break;
927 fp[++includelevel] = includefile;
928 break;
930 case CONFIG_LOGFILE:
931 if (ntokens >= 2) {
932 FILE *new_file;
934 new_file = fopen(tokens[1], "a");
935 if (new_file != NULL) {
936 NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
937 msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
938 if (syslog_file != NULL &&
939 fileno(syslog_file) != fileno(new_file))
940 (void)fclose(syslog_file);
942 syslog_file = new_file;
943 syslogit = 0;
945 else
946 msyslog(LOG_ERR,
947 "Cannot open log file %s",
948 tokens[1]);
950 else
951 msyslog(LOG_ERR, "logfile needs one argument");
952 break;
954 case CONFIG_LOGCONFIG:
955 for (i = 1; i < ntokens; i++)
957 int add = 1;
958 int equals = 0;
959 char * s = &tokens[i][0];
961 switch (*s) {
962 case '+':
963 case '-':
964 case '=':
965 add = *s == '+';
966 equals = *s == '=';
967 s++;
968 break;
970 default:
971 break;
973 if (equals) {
974 ntp_syslogmask = get_logmask(s);
975 } else {
976 if (add) {
977 ntp_syslogmask |= get_logmask(s);
978 } else {
979 ntp_syslogmask &= ~get_logmask(s);
982 #ifdef DEBUG
983 if (debug)
984 printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
985 #endif
987 break;
989 case CONFIG_BROADCASTCLIENT:
990 if (ntokens == 1) {
991 proto_config(PROTO_BROADCLIENT, 1, 0., NULL);
992 } else {
993 proto_config(PROTO_BROADCLIENT, 2, 0., NULL);
995 break;
997 case CONFIG_MULTICASTCLIENT:
998 case CONFIG_MANYCASTSERVER:
999 if (ntokens > 1) {
1000 istart = 1;
1001 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1002 peeraddr.ss_family = default_ai_family;
1003 switch (matchkey(tokens[istart],
1004 addr_type, 0)) {
1005 case CONF_ADDR_IPV4:
1006 peeraddr.ss_family = AF_INET;
1007 istart++;
1008 break;
1009 case CONF_ADDR_IPV6:
1010 peeraddr.ss_family = AF_INET6;
1011 istart++;
1012 break;
1015 * Abuse maskaddr to store the prefered ip
1016 * version.
1018 memset((char *)&maskaddr, 0, sizeof(maskaddr));
1019 maskaddr.ss_family = peeraddr.ss_family;
1021 for (i = istart; i < ntokens; i++) {
1022 memset((char *)&peeraddr, 0,
1023 sizeof(peeraddr));
1024 peeraddr.ss_family = maskaddr.ss_family;
1025 if (getnetnum(tokens[i], &peeraddr, 1,
1026 t_UNK) == 1)
1027 proto_config(PROTO_MULTICAST_ADD,
1028 0, 0., &peeraddr);
1030 } else
1031 proto_config(PROTO_MULTICAST_ADD,
1032 0, 0., NULL);
1033 if (tok == CONFIG_MULTICASTCLIENT)
1034 proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1035 else if (tok == CONFIG_MANYCASTSERVER)
1036 sys_manycastserver = 1;
1037 break;
1039 case CONFIG_KEYS:
1040 if (ntokens >= 2) {
1041 getauthkeys(tokens[1]);
1043 break;
1045 case CONFIG_KEYSDIR:
1046 if (ntokens < 2) {
1047 msyslog(LOG_ERR,
1048 "Keys directory name required");
1049 break;
1051 keysdir = (char *)emalloc(strlen(tokens[1]) + 1);
1052 strcpy(keysdir, tokens[1]);
1053 break;
1055 case CONFIG_TINKER:
1056 for (i = 1; i < ntokens; i++) {
1057 int temp;
1058 double ftemp;
1060 temp = matchkey(tokens[i++], tinker_keywords, 1);
1061 if (i > ntokens - 1) {
1062 msyslog(LOG_ERR,
1063 "tinker: missing argument");
1064 errflg++;
1065 break;
1067 sscanf(tokens[i], "%lf", &ftemp);
1068 switch(temp) {
1070 case CONF_CLOCK_MAX:
1071 loop_config(LOOP_MAX, ftemp);
1072 break;
1074 case CONF_CLOCK_PANIC:
1075 loop_config(LOOP_PANIC, ftemp);
1076 break;
1078 case CONF_CLOCK_PHI:
1079 loop_config(LOOP_PHI, ftemp);
1080 break;
1082 case CONF_CLOCK_MINSTEP:
1083 loop_config(LOOP_MINSTEP, ftemp);
1084 break;
1086 case CONF_CLOCK_ALLAN:
1087 loop_config(LOOP_ALLAN, ftemp);
1088 break;
1090 case CONF_CLOCK_HUFFPUFF:
1091 loop_config(LOOP_HUFFPUFF, ftemp);
1092 break;
1094 case CONF_CLOCK_FREQ:
1095 loop_config(LOOP_FREQ, ftemp);
1096 break;
1099 break;
1101 case CONFIG_TOS:
1102 for (i = 1; i < ntokens; i++) {
1103 int temp;
1104 double ftemp;
1106 temp = matchkey(tokens[i++], tos_keywords, 1);
1107 if (i > ntokens - 1) {
1108 msyslog(LOG_ERR,
1109 "tos: missing argument");
1110 errflg++;
1111 break;
1113 sscanf(tokens[i], "%lf", &ftemp);
1114 switch(temp) {
1116 case CONF_TOS_MINCLOCK:
1117 proto_config(PROTO_MINCLOCK, 0, ftemp, NULL);
1118 break;
1120 case CONF_TOS_MAXCLOCK:
1121 proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL);
1122 break;
1124 case CONF_TOS_MINSANE:
1125 proto_config(PROTO_MINSANE, 0, ftemp, NULL);
1126 break;
1128 case CONF_TOS_FLOOR:
1129 proto_config(PROTO_FLOOR, 0, ftemp, NULL);
1130 break;
1132 case CONF_TOS_CEILING:
1133 proto_config(PROTO_CEILING, 0, ftemp, NULL);
1134 break;
1136 case CONF_TOS_COHORT:
1137 proto_config(PROTO_COHORT, 0, ftemp, NULL);
1138 break;
1140 case CONF_TOS_MINDISP:
1141 proto_config(PROTO_MINDISP, 0, ftemp, NULL);
1142 break;
1144 case CONF_TOS_MAXDIST:
1145 proto_config(PROTO_MAXDIST, 0, ftemp, NULL);
1146 break;
1148 case CONF_TOS_MAXHOP:
1149 proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
1150 break;
1152 case CONF_TOS_ORPHAN:
1153 proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
1154 break;
1156 case CONF_TOS_BEACON:
1157 proto_config(PROTO_BEACON, 0, ftemp, NULL);
1158 break;
1161 break;
1163 case CONFIG_TTL:
1164 for (i = 1; i < ntokens && i < MAX_TTL; i++) {
1165 sys_ttl[i - 1] = (u_char) atoi(tokens[i]);
1166 sys_ttlmax = i - 1;
1168 break;
1170 case CONFIG_DISCARD:
1171 for (i = 1; i < ntokens; i++) {
1172 int temp;
1174 temp = matchkey(tokens[i++],
1175 discard_keywords, 1);
1176 if (i > ntokens - 1) {
1177 msyslog(LOG_ERR,
1178 "discard: missing argument");
1179 errflg++;
1180 break;
1182 switch(temp) {
1183 case CONF_DISCARD_AVERAGE:
1184 res_avg_interval = atoi(tokens[i]);
1185 break;
1187 case CONF_DISCARD_MINIMUM:
1188 res_min_interval = atoi(tokens[i]);
1189 break;
1191 case CONF_DISCARD_MONITOR:
1192 mon_age = atoi(tokens[i]);
1193 break;
1195 default:
1196 msyslog(LOG_ERR,
1197 "discard: unknown keyword");
1198 break;
1201 break;
1203 #ifdef OPENSSL
1204 case CONFIG_REVOKE:
1205 if (ntokens >= 2)
1206 sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE);
1207 break;
1209 case CONFIG_AUTOMAX:
1210 if (ntokens >= 2)
1211 sys_automax = 1 << max(atoi(tokens[1]), 10);
1212 break;
1214 case CONFIG_CRYPTO:
1215 if (ntokens == 1) {
1216 crypto_config(CRYPTO_CONF_NONE, NULL);
1217 break;
1219 for (i = 1; i < ntokens; i++) {
1220 int temp;
1222 temp = matchkey(tokens[i++],
1223 crypto_keywords, 1);
1224 if (i > ntokens - 1) {
1225 msyslog(LOG_ERR,
1226 "crypto: missing argument");
1227 errflg++;
1228 break;
1230 switch(temp) {
1232 case CONF_CRYPTO_CERT:
1233 crypto_config(CRYPTO_CONF_CERT,
1234 tokens[i]);
1235 break;
1237 case CONF_CRYPTO_RSA:
1238 crypto_config(CRYPTO_CONF_PRIV,
1239 tokens[i]);
1240 break;
1242 case CONF_CRYPTO_IDENT:
1243 crypto_config(CRYPTO_CONF_IDENT,
1244 tokens[i]);
1245 break;
1247 case CONF_CRYPTO_IFFPAR:
1248 crypto_config(CRYPTO_CONF_IFFPAR,
1249 tokens[i]);
1250 break;
1252 case CONF_CRYPTO_GQPAR:
1253 crypto_config(CRYPTO_CONF_GQPAR,
1254 tokens[i]);
1255 break;
1257 case CONF_CRYPTO_MVPAR:
1258 crypto_config(CRYPTO_CONF_MVPAR,
1259 tokens[i]);
1260 break;
1262 case CONF_CRYPTO_LEAP:
1263 crypto_config(CRYPTO_CONF_LEAP,
1264 tokens[i]);
1265 break;
1267 case CONF_CRYPTO_PW:
1268 crypto_config(CRYPTO_CONF_PW,
1269 tokens[i]);
1270 break;
1272 case CONF_CRYPTO_RAND:
1273 crypto_config(CRYPTO_CONF_RAND,
1274 tokens[i]);
1275 break;
1277 case CONF_CRYPTO_SIGN:
1278 crypto_config(CRYPTO_CONF_SIGN,
1279 tokens[i]);
1280 break;
1282 default:
1283 msyslog(LOG_ERR,
1284 "crypto: unknown keyword");
1285 break;
1288 break;
1289 #endif /* OPENSSL */
1291 case CONFIG_RESTRICT:
1292 if (ntokens < 2) {
1293 msyslog(LOG_ERR, "restrict requires an address");
1294 break;
1296 istart = 1;
1297 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1298 peeraddr.ss_family = default_ai_family;
1299 switch (matchkey(tokens[istart], addr_type, 0)) {
1300 case CONF_ADDR_IPV4:
1301 peeraddr.ss_family = AF_INET;
1302 istart++;
1303 break;
1304 case CONF_ADDR_IPV6:
1305 peeraddr.ss_family = AF_INET6;
1306 istart++;
1307 break;
1311 * Assume default means an IPv4 address, except
1312 * if forced by a -4 or -6.
1314 if (STREQ(tokens[istart], "default")) {
1315 if (peeraddr.ss_family == 0)
1316 peeraddr.ss_family = AF_INET;
1317 } else if (getnetnum(tokens[istart], &peeraddr, 1,
1318 t_UNK) != 1)
1319 break;
1322 * Use peerversion as flags, peerkey as mflags. Ick.
1324 peerversion = 0;
1325 peerkey = 0;
1326 errflg = 0;
1327 SET_HOSTMASK(&maskaddr, peeraddr.ss_family);
1328 istart++;
1329 for (i = istart; i < ntokens; i++) {
1330 switch (matchkey(tokens[i], res_keywords, 1)) {
1331 case CONF_RES_MASK:
1332 if (i >= ntokens-1) {
1333 msyslog(LOG_ERR,
1334 "mask keyword needs argument");
1335 errflg++;
1336 break;
1338 i++;
1339 if (getnetnum(tokens[i], &maskaddr, 1,
1340 t_MSK) != 1)
1341 errflg++;
1342 break;
1344 case CONF_RES_IGNORE:
1345 peerversion |= RES_IGNORE;
1346 break;
1348 case CONF_RES_NOSERVE:
1349 peerversion |= RES_DONTSERVE;
1350 break;
1352 case CONF_RES_NOTRUST:
1353 peerversion |= RES_DONTTRUST;
1354 break;
1356 case CONF_RES_NOQUERY:
1357 peerversion |= RES_NOQUERY;
1358 break;
1360 case CONF_RES_NOMODIFY:
1361 peerversion |= RES_NOMODIFY;
1362 break;
1364 case CONF_RES_NOPEER:
1365 peerversion |= RES_NOPEER;
1366 break;
1368 case CONF_RES_NOTRAP:
1369 peerversion |= RES_NOTRAP;
1370 break;
1372 case CONF_RES_LPTRAP:
1373 peerversion |= RES_LPTRAP;
1374 break;
1376 case CONF_RES_NTPPORT:
1377 peerkey |= RESM_NTPONLY;
1378 break;
1380 case CONF_RES_VERSION:
1381 peerversion |= RES_VERSION;
1382 break;
1384 case CONF_RES_DEMOBILIZE:
1385 peerversion |= RES_DEMOBILIZE;
1386 break;
1388 case CONF_RES_LIMITED:
1389 peerversion |= RES_LIMITED;
1390 break;
1392 case CONFIG_UNKNOWN:
1393 errflg++;
1394 break;
1397 if (SOCKNUL(&peeraddr))
1398 ANYSOCK(&maskaddr);
1399 if (!errflg)
1400 hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
1401 (int)peerkey, peerversion);
1402 break;
1404 case CONFIG_BDELAY:
1405 if (ntokens >= 2) {
1406 double tmp;
1408 if (sscanf(tokens[1], "%lf", &tmp) != 1) {
1409 msyslog(LOG_ERR,
1410 "broadcastdelay value %s undecodable",
1411 tokens[1]);
1412 } else {
1413 proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
1416 break;
1418 case CONFIG_CDELAY:
1419 if (ntokens >= 2) {
1420 u_long ui;
1422 if (sscanf(tokens[1], "%ld", &ui) != 1)
1423 msyslog(LOG_ERR,
1424 "illegal value - line ignored");
1425 else
1426 proto_config(PROTO_CALLDELAY, ui, 0, NULL);
1428 break;
1430 case CONFIG_TRUSTEDKEY:
1431 for (i = 1; i < ntokens; i++) {
1432 keyid_t tkey;
1434 tkey = atol(tokens[i]);
1435 if (tkey == 0) {
1436 msyslog(LOG_ERR,
1437 "trusted key %s unlikely",
1438 tokens[i]);
1439 } else {
1440 authtrust(tkey, 1);
1443 break;
1445 case CONFIG_REQUESTKEY:
1446 if (ntokens >= 2) {
1447 if (!atouint(tokens[1], &ul)) {
1448 msyslog(LOG_ERR,
1449 "%s is undecodable as request key",
1450 tokens[1]);
1451 } else if (ul == 0) {
1452 msyslog(LOG_ERR,
1453 "%s makes a poor request keyid",
1454 tokens[1]);
1455 } else {
1456 #ifdef DEBUG
1457 if (debug > 3)
1458 printf(
1459 "set info_auth_key to %08lx\n", ul);
1460 #endif
1461 info_auth_keyid = (keyid_t)ul;
1464 break;
1466 case CONFIG_CONTROLKEY:
1467 if (ntokens >= 2) {
1468 keyid_t ckey;
1470 ckey = atol(tokens[1]);
1471 if (ckey == 0) {
1472 msyslog(LOG_ERR,
1473 "%s makes a poor control keyid",
1474 tokens[1]);
1475 } else {
1476 ctl_auth_keyid = ckey;
1479 break;
1481 case CONFIG_TRAP:
1482 if (ntokens < 2) {
1483 msyslog(LOG_ERR,
1484 "no address for trap command, line ignored");
1485 break;
1487 istart = 1;
1488 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1489 peeraddr.ss_family = default_ai_family;
1490 switch (matchkey(tokens[istart], addr_type, 0)) {
1491 case CONF_ADDR_IPV4:
1492 peeraddr.ss_family = AF_INET;
1493 istart++;
1494 break;
1495 case CONF_ADDR_IPV6:
1496 peeraddr.ss_family = AF_INET6;
1497 istart++;
1498 break;
1501 if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1)
1502 break;
1505 * Use peerversion for port number. Barf.
1507 errflg = 0;
1508 peerversion = 0;
1509 localaddr = 0;
1510 istart++;
1511 for (i = istart; i < ntokens-1; i++)
1512 switch (matchkey(tokens[i], trap_keywords, 1)) {
1513 case CONF_TRAP_PORT:
1514 if (i >= ntokens-1) {
1515 msyslog(LOG_ERR,
1516 "trap port requires an argument");
1517 errflg = 1;
1518 break;
1520 peerversion = atoi(tokens[++i]);
1521 if (peerversion <= 0
1522 || peerversion > 32767) {
1523 msyslog(LOG_ERR,
1524 "invalid port number %s, trap ignored",
1525 tokens[i]);
1526 errflg = 1;
1528 break;
1530 case CONF_TRAP_INTERFACE:
1531 if (i >= ntokens-1) {
1532 msyslog(LOG_ERR,
1533 "trap interface requires an argument");
1534 errflg = 1;
1535 break;
1538 memset((char *)&maskaddr, 0,
1539 sizeof(maskaddr));
1540 maskaddr.ss_family = peeraddr.ss_family;
1541 if (getnetnum(tokens[++i],
1542 &maskaddr, 1, t_UNK) != 1) {
1543 errflg = 1;
1544 break;
1547 localaddr = findinterface(&maskaddr);
1548 if (localaddr == NULL) {
1549 msyslog(LOG_ERR,
1550 "can't find interface with address %s",
1551 stoa(&maskaddr));
1552 errflg = 1;
1554 break;
1556 case CONFIG_UNKNOWN:
1557 errflg++;
1558 break;
1561 if (!errflg) {
1562 if (peerversion != 0)
1563 ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion);
1564 else
1565 ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);
1566 if (localaddr == NULL)
1567 localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
1568 if (!ctlsettrap(&peeraddr, localaddr, 0,
1569 NTP_VERSION))
1570 msyslog(LOG_ERR,
1571 "can't set trap for %s, no resources",
1572 stoa(&peeraddr));
1574 break;
1576 case CONFIG_FUDGE:
1577 if (ntokens < 2) {
1578 msyslog(LOG_ERR,
1579 "no address for fudge command, line ignored");
1580 break;
1582 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1583 if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1)
1584 break;
1586 if (!ISREFCLOCKADR(&peeraddr)) {
1587 msyslog(LOG_ERR,
1588 "%s is inappropriate address for the fudge command, line ignored",
1589 stoa(&peeraddr));
1590 break;
1593 memset((void *)&clock_stat, 0, sizeof clock_stat);
1594 fudgeflag = 0;
1595 errflg = 0;
1596 for (i = 2; i < ntokens-1; i++) {
1597 switch (c = matchkey(tokens[i],
1598 fudge_keywords, 1)) {
1599 case CONF_FDG_TIME1:
1600 if (sscanf(tokens[++i], "%lf",
1601 &clock_stat.fudgetime1) != 1) {
1602 msyslog(LOG_ERR,
1603 "fudge %s time1 value in error",
1604 stoa(&peeraddr));
1605 errflg = i;
1606 break;
1608 clock_stat.haveflags |= CLK_HAVETIME1;
1609 break;
1611 case CONF_FDG_TIME2:
1612 if (sscanf(tokens[++i], "%lf",
1613 &clock_stat.fudgetime2) != 1) {
1614 msyslog(LOG_ERR,
1615 "fudge %s time2 value in error",
1616 stoa(&peeraddr));
1617 errflg = i;
1618 break;
1620 clock_stat.haveflags |= CLK_HAVETIME2;
1621 break;
1624 case CONF_FDG_STRATUM:
1625 if (!atoint(tokens[++i], &stratum))
1627 msyslog(LOG_ERR,
1628 "fudge %s stratum value in error",
1629 stoa(&peeraddr));
1630 errflg = i;
1631 break;
1633 clock_stat.fudgeval1 = stratum;
1634 clock_stat.haveflags |= CLK_HAVEVAL1;
1635 break;
1637 case CONF_FDG_REFID:
1638 i++;
1639 memcpy(&clock_stat.fudgeval2,
1640 tokens[i], min(strlen(tokens[i]),
1641 4));
1642 clock_stat.haveflags |= CLK_HAVEVAL2;
1643 break;
1645 case CONF_FDG_FLAG1:
1646 case CONF_FDG_FLAG2:
1647 case CONF_FDG_FLAG3:
1648 case CONF_FDG_FLAG4:
1649 if (!atouint(tokens[++i], &fudgeflag)
1650 || fudgeflag > 1) {
1651 msyslog(LOG_ERR,
1652 "fudge %s flag value in error",
1653 stoa(&peeraddr));
1654 errflg = i;
1655 break;
1657 switch(c) {
1658 case CONF_FDG_FLAG1:
1659 c = CLK_FLAG1;
1660 clock_stat.haveflags|=CLK_HAVEFLAG1;
1661 break;
1662 case CONF_FDG_FLAG2:
1663 c = CLK_FLAG2;
1664 clock_stat.haveflags|=CLK_HAVEFLAG2;
1665 break;
1666 case CONF_FDG_FLAG3:
1667 c = CLK_FLAG3;
1668 clock_stat.haveflags|=CLK_HAVEFLAG3;
1669 break;
1670 case CONF_FDG_FLAG4:
1671 c = CLK_FLAG4;
1672 clock_stat.haveflags|=CLK_HAVEFLAG4;
1673 break;
1675 if (fudgeflag == 0)
1676 clock_stat.flags &= ~c;
1677 else
1678 clock_stat.flags |= c;
1679 break;
1681 case CONFIG_UNKNOWN:
1682 errflg = -1;
1683 break;
1687 #ifdef REFCLOCK
1689 * If reference clock support isn't defined the
1690 * fudge line will still be accepted and syntax
1691 * checked, but will essentially do nothing.
1693 if (!errflg) {
1694 refclock_control(&peeraddr, &clock_stat,
1695 (struct refclockstat *)0);
1697 #endif
1698 break;
1700 case CONFIG_STATSDIR:
1701 if (ntokens >= 2)
1702 stats_config(STATS_STATSDIR,tokens[1]);
1703 break;
1705 case CONFIG_STATISTICS:
1706 for (i = 1; i < ntokens; i++) {
1707 filegen = filegen_get(tokens[i]);
1709 if (filegen == NULL) {
1710 msyslog(LOG_ERR,
1711 "no statistics named %s available",
1712 tokens[i]);
1713 continue;
1715 #ifdef DEBUG
1716 if (debug > 3)
1717 printf("enabling filegen for %s statistics \"%s%s\"\n",
1718 tokens[i], filegen->prefix, filegen->basename);
1719 #endif
1720 filegen->flag |= FGEN_FLAG_ENABLED;
1722 break;
1724 case CONFIG_FILEGEN:
1725 if (ntokens < 2) {
1726 msyslog(LOG_ERR,
1727 "no id for filegen command, line ignored");
1728 break;
1731 filegen = filegen_get(tokens[1]);
1732 if (filegen == NULL) {
1733 msyslog(LOG_ERR,
1734 "unknown filegen \"%s\" ignored",
1735 tokens[1]);
1736 break;
1739 * peerversion is (ab)used for filegen file (index)
1740 * peerkey is (ab)used for filegen type
1741 * peerflags is (ab)used for filegen flags
1743 peerversion = 0;
1744 peerkey = filegen->type;
1745 peerflags = filegen->flag;
1746 errflg = 0;
1748 for (i = 2; i < ntokens; i++) {
1749 switch (matchkey(tokens[i],
1750 filegen_keywords, 1)) {
1751 case CONF_FGEN_FILE:
1752 if (i >= ntokens - 1) {
1753 msyslog(LOG_ERR,
1754 "filegen %s file requires argument",
1755 tokens[1]);
1756 errflg = i;
1757 break;
1759 peerversion = ++i;
1760 break;
1761 case CONF_FGEN_TYPE:
1762 if (i >= ntokens -1) {
1763 msyslog(LOG_ERR,
1764 "filegen %s type requires argument",
1765 tokens[1]);
1766 errflg = i;
1767 break;
1769 peerkey = matchkey(tokens[++i],
1770 fgen_types, 1);
1771 if (peerkey == CONFIG_UNKNOWN) {
1772 msyslog(LOG_ERR,
1773 "filegen %s unknown type \"%s\"",
1774 tokens[1], tokens[i]);
1775 errflg = i;
1776 break;
1778 break;
1780 case CONF_FGEN_FLAG_LINK:
1781 peerflags |= FGEN_FLAG_LINK;
1782 break;
1784 case CONF_FGEN_FLAG_NOLINK:
1785 peerflags &= ~FGEN_FLAG_LINK;
1786 break;
1788 case CONF_FGEN_FLAG_ENABLE:
1789 peerflags |= FGEN_FLAG_ENABLED;
1790 break;
1792 case CONF_FGEN_FLAG_DISABLE:
1793 peerflags &= ~FGEN_FLAG_ENABLED;
1794 break;
1797 if (!errflg)
1798 filegen_config(filegen, tokens[peerversion],
1799 (u_char)peerkey, (u_char)peerflags);
1800 break;
1802 case CONFIG_SETVAR:
1803 if (ntokens < 2) {
1804 msyslog(LOG_ERR,
1805 "no value for setvar command - line ignored");
1806 } else {
1807 set_sys_var(tokens[1], strlen(tokens[1])+1,
1808 (u_short) (RW |
1809 ((((ntokens > 2)
1810 && !strcmp(tokens[2],
1811 "default")))
1812 ? DEF
1813 : 0)));
1815 break;
1817 case CONFIG_ENABLE:
1818 for (i = 1; i < ntokens; i++) {
1819 int flag;
1821 flag = matchkey(tokens[i], flags_keywords, 1);
1822 if (flag == CONFIG_UNKNOWN) {
1823 msyslog(LOG_ERR,
1824 "enable unknown flag %s",
1825 tokens[i]);
1826 errflg = 1;
1827 break;
1829 proto_config(flag, 1, 0., NULL);
1831 break;
1833 case CONFIG_DISABLE:
1834 for (i = 1; i < ntokens; i++) {
1835 int flag;
1837 flag = matchkey(tokens[i], flags_keywords, 1);
1838 if (flag == CONFIG_UNKNOWN) {
1839 msyslog(LOG_ERR,
1840 "disable unknown flag %s",
1841 tokens[i]);
1842 errflg = 1;
1843 break;
1845 proto_config(flag, 0, 0., NULL);
1847 break;
1849 case CONFIG_PHONE:
1850 for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) {
1851 sys_phone[i - 1] =
1852 emalloc(strlen(tokens[i]) + 1);
1853 strcpy(sys_phone[i - 1], tokens[i]);
1855 sys_phone[i] = NULL;
1856 break;
1858 case CONFIG_ADJ: {
1859 double ftemp;
1861 sscanf(tokens[1], "%lf", &ftemp);
1862 proto_config(PROTO_ADJ, 0, ftemp, NULL);
1864 break;
1868 if (fp[0])
1869 (void)fclose(fp[0]);
1871 #ifdef HAVE_NETINFO
1872 if (config_netinfo)
1873 free_netinfo_config(config_netinfo);
1874 #endif /* HAVE_NETINFO */
1876 #if !defined(VMS) && !defined(SYS_VXWORKS)
1877 /* find a keyid */
1878 if (info_auth_keyid == 0)
1879 req_keyid = 65535;
1880 else
1881 req_keyid = info_auth_keyid;
1883 /* if doesn't exist, make up one at random */
1884 if (!authhavekey(req_keyid)) {
1885 char rankey[9];
1886 int j;
1888 for (i = 0; i < 8; i++)
1889 for (j = 1; j < 100; ++j) {
1890 rankey[i] = (char) (ntp_random() & 0xff);
1891 if (rankey[i] != 0) break;
1893 rankey[8] = 0;
1894 authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
1895 authtrust(req_keyid, 1);
1896 if (!authhavekey(req_keyid)) {
1897 msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
1898 /* HMS: Should this be fatal? */
1902 /* save keyid so we will accept config requests with it */
1903 info_auth_keyid = req_keyid;
1904 #endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
1906 if (res_fp != NULL) {
1907 if (call_resolver) {
1909 * Need name resolution
1911 do_resolve_internal();
1917 #ifdef HAVE_NETINFO
1920 * get_netinfo_config - find the nearest NetInfo domain with an ntp
1921 * configuration and initialize the configuration state.
1923 static struct netinfo_config_state *
1924 get_netinfo_config()
1926 ni_status status;
1927 void *domain;
1928 ni_id config_dir;
1929 struct netinfo_config_state *config;
1931 if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
1933 while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
1934 void *next_domain;
1935 if (ni_open(domain, "..", &next_domain) != NI_OK) {
1936 ni_free(next_domain);
1937 break;
1939 ni_free(domain);
1940 domain = next_domain;
1942 if (status != NI_OK) {
1943 ni_free(domain);
1944 return NULL;
1947 config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
1948 config->domain = domain;
1949 config->config_dir = config_dir;
1950 config->prop_index = 0;
1951 config->val_index = 0;
1952 config->val_list = NULL;
1954 return config;
1960 * free_netinfo_config - release NetInfo configuration state
1962 static void
1963 free_netinfo_config(struct netinfo_config_state *config)
1965 ni_free(config->domain);
1966 free(config);
1972 * gettokens_netinfo - return tokens from NetInfo
1974 static int
1975 gettokens_netinfo (
1976 struct netinfo_config_state *config,
1977 char **tokenlist,
1978 int *ntokens
1981 int prop_index = config->prop_index;
1982 int val_index = config->val_index;
1983 char **val_list = config->val_list;
1986 * Iterate through each keyword and look for a property that matches it.
1988 again:
1989 if (!val_list) {
1990 for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
1992 ni_namelist namelist;
1993 struct keyword current_prop = keywords[prop_index];
1996 * For each value associated in the property, we're going to return
1997 * a separate line. We squirrel away the values in the config state
1998 * so the next time through, we don't need to do this lookup.
2000 NI_INIT(&namelist);
2001 if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
2002 ni_index index;
2004 /* Found the property, but it has no values */
2005 if (namelist.ni_namelist_len == 0) continue;
2007 if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
2008 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
2010 for (index = 0; index < namelist.ni_namelist_len; index++) {
2011 char *value = namelist.ni_namelist_val[index];
2013 if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
2014 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
2016 strcpy(val_list[index], value);
2018 val_list[index] = NULL;
2020 break;
2022 ni_namelist_free(&namelist);
2024 config->prop_index = prop_index;
2027 /* No list; we're done here. */
2028 if (!val_list) return CONFIG_UNKNOWN;
2031 * We have a list of values for the current property.
2032 * Iterate through them and return each in order.
2034 if (val_list[val_index])
2036 int ntok = 1;
2037 int quoted = 0;
2038 char *tokens = val_list[val_index];
2040 msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
2042 (const char*)tokenlist[0] = keywords[prop_index].text;
2043 for (ntok = 1; ntok < MAXTOKENS; ntok++) {
2044 tokenlist[ntok] = tokens;
2045 while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
2046 quoted ^= (*tokens++ == '"');
2048 if (ISEOL(*tokens)) {
2049 *tokens = '\0';
2050 break;
2051 } else { /* must be space */
2052 *tokens++ = '\0';
2053 while (ISSPACE(*tokens)) tokens++;
2054 if (ISEOL(*tokens)) break;
2058 if (ntok == MAXTOKENS) {
2059 /* HMS: chomp it to lose the EOL? */
2060 msyslog(LOG_ERR,
2061 "gettokens_netinfo: too many tokens. Ignoring: %s",
2062 tokens);
2063 } else {
2064 *ntokens = ntok + 1;
2067 config->val_index++; /* HMS: Should this be in the 'else'? */
2069 return keywords[prop_index].keytype;
2072 /* We're done with the current property. */
2073 prop_index = ++config->prop_index;
2075 /* Free val_list and reset counters. */
2076 for (val_index = 0; val_list[val_index]; val_index++)
2077 free(val_list[val_index]);
2078 free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0;
2080 goto again;
2083 #endif /* HAVE_NETINFO */
2087 * gettokens - read a line and return tokens
2089 static int
2090 gettokens (
2091 FILE *fp,
2092 char *line,
2093 char **tokenlist,
2094 int *ntokens
2097 register char *cp;
2098 register int ntok;
2099 register int quoted = 0;
2102 * Find start of first token
2104 again:
2105 while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
2106 cp = line;
2107 while (ISSPACE(*cp))
2108 cp++;
2109 if (!ISEOL(*cp))
2110 break;
2112 if (cp == NULL) {
2113 *ntokens = 0;
2114 return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
2118 * Now separate out the tokens
2120 for (ntok = 0; ntok < MAXTOKENS; ntok++) {
2121 tokenlist[ntok] = cp;
2122 while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
2123 quoted ^= (*cp++ == '"');
2125 if (ISEOL(*cp)) {
2126 *cp = '\0';
2127 break;
2128 } else { /* must be space */
2129 *cp++ = '\0';
2130 while (ISSPACE(*cp))
2131 cp++;
2132 if (ISEOL(*cp))
2133 break;
2137 /* Heiko: Remove leading and trailing quotes around tokens */
2139 int i,j = 0;
2142 for (i = 0; i < ntok; i++) {
2143 /* Now check if the first char is a quote and remove that */
2144 if ( tokenlist[ntok][0] == '"' )
2145 tokenlist[ntok]++;
2147 /* Now check the last char ... */
2148 j = strlen(tokenlist[ntok])-1;
2149 if ( tokenlist[ntok][j] == '"' )
2150 tokenlist[ntok][j] = '\0';
2155 if (ntok == MAXTOKENS) {
2156 --ntok;
2157 /* HMS: chomp it to lose the EOL? */
2158 msyslog(LOG_ERR,
2159 "gettokens: too many tokens on the line. Ignoring %s",
2160 cp);
2161 } else {
2163 * Return the match
2165 *ntokens = ntok + 1;
2166 ntok = matchkey(tokenlist[0], keywords, 1);
2167 if (ntok == CONFIG_UNKNOWN)
2168 goto again;
2171 return ntok;
2177 * matchkey - match a keyword to a list
2179 static int
2180 matchkey(
2181 register char *word,
2182 register struct keyword *keys,
2183 int complain
2186 for (;;) {
2187 if (keys->keytype == CONFIG_UNKNOWN) {
2188 if (complain)
2189 msyslog(LOG_ERR,
2190 "configure: keyword \"%s\" unknown, line ignored",
2191 word);
2192 return CONFIG_UNKNOWN;
2194 if (STRSAME(word, keys->text))
2195 return keys->keytype;
2196 keys++;
2202 * getnetnum - return a net number (this is crude, but careful)
2204 static int
2205 getnetnum(
2206 const char *num,
2207 struct sockaddr_storage *addr,
2208 int complain,
2209 enum gnn_type a_type
2212 struct addrinfo hints;
2213 struct addrinfo *ptr;
2214 int retval;
2216 #if 0
2217 printf("getnetnum: <%s> is a %s (%d)\n",
2218 num,
2219 (a_type == t_UNK)
2220 ? "t_UNK"
2221 : (a_type == t_REF)
2222 ? "t_REF"
2223 : (a_type == t_MSK)
2224 ? "t_MSK"
2225 : "???",
2226 a_type);
2227 #endif
2229 /* Get host address. Looking for UDP datagram connection */
2230 memset(&hints, 0, sizeof (hints));
2231 if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
2232 hints.ai_family = addr->ss_family;
2233 else
2234 hints.ai_family = AF_UNSPEC;
2236 * If we don't have an IPv6 stack, just look up IPv4 addresses
2238 if (isc_net_probeipv6() != ISC_R_SUCCESS)
2239 hints.ai_family = AF_INET;
2241 hints.ai_socktype = SOCK_DGRAM;
2243 if (a_type != t_UNK) {
2244 hints.ai_flags = AI_NUMERICHOST;
2247 #ifdef DEBUG
2248 if (debug > 3)
2249 printf("getnetnum: calling getaddrinfo(%s,...)\n", num);
2250 #endif
2251 retval = getaddrinfo(num, "ntp", &hints, &ptr);
2252 if (retval != 0 ||
2253 (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
2254 if (complain)
2255 msyslog(LOG_ERR,
2256 "getaddrinfo: \"%s\" invalid host address, ignored",
2257 num);
2258 #ifdef DEBUG
2259 if (debug > 0)
2260 printf(
2261 "getaddrinfo: \"%s\" invalid host address%s.\n",
2262 num, (complain)
2263 ? ", ignored"
2264 : "");
2265 #endif
2266 if (retval == 0 &&
2267 ptr->ai_family == AF_INET6 &&
2268 isc_net_probeipv6() != ISC_R_SUCCESS)
2270 return -1;
2272 else {
2273 return 0;
2277 memcpy(addr, ptr->ai_addr, ptr->ai_addrlen);
2278 #ifdef DEBUG
2279 if (debug > 1)
2280 printf("getnetnum given %s, got %s (%s/%d)\n",
2281 num, stoa(addr),
2282 (a_type == t_UNK)
2283 ? "t_UNK"
2284 : (a_type == t_REF)
2285 ? "t_REF"
2286 : (a_type == t_MSK)
2287 ? "t_MSK"
2288 : "???",
2289 a_type);
2290 #endif
2291 freeaddrinfo(ptr);
2292 return 1;
2296 #if !defined(VMS) && !defined(SYS_WINNT)
2298 * catchchild - receive the resolver's exit status
2300 static RETSIGTYPE
2301 catchchild(
2302 int sig
2306 * We only start up one child, and if we're here
2307 * it should have already exited. Hence the following
2308 * shouldn't hang. If it does, please tell me.
2310 #if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
2311 (void) wait(0);
2312 #endif /* SYS_WINNT && VXWORKS*/
2314 #endif /* VMS */
2318 * save_resolve - save configuration info into a file for later name resolution
2320 static void
2321 save_resolve(
2322 char *name,
2323 int mode,
2324 int version,
2325 int minpoll,
2326 int maxpoll,
2327 u_int flags,
2328 int ttl,
2329 keyid_t keyid,
2330 u_char *keystr
2333 #ifndef SYS_VXWORKS
2334 if (res_fp == NULL) {
2335 #ifndef SYS_WINNT
2336 (void) strcpy(res_file, RES_TEMPFILE);
2337 #else
2338 /* no /tmp directory under NT */
2340 if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
2341 msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
2342 return;
2344 (void) strcat(res_file, "ntpdXXXXXX");
2346 #endif /* SYS_WINNT */
2347 #ifdef HAVE_MKSTEMP
2349 int fd;
2351 res_fp = NULL;
2352 if ((fd = mkstemp(res_file)) != -1)
2353 res_fp = fdopen(fd, "r+");
2355 #else
2356 (void) mktemp(res_file);
2357 res_fp = fopen(res_file, "w");
2358 #endif
2359 if (res_fp == NULL) {
2360 msyslog(LOG_ERR, "open failed for %s: %m", res_file);
2361 return;
2364 #ifdef DEBUG
2365 if (debug) {
2366 printf("resolving %s\n", name);
2368 #endif
2370 (void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %s\n", name,
2371 mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2372 #ifdef DEBUG
2373 if (debug > 1)
2374 printf("config: %s %d %d %d %d %x %d %u %s\n", name, mode,
2375 version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2376 #endif
2378 #else /* SYS_VXWORKS */
2379 /* save resolve info to a struct */
2380 #endif /* SYS_VXWORKS */
2385 * abort_resolve - terminate the resolver stuff and delete the file
2387 static void
2388 abort_resolve(void)
2391 * In an ideal world we would might reread the file and
2392 * log the hosts which aren't getting configured. Since
2393 * this is too much work, however, just close and delete
2394 * the temp file.
2396 if (res_fp != NULL)
2397 (void) fclose(res_fp);
2398 res_fp = NULL;
2400 #ifndef SYS_VXWORKS /* we don't open the file to begin with */
2401 #if !defined(VMS)
2402 (void) unlink(res_file);
2403 #else
2404 (void) delete(res_file);
2405 #endif /* VMS */
2406 #endif /* SYS_VXWORKS */
2411 * do_resolve_internal - start up the resolver function (not program)
2414 * On VMS, this routine will simply refuse to resolve anything.
2416 * Possible implementation: keep `res_file' in memory, do async
2417 * name resolution via QIO, update from within completion AST.
2418 * I'm unlikely to find the time for doing this, though. -wjm
2420 static void
2421 do_resolve_internal(void)
2423 int i;
2425 if (res_fp == NULL) {
2426 /* belch */
2427 msyslog(LOG_ERR,
2428 "do_resolve_internal: Fatal: res_fp == NULL");
2429 exit(1);
2432 /* we are done with this now */
2433 (void) fclose(res_fp);
2434 res_fp = NULL;
2436 #if !defined(VMS) && !defined (SYS_VXWORKS)
2437 req_file = res_file; /* set up pointer to res file */
2438 #ifndef SYS_WINNT
2439 (void) signal_no_reset(SIGCHLD, catchchild);
2441 #ifndef SYS_VXWORKS
2442 /* the parent process will write to the pipe
2443 * in order to wake up to child process
2444 * which may be waiting in a select() call
2445 * on the read fd */
2446 if (pipe(resolver_pipe_fd) < 0) {
2447 msyslog(LOG_ERR,
2448 "unable to open resolver pipe");
2449 exit(1);
2452 i = fork();
2453 /* Shouldn't the code below be re-ordered?
2454 * I.e. first check if the fork() returned an error, then
2455 * check whether we're parent or child.
2456 * Martin Burnicki
2458 if (i == 0) {
2460 * this used to close everything
2461 * I don't think this is necessary
2464 * To the unknown commenter above:
2465 * Well, I think it's better to clean up
2466 * after oneself. I have had problems with
2467 * refclock-io when intres was running - things
2468 * where fine again when ntpintres was gone.
2469 * So some systems react erratic at least.
2471 * Frank Kardel
2473 * 94-11-16:
2474 * Further debugging has proven that the above is
2475 * absolutely harmful. The internal resolver
2476 * is still in the SIGIO process group and the lingering
2477 * async io information causes it to process requests from
2478 * all file decriptor causing a race between the NTP daemon
2479 * and the resolver. which then eats data when it wins 8-(.
2480 * It is absolutly necessary to kill any IO associations
2481 * shared with the NTP daemon.
2483 * We also block SIGIO (currently no ports means to
2484 * disable the signal handle for IO).
2486 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
2487 * that it is the ntp-resolver child running into trouble.
2489 * THUS:
2492 /* This is the child process who will read the pipe,
2493 * so we close the write fd */
2494 close(resolver_pipe_fd[1]);
2495 closelog();
2496 kill_asyncio(0);
2498 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2500 #ifdef DEBUG
2501 if (0)
2502 debug = 2;
2503 #endif
2505 # ifndef LOG_DAEMON
2506 openlog("ntpd_initres", LOG_PID);
2507 # else /* LOG_DAEMON */
2509 # ifndef LOG_NTP
2510 # define LOG_NTP LOG_DAEMON
2511 # endif
2512 openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
2513 #ifndef SYS_CYGWIN32
2514 # ifdef DEBUG
2515 if (debug)
2516 setlogmask(LOG_UPTO(LOG_DEBUG));
2517 else
2518 # endif /* DEBUG */
2519 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
2520 # endif /* LOG_DAEMON */
2521 #endif
2523 ntp_intres();
2526 * If we got here, the intres code screwed up.
2527 * Print something so we don't die without complaint
2529 msyslog(LOG_ERR, "call to ntp_intres lost");
2530 abort_resolve();
2531 exit(1);
2533 #else
2534 /* vxWorks spawns a thread... -casey */
2535 i = sp (ntp_intres);
2536 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
2537 #endif
2538 if (i == -1) {
2539 msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
2540 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2541 abort_resolve();
2543 else {
2544 /* This is the parent process who will write to the pipe,
2545 * so we close the read fd */
2546 close(resolver_pipe_fd[0]);
2548 #else /* SYS_WINNT */
2550 /* NT's equivalent of fork() is _spawn(), but the start point
2551 * of the new process is an executable filename rather than
2552 * a function name as desired here.
2554 DWORD dwThreadId;
2555 fflush(stdout);
2556 ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
2557 if (ResolverEventHandle == NULL) {
2558 msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
2559 abort_resolve();
2561 ResolverThreadHandle = CreateThread(
2562 NULL, /* no security attributes */
2563 0, /* use default stack size */
2564 (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */
2565 NULL, /* argument to thread function */
2566 0, /* use default creation flags */
2567 &dwThreadId); /* returns the thread identifier */
2568 if (ResolverThreadHandle == NULL) {
2569 msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
2570 CloseHandle(ResolverEventHandle);
2571 ResolverEventHandle = NULL;
2572 abort_resolve();
2575 #endif /* SYS_WINNT */
2576 #else /* VMS VX_WORKS */
2577 msyslog(LOG_ERR,
2578 "Name resolution not implemented for VMS - use numeric addresses");
2579 abort_resolve();
2580 #endif /* VMS VX_WORKS */