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