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