1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1985, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#ifndef lint 33static const char copyright[] = 34"@(#) Copyright (c) 1985, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36#endif /* not lint */ 37 38#if 0 39#ifndef lint 40static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93"; 41#endif /* not lint */ 42#endif 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD$"); 46 47#include "globals.h" 48#include <net/if.h> 49#include <sys/file.h> 50#include <sys/ioctl.h> 51#include <setjmp.h> 52#include "pathnames.h" 53#include <math.h> 54#include <sys/types.h> 55#include <sys/times.h> 56 57int trace = 0; 58int sock, sock_raw = -1; 59int status = 0; 60u_short sequence; /* sequence number */ 61long delay1; 62long delay2; 63 64int nslavenets; /* nets were I could be a slave */ 65int nmasternets; /* nets were I could be a master */ 66int nignorednets; /* ignored nets */ 67int nnets; /* nets I am connected to */ 68 69FILE *fd; /* trace file FD */ 70 71jmp_buf jmpenv; 72 73struct netinfo *nettab = NULL; 74struct netinfo *slavenet; 75int Mflag; 76int justquit = 0; 77int debug; 78 79static struct nets { 80 char *name; 81 long net; 82 struct nets *next; 83} *nets = NULL; 84 85struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */ 86 87static struct goodhost { /* hosts that we trust */ 88 char name[MAXHOSTNAMELEN]; 89 struct goodhost *next; 90 char perm; 91} *goodhosts; 92 93static char *goodgroup; /* net group of trusted hosts */ 94static void checkignorednets(void); 95static void pickslavenet(struct netinfo *); 96static void add_good_host(char *, int); 97static void usage(void); 98 99/* 100 * The timedaemons synchronize the clocks of hosts in a local area network. 101 * One daemon runs as master, all the others as slaves. The master 102 * performs the task of computing clock differences and sends correction 103 * values to the slaves. 104 * Slaves start an election to choose a new master when the latter disappears 105 * because of a machine crash, network partition, or when killed. 106 * A resolution protocol is used to kill all but one of the masters 107 * that happen to exist in segments of a partitioned network when the 108 * network partition is fixed. 109 * 110 * Authors: Riccardo Gusella & Stefano Zatti 111 * 112 * overhauled at Silicon Graphics 113 */ 114int 115main(int argc, 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 != NULL) 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 fprintf(stderr, "TIMED will be removed from FreeBSD-13, and will be " 196 "provided as a port (net/timed) or package (timed).\n"); 197 198 /* If we care about which machine is the master, then we must 199 * be willing to be a master 200 */ 201 if (goodgroup != NULL || goodhosts != NULL) 202 Mflag = 1; 203 204 if (gethostname(hostname, sizeof(hostname) - 1) < 0) 205 err(1, "gethostname"); 206 self.l_bak = &self; 207 self.l_fwd = &self; 208 self.h_bak = &self; 209 self.h_fwd = &self; 210 self.head = 1; 211 self.good = 1; 212 213 if (goodhosts != NULL) /* trust ourself */ 214 add_good_host(hostname,1); 215 216 srvp = getservbyname("timed", "udp"); 217 if (srvp == NULL) 218 errx(1, "timed/udp: unknown service"); 219 port = srvp->s_port; 220 bzero(&server, sizeof(struct sockaddr_in)); 221 server.sin_port = srvp->s_port; 222 server.sin_family = AF_INET; 223 sock = socket(AF_INET, SOCK_DGRAM, 0); 224 if (sock < 0) 225 err(1, "socket"); 226 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, 227 sizeof(on)) < 0) 228 err(1, "setsockopt"); 229 if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { 230 if (errno == EADDRINUSE) 231 warnx("time daemon already running"); 232 else 233 warn("bind"); 234 exit(1); 235 } 236 237 sequence = arc4random(); /* initial seq number */ 238 239 (void)gettimeofday(&ntime, NULL); 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 == NULL) { 248 nt->net = inet_network(nt->name); 249 if (nt->net != INADDR_NONE) 250 nentp = getnetbyaddr(nt->net, AF_INET); 251 } 252 if (nentp != NULL) { 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 != NULL) 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(void) 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(struct sockaddr_in *addr, char *name, struct netinfo *net) 454{ 455 struct sockaddr_in tgt; 456 char tname[MAXHOSTNAMELEN]; 457 struct tsp msg; 458 static struct timeval wait; 459 460 if (trace) 461 fprintf(fd, "suppress: %s\n", name); 462 tgt = *addr; 463 (void)strlcpy(tname, name, sizeof(tname)); 464 465 while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) { 466 if (trace) 467 fprintf(fd, "suppress:\tdiscarded packet from %s\n", 468 name); 469 } 470 471 syslog(LOG_NOTICE, "suppressing false master %s", tname); 472 msg.tsp_type = TSP_QUIT; 473 (void)strcpy(msg.tsp_name, hostname); 474 (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1); 475} 476 477void 478lookformaster(struct netinfo *ntp) 479{ 480 struct tsp resp, conflict, *answer; 481 struct timeval ntime; 482 char mastername[MAXHOSTNAMELEN]; 483 struct sockaddr_in masteraddr; 484 485 get_goodgroup(0); 486 ntp->status = SLAVE; 487 488 /* look for master */ 489 resp.tsp_type = TSP_MASTERREQ; 490 (void)strcpy(resp.tsp_name, hostname); 491 answer = acksend(&resp, &ntp->dest_addr, ANYADDR, 492 TSP_MASTERACK, ntp, 0); 493 if (answer != NULL && !good_host_name(answer->tsp_name)) { 494 suppress(&from, answer->tsp_name, ntp); 495 ntp->status = NOMASTER; 496 answer = NULL; 497 } 498 if (answer == NULL) { 499 /* 500 * Various conditions can cause conflict: races between 501 * two just started timedaemons when no master is 502 * present, or timedaemons started during an election. 503 * A conservative approach is taken. Give up and became a 504 * slave, postponing election of a master until first 505 * timer expires. 506 */ 507 ntime.tv_sec = ntime.tv_usec = 0; 508 answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp); 509 if (answer != NULL) { 510 if (!good_host_name(answer->tsp_name)) { 511 suppress(&from, answer->tsp_name, ntp); 512 ntp->status = NOMASTER; 513 } 514 return; 515 } 516 517 ntime.tv_sec = ntime.tv_usec = 0; 518 answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp); 519 if (answer != NULL) { 520 if (!good_host_name(answer->tsp_name)) { 521 suppress(&from, answer->tsp_name, ntp); 522 ntp->status = NOMASTER; 523 } 524 return; 525 } 526 527 ntime.tv_sec = ntime.tv_usec = 0; 528 answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp); 529 if (answer != NULL) { 530 if (!good_host_name(answer->tsp_name)) { 531 suppress(&from, answer->tsp_name, ntp); 532 ntp->status = NOMASTER; 533 } 534 return; 535 } 536 537 if (Mflag) 538 ntp->status = MASTER; 539 else 540 ntp->status = NOMASTER; 541 return; 542 } 543 544 ntp->status = SLAVE; 545 (void)strcpy(mastername, answer->tsp_name); 546 masteraddr = from; 547 548 /* 549 * If network has been partitioned, there might be other 550 * masters; tell the one we have just acknowledged that 551 * it has to gain control over the others. 552 */ 553 ntime.tv_sec = 0; 554 ntime.tv_usec = 300000; 555 answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp); 556 /* 557 * checking also not to send CONFLICT to ack'ed master 558 * due to duplicated MASTERACKs 559 */ 560 if (answer != NULL && 561 strcmp(answer->tsp_name, mastername) != 0) { 562 conflict.tsp_type = TSP_CONFLICT; 563 (void)strcpy(conflict.tsp_name, hostname); 564 if (!acksend(&conflict, &masteraddr, mastername, 565 TSP_ACK, 0, 0)) { 566 syslog(LOG_ERR, 567 "error on sending TSP_CONFLICT"); 568 } 569 } 570} 571 572/* 573 * based on the current network configuration, set the status, and count 574 * networks; 575 */ 576void 577setstatus(void) 578{ 579 struct netinfo *ntp; 580 581 status = 0; 582 nmasternets = nslavenets = nnets = nignorednets = 0; 583 if (trace) 584 fprintf(fd, "Net status:\n"); 585 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 586 switch ((int)ntp->status) { 587 case MASTER: 588 nmasternets++; 589 break; 590 case SLAVE: 591 nslavenets++; 592 break; 593 case NOMASTER: 594 case IGNORE: 595 nignorednets++; 596 break; 597 } 598 if (trace) { 599 fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); 600 switch ((int)ntp->status) { 601 case NOMASTER: 602 fprintf(fd, "NOMASTER\n"); 603 break; 604 case MASTER: 605 fprintf(fd, "MASTER\n"); 606 break; 607 case SLAVE: 608 fprintf(fd, "SLAVE\n"); 609 break; 610 case IGNORE: 611 fprintf(fd, "IGNORE\n"); 612 break; 613 default: 614 fprintf(fd, "invalid state %d\n", 615 (int)ntp->status); 616 break; 617 } 618 } 619 nnets++; 620 status |= ntp->status; 621 } 622 status &= ~IGNORE; 623 if (trace) 624 fprintf(fd, 625 "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%ld\n", 626 nnets, nmasternets, nslavenets, nignorednets, delay2); 627} 628 629void 630makeslave(struct netinfo *net) 631{ 632 register struct netinfo *ntp; 633 634 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 635 if (ntp->status == SLAVE && ntp != net) 636 ntp->status = IGNORE; 637 } 638 slavenet = net; 639} 640 641/* 642 * Try to become master over ignored nets.. 643 */ 644static void 645checkignorednets(void) 646{ 647 register struct netinfo *ntp; 648 649 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 650 if (!Mflag && ntp->status == SLAVE) 651 break; 652 653 if (ntp->status == IGNORE || ntp->status == NOMASTER) { 654 lookformaster(ntp); 655 if (!Mflag && ntp->status == SLAVE) 656 break; 657 } 658 } 659} 660 661/* 662 * choose a good network on which to be a slave 663 * The ignored networks must have already been checked. 664 * Take a hint about for a good network. 665 */ 666static void 667pickslavenet(struct netinfo *ntp) 668{ 669 if (slavenet != NULL && slavenet->status == SLAVE) { 670 makeslave(slavenet); /* prune extras */ 671 return; 672 } 673 674 if (ntp == NULL || ntp->status != SLAVE) { 675 for (ntp = nettab; ntp != NULL; ntp = ntp->next) { 676 if (ntp->status == SLAVE) 677 break; 678 } 679 } 680 makeslave(ntp); 681} 682 683/* 684 * returns a random number in the range [inf, sup] 685 */ 686long 687casual(long inf, long sup) 688{ 689 double value; 690 691 value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0); 692 return(inf + (sup - inf)*value); 693} 694 695char * 696date(void) 697{ 698 time_t tv_sec; 699 700 tv_sec = time(NULL); 701 return (ctime(&tv_sec)); 702} 703 704void 705addnetname(char *name) 706{ 707 register struct nets **netlist = &nets; 708 709 while (*netlist) 710 netlist = &((*netlist)->next); 711 *netlist = (struct nets *)malloc(sizeof **netlist); 712 if (*netlist == NULL) 713 errx(1, "malloc failed"); 714 bzero((char *)*netlist, sizeof(**netlist)); 715 (*netlist)->name = name; 716} 717 718/* note a host as trustworthy 719 * perm 1=not part of the netgroup 720 */ 721static void 722add_good_host(char *name, int perm) 723{ 724 register struct goodhost *ghp; 725 register struct hostent *hentp; 726 727 ghp = (struct goodhost*)malloc(sizeof(*ghp)); 728 if (!ghp) { 729 syslog(LOG_ERR, "malloc failed"); 730 exit(1); 731 } 732 733 bzero((char*)ghp, sizeof(*ghp)); 734 (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); 735 ghp->next = goodhosts; 736 ghp->perm = perm; 737 goodhosts = ghp; 738 739 hentp = gethostbyname(name); 740 if (hentp == NULL && perm) 741 warnx("unknown host %s", name); 742} 743 744 745/* update our image of the net-group of trustworthy hosts 746 */ 747void 748get_goodgroup(int force) 749{ 750# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ 751 static unsigned long last_update = -NG_DELAY; 752 unsigned long new_update; 753 struct goodhost *ghp, **ghpp; 754#ifdef HAVENIS 755 struct hosttbl *htp; 756 char *mach, *usr, *dom; 757#endif /* HAVENIS */ 758 struct tms tm; 759 760 761 /* if no netgroup, then we are finished */ 762 if (goodgroup == NULL || !Mflag) 763 return; 764 765 /* Do not chatter with the netgroup master too often. 766 */ 767 new_update = times(&tm); 768 if (new_update < last_update + NG_DELAY 769 && !force) 770 return; 771 last_update = new_update; 772 773 /* forget the old temporary entries */ 774 ghpp = &goodhosts; 775 while ((ghp = *ghpp) != NULL) { 776 if (!ghp->perm) { 777 *ghpp = ghp->next; 778 free(ghp); 779 } else { 780 ghpp = &ghp->next; 781 } 782 } 783 784#ifdef HAVENIS 785 /* quit now if we are not one of the trusted masters 786 */ 787 if (!innetgr(goodgroup, &hostname[0], 0,0)) { 788 if (trace) 789 (void)fprintf(fd, "get_goodgroup: %s not in %s\n", 790 &hostname[0], goodgroup); 791 return; 792 } 793 if (trace) 794 (void)fprintf(fd, "get_goodgroup: %s in %s\n", 795 &hostname[0], goodgroup); 796 797 /* mark the entire netgroup as trusted */ 798 (void)setnetgrent(goodgroup); 799 while (getnetgrent(&mach,&usr,&dom)) { 800 if (mach != NULL) 801 add_good_host(mach,0); 802 } 803 (void)endnetgrent(); 804 805 /* update list of slaves */ 806 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 807 htp->good = good_host_name(&htp->name[0]); 808 } 809#endif /* HAVENIS */ 810} 811 812 813/* see if a machine is trustworthy 814 */ 815int /* 1=trust hp to change our date */ 816good_host_name(char *name) 817{ 818 register struct goodhost *ghp = goodhosts; 819 register char c; 820 821 if (!ghp || !Mflag) /* trust everyone if no one named */ 822 return 1; 823 824 c = *name; 825 do { 826 if (c == ghp->name[0] 827 && !strcasecmp(name, ghp->name)) 828 return 1; /* found him, so say so */ 829 } while ((ghp = ghp->next) != NULL); 830 831 if (!strcasecmp(name,hostname)) /* trust ourself */ 832 return 1; 833 834 return 0; /* did not find him */ 835} 836