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