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