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