timed.c revision 8532
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.1.1.1 $" 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 bzero(&server, sizeof(struct sockaddr_in)); 316 server.sin_port = srvp->s_port; 317 server.sin_family = AF_INET; 318 sock = socket(AF_INET, SOCK_DGRAM, 0); 319 if (sock < 0) { 320 perror("socket"); 321 exit(1); 322 } 323 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, 324 sizeof(on)) < 0) { 325 perror("setsockopt"); 326 exit(1); 327 } 328 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { 329 if (errno == EADDRINUSE) 330 fprintf(stderr,"timed: time daemon already running\n"); 331 else 332 perror("bind"); 333 exit(1); 334 } 335#ifdef sgi 336 /* 337 * handle many slaves with our buffer 338 */ 339 if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace, 340 sizeof(bufspace))) { 341 perror("setsockopt"); 342 exit(1); 343 } 344#endif /* sgi */ 345 346 /* choose a unique seed for random number generation */ 347 (void)gettimeofday(&ntime, 0); 348 srandom(ntime.tv_sec + ntime.tv_usec); 349 350 sequence = random(); /* initial seq number */ 351 352#ifndef sgi 353 /* rounds kernel variable time to multiple of 5 ms. */ 354 ntime.tv_sec = 0; 355 ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000; 356 (void)adjtime(&ntime, (struct timeval *)0); 357#endif /* sgi */ 358 359 for (nt = nets; nt; nt = nt->next) { 360 nentp = getnetbyname(nt->name); 361 if (nentp == 0) { 362 nt->net = inet_network(nt->name); 363 if (nt->net != INADDR_NONE) 364 nentp = getnetbyaddr(nt->net, AF_INET); 365 } 366 if (nentp != 0) { 367 nt->net = nentp->n_net; 368 } else if (nt->net == INADDR_NONE) { 369 fprintf(stderr, "timed: unknown net %s\n", nt->name); 370 exit(1); 371 } else if (nt->net == INADDR_ANY) { 372 fprintf(stderr, "timed: bad net %s\n", nt->name); 373 exit(1); 374 } else { 375 fprintf(stderr, 376 "timed: warning: %s unknown in /etc/networks\n", 377 nt->name); 378 } 379 380 if (0 == (nt->net & 0xff000000)) 381 nt->net <<= 8; 382 if (0 == (nt->net & 0xff000000)) 383 nt->net <<= 8; 384 if (0 == (nt->net & 0xff000000)) 385 nt->net <<= 8; 386 } 387 ifc.ifc_len = sizeof(buf); 388 ifc.ifc_buf = buf; 389 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 390 perror("timed: get interface configuration"); 391 exit(1); 392 } 393 ntp = NULL; 394#ifdef sgi 395#define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */ 396#else 397#define size(p) max((p).sa_len, sizeof(p)) 398#endif 399 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 400 for (cp = buf; cp < cplim; 401 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 402 ifr = (struct ifreq *)cp; 403 if (ifr->ifr_addr.sa_family != AF_INET) 404 continue; 405 if (!ntp) 406 ntp = (struct netinfo*)malloc(sizeof(struct netinfo)); 407 bzero(ntp,sizeof(*ntp)); 408 ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; 409 ntp->status = NOMASTER; 410 ifreq = *ifr; 411 ifreqf = *ifr; 412 413 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) { 414 perror("get interface flags"); 415 continue; 416 } 417 if ((ifreqf.ifr_flags & IFF_UP) == 0) 418 continue; 419 if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 && 420 (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) { 421 continue; 422 } 423 424 425 if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 426 perror("get netmask"); 427 continue; 428 } 429 ntp->mask = ((struct sockaddr_in *) 430 &ifreq.ifr_addr)->sin_addr.s_addr; 431 432 if (ifreqf.ifr_flags & IFF_BROADCAST) { 433 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 434 perror("get broadaddr"); 435 continue; 436 } 437 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; 438 /* What if the broadcast address is all ones? 439 * So we cannot just mask ntp->dest_addr. */ 440 ntp->net = ntp->my_addr; 441 ntp->net.s_addr &= ntp->mask; 442 } else { 443 if (ioctl(sock, SIOCGIFDSTADDR, 444 (char *)&ifreq) < 0) { 445 perror("get destaddr"); 446 continue; 447 } 448 ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; 449 ntp->net = ntp->dest_addr.sin_addr; 450 } 451 452 ntp->dest_addr.sin_port = port; 453 454 for (nt = nets; nt; nt = nt->next) { 455 if (ntp->net.s_addr == nt->net) 456 break; 457 } 458 if (nflag && !nt || iflag && nt) 459 continue; 460 461 ntp->next = NULL; 462 if (nettab == NULL) { 463 nettab = ntp; 464 } else { 465 ntip->next = ntp; 466 } 467 ntip = ntp; 468 ntp = NULL; 469 } 470 if (ntp) 471 (void) free((char *)ntp); 472 if (nettab == NULL) { 473 fprintf(stderr, "timed: no network usable\n"); 474 exit(1); 475 } 476 477 478#ifdef sgi 479 (void)schedctl(RENICE,0,10); /* run fast to get good time */ 480 481 /* ticks to delay before responding to a broadcast */ 482 delay1 = casual(0, CLK_TCK/10); 483#else 484 485 /* microseconds to delay before responding to a broadcast */ 486 delay1 = casual(1, 100*1000); 487#endif /* sgi */ 488 489 /* election timer delay in secs. */ 490 delay2 = casual(MINTOUT, MAXTOUT); 491 492 493#ifdef sgi 494 (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1); 495#else 496 if (!debug) 497 daemon(debug, 0); 498#endif /* sgi */ 499 500 if (trace) 501 traceon(); 502 openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON); 503 504 /* 505 * keep returning here 506 */ 507 ret = setjmp(jmpenv); 508 savefromnet = fromnet; 509 setstatus(); 510 511 if (Mflag) { 512 switch (ret) { 513 514 case 0: 515 checkignorednets(); 516 pickslavenet(0); 517 break; 518 case 1: 519 /* Just lost our master */ 520 if (slavenet != 0) 521 slavenet->status = election(slavenet); 522 if (!slavenet || slavenet->status == MASTER) { 523 checkignorednets(); 524 pickslavenet(0); 525 } else { 526 makeslave(slavenet); /* prune extras */ 527 } 528 break; 529 530 case 2: 531 /* Just been told to quit */ 532 justquit = 1; 533 pickslavenet(savefromnet); 534 break; 535 } 536 537 setstatus(); 538 if (!(status & MASTER) && sock_raw != -1) { 539 /* sock_raw is not being used now */ 540 (void)close(sock_raw); 541 sock_raw = -1; 542 } 543 544 if (status == MASTER) 545 master(); 546 else 547 slave(); 548 549 } else { 550 if (sock_raw != -1) { 551 (void)close(sock_raw); 552 sock_raw = -1; 553 } 554 555 if (ret) { 556 /* we just lost our master or were told to quit */ 557 justquit = 1; 558 } 559 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 560 if (ntp->status == MASTER) 561 rmnetmachs(ntp); 562 ntp->status = NOMASTER; 563 } 564 checkignorednets(); 565 pickslavenet(0); 566 setstatus(); 567 568 slave(); 569 } 570 /* NOTREACHED */ 571#ifdef lint 572 return(0); 573#endif 574} 575 576/* 577 * suppress an upstart, untrustworthy, self-appointed master 578 */ 579void 580suppress(addr, name,net) 581 struct sockaddr_in *addr; 582 char *name; 583 struct netinfo *net; 584{ 585 struct sockaddr_in tgt; 586 char tname[MAXHOSTNAMELEN]; 587 struct tsp msg; 588 static struct timeval wait; 589 590 if (trace) 591 fprintf(fd, "suppress: %s\n", name); 592 tgt = *addr; 593 (void)strcpy(tname, name); 594 595 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) { 596 if (trace) 597 fprintf(fd, "suppress:\tdiscarded packet from %s\n", 598 name); 599 } 600 601 syslog(LOG_NOTICE, "suppressing false master %s", tname); 602 msg.tsp_type = TSP_QUIT; 603 (void)strcpy(msg.tsp_name, hostname); 604 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1); 605} 606 607void 608lookformaster(ntp) 609 struct netinfo *ntp; 610{ 611 struct tsp resp, conflict, *answer; 612 struct timeval ntime; 613 char mastername[MAXHOSTNAMELEN]; 614 struct sockaddr_in masteraddr; 615 616 get_goodgroup(0); 617 ntp->status = SLAVE; 618 619 /* look for master */ 620 resp.tsp_type = TSP_MASTERREQ; 621 (void)strcpy(resp.tsp_name, hostname); 622 answer = acksend(&resp, &ntp->dest_addr, ANYADDR, 623 TSP_MASTERACK, ntp, 0); 624 if (answer != 0 && !good_host_name(answer->tsp_name)) { 625 suppress(&from, answer->tsp_name, ntp); 626 ntp->status = NOMASTER; 627 answer = 0; 628 } 629 if (answer == 0) { 630 /* 631 * Various conditions can cause conflict: races between 632 * two just started timedaemons when no master is 633 * present, or timedaemons started during an election. 634 * A conservative approach is taken. Give up and became a 635 * slave, postponing election of a master until first 636 * timer expires. 637 */ 638 ntime.tv_sec = ntime.tv_usec = 0; 639 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp); 640 if (answer != 0) { 641 if (!good_host_name(answer->tsp_name)) { 642 suppress(&from, answer->tsp_name, ntp); 643 ntp->status = NOMASTER; 644 } 645 return; 646 } 647 648 ntime.tv_sec = ntime.tv_usec = 0; 649 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp); 650 if (answer != 0) { 651 if (!good_host_name(answer->tsp_name)) { 652 suppress(&from, answer->tsp_name, ntp); 653 ntp->status = NOMASTER; 654 } 655 return; 656 } 657 658 ntime.tv_sec = ntime.tv_usec = 0; 659 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp); 660 if (answer != 0) { 661 if (!good_host_name(answer->tsp_name)) { 662 suppress(&from, answer->tsp_name, ntp); 663 ntp->status = NOMASTER; 664 } 665 return; 666 } 667 668 if (Mflag) 669 ntp->status = MASTER; 670 else 671 ntp->status = NOMASTER; 672 return; 673 } 674 675 ntp->status = SLAVE; 676 (void)strcpy(mastername, answer->tsp_name); 677 masteraddr = from; 678 679 /* 680 * If network has been partitioned, there might be other 681 * masters; tell the one we have just acknowledged that 682 * it has to gain control over the others. 683 */ 684 ntime.tv_sec = 0; 685 ntime.tv_usec = 300000; 686 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp); 687 /* 688 * checking also not to send CONFLICT to ack'ed master 689 * due to duplicated MASTERACKs 690 */ 691 if (answer != NULL && 692 strcmp(answer->tsp_name, mastername) != 0) { 693 conflict.tsp_type = TSP_CONFLICT; 694 (void)strcpy(conflict.tsp_name, hostname); 695 if (!acksend(&conflict, &masteraddr, mastername, 696 TSP_ACK, 0, 0)) { 697 syslog(LOG_ERR, 698 "error on sending TSP_CONFLICT"); 699 } 700 } 701} 702 703/* 704 * based on the current network configuration, set the status, and count 705 * networks; 706 */ 707void 708setstatus() 709{ 710 struct netinfo *ntp; 711 712 status = 0; 713 nmasternets = nslavenets = nnets = nignorednets = 0; 714 if (trace) 715 fprintf(fd, "Net status:\n"); 716 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 717 switch ((int)ntp->status) { 718 case MASTER: 719 nmasternets++; 720 break; 721 case SLAVE: 722 nslavenets++; 723 break; 724 case NOMASTER: 725 case IGNORE: 726 nignorednets++; 727 break; 728 } 729 if (trace) { 730 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); 731 switch ((int)ntp->status) { 732 case NOMASTER: 733 fprintf(fd, "NOMASTER\n"); 734 break; 735 case MASTER: 736 fprintf(fd, "MASTER\n"); 737 break; 738 case SLAVE: 739 fprintf(fd, "SLAVE\n"); 740 break; 741 case IGNORE: 742 fprintf(fd, "IGNORE\n"); 743 break; 744 default: 745 fprintf(fd, "invalid state %d\n", 746 (int)ntp->status); 747 break; 748 } 749 } 750 nnets++; 751 status |= ntp->status; 752 } 753 status &= ~IGNORE; 754 if (trace) 755 fprintf(fd, 756 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n", 757 nnets, nmasternets, nslavenets, nignorednets, delay2); 758} 759 760void 761makeslave(net) 762 struct netinfo *net; 763{ 764 register struct netinfo *ntp; 765 766 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 767 if (ntp->status == SLAVE && ntp != net) 768 ntp->status = IGNORE; 769 } 770 slavenet = net; 771} 772 773/* 774 * Try to become master over ignored nets.. 775 */ 776static void 777checkignorednets() 778{ 779 register struct netinfo *ntp; 780 781 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 782 if (!Mflag && ntp->status == SLAVE) 783 break; 784 785 if (ntp->status == IGNORE || ntp->status == NOMASTER) { 786 lookformaster(ntp); 787 if (!Mflag && ntp->status == SLAVE) 788 break; 789 } 790 } 791} 792 793/* 794 * choose a good network on which to be a slave 795 * The ignored networks must have already been checked. 796 * Take a hint about for a good network. 797 */ 798static void 799pickslavenet(ntp) 800 struct netinfo *ntp; 801{ 802 if (slavenet != 0 && slavenet->status == SLAVE) { 803 makeslave(slavenet); /* prune extras */ 804 return; 805 } 806 807 if (ntp == 0 || ntp->status != SLAVE) { 808 for (ntp = nettab; ntp != 0; ntp = ntp->next) { 809 if (ntp->status == SLAVE) 810 break; 811 } 812 } 813 makeslave(ntp); 814} 815 816/* 817 * returns a random number in the range [inf, sup] 818 */ 819long 820casual(inf, sup) 821 long inf, sup; 822{ 823 double value; 824 825 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0); 826 return(inf + (sup - inf)*value); 827} 828 829char * 830date() 831{ 832#ifdef sgi 833 struct timeval tv; 834 static char tm[32]; 835 836 (void)gettimeofday(&tv, (struct timezone *)0); 837 (void)cftime(tm, "%D %T", &tv.tv_sec); 838 return (tm); 839#else 840 struct timeval tv; 841 842 (void)gettimeofday(&tv, (struct timezone *)0); 843 return (ctime(&tv.tv_sec)); 844#endif /* sgi */ 845} 846 847void 848addnetname(name) 849 char *name; 850{ 851 register struct nets **netlist = &nets; 852 853 while (*netlist) 854 netlist = &((*netlist)->next); 855 *netlist = (struct nets *)malloc(sizeof **netlist); 856 if (*netlist == 0) { 857 fprintf(stderr,"malloc failed\n"); 858 exit(1); 859 } 860 bzero((char *)*netlist, sizeof(**netlist)); 861 (*netlist)->name = name; 862} 863 864/* note a host as trustworthy */ 865static void 866add_good_host(name, perm) 867 char *name; 868 int perm; /* 1=not part of the netgroup */ 869{ 870 register struct goodhost *ghp; 871 register struct hostent *hentp; 872 873 ghp = (struct goodhost*)malloc(sizeof(*ghp)); 874 if (!ghp) { 875 syslog(LOG_ERR, "malloc failed"); 876 exit(1); 877 } 878 879 bzero((char*)ghp, sizeof(*ghp)); 880 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); 881 ghp->next = goodhosts; 882 ghp->perm = perm; 883 goodhosts = ghp; 884 885 hentp = gethostbyname(name); 886 if (0 == hentp && perm) 887 (void)fprintf(stderr, "unknown host %s\n", name); 888} 889 890 891/* update our image of the net-group of trustworthy hosts 892 */ 893void 894get_goodgroup(force) 895 int force; 896{ 897# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ 898 static unsigned long last_update = -NG_DELAY; 899 unsigned long new_update; 900 struct hosttbl *htp; 901 struct goodhost *ghp, **ghpp; 902 char *mach, *usr, *dom; 903 struct tms tm; 904 905 906 /* if no netgroup, then we are finished */ 907 if (goodgroup == 0 || !Mflag) 908 return; 909 910 /* Do not chatter with the netgroup master too often. 911 */ 912 new_update = times(&tm); 913 if (new_update < last_update + NG_DELAY 914 && !force) 915 return; 916 last_update = new_update; 917 918 /* forget the old temporary entries */ 919 ghpp = &goodhosts; 920 while (0 != (ghp = *ghpp)) { 921 if (!ghp->perm) { 922 *ghpp = ghp->next; 923 free((char*)ghp); 924 } else { 925 ghpp = &ghp->next; 926 } 927 } 928 929#ifdef HAVENIS 930 /* quit now if we are not one of the trusted masters 931 */ 932 if (!innetgr(goodgroup, &hostname[0], 0,0)) { 933 if (trace) 934 (void)fprintf(fd, "get_goodgroup: %s not in %s\n", 935 &hostname[0], goodgroup); 936 return; 937 } 938 if (trace) 939 (void)fprintf(fd, "get_goodgroup: %s in %s\n", 940 &hostname[0], goodgroup); 941 942 /* mark the entire netgroup as trusted */ 943 (void)setnetgrent(goodgroup); 944 while (getnetgrent(&mach,&usr,&dom)) { 945 if (0 != mach) 946 add_good_host(mach,0); 947 } 948 (void)endnetgrent(); 949 950 /* update list of slaves */ 951 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 952 htp->good = good_host_name(&htp->name[0]); 953 } 954#endif /* HAVENIS */ 955} 956 957 958/* see if a machine is trustworthy 959 */ 960int /* 1=trust hp to change our date */ 961good_host_name(name) 962 char *name; 963{ 964 register struct goodhost *ghp = goodhosts; 965 register char c; 966 967 if (!ghp || !Mflag) /* trust everyone if no one named */ 968 return 1; 969 970 c = *name; 971 do { 972 if (c == ghp->name[0] 973 && !strcasecmp(name, ghp->name)) 974 return 1; /* found him, so say so */ 975 } while (0 != (ghp = ghp->next)); 976 977 if (!strcasecmp(name,hostname)) /* trust ourself */ 978 return 1; 979 980 return 0; /* did not find him */ 981} 982