]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/ntp_util.c
Fix multiple denial of service in ntpd.
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / ntp_util.c
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 }