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