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