1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1985, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1985, 1993\n\
35 The Regents of the University of California. All rights reserved.\n";
36 #endif /* not lint */
37
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";
41 #endif /* not lint */
42 #endif
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include "globals.h"
48 #include <net/if.h>
49 #include <sys/file.h>
50 #include <sys/ioctl.h>
51 #include <setjmp.h>
52 #include "pathnames.h"
53 #include <math.h>
54 #include <sys/types.h>
55 #include <sys/times.h>
56
57 int trace = 0;
58 int sock, sock_raw = -1;
59 int status = 0;
60 u_short sequence; /* sequence number */
61 long delay1;
62 long delay2;
63
64 int nslavenets; /* nets were I could be a slave */
65 int nmasternets; /* nets were I could be a master */
66 int nignorednets; /* ignored nets */
67 int nnets; /* nets I am connected to */
68
69 FILE *fd; /* trace file FD */
70
71 jmp_buf jmpenv;
72
73 struct netinfo *nettab = NULL;
74 struct netinfo *slavenet;
75 int Mflag;
76 int justquit = 0;
77 int debug;
78
79 static struct nets {
80 char *name;
81 long net;
82 struct nets *next;
83 } *nets = NULL;
84
85 struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
86
87 static struct goodhost { /* hosts that we trust */
88 char name[MAXHOSTNAMELEN];
89 struct goodhost *next;
90 char perm;
91 } *goodhosts;
92
93 static char *goodgroup; /* net group of trusted hosts */
94 static void checkignorednets(void);
95 static void pickslavenet(struct netinfo *);
96 static void add_good_host(char *, int);
97 static void usage(void);
98
99 /*
100 * The timedaemons synchronize the clocks of hosts in a local area network.
101 * One daemon runs as master, all the others as slaves. The master
102 * performs the task of computing clock differences and sends correction
103 * values to the slaves.
104 * Slaves start an election to choose a new master when the latter disappears
105 * because of a machine crash, network partition, or when killed.
106 * A resolution protocol is used to kill all but one of the masters
107 * that happen to exist in segments of a partitioned network when the
108 * network partition is fixed.
109 *
110 * Authors: Riccardo Gusella & Stefano Zatti
111 *
112 * overhauled at Silicon Graphics
113 */
114 int
main(int argc,char * argv[])115 main(int argc, char *argv[])
116 {
117 int on;
118 int ret;
119 int nflag, iflag;
120 struct timeval ntime;
121 struct servent *srvp;
122 char buf[BUFSIZ], *cp, *cplim;
123 struct ifconf ifc;
124 struct ifreq ifreq, ifreqf, *ifr;
125 register struct netinfo *ntp;
126 struct netinfo *ntip;
127 struct netinfo *savefromnet;
128 struct netent *nentp;
129 struct nets *nt;
130 struct sockaddr_in server;
131 u_short port;
132 int c;
133
134 #ifdef lint
135 ntip = NULL;
136 #endif
137
138 on = 1;
139 nflag = OFF;
140 iflag = OFF;
141
142
143 opterr = 0;
144 while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
145 switch (c) {
146 case 'M':
147 Mflag = 1;
148 break;
149
150 case 't':
151 trace = 1;
152 break;
153
154 case 'n':
155 if (iflag) {
156 errx(1, "-i and -n make no sense together");
157 } else {
158 nflag = ON;
159 addnetname(optarg);
160 }
161 break;
162
163 case 'i':
164 if (nflag) {
165 errx(1, "-i and -n make no sense together");
166 } else {
167 iflag = ON;
168 addnetname(optarg);
169 }
170 break;
171
172 case 'F':
173 add_good_host(optarg,1);
174 while (optind < argc && argv[optind][0] != '-')
175 add_good_host(argv[optind++], 1);
176 break;
177
178 case 'd':
179 debug = 1;
180 break;
181 case 'G':
182 if (goodgroup != NULL)
183 errx(1, "only one net group");
184 goodgroup = optarg;
185 break;
186
187 default:
188 usage();
189 break;
190 }
191 }
192 if (optind < argc)
193 usage();
194
195 /* If we care about which machine is the master, then we must
196 * be willing to be a master
197 */
198 if (goodgroup != NULL || goodhosts != NULL)
199 Mflag = 1;
200
201 if (gethostname(hostname, sizeof(hostname) - 1) < 0)
202 err(1, "gethostname");
203 self.l_bak = &self;
204 self.l_fwd = &self;
205 self.h_bak = &self;
206 self.h_fwd = &self;
207 self.head = 1;
208 self.good = 1;
209
210 if (goodhosts != NULL) /* trust ourself */
211 add_good_host(hostname,1);
212
213 srvp = getservbyname("timed", "udp");
214 if (srvp == NULL)
215 errx(1, "timed/udp: unknown service");
216 port = srvp->s_port;
217 bzero(&server, sizeof(struct sockaddr_in));
218 server.sin_port = srvp->s_port;
219 server.sin_family = AF_INET;
220 sock = socket(AF_INET, SOCK_DGRAM, 0);
221 if (sock < 0)
222 err(1, "socket");
223 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
224 sizeof(on)) < 0)
225 err(1, "setsockopt");
226 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
227 if (errno == EADDRINUSE)
228 warnx("time daemon already running");
229 else
230 warn("bind");
231 exit(1);
232 }
233
234 sequence = arc4random(); /* initial seq number */
235
236 (void)gettimeofday(&ntime, NULL);
237 /* rounds kernel variable time to multiple of 5 ms. */
238 ntime.tv_sec = 0;
239 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
240 (void)adjtime(&ntime, (struct timeval *)0);
241
242 for (nt = nets; nt; nt = nt->next) {
243 nentp = getnetbyname(nt->name);
244 if (nentp == NULL) {
245 nt->net = inet_network(nt->name);
246 if (nt->net != INADDR_NONE)
247 nentp = getnetbyaddr(nt->net, AF_INET);
248 }
249 if (nentp != NULL) {
250 nt->net = nentp->n_net;
251 } else if (nt->net == INADDR_NONE) {
252 errx(1, "unknown net %s", nt->name);
253 } else if (nt->net == INADDR_ANY) {
254 errx(1, "bad net %s", nt->name);
255 } else {
256 warnx("warning: %s unknown in /etc/networks",
257 nt->name);
258 }
259
260 if (0 == (nt->net & 0xff000000))
261 nt->net <<= 8;
262 if (0 == (nt->net & 0xff000000))
263 nt->net <<= 8;
264 if (0 == (nt->net & 0xff000000))
265 nt->net <<= 8;
266 }
267 ifc.ifc_len = sizeof(buf);
268 ifc.ifc_buf = buf;
269 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
270 err(1, "get interface configuration");
271 ntp = NULL;
272 #define size(p) max((p).sa_len, sizeof(p))
273 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
274 for (cp = buf; cp < cplim;
275 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
276 ifr = (struct ifreq *)cp;
277 if (ifr->ifr_addr.sa_family != AF_INET)
278 continue;
279 if (!ntp)
280 ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
281 bzero(ntp,sizeof(*ntp));
282 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
283 ntp->status = NOMASTER;
284 ifreq = *ifr;
285 ifreqf = *ifr;
286
287 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
288 warn("get interface flags");
289 continue;
290 }
291 if ((ifreqf.ifr_flags & IFF_UP) == 0)
292 continue;
293 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
294 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
295 continue;
296 }
297
298
299 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
300 warn("get netmask");
301 continue;
302 }
303 ntp->mask = ((struct sockaddr_in *)
304 &ifreq.ifr_addr)->sin_addr.s_addr;
305
306 if (ifreqf.ifr_flags & IFF_BROADCAST) {
307 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
308 warn("get broadaddr");
309 continue;
310 }
311 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
312 /* What if the broadcast address is all ones?
313 * So we cannot just mask ntp->dest_addr. */
314 ntp->net = ntp->my_addr;
315 ntp->net.s_addr &= ntp->mask;
316 } else {
317 if (ioctl(sock, SIOCGIFDSTADDR,
318 (char *)&ifreq) < 0) {
319 warn("get destaddr");
320 continue;
321 }
322 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
323 ntp->net = ntp->dest_addr.sin_addr;
324 }
325
326 ntp->dest_addr.sin_port = port;
327
328 for (nt = nets; nt; nt = nt->next) {
329 if (ntp->net.s_addr == htonl(nt->net))
330 break;
331 }
332 if ((nflag && !nt) || (iflag && nt))
333 continue;
334
335 ntp->next = NULL;
336 if (nettab == NULL) {
337 nettab = ntp;
338 } else {
339 ntip->next = ntp;
340 }
341 ntip = ntp;
342 ntp = NULL;
343 }
344 if (ntp)
345 (void) free((char *)ntp);
346 if (nettab == NULL)
347 errx(1, "no network usable");
348
349 /* microseconds to delay before responding to a broadcast */
350 delay1 = casual(1, 100*1000);
351
352 /* election timer delay in secs. */
353 delay2 = casual(MINTOUT, MAXTOUT);
354
355 if (!debug)
356 daemon(debug, 0);
357
358 if (trace)
359 traceon();
360 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
361
362 /*
363 * keep returning here
364 */
365 ret = setjmp(jmpenv);
366 savefromnet = fromnet;
367 setstatus();
368
369 if (Mflag) {
370 switch (ret) {
371
372 case 0:
373 checkignorednets();
374 pickslavenet(0);
375 break;
376 case 1:
377 /* Just lost our master */
378 if (slavenet != NULL)
379 slavenet->status = election(slavenet);
380 if (!slavenet || slavenet->status == MASTER) {
381 checkignorednets();
382 pickslavenet(0);
383 } else {
384 makeslave(slavenet); /* prune extras */
385 }
386 break;
387
388 case 2:
389 /* Just been told to quit */
390 justquit = 1;
391 pickslavenet(savefromnet);
392 break;
393 }
394
395 setstatus();
396 if (!(status & MASTER) && sock_raw != -1) {
397 /* sock_raw is not being used now */
398 (void)close(sock_raw);
399 sock_raw = -1;
400 }
401
402 if (status == MASTER)
403 master();
404 else
405 slave();
406
407 } else {
408 if (sock_raw != -1) {
409 (void)close(sock_raw);
410 sock_raw = -1;
411 }
412
413 if (ret) {
414 /* we just lost our master or were told to quit */
415 justquit = 1;
416 }
417 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
418 if (ntp->status == MASTER) {
419 rmnetmachs(ntp);
420 ntp->status = NOMASTER;
421 }
422 }
423 checkignorednets();
424 pickslavenet(0);
425 setstatus();
426
427 slave();
428 }
429 /* NOTREACHED */
430 return(0);
431 }
432
433 static void
usage(void)434 usage(void)
435 {
436 #ifdef HAVENIS
437 fprintf(stderr,
438 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
439 #else
440 fprintf(stderr,
441 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
442 #endif /* HAVENIS */
443 exit(1);
444 }
445
446 /*
447 * suppress an upstart, untrustworthy, self-appointed master
448 */
449 void
suppress(struct sockaddr_in * addr,char * name,struct netinfo * net)450 suppress(struct sockaddr_in *addr, char *name, struct netinfo *net)
451 {
452 struct sockaddr_in tgt;
453 char tname[MAXHOSTNAMELEN];
454 struct tsp msg;
455 static struct timeval wait;
456
457 if (trace)
458 fprintf(fd, "suppress: %s\n", name);
459 tgt = *addr;
460 (void)strlcpy(tname, name, sizeof(tname));
461
462 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
463 if (trace)
464 fprintf(fd, "suppress:\tdiscarded packet from %s\n",
465 name);
466 }
467
468 syslog(LOG_NOTICE, "suppressing false master %s", tname);
469 msg.tsp_type = TSP_QUIT;
470 (void)strcpy(msg.tsp_name, hostname);
471 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
472 }
473
474 void
lookformaster(struct netinfo * ntp)475 lookformaster(struct netinfo *ntp)
476 {
477 struct tsp resp, conflict, *answer;
478 struct timeval ntime;
479 char mastername[MAXHOSTNAMELEN];
480 struct sockaddr_in masteraddr;
481
482 get_goodgroup(0);
483 ntp->status = SLAVE;
484
485 /* look for master */
486 resp.tsp_type = TSP_MASTERREQ;
487 (void)strcpy(resp.tsp_name, hostname);
488 answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
489 TSP_MASTERACK, ntp, 0);
490 if (answer != NULL && !good_host_name(answer->tsp_name)) {
491 suppress(&from, answer->tsp_name, ntp);
492 ntp->status = NOMASTER;
493 answer = NULL;
494 }
495 if (answer == NULL) {
496 /*
497 * Various conditions can cause conflict: races between
498 * two just started timedaemons when no master is
499 * present, or timedaemons started during an election.
500 * A conservative approach is taken. Give up and became a
501 * slave, postponing election of a master until first
502 * timer expires.
503 */
504 ntime.tv_sec = ntime.tv_usec = 0;
505 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
506 if (answer != NULL) {
507 if (!good_host_name(answer->tsp_name)) {
508 suppress(&from, answer->tsp_name, ntp);
509 ntp->status = NOMASTER;
510 }
511 return;
512 }
513
514 ntime.tv_sec = ntime.tv_usec = 0;
515 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
516 if (answer != NULL) {
517 if (!good_host_name(answer->tsp_name)) {
518 suppress(&from, answer->tsp_name, ntp);
519 ntp->status = NOMASTER;
520 }
521 return;
522 }
523
524 ntime.tv_sec = ntime.tv_usec = 0;
525 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
526 if (answer != NULL) {
527 if (!good_host_name(answer->tsp_name)) {
528 suppress(&from, answer->tsp_name, ntp);
529 ntp->status = NOMASTER;
530 }
531 return;
532 }
533
534 if (Mflag)
535 ntp->status = MASTER;
536 else
537 ntp->status = NOMASTER;
538 return;
539 }
540
541 ntp->status = SLAVE;
542 (void)strcpy(mastername, answer->tsp_name);
543 masteraddr = from;
544
545 /*
546 * If network has been partitioned, there might be other
547 * masters; tell the one we have just acknowledged that
548 * it has to gain control over the others.
549 */
550 ntime.tv_sec = 0;
551 ntime.tv_usec = 300000;
552 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
553 /*
554 * checking also not to send CONFLICT to ack'ed master
555 * due to duplicated MASTERACKs
556 */
557 if (answer != NULL &&
558 strcmp(answer->tsp_name, mastername) != 0) {
559 conflict.tsp_type = TSP_CONFLICT;
560 (void)strcpy(conflict.tsp_name, hostname);
561 if (!acksend(&conflict, &masteraddr, mastername,
562 TSP_ACK, 0, 0)) {
563 syslog(LOG_ERR,
564 "error on sending TSP_CONFLICT");
565 }
566 }
567 }
568
569 /*
570 * based on the current network configuration, set the status, and count
571 * networks;
572 */
573 void
setstatus(void)574 setstatus(void)
575 {
576 struct netinfo *ntp;
577
578 status = 0;
579 nmasternets = nslavenets = nnets = nignorednets = 0;
580 if (trace)
581 fprintf(fd, "Net status:\n");
582 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
583 switch ((int)ntp->status) {
584 case MASTER:
585 nmasternets++;
586 break;
587 case SLAVE:
588 nslavenets++;
589 break;
590 case NOMASTER:
591 case IGNORE:
592 nignorednets++;
593 break;
594 }
595 if (trace) {
596 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
597 switch ((int)ntp->status) {
598 case NOMASTER:
599 fprintf(fd, "NOMASTER\n");
600 break;
601 case MASTER:
602 fprintf(fd, "MASTER\n");
603 break;
604 case SLAVE:
605 fprintf(fd, "SLAVE\n");
606 break;
607 case IGNORE:
608 fprintf(fd, "IGNORE\n");
609 break;
610 default:
611 fprintf(fd, "invalid state %d\n",
612 (int)ntp->status);
613 break;
614 }
615 }
616 nnets++;
617 status |= ntp->status;
618 }
619 status &= ~IGNORE;
620 if (trace)
621 fprintf(fd,
622 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
623 nnets, nmasternets, nslavenets, nignorednets, delay2);
624 }
625
626 void
makeslave(struct netinfo * net)627 makeslave(struct netinfo *net)
628 {
629 register struct netinfo *ntp;
630
631 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
632 if (ntp->status == SLAVE && ntp != net)
633 ntp->status = IGNORE;
634 }
635 slavenet = net;
636 }
637
638 /*
639 * Try to become master over ignored nets..
640 */
641 static void
checkignorednets(void)642 checkignorednets(void)
643 {
644 register struct netinfo *ntp;
645
646 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
647 if (!Mflag && ntp->status == SLAVE)
648 break;
649
650 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
651 lookformaster(ntp);
652 if (!Mflag && ntp->status == SLAVE)
653 break;
654 }
655 }
656 }
657
658 /*
659 * choose a good network on which to be a slave
660 * The ignored networks must have already been checked.
661 * Take a hint about for a good network.
662 */
663 static void
pickslavenet(struct netinfo * ntp)664 pickslavenet(struct netinfo *ntp)
665 {
666 if (slavenet != NULL && slavenet->status == SLAVE) {
667 makeslave(slavenet); /* prune extras */
668 return;
669 }
670
671 if (ntp == NULL || ntp->status != SLAVE) {
672 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
673 if (ntp->status == SLAVE)
674 break;
675 }
676 }
677 makeslave(ntp);
678 }
679
680 /*
681 * returns a random number in the range [inf, sup]
682 */
683 long
casual(long inf,long sup)684 casual(long inf, long sup)
685 {
686 double value;
687
688 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
689 return(inf + (sup - inf)*value);
690 }
691
692 char *
date(void)693 date(void)
694 {
695 time_t tv_sec;
696
697 tv_sec = time(NULL);
698 return (ctime(&tv_sec));
699 }
700
701 void
addnetname(char * name)702 addnetname(char *name)
703 {
704 register struct nets **netlist = &nets;
705
706 while (*netlist)
707 netlist = &((*netlist)->next);
708 *netlist = (struct nets *)malloc(sizeof **netlist);
709 if (*netlist == NULL)
710 errx(1, "malloc failed");
711 bzero((char *)*netlist, sizeof(**netlist));
712 (*netlist)->name = name;
713 }
714
715 /* note a host as trustworthy
716 * perm 1=not part of the netgroup
717 */
718 static void
add_good_host(char * name,int perm)719 add_good_host(char *name, int perm)
720 {
721 register struct goodhost *ghp;
722 register struct hostent *hentp;
723
724 ghp = (struct goodhost*)malloc(sizeof(*ghp));
725 if (!ghp) {
726 syslog(LOG_ERR, "malloc failed");
727 exit(1);
728 }
729
730 bzero((char*)ghp, sizeof(*ghp));
731 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
732 ghp->next = goodhosts;
733 ghp->perm = perm;
734 goodhosts = ghp;
735
736 hentp = gethostbyname(name);
737 if (hentp == NULL && perm)
738 warnx("unknown host %s", name);
739 }
740
741
742 /* update our image of the net-group of trustworthy hosts
743 */
744 void
get_goodgroup(int force)745 get_goodgroup(int force)
746 {
747 # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
748 static unsigned long last_update = -NG_DELAY;
749 unsigned long new_update;
750 struct goodhost *ghp, **ghpp;
751 #ifdef HAVENIS
752 struct hosttbl *htp;
753 char *mach, *usr, *dom;
754 #endif /* HAVENIS */
755 struct tms tm;
756
757
758 /* if no netgroup, then we are finished */
759 if (goodgroup == NULL || !Mflag)
760 return;
761
762 /* Do not chatter with the netgroup master too often.
763 */
764 new_update = times(&tm);
765 if (new_update < last_update + NG_DELAY
766 && !force)
767 return;
768 last_update = new_update;
769
770 /* forget the old temporary entries */
771 ghpp = &goodhosts;
772 while ((ghp = *ghpp) != NULL) {
773 if (!ghp->perm) {
774 *ghpp = ghp->next;
775 free(ghp);
776 } else {
777 ghpp = &ghp->next;
778 }
779 }
780
781 #ifdef HAVENIS
782 /* quit now if we are not one of the trusted masters
783 */
784 if (!innetgr(goodgroup, &hostname[0], 0,0)) {
785 if (trace)
786 (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
787 &hostname[0], goodgroup);
788 return;
789 }
790 if (trace)
791 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
792 &hostname[0], goodgroup);
793
794 /* mark the entire netgroup as trusted */
795 (void)setnetgrent(goodgroup);
796 while (getnetgrent(&mach,&usr,&dom)) {
797 if (mach != NULL)
798 add_good_host(mach,0);
799 }
800 (void)endnetgrent();
801
802 /* update list of slaves */
803 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
804 htp->good = good_host_name(&htp->name[0]);
805 }
806 #endif /* HAVENIS */
807 }
808
809
810 /* see if a machine is trustworthy
811 */
812 int /* 1=trust hp to change our date */
good_host_name(char * name)813 good_host_name(char *name)
814 {
815 register struct goodhost *ghp = goodhosts;
816 register char c;
817
818 if (!ghp || !Mflag) /* trust everyone if no one named */
819 return 1;
820
821 c = *name;
822 do {
823 if (c == ghp->name[0]
824 && !strcasecmp(name, ghp->name))
825 return 1; /* found him, so say so */
826 } while ((ghp = ghp->next) != NULL);
827
828 if (!strcasecmp(name,hostname)) /* trust ourself */
829 return 1;
830
831 return 0; /* did not find him */
832 }
833