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