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