1 /* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos 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.30 2011/01/29 02:16:52 christos 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 static const char * 63 tsp_type_to_string(const struct tsp *msg) 64 { 65 unsigned i; 66 67 i = msg->tsp_type; 68 return i < TSPTYPENUMBER ? tsptype[i] : "unknown"; 69 } 70 71 /* 72 * Set the date in the machines controlled by timedaemons by communicating the 73 * new date to the local timedaemon. If the timedaemon is in the master state, 74 * it performs the correction on all slaves. If it is in the slave state, it 75 * notifies the master that a correction is needed. 76 * Returns 0 on success. Returns > 0 on failure. 77 */ 78 int 79 netsettime(time_t tval) 80 { 81 struct sockaddr_in dest; 82 struct tsp msg; 83 char hostname[MAXHOSTNAMELEN]; 84 struct servent *sp; 85 struct pollfd ready; 86 int found, s, timed_ack, waittime; 87 88 if ((sp = getservbyname("timed", "udp")) == NULL) { 89 warnx("udp/timed: unknown service"); 90 return 2; 91 } 92 93 (void)memset(&dest, 0, sizeof(dest)); 94 #ifdef BSD4_4 95 dest.sin_len = sizeof(dest); 96 #endif 97 dest.sin_family = AF_INET; 98 dest.sin_port = sp->s_port; 99 dest.sin_addr.s_addr = htonl(INADDR_ANY); 100 s = socket(AF_INET, SOCK_DGRAM, 0); 101 if (s == -1) { 102 if (errno != EAFNOSUPPORT) 103 warn("timed"); 104 return 2; 105 } 106 107 #ifdef IP_PORTRANGE 108 { 109 static const int on = IP_PORTRANGE_LOW; 110 111 if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on, 112 sizeof(on)) == -1) { 113 warn("setsockopt"); 114 goto bad; 115 } 116 } 117 #endif 118 119 msg.tsp_type = TSP_SETDATE; 120 msg.tsp_vers = TSPVERSION; 121 if (gethostname(hostname, sizeof(hostname)) == -1) { 122 warn("gethostname"); 123 goto bad; 124 } 125 (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); 126 msg.tsp_seq = htons((in_port_t)0); 127 msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */ 128 msg.tsp_time.tv_usec = htonl((in_addr_t)0); 129 if (connect(s, (const void *)&dest, sizeof(dest)) == -1) { 130 warn("connect"); 131 goto bad; 132 } 133 if (send(s, &msg, sizeof(msg), 0) == -1) { 134 if (errno != ECONNREFUSED) 135 warn("send"); 136 goto bad; 137 } 138 139 timed_ack = -1; 140 waittime = WAITACK; 141 ready.fd = s; 142 ready.events = POLLIN; 143 loop: 144 found = poll(&ready, 1, waittime); 145 146 { 147 socklen_t len; 148 int error; 149 150 len = sizeof(error); 151 if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) { 152 warn("getsockopt"); 153 goto bad; 154 } 155 if (error) { 156 if (error != ECONNREFUSED) { 157 errno = error; 158 warn("send (delayed error)"); 159 } 160 goto bad; 161 } 162 } 163 164 if (found > 0 && ready.revents & POLLIN) { 165 ssize_t ret; 166 167 if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) { 168 if (errno != ECONNREFUSED) 169 warn("recv"); 170 goto bad; 171 } else if ((size_t)ret < sizeof(msg)) { 172 warnx("recv: incomplete packet"); 173 goto bad; 174 } 175 176 msg.tsp_seq = ntohs(msg.tsp_seq); 177 msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); 178 msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); 179 switch (msg.tsp_type) { 180 case TSP_ACK: 181 timed_ack = TSP_ACK; 182 waittime = WAITDATEACK; 183 goto loop; 184 case TSP_DATEACK: 185 (void)close(s); 186 return 0; 187 default: 188 warnx("wrong ack received from timed: %s", 189 tsp_type_to_string(&msg)); 190 timed_ack = -1; 191 break; 192 } 193 } 194 if (timed_ack == -1) 195 warnx("can't reach time daemon, time set locally"); 196 197 bad: 198 (void)close(s); 199 return 2; 200 } 201