1 /* $NetBSD: netdate.c,v 1.27 2008/02/24 04:49:45 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95"; 36 #else 37 __RCSID("$NetBSD: netdate.c,v 1.27 2008/02/24 04:49:45 dholland Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/time.h> 43 #include <sys/socket.h> 44 45 #include <netinet/in.h> 46 #include <netdb.h> 47 #define TSPTYPES 48 #include <protocols/timed.h> 49 50 #include <err.h> 51 #include <errno.h> 52 #include <poll.h> 53 #include <stdio.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 #include "extern.h" 58 59 #define WAITACK 2000 /* milliseconds */ 60 #define WAITDATEACK 5000 /* milliseconds */ 61 62 extern int retval; 63 64 static const char * 65 tsp_type_to_string(const struct tsp *msg) 66 { 67 unsigned i; 68 69 i = msg->tsp_type; 70 return i < TSPTYPENUMBER ? tsptype[i] : "unknown"; 71 } 72 73 /* 74 * Set the date in the machines controlled by timedaemons by communicating the 75 * new date to the local timedaemon. If the timedaemon is in the master state, 76 * it performs the correction on all slaves. If it is in the slave state, it 77 * notifies the master that a correction is needed. 78 * Returns 0 on success. Returns > 0 on failure, setting retval to 2; 79 */ 80 int 81 netsettime(time_t tval) 82 { 83 struct sockaddr_in dest; 84 struct tsp msg; 85 char hostname[MAXHOSTNAMELEN]; 86 struct servent *sp; 87 struct pollfd ready; 88 int found, s, timed_ack, waittime; 89 90 if ((sp = getservbyname("timed", "udp")) == NULL) { 91 warnx("udp/timed: unknown service"); 92 return (retval = 2); 93 } 94 95 (void)memset(&dest, 0, sizeof(dest)); 96 #ifdef BSD4_4 97 dest.sin_len = sizeof(dest); 98 #endif 99 dest.sin_family = AF_INET; 100 dest.sin_port = sp->s_port; 101 dest.sin_addr.s_addr = htonl(INADDR_ANY); 102 s = socket(AF_INET, SOCK_DGRAM, 0); 103 if (s < 0) { 104 if (errno != EAFNOSUPPORT) 105 warn("timed"); 106 return (retval = 2); 107 } 108 109 #ifdef IP_PORTRANGE 110 { 111 static const int on = IP_PORTRANGE_LOW; 112 113 if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, 114 &on, sizeof(on)) < 0) { 115 warn("setsockopt"); 116 goto bad; 117 } 118 } 119 #endif 120 121 msg.tsp_type = TSP_SETDATE; 122 msg.tsp_vers = TSPVERSION; 123 if (gethostname(hostname, sizeof(hostname))) { 124 warn("gethostname"); 125 goto bad; 126 } 127 strncpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); 128 msg.tsp_name[sizeof(msg.tsp_name) - 1] = '\0'; 129 msg.tsp_seq = htons((uint16_t)0); 130 msg.tsp_time.tv_sec = htonl((uint32_t)tval); /* XXX: y2038 */ 131 msg.tsp_time.tv_usec = htonl((uint32_t)0); 132 if (connect(s, (const struct sockaddr *)&dest, sizeof(dest)) < 0) { 133 warn("connect"); 134 goto bad; 135 } 136 if (send(s, &msg, sizeof(msg), 0) < 0) { 137 if (errno != ECONNREFUSED) 138 warn("send"); 139 goto bad; 140 } 141 142 timed_ack = -1; 143 waittime = WAITACK; 144 ready.fd = s; 145 ready.events = POLLIN; 146 loop: 147 found = poll(&ready, 1, waittime); 148 149 { 150 socklen_t length; 151 int error; 152 153 length = sizeof(error); 154 if (!getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &length) 155 && error) { 156 if (error != ECONNREFUSED) 157 warn("send (delayed error)"); 158 goto bad; 159 } 160 } 161 162 if (found > 0 && ready.revents & POLLIN) { 163 ssize_t ret; 164 165 ret = recv(s, &msg, sizeof(msg), 0); 166 if (ret < 0) { 167 if (errno != ECONNREFUSED) 168 warn("recv"); 169 goto bad; 170 } else if ((size_t)ret < sizeof(msg)) { 171 warnx("recv: incomplete packet"); 172 goto bad; 173 } 174 175 msg.tsp_seq = ntohs(msg.tsp_seq); 176 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 177 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 178 switch (msg.tsp_type) { 179 case TSP_ACK: 180 timed_ack = TSP_ACK; 181 waittime = WAITDATEACK; 182 goto loop; 183 case TSP_DATEACK: 184 (void)close(s); 185 return (0); 186 default: 187 warnx("wrong ack received from timed: %s", 188 tsp_type_to_string(&msg)); 189 timed_ack = -1; 190 break; 191 } 192 } 193 if (timed_ack == -1) 194 warnx("can't reach time daemon, time set locally"); 195 196 bad: 197 (void)close(s); 198 return (retval = 2); 199 } 200