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