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