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