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