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