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