1 /* 2 * ntp_config.c - read and apply configuration information 3 */ 4 5 #ifdef HAVE_CONFIG_H 6 # include <config.h> 7 #endif 8 9 #include <stdio.h> 10 #include <ctype.h> 11 #include <sys/param.h> 12 #include <sys/types.h> 13 #include <signal.h> 14 #ifndef SIGCHLD 15 #define SIGCHLD SIGCLD 16 #endif 17 #if !defined(VMS) 18 #ifdef HAVE_SYS_WAIT_H 19 #include <sys/wait.h> 20 #endif 21 #endif /* VMS */ 22 #include <sys/time.h> 23 24 #ifdef HAVE_NETINFO 25 #include <netinfo/ni.h> 26 #endif 27 28 #include "ntpd.h" 29 #include "ntp_io.h" 30 #include "ntp_unixtime.h" 31 #include "ntp_refclock.h" 32 #include "ntp_filegen.h" 33 #include "ntp_stdlib.h" 34 35 #ifdef SYS_WINNT 36 #include <io.h> 37 extern HANDLE ResolverThreadHandle; 38 #endif /* SYS_WINNT */ 39 40 /* 41 * These routines are used to read the configuration file at 42 * startup time. An entry in the file must fit on a single line. 43 * Entries are processed as multiple tokens separated by white space 44 * Lines are considered terminated when a '#' is encountered. Blank 45 * lines are ignored. 46 */ 47 48 /* 49 * Configuration file name 50 */ 51 #ifndef CONFIG_FILE 52 # ifndef SYS_WINNT 53 # define CONFIG_FILE "/etc/ntp.conf" 54 # else /* SYS_WINNT */ 55 # define CONFIG_FILE "%windir%\\system32\\drivers\\etc\\ntp.conf" 56 # define ALT_CONFIG_FILE "%windir%\\ntp.conf" 57 # endif /* SYS_WINNT */ 58 #endif /* not CONFIG_FILE */ 59 60 /* 61 * We understand the following configuration entries and defaults. 62 * 63 * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] 64 * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] 65 * broadcast [ addr ] [ version 3 ] [ key 0 ] [ ttl 1 ] 66 * broadcastclient 67 * multicastclient [ 224.0.1.1 ] 68 * manycastclient [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] 69 * manycastserver [ 224.0.1.1 ] 70 * broadcastdelay 0.0102 71 * restrict [ addr ] [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery 72 * driftfile file_name 73 * keys file_name 74 * statsdir /var/NTP/ 75 * filegen peerstats [ file peerstats ] [ type day ] [ link ] 76 * clientlimit [ n ] 77 * clientperiod [ 3600 ] 78 * trustedkey [ key ] 79 * requestkey [ key] 80 * controlkey [ key ] 81 * trap [ addr ] 82 * fudge [ addr ] [ stratum ] [ refid ] ... 83 * pidfile [ ] 84 * setvar [ ] 85 * logfile logfile 86 * logconfig [+|-|=][{sync|sys|peer|clock}{{,all}{info|statistics|events|status}}]... 87 * enable auth|bclient|pll|kernel|monitor|stats 88 * disable auth|bclient|pll|kernel|monitor|stats 89 * phone ... 90 * pps device [assert|clear] [hardpps] 91 */ 92 93 /* 94 * Types of entries we understand. 95 */ 96 #define CONFIG_UNKNOWN 0 97 98 #define CONFIG_PEER 1 99 #define CONFIG_SERVER 2 100 #define CONFIG_AUTOMAX 3 101 #define CONFIG_DRIFTFILE 4 102 #define CONFIG_BROADCAST 5 103 #define CONFIG_BROADCASTCLIENT 6 104 #define CONFIG_AUTHENTICATE 7 105 #define CONFIG_KEYS 8 106 #define CONFIG_REVOKE 9 107 #define CONFIG_PPS 10 108 #define CONFIG_RESTRICT 11 109 #define CONFIG_BDELAY 12 110 #define CONFIG_TRUSTEDKEY 13 111 #define CONFIG_REQUESTKEY 14 112 #define CONFIG_CONTROLKEY 15 113 #define CONFIG_TRAP 16 114 #define CONFIG_FUDGE 17 115 #define CONFIG_18 18 /* unused */ 116 #define CONFIG_STATSDIR 19 117 #define CONFIG_FILEGEN 20 118 #define CONFIG_STATISTICS 21 119 #define CONFIG_PIDFILE 22 120 #define CONFIG_SETVAR 23 121 #define CONFIG_CLIENTLIMIT 24 122 #define CONFIG_CLIENTPERIOD 25 123 #define CONFIG_MULTICASTCLIENT 26 124 #define CONFIG_ENABLE 27 125 #define CONFIG_DISABLE 28 126 #define CONFIG_PHONE 29 127 #define CONFIG_LOGFILE 30 128 #define CONFIG_LOGCONFIG 31 129 #define CONFIG_MANYCASTCLIENT 32 130 #define CONFIG_MANYCASTSERVER 33 131 132 #define CONF_MOD_VERSION 1 133 #define CONF_MOD_KEY 2 134 #define CONF_MOD_MINPOLL 3 135 #define CONF_MOD_MAXPOLL 4 136 #define CONF_MOD_PREFER 5 137 #define CONF_MOD_BURST 6 138 #define CONF_MOD_SKEY 7 139 #define CONF_MOD_TTL 8 140 #define CONF_MOD_MODE 9 141 #define CONF_MOD_NOSELECT 10 142 143 #define CONF_RES_MASK 1 144 #define CONF_RES_IGNORE 2 145 #define CONF_RES_NOSERVE 3 146 #define CONF_RES_NOTRUST 4 147 #define CONF_RES_NOQUERY 5 148 #define CONF_RES_NOMODIFY 6 149 #define CONF_RES_NOPEER 7 150 #define CONF_RES_NOTRAP 8 151 #define CONF_RES_LPTRAP 9 152 #define CONF_RES_NTPPORT 10 153 #define CONF_RES_LIMITED 11 154 155 #define CONF_TRAP_PORT 1 156 #define CONF_TRAP_INTERFACE 2 157 158 #define CONF_FDG_TIME1 1 159 #define CONF_FDG_TIME2 2 160 #define CONF_FDG_STRATUM 3 161 #define CONF_FDG_REFID 4 162 #define CONF_FDG_FLAG1 5 163 #define CONF_FDG_FLAG2 6 164 #define CONF_FDG_FLAG3 7 165 #define CONF_FDG_FLAG4 8 166 167 #define CONF_FGEN_FILE 1 168 #define CONF_FGEN_TYPE 2 169 #define CONF_FGEN_FLAG_LINK 3 170 #define CONF_FGEN_FLAG_NOLINK 4 171 #define CONF_FGEN_FLAG_ENABLE 5 172 #define CONF_FGEN_FLAG_DISABLE 6 173 174 #define CONF_PPS_ASSERT 1 175 #define CONF_PPS_CLEAR 2 176 #define CONF_PPS_HARDPPS 3 177 178 /* 179 * Translation table - keywords to function index 180 */ 181 struct keyword { 182 const char *text; 183 int keytype; 184 }; 185 186 /* 187 * Command keywords 188 */ 189 static struct keyword keywords[] = { 190 { "peer", CONFIG_PEER }, 191 { "server", CONFIG_SERVER }, 192 { "driftfile", CONFIG_DRIFTFILE }, 193 { "broadcast", CONFIG_BROADCAST }, 194 { "broadcastclient", CONFIG_BROADCASTCLIENT }, 195 { "multicastclient", CONFIG_MULTICASTCLIENT }, 196 { "manycastclient", CONFIG_MANYCASTCLIENT }, 197 { "manycastserver", CONFIG_MANYCASTSERVER }, 198 { "authenticate", CONFIG_AUTHENTICATE }, 199 { "keys", CONFIG_KEYS }, 200 { "revoke", CONFIG_REVOKE }, 201 { "pps", CONFIG_PPS }, 202 { "automax", CONFIG_AUTOMAX }, 203 { "restrict", CONFIG_RESTRICT }, 204 { "broadcastdelay", CONFIG_BDELAY }, 205 { "trustedkey", CONFIG_TRUSTEDKEY }, 206 { "requestkey", CONFIG_REQUESTKEY }, 207 { "controlkey", CONFIG_CONTROLKEY }, 208 { "trap", CONFIG_TRAP }, 209 { "fudge", CONFIG_FUDGE }, 210 { "statsdir", CONFIG_STATSDIR }, 211 { "filegen", CONFIG_FILEGEN }, 212 { "statistics", CONFIG_STATISTICS }, 213 { "pidfile", CONFIG_PIDFILE }, 214 { "setvar", CONFIG_SETVAR }, 215 { "clientlimit", CONFIG_CLIENTLIMIT }, 216 { "clientperiod", CONFIG_CLIENTPERIOD }, 217 { "enable", CONFIG_ENABLE }, 218 { "disable", CONFIG_DISABLE }, 219 { "phone", CONFIG_PHONE }, 220 { "logfile", CONFIG_LOGFILE }, 221 { "logconfig", CONFIG_LOGCONFIG }, 222 { "", CONFIG_UNKNOWN } 223 }; 224 225 /* 226 * "peer", "server", "broadcast" modifier keywords 227 */ 228 static struct keyword mod_keywords[] = { 229 { "version", CONF_MOD_VERSION }, 230 { "key", CONF_MOD_KEY }, 231 { "minpoll", CONF_MOD_MINPOLL }, 232 { "maxpoll", CONF_MOD_MAXPOLL }, 233 { "prefer", CONF_MOD_PREFER }, 234 { "noselect", CONF_MOD_NOSELECT }, 235 { "burst", CONF_MOD_BURST }, 236 { "autokey", CONF_MOD_SKEY }, 237 { "mode", CONF_MOD_MODE }, /* reference clocks */ 238 { "ttl", CONF_MOD_TTL }, /* NTP peers */ 239 { "", CONFIG_UNKNOWN } 240 }; 241 242 /* 243 * "restrict" modifier keywords 244 */ 245 static struct keyword res_keywords[] = { 246 { "mask", CONF_RES_MASK }, 247 { "ignore", CONF_RES_IGNORE }, 248 { "noserve", CONF_RES_NOSERVE }, 249 { "notrust", CONF_RES_NOTRUST }, 250 { "noquery", CONF_RES_NOQUERY }, 251 { "nomodify", CONF_RES_NOMODIFY }, 252 { "nopeer", CONF_RES_NOPEER }, 253 { "notrap", CONF_RES_NOTRAP }, 254 { "lowpriotrap", CONF_RES_LPTRAP }, 255 { "ntpport", CONF_RES_NTPPORT }, 256 { "limited", CONF_RES_LIMITED }, 257 { "", CONFIG_UNKNOWN } 258 }; 259 260 /* 261 * "trap" modifier keywords 262 */ 263 static struct keyword trap_keywords[] = { 264 { "port", CONF_TRAP_PORT }, 265 { "interface", CONF_TRAP_INTERFACE }, 266 { "", CONFIG_UNKNOWN } 267 }; 268 269 270 /* 271 * "fudge" modifier keywords 272 */ 273 static struct keyword fudge_keywords[] = { 274 { "time1", CONF_FDG_TIME1 }, 275 { "time2", CONF_FDG_TIME2 }, 276 { "stratum", CONF_FDG_STRATUM }, 277 { "refid", CONF_FDG_REFID }, 278 { "flag1", CONF_FDG_FLAG1 }, 279 { "flag2", CONF_FDG_FLAG2 }, 280 { "flag3", CONF_FDG_FLAG3 }, 281 { "flag4", CONF_FDG_FLAG4 }, 282 { "", CONFIG_UNKNOWN } 283 }; 284 285 286 /* 287 * "filegen" modifier keywords 288 */ 289 static struct keyword filegen_keywords[] = { 290 { "file", CONF_FGEN_FILE }, 291 { "type", CONF_FGEN_TYPE }, 292 { "link", CONF_FGEN_FLAG_LINK }, 293 { "nolink", CONF_FGEN_FLAG_NOLINK }, 294 { "enable", CONF_FGEN_FLAG_ENABLE }, 295 { "disable", CONF_FGEN_FLAG_DISABLE }, 296 { "", CONFIG_UNKNOWN } 297 }; 298 299 /* 300 * "type" modifier keywords 301 */ 302 static struct keyword fgen_types[] = { 303 { "none", FILEGEN_NONE }, 304 { "pid", FILEGEN_PID }, 305 { "day", FILEGEN_DAY }, 306 { "week", FILEGEN_WEEK }, 307 { "month", FILEGEN_MONTH }, 308 { "year", FILEGEN_YEAR }, 309 { "age", FILEGEN_AGE }, 310 { "", CONFIG_UNKNOWN} 311 }; 312 313 /* 314 * "enable", "disable" modifier keywords 315 */ 316 static struct keyword flags_keywords[] = { 317 { "auth", PROTO_AUTHENTICATE }, 318 { "bclient", PROTO_BROADCLIENT }, 319 { "ntp", PROTO_NTP }, 320 { "kernel", PROTO_KERNEL }, 321 { "monitor", PROTO_MONITOR }, 322 { "stats", PROTO_FILEGEN }, 323 { "", CONFIG_UNKNOWN } 324 }; 325 326 /* 327 * pps modifier keywords 328 */ 329 static struct keyword pps_keywords[] = { 330 { "assert", CONF_PPS_ASSERT }, 331 { "clear", CONF_PPS_CLEAR }, 332 { "hardpps", CONF_PPS_HARDPPS }, 333 { "", CONFIG_UNKNOWN } 334 }; 335 336 /* 337 * "logconfig" building blocks 338 */ 339 struct masks { 340 const char *name; 341 unsigned long mask; 342 }; 343 344 static struct masks logcfg_class[] = { 345 { "sys", NLOG_OSYS }, 346 { "peer", NLOG_OPEER }, 347 { "clock", NLOG_OCLOCK }, 348 { "sync", NLOG_OSYNC }, 349 { (char *)0, 0 } 350 }; 351 352 static struct masks logcfg_item[] = { 353 { "info", NLOG_INFO }, 354 { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO }, 355 { "events", NLOG_EVENT }, 356 { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT }, 357 { "status", NLOG_STATUS }, 358 { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS }, 359 { "statistics", NLOG_STATIST }, 360 { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST }, 361 { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK }, 362 { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER }, 363 { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS }, 364 { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC }, 365 { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK }, 366 { (char *)0, 0 } 367 }; 368 369 /* 370 * Limits on things 371 */ 372 #define MAXTOKENS 20 /* 20 tokens on line */ 373 #define MAXLINE 1024 /* maximum length of line */ 374 #define MAXPHONE 5 /* maximum number of phone strings */ 375 #define MAXPPS 20 /* maximum length of PPS device string */ 376 #define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */ 377 378 379 /* 380 * Miscellaneous macros 381 */ 382 #define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) 383 #define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0') 384 #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 385 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 386 387 /* 388 * File descriptor used by the resolver save routines, and temporary file 389 * name. 390 */ 391 static FILE *res_fp; 392 #ifndef SYS_WINNT 393 static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */ 394 #define RES_TEMPFILE "/tmp/ntpXXXXXX" 395 #else 396 static char res_file[MAX_PATH]; 397 #endif /* SYS_WINNT */ 398 399 /* 400 * Definitions of things either imported from or exported to outside 401 */ 402 char const *progname; 403 char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */ 404 char pps_device[MAXPPS + 1]; /* PPS device name */ 405 int pps_assert = 1; 406 int pps_hardpps; 407 int listen_to_virtual_ips = 0; 408 #if defined(HAVE_SCHED_SETSCHEDULER) 409 int config_priority_override = 0; 410 int config_priority; 411 #endif 412 413 static const char *ntp_options = "aAbc:dD:f:gk:l:Lmnp:P:r:s:t:v:V:x"; 414 415 #ifdef HAVE_NETINFO 416 /* 417 * NetInfo configuration state 418 */ 419 struct netinfo_config_state { 420 void *domain; /* domain with config */ 421 ni_id config_dir; /* ID config dir */ 422 int prop_index; /* current property */ 423 int val_index; /* current value */ 424 char **val_list; /* value list */ 425 }; 426 #endif 427 428 /* 429 * Function prototypes 430 */ 431 static unsigned long get_pfxmatch P((char **, struct masks *)); 432 static unsigned long get_match P((char *, struct masks *)); 433 static unsigned long get_logmask P((char *)); 434 #ifdef HAVE_NETINFO 435 static struct netinfo_config_state *get_netinfo_config P((void)); 436 static void free_netinfo_config P((struct netinfo_config_state *)); 437 static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *)); 438 #endif 439 static int gettokens P((FILE *, char *, char **, int *)); 440 static int matchkey P((char *, struct keyword *)); 441 static int getnetnum P((const char *, struct sockaddr_in *, int)); 442 static void save_resolve P((char *, int, int, int, int, int, int, u_long)); 443 static void do_resolve_internal P((void)); 444 static void abort_resolve P((void)); 445 #if !defined(VMS) 446 static RETSIGTYPE catchchild P((int)); 447 #endif /* VMS */ 448 449 /* 450 * get_pfxmatch - find value for prefixmatch 451 * and update char * accordingly 452 */ 453 static unsigned long 454 get_pfxmatch( 455 char ** s, 456 struct masks *m 457 ) 458 { 459 while (m->name) { 460 if (strncmp(*s, m->name, strlen(m->name)) == 0) { 461 *s += strlen(m->name); 462 return m->mask; 463 } else { 464 m++; 465 } 466 } 467 return 0; 468 } 469 470 /* 471 * get_match - find logmask value 472 */ 473 static unsigned long 474 get_match( 475 char *s, 476 struct masks *m 477 ) 478 { 479 while (m->name) { 480 if (strcmp(s, m->name) == 0) { 481 return m->mask; 482 } else { 483 m++; 484 } 485 } 486 return 0; 487 } 488 489 /* 490 * get_logmask - build bitmask for ntp_syslogmask 491 */ 492 static unsigned long 493 get_logmask( 494 char *s 495 ) 496 { 497 char *t; 498 unsigned long offset; 499 unsigned long mask; 500 501 t = s; 502 offset = get_pfxmatch(&t, logcfg_class); 503 mask = get_match(t, logcfg_item); 504 505 if (mask) 506 return mask << offset; 507 else 508 msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s); 509 510 return 0; 511 } 512 513 /* 514 * getstartup - search through the options looking for a debugging flag 515 */ 516 void 517 getstartup( 518 int argc, 519 char *argv[] 520 ) 521 { 522 int errflg; 523 int c; 524 525 #ifdef DEBUG 526 debug = 0; /* no debugging by default */ 527 #endif 528 529 /* 530 * This is a big hack. We don't really want to read command line 531 * configuration until everything else is initialized, since 532 * the ability to configure the system may depend on storage 533 * and the like having been initialized. Except that we also 534 * don't want to initialize anything until after detaching from 535 * the terminal, but we won't know to do that until we've 536 * parsed the command line. Do that now, crudely, and do it 537 * again later. Our ntp_getopt() is explicitly reusable, by the 538 * way. Your own mileage may vary. 539 * 540 * This hack is even called twice (to allow complete logging to file) 541 */ 542 errflg = 0; 543 progname = argv[0]; 544 545 /* 546 * Decode argument list 547 */ 548 while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) 549 switch (c) { 550 #ifdef DEBUG 551 case 'd': 552 ++debug; 553 break; 554 case 'D': 555 debug = (int)atol(ntp_optarg); 556 printf("Debug1: %s -> %x = %d\n", ntp_optarg, debug, debug); 557 break; 558 #else 559 case 'd': 560 case 'D': 561 msyslog(LOG_ERR, "ntpd not compiled with -DDEBUG option - no DEBUG support"); 562 fprintf(stderr, "ntpd not compiled with -DDEBUG option - no DEBUG support"); 563 ++errflg; 564 break; 565 #endif 566 case 'L': 567 listen_to_virtual_ips = 1; 568 break; 569 case 'l': 570 { 571 FILE *new_file; 572 573 new_file = fopen(ntp_optarg, "a"); 574 if (new_file != NULL) { 575 NLOG(NLOG_SYSINFO) 576 msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); 577 if (syslog_file != NULL && 578 fileno(syslog_file) != fileno(new_file)) 579 (void)fclose(syslog_file); 580 581 syslog_file = new_file; 582 syslogit = 0; 583 } 584 else 585 msyslog(LOG_ERR, 586 "Cannot open log file %s", 587 ntp_optarg); 588 } 589 break; 590 591 case 'n': 592 ++nofork; 593 break; 594 595 case '?': 596 ++errflg; 597 break; 598 599 default: 600 break; 601 } 602 603 if (errflg || ntp_optind != argc) { 604 (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); 605 (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); 606 (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); 607 (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); 608 #if defined(HAVE_SCHED_SETSCHEDULER) 609 (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); 610 #endif 611 exit(2); 612 } 613 ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ 614 615 #ifdef DEBUG 616 if (debug) { 617 #ifdef HAVE_SETVBUF 618 static char buf[BUFSIZ]; 619 setvbuf(stdout, buf, _IOLBF, BUFSIZ); 620 #else 621 setlinebuf(stdout); 622 #endif 623 } 624 #endif 625 } 626 627 /* 628 * getconfig - get command line options and read the configuration file 629 */ 630 void 631 getconfig( 632 int argc, 633 char *argv[] 634 ) 635 { 636 register int i; 637 int c; 638 int errflg; 639 int peerversion; 640 int minpoll; 641 int maxpoll; 642 int ttl; 643 u_long peerkey; 644 u_long lpeerkey; 645 int peerflags; 646 int hmode; 647 struct sockaddr_in peeraddr; 648 struct sockaddr_in maskaddr; 649 FILE *fp; 650 char line[MAXLINE]; 651 char *(tokens[MAXTOKENS]); 652 int ntokens; 653 int tok = CONFIG_UNKNOWN; 654 struct interface *localaddr; 655 const char *config_file; 656 #ifdef HAVE_NETINFO 657 struct netinfo_config_state *config_netinfo = NULL; 658 int check_netinfo = 1; 659 #endif /* HAVE_NETINFO */ 660 #ifdef SYS_WINNT 661 char *alt_config_file; 662 LPTSTR temp; 663 char config_file_storage[MAX_PATH]; 664 char alt_config_file_storage[MAX_PATH]; 665 #endif /* SYS_WINNT */ 666 struct refclockstat clock_stat; 667 FILEGEN *filegen; 668 669 /* 670 * Initialize, initialize 671 */ 672 errflg = 0; 673 #ifdef DEBUG 674 debug = 0; 675 #endif /* DEBUG */ 676 #ifndef SYS_WINNT 677 config_file = CONFIG_FILE; 678 #else 679 temp = CONFIG_FILE; 680 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { 681 msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); 682 exit(1); 683 } 684 config_file = config_file_storage; 685 686 temp = ALT_CONFIG_FILE; 687 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { 688 msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); 689 exit(1); 690 } 691 alt_config_file = alt_config_file_storage; 692 693 #endif /* SYS_WINNT */ 694 progname = argv[0]; 695 res_fp = NULL; 696 memset((char *)sys_phone, 0, sizeof(sys_phone)); 697 ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */ 698 699 /* 700 * install a non default variable with this daemon version 701 */ 702 (void) sprintf(line, "daemon_version=\"%s\"", Version); 703 set_sys_var(line, strlen(line)+1, RO); 704 705 /* 706 * Say how we're setting the time of day 707 */ 708 (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using); 709 set_sys_var(line, strlen(line)+1, RO); 710 711 /* 712 * Initialize the loop. 713 */ 714 loop_config(LOOP_DRIFTINIT, 0.); 715 716 /* 717 * Decode argument list 718 */ 719 while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) { 720 switch (c) { 721 case 'a': 722 proto_config(PROTO_AUTHENTICATE, 1, 0.); 723 break; 724 725 case 'A': 726 proto_config(PROTO_AUTHENTICATE, 0, 0.); 727 break; 728 729 case 'b': 730 proto_config(PROTO_BROADCLIENT, 1, 0.); 731 break; 732 733 case 'c': 734 config_file = ntp_optarg; 735 #ifdef HAVE_NETINFO 736 check_netinfo = 0; 737 #endif 738 break; 739 740 case 'd': 741 #ifdef DEBUG 742 debug++; 743 #else 744 errflg++; 745 #endif /* DEBUG */ 746 break; 747 748 case 'D': 749 #ifdef DEBUG 750 debug = (int)atol(ntp_optarg); 751 printf("Debug2: %s -> %x = %d\n", ntp_optarg, debug, debug); 752 #else 753 errflg++; 754 #endif /* DEBUG */ 755 break; 756 757 case 'f': 758 stats_config(STATS_FREQ_FILE, ntp_optarg); 759 break; 760 761 case 'g': 762 correct_any = TRUE; 763 break; 764 765 case 'k': 766 getauthkeys(ntp_optarg); 767 break; 768 769 case 'L': /* already done at pre-scan */ 770 case 'l': /* already done at pre-scan */ 771 break; 772 773 case 'm': 774 proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); 775 sys_bclient = 1; 776 break; 777 778 case 'n': /* already done at pre-scan */ 779 break; 780 781 case 'p': 782 stats_config(STATS_PID_FILE, ntp_optarg); 783 break; 784 785 case 'P': 786 #if defined(HAVE_SCHED_SETSCHEDULER) 787 config_priority = (int)atol(ntp_optarg); 788 config_priority_override = 1; 789 #else 790 errflg++; 791 #endif 792 break; 793 794 case 'r': 795 do { 796 double tmp; 797 798 if (sscanf(ntp_optarg, "%lf", &tmp) != 1) { 799 msyslog(LOG_ERR, 800 "command line broadcast delay value %s undecodable", 801 ntp_optarg); 802 } else { 803 proto_config(PROTO_BROADDELAY, 0, tmp); 804 } 805 } while (0); 806 break; 807 808 case 's': 809 stats_config(STATS_STATSDIR, ntp_optarg); 810 break; 811 812 case 't': 813 do { 814 u_long tkey; 815 816 tkey = (int)atol(ntp_optarg); 817 if (tkey <= 0 || tkey > NTP_MAXKEY) { 818 msyslog(LOG_ERR, 819 "command line trusted key %s is invalid", 820 ntp_optarg); 821 } else { 822 authtrust(tkey, 1); 823 } 824 } while (0); 825 break; 826 827 case 'v': 828 case 'V': 829 set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, 830 RW | ((c == 'V') ? DEF : 0)); 831 break; 832 833 case 'x': 834 allow_set_backward = FALSE; 835 break; 836 837 default: 838 errflg++; 839 break; 840 } 841 } 842 843 if (errflg || ntp_optind != argc) { 844 (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); 845 (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); 846 (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); 847 (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); 848 #if defined(HAVE_SCHED_SETSCHEDULER) 849 (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); 850 #endif 851 exit(2); 852 } 853 854 if ( 855 (fp = fopen(FindConfig(config_file), "r")) == NULL 856 #ifdef HAVE_NETINFO 857 /* If there is no config_file, try NetInfo. */ 858 && check_netinfo && !(config_netinfo = get_netinfo_config()) 859 #endif /* HAVE_NETINFO */ 860 ) { 861 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); 862 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); 863 #ifdef SYS_WINNT 864 /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ 865 866 if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { 867 868 /* 869 * Broadcast clients can sometimes run without 870 * a configuration file. 871 */ 872 873 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); 874 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); 875 return; 876 } 877 #else /* not SYS_WINNT */ 878 return; 879 #endif /* not SYS_WINNT */ 880 } 881 882 for (;;) { 883 if (fp) 884 tok = gettokens(fp, line, tokens, &ntokens); 885 #ifdef HAVE_NETINFO 886 else 887 tok = gettokens_netinfo(config_netinfo, tokens, &ntokens); 888 #endif /* HAVE_NETINFO */ 889 890 if (tok == CONFIG_UNKNOWN) break; 891 892 switch(tok) { 893 case CONFIG_PEER: 894 case CONFIG_SERVER: 895 case CONFIG_MANYCASTCLIENT: 896 case CONFIG_BROADCAST: 897 if (tok == CONFIG_PEER) 898 hmode = MODE_ACTIVE; 899 else if (tok == CONFIG_SERVER) 900 hmode = MODE_CLIENT; 901 else if (tok == CONFIG_MANYCASTCLIENT) 902 hmode = MODE_CLIENT; 903 else 904 hmode = MODE_BROADCAST; 905 906 if (ntokens < 2) { 907 msyslog(LOG_ERR, 908 "No address for %s, line ignored", 909 tokens[0]); 910 break; 911 } 912 913 if (!getnetnum(tokens[1], &peeraddr, 0)) { 914 errflg = -1; 915 } else { 916 errflg = 0; 917 918 if ( 919 #ifdef REFCLOCK 920 !ISREFCLOCKADR(&peeraddr) && 921 #endif 922 ISBADADR(&peeraddr)) { 923 msyslog(LOG_ERR, 924 "attempt to configure invalid address %s", 925 ntoa(&peeraddr)); 926 break; 927 } 928 /* 929 * Shouldn't be able to specify multicast 930 * address for server/peer! 931 * and unicast address for manycastclient! 932 */ 933 if (((tok == CONFIG_SERVER) || 934 (tok == CONFIG_PEER)) && 935 #ifdef REFCLOCK 936 !ISREFCLOCKADR(&peeraddr) && 937 #endif 938 IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { 939 msyslog(LOG_ERR, 940 "attempt to configure invalid address %s", 941 ntoa(&peeraddr)); 942 break; 943 } 944 if ((tok == CONFIG_MANYCASTCLIENT) && 945 !IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { 946 msyslog(LOG_ERR, 947 "attempt to configure invalid address %s", 948 ntoa(&peeraddr)); 949 break; 950 } 951 } 952 953 peerversion = NTP_VERSION; 954 minpoll = NTP_MINDPOLL; 955 maxpoll = NTP_MAXDPOLL; 956 peerkey = 0; 957 peerflags = 0; 958 ttl = 0; 959 for (i = 2; i < ntokens; i++) 960 switch (matchkey(tokens[i], mod_keywords)) { 961 case CONF_MOD_VERSION: 962 if (i >= ntokens-1) { 963 msyslog(LOG_ERR, 964 "peer/server version requires an argument"); 965 errflg = 1; 966 break; 967 } 968 peerversion = atoi(tokens[++i]); 969 if ((u_char)peerversion > NTP_VERSION 970 || (u_char)peerversion < NTP_OLDVERSION) { 971 msyslog(LOG_ERR, 972 "inappropriate version number %s, line ignored", 973 tokens[i]); 974 errflg = 1; 975 } 976 break; 977 978 case CONF_MOD_KEY: 979 if (i >= ntokens-1) { 980 msyslog(LOG_ERR, 981 "key: argument required"); 982 errflg = 1; 983 break; 984 } 985 peerkey = (int)atol(tokens[++i]); 986 peerflags |= FLAG_AUTHENABLE; 987 break; 988 989 case CONF_MOD_MINPOLL: 990 if (i >= ntokens-1) { 991 msyslog(LOG_ERR, 992 "minpoll: argument required"); 993 errflg = 1; 994 break; 995 } 996 minpoll = atoi(tokens[++i]); 997 if (minpoll < NTP_MINPOLL) 998 minpoll = NTP_MINPOLL; 999 break; 1000 1001 case CONF_MOD_MAXPOLL: 1002 if (i >= ntokens-1) { 1003 msyslog(LOG_ERR, 1004 "maxpoll: argument required" 1005 ); 1006 errflg = 1; 1007 break; 1008 } 1009 maxpoll = atoi(tokens[++i]); 1010 if (maxpoll > NTP_MAXPOLL) 1011 maxpoll = NTP_MAXPOLL; 1012 break; 1013 1014 case CONF_MOD_PREFER: 1015 peerflags |= FLAG_PREFER; 1016 break; 1017 1018 case CONF_MOD_NOSELECT: 1019 peerflags |= FLAG_NOSELECT; 1020 break; 1021 1022 case CONF_MOD_BURST: 1023 peerflags |= FLAG_BURST; 1024 break; 1025 1026 case CONF_MOD_SKEY: 1027 peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; 1028 break; 1029 1030 case CONF_MOD_TTL: 1031 if (i >= ntokens-1) { 1032 msyslog(LOG_ERR, 1033 "ttl: argument required"); 1034 errflg = 1; 1035 break; 1036 } 1037 ttl = atoi(tokens[++i]); 1038 break; 1039 1040 case CONF_MOD_MODE: 1041 if (i >= ntokens-1) { 1042 msyslog(LOG_ERR, 1043 "mode: argument required"); 1044 errflg = 1; 1045 break; 1046 } 1047 ttl = atoi(tokens[++i]); 1048 break; 1049 1050 case CONFIG_UNKNOWN: 1051 errflg = 1; 1052 break; 1053 } 1054 if (minpoll > maxpoll) { 1055 msyslog(LOG_ERR, "config error: minpoll > maxpoll"); 1056 errflg = 1; 1057 } 1058 if (errflg == 0) { 1059 if (peer_config(&peeraddr, 1060 (struct interface *)0, hmode, 1061 peerversion, minpoll, maxpoll, 1062 peerflags, ttl, peerkey) 1063 == 0) { 1064 msyslog(LOG_ERR, 1065 "configuration of %s failed", 1066 ntoa(&peeraddr)); 1067 } 1068 } else if (errflg == -1) { 1069 save_resolve(tokens[1], hmode, peerversion, 1070 minpoll, maxpoll, peerflags, ttl, 1071 peerkey); 1072 } 1073 break; 1074 1075 case CONFIG_DRIFTFILE: 1076 if (ntokens >= 2) 1077 stats_config(STATS_FREQ_FILE, tokens[1]); 1078 else 1079 stats_config(STATS_FREQ_FILE, (char *)0); 1080 break; 1081 1082 case CONFIG_PIDFILE: 1083 if (ntokens >= 2) 1084 stats_config(STATS_PID_FILE, tokens[1]); 1085 else 1086 stats_config(STATS_PID_FILE, (char *)0); 1087 break; 1088 1089 case CONFIG_LOGFILE: 1090 if (ntokens >= 2) { 1091 FILE *new_file; 1092 new_file = fopen(tokens[1], "a"); 1093 if (new_file != NULL) { 1094 NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ 1095 msyslog(LOG_NOTICE, "logging to file %s", tokens[1]); 1096 if (syslog_file != NULL && 1097 fileno(syslog_file) != fileno(new_file)) 1098 (void)fclose(syslog_file); 1099 1100 syslog_file = new_file; 1101 syslogit = 0; 1102 } 1103 else 1104 msyslog(LOG_ERR, 1105 "Cannot open log file %s", 1106 tokens[1]); 1107 } 1108 else 1109 msyslog(LOG_ERR, "logfile needs one argument"); 1110 break; 1111 1112 case CONFIG_LOGCONFIG: 1113 for (i = 1; i < ntokens; i++) 1114 { 1115 int add = 1; 1116 int equals = 0; 1117 char * s = &tokens[i][0]; 1118 1119 switch (*s) { 1120 case '+': 1121 case '-': 1122 case '=': 1123 add = *s == '+'; 1124 equals = *s == '='; 1125 s++; 1126 break; 1127 1128 default: 1129 break; 1130 } 1131 if (equals) { 1132 ntp_syslogmask = get_logmask(s); 1133 } else { 1134 if (add) { 1135 ntp_syslogmask |= get_logmask(s); 1136 } else { 1137 ntp_syslogmask &= ~get_logmask(s); 1138 } 1139 } 1140 #ifdef DEBUG 1141 if (debug) 1142 printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]); 1143 #endif 1144 } 1145 break; 1146 1147 case CONFIG_BROADCASTCLIENT: 1148 proto_config(PROTO_BROADCLIENT, 1, 0.); 1149 break; 1150 1151 case CONFIG_MULTICASTCLIENT: 1152 case CONFIG_MANYCASTSERVER: 1153 if (ntokens > 1) { 1154 for (i = 1; i < ntokens; i++) { 1155 if (getnetnum(tokens[i], &peeraddr, 1)) 1156 proto_config(PROTO_MULTICAST_ADD, 1157 peeraddr.sin_addr.s_addr, 0.); 1158 } 1159 } else 1160 proto_config(PROTO_MULTICAST_ADD, 1161 htonl(INADDR_NTP), 0.); 1162 if (tok == CONFIG_MULTICASTCLIENT) { 1163 sys_bclient = 1; 1164 #ifdef DEBUG 1165 if (debug) 1166 printf("sys_bclient\n"); 1167 #endif /* DEBUG */ 1168 } 1169 else if (tok == CONFIG_MANYCASTSERVER) { 1170 sys_manycastserver = 1; 1171 #ifdef DEBUG 1172 if (debug) 1173 printf("sys_manycastserver\n"); 1174 #endif /* DEBUG */ 1175 } 1176 break; 1177 1178 case CONFIG_AUTHENTICATE: 1179 errflg = 0; 1180 if (ntokens >= 2) { 1181 if (STREQ(tokens[1], "yes")) 1182 proto_config(PROTO_AUTHENTICATE, 1, 0.); 1183 else if (STREQ(tokens[1], "no")) 1184 proto_config(PROTO_AUTHENTICATE, 0, 0.); 1185 else 1186 errflg++; 1187 } else { 1188 errflg++; 1189 } 1190 1191 if (errflg) 1192 msyslog(LOG_ERR, 1193 "should be `authenticate yes|no'"); 1194 break; 1195 1196 case CONFIG_KEYS: 1197 if (ntokens >= 2) { 1198 getauthkeys(tokens[1]); 1199 } 1200 break; 1201 1202 case CONFIG_REVOKE: 1203 if (ntokens >= 2) { 1204 sys_revoke = 1 << max(atoi(tokens[1]), 10); 1205 } 1206 break; 1207 1208 case CONFIG_AUTOMAX: 1209 if (ntokens >= 2) { 1210 sys_automax = 1 << max(atoi(tokens[1]), 10); 1211 } 1212 break; 1213 1214 case CONFIG_RESTRICT: 1215 if (ntokens < 2) { 1216 msyslog(LOG_ERR, "restrict requires an address"); 1217 break; 1218 } 1219 if (STREQ(tokens[1], "default")) 1220 peeraddr.sin_addr.s_addr = htonl(INADDR_ANY); 1221 else if (!getnetnum(tokens[1], &peeraddr, 1)) 1222 break; 1223 1224 /* 1225 * Use peerversion as flags, peerkey as mflags. Ick. 1226 */ 1227 peerversion = 0; 1228 peerkey = 0; 1229 errflg = 0; 1230 maskaddr.sin_addr.s_addr = ~(u_int32)0; 1231 for (i = 2; i < ntokens; i++) { 1232 switch (matchkey(tokens[i], res_keywords)) { 1233 case CONF_RES_MASK: 1234 if (i >= ntokens-1) { 1235 msyslog(LOG_ERR, 1236 "mask keyword needs argument"); 1237 errflg++; 1238 break; 1239 } 1240 i++; 1241 if (!getnetnum(tokens[i], &maskaddr, 1)) 1242 errflg++; 1243 break; 1244 1245 case CONF_RES_IGNORE: 1246 peerversion |= RES_IGNORE; 1247 break; 1248 1249 case CONF_RES_NOSERVE: 1250 peerversion |= RES_DONTSERVE; 1251 break; 1252 1253 case CONF_RES_NOTRUST: 1254 peerversion |= RES_DONTTRUST; 1255 break; 1256 1257 case CONF_RES_NOQUERY: 1258 peerversion |= RES_NOQUERY; 1259 break; 1260 1261 case CONF_RES_NOMODIFY: 1262 peerversion |= RES_NOMODIFY; 1263 break; 1264 1265 case CONF_RES_NOPEER: 1266 peerversion |= RES_NOPEER; 1267 break; 1268 1269 case CONF_RES_NOTRAP: 1270 peerversion |= RES_NOTRAP; 1271 break; 1272 1273 case CONF_RES_LPTRAP: 1274 peerversion |= RES_LPTRAP; 1275 break; 1276 1277 case CONF_RES_NTPPORT: 1278 peerkey |= RESM_NTPONLY; 1279 break; 1280 1281 case CONF_RES_LIMITED: 1282 peerversion |= RES_LIMITED; 1283 break; 1284 1285 case CONFIG_UNKNOWN: 1286 errflg++; 1287 break; 1288 } 1289 } 1290 if (SRCADR(&peeraddr) == htonl(INADDR_ANY)) 1291 maskaddr.sin_addr.s_addr = 0; 1292 if (!errflg) 1293 hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, 1294 (int)peerkey, peerversion); 1295 break; 1296 1297 case CONFIG_BDELAY: 1298 if (ntokens >= 2) { 1299 double tmp; 1300 1301 if (sscanf(tokens[1], "%lf", &tmp) != 1) { 1302 msyslog(LOG_ERR, 1303 "broadcastdelay value %s undecodable", 1304 tokens[1]); 1305 } else { 1306 proto_config(PROTO_BROADDELAY, 0, tmp); 1307 } 1308 } 1309 break; 1310 1311 case CONFIG_TRUSTEDKEY: 1312 for (i = 1; i < ntokens; i++) { 1313 u_long tkey; 1314 1315 tkey = atol(tokens[i]); 1316 if (tkey == 0) { 1317 msyslog(LOG_ERR, 1318 "trusted key %s unlikely", 1319 tokens[i]); 1320 } else { 1321 authtrust(tkey, 1); 1322 } 1323 } 1324 break; 1325 1326 case CONFIG_REQUESTKEY: 1327 if (ntokens >= 2) { 1328 u_long rkey; 1329 1330 if (!atouint(tokens[1], &rkey)) { 1331 msyslog(LOG_ERR, 1332 "%s is undecodable as request key", 1333 tokens[1]); 1334 } else if (rkey == 0) { 1335 msyslog(LOG_ERR, 1336 "%s makes a poor request keyid", 1337 tokens[1]); 1338 } else { 1339 #ifdef DEBUG 1340 if (debug > 3) 1341 printf( 1342 "set info_auth_key to %lu\n", rkey); 1343 #endif 1344 info_auth_keyid = rkey; 1345 } 1346 } 1347 break; 1348 1349 case CONFIG_CONTROLKEY: 1350 if (ntokens >= 2) { 1351 u_long ckey; 1352 1353 ckey = atol(tokens[1]); 1354 if (ckey == 0) { 1355 msyslog(LOG_ERR, 1356 "%s makes a poor control keyid", 1357 tokens[1]); 1358 } else { 1359 ctl_auth_keyid = ckey; 1360 } 1361 } 1362 break; 1363 1364 case CONFIG_TRAP: 1365 if (ntokens < 2) { 1366 msyslog(LOG_ERR, 1367 "no address for trap command, line ignored"); 1368 break; 1369 } 1370 if (!getnetnum(tokens[1], &peeraddr, 1)) 1371 break; 1372 1373 /* 1374 * Use peerversion for port number. Barf. 1375 */ 1376 errflg = 0; 1377 peerversion = 0; 1378 localaddr = 0; 1379 for (i = 2; i < ntokens-1; i++) 1380 switch (matchkey(tokens[i], trap_keywords)) { 1381 case CONF_TRAP_PORT: 1382 if (i >= ntokens-1) { 1383 msyslog(LOG_ERR, 1384 "trap port requires an argument"); 1385 errflg = 1; 1386 break; 1387 } 1388 peerversion = atoi(tokens[++i]); 1389 if (peerversion <= 0 1390 || peerversion > 32767) { 1391 msyslog(LOG_ERR, 1392 "invalid port number %s, trap ignored", 1393 tokens[i]); 1394 errflg = 1; 1395 } 1396 break; 1397 1398 case CONF_TRAP_INTERFACE: 1399 if (i >= ntokens-1) { 1400 msyslog(LOG_ERR, 1401 "trap interface requires an argument"); 1402 errflg = 1; 1403 break; 1404 } 1405 1406 if (!getnetnum(tokens[++i], 1407 &maskaddr, 1)) { 1408 errflg = 1; 1409 break; 1410 } 1411 1412 localaddr = findinterface(&maskaddr); 1413 if (localaddr == NULL) { 1414 msyslog(LOG_ERR, 1415 "can't find interface with address %s", 1416 ntoa(&maskaddr)); 1417 errflg = 1; 1418 } 1419 break; 1420 1421 case CONFIG_UNKNOWN: 1422 errflg++; 1423 break; 1424 } 1425 1426 if (!errflg) { 1427 if (peerversion != 0) 1428 peeraddr.sin_port = htons( (u_short) peerversion); 1429 else 1430 peeraddr.sin_port = htons(TRAPPORT); 1431 if (localaddr == NULL) 1432 localaddr = any_interface; 1433 if (!ctlsettrap(&peeraddr, localaddr, 0, 1434 NTP_VERSION)) 1435 msyslog(LOG_ERR, 1436 "can't set trap for %s, no resources", 1437 ntoa(&peeraddr)); 1438 } 1439 break; 1440 1441 case CONFIG_FUDGE: 1442 if (ntokens < 2) { 1443 msyslog(LOG_ERR, 1444 "no address for fudge command, line ignored"); 1445 break; 1446 } 1447 if (!getnetnum(tokens[1], &peeraddr, 1)) 1448 break; 1449 1450 if (!ISREFCLOCKADR(&peeraddr)) { 1451 msyslog(LOG_ERR, 1452 "%s is inappropriate address for the fudge command, line ignored", 1453 ntoa(&peeraddr)); 1454 break; 1455 } 1456 1457 memset((void *)&clock_stat, 0, sizeof clock_stat); 1458 errflg = 0; 1459 for (i = 2; i < ntokens-1; i++) { 1460 switch (c = matchkey(tokens[i], 1461 fudge_keywords)) { 1462 case CONF_FDG_TIME1: 1463 if (sscanf(tokens[++i], "%lf", 1464 &clock_stat.fudgetime1) != 1) { 1465 msyslog(LOG_ERR, 1466 "fudge %s time1 value in error", 1467 ntoa(&peeraddr)); 1468 errflg = i; 1469 break; 1470 } 1471 clock_stat.haveflags |= CLK_HAVETIME1; 1472 break; 1473 1474 case CONF_FDG_TIME2: 1475 if (sscanf(tokens[++i], "%lf", 1476 &clock_stat.fudgetime2) != 1) { 1477 msyslog(LOG_ERR, 1478 "fudge %s time2 value in error", 1479 ntoa(&peeraddr)); 1480 errflg = i; 1481 break; 1482 } 1483 clock_stat.haveflags |= CLK_HAVETIME2; 1484 break; 1485 1486 1487 case CONF_FDG_STRATUM: 1488 /* HMS: the (long *)_ may be trouble */ 1489 if (!atoint(tokens[++i], 1490 (long *)&clock_stat.fudgeval1)) 1491 { 1492 msyslog(LOG_ERR, 1493 "fudge %s stratum value in error", 1494 ntoa(&peeraddr)); 1495 errflg = i; 1496 break; 1497 } 1498 clock_stat.haveflags |= CLK_HAVEVAL1; 1499 break; 1500 1501 case CONF_FDG_REFID: 1502 /* HMS: Endianness and 0 bytes? */ 1503 /* XXX */ 1504 strncpy((char *)&clock_stat.fudgeval2, 1505 tokens[++i], 4); 1506 clock_stat.haveflags |= CLK_HAVEVAL2; 1507 break; 1508 1509 case CONF_FDG_FLAG1: 1510 case CONF_FDG_FLAG2: 1511 case CONF_FDG_FLAG3: 1512 case CONF_FDG_FLAG4: 1513 if (!atouint(tokens[++i], &lpeerkey) 1514 || lpeerkey > 1) { 1515 msyslog(LOG_ERR, 1516 "fudge %s flag value in error", 1517 ntoa(&peeraddr)); 1518 peerkey = lpeerkey; 1519 errflg = i; 1520 break; 1521 } 1522 peerkey = lpeerkey; 1523 switch(c) { 1524 case CONF_FDG_FLAG1: 1525 c = CLK_FLAG1; 1526 clock_stat.haveflags|=CLK_HAVEFLAG1; 1527 break; 1528 case CONF_FDG_FLAG2: 1529 c = CLK_FLAG2; 1530 clock_stat.haveflags|=CLK_HAVEFLAG2; 1531 break; 1532 case CONF_FDG_FLAG3: 1533 c = CLK_FLAG3; 1534 clock_stat.haveflags|=CLK_HAVEFLAG3; 1535 break; 1536 case CONF_FDG_FLAG4: 1537 c = CLK_FLAG4; 1538 clock_stat.haveflags|=CLK_HAVEFLAG4; 1539 break; 1540 } 1541 if (peerkey == 0) 1542 clock_stat.flags &= ~c; 1543 else 1544 clock_stat.flags |= c; 1545 break; 1546 1547 case CONFIG_UNKNOWN: 1548 errflg = -1; 1549 break; 1550 } 1551 } 1552 1553 #ifdef REFCLOCK 1554 /* 1555 * If reference clock support isn't defined the 1556 * fudge line will still be accepted and syntax 1557 * checked, but will essentially do nothing. 1558 */ 1559 if (!errflg) { 1560 refclock_control(&peeraddr, &clock_stat, 1561 (struct refclockstat *)0); 1562 } 1563 #endif 1564 break; 1565 1566 case CONFIG_STATSDIR: 1567 if (ntokens >= 2) { 1568 stats_config(STATS_STATSDIR,tokens[1]); 1569 } 1570 break; 1571 1572 case CONFIG_STATISTICS: 1573 for (i = 1; i < ntokens; i++) { 1574 filegen = filegen_get(tokens[i]); 1575 1576 if (filegen == NULL) { 1577 msyslog(LOG_ERR, 1578 "no statistics named %s available", 1579 tokens[i]); 1580 continue; 1581 } 1582 #ifdef DEBUG 1583 if (debug > 3) 1584 printf("enabling filegen for %s statistics \"%s%s\"\n", 1585 tokens[i], filegen->prefix, filegen->basename); 1586 #endif 1587 filegen->flag |= FGEN_FLAG_ENABLED; 1588 } 1589 break; 1590 1591 case CONFIG_FILEGEN: 1592 if (ntokens < 2) { 1593 msyslog(LOG_ERR, 1594 "no id for filegen command, line ignored"); 1595 break; 1596 } 1597 1598 filegen = filegen_get(tokens[1]); 1599 if (filegen == NULL) { 1600 msyslog(LOG_ERR, 1601 "unknown filegen \"%s\" ignored", 1602 tokens[1]); 1603 break; 1604 } 1605 /* 1606 * peerversion is (ab)used for filegen file (index) 1607 * peerkey is (ab)used for filegen type 1608 * peerflags is (ab)used for filegen flags 1609 */ 1610 peerversion = 0; 1611 peerkey = filegen->type; 1612 peerflags = filegen->flag; 1613 errflg = 0; 1614 1615 for (i = 2; i < ntokens; i++) { 1616 switch (matchkey(tokens[i], filegen_keywords)) { 1617 case CONF_FGEN_FILE: 1618 if (i >= ntokens - 1) { 1619 msyslog(LOG_ERR, 1620 "filegen %s file requires argument", 1621 tokens[1]); 1622 errflg = i; 1623 break; 1624 } 1625 peerversion = ++i; 1626 break; 1627 case CONF_FGEN_TYPE: 1628 if (i >= ntokens -1) { 1629 msyslog(LOG_ERR, 1630 "filegen %s type requires argument", 1631 tokens[1]); 1632 errflg = i; 1633 break; 1634 } 1635 peerkey = matchkey(tokens[++i], fgen_types); 1636 if (peerkey == CONFIG_UNKNOWN) { 1637 msyslog(LOG_ERR, 1638 "filegen %s unknown type \"%s\"", 1639 tokens[1], tokens[i]); 1640 errflg = i; 1641 break; 1642 } 1643 break; 1644 1645 case CONF_FGEN_FLAG_LINK: 1646 peerflags |= FGEN_FLAG_LINK; 1647 break; 1648 1649 case CONF_FGEN_FLAG_NOLINK: 1650 peerflags &= ~FGEN_FLAG_LINK; 1651 break; 1652 1653 case CONF_FGEN_FLAG_ENABLE: 1654 peerflags |= FGEN_FLAG_ENABLED; 1655 break; 1656 1657 case CONF_FGEN_FLAG_DISABLE: 1658 peerflags &= ~FGEN_FLAG_ENABLED; 1659 break; 1660 } 1661 } 1662 if (!errflg) { 1663 filegen_config(filegen, tokens[peerversion], 1664 (u_char)peerkey, (u_char)peerflags); 1665 } 1666 break; 1667 1668 case CONFIG_SETVAR: 1669 if (ntokens < 2) { 1670 msyslog(LOG_ERR, 1671 "no value for setvar command - line ignored"); 1672 } else { 1673 set_sys_var(tokens[1], strlen(tokens[1])+1, 1674 RW | 1675 ((((ntokens > 2) 1676 && !strcmp(tokens[2], 1677 "default"))) 1678 ? DEF 1679 : 0)); 1680 } 1681 break; 1682 1683 case CONFIG_CLIENTLIMIT: 1684 if (ntokens < 2) { 1685 msyslog(LOG_ERR, 1686 "no value for clientlimit command - line ignored"); 1687 } else { 1688 u_long ui; 1689 1690 if (!atouint(tokens[1], &ui) || !ui) { 1691 msyslog(LOG_ERR, 1692 "illegal value for clientlimit command - line ignored"); 1693 } else { 1694 char bp[80]; 1695 1696 #ifdef DEBUG 1697 if (debug) 1698 sprintf(bp, "client_limit=%lu", ui); 1699 #endif 1700 set_sys_var(bp, strlen(bp)+1, RO); 1701 client_limit = ui; 1702 } 1703 } 1704 break; 1705 1706 case CONFIG_CLIENTPERIOD: 1707 if (ntokens < 2) { 1708 msyslog(LOG_ERR, 1709 "no value for clientperiod command - line ignored"); 1710 } else { 1711 u_long ui; 1712 1713 if (!atouint(tokens[1], &ui) || ui < 64) { 1714 msyslog(LOG_ERR, 1715 "illegal value for clientperiod command - line ignored"); 1716 } else { 1717 char bp[80]; 1718 1719 sprintf(bp, "client_limit_period=%ld", ui); 1720 set_sys_var(bp, strlen(bp)+1, RO); 1721 client_limit_period = ui; 1722 } 1723 } 1724 break; 1725 1726 case CONFIG_ENABLE: 1727 for (i = 1; i < ntokens; i++) { 1728 int flag; 1729 1730 flag = matchkey(tokens[i], flags_keywords); 1731 if (flag == CONFIG_UNKNOWN) { 1732 msyslog(LOG_ERR, 1733 "enable unknown flag %s", 1734 tokens[i]); 1735 errflg = 1; 1736 break; 1737 } 1738 proto_config(flag, 1, 0.); 1739 } 1740 break; 1741 1742 case CONFIG_DISABLE: 1743 for (i = 1; i < ntokens; i++) { 1744 int flag; 1745 1746 flag = matchkey(tokens[i], flags_keywords); 1747 if (flag == CONFIG_UNKNOWN) { 1748 msyslog(LOG_ERR, 1749 "disable unknown flag %s", 1750 tokens[i]); 1751 errflg = 1; 1752 break; 1753 } 1754 proto_config(flag, 0, 0.); 1755 } 1756 break; 1757 1758 case CONFIG_PHONE: 1759 for (i = 1; i < ntokens && i < MAXPHONE; i++) { 1760 (void)strncpy(sys_phone[i - 1], 1761 tokens[i], MAXDIAL); 1762 } 1763 sys_phone[i - 1][0] = '\0'; 1764 break; 1765 1766 case CONFIG_PPS: 1767 if (ntokens < 2) { 1768 msyslog(LOG_ERR, 1769 "pps missing device name"); 1770 break; 1771 } 1772 (void)strncpy(pps_device, tokens[1], MAXPPS); 1773 for (i = 2; i < ntokens; i++) { 1774 int flag; 1775 1776 flag = matchkey(tokens[i], pps_keywords); 1777 switch(flag) { 1778 case CONF_PPS_ASSERT: 1779 pps_assert = 1; 1780 break; 1781 case CONF_PPS_CLEAR: 1782 pps_assert = 0; 1783 break; 1784 case CONF_PPS_HARDPPS: 1785 pps_hardpps = 1; 1786 break; 1787 default: 1788 msyslog(LOG_ERR, 1789 "pps unknown flag %s", 1790 tokens[i]); 1791 errflg = 1; 1792 break; 1793 } 1794 if(errflg) 1795 break; 1796 } 1797 break; 1798 } 1799 } 1800 if (fp) (void)fclose(fp); 1801 #ifdef HAVE_NETINFO 1802 if (config_netinfo) free_netinfo_config(config_netinfo); 1803 #endif /* HAVE_NETINFO */ 1804 1805 if (res_fp != NULL) { 1806 /* 1807 * Need name resolution 1808 */ 1809 do_resolve_internal(); 1810 } 1811 } 1812 1813 1814 #ifdef HAVE_NETINFO 1815 1816 /* 1817 * get_netinfo_config - find the nearest NetInfo domain with an ntp 1818 * configuration and initialize the configuration state. 1819 */ 1820 static struct netinfo_config_state * 1821 get_netinfo_config() 1822 { 1823 ni_status status; 1824 void *domain; 1825 ni_id config_dir; 1826 struct netinfo_config_state *config; 1827 1828 if (ni_open(NULL, ".", &domain) != NI_OK) return NULL; 1829 1830 while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) { 1831 void *next_domain; 1832 if (ni_open(domain, "..", &next_domain) != NI_OK) { 1833 ni_free(next_domain); 1834 break; 1835 } 1836 ni_free(domain); 1837 domain = next_domain; 1838 } 1839 if (status != NI_OK) { 1840 ni_free(domain); 1841 return NULL; 1842 } 1843 1844 config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state)); 1845 config->domain = domain; 1846 config->config_dir = config_dir; 1847 config->prop_index = 0; 1848 config->val_index = 0; 1849 config->val_list = NULL; 1850 1851 return config; 1852 } 1853 1854 1855 1856 /* 1857 * free_netinfo_config - release NetInfo configuration state 1858 */ 1859 static void 1860 free_netinfo_config(struct netinfo_config_state *config) 1861 { 1862 ni_free(config->domain); 1863 free(config); 1864 } 1865 1866 1867 1868 /* 1869 * gettokens_netinfo - return tokens from NetInfo 1870 */ 1871 static int 1872 gettokens_netinfo ( 1873 struct netinfo_config_state *config, 1874 char **tokenlist, 1875 int *ntokens 1876 ) 1877 { 1878 int prop_index = config->prop_index; 1879 int val_index = config->val_index; 1880 char **val_list = config->val_list; 1881 1882 /* 1883 * Iterate through each keyword and look for a property that matches it. 1884 */ 1885 again: 1886 if (!val_list) { 1887 for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++) 1888 { 1889 ni_namelist namelist; 1890 struct keyword current_prop = keywords[prop_index]; 1891 1892 /* 1893 * For each value associated in the property, we're going to return 1894 * a separate line. We squirrel away the values in the config state 1895 * so the next time through, we don't need to do this lookup. 1896 */ 1897 NI_INIT(&namelist); 1898 if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) { 1899 ni_index index; 1900 1901 /* Found the property, but it has no values */ 1902 if (namelist.ni_namelist_len == 0) continue; 1903 1904 if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1)))) 1905 { msyslog(LOG_ERR, "out of memory while configuring"); break; } 1906 1907 for (index = 0; index < namelist.ni_namelist_len; index++) { 1908 char *value = namelist.ni_namelist_val[index]; 1909 1910 if (! (val_list[index] = (char*)malloc(strlen(value+1)))) 1911 { msyslog(LOG_ERR, "out of memory while configuring"); break; } 1912 1913 strcpy(val_list[index], value); 1914 } 1915 val_list[index] = NULL; 1916 1917 break; 1918 } 1919 ni_namelist_free(&namelist); 1920 } 1921 config->prop_index = prop_index; 1922 } 1923 1924 /* No list; we're done here. */ 1925 if (!val_list) return CONFIG_UNKNOWN; 1926 1927 /* 1928 * We have a list of values for the current property. 1929 * Iterate through them and return each in order. 1930 */ 1931 if (val_list[val_index]) 1932 { 1933 int ntok = 1; 1934 int quoted = 0; 1935 char *tokens = val_list[val_index]; 1936 1937 msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]); 1938 1939 (const char*)tokenlist[0] = keywords[prop_index].text; 1940 for (ntok = 1; ntok < MAXTOKENS; ntok++) { 1941 tokenlist[ntok] = tokens; 1942 while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted)) 1943 quoted ^= (*tokens++ == '"'); 1944 1945 if (ISEOL(*tokens)) { 1946 *tokens = '\0'; 1947 break; 1948 } else { /* must be space */ 1949 *tokens++ = '\0'; 1950 while (ISSPACE(*tokens)) tokens++; 1951 if (ISEOL(*tokens)) break; 1952 } 1953 } 1954 *ntokens = ntok + 1; 1955 1956 config->val_index++; 1957 1958 return keywords[prop_index].keytype; 1959 } 1960 1961 /* We're done with the current property. */ 1962 prop_index = ++config->prop_index; 1963 1964 /* Free val_list and reset counters. */ 1965 for (val_index = 0; val_list[val_index]; val_index++) 1966 free(val_list[val_index]); 1967 free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0; 1968 1969 goto again; 1970 } 1971 1972 #endif /* HAVE_NETINFO */ 1973 1974 1975 /* 1976 * gettokens - read a line and return tokens 1977 */ 1978 static int 1979 gettokens ( 1980 FILE *fp, 1981 char *line, 1982 char **tokenlist, 1983 int *ntokens 1984 ) 1985 { 1986 register char *cp; 1987 register int ntok; 1988 register int quoted = 0; 1989 1990 /* 1991 * Find start of first token 1992 */ 1993 again: 1994 while ((cp = fgets(line, MAXLINE, fp)) != NULL) { 1995 cp = line; 1996 while (ISSPACE(*cp)) 1997 cp++; 1998 if (!ISEOL(*cp)) 1999 break; 2000 } 2001 if (cp == NULL) { 2002 *ntokens = 0; 2003 return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */ 2004 } 2005 2006 /* 2007 * Now separate out the tokens 2008 */ 2009 for (ntok = 0; ntok < MAXTOKENS; ntok++) { 2010 tokenlist[ntok] = cp; 2011 while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted)) 2012 quoted ^= (*cp++ == '"'); 2013 2014 if (ISEOL(*cp)) { 2015 *cp = '\0'; 2016 break; 2017 } else { /* must be space */ 2018 *cp++ = '\0'; 2019 while (ISSPACE(*cp)) 2020 cp++; 2021 if (ISEOL(*cp)) 2022 break; 2023 } 2024 } 2025 2026 /* 2027 * Return the match 2028 */ 2029 *ntokens = ntok + 1; 2030 ntok = matchkey(tokenlist[0], keywords); 2031 if (ntok == CONFIG_UNKNOWN) 2032 goto again; 2033 return ntok; 2034 } 2035 2036 2037 2038 /* 2039 * matchkey - match a keyword to a list 2040 */ 2041 static int 2042 matchkey( 2043 register char *word, 2044 register struct keyword *keys 2045 ) 2046 { 2047 for (;;) { 2048 if (keys->keytype == CONFIG_UNKNOWN) { 2049 msyslog(LOG_ERR, 2050 "configure: keyword \"%s\" unknown, line ignored", 2051 word); 2052 return CONFIG_UNKNOWN; 2053 } 2054 if (STRSAME(word, keys->text)) 2055 return keys->keytype; 2056 keys++; 2057 } 2058 } 2059 2060 2061 /* 2062 * getnetnum - return a net number (this is crude, but careful) 2063 */ 2064 static int 2065 getnetnum( 2066 const char *num, 2067 struct sockaddr_in *addr, 2068 int complain 2069 ) 2070 { 2071 register const char *cp; 2072 register char *bp; 2073 register int i; 2074 register int temp; 2075 char buf[80]; /* will core dump on really stupid stuff */ 2076 u_int32 netnum; 2077 2078 /* XXX ELIMINATE replace with decodenetnum */ 2079 cp = num; 2080 netnum = 0; 2081 for (i = 0; i < 4; i++) { 2082 bp = buf; 2083 while (isdigit((int)*cp)) 2084 *bp++ = *cp++; 2085 if (bp == buf) 2086 break; 2087 2088 if (i < 3) { 2089 if (*cp++ != '.') 2090 break; 2091 } else if (*cp != '\0') 2092 break; 2093 2094 *bp = '\0'; 2095 temp = atoi(buf); 2096 if (temp > 255) 2097 break; 2098 netnum <<= 8; 2099 netnum += temp; 2100 #ifdef DEBUG 2101 if (debug > 3) 2102 printf("getnetnum %s step %d buf %s temp %d netnum %lu\n", 2103 num, i, buf, temp, (u_long)netnum); 2104 #endif 2105 } 2106 2107 if (i < 4) { 2108 if (complain) 2109 msyslog(LOG_ERR, 2110 "getnetnum: \"%s\" invalid host number, line ignored", 2111 num); 2112 #ifdef DEBUG 2113 if (debug > 3) 2114 printf( 2115 "getnetnum: \"%s\" invalid host number, line ignored\n", 2116 num); 2117 #endif 2118 return 0; 2119 } 2120 2121 /* 2122 * make up socket address. Clear it out for neatness. 2123 */ 2124 memset((void *)addr, 0, sizeof(struct sockaddr_in)); 2125 addr->sin_family = AF_INET; 2126 addr->sin_port = htons(NTP_PORT); 2127 addr->sin_addr.s_addr = htonl(netnum); 2128 #ifdef DEBUG 2129 if (debug > 1) 2130 printf("getnetnum given %s, got %s (%lx)\n", 2131 num, ntoa(addr), (u_long)netnum); 2132 #endif 2133 return 1; 2134 } 2135 2136 2137 #if !defined(VMS) 2138 /* 2139 * catchchild - receive the resolver's exit status 2140 */ 2141 static RETSIGTYPE 2142 catchchild( 2143 int sig 2144 ) 2145 { 2146 /* 2147 * We only start up one child, and if we're here 2148 * it should have already exited. Hence the following 2149 * shouldn't hang. If it does, please tell me. 2150 */ 2151 #if !defined (SYS_WINNT) && !defined(SYS_VXWORKS) 2152 (void) wait(0); 2153 #endif /* SYS_WINNT && VXWORKS*/ 2154 } 2155 #endif /* VMS */ 2156 2157 2158 /* 2159 * save_resolve - save configuration info into a file for later name resolution 2160 */ 2161 static void 2162 save_resolve( 2163 char *name, 2164 int mode, 2165 int version, 2166 int minpoll, 2167 int maxpoll, 2168 int flags, 2169 int ttl, 2170 u_long keyid 2171 ) 2172 { 2173 #ifndef SYS_VXWORKS 2174 if (res_fp == NULL) { 2175 #ifndef SYS_WINNT 2176 (void) strcpy(res_file, RES_TEMPFILE); 2177 #else 2178 /* no /tmp directory under NT */ 2179 { 2180 DWORD len; 2181 if(!(len = GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { 2182 msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m"); 2183 return; 2184 } 2185 (void) strcat(res_file, "ntpdXXXXXX"); 2186 } 2187 #endif /* SYS_WINNT */ 2188 #ifdef HAVE_MKSTEMP 2189 { 2190 int fd; 2191 2192 res_fp = NULL; 2193 if ((fd = mkstemp(res_file)) != -1) 2194 res_fp = fdopen(fd, "w"); 2195 } 2196 #else 2197 (void) mktemp(res_file); 2198 res_fp = fopen(res_file, "w"); 2199 #endif 2200 if (res_fp == NULL) { 2201 msyslog(LOG_ERR, "open failed for %s: %m", res_file); 2202 return; 2203 } 2204 } 2205 #ifdef DEBUG 2206 if (debug) { 2207 printf("resolving %s\n", name); 2208 } 2209 #endif 2210 2211 (void) fprintf(res_fp, "%s %d %d %d %d %d %d %lu\n", name, mode, 2212 version, minpoll, maxpoll, flags, ttl, keyid); 2213 #else /* SYS_VXWORKS */ 2214 /* save resolve info to a struct */ 2215 #endif /* SYS_VXWORKS */ 2216 } 2217 2218 2219 /* 2220 * abort_resolve - terminate the resolver stuff and delete the file 2221 */ 2222 static void 2223 abort_resolve(void) 2224 { 2225 /* 2226 * In an ideal world we would might reread the file and 2227 * log the hosts which aren't getting configured. Since 2228 * this is too much work, however, just close and delete 2229 * the temp file. 2230 */ 2231 if (res_fp != NULL) 2232 (void) fclose(res_fp); 2233 res_fp = NULL; 2234 2235 #ifndef SYS_VXWORKS /* we don't open the file to begin with */ 2236 #if !defined(VMS) 2237 (void) unlink(res_file); 2238 #else 2239 (void) delete(res_file); 2240 #endif /* VMS */ 2241 #endif /* SYS_VXWORKS */ 2242 } 2243 2244 2245 #define KEY_TYPE_MD5 4 2246 2247 /* 2248 * do_resolve_internal - start up the resolver function (not program) 2249 */ 2250 /* 2251 * On VMS, this routine will simply refuse to resolve anything. 2252 * 2253 * Possible implementation: keep `res_file' in memory, do async 2254 * name resolution via QIO, update from within completion AST. 2255 * I'm unlikely to find the time for doing this, though. -wjm 2256 */ 2257 static void 2258 do_resolve_internal(void) 2259 { 2260 int i; 2261 2262 if (res_fp == NULL) { 2263 /* belch */ 2264 msyslog(LOG_ERR, 2265 "internal error in do_resolve_internal: res_fp == NULL"); 2266 exit(1); 2267 } 2268 2269 /* we are done with this now */ 2270 (void) fclose(res_fp); 2271 res_fp = NULL; 2272 2273 #if !defined(VMS) && !defined (SYS_VXWORKS) 2274 /* find a keyid */ 2275 if (info_auth_keyid == 0) 2276 req_keyid = 65535; 2277 else 2278 req_keyid = info_auth_keyid; 2279 2280 /* if doesn't exist, make up one at random */ 2281 if (!authhavekey(req_keyid)) { 2282 char rankey[8]; 2283 2284 for (i = 0; i < 8; i++) 2285 rankey[i] = RANDOM & 0xff; 2286 authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey); 2287 authtrust(req_keyid, 1); 2288 } 2289 2290 /* save keyid so we will accept config requests with it */ 2291 info_auth_keyid = req_keyid; 2292 req_file = res_file; /* set up pointer to res file */ 2293 #ifndef SYS_WINNT 2294 (void) signal_no_reset(SIGCHLD, catchchild); 2295 2296 #ifndef SYS_VXWORKS 2297 i = fork(); 2298 if (i == 0) { 2299 /* 2300 * this used to close everything 2301 * I don't think this is necessary 2302 */ 2303 /* 2304 * To the unknown commenter above: 2305 * Well, I think it's better to clean up 2306 * after oneself. I have had problems with 2307 * refclock-io when intres was running - things 2308 * where fine again when ntpintres was gone. 2309 * So some systems react erratic at least. 2310 * 2311 * Frank Kardel 2312 * 2313 * 94-11-16: 2314 * Further debugging has proven that the above is 2315 * absolutely harmful. The internal resolver 2316 * is still in the SIGIO process group and the lingering 2317 * async io information causes it to process requests from 2318 * all file decriptor causing a race between the NTP daemon 2319 * and the resolver. which then eats data when it wins 8-(. 2320 * It is absolutly necessary to kill ane io associations 2321 * shared with the NTP daemon. I currently don't want 2322 * 2323 * we also block SIGIO (currently no portes means to 2324 * disable the signal handle for IO). 2325 * 2326 * Thanks to wgstuken@informatik.uni-erlangen.de to notice 2327 * that it is the ntp-resolver child running into trouble. 2328 * 2329 * THUS: 2330 */ 2331 2332 closelog(); 2333 kill_asyncio(); 2334 2335 (void) signal_no_reset(SIGCHLD, SIG_DFL); 2336 2337 #ifdef DEBUG 2338 if (0) 2339 debug = 2; 2340 #endif 2341 2342 # ifndef LOG_DAEMON 2343 openlog("ntpd_initres", LOG_PID); 2344 # else /* LOG_DAEMON */ 2345 2346 # ifndef LOG_NTP 2347 # define LOG_NTP LOG_DAEMON 2348 # endif 2349 openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP); 2350 #ifndef SYS_CYGWIN32 2351 # ifdef DEBUG 2352 if (debug) 2353 setlogmask(LOG_UPTO(LOG_DEBUG)); 2354 else 2355 # endif /* DEBUG */ 2356 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ 2357 # endif /* LOG_DAEMON */ 2358 #endif 2359 2360 ntp_intres(); 2361 2362 /* 2363 * If we got here, the intres code screwed up. 2364 * Print something so we don't die without complaint 2365 */ 2366 msyslog(LOG_ERR, "call to ntp_intres lost"); 2367 abort_resolve(); 2368 exit(1); 2369 } 2370 #else 2371 /* vxWorks spawns a thread... -casey */ 2372 i = sp (ntp_intres); 2373 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/ 2374 #endif 2375 if (i == -1) { 2376 msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m"); 2377 (void) signal_no_reset(SIGCHLD, SIG_DFL); 2378 abort_resolve(); 2379 } 2380 #else /* SYS_WINNT */ 2381 { 2382 /* NT's equivalent of fork() is _spawn(), but the start point 2383 * of the new process is an executable filename rather than 2384 * a function name as desired here. 2385 */ 2386 DWORD dwThreadId; 2387 fflush(stdout); 2388 if (!(ResolverThreadHandle = CreateThread( 2389 NULL, /* no security attributes */ 2390 0, /* use default stack size */ 2391 (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */ 2392 NULL, /* argument to thread function */ 2393 0, /* use default creation flags */ 2394 &dwThreadId))) { /* returns the thread identifier */ 2395 msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres"); 2396 abort_resolve(); 2397 } 2398 } 2399 #endif /* SYS_WINNT */ 2400 #else /* VMS VX_WORKS */ 2401 msyslog(LOG_ERR, 2402 "Name resolution not implemented for VMS - use numeric addresses"); 2403 abort_resolve(); 2404 #endif /* VMS VX_WORKS */ 2405 } 2406