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