timed.c revision 179485
11553Srgrimes/*-
21553Srgrimes * Copyright (c) 1985, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3530642Scharnierstatic const char copyright[] =
361553Srgrimes"@(#) Copyright (c) 1985, 1993\n\
371553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381553Srgrimes#endif /* not lint */
391553Srgrimes
40117278Scharnier#if 0
411553Srgrimes#ifndef lint
421553Srgrimesstatic char sccsid[] = "@(#)timed.c	8.1 (Berkeley) 6/6/93";
43117278Scharnier#endif /* not lint */
4430642Scharnier#endif
451553Srgrimes
46117278Scharnier#include <sys/cdefs.h>
47117278Scharnier__FBSDID("$FreeBSD: head/usr.sbin/timed/timed/timed.c 179485 2008-06-02 04:50:47Z imp $");
48117278Scharnier
491553Srgrimes#define TSPTYPES
501553Srgrimes#include "globals.h"
511553Srgrimes#include <net/if.h>
521553Srgrimes#include <sys/file.h>
531553Srgrimes#include <sys/ioctl.h>
541553Srgrimes#include <setjmp.h>
551553Srgrimes#include "pathnames.h"
561553Srgrimes#include <math.h>
571553Srgrimes#include <sys/types.h>
581553Srgrimes#include <sys/times.h>
591553Srgrimes
601553Srgrimesint trace = 0;
611553Srgrimesint sock, sock_raw = -1;
621553Srgrimesint status = 0;
631553Srgrimesu_short sequence;			/* sequence number */
641553Srgrimeslong delay1;
651553Srgrimeslong delay2;
661553Srgrimes
671553Srgrimesint nslavenets;				/* nets were I could be a slave */
681553Srgrimesint nmasternets;			/* nets were I could be a master */
691553Srgrimesint nignorednets;			/* ignored nets */
701553Srgrimesint nnets;				/* nets I am connected to */
711553Srgrimes
721553SrgrimesFILE *fd;				/* trace file FD */
731553Srgrimes
741553Srgrimesjmp_buf jmpenv;
751553Srgrimes
761553Srgrimesstruct netinfo *nettab = 0;
771553Srgrimesstruct netinfo *slavenet;
781553Srgrimesint Mflag;
791553Srgrimesint justquit = 0;
801553Srgrimesint debug;
811553Srgrimes
821553Srgrimesstatic struct nets {
831553Srgrimes	char	*name;
841553Srgrimes	long	net;
851553Srgrimes	struct nets *next;
861553Srgrimes} *nets = 0;
871553Srgrimes
881553Srgrimesstruct hosttbl hosttbl[NHOSTS+1];	/* known hosts */
891553Srgrimes
901553Srgrimesstatic struct goodhost {		/* hosts that we trust */
9130872Scharnier	char	name[MAXHOSTNAMELEN];
921553Srgrimes	struct goodhost *next;
931553Srgrimes	char	perm;
941553Srgrimes} *goodhosts;
951553Srgrimes
961553Srgrimesstatic char *goodgroup;			/* net group of trusted hosts */
97117278Scharnierstatic void checkignorednets(void);
98117278Scharnierstatic void pickslavenet(struct netinfo *);
99117278Scharnierstatic void add_good_host(char *, int);
100117278Scharnierstatic void usage(void);
1011553Srgrimes
1021553Srgrimes/*
1031553Srgrimes * The timedaemons synchronize the clocks of hosts in a local area network.
1041553Srgrimes * One daemon runs as master, all the others as slaves. The master
1051553Srgrimes * performs the task of computing clock differences and sends correction
1061553Srgrimes * values to the slaves.
1071553Srgrimes * Slaves start an election to choose a new master when the latter disappears
1081553Srgrimes * because of a machine crash, network partition, or when killed.
1091553Srgrimes * A resolution protocol is used to kill all but one of the masters
1101553Srgrimes * that happen to exist in segments of a partitioned network when the
1111553Srgrimes * network partition is fixed.
1121553Srgrimes *
1131553Srgrimes * Authors: Riccardo Gusella & Stefano Zatti
1141553Srgrimes *
1151553Srgrimes * overhauled at Silicon Graphics
1161553Srgrimes */
1171553Srgrimesint
1181553Srgrimesmain(argc, argv)
1191553Srgrimes	int argc;
1201553Srgrimes	char *argv[];
1211553Srgrimes{
1221553Srgrimes	int on;
1231553Srgrimes	int ret;
1241553Srgrimes	int nflag, iflag;
1251553Srgrimes	struct timeval ntime;
1261553Srgrimes	struct servent *srvp;
1271553Srgrimes	char buf[BUFSIZ], *cp, *cplim;
1281553Srgrimes	struct ifconf ifc;
1291553Srgrimes	struct ifreq ifreq, ifreqf, *ifr;
1301553Srgrimes	register struct netinfo *ntp;
1311553Srgrimes	struct netinfo *ntip;
1321553Srgrimes	struct netinfo *savefromnet;
1331553Srgrimes	struct netent *nentp;
1341553Srgrimes	struct nets *nt;
1351553Srgrimes	struct sockaddr_in server;
1361553Srgrimes	u_short port;
137179485Simp	int c;
1381553Srgrimes
1391553Srgrimes#ifdef lint
1401553Srgrimes	ntip = NULL;
1411553Srgrimes#endif
1421553Srgrimes
1431553Srgrimes	on = 1;
1441553Srgrimes	nflag = OFF;
1451553Srgrimes	iflag = OFF;
1461553Srgrimes
1471553Srgrimes
1481553Srgrimes	opterr = 0;
14924428Simp	while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
1501553Srgrimes		switch (c) {
1511553Srgrimes		case 'M':
1521553Srgrimes			Mflag = 1;
1531553Srgrimes			break;
1541553Srgrimes
1551553Srgrimes		case 't':
1561553Srgrimes			trace = 1;
1571553Srgrimes			break;
1581553Srgrimes
1591553Srgrimes		case 'n':
1601553Srgrimes			if (iflag) {
16130642Scharnier				errx(1, "-i and -n make no sense together");
1621553Srgrimes			} else {
1631553Srgrimes				nflag = ON;
1641553Srgrimes				addnetname(optarg);
1651553Srgrimes			}
1661553Srgrimes			break;
1671553Srgrimes
1681553Srgrimes		case 'i':
1691553Srgrimes			if (nflag) {
17030642Scharnier				errx(1, "-i and -n make no sense together");
1711553Srgrimes			} else {
1721553Srgrimes				iflag = ON;
1731553Srgrimes				addnetname(optarg);
1741553Srgrimes			}
1751553Srgrimes			break;
1761553Srgrimes
1771553Srgrimes		case 'F':
1781553Srgrimes			add_good_host(optarg,1);
1791553Srgrimes			while (optind < argc && argv[optind][0] != '-')
1801553Srgrimes				add_good_host(argv[optind++], 1);
1811553Srgrimes			break;
1821553Srgrimes
1831553Srgrimes		case 'd':
1841553Srgrimes			debug = 1;
1851553Srgrimes			break;
1861553Srgrimes		case 'G':
18730642Scharnier			if (goodgroup != 0)
18830642Scharnier				errx(1, "only one net group");
1891553Srgrimes			goodgroup = optarg;
1901553Srgrimes			break;
1911553Srgrimes
1921553Srgrimes		default:
19330642Scharnier			usage();
1941553Srgrimes			break;
1951553Srgrimes		}
1961553Srgrimes	}
19730642Scharnier	if (optind < argc)
19830642Scharnier		usage();
1991553Srgrimes
2001553Srgrimes	/* If we care about which machine is the master, then we must
2011553Srgrimes	 *	be willing to be a master
2021553Srgrimes	 */
2031553Srgrimes	if (0 != goodgroup || 0 != goodhosts)
2041553Srgrimes		Mflag = 1;
2051553Srgrimes
20630642Scharnier	if (gethostname(hostname, sizeof(hostname) - 1) < 0)
20730642Scharnier		err(1, "gethostname");
2081553Srgrimes	self.l_bak = &self;
2091553Srgrimes	self.l_fwd = &self;
2101553Srgrimes	self.h_bak = &self;
2111553Srgrimes	self.h_fwd = &self;
2121553Srgrimes	self.head = 1;
2131553Srgrimes	self.good = 1;
2141553Srgrimes
2151553Srgrimes	if (goodhosts != 0)		/* trust ourself */
2161553Srgrimes		add_good_host(hostname,1);
2171553Srgrimes
2181553Srgrimes	srvp = getservbyname("timed", "udp");
21930642Scharnier	if (srvp == 0)
220117278Scharnier		errx(1, "timed/udp: unknown service");
2211553Srgrimes	port = srvp->s_port;
2228532Sdg	bzero(&server, sizeof(struct sockaddr_in));
2231553Srgrimes	server.sin_port = srvp->s_port;
2241553Srgrimes	server.sin_family = AF_INET;
2251553Srgrimes	sock = socket(AF_INET, SOCK_DGRAM, 0);
22630642Scharnier	if (sock < 0)
22730642Scharnier		err(1, "socket");
2281553Srgrimes	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
22930642Scharnier							sizeof(on)) < 0)
23030642Scharnier		err(1, "setsockopt");
2311553Srgrimes	if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
2321553Srgrimes		if (errno == EADDRINUSE)
23330642Scharnier			warnx("time daemon already running");
2341553Srgrimes		else
23530642Scharnier			warn("bind");
2361553Srgrimes		exit(1);
2371553Srgrimes	}
2381553Srgrimes
2391553Srgrimes	/* choose a unique seed for random number generation */
2401553Srgrimes	(void)gettimeofday(&ntime, 0);
2411553Srgrimes	srandom(ntime.tv_sec + ntime.tv_usec);
2421553Srgrimes
2431553Srgrimes	sequence = random();     /* initial seq number */
2441553Srgrimes
2451553Srgrimes	/* rounds kernel variable time to multiple of 5 ms. */
2461553Srgrimes	ntime.tv_sec = 0;
2471553Srgrimes	ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
2481553Srgrimes	(void)adjtime(&ntime, (struct timeval *)0);
2491553Srgrimes
2501553Srgrimes	for (nt = nets; nt; nt = nt->next) {
2511553Srgrimes		nentp = getnetbyname(nt->name);
2521553Srgrimes		if (nentp == 0) {
2531553Srgrimes			nt->net = inet_network(nt->name);
2541553Srgrimes			if (nt->net != INADDR_NONE)
2551553Srgrimes				nentp = getnetbyaddr(nt->net, AF_INET);
2561553Srgrimes		}
2571553Srgrimes		if (nentp != 0) {
2581553Srgrimes			nt->net = nentp->n_net;
2591553Srgrimes		} else if (nt->net == INADDR_NONE) {
26030642Scharnier			errx(1, "unknown net %s", nt->name);
2611553Srgrimes		} else if (nt->net == INADDR_ANY) {
26230642Scharnier			errx(1, "bad net %s", nt->name);
2631553Srgrimes		} else {
26430642Scharnier			warnx("warning: %s unknown in /etc/networks",
2651553Srgrimes				nt->name);
2661553Srgrimes		}
2671553Srgrimes
2681553Srgrimes		if (0 == (nt->net & 0xff000000))
2691553Srgrimes		    nt->net <<= 8;
2701553Srgrimes		if (0 == (nt->net & 0xff000000))
2711553Srgrimes		    nt->net <<= 8;
2721553Srgrimes		if (0 == (nt->net & 0xff000000))
2731553Srgrimes		    nt->net <<= 8;
2741553Srgrimes	}
2751553Srgrimes	ifc.ifc_len = sizeof(buf);
2761553Srgrimes	ifc.ifc_buf = buf;
27730642Scharnier	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
27830642Scharnier		err(1, "get interface configuration");
2791553Srgrimes	ntp = NULL;
2801553Srgrimes#define size(p)	max((p).sa_len, sizeof(p))
2811553Srgrimes	cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
2821553Srgrimes	for (cp = buf; cp < cplim;
2831553Srgrimes			cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
2841553Srgrimes		ifr = (struct ifreq *)cp;
2851553Srgrimes		if (ifr->ifr_addr.sa_family != AF_INET)
2861553Srgrimes			continue;
2871553Srgrimes		if (!ntp)
2881553Srgrimes			ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
2891553Srgrimes		bzero(ntp,sizeof(*ntp));
2901553Srgrimes		ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
2911553Srgrimes		ntp->status = NOMASTER;
2921553Srgrimes		ifreq = *ifr;
2931553Srgrimes		ifreqf = *ifr;
2941553Srgrimes
2951553Srgrimes		if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
29630642Scharnier			warn("get interface flags");
2971553Srgrimes			continue;
2981553Srgrimes		}
2991553Srgrimes		if ((ifreqf.ifr_flags & IFF_UP) == 0)
3001553Srgrimes			continue;
3011553Srgrimes		if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
3021553Srgrimes		    (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
3031553Srgrimes			continue;
3041553Srgrimes		}
3051553Srgrimes
3061553Srgrimes
3071553Srgrimes		if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
30830642Scharnier			warn("get netmask");
3091553Srgrimes			continue;
3101553Srgrimes		}
3111553Srgrimes		ntp->mask = ((struct sockaddr_in *)
3121553Srgrimes			&ifreq.ifr_addr)->sin_addr.s_addr;
3131553Srgrimes
3141553Srgrimes		if (ifreqf.ifr_flags & IFF_BROADCAST) {
3151553Srgrimes			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
31630642Scharnier				warn("get broadaddr");
3171553Srgrimes				continue;
3181553Srgrimes			}
3191553Srgrimes			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
3201553Srgrimes			/* What if the broadcast address is all ones?
3211553Srgrimes			 * So we cannot just mask ntp->dest_addr.  */
3221553Srgrimes			ntp->net = ntp->my_addr;
3231553Srgrimes			ntp->net.s_addr &= ntp->mask;
3241553Srgrimes		} else {
3251553Srgrimes			if (ioctl(sock, SIOCGIFDSTADDR,
3261553Srgrimes						(char *)&ifreq) < 0) {
32730642Scharnier				warn("get destaddr");
3281553Srgrimes				continue;
3291553Srgrimes			}
3301553Srgrimes			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
3311553Srgrimes			ntp->net = ntp->dest_addr.sin_addr;
3321553Srgrimes		}
3331553Srgrimes
3341553Srgrimes		ntp->dest_addr.sin_port = port;
3351553Srgrimes
3361553Srgrimes		for (nt = nets; nt; nt = nt->next) {
33728547Sjlemon			if (ntp->net.s_addr == htonl(nt->net))
3381553Srgrimes				break;
3391553Srgrimes		}
34030642Scharnier		if ((nflag && !nt) || (iflag && nt))
3411553Srgrimes			continue;
3421553Srgrimes
3431553Srgrimes		ntp->next = NULL;
3441553Srgrimes		if (nettab == NULL) {
3451553Srgrimes			nettab = ntp;
3461553Srgrimes		} else {
3471553Srgrimes			ntip->next = ntp;
3481553Srgrimes		}
3491553Srgrimes		ntip = ntp;
3501553Srgrimes		ntp = NULL;
3511553Srgrimes	}
3521553Srgrimes	if (ntp)
3531553Srgrimes		(void) free((char *)ntp);
35430642Scharnier	if (nettab == NULL)
35530642Scharnier		errx(1, "no network usable");
3561553Srgrimes
3571553Srgrimes	/* microseconds to delay before responding to a broadcast */
3581553Srgrimes	delay1 = casual(1, 100*1000);
3591553Srgrimes
3601553Srgrimes	/* election timer delay in secs. */
3611553Srgrimes	delay2 = casual(MINTOUT, MAXTOUT);
3621553Srgrimes
3631553Srgrimes	if (!debug)
3641553Srgrimes		daemon(debug, 0);
3651553Srgrimes
3661553Srgrimes	if (trace)
3671553Srgrimes		traceon();
3681553Srgrimes	openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
3691553Srgrimes
3701553Srgrimes	/*
3711553Srgrimes	 * keep returning here
3721553Srgrimes	 */
3731553Srgrimes	ret = setjmp(jmpenv);
3741553Srgrimes	savefromnet = fromnet;
3751553Srgrimes	setstatus();
3761553Srgrimes
3771553Srgrimes	if (Mflag) {
3781553Srgrimes		switch (ret) {
3791553Srgrimes
3801553Srgrimes		case 0:
3811553Srgrimes			checkignorednets();
3821553Srgrimes			pickslavenet(0);
3831553Srgrimes			break;
3841553Srgrimes		case 1:
3851553Srgrimes			/* Just lost our master */
3861553Srgrimes			if (slavenet != 0)
3871553Srgrimes				slavenet->status = election(slavenet);
3881553Srgrimes			if (!slavenet || slavenet->status == MASTER) {
3891553Srgrimes				checkignorednets();
3901553Srgrimes				pickslavenet(0);
3911553Srgrimes			} else {
3921553Srgrimes				makeslave(slavenet);	/* prune extras */
3931553Srgrimes			}
3941553Srgrimes			break;
3951553Srgrimes
3961553Srgrimes		case 2:
3971553Srgrimes			/* Just been told to quit */
3981553Srgrimes			justquit = 1;
3991553Srgrimes			pickslavenet(savefromnet);
4001553Srgrimes			break;
4011553Srgrimes		}
4021553Srgrimes
4031553Srgrimes		setstatus();
4041553Srgrimes		if (!(status & MASTER) && sock_raw != -1) {
4051553Srgrimes			/* sock_raw is not being used now */
4061553Srgrimes			(void)close(sock_raw);
4071553Srgrimes			sock_raw = -1;
4081553Srgrimes		}
4091553Srgrimes
4101553Srgrimes		if (status == MASTER)
4111553Srgrimes			master();
4121553Srgrimes		else
4131553Srgrimes			slave();
4141553Srgrimes
4151553Srgrimes	} else {
4161553Srgrimes		if (sock_raw != -1) {
4171553Srgrimes			(void)close(sock_raw);
4181553Srgrimes			sock_raw = -1;
4191553Srgrimes		}
4201553Srgrimes
4211553Srgrimes		if (ret) {
4221553Srgrimes			/* we just lost our master or were told to quit */
4231553Srgrimes			justquit = 1;
4241553Srgrimes		}
4251553Srgrimes		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
4261553Srgrimes			if (ntp->status == MASTER)
4271553Srgrimes				rmnetmachs(ntp);
4281553Srgrimes				ntp->status = NOMASTER;
4291553Srgrimes		}
4301553Srgrimes		checkignorednets();
4311553Srgrimes		pickslavenet(0);
4321553Srgrimes		setstatus();
4331553Srgrimes
4341553Srgrimes		slave();
4351553Srgrimes	}
4361553Srgrimes	/* NOTREACHED */
4371553Srgrimes	return(0);
4381553Srgrimes}
4391553Srgrimes
44030642Scharnierstatic void
44130642Scharnierusage()
44230642Scharnier{
44330642Scharnier#ifdef HAVENIS
44430642Scharnier	fprintf(stderr,
44530642Scharnier"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
44630642Scharnier#else
44730642Scharnier	fprintf(stderr,
44830642Scharnier"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
44930642Scharnier#endif /* HAVENIS */
45030642Scharnier	exit(1);
45130642Scharnier}
45230642Scharnier
4531553Srgrimes/*
4541553Srgrimes * suppress an upstart, untrustworthy, self-appointed master
4551553Srgrimes */
4561553Srgrimesvoid
4571553Srgrimessuppress(addr, name,net)
4581553Srgrimes	struct sockaddr_in *addr;
4591553Srgrimes	char *name;
4601553Srgrimes	struct netinfo *net;
4611553Srgrimes{
4621553Srgrimes	struct sockaddr_in tgt;
4631553Srgrimes	char tname[MAXHOSTNAMELEN];
4641553Srgrimes	struct tsp msg;
4651553Srgrimes	static struct timeval wait;
4661553Srgrimes
4671553Srgrimes	if (trace)
4681553Srgrimes		fprintf(fd, "suppress: %s\n", name);
4691553Srgrimes	tgt = *addr;
47030830Scharnier	(void)strcpy(tname, name);
4711553Srgrimes
4721553Srgrimes	while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
4731553Srgrimes		if (trace)
4741553Srgrimes			fprintf(fd, "suppress:\tdiscarded packet from %s\n",
4751553Srgrimes				    name);
4761553Srgrimes	}
4771553Srgrimes
4781553Srgrimes	syslog(LOG_NOTICE, "suppressing false master %s", tname);
4791553Srgrimes	msg.tsp_type = TSP_QUIT;
48030830Scharnier	(void)strcpy(msg.tsp_name, hostname);
4811553Srgrimes	(void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
4821553Srgrimes}
4831553Srgrimes
4841553Srgrimesvoid
4851553Srgrimeslookformaster(ntp)
4861553Srgrimes	struct netinfo *ntp;
4871553Srgrimes{
4881553Srgrimes	struct tsp resp, conflict, *answer;
4891553Srgrimes	struct timeval ntime;
4901553Srgrimes	char mastername[MAXHOSTNAMELEN];
4911553Srgrimes	struct sockaddr_in masteraddr;
4921553Srgrimes
4931553Srgrimes	get_goodgroup(0);
4941553Srgrimes	ntp->status = SLAVE;
4951553Srgrimes
4961553Srgrimes	/* look for master */
4971553Srgrimes	resp.tsp_type = TSP_MASTERREQ;
49830830Scharnier	(void)strcpy(resp.tsp_name, hostname);
4991553Srgrimes	answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
5001553Srgrimes			 TSP_MASTERACK, ntp, 0);
5011553Srgrimes	if (answer != 0 && !good_host_name(answer->tsp_name)) {
5021553Srgrimes		suppress(&from, answer->tsp_name, ntp);
5031553Srgrimes		ntp->status = NOMASTER;
5041553Srgrimes		answer = 0;
5051553Srgrimes	}
5061553Srgrimes	if (answer == 0) {
5071553Srgrimes		/*
5081553Srgrimes		 * Various conditions can cause conflict: races between
5091553Srgrimes		 * two just started timedaemons when no master is
5101553Srgrimes		 * present, or timedaemons started during an election.
5111553Srgrimes		 * A conservative approach is taken.  Give up and became a
5121553Srgrimes		 * slave, postponing election of a master until first
5131553Srgrimes		 * timer expires.
5141553Srgrimes		 */
5151553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5161553Srgrimes		answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
5171553Srgrimes		if (answer != 0) {
5181553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5191553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5201553Srgrimes				ntp->status = NOMASTER;
5211553Srgrimes			}
5221553Srgrimes			return;
5231553Srgrimes		}
5241553Srgrimes
5251553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5261553Srgrimes		answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
5271553Srgrimes		if (answer != 0) {
5281553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5291553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5301553Srgrimes				ntp->status = NOMASTER;
5311553Srgrimes			}
5321553Srgrimes			return;
5331553Srgrimes		}
5341553Srgrimes
5351553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5361553Srgrimes		answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
5371553Srgrimes		if (answer != 0) {
5381553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5391553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5401553Srgrimes				ntp->status = NOMASTER;
5411553Srgrimes			}
5421553Srgrimes			return;
5431553Srgrimes		}
5441553Srgrimes
5451553Srgrimes		if (Mflag)
5461553Srgrimes			ntp->status = MASTER;
5471553Srgrimes		else
5481553Srgrimes			ntp->status = NOMASTER;
5491553Srgrimes		return;
5501553Srgrimes	}
5511553Srgrimes
5521553Srgrimes	ntp->status = SLAVE;
55330830Scharnier	(void)strcpy(mastername, answer->tsp_name);
5541553Srgrimes	masteraddr = from;
5551553Srgrimes
5561553Srgrimes	/*
5571553Srgrimes	 * If network has been partitioned, there might be other
5581553Srgrimes	 * masters; tell the one we have just acknowledged that
5591553Srgrimes	 * it has to gain control over the others.
5601553Srgrimes	 */
5611553Srgrimes	ntime.tv_sec = 0;
5621553Srgrimes	ntime.tv_usec = 300000;
5631553Srgrimes	answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
5641553Srgrimes	/*
5651553Srgrimes	 * checking also not to send CONFLICT to ack'ed master
5661553Srgrimes	 * due to duplicated MASTERACKs
5671553Srgrimes	 */
5681553Srgrimes	if (answer != NULL &&
5691553Srgrimes	    strcmp(answer->tsp_name, mastername) != 0) {
5701553Srgrimes		conflict.tsp_type = TSP_CONFLICT;
57130830Scharnier		(void)strcpy(conflict.tsp_name, hostname);
5721553Srgrimes		if (!acksend(&conflict, &masteraddr, mastername,
5731553Srgrimes			     TSP_ACK, 0, 0)) {
5741553Srgrimes			syslog(LOG_ERR,
5751553Srgrimes			       "error on sending TSP_CONFLICT");
5761553Srgrimes		}
5771553Srgrimes	}
5781553Srgrimes}
5791553Srgrimes
5801553Srgrimes/*
5811553Srgrimes * based on the current network configuration, set the status, and count
5821553Srgrimes * networks;
5831553Srgrimes */
5841553Srgrimesvoid
5851553Srgrimessetstatus()
5861553Srgrimes{
5871553Srgrimes	struct netinfo *ntp;
5881553Srgrimes
5891553Srgrimes	status = 0;
5901553Srgrimes	nmasternets = nslavenets = nnets = nignorednets = 0;
5911553Srgrimes	if (trace)
5921553Srgrimes		fprintf(fd, "Net status:\n");
5931553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
5941553Srgrimes		switch ((int)ntp->status) {
5951553Srgrimes		case MASTER:
5961553Srgrimes			nmasternets++;
5971553Srgrimes			break;
5981553Srgrimes		case SLAVE:
5991553Srgrimes			nslavenets++;
6001553Srgrimes			break;
6011553Srgrimes		case NOMASTER:
6021553Srgrimes		case IGNORE:
6031553Srgrimes			nignorednets++;
6041553Srgrimes			break;
6051553Srgrimes		}
6061553Srgrimes		if (trace) {
6071553Srgrimes			fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
6081553Srgrimes			switch ((int)ntp->status) {
6091553Srgrimes			case NOMASTER:
6101553Srgrimes				fprintf(fd, "NOMASTER\n");
6111553Srgrimes				break;
6121553Srgrimes			case MASTER:
6131553Srgrimes				fprintf(fd, "MASTER\n");
6141553Srgrimes				break;
6151553Srgrimes			case SLAVE:
6161553Srgrimes				fprintf(fd, "SLAVE\n");
6171553Srgrimes				break;
6181553Srgrimes			case IGNORE:
6191553Srgrimes				fprintf(fd, "IGNORE\n");
6201553Srgrimes				break;
6211553Srgrimes			default:
6221553Srgrimes				fprintf(fd, "invalid state %d\n",
6231553Srgrimes					(int)ntp->status);
6241553Srgrimes				break;
6251553Srgrimes			}
6261553Srgrimes		}
6271553Srgrimes		nnets++;
6281553Srgrimes		status |= ntp->status;
6291553Srgrimes	}
6301553Srgrimes	status &= ~IGNORE;
6311553Srgrimes	if (trace)
6321553Srgrimes		fprintf(fd,
63337268Sbde		    "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
63437268Sbde		    nnets, nmasternets, nslavenets, nignorednets, delay2);
6351553Srgrimes}
6361553Srgrimes
6371553Srgrimesvoid
6381553Srgrimesmakeslave(net)
6391553Srgrimes	struct netinfo *net;
6401553Srgrimes{
6411553Srgrimes	register struct netinfo *ntp;
6421553Srgrimes
6431553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
6441553Srgrimes		if (ntp->status == SLAVE && ntp != net)
6451553Srgrimes			ntp->status = IGNORE;
6461553Srgrimes	}
6471553Srgrimes	slavenet = net;
6481553Srgrimes}
6491553Srgrimes
6501553Srgrimes/*
6511553Srgrimes * Try to become master over ignored nets..
6521553Srgrimes */
6531553Srgrimesstatic void
6541553Srgrimescheckignorednets()
6551553Srgrimes{
6561553Srgrimes	register struct netinfo *ntp;
6571553Srgrimes
6581553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
6591553Srgrimes		if (!Mflag && ntp->status == SLAVE)
6601553Srgrimes			break;
6611553Srgrimes
6621553Srgrimes		if (ntp->status == IGNORE || ntp->status == NOMASTER) {
6631553Srgrimes			lookformaster(ntp);
6641553Srgrimes			if (!Mflag && ntp->status == SLAVE)
6651553Srgrimes				break;
6661553Srgrimes		}
6671553Srgrimes	}
6681553Srgrimes}
6691553Srgrimes
6701553Srgrimes/*
6711553Srgrimes * choose a good network on which to be a slave
6721553Srgrimes *	The ignored networks must have already been checked.
6731553Srgrimes *	Take a hint about for a good network.
6741553Srgrimes */
6751553Srgrimesstatic void
6761553Srgrimespickslavenet(ntp)
6771553Srgrimes	struct netinfo *ntp;
6781553Srgrimes{
6791553Srgrimes	if (slavenet != 0 && slavenet->status == SLAVE) {
6801553Srgrimes		makeslave(slavenet);		/* prune extras */
6811553Srgrimes		return;
6821553Srgrimes	}
6831553Srgrimes
6841553Srgrimes	if (ntp == 0 || ntp->status != SLAVE) {
6851553Srgrimes		for (ntp = nettab; ntp != 0; ntp = ntp->next) {
6861553Srgrimes			if (ntp->status == SLAVE)
6871553Srgrimes				break;
6881553Srgrimes		}
6891553Srgrimes	}
6901553Srgrimes	makeslave(ntp);
6911553Srgrimes}
6921553Srgrimes
6931553Srgrimes/*
6941553Srgrimes * returns a random number in the range [inf, sup]
6951553Srgrimes */
6961553Srgrimeslong
6971553Srgrimescasual(inf, sup)
6981553Srgrimes	long inf, sup;
6991553Srgrimes{
7001553Srgrimes	double value;
7011553Srgrimes
7021553Srgrimes	value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
7031553Srgrimes	return(inf + (sup - inf)*value);
7041553Srgrimes}
7051553Srgrimes
7061553Srgrimeschar *
7071553Srgrimesdate()
7081553Srgrimes{
7091553Srgrimes	struct	timeval tv;
71037268Sbde	time_t	tv_sec;
7111553Srgrimes
7121553Srgrimes	(void)gettimeofday(&tv, (struct timezone *)0);
71337268Sbde	tv_sec = tv.tv_sec;
71437268Sbde	return (ctime(&tv_sec));
7151553Srgrimes}
7161553Srgrimes
7171553Srgrimesvoid
7181553Srgrimesaddnetname(name)
7191553Srgrimes	char *name;
7201553Srgrimes{
7211553Srgrimes	register struct nets **netlist = &nets;
7221553Srgrimes
7231553Srgrimes	while (*netlist)
7241553Srgrimes		netlist = &((*netlist)->next);
7251553Srgrimes	*netlist = (struct nets *)malloc(sizeof **netlist);
72630642Scharnier	if (*netlist == 0)
72730642Scharnier		errx(1, "malloc failed");
7281553Srgrimes	bzero((char *)*netlist, sizeof(**netlist));
7291553Srgrimes	(*netlist)->name = name;
7301553Srgrimes}
7311553Srgrimes
7321553Srgrimes/* note a host as trustworthy */
7331553Srgrimesstatic void
7341553Srgrimesadd_good_host(name, perm)
7351553Srgrimes	char *name;
7361553Srgrimes	int perm;			/* 1=not part of the netgroup */
7371553Srgrimes{
7381553Srgrimes	register struct goodhost *ghp;
7391553Srgrimes	register struct hostent *hentp;
7401553Srgrimes
7411553Srgrimes	ghp = (struct goodhost*)malloc(sizeof(*ghp));
7421553Srgrimes	if (!ghp) {
7431553Srgrimes		syslog(LOG_ERR, "malloc failed");
7441553Srgrimes		exit(1);
7451553Srgrimes	}
7461553Srgrimes
7471553Srgrimes	bzero((char*)ghp, sizeof(*ghp));
7481553Srgrimes	(void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
7491553Srgrimes	ghp->next = goodhosts;
7501553Srgrimes	ghp->perm = perm;
7511553Srgrimes	goodhosts = ghp;
7521553Srgrimes
7531553Srgrimes	hentp = gethostbyname(name);
7541553Srgrimes	if (0 == hentp && perm)
75530642Scharnier		warnx("unknown host %s", name);
7561553Srgrimes}
7571553Srgrimes
7581553Srgrimes
7591553Srgrimes/* update our image of the net-group of trustworthy hosts
7601553Srgrimes */
7611553Srgrimesvoid
7621553Srgrimesget_goodgroup(force)
7631553Srgrimes	int force;
7641553Srgrimes{
7651553Srgrimes# define NG_DELAY (30*60*CLK_TCK)	/* 30 minutes */
7661553Srgrimes	static unsigned long last_update = -NG_DELAY;
7671553Srgrimes	unsigned long new_update;
76830642Scharnier	struct goodhost *ghp, **ghpp;
76930642Scharnier#ifdef HAVENIS
7701553Srgrimes	struct hosttbl *htp;
7711553Srgrimes	char *mach, *usr, *dom;
77230642Scharnier#endif /* HAVENIS */
7731553Srgrimes	struct tms tm;
7741553Srgrimes
7751553Srgrimes
7761553Srgrimes	/* if no netgroup, then we are finished */
7771553Srgrimes	if (goodgroup == 0 || !Mflag)
7781553Srgrimes		return;
7791553Srgrimes
7801553Srgrimes	/* Do not chatter with the netgroup master too often.
7811553Srgrimes	 */
7821553Srgrimes	new_update = times(&tm);
7831553Srgrimes	if (new_update < last_update + NG_DELAY
7841553Srgrimes	    && !force)
7851553Srgrimes		return;
7861553Srgrimes	last_update = new_update;
7871553Srgrimes
7881553Srgrimes	/* forget the old temporary entries */
7891553Srgrimes	ghpp = &goodhosts;
7901553Srgrimes	while (0 != (ghp = *ghpp)) {
7911553Srgrimes		if (!ghp->perm) {
7921553Srgrimes			*ghpp = ghp->next;
7931553Srgrimes			free((char*)ghp);
7941553Srgrimes		} else {
7951553Srgrimes			ghpp = &ghp->next;
7961553Srgrimes		}
7971553Srgrimes	}
7981553Srgrimes
7991553Srgrimes#ifdef HAVENIS
8001553Srgrimes	/* quit now if we are not one of the trusted masters
8011553Srgrimes	 */
8021553Srgrimes	if (!innetgr(goodgroup, &hostname[0], 0,0)) {
8031553Srgrimes		if (trace)
8041553Srgrimes			(void)fprintf(fd, "get_goodgroup: %s not in %s\n",
8051553Srgrimes				      &hostname[0], goodgroup);
8061553Srgrimes		return;
8071553Srgrimes	}
8081553Srgrimes	if (trace)
8091553Srgrimes		(void)fprintf(fd, "get_goodgroup: %s in %s\n",
8101553Srgrimes				  &hostname[0], goodgroup);
8111553Srgrimes
8121553Srgrimes	/* mark the entire netgroup as trusted */
8131553Srgrimes	(void)setnetgrent(goodgroup);
8141553Srgrimes	while (getnetgrent(&mach,&usr,&dom)) {
8151553Srgrimes		if (0 != mach)
8161553Srgrimes			add_good_host(mach,0);
8171553Srgrimes	}
8181553Srgrimes	(void)endnetgrent();
8191553Srgrimes
8201553Srgrimes	/* update list of slaves */
8211553Srgrimes	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
8221553Srgrimes		htp->good = good_host_name(&htp->name[0]);
8231553Srgrimes	}
8241553Srgrimes#endif /* HAVENIS */
8251553Srgrimes}
8261553Srgrimes
8271553Srgrimes
8281553Srgrimes/* see if a machine is trustworthy
8291553Srgrimes */
8301553Srgrimesint					/* 1=trust hp to change our date */
8311553Srgrimesgood_host_name(name)
8321553Srgrimes	char *name;
8331553Srgrimes{
8341553Srgrimes	register struct goodhost *ghp = goodhosts;
8351553Srgrimes	register char c;
8361553Srgrimes
8371553Srgrimes	if (!ghp || !Mflag)		/* trust everyone if no one named */
8381553Srgrimes		return 1;
8391553Srgrimes
8401553Srgrimes	c = *name;
8411553Srgrimes	do {
8421553Srgrimes		if (c == ghp->name[0]
8431553Srgrimes		    && !strcasecmp(name, ghp->name))
8441553Srgrimes			return 1;	/* found him, so say so */
8451553Srgrimes	} while (0 != (ghp = ghp->next));
8461553Srgrimes
8471553Srgrimes	if (!strcasecmp(name,hostname))	/* trust ourself */
8481553Srgrimes		return 1;
8491553Srgrimes
8501553Srgrimes	return 0;			/* did not find him */
8511553Srgrimes}
852