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