]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - usr.sbin/timed/timed/timed.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.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                 checkignorednets();
427                 pickslavenet(0);
428                 setstatus();
429
430                 slave();
431         }
432         /* NOTREACHED */
433         return(0);
434 }
435
436 static void
437 usage()
438 {
439 #ifdef HAVENIS
440         fprintf(stderr, 
441 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
442 #else
443         fprintf(stderr,
444 "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
445 #endif /* HAVENIS */
446         exit(1);
447 }
448
449 /*
450  * suppress an upstart, untrustworthy, self-appointed master
451  */
452 void
453 suppress(addr, name,net)
454         struct sockaddr_in *addr;
455         char *name;
456         struct netinfo *net;
457 {
458         struct sockaddr_in tgt;
459         char tname[MAXHOSTNAMELEN];
460         struct tsp msg;
461         static struct timeval wait;
462
463         if (trace)
464                 fprintf(fd, "suppress: %s\n", name);
465         tgt = *addr;
466         (void)strcpy(tname, name);
467
468         while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
469                 if (trace)
470                         fprintf(fd, "suppress:\tdiscarded packet from %s\n",
471                                     name);
472         }
473
474         syslog(LOG_NOTICE, "suppressing false master %s", tname);
475         msg.tsp_type = TSP_QUIT;
476         (void)strcpy(msg.tsp_name, hostname);
477         (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
478 }
479
480 void
481 lookformaster(ntp)
482         struct netinfo *ntp;
483 {
484         struct tsp resp, conflict, *answer;
485         struct timeval ntime;
486         char mastername[MAXHOSTNAMELEN];
487         struct sockaddr_in masteraddr;
488
489         get_goodgroup(0);
490         ntp->status = SLAVE;
491
492         /* look for master */
493         resp.tsp_type = TSP_MASTERREQ;
494         (void)strcpy(resp.tsp_name, hostname);
495         answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
496                          TSP_MASTERACK, ntp, 0);
497         if (answer != 0 && !good_host_name(answer->tsp_name)) {
498                 suppress(&from, answer->tsp_name, ntp);
499                 ntp->status = NOMASTER;
500                 answer = 0;
501         }
502         if (answer == 0) {
503                 /*
504                  * Various conditions can cause conflict: races between
505                  * two just started timedaemons when no master is
506                  * present, or timedaemons started during an election.
507                  * A conservative approach is taken.  Give up and became a
508                  * slave, postponing election of a master until first
509                  * timer expires.
510                  */
511                 ntime.tv_sec = ntime.tv_usec = 0;
512                 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
513                 if (answer != 0) {
514                         if (!good_host_name(answer->tsp_name)) {
515                                 suppress(&from, answer->tsp_name, ntp);
516                                 ntp->status = NOMASTER;
517                         }
518                         return;
519                 }
520
521                 ntime.tv_sec = ntime.tv_usec = 0;
522                 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
523                 if (answer != 0) {
524                         if (!good_host_name(answer->tsp_name)) {
525                                 suppress(&from, answer->tsp_name, ntp);
526                                 ntp->status = NOMASTER;
527                         }
528                         return;
529                 }
530
531                 ntime.tv_sec = ntime.tv_usec = 0;
532                 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
533                 if (answer != 0) {
534                         if (!good_host_name(answer->tsp_name)) {
535                                 suppress(&from, answer->tsp_name, ntp);
536                                 ntp->status = NOMASTER;
537                         }
538                         return;
539                 }
540
541                 if (Mflag)
542                         ntp->status = MASTER;
543                 else
544                         ntp->status = NOMASTER;
545                 return;
546         }
547
548         ntp->status = SLAVE;
549         (void)strcpy(mastername, answer->tsp_name);
550         masteraddr = from;
551
552         /*
553          * If network has been partitioned, there might be other
554          * masters; tell the one we have just acknowledged that
555          * it has to gain control over the others.
556          */
557         ntime.tv_sec = 0;
558         ntime.tv_usec = 300000;
559         answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
560         /*
561          * checking also not to send CONFLICT to ack'ed master
562          * due to duplicated MASTERACKs
563          */
564         if (answer != NULL &&
565             strcmp(answer->tsp_name, mastername) != 0) {
566                 conflict.tsp_type = TSP_CONFLICT;
567                 (void)strcpy(conflict.tsp_name, hostname);
568                 if (!acksend(&conflict, &masteraddr, mastername,
569                              TSP_ACK, 0, 0)) {
570                         syslog(LOG_ERR,
571                                "error on sending TSP_CONFLICT");
572                 }
573         }
574 }
575
576 /*
577  * based on the current network configuration, set the status, and count
578  * networks;
579  */
580 void
581 setstatus()
582 {
583         struct netinfo *ntp;
584
585         status = 0;
586         nmasternets = nslavenets = nnets = nignorednets = 0;
587         if (trace)
588                 fprintf(fd, "Net status:\n");
589         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
590                 switch ((int)ntp->status) {
591                 case MASTER:
592                         nmasternets++;
593                         break;
594                 case SLAVE:
595                         nslavenets++;
596                         break;
597                 case NOMASTER:
598                 case IGNORE:
599                         nignorednets++;
600                         break;
601                 }
602                 if (trace) {
603                         fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
604                         switch ((int)ntp->status) {
605                         case NOMASTER:
606                                 fprintf(fd, "NOMASTER\n");
607                                 break;
608                         case MASTER:
609                                 fprintf(fd, "MASTER\n");
610                                 break;
611                         case SLAVE:
612                                 fprintf(fd, "SLAVE\n");
613                                 break;
614                         case IGNORE:
615                                 fprintf(fd, "IGNORE\n");
616                                 break;
617                         default:
618                                 fprintf(fd, "invalid state %d\n",
619                                         (int)ntp->status);
620                                 break;
621                         }
622                 }
623                 nnets++;
624                 status |= ntp->status;
625         }
626         status &= ~IGNORE;
627         if (trace)
628                 fprintf(fd,
629                     "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
630                     nnets, nmasternets, nslavenets, nignorednets, delay2);
631 }
632
633 void
634 makeslave(net)
635         struct netinfo *net;
636 {
637         register struct netinfo *ntp;
638
639         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
640                 if (ntp->status == SLAVE && ntp != net)
641                         ntp->status = IGNORE;
642         }
643         slavenet = net;
644 }
645
646 /*
647  * Try to become master over ignored nets..
648  */
649 static void
650 checkignorednets()
651 {
652         register struct netinfo *ntp;
653
654         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
655                 if (!Mflag && ntp->status == SLAVE)
656                         break;
657
658                 if (ntp->status == IGNORE || ntp->status == NOMASTER) {
659                         lookformaster(ntp);
660                         if (!Mflag && ntp->status == SLAVE)
661                                 break;
662                 }
663         }
664 }
665
666 /*
667  * choose a good network on which to be a slave
668  *      The ignored networks must have already been checked.
669  *      Take a hint about for a good network.
670  */
671 static void
672 pickslavenet(ntp)
673         struct netinfo *ntp;
674 {
675         if (slavenet != 0 && slavenet->status == SLAVE) {
676                 makeslave(slavenet);            /* prune extras */
677                 return;
678         }
679
680         if (ntp == 0 || ntp->status != SLAVE) {
681                 for (ntp = nettab; ntp != 0; ntp = ntp->next) {
682                         if (ntp->status == SLAVE)
683                                 break;
684                 }
685         }
686         makeslave(ntp);
687 }
688
689 /*
690  * returns a random number in the range [inf, sup]
691  */
692 long
693 casual(inf, sup)
694         long inf, sup;
695 {
696         double value;
697
698         value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
699         return(inf + (sup - inf)*value);
700 }
701
702 char *
703 date()
704 {
705         struct  timeval tv;
706         time_t  tv_sec;
707
708         (void)gettimeofday(&tv, (struct timezone *)0);
709         tv_sec = tv.tv_sec;
710         return (ctime(&tv_sec));
711 }
712
713 void
714 addnetname(name)
715         char *name;
716 {
717         register struct nets **netlist = &nets;
718
719         while (*netlist)
720                 netlist = &((*netlist)->next);
721         *netlist = (struct nets *)malloc(sizeof **netlist);
722         if (*netlist == 0)
723                 errx(1, "malloc failed");
724         bzero((char *)*netlist, sizeof(**netlist));
725         (*netlist)->name = name;
726 }
727
728 /* note a host as trustworthy */
729 static void
730 add_good_host(name, perm)
731         char *name;
732         int perm;                       /* 1=not part of the netgroup */
733 {
734         register struct goodhost *ghp;
735         register struct hostent *hentp;
736
737         ghp = (struct goodhost*)malloc(sizeof(*ghp));
738         if (!ghp) {
739                 syslog(LOG_ERR, "malloc failed");
740                 exit(1);
741         }
742
743         bzero((char*)ghp, sizeof(*ghp));
744         (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
745         ghp->next = goodhosts;
746         ghp->perm = perm;
747         goodhosts = ghp;
748
749         hentp = gethostbyname(name);
750         if (0 == hentp && perm)
751                 warnx("unknown host %s", name);
752 }
753
754
755 /* update our image of the net-group of trustworthy hosts
756  */
757 void
758 get_goodgroup(force)
759         int force;
760 {
761 # define NG_DELAY (30*60*CLK_TCK)       /* 30 minutes */
762         static unsigned long last_update = -NG_DELAY;
763         unsigned long new_update;
764         struct goodhost *ghp, **ghpp;
765 #ifdef HAVENIS
766         struct hosttbl *htp;
767         char *mach, *usr, *dom;
768 #endif /* HAVENIS */
769         struct tms tm;
770
771
772         /* if no netgroup, then we are finished */
773         if (goodgroup == 0 || !Mflag)
774                 return;
775
776         /* Do not chatter with the netgroup master too often.
777          */
778         new_update = times(&tm);
779         if (new_update < last_update + NG_DELAY
780             && !force)
781                 return;
782         last_update = new_update;
783
784         /* forget the old temporary entries */
785         ghpp = &goodhosts;
786         while (0 != (ghp = *ghpp)) {
787                 if (!ghp->perm) {
788                         *ghpp = ghp->next;
789                         free((char*)ghp);
790                 } else {
791                         ghpp = &ghp->next;
792                 }
793         }
794
795 #ifdef HAVENIS
796         /* quit now if we are not one of the trusted masters
797          */
798         if (!innetgr(goodgroup, &hostname[0], 0,0)) {
799                 if (trace)
800                         (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
801                                       &hostname[0], goodgroup);
802                 return;
803         }
804         if (trace)
805                 (void)fprintf(fd, "get_goodgroup: %s in %s\n",
806                                   &hostname[0], goodgroup);
807
808         /* mark the entire netgroup as trusted */
809         (void)setnetgrent(goodgroup);
810         while (getnetgrent(&mach,&usr,&dom)) {
811                 if (0 != mach)
812                         add_good_host(mach,0);
813         }
814         (void)endnetgrent();
815
816         /* update list of slaves */
817         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
818                 htp->good = good_host_name(&htp->name[0]);
819         }
820 #endif /* HAVENIS */
821 }
822
823
824 /* see if a machine is trustworthy
825  */
826 int                                     /* 1=trust hp to change our date */
827 good_host_name(name)
828         char *name;
829 {
830         register struct goodhost *ghp = goodhosts;
831         register char c;
832
833         if (!ghp || !Mflag)             /* trust everyone if no one named */
834                 return 1;
835
836         c = *name;
837         do {
838                 if (c == ghp->name[0]
839                     && !strcasecmp(name, ghp->name))
840                         return 1;       /* found him, so say so */
841         } while (0 != (ghp = ghp->next));
842
843         if (!strcasecmp(name,hostname)) /* trust ourself */
844                 return 1;
845
846         return 0;                       /* did not find him */
847 }