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