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