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