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