xref: /freebsd/contrib/ntp/ntpd/ntp_util.c (revision 7bd6fde3)
1 /*
2  * ntp_util.c - stuff I didn't have any other place for
3  */
4 
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8 
9 #include "ntpd.h"
10 #include "ntp_io.h"
11 #include "ntp_unixtime.h"
12 #include "ntp_filegen.h"
13 #include "ntp_if.h"
14 #include "ntp_stdlib.h"
15 
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_IOCTL_H
20 # include <sys/ioctl.h>
21 #endif
22 
23 #ifdef HAVE_IEEEFP_H
24 # include <ieeefp.h>
25 #endif
26 #ifdef HAVE_MATH_H
27 # include <math.h>
28 #endif
29 
30 #ifdef  DOSYNCTODR
31 #if !defined(VMS)
32 #include <sys/resource.h>
33 #endif /* VMS */
34 #endif
35 
36 #if defined(VMS)
37 #include <descrip.h>
38 #endif /* VMS */
39 
40 /*
41  * This contains odds and ends.  Right now the only thing you'll find
42  * in here is the hourly stats printer and some code to support
43  * rereading the keys file, but I may eventually put other things in
44  * here such as code to do something with the leap bits.
45  */
46 /*
47  * Name of the keys file
48  */
49 static	char *key_file_name;
50 
51 /*
52  * The name of the drift_comp file and the temporary.
53  */
54 static	char *stats_drift_file;
55 static	char *stats_temp_file;
56 
57 /*
58  * Statistics file stuff
59  */
60 #ifndef NTP_VAR
61 #ifndef SYS_WINNT
62 #define NTP_VAR "/var/NTP/"		/* NOTE the trailing '/' */
63 #else
64 #define NTP_VAR "c:\\var\\ntp\\"		/* NOTE the trailing '\\' */
65 #endif /* SYS_WINNT */
66 #endif
67 
68 #ifndef MAXPATHLEN
69 #define MAXPATHLEN 256
70 #endif
71 
72 static	char statsdir[MAXPATHLEN] = NTP_VAR;
73 
74 static FILEGEN peerstats;
75 static FILEGEN loopstats;
76 static FILEGEN clockstats;
77 static FILEGEN rawstats;
78 static FILEGEN sysstats;
79 #ifdef OPENSSL
80 static FILEGEN cryptostats;
81 #endif /* OPENSSL */
82 
83 /*
84  * This controls whether stats are written to the fileset. Provided
85  * so that ntpdc can turn off stats when the file system fills up.
86  */
87 int stats_control;
88 
89 /*
90  * init_util - initialize the utilities
91  */
92 void
93 init_util(void)
94 {
95 	stats_drift_file = 0;
96 	stats_temp_file = 0;
97 	key_file_name = 0;
98 
99 #define PEERNAME "peerstats"
100 #define LOOPNAME "loopstats"
101 #define CLOCKNAME "clockstats"
102 #define RAWNAME "rawstats"
103 #define STANAME "systats"
104 #ifdef OPENSSL
105 #define CRYPTONAME "cryptostats"
106 #endif /* OPENSSL */
107 
108 	peerstats.fp       = NULL;
109 	peerstats.prefix   = &statsdir[0];
110 	peerstats.basename = (char*)emalloc(strlen(PEERNAME)+1);
111 	strcpy(peerstats.basename, PEERNAME);
112 	peerstats.id       = 0;
113 	peerstats.type     = FILEGEN_DAY;
114 	peerstats.flag     = FGEN_FLAG_LINK; /* not yet enabled !!*/
115 	filegen_register("peerstats", &peerstats);
116 
117 	loopstats.fp       = NULL;
118 	loopstats.prefix   = &statsdir[0];
119 	loopstats.basename = (char*)emalloc(strlen(LOOPNAME)+1);
120 	strcpy(loopstats.basename, LOOPNAME);
121 	loopstats.id       = 0;
122 	loopstats.type     = FILEGEN_DAY;
123 	loopstats.flag     = FGEN_FLAG_LINK; /* not yet enabled !!*/
124 	filegen_register("loopstats", &loopstats);
125 
126 	clockstats.fp      = NULL;
127 	clockstats.prefix  = &statsdir[0];
128 	clockstats.basename = (char*)emalloc(strlen(CLOCKNAME)+1);
129 	strcpy(clockstats.basename, CLOCKNAME);
130 	clockstats.id      = 0;
131 	clockstats.type    = FILEGEN_DAY;
132 	clockstats.flag    = FGEN_FLAG_LINK; /* not yet enabled !!*/
133 	filegen_register("clockstats", &clockstats);
134 
135 	rawstats.fp      = NULL;
136 	rawstats.prefix  = &statsdir[0];
137 	rawstats.basename = (char*)emalloc(strlen(RAWNAME)+1);
138 	strcpy(rawstats.basename, RAWNAME);
139 	rawstats.id      = 0;
140 	rawstats.type    = FILEGEN_DAY;
141 	rawstats.flag    = FGEN_FLAG_LINK; /* not yet enabled !!*/
142 	filegen_register("rawstats", &rawstats);
143 
144 	sysstats.fp      = NULL;
145 	sysstats.prefix  = &statsdir[0];
146 	sysstats.basename = (char*)emalloc(strlen(STANAME)+1);
147 	strcpy(sysstats.basename, STANAME);
148 	sysstats.id      = 0;
149 	sysstats.type    = FILEGEN_DAY;
150 	sysstats.flag    = FGEN_FLAG_LINK; /* not yet enabled !!*/
151 	filegen_register("sysstats", &sysstats);
152 
153 #ifdef OPENSSL
154 	cryptostats.fp	 = NULL;
155 	cryptostats.prefix = &statsdir[0];
156 	cryptostats.basename = (char*)emalloc(strlen(CRYPTONAME)+1);
157 	strcpy(cryptostats.basename, CRYPTONAME);
158 	cryptostats.id	 = 0;
159 	cryptostats.type = FILEGEN_DAY;
160 	cryptostats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/
161 	filegen_register("cryptostats", &cryptostats);
162 #endif /* OPENSSL */
163 
164 #undef PEERNAME
165 #undef LOOPNAME
166 #undef CLOCKNAME
167 #undef RAWNAME
168 #undef STANAME
169 #ifdef OPENSSL
170 #undef CRYPTONAME
171 #endif /* OPENSSL */
172 }
173 
174 
175 /*
176  * hourly_stats - print some interesting stats
177  */
178 void
179 hourly_stats(void)
180 {
181 	FILE *fp;
182 
183 #ifdef DOSYNCTODR
184 	struct timeval tv;
185 #if !defined(VMS)
186 	int prio_set;
187 #endif
188 #ifdef HAVE_GETCLOCK
189         struct timespec ts;
190 #endif
191 	int o_prio;
192 
193 	/*
194 	 * Sometimes having a Sun can be a drag.
195 	 *
196 	 * The kernel variable dosynctodr controls whether the system's
197 	 * soft clock is kept in sync with the battery clock. If it
198 	 * is zero, then the soft clock is not synced, and the battery
199 	 * clock is simply left to rot. That means that when the system
200 	 * reboots, the battery clock (which has probably gone wacky)
201 	 * sets the soft clock. That means ntpd starts off with a very
202 	 * confused idea of what time it is. It then takes a large
203 	 * amount of time to figure out just how wacky the battery clock
204 	 * has made things drift, etc, etc. The solution is to make the
205 	 * battery clock sync up to system time. The way to do THAT is
206 	 * to simply set the time of day to the current time of day, but
207 	 * as quickly as possible. This may, or may not be a sensible
208 	 * thing to do.
209 	 *
210 	 * CAVEAT: settimeofday() steps the sun clock by about 800 us,
211 	 *         so setting DOSYNCTODR seems a bad idea in the
212 	 *         case of us resolution
213 	 */
214 
215 #if !defined(VMS)
216 	/* (prr) getpriority returns -1 on error, but -1 is also a valid
217 	 * return value (!), so instead we have to zero errno before the
218 	 * call and check it for non-zero afterwards.
219 	 */
220 	errno = 0;
221 	prio_set = 0;
222 	o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */
223 
224 	/*
225 	 * (prr) if getpriority succeeded, call setpriority to raise
226 	 * scheduling priority as high as possible.  If that succeeds
227 	 * as well, set the prio_set flag so we remember to reset
228 	 * priority to its previous value below.  Note that on Solaris
229 	 * 2.6 (and beyond?), both getpriority and setpriority will fail
230 	 * with ESRCH, because sched_setscheduler (called from main) put
231 	 * us in the real-time scheduling class which setpriority
232 	 * doesn't know about. Being in the real-time class is better
233 	 * than anything setpriority can do, anyhow, so this error is
234 	 * silently ignored.
235 	 */
236 	if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0))
237 		prio_set = 1;	/* overdrive */
238 #endif /* VMS */
239 #ifdef HAVE_GETCLOCK
240         (void) getclock(TIMEOFDAY, &ts);
241         tv.tv_sec = ts.tv_sec;
242         tv.tv_usec = ts.tv_nsec / 1000;
243 #else /*  not HAVE_GETCLOCK */
244 	GETTIMEOFDAY(&tv,(struct timezone *)NULL);
245 #endif /* not HAVE_GETCLOCK */
246 	if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) {
247 		msyslog(LOG_ERR, "can't sync battery time: %m");
248 	}
249 #if !defined(VMS)
250 	if (prio_set)
251 		setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
252 #endif /* VMS */
253 #endif /* DOSYNCTODR */
254 
255 	NLOG(NLOG_SYSSTATIST)
256 		msyslog(LOG_INFO,
257 		    "offset %.6f sec freq %.3f ppm error %.6f poll %d",
258 		    last_offset, drift_comp * 1e6, sys_jitter,
259 		    sys_poll);
260 
261 
262 	record_sys_stats();
263 	if (stats_drift_file != 0) {
264 		if ((fp = fopen(stats_temp_file, "w")) == NULL) {
265 			msyslog(LOG_ERR, "can't open %s: %m",
266 			    stats_temp_file);
267 			return;
268 		}
269 		fprintf(fp, "%.3f\n", drift_comp * 1e6);
270 		(void)fclose(fp);
271 		/* atomic */
272 #ifdef SYS_WINNT
273 		(void) _unlink(stats_drift_file); /* rename semantics differ under NT */
274 #endif /* SYS_WINNT */
275 
276 #ifndef NO_RENAME
277 		(void) rename(stats_temp_file, stats_drift_file);
278 #else
279         /* we have no rename NFS of ftp in use*/
280 		if ((fp = fopen(stats_drift_file, "w")) == NULL) {
281 			msyslog(LOG_ERR, "can't open %s: %m",
282 			    stats_drift_file);
283 			return;
284 		}
285 
286 #endif
287 
288 #if defined(VMS)
289 		/* PURGE */
290 		{
291 			$DESCRIPTOR(oldvers,";-1");
292 			struct dsc$descriptor driftdsc = {
293 				strlen(stats_drift_file),0,0,stats_drift_file };
294 
295 			while(lib$delete_file(&oldvers,&driftdsc) & 1) ;
296 		}
297 #endif
298 	}
299 }
300 
301 
302 /*
303  * stats_config - configure the stats operation
304  */
305 void
306 stats_config(
307 	int item,
308 	char *invalue	/* only one type so far */
309 	)
310 {
311 	FILE *fp;
312 	char *value;
313 	double old_drift;
314 	int len;
315 
316 	/*
317 	 * Expand environment strings under Windows NT, since the
318 	 * command interpreter doesn't do this, the program must.
319 	 */
320 #ifdef SYS_WINNT
321 	char newvalue[MAX_PATH], parameter[MAX_PATH];
322 
323 	if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
324  		switch(item) {
325 		    case STATS_FREQ_FILE:
326 			strcpy(parameter,"STATS_FREQ_FILE");
327 			break;
328 		    case STATS_STATSDIR:
329 			strcpy(parameter,"STATS_STATSDIR");
330 			break;
331 		    case STATS_PID_FILE:
332 			strcpy(parameter,"STATS_PID_FILE");
333 			break;
334 		    default:
335 			strcpy(parameter,"UNKNOWN");
336 			break;
337 		}
338 		value = invalue;
339 
340 		msyslog(LOG_ERR,
341 		    "ExpandEnvironmentStrings(%s) failed: %m\n", parameter);
342 	} else {
343 		value = newvalue;
344 	}
345 #else
346 	value = invalue;
347 #endif /* SYS_WINNT */
348 
349 	switch(item) {
350 	    case STATS_FREQ_FILE:
351 		if (stats_drift_file != 0) {
352 			(void) free(stats_drift_file);
353 			(void) free(stats_temp_file);
354 			stats_drift_file = 0;
355 			stats_temp_file = 0;
356 		}
357 
358 		if (value == 0 || (len = strlen(value)) == 0)
359 		    break;
360 
361 		stats_drift_file = (char*)emalloc((u_int)(len + 1));
362 #if !defined(VMS)
363 		stats_temp_file = (char*)emalloc((u_int)(len +
364 		    sizeof(".TEMP")));
365 #else
366 		stats_temp_file = (char*)emalloc((u_int)(len +
367 		    sizeof("-TEMP")));
368 #endif /* VMS */
369 		memmove(stats_drift_file, value, (unsigned)(len+1));
370 		memmove(stats_temp_file, value, (unsigned)len);
371 #if !defined(VMS)
372 		memmove(stats_temp_file + len, ".TEMP",
373 		    sizeof(".TEMP"));
374 #else
375 		memmove(stats_temp_file + len, "-TEMP",
376 		    sizeof("-TEMP"));
377 #endif /* VMS */
378 
379 		/*
380 		 * Open drift file and read frequency. If the file is
381 		 * missing or contains errors, tell the loop to reset.
382 		 */
383 		if ((fp = fopen(stats_drift_file, "r")) == NULL) {
384 			loop_config(LOOP_DRIFTCOMP, 1e9);
385 			break;
386 		}
387 		if (fscanf(fp, "%lf", &old_drift) != 1) {
388 			msyslog(LOG_ERR, "Frequency format error in %s",
389 			    stats_drift_file);
390 			loop_config(LOOP_DRIFTCOMP, 1e9);
391 			fclose(fp);
392 			break;
393 		}
394 		fclose(fp);
395 		msyslog(LOG_INFO,
396 		    "frequency initialized %.3f PPM from %s",
397 			old_drift, stats_drift_file);
398 		loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
399 		break;
400 
401 	    case STATS_STATSDIR:
402 		if (strlen(value) >= sizeof(statsdir)) {
403 			msyslog(LOG_ERR,
404 			    "value for statsdir too long (>%d, sigh)",
405 			    (int)sizeof(statsdir)-1);
406 		} else {
407 			l_fp now;
408 
409 			get_systime(&now);
410 			strcpy(statsdir,value);
411 			if(peerstats.prefix == &statsdir[0] &&
412 			    peerstats.fp != NULL) {
413 				fclose(peerstats.fp);
414 				peerstats.fp = NULL;
415 				filegen_setup(&peerstats, now.l_ui);
416 			}
417 			if(loopstats.prefix == &statsdir[0] &&
418 			    loopstats.fp != NULL) {
419 				fclose(loopstats.fp);
420 				loopstats.fp = NULL;
421 				filegen_setup(&loopstats, now.l_ui);
422 			}
423 			if(clockstats.prefix == &statsdir[0] &&
424 			    clockstats.fp != NULL) {
425 				fclose(clockstats.fp);
426 				clockstats.fp = NULL;
427 				filegen_setup(&clockstats, now.l_ui);
428 			}
429 			if(rawstats.prefix == &statsdir[0] &&
430 			    rawstats.fp != NULL) {
431 				fclose(rawstats.fp);
432 				rawstats.fp = NULL;
433 				filegen_setup(&rawstats, now.l_ui);
434 			}
435 			if(sysstats.prefix == &statsdir[0] &&
436 			    sysstats.fp != NULL) {
437 				fclose(sysstats.fp);
438 				sysstats.fp = NULL;
439 				filegen_setup(&sysstats, now.l_ui);
440 			}
441 #ifdef OPENSSL
442 			if(cryptostats.prefix == &statsdir[0] &&
443 			    cryptostats.fp != NULL) {
444 				fclose(cryptostats.fp);
445 				cryptostats.fp = NULL;
446 				filegen_setup(&cryptostats, now.l_ui);
447 			}
448 #endif /* OPENSSL */
449 		}
450 		break;
451 
452 	    case STATS_PID_FILE:
453 		if ((fp = fopen(value, "w")) == NULL) {
454 			msyslog(LOG_ERR, "Can't open %s: %m", value);
455 			break;
456 		}
457 		fprintf(fp, "%d", (int) getpid());
458 		fclose(fp);;
459 		break;
460 
461 	    default:
462 		/* oh well */
463 		break;
464 	}
465 }
466 
467 /*
468  * record_peer_stats - write peer statistics to file
469  *
470  * file format:
471  * day (mjd)
472  * time (s past UTC midnight)
473  * peer (ip address)
474  * peer status word (hex)
475  * peer offset (s)
476  * peer delay (s)
477  * peer error bound (s)
478  * peer error (s)
479 */
480 void
481 record_peer_stats(
482 	struct sockaddr_storage *addr,
483 	int	status,
484 	double	offset,
485 	double	delay,
486 	double	dispersion,
487 	double	skew
488 	)
489 {
490 	l_fp	now;
491 	u_long	day;
492 
493 	if (!stats_control)
494 		return;
495 
496 	get_systime(&now);
497 	filegen_setup(&peerstats, now.l_ui);
498 	day = now.l_ui / 86400 + MJD_1900;
499 	now.l_ui %= 86400;
500 	if (peerstats.fp != NULL) {
501 		fprintf(peerstats.fp,
502 		    "%lu %s %s %x %.9f %.9f %.9f %.9f\n",
503 		    day, ulfptoa(&now, 3), stoa(addr), status, offset,
504 		    delay, dispersion, skew);
505 		fflush(peerstats.fp);
506 	}
507 }
508 /*
509  * record_loop_stats - write loop filter statistics to file
510  *
511  * file format:
512  * day (mjd)
513  * time (s past midnight)
514  * offset (s)
515  * frequency (approx ppm)
516  * time constant (log base 2)
517  */
518 void
519 record_loop_stats(
520 	double	offset,
521 	double	freq,
522 	double	jitter,
523 	double	stability,
524 	int spoll
525 	)
526 {
527 	l_fp	now;
528 	u_long	day;
529 
530 	if (!stats_control)
531 		return;
532 
533 	get_systime(&now);
534 	filegen_setup(&loopstats, now.l_ui);
535 	day = now.l_ui / 86400 + MJD_1900;
536 	now.l_ui %= 86400;
537 	if (loopstats.fp != NULL) {
538 		fprintf(loopstats.fp, "%lu %s %.9f %.6f %.9f %.6f %d\n",
539 		    day, ulfptoa(&now, 3), offset, freq * 1e6, jitter,
540 		    stability * 1e6, spoll);
541 		fflush(loopstats.fp);
542 	}
543 }
544 
545 /*
546  * record_clock_stats - write clock statistics to file
547  *
548  * file format:
549  * day (mjd)
550  * time (s past midnight)
551  * peer (ip address)
552  * text message
553  */
554 void
555 record_clock_stats(
556 	struct sockaddr_storage *addr,
557 	const char *text
558 	)
559 {
560 	l_fp	now;
561 	u_long	day;
562 
563 	if (!stats_control)
564 		return;
565 
566 	get_systime(&now);
567 	filegen_setup(&clockstats, now.l_ui);
568 	day = now.l_ui / 86400 + MJD_1900;
569 	now.l_ui %= 86400;
570 	if (clockstats.fp != NULL) {
571 		fprintf(clockstats.fp, "%lu %s %s %s\n",
572 		    day, ulfptoa(&now, 3), stoa(addr), text);
573 		fflush(clockstats.fp);
574 	}
575 }
576 
577 /*
578  * record_raw_stats - write raw timestamps to file
579  *
580  *
581  * file format
582  * time (s past midnight)
583  * peer ip address
584  * local ip address
585  * t1 t2 t3 t4 timestamps
586  */
587 void
588 record_raw_stats(
589         struct sockaddr_storage *srcadr,
590         struct sockaddr_storage *dstadr,
591 	l_fp	*t1,
592 	l_fp	*t2,
593 	l_fp	*t3,
594 	l_fp	*t4
595 	)
596 {
597 	l_fp	now;
598 	u_long	day;
599 
600 	if (!stats_control)
601 		return;
602 
603 	get_systime(&now);
604 	filegen_setup(&rawstats, now.l_ui);
605 	day = now.l_ui / 86400 + MJD_1900;
606 	now.l_ui %= 86400;
607 	if (rawstats.fp != NULL) {
608                 fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n",
609 		    day, ulfptoa(&now, 3), stoa(srcadr), stoa(dstadr),
610 		    ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9),
611 		    ulfptoa(t4, 9));
612 		fflush(rawstats.fp);
613 	}
614 }
615 
616 
617 /*
618  * record_sys_stats - write system statistics to file
619  *
620  * file format
621  * time (s past midnight)
622  * time since startup (hr)
623  * packets recieved
624  * packets processed
625  * current version
626  * previous version
627  * bad version
628  * access denied
629  * bad length or format
630  * bad authentication
631  * rate exceeded
632  */
633 void
634 record_sys_stats(void)
635 {
636 	l_fp	now;
637 	u_long	day;
638 
639 	if (!stats_control)
640 		return;
641 
642 	get_systime(&now);
643 	filegen_setup(&sysstats, now.l_ui);
644 	day = now.l_ui / 86400 + MJD_1900;
645 	now.l_ui %= 86400;
646 	if (sysstats.fp != NULL) {
647                 fprintf(sysstats.fp,
648 		    "%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
649 		    day, ulfptoa(&now, 3), sys_stattime / 3600,
650 		    sys_received, sys_processed, sys_newversionpkt,
651 		    sys_oldversionpkt, sys_unknownversion,
652 		    sys_restricted, sys_badlength, sys_badauth,
653 		    sys_limitrejected);
654 		fflush(sysstats.fp);
655 		proto_clr_stats();
656 	}
657 }
658 
659 
660 #ifdef OPENSSL
661 /*
662  * record_crypto_stats - write crypto statistics to file
663  *
664  * file format:
665  * day (mjd)
666  * time (s past midnight)
667  * peer (ip address)
668  * text message
669  */
670 void
671 record_crypto_stats(
672 	struct sockaddr_storage *addr,
673 	const char *text
674 	)
675 {
676 	l_fp	now;
677 	u_long	day;
678 
679 	if (!stats_control)
680 		return;
681 
682 	get_systime(&now);
683 	filegen_setup(&cryptostats, now.l_ui);
684 	day = now.l_ui / 86400 + MJD_1900;
685 	now.l_ui %= 86400;
686 	if (cryptostats.fp != NULL) {
687 		if (addr == NULL)
688 			fprintf(cryptostats.fp, "%lu %s %s\n",
689 			    day, ulfptoa(&now, 3), text);
690 		else
691 			fprintf(cryptostats.fp, "%lu %s %s %s\n",
692 			    day, ulfptoa(&now, 3), stoa(addr), text);
693 		fflush(cryptostats.fp);
694 	}
695 }
696 #endif /* OPENSSL */
697 
698 
699 /*
700  * getauthkeys - read the authentication keys from the specified file
701  */
702 void
703 getauthkeys(
704 	char *keyfile
705 	)
706 {
707 	int len;
708 
709 	len = strlen(keyfile);
710 	if (len == 0)
711 		return;
712 
713 	if (key_file_name != 0) {
714 		if (len > (int)strlen(key_file_name)) {
715 			(void) free(key_file_name);
716 			key_file_name = 0;
717 		}
718 	}
719 
720 	if (key_file_name == 0) {
721 #ifndef SYS_WINNT
722 		key_file_name = (char*)emalloc((u_int) (len + 1));
723 #else
724 		key_file_name = (char*)emalloc((u_int)  (MAXPATHLEN));
725 #endif
726 	}
727 #ifndef SYS_WINNT
728  	memmove(key_file_name, keyfile, (unsigned)(len+1));
729 #else
730 	if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN))
731 	{
732 		msyslog(LOG_ERR,
733 		    "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n");
734 	}
735 #endif /* SYS_WINNT */
736 
737 	authreadkeys(key_file_name);
738 }
739 
740 
741 /*
742  * rereadkeys - read the authentication key file over again.
743  */
744 void
745 rereadkeys(void)
746 {
747 	if (key_file_name != 0)
748 	    authreadkeys(key_file_name);
749 }
750 
751 /*
752  * sock_hash - hash an sockaddr_storage structure
753  */
754 int
755 sock_hash(
756 	struct sockaddr_storage *addr
757 	)
758 {
759 	int hashVal;
760 	int i;
761 	int len;
762 	char *ch;
763 
764 	hashVal = 0;
765 	len = 0;
766 	/*
767 	 * We can't just hash the whole thing because there are hidden
768 	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
769 	 * so just use the family, port and address.
770 	 */
771 	ch = (char *)&addr->ss_family;
772 	hashVal = 37 * hashVal + (int)*ch;
773 	if (sizeof(addr->ss_family) > 1) {
774 		ch++;
775 		hashVal = 37 * hashVal + (int)*ch;
776 	}
777 	switch(addr->ss_family) {
778 	case AF_INET:
779 		ch = (char *)&((struct sockaddr_in *)addr)->sin_addr;
780 		len = sizeof(struct in_addr);
781 		break;
782 	case AF_INET6:
783 		ch = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr;
784 		len = sizeof(struct in6_addr);
785 		break;
786 	}
787 
788 	for (i = 0; i < len ; i++)
789 		hashVal = 37 * hashVal + (int)*(ch + i);
790 
791 	hashVal = hashVal % 128;  /* % MON_HASH_SIZE hardcoded */
792 
793 	if (hashVal < 0)
794 		hashVal += 128;
795 
796 	return hashVal;
797 }
798