blob: 4617567eefa06cf22c19cc3d1145b357ff741208 [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
Jacob Appelbaum96390032012-07-15 15:53:13 -040076#include "../config/tlsdate-config.h"
Christian Grothoff90e9f832012-02-07 11:16:47 +010077
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!
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400108#ifndef RECENT_COMPILE_DATE
109#define RECENT_COMPILE_DATE (uint32_t) 1342323666
110#endif
111
112#ifndef MAX_REASONABLE_TIME
dave bl30d82102012-02-08 01:39:24 +1100113#define MAX_REASONABLE_TIME (uint32_t) 1999991337
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400114#endif
Christian Grothoff90e9f832012-02-07 11:16:47 +0100115
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800116// After the duration of the TLS handshake exceeds this threshold
Philipp Winterb3ca5772012-02-16 11:56:11 +0100117// (in msec), a warning is printed.
118#define TLS_RTT_THRESHOLD 2000
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800119
Christian Grothoff90e9f832012-02-07 11:16:47 +0100120static int verbose;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100121
Christian Grothoff88b422b2012-02-14 00:35:09 +0100122static int ca_racket;
123
124static const char *host;
125
126static const char *port;
127
128static const char *protocol;
129
Elly Jones9ae3aa62012-06-20 15:32:46 -0400130static const char *certdir;
131
Christian Grothoff191cd982012-02-14 00:48:45 +0100132/** helper function to print message and die */
Christian Grothoff90e9f832012-02-07 11:16:47 +0100133static void
134die(const char *fmt, ...)
135{
136 va_list ap;
137
138 va_start(ap, fmt);
139 vfprintf(stderr, fmt, ap);
140 va_end(ap);
141 exit(1);
142}
143
144
Christian Grothoff90e9f832012-02-07 11:16:47 +0100145/** helper function for 'verbose' output */
146static void
147verb (const char *fmt, ...)
148{
149 va_list ap;
150
Christian Grothoffafbae372012-02-07 14:17:53 +0100151 if (! verbose) return;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100152 va_start(ap, fmt);
153 // FIXME: stdout or stderr for verbose messages?
154 vfprintf(stderr, fmt, ap);
155 va_end(ap);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100156}
157
158
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700159void
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700160openssl_time_callback(const SSL* ssl, int where, int ret)
161{
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700162 if (where == SSL_CB_CONNECT_LOOP && ssl->state == SSL3_ST_CR_CERT_A)
163 {
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700164 // XXX TODO: If we want to trust the remote system for time,
165 // can we just read that time out of the remote system and if the
166 // cert verifies, decide that the time is reasonable?
167 // Such a process seems to indicate that a once valid cert would be
168 // forever valid - we stopgap that by ensuring it isn't less than
169 // the latest compiled_time and isn't above max_reasonable_time...
170 // XXX TODO: Solve eternal question about the Chicken and the Egg...
171 uint32_t compiled_time = RECENT_COMPILE_DATE;
172 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700173 uint32_t server_time;
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700174 verb("V: freezing time for x509 verification\n");
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700175 memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700176 if (compiled_time < ntohl(server_time)
177 &&
178 ntohl(server_time) < max_reasonable_time)
179 {
180 verb("V: remote peer provided: %d, prefered over compile time: %d\n",
181 ntohl(server_time), compiled_time);
182 verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
183 X509_VERIFY_PARAM_set_time(ssl->ctx->param, (time_t) ntohl(server_time));
184 } else {
185 die("V: the remote server is a false ticker! server: %d compile: %d\n",
186 ntohl(server_time), compiled_time);
187 }
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700188 }
189}
190
Christian Grothoff88b422b2012-02-14 00:35:09 +0100191/**
192 * Run SSL handshake and store the resulting time value in the
193 * 'time_map'.
194 *
195 * @param time_map where to store the current time
196 */
197static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400198run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100199{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100200 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100201 SSL_CTX *ctx;
202 SSL *ssl;
203
Christian Grothoff90e9f832012-02-07 11:16:47 +0100204 SSL_load_error_strings();
205 SSL_library_init();
206
207 ctx = NULL;
208 if (0 == strcmp("sslv23", protocol))
209 {
210 verb ("V: using SSLv23_client_method()\n");
211 ctx = SSL_CTX_new(SSLv23_client_method());
212 } else if (0 == strcmp("sslv3", protocol))
213 {
214 verb ("V: using SSLv3_client_method()\n");
215 ctx = SSL_CTX_new(SSLv3_client_method());
216 } else if (0 == strcmp("tlsv1", protocol))
217 {
218 verb ("V: using TLSv1_client_method()\n");
219 ctx = SSL_CTX_new(TLSv1_client_method());
220 } else
221 die("Unsupported protocol `%s'\n", protocol);
222
223 if (ctx == NULL)
224 die("OpenSSL failed to support protocol `%s'\n", protocol);
225
226 if (ca_racket)
227 {
Elly Jones9ae3aa62012-06-20 15:32:46 -0400228 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, certdir))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100229 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
230 }
231
232 if (NULL == (s_bio = BIO_new_ssl_connect(ctx)))
233 die ("SSL BIO setup failed\n");
234 BIO_get_ssl(s_bio, &ssl);
235 if (NULL == ssl)
236 die ("SSL setup failed\n");
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700237
238 if (time_is_an_illusion)
239 {
240 SSL_set_info_callback(ssl, openssl_time_callback);
241 }
242
Christian Grothoff90e9f832012-02-07 11:16:47 +0100243 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
244 if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
245 (1 != BIO_set_conn_port(s_bio, port)) )
246 die ("Failed to initialize connection to `%s:%s'\n", host, port);
247
Stewart Smith3aa3f382012-06-29 14:36:34 +1000248 if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
249 die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
Christian Grothoff90e9f832012-02-07 11:16:47 +0100250
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800251 // This should run in seccomp
252 // eg: prctl(PR_SET_SECCOMP, 1);
253 if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800254 die ("SSL connection failed\n");
Philipp Winterd96af622012-02-15 22:15:50 +0100255 if (1 != BIO_do_handshake(s_bio))
256 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100257 // Verify the peer certificate against the CA certs on the local system
258 if (ca_racket) {
Christian Grothoff90e9f832012-02-07 11:16:47 +0100259 long ssl_verify_result;
260
Stewart Smithfc0171f2012-06-29 14:38:24 +1000261 if (NULL == SSL_get_peer_certificate(ssl))
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400262 {
Christian Grothoff90e9f832012-02-07 11:16:47 +0100263 die ("Getting SSL certificate failed\n");
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400264 }
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700265/*
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400266 if (time_is_an_illusion)
267 {
268 // XXX TODO: If we want to trust the remote system for time,
269 // can we just read that time out of the remote system and if the
270 // cert verifies, decide that the time is reasonable?
271 // Such a process seems to indicate that a once valid cert would be
272 // forever valid - we stopgap that by ensuring it isn't less than
273 // the latest compiled_time and isn't above max_reasonable_time...
274 // XXX TODO: Solve eternal question about the Chicken and the Egg...
275 verb("V: freezing time for x509 verification\n");
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400276 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400277 if (compiled_time < ntohl( * time_map)
278 &&
279 ntohl(*time_map) < max_reasonable_time)
280 {
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400281 verb("V: remote peer provided: %d, prefered over compile time: %d\n",
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400282 ntohl( *time_map), compiled_time);
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400283 // In theory, we instruct verify to check if it _would be valid_ if the
284 // verification happened at ((time_t) ntohl(*time_map))
285 X509_VERIFY_PARAM_set_time(ctx->param, (time_t) ntohl(*time_map));
286 } else {
Jacob Appelbaum64d18952012-07-15 18:28:07 -0400287 die("V: the remote server is a false ticker! server: %d compile: %d\n",
288 ntohl(*time_map), compiled_time);
289 }
290 }
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700291*/
Christian Grothoff90e9f832012-02-07 11:16:47 +0100292 // In theory, we verify that the cert is valid
293 ssl_verify_result = SSL_get_verify_result(ssl);
294 switch (ssl_verify_result)
295 {
296 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
297 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Christian Grothoffe267c352012-02-14 01:10:54 +0100298 die ("SSL certificate is self signed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100299 case X509_V_OK:
Christian Grothoffe267c352012-02-14 01:10:54 +0100300 verb ("V: SSL certificate verification passed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100301 break;
302 default:
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800303 die ("SSL certification verification error: %ld\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800304 ssl_verify_result);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100305 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100306 } else {
307 verb ("V: Certificate verification skipped!\n");
308 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100309 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700310 // ssl->s3->server_random is an unsigned char of 32 bits
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800311 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100312}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100313
314
Christian Grothoff191cd982012-02-14 00:48:45 +0100315/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100316static void
317become_nobody ()
318{
319 uid_t uid;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800320 gid_t gid;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100321 struct passwd *pw;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800322 struct group *gr;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100323
Christian Grothoffe267c352012-02-14 01:10:54 +0100324 if (0 != getuid ())
325 return; /* not running as root to begin with; should (!) be harmless to continue
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800326 without dropping to 'nobody' (setting time will fail in the end) */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100327 pw = getpwnam(UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800328 gr = getgrnam(UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100329 if (NULL == pw)
330 die ("Failed to obtain UID for `%s'\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800331 if (NULL == gr)
332 die ("Failed to obtain GID for `%s'\n", UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100333 uid = pw->pw_uid;
334 if (0 == uid)
335 die ("UID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800336 gid = pw->pw_gid;
337 if (0 == gid || 0 == gr->gr_gid)
338 die ("GID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
339 if (pw->pw_gid != gr->gr_gid)
Jacob Appelbaumad873f32012-02-21 14:36:10 -0800340 die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
341 UNPRIV_USER, UNPRIV_GROUP);
342
343 if (0 != initgroups((const char *)UNPRIV_USER, gr->gr_gid))
344 die ("Unable to initgroups for `%s' in group `%s' as expected\n",
345 UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800346
347#ifdef HAVE_SETRESGID
348 if (0 != setresgid (gid, gid, gid))
349 die ("Failed to setresgid: %s\n", strerror (errno));
350#else
351 if (0 != (setgid (gid) | setegid (gid)))
352 die ("Failed to setgid: %s\n", strerror (errno));
353#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100354#ifdef HAVE_SETRESUID
355 if (0 != setresuid (uid, uid, uid))
356 die ("Failed to setresuid: %s\n", strerror (errno));
357#else
358 if (0 != (setuid (uid) | seteuid (uid)))
359 die ("Failed to setuid: %s\n", strerror (errno));
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800360#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100361}
362
363
Christian Grothoff88b422b2012-02-14 00:35:09 +0100364int
365main(int argc, char **argv)
366{
367 uint32_t *time_map;
368 struct timeval start_timeval;
369 struct timeval end_timeval;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400370 struct timeval warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100371 int status;
372 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100373 long long rt_time_ms;
374 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200375 int setclock;
376 int showtime;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400377 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400378 int leap;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100379
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400380 if (argc != 11)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100381 return 1;
382 host = argv[1];
383 port = argv[2];
384 protocol = argv[3];
Elly Jones9ae3aa62012-06-20 15:32:46 -0400385 certdir = argv[6];
Christian Grothoff88b422b2012-02-14 00:35:09 +0100386 ca_racket = (0 != strcmp ("unchecked", argv[4]));
387 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200388 setclock = (0 == strcmp ("setclock", argv[7]));
389 showtime = (0 == strcmp ("showtime", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400390 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400391 leap = (0 == strcmp ("leapaway", argv[10]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400392
393 if (timewarp)
394 {
395 warp_time.tv_sec = RECENT_COMPILE_DATE;
396 warp_time.tv_usec = 0;
Jacob Appelbaum96390032012-07-15 15:53:13 -0400397 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
398 (unsigned long)warp_time.tv_sec,
399 (unsigned long)warp_time.tv_usec);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400400 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200401
402 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400403 if (0 == setclock && 0 == timewarp)
404 {
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200405 become_nobody ();
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400406 }
Christian Grothoff88b422b2012-02-14 00:35:09 +0100407
408 time_map = mmap (NULL, sizeof (uint32_t),
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800409 PROT_READ | PROT_WRITE,
410 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100411 if (MAP_FAILED == time_map)
412 {
413 fprintf (stderr, "mmap failed: %s\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400414 strerror (errno));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100415 return 1;
416 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100417
418 /* Get the current time from the system clock. */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100419 if (0 != gettimeofday(&start_timeval, NULL))
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400420 {
Christian Grothoff88b422b2012-02-14 00:35:09 +0100421 die ("Failed to read current time of day: %s\n", strerror (errno));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400422 }
423
Christian Grothoff191cd982012-02-14 00:48:45 +0100424 verb ("V: time is currently %lu.%06lu\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400425 (unsigned long)start_timeval.tv_sec,
426 (unsigned long)start_timeval.tv_usec);
427
428 if (((unsigned long)start_timeval.tv_sec) < ((unsigned long)warp_time.tv_sec))
429 {
430 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
431 if (timewarp)
432 {
433 verb ("V: Attempting to warp local clock into the future\n");
434 if (0 != settimeofday(&warp_time, NULL))
435 {
436 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
437 strerror (errno),
438 (unsigned long)warp_time.tv_sec,
439 (unsigned long)warp_time.tv_usec);
440 }
441 if (0 != gettimeofday(&start_timeval, NULL))
442 {
443 die ("Failed to read current time of day: %s\n", strerror (errno));
444 }
445 verb ("V: time is currently %lu.%06lu\n",
446 (unsigned long)start_timeval.tv_sec,
447 (unsigned long)start_timeval.tv_usec);
448 verb ("V: It's just a step to the left...\n");
449 }
450 } else {
451 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
452 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100453
454 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100455 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +0100456
457 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100458 ssl_child = fork ();
459 if (-1 == ssl_child)
460 die ("fork failed: %s\n", strerror (errno));
461 if (0 == ssl_child)
462 {
Christian Grothoffbd15a222012-02-14 00:40:57 +0100463 become_nobody ();
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400464 run_ssl (time_map, leap);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100465 (void) munmap (time_map, sizeof (uint32_t));
466 _exit (0);
467 }
468 if (ssl_child != waitpid (ssl_child, &status, 0))
469 die ("waitpid failed: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +0100470 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
471 die ("child process failed in SSL handshake\n");
Christian Grothoff88b422b2012-02-14 00:35:09 +0100472
473 if (0 != gettimeofday(&end_timeval, NULL))
474 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +0100475
476 /* calculate RTT */
477 rt_time_ms = (end_timeval.tv_sec - start_timeval.tv_sec) * 1000 + (end_timeval.tv_usec - start_timeval.tv_usec) / 1000;
478 if (rt_time_ms < 0)
479 rt_time_ms = 0; /* non-linear time... */
480 server_time_s = ntohl (*time_map);
481 munmap (time_map, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100482
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800483 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800484 (unsigned int) server_time_s,
485 start_timeval.tv_sec - server_time_s,
486 rt_time_ms);
Christian Grothoff191cd982012-02-14 00:48:45 +0100487
Philipp Winterb3ca5772012-02-16 11:56:11 +0100488 /* warning if the handshake took too long */
489 if (rt_time_ms > TLS_RTT_THRESHOLD) {
490 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
491 "server or run it again\n", TLS_RTT_THRESHOLD);
492 }
493
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200494 if (showtime)
495 {
Jacob Appelbaum699a2762012-07-15 16:14:14 -0400496 struct tm ltm;
497 time_t tim = server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200498 char buf[256];
499
500 localtime_r(&tim, &ltm);
501 (void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm);
502 fprintf(stdout, "%s\n", buf);
503 }
504
Christian Grothoff191cd982012-02-14 00:48:45 +0100505 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200506 if (setclock)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100507 {
508 struct timeval server_time;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100509
Christian Grothoffe267c352012-02-14 01:10:54 +0100510 /* correct server time by half of RTT */
511 server_time.tv_sec = server_time_s + (rt_time_ms / 2 / 1000);
512 server_time.tv_usec = (rt_time_ms / 2) % 1000;
513
Christian Grothoff90e9f832012-02-07 11:16:47 +0100514 // We should never receive a time that is before the time we were last
515 // compiled; we subscribe to the linear theory of time for this program
516 // and this program alone!
Christian Grothofff5098b42012-02-07 12:20:33 +0100517 if (server_time.tv_sec >= MAX_REASONABLE_TIME)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800518 die("remote server is a false ticker from the future!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100519 if (server_time.tv_sec <= RECENT_COMPILE_DATE)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800520 die ("remote server is a false ticker!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100521 if (0 != settimeofday(&server_time, NULL))
Stewart Smithf4780442012-06-29 14:31:49 +1000522 die ("setting time failed: %s (Difference from server is about %d)\n",
Jacob Appelbaum699a2762012-07-15 16:14:14 -0400523 strerror (errno),
524 start_timeval.tv_sec - server_time_s);
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200525 verb ("V: setting time succeeded\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100526 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100527 return 0;
528}