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