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