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 * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
301553Srgrimes#ifndef lint
3130642Scharnierstatic const char copyright[] =
321553Srgrimes"@(#) Copyright (c) 1985, 1993\n\
331553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341553Srgrimes#endif /* not lint */
351553Srgrimes
36117278Scharnier#if 0
371553Srgrimes#ifndef lint
381553Srgrimesstatic char sccsid[] = "@(#)timed.c	8.1 (Berkeley) 6/6/93";
39117278Scharnier#endif /* not lint */
4030642Scharnier#endif
411553Srgrimes
42117278Scharnier#include <sys/cdefs.h>
43117278Scharnier__FBSDID("$FreeBSD$");
44117278Scharnier
451553Srgrimes#include "globals.h"
461553Srgrimes#include <net/if.h>
471553Srgrimes#include <sys/file.h>
481553Srgrimes#include <sys/ioctl.h>
491553Srgrimes#include <setjmp.h>
501553Srgrimes#include "pathnames.h"
511553Srgrimes#include <math.h>
521553Srgrimes#include <sys/types.h>
531553Srgrimes#include <sys/times.h>
541553Srgrimes
551553Srgrimesint trace = 0;
561553Srgrimesint sock, sock_raw = -1;
571553Srgrimesint status = 0;
581553Srgrimesu_short sequence;			/* sequence number */
591553Srgrimeslong delay1;
601553Srgrimeslong delay2;
611553Srgrimes
621553Srgrimesint nslavenets;				/* nets were I could be a slave */
631553Srgrimesint nmasternets;			/* nets were I could be a master */
641553Srgrimesint nignorednets;			/* ignored nets */
651553Srgrimesint nnets;				/* nets I am connected to */
661553Srgrimes
671553SrgrimesFILE *fd;				/* trace file FD */
681553Srgrimes
691553Srgrimesjmp_buf jmpenv;
701553Srgrimes
71299707Spfgstruct netinfo *nettab = NULL;
721553Srgrimesstruct netinfo *slavenet;
731553Srgrimesint Mflag;
741553Srgrimesint justquit = 0;
751553Srgrimesint debug;
761553Srgrimes
771553Srgrimesstatic struct nets {
781553Srgrimes	char	*name;
791553Srgrimes	long	net;
801553Srgrimes	struct nets *next;
81299707Spfg} *nets = NULL;
821553Srgrimes
831553Srgrimesstruct hosttbl hosttbl[NHOSTS+1];	/* known hosts */
841553Srgrimes
851553Srgrimesstatic struct goodhost {		/* hosts that we trust */
8630872Scharnier	char	name[MAXHOSTNAMELEN];
871553Srgrimes	struct goodhost *next;
881553Srgrimes	char	perm;
891553Srgrimes} *goodhosts;
901553Srgrimes
911553Srgrimesstatic char *goodgroup;			/* net group of trusted hosts */
92117278Scharnierstatic void checkignorednets(void);
93117278Scharnierstatic void pickslavenet(struct netinfo *);
94117278Scharnierstatic void add_good_host(char *, int);
95117278Scharnierstatic void usage(void);
961553Srgrimes
971553Srgrimes/*
981553Srgrimes * The timedaemons synchronize the clocks of hosts in a local area network.
991553Srgrimes * One daemon runs as master, all the others as slaves. The master
1001553Srgrimes * performs the task of computing clock differences and sends correction
1011553Srgrimes * values to the slaves.
1021553Srgrimes * Slaves start an election to choose a new master when the latter disappears
1031553Srgrimes * because of a machine crash, network partition, or when killed.
1041553Srgrimes * A resolution protocol is used to kill all but one of the masters
1051553Srgrimes * that happen to exist in segments of a partitioned network when the
1061553Srgrimes * network partition is fixed.
1071553Srgrimes *
1081553Srgrimes * Authors: Riccardo Gusella & Stefano Zatti
1091553Srgrimes *
1101553Srgrimes * overhauled at Silicon Graphics
1111553Srgrimes */
1121553Srgrimesint
113246209Scharniermain(int argc, char *argv[])
1141553Srgrimes{
1151553Srgrimes	int on;
1161553Srgrimes	int ret;
1171553Srgrimes	int nflag, iflag;
1181553Srgrimes	struct timeval ntime;
1191553Srgrimes	struct servent *srvp;
1201553Srgrimes	char buf[BUFSIZ], *cp, *cplim;
1211553Srgrimes	struct ifconf ifc;
1221553Srgrimes	struct ifreq ifreq, ifreqf, *ifr;
1231553Srgrimes	register struct netinfo *ntp;
1241553Srgrimes	struct netinfo *ntip;
1251553Srgrimes	struct netinfo *savefromnet;
1261553Srgrimes	struct netent *nentp;
1271553Srgrimes	struct nets *nt;
1281553Srgrimes	struct sockaddr_in server;
1291553Srgrimes	u_short port;
130179485Simp	int c;
1311553Srgrimes
1321553Srgrimes#ifdef lint
1331553Srgrimes	ntip = NULL;
1341553Srgrimes#endif
1351553Srgrimes
1361553Srgrimes	on = 1;
1371553Srgrimes	nflag = OFF;
1381553Srgrimes	iflag = OFF;
1391553Srgrimes
1401553Srgrimes
1411553Srgrimes	opterr = 0;
14224428Simp	while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) {
1431553Srgrimes		switch (c) {
1441553Srgrimes		case 'M':
1451553Srgrimes			Mflag = 1;
1461553Srgrimes			break;
1471553Srgrimes
1481553Srgrimes		case 't':
1491553Srgrimes			trace = 1;
1501553Srgrimes			break;
1511553Srgrimes
1521553Srgrimes		case 'n':
1531553Srgrimes			if (iflag) {
15430642Scharnier				errx(1, "-i and -n make no sense together");
1551553Srgrimes			} else {
1561553Srgrimes				nflag = ON;
1571553Srgrimes				addnetname(optarg);
1581553Srgrimes			}
1591553Srgrimes			break;
1601553Srgrimes
1611553Srgrimes		case 'i':
1621553Srgrimes			if (nflag) {
16330642Scharnier				errx(1, "-i and -n make no sense together");
1641553Srgrimes			} else {
1651553Srgrimes				iflag = ON;
1661553Srgrimes				addnetname(optarg);
1671553Srgrimes			}
1681553Srgrimes			break;
1691553Srgrimes
1701553Srgrimes		case 'F':
1711553Srgrimes			add_good_host(optarg,1);
1721553Srgrimes			while (optind < argc && argv[optind][0] != '-')
1731553Srgrimes				add_good_host(argv[optind++], 1);
1741553Srgrimes			break;
1751553Srgrimes
1761553Srgrimes		case 'd':
1771553Srgrimes			debug = 1;
1781553Srgrimes			break;
1791553Srgrimes		case 'G':
180299707Spfg			if (goodgroup != NULL)
18130642Scharnier				errx(1, "only one net group");
1821553Srgrimes			goodgroup = optarg;
1831553Srgrimes			break;
1841553Srgrimes
1851553Srgrimes		default:
18630642Scharnier			usage();
1871553Srgrimes			break;
1881553Srgrimes		}
1891553Srgrimes	}
19030642Scharnier	if (optind < argc)
19130642Scharnier		usage();
1921553Srgrimes
1931553Srgrimes	/* If we care about which machine is the master, then we must
1941553Srgrimes	 *	be willing to be a master
1951553Srgrimes	 */
196299707Spfg	if (goodgroup != NULL || goodhosts != NULL)
1971553Srgrimes		Mflag = 1;
1981553Srgrimes
199299713Spfg	if (gethostname(hostname, sizeof(hostname) - 1) < 0)
20030642Scharnier		err(1, "gethostname");
2011553Srgrimes	self.l_bak = &self;
2021553Srgrimes	self.l_fwd = &self;
2031553Srgrimes	self.h_bak = &self;
2041553Srgrimes	self.h_fwd = &self;
2051553Srgrimes	self.head = 1;
2061553Srgrimes	self.good = 1;
2071553Srgrimes
208299707Spfg	if (goodhosts != NULL)		/* trust ourself */
2091553Srgrimes		add_good_host(hostname,1);
2101553Srgrimes
2111553Srgrimes	srvp = getservbyname("timed", "udp");
212299707Spfg	if (srvp == NULL)
213117278Scharnier		errx(1, "timed/udp: unknown service");
2141553Srgrimes	port = srvp->s_port;
2158532Sdg	bzero(&server, sizeof(struct sockaddr_in));
2161553Srgrimes	server.sin_port = srvp->s_port;
2171553Srgrimes	server.sin_family = AF_INET;
2181553Srgrimes	sock = socket(AF_INET, SOCK_DGRAM, 0);
21930642Scharnier	if (sock < 0)
22030642Scharnier		err(1, "socket");
2211553Srgrimes	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
22230642Scharnier							sizeof(on)) < 0)
22330642Scharnier		err(1, "setsockopt");
2241553Srgrimes	if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
2251553Srgrimes		if (errno == EADDRINUSE)
22630642Scharnier			warnx("time daemon already running");
2271553Srgrimes		else
22830642Scharnier			warn("bind");
2291553Srgrimes		exit(1);
2301553Srgrimes	}
2311553Srgrimes
232299708Spfg	sequence = arc4random();     /* initial seq number */
233299708Spfg
234239991Sed	(void)gettimeofday(&ntime, NULL);
2351553Srgrimes	/* rounds kernel variable time to multiple of 5 ms. */
2361553Srgrimes	ntime.tv_sec = 0;
2371553Srgrimes	ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
2381553Srgrimes	(void)adjtime(&ntime, (struct timeval *)0);
2391553Srgrimes
2401553Srgrimes	for (nt = nets; nt; nt = nt->next) {
2411553Srgrimes		nentp = getnetbyname(nt->name);
242299707Spfg		if (nentp == NULL) {
2431553Srgrimes			nt->net = inet_network(nt->name);
2441553Srgrimes			if (nt->net != INADDR_NONE)
2451553Srgrimes				nentp = getnetbyaddr(nt->net, AF_INET);
2461553Srgrimes		}
247299707Spfg		if (nentp != NULL) {
2481553Srgrimes			nt->net = nentp->n_net;
2491553Srgrimes		} else if (nt->net == INADDR_NONE) {
25030642Scharnier			errx(1, "unknown net %s", nt->name);
2511553Srgrimes		} else if (nt->net == INADDR_ANY) {
25230642Scharnier			errx(1, "bad net %s", nt->name);
2531553Srgrimes		} else {
25430642Scharnier			warnx("warning: %s unknown in /etc/networks",
2551553Srgrimes				nt->name);
2561553Srgrimes		}
2571553Srgrimes
2581553Srgrimes		if (0 == (nt->net & 0xff000000))
2591553Srgrimes		    nt->net <<= 8;
2601553Srgrimes		if (0 == (nt->net & 0xff000000))
2611553Srgrimes		    nt->net <<= 8;
2621553Srgrimes		if (0 == (nt->net & 0xff000000))
2631553Srgrimes		    nt->net <<= 8;
2641553Srgrimes	}
2651553Srgrimes	ifc.ifc_len = sizeof(buf);
2661553Srgrimes	ifc.ifc_buf = buf;
26730642Scharnier	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
26830642Scharnier		err(1, "get interface configuration");
2691553Srgrimes	ntp = NULL;
2701553Srgrimes#define size(p)	max((p).sa_len, sizeof(p))
2711553Srgrimes	cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
2721553Srgrimes	for (cp = buf; cp < cplim;
2731553Srgrimes			cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
2741553Srgrimes		ifr = (struct ifreq *)cp;
2751553Srgrimes		if (ifr->ifr_addr.sa_family != AF_INET)
2761553Srgrimes			continue;
2771553Srgrimes		if (!ntp)
2781553Srgrimes			ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
2791553Srgrimes		bzero(ntp,sizeof(*ntp));
2801553Srgrimes		ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
2811553Srgrimes		ntp->status = NOMASTER;
2821553Srgrimes		ifreq = *ifr;
2831553Srgrimes		ifreqf = *ifr;
2841553Srgrimes
2851553Srgrimes		if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
28630642Scharnier			warn("get interface flags");
2871553Srgrimes			continue;
2881553Srgrimes		}
2891553Srgrimes		if ((ifreqf.ifr_flags & IFF_UP) == 0)
2901553Srgrimes			continue;
2911553Srgrimes		if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
2921553Srgrimes		    (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
2931553Srgrimes			continue;
2941553Srgrimes		}
2951553Srgrimes
2961553Srgrimes
2971553Srgrimes		if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
29830642Scharnier			warn("get netmask");
2991553Srgrimes			continue;
3001553Srgrimes		}
3011553Srgrimes		ntp->mask = ((struct sockaddr_in *)
3021553Srgrimes			&ifreq.ifr_addr)->sin_addr.s_addr;
3031553Srgrimes
3041553Srgrimes		if (ifreqf.ifr_flags & IFF_BROADCAST) {
3051553Srgrimes			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
30630642Scharnier				warn("get broadaddr");
3071553Srgrimes				continue;
3081553Srgrimes			}
3091553Srgrimes			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
3101553Srgrimes			/* What if the broadcast address is all ones?
3111553Srgrimes			 * So we cannot just mask ntp->dest_addr.  */
3121553Srgrimes			ntp->net = ntp->my_addr;
3131553Srgrimes			ntp->net.s_addr &= ntp->mask;
3141553Srgrimes		} else {
3151553Srgrimes			if (ioctl(sock, SIOCGIFDSTADDR,
3161553Srgrimes						(char *)&ifreq) < 0) {
31730642Scharnier				warn("get destaddr");
3181553Srgrimes				continue;
3191553Srgrimes			}
3201553Srgrimes			ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
3211553Srgrimes			ntp->net = ntp->dest_addr.sin_addr;
3221553Srgrimes		}
3231553Srgrimes
3241553Srgrimes		ntp->dest_addr.sin_port = port;
3251553Srgrimes
3261553Srgrimes		for (nt = nets; nt; nt = nt->next) {
32728547Sjlemon			if (ntp->net.s_addr == htonl(nt->net))
3281553Srgrimes				break;
3291553Srgrimes		}
33030642Scharnier		if ((nflag && !nt) || (iflag && nt))
3311553Srgrimes			continue;
3321553Srgrimes
3331553Srgrimes		ntp->next = NULL;
3341553Srgrimes		if (nettab == NULL) {
3351553Srgrimes			nettab = ntp;
3361553Srgrimes		} else {
3371553Srgrimes			ntip->next = ntp;
3381553Srgrimes		}
3391553Srgrimes		ntip = ntp;
3401553Srgrimes		ntp = NULL;
3411553Srgrimes	}
3421553Srgrimes	if (ntp)
3431553Srgrimes		(void) free((char *)ntp);
34430642Scharnier	if (nettab == NULL)
34530642Scharnier		errx(1, "no network usable");
3461553Srgrimes
3471553Srgrimes	/* microseconds to delay before responding to a broadcast */
3481553Srgrimes	delay1 = casual(1, 100*1000);
3491553Srgrimes
3501553Srgrimes	/* election timer delay in secs. */
3511553Srgrimes	delay2 = casual(MINTOUT, MAXTOUT);
3521553Srgrimes
3531553Srgrimes	if (!debug)
3541553Srgrimes		daemon(debug, 0);
3551553Srgrimes
3561553Srgrimes	if (trace)
3571553Srgrimes		traceon();
3581553Srgrimes	openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
3591553Srgrimes
3601553Srgrimes	/*
3611553Srgrimes	 * keep returning here
3621553Srgrimes	 */
3631553Srgrimes	ret = setjmp(jmpenv);
3641553Srgrimes	savefromnet = fromnet;
3651553Srgrimes	setstatus();
3661553Srgrimes
3671553Srgrimes	if (Mflag) {
3681553Srgrimes		switch (ret) {
3691553Srgrimes
3701553Srgrimes		case 0:
3711553Srgrimes			checkignorednets();
3721553Srgrimes			pickslavenet(0);
3731553Srgrimes			break;
3741553Srgrimes		case 1:
3751553Srgrimes			/* Just lost our master */
376299707Spfg			if (slavenet != NULL)
3771553Srgrimes				slavenet->status = election(slavenet);
3781553Srgrimes			if (!slavenet || slavenet->status == MASTER) {
3791553Srgrimes				checkignorednets();
3801553Srgrimes				pickslavenet(0);
3811553Srgrimes			} else {
3821553Srgrimes				makeslave(slavenet);	/* prune extras */
3831553Srgrimes			}
3841553Srgrimes			break;
3851553Srgrimes
3861553Srgrimes		case 2:
3871553Srgrimes			/* Just been told to quit */
3881553Srgrimes			justquit = 1;
3891553Srgrimes			pickslavenet(savefromnet);
3901553Srgrimes			break;
3911553Srgrimes		}
3921553Srgrimes
3931553Srgrimes		setstatus();
3941553Srgrimes		if (!(status & MASTER) && sock_raw != -1) {
3951553Srgrimes			/* sock_raw is not being used now */
3961553Srgrimes			(void)close(sock_raw);
3971553Srgrimes			sock_raw = -1;
3981553Srgrimes		}
3991553Srgrimes
4001553Srgrimes		if (status == MASTER)
4011553Srgrimes			master();
4021553Srgrimes		else
4031553Srgrimes			slave();
4041553Srgrimes
4051553Srgrimes	} else {
4061553Srgrimes		if (sock_raw != -1) {
4071553Srgrimes			(void)close(sock_raw);
4081553Srgrimes			sock_raw = -1;
4091553Srgrimes		}
4101553Srgrimes
4111553Srgrimes		if (ret) {
4121553Srgrimes			/* we just lost our master or were told to quit */
4131553Srgrimes			justquit = 1;
4141553Srgrimes		}
4151553Srgrimes		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
416240388Skevlo			if (ntp->status == MASTER) {
4171553Srgrimes				rmnetmachs(ntp);
4181553Srgrimes				ntp->status = NOMASTER;
419240388Skevlo			}
4201553Srgrimes		}
4211553Srgrimes		checkignorednets();
4221553Srgrimes		pickslavenet(0);
4231553Srgrimes		setstatus();
4241553Srgrimes
4251553Srgrimes		slave();
4261553Srgrimes	}
4271553Srgrimes	/* NOTREACHED */
4281553Srgrimes	return(0);
4291553Srgrimes}
4301553Srgrimes
43130642Scharnierstatic void
432246209Scharnierusage(void)
43330642Scharnier{
43430642Scharnier#ifdef HAVENIS
43530642Scharnier	fprintf(stderr,
43630642Scharnier"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n");
43730642Scharnier#else
43830642Scharnier	fprintf(stderr,
43930642Scharnier"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n");
44030642Scharnier#endif /* HAVENIS */
44130642Scharnier	exit(1);
44230642Scharnier}
44330642Scharnier
4441553Srgrimes/*
4451553Srgrimes * suppress an upstart, untrustworthy, self-appointed master
4461553Srgrimes */
4471553Srgrimesvoid
448246209Scharniersuppress(struct sockaddr_in *addr, char *name, struct netinfo *net)
4491553Srgrimes{
4501553Srgrimes	struct sockaddr_in tgt;
4511553Srgrimes	char tname[MAXHOSTNAMELEN];
4521553Srgrimes	struct tsp msg;
4531553Srgrimes	static struct timeval wait;
4541553Srgrimes
4551553Srgrimes	if (trace)
4561553Srgrimes		fprintf(fd, "suppress: %s\n", name);
4571553Srgrimes	tgt = *addr;
458299709Spfg	(void)strlcpy(tname, name, sizeof(tname));
4591553Srgrimes
4601553Srgrimes	while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
4611553Srgrimes		if (trace)
4621553Srgrimes			fprintf(fd, "suppress:\tdiscarded packet from %s\n",
4631553Srgrimes				    name);
4641553Srgrimes	}
4651553Srgrimes
4661553Srgrimes	syslog(LOG_NOTICE, "suppressing false master %s", tname);
4671553Srgrimes	msg.tsp_type = TSP_QUIT;
46830830Scharnier	(void)strcpy(msg.tsp_name, hostname);
4691553Srgrimes	(void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
4701553Srgrimes}
4711553Srgrimes
4721553Srgrimesvoid
473246209Scharnierlookformaster(struct netinfo *ntp)
4741553Srgrimes{
4751553Srgrimes	struct tsp resp, conflict, *answer;
4761553Srgrimes	struct timeval ntime;
4771553Srgrimes	char mastername[MAXHOSTNAMELEN];
4781553Srgrimes	struct sockaddr_in masteraddr;
4791553Srgrimes
4801553Srgrimes	get_goodgroup(0);
4811553Srgrimes	ntp->status = SLAVE;
4821553Srgrimes
4831553Srgrimes	/* look for master */
4841553Srgrimes	resp.tsp_type = TSP_MASTERREQ;
48530830Scharnier	(void)strcpy(resp.tsp_name, hostname);
4861553Srgrimes	answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
4871553Srgrimes			 TSP_MASTERACK, ntp, 0);
488299707Spfg	if (answer != NULL && !good_host_name(answer->tsp_name)) {
4891553Srgrimes		suppress(&from, answer->tsp_name, ntp);
4901553Srgrimes		ntp->status = NOMASTER;
491299707Spfg		answer = NULL;
4921553Srgrimes	}
493299707Spfg	if (answer == NULL) {
4941553Srgrimes		/*
4951553Srgrimes		 * Various conditions can cause conflict: races between
4961553Srgrimes		 * two just started timedaemons when no master is
4971553Srgrimes		 * present, or timedaemons started during an election.
4981553Srgrimes		 * A conservative approach is taken.  Give up and became a
4991553Srgrimes		 * slave, postponing election of a master until first
5001553Srgrimes		 * timer expires.
5011553Srgrimes		 */
5021553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5031553Srgrimes		answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
504299707Spfg		if (answer != NULL) {
5051553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5061553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5071553Srgrimes				ntp->status = NOMASTER;
5081553Srgrimes			}
5091553Srgrimes			return;
5101553Srgrimes		}
5111553Srgrimes
5121553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5131553Srgrimes		answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
514299707Spfg		if (answer != NULL) {
5151553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5161553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5171553Srgrimes				ntp->status = NOMASTER;
5181553Srgrimes			}
5191553Srgrimes			return;
5201553Srgrimes		}
5211553Srgrimes
5221553Srgrimes		ntime.tv_sec = ntime.tv_usec = 0;
5231553Srgrimes		answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
524299707Spfg		if (answer != NULL) {
5251553Srgrimes			if (!good_host_name(answer->tsp_name)) {
5261553Srgrimes				suppress(&from, answer->tsp_name, ntp);
5271553Srgrimes				ntp->status = NOMASTER;
5281553Srgrimes			}
5291553Srgrimes			return;
5301553Srgrimes		}
5311553Srgrimes
5321553Srgrimes		if (Mflag)
5331553Srgrimes			ntp->status = MASTER;
5341553Srgrimes		else
5351553Srgrimes			ntp->status = NOMASTER;
5361553Srgrimes		return;
5371553Srgrimes	}
5381553Srgrimes
5391553Srgrimes	ntp->status = SLAVE;
54030830Scharnier	(void)strcpy(mastername, answer->tsp_name);
5411553Srgrimes	masteraddr = from;
5421553Srgrimes
5431553Srgrimes	/*
5441553Srgrimes	 * If network has been partitioned, there might be other
5451553Srgrimes	 * masters; tell the one we have just acknowledged that
5461553Srgrimes	 * it has to gain control over the others.
5471553Srgrimes	 */
5481553Srgrimes	ntime.tv_sec = 0;
5491553Srgrimes	ntime.tv_usec = 300000;
5501553Srgrimes	answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
5511553Srgrimes	/*
5521553Srgrimes	 * checking also not to send CONFLICT to ack'ed master
5531553Srgrimes	 * due to duplicated MASTERACKs
5541553Srgrimes	 */
5551553Srgrimes	if (answer != NULL &&
5561553Srgrimes	    strcmp(answer->tsp_name, mastername) != 0) {
5571553Srgrimes		conflict.tsp_type = TSP_CONFLICT;
55830830Scharnier		(void)strcpy(conflict.tsp_name, hostname);
5591553Srgrimes		if (!acksend(&conflict, &masteraddr, mastername,
5601553Srgrimes			     TSP_ACK, 0, 0)) {
5611553Srgrimes			syslog(LOG_ERR,
5621553Srgrimes			       "error on sending TSP_CONFLICT");
5631553Srgrimes		}
5641553Srgrimes	}
5651553Srgrimes}
5661553Srgrimes
5671553Srgrimes/*
5681553Srgrimes * based on the current network configuration, set the status, and count
5691553Srgrimes * networks;
5701553Srgrimes */
5711553Srgrimesvoid
572246209Scharniersetstatus(void)
5731553Srgrimes{
5741553Srgrimes	struct netinfo *ntp;
5751553Srgrimes
5761553Srgrimes	status = 0;
5771553Srgrimes	nmasternets = nslavenets = nnets = nignorednets = 0;
5781553Srgrimes	if (trace)
5791553Srgrimes		fprintf(fd, "Net status:\n");
5801553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
5811553Srgrimes		switch ((int)ntp->status) {
5821553Srgrimes		case MASTER:
5831553Srgrimes			nmasternets++;
5841553Srgrimes			break;
5851553Srgrimes		case SLAVE:
5861553Srgrimes			nslavenets++;
5871553Srgrimes			break;
5881553Srgrimes		case NOMASTER:
5891553Srgrimes		case IGNORE:
5901553Srgrimes			nignorednets++;
5911553Srgrimes			break;
5921553Srgrimes		}
5931553Srgrimes		if (trace) {
5941553Srgrimes			fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
5951553Srgrimes			switch ((int)ntp->status) {
5961553Srgrimes			case NOMASTER:
5971553Srgrimes				fprintf(fd, "NOMASTER\n");
5981553Srgrimes				break;
5991553Srgrimes			case MASTER:
6001553Srgrimes				fprintf(fd, "MASTER\n");
6011553Srgrimes				break;
6021553Srgrimes			case SLAVE:
6031553Srgrimes				fprintf(fd, "SLAVE\n");
6041553Srgrimes				break;
6051553Srgrimes			case IGNORE:
6061553Srgrimes				fprintf(fd, "IGNORE\n");
6071553Srgrimes				break;
6081553Srgrimes			default:
6091553Srgrimes				fprintf(fd, "invalid state %d\n",
6101553Srgrimes					(int)ntp->status);
6111553Srgrimes				break;
6121553Srgrimes			}
6131553Srgrimes		}
6141553Srgrimes		nnets++;
6151553Srgrimes		status |= ntp->status;
6161553Srgrimes	}
6171553Srgrimes	status &= ~IGNORE;
6181553Srgrimes	if (trace)
6191553Srgrimes		fprintf(fd,
62037268Sbde		    "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n",
62137268Sbde		    nnets, nmasternets, nslavenets, nignorednets, delay2);
6221553Srgrimes}
6231553Srgrimes
6241553Srgrimesvoid
625246209Scharniermakeslave(struct netinfo *net)
6261553Srgrimes{
6271553Srgrimes	register struct netinfo *ntp;
6281553Srgrimes
6291553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
6301553Srgrimes		if (ntp->status == SLAVE && ntp != net)
6311553Srgrimes			ntp->status = IGNORE;
6321553Srgrimes	}
6331553Srgrimes	slavenet = net;
6341553Srgrimes}
6351553Srgrimes
6361553Srgrimes/*
6371553Srgrimes * Try to become master over ignored nets..
6381553Srgrimes */
6391553Srgrimesstatic void
640246209Scharniercheckignorednets(void)
6411553Srgrimes{
6421553Srgrimes	register struct netinfo *ntp;
6431553Srgrimes
6441553Srgrimes	for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
6451553Srgrimes		if (!Mflag && ntp->status == SLAVE)
6461553Srgrimes			break;
6471553Srgrimes
6481553Srgrimes		if (ntp->status == IGNORE || ntp->status == NOMASTER) {
6491553Srgrimes			lookformaster(ntp);
6501553Srgrimes			if (!Mflag && ntp->status == SLAVE)
6511553Srgrimes				break;
6521553Srgrimes		}
6531553Srgrimes	}
6541553Srgrimes}
6551553Srgrimes
6561553Srgrimes/*
6571553Srgrimes * choose a good network on which to be a slave
6581553Srgrimes *	The ignored networks must have already been checked.
6591553Srgrimes *	Take a hint about for a good network.
6601553Srgrimes */
6611553Srgrimesstatic void
662246209Scharnierpickslavenet(struct netinfo *ntp)
6631553Srgrimes{
664299707Spfg	if (slavenet != NULL && slavenet->status == SLAVE) {
6651553Srgrimes		makeslave(slavenet);		/* prune extras */
6661553Srgrimes		return;
6671553Srgrimes	}
6681553Srgrimes
669299707Spfg	if (ntp == NULL || ntp->status != SLAVE) {
670299707Spfg		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
6711553Srgrimes			if (ntp->status == SLAVE)
6721553Srgrimes				break;
6731553Srgrimes		}
6741553Srgrimes	}
6751553Srgrimes	makeslave(ntp);
6761553Srgrimes}
6771553Srgrimes
6781553Srgrimes/*
6791553Srgrimes * returns a random number in the range [inf, sup]
6801553Srgrimes */
6811553Srgrimeslong
682246209Scharniercasual(long inf, long sup)
6831553Srgrimes{
6841553Srgrimes	double value;
6851553Srgrimes
6861553Srgrimes	value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
6871553Srgrimes	return(inf + (sup - inf)*value);
6881553Srgrimes}
6891553Srgrimes
6901553Srgrimeschar *
691246209Scharnierdate(void)
6921553Srgrimes{
69337268Sbde	time_t	tv_sec;
6941553Srgrimes
695239991Sed	tv_sec = time(NULL);
69637268Sbde	return (ctime(&tv_sec));
6971553Srgrimes}
6981553Srgrimes
6991553Srgrimesvoid
700246209Scharnieraddnetname(char *name)
7011553Srgrimes{
7021553Srgrimes	register struct nets **netlist = &nets;
7031553Srgrimes
7041553Srgrimes	while (*netlist)
7051553Srgrimes		netlist = &((*netlist)->next);
7061553Srgrimes	*netlist = (struct nets *)malloc(sizeof **netlist);
707299707Spfg	if (*netlist == NULL)
70830642Scharnier		errx(1, "malloc failed");
7091553Srgrimes	bzero((char *)*netlist, sizeof(**netlist));
7101553Srgrimes	(*netlist)->name = name;
7111553Srgrimes}
7121553Srgrimes
713246209Scharnier/* note a host as trustworthy
714246209Scharnier * perm		1=not part of the netgroup
715246209Scharnier */
7161553Srgrimesstatic void
717246209Scharnieradd_good_host(char *name, int perm)
7181553Srgrimes{
7191553Srgrimes	register struct goodhost *ghp;
7201553Srgrimes	register struct hostent *hentp;
7211553Srgrimes
7221553Srgrimes	ghp = (struct goodhost*)malloc(sizeof(*ghp));
7231553Srgrimes	if (!ghp) {
7241553Srgrimes		syslog(LOG_ERR, "malloc failed");
7251553Srgrimes		exit(1);
7261553Srgrimes	}
7271553Srgrimes
7281553Srgrimes	bzero((char*)ghp, sizeof(*ghp));
7291553Srgrimes	(void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
7301553Srgrimes	ghp->next = goodhosts;
7311553Srgrimes	ghp->perm = perm;
7321553Srgrimes	goodhosts = ghp;
7331553Srgrimes
7341553Srgrimes	hentp = gethostbyname(name);
735299707Spfg	if (hentp == NULL && perm)
73630642Scharnier		warnx("unknown host %s", name);
7371553Srgrimes}
7381553Srgrimes
7391553Srgrimes
7401553Srgrimes/* update our image of the net-group of trustworthy hosts
7411553Srgrimes */
7421553Srgrimesvoid
743246209Scharnierget_goodgroup(int force)
7441553Srgrimes{
7451553Srgrimes# define NG_DELAY (30*60*CLK_TCK)	/* 30 minutes */
7461553Srgrimes	static unsigned long last_update = -NG_DELAY;
7471553Srgrimes	unsigned long new_update;
74830642Scharnier	struct goodhost *ghp, **ghpp;
74930642Scharnier#ifdef HAVENIS
7501553Srgrimes	struct hosttbl *htp;
7511553Srgrimes	char *mach, *usr, *dom;
75230642Scharnier#endif /* HAVENIS */
7531553Srgrimes	struct tms tm;
7541553Srgrimes
7551553Srgrimes
7561553Srgrimes	/* if no netgroup, then we are finished */
757299707Spfg	if (goodgroup == NULL || !Mflag)
7581553Srgrimes		return;
7591553Srgrimes
7601553Srgrimes	/* Do not chatter with the netgroup master too often.
7611553Srgrimes	 */
7621553Srgrimes	new_update = times(&tm);
7631553Srgrimes	if (new_update < last_update + NG_DELAY
7641553Srgrimes	    && !force)
7651553Srgrimes		return;
7661553Srgrimes	last_update = new_update;
7671553Srgrimes
7681553Srgrimes	/* forget the old temporary entries */
7691553Srgrimes	ghpp = &goodhosts;
770299707Spfg	while ((ghp = *ghpp) != NULL) {
7711553Srgrimes		if (!ghp->perm) {
7721553Srgrimes			*ghpp = ghp->next;
773299707Spfg			free(ghp);
7741553Srgrimes		} else {
7751553Srgrimes			ghpp = &ghp->next;
7761553Srgrimes		}
7771553Srgrimes	}
7781553Srgrimes
7791553Srgrimes#ifdef HAVENIS
7801553Srgrimes	/* quit now if we are not one of the trusted masters
7811553Srgrimes	 */
7821553Srgrimes	if (!innetgr(goodgroup, &hostname[0], 0,0)) {
7831553Srgrimes		if (trace)
7841553Srgrimes			(void)fprintf(fd, "get_goodgroup: %s not in %s\n",
7851553Srgrimes				      &hostname[0], goodgroup);
7861553Srgrimes		return;
7871553Srgrimes	}
7881553Srgrimes	if (trace)
7891553Srgrimes		(void)fprintf(fd, "get_goodgroup: %s in %s\n",
7901553Srgrimes				  &hostname[0], goodgroup);
7911553Srgrimes
7921553Srgrimes	/* mark the entire netgroup as trusted */
7931553Srgrimes	(void)setnetgrent(goodgroup);
7941553Srgrimes	while (getnetgrent(&mach,&usr,&dom)) {
795299707Spfg		if (mach != NULL)
7961553Srgrimes			add_good_host(mach,0);
7971553Srgrimes	}
7981553Srgrimes	(void)endnetgrent();
7991553Srgrimes
8001553Srgrimes	/* update list of slaves */
8011553Srgrimes	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
8021553Srgrimes		htp->good = good_host_name(&htp->name[0]);
8031553Srgrimes	}
8041553Srgrimes#endif /* HAVENIS */
8051553Srgrimes}
8061553Srgrimes
8071553Srgrimes
8081553Srgrimes/* see if a machine is trustworthy
8091553Srgrimes */
8101553Srgrimesint					/* 1=trust hp to change our date */
811246209Scharniergood_host_name(char *name)
8121553Srgrimes{
8131553Srgrimes	register struct goodhost *ghp = goodhosts;
8141553Srgrimes	register char c;
8151553Srgrimes
8161553Srgrimes	if (!ghp || !Mflag)		/* trust everyone if no one named */
8171553Srgrimes		return 1;
8181553Srgrimes
8191553Srgrimes	c = *name;
8201553Srgrimes	do {
8211553Srgrimes		if (c == ghp->name[0]
8221553Srgrimes		    && !strcasecmp(name, ghp->name))
8231553Srgrimes			return 1;	/* found him, so say so */
824299707Spfg	} while ((ghp = ghp->next) != NULL);
8251553Srgrimes
8261553Srgrimes	if (!strcasecmp(name,hostname))	/* trust ourself */
8271553Srgrimes		return 1;
8281553Srgrimes
8291553Srgrimes	return 0;			/* did not find him */
8301553Srgrimes}
831