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