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