blob: 5b66815b2c083906b2be0f43a96e8fd8c044ae85 [file] [log] [blame]
Christian Grothoff90e9f832012-02-07 11:16:47 +01001/* Copyright (c) 2012, Jacob Appelbaum.
2 * Copyright (c) 2012, The Tor Project, Inc. */
3/* See LICENSE for licensing information */
4/*
5 This file contains the license for tlsdate,
6 a free software project to set your system clock securely.
7
8 It also lists the licenses for other components used by tlsdate.
9
10 For more information about tlsdate, see https://github.com/ioerror/tlsdate
11
12 If you got this file as a part of a larger bundle,
13 there may be other license terms that you should be aware of.
14
15===============================================================================
16tlsdate is distributed under this license:
17
18Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
19Copyright (c) 2011-2012, The Tor Project, Inc.
20
21Redistribution and use in source and binary forms, with or without
22modification, are permitted provided that the following conditions are
23met:
24
25 * Redistributions of source code must retain the above copyright
26notice, this list of conditions and the following disclaimer.
27
28 * Redistributions in binary form must reproduce the above
29copyright notice, this list of conditions and the following disclaimer
30in the documentation and/or other materials provided with the
31distribution.
32
33 * Neither the names of the copyright owners nor the names of its
34contributors may be used to endorse or promote products derived from
35this software without specific prior written permission.
36
37THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48===============================================================================
49If you got tlsdate as a static binary with OpenSSL included, then you should
50know:
51
52 "This product includes software developed by the OpenSSL Project for use in
53 the OpenSSL Toolkit (http://www.openssl.org/)"
54
55===============================================================================
56*/
57
58/**
Christian Grothoffe267c352012-02-14 01:10:54 +010059 * \file tlsdate-helper.c
60 * \brief Helper program that does the actual work of setting the system clock.
Christian Grothoff90e9f832012-02-07 11:16:47 +010061 **/
62
63/*
64 * tlsdate is a tool for setting the system clock by hand or by communication
65 * with the network. It does not set the RTC. It is designed to be as secure as
66 * TLS (RFC 2246) but of course the security of TLS is often reduced to
67 * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
68 * your local CA root store - so any of these companies could assist in a MITM
69 * attack against you and you'd be screwed.
70
71 * This tool is designed to be run by hand or as a system daemon. It must be
72 * run as root or otherwise have the proper caps; it will not be able to set
73 * the system time without running as root or another privileged user.
74 */
75
76#include "tlsdate-config.h"
77
78#include <stdarg.h>
79#include <stdint.h>
Christian Grothoff191cd982012-02-14 00:48:45 +010080#include <stdio.h>
81#include <unistd.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010082#include <sys/time.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010083#include <sys/types.h>
84#include <sys/wait.h>
Christian Grothoff88b422b2012-02-14 00:35:09 +010085#include <sys/mman.h>
Christian Grothoff191cd982012-02-14 00:48:45 +010086#include <time.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010087#include <pwd.h>
Jacob Appelbaum2c385d22012-02-21 14:04:15 -080088#include <grp.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010089#include <arpa/inet.h>
90
91#include <openssl/bio.h>
92#include <openssl/ssl.h>
93#include <openssl/err.h>
94#include <openssl/evp.h>
95
Christian Grothoff191cd982012-02-14 00:48:45 +010096/** Name of user that we feel safe to run SSL handshake with. */
Elly Jones1cddca62012-06-20 15:00:33 -040097#ifndef UNPRIV_USER
Christian Grothoff90e9f832012-02-07 11:16:47 +010098#define UNPRIV_USER "nobody"
Elly Jones1cddca62012-06-20 15:00:33 -040099#endif
100#ifndef UNPRIV_GROUP
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800101#define UNPRIV_GROUP "nogroup"
Elly Jones1cddca62012-06-20 15:00:33 -0400102#endif
Christian Grothoff90e9f832012-02-07 11:16:47 +0100103
104// We should never accept a time before we were compiled
105// We measure in seconds since the epoch - eg: echo `date '+%s'`
106// We set this manually to ensure others can reproduce a build;
107// automation of this will make every build different!
Elly Jones1cddca62012-06-20 15:00:33 -0400108#ifndef RECENT_COMPILE_DATE
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400109#define RECENT_COMPILE_DATE (uint32_t) 1342323666
Elly Jones1cddca62012-06-20 15:00:33 -0400110#endif
dave bl30d82102012-02-08 01:39:24 +1100111#define MAX_REASONABLE_TIME (uint32_t) 1999991337
Christian Grothoff90e9f832012-02-07 11:16:47 +0100112
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800113// After the duration of the TLS handshake exceeds this threshold
Philipp Winterb3ca5772012-02-16 11:56:11 +0100114// (in msec), a warning is printed.
115#define TLS_RTT_THRESHOLD 2000
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800116
Christian Grothoff90e9f832012-02-07 11:16:47 +0100117static int verbose;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100118
Christian Grothoff88b422b2012-02-14 00:35:09 +0100119static int ca_racket;
120
121static const char *host;
122
123static const char *port;
124
125static const char *protocol;
126
Elly Jones9ae3aa62012-06-20 15:32:46 -0400127static const char *certdir;
128
Christian Grothoff191cd982012-02-14 00:48:45 +0100129/** helper function to print message and die */
Christian Grothoff90e9f832012-02-07 11:16:47 +0100130static void
131die(const char *fmt, ...)
132{
133 va_list ap;
134
135 va_start(ap, fmt);
136 vfprintf(stderr, fmt, ap);
137 va_end(ap);
138 exit(1);
139}
140
141
Christian Grothoff90e9f832012-02-07 11:16:47 +0100142/** helper function for 'verbose' output */
143static void
144verb (const char *fmt, ...)
145{
146 va_list ap;
147
Christian Grothoffafbae372012-02-07 14:17:53 +0100148 if (! verbose) return;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100149 va_start(ap, fmt);
150 // FIXME: stdout or stderr for verbose messages?
151 vfprintf(stderr, fmt, ap);
152 va_end(ap);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100153}
154
155
Christian Grothoff88b422b2012-02-14 00:35:09 +0100156/**
157 * Run SSL handshake and store the resulting time value in the
158 * 'time_map'.
159 *
160 * @param time_map where to store the current time
161 */
162static void
163run_ssl (uint32_t *time_map)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100164{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100165 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100166 SSL_CTX *ctx;
167 SSL *ssl;
168
Christian Grothoff90e9f832012-02-07 11:16:47 +0100169 SSL_load_error_strings();
170 SSL_library_init();
171
172 ctx = NULL;
173 if (0 == strcmp("sslv23", protocol))
174 {
175 verb ("V: using SSLv23_client_method()\n");
176 ctx = SSL_CTX_new(SSLv23_client_method());
177 } else if (0 == strcmp("sslv3", protocol))
178 {
179 verb ("V: using SSLv3_client_method()\n");
180 ctx = SSL_CTX_new(SSLv3_client_method());
181 } else if (0 == strcmp("tlsv1", protocol))
182 {
183 verb ("V: using TLSv1_client_method()\n");
184 ctx = SSL_CTX_new(TLSv1_client_method());
185 } else
186 die("Unsupported protocol `%s'\n", protocol);
187
188 if (ctx == NULL)
189 die("OpenSSL failed to support protocol `%s'\n", protocol);
190
191 if (ca_racket)
192 {
Elly Jones9ae3aa62012-06-20 15:32:46 -0400193 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, certdir))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100194 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
195 }
196
197 if (NULL == (s_bio = BIO_new_ssl_connect(ctx)))
198 die ("SSL BIO setup failed\n");
199 BIO_get_ssl(s_bio, &ssl);
200 if (NULL == ssl)
201 die ("SSL setup failed\n");
202 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
203 if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
204 (1 != BIO_set_conn_port(s_bio, port)) )
205 die ("Failed to initialize connection to `%s:%s'\n", host, port);
206
Stewart Smith3aa3f382012-06-29 14:36:34 +1000207 if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
208 die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
Christian Grothoff90e9f832012-02-07 11:16:47 +0100209
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800210 // This should run in seccomp
211 // eg: prctl(PR_SET_SECCOMP, 1);
212 if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800213 die ("SSL connection failed\n");
Philipp Winterd96af622012-02-15 22:15:50 +0100214 if (1 != BIO_do_handshake(s_bio))
215 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100216 // Verify the peer certificate against the CA certs on the local system
217 if (ca_racket) {
Christian Grothoff90e9f832012-02-07 11:16:47 +0100218 long ssl_verify_result;
219
Stewart Smithfc0171f2012-06-29 14:38:24 +1000220 if (NULL == SSL_get_peer_certificate(ssl))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100221 die ("Getting SSL certificate failed\n");
222
223 // In theory, we verify that the cert is valid
224 ssl_verify_result = SSL_get_verify_result(ssl);
225 switch (ssl_verify_result)
226 {
227 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
228 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Christian Grothoffe267c352012-02-14 01:10:54 +0100229 die ("SSL certificate is self signed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100230 case X509_V_OK:
Christian Grothoffe267c352012-02-14 01:10:54 +0100231 verb ("V: SSL certificate verification passed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100232 break;
233 default:
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800234 die ("SSL certification verification error: %ld\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800235 ssl_verify_result);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100236 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100237 } else {
238 verb ("V: Certificate verification skipped!\n");
239 }
240
Christian Grothoff90e9f832012-02-07 11:16:47 +0100241 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700242 // ssl->s3->server_random is an unsigned char of 32 bits
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800243 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100244}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100245
246
Christian Grothoff191cd982012-02-14 00:48:45 +0100247/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100248static void
249become_nobody ()
250{
251 uid_t uid;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800252 gid_t gid;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100253 struct passwd *pw;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800254 struct group *gr;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100255
Christian Grothoffe267c352012-02-14 01:10:54 +0100256 if (0 != getuid ())
257 return; /* not running as root to begin with; should (!) be harmless to continue
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800258 without dropping to 'nobody' (setting time will fail in the end) */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100259 pw = getpwnam(UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800260 gr = getgrnam(UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100261 if (NULL == pw)
262 die ("Failed to obtain UID for `%s'\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800263 if (NULL == gr)
264 die ("Failed to obtain GID for `%s'\n", UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100265 uid = pw->pw_uid;
266 if (0 == uid)
267 die ("UID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800268 gid = pw->pw_gid;
269 if (0 == gid || 0 == gr->gr_gid)
270 die ("GID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
271 if (pw->pw_gid != gr->gr_gid)
Jacob Appelbaumad873f32012-02-21 14:36:10 -0800272 die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
273 UNPRIV_USER, UNPRIV_GROUP);
274
275 if (0 != initgroups((const char *)UNPRIV_USER, gr->gr_gid))
276 die ("Unable to initgroups for `%s' in group `%s' as expected\n",
277 UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800278
279#ifdef HAVE_SETRESGID
280 if (0 != setresgid (gid, gid, gid))
281 die ("Failed to setresgid: %s\n", strerror (errno));
282#else
283 if (0 != (setgid (gid) | setegid (gid)))
284 die ("Failed to setgid: %s\n", strerror (errno));
285#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100286#ifdef HAVE_SETRESUID
287 if (0 != setresuid (uid, uid, uid))
288 die ("Failed to setresuid: %s\n", strerror (errno));
289#else
290 if (0 != (setuid (uid) | seteuid (uid)))
291 die ("Failed to setuid: %s\n", strerror (errno));
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800292#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100293}
294
295
Christian Grothoff88b422b2012-02-14 00:35:09 +0100296int
297main(int argc, char **argv)
298{
299 uint32_t *time_map;
300 struct timeval start_timeval;
301 struct timeval end_timeval;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400302 struct timeval warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100303 int status;
304 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100305 long long rt_time_ms;
306 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200307 int setclock;
308 int showtime;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400309 int timewarp;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100310
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400311 if (argc != 10)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100312 return 1;
313 host = argv[1];
314 port = argv[2];
315 protocol = argv[3];
Elly Jones9ae3aa62012-06-20 15:32:46 -0400316 certdir = argv[6];
Christian Grothoff88b422b2012-02-14 00:35:09 +0100317 ca_racket = (0 != strcmp ("unchecked", argv[4]));
318 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200319 setclock = (0 == strcmp ("setclock", argv[7]));
320 showtime = (0 == strcmp ("showtime", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400321 timewarp = (0 == strcmp ("timewarp", argv[9]));
322
323 if (timewarp)
324 {
325 warp_time.tv_sec = RECENT_COMPILE_DATE;
326 warp_time.tv_usec = 0;
327 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200328
329 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400330 if (0 == setclock && 0 == timewarp)
331 {
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200332 become_nobody ();
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400333 }
Christian Grothoff88b422b2012-02-14 00:35:09 +0100334
335 time_map = mmap (NULL, sizeof (uint32_t),
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800336 PROT_READ | PROT_WRITE,
337 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100338 if (MAP_FAILED == time_map)
339 {
340 fprintf (stderr, "mmap failed: %s\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400341 strerror (errno));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100342 return 1;
343 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100344
345 /* Get the current time from the system clock. */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100346 if (0 != gettimeofday(&start_timeval, NULL))
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400347 {
Christian Grothoff88b422b2012-02-14 00:35:09 +0100348 die ("Failed to read current time of day: %s\n", strerror (errno));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400349 }
350
Christian Grothoff191cd982012-02-14 00:48:45 +0100351 verb ("V: time is currently %lu.%06lu\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400352 (unsigned long)start_timeval.tv_sec,
353 (unsigned long)start_timeval.tv_usec);
354
355 if (((unsigned long)start_timeval.tv_sec) < ((unsigned long)warp_time.tv_sec))
356 {
357 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
358 if (timewarp)
359 {
360 verb ("V: Attempting to warp local clock into the future\n");
361 if (0 != settimeofday(&warp_time, NULL))
362 {
363 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
364 strerror (errno),
365 (unsigned long)warp_time.tv_sec,
366 (unsigned long)warp_time.tv_usec);
367 }
368 if (0 != gettimeofday(&start_timeval, NULL))
369 {
370 die ("Failed to read current time of day: %s\n", strerror (errno));
371 }
372 verb ("V: time is currently %lu.%06lu\n",
373 (unsigned long)start_timeval.tv_sec,
374 (unsigned long)start_timeval.tv_usec);
375 verb ("V: It's just a step to the left...\n");
376 }
377 } else {
378 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
379 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100380
381 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100382 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +0100383
384 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100385 ssl_child = fork ();
386 if (-1 == ssl_child)
387 die ("fork failed: %s\n", strerror (errno));
388 if (0 == ssl_child)
389 {
Christian Grothoffbd15a222012-02-14 00:40:57 +0100390 become_nobody ();
Christian Grothoff88b422b2012-02-14 00:35:09 +0100391 run_ssl (time_map);
392 (void) munmap (time_map, sizeof (uint32_t));
393 _exit (0);
394 }
395 if (ssl_child != waitpid (ssl_child, &status, 0))
396 die ("waitpid failed: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +0100397 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
398 die ("child process failed in SSL handshake\n");
Christian Grothoff88b422b2012-02-14 00:35:09 +0100399
400 if (0 != gettimeofday(&end_timeval, NULL))
401 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +0100402
403 /* calculate RTT */
404 rt_time_ms = (end_timeval.tv_sec - start_timeval.tv_sec) * 1000 + (end_timeval.tv_usec - start_timeval.tv_usec) / 1000;
405 if (rt_time_ms < 0)
406 rt_time_ms = 0; /* non-linear time... */
407 server_time_s = ntohl (*time_map);
408 munmap (time_map, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100409
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800410 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800411 (unsigned int) server_time_s,
412 start_timeval.tv_sec - server_time_s,
413 rt_time_ms);
Christian Grothoff191cd982012-02-14 00:48:45 +0100414
Philipp Winterb3ca5772012-02-16 11:56:11 +0100415 /* warning if the handshake took too long */
416 if (rt_time_ms > TLS_RTT_THRESHOLD) {
417 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
418 "server or run it again\n", TLS_RTT_THRESHOLD);
419 }
420
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200421 if (showtime)
422 {
423 struct tm ltm;
424 time_t tim = server_time_s;
425 char buf[256];
426
427 localtime_r(&tim, &ltm);
428 (void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm);
429 fprintf(stdout, "%s\n", buf);
430 }
431
Christian Grothoff191cd982012-02-14 00:48:45 +0100432 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200433 if (setclock)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100434 {
435 struct timeval server_time;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100436
Christian Grothoffe267c352012-02-14 01:10:54 +0100437 /* correct server time by half of RTT */
438 server_time.tv_sec = server_time_s + (rt_time_ms / 2 / 1000);
439 server_time.tv_usec = (rt_time_ms / 2) % 1000;
440
Christian Grothoff90e9f832012-02-07 11:16:47 +0100441 // We should never receive a time that is before the time we were last
442 // compiled; we subscribe to the linear theory of time for this program
443 // and this program alone!
Christian Grothofff5098b42012-02-07 12:20:33 +0100444 if (server_time.tv_sec >= MAX_REASONABLE_TIME)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800445 die("remote server is a false ticker from the future!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100446 if (server_time.tv_sec <= RECENT_COMPILE_DATE)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800447 die ("remote server is a false ticker!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100448 if (0 != settimeofday(&server_time, NULL))
Stewart Smithf4780442012-06-29 14:31:49 +1000449 die ("setting time failed: %s (Difference from server is about %d)\n",
450 strerror (errno),
451 start_timeval.tv_sec - server_time_s);
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200452 verb ("V: setting time succeeded\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100453 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100454 return 0;
455}