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