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