timed.c revision 216372
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
31static 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
38static 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: head/usr.sbin/timed/timed/timed.c 216372 2010-12-11 09:38:12Z joel $");
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
56int trace = 0;
57int sock, sock_raw = -1;
58int status = 0;
59u_short sequence;			/* sequence number */
60long delay1;
61long delay2;
62
63int nslavenets;				/* nets were I could be a slave */
64int nmasternets;			/* nets were I could be a master */
65int nignorednets;			/* ignored nets */
66int nnets;				/* nets I am connected to */
67
68FILE *fd;				/* trace file FD */
69
70jmp_buf jmpenv;
71
72struct netinfo *nettab = 0;
73struct netinfo *slavenet;
74int Mflag;
75int justquit = 0;
76int debug;
77
78static struct nets {
79	char	*name;
80	long	net;
81	struct nets *next;
82} *nets = 0;
83
84struct hosttbl hosttbl[NHOSTS+1];	/* known hosts */
85
86static struct goodhost {		/* hosts that we trust */
87	char	name[MAXHOSTNAMELEN];
88	struct goodhost *next;
89	char	perm;
90} *goodhosts;
91
92static char *goodgroup;			/* net group of trusted hosts */
93static void checkignorednets(void);
94static void pickslavenet(struct netinfo *);
95static void add_good_host(char *, int);
96static 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 */
113int
114main(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
436static void
437usage()
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 */
452void
453suppress(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
480void
481lookformaster(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 */
580void
581setstatus()
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
633void
634makeslave(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 */
649static void
650checkignorednets()
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 */
671static void
672pickslavenet(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 */
692long
693casual(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
702char *
703date()
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
713void
714addnetname(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 */
729static void
730add_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 */
757void
758get_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 */
826int					/* 1=trust hp to change our date */
827good_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}
848