timed.c revision 240388
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 240388 2012-09-12 10:16:39Z kevlo $"); 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, NULL); 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 } 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 time_t tv_sec; 706 707 tv_sec = time(NULL); 708 return (ctime(&tv_sec)); 709} 710 711void 712addnetname(name) 713 char *name; 714{ 715 register struct nets **netlist = &nets; 716 717 while (*netlist) 718 netlist = &((*netlist)->next); 719 *netlist = (struct nets *)malloc(sizeof **netlist); 720 if (*netlist == 0) 721 errx(1, "malloc failed"); 722 bzero((char *)*netlist, sizeof(**netlist)); 723 (*netlist)->name = name; 724} 725 726/* note a host as trustworthy */ 727static void 728add_good_host(name, perm) 729 char *name; 730 int perm; /* 1=not part of the netgroup */ 731{ 732 register struct goodhost *ghp; 733 register struct hostent *hentp; 734 735 ghp = (struct goodhost*)malloc(sizeof(*ghp)); 736 if (!ghp) { 737 syslog(LOG_ERR, "malloc failed"); 738 exit(1); 739 } 740 741 bzero((char*)ghp, sizeof(*ghp)); 742 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); 743 ghp->next = goodhosts; 744 ghp->perm = perm; 745 goodhosts = ghp; 746 747 hentp = gethostbyname(name); 748 if (0 == hentp && perm) 749 warnx("unknown host %s", name); 750} 751 752 753/* update our image of the net-group of trustworthy hosts 754 */ 755void 756get_goodgroup(force) 757 int force; 758{ 759# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ 760 static unsigned long last_update = -NG_DELAY; 761 unsigned long new_update; 762 struct goodhost *ghp, **ghpp; 763#ifdef HAVENIS 764 struct hosttbl *htp; 765 char *mach, *usr, *dom; 766#endif /* HAVENIS */ 767 struct tms tm; 768 769 770 /* if no netgroup, then we are finished */ 771 if (goodgroup == 0 || !Mflag) 772 return; 773 774 /* Do not chatter with the netgroup master too often. 775 */ 776 new_update = times(&tm); 777 if (new_update < last_update + NG_DELAY 778 && !force) 779 return; 780 last_update = new_update; 781 782 /* forget the old temporary entries */ 783 ghpp = &goodhosts; 784 while (0 != (ghp = *ghpp)) { 785 if (!ghp->perm) { 786 *ghpp = ghp->next; 787 free((char*)ghp); 788 } else { 789 ghpp = &ghp->next; 790 } 791 } 792 793#ifdef HAVENIS 794 /* quit now if we are not one of the trusted masters 795 */ 796 if (!innetgr(goodgroup, &hostname[0], 0,0)) { 797 if (trace) 798 (void)fprintf(fd, "get_goodgroup: %s not in %s\n", 799 &hostname[0], goodgroup); 800 return; 801 } 802 if (trace) 803 (void)fprintf(fd, "get_goodgroup: %s in %s\n", 804 &hostname[0], goodgroup); 805 806 /* mark the entire netgroup as trusted */ 807 (void)setnetgrent(goodgroup); 808 while (getnetgrent(&mach,&usr,&dom)) { 809 if (0 != mach) 810 add_good_host(mach,0); 811 } 812 (void)endnetgrent(); 813 814 /* update list of slaves */ 815 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 816 htp->good = good_host_name(&htp->name[0]); 817 } 818#endif /* HAVENIS */ 819} 820 821 822/* see if a machine is trustworthy 823 */ 824int /* 1=trust hp to change our date */ 825good_host_name(name) 826 char *name; 827{ 828 register struct goodhost *ghp = goodhosts; 829 register char c; 830 831 if (!ghp || !Mflag) /* trust everyone if no one named */ 832 return 1; 833 834 c = *name; 835 do { 836 if (c == ghp->name[0] 837 && !strcasecmp(name, ghp->name)) 838 return 1; /* found him, so say so */ 839 } while (0 != (ghp = ghp->next)); 840 841 if (!strcasecmp(name,hostname)) /* trust ourself */ 842 return 1; 843 844 return 0; /* did not find him */ 845} 846