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