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