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