netdate.c revision 90108
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 * 3. All advertising materials mentioning features or use of this software
141556Srgrimes *    must display the following acknowledgement:
151556Srgrimes *	This product includes software developed by the University of
161556Srgrimes *	California, Berkeley and its contributors.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3535773Scharnier#if 0
3636006Scharnierstatic char sccsid[] = "@(#)netdate.c	8.1 (Berkeley) 5/31/93";
3735773Scharnier#endif
3835773Scharnierstatic const char rcsid[] =
3950471Speter  "$FreeBSD: head/bin/date/netdate.c 90108 2002-02-02 06:24:13Z imp $";
401556Srgrimes#endif /* not lint */
411556Srgrimes
421556Srgrimes#include <sys/param.h>
431556Srgrimes#include <sys/time.h>
441556Srgrimes#include <sys/socket.h>
451556Srgrimes
461556Srgrimes#include <netinet/in.h>
471556Srgrimes#include <netdb.h>
481556Srgrimes#define TSPTYPES
491556Srgrimes#include <protocols/timed.h>
501556Srgrimes
511556Srgrimes#include <err.h>
521556Srgrimes#include <errno.h>
531556Srgrimes#include <string.h>
541556Srgrimes#include <unistd.h>
551556Srgrimes
561556Srgrimes#include "extern.h"
571556Srgrimes
581556Srgrimes#define	WAITACK		2	/* seconds */
591556Srgrimes#define	WAITDATEACK	5	/* seconds */
601556Srgrimes
611556Srgrimesextern int retval;
621556Srgrimes
631556Srgrimes/*
641556Srgrimes * Set the date in the machines controlled by timedaemons by communicating the
651556Srgrimes * new date to the local timedaemon.  If the timedaemon is in the master state,
661556Srgrimes * it performs the correction on all slaves.  If it is in the slave state, it
671556Srgrimes * notifies the master that a correction is needed.
681556Srgrimes * Returns 0 on success.  Returns > 0 on failure, setting retval to 2;
691556Srgrimes */
701556Srgrimesint
7190108Simpnetsettime(time_t tval)
721556Srgrimes{
731556Srgrimes	struct timeval tout;
741556Srgrimes	struct servent *sp;
751556Srgrimes	struct tsp msg;
761556Srgrimes	struct sockaddr_in sin, dest, from;
771556Srgrimes	fd_set ready;
781556Srgrimes	long waittime;
791556Srgrimes	int s, length, port, timed_ack, found, err;
801556Srgrimes	char hostname[MAXHOSTNAMELEN];
811556Srgrimes
821556Srgrimes	if ((sp = getservbyname("timed", "udp")) == NULL) {
831556Srgrimes		warnx("udp/timed: unknown service");
841556Srgrimes		return (retval = 2);
851556Srgrimes	}
861556Srgrimes
871556Srgrimes	dest.sin_port = sp->s_port;
881556Srgrimes	dest.sin_family = AF_INET;
891556Srgrimes	dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
901556Srgrimes	s = socket(AF_INET, SOCK_DGRAM, 0);
911556Srgrimes	if (s < 0) {
921556Srgrimes		if (errno != EPROTONOSUPPORT)
931556Srgrimes			warn("timed");
941556Srgrimes		return (retval = 2);
951556Srgrimes	}
961556Srgrimes
971556Srgrimes	memset(&sin, 0, sizeof(sin));
981556Srgrimes	sin.sin_family = AF_INET;
991556Srgrimes	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
1001556Srgrimes		sin.sin_port = htons((u_short)port);
1011556Srgrimes		if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
1021556Srgrimes			break;
1031556Srgrimes		if (errno == EADDRINUSE)
1041556Srgrimes			continue;
1051556Srgrimes		if (errno != EADDRNOTAVAIL)
1061556Srgrimes			warn("bind");
1071556Srgrimes		goto bad;
1081556Srgrimes	}
1091556Srgrimes	if (port == IPPORT_RESERVED / 2) {
1101556Srgrimes		warnx("all ports in use");
1111556Srgrimes		goto bad;
1121556Srgrimes	}
1131556Srgrimes	msg.tsp_type = TSP_SETDATE;
1141556Srgrimes	msg.tsp_vers = TSPVERSION;
1151556Srgrimes	if (gethostname(hostname, sizeof(hostname))) {
1161556Srgrimes		warn("gethostname");
1171556Srgrimes		goto bad;
1181556Srgrimes	}
11926362Scharnier	(void)strncpy(msg.tsp_name, hostname, sizeof(msg.tsp_name) - 1);
12023622Sguido	msg.tsp_name[sizeof(msg.tsp_name) - 1] = '\0';
1211556Srgrimes	msg.tsp_seq = htons((u_short)0);
1221556Srgrimes	msg.tsp_time.tv_sec = htonl((u_long)tval);
1231556Srgrimes	msg.tsp_time.tv_usec = htonl((u_long)0);
1241556Srgrimes	length = sizeof(struct sockaddr_in);
1251556Srgrimes	if (connect(s, (struct sockaddr *)&dest, length) < 0) {
1261556Srgrimes		warn("connect");
1271556Srgrimes		goto bad;
1281556Srgrimes	}
1291556Srgrimes	if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
1301556Srgrimes		if (errno != ECONNREFUSED)
1311556Srgrimes			warn("send");
1321556Srgrimes		goto bad;
1331556Srgrimes	}
1341556Srgrimes
1351556Srgrimes	timed_ack = -1;
1361556Srgrimes	waittime = WAITACK;
1371556Srgrimesloop:
1381556Srgrimes	tout.tv_sec = waittime;
1391556Srgrimes	tout.tv_usec = 0;
1401556Srgrimes
1411556Srgrimes	FD_ZERO(&ready);
1421556Srgrimes	FD_SET(s, &ready);
1431556Srgrimes	found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
1441556Srgrimes
1451556Srgrimes	length = sizeof(err);
1461556Srgrimes	if (!getsockopt(s,
1471556Srgrimes	    SOL_SOCKET, SO_ERROR, (char *)&err, &length) && err) {
1481556Srgrimes		if (err != ECONNREFUSED)
14974819Sfenner			warnc(err, "send (delayed error)");
1501556Srgrimes		goto bad;
1511556Srgrimes	}
1521556Srgrimes
1531556Srgrimes	if (found > 0 && FD_ISSET(s, &ready)) {
1541556Srgrimes		length = sizeof(struct sockaddr_in);
1551556Srgrimes		if (recvfrom(s, &msg, sizeof(struct tsp), 0,
1561556Srgrimes		    (struct sockaddr *)&from, &length) < 0) {
1571556Srgrimes			if (errno != ECONNREFUSED)
1581556Srgrimes				warn("recvfrom");
1591556Srgrimes			goto bad;
1601556Srgrimes		}
1611556Srgrimes		msg.tsp_seq = ntohs(msg.tsp_seq);
1621556Srgrimes		msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
1631556Srgrimes		msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
1641556Srgrimes		switch (msg.tsp_type) {
1651556Srgrimes		case TSP_ACK:
1661556Srgrimes			timed_ack = TSP_ACK;
1671556Srgrimes			waittime = WAITDATEACK;
1681556Srgrimes			goto loop;
1691556Srgrimes		case TSP_DATEACK:
1701556Srgrimes			(void)close(s);
1711556Srgrimes			return (0);
1721556Srgrimes		default:
1738855Srgrimes			warnx("wrong ack received from timed: %s",
1741556Srgrimes			    tsptype[msg.tsp_type]);
1751556Srgrimes			timed_ack = -1;
1761556Srgrimes			break;
1771556Srgrimes		}
1781556Srgrimes	}
1791556Srgrimes	if (timed_ack == -1)
1801556Srgrimes		warnx("can't reach time daemon, time set locally");
1811556Srgrimes
1821556Srgrimesbad:
1831556Srgrimes	(void)close(s);
1841556Srgrimes	return (retval = 2);
1851556Srgrimes}
186