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