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 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; 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 #ifdef DEBUG 269 if (debug) 270 printf("write_stats: frequency %.6lf thresh %.6lf, freq %.6lf\n", 271 (prev_drift_comp - drift_comp) * 1e6, wander_resid * 272 1e6, drift_comp * 1e6); 273 #endif 274 if (fabs(prev_drift_comp - drift_comp) < wander_resid) { 275 wander_resid *= 0.5; 276 return; 277 } 278 prev_drift_comp = drift_comp; 279 wander_resid = wander_threshold; 280 if ((fp = fopen(stats_temp_file, "w")) == NULL) { 281 msyslog(LOG_ERR, "frequency file %s: %m", 282 stats_temp_file); 283 return; 284 } 285 fprintf(fp, "%.3f\n", drift_comp * 1e6); 286 (void)fclose(fp); 287 /* atomic */ 288 #ifdef SYS_WINNT 289 if (_unlink(stats_drift_file)) /* rename semantics differ under NT */ 290 msyslog(LOG_WARNING, 291 "Unable to remove prior drift file %s, %m", 292 stats_drift_file); 293 #endif /* SYS_WINNT */ 294 295 #ifndef NO_RENAME 296 if (rename(stats_temp_file, stats_drift_file)) 297 msyslog(LOG_WARNING, 298 "Unable to rename temp drift file %s to %s, %m", 299 stats_temp_file, stats_drift_file); 300 #else 301 /* we have no rename NFS of ftp in use */ 302 if ((fp = fopen(stats_drift_file, "w")) == 303 NULL) { 304 msyslog(LOG_ERR, 305 "frequency file %s: %m", 306 stats_drift_file); 307 return; 308 } 309 #endif 310 311 #if defined(VMS) 312 /* PURGE */ 313 { 314 $DESCRIPTOR(oldvers,";-1"); 315 struct dsc$descriptor driftdsc = { 316 strlen(stats_drift_file), 0, 0, 317 stats_drift_file }; 318 while(lib$delete_file(&oldvers, 319 &driftdsc) & 1); 320 } 321 #endif 322 } 323 } 324 325 326 /* 327 * stats_config - configure the stats operation 328 */ 329 void 330 stats_config( 331 int item, 332 const char *invalue /* only one type so far */ 333 ) 334 { 335 FILE *fp; 336 const char *value; 337 size_t len; 338 double old_drift; 339 l_fp now; 340 time_t ttnow; 341 #ifndef VMS 342 const char temp_ext[] = ".TEMP"; 343 #else 344 const char temp_ext[] = "-TEMP"; 345 #endif 346 347 /* 348 * Expand environment strings under Windows NT, since the 349 * command interpreter doesn't do this, the program must. 350 */ 351 #ifdef SYS_WINNT 352 char newvalue[MAX_PATH], parameter[MAX_PATH]; 353 354 if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) { 355 switch (item) { 356 case STATS_FREQ_FILE: 357 strlcpy(parameter, "STATS_FREQ_FILE", 358 sizeof(parameter)); 359 break; 360 361 case STATS_LEAP_FILE: 362 strlcpy(parameter, "STATS_LEAP_FILE", 363 sizeof(parameter)); 364 break; 365 366 case STATS_STATSDIR: 367 strlcpy(parameter, "STATS_STATSDIR", 368 sizeof(parameter)); 369 break; 370 371 case STATS_PID_FILE: 372 strlcpy(parameter, "STATS_PID_FILE", 373 sizeof(parameter)); 374 break; 375 376 default: 377 strlcpy(parameter, "UNKNOWN", 378 sizeof(parameter)); 379 break; 380 } 381 value = invalue; 382 msyslog(LOG_ERR, 383 "ExpandEnvironmentStrings(%s) failed: %m\n", 384 parameter); 385 } else { 386 value = newvalue; 387 } 388 #else 389 value = invalue; 390 #endif /* SYS_WINNT */ 391 392 switch (item) { 393 394 /* 395 * Open and read frequency file. 396 */ 397 case STATS_FREQ_FILE: 398 if (!value || (len = strlen(value)) == 0) 399 break; 400 401 stats_drift_file = erealloc(stats_drift_file, len + 1); 402 stats_temp_file = erealloc(stats_temp_file, 403 len + sizeof(".TEMP")); 404 memcpy(stats_drift_file, value, (size_t)(len+1)); 405 memcpy(stats_temp_file, value, (size_t)len); 406 memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext)); 407 408 /* 409 * Open drift file and read frequency. If the file is 410 * missing or contains errors, tell the loop to reset. 411 */ 412 if ((fp = fopen(stats_drift_file, "r")) == NULL) 413 break; 414 415 if (fscanf(fp, "%lf", &old_drift) != 1) { 416 msyslog(LOG_ERR, 417 "format error frequency file %s", 418 stats_drift_file); 419 fclose(fp); 420 break; 421 422 } 423 fclose(fp); 424 loop_config(LOOP_FREQ, old_drift); 425 prev_drift_comp = drift_comp; 426 break; 427 428 /* 429 * Specify statistics directory. 430 */ 431 case STATS_STATSDIR: 432 433 /* - 1 since value may be missing the DIR_SEP. */ 434 if (strlen(value) >= sizeof(statsdir) - 1) { 435 msyslog(LOG_ERR, 436 "statsdir too long (>%d, sigh)", 437 (int)sizeof(statsdir) - 2); 438 } else { 439 int add_dir_sep; 440 size_t value_l; 441 442 /* Add a DIR_SEP unless we already have one. */ 443 value_l = strlen(value); 444 if (0 == value_l) 445 add_dir_sep = FALSE; 446 else 447 add_dir_sep = (DIR_SEP != 448 value[value_l - 1]); 449 450 if (add_dir_sep) 451 snprintf(statsdir, sizeof(statsdir), 452 "%s%c", value, DIR_SEP); 453 else 454 snprintf(statsdir, sizeof(statsdir), 455 "%s", value); 456 filegen_statsdir(); 457 } 458 break; 459 460 /* 461 * Open pid file. 462 */ 463 case STATS_PID_FILE: 464 if ((fp = fopen(value, "w")) == NULL) { 465 msyslog(LOG_ERR, "pid file %s: %m", 466 value); 467 break; 468 } 469 fprintf(fp, "%d", (int)getpid()); 470 fclose(fp); 471 break; 472 473 /* 474 * Read leapseconds file. 475 * 476 * Note: Currently a leap file without SHA1 signature is 477 * accepted, but if there is a signature line, the signature 478 * must be valid or the file is rejected. 479 */ 480 case STATS_LEAP_FILE: 481 if (!value || (len = strlen(value)) == 0) 482 break; 483 484 leapfile_name = erealloc(leapfile_name, len + 1); 485 memcpy(leapfile_name, value, len + 1); 486 487 if (leapsec_load_file( 488 leapfile_name, &leapfile_stat, TRUE, TRUE)) 489 { 490 leap_signature_t lsig; 491 492 get_systime(&now); 493 time(&ttnow); 494 leapsec_getsig(&lsig); 495 mprintf_event(EVNT_TAI, NULL, 496 "%d leap %s %s %s", 497 lsig.taiof, 498 fstostr(lsig.ttime), 499 leapsec_expired(now.l_ui, NULL) 500 ? "expired" 501 : "expires", 502 fstostr(lsig.etime)); 503 504 have_leapfile = TRUE; 505 506 /* force an immediate daily expiration check of 507 * the leap seconds table 508 */ 509 check_leap_expiration(TRUE, now.l_ui, &ttnow); 510 } 511 break; 512 513 default: 514 /* oh well */ 515 break; 516 } 517 } 518 519 520 /* 521 * record_peer_stats - write peer statistics to file 522 * 523 * file format: 524 * day (MJD) 525 * time (s past UTC midnight) 526 * IP address 527 * status word (hex) 528 * offset 529 * delay 530 * dispersion 531 * jitter 532 */ 533 void 534 record_peer_stats( 535 sockaddr_u *addr, 536 int status, 537 double offset, /* offset */ 538 double delay, /* delay */ 539 double dispersion, /* dispersion */ 540 double jitter /* jitter */ 541 ) 542 { 543 l_fp now; 544 u_long day; 545 546 if (!stats_control) 547 return; 548 549 get_systime(&now); 550 filegen_setup(&peerstats, now.l_ui); 551 day = now.l_ui / 86400 + MJD_1900; 552 now.l_ui %= 86400; 553 if (peerstats.fp != NULL) { 554 fprintf(peerstats.fp, 555 "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, 556 ulfptoa(&now, 3), stoa(addr), status, offset, 557 delay, dispersion, jitter); 558 fflush(peerstats.fp); 559 } 560 } 561 562 563 /* 564 * record_loop_stats - write loop filter statistics to file 565 * 566 * file format: 567 * day (MJD) 568 * time (s past midnight) 569 * offset 570 * frequency (PPM) 571 * jitter 572 * wnder (PPM) 573 * time constant (log2) 574 */ 575 void 576 record_loop_stats( 577 double offset, /* offset */ 578 double freq, /* frequency (PPM) */ 579 double jitter, /* jitter */ 580 double wander, /* wander (PPM) */ 581 int spoll 582 ) 583 { 584 l_fp now; 585 u_long day; 586 587 if (!stats_control) 588 return; 589 590 get_systime(&now); 591 filegen_setup(&loopstats, now.l_ui); 592 day = now.l_ui / 86400 + MJD_1900; 593 now.l_ui %= 86400; 594 if (loopstats.fp != NULL) { 595 fprintf(loopstats.fp, "%lu %s %.9f %.3f %.9f %.6f %d\n", 596 day, ulfptoa(&now, 3), offset, freq * 1e6, jitter, 597 wander * 1e6, spoll); 598 fflush(loopstats.fp); 599 } 600 } 601 602 603 /* 604 * record_clock_stats - write clock statistics to file 605 * 606 * file format: 607 * day (MJD) 608 * time (s past midnight) 609 * IP address 610 * text message 611 */ 612 void 613 record_clock_stats( 614 sockaddr_u *addr, 615 const char *text /* timecode string */ 616 ) 617 { 618 l_fp now; 619 u_long day; 620 621 if (!stats_control) 622 return; 623 624 get_systime(&now); 625 filegen_setup(&clockstats, now.l_ui); 626 day = now.l_ui / 86400 + MJD_1900; 627 now.l_ui %= 86400; 628 if (clockstats.fp != NULL) { 629 fprintf(clockstats.fp, "%lu %s %s %s\n", day, 630 ulfptoa(&now, 3), stoa(addr), text); 631 fflush(clockstats.fp); 632 } 633 } 634 635 636 /* 637 * mprintf_clock_stats - write clock statistics to file with 638 * msnprintf-style formatting. 639 */ 640 int 641 mprintf_clock_stats( 642 sockaddr_u *addr, 643 const char *fmt, 644 ... 645 ) 646 { 647 va_list ap; 648 int rc; 649 char msg[512]; 650 651 va_start(ap, fmt); 652 rc = mvsnprintf(msg, sizeof(msg), fmt, ap); 653 va_end(ap); 654 if (stats_control) 655 record_clock_stats(addr, msg); 656 657 return rc; 658 } 659 660 /* 661 * record_raw_stats - write raw timestamps to file 662 * 663 * file format 664 * day (MJD) 665 * time (s past midnight) 666 * peer ip address 667 * IP address 668 * t1 t2 t3 t4 timestamps 669 * leap, version, mode, stratum, ppoll, precision, root delay, root dispersion, REFID 670 * length and hex dump of any EFs and any legacy MAC. 671 */ 672 void 673 record_raw_stats( 674 sockaddr_u *srcadr, 675 sockaddr_u *dstadr, 676 l_fp *t1, /* originate timestamp */ 677 l_fp *t2, /* receive timestamp */ 678 l_fp *t3, /* transmit timestamp */ 679 l_fp *t4, /* destination timestamp */ 680 int leap, 681 int version, 682 int mode, 683 int stratum, 684 int ppoll, 685 int precision, 686 double root_delay, /* seconds */ 687 double root_dispersion,/* seconds */ 688 u_int32 refid, 689 int len, 690 u_char *extra 691 ) 692 { 693 l_fp now; 694 u_long day; 695 696 if (!stats_control) 697 return; 698 699 get_systime(&now); 700 filegen_setup(&rawstats, now.l_ui); 701 day = now.l_ui / 86400 + MJD_1900; 702 now.l_ui %= 86400; 703 if (rawstats.fp != NULL) { 704 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s", 705 day, ulfptoa(&now, 3), 706 srcadr ? stoa(srcadr) : "-", 707 dstadr ? stoa(dstadr) : "-", 708 ulfptoa(t1, 9), ulfptoa(t2, 9), 709 ulfptoa(t3, 9), ulfptoa(t4, 9), 710 leap, version, mode, stratum, ppoll, precision, 711 root_delay, root_dispersion, refid_str(refid, stratum)); 712 if (len > 0) { 713 int i; 714 715 fprintf(rawstats.fp, " %d: ", len); 716 for (i = 0; i < len; ++i) { 717 fprintf(rawstats.fp, "%02x", extra[i]); 718 } 719 } 720 fprintf(rawstats.fp, "\n"); 721 fflush(rawstats.fp); 722 } 723 } 724 725 726 /* 727 * record_sys_stats - write system statistics to file 728 * 729 * file format 730 * day (MJD) 731 * time (s past midnight) 732 * time since reset 733 * packets recieved 734 * packets for this host 735 * current version 736 * old version 737 * access denied 738 * bad length or format 739 * bad authentication 740 * declined 741 * rate exceeded 742 * KoD sent 743 */ 744 void 745 record_sys_stats(void) 746 { 747 l_fp now; 748 u_long day; 749 750 if (!stats_control) 751 return; 752 753 get_systime(&now); 754 filegen_setup(&sysstats, now.l_ui); 755 day = now.l_ui / 86400 + MJD_1900; 756 now.l_ui %= 86400; 757 if (sysstats.fp != NULL) { 758 fprintf(sysstats.fp, 759 "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 760 day, ulfptoa(&now, 3), current_time - sys_stattime, 761 sys_received, sys_processed, sys_newversion, 762 sys_oldversion, sys_restricted, sys_badlength, 763 sys_badauth, sys_declined, sys_limitrejected, 764 sys_kodsent); 765 fflush(sysstats.fp); 766 proto_clr_stats(); 767 } 768 } 769 770 771 /* 772 * record_proto_stats - write system statistics to file 773 * 774 * file format 775 * day (MJD) 776 * time (s past midnight) 777 * text message 778 */ 779 void 780 record_proto_stats( 781 char *str /* text string */ 782 ) 783 { 784 l_fp now; 785 u_long day; 786 787 if (!stats_control) 788 return; 789 790 get_systime(&now); 791 filegen_setup(&protostats, now.l_ui); 792 day = now.l_ui / 86400 + MJD_1900; 793 now.l_ui %= 86400; 794 if (protostats.fp != NULL) { 795 fprintf(protostats.fp, "%lu %s %s\n", day, 796 ulfptoa(&now, 3), str); 797 fflush(protostats.fp); 798 } 799 } 800 801 802 #ifdef AUTOKEY 803 /* 804 * record_crypto_stats - write crypto statistics to file 805 * 806 * file format: 807 * day (mjd) 808 * time (s past midnight) 809 * peer ip address 810 * text message 811 */ 812 void 813 record_crypto_stats( 814 sockaddr_u *addr, 815 const char *text /* text message */ 816 ) 817 { 818 l_fp now; 819 u_long day; 820 821 if (!stats_control) 822 return; 823 824 get_systime(&now); 825 filegen_setup(&cryptostats, now.l_ui); 826 day = now.l_ui / 86400 + MJD_1900; 827 now.l_ui %= 86400; 828 if (cryptostats.fp != NULL) { 829 if (addr == NULL) 830 fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", 831 day, ulfptoa(&now, 3), text); 832 else 833 fprintf(cryptostats.fp, "%lu %s %s %s\n", 834 day, ulfptoa(&now, 3), stoa(addr), text); 835 fflush(cryptostats.fp); 836 } 837 } 838 #endif /* AUTOKEY */ 839 840 841 #ifdef DEBUG_TIMING 842 /* 843 * record_timing_stats - write timing statistics to file 844 * 845 * file format: 846 * day (mjd) 847 * time (s past midnight) 848 * text message 849 */ 850 void 851 record_timing_stats( 852 const char *text /* text message */ 853 ) 854 { 855 static unsigned int flshcnt; 856 l_fp now; 857 u_long day; 858 859 if (!stats_control) 860 return; 861 862 get_systime(&now); 863 filegen_setup(&timingstats, now.l_ui); 864 day = now.l_ui / 86400 + MJD_1900; 865 now.l_ui %= 86400; 866 if (timingstats.fp != NULL) { 867 fprintf(timingstats.fp, "%lu %s %s\n", day, lfptoa(&now, 868 3), text); 869 if (++flshcnt % 100 == 0) 870 fflush(timingstats.fp); 871 } 872 } 873 #endif 874 875 876 /* 877 * check_leap_file - See if the leapseconds file has been updated. 878 * 879 * Returns: n/a 880 * 881 * Note: This loads a new leapfile on the fly. Currently a leap file 882 * without SHA1 signature is accepted, but if there is a signature line, 883 * the signature must be valid or the file is rejected. 884 */ 885 void 886 check_leap_file( 887 int is_daily_check, 888 uint32_t ntptime , 889 const time_t *systime 890 ) 891 { 892 /* just do nothing if there is no leap file */ 893 if ( ! (leapfile_name && *leapfile_name)) 894 return; 895 896 /* try to load leapfile, force it if no leapfile loaded yet */ 897 if (leapsec_load_file( 898 leapfile_name, &leapfile_stat, 899 !have_leapfile, is_daily_check)) 900 have_leapfile = TRUE; 901 else if (!have_leapfile) 902 return; 903 904 check_leap_expiration(is_daily_check, ntptime, systime); 905 } 906 907 /* 908 * check expiration of a loaded leap table 909 */ 910 static void 911 check_leap_expiration( 912 int is_daily_check, 913 uint32_t ntptime , 914 const time_t *systime 915 ) 916 { 917 static const char * const logPrefix = "leapsecond file"; 918 int rc; 919 920 /* test the expiration of the leap data and log with proper 921 * level and frequency (once/hour or once/day, depending on the 922 * state. 923 */ 924 rc = leapsec_daystolive(ntptime, systime); 925 if (rc == 0) { 926 msyslog(LOG_WARNING, 927 "%s ('%s'): will expire in less than one day", 928 logPrefix, leapfile_name); 929 } else if (is_daily_check && rc < 28) { 930 if (rc < 0) 931 msyslog(LOG_ERR, 932 "%s ('%s'): expired less than %d day%s ago", 933 logPrefix, leapfile_name, -rc, (rc == -1 ? "" : "s")); 934 else 935 msyslog(LOG_WARNING, 936 "%s ('%s'): will expire in less than %d days", 937 logPrefix, leapfile_name, 1+rc); 938 } 939 } 940 941 942 /* 943 * getauthkeys - read the authentication keys from the specified file 944 */ 945 void 946 getauthkeys( 947 const char *keyfile 948 ) 949 { 950 size_t len; 951 952 len = strlen(keyfile); 953 if (!len) 954 return; 955 956 #ifndef SYS_WINNT 957 key_file_name = erealloc(key_file_name, len + 1); 958 memcpy(key_file_name, keyfile, len + 1); 959 #else 960 key_file_name = erealloc(key_file_name, _MAX_PATH); 961 if (len + 1 > _MAX_PATH) 962 return; 963 if (!ExpandEnvironmentStrings(keyfile, key_file_name, 964 _MAX_PATH)) { 965 msyslog(LOG_ERR, 966 "ExpandEnvironmentStrings(KEY_FILE) failed: %m"); 967 strlcpy(key_file_name, keyfile, _MAX_PATH); 968 } 969 key_file_name = erealloc(key_file_name, 970 1 + strlen(key_file_name)); 971 #endif /* SYS_WINNT */ 972 973 authreadkeys(key_file_name); 974 } 975 976 977 /* 978 * rereadkeys - read the authentication key file over again. 979 */ 980 void 981 rereadkeys(void) 982 { 983 if (NULL != key_file_name) 984 authreadkeys(key_file_name); 985 } 986 987 988 #if notyet 989 /* 990 * ntp_exit - document explicitly that ntpd has exited 991 */ 992 void 993 ntp_exit(int retval) 994 { 995 msyslog(LOG_ERR, "EXITING with return code %d", retval); 996 exit(retval); 997 } 998 #endif 999 1000 /* 1001 * fstostr - prettyprint NTP seconds 1002 */ 1003 char * fstostr( 1004 time_t ntp_stamp 1005 ) 1006 { 1007 char * buf; 1008 struct calendar tm; 1009 1010 LIB_GETBUF(buf); 1011 if (ntpcal_ntp_to_date(&tm, (u_int32)ntp_stamp, NULL) < 0) 1012 snprintf(buf, LIB_BUFLENGTH, "ntpcal_ntp_to_date: %ld: range error", 1013 (long)ntp_stamp); 1014 else 1015 snprintf(buf, LIB_BUFLENGTH, "%04d%02d%02d%02d%02d", 1016 tm.year, tm.month, tm.monthday, 1017 tm.hour, tm.minute); 1018 return buf; 1019 } 1020 1021 1022 /* 1023 * ntpd_time_stepped is called back by step_systime(), allowing ntpd 1024 * to do any one-time processing necessitated by the step. 1025 */ 1026 void 1027 ntpd_time_stepped(void) 1028 { 1029 u_int saved_mon_enabled; 1030 1031 /* 1032 * flush the monitor MRU list which contains l_fp timestamps 1033 * which should not be compared across the step. 1034 */ 1035 if (MON_OFF != mon_enabled) { 1036 saved_mon_enabled = mon_enabled; 1037 mon_stop(MON_OFF); 1038 mon_start(saved_mon_enabled); 1039 } 1040 1041 /* inform interpolating Windows code to allow time to go back */ 1042 #ifdef SYS_WINNT 1043 win_time_stepped(); 1044 #endif 1045 } 1046