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