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