11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1990, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 45455Sdg * 55455Sdg * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes */ 291541Srgrimes 301541Srgrimes#if 0 311541Srgrimes#ifndef lint 321541Srgrimesstatic char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93"; 331541Srgrimes#endif /* not lint */ 341541Srgrimes#endif 351541Srgrimes 367164Sdg#include <sys/cdefs.h> 371541Srgrimes__FBSDID("$FreeBSD$"); 381541Srgrimes 391541Srgrimes#include <sys/param.h> 401549Srgrimes#include <sys/time.h> 411541Srgrimes#include <sys/socket.h> 421541Srgrimes 431541Srgrimes#include <netinet/in.h> 441541Srgrimes#include <netdb.h> 451541Srgrimes#define TSPTYPES 461541Srgrimes#include <protocols/timed.h> 475455Sdg 485455Sdg#include <err.h> 496621Sdg#include <errno.h> 506621Sdg#include <string.h> 511541Srgrimes#include <unistd.h> 521541Srgrimes 531541Srgrimes#include "extern.h" 541541Srgrimes 553055Sdg#define WAITACK 2 /* seconds */ 565455Sdg#define WAITDATEACK 5 /* seconds */ 575455Sdg 581541Srgrimes/* 591541Srgrimes * Set the date in the machines controlled by timedaemons by communicating the 603055Sdg * new date to the local timedaemon. If the timedaemon is in the master state, 611541Srgrimes * it performs the correction on all slaves. If it is in the slave state, it 621541Srgrimes * notifies the master that a correction is needed. 631541Srgrimes * Returns 0 on success. Returns > 0 on failure, setting retval to 2; 641541Srgrimes */ 651541Srgrimesint 661541Srgrimesnetsettime(time_t tval) 675455Sdg{ 681541Srgrimes struct timeval tout; 691541Srgrimes struct servent *sp; 705455Sdg struct tsp msg; 715455Sdg struct sockaddr_in lsin, dest, from; 725455Sdg fd_set ready; 731541Srgrimes long waittime; 741541Srgrimes int s, port, timed_ack, found, lerr; 751541Srgrimes socklen_t length; 761541Srgrimes char hostname[MAXHOSTNAMELEN]; 771541Srgrimes 781541Srgrimes if ((sp = getservbyname("timed", "udp")) == NULL) { 791541Srgrimes warnx("timed/udp: unknown service"); 801541Srgrimes return (retval = 2); 811541Srgrimes } 821541Srgrimes 831541Srgrimes dest.sin_port = sp->s_port; 841541Srgrimes dest.sin_family = AF_INET; 851541Srgrimes dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 865455Sdg s = socket(AF_INET, SOCK_DGRAM, 0); 875455Sdg if (s < 0) { 881541Srgrimes if (errno != EAFNOSUPPORT) 891541Srgrimes warn("timed"); 901541Srgrimes return (retval = 2); 911541Srgrimes } 921541Srgrimes 935839Sdg memset(&lsin, 0, sizeof(lsin)); 941541Srgrimes lsin.sin_family = AF_INET; 951541Srgrimes for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 961541Srgrimes lsin.sin_port = htons((u_short)port); 971541Srgrimes if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0) 981541Srgrimes break; 991541Srgrimes if (errno == EADDRINUSE) 1001541Srgrimes continue; 1011541Srgrimes if (errno != EADDRNOTAVAIL) 1021541Srgrimes warn("bind"); 1031541Srgrimes goto bad; 1041541Srgrimes } 1051549Srgrimes if (port == IPPORT_RESERVED / 2) { 1061541Srgrimes warnx("all ports in use"); 1071541Srgrimes goto bad; 1081541Srgrimes } 1091541Srgrimes memset(&msg, 0, sizeof(msg)); 1101541Srgrimes msg.tsp_type = TSP_SETDATE; 1111541Srgrimes msg.tsp_vers = TSPVERSION; 1121541Srgrimes if (gethostname(hostname, sizeof(hostname))) { 1131541Srgrimes warn("gethostname"); 1141541Srgrimes goto bad; 1155455Sdg } 1161541Srgrimes (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); 1171541Srgrimes msg.tsp_seq = htons((u_short)0); 1181541Srgrimes msg.tsp_time.tv_sec = htonl((u_long)tval); 1195455Sdg msg.tsp_time.tv_usec = htonl((u_long)0); 1201541Srgrimes length = sizeof(struct sockaddr_in); 1215455Sdg if (connect(s, (struct sockaddr *)&dest, length) < 0) { 1225455Sdg warn("connect"); 1235455Sdg goto bad; 1241541Srgrimes } 1255455Sdg if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) { 1265455Sdg if (errno != ECONNREFUSED) 1275455Sdg warn("send"); 1285455Sdg goto bad; 1295455Sdg } 1301541Srgrimes 1315455Sdg timed_ack = -1; 1325455Sdg waittime = WAITACK; 1335455Sdgloop: 1346621Sdg tout.tv_sec = waittime; 1355455Sdg tout.tv_usec = 0; 1365455Sdg 1376621Sdg FD_ZERO(&ready); 1385839Sdg FD_SET(s, &ready); 1395839Sdg found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 1406621Sdg 1415839Sdg length = sizeof(lerr); 1426621Sdg if (!getsockopt(s, 1435839Sdg SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) { 1445455Sdg if (lerr != ECONNREFUSED) 1455455Sdg warnc(lerr, "send (delayed error)"); 1461541Srgrimes goto bad; 1475455Sdg } 1485455Sdg 1491541Srgrimes if (found > 0 && FD_ISSET(s, &ready)) { 1501541Srgrimes length = sizeof(struct sockaddr_in); 1515455Sdg if (recvfrom(s, &msg, sizeof(struct tsp), 0, 1525455Sdg (struct sockaddr *)&from, &length) < 0) { 1531541Srgrimes if (errno != ECONNREFUSED) 1541541Srgrimes warn("recvfrom"); 1555455Sdg goto bad; 1561541Srgrimes } 1575455Sdg msg.tsp_seq = ntohs(msg.tsp_seq); 1585455Sdg msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 1595455Sdg msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 1605455Sdg switch (msg.tsp_type) { 1615455Sdg case TSP_ACK: 1625455Sdg timed_ack = TSP_ACK; 1635455Sdg waittime = WAITDATEACK; 1645455Sdg goto loop; 1655455Sdg case TSP_DATEACK: 1665455Sdg (void)close(s); 1675455Sdg return (0); 1685455Sdg default: 1695455Sdg warnx("wrong ack received from timed: %s", 1705455Sdg tsptype[msg.tsp_type]); 1711541Srgrimes timed_ack = -1; 1725455Sdg break; 1735455Sdg } 1745455Sdg } 1755455Sdg if (timed_ack == -1) 1761541Srgrimes warnx("can't reach time daemon, time set locally"); 1775455Sdg 1785455Sdgbad: 1795455Sdg (void)close(s); 1805455Sdg return (retval = 2); 1815455Sdg} 1825455Sdg