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