xref: /original-bsd/usr.sbin/timed/timed/slave.c (revision a69cfb4b)
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 sccsid[] = "@(#)slave.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #ifdef sgi
13 #ident "$Revision: 1.20 $"
14 #endif
15 
16 #include "globals.h"
17 #include <setjmp.h>
18 #include "pathnames.h"
19 
20 extern jmp_buf jmpenv;
21 extern int Mflag;
22 extern int justquit;
23 
24 extern u_short sequence;
25 
26 static char master_name[MAXHOSTNAMELEN+1];
27 static struct netinfo *old_slavenet;
28 static int old_status;
29 
30 static void schgdate __P((struct tsp *, char *));
31 static void setmaster __P((struct tsp *));
32 static void answerdelay __P((void));
33 
34 #ifdef sgi
35 extern void logwtmp __P((struct timeval *, struct timeval *));
36 #else
37 extern void logwtmp __P((char *, char *, char *));
38 #endif /* sgi */
39 
40 int
41 slave()
42 {
43 	int tries;
44 	long electiontime, refusetime, looktime, looptime, adjtime;
45 	u_short seq;
46 	long fastelection;
47 #define FASTTOUT 3
48 	struct in_addr cadr;
49 	struct timeval otime;
50 	struct sockaddr_in taddr;
51 	char tname[MAXHOSTNAMELEN];
52 	struct tsp *msg, to;
53 	struct timeval ntime, wait;
54 	struct tsp *answer;
55 	int timeout();
56 	char olddate[32];
57 	char newdate[32];
58 	struct netinfo *ntp;
59 	struct hosttbl *htp;
60 
61 
62 	old_slavenet = 0;
63 	seq = 0;
64 	refusetime = 0;
65 	adjtime = 0;
66 
67 	(void)gettimeofday(&ntime, 0);
68 	electiontime = ntime.tv_sec + delay2;
69 	fastelection = ntime.tv_sec + FASTTOUT;
70 	if (justquit)
71 		looktime = electiontime;
72 	else
73 		looktime = fastelection;
74 	looptime = fastelection;
75 
76 	if (slavenet)
77 		xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
78 	if (status & MASTER) {
79 		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
80 			if (ntp->status == MASTER)
81 				masterup(ntp);
82 		}
83 	}
84 
85 loop:
86 	get_goodgroup(0);
87 	(void)gettimeofday(&ntime, (struct timezone *)0);
88 	if (ntime.tv_sec > electiontime) {
89 		if (trace)
90 			fprintf(fd, "election timer expired\n");
91 		longjmp(jmpenv, 1);
92 	}
93 
94 	if (ntime.tv_sec >= looktime) {
95 		if (trace)
96 			fprintf(fd, "Looking for nets to master\n");
97 
98 		if (Mflag && nignorednets > 0) {
99 			for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
100 				if (ntp->status == IGNORE
101 				    || ntp->status == NOMASTER) {
102 					lookformaster(ntp);
103 					if (ntp->status == MASTER) {
104 						masterup(ntp);
105 					} else if (ntp->status == MASTER) {
106 						ntp->status = NOMASTER;
107 					}
108 				}
109 				if (ntp->status == MASTER
110 				    && --ntp->quit_count < 0)
111 					ntp->quit_count = 0;
112 			}
113 			makeslave(slavenet);	/* prune extras */
114 			setstatus();
115 		}
116 		(void)gettimeofday(&ntime, 0);
117 		looktime = ntime.tv_sec + delay2;
118 	}
119 	if (ntime.tv_sec >= looptime) {
120 		if (trace)
121 			fprintf(fd, "Looking for loops\n");
122 		for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
123 		    if (ntp->status == MASTER) {
124 			to.tsp_type = TSP_LOOP;
125 			to.tsp_vers = TSPVERSION;
126 			to.tsp_seq = sequence++;
127 			to.tsp_hopcnt = MAX_HOPCNT;
128 			(void)strcpy(to.tsp_name, hostname);
129 			bytenetorder(&to);
130 			if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
131 				   (struct sockaddr*)&ntp->dest_addr,
132 				   sizeof(ntp->dest_addr)) < 0) {
133 				trace_sendto_err(ntp->dest_addr.sin_addr);
134 			}
135 		    }
136 		}
137 		(void)gettimeofday(&ntime, 0);
138 		looptime = ntime.tv_sec + delay2;
139 	}
140 
141 	wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
142 	if (wait.tv_sec < 0)
143 		wait.tv_sec = 0;
144 	wait.tv_sec += FASTTOUT;
145 	wait.tv_usec = 0;
146 	msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
147 
148 	if (msg != NULL) {
149 		/*
150 		 * filter stuff not for us
151 		 */
152 		switch (msg->tsp_type) {
153 		case TSP_SETDATE:
154 		case TSP_TRACEOFF:
155 		case TSP_TRACEON:
156 			/*
157 			 * XXX check to see they are from ourself
158 			 */
159 			break;
160 
161 		case TSP_TEST:
162 		case TSP_MSITE:
163 			break;
164 
165 		case TSP_MASTERUP:
166 			if (!fromnet) {
167 				if (trace) {
168 					fprintf(fd, "slave ignored: ");
169 					print(msg, &from);
170 				}
171 				goto loop;
172 			}
173 			break;
174 
175 		default:
176 			if (!fromnet
177 			    || fromnet->status == IGNORE
178 			    || fromnet->status == NOMASTER) {
179 				if (trace) {
180 					fprintf(fd, "slave ignored: ");
181 					print(msg, &from);
182 				}
183 				goto loop;
184 			}
185 			break;
186 		}
187 
188 
189 		/*
190 		 * now process the message
191 		 */
192 		switch (msg->tsp_type) {
193 
194 		case TSP_ADJTIME:
195 			if (fromnet != slavenet)
196 				break;
197 			if (!good_host_name(msg->tsp_name)) {
198 				syslog(LOG_NOTICE,
199 				   "attempted time adjustment by %s",
200 				       msg->tsp_name);
201 				suppress(&from, msg->tsp_name, fromnet);
202 				break;
203 			}
204 			/*
205 			 * Speed up loop detection in case we have a loop.
206 			 * Otherwise the clocks can race until the loop
207 			 * is found.
208 			 */
209 			(void)gettimeofday(&otime, 0);
210 			if (adjtime < otime.tv_sec)
211 				looptime -= (looptime-otime.tv_sec)/2 + 1;
212 
213 			setmaster(msg);
214 			if (seq != msg->tsp_seq) {
215 				seq = msg->tsp_seq;
216 				synch(tvtomsround(msg->tsp_time));
217 			}
218 			(void)gettimeofday(&ntime, 0);
219 			electiontime = ntime.tv_sec + delay2;
220 			fastelection = ntime.tv_sec + FASTTOUT;
221 			adjtime = ntime.tv_sec + SAMPLEINTVL*2;
222 			break;
223 
224 		case TSP_SETTIME:
225 			if (fromnet != slavenet)
226 				break;
227 			if (seq == msg->tsp_seq)
228 				break;
229 			seq = msg->tsp_seq;
230 
231 			/* adjust time for residence on the queue */
232 			(void)gettimeofday(&otime, 0);
233 			adj_msg_time(msg,&otime);
234 #ifdef sgi
235 			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
236 			(void)cftime(olddate, "%D %T", &otime.tv_sec);
237 #else
238 			/*
239 			 * the following line is necessary due to syslog
240 			 * calling ctime() which clobbers the static buffer
241 			 */
242 			(void)strcpy(olddate, date());
243 			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
244 #endif /* sgi */
245 
246 			if (!good_host_name(msg->tsp_name)) {
247 				syslog(LOG_NOTICE,
248 			    "attempted time setting by untrusted %s to %s",
249 				       msg->tsp_name, newdate);
250 				suppress(&from, msg->tsp_name, fromnet);
251 				break;
252 			}
253 
254 			setmaster(msg);
255 			timevalsub(&ntime, &msg->tsp_time, &otime);
256 			if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
257 				/*
258 				 * do not change the clock if we can adjust it
259 				 */
260 				synch(tvtomsround(ntime));
261 			} else {
262 #ifdef sgi
263 				if (0 > settimeofday(&msg->tsp_time, 0)) {
264 					syslog(LOG_ERR,"settimeofdate(): %m");
265 					break;
266 				}
267 				logwtmp(&otime, &msg->tsp_time);
268 #else
269 				logwtmp("|", "date", "");
270 				(void)settimeofday(&msg->tsp_time, 0);
271 				logwtmp("}", "date", "");
272 #endif /* sgi */
273 				syslog(LOG_NOTICE,
274 				       "date changed by %s from %s",
275 					msg->tsp_name, olddate);
276 				if (status & MASTER)
277 					spreadtime();
278 			}
279 			(void)gettimeofday(&ntime, 0);
280 			electiontime = ntime.tv_sec + delay2;
281 			fastelection = ntime.tv_sec + FASTTOUT;
282 
283 /* This patches a bad protocol bug.  Imagine a system with several networks,
284  * where there are a pair of redundant gateways between a pair of networks,
285  * each running timed.  Assume that we start with a third machine mastering
286  * one of the networks, and one of the gateways mastering the other.
287  * Imagine that the third machine goes away and the non-master gateway
288  * decides to replace it.  If things are timed just 'right,' we will have
289  * each gateway mastering one network for a little while.  If a SETTIME
290  * message gets into the network at that time, perhaps from the newly
291  * masterful gateway as it was taking control, the SETTIME will loop
292  * forever.  Each time a gateway receives it on its slave side, it will
293  * call spreadtime to forward it on its mastered network.  We are now in
294  * a permanent loop, since the SETTIME msgs will keep any clock
295  * in the network from advancing.  Normally, the 'LOOP' stuff will detect
296  * and correct the situation.  However, with the clocks stopped, the
297  * 'looptime' timer cannot expire.  While they are in this state, the
298  * masters will try to saturate the network with SETTIME packets.
299  */
300 			looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
301 			break;
302 
303 		case TSP_MASTERUP:
304 			if (slavenet && fromnet != slavenet)
305 				break;
306 			if (!good_host_name(msg->tsp_name)) {
307 				suppress(&from, msg->tsp_name, fromnet);
308 				if (electiontime > fastelection)
309 					electiontime = fastelection;
310 				break;
311 			}
312 			makeslave(fromnet);
313 			setmaster(msg);
314 			setstatus();
315 			answerdelay();
316 			xmit(TSP_SLAVEUP, 0, &from);
317 			(void)gettimeofday(&ntime, 0);
318 			electiontime = ntime.tv_sec + delay2;
319 			fastelection = ntime.tv_sec + FASTTOUT;
320 			refusetime = 0;
321 			break;
322 
323 		case TSP_MASTERREQ:
324 			if (fromnet->status != SLAVE)
325 				break;
326 			(void)gettimeofday(&ntime, 0);
327 			electiontime = ntime.tv_sec + delay2;
328 			break;
329 
330 		case TSP_SETDATE:
331 #ifdef sgi
332 			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
333 #else
334 			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
335 #endif /* sgi */
336 			schgdate(msg, newdate);
337 			break;
338 
339 		case TSP_SETDATEREQ:
340 			if (fromnet->status != MASTER)
341 				break;
342 #ifdef sgi
343 			(void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
344 #else
345 			(void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
346 #endif /* sgi */
347 			htp = findhost(msg->tsp_name);
348 			if (0 == htp) {
349 				syslog(LOG_WARNING,
350 				       "DATEREQ from uncontrolled machine");
351 				break;
352 			}
353 			if (!htp->good) {
354 				syslog(LOG_WARNING,
355 				"attempted date change by untrusted %s to %s",
356 				       htp->name, newdate);
357 				spreadtime();
358 				break;
359 			}
360 			schgdate(msg, newdate);
361 			break;
362 
363 		case TSP_TRACEON:
364 			traceon();
365 			break;
366 
367 		case TSP_TRACEOFF:
368 			traceoff("Tracing ended at %s\n");
369 			break;
370 
371 		case TSP_SLAVEUP:
372 			newslave(msg);
373 			break;
374 
375 		case TSP_ELECTION:
376 			if (fromnet->status == SLAVE) {
377 				(void)gettimeofday(&ntime, 0);
378 				electiontime = ntime.tv_sec + delay2;
379 				fastelection = ntime.tv_sec + FASTTOUT;
380 				seq = 0;
381 				if (!good_host_name(msg->tsp_name)) {
382 					syslog(LOG_NOTICE,
383 					       "suppress election of %s",
384 					       msg->tsp_name);
385 					to.tsp_type = TSP_QUIT;
386 					electiontime = fastelection;
387 				} else if (cadr.s_addr != from.sin_addr.s_addr
388 					   && ntime.tv_sec < refusetime) {
389 /* if the candidate has to repeat itself, the old code would refuse it
390  * the second time.  That would prevent elections.
391  */
392 					to.tsp_type = TSP_REFUSE;
393 				} else {
394 					cadr.s_addr = from.sin_addr.s_addr;
395 					to.tsp_type = TSP_ACCEPT;
396 					refusetime = ntime.tv_sec + 30;
397 				}
398 				taddr = from;
399 				(void)strcpy(tname, msg->tsp_name);
400 				(void)strcpy(to.tsp_name, hostname);
401 				answerdelay();
402 				if (!acksend(&to, &taddr, tname,
403 					     TSP_ACK, 0, 0))
404 					syslog(LOG_WARNING,
405 					     "no answer from candidate %s\n",
406 					       tname);
407 
408 			} else {	/* fromnet->status == MASTER */
409 				htp = addmach(msg->tsp_name, &from,fromnet);
410 				to.tsp_type = TSP_QUIT;
411 				(void)strcpy(to.tsp_name, hostname);
412 				if (!acksend(&to, &htp->addr, htp->name,
413 					     TSP_ACK, 0, htp->noanswer)) {
414 					syslog(LOG_ERR,
415 					  "no reply from %s to ELECTION-QUIT",
416 					       htp->name);
417 					(void)remmach(htp);
418 				}
419 			}
420 			break;
421 
422 		case TSP_CONFLICT:
423 			if (fromnet->status != MASTER)
424 				break;
425 			/*
426 			 * After a network partition, there can be
427 			 * more than one master: the first slave to
428 			 * come up will notify here the situation.
429 			 */
430 			(void)strcpy(to.tsp_name, hostname);
431 
432 			/* The other master often gets into the same state,
433 			 * with boring results.
434 			 */
435 			ntp = fromnet;	/* (acksend() can leave fromnet=0 */
436 			for (tries = 0; tries < 3; tries++) {
437 				to.tsp_type = TSP_RESOLVE;
438 				answer = acksend(&to, &ntp->dest_addr,
439 						 ANYADDR, TSP_MASTERACK,
440 						 ntp, 0);
441 				if (answer == NULL)
442 					break;
443 				htp = addmach(answer->tsp_name,&from,ntp);
444 				to.tsp_type = TSP_QUIT;
445 				answer = acksend(&to, &htp->addr, htp->name,
446 						 TSP_ACK, 0, htp->noanswer);
447 				if (!answer) {
448 					syslog(LOG_WARNING,
449 				  "conflict error: no reply from %s to QUIT",
450 						htp->name);
451 					(void)remmach(htp);
452 				}
453 			}
454 			masterup(ntp);
455 			break;
456 
457 		case TSP_MSITE:
458 			if (!slavenet)
459 				break;
460 			taddr = from;
461 			to.tsp_type = TSP_MSITEREQ;
462 			to.tsp_vers = TSPVERSION;
463 			to.tsp_seq = 0;
464 			(void)strcpy(to.tsp_name, hostname);
465 			answer = acksend(&to, &slavenet->dest_addr,
466 					 ANYADDR, TSP_ACK,
467 					 slavenet, 0);
468 			if (answer != NULL
469 			    && good_host_name(answer->tsp_name)) {
470 				setmaster(answer);
471 				to.tsp_type = TSP_ACK;
472 				(void)strcpy(to.tsp_name, answer->tsp_name);
473 				bytenetorder(&to);
474 				if (sendto(sock, (char *)&to,
475 					   sizeof(struct tsp), 0,
476 					   (struct sockaddr*)&taddr, sizeof(taddr)) < 0) {
477 					trace_sendto_err(taddr.sin_addr);
478 				}
479 			}
480 			break;
481 
482 		case TSP_MSITEREQ:
483 			break;
484 
485 		case TSP_ACCEPT:
486 		case TSP_REFUSE:
487 		case TSP_RESOLVE:
488 			break;
489 
490 		case TSP_QUIT:
491 			doquit(msg);		/* become a slave */
492 			break;
493 
494 		case TSP_TEST:
495 			electiontime = 0;
496 			break;
497 
498 		case TSP_LOOP:
499 			/* looking for loops of masters */
500 			if (!(status & MASTER))
501 				break;
502 			if (fromnet->status == SLAVE) {
503 			    if (!strcmp(msg->tsp_name, hostname)) {
504 				/*
505 				 * Someone forwarded our message back to
506 				 * us.  There must be a loop.  Tell the
507 				 * master of this network to quit.
508 				 *
509 				 * The other master often gets into
510 				 * the same state, with boring results.
511 				 */
512 				ntp = fromnet;
513 				for (tries = 0; tries < 3; tries++) {
514 				    to.tsp_type = TSP_RESOLVE;
515 				    answer = acksend(&to, &ntp->dest_addr,
516 						     ANYADDR, TSP_MASTERACK,
517 						     ntp,0);
518 				    if (answer == NULL)
519 					break;
520 				    taddr = from;
521 				    (void)strcpy(tname, answer->tsp_name);
522 				    to.tsp_type = TSP_QUIT;
523 				    (void)strcpy(to.tsp_name, hostname);
524 				    if (!acksend(&to, &taddr, tname,
525 						 TSP_ACK, 0, 1)) {
526 					syslog(LOG_ERR,
527 					"no reply from %s to slave LOOP-QUIT",
528 						 tname);
529 				    } else {
530 					electiontime = 0;
531 				    }
532 				}
533 				(void)gettimeofday(&ntime, 0);
534 				looptime = ntime.tv_sec + FASTTOUT;
535 			    } else {
536 				if (msg->tsp_hopcnt-- < 1)
537 				    break;
538 				bytenetorder(msg);
539 				for (ntp = nettab; ntp != 0; ntp = ntp->next) {
540 				    if (ntp->status == MASTER
541 					&& 0 > sendto(sock, (char *)msg,
542 						      sizeof(struct tsp), 0,
543 					      (struct sockaddr*)&ntp->dest_addr,
544 						      sizeof(ntp->dest_addr)))
545 				    trace_sendto_err(ntp->dest_addr.sin_addr);
546 				}
547 			    }
548 			} else {	/* fromnet->status == MASTER */
549 			    /*
550 			     * We should not have received this from a net
551 			     * we are master on.  There must be two masters,
552 			     * unless the packet was really from us.
553 			     */
554 			    if (from.sin_addr.s_addr
555 				== fromnet->my_addr.s_addr) {
556 				if (trace)
557 				    fprintf(fd,"discarding forwarded LOOP\n");
558 				break;
559 			    }
560 
561 			    /*
562 			     * The other master often gets into the same
563 			     * state, with boring results.
564 			     */
565 			    ntp = fromnet;
566 			    for (tries = 0; tries < 3; tries++) {
567 				to.tsp_type = TSP_RESOLVE;
568 				answer = acksend(&to, &ntp->dest_addr,
569 						 ANYADDR, TSP_MASTERACK,
570 						ntp,0);
571 				if (!answer)
572 					break;
573 				htp = addmach(answer->tsp_name,
574 					      &from,ntp);
575 				to.tsp_type = TSP_QUIT;
576 				(void)strcpy(to.tsp_name, hostname);
577 				if (!acksend(&to,&htp->addr,htp->name,
578 					     TSP_ACK, 0, htp->noanswer)) {
579 					syslog(LOG_ERR,
580 				    "no reply from %s to master LOOP-QUIT",
581 					       htp->name);
582 					(void)remmach(htp);
583 				}
584 			    }
585 			    (void)gettimeofday(&ntime, 0);
586 			    looptime = ntime.tv_sec + FASTTOUT;
587 			}
588 			break;
589 		default:
590 			if (trace) {
591 				fprintf(fd, "garbage message: ");
592 				print(msg, &from);
593 			}
594 			break;
595 		}
596 	}
597 	goto loop;
598 }
599 
600 
601 /*
602  * tell the world who our master is
603  */
604 static void
605 setmaster(msg)
606 	struct tsp *msg;
607 {
608 	if (slavenet
609 	    && (slavenet != old_slavenet
610 		|| strcmp(msg->tsp_name, master_name)
611 		|| old_status != status)) {
612 		(void)strcpy(master_name, msg->tsp_name);
613 		old_slavenet = slavenet;
614 		old_status = status;
615 
616 		if (status & MASTER) {
617 			syslog(LOG_NOTICE, "submaster to %s", master_name);
618 			if (trace)
619 				fprintf(fd, "submaster to %s\n", master_name);
620 
621 		} else {
622 			syslog(LOG_NOTICE, "slave to %s", master_name);
623 			if (trace)
624 				fprintf(fd, "slave to %s\n", master_name);
625 		}
626 	}
627 }
628 
629 
630 
631 /*
632  * handle date change request on a slave
633  */
634 static void
635 schgdate(msg, newdate)
636 	struct tsp *msg;
637 	char *newdate;
638 {
639 	struct tsp to;
640 	u_short seq;
641 	struct sockaddr_in taddr;
642 	struct timeval otime;
643 
644 	if (!slavenet)
645 		return;			/* no where to forward */
646 
647 	taddr = from;
648 	seq = msg->tsp_seq;
649 
650 	syslog(LOG_INFO,
651 	       "forwarding date change by %s to %s",
652 	       msg->tsp_name, newdate);
653 
654 	/* adjust time for residence on the queue */
655 	(void)gettimeofday(&otime, 0);
656 	adj_msg_time(msg, &otime);
657 
658 	to.tsp_type = TSP_SETDATEREQ;
659 	to.tsp_time = msg->tsp_time;
660 	(void)strcpy(to.tsp_name, hostname);
661 	if (!acksend(&to, &slavenet->dest_addr,
662 		     ANYADDR, TSP_DATEACK,
663 		     slavenet, 0))
664 		return;			/* no answer */
665 
666 	xmit(TSP_DATEACK, seq, &taddr);
667 }
668 
669 
670 /*
671  * Used before answering a broadcast message to avoid network
672  * contention and likely collisions.
673  */
674 static void
675 answerdelay()
676 {
677 #ifdef sgi
678 	sginap(delay1);
679 #else
680 	struct timeval timeout;
681 
682 	timeout.tv_sec = 0;
683 	timeout.tv_usec = delay1;
684 
685 	(void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
686 	    &timeout);
687 	return;
688 #endif /* sgi */
689 }
690