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