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