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