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