1 /* 2 * ntp_util.c - stuff I didn't have any other place for 3 */ 4 #ifdef HAVE_CONFIG_H 5 # include <config.h> 6 #endif 7 8 #include "ntpd.h" 9 #include "ntp_unixtime.h" 10 #include "ntp_filegen.h" 11 #include "ntp_if.h" 12 #include "ntp_stdlib.h" 13 #include "ntp_assert.h" 14 #include "ntp_calendar.h" 15 #include "ntp_leapsec.h" 16 17 #include <stdio.h> 18 #include <ctype.h> 19 #include <sys/types.h> 20 #ifdef HAVE_SYS_IOCTL_H 21 # include <sys/ioctl.h> 22 #endif 23 #ifdef HAVE_UNISTD_H 24 # include <unistd.h> 25 #endif 26 #include <sys/stat.h> 27 28 #ifdef HAVE_IEEEFP_H 29 # include <ieeefp.h> 30 #endif 31 #ifdef HAVE_MATH_H 32 # include <math.h> 33 #endif 34 35 #if defined(VMS) 36 # include <descrip.h> 37 #endif /* VMS */ 38 39 /* 40 * Defines used by the leapseconds stuff 41 */ 42 #define MAX_TAI 100 /* max TAI offset (s) */ 43 #define L_DAY 86400UL /* seconds per day */ 44 #define L_YEAR (L_DAY * 365) /* days per year */ 45 #define L_LYEAR (L_YEAR + L_DAY) /* days per leap year */ 46 #define L_4YEAR (L_LYEAR + 3 * L_YEAR) /* days per leap cycle */ 47 #define L_CENT (L_4YEAR * 25) /* days per century */ 48 49 /* 50 * This contains odds and ends, including the hourly stats, various 51 * configuration items, leapseconds stuff, etc. 52 */ 53 /* 54 * File names 55 */ 56 static char *key_file_name; /* keys file name */ 57 static char *leapfile_name; /* leapseconds file name */ 58 static struct stat leapfile_stat; /* leapseconds file stat() buffer */ 59 static int /*BOOL*/have_leapfile = FALSE; 60 static int /*BOOL*/chck_leaphash = TRUE; 61 char *stats_drift_file; /* frequency file name */ 62 static char *stats_temp_file; /* temp frequency file name */ 63 static double wander_resid; /* last frequency update */ 64 double wander_threshold = 1e-7; /* initial frequency threshold */ 65 66 /* 67 * Statistics file stuff 68 */ 69 #ifndef NTP_VAR 70 # ifndef SYS_WINNT 71 # define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ 72 # else 73 # define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ 74 # endif /* SYS_WINNT */ 75 #endif 76 77 78 char statsdir[MAXFILENAME] = NTP_VAR; 79 static FILEGEN peerstats; 80 static FILEGEN loopstats; 81 static FILEGEN clockstats; 82 static FILEGEN rawstats; 83 static FILEGEN sysstats; 84 static FILEGEN protostats; 85 static FILEGEN cryptostats; 86 static FILEGEN timingstats; 87 88 /* 89 * This controls whether stats are written to the fileset. Provided 90 * so that ntpdc can turn off stats when the file system fills up. 91 */ 92 int stats_control; 93 94 /* 95 * Last frequency written to file. 96 */ 97 static double prev_drift_comp; /* last frequency update */ 98 99 /* 100 * Function prototypes 101 */ 102 static void record_sys_stats(void); 103 void ntpd_time_stepped(void); 104 static void check_leap_expiration(int, uint32_t, const time_t*); 105 106 /* 107 * Prototypes 108 */ 109 #ifdef DEBUG 110 void uninit_util(void); 111 #endif 112 113 /* 114 * uninit_util - free memory allocated by init_util 115 */ 116 #ifdef DEBUG 117 void 118 uninit_util(void) 119 { 120 #if defined(_MSC_VER) && defined (_DEBUG) 121 _CrtCheckMemory(); 122 #endif 123 if (stats_drift_file) { 124 free(stats_drift_file); 125 free(stats_temp_file); 126 stats_drift_file = NULL; 127 stats_temp_file = NULL; 128 } 129 if (key_file_name) { 130 free(key_file_name); 131 key_file_name = NULL; 132 } 133 filegen_unregister("peerstats"); 134 filegen_unregister("loopstats"); 135 filegen_unregister("clockstats"); 136 filegen_unregister("rawstats"); 137 filegen_unregister("sysstats"); 138 filegen_unregister("protostats"); 139 #ifdef AUTOKEY 140 filegen_unregister("cryptostats"); 141 #endif /* AUTOKEY */ 142 #ifdef DEBUG_TIMING 143 filegen_unregister("timingstats"); 144 #endif /* DEBUG_TIMING */ 145 146 #if defined(_MSC_VER) && defined (_DEBUG) 147 _CrtCheckMemory(); 148 #endif 149 } 150 #endif /* DEBUG */ 151 152 153 /* 154 * init_util - initialize the util module of ntpd 155 */ 156 void 157 init_util(void) 158 { 159 filegen_register(statsdir, "peerstats", &peerstats); 160 filegen_register(statsdir, "loopstats", &loopstats); 161 filegen_register(statsdir, "clockstats", &clockstats); 162 filegen_register(statsdir, "rawstats", &rawstats); 163 filegen_register(statsdir, "sysstats", &sysstats); 164 filegen_register(statsdir, "protostats", &protostats); 165 filegen_register(statsdir, "cryptostats", &cryptostats); 166 filegen_register(statsdir, "timingstats", &timingstats); 167 /* 168 * register with libntp ntp_set_tod() to call us back 169 * when time is stepped. 170 */ 171 step_callback = &ntpd_time_stepped; 172 #ifdef DEBUG 173 atexit(&uninit_util); 174 #endif /* DEBUG */ 175 } 176 177 178 /* 179 * hourly_stats - print some interesting stats 180 */ 181 void 182 write_stats(void) 183 { 184 FILE *fp = NULL; 185 #ifdef DOSYNCTODR 186 struct timeval tv; 187 #if !defined(VMS) 188 int prio_set; 189 #endif 190 #ifdef HAVE_GETCLOCK 191 struct timespec ts; 192 #endif 193 int o_prio; 194 195 /* 196 * Sometimes having a Sun can be a drag. 197 * 198 * The kernel variable dosynctodr controls whether the system's 199 * soft clock is kept in sync with the battery clock. If it 200 * is zero, then the soft clock is not synced, and the battery 201 * clock is simply left to rot. That means that when the system 202 * reboots, the battery clock (which has probably gone wacky) 203 * sets the soft clock. That means ntpd starts off with a very 204 * confused idea of what time it is. It then takes a large 205 * amount of time to figure out just how wacky the battery clock 206 * has made things drift, etc, etc. The solution is to make the 207 * battery clock sync up to system time. The way to do THAT is 208 * to simply set the time of day to the current time of day, but 209 * as quickly as possible. This may, or may not be a sensible 210 * thing to do. 211 * 212 * CAVEAT: settimeofday() steps the sun clock by about 800 us, 213 * so setting DOSYNCTODR seems a bad idea in the 214 * case of us resolution 215 */ 216 217 #if !defined(VMS) 218 /* 219 * (prr) getpriority returns -1 on error, but -1 is also a valid 220 * return value (!), so instead we have to zero errno before the 221 * call and check it for non-zero afterwards. 222 */ 223 errno = 0; 224 prio_set = 0; 225 o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ 226 227 /* 228 * (prr) if getpriority succeeded, call setpriority to raise 229 * scheduling priority as high as possible. If that succeeds 230 * as well, set the prio_set flag so we remember to reset 231 * priority to its previous value below. Note that on Solaris 232 * 2.6 (and beyond?), both getpriority and setpriority will fail 233 * with ESRCH, because sched_setscheduler (called from main) put 234 * us in the real-time scheduling class which setpriority 235 * doesn't know about. Being in the real-time class is better 236 * than anything setpriority can do, anyhow, so this error is 237 * silently ignored. 238 */ 239 if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) 240 prio_set = 1; /* overdrive */ 241 #endif /* VMS */ 242 #ifdef HAVE_GETCLOCK 243 (void) getclock(TIMEOFDAY, &ts); 244 tv.tv_sec = ts.tv_sec; 245 tv.tv_usec = ts.tv_nsec / 1000; 246 #else /* not HAVE_GETCLOCK */ 247 GETTIMEOFDAY(&tv,(struct timezone *)NULL); 248 #endif /* not HAVE_GETCLOCK */ 249 if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) 250 msyslog(LOG_ERR, "can't sync battery time: %m"); 251 #if !defined(VMS) 252 if (prio_set) 253 setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ 254 #endif /* VMS */ 255 #endif /* DOSYNCTODR */ 256 record_sys_stats(); 257 if (stats_drift_file != 0) { 258 259 /* 260 * When the frequency file is written, initialize the 261 * prev_drift_comp and wander_resid. Thereafter, 262 * reduce the wander_resid by half each hour. When 263 * the difference between the prev_drift_comp and 264 * drift_comp is less than the wander_resid, update 265 * the frequncy file. This minimizes the file writes to 266 * nonvolaile storage. 267 */ 268 DPRINTF(1, ("write_stats: frequency %.6f thresh %.6f, freq %.6f\n", 269 (prev_drift_comp - drift_comp) * 1e6, wander_resid * 270 1e6, drift_comp * 1e6)); 271 272 if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 273 wander_resid *= 0.5; 274 return; 275 } 276 prev_drift_comp = drift_comp; 277 wander_resid = wander_threshold; 278 if ((fp = fopen(stats_temp_file, "w")) == NULL) { 279 msyslog(LOG_ERR, "frequency file %s: %m", 280 stats_temp_file); 281 return; 282 } 283 fprintf(fp, "%.6f\n", drift_comp * 1e6); 284 (void)fclose(fp); 285 /* atomic */ 286 #ifdef SYS_WINNT 287 if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 288 msyslog(LOG_WARNING, 289 "Unable to remove prior drift file %s, %m", 290 stats_drift_file); 291 #endif /* SYS_WINNT */ 292 293 #ifndef NO_RENAME 294 if (rename(stats_temp_file, stats_drift_file)) 295 msyslog(LOG_WARNING, 296 "Unable to rename temp drift file %s to %s, %m", 297 stats_temp_file, stats_drift_file); 298 #else 299 /* we have no rename NFS of ftp in use */ 300 if ((fp = fopen(stats_drift_file, "w")) == 301 NULL) { 302 msyslog(LOG_ERR, 303 "frequency file %s: %m", 304 stats_drift_file); 305 return; 306 } 307 #endif 308 309 #if defined(VMS) 310 /* PURGE */ 311 { 312 $DESCRIPTOR(oldvers,";-1"); 313 struct dsc$descriptor driftdsc = { 314 strlen(stats_drift_file), 0, 0, 315 stats_drift_file }; 316 while(lib$delete_file(&oldvers, 317 &driftdsc) & 1); 318 } 319 #endif 320 } 321 } 322 323 324 /* 325 * If an option was given on the command line make sure it takes 326 * precedence over the configuration file, as command-line options 327 * are processed first. Similarly, if an option is given in the 328 * configuration file, do not allow it to be overridden with runtime 329 * configuration. Done by simply remembering an option was already 330 * seen. 331 */ 332 static int 333 allow_config( 334 u_int option, 335 int/*BOOL*/ cmdopt 336 ) 337 { 338 static u_int seen = 0; /* stat options previously set */ 339 u_int mask; 340 int retv; 341 342 if (cmdopt) { 343 DEBUG_REQUIRE(option < sizeof(mask) * 8); 344 mask = 1u << option; 345 retv = !(seen & mask); 346 seen |= mask; 347 } else { 348 retv = FALSE; 349 } 350 return retv; 351 } 352 353 354 /* 355 * stats_config - configure the stats operation 356 */ 357 void 358 stats_config( 359 int item, 360 const char *invalue, /* only one type so far */ 361 int optflag 362 ) 363 { 364 FILE *fp = NULL; 365 const char *value; 366 size_t len; 367 double old_drift; 368 l_fp now; 369 time_t ttnow; 370 char dirsep_or_nul; 371 #ifndef VMS 372 static const char temp_ext[] = ".TEMP"; 373 #else 374 static const char temp_ext[] = "-TEMP"; 375 #endif 376 377 /* 378 * Expand environment strings under Windows NT, since the 379 * command interpreter doesn't do this, the program must. 380 */ 381 #ifdef SYS_WINNT 382 char newvalue[MAX_PATH], parameter[MAX_PATH]; 383 384 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 385 switch (item) { 386 case STATS_FREQ_FILE: 387 strlcpy(parameter, "STATS_FREQ_FILE", 388 sizeof(parameter)); 389 break; 390 391 case STATS_LEAP_FILE: 392 strlcpy(parameter, "STATS_LEAP_FILE", 393 sizeof(parameter)); 394 break; 395 396 case STATS_STATSDIR: 397 strlcpy(parameter, "STATS_STATSDIR", 398 sizeof(parameter)); 399 break; 400 401 case STATS_PID_FILE: 402 strlcpy(parameter, "STATS_PID_FILE", 403 sizeof(parameter)); 404 break; 405 406 default: 407 strlcpy(parameter, "UNKNOWN", 408 sizeof(parameter)); 409 break; 410 } 411 value = invalue; 412 msyslog(LOG_ERR, 413 "ExpandEnvironmentStrings(%s) failed: %m\n", 414 parameter); 415 } else { 416 value = newvalue; 417 } 418 #else 419 value = invalue; 420 #endif /* SYS_WINNT */ 421 422 switch (item) { 423 424 /* 425 * Open and read frequency file. 426 */ 427 case STATS_FREQ_FILE: 428 if (!allow_config(STATS_FREQ_FILE, optflag)) { 429 break; 430 } 431 if (!value || 0 == (len = strlen(value))) { 432 free(stats_drift_file); 433 free(stats_temp_file); 434 stats_drift_file = stats_temp_file = NULL; 435 } else { 436 stats_drift_file = erealloc(stats_drift_file, 437 1 + len); 438 stats_temp_file = erealloc(stats_temp_file, 439 len + sizeof(temp_ext)); 440 memcpy(stats_drift_file, value, 1 + len); 441 memcpy(stats_temp_file, value, len); 442 memcpy(stats_temp_file + len, temp_ext, 443 sizeof(temp_ext)); 444 } 445 446 /* 447 * Open drift file and read frequency. If the file is 448 * missing or contains errors, tell the loop to reset. 449 */ 450 if (NULL == stats_drift_file) { 451 goto nofreq; 452 } else if ((fp = fopen(stats_drift_file, "r")) == NULL) { 453 if (errno != ENOENT) { 454 msyslog(LOG_WARNING, 455 "cannot read frequency file %s: %m", 456 stats_drift_file); 457 } 458 goto nofreq; 459 } else if (fscanf(fp, "%lf", &old_drift) != 1) { 460 msyslog(LOG_ERR, 461 "format error frequency file %s", 462 stats_drift_file); 463 nofreq: 464 prev_drift_comp = 0.0; 465 loop_config(LOOP_NOFREQ, prev_drift_comp); 466 } else { 467 loop_config(LOOP_FREQ, old_drift); 468 prev_drift_comp = drift_comp; 469 msyslog(LOG_INFO, 470 "initial drift restored to %.6f", 471 old_drift); 472 } 473 if (NULL != fp) { 474 fclose(fp); 475 } 476 break; 477 478 /* 479 * Specify statistics directory. 480 */ 481 case STATS_STATSDIR: 482 if (!allow_config(STATS_STATSDIR, optflag)) { 483 break; 484 } 485 /* - 2 since value may be missing the DIR_SEP. */ 486 len = strlen(value); 487 if (len > sizeof(statsdir) - 2) { 488 msyslog(LOG_ERR, 489 "statsdir %s too long (>%u)", value, 490 (u_int)sizeof(statsdir) - 2); 491 break; 492 } 493 /* Add a DIR_SEP unless we already have one. */ 494 if (0 == len || DIR_SEP == value[len - 1]) { 495 dirsep_or_nul = '\0'; 496 } else { 497 dirsep_or_nul = DIR_SEP; 498 } 499 snprintf(statsdir, sizeof(statsdir), "%s%c", 500 value, dirsep_or_nul); 501 filegen_statsdir(); 502 break; 503 504 /* 505 * Write pid file. 506 */ 507 case STATS_PID_FILE: 508 if (!allow_config(STATS_PID_FILE, optflag)) { 509 break; 510 } 511 if ((fp = fopen(value, "w")) == NULL) { 512 msyslog(LOG_ERR, "pid file %s: %m", value); 513 break; 514 } 515 fprintf(fp, "%ld", (long)getpid()); 516 fclose(fp); 517 break; 518 519 /* 520 * Read leapseconds file. 521 * 522 * By default a leap file without SHA1 signature is accepted, 523 * but if there is a signature line, the signature must be 524 * valid or the leapfile line in ntp.conf must have ignorehash. 525 */ 526 case STATS_LEAP_FILE: 527 if (NULL == value || 0 == (len = strlen(value))) { 528 break; 529 } 530 leapfile_name = erealloc(leapfile_name, len + 1); 531 memcpy(leapfile_name, value, len + 1); 532 chck_leaphash = optflag; 533 534 if (leapsec_load_file( 535 leapfile_name, &leapfile_stat, 536 TRUE, TRUE, chck_leaphash)) { 537 leap_signature_t lsig; 538 539 get_systime(&now); 540 time(&ttnow); 541 leapsec_getsig(&lsig); 542 mprintf_event(EVNT_TAI, NULL, 543 "%d leap %s expire%s %s", 544 lsig.taiof, 545 fstostr(lsig.ttime), 546 leapsec_expired(now.l_ui, NULL) 547 ? "d" 548 : "s", 549 fstostr(lsig.etime)); 550 551 have_leapfile = TRUE; 552 553 /* force an immediate daily expiration check of 554 * the leap seconds table 555 */ 556 check_leap_expiration(TRUE, now.l_ui, &ttnow); 557 } 558 break; 559 560 default: 561 /* oh well */ 562 break; 563 } 564 } 565 566 567 /* 568 * record_peer_stats - write peer statistics to file 569 * 570 * file format: 571 * day (MJD) 572 * time (s past UTC midnight) 573 * IP address 574 * status word (hex) 575 * offset 576 * delay 577 * dispersion 578 * jitter 579 */ 580 void 581 record_peer_stats( 582 sockaddr_u * addr, 583 int status, 584 double offset, 585 double delay, 586 double dispersion, 587 double jitter 588 ) 589 { 590 l_fp now; 591 u_long day; 592 593 if (!stats_control) { 594 return; 595 } 596 get_systime(&now); 597 filegen_setup(&peerstats, now.l_ui); 598 if (NULL == peerstats.fp) { 599 return; 600 } 601 day = now.l_ui / 86400 + MJD_1900; 602 now.l_ui %= 86400; 603 fprintf(peerstats.fp, 604 "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 605 ulfptoa(&now, 3), stoa(addr), status, offset, 606 delay, dispersion, jitter); 607 fflush(peerstats.fp); 608 } 609 610 611 /* 612 * record_loop_stats - write loop filter statistics to file 613 * 614 * file format: 615 * day (MJD) 616 * time (s past midnight) 617 * offset 618 * frequency (PPM) 619 * jitter 620 * wnder (PPM) 621 * time constant (log2) 622 */ 623 void 624 record_loop_stats( 625 double offset, /* offset */ 626 double freq, /* frequency (PPM) */ 627 double jitter, /* jitter */ 628 double wander, /* wander (PPM) */ 629 int spoll 630 ) 631 { 632 l_fp now; 633 u_long day; 634 635 if (!stats_control) 636 return; 637 638 get_systime(&now); 639 filegen_setup(&loopstats, now.l_ui); 640 day = now.l_ui / 86400 + MJD_1900; 641 now.l_ui %= 86400; 642 if (loopstats.fp != NULL) { 643 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 644 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 645 wander * 1e6, spoll); 646 fflush(loopstats.fp); 647 } 648 } 649 650 651 /* 652 * record_clock_stats - write clock statistics to file 653 * 654 * file format: 655 * day (MJD) 656 * time (s past midnight) 657 * IP address 658 * text message 659 */ 660 void 661 record_clock_stats( 662 sockaddr_u *addr, 663 const char *text /* timecode string */ 664 ) 665 { 666 l_fp now; 667 u_long day; 668 669 if (!stats_control) 670 return; 671 672 get_systime(&now); 673 filegen_setup(&clockstats, now.l_ui); 674 day = now.l_ui / 86400 + MJD_1900; 675 now.l_ui %= 86400; 676 if (clockstats.fp != NULL) { 677 fprintf(clockstats.fp, "%lu %s %s %s\n", day, 678 ulfptoa(&now, 3), stoa(addr), text); 679 fflush(clockstats.fp); 680 } 681 } 682 683 684 /* 685 * mprintf_clock_stats - write clock statistics to file with 686 * msnprintf-style formatting. 687 */ 688 int 689 mprintf_clock_stats( 690 sockaddr_u *addr, 691 const char *fmt, 692 ... 693 ) 694 { 695 va_list ap; 696 int rc; 697 char msg[512]; 698 699 va_start(ap, fmt); 700 rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 701 va_end(ap); 702 if (stats_control) 703 record_clock_stats(addr, msg); 704 705 return rc; 706 } 707 708 /* 709 * record_raw_stats - write raw timestamps to file 710 * 711 * file format 712 * day (MJD) 713 * time (s past midnight) 714 * peer ip address 715 * IP address 716 * t1 t2 t3 t4 timestamps 717 * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 718 * length and hex dump of any EFs and any legacy MAC. 719 */ 720 void 721 record_raw_stats( 722 sockaddr_u *srcadr, 723 sockaddr_u *dstadr, 724 l_fp *t1, /* originate timestamp */ 725 l_fp *t2, /* receive timestamp */ 726 l_fp *t3, /* transmit timestamp */ 727 l_fp *t4, /* destination timestamp */ 728 int leap, 729 int version, 730 int mode, 731 int stratum, 732 int ppoll, 733 int precision, 734 double root_delay, /* seconds */ 735 double root_dispersion,/* seconds */ 736 u_int32 refid, 737 int len, 738 u_char *extra 739 ) 740 { 741 l_fp now; 742 u_long day; 743 744 if (!stats_control) 745 return; 746 747 /* 748 * Mode 6 and mode 7 packets do not have the format of normal 749 * NTP packets and will log garbage. So don't. [Bug 3774] 750 */ 751 if (MODE_CONTROL == mode || MODE_PRIVATE == mode) 752 return; 753 754 get_systime(&now); 755 filegen_setup(&rawstats, now.l_ui); 756 day = now.l_ui / 86400 + MJD_1900; 757 now.l_ui %= 86400; 758 if (rawstats.fp != NULL) { 759 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 760 day, ulfptoa(&now, 3), 761 srcadr ? stoa(srcadr) : "-", 762 dstadr ? stoa(dstadr) : "-", 763 ulfptoa(t1, 9), ulfptoa(t2, 9), 764 ulfptoa(t3, 9), ulfptoa(t4, 9), 765 leap, version, mode, stratum, ppoll, precision, 766 root_delay, root_dispersion, refid_str(refid, stratum)); 767 if (len > 0) { 768 int i; 769 770 fprintf(rawstats.fp, " %d: ", len); 771 for (i = 0; i < len; ++i) { 772 fprintf(rawstats.fp, "%02x", extra[i]); 773 } 774 } 775 fprintf(rawstats.fp, "\n"); 776 fflush(rawstats.fp); 777 } 778 } 779 780 781 /* 782 * record_sys_stats - write system statistics to file 783 * 784 * file format 785 * day (MJD) 786 * time (s past midnight) 787 * time since reset 788 * packets recieved 789 * packets for this host 790 * current version 791 * old version 792 * access denied 793 * bad length or format 794 * bad authentication 795 * declined 796 * rate exceeded 797 * KoD sent 798 */ 799 void 800 record_sys_stats(void) 801 { 802 l_fp now; 803 u_long day; 804 805 if (!stats_control) 806 return; 807 808 get_systime(&now); 809 filegen_setup(&sysstats, now.l_ui); 810 day = now.l_ui / 86400 + MJD_1900; 811 now.l_ui %= 86400; 812 if (sysstats.fp != NULL) { 813 fprintf(sysstats.fp, 814 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 815 day, ulfptoa(&now, 3), current_time - sys_stattime, 816 sys_received, sys_processed, sys_newversion, 817 sys_oldversion, sys_restricted, sys_badlength, 818 sys_badauth, sys_declined, sys_limitrejected, 819 sys_kodsent); 820 fflush(sysstats.fp); 821 proto_clr_stats(); 822 } 823 } 824 825 826 /* 827 * record_proto_stats - write system statistics to file 828 * 829 * file format 830 * day (MJD) 831 * time (s past midnight) 832 * text message 833 */ 834 void 835 record_proto_stats( 836 char *str /* text string */ 837 ) 838 { 839 l_fp now; 840 u_long day; 841 842 if (!stats_control) 843 return; 844 845 get_systime(&now); 846 filegen_setup(&protostats, now.l_ui); 847 day = now.l_ui / 86400 + MJD_1900; 848 now.l_ui %= 86400; 849 if (protostats.fp != NULL) { 850 fprintf(protostats.fp, "%lu %s %s\n", day, 851 ulfptoa(&now, 3), str); 852 fflush(protostats.fp); 853 } 854 } 855 856 857 #ifdef AUTOKEY 858 /* 859 * record_crypto_stats - write crypto statistics to file 860 * 861 * file format: 862 * day (mjd) 863 * time (s past midnight) 864 * peer ip address 865 * text message 866 */ 867 void 868 record_crypto_stats( 869 sockaddr_u *addr, 870 const char *text /* text message */ 871 ) 872 { 873 l_fp now; 874 u_long day; 875 876 if (!stats_control) 877 return; 878 879 get_systime(&now); 880 filegen_setup(&cryptostats, now.l_ui); 881 day = now.l_ui / 86400 + MJD_1900; 882 now.l_ui %= 86400; 883 if (cryptostats.fp != NULL) { 884 if (addr == NULL) 885 fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 886 day, ulfptoa(&now, 3), text); 887 else 888 fprintf(cryptostats.fp, "%lu %s %s %s\n", 889 day, ulfptoa(&now, 3), stoa(addr), text); 890 fflush(cryptostats.fp); 891 } 892 } 893 #endif /* AUTOKEY */ 894 895 896 #ifdef DEBUG_TIMING 897 /* 898 * record_timing_stats - write timing statistics to file 899 * 900 * file format: 901 * day (mjd) 902 * time (s past midnight) 903 * text message 904 */ 905 void 906 record_timing_stats( 907 const char *text /* text message */ 908 ) 909 { 910 static unsigned int flshcnt; 911 l_fp now; 912 u_long day; 913 914 if (!stats_control) 915 return; 916 917 get_systime(&now); 918 filegen_setup(&timingstats, now.l_ui); 919 day = now.l_ui / 86400 + MJD_1900; 920 now.l_ui %= 86400; 921 if (timingstats.fp != NULL) { 922 fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 923 3), text); 924 if (++flshcnt % 100 == 0) 925 fflush(timingstats.fp); 926 } 927 } 928 #endif 929 930 931 /* 932 * check_leap_file - See if the leapseconds file has been updated. 933 * 934 * Returns: n/a 935 * 936 * Note: This loads a new leapfile on the fly. Currently a leap file 937 * without SHA1 signature is accepted, but if there is a signature line, 938 * the signature must be valid unless the ntp.conf leapfile line specified 939 * ignorehash. 940 */ 941 void 942 check_leap_file( 943 int is_daily_check, 944 uint32_t ntptime, 945 const time_t * systime 946 ) 947 { 948 /* just do nothing if there is no leap file */ 949 if ( ! (leapfile_name && *leapfile_name)) 950 return; 951 952 /* try to load leapfile, force it if no leapfile loaded yet */ 953 if (leapsec_load_file( 954 leapfile_name, &leapfile_stat, 955 !have_leapfile, is_daily_check, chck_leaphash)) 956 have_leapfile = TRUE; 957 else if (!have_leapfile) 958 return; 959 960 check_leap_expiration(is_daily_check, ntptime, systime); 961 } 962 963 /* 964 * check expiration of a loaded leap table 965 */ 966 static void 967 check_leap_expiration( 968 int is_daily_check, 969 uint32_t ntptime , 970 const time_t *systime 971 ) 972 { 973 static const char * const logPrefix = "leapsecond file"; 974 int rc; 975 976 /* test the expiration of the leap data and log with proper 977 * level and frequency (once/hour or once/day, depending on the 978 * state. 979 */ 980 rc = leapsec_daystolive(ntptime, systime); 981 if (rc == 0) { 982 msyslog(LOG_WARNING, 983 "%s ('%s'): will expire in less than one day", 984 logPrefix, leapfile_name); 985 } else if (is_daily_check && rc < 28) { 986 if (rc < 0) 987 msyslog(LOG_ERR, 988 "%s ('%s'): expired %d day%s ago", 989 logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 990 else 991 msyslog(LOG_WARNING, 992 "%s ('%s'): will expire in less than %d days", 993 logPrefix, leapfile_name, 1+rc); 994 } 995 } 996 997 998 /* 999 * getauthkeys - read the authentication keys from the specified file 1000 */ 1001 void 1002 getauthkeys( 1003 const char *keyfile 1004 ) 1005 { 1006 size_t len; 1007 1008 len = strlen(keyfile); 1009 if (!len) 1010 return; 1011 1012 #ifndef SYS_WINNT 1013 key_file_name = erealloc(key_file_name, len + 1); 1014 memcpy(key_file_name, keyfile, len + 1); 1015 #else 1016 key_file_name = erealloc(key_file_name, _MAX_PATH); 1017 if (len + 1 > _MAX_PATH) 1018 return; 1019 if (!ExpandEnvironmentStrings(keyfile, key_file_name, 1020 _MAX_PATH)) { 1021 msyslog(LOG_ERR, 1022 "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 1023 strlcpy(key_file_name, keyfile, _MAX_PATH); 1024 } 1025 key_file_name = erealloc(key_file_name, 1026 1 + strlen(key_file_name)); 1027 #endif /* SYS_WINNT */ 1028 1029 authreadkeys(key_file_name); 1030 } 1031 1032 1033 /* 1034 * rereadkeys - read the authentication key file over again. 1035 */ 1036 void 1037 rereadkeys(void) 1038 { 1039 if (NULL != key_file_name) 1040 authreadkeys(key_file_name); 1041 } 1042 1043 1044 #if notyet 1045 /* 1046 * ntp_exit - document explicitly that ntpd has exited 1047 */ 1048 void 1049 ntp_exit(int retval) 1050 { 1051 msyslog(LOG_ERR, "EXITING with return code %d", retval); 1052 exit(retval); 1053 } 1054 #endif 1055 1056 /* 1057 * fstostr - prettyprint NTP seconds 1058 */ 1059 char * fstostr( 1060 time_t ntp_stamp 1061 ) 1062 { 1063 char * buf; 1064 struct calendar tm; 1065 1066 LIB_GETBUF(buf); 1067 if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 1068 snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 1069 (long)ntp_stamp); 1070 else 1071 snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1072 tm.year, tm.month, tm.monthday, 1073 tm.hour, tm.minute); 1074 return buf; 1075 } 1076 1077 1078 /* 1079 * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1080 * to do any one-time processing necessitated by the step. 1081 */ 1082 void 1083 ntpd_time_stepped(void) 1084 { 1085 u_int saved_mon_enabled; 1086 1087 /* 1088 * flush the monitor MRU list which contains l_fp timestamps 1089 * which should not be compared across the step. 1090 */ 1091 if (MON_OFF != mon_enabled) { 1092 saved_mon_enabled = mon_enabled; 1093 mon_stop(MON_OFF); 1094 mon_start(saved_mon_enabled); 1095 } 1096 1097 /* inform interpolating Windows code to allow time to go back */ 1098 #ifdef SYS_WINNT 1099 win_time_stepped(); 1100 #endif 1101 } 1102 1103 1104 #ifdef DEBUG 1105 void 1106 append_flagstr( 1107 char * flagstr, 1108 size_t sz, 1109 const char * text 1110 ) 1111 { 1112 if ('\0' != flagstr[0]) { 1113 strlcat(flagstr, ",", sz); 1114 } 1115 /* bail if we ran out of room */ 1116 INSIST(strlcat(flagstr, text, sz) < sz); 1117 } 1118 #endif /* DEBUG */ 1119