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