11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1990, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 4. Neither the name of the University nor the names of its contributors 141556Srgrimes * may be used to endorse or promote products derived from this software 151556Srgrimes * without specific prior written permission. 161556Srgrimes * 171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271556Srgrimes * SUCH DAMAGE. 281556Srgrimes */ 291556Srgrimes 30110390Scharnier#if 0 311556Srgrimes#ifndef lint 3236006Scharnierstatic char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93"; 33110390Scharnier#endif /* not lint */ 3435773Scharnier#endif 35110390Scharnier 3699109Sobrien#include <sys/cdefs.h> 3799109Sobrien__FBSDID("$FreeBSD$"); 381556Srgrimes 391556Srgrimes#include <sys/param.h> 401556Srgrimes#include <sys/time.h> 411556Srgrimes#include <sys/socket.h> 421556Srgrimes 431556Srgrimes#include <netinet/in.h> 441556Srgrimes#include <netdb.h> 451556Srgrimes#define TSPTYPES 461556Srgrimes#include <protocols/timed.h> 471556Srgrimes 481556Srgrimes#include <err.h> 491556Srgrimes#include <errno.h> 501556Srgrimes#include <string.h> 511556Srgrimes#include <unistd.h> 521556Srgrimes 531556Srgrimes#include "extern.h" 541556Srgrimes 551556Srgrimes#define WAITACK 2 /* seconds */ 561556Srgrimes#define WAITDATEACK 5 /* seconds */ 571556Srgrimes 581556Srgrimes/* 591556Srgrimes * Set the date in the machines controlled by timedaemons by communicating the 601556Srgrimes * new date to the local timedaemon. If the timedaemon is in the master state, 611556Srgrimes * it performs the correction on all slaves. If it is in the slave state, it 621556Srgrimes * notifies the master that a correction is needed. 631556Srgrimes * Returns 0 on success. Returns > 0 on failure, setting retval to 2; 641556Srgrimes */ 651556Srgrimesint 6690108Simpnetsettime(time_t tval) 671556Srgrimes{ 681556Srgrimes struct timeval tout; 691556Srgrimes struct servent *sp; 701556Srgrimes struct tsp msg; 7191079Smarkm struct sockaddr_in lsin, dest, from; 721556Srgrimes fd_set ready; 731556Srgrimes long waittime; 7498062Skeramida int s, port, timed_ack, found, lerr; 7598062Skeramida socklen_t length; 761556Srgrimes char hostname[MAXHOSTNAMELEN]; 771556Srgrimes 781556Srgrimes if ((sp = getservbyname("timed", "udp")) == NULL) { 79110390Scharnier warnx("timed/udp: unknown service"); 801556Srgrimes return (retval = 2); 811556Srgrimes } 821556Srgrimes 831556Srgrimes dest.sin_port = sp->s_port; 841556Srgrimes dest.sin_family = AF_INET; 851556Srgrimes dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); 861556Srgrimes s = socket(AF_INET, SOCK_DGRAM, 0); 871556Srgrimes if (s < 0) { 88244538Skevlo if (errno != EAFNOSUPPORT) 891556Srgrimes warn("timed"); 901556Srgrimes return (retval = 2); 911556Srgrimes } 921556Srgrimes 9391079Smarkm memset(&lsin, 0, sizeof(lsin)); 9491079Smarkm lsin.sin_family = AF_INET; 951556Srgrimes for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 9691079Smarkm lsin.sin_port = htons((u_short)port); 9791079Smarkm if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0) 981556Srgrimes break; 991556Srgrimes if (errno == EADDRINUSE) 1001556Srgrimes continue; 1011556Srgrimes if (errno != EADDRNOTAVAIL) 1021556Srgrimes warn("bind"); 1031556Srgrimes goto bad; 1041556Srgrimes } 1051556Srgrimes if (port == IPPORT_RESERVED / 2) { 1061556Srgrimes warnx("all ports in use"); 1071556Srgrimes goto bad; 1081556Srgrimes } 109161469Simp memset(&msg, 0, sizeof(msg)); 1101556Srgrimes msg.tsp_type = TSP_SETDATE; 1111556Srgrimes msg.tsp_vers = TSPVERSION; 1121556Srgrimes if (gethostname(hostname, sizeof(hostname))) { 1131556Srgrimes warn("gethostname"); 1141556Srgrimes goto bad; 1151556Srgrimes } 116161469Simp (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); 1171556Srgrimes msg.tsp_seq = htons((u_short)0); 1181556Srgrimes msg.tsp_time.tv_sec = htonl((u_long)tval); 1191556Srgrimes msg.tsp_time.tv_usec = htonl((u_long)0); 1201556Srgrimes length = sizeof(struct sockaddr_in); 1211556Srgrimes if (connect(s, (struct sockaddr *)&dest, length) < 0) { 1221556Srgrimes warn("connect"); 1231556Srgrimes goto bad; 1241556Srgrimes } 1251556Srgrimes if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) { 1261556Srgrimes if (errno != ECONNREFUSED) 1271556Srgrimes warn("send"); 1281556Srgrimes goto bad; 1291556Srgrimes } 1301556Srgrimes 1311556Srgrimes timed_ack = -1; 1321556Srgrimes waittime = WAITACK; 1331556Srgrimesloop: 1341556Srgrimes tout.tv_sec = waittime; 1351556Srgrimes tout.tv_usec = 0; 1361556Srgrimes 1371556Srgrimes FD_ZERO(&ready); 1381556Srgrimes FD_SET(s, &ready); 1391556Srgrimes found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); 1401556Srgrimes 14191079Smarkm length = sizeof(lerr); 1421556Srgrimes if (!getsockopt(s, 14391079Smarkm SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) { 14491079Smarkm if (lerr != ECONNREFUSED) 14591079Smarkm warnc(lerr, "send (delayed error)"); 1461556Srgrimes goto bad; 1471556Srgrimes } 1481556Srgrimes 1491556Srgrimes if (found > 0 && FD_ISSET(s, &ready)) { 1501556Srgrimes length = sizeof(struct sockaddr_in); 1511556Srgrimes if (recvfrom(s, &msg, sizeof(struct tsp), 0, 1521556Srgrimes (struct sockaddr *)&from, &length) < 0) { 1531556Srgrimes if (errno != ECONNREFUSED) 1541556Srgrimes warn("recvfrom"); 1551556Srgrimes goto bad; 1561556Srgrimes } 1571556Srgrimes msg.tsp_seq = ntohs(msg.tsp_seq); 1581556Srgrimes msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 1591556Srgrimes msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 1601556Srgrimes switch (msg.tsp_type) { 1611556Srgrimes case TSP_ACK: 1621556Srgrimes timed_ack = TSP_ACK; 1631556Srgrimes waittime = WAITDATEACK; 1641556Srgrimes goto loop; 1651556Srgrimes case TSP_DATEACK: 1661556Srgrimes (void)close(s); 1671556Srgrimes return (0); 1681556Srgrimes default: 1698855Srgrimes warnx("wrong ack received from timed: %s", 1701556Srgrimes tsptype[msg.tsp_type]); 1711556Srgrimes timed_ack = -1; 1721556Srgrimes break; 1731556Srgrimes } 1741556Srgrimes } 1751556Srgrimes if (timed_ack == -1) 1761556Srgrimes warnx("can't reach time daemon, time set locally"); 1771556Srgrimes 1781556Srgrimesbad: 1791556Srgrimes (void)close(s); 1801556Srgrimes return (retval = 2); 1811556Srgrimes} 182