]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/ntp_config.c
MFV r362565:
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / ntp_config.c
1 /* ntp_config.c
2  *
3  * This file contains the ntpd configuration code.
4  *
5  * Written By:  Sachin Kamboj
6  *              University of Delaware
7  *              Newark, DE 19711
8  * Some parts borrowed from the older ntp_config.c
9  * Copyright (c) 2006
10  */
11
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #ifdef HAVE_NETINFO
17 # include <netinfo/ni.h>
18 #endif
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #ifdef HAVE_SYS_PARAM_H
23 # include <sys/param.h>
24 #endif
25 #include <signal.h>
26 #ifndef SIGCHLD
27 # define SIGCHLD SIGCLD
28 #endif
29 #ifdef HAVE_SYS_WAIT_H
30 # include <sys/wait.h>
31 #endif
32 #include <time.h>
33
34 #include <isc/net.h>
35 #include <isc/result.h>
36
37 #include "ntp.h"
38 #include "ntpd.h"
39 #include "ntp_io.h"
40 #include "ntp_unixtime.h"
41 #include "ntp_refclock.h"
42 #include "ntp_filegen.h"
43 #include "ntp_stdlib.h"
44 #include "lib_strbuf.h"
45 #include "ntp_assert.h"
46 #include "ntp_random.h"
47 /*
48  * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
49  * so #include these later.
50  */
51 #include "ntp_config.h"
52 #include "ntp_cmdargs.h"
53 #include "ntp_scanner.h"
54 #include "ntp_parser.h"
55 #include "ntpd-opts.h"
56
57 #ifndef IGNORE_DNS_ERRORS
58 # define DNSFLAGS 0
59 #else
60 # define DNSFLAGS GAIR_F_IGNDNSERR
61 #endif
62
63 extern int yyparse(void);
64
65 /* Bug 2817 */
66 #if defined(HAVE_SYS_MMAN_H)
67 # include <sys/mman.h>
68 #endif
69
70 /* list of servers from command line for config_peers() */
71 int     cmdline_server_count;
72 char ** cmdline_servers;
73
74 /* Current state of memory locking:
75  * -1: default
76  *  0: memory locking disabled
77  *  1: Memory locking enabled
78  */
79 int     cur_memlock = -1;
80
81 /*
82  * "logconfig" building blocks
83  */
84 struct masks {
85         const char * const      name;
86         const u_int32           mask;
87 };
88
89 static struct masks logcfg_class[] = {
90         { "clock",      NLOG_OCLOCK },
91         { "peer",       NLOG_OPEER },
92         { "sync",       NLOG_OSYNC },
93         { "sys",        NLOG_OSYS },
94         { NULL,         0 }
95 };
96
97 /* logcfg_noclass_items[] masks are complete and must not be shifted */
98 static struct masks logcfg_noclass_items[] = {
99         { "allall",             NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK },
100         { "allinfo",            NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO },
101         { "allevents",          NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT },
102         { "allstatus",          NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS },
103         { "allstatistics",      NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST },
104         /* the remainder are misspellings of clockall, peerall, sysall, and syncall. */
105         { "allclock",           (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK },
106         { "allpeer",            (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER },
107         { "allsys",             (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS },
108         { "allsync",            (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC },
109         { NULL,                 0 }
110 };
111
112 /* logcfg_class_items[] masks are shiftable by NLOG_O* counts */
113 static struct masks logcfg_class_items[] = {
114         { "all",                NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST },
115         { "info",               NLOG_INFO },
116         { "events",             NLOG_EVENT },
117         { "status",             NLOG_STATUS },
118         { "statistics",         NLOG_STATIST },
119         { NULL,                 0 }
120 };
121
122 typedef struct peer_resolved_ctx_tag {
123         int             flags;
124         int             host_mode;      /* T_* token identifier */
125         u_short         family;
126         keyid_t         keyid;
127         u_char          hmode;          /* MODE_* */
128         u_char          version;
129         u_char          minpoll;
130         u_char          maxpoll;
131         u_int32         ttl;
132         const char *    group;
133 } peer_resolved_ctx;
134
135 /* Limits */
136 #define MAXPHONE        10      /* maximum number of phone strings */
137 #define MAXPPS          20      /* maximum length of PPS device string */
138
139 /*
140  * Poll Skew List
141  */
142
143 static psl_item psl[17-3+1];    /* values for polls 3-17 */
144                                 /* To simplify the runtime code we */
145                                 /* don't want to have to special-case */
146                                 /* dealing with a default */
147
148
149 /*
150  * Miscellaneous macros
151  */
152 #define ISEOL(c)        ((c) == '#' || (c) == '\n' || (c) == '\0')
153 #define ISSPACE(c)      ((c) == ' ' || (c) == '\t')
154
155 #define _UC(str)        ((char *)(intptr_t)(str))
156
157 /*
158  * Definitions of things either imported from or exported to outside
159  */
160 extern int yydebug;                     /* ntp_parser.c (.y) */
161 config_tree cfgt;                       /* Parser output stored here */
162 config_tree *cfg_tree_history;          /* History of configs */
163 char *  sys_phone[MAXPHONE] = {NULL};   /* ACTS phone numbers */
164 char    default_keysdir[] = NTP_KEYSDIR;
165 char *  keysdir = default_keysdir;      /* crypto keys directory */
166 char *  saveconfigdir;
167 #if defined(HAVE_SCHED_SETSCHEDULER)
168 int     config_priority_override = 0;
169 int     config_priority;
170 #endif
171
172 const char *config_file;
173 static char default_ntp_signd_socket[] =
174 #ifdef NTP_SIGND_PATH
175                                         NTP_SIGND_PATH;
176 #else
177                                         "";
178 #endif
179 char *ntp_signd_socket = default_ntp_signd_socket;
180 #ifdef HAVE_NETINFO
181 struct netinfo_config_state *config_netinfo = NULL;
182 int check_netinfo = 1;
183 #endif /* HAVE_NETINFO */
184 #ifdef SYS_WINNT
185 char *alt_config_file;
186 LPTSTR temp;
187 char config_file_storage[MAX_PATH];
188 char alt_config_file_storage[MAX_PATH];
189 #endif /* SYS_WINNT */
190
191 #ifdef HAVE_NETINFO
192 /*
193  * NetInfo configuration state
194  */
195 struct netinfo_config_state {
196         void *domain;           /* domain with config */
197         ni_id config_dir;       /* ID config dir      */
198         int prop_index;         /* current property   */
199         int val_index;          /* current value      */
200         char **val_list;        /* value list         */
201 };
202 #endif
203
204 struct REMOTE_CONFIG_INFO remote_config;  /* Remote configuration buffer and
205                                              pointer info */
206 int old_config_style = 1;    /* A boolean flag, which when set,
207                               * indicates that the old configuration
208                               * format with a newline at the end of
209                               * every command is being used
210                               */
211 int     cryptosw;               /* crypto command called */
212
213 extern char *stats_drift_file;  /* name of the driftfile */
214
215 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
216 /*
217  * backwards compatibility flags
218  */
219 bc_entry bc_list[] = {
220         { T_Bc_bugXXXX,         1       }       /* default enabled */
221 };
222
223 /*
224  * declare an int pointer for each flag for quick testing without
225  * walking bc_list.  If the pointer is consumed by libntp rather
226  * than ntpd, declare it in a libntp source file pointing to storage
227  * initialized with the appropriate value for other libntp clients, and
228  * redirect it to point into bc_list during ntpd startup.
229  */
230 int *p_bcXXXX_enabled = &bc_list[0].enabled;
231 #endif
232
233 /* FUNCTION PROTOTYPES */
234
235 static void init_syntax_tree(config_tree *);
236 static void apply_enable_disable(attr_val_fifo *q, int enable);
237
238 #ifdef FREE_CFG_T
239 static void free_auth_node(config_tree *);
240 static void free_all_config_trees(void);
241
242 static void free_config_access(config_tree *);
243 static void free_config_auth(config_tree *);
244 static void free_config_fudge(config_tree *);
245 static void free_config_logconfig(config_tree *);
246 static void free_config_monitor(config_tree *);
247 static void free_config_nic_rules(config_tree *);
248 static void free_config_other_modes(config_tree *);
249 static void free_config_peers(config_tree *);
250 static void free_config_phone(config_tree *);
251 static void free_config_reset_counters(config_tree *);
252 static void free_config_rlimit(config_tree *);
253 static void free_config_setvar(config_tree *);
254 static void free_config_system_opts(config_tree *);
255 static void free_config_tinker(config_tree *);
256 static void free_config_tos(config_tree *);
257 static void free_config_trap(config_tree *);
258 static void free_config_ttl(config_tree *);
259 static void free_config_unpeers(config_tree *);
260 static void free_config_vars(config_tree *);
261
262 #ifdef SIM
263 static void free_config_sim(config_tree *);
264 #endif
265 static void destroy_address_fifo(address_fifo *);
266 #define FREE_ADDRESS_FIFO(pf)                   \
267         do {                                    \
268                 destroy_address_fifo(pf);       \
269                 (pf) = NULL;                    \
270         } while (0)
271        void free_all_config_trees(void);        /* atexit() */
272 static void free_config_tree(config_tree *ptree);
273 #endif  /* FREE_CFG_T */
274
275 static void destroy_restrict_node(restrict_node *my_node);
276 static int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
277 static void save_and_apply_config_tree(int/*BOOL*/ from_file);
278 static void destroy_int_fifo(int_fifo *);
279 #define FREE_INT_FIFO(pf)                       \
280         do {                                    \
281                 destroy_int_fifo(pf);           \
282                 (pf) = NULL;                    \
283         } while (0)
284 static void destroy_string_fifo(string_fifo *);
285 #define FREE_STRING_FIFO(pf)                    \
286         do {                                    \
287                 destroy_string_fifo(pf);                \
288                 (pf) = NULL;                    \
289         } while (0)
290 static void destroy_attr_val_fifo(attr_val_fifo *);
291 #define FREE_ATTR_VAL_FIFO(pf)                  \
292         do {                                    \
293                 destroy_attr_val_fifo(pf);      \
294                 (pf) = NULL;                    \
295         } while (0)
296 static void destroy_filegen_fifo(filegen_fifo *);
297 #define FREE_FILEGEN_FIFO(pf)                   \
298         do {                                    \
299                 destroy_filegen_fifo(pf);       \
300                 (pf) = NULL;                    \
301         } while (0)
302 static void destroy_restrict_fifo(restrict_fifo *);
303 #define FREE_RESTRICT_FIFO(pf)                  \
304         do {                                    \
305                 destroy_restrict_fifo(pf);      \
306                 (pf) = NULL;                    \
307         } while (0)
308 static void destroy_setvar_fifo(setvar_fifo *);
309 #define FREE_SETVAR_FIFO(pf)                    \
310         do {                                    \
311                 destroy_setvar_fifo(pf);        \
312                 (pf) = NULL;                    \
313         } while (0)
314 static void destroy_addr_opts_fifo(addr_opts_fifo *);
315 #define FREE_ADDR_OPTS_FIFO(pf)                 \
316         do {                                    \
317                 destroy_addr_opts_fifo(pf);     \
318                 (pf) = NULL;                    \
319         } while (0)
320
321 static void config_logconfig(config_tree *);
322 static void config_monitor(config_tree *);
323 static void config_rlimit(config_tree *);
324 static void config_system_opts(config_tree *);
325 static void config_tinker(config_tree *);
326 static int  config_tos_clock(config_tree *);
327 static void config_tos(config_tree *);
328 static void config_vars(config_tree *);
329
330 #ifdef SIM
331 static sockaddr_u *get_next_address(address_node *addr);
332 static void config_sim(config_tree *);
333 static void config_ntpdsim(config_tree *);
334 #else   /* !SIM follows */
335 static void config_ntpd(config_tree *, int/*BOOL*/ input_from_file);
336 static void config_other_modes(config_tree *);
337 static void config_auth(config_tree *);
338 static void attrtopsl(int poll, attr_val *avp);
339 static void config_access(config_tree *);
340 static void config_mdnstries(config_tree *);
341 static void config_phone(config_tree *);
342 static void config_setvar(config_tree *);
343 static void config_ttl(config_tree *);
344 static void config_trap(config_tree *);
345 static void config_fudge(config_tree *);
346 static void config_peers(config_tree *);
347 static void config_unpeers(config_tree *);
348 static void config_nic_rules(config_tree *, int/*BOOL*/ input_from_file);
349 static void config_reset_counters(config_tree *);
350 static u_char get_correct_host_mode(int token);
351 static int peerflag_bits(peer_node *);
352 #endif  /* !SIM */
353
354 #ifdef WORKER
355 static void peer_name_resolved(int, int, void *, const char *, const char *,
356                         const struct addrinfo *,
357                         const struct addrinfo *);
358 static void unpeer_name_resolved(int, int, void *, const char *, const char *,
359                           const struct addrinfo *,
360                           const struct addrinfo *);
361 static void trap_name_resolved(int, int, void *, const char *, const char *,
362                         const struct addrinfo *,
363                         const struct addrinfo *);
364 #endif
365
366 enum gnn_type {
367         t_UNK,          /* Unknown */
368         t_REF,          /* Refclock */
369         t_MSK           /* Network Mask */
370 };
371
372 static void ntpd_set_tod_using(const char *);
373 static char * normal_dtoa(double);
374 static u_int32 get_pfxmatch(const char **, struct masks *);
375 static u_int32 get_match(const char *, struct masks *);
376 static u_int32 get_logmask(const char *);
377 static int/*BOOL*/ is_refclk_addr(const address_node * addr);
378
379 static void     appendstr(char *, size_t, const char *);
380
381
382 #ifndef SIM
383 static int getnetnum(const char *num, sockaddr_u *addr, int complain,
384                      enum gnn_type a_type);
385
386 #endif
387
388 #if defined(__GNUC__) /* this covers CLANG, too */
389 static void  __attribute__((noreturn,format(printf,1,2))) fatal_error(const char *fmt, ...)
390 #elif defined(_MSC_VER)
391 static void __declspec(noreturn) fatal_error(const char *fmt, ...)
392 #else
393 static void fatal_error(const char *fmt, ...)
394 #endif
395 {
396         va_list va;
397
398         va_start(va, fmt);
399         mvsyslog(LOG_EMERG, fmt, va);
400         va_end(va);
401         _exit(1);
402 }
403
404
405 /* FUNCTIONS FOR INITIALIZATION
406  * ----------------------------
407  */
408
409 #ifdef FREE_CFG_T
410 static void
411 free_auth_node(
412         config_tree *ptree
413         )
414 {
415         if (ptree->auth.keys) {
416                 free(ptree->auth.keys);
417                 ptree->auth.keys = NULL;
418         }
419
420         if (ptree->auth.keysdir) {
421                 free(ptree->auth.keysdir);
422                 ptree->auth.keysdir = NULL;
423         }
424
425         if (ptree->auth.ntp_signd_socket) {
426                 free(ptree->auth.ntp_signd_socket);
427                 ptree->auth.ntp_signd_socket = NULL;
428         }
429 }
430 #endif /* DEBUG */
431
432
433 static void
434 init_syntax_tree(
435         config_tree *ptree
436         )
437 {
438         ZERO(*ptree);
439         ptree->mdnstries = 5;
440 }
441
442
443 #ifdef FREE_CFG_T
444 static void
445 free_all_config_trees(void)
446 {
447         config_tree *ptree;
448         config_tree *pnext;
449
450         ptree = cfg_tree_history;
451
452         while (ptree != NULL) {
453                 pnext = ptree->link;
454                 free_config_tree(ptree);
455                 ptree = pnext;
456         }
457 }
458
459
460 static void
461 free_config_tree(
462         config_tree *ptree
463         )
464 {
465 #if defined(_MSC_VER) && defined (_DEBUG)
466         _CrtCheckMemory();
467 #endif
468
469         if (ptree->source.value.s != NULL)
470                 free(ptree->source.value.s);
471
472         free_config_other_modes(ptree);
473         free_config_auth(ptree);
474         free_config_tos(ptree);
475         free_config_monitor(ptree);
476         free_config_access(ptree);
477         free_config_tinker(ptree);
478         free_config_rlimit(ptree);
479         free_config_system_opts(ptree);
480         free_config_logconfig(ptree);
481         free_config_phone(ptree);
482         free_config_setvar(ptree);
483         free_config_ttl(ptree);
484         free_config_trap(ptree);
485         free_config_fudge(ptree);
486         free_config_vars(ptree);
487         free_config_peers(ptree);
488         free_config_unpeers(ptree);
489         free_config_nic_rules(ptree);
490         free_config_reset_counters(ptree);
491 #ifdef SIM
492         free_config_sim(ptree);
493 #endif
494         free_auth_node(ptree);
495
496         free(ptree);
497
498 #if defined(_MSC_VER) && defined (_DEBUG)
499         _CrtCheckMemory();
500 #endif
501 }
502 #endif /* FREE_CFG_T */
503
504
505 #ifdef SAVECONFIG
506 /* Dump all trees */
507 int
508 dump_all_config_trees(
509         FILE *df,
510         int comment
511         )
512 {
513         config_tree *   cfg_ptr;
514         int             return_value;
515         time_t          now = time(NULL);
516         struct tm       tm = *localtime(&now);
517
518         fprintf(df, "#NTF:D %04d%02d%02d@%02d:%02d:%02d\n",
519                 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
520                 tm.tm_hour, tm.tm_min, tm.tm_sec);
521         fprintf(df, "#NTF:V %s\n", Version);
522
523         return_value = 0;
524         for (cfg_ptr = cfg_tree_history;
525              cfg_ptr != NULL;
526              cfg_ptr = cfg_ptr->link)
527                 return_value |= dump_config_tree(cfg_ptr, df, comment);
528
529         return return_value;
530 }
531
532
533 /* The config dumper */
534 int
535 dump_config_tree(
536         config_tree *ptree,
537         FILE *df,
538         int comment
539         )
540 {
541         peer_node *peern;
542         unpeer_node *unpeern;
543         attr_val *atrv;
544         address_node *addr;
545         address_node *peer_addr;
546         address_node *fudge_addr;
547         filegen_node *fgen_node;
548         restrict_node *rest_node;
549         addr_opts_node *addr_opts;
550         setvar_node *setv_node;
551         nic_rule_node *rule_node;
552         int_node *i_n;
553         int_node *counter_set;
554         string_node *str_node;
555
556         const char *s = NULL;
557         char *s1;
558         char *s2;
559         char timestamp[80];
560         int enable;
561
562         DPRINTF(1, ("dump_config_tree(%p)\n", ptree));
563
564         if (comment) {
565                 if (!strftime(timestamp, sizeof(timestamp),
566                               "%Y-%m-%d %H:%M:%S",
567                               localtime(&ptree->timestamp)))
568                         timestamp[0] = '\0';
569
570                 fprintf(df, "# %s %s %s\n",
571                         timestamp,
572                         (CONF_SOURCE_NTPQ == ptree->source.attr)
573                             ? "ntpq remote config from"
574                             : "startup configuration file",
575                         ptree->source.value.s);
576         }
577
578         /*
579          * For options without documentation we just output the name
580          * and its data value
581          */
582         atrv = HEAD_PFIFO(ptree->vars);
583         for ( ; atrv != NULL; atrv = atrv->link) {
584                 switch (atrv->type) {
585 #ifdef DEBUG
586                 default:
587                         fprintf(df, "\n# dump error:\n"
588                                 "# unknown vars type %d (%s) for %s\n",
589                                 atrv->type, token_name(atrv->type),
590                                 token_name(atrv->attr));
591                         break;
592 #endif
593                 case T_Double:
594                         fprintf(df, "%s %s\n", keyword(atrv->attr),
595                                 normal_dtoa(atrv->value.d));
596                         break;
597
598                 case T_Integer:
599                         fprintf(df, "%s %d\n", keyword(atrv->attr),
600                                 atrv->value.i);
601                         break;
602
603                 case T_String:
604                         fprintf(df, "%s \"%s\"", keyword(atrv->attr),
605                                 atrv->value.s);
606                         if (T_Driftfile == atrv->attr &&
607                             atrv->link != NULL &&
608                             T_WanderThreshold == atrv->link->attr) {
609                                 atrv = atrv->link;
610                                 fprintf(df, " %s\n",
611                                         normal_dtoa(atrv->value.d));
612                         } else if (T_Leapfile == atrv->attr) {
613                                 fputs((atrv->flag
614                                        ? " checkhash\n"
615                                        : " ignorehash\n"),
616                                       df);
617                         } else {
618                                 fprintf(df, "\n");
619                         }
620                         break;
621                 }
622         }
623
624         atrv = HEAD_PFIFO(ptree->logconfig);
625         if (atrv != NULL) {
626                 fprintf(df, "logconfig");
627                 for ( ; atrv != NULL; atrv = atrv->link)
628                         fprintf(df, " %c%s", atrv->attr, atrv->value.s);
629                 fprintf(df, "\n");
630         }
631
632         if (ptree->stats_dir)
633                 fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir);
634
635         i_n = HEAD_PFIFO(ptree->stats_list);
636         if (i_n != NULL) {
637                 fprintf(df, "statistics");
638                 for ( ; i_n != NULL; i_n = i_n->link)
639                         fprintf(df, " %s", keyword(i_n->i));
640                 fprintf(df, "\n");
641         }
642
643         fgen_node = HEAD_PFIFO(ptree->filegen_opts);
644         for ( ; fgen_node != NULL; fgen_node = fgen_node->link) {
645                 atrv = HEAD_PFIFO(fgen_node->options);
646                 if (atrv != NULL) {
647                         fprintf(df, "filegen %s",
648                                 keyword(fgen_node->filegen_token));
649                         for ( ; atrv != NULL; atrv = atrv->link) {
650                                 switch (atrv->attr) {
651 #ifdef DEBUG
652                                 default:
653                                         fprintf(df, "\n# dump error:\n"
654                                                 "# unknown filegen option token %s\n"
655                                                 "filegen %s",
656                                                 token_name(atrv->attr),
657                                                 keyword(fgen_node->filegen_token));
658                                         break;
659 #endif
660                                 case T_File:
661                                         fprintf(df, " file %s",
662                                                 atrv->value.s);
663                                         break;
664
665                                 case T_Type:
666                                         fprintf(df, " type %s",
667                                                 keyword(atrv->value.i));
668                                         break;
669
670                                 case T_Flag:
671                                         fprintf(df, " %s",
672                                                 keyword(atrv->value.i));
673                                         break;
674                                 }
675                         }
676                         fprintf(df, "\n");
677                 }
678         }
679
680         atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
681         if (atrv != NULL) {
682                 fprintf(df, "crypto");
683                 for ( ; atrv != NULL; atrv = atrv->link) {
684                         fprintf(df, " %s %s", keyword(atrv->attr),
685                                 atrv->value.s);
686                 }
687                 fprintf(df, "\n");
688         }
689
690         if (ptree->auth.revoke != 0)
691                 fprintf(df, "revoke %d\n", ptree->auth.revoke);
692
693         if (ptree->auth.keysdir != NULL)
694                 fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir);
695
696         if (ptree->auth.keys != NULL)
697                 fprintf(df, "keys \"%s\"\n", ptree->auth.keys);
698
699         atrv = HEAD_PFIFO(ptree->auth.trusted_key_list);
700         if (atrv != NULL) {
701                 fprintf(df, "trustedkey");
702                 for ( ; atrv != NULL; atrv = atrv->link) {
703                         if (T_Integer == atrv->type)
704                                 fprintf(df, " %d", atrv->value.i);
705                         else if (T_Intrange == atrv->type)
706                                 fprintf(df, " (%d ... %d)",
707                                         atrv->value.r.first,
708                                         atrv->value.r.last);
709 #ifdef DEBUG
710                         else
711                                 fprintf(df, "\n# dump error:\n"
712                                         "# unknown trustedkey attr type %d\n"
713                                         "trustedkey", atrv->type);
714 #endif
715                 }
716                 fprintf(df, "\n");
717         }
718
719         if (ptree->auth.control_key)
720                 fprintf(df, "controlkey %d\n", ptree->auth.control_key);
721
722         if (ptree->auth.request_key)
723                 fprintf(df, "requestkey %d\n", ptree->auth.request_key);
724
725         /* dump enable list, then disable list */
726         for (enable = 1; enable >= 0; enable--) {
727                 atrv = (enable)
728                            ? HEAD_PFIFO(ptree->enable_opts)
729                            : HEAD_PFIFO(ptree->disable_opts);
730                 if (atrv != NULL) {
731                         fprintf(df, "%s", (enable)
732                                         ? "enable"
733                                         : "disable");
734                         for ( ; atrv != NULL; atrv = atrv->link)
735                                 fprintf(df, " %s",
736                                         keyword(atrv->value.i));
737                         fprintf(df, "\n");
738                 }
739         }
740
741         atrv = HEAD_PFIFO(ptree->orphan_cmds);
742         if (atrv != NULL) {
743                 fprintf(df, "tos");
744                 for ( ; atrv != NULL; atrv = atrv->link) {
745                         switch (atrv->type) {
746 #ifdef DEBUG
747                         default:
748                                 fprintf(df, "\n# dump error:\n"
749                                         "# unknown tos attr type %d %s\n"
750                                         "tos", atrv->type,
751                                         token_name(atrv->type));
752                                 break;
753 #endif
754                         case T_Integer:
755                                 if (atrv->attr == T_Basedate) {
756                                         struct calendar jd;
757                                         ntpcal_rd_to_date(&jd, atrv->value.i + DAY_NTP_STARTS);
758                                         fprintf(df, " %s \"%04hu-%02hu-%02hu\"",
759                                                 keyword(atrv->attr), jd.year,
760                                                 (u_short)jd.month,
761                                                 (u_short)jd.monthday);
762                                 } else {
763                                         fprintf(df, " %s %d",
764                                         keyword(atrv->attr),
765                                         atrv->value.i);
766                                 }
767                                 break;
768
769                         case T_Double:
770                                 fprintf(df, " %s %s",
771                                         keyword(atrv->attr),
772                                         normal_dtoa(atrv->value.d));
773                                 break;
774                         }
775                 }
776                 fprintf(df, "\n");
777         }
778
779         atrv = HEAD_PFIFO(ptree->rlimit);
780         if (atrv != NULL) {
781                 fprintf(df, "rlimit");
782                 for ( ; atrv != NULL; atrv = atrv->link) {
783                         INSIST(T_Integer == atrv->type);
784                         fprintf(df, " %s %d", keyword(atrv->attr),
785                                 atrv->value.i);
786                 }
787                 fprintf(df, "\n");
788         }
789
790         atrv = HEAD_PFIFO(ptree->tinker);
791         if (atrv != NULL) {
792                 fprintf(df, "tinker");
793                 for ( ; atrv != NULL; atrv = atrv->link) {
794                         INSIST(T_Double == atrv->type);
795                         fprintf(df, " %s %s", keyword(atrv->attr),
796                                 normal_dtoa(atrv->value.d));
797                 }
798                 fprintf(df, "\n");
799         }
800
801         if (ptree->broadcastclient)
802                 fprintf(df, "broadcastclient\n");
803
804         peern = HEAD_PFIFO(ptree->peers);
805         for ( ; peern != NULL; peern = peern->link) {
806                 addr = peern->addr;
807                 fprintf(df, "%s", keyword(peern->host_mode));
808                 switch (addr->type) {
809 #ifdef DEBUG
810                 default:
811                         fprintf(df, "# dump error:\n"
812                                 "# unknown peer family %d for:\n"
813                                 "%s", addr->type,
814                                 keyword(peern->host_mode));
815                         break;
816 #endif
817                 case AF_UNSPEC:
818                         break;
819
820                 case AF_INET:
821                         fprintf(df, " -4");
822                         break;
823
824                 case AF_INET6:
825                         fprintf(df, " -6");
826                         break;
827                 }
828                 fprintf(df, " %s", addr->address);
829
830                 if (peern->minpoll != 0)
831                         fprintf(df, " minpoll %u", peern->minpoll);
832
833                 if (peern->maxpoll != 0)
834                         fprintf(df, " maxpoll %u", peern->maxpoll);
835
836                 if (peern->ttl != 0) {
837                         if (strlen(addr->address) > 8
838                             && !memcmp(addr->address, "127.127.", 8))
839                                 fprintf(df, " mode %u", peern->ttl);
840                         else
841                                 fprintf(df, " ttl %u", peern->ttl);
842                 }
843
844                 if (peern->peerversion != NTP_VERSION)
845                         fprintf(df, " version %u", peern->peerversion);
846
847                 if (peern->peerkey != 0)
848                         fprintf(df, " key %u", peern->peerkey);
849
850                 if (peern->group != NULL)
851                         fprintf(df, " ident \"%s\"", peern->group);
852
853                 atrv = HEAD_PFIFO(peern->peerflags);
854                 for ( ; atrv != NULL; atrv = atrv->link) {
855                         INSIST(T_Flag == atrv->attr);
856                         INSIST(T_Integer == atrv->type);
857                         fprintf(df, " %s", keyword(atrv->value.i));
858                 }
859
860                 fprintf(df, "\n");
861
862                 addr_opts = HEAD_PFIFO(ptree->fudge);
863                 for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
864                         peer_addr = peern->addr;
865                         fudge_addr = addr_opts->addr;
866
867                         s1 = peer_addr->address;
868                         s2 = fudge_addr->address;
869
870                         if (strcmp(s1, s2))
871                                 continue;
872
873                         fprintf(df, "fudge %s", s1);
874
875                         for (atrv = HEAD_PFIFO(addr_opts->options);
876                              atrv != NULL;
877                              atrv = atrv->link) {
878
879                                 switch (atrv->type) {
880 #ifdef DEBUG
881                                 default:
882                                         fprintf(df, "\n# dump error:\n"
883                                                 "# unknown fudge atrv->type %d\n"
884                                                 "fudge %s", atrv->type,
885                                                 s1);
886                                         break;
887 #endif
888                                 case T_Double:
889                                         fprintf(df, " %s %s",
890                                                 keyword(atrv->attr),
891                                                 normal_dtoa(atrv->value.d));
892                                         break;
893
894                                 case T_Integer:
895                                         fprintf(df, " %s %d",
896                                                 keyword(atrv->attr),
897                                                 atrv->value.i);
898                                         break;
899
900                                 case T_String:
901                                         fprintf(df, " %s %s",
902                                                 keyword(atrv->attr),
903                                                 atrv->value.s);
904                                         break;
905                                 }
906                         }
907                         fprintf(df, "\n");
908                 }
909         }
910
911         addr = HEAD_PFIFO(ptree->manycastserver);
912         if (addr != NULL) {
913                 fprintf(df, "manycastserver");
914                 for ( ; addr != NULL; addr = addr->link)
915                         fprintf(df, " %s", addr->address);
916                 fprintf(df, "\n");
917         }
918
919         addr = HEAD_PFIFO(ptree->multicastclient);
920         if (addr != NULL) {
921                 fprintf(df, "multicastclient");
922                 for ( ; addr != NULL; addr = addr->link)
923                         fprintf(df, " %s", addr->address);
924                 fprintf(df, "\n");
925         }
926
927
928         for (unpeern = HEAD_PFIFO(ptree->unpeers);
929              unpeern != NULL;
930              unpeern = unpeern->link)
931                 fprintf(df, "unpeer %s\n", unpeern->addr->address);
932
933         atrv = HEAD_PFIFO(ptree->mru_opts);
934         if (atrv != NULL) {
935                 fprintf(df, "mru");
936                 for ( ; atrv != NULL; atrv = atrv->link)
937                         fprintf(df, " %s %d", keyword(atrv->attr),
938                                 atrv->value.i);
939                 fprintf(df, "\n");
940         }
941
942         atrv = HEAD_PFIFO(ptree->discard_opts);
943         if (atrv != NULL) {
944                 fprintf(df, "discard");
945                 for ( ; atrv != NULL; atrv = atrv->link)
946                         fprintf(df, " %s %d", keyword(atrv->attr),
947                                 atrv->value.i);
948                 fprintf(df, "\n");
949         }
950
951         atrv = HEAD_PFIFO(ptree->pollskewlist);
952         if (atrv != NULL) {
953                 fprintf(df, "pollskewlist");
954                 for ( ; atrv != NULL; atrv = atrv->link) {
955                         if (-1 == atrv->attr) {
956                                 fprintf(df, " default");
957                         } else {
958                                 fprintf(df, " %d", atrv->attr);
959                         }
960                         fprintf(df, " %d|%d",
961                                 atrv->value.r.first, atrv->value.r.last);
962                 }
963                 fprintf(df, "\n");
964         }
965
966         for (rest_node = HEAD_PFIFO(ptree->restrict_opts);
967              rest_node != NULL;
968              rest_node = rest_node->link) {
969                 int is_default = 0;
970
971                 if (NULL == rest_node->addr) {
972                         s = "default";
973                         /* Don't need to set is_default=1 here */
974                         atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
975                         for ( ; atrv != NULL; atrv = atrv->link) {
976                                 if (   T_Integer == atrv->type
977                                     && T_Source == atrv->attr) {
978                                         s = "source";
979                                         break;
980                                 }
981                         }
982                 } else {
983                         const char *ap = rest_node->addr->address;
984                         const char *mp = "";
985
986                         if (rest_node->mask)
987                                 mp = rest_node->mask->address;
988
989                         if (   rest_node->addr->type == AF_INET
990                             && !strcmp(ap, "0.0.0.0")
991                             && !strcmp(mp, "0.0.0.0")) {
992                                 is_default = 1;
993                                 s = "-4 default";
994                         } else if (   rest_node->mask
995                                    && rest_node->mask->type == AF_INET6
996                                    && !strcmp(ap, "::")
997                                    && !strcmp(mp, "::")) {
998                                 is_default = 1;
999                                 s = "-6 default";
1000                         } else {
1001                                 s = ap;
1002                         }
1003                 }
1004                 fprintf(df, "restrict %s", s);
1005                 if (rest_node->mask != NULL && !is_default)
1006                         fprintf(df, " mask %s",
1007                                 rest_node->mask->address);
1008                 fprintf(df, " ippeerlimit %d", rest_node->ippeerlimit);
1009                 atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1010                 for ( ; atrv != NULL; atrv = atrv->link) {
1011                         if (   T_Integer == atrv->type
1012                             && T_Source != atrv->attr) {
1013                                 fprintf(df, " %s", keyword(atrv->attr));
1014                         }
1015                 }
1016                 fprintf(df, "\n");            
1017 /**/
1018 #if 0
1019 msyslog(LOG_INFO, "Dumping flag_tok_fifo:");
1020 atrv = HEAD_PFIFO(rest_node->flag_tok_fifo);
1021 for ( ; atrv != NULL; atrv = atrv->link) {
1022         msyslog(LOG_INFO, "- flag_tok_fifo: flags: %08x", atrv->flag);
1023         switch(atrv->type) {
1024             case T_Integer:
1025                 msyslog(LOG_INFO, "- T_Integer: attr <%s>/%d, value %d",
1026                         keyword(atrv->attr), atrv->attr, atrv->value.i);
1027                 break;
1028             default:
1029                 msyslog(LOG_INFO, "- Other: attr <%s>/%d, value ???",
1030                         keyword(atrv->attr), atrv->attr);
1031                 break;
1032                 
1033         }
1034 }
1035 #endif
1036 /**/
1037         }
1038
1039         rule_node = HEAD_PFIFO(ptree->nic_rules);
1040         for ( ; rule_node != NULL; rule_node = rule_node->link) {
1041                 fprintf(df, "interface %s %s\n",
1042                         keyword(rule_node->action),
1043                         (rule_node->match_class)
1044                             ? keyword(rule_node->match_class)
1045                             : rule_node->if_name);
1046         }
1047
1048         str_node = HEAD_PFIFO(ptree->phone);
1049         if (str_node != NULL) {
1050                 fprintf(df, "phone");
1051                 for ( ; str_node != NULL; str_node = str_node->link)
1052                         fprintf(df, " \"%s\"", str_node->s);
1053                 fprintf(df, "\n");
1054         }
1055
1056         setv_node = HEAD_PFIFO(ptree->setvar);
1057         for ( ; setv_node != NULL; setv_node = setv_node->link) {
1058                 s1 = quote_if_needed(setv_node->var);
1059                 s2 = quote_if_needed(setv_node->val);
1060                 fprintf(df, "setvar %s = %s", s1, s2);
1061                 free(s1);
1062                 free(s2);
1063                 if (setv_node->isdefault)
1064                         fprintf(df, " default");
1065                 fprintf(df, "\n");
1066         }
1067
1068         i_n = HEAD_PFIFO(ptree->ttl);
1069         if (i_n != NULL) {
1070                 fprintf(df, "ttl");
1071                 for( ; i_n != NULL; i_n = i_n->link)
1072                         fprintf(df, " %d", i_n->i);
1073                 fprintf(df, "\n");
1074         }
1075
1076         addr_opts = HEAD_PFIFO(ptree->trap);
1077         for ( ; addr_opts != NULL; addr_opts = addr_opts->link) {
1078                 addr = addr_opts->addr;
1079                 fprintf(df, "trap %s", addr->address);
1080                 atrv = HEAD_PFIFO(addr_opts->options);
1081                 for ( ; atrv != NULL; atrv = atrv->link) {
1082                         switch (atrv->attr) {
1083 #ifdef DEBUG
1084                         default:
1085                                 fprintf(df, "\n# dump error:\n"
1086                                         "# unknown trap token %d\n"
1087                                         "trap %s", atrv->attr,
1088                                         addr->address);
1089                                 break;
1090 #endif
1091                         case T_Port:
1092                                 fprintf(df, " port %d", atrv->value.i);
1093                                 break;
1094
1095                         case T_Interface:
1096                                 fprintf(df, " interface %s",
1097                                         atrv->value.s);
1098                                 break;
1099                         }
1100                 }
1101                 fprintf(df, "\n");
1102         }
1103
1104         counter_set = HEAD_PFIFO(ptree->reset_counters);
1105         if (counter_set != NULL) {
1106                 fprintf(df, "reset");
1107                 for ( ; counter_set != NULL;
1108                      counter_set = counter_set->link)
1109                         fprintf(df, " %s", keyword(counter_set->i));
1110                 fprintf(df, "\n");
1111         }
1112
1113         return 0;
1114 }
1115 #endif  /* SAVECONFIG */
1116
1117
1118 /* generic fifo routines for structs linked by 1st member */
1119 void *
1120 append_gen_fifo(
1121         void *fifo,
1122         void *entry
1123         )
1124 {
1125         gen_fifo *pf;
1126         gen_node *pe;
1127
1128         pf = fifo;
1129         pe = entry;
1130         if (NULL == pf)
1131                 pf = emalloc_zero(sizeof(*pf));
1132         else
1133                 CHECK_FIFO_CONSISTENCY(*pf);
1134         if (pe != NULL)
1135                 LINK_FIFO(*pf, pe, link);
1136         CHECK_FIFO_CONSISTENCY(*pf);
1137
1138         return pf;
1139 }
1140
1141
1142 void *
1143 concat_gen_fifos(
1144         void *first,
1145         void *second
1146         )
1147 {
1148         gen_fifo *pf1;
1149         gen_fifo *pf2;
1150
1151         pf1 = first;
1152         pf2 = second;
1153         if (NULL == pf1)
1154                 return pf2;
1155         if (NULL == pf2)
1156                 return pf1;
1157
1158         CONCAT_FIFO(*pf1, *pf2, link);
1159         free(pf2);
1160
1161         return pf1;
1162 }
1163
1164 void*
1165 destroy_gen_fifo(
1166         void        *fifo,
1167         fifo_deleter func
1168         )
1169 {
1170         any_node *      np  = NULL;
1171         any_node_fifo * pf1 = fifo;
1172
1173         if (pf1 != NULL) {
1174                 if (!func)
1175                         func = free;
1176                 for (;;) {
1177                         UNLINK_FIFO(np, *pf1, link);
1178                         if (np == NULL)
1179                                 break;
1180                         (*func)(np);
1181                 }
1182                 free(pf1);
1183         }
1184         return NULL;
1185 }
1186
1187 /* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE
1188  * -----------------------------------------------
1189  */
1190
1191 void
1192 destroy_attr_val(
1193         attr_val *      av
1194         )
1195 {
1196         if (av) {
1197                 if (T_String == av->type)
1198                         free(av->value.s);
1199                 free(av);
1200         }
1201 }
1202
1203 attr_val *
1204 create_attr_dval(
1205         int attr,
1206         double value
1207         )
1208 {
1209         attr_val *my_val;
1210
1211         my_val = emalloc_zero(sizeof(*my_val));
1212         my_val->attr = attr;
1213         my_val->value.d = value;
1214         my_val->type = T_Double;
1215
1216         return my_val;
1217 }
1218
1219
1220 attr_val *
1221 create_attr_ival(
1222         int attr,
1223         int value
1224         )
1225 {
1226         attr_val *my_val;
1227
1228         my_val = emalloc_zero(sizeof(*my_val));
1229         my_val->attr = attr;
1230         my_val->value.i = value;
1231         my_val->type = T_Integer;
1232
1233         return my_val;
1234 }
1235
1236
1237 attr_val *
1238 create_attr_uval(
1239         int     attr,
1240         u_int   value
1241         )
1242 {
1243         attr_val *my_val;
1244
1245         my_val = emalloc_zero(sizeof(*my_val));
1246         my_val->attr = attr;
1247         my_val->value.u = value;
1248         my_val->type = T_U_int;
1249
1250         return my_val;
1251 }
1252
1253
1254 attr_val *
1255 create_attr_rval(
1256         int     attr,
1257         int     first,
1258         int     last
1259         )
1260 {
1261         attr_val *my_val;
1262
1263         my_val = emalloc_zero(sizeof(*my_val));
1264         my_val->attr = attr;
1265         my_val->value.r.first = first;
1266         my_val->value.r.last = last;
1267         my_val->type = T_Intrange;
1268
1269         return my_val;
1270 }
1271
1272
1273 attr_val *
1274 create_attr_sval(
1275         int attr,
1276         const char *s
1277         )
1278 {
1279         attr_val *my_val;
1280
1281         my_val = emalloc_zero(sizeof(*my_val));
1282         my_val->attr = attr;
1283         if (NULL == s)                  /* free() hates NULL */
1284                 s = estrdup("");
1285         my_val->value.s = _UC(s);
1286         my_val->type = T_String;
1287
1288         return my_val;
1289 }
1290
1291
1292 int_node *
1293 create_int_node(
1294         int val
1295         )
1296 {
1297         int_node *i_n;
1298
1299         i_n = emalloc_zero(sizeof(*i_n));
1300         i_n->i = val;
1301
1302         return i_n;
1303 }
1304
1305
1306 string_node *
1307 create_string_node(
1308         char *str
1309         )
1310 {
1311         string_node *sn;
1312
1313         sn = emalloc_zero(sizeof(*sn));
1314         sn->s = str;
1315
1316         return sn;
1317 }
1318
1319
1320 address_node *
1321 create_address_node(
1322         char *  addr,
1323         int     type
1324         )
1325 {
1326         address_node *my_node;
1327
1328         REQUIRE(NULL != addr);
1329         REQUIRE(AF_INET == type || AF_INET6 == type || AF_UNSPEC == type);
1330         my_node = emalloc_zero(sizeof(*my_node));
1331         my_node->address = addr;
1332         my_node->type = (u_short)type;
1333
1334         return my_node;
1335 }
1336
1337
1338 void
1339 destroy_address_node(
1340         address_node *my_node
1341         )
1342 {
1343         if (NULL == my_node)
1344                 return;
1345         REQUIRE(NULL != my_node->address);
1346
1347         free(my_node->address);
1348         free(my_node);
1349 }
1350
1351
1352 peer_node *
1353 create_peer_node(
1354         int             hmode,
1355         address_node *  addr,
1356         attr_val_fifo * options
1357         )
1358 {
1359         peer_node *my_node;
1360         attr_val *option;
1361         int freenode;
1362         int errflag = 0;
1363
1364         my_node = emalloc_zero(sizeof(*my_node));
1365
1366         /* Initialize node values to default */
1367         my_node->peerversion = NTP_VERSION;
1368
1369         /* Now set the node to the read values */
1370         my_node->host_mode = hmode;
1371         my_node->addr = addr;
1372
1373         /*
1374          * the options FIFO mixes items that will be saved in the
1375          * peer_node as explicit members, such as minpoll, and
1376          * those that are moved intact to the peer_node's peerflags
1377          * FIFO.  The options FIFO is consumed and reclaimed here.
1378          */
1379
1380         if (options != NULL)
1381                 CHECK_FIFO_CONSISTENCY(*options);
1382         while (options != NULL) {
1383                 UNLINK_FIFO(option, *options, link);
1384                 if (NULL == option) {
1385                         free(options);
1386                         break;
1387                 }
1388
1389                 freenode = 1;
1390                 /* Check the kind of option being set */
1391                 switch (option->attr) {
1392
1393                 case T_Flag:
1394                         APPEND_G_FIFO(my_node->peerflags, option);
1395                         freenode = 0;
1396                         break;
1397
1398                 case T_Minpoll:
1399                         if (option->value.i < NTP_MINPOLL ||
1400                             option->value.i > UCHAR_MAX) {
1401                                 msyslog(LOG_INFO,
1402                                         "minpoll: provided value (%d) is out of range [%d-%d])",
1403                                         option->value.i, NTP_MINPOLL,
1404                                         UCHAR_MAX);
1405                                 my_node->minpoll = NTP_MINPOLL;
1406                         } else {
1407                                 my_node->minpoll =
1408                                         (u_char)option->value.u;
1409                         }
1410                         break;
1411
1412                 case T_Maxpoll:
1413                         if (option->value.i < 0 ||
1414                             option->value.i > NTP_MAXPOLL) {
1415                                 msyslog(LOG_INFO,
1416                                         "maxpoll: provided value (%d) is out of range [0-%d])",
1417                                         option->value.i, NTP_MAXPOLL);
1418                                 my_node->maxpoll = NTP_MAXPOLL;
1419                         } else {
1420                                 my_node->maxpoll =
1421                                         (u_char)option->value.u;
1422                         }
1423                         break;
1424
1425                 case T_Ttl:
1426                         if (is_refclk_addr(addr)) {
1427                                 msyslog(LOG_ERR, "'ttl' does not apply for refclocks");
1428                                 errflag = 1;
1429                         } else if (option->value.u >= MAX_TTL) {
1430                                 msyslog(LOG_ERR, "ttl: invalid argument");
1431                                 errflag = 1;
1432                         } else {
1433                                 my_node->ttl = (u_char)option->value.u;
1434                         }
1435                         break;
1436
1437                 case T_Mode:
1438                         if (is_refclk_addr(addr)) {
1439                                 my_node->ttl = option->value.u;
1440                         } else {
1441                                 msyslog(LOG_ERR, "'mode' does not apply for network peers");
1442                                 errflag = 1;
1443                         }
1444                         break;
1445
1446                 case T_Key:
1447                         if (option->value.u >= KEYID_T_MAX) {
1448                                 msyslog(LOG_ERR, "key: invalid argument");
1449                                 errflag = 1;
1450                         } else {
1451                                 my_node->peerkey =
1452                                         (keyid_t)option->value.u;
1453                         }
1454                         break;
1455
1456                 case T_Version:
1457                         if (option->value.u >= UCHAR_MAX) {
1458                                 msyslog(LOG_ERR, "version: invalid argument");
1459                                 errflag = 1;
1460                         } else {
1461                                 my_node->peerversion =
1462                                         (u_char)option->value.u;
1463                         }
1464                         break;
1465
1466                 case T_Ident:
1467                         my_node->group = option->value.s;
1468                         break;
1469
1470                 default:
1471                         msyslog(LOG_ERR,
1472                                 "Unknown peer/server option token %s",
1473                                 token_name(option->attr));
1474                         errflag = 1;
1475                 }
1476                 if (freenode)
1477                         free(option);
1478         }
1479
1480         /* Check if errors were reported. If yes, ignore the node */
1481         if (errflag) {
1482                 free(my_node);
1483                 my_node = NULL;
1484         }
1485
1486         return my_node;
1487 }
1488
1489
1490 unpeer_node *
1491 create_unpeer_node(
1492         address_node *addr
1493         )
1494 {
1495         unpeer_node *   my_node;
1496         u_long          u;
1497         const u_char *  pch;
1498
1499         my_node = emalloc_zero(sizeof(*my_node));
1500
1501         /*
1502          * From the parser's perspective an association ID fits into
1503          * its generic T_String definition of a name/address "address".
1504          * We treat all valid 16-bit numbers as association IDs.
1505          */
1506         for (u = 0, pch = (u_char*)addr->address; isdigit(*pch); ++pch) {
1507                 /* accumulate with overflow retention */
1508                 u = (10 * u + *pch - '0') | (u & 0xFF000000u);
1509         }
1510
1511         if (!*pch && u <= ASSOCID_MAX) {
1512                 my_node->assocID = (associd_t)u;
1513                 my_node->addr = NULL;
1514                 destroy_address_node(addr);
1515         } else {
1516                 my_node->assocID = 0;
1517                 my_node->addr = addr;
1518         }
1519
1520         return my_node;
1521 }
1522
1523 filegen_node *
1524 create_filegen_node(
1525         int             filegen_token,
1526         attr_val_fifo * options
1527         )
1528 {
1529         filegen_node *my_node;
1530
1531         my_node = emalloc_zero(sizeof(*my_node));
1532         my_node->filegen_token = filegen_token;
1533         my_node->options = options;
1534
1535         return my_node;
1536 }
1537
1538
1539 restrict_node *
1540 create_restrict_node(
1541         address_node *  addr,
1542         address_node *  mask,
1543         short           ippeerlimit,
1544         attr_val_fifo * flag_tok_fifo,
1545         int             nline
1546         )
1547 {
1548         restrict_node *my_node;
1549
1550         my_node = emalloc_zero(sizeof(*my_node));
1551         my_node->addr = addr;
1552         my_node->mask = mask;
1553         my_node->ippeerlimit = ippeerlimit;
1554         my_node->flag_tok_fifo = flag_tok_fifo;
1555         my_node->line_no = nline;
1556
1557         return my_node;
1558 }
1559
1560
1561 static void
1562 destroy_restrict_node(
1563         restrict_node *my_node
1564         )
1565 {
1566         /* With great care, free all the memory occupied by
1567          * the restrict node
1568          */
1569         destroy_address_node(my_node->addr);
1570         destroy_address_node(my_node->mask);
1571         destroy_attr_val_fifo(my_node->flag_tok_fifo);
1572         free(my_node);
1573 }
1574
1575
1576 static void
1577 destroy_int_fifo(
1578         int_fifo *      fifo
1579         )
1580 {
1581         int_node *      i_n;
1582
1583         if (fifo != NULL) {
1584                 for (;;) {
1585                         UNLINK_FIFO(i_n, *fifo, link);
1586                         if (i_n == NULL)
1587                                 break;
1588                         free(i_n);
1589                 }
1590                 free(fifo);
1591         }
1592 }
1593
1594
1595 static void
1596 destroy_string_fifo(
1597         string_fifo *   fifo
1598         )
1599 {
1600         string_node *   sn;
1601
1602         if (fifo != NULL) {
1603                 for (;;) {
1604                         UNLINK_FIFO(sn, *fifo, link);
1605                         if (sn == NULL)
1606                                 break;
1607                         free(sn->s);
1608                         free(sn);
1609                 }
1610                 free(fifo);
1611         }
1612 }
1613
1614
1615 static void
1616 destroy_attr_val_fifo(
1617         attr_val_fifo * av_fifo
1618         )
1619 {
1620         attr_val *      av;
1621
1622         if (av_fifo != NULL) {
1623                 for (;;) {
1624                         UNLINK_FIFO(av, *av_fifo, link);
1625                         if (av == NULL)
1626                                 break;
1627                         destroy_attr_val(av);
1628                 }
1629                 free(av_fifo);
1630         }
1631 }
1632
1633
1634 static void
1635 destroy_filegen_fifo(
1636         filegen_fifo *  fifo
1637         )
1638 {
1639         filegen_node *  fg;
1640
1641         if (fifo != NULL) {
1642                 for (;;) {
1643                         UNLINK_FIFO(fg, *fifo, link);
1644                         if (fg == NULL)
1645                                 break;
1646                         destroy_attr_val_fifo(fg->options);
1647                         free(fg);
1648                 }
1649                 free(fifo);
1650         }
1651 }
1652
1653
1654 static void
1655 destroy_restrict_fifo(
1656         restrict_fifo * fifo
1657         )
1658 {
1659         restrict_node * rn;
1660
1661         if (fifo != NULL) {
1662                 for (;;) {
1663                         UNLINK_FIFO(rn, *fifo, link);
1664                         if (rn == NULL)
1665                                 break;
1666                         destroy_restrict_node(rn);
1667                 }
1668                 free(fifo);
1669         }
1670 }
1671
1672
1673 static void
1674 destroy_setvar_fifo(
1675         setvar_fifo *   fifo
1676         )
1677 {
1678         setvar_node *   sv;
1679
1680         if (fifo != NULL) {
1681                 for (;;) {
1682                         UNLINK_FIFO(sv, *fifo, link);
1683                         if (sv == NULL)
1684                                 break;
1685                         free(sv->var);
1686                         free(sv->val);
1687                         free(sv);
1688                 }
1689                 free(fifo);
1690         }
1691 }
1692
1693
1694 static void
1695 destroy_addr_opts_fifo(
1696         addr_opts_fifo *        fifo
1697         )
1698 {
1699         addr_opts_node *        aon;
1700
1701         if (fifo != NULL) {
1702                 for (;;) {
1703                         UNLINK_FIFO(aon, *fifo, link);
1704                         if (aon == NULL)
1705                                 break;
1706                         destroy_address_node(aon->addr);
1707                         destroy_attr_val_fifo(aon->options);
1708                         free(aon);
1709                 }
1710                 free(fifo);
1711         }
1712 }
1713
1714
1715 setvar_node *
1716 create_setvar_node(
1717         char *  var,
1718         char *  val,
1719         int     isdefault
1720         )
1721 {
1722         setvar_node *   my_node;
1723         char *          pch;
1724
1725         /* do not allow = in the variable name */
1726         pch = strchr(var, '=');
1727         if (NULL != pch)
1728                 *pch = '\0';
1729
1730         /* Now store the string into a setvar_node */
1731         my_node = emalloc_zero(sizeof(*my_node));
1732         my_node->var = var;
1733         my_node->val = val;
1734         my_node->isdefault = isdefault;
1735
1736         return my_node;
1737 }
1738
1739
1740 nic_rule_node *
1741 create_nic_rule_node(
1742         int match_class,
1743         char *if_name,  /* interface name or numeric address */
1744         int action
1745         )
1746 {
1747         nic_rule_node *my_node;
1748
1749         REQUIRE(match_class != 0 || if_name != NULL);
1750
1751         my_node = emalloc_zero(sizeof(*my_node));
1752         my_node->match_class = match_class;
1753         my_node->if_name = if_name;
1754         my_node->action = action;
1755
1756         return my_node;
1757 }
1758
1759
1760 addr_opts_node *
1761 create_addr_opts_node(
1762         address_node *  addr,
1763         attr_val_fifo * options
1764         )
1765 {
1766         addr_opts_node *my_node;
1767
1768         my_node = emalloc_zero(sizeof(*my_node));
1769         my_node->addr = addr;
1770         my_node->options = options;
1771
1772         return my_node;
1773 }
1774
1775
1776 #ifdef SIM
1777 script_info *
1778 create_sim_script_info(
1779         double          duration,
1780         attr_val_fifo * script_queue
1781         )
1782 {
1783         script_info *my_info;
1784         attr_val *my_attr_val;
1785
1786         my_info = emalloc_zero(sizeof(*my_info));
1787
1788         /* Initialize Script Info with default values*/
1789         my_info->duration = duration;
1790         my_info->prop_delay = NET_DLY;
1791         my_info->proc_delay = PROC_DLY;
1792
1793         /* Traverse the script_queue and fill out non-default values */
1794
1795         for (my_attr_val = HEAD_PFIFO(script_queue);
1796              my_attr_val != NULL;
1797              my_attr_val = my_attr_val->link) {
1798
1799                 /* Set the desired value */
1800                 switch (my_attr_val->attr) {
1801
1802                 case T_Freq_Offset:
1803                         my_info->freq_offset = my_attr_val->value.d;
1804                         break;
1805
1806                 case T_Wander:
1807                         my_info->wander = my_attr_val->value.d;
1808                         break;
1809
1810                 case T_Jitter:
1811                         my_info->jitter = my_attr_val->value.d;
1812                         break;
1813
1814                 case T_Prop_Delay:
1815                         my_info->prop_delay = my_attr_val->value.d;
1816                         break;
1817
1818                 case T_Proc_Delay:
1819                         my_info->proc_delay = my_attr_val->value.d;
1820                         break;
1821
1822                 default:
1823                         msyslog(LOG_ERR, "Unknown script token %d",
1824                                 my_attr_val->attr);
1825                 }
1826         }
1827
1828         return my_info;
1829 }
1830 #endif  /* SIM */
1831
1832
1833 #ifdef SIM
1834 static sockaddr_u *
1835 get_next_address(
1836         address_node *addr
1837         )
1838 {
1839         const char addr_prefix[] = "192.168.0.";
1840         static int curr_addr_num = 1;
1841 #define ADDR_LENGTH 16 + 1      /* room for 192.168.1.255 */
1842         char addr_string[ADDR_LENGTH];
1843         sockaddr_u *final_addr;
1844         struct addrinfo *ptr;
1845         int gai_err;
1846
1847         final_addr = emalloc(sizeof(*final_addr));
1848
1849         if (addr->type == T_String) {
1850                 snprintf(addr_string, sizeof(addr_string), "%s%d",
1851                          addr_prefix, curr_addr_num++);
1852                 printf("Selecting ip address %s for hostname %s\n",
1853                        addr_string, addr->address);
1854                 gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr);
1855         } else {
1856                 gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr);
1857         }
1858
1859         if (gai_err) {
1860                 fprintf(stderr, "ERROR!! Could not get a new address\n");
1861                 exit(1);
1862         }
1863         memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen);
1864         fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n",
1865                 stoa(final_addr));
1866         freeaddrinfo(ptr);
1867
1868         return final_addr;
1869 }
1870 #endif /* SIM */
1871
1872
1873 #ifdef SIM
1874 server_info *
1875 create_sim_server(
1876         address_node *          addr,
1877         double                  server_offset,
1878         script_info_fifo *      script
1879         )
1880 {
1881         server_info *my_info;
1882
1883         my_info = emalloc_zero(sizeof(*my_info));
1884         my_info->server_time = server_offset;
1885         my_info->addr = get_next_address(addr);
1886         my_info->script = script;
1887         UNLINK_FIFO(my_info->curr_script, *my_info->script, link);
1888
1889         return my_info;
1890 }
1891 #endif  /* SIM */
1892
1893 sim_node *
1894 create_sim_node(
1895         attr_val_fifo *         init_opts,
1896         server_info_fifo *      servers
1897         )
1898 {
1899         sim_node *my_node;
1900
1901         my_node = emalloc(sizeof(*my_node));
1902         my_node->init_opts = init_opts;
1903         my_node->servers = servers;
1904
1905         return my_node;
1906 }
1907
1908
1909
1910
1911 /* FUNCTIONS FOR PERFORMING THE CONFIGURATION
1912  * ------------------------------------------
1913  */
1914
1915 #ifndef SIM
1916 static void
1917 config_other_modes(
1918         config_tree *   ptree
1919         )
1920 {
1921         sockaddr_u      addr_sock;
1922         address_node *  addr_node;
1923
1924         if (ptree->broadcastclient)
1925                 proto_config(PROTO_BROADCLIENT, ptree->broadcastclient,
1926                              0., NULL);
1927
1928         addr_node = HEAD_PFIFO(ptree->manycastserver);
1929         while (addr_node != NULL) {
1930                 ZERO_SOCK(&addr_sock);
1931                 AF(&addr_sock) = addr_node->type;
1932                 if (1 == getnetnum(addr_node->address, &addr_sock, 1,
1933                                    t_UNK)) {
1934                         proto_config(PROTO_MULTICAST_ADD,
1935                                      0, 0., &addr_sock);
1936                         sys_manycastserver = 1;
1937                 }
1938                 addr_node = addr_node->link;
1939         }
1940
1941         /* Configure the multicast clients */
1942         addr_node = HEAD_PFIFO(ptree->multicastclient);
1943         if (addr_node != NULL) {
1944                 do {
1945                         ZERO_SOCK(&addr_sock);
1946                         AF(&addr_sock) = addr_node->type;
1947                         if (1 == getnetnum(addr_node->address,
1948                                            &addr_sock, 1, t_UNK)) {
1949                                 proto_config(PROTO_MULTICAST_ADD, 0, 0.,
1950                                              &addr_sock);
1951                         }
1952                         addr_node = addr_node->link;
1953                 } while (addr_node != NULL);
1954                 proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1955         }
1956 }
1957 #endif  /* !SIM */
1958
1959
1960 #ifdef FREE_CFG_T
1961 static void
1962 destroy_address_fifo(
1963         address_fifo *  pfifo
1964         )
1965 {
1966         address_node *  addr_node;
1967
1968         if (pfifo != NULL) {
1969                 for (;;) {
1970                         UNLINK_FIFO(addr_node, *pfifo, link);
1971                         if (addr_node == NULL)
1972                                 break;
1973                         destroy_address_node(addr_node);
1974                 }
1975                 free(pfifo);
1976         }
1977 }
1978
1979
1980 static void
1981 free_config_other_modes(
1982         config_tree *ptree
1983         )
1984 {
1985         FREE_ADDRESS_FIFO(ptree->manycastserver);
1986         FREE_ADDRESS_FIFO(ptree->multicastclient);
1987 }
1988 #endif  /* FREE_CFG_T */
1989
1990
1991 #ifndef SIM
1992 static void
1993 config_auth(
1994         config_tree *ptree
1995         )
1996 {
1997         attr_val *      my_val;
1998         int             first;
1999         int             last;
2000         int             i;
2001         int             count;
2002 #ifdef AUTOKEY
2003         int             item;
2004 #endif
2005
2006         /* Crypto Command */
2007 #ifdef AUTOKEY
2008         my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list);
2009         for (; my_val != NULL; my_val = my_val->link) {
2010                 switch (my_val->attr) {
2011
2012                 default:
2013                         fatal_error("config_auth: attr-token=%d", my_val->attr);
2014
2015                 case T_Host:
2016                         item = CRYPTO_CONF_PRIV;
2017                         break;
2018
2019                 case T_Ident:
2020                         item = CRYPTO_CONF_IDENT;
2021                         break;
2022
2023                 case T_Pw:
2024                         item = CRYPTO_CONF_PW;
2025                         break;
2026
2027                 case T_Randfile:
2028                         item = CRYPTO_CONF_RAND;
2029                         break;
2030
2031                 case T_Digest:
2032                         item = CRYPTO_CONF_NID;
2033                         break;
2034                 }
2035                 crypto_config(item, my_val->value.s);
2036         }
2037 #endif  /* AUTOKEY */
2038
2039         /* Keysdir Command */
2040         if (ptree->auth.keysdir) {
2041                 if (keysdir != default_keysdir)
2042                         free(keysdir);
2043                 keysdir = estrdup(ptree->auth.keysdir);
2044         }
2045
2046
2047         /* ntp_signd_socket Command */
2048         if (ptree->auth.ntp_signd_socket) {
2049                 if (ntp_signd_socket != default_ntp_signd_socket)
2050                         free(ntp_signd_socket);
2051                 ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket);
2052         }
2053
2054 #ifdef AUTOKEY
2055         if (ptree->auth.cryptosw && !cryptosw) {
2056                 crypto_setup();
2057                 cryptosw = 1;
2058         }
2059 #endif  /* AUTOKEY */
2060
2061         /*
2062          * Count the number of trusted keys to preallocate storage and
2063          * size the hash table.
2064          */
2065         count = 0;
2066         my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2067         for (; my_val != NULL; my_val = my_val->link) {
2068                 if (T_Integer == my_val->type) {
2069                         first = my_val->value.i;
2070                         if (first > 1 && first <= NTP_MAXKEY)
2071                                 count++;
2072                 } else {
2073                         REQUIRE(T_Intrange == my_val->type);
2074                         first = my_val->value.r.first;
2075                         last = my_val->value.r.last;
2076                         if (!(first > last || first < 1 ||
2077                             last > NTP_MAXKEY)) {
2078                                 count += 1 + last - first;
2079                         }
2080                 }
2081         }
2082         auth_prealloc_symkeys(count);
2083
2084         /* Keys Command */
2085         if (ptree->auth.keys)
2086                 getauthkeys(ptree->auth.keys);
2087
2088         /* Control Key Command */
2089         if (ptree->auth.control_key)
2090                 ctl_auth_keyid = (keyid_t)ptree->auth.control_key;
2091
2092         /* Requested Key Command */
2093         if (ptree->auth.request_key) {
2094                 DPRINTF(4, ("set info_auth_keyid to %08lx\n",
2095                             (u_long) ptree->auth.request_key));
2096                 info_auth_keyid = (keyid_t)ptree->auth.request_key;
2097         }
2098
2099         /* Trusted Key Command */
2100         my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
2101         for (; my_val != NULL; my_val = my_val->link) {
2102                 if (T_Integer == my_val->type) {
2103                         first = my_val->value.i;
2104                         if (first >= 1 && first <= NTP_MAXKEY) {
2105                                 authtrust(first, TRUE);
2106                         } else {
2107                                 msyslog(LOG_NOTICE,
2108                                         "Ignoring invalid trustedkey %d, min 1 max %d.",
2109                                         first, NTP_MAXKEY);
2110                         }
2111                 } else {
2112                         first = my_val->value.r.first;
2113                         last = my_val->value.r.last;
2114                         if (first > last || first < 1 ||
2115                             last > NTP_MAXKEY) {
2116                                 msyslog(LOG_NOTICE,
2117                                         "Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
2118                                         first, last, NTP_MAXKEY);
2119                         } else {
2120                                 for (i = first; i <= last; i++) {
2121                                         authtrust(i, TRUE);
2122                                 }
2123                         }
2124                 }
2125         }
2126
2127 #ifdef AUTOKEY
2128         /* crypto revoke command */
2129         if (ptree->auth.revoke > 2 && ptree->auth.revoke < 32)
2130                 sys_revoke = (u_char)ptree->auth.revoke;
2131         else if (ptree->auth.revoke)
2132                 msyslog(LOG_ERR,
2133                         "'revoke' value %d ignored",
2134                         ptree->auth.revoke);
2135 #endif  /* AUTOKEY */
2136 }
2137 #endif  /* !SIM */
2138
2139
2140 #ifdef FREE_CFG_T
2141 static void
2142 free_config_auth(
2143         config_tree *ptree
2144         )
2145 {
2146         destroy_attr_val_fifo(ptree->auth.crypto_cmd_list);
2147         ptree->auth.crypto_cmd_list = NULL;
2148         destroy_attr_val_fifo(ptree->auth.trusted_key_list);
2149         ptree->auth.trusted_key_list = NULL;
2150 }
2151 #endif  /* FREE_CFG_T */
2152
2153
2154 /* Configure low-level clock-related parameters. Return TRUE if the
2155  * clock might need adjustment like era-checking after the call, FALSE
2156  * otherwise.
2157  */
2158 static int/*BOOL*/
2159 config_tos_clock(
2160         config_tree *ptree
2161         )
2162 {
2163         int             ret;
2164         attr_val *      tos;
2165
2166         ret = FALSE;
2167         tos = HEAD_PFIFO(ptree->orphan_cmds);
2168         for (; tos != NULL; tos = tos->link) {
2169                 switch(tos->attr) {
2170
2171                 default:
2172                         break;
2173
2174                 case T_Basedate:
2175                         basedate_set_day(tos->value.i);
2176                         ret = TRUE;
2177                         break;
2178                 }
2179         }
2180
2181         if (basedate_get_day() <= NTP_TO_UNIX_DAYS)
2182                 basedate_set_day(basedate_eval_buildstamp() - 11);
2183             
2184         return ret;
2185 }
2186
2187 static void
2188 config_tos(
2189         config_tree *ptree
2190         )
2191 {
2192         attr_val *      tos;
2193         int             item;
2194         double          val;
2195
2196         /* [Bug 2896] For the daemon to work properly it is essential
2197          * that minsane < minclock <= maxclock.
2198          *
2199          * If either constraint is violated, the daemon will be or might
2200          * become dysfunctional. Fixing the values is too fragile here,
2201          * since three variables with interdependecies are involved. We
2202          * just log an error but do not stop: This might be caused by
2203          * remote config, and it might be fixed by remote config, too.
2204          */
2205         int l_maxclock = sys_maxclock;
2206         int l_minclock = sys_minclock;
2207         int l_minsane  = sys_minsane;
2208
2209         /* -*- phase one: inspect / sanitize the values */
2210         tos = HEAD_PFIFO(ptree->orphan_cmds);
2211         for (; tos != NULL; tos = tos->link) {
2212                 /* not all attributes are doubles (any more), so loading
2213                  * 'val' in all cases is not a good idea: It should be
2214                  * done as needed in every case processed here.
2215                  */
2216                 switch(tos->attr) {
2217                 default:
2218                         break;
2219
2220                 case T_Bcpollbstep:
2221                         val = tos->value.d;
2222                         if (val > 4) {
2223                                 msyslog(LOG_WARNING,
2224                                         "Using maximum bcpollbstep ceiling %d, %d requested",
2225                                         4, (int)val);
2226                                 tos->value.d = 4;
2227                         } else if (val < 0) {
2228                                 msyslog(LOG_WARNING,
2229                                         "Using minimum bcpollbstep floor %d, %d requested",
2230                                         0, (int)val);
2231                                 tos->value.d = 0;
2232                         }
2233                         break;
2234
2235                 case T_Ceiling:
2236                         val = tos->value.d;
2237                         if (val > STRATUM_UNSPEC - 1) {
2238                                 msyslog(LOG_WARNING,
2239                                         "Using maximum tos ceiling %d, %d requested",
2240                                         STRATUM_UNSPEC - 1, (int)val);
2241                                 tos->value.d = STRATUM_UNSPEC - 1;
2242                         } else if (val < 1) {
2243                                 msyslog(LOG_WARNING,
2244                                         "Using minimum tos floor %d, %d requested",
2245                                         1, (int)val);
2246                                 tos->value.d = 1;
2247                         }
2248                         break;
2249
2250                 case T_Minclock:
2251                         val = tos->value.d;
2252                         if ((int)tos->value.d < 1)
2253                                 tos->value.d = 1;
2254                         l_minclock = (int)tos->value.d;
2255                         break;
2256
2257                 case T_Maxclock:
2258                         val = tos->value.d;
2259                         if ((int)tos->value.d < 1)
2260                                 tos->value.d = 1;
2261                         l_maxclock = (int)tos->value.d;
2262                         break;
2263
2264                 case T_Minsane:
2265                         val = tos->value.d;
2266                         if ((int)tos->value.d < 0)
2267                                 tos->value.d = 0;
2268                         l_minsane = (int)tos->value.d;
2269                         break;
2270                 }
2271         }
2272
2273         if ( ! (l_minsane < l_minclock && l_minclock <= l_maxclock)) {
2274                 msyslog(LOG_ERR,
2275                         "tos error: must have minsane (%d) < minclock (%d) <= maxclock (%d)"
2276                         " - daemon will not operate properly!",
2277                         l_minsane, l_minclock, l_maxclock);
2278         }
2279
2280         /* -*- phase two: forward the values to the protocol machinery */
2281         tos = HEAD_PFIFO(ptree->orphan_cmds);
2282         for (; tos != NULL; tos = tos->link) {
2283                 switch(tos->attr) {
2284
2285                 default:
2286                         fatal_error("config-tos: attr-token=%d", tos->attr);
2287
2288                 case T_Bcpollbstep:
2289                         item = PROTO_BCPOLLBSTEP;
2290                         break;
2291
2292                 case T_Ceiling:
2293                         item = PROTO_CEILING;
2294                         break;
2295
2296                 case T_Floor:
2297                         item = PROTO_FLOOR;
2298                         break;
2299
2300                 case T_Cohort:
2301                         item = PROTO_COHORT;
2302                         break;
2303
2304                 case T_Orphan:
2305                         item = PROTO_ORPHAN;
2306                         break;
2307
2308                 case T_Orphanwait:
2309                         item = PROTO_ORPHWAIT;
2310                         break;
2311
2312                 case T_Mindist:
2313                         item = PROTO_MINDISP;
2314                         break;
2315
2316                 case T_Maxdist:
2317                         item = PROTO_MAXDIST;
2318                         break;
2319
2320                 case T_Minclock:
2321                         item = PROTO_MINCLOCK;
2322                         break;
2323
2324                 case T_Maxclock:
2325                         item = PROTO_MAXCLOCK;
2326                         break;
2327
2328                 case T_Minsane:
2329                         item = PROTO_MINSANE;
2330                         break;
2331
2332                 case T_Beacon:
2333                         item = PROTO_BEACON;
2334                         break;
2335
2336                 case T_Basedate:
2337                         continue; /* SKIP proto-config for this! */
2338                 }
2339                 proto_config(item, 0, tos->value.d, NULL);
2340         }
2341 }
2342
2343
2344 #ifdef FREE_CFG_T
2345 static void
2346 free_config_tos(
2347         config_tree *ptree
2348         )
2349 {
2350         FREE_ATTR_VAL_FIFO(ptree->orphan_cmds);
2351 }
2352 #endif  /* FREE_CFG_T */
2353
2354
2355 static void
2356 config_monitor(
2357         config_tree *ptree
2358         )
2359 {
2360         int_node *pfilegen_token;
2361         const char *filegen_string;
2362         const char *filegen_file;
2363         FILEGEN *filegen;
2364         filegen_node *my_node;
2365         attr_val *my_opts;
2366         int filegen_type;
2367         int filegen_flag;
2368
2369         /* Set the statistics directory */
2370         if (ptree->stats_dir)
2371             stats_config(STATS_STATSDIR, ptree->stats_dir, 0);
2372
2373         /* NOTE:
2374          * Calling filegen_get is brain dead. Doing a string
2375          * comparison to find the relavant filegen structure is
2376          * expensive.
2377          *
2378          * Through the parser, we already know which filegen is
2379          * being specified. Hence, we should either store a
2380          * pointer to the specified structure in the syntax tree
2381          * or an index into a filegen array.
2382          *
2383          * Need to change the filegen code to reflect the above.
2384          */
2385
2386         /* Turn on the specified statistics */
2387         pfilegen_token = HEAD_PFIFO(ptree->stats_list);
2388         for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) {
2389                 filegen_string = keyword(pfilegen_token->i);
2390                 filegen = filegen_get(filegen_string);
2391                 if (NULL == filegen) {
2392                         msyslog(LOG_ERR,
2393                                 "stats %s unrecognized",
2394                                 filegen_string);
2395                         continue;
2396                 }
2397                 DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n",
2398                             filegen_string, filegen->dir,
2399                             filegen->fname));
2400                 filegen_flag = filegen->flag;
2401                 filegen_flag |= FGEN_FLAG_ENABLED;
2402                 filegen_config(filegen, statsdir, filegen_string,
2403                                filegen->type, filegen_flag);
2404         }
2405
2406         /* Configure the statistics with the options */
2407         my_node = HEAD_PFIFO(ptree->filegen_opts);
2408         for (; my_node != NULL; my_node = my_node->link) {
2409                 filegen_string = keyword(my_node->filegen_token);
2410                 filegen = filegen_get(filegen_string);
2411                 if (NULL == filegen) {
2412                         msyslog(LOG_ERR,
2413                                 "filegen category '%s' unrecognized",
2414                                 filegen_string);
2415                         continue;
2416                 }
2417                 filegen_file = filegen_string;
2418
2419                 /* Initialize the filegen variables to their pre-configuration states */
2420                 filegen_flag = filegen->flag;
2421                 filegen_type = filegen->type;
2422
2423                 /* "filegen ... enabled" is the default (when filegen is used) */
2424                 filegen_flag |= FGEN_FLAG_ENABLED;
2425
2426                 my_opts = HEAD_PFIFO(my_node->options);
2427                 for (; my_opts != NULL; my_opts = my_opts->link) {
2428                         switch (my_opts->attr) {
2429
2430                         case T_File:
2431                                 filegen_file = my_opts->value.s;
2432                                 break;
2433
2434                         case T_Type:
2435                                 switch (my_opts->value.i) {
2436
2437                                 default:
2438                                         fatal_error("config-monitor: type-token=%d", my_opts->value.i);
2439
2440                                 case T_None:
2441                                         filegen_type = FILEGEN_NONE;
2442                                         break;
2443
2444                                 case T_Pid:
2445                                         filegen_type = FILEGEN_PID;
2446                                         break;
2447
2448                                 case T_Day:
2449                                         filegen_type = FILEGEN_DAY;
2450                                         break;
2451
2452                                 case T_Week:
2453                                         filegen_type = FILEGEN_WEEK;
2454                                         break;
2455
2456                                 case T_Month:
2457                                         filegen_type = FILEGEN_MONTH;
2458                                         break;
2459
2460                                 case T_Year:
2461                                         filegen_type = FILEGEN_YEAR;
2462                                         break;
2463
2464                                 case T_Age:
2465                                         filegen_type = FILEGEN_AGE;
2466                                         break;
2467                                 }
2468                                 break;
2469
2470                         case T_Flag:
2471                                 switch (my_opts->value.i) {
2472
2473                                 case T_Link:
2474                                         filegen_flag |= FGEN_FLAG_LINK;
2475                                         break;
2476
2477                                 case T_Nolink:
2478                                         filegen_flag &= ~FGEN_FLAG_LINK;
2479                                         break;
2480
2481                                 case T_Enable:
2482                                         filegen_flag |= FGEN_FLAG_ENABLED;
2483                                         break;
2484
2485                                 case T_Disable:
2486                                         filegen_flag &= ~FGEN_FLAG_ENABLED;
2487                                         break;
2488
2489                                 default:
2490                                         msyslog(LOG_ERR,
2491                                                 "Unknown filegen flag token %d",
2492                                                 my_opts->value.i);
2493                                         exit(1);
2494                                 }
2495                                 break;
2496
2497                         default:
2498                                 msyslog(LOG_ERR,
2499                                         "Unknown filegen option token %d",
2500                                         my_opts->attr);
2501                                 exit(1);
2502                         }
2503                 }
2504                 filegen_config(filegen, statsdir, filegen_file,
2505                                filegen_type, filegen_flag);
2506         }
2507 }
2508
2509
2510 #ifdef FREE_CFG_T
2511 static void
2512 free_config_monitor(
2513         config_tree *ptree
2514         )
2515 {
2516         if (ptree->stats_dir) {
2517                 free(ptree->stats_dir);
2518                 ptree->stats_dir = NULL;
2519         }
2520
2521         FREE_INT_FIFO(ptree->stats_list);
2522         FREE_FILEGEN_FIFO(ptree->filegen_opts);
2523 }
2524 #endif  /* FREE_CFG_T */
2525
2526
2527 #ifndef SIM
2528 static void
2529 config_access(
2530         config_tree *ptree
2531         )
2532 {
2533         static int              warned_signd;
2534         attr_val *              my_opt;
2535         restrict_node *         my_node;
2536         sockaddr_u              addr;
2537         sockaddr_u              mask;
2538         struct addrinfo         hints;
2539         struct addrinfo *       ai_list;
2540         struct addrinfo *       pai;
2541         int                     rc;
2542         int                     restrict_default;
2543         u_short                 rflags;
2544         u_short                 mflags;
2545         short                   ippeerlimit;
2546         int                     range_err;
2547         psl_item                my_psl_item;
2548         attr_val *              atrv;
2549         attr_val *              dflt_psl_atr;
2550         const char *            signd_warning =
2551 #ifdef HAVE_NTP_SIGND
2552             "MS-SNTP signd operations currently block ntpd degrading service to all clients.";
2553 #else
2554             "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd.";
2555 #endif
2556
2557         /* Configure the mru options */
2558         my_opt = HEAD_PFIFO(ptree->mru_opts);
2559         for (; my_opt != NULL; my_opt = my_opt->link) {
2560
2561                 range_err = FALSE;
2562
2563                 switch (my_opt->attr) {
2564
2565                 case T_Incalloc:
2566                         if (0 <= my_opt->value.i)
2567                                 mru_incalloc = my_opt->value.u;
2568                         else
2569                                 range_err = TRUE;
2570                         break;
2571
2572                 case T_Incmem:
2573                         if (0 <= my_opt->value.i)
2574                                 mru_incalloc = (my_opt->value.u * 1024U)
2575                                                 / sizeof(mon_entry);
2576                         else
2577                                 range_err = TRUE;
2578                         break;
2579
2580                 case T_Initalloc:
2581                         if (0 <= my_opt->value.i)
2582                                 mru_initalloc = my_opt->value.u;
2583                         else
2584                                 range_err = TRUE;
2585                         break;
2586
2587                 case T_Initmem:
2588                         if (0 <= my_opt->value.i)
2589                                 mru_initalloc = (my_opt->value.u * 1024U)
2590                                                  / sizeof(mon_entry);
2591                         else
2592                                 range_err = TRUE;
2593                         break;
2594
2595                 case T_Mindepth:
2596                         if (0 <= my_opt->value.i)
2597                                 mru_mindepth = my_opt->value.u;
2598                         else
2599                                 range_err = TRUE;
2600                         break;
2601
2602                 case T_Maxage:
2603                         mru_maxage = my_opt->value.i;
2604                         break;
2605
2606                 case T_Maxdepth:
2607                         if (0 <= my_opt->value.i)
2608                                 mru_maxdepth = my_opt->value.u;
2609                         else
2610                                 mru_maxdepth = UINT_MAX;
2611                         break;
2612
2613                 case T_Maxmem:
2614                         if (0 <= my_opt->value.i)
2615                                 mru_maxdepth = (my_opt->value.u * 1024U) /
2616                                                sizeof(mon_entry);
2617                         else
2618                                 mru_maxdepth = UINT_MAX;
2619                         break;
2620
2621                 default:
2622                         msyslog(LOG_ERR,
2623                                 "Unknown mru option %s (%d)",
2624                                 keyword(my_opt->attr), my_opt->attr);
2625                         exit(1);
2626                 }
2627                 if (range_err)
2628                         msyslog(LOG_ERR,
2629                                 "mru %s %d out of range, ignored.",
2630                                 keyword(my_opt->attr), my_opt->value.i);
2631         }
2632
2633         /* Configure the discard options */
2634         my_opt = HEAD_PFIFO(ptree->discard_opts);
2635         for (; my_opt != NULL; my_opt = my_opt->link) {
2636
2637                 switch (my_opt->attr) {
2638
2639                 case T_Average:
2640                         if (0 <= my_opt->value.i &&
2641                             my_opt->value.i <= UCHAR_MAX)
2642                                 ntp_minpoll = (u_char)my_opt->value.u;
2643                         else
2644                                 msyslog(LOG_ERR,
2645                                         "discard average %d out of range, ignored.",
2646                                         my_opt->value.i);
2647                         break;
2648
2649                 case T_Minimum:
2650                         ntp_minpkt = my_opt->value.i;
2651                         break;
2652
2653                 case T_Monitor:
2654                         mon_age = my_opt->value.i;
2655                         break;
2656
2657                 default:
2658                         msyslog(LOG_ERR,
2659                                 "Unknown discard option %s (%d)",
2660                                 keyword(my_opt->attr), my_opt->attr);
2661                         exit(1);
2662                 }
2663         }
2664
2665         /* Configure each line of restrict options */
2666         my_node = HEAD_PFIFO(ptree->restrict_opts);
2667
2668         for (; my_node != NULL; my_node = my_node->link) {
2669
2670                 /* Grab the ippeerlmit */
2671                 ippeerlimit = my_node->ippeerlimit;
2672
2673                 /* Parse the flags */
2674                 rflags = 0;
2675                 mflags = 0;
2676
2677                 my_opt = HEAD_PFIFO(my_node->flag_tok_fifo);
2678                 for (; my_opt != NULL; my_opt = my_opt->link) {
2679                         switch (my_opt->attr) {
2680
2681                         default:
2682                                 fatal_error("config_access: Unknown flag-type-token=%s/%d", keyword(my_opt->attr), my_opt->attr);
2683
2684                         case T_Ntpport:
2685                                 mflags |= RESM_NTPONLY;
2686                                 break;
2687
2688                         case T_Source:
2689                                 mflags |= RESM_SOURCE;
2690                                 break;
2691
2692                         case T_Flake:
2693                                 rflags |= RES_FLAKE;
2694                                 break;
2695
2696                         case T_Ignore:
2697                                 rflags |= RES_IGNORE;
2698                                 break;
2699
2700                         case T_Kod:
2701                                 rflags |= RES_KOD;
2702                                 break;
2703
2704                         case T_Limited:
2705                                 rflags |= RES_LIMITED;
2706                                 break;
2707
2708                         case T_Lowpriotrap:
2709                                 rflags |= RES_LPTRAP;
2710                                 break;
2711
2712                         case T_Mssntp:
2713                                 rflags |= RES_MSSNTP;
2714                                 break;
2715
2716                         case T_Nomodify:
2717                                 rflags |= RES_NOMODIFY;
2718                                 break;
2719
2720                         case T_Nomrulist:
2721                                 rflags |= RES_NOMRULIST;
2722                                 break;
2723
2724                         case T_Noepeer:
2725                                 rflags |= RES_NOEPEER;
2726                                 break;
2727
2728                         case T_Nopeer:
2729                                 rflags |= RES_NOPEER;
2730                                 break;
2731
2732                         case T_Noquery:
2733                                 rflags |= RES_NOQUERY;
2734                                 break;
2735
2736                         case T_Noserve:
2737                                 rflags |= RES_DONTSERVE;
2738                                 break;
2739
2740                         case T_Notrap:
2741                                 rflags |= RES_NOTRAP;
2742                                 break;
2743
2744                         case T_Notrust:
2745                                 rflags |= RES_DONTTRUST;
2746                                 break;
2747
2748                         case T_ServerresponseFuzz:
2749                                 rflags |= RES_SRVRSPFUZ;
2750                                 break;
2751
2752                         case T_Version:
2753                                 rflags |= RES_VERSION;
2754                                 break;
2755                         }
2756                 }
2757
2758                 if ((RES_MSSNTP & rflags) && !warned_signd) {
2759                         warned_signd = 1;
2760                         fprintf(stderr, "%s\n", signd_warning);
2761                         msyslog(LOG_WARNING, "%s", signd_warning);
2762                 }
2763
2764                 /* It would be swell if we could identify the line number */
2765                 if ((RES_KOD & rflags) && !(RES_LIMITED & rflags)) {
2766                         const char *kod_where = (my_node->addr)
2767                                           ? my_node->addr->address
2768                                           : (mflags & RESM_SOURCE)
2769                                             ? "source"
2770                                             : "default";
2771                         const char *kod_warn = "KOD does nothing without LIMITED.";
2772
2773                         fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn);
2774                         msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn);
2775                 }
2776
2777                 ZERO_SOCK(&addr);
2778                 ai_list = NULL;
2779                 pai = NULL;
2780                 restrict_default = 0;
2781
2782                 if (NULL == my_node->addr) {
2783                         ZERO_SOCK(&mask);
2784                         if (!(RESM_SOURCE & mflags)) {
2785                                 /*
2786                                  * The user specified a default rule
2787                                  * without a -4 / -6 qualifier, add to
2788                                  * both lists
2789                                  */
2790                                 restrict_default = 1;
2791                         } else {
2792                                 /* apply "restrict source ..." */
2793                                 DPRINTF(1, ("restrict source template ippeerlimit %d mflags %x rflags %x\n",
2794                                         ippeerlimit, mflags, rflags));
2795                                 hack_restrict(RESTRICT_FLAGS, NULL, NULL,
2796                                               ippeerlimit, mflags, rflags, 0);
2797                                 continue;
2798                         }
2799                 } else {
2800                         /* Resolve the specified address */
2801                         AF(&addr) = (u_short)my_node->addr->type;
2802
2803                         if (getnetnum(my_node->addr->address,
2804                                       &addr, 1, t_UNK) != 1) {
2805                                 /*
2806                                  * Attempt a blocking lookup.  This
2807                                  * is in violation of the nonblocking
2808                                  * design of ntpd's mainline code.  The
2809                                  * alternative of running without the
2810                                  * restriction until the name resolved
2811                                  * seems worse.
2812                                  * Ideally some scheme could be used for
2813                                  * restrict directives in the startup
2814                                  * ntp.conf to delay starting up the
2815                                  * protocol machinery until after all
2816                                  * restrict hosts have been resolved.
2817                                  */
2818                                 ai_list = NULL;
2819                                 ZERO(hints);
2820                                 hints.ai_protocol = IPPROTO_UDP;
2821                                 hints.ai_socktype = SOCK_DGRAM;
2822                                 hints.ai_family = my_node->addr->type;
2823                                 rc = getaddrinfo(my_node->addr->address,
2824                                                  "ntp", &hints,
2825                                                  &ai_list);
2826                                 if (rc) {
2827                                         msyslog(LOG_ERR,
2828                                                 "restrict: ignoring line %d, address/host '%s' unusable.",
2829                                                 my_node->line_no,
2830                                                 my_node->addr->address);
2831                                         continue;
2832                                 }
2833                                 INSIST(ai_list != NULL);
2834                                 pai = ai_list;
2835                                 INSIST(pai->ai_addr != NULL);
2836                                 INSIST(sizeof(addr) >=
2837                                            pai->ai_addrlen);
2838                                 memcpy(&addr, pai->ai_addr,
2839                                        pai->ai_addrlen);
2840                                 INSIST(AF_INET == AF(&addr) ||
2841                                            AF_INET6 == AF(&addr));
2842                         }
2843
2844                         SET_HOSTMASK(&mask, AF(&addr));
2845
2846                         /* Resolve the mask */
2847                         if (my_node->mask) {
2848                                 ZERO_SOCK(&mask);
2849                                 AF(&mask) = my_node->mask->type;
2850                                 if (getnetnum(my_node->mask->address,
2851                                               &mask, 1, t_MSK) != 1) {
2852                                         msyslog(LOG_ERR,
2853                                                 "restrict: ignoring line %d, mask '%s' unusable.",
2854                                                 my_node->line_no,
2855                                                 my_node->mask->address);
2856                                         continue;
2857                                 }
2858                         }
2859                 }
2860
2861                 /* Set the flags */
2862                 if (restrict_default) {
2863                         AF(&addr) = AF_INET;
2864                         AF(&mask) = AF_INET;
2865                         hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2866                                       ippeerlimit, mflags, rflags, 0);
2867                         AF(&addr) = AF_INET6;
2868                         AF(&mask) = AF_INET6;
2869                 }
2870
2871                 do {
2872                         hack_restrict(RESTRICT_FLAGS, &addr, &mask,
2873                                       ippeerlimit, mflags, rflags, 0);
2874                         if (pai != NULL &&
2875                             NULL != (pai = pai->ai_next)) {
2876                                 INSIST(pai->ai_addr != NULL);
2877                                 INSIST(sizeof(addr) >=
2878                                            pai->ai_addrlen);
2879                                 ZERO_SOCK(&addr);
2880                                 memcpy(&addr, pai->ai_addr,
2881                                        pai->ai_addrlen);
2882                                 INSIST(AF_INET == AF(&addr) ||
2883                                            AF_INET6 == AF(&addr));
2884                                 SET_HOSTMASK(&mask, AF(&addr));
2885                         }
2886                 } while (pai != NULL);
2887
2888                 if (ai_list != NULL)
2889                         freeaddrinfo(ai_list);
2890         }
2891
2892         /* Deal with the Poll Skew List */
2893
2894         ZERO(psl);
2895         ZERO(my_psl_item);
2896
2897         /*
2898          * First, find the last default pollskewlist item.
2899          * There should only be one of these with the current grammar,
2900          * but better safe than sorry.
2901          */
2902         dflt_psl_atr = NULL;
2903         atrv = HEAD_PFIFO(ptree->pollskewlist);
2904         for ( ; atrv != NULL; atrv = atrv->link) {
2905                 switch (atrv->attr) {
2906                 case -1:        /* default */
2907                         dflt_psl_atr = atrv;
2908                         break;
2909
2910                 case 3:         /* Fall through */
2911                 case 4:         /* Fall through */
2912                 case 5:         /* Fall through */
2913                 case 6:         /* Fall through */
2914                 case 7:         /* Fall through */
2915                 case 8:         /* Fall through */
2916                 case 9:         /* Fall through */
2917                 case 10:        /* Fall through */
2918                 case 11:        /* Fall through */
2919                 case 12:        /* Fall through */
2920                 case 13:        /* Fall through */
2921                 case 14:        /* Fall through */
2922                 case 15:        /* Fall through */
2923                 case 16:        /* Fall through */
2924                 case 17:
2925                         /* ignore */
2926                         break;
2927
2928                 default:
2929                         msyslog(LOG_ERR,
2930                                 "config_access: default PSL scan: ignoring unexpected poll value %d",
2931                                 atrv->attr);
2932                         break;
2933                 }
2934         }
2935
2936         /* If we have a nonzero default, initialize the PSL */
2937         if (   dflt_psl_atr
2938             && (   0 != dflt_psl_atr->value.r.first
2939                 || 0 != dflt_psl_atr->value.r.last)) {
2940                 int i;
2941
2942                 for (i = 3; i <= 17; ++i) {
2943                         attrtopsl(i, dflt_psl_atr);
2944                 }
2945         }
2946
2947         /* Finally, update the PSL with any explicit entries */
2948         atrv = HEAD_PFIFO(ptree->pollskewlist);
2949         for ( ; atrv != NULL; atrv = atrv->link) {
2950                 switch (atrv->attr) {
2951                 case -1:        /* default */
2952                         /* Ignore */
2953                         break;
2954
2955                 case 3:         /* Fall through */
2956                 case 4:         /* Fall through */
2957                 case 5:         /* Fall through */
2958                 case 6:         /* Fall through */
2959                 case 7:         /* Fall through */
2960                 case 8:         /* Fall through */
2961                 case 9:         /* Fall through */
2962                 case 10:        /* Fall through */
2963                 case 11:        /* Fall through */
2964                 case 12:        /* Fall through */
2965                 case 13:        /* Fall through */
2966                 case 14:        /* Fall through */
2967                 case 15:        /* Fall through */
2968                 case 16:        /* Fall through */
2969                 case 17:
2970                         attrtopsl(atrv->attr, atrv);
2971                         break;
2972
2973                 default:
2974                         break;  /* Ignore - we reported this above */
2975                 }
2976         }
2977
2978 #if 0
2979         int p;
2980         msyslog(LOG_INFO, "Dumping PSL:");
2981         for (p = 3; p <= 17; ++p) {
2982                 psl_item psi;
2983
2984                 if (0 == get_pollskew(p, &psi)) {
2985                         msyslog(LOG_INFO, "poll %d: sub %d, qty %d, msk %d",
2986                                 p, psi.sub, psi.qty, psi.msk);
2987                 } else {
2988                         msyslog(LOG_ERR, "Dumping PSL: get_pollskew(%d) failed!", p);
2989                 }
2990         }
2991 #endif
2992 }
2993
2994
2995 void
2996 attrtopsl(int poll, attr_val *avp)
2997 {
2998
2999         DEBUG_INSIST((poll - 3) < sizeof psl);
3000         if (poll < 3 || poll > 17) {
3001                 msyslog(LOG_ERR, "attrtopsl(%d, ...): Poll value is out of range - ignoring", poll);
3002         } else {
3003                 int pao = poll - 3;             /* poll array offset */
3004                 int lower = avp->value.r.first; /* a positive number */
3005                 int upper = avp->value.r.last;
3006                 int psmax = 1 << (poll - 1);
3007                 int qmsk;
3008
3009                 if (lower > psmax) {
3010                         msyslog(LOG_WARNING, "attrtopsl: default: poll %d lower bound reduced from %d to %d",
3011                                 poll, lower, psmax);
3012                         lower = psmax;
3013                 }
3014                 if (upper > psmax) {
3015                         msyslog(LOG_WARNING, "attrtopsl: default: poll %d upper bound reduced from %d to %d",
3016                                 poll, upper, psmax);
3017                         upper = psmax;
3018                 }
3019                 psl[pao].sub = lower;
3020                 psl[pao].qty = lower + upper;
3021
3022                 qmsk = 1;
3023                 while (qmsk < (lower + upper)) {
3024                         qmsk <<= 1;
3025                         qmsk |=  1;
3026                 };
3027                 psl[pao].msk = qmsk;
3028         }
3029
3030         return;
3031
3032 #endif  /* !SIM */
3033
3034
3035 int
3036 get_pollskew(
3037         int p,
3038         psl_item *rv
3039         )
3040 {
3041
3042         DEBUG_INSIST(3 <= p && 17 >= p);
3043         if (3 <= p && 17 >= p) {
3044                 *rv = psl[p - 3];
3045
3046                 return 0;
3047         } else {
3048                 msyslog(LOG_ERR, "get_pollskew(%d): poll is not between 3 and 17!", p);
3049                 return -1;
3050         }
3051
3052         /* NOTREACHED */
3053 }
3054
3055
3056 #ifdef FREE_CFG_T
3057 static void
3058 free_config_access(
3059         config_tree *ptree
3060         )
3061 {
3062         FREE_ATTR_VAL_FIFO(ptree->mru_opts);
3063         FREE_ATTR_VAL_FIFO(ptree->discard_opts);
3064         FREE_RESTRICT_FIFO(ptree->restrict_opts);
3065 }
3066 #endif  /* FREE_CFG_T */
3067
3068
3069 static void
3070 config_rlimit(
3071         config_tree *ptree
3072         )
3073 {
3074         attr_val *      rlimit_av;
3075
3076         rlimit_av = HEAD_PFIFO(ptree->rlimit);
3077         for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) {
3078                 switch (rlimit_av->attr) {
3079
3080                 default:
3081                         fatal_error("config-rlimit: value-token=%d", rlimit_av->attr);
3082
3083                 case T_Memlock:
3084                         /* What if we HAVE_OPT(SAVECONFIGQUIT) ? */
3085                         if (HAVE_OPT( SAVECONFIGQUIT )) {
3086                                 break;
3087                         }
3088                         if (rlimit_av->value.i == -1) {
3089 # if defined(HAVE_MLOCKALL)
3090                                 if (cur_memlock != 0) {
3091                                         if (-1 == munlockall()) {
3092                                                 msyslog(LOG_ERR, "munlockall() failed: %m");
3093                                         }
3094                                 }
3095                                 cur_memlock = 0;
3096 # endif /* HAVE_MLOCKALL */
3097                         } else if (rlimit_av->value.i >= 0) {
3098 #if defined(RLIMIT_MEMLOCK)
3099 # if defined(HAVE_MLOCKALL)
3100                                 if (cur_memlock != 1) {
3101                                         if (-1 == mlockall(MCL_CURRENT|MCL_FUTURE)) {
3102                                                 msyslog(LOG_ERR, "mlockall() failed: %m");
3103                                         }
3104                                 }
3105 # endif /* HAVE_MLOCKALL */
3106                                 ntp_rlimit(RLIMIT_MEMLOCK,
3107                                            (rlim_t)(rlimit_av->value.i * 1024 * 1024),
3108                                            1024 * 1024,
3109                                            "MB");
3110                                 cur_memlock = 1;
3111 #else
3112                                 /* STDERR as well would be fine... */
3113                                 msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system.");
3114 #endif /* RLIMIT_MEMLOCK */
3115                         } else {
3116                                 msyslog(LOG_WARNING, "'rlimit memlock' value of %d is unexpected!", rlimit_av->value.i);
3117                         }
3118                         break;
3119
3120                 case T_Stacksize:
3121 #if defined(RLIMIT_STACK)
3122                         ntp_rlimit(RLIMIT_STACK,
3123                                    (rlim_t)(rlimit_av->value.i * 4096),
3124                                    4096,
3125                                    "4k");
3126 #else
3127                         /* STDERR as well would be fine... */
3128                         msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system.");
3129 #endif /* RLIMIT_STACK */
3130                         break;
3131
3132                 case T_Filenum:
3133 #if defined(RLIMIT_NOFILE)
3134                         ntp_rlimit(RLIMIT_NOFILE,
3135                                   (rlim_t)(rlimit_av->value.i),
3136                                   1,
3137                                   "");
3138 #else
3139                         /* STDERR as well would be fine... */
3140                         msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system.");
3141 #endif /* RLIMIT_NOFILE */
3142                         break;
3143
3144                 }
3145         }
3146 }
3147
3148
3149 static void
3150 config_tinker(
3151         config_tree *ptree
3152         )
3153 {
3154         attr_val *      tinker;
3155         int             item;
3156
3157         tinker = HEAD_PFIFO(ptree->tinker);
3158         for (; tinker != NULL; tinker = tinker->link) {
3159                 switch (tinker->attr) {
3160
3161                 default:
3162                         fatal_error("config_tinker: attr-token=%d", tinker->attr);
3163
3164                 case T_Allan:
3165                         item = LOOP_ALLAN;
3166                         break;
3167
3168                 case T_Dispersion:
3169                         item = LOOP_PHI;
3170                         break;
3171
3172                 case T_Freq:
3173                         item = LOOP_FREQ;
3174                         break;
3175
3176                 case T_Huffpuff:
3177                         item = LOOP_HUFFPUFF;
3178                         break;
3179
3180                 case T_Panic:
3181                         item = LOOP_PANIC;
3182                         break;
3183
3184                 case T_Step:
3185                         item = LOOP_MAX;
3186                         break;
3187
3188                 case T_Stepback:
3189                         item = LOOP_MAX_BACK;
3190                         break;
3191
3192                 case T_Stepfwd:
3193                         item = LOOP_MAX_FWD;
3194                         break;
3195
3196                 case T_Stepout:
3197                         item = LOOP_MINSTEP;
3198                         break;
3199
3200                 case T_Tick:
3201                         item = LOOP_TICK;
3202                         break;
3203                 }
3204                 loop_config(item, tinker->value.d);
3205         }
3206 }
3207
3208
3209 #ifdef FREE_CFG_T
3210 static void
3211 free_config_rlimit(
3212         config_tree *ptree
3213         )
3214 {
3215         FREE_ATTR_VAL_FIFO(ptree->rlimit);
3216 }
3217
3218 static void
3219 free_config_tinker(
3220         config_tree *ptree
3221         )
3222 {
3223         FREE_ATTR_VAL_FIFO(ptree->tinker);
3224 }
3225 #endif  /* FREE_CFG_T */
3226
3227
3228 /*
3229  * config_nic_rules - apply interface listen/ignore/drop items
3230  */
3231 #ifndef SIM
3232 static void
3233 config_nic_rules(
3234         config_tree *ptree,
3235         int/*BOOL*/ input_from_file
3236         )
3237 {
3238         nic_rule_node * curr_node;
3239         sockaddr_u      addr;
3240         nic_rule_match  match_type;
3241         nic_rule_action action;
3242         char *          if_name;
3243         char *          pchSlash;
3244         int             prefixlen;
3245         int             addrbits;
3246
3247         curr_node = HEAD_PFIFO(ptree->nic_rules);
3248
3249         if (curr_node != NULL
3250             && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) {
3251                 msyslog(LOG_ERR,
3252                         "interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s",
3253                         (input_from_file) ? ", exiting" : "");
3254                 if (input_from_file)
3255                         exit(1);
3256                 else
3257                         return;
3258         }
3259
3260         for (; curr_node != NULL; curr_node = curr_node->link) {
3261                 prefixlen = -1;
3262                 if_name = curr_node->if_name;
3263                 if (if_name != NULL)
3264                         if_name = estrdup(if_name);
3265
3266                 switch (curr_node->match_class) {
3267
3268                 default:
3269                         fatal_error("config_nic_rules: match-class-token=%d", curr_node->match_class);
3270
3271                 case 0:
3272                         /*
3273                          * 0 is out of range for valid token T_...
3274                          * and in a nic_rules_node indicates the
3275                          * interface descriptor is either a name or
3276                          * address, stored in if_name in either case.
3277                          */
3278                         INSIST(if_name != NULL);
3279                         pchSlash = strchr(if_name, '/');
3280                         if (pchSlash != NULL)
3281                                 *pchSlash = '\0';
3282                         if (is_ip_address(if_name, AF_UNSPEC, &addr)) {
3283                                 match_type = MATCH_IFADDR;
3284                                 if (pchSlash != NULL
3285                                     && 1 == sscanf(pchSlash + 1, "%d",
3286                                             &prefixlen)) {
3287                                         addrbits = 8 *
3288                                             SIZEOF_INADDR(AF(&addr));
3289                                         prefixlen = max(-1, prefixlen);
3290                                         prefixlen = min(prefixlen,
3291                                                         addrbits);
3292                                 }
3293                         } else {
3294                                 match_type = MATCH_IFNAME;
3295                                 if (pchSlash != NULL)
3296                                         *pchSlash = '/';
3297                         }
3298                         break;
3299
3300                 case T_All:
3301                         match_type = MATCH_ALL;
3302                         break;
3303
3304                 case T_Ipv4:
3305                         match_type = MATCH_IPV4;
3306                         break;
3307
3308                 case T_Ipv6:
3309                         match_type = MATCH_IPV6;
3310                         break;
3311
3312                 case T_Wildcard:
3313                         match_type = MATCH_WILDCARD;
3314                         break;
3315                 }
3316
3317                 switch (curr_node->action) {
3318
3319                 default:
3320                         fatal_error("config_nic_rules: action-token=%d", curr_node->action);
3321
3322                 case T_Listen:
3323                         action = ACTION_LISTEN;
3324                         break;
3325
3326                 case T_Ignore:
3327                         action = ACTION_IGNORE;
3328                         break;
3329
3330                 case T_Drop:
3331                         action = ACTION_DROP;
3332                         break;
3333                 }
3334
3335                 add_nic_rule(match_type, if_name, prefixlen,
3336                              action);
3337                 timer_interfacetimeout(current_time + 2);
3338                 if (if_name != NULL)
3339                         free(if_name);
3340         }
3341 }
3342 #endif  /* !SIM */
3343
3344
3345 #ifdef FREE_CFG_T
3346 static void
3347 free_config_nic_rules(
3348         config_tree *ptree
3349         )
3350 {
3351         nic_rule_node *curr_node;
3352
3353         if (ptree->nic_rules != NULL) {
3354                 for (;;) {
3355                         UNLINK_FIFO(curr_node, *ptree->nic_rules, link);
3356                         if (NULL == curr_node)
3357                                 break;
3358                         free(curr_node->if_name);
3359                         free(curr_node);
3360                 }
3361                 free(ptree->nic_rules);
3362                 ptree->nic_rules = NULL;
3363         }
3364 }
3365 #endif  /* FREE_CFG_T */
3366
3367
3368 static void
3369 apply_enable_disable(
3370         attr_val_fifo * fifo,
3371         int             enable
3372         )
3373 {
3374         attr_val *curr_tok_fifo;
3375         int option;
3376 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3377         bc_entry *pentry;
3378 #endif
3379
3380         for (curr_tok_fifo = HEAD_PFIFO(fifo);
3381              curr_tok_fifo != NULL;
3382              curr_tok_fifo = curr_tok_fifo->link) {
3383
3384                 option = curr_tok_fifo->value.i;
3385                 switch (option) {
3386
3387                 default:
3388                         msyslog(LOG_ERR,
3389                                 "can not apply enable/disable token %d, unknown",
3390                                 option);
3391                         break;
3392
3393                 case T_Auth:
3394                         proto_config(PROTO_AUTHENTICATE, enable, 0., NULL);
3395                         break;
3396
3397                 case T_Bclient:
3398                         proto_config(PROTO_BROADCLIENT, enable, 0., NULL);
3399                         break;
3400
3401                 case T_Calibrate:
3402                         proto_config(PROTO_CAL, enable, 0., NULL);
3403                         break;
3404
3405                 case T_Kernel:
3406                         proto_config(PROTO_KERNEL, enable, 0., NULL);
3407                         break;
3408
3409                 case T_Monitor:
3410                         proto_config(PROTO_MONITOR, enable, 0., NULL);
3411                         break;
3412
3413                 case T_Mode7:
3414                         proto_config(PROTO_MODE7, enable, 0., NULL);
3415                         break;
3416
3417                 case T_Ntp:
3418                         proto_config(PROTO_NTP, enable, 0., NULL);
3419                         break;
3420
3421                 case T_PCEdigest:
3422                         proto_config(PROTO_PCEDIGEST, enable, 0., NULL);
3423                         break;
3424
3425                 case T_Stats:
3426                         proto_config(PROTO_FILEGEN, enable, 0., NULL);
3427                         break;
3428
3429                 case T_UEcrypto:
3430                         proto_config(PROTO_UECRYPTO, enable, 0., NULL);
3431                         break;
3432
3433                 case T_UEcryptonak:
3434                         proto_config(PROTO_UECRYPTONAK, enable, 0., NULL);
3435                         break;
3436
3437                 case T_UEdigest:
3438                         proto_config(PROTO_UEDIGEST, enable, 0., NULL);
3439                         break;
3440
3441 #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED
3442                 case T_Bc_bugXXXX:
3443                         pentry = bc_list;
3444                         while (pentry->token) {
3445                                 if (pentry->token == option)
3446                                         break;
3447                                 pentry++;
3448                         }
3449                         if (!pentry->token) {
3450                                 msyslog(LOG_ERR,
3451                                         "compat token %d not in bc_list[]",
3452                                         option);
3453                                 continue;
3454                         }
3455                         pentry->enabled = enable;
3456                         break;
3457 #endif
3458                 }
3459         }
3460 }
3461
3462
3463 static void
3464 config_system_opts(
3465         config_tree *ptree
3466         )
3467 {
3468         apply_enable_disable(ptree->enable_opts, 1);
3469         apply_enable_disable(ptree->disable_opts, 0);
3470 }
3471
3472
3473 #ifdef FREE_CFG_T
3474 static void
3475 free_config_system_opts(
3476         config_tree *ptree
3477         )
3478 {
3479         FREE_ATTR_VAL_FIFO(ptree->enable_opts);
3480         FREE_ATTR_VAL_FIFO(ptree->disable_opts);
3481 }
3482 #endif  /* FREE_CFG_T */
3483
3484
3485 static void
3486 config_logconfig(
3487         config_tree *ptree
3488         )
3489 {
3490         attr_val *      my_lc;
3491
3492         my_lc = HEAD_PFIFO(ptree->logconfig);
3493         for (; my_lc != NULL; my_lc = my_lc->link) {
3494                 switch (my_lc->attr) {
3495
3496                 case '+':
3497                         ntp_syslogmask |= get_logmask(my_lc->value.s);
3498                         break;
3499
3500                 case '-':
3501                         ntp_syslogmask &= ~get_logmask(my_lc->value.s);
3502                         break;
3503
3504                 case '=':
3505                         ntp_syslogmask = get_logmask(my_lc->value.s);
3506                         break;
3507                 default:
3508                         fatal_error("config-logconfig: modifier='%c'", my_lc->attr);
3509                 }
3510         }
3511 }
3512
3513
3514 #ifdef FREE_CFG_T
3515 static void
3516 free_config_logconfig(
3517         config_tree *ptree
3518         )
3519 {
3520         FREE_ATTR_VAL_FIFO(ptree->logconfig);
3521 }
3522 #endif  /* FREE_CFG_T */
3523
3524
3525 #ifndef SIM
3526 static void
3527 config_phone(
3528         config_tree *ptree
3529         )
3530 {
3531         size_t          i;
3532         string_node *   sn;
3533
3534         i = 0;
3535         sn = HEAD_PFIFO(ptree->phone);
3536         for (; sn != NULL; sn = sn->link) {
3537                 /* need to leave array entry for NULL terminator */
3538                 if (i < COUNTOF(sys_phone) - 1) {
3539                         sys_phone[i++] = estrdup(sn->s);
3540                         sys_phone[i] = NULL;
3541                 } else {
3542                         msyslog(LOG_INFO,
3543                                 "phone: Number of phone entries exceeds %zu. Ignoring phone %s...",
3544                                 (COUNTOF(sys_phone) - 1), sn->s);
3545                 }
3546         }
3547 }
3548 #endif  /* !SIM */
3549
3550 static void
3551 config_mdnstries(
3552         config_tree *ptree
3553         )
3554 {
3555 #ifdef HAVE_DNSREGISTRATION
3556         extern int mdnstries;
3557         mdnstries = ptree->mdnstries;
3558 #endif  /* HAVE_DNSREGISTRATION */
3559 }
3560
3561 #ifdef FREE_CFG_T
3562 static void
3563 free_config_phone(
3564         config_tree *ptree
3565         )
3566 {
3567         FREE_STRING_FIFO(ptree->phone);
3568 }
3569 #endif  /* FREE_CFG_T */
3570
3571
3572 #ifndef SIM
3573 static void
3574 config_setvar(
3575         config_tree *ptree
3576         )
3577 {
3578         setvar_node *my_node;
3579         size_t  varlen, vallen, octets;
3580         char *  str;
3581
3582         str = NULL;
3583         my_node = HEAD_PFIFO(ptree->setvar);
3584         for (; my_node != NULL; my_node = my_node->link) {
3585                 varlen = strlen(my_node->var);
3586                 vallen = strlen(my_node->val);
3587                 octets = varlen + vallen + 1 + 1;
3588                 str = erealloc(str, octets);
3589                 snprintf(str, octets, "%s=%s", my_node->var,
3590                          my_node->val);
3591                 set_sys_var(str, octets, (my_node->isdefault)
3592                                                 ? DEF
3593                                                 : 0);
3594         }
3595         if (str != NULL)
3596                 free(str);
3597 }
3598 #endif  /* !SIM */
3599
3600
3601 #ifdef FREE_CFG_T
3602 static void
3603 free_config_setvar(
3604         config_tree *ptree
3605         )
3606 {
3607         FREE_SETVAR_FIFO(ptree->setvar);
3608 }
3609 #endif  /* FREE_CFG_T */
3610
3611
3612 #ifndef SIM
3613 static void
3614 config_ttl(
3615         config_tree *ptree
3616         )
3617 {
3618         size_t i = 0;
3619         int_node *curr_ttl;
3620
3621         /* [Bug 3465] There is a built-in default for the TTLs. We must
3622          * overwrite 'sys_ttlmax' if we change that preset, and leave it
3623          * alone otherwise!
3624          */
3625         curr_ttl = HEAD_PFIFO(ptree->ttl);
3626         for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) {
3627                 if (i < COUNTOF(sys_ttl))
3628                         sys_ttl[i++] = (u_char)curr_ttl->i;
3629                 else
3630                         msyslog(LOG_INFO,
3631                                 "ttl: Number of TTL entries exceeds %zu. Ignoring TTL %d...",
3632                                 COUNTOF(sys_ttl), curr_ttl->i);
3633         }
3634         if (0 != i) /* anything written back at all? */
3635                 sys_ttlmax = i - 1;
3636 }
3637 #endif  /* !SIM */
3638
3639
3640 #ifdef FREE_CFG_T
3641 static void
3642 free_config_ttl(
3643         config_tree *ptree
3644         )
3645 {
3646         FREE_INT_FIFO(ptree->ttl);
3647 }
3648 #endif  /* FREE_CFG_T */
3649
3650
3651 #ifndef SIM
3652 static void
3653 config_trap(
3654         config_tree *ptree
3655         )
3656 {
3657         addr_opts_node *curr_trap;
3658         attr_val *curr_opt;
3659         sockaddr_u addr_sock;
3660         sockaddr_u peeraddr;
3661         struct interface *localaddr;
3662         struct addrinfo hints;
3663         char port_text[8];
3664         settrap_parms *pstp;
3665         u_short port;
3666         int err_flag;
3667         int rc;
3668
3669         /* silence warning about addr_sock potentially uninitialized */
3670         AF(&addr_sock) = AF_UNSPEC;
3671
3672         curr_trap = HEAD_PFIFO(ptree->trap);
3673         for (; curr_trap != NULL; curr_trap = curr_trap->link) {
3674                 err_flag = 0;
3675                 port = 0;
3676                 localaddr = NULL;
3677
3678                 curr_opt = HEAD_PFIFO(curr_trap->options);
3679                 for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3680                         if (T_Port == curr_opt->attr) {
3681                                 if (curr_opt->value.i < 1
3682                                     || curr_opt->value.i > USHRT_MAX) {
3683                                         msyslog(LOG_ERR,
3684                                                 "invalid port number "
3685                                                 "%d, trap ignored",
3686                                                 curr_opt->value.i);
3687                                         err_flag = 1;
3688                                 }
3689                                 port = (u_short)curr_opt->value.i;
3690                         }
3691                         else if (T_Interface == curr_opt->attr) {
3692                                 /* Resolve the interface address */
3693                                 ZERO_SOCK(&addr_sock);
3694                                 if (getnetnum(curr_opt->value.s,
3695                                               &addr_sock, 1, t_UNK) != 1) {
3696                                         err_flag = 1;
3697                                         break;
3698                                 }
3699
3700                                 localaddr = findinterface(&addr_sock);
3701
3702                                 if (NULL == localaddr) {
3703                                         msyslog(LOG_ERR,
3704                                                 "can't find interface with address %s",
3705                                                 stoa(&addr_sock));
3706                                         err_flag = 1;
3707                                 }
3708                         }
3709                 }
3710
3711                 /* Now process the trap for the specified interface
3712                  * and port number
3713                  */
3714                 if (!err_flag) {
3715                         if (!port)
3716                                 port = TRAPPORT;
3717                         ZERO_SOCK(&peeraddr);
3718                         rc = getnetnum(curr_trap->addr->address,
3719                                        &peeraddr, 1, t_UNK);
3720                         if (1 != rc) {
3721 #ifndef WORKER
3722                                 msyslog(LOG_ERR,
3723                                         "trap: unable to use IP address %s.",
3724                                         curr_trap->addr->address);
3725 #else   /* WORKER follows */
3726                                 /*
3727                                  * save context and hand it off
3728                                  * for name resolution.
3729                                  */
3730                                 ZERO(hints);
3731                                 hints.ai_protocol = IPPROTO_UDP;
3732                                 hints.ai_socktype = SOCK_DGRAM;
3733                                 snprintf(port_text, sizeof(port_text),
3734                                          "%u", port);
3735                                 hints.ai_flags = Z_AI_NUMERICSERV;
3736                                 pstp = emalloc_zero(sizeof(*pstp));
3737                                 if (localaddr != NULL) {
3738                                         hints.ai_family = localaddr->family;
3739                                         pstp->ifaddr_nonnull = 1;
3740                                         memcpy(&pstp->ifaddr,
3741                                                &localaddr->sin,
3742                                                sizeof(pstp->ifaddr));
3743                                 }
3744                                 rc = getaddrinfo_sometime(
3745                                         curr_trap->addr->address,
3746                                         port_text, &hints,
3747                                         INITIAL_DNS_RETRY,
3748                                         &trap_name_resolved,
3749                                         pstp);
3750                                 if (!rc)
3751                                         msyslog(LOG_ERR,
3752                                                 "config_trap: getaddrinfo_sometime(%s,%s): %m",
3753                                                 curr_trap->addr->address,
3754                                                 port_text);
3755 #endif  /* WORKER */
3756                                 continue;
3757                         }
3758                         /* port is at same location for v4 and v6 */
3759                         SET_PORT(&peeraddr, port);
3760
3761                         if (NULL == localaddr)
3762                                 localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3763                         else
3764                                 AF(&peeraddr) = AF(&addr_sock);
3765
3766                         if (!ctlsettrap(&peeraddr, localaddr, 0,
3767                                         NTP_VERSION))
3768                                 msyslog(LOG_ERR,
3769                                         "set trap %s -> %s failed.",
3770                                         latoa(localaddr),
3771                                         stoa(&peeraddr));
3772                 }
3773         }
3774 }
3775
3776
3777 /*
3778  * trap_name_resolved()
3779  *
3780  * Callback invoked when config_trap()'s DNS lookup completes.
3781  */
3782 # ifdef WORKER
3783 static void
3784 trap_name_resolved(
3785         int                     rescode,
3786         int                     gai_errno,
3787         void *                  context,
3788         const char *            name,
3789         const char *            service,
3790         const struct addrinfo * hints,
3791         const struct addrinfo * res
3792         )
3793 {
3794         settrap_parms *pstp;
3795         struct interface *localaddr;
3796         sockaddr_u peeraddr;
3797
3798         (void)gai_errno;
3799         (void)service;
3800         (void)hints;
3801         pstp = context;
3802         if (rescode) {
3803                 msyslog(LOG_ERR,
3804                         "giving up resolving trap host %s: %s (%d)",
3805                         name, gai_strerror(rescode), rescode);
3806                 free(pstp);
3807                 return;
3808         }
3809         INSIST(sizeof(peeraddr) >= res->ai_addrlen);
3810         ZERO(peeraddr);
3811         memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
3812         localaddr = NULL;
3813         if (pstp->ifaddr_nonnull)
3814                 localaddr = findinterface(&pstp->ifaddr);
3815         if (NULL == localaddr)
3816                 localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
3817         if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION))
3818                 msyslog(LOG_ERR, "set trap %s -> %s failed.",
3819                         latoa(localaddr), stoa(&peeraddr));
3820         free(pstp);
3821 }
3822 # endif /* WORKER */
3823 #endif  /* !SIM */
3824
3825
3826 #ifdef FREE_CFG_T
3827 static void
3828 free_config_trap(
3829         config_tree *ptree
3830         )
3831 {
3832         FREE_ADDR_OPTS_FIFO(ptree->trap);
3833 }
3834 #endif  /* FREE_CFG_T */
3835
3836
3837 #ifndef SIM
3838 static void
3839 config_fudge(
3840         config_tree *ptree
3841         )
3842 {
3843         addr_opts_node *curr_fudge;
3844         attr_val *curr_opt;
3845         sockaddr_u addr_sock;
3846         address_node *addr_node;
3847         struct refclockstat clock_stat;
3848         int err_flag;
3849
3850         curr_fudge = HEAD_PFIFO(ptree->fudge);
3851         for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) {
3852                 err_flag = 0;
3853
3854                 /* Get the reference clock address and
3855                  * ensure that it is sane
3856                  */
3857                 addr_node = curr_fudge->addr;
3858                 ZERO_SOCK(&addr_sock);
3859                 if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
3860                     != 1) {
3861                         err_flag = 1;
3862                         msyslog(LOG_ERR,
3863                                 "unrecognized fudge reference clock address %s, line ignored",
3864                                 addr_node->address);
3865                 } else if (!ISREFCLOCKADR(&addr_sock)) {
3866                         err_flag = 1;
3867                         msyslog(LOG_ERR,
3868                                 "inappropriate address %s for the fudge command, line ignored",
3869                                 stoa(&addr_sock));
3870                 }
3871
3872                 /* Parse all the options to the fudge command */
3873                 ZERO(clock_stat);
3874                 /* some things are not necessarily cleared by ZERO...*/
3875                 clock_stat.fudgeminjitter = 0.0;
3876                 clock_stat.fudgetime1     = 0.0;
3877                 clock_stat.fudgetime2     = 0.0;
3878                 clock_stat.p_lastcode     = NULL;
3879                 clock_stat.clockdesc      = NULL;
3880                 clock_stat.kv_list        = NULL;
3881                 curr_opt = HEAD_PFIFO(curr_fudge->options);
3882                 for (; curr_opt != NULL; curr_opt = curr_opt->link) {
3883                         switch (curr_opt->attr) {
3884
3885                         case T_Time1:
3886                                 clock_stat.haveflags |= CLK_HAVETIME1;
3887                                 clock_stat.fudgetime1 = curr_opt->value.d;
3888                                 break;
3889
3890                         case T_Time2:
3891                                 clock_stat.haveflags |= CLK_HAVETIME2;
3892                                 clock_stat.fudgetime2 = curr_opt->value.d;
3893                                 break;
3894
3895                         case T_Stratum:
3896                                 clock_stat.haveflags |= CLK_HAVEVAL1;
3897                                 clock_stat.fudgeval1 = curr_opt->value.i;
3898                                 break;
3899
3900                         case T_Refid:
3901                                 clock_stat.haveflags |= CLK_HAVEVAL2;
3902                                 /* strncpy() does exactly what we want here: */
3903                                 strncpy((char*)&clock_stat.fudgeval2,
3904                                         curr_opt->value.s, 4);
3905                                 break;
3906
3907                         case T_Flag1:
3908                                 clock_stat.haveflags |= CLK_HAVEFLAG1;
3909                                 if (curr_opt->value.i)
3910                                         clock_stat.flags |= CLK_FLAG1;
3911                                 else
3912                                         clock_stat.flags &= ~CLK_FLAG1;
3913                                 break;
3914
3915                         case T_Flag2:
3916                                 clock_stat.haveflags |= CLK_HAVEFLAG2;
3917                                 if (curr_opt->value.i)
3918                                         clock_stat.flags |= CLK_FLAG2;
3919                                 else
3920                                         clock_stat.flags &= ~CLK_FLAG2;
3921                                 break;
3922
3923                         case T_Flag3:
3924                                 clock_stat.haveflags |= CLK_HAVEFLAG3;
3925                                 if (curr_opt->value.i)
3926                                         clock_stat.flags |= CLK_FLAG3;
3927                                 else
3928                                         clock_stat.flags &= ~CLK_FLAG3;
3929                                 break;
3930
3931                         case T_Flag4:
3932                                 clock_stat.haveflags |= CLK_HAVEFLAG4;
3933                                 if (curr_opt->value.i)
3934                                         clock_stat.flags |= CLK_FLAG4;
3935                                 else
3936                                         clock_stat.flags &= ~CLK_FLAG4;
3937                                 break;
3938
3939                         case T_Minjitter:
3940                                 clock_stat.haveflags |= CLK_HAVEMINJIT;
3941                                 clock_stat.fudgeminjitter = curr_opt->value.d;
3942                                 break;
3943
3944                         default:
3945                                 msyslog(LOG_ERR,
3946                                         "Unexpected fudge flag %s (%d) for %s",
3947                                         token_name(curr_opt->attr),
3948                                         curr_opt->attr, addr_node->address);
3949                                 exit(curr_opt->attr ? curr_opt->attr : 1);
3950                         }
3951                 }
3952 # ifdef REFCLOCK
3953                 if (!err_flag)
3954                         refclock_control(&addr_sock, &clock_stat, NULL);
3955 # endif
3956         }
3957 }
3958 #endif  /* !SIM */
3959
3960
3961 #ifdef FREE_CFG_T
3962 static void
3963 free_config_fudge(
3964         config_tree *ptree
3965         )
3966 {
3967         FREE_ADDR_OPTS_FIFO(ptree->fudge);
3968 }
3969 #endif  /* FREE_CFG_T */
3970
3971
3972 static void
3973 config_vars(
3974         config_tree *ptree
3975         )
3976 {
3977         attr_val *curr_var;
3978         int len;
3979
3980         curr_var = HEAD_PFIFO(ptree->vars);
3981         for (; curr_var != NULL; curr_var = curr_var->link) {
3982                 /* Determine which variable to set and set it */
3983                 switch (curr_var->attr) {
3984
3985                 case T_Broadcastdelay:
3986                         proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL);
3987                         break;
3988
3989                 case T_Tick:
3990                         loop_config(LOOP_TICK, curr_var->value.d);
3991                         break;
3992
3993                 case T_Driftfile:
3994                         if ('\0' == curr_var->value.s[0]) {
3995                                 stats_drift_file = 0;
3996                                 msyslog(LOG_INFO, "config: driftfile disabled");
3997                         } else
3998                             stats_config(STATS_FREQ_FILE, curr_var->value.s, 0);
3999                         break;
4000
4001                 case T_Dscp:
4002                         /* DSCP is in the upper 6 bits of the IP TOS/DS field */
4003                         qos = curr_var->value.i << 2;
4004                         break;
4005
4006                 case T_Ident:
4007                         sys_ident = curr_var->value.s;
4008                         break;
4009
4010                 case T_WanderThreshold:         /* FALLTHROUGH */
4011                 case T_Nonvolatile:
4012                         wander_threshold = curr_var->value.d;
4013                         break;
4014
4015                 case T_Leapfile:
4016                     stats_config(STATS_LEAP_FILE, curr_var->value.s, curr_var->flag);
4017                         break;
4018
4019 #ifdef LEAP_SMEAR
4020                 case T_Leapsmearinterval:
4021                         leap_smear_intv = curr_var->value.i;
4022                         msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv);
4023                         break;
4024 #endif
4025
4026                 case T_Pidfile:
4027                     stats_config(STATS_PID_FILE, curr_var->value.s, 0);
4028                         break;
4029
4030                 case T_Logfile:
4031                         if (-1 == change_logfile(curr_var->value.s, TRUE))
4032                                 msyslog(LOG_ERR,
4033                                         "Cannot open logfile %s: %m",
4034                                         curr_var->value.s);
4035                         break;
4036
4037                 case T_Saveconfigdir:
4038                         if (saveconfigdir != NULL)
4039                                 free(saveconfigdir);
4040                         len = strlen(curr_var->value.s);
4041                         if (0 == len) {
4042                                 saveconfigdir = NULL;
4043                         } else if (DIR_SEP != curr_var->value.s[len - 1]
4044 #ifdef SYS_WINNT        /* slash is also a dir. sep. on Windows */
4045                                    && '/' != curr_var->value.s[len - 1]
4046 #endif
4047                                  ) {
4048                                         len++;
4049                                         saveconfigdir = emalloc(len + 1);
4050                                         snprintf(saveconfigdir, len + 1,
4051                                                  "%s%c",
4052                                                  curr_var->value.s,
4053                                                  DIR_SEP);
4054                         } else {
4055                                         saveconfigdir = estrdup(
4056                                             curr_var->value.s);
4057                         }
4058                         break;
4059
4060                 case T_Automax:
4061 #ifdef AUTOKEY
4062                         if (curr_var->value.i > 2 && curr_var->value.i < 32)
4063                                 sys_automax = (u_char)curr_var->value.i;
4064                         else
4065                                 msyslog(LOG_ERR,
4066                                         "'automax' value %d ignored",
4067                                         curr_var->value.i);
4068 #endif
4069                         break;
4070
4071                 default:
4072                         msyslog(LOG_ERR,
4073                                 "config_vars(): unexpected token %d",
4074                                 curr_var->attr);
4075                 }
4076         }
4077 }
4078
4079
4080 #ifdef FREE_CFG_T
4081 static void
4082 free_config_vars(
4083         config_tree *ptree
4084         )
4085 {
4086         FREE_ATTR_VAL_FIFO(ptree->vars);
4087 }
4088 #endif  /* FREE_CFG_T */
4089
4090
4091 /* Define a function to check if a resolved address is sane.
4092  * If yes, return 1, else return 0;
4093  */
4094 static int
4095 is_sane_resolved_address(
4096         sockaddr_u *    peeraddr,
4097         int             hmode
4098         )
4099 {
4100         if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) {
4101                 msyslog(LOG_ERR,
4102                         "attempt to configure invalid address %s",
4103                         stoa(peeraddr));
4104                 return 0;
4105         }
4106         /*
4107          * Shouldn't be able to specify:
4108          * - multicast address for server/peer!
4109          * - unicast address for manycastclient!
4110          */
4111         if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode)
4112             && IS_MCAST(peeraddr)) {
4113                 msyslog(LOG_ERR,
4114                         "attempt to configure invalid address %s",
4115                         stoa(peeraddr));
4116                 return 0;
4117         }
4118         if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) {
4119                 msyslog(LOG_ERR,
4120                         "attempt to configure invalid address %s",
4121                         stoa(peeraddr));
4122                 return 0;
4123         }
4124
4125         if (IS_IPV6(peeraddr) && !ipv6_works)
4126                 return 0;
4127
4128         /* Ok, all tests succeeded, now we can return 1 */
4129         return 1;
4130 }
4131
4132
4133 #ifndef SIM
4134 static u_char
4135 get_correct_host_mode(
4136         int token
4137         )
4138 {
4139         switch (token) {
4140
4141         case T_Server:
4142         case T_Pool:
4143         case T_Manycastclient:
4144                 return MODE_CLIENT;
4145
4146         case T_Peer:
4147                 return MODE_ACTIVE;
4148
4149         case T_Broadcast:
4150                 return MODE_BROADCAST;
4151
4152         default:
4153                 return 0;
4154         }
4155 }
4156
4157
4158 /*
4159  * peerflag_bits()      get config_peers() peerflags value from a
4160  *                      peer_node's queue of flag attr_val entries.
4161  */
4162 static int
4163 peerflag_bits(
4164         peer_node *pn
4165         )
4166 {
4167         int peerflags;
4168         attr_val *option;
4169         int     hmode;
4170
4171         DEBUG_INSIST(pn);
4172         /* translate peerflags options to bits */
4173         peerflags = 0;
4174         hmode = pn->host_mode;
4175         option = HEAD_PFIFO(pn->peerflags);
4176         for (; option != NULL; option = option->link) {
4177                 switch (option->value.i) {
4178
4179                 default:
4180                         fatal_error("peerflag_bits: option-token=%d", option->value.i);
4181
4182                 case T_Autokey:
4183                         peerflags |= FLAG_SKEY;
4184                         break;
4185
4186                 case T_Burst:
4187                         peerflags |= FLAG_BURST;
4188                         break;
4189
4190                 case T_Iburst:
4191                         peerflags |= FLAG_IBURST;
4192                         break;
4193
4194                 case T_Noselect:
4195                         peerflags |= FLAG_NOSELECT;
4196                         break;
4197
4198                 case T_Preempt:
4199                         peerflags |= FLAG_PREEMPT;
4200                         break;
4201
4202                 case T_Prefer:
4203                         peerflags |= FLAG_PREFER;
4204                         break;
4205
4206                 case T_True:
4207                         peerflags |= FLAG_TRUE;
4208                         break;
4209
4210                 case T_Xleave:
4211                         peerflags |= FLAG_XLEAVE;
4212                         break;
4213
4214                 case T_Xmtnonce:
4215                         if (   MODE_CLIENT == hmode ) {
4216                                 peerflags |= FLAG_LOOPNONCE;
4217                         }
4218                         break;
4219                 }
4220         }
4221
4222         return peerflags;
4223 }
4224
4225
4226 static void
4227 config_peers(
4228         config_tree *ptree
4229         )
4230 {
4231         sockaddr_u              peeraddr;
4232         struct addrinfo         hints;
4233         peer_node *             curr_peer;
4234         peer_resolved_ctx *     ctx;
4235         u_char                  hmode;
4236
4237         /* add servers named on the command line with iburst implied */
4238         for (;
4239              cmdline_server_count > 0;
4240              cmdline_server_count--, cmdline_servers++) {
4241
4242                 ZERO_SOCK(&peeraddr);
4243                 /*
4244                  * If we have a numeric address, we can safely
4245                  * proceed in the mainline with it.  Otherwise, hand
4246                  * the hostname off to the blocking child.
4247                  *
4248                  * Note that if we're told to add the peer here, we
4249                  * do that regardless of ippeerlimit.
4250                  */
4251                 if (is_ip_address(*cmdline_servers, AF_UNSPEC,
4252                                   &peeraddr)) {
4253
4254                         SET_PORT(&peeraddr, NTP_PORT);
4255                         if (is_sane_resolved_address(&peeraddr,
4256                                                      T_Server))
4257                                 peer_config(
4258                                         &peeraddr,
4259                                         NULL,
4260                                         NULL,
4261                                         -1,
4262                                         MODE_CLIENT,
4263                                         NTP_VERSION,
4264                                         0,
4265                                         0,
4266                                         FLAG_IBURST,
4267                                         0,
4268                                         0,
4269                                         NULL);
4270                 } else {
4271                         /* we have a hostname to resolve */
4272 # ifdef WORKER
4273                         ctx = emalloc_zero(sizeof(*ctx));
4274                         ctx->family = AF_UNSPEC;
4275                         ctx->host_mode = T_Server;
4276                         ctx->hmode = MODE_CLIENT;
4277                         ctx->version = NTP_VERSION;
4278                         ctx->flags = FLAG_IBURST;
4279
4280                         ZERO(hints);
4281                         hints.ai_family = (u_short)ctx->family;
4282                         hints.ai_socktype = SOCK_DGRAM;
4283                         hints.ai_protocol = IPPROTO_UDP;
4284
4285                         getaddrinfo_sometime_ex(*cmdline_servers,
4286                                              "ntp", &hints,
4287                                              INITIAL_DNS_RETRY,
4288                                              &peer_name_resolved,
4289                                              (void *)ctx, DNSFLAGS);
4290 # else  /* !WORKER follows */
4291                         msyslog(LOG_ERR,
4292                                 "hostname %s can not be used, please use IP address instead.",
4293                                 curr_peer->addr->address);
4294 # endif
4295                 }
4296         }
4297
4298         /* add associations from the configuration file */
4299         curr_peer = HEAD_PFIFO(ptree->peers);
4300         for (; curr_peer != NULL; curr_peer = curr_peer->link) {
4301                 ZERO_SOCK(&peeraddr);
4302                 /* Find the correct host-mode */
4303                 hmode = get_correct_host_mode(curr_peer->host_mode);
4304                 INSIST(hmode != 0);
4305
4306                 if (T_Pool == curr_peer->host_mode) {
4307                         AF(&peeraddr) = curr_peer->addr->type;
4308                         peer_config(
4309                                 &peeraddr,
4310                                 curr_peer->addr->address,
4311                                 NULL,
4312                                 -1,
4313                                 hmode,
4314                                 curr_peer->peerversion,
4315                                 curr_peer->minpoll,
4316                                 curr_peer->maxpoll,
4317                                 peerflag_bits(curr_peer),
4318                                 curr_peer->ttl,
4319                                 curr_peer->peerkey,
4320                                 curr_peer->group);
4321                 /*
4322                  * If we have a numeric address, we can safely
4323                  * proceed in the mainline with it.  Otherwise, hand
4324                  * the hostname off to the blocking child.
4325                  */
4326                 } else if (is_ip_address(curr_peer->addr->address,
4327                                   curr_peer->addr->type, &peeraddr)) {
4328
4329                         SET_PORT(&peeraddr, NTP_PORT);
4330                         if (is_sane_resolved_address(&peeraddr,
4331                             curr_peer->host_mode))
4332                                 peer_config(
4333                                         &peeraddr,
4334                                         NULL,
4335                                         NULL,
4336                                         -1,
4337                                         hmode,
4338                                         curr_peer->peerversion,
4339                                         curr_peer->minpoll,
4340                                         curr_peer->maxpoll,
4341                                         peerflag_bits(curr_peer),
4342                                         curr_peer->ttl,
4343                                         curr_peer->peerkey,
4344                                         curr_peer->group);
4345                 } else {
4346                         /* we have a hostname to resolve */
4347 # ifdef WORKER
4348                         ctx = emalloc_zero(sizeof(*ctx));
4349                         ctx->family = curr_peer->addr->type;
4350                         ctx->host_mode = curr_peer->host_mode;
4351                         ctx->hmode = hmode;
4352                         ctx->version = curr_peer->peerversion;
4353                         ctx->minpoll = curr_peer->minpoll;
4354                         ctx->maxpoll = curr_peer->maxpoll;
4355                         ctx->flags = peerflag_bits(curr_peer);
4356                         ctx->ttl = curr_peer->ttl;
4357                         ctx->keyid = curr_peer->peerkey;
4358                         ctx->group = curr_peer->group;
4359
4360                         ZERO(hints);
4361                         hints.ai_family = ctx->family;
4362                         hints.ai_socktype = SOCK_DGRAM;
4363                         hints.ai_protocol = IPPROTO_UDP;
4364
4365                         getaddrinfo_sometime_ex(curr_peer->addr->address,
4366                                              "ntp", &hints,
4367                                              INITIAL_DNS_RETRY,
4368                                              &peer_name_resolved, ctx,
4369                                              DNSFLAGS);
4370 # else  /* !WORKER follows */
4371                         msyslog(LOG_ERR,
4372                                 "hostname %s can not be used, please use IP address instead.",
4373                                 curr_peer->addr->address);
4374 # endif
4375                 }
4376         }
4377 }
4378 #endif  /* !SIM */
4379
4380 /*
4381  * peer_name_resolved()
4382  *
4383  * Callback invoked when config_peers()'s DNS lookup completes.
4384  */
4385 #ifdef WORKER
4386 static void
4387 peer_name_resolved(
4388         int                     rescode,
4389         int                     gai_errno,
4390         void *                  context,
4391         const char *            name,
4392         const char *            service,
4393         const struct addrinfo * hints,
4394         const struct addrinfo * res
4395         )
4396 {
4397         sockaddr_u              peeraddr;
4398         peer_resolved_ctx *     ctx;
4399         u_short                 af;
4400         const char *            fam_spec;
4401
4402         (void)gai_errno;
4403         (void)service;
4404         (void)hints;
4405         ctx = context;
4406
4407         DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
4408
4409         if (rescode) {
4410                 free(ctx);
4411                 msyslog(LOG_ERR,
4412                         "giving up resolving host %s: %s (%d)",
4413                         name, gai_strerror(rescode), rescode);
4414                 return;
4415         }
4416
4417         /* Loop to configure a single association */
4418         for (; res != NULL; res = res->ai_next) {
4419                 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4420                 if (is_sane_resolved_address(&peeraddr,
4421                                              ctx->host_mode)) {
4422                         NLOG(NLOG_SYSINFO) {
4423                                 af = ctx->family;
4424                                 fam_spec = (AF_INET6 == af)
4425                                                ? "(AAAA) "
4426                                                : (AF_INET == af)
4427                                                      ? "(A) "
4428                                                      : "";
4429                                 msyslog(LOG_INFO, "DNS %s %s-> %s",
4430                                         name, fam_spec,
4431                                         stoa(&peeraddr));
4432                         }
4433                         peer_config(
4434                                 &peeraddr,
4435                                 NULL,
4436                                 NULL,
4437                                 -1,
4438                                 ctx->hmode,
4439                                 ctx->version,
4440                                 ctx->minpoll,
4441                                 ctx->maxpoll,
4442                                 ctx->flags,
4443                                 ctx->ttl,
4444                                 ctx->keyid,
4445                                 ctx->group);
4446                         break;
4447                 }
4448         }
4449         free(ctx);
4450 }
4451 #endif  /* WORKER */
4452
4453
4454 #ifdef FREE_CFG_T
4455 static void
4456 free_config_peers(
4457         config_tree *ptree
4458         )
4459 {
4460         peer_node *curr_peer;
4461
4462         if (ptree->peers != NULL) {
4463                 for (;;) {
4464                         UNLINK_FIFO(curr_peer, *ptree->peers, link);
4465                         if (NULL == curr_peer)
4466                                 break;
4467                         destroy_address_node(curr_peer->addr);
4468                         destroy_attr_val_fifo(curr_peer->peerflags);
4469                         free(curr_peer);
4470                 }
4471                 free(ptree->peers);
4472                 ptree->peers = NULL;
4473         }
4474 }
4475 #endif  /* FREE_CFG_T */
4476
4477
4478 #ifndef SIM
4479 static void
4480 config_unpeers(
4481         config_tree *ptree
4482         )
4483 {
4484         sockaddr_u              peeraddr;
4485         struct addrinfo         hints;
4486         unpeer_node *           curr_unpeer;
4487         struct peer *           p;
4488         const char *            name;
4489         int                     rc;
4490
4491         curr_unpeer = HEAD_PFIFO(ptree->unpeers);
4492         for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) {
4493                 /*
4494                  * If we have no address attached, assume we have to
4495                  * unpeer by AssocID.
4496                  */
4497                 if (!curr_unpeer->addr) {
4498                         p = findpeerbyassoc(curr_unpeer->assocID);
4499                         if (p != NULL) {
4500                                 msyslog(LOG_NOTICE, "unpeered %s",
4501                                         stoa(&p->srcadr));
4502                                 peer_clear(p, "GONE");
4503                                 unpeer(p);
4504                         }
4505                         continue;
4506                 }
4507
4508                 ZERO(peeraddr);
4509                 AF(&peeraddr) = curr_unpeer->addr->type;
4510                 name = curr_unpeer->addr->address;
4511                 rc = getnetnum(name, &peeraddr, 0, t_UNK);
4512                 /* Do we have a numeric address? */
4513                 if (rc > 0) {
4514                         DPRINTF(1, ("unpeer: searching for %s\n",
4515                                     stoa(&peeraddr)));
4516                         p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4517                         if (p != NULL) {
4518                                 msyslog(LOG_NOTICE, "unpeered %s",
4519                                         stoa(&peeraddr));
4520                                 peer_clear(p, "GONE");
4521                                 unpeer(p);
4522                         }
4523                         continue;
4524                 }
4525                 /*
4526                  * It's not a numeric IP address, it's a hostname.
4527                  * Check for associations with a matching hostname.
4528                  */
4529                 for (p = peer_list; p != NULL; p = p->p_link)
4530                         if (p->hostname != NULL)
4531                                 if (!strcasecmp(p->hostname, name))
4532                                         break;
4533                 if (p != NULL) {
4534                         msyslog(LOG_NOTICE, "unpeered %s", name);
4535                         peer_clear(p, "GONE");
4536                         unpeer(p);
4537                 }
4538                 /* Resolve the hostname to address(es). */
4539 # ifdef WORKER
4540                 ZERO(hints);
4541                 hints.ai_family = curr_unpeer->addr->type;
4542                 hints.ai_socktype = SOCK_DGRAM;
4543                 hints.ai_protocol = IPPROTO_UDP;
4544                 getaddrinfo_sometime(name, "ntp", &hints,
4545                                      INITIAL_DNS_RETRY,
4546                                      &unpeer_name_resolved, NULL);
4547 # else  /* !WORKER follows */
4548                 msyslog(LOG_ERR,
4549                         "hostname %s can not be used, please use IP address instead.",
4550                         name);
4551 # endif
4552         }
4553 }
4554 #endif  /* !SIM */
4555
4556
4557 /*
4558  * unpeer_name_resolved()
4559  *
4560  * Callback invoked when config_unpeers()'s DNS lookup completes.
4561  */
4562 #ifdef WORKER
4563 static void
4564 unpeer_name_resolved(
4565         int                     rescode,
4566         int                     gai_errno,
4567         void *                  context,
4568         const char *            name,
4569         const char *            service,
4570         const struct addrinfo * hints,
4571         const struct addrinfo * res
4572         )
4573 {
4574         sockaddr_u      peeraddr;
4575         struct peer *   peer;
4576         u_short         af;
4577         const char *    fam_spec;
4578
4579         (void)context;
4580         (void)hints;
4581         DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
4582
4583         if (rescode) {
4584                 msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
4585                         name, gai_strerror(rescode), rescode);
4586                 return;
4587         }
4588         /*
4589          * Loop through the addresses found
4590          */
4591         for (; res != NULL; res = res->ai_next) {
4592                 INSIST(res->ai_addrlen <= sizeof(peeraddr));
4593                 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
4594                 DPRINTF(1, ("unpeer: searching for peer %s\n",
4595                             stoa(&peeraddr)));
4596                 peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
4597                 if (peer != NULL) {
4598                         af = AF(&peeraddr);
4599                         fam_spec = (AF_INET6 == af)
4600                                        ? "(AAAA) "
4601                                        : (AF_INET == af)
4602                                              ? "(A) "
4603                                              : "";
4604                         msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
4605                                 fam_spec, stoa(&peeraddr));
4606                         peer_clear(peer, "GONE");
4607                         unpeer(peer);
4608                 }
4609         }
4610 }
4611 #endif  /* WORKER */
4612
4613
4614 #ifdef FREE_CFG_T
4615 static void
4616 free_config_unpeers(
4617         config_tree *ptree
4618         )
4619 {
4620         unpeer_node *curr_unpeer;
4621
4622         if (ptree->unpeers != NULL) {
4623                 for (;;) {
4624                         UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link);
4625                         if (NULL == curr_unpeer)
4626                                 break;
4627                         destroy_address_node(curr_unpeer->addr);
4628                         free(curr_unpeer);
4629                 }
4630                 free(ptree->unpeers);
4631         }
4632 }
4633 #endif  /* FREE_CFG_T */
4634
4635
4636 #ifndef SIM
4637 static void
4638 config_reset_counters(
4639         config_tree *ptree
4640         )
4641 {
4642         int_node *counter_set;
4643
4644         for (counter_set = HEAD_PFIFO(ptree->reset_counters);
4645              counter_set != NULL;
4646              counter_set = counter_set->link) {
4647                 switch (counter_set->i) {
4648                 default:
4649                         DPRINTF(1, ("config_reset_counters %s (%d) invalid\n",
4650                                     keyword(counter_set->i), counter_set->i));
4651                         break;
4652
4653                 case T_Allpeers:
4654                         peer_all_reset();
4655                         break;
4656
4657                 case T_Auth:
4658                         reset_auth_stats();
4659                         break;
4660
4661                 case T_Ctl:
4662                         ctl_clr_stats();
4663                         break;
4664
4665                 case T_Io:
4666                         io_clr_stats();
4667                         break;
4668
4669                 case T_Mem:
4670                         peer_clr_stats();
4671                         break;
4672
4673                 case T_Sys:
4674                         proto_clr_stats();
4675                         break;
4676
4677                 case T_Timer:
4678                         timer_clr_stats();
4679                         break;
4680                 }
4681         }
4682 }
4683 #endif  /* !SIM */
4684
4685
4686 #ifdef FREE_CFG_T
4687 static void
4688 free_config_reset_counters(
4689         config_tree *ptree
4690         )
4691 {
4692         FREE_INT_FIFO(ptree->reset_counters);
4693 }
4694 #endif  /* FREE_CFG_T */
4695
4696
4697 #ifdef SIM
4698 static void
4699 config_sim(
4700         config_tree *ptree
4701         )
4702 {
4703         int i;
4704         server_info *serv_info;
4705         attr_val *init_stmt;
4706         sim_node *sim_n;
4707
4708         /* Check if a simulate block was found in the configuration code.
4709          * If not, return an error and exit
4710          */
4711         sim_n = HEAD_PFIFO(ptree->sim_details);
4712         if (NULL == sim_n) {
4713                 fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n");
4714                 fprintf(stderr, "\tCheck your configuration file.\n");
4715                 exit(1);
4716         }
4717
4718         /* Process the initialization statements
4719          * -------------------------------------
4720          */
4721         init_stmt = HEAD_PFIFO(sim_n->init_opts);
4722         for (; init_stmt != NULL; init_stmt = init_stmt->link) {
4723                 switch(init_stmt->attr) {
4724
4725                 case T_Beep_Delay:
4726                         simulation.beep_delay = init_stmt->value.d;
4727                         break;
4728
4729                 case T_Sim_Duration:
4730                         simulation.end_time = init_stmt->value.d;
4731                         break;
4732
4733                 default:
4734                         fprintf(stderr,
4735                                 "Unknown simulator init token %d\n",
4736                                 init_stmt->attr);
4737                         exit(1);
4738                 }
4739         }
4740
4741         /* Process the server list
4742          * -----------------------
4743          */
4744         simulation.num_of_servers = 0;
4745         serv_info = HEAD_PFIFO(sim_n->servers);
4746         for (; serv_info != NULL; serv_info = serv_info->link)
4747                 simulation.num_of_servers++;
4748         simulation.servers = eallocarray(simulation.num_of_servers,
4749                                      sizeof(simulation.servers[0]));
4750
4751         i = 0;
4752         serv_info = HEAD_PFIFO(sim_n->servers);
4753         for (; serv_info != NULL; serv_info = serv_info->link) {
4754                 if (NULL == serv_info) {
4755                         fprintf(stderr, "Simulator server list is corrupt\n");
4756                         exit(1);
4757                 } else {
4758                         simulation.servers[i] = *serv_info;
4759                         simulation.servers[i].link = NULL;
4760                         i++;
4761                 }
4762         }
4763
4764         printf("Creating server associations\n");
4765         create_server_associations();
4766         fprintf(stderr,"\tServer associations successfully created!!\n");
4767 }
4768
4769
4770 #ifdef FREE_CFG_T
4771 static void
4772 free_config_sim(
4773         config_tree *ptree
4774         )
4775 {
4776         sim_node *sim_n;
4777         server_info *serv_n;
4778         script_info *script_n;
4779
4780         if (NULL == ptree->sim_details)
4781                 return;
4782         sim_n = HEAD_PFIFO(ptree->sim_details);
4783         free(ptree->sim_details);
4784         ptree->sim_details = NULL;
4785         if (NULL == sim_n)
4786                 return;
4787
4788         FREE_ATTR_VAL_FIFO(sim_n->init_opts);
4789         for (;;) {
4790                 UNLINK_FIFO(serv_n, *sim_n->servers, link);
4791                 if (NULL == serv_n)
4792                         break;
4793                 free(serv_n->curr_script);
4794                 if (serv_n->script != NULL) {
4795                         for (;;) {
4796                                 UNLINK_FIFO(script_n, *serv_n->script,
4797                                             link);
4798                                 if (script_n == NULL)
4799                                         break;
4800                                 free(script_n);
4801                         }
4802                         free(serv_n->script);
4803                 }
4804                 free(serv_n);
4805         }
4806         free(sim_n);
4807 }
4808 #endif  /* FREE_CFG_T */
4809 #endif  /* SIM */
4810
4811
4812 /* Define two different config functions. One for the daemon and the other for
4813  * the simulator. The simulator ignores a lot of the standard ntpd configuration
4814  * options
4815  */
4816 #ifndef SIM
4817 static void
4818 config_ntpd(
4819         config_tree *ptree,
4820         int/*BOOL*/ input_from_files
4821         )
4822 {
4823         /* [Bug 3435] check and esure clock sanity if configured from
4824          * file and clock sanity parameters (-> basedate) are given. Do
4825          * this ASAP, so we don't disturb the closed loop controller.
4826          */
4827         if (input_from_files) {
4828                 if (config_tos_clock(ptree))
4829                         clamp_systime();
4830         }
4831
4832         config_nic_rules(ptree, input_from_files);
4833         config_monitor(ptree);
4834         config_auth(ptree);
4835         config_tos(ptree);
4836         config_access(ptree);
4837         config_tinker(ptree);
4838         config_rlimit(ptree);
4839         config_system_opts(ptree);
4840         config_logconfig(ptree);
4841         config_phone(ptree);
4842         config_mdnstries(ptree);
4843         config_setvar(ptree);
4844         config_ttl(ptree);
4845         config_vars(ptree);
4846
4847         io_open_sockets();      /* [bug 2837] dep. on config_vars() */
4848
4849         config_trap(ptree);     /* [bug 2923] dep. on io_open_sockets() */
4850         config_other_modes(ptree);
4851         config_peers(ptree);
4852         config_unpeers(ptree);
4853         config_fudge(ptree);
4854         config_reset_counters(ptree);
4855
4856 #ifdef DEBUG
4857         if (debug > 1) {
4858                 dump_restricts();
4859         }
4860 #endif
4861
4862 #ifdef TEST_BLOCKING_WORKER
4863         {
4864                 struct addrinfo hints;
4865
4866                 ZERO(hints);
4867                 hints.ai_socktype = SOCK_STREAM;
4868                 hints.ai_protocol = IPPROTO_TCP;
4869                 getaddrinfo_sometime("www.cnn.com", "ntp", &hints,
4870                                      INITIAL_DNS_RETRY,
4871                                      gai_test_callback, (void *)1);
4872                 hints.ai_family = AF_INET6;
4873                 getaddrinfo_sometime("ipv6.google.com", "ntp", &hints,
4874                                      INITIAL_DNS_RETRY,
4875                                      gai_test_callback, (void *)0x600);
4876         }
4877 #endif
4878 }
4879 #endif  /* !SIM */
4880
4881
4882 #ifdef SIM
4883 static void
4884 config_ntpdsim(
4885         config_tree *ptree
4886         )
4887 {
4888         printf("Configuring Simulator...\n");
4889         printf("Some ntpd-specific commands in the configuration file will be ignored.\n");
4890
4891         config_tos(ptree);
4892         config_monitor(ptree);
4893         config_tinker(ptree);
4894         if (0)
4895                 config_rlimit(ptree);   /* not needed for the simulator */
4896         config_system_opts(ptree);
4897         config_logconfig(ptree);
4898         config_vars(ptree);
4899         config_sim(ptree);
4900 }
4901 #endif /* SIM */
4902
4903
4904 /*
4905  * config_remotely() - implements ntpd side of ntpq :config
4906  */
4907 void
4908 config_remotely(
4909         sockaddr_u *    remote_addr
4910         )
4911 {
4912         char origin[128];
4913
4914         snprintf(origin, sizeof(origin), "remote config from %s",
4915                  stoa(remote_addr));
4916         lex_init_stack(origin, NULL); /* no checking needed... */
4917         init_syntax_tree(&cfgt);
4918         yyparse();
4919         lex_drop_stack();
4920
4921         cfgt.source.attr = CONF_SOURCE_NTPQ;
4922         cfgt.timestamp = time(NULL);
4923         cfgt.source.value.s = estrdup(stoa(remote_addr));
4924
4925         DPRINTF(1, ("Finished Parsing!!\n"));
4926
4927         save_and_apply_config_tree(FALSE);
4928 }
4929
4930
4931 /*
4932  * getconfig() - process startup configuration file e.g /etc/ntp.conf
4933  */
4934 void
4935 getconfig(
4936         int     argc,
4937         char ** argv
4938         )
4939 {
4940         char    line[256];
4941
4942 #ifdef DEBUG
4943         atexit(free_all_config_trees);
4944 #endif
4945 #ifndef SYS_WINNT
4946         config_file = CONFIG_FILE;
4947 #else
4948         temp = CONFIG_FILE;
4949         if (!ExpandEnvironmentStringsA(temp, config_file_storage,
4950                                        sizeof(config_file_storage))) {
4951                 msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m");
4952                 exit(1);
4953         }
4954         config_file = config_file_storage;
4955
4956         temp = ALT_CONFIG_FILE;
4957         if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage,
4958                                        sizeof(alt_config_file_storage))) {
4959                 msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m");
4960                 exit(1);
4961         }
4962         alt_config_file = alt_config_file_storage;
4963 #endif /* SYS_WINNT */
4964
4965         /*
4966          * install a non default variable with this daemon version
4967          */
4968         snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version);
4969         set_sys_var(line, strlen(line) + 1, RO);
4970
4971         /*
4972          * Set up for the first time step to install a variable showing
4973          * which syscall is being used to step.
4974          */
4975         set_tod_using = &ntpd_set_tod_using;
4976
4977         getCmdOpts(argc, argv);
4978         init_syntax_tree(&cfgt);
4979         if (
4980                 !lex_init_stack(FindConfig(config_file), "r")
4981 #ifdef HAVE_NETINFO
4982                 /* If there is no config_file, try NetInfo. */
4983                 && check_netinfo && !(config_netinfo = get_netinfo_config())
4984 #endif /* HAVE_NETINFO */
4985                 ) {
4986                 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(config_file));
4987 #ifndef SYS_WINNT
4988                 io_open_sockets();
4989
4990                 return;
4991 #else
4992                 /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
4993
4994                 if (!lex_init_stack(FindConfig(alt_config_file), "r"))  {
4995                         /*
4996                          * Broadcast clients can sometimes run without
4997                          * a configuration file.
4998                          */
4999                         msyslog(LOG_INFO, "getconfig: Couldn't open <%s>: %m", FindConfig(alt_config_file));
5000                         io_open_sockets();
5001
5002                         return;
5003                 }
5004                 cfgt.source.value.s = estrdup(alt_config_file);
5005 #endif  /* SYS_WINNT */
5006         } else
5007                 cfgt.source.value.s = estrdup(config_file);
5008
5009
5010         /*** BULK OF THE PARSER ***/
5011 #ifdef DEBUG
5012         yydebug = !!(debug >= 5);
5013 #endif
5014         yyparse();
5015         lex_drop_stack();
5016
5017         DPRINTF(1, ("Finished Parsing!!\n"));
5018
5019         cfgt.source.attr = CONF_SOURCE_FILE;
5020         cfgt.timestamp = time(NULL);
5021
5022         save_and_apply_config_tree(TRUE);
5023
5024 #ifdef HAVE_NETINFO
5025         if (config_netinfo)
5026                 free_netinfo_config(config_netinfo);
5027 #endif /* HAVE_NETINFO */
5028 }
5029
5030
5031 void
5032 save_and_apply_config_tree(int/*BOOL*/ input_from_file)
5033 {
5034         config_tree *ptree;
5035 #ifndef SAVECONFIG
5036         config_tree *punlinked;
5037 #endif
5038
5039         /*
5040          * Keep all the configuration trees applied since startup in
5041          * a list that can be used to dump the configuration back to
5042          * a text file.
5043          */
5044         ptree = emalloc(sizeof(*ptree));
5045         memcpy(ptree, &cfgt, sizeof(*ptree));
5046         ZERO(cfgt);
5047
5048         LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree);
5049
5050 #ifdef SAVECONFIG
5051         if (HAVE_OPT( SAVECONFIGQUIT )) {
5052                 FILE *dumpfile;
5053                 int err;
5054                 int dumpfailed;
5055
5056                 dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w");
5057                 if (NULL == dumpfile) {
5058                         err = errno;
5059                         mfprintf(stderr,
5060                                  "can not create save file %s, error %d %m\n",
5061                                  OPT_ARG(SAVECONFIGQUIT), err);
5062                         exit(err);
5063                 }
5064
5065                 dumpfailed = dump_all_config_trees(dumpfile, 0);
5066                 if (dumpfailed)
5067                         fprintf(stderr,
5068                                 "--saveconfigquit %s error %d\n",
5069                                 OPT_ARG( SAVECONFIGQUIT ),
5070                                 dumpfailed);
5071                 else
5072                         fprintf(stderr,
5073                                 "configuration saved to %s\n",
5074                                 OPT_ARG( SAVECONFIGQUIT ));
5075
5076                 exit(dumpfailed);
5077         }
5078 #endif  /* SAVECONFIG */
5079
5080         /* The actual configuration done depends on whether we are configuring the
5081          * simulator or the daemon. Perform a check and call the appropriate
5082          * function as needed.
5083          */
5084
5085 #ifndef SIM
5086         config_ntpd(ptree, input_from_file);
5087 #else
5088         config_ntpdsim(ptree);
5089 #endif
5090
5091         /*
5092          * With configure --disable-saveconfig, there's no use keeping
5093          * the config tree around after application, so free it.
5094          */
5095 #ifndef SAVECONFIG
5096         UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link,
5097                      config_tree);
5098         INSIST(punlinked == ptree);
5099         free_config_tree(ptree);
5100 #endif
5101 }
5102
5103 /* Hack to disambiguate 'server' statements for refclocks and network peers.
5104  * Please note the qualification 'hack'. It's just that.
5105  */
5106 static int/*BOOL*/
5107 is_refclk_addr(
5108         const address_node * addr
5109         )
5110 {
5111         return addr && addr->address && !strncmp(addr->address, "127.127.", 8);
5112 }
5113
5114 static void
5115 ntpd_set_tod_using(
5116         const char *which
5117         )
5118 {
5119         char line[128];
5120
5121         snprintf(line, sizeof(line), "settimeofday=\"%s\"", which);
5122         set_sys_var(line, strlen(line) + 1, RO);
5123 }
5124
5125
5126 static char *
5127 normal_dtoa(
5128         double d
5129         )
5130 {
5131         char *  buf;
5132         char *  pch_e;
5133         char *  pch_nz;
5134
5135         LIB_GETBUF(buf);
5136         snprintf(buf, LIB_BUFLENGTH, "%g", d);
5137
5138         /* use lowercase 'e', strip any leading zeroes in exponent */
5139         pch_e = strchr(buf, 'e');
5140         if (NULL == pch_e) {
5141                 pch_e = strchr(buf, 'E');
5142                 if (NULL == pch_e)
5143                         return buf;
5144                 *pch_e = 'e';
5145         }
5146         pch_e++;
5147         if ('-' == *pch_e)
5148                 pch_e++;
5149         pch_nz = pch_e;
5150         while ('0' == *pch_nz)
5151                 pch_nz++;
5152         if (pch_nz == pch_e)
5153                 return buf;
5154         strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf));
5155
5156         return buf;
5157 }
5158
5159
5160 /* FUNCTIONS COPIED FROM THE OLDER ntp_config.c
5161  * --------------------------------------------
5162  */
5163
5164
5165 /*
5166  * get_pfxmatch - find value for prefixmatch
5167  * and update char * accordingly
5168  */
5169 static u_int32
5170 get_pfxmatch(
5171         const char **   pstr,
5172         struct masks *  m
5173         )
5174 {
5175         while (m->name != NULL) {
5176                 if (strncmp(*pstr, m->name, strlen(m->name)) == 0) {
5177                         *pstr += strlen(m->name);
5178                         return m->mask;
5179                 } else {
5180                         m++;
5181                 }
5182         }
5183         return 0;
5184 }
5185
5186 /*
5187  * get_match - find logmask value
5188  */
5189 static u_int32
5190 get_match(
5191         const char *    str,
5192         struct masks *  m
5193         )
5194 {
5195         while (m->name != NULL) {
5196                 if (strcmp(str, m->name) == 0)
5197                         return m->mask;
5198                 else
5199                         m++;
5200         }
5201         return 0;
5202 }
5203
5204 /*
5205  * get_logmask - build bitmask for ntp_syslogmask
5206  */
5207 static u_int32
5208 get_logmask(
5209         const char *    str
5210         )
5211 {
5212         const char *    t;
5213         u_int32         offset;
5214         u_int32         mask;
5215
5216         mask = get_match(str, logcfg_noclass_items);
5217         if (mask != 0)
5218                 return mask;
5219
5220         t = str;
5221         offset = get_pfxmatch(&t, logcfg_class);
5222         mask   = get_match(t, logcfg_class_items);
5223
5224         if (mask)
5225                 return mask << offset;
5226         else
5227                 msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored",
5228                         str);
5229
5230         return 0;
5231 }
5232
5233
5234 #ifdef HAVE_NETINFO
5235
5236 /*
5237  * get_netinfo_config - find the nearest NetInfo domain with an ntp
5238  * configuration and initialize the configuration state.
5239  */
5240 static struct netinfo_config_state *
5241 get_netinfo_config(void)
5242 {
5243         ni_status status;
5244         void *domain;
5245         ni_id config_dir;
5246         struct netinfo_config_state *config;
5247
5248         if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
5249
5250         while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
5251                 void *next_domain;
5252                 if (ni_open(domain, "..", &next_domain) != NI_OK) {
5253                         ni_free(next_domain);
5254                         break;
5255                 }
5256                 ni_free(domain);
5257                 domain = next_domain;
5258         }
5259         if (status != NI_OK) {
5260                 ni_free(domain);
5261                 return NULL;
5262         }
5263
5264         config = emalloc(sizeof(*config));
5265         config->domain = domain;
5266         config->config_dir = config_dir;
5267         config->prop_index = 0;
5268         config->val_index = 0;
5269         config->val_list = NULL;
5270
5271         return config;
5272 }
5273
5274
5275 /*
5276  * free_netinfo_config - release NetInfo configuration state
5277  */
5278 static void
5279 free_netinfo_config(
5280         struct netinfo_config_state *config
5281         )
5282 {
5283         ni_free(config->domain);
5284         free(config);
5285 }
5286
5287
5288 /*
5289  * gettokens_netinfo - return tokens from NetInfo
5290  */
5291 static int
5292 gettokens_netinfo (
5293         struct netinfo_config_state *config,
5294         char **tokenlist,
5295         int *ntokens
5296         )
5297 {
5298         int prop_index = config->prop_index;
5299         int val_index = config->val_index;
5300         char **val_list = config->val_list;
5301
5302         /*
5303          * Iterate through each keyword and look for a property that matches it.
5304          */
5305   again:
5306         if (!val_list) {
5307                 for (; prop_index < COUNTOF(keywords); prop_index++)
5308                 {
5309                         ni_namelist namelist;
5310                         struct keyword current_prop = keywords[prop_index];
5311                         ni_index index;
5312
5313                         /*
5314                          * For each value associated in the property, we're going to return
5315                          * a separate line. We squirrel away the values in the config state
5316                          * so the next time through, we don't need to do this lookup.
5317                          */
5318                         NI_INIT(&namelist);
5319                         if (NI_OK == ni_lookupprop(config->domain,
5320                             &config->config_dir, current_prop.text,
5321                             &namelist)) {
5322
5323                                 /* Found the property, but it has no values */
5324                                 if (namelist.ni_namelist_len == 0) continue;
5325
5326                                 config->val_list =
5327                                     eallocarray(
5328                                         (namelist.ni_namelist_len + 1),
5329                                         sizeof(char*));
5330                                 val_list = config->val_list;
5331
5332                                 for (index = 0;
5333                                      index < namelist.ni_namelist_len;
5334                                      index++) {
5335                                         char *value;
5336
5337                                         value = namelist.ni_namelist_val[index];
5338                                         val_list[index] = estrdup(value);
5339                                 }
5340                                 val_list[index] = NULL;
5341
5342                                 break;
5343                         }
5344                         ni_namelist_free(&namelist);
5345                 }
5346                 config->prop_index = prop_index;
5347         }
5348
5349         /* No list; we're done here. */
5350         if (!val_list)
5351                 return CONFIG_UNKNOWN;
5352
5353         /*
5354          * We have a list of values for the current property.
5355          * Iterate through them and return each in order.
5356          */
5357         if (val_list[val_index]) {
5358                 int ntok = 1;
5359                 int quoted = 0;
5360                 char *tokens = val_list[val_index];
5361
5362                 msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
5363
5364                 (const char*)tokenlist[0] = keywords[prop_index].text;
5365                 for (ntok = 1; ntok < MAXTOKENS; ntok++) {
5366                         tokenlist[ntok] = tokens;
5367                         while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
5368                                 quoted ^= (*tokens++ == '"');
5369
5370                         if (ISEOL(*tokens)) {
5371                                 *tokens = '\0';
5372                                 break;
5373                         } else {                /* must be space */
5374                                 *tokens++ = '\0';
5375                                 while (ISSPACE(*tokens))
5376                                         tokens++;
5377                                 if (ISEOL(*tokens))
5378                                         break;
5379                         }
5380                 }
5381
5382                 if (ntok == MAXTOKENS) {
5383                         /* HMS: chomp it to lose the EOL? */
5384                         msyslog(LOG_ERR,
5385                                 "gettokens_netinfo: too many tokens.  Ignoring: %s",
5386                                 tokens);
5387                 } else {
5388                         *ntokens = ntok + 1;
5389                 }
5390
5391                 config->val_index++;    /* HMS: Should this be in the 'else'? */
5392
5393                 return keywords[prop_index].keytype;
5394         }
5395
5396         /* We're done with the current property. */
5397         prop_index = ++config->prop_index;
5398
5399         /* Free val_list and reset counters. */
5400         for (val_index = 0; val_list[val_index]; val_index++)
5401                 free(val_list[val_index]);
5402         free(val_list);
5403         val_list = config->val_list = NULL;
5404         val_index = config->val_index = 0;
5405
5406         goto again;
5407 }
5408 #endif /* HAVE_NETINFO */
5409
5410
5411 /*
5412  * getnetnum - return a net number (this is crude, but careful)
5413  *
5414  * returns 1 for success, and mysteriously, 0 for most failures, and
5415  * -1 if the address found is IPv6 and we believe IPv6 isn't working.
5416  */
5417 #ifndef SIM
5418 static int
5419 getnetnum(
5420         const char *num,
5421         sockaddr_u *addr,
5422         int complain,
5423         enum gnn_type a_type    /* ignored */
5424         )
5425 {
5426         REQUIRE(AF_UNSPEC == AF(addr) ||
5427                 AF_INET == AF(addr) ||
5428                 AF_INET6 == AF(addr));
5429
5430         if (!is_ip_address(num, AF(addr), addr))
5431                 return 0;
5432
5433         if (IS_IPV6(addr) && !ipv6_works)
5434                 return -1;
5435
5436 # ifdef ISC_PLATFORM_HAVESALEN
5437         addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr));
5438 # endif
5439         SET_PORT(addr, NTP_PORT);
5440
5441         DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr)));
5442
5443         return 1;
5444 }
5445 #endif  /* !SIM */
5446
5447 #if defined(HAVE_SETRLIMIT)
5448 void
5449 ntp_rlimit(
5450         int     rl_what,
5451         rlim_t  rl_value,
5452         int     rl_scale,
5453         const char *    rl_sstr
5454         )
5455 {
5456         struct rlimit   rl;
5457
5458         switch (rl_what) {
5459 # ifdef RLIMIT_MEMLOCK
5460             case RLIMIT_MEMLOCK:
5461                 if (HAVE_OPT( SAVECONFIGQUIT )) {
5462                         break;
5463                 }
5464                 /*
5465                  * The default RLIMIT_MEMLOCK is very low on Linux systems.
5466                  * Unless we increase this limit malloc calls are likely to
5467                  * fail if we drop root privilege.  To be useful the value
5468                  * has to be larger than the largest ntpd resident set size.
5469                  */
5470                 DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n",
5471                         (int)(rl_value / rl_scale), rl_sstr));
5472                 rl.rlim_cur = rl.rlim_max = rl_value;
5473                 if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1)
5474                         msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
5475                 break;
5476 # endif /* RLIMIT_MEMLOCK */
5477
5478 # ifdef RLIMIT_NOFILE
5479             case RLIMIT_NOFILE:
5480                 /*
5481                  * For large systems the default file descriptor limit may
5482                  * not be enough.
5483                  */
5484                 DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n",
5485                         (int)(rl_value / rl_scale), rl_sstr));
5486                 rl.rlim_cur = rl.rlim_max = rl_value;
5487                 if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
5488                         msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m");
5489                 break;
5490 # endif /* RLIMIT_NOFILE */
5491
5492 # ifdef RLIMIT_STACK
5493             case RLIMIT_STACK:
5494                 /*
5495                  * Provide a way to set the stack limit to something
5496                  * smaller, so that we don't lock a lot of unused
5497                  * stack memory.
5498                  */
5499                 DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n",
5500                             (int)(rl_value / rl_scale), rl_sstr));
5501                 if (-1 == getrlimit(RLIMIT_STACK, &rl)) {
5502                         msyslog(LOG_ERR, "getrlimit(RLIMIT_STACK) failed: %m");
5503                 } else {
5504                         if (rl_value > rl.rlim_max) {
5505                                 msyslog(LOG_WARNING,
5506                                         "ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.",
5507                                         (u_long)rl.rlim_max,
5508                                         (u_long)rl_value);
5509                                 rl_value = rl.rlim_max;
5510                         }
5511                         rl.rlim_cur = rl_value;
5512                         if (-1 == setrlimit(RLIMIT_STACK, &rl)) {
5513                                 msyslog(LOG_ERR,
5514                                         "ntp_rlimit: Cannot set RLIMIT_STACK: %m");
5515                         }
5516                 }
5517                 break;
5518 # endif /* RLIMIT_STACK */
5519
5520             default:
5521                     fatal_error("ntp_rlimit: unexpected RLIMIT case: %d", rl_what);
5522         }
5523 }
5524 #endif  /* HAVE_SETRLIMIT */
5525
5526
5527 char *
5528 build_iflags(
5529         u_int32 iflags
5530         )
5531 {
5532         static char ifs[1024];
5533
5534         ifs[0] = '\0';
5535
5536         if (iflags & INT_UP) {
5537                 iflags &= ~INT_UP;
5538                 appendstr(ifs, sizeof ifs, "up");
5539         }
5540
5541         if (iflags & INT_PPP) {
5542                 iflags &= ~INT_PPP;
5543                 appendstr(ifs, sizeof ifs, "ppp");
5544         }
5545
5546         if (iflags & INT_LOOPBACK) {
5547                 iflags &= ~INT_LOOPBACK;
5548                 appendstr(ifs, sizeof ifs, "loopback");
5549         }
5550
5551         if (iflags & INT_BROADCAST) {
5552                 iflags &= ~INT_BROADCAST;
5553                 appendstr(ifs, sizeof ifs, "broadcast");
5554         }
5555
5556         if (iflags & INT_MULTICAST) {
5557                 iflags &= ~INT_MULTICAST;
5558                 appendstr(ifs, sizeof ifs, "multicast");
5559         }
5560
5561         if (iflags & INT_BCASTOPEN) {
5562                 iflags &= ~INT_BCASTOPEN;
5563                 appendstr(ifs, sizeof ifs, "bcastopen");
5564         }
5565
5566         if (iflags & INT_MCASTOPEN) {
5567                 iflags &= ~INT_MCASTOPEN;
5568                 appendstr(ifs, sizeof ifs, "mcastopen");
5569         }
5570
5571         if (iflags & INT_WILDCARD) {
5572                 iflags &= ~INT_WILDCARD;
5573                 appendstr(ifs, sizeof ifs, "wildcard");
5574         }
5575
5576         if (iflags & INT_MCASTIF) {
5577                 iflags &= ~INT_MCASTIF;
5578                 appendstr(ifs, sizeof ifs, "MCASTif");
5579         }
5580
5581         if (iflags & INT_PRIVACY) {
5582                 iflags &= ~INT_PRIVACY;
5583                 appendstr(ifs, sizeof ifs, "IPv6privacy");
5584         }
5585
5586         if (iflags & INT_BCASTXMIT) {
5587                 iflags &= ~INT_BCASTXMIT;
5588                 appendstr(ifs, sizeof ifs, "bcastxmit");
5589         }
5590
5591         if (iflags) {
5592                 char string[10];
5593
5594                 snprintf(string, sizeof string, "%0x", iflags);
5595                 appendstr(ifs, sizeof ifs, string);
5596         }
5597
5598         return ifs;
5599 }
5600
5601
5602 char *
5603 build_mflags(
5604         u_short mflags
5605         )
5606 {
5607         static char mfs[1024];
5608
5609         mfs[0] = '\0';
5610
5611         if (mflags & RESM_NTPONLY) {
5612                 mflags &= ~RESM_NTPONLY;
5613                 appendstr(mfs, sizeof mfs, "ntponly");
5614         }
5615
5616         if (mflags & RESM_SOURCE) {
5617                 mflags &= ~RESM_SOURCE;
5618                 appendstr(mfs, sizeof mfs, "source");
5619         }
5620
5621         if (mflags) {
5622                 char string[10];
5623
5624                 snprintf(string, sizeof string, "%0x", mflags);
5625                 appendstr(mfs, sizeof mfs, string);
5626         }
5627
5628         return mfs;
5629 }
5630
5631
5632 char *
5633 build_rflags(
5634         u_short rflags
5635         )
5636 {
5637         static char rfs[1024];
5638
5639         rfs[0] = '\0';
5640
5641         if (rflags & RES_FLAKE) {
5642                 rflags &= ~RES_FLAKE;
5643                 appendstr(rfs, sizeof rfs, "flake");
5644         }
5645
5646         if (rflags & RES_IGNORE) {
5647                 rflags &= ~RES_IGNORE;
5648                 appendstr(rfs, sizeof rfs, "ignore");
5649         }
5650
5651         if (rflags & RES_KOD) {
5652                 rflags &= ~RES_KOD;
5653                 appendstr(rfs, sizeof rfs, "kod");
5654         }
5655
5656         if (rflags & RES_MSSNTP) {
5657                 rflags &= ~RES_MSSNTP;
5658                 appendstr(rfs, sizeof rfs, "mssntp");
5659         }
5660
5661         if (rflags & RES_LIMITED) {
5662                 rflags &= ~RES_LIMITED;
5663                 appendstr(rfs, sizeof rfs, "limited");
5664         }
5665
5666         if (rflags & RES_LPTRAP) {
5667                 rflags &= ~RES_LPTRAP;
5668                 appendstr(rfs, sizeof rfs, "lptrap");
5669         }
5670
5671         if (rflags & RES_NOMODIFY) {
5672                 rflags &= ~RES_NOMODIFY;
5673                 appendstr(rfs, sizeof rfs, "nomodify");
5674         }
5675
5676         if (rflags & RES_NOMRULIST) {
5677                 rflags &= ~RES_NOMRULIST;
5678                 appendstr(rfs, sizeof rfs, "nomrulist");
5679         }
5680
5681         if (rflags & RES_NOEPEER) {
5682                 rflags &= ~RES_NOEPEER;
5683                 appendstr(rfs, sizeof rfs, "noepeer");
5684         }
5685
5686         if (rflags & RES_NOPEER) {
5687                 rflags &= ~RES_NOPEER;
5688                 appendstr(rfs, sizeof rfs, "nopeer");
5689         }
5690
5691         if (rflags & RES_NOQUERY) {
5692                 rflags &= ~RES_NOQUERY;
5693                 appendstr(rfs, sizeof rfs, "noquery");
5694         }
5695
5696         if (rflags & RES_DONTSERVE) {
5697                 rflags &= ~RES_DONTSERVE;
5698                 appendstr(rfs, sizeof rfs, "dontserve");
5699         }
5700
5701         if (rflags & RES_NOTRAP) {
5702                 rflags &= ~RES_NOTRAP;
5703                 appendstr(rfs, sizeof rfs, "notrap");
5704         }
5705
5706         if (rflags & RES_DONTTRUST) {
5707                 rflags &= ~RES_DONTTRUST;
5708                 appendstr(rfs, sizeof rfs, "notrust");
5709         }
5710
5711         if (rflags & RES_SRVRSPFUZ) {
5712                 rflags &= ~RES_SRVRSPFUZ;
5713                 appendstr(rfs, sizeof rfs, "srvrspfuz");
5714         }
5715
5716         if (rflags & RES_VERSION) {
5717                 rflags &= ~RES_VERSION;
5718                 appendstr(rfs, sizeof rfs, "version");
5719         }
5720
5721         if (rflags) {
5722                 char string[10];
5723
5724                 snprintf(string, sizeof string, "%0x", rflags);
5725                 appendstr(rfs, sizeof rfs, string);
5726         }
5727
5728         if ('\0' == rfs[0]) {
5729                 appendstr(rfs, sizeof rfs, "(none)");
5730         }
5731
5732         return rfs;
5733 }
5734
5735
5736 static void
5737 appendstr(
5738         char *string,
5739         size_t s,
5740         const char *new
5741         )
5742 {
5743         if (*string != '\0') {
5744                 (void)strlcat(string, ",", s);
5745         }
5746         (void)strlcat(string, new, s);
5747
5748         return;
5749 }