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