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