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