]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/timed/timed/timed.c
- Set CF physical address base in sysinfo structure
[FreeBSD/FreeBSD.git] / usr.sbin / timed / timed / timed.c
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 = 0;
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 = 0;
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
113 main(argc, argv)
114         int argc;
115         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 != 0)
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 (0 != goodgroup || 0 != goodhosts)
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 != 0)             /* trust ourself */
211                 add_good_host(hostname,1);
212
213         srvp = getservbyname("timed", "udp");
214         if (srvp == 0)
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         /* choose a unique seed for random number generation */
235         (void)gettimeofday(&ntime, 0);
236         srandom(ntime.tv_sec + ntime.tv_usec);
237
238         sequence = random();     /* initial seq number */
239
240         /* rounds kernel variable time to multiple of 5 ms. */
241         ntime.tv_sec = 0;
242         ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
243         (void)adjtime(&ntime, (struct timeval *)0);
244
245         for (nt = nets; nt; nt = nt->next) {
246                 nentp = getnetbyname(nt->name);
247                 if (nentp == 0) {
248                         nt->net = inet_network(nt->name);
249                         if (nt->net != INADDR_NONE)
250                                 nentp = getnetbyaddr(nt->net, AF_INET);
251                 }
252                 if (nentp != 0) {
253                         nt->net = nentp->n_net;
254                 } else if (nt->net == INADDR_NONE) {
255                         errx(1, "unknown net %s", nt->name);
256                 } else if (nt->net == INADDR_ANY) {
257                         errx(1, "bad net %s", nt->name);
258                 } else {
259                         warnx("warning: %s unknown in /etc/networks",
260                                 nt->name);
261                 }
262
263                 if (0 == (nt->net & 0xff000000))
264                     nt->net <<= 8;
265                 if (0 == (nt->net & 0xff000000))
266                     nt->net <<= 8;
267                 if (0 == (nt->net & 0xff000000))
268                     nt->net <<= 8;
269         }
270         ifc.ifc_len = sizeof(buf);
271         ifc.ifc_buf = buf;
272         if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
273                 err(1, "get interface configuration");
274         ntp = NULL;
275 #define size(p) max((p).sa_len, sizeof(p))
276         cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
277         for (cp = buf; cp < cplim;
278                         cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
279                 ifr = (struct ifreq *)cp;
280                 if (ifr->ifr_addr.sa_family != AF_INET)
281                         continue;
282                 if (!ntp)
283                         ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
284                 bzero(ntp,sizeof(*ntp));
285                 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
286                 ntp->status = NOMASTER;
287                 ifreq = *ifr;
288                 ifreqf = *ifr;
289
290                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
291                         warn("get interface flags");
292                         continue;
293                 }
294                 if ((ifreqf.ifr_flags & IFF_UP) == 0)
295                         continue;
296                 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
297                     (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
298                         continue;
299                 }
300
301
302                 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
303                         warn("get netmask");
304                         continue;
305                 }
306                 ntp->mask = ((struct sockaddr_in *)
307                         &ifreq.ifr_addr)->sin_addr.s_addr;
308
309                 if (ifreqf.ifr_flags & IFF_BROADCAST) {
310                         if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
311                                 warn("get broadaddr");
312                                 continue;
313                         }
314                         ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
315                         /* What if the broadcast address is all ones?
316                          * So we cannot just mask ntp->dest_addr.  */
317                         ntp->net = ntp->my_addr;
318                         ntp->net.s_addr &= ntp->mask;
319                 } else {
320                         if (ioctl(sock, SIOCGIFDSTADDR,
321                                                 (char *)&ifreq) < 0) {
322                                 warn("get destaddr");
323                                 continue;
324                         }
325                         ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
326                         ntp->net = ntp->dest_addr.sin_addr;
327                 }
328
329                 ntp->dest_addr.sin_port = port;
330
331                 for (nt = nets; nt; nt = nt->next) {
332                         if (ntp->net.s_addr == htonl(nt->net))
333                                 break;
334                 }
335                 if ((nflag && !nt) || (iflag && nt))
336                         continue;
337
338                 ntp->next = NULL;
339                 if (nettab == NULL) {
340                         nettab = ntp;
341                 } else {
342                         ntip->next = ntp;
343                 }
344                 ntip = ntp;
345                 ntp = NULL;
346         }
347         if (ntp)
348                 (void) free((char *)ntp);
349         if (nettab == NULL)
350                 errx(1, "no network usable");
351
352         /* microseconds to delay before responding to a broadcast */
353         delay1 = casual(1, 100*1000);
354
355         /* election timer delay in secs. */
356         delay2 = casual(MINTOUT, MAXTOUT);
357
358         if (!debug)
359                 daemon(debug, 0);
360
361         if (trace)
362                 traceon();
363         openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
364
365         /*
366          * keep returning here
367          */
368         ret = setjmp(jmpenv);
369         savefromnet = fromnet;
370         setstatus();
371
372         if (Mflag) {
373                 switch (ret) {
374
375                 case 0:
376                         checkignorednets();
377                         pickslavenet(0);
378                         break;
379                 case 1:
380                         /* Just lost our master */
381                         if (slavenet != 0)
382                                 slavenet->status = election(slavenet);
383                         if (!slavenet || slavenet->status == MASTER) {
384                                 checkignorednets();
385                                 pickslavenet(0);
386                         } else {
387                                 makeslave(slavenet);    /* prune extras */
388                         }
389                         break;
390
391                 case 2:
392                         /* Just been told to quit */
393                         justquit = 1;
394                         pickslavenet(savefromnet);
395                         break;
396                 }
397
398                 setstatus();
399                 if (!(status & MASTER) && sock_raw != -1) {
400                         /* sock_raw is not being used now */
401                         (void)close(sock_raw);
402                         sock_raw = -1;
403                 }
404
405                 if (status == MASTER)
406                         master();
407                 else
408                         slave();
409
410         } else {
411                 if (sock_raw != -1) {
412                         (void)close(sock_raw);
413                         sock_raw = -1;
414                 }
415
416                 if (ret) {
417                         /* we just lost our master or were told to quit */
418                         justquit = 1;
419                 }
420                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
421                         if (ntp->status == MASTER)
422                                 rmnetmachs(ntp);
423                                 ntp->status = NOMASTER;
424                 }
425                 checkignorednets();
426                 pickslavenet(0);
427                 setstatus();
428
429                 slave();
430         }
431         /* NOTREACHED */
432         return(0);
433 }
434
435 static void
436 usage()
437 {
438 #ifdef HAVENIS
439         fprintf(stderr, 
440 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
441 #else
442         fprintf(stderr,
443 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
444 #endif /* HAVENIS */
445         exit(1);
446 }
447
448 /*
449  * suppress an upstart, untrustworthy, self-appointed master
450  */
451 void
452 suppress(addr, name,net)
453         struct sockaddr_in *addr;
454         char *name;
455         struct netinfo *net;
456 {
457         struct sockaddr_in tgt;
458         char tname[MAXHOSTNAMELEN];
459         struct tsp msg;
460         static struct timeval wait;
461
462         if (trace)
463                 fprintf(fd, "suppress: %s\n", name);
464         tgt = *addr;
465         (void)strcpy(tname, name);
466
467         while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
468                 if (trace)
469                         fprintf(fd, "suppress:\tdiscarded packet from %s\n",
470                                     name);
471         }
472
473         syslog(LOG_NOTICE, "suppressing false master %s", tname);
474         msg.tsp_type = TSP_QUIT;
475         (void)strcpy(msg.tsp_name, hostname);
476         (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
477 }
478
479 void
480 lookformaster(ntp)
481         struct netinfo *ntp;
482 {
483         struct tsp resp, conflict, *answer;
484         struct timeval ntime;
485         char mastername[MAXHOSTNAMELEN];
486         struct sockaddr_in masteraddr;
487
488         get_goodgroup(0);
489         ntp->status = SLAVE;
490
491         /* look for master */
492         resp.tsp_type = TSP_MASTERREQ;
493         (void)strcpy(resp.tsp_name, hostname);
494         answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
495                          TSP_MASTERACK, ntp, 0);
496         if (answer != 0 && !good_host_name(answer->tsp_name)) {
497                 suppress(&from, answer->tsp_name, ntp);
498                 ntp->status = NOMASTER;
499                 answer = 0;
500         }
501         if (answer == 0) {
502                 /*
503                  * Various conditions can cause conflict: races between
504                  * two just started timedaemons when no master is
505                  * present, or timedaemons started during an election.
506                  * A conservative approach is taken.  Give up and became a
507                  * slave, postponing election of a master until first
508                  * timer expires.
509                  */
510                 ntime.tv_sec = ntime.tv_usec = 0;
511                 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
512                 if (answer != 0) {
513                         if (!good_host_name(answer->tsp_name)) {
514                                 suppress(&from, answer->tsp_name, ntp);
515                                 ntp->status = NOMASTER;
516                         }
517                         return;
518                 }
519
520                 ntime.tv_sec = ntime.tv_usec = 0;
521                 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
522                 if (answer != 0) {
523                         if (!good_host_name(answer->tsp_name)) {
524                                 suppress(&from, answer->tsp_name, ntp);
525                                 ntp->status = NOMASTER;
526                         }
527                         return;
528                 }
529
530                 ntime.tv_sec = ntime.tv_usec = 0;
531                 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
532                 if (answer != 0) {
533                         if (!good_host_name(answer->tsp_name)) {
534                                 suppress(&from, answer->tsp_name, ntp);
535                                 ntp->status = NOMASTER;
536                         }
537                         return;
538                 }
539
540                 if (Mflag)
541                         ntp->status = MASTER;
542                 else
543                         ntp->status = NOMASTER;
544                 return;
545         }
546
547         ntp->status = SLAVE;
548         (void)strcpy(mastername, answer->tsp_name);
549         masteraddr = from;
550
551         /*
552          * If network has been partitioned, there might be other
553          * masters; tell the one we have just acknowledged that
554          * it has to gain control over the others.
555          */
556         ntime.tv_sec = 0;
557         ntime.tv_usec = 300000;
558         answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
559         /*
560          * checking also not to send CONFLICT to ack'ed master
561          * due to duplicated MASTERACKs
562          */
563         if (answer != NULL &&
564             strcmp(answer->tsp_name, mastername) != 0) {
565                 conflict.tsp_type = TSP_CONFLICT;
566                 (void)strcpy(conflict.tsp_name, hostname);
567                 if (!acksend(&conflict, &masteraddr, mastername,
568                              TSP_ACK, 0, 0)) {
569                         syslog(LOG_ERR,
570                                "error on sending TSP_CONFLICT");
571                 }
572         }
573 }
574
575 /*
576  * based on the current network configuration, set the status, and count
577  * networks;
578  */
579 void
580 setstatus()
581 {
582         struct netinfo *ntp;
583
584         status = 0;
585         nmasternets = nslavenets = nnets = nignorednets = 0;
586         if (trace)
587                 fprintf(fd, "Net status:\n");
588         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
589                 switch ((int)ntp->status) {
590                 case MASTER:
591                         nmasternets++;
592                         break;
593                 case SLAVE:
594                         nslavenets++;
595                         break;
596                 case NOMASTER:
597                 case IGNORE:
598                         nignorednets++;
599                         break;
600                 }
601                 if (trace) {
602                         fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
603                         switch ((int)ntp->status) {
604                         case NOMASTER:
605                                 fprintf(fd, "NOMASTER\n");
606                                 break;
607                         case MASTER:
608                                 fprintf(fd, "MASTER\n");
609                                 break;
610                         case SLAVE:
611                                 fprintf(fd, "SLAVE\n");
612                                 break;
613                         case IGNORE:
614                                 fprintf(fd, "IGNORE\n");
615                                 break;
616                         default:
617                                 fprintf(fd, "invalid state %d\n",
618                                         (int)ntp->status);
619                                 break;
620                         }
621                 }
622                 nnets++;
623                 status |= ntp->status;
624         }
625         status &= ~IGNORE;
626         if (trace)
627                 fprintf(fd,
628                     "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
629                     nnets, nmasternets, nslavenets, nignorednets, delay2);
630 }
631
632 void
633 makeslave(net)
634         struct netinfo *net;
635 {
636         register struct netinfo *ntp;
637
638         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
639                 if (ntp->status == SLAVE && ntp != net)
640                         ntp->status = IGNORE;
641         }
642         slavenet = net;
643 }
644
645 /*
646  * Try to become master over ignored nets..
647  */
648 static void
649 checkignorednets()
650 {
651         register struct netinfo *ntp;
652
653         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
654                 if (!Mflag && ntp->status == SLAVE)
655                         break;
656
657                 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
658                         lookformaster(ntp);
659                         if (!Mflag && ntp->status == SLAVE)
660                                 break;
661                 }
662         }
663 }
664
665 /*
666  * choose a good network on which to be a slave
667  *      The ignored networks must have already been checked.
668  *      Take a hint about for a good network.
669  */
670 static void
671 pickslavenet(ntp)
672         struct netinfo *ntp;
673 {
674         if (slavenet != 0 && slavenet->status == SLAVE) {
675                 makeslave(slavenet);            /* prune extras */
676                 return;
677         }
678
679         if (ntp == 0 || ntp->status != SLAVE) {
680                 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
681                         if (ntp->status == SLAVE)
682                                 break;
683                 }
684         }
685         makeslave(ntp);
686 }
687
688 /*
689  * returns a random number in the range [inf, sup]
690  */
691 long
692 casual(inf, sup)
693         long inf, sup;
694 {
695         double value;
696
697         value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
698         return(inf + (sup - inf)*value);
699 }
700
701 char *
702 date()
703 {
704         struct  timeval tv;
705         time_t  tv_sec;
706
707         (void)gettimeofday(&tv, (struct timezone *)0);
708         tv_sec = tv.tv_sec;
709         return (ctime(&tv_sec));
710 }
711
712 void
713 addnetname(name)
714         char *name;
715 {
716         register struct nets **netlist = &nets;
717
718         while (*netlist)
719                 netlist = &((*netlist)->next);
720         *netlist = (struct nets *)malloc(sizeof **netlist);
721         if (*netlist == 0)
722                 errx(1, "malloc failed");
723         bzero((char *)*netlist, sizeof(**netlist));
724         (*netlist)->name = name;
725 }
726
727 /* note a host as trustworthy */
728 static void
729 add_good_host(name, perm)
730         char *name;
731         int perm;                       /* 1=not part of the netgroup */
732 {
733         register struct goodhost *ghp;
734         register struct hostent *hentp;
735
736         ghp = (struct goodhost*)malloc(sizeof(*ghp));
737         if (!ghp) {
738                 syslog(LOG_ERR, "malloc failed");
739                 exit(1);
740         }
741
742         bzero((char*)ghp, sizeof(*ghp));
743         (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
744         ghp->next = goodhosts;
745         ghp->perm = perm;
746         goodhosts = ghp;
747
748         hentp = gethostbyname(name);
749         if (0 == hentp && perm)
750                 warnx("unknown host %s", name);
751 }
752
753
754 /* update our image of the net-group of trustworthy hosts
755  */
756 void
757 get_goodgroup(force)
758         int force;
759 {
760 # define NG_DELAY (30*60*CLK_TCK)       /* 30 minutes */
761         static unsigned long last_update = -NG_DELAY;
762         unsigned long new_update;
763         struct goodhost *ghp, **ghpp;
764 #ifdef HAVENIS
765         struct hosttbl *htp;
766         char *mach, *usr, *dom;
767 #endif /* HAVENIS */
768         struct tms tm;
769
770
771         /* if no netgroup, then we are finished */
772         if (goodgroup == 0 || !Mflag)
773                 return;
774
775         /* Do not chatter with the netgroup master too often.
776          */
777         new_update = times(&tm);
778         if (new_update < last_update + NG_DELAY
779             && !force)
780                 return;
781         last_update = new_update;
782
783         /* forget the old temporary entries */
784         ghpp = &goodhosts;
785         while (0 != (ghp = *ghpp)) {
786                 if (!ghp->perm) {
787                         *ghpp = ghp->next;
788                         free((char*)ghp);
789                 } else {
790                         ghpp = &ghp->next;
791                 }
792         }
793
794 #ifdef HAVENIS
795         /* quit now if we are not one of the trusted masters
796          */
797         if (!innetgr(goodgroup, &hostname[0], 0,0)) {
798                 if (trace)
799                         (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
800                                       &hostname[0], goodgroup);
801                 return;
802         }
803         if (trace)
804                 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
805                                   &hostname[0], goodgroup);
806
807         /* mark the entire netgroup as trusted */
808         (void)setnetgrent(goodgroup);
809         while (getnetgrent(&mach,&usr,&dom)) {
810                 if (0 != mach)
811                         add_good_host(mach,0);
812         }
813         (void)endnetgrent();
814
815         /* update list of slaves */
816         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
817                 htp->good = good_host_name(&htp->name[0]);
818         }
819 #endif /* HAVENIS */
820 }
821
822
823 /* see if a machine is trustworthy
824  */
825 int                                     /* 1=trust hp to change our date */
826 good_host_name(name)
827         char *name;
828 {
829         register struct goodhost *ghp = goodhosts;
830         register char c;
831
832         if (!ghp || !Mflag)             /* trust everyone if no one named */
833                 return 1;
834
835         c = *name;
836         do {
837                 if (c == ghp->name[0]
838                     && !strcasecmp(name, ghp->name))
839                         return 1;       /* found him, so say so */
840         } while (0 != (ghp = ghp->next));
841
842         if (!strcasecmp(name,hostname)) /* trust ourself */
843                 return 1;
844
845         return 0;                       /* did not find him */
846 }