1 /* 2 * time_set.c - time setting functions 3 * Copyright (c) 2013 The Chromium Authors. All rights reserved. 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "config.h" 9 10 #include <assert.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 #include <signal.h> 14 #include <stdarg.h> 15 #include <stdint.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <sys/wait.h> 19 #include <sys/types.h> 20 #include <time.h> 21 #include <unistd.h> 22 23 #include <event2/event.h> 24 25 #include "src/conf.h" 26 #include "src/dbus.h" 27 #include "src/tlsdate.h" 28 #include "src/util.h" 29 30 void 31 handle_time_setter (struct state *state, int status) 32 { 33 switch (status) 34 { 35 case SETTER_BAD_TIME: 36 info ("[event:%s] time setter received bad time", __func__); 37 /* This is the leaf node. Failure means that our source 38 * tried to walk back in time. 39 */ 40 state->last_sync_type = SYNC_TYPE_RTC; 41 state->last_time = time (NULL); 42 break; 43 case SETTER_TIME_SET: 44 info ("[event:%s] time set from the %s (%ld)", 45 __func__, sync_type_str (state->last_sync_type), state->last_time); 46 if (state->last_sync_type == SYNC_TYPE_NET) 47 { 48 /* Update the delta so it doesn't fire again immediately. */ 49 state->clock_delta = 0; 50 check_continuity (&state->clock_delta); 51 /* Reset the sources list! */ 52 state->opts.cur_source = NULL; 53 } 54 /* Share our success. */ 55 if (state->opts.should_dbus) 56 dbus_announce (state); 57 break; 58 case SETTER_NO_SBOX: 59 error ("[event:%s] time setter failed to sandbox", __func__); 60 break; 61 case SETTER_EXIT: 62 error ("[event:%s] time setter exited gracefully", __func__); 63 break; 64 case SETTER_SET_ERR: 65 error ("[event:%s] time setter could not settimeofday()", __func__); 66 break; 67 case SETTER_NO_RTC: 68 error ("[event:%s] time setter could sync rtc", __func__); 69 break; 70 case SETTER_NO_SAVE: 71 error ("[event:%s] time setter could not open save file", __func__); 72 break; 73 case SETTER_READ_ERR: 74 error ("[event:%s] time setter could not read time", __func__); 75 break; 76 default: 77 error ("[event:%s] received bogus status from time setter: %d", 78 __func__, status); 79 exit (status); 80 } 81 } 82 83 void 84 action_time_set (evutil_socket_t fd, short what, void *arg) 85 { 86 struct state *state = arg; 87 int status = -1; 88 ssize_t bytes = 0; 89 verb_debug ("[event:%s] fired", __func__); 90 bytes = IGNORE_EINTR (read (fd, &status, sizeof (status))); 91 if (bytes == -1 && errno == EAGAIN) 92 return; /* Catch next wake up */ 93 /* Catch the rest of the errnos and any truncation. */ 94 if (bytes != sizeof (status)) 95 { 96 /* Truncation of an int over a pipe shouldn't happen except in 97 * terminal cases. 98 */ 99 perror ("[event:%s] time setter pipe truncated! (%d)", __func__, 100 bytes); 101 /* Let SIGCHLD do the teardown. */ 102 close (fd); 103 return; 104 } 105 handle_time_setter (state, status); 106 } 107 108 int 109 setup_time_setter (struct state *state) 110 { 111 struct event *event; 112 int to_fds[2]; 113 int from_fds[2]; 114 if (pipe (to_fds) < 0) 115 { 116 perror ("pipe failed"); 117 return 1; 118 } 119 if (pipe (from_fds) < 0) 120 { 121 perror ("pipe failed"); 122 close (to_fds[0]); 123 close (to_fds[1]); 124 return 1; 125 } 126 /* The fd that tlsdated will write to */ 127 state->setter_save_fd = to_fds[1]; 128 state->setter_notify_fd = from_fds[0]; 129 /* Make the notifications fd non-blocking. */ 130 if (fcntl (from_fds[0], F_SETFL, O_NONBLOCK) < 0) 131 { 132 perror ("notifier_fd fcntl(O_NONBLOCK) failed"); 133 goto close_and_fail; 134 } 135 /* Make writes non-blocking */ 136 if (fcntl (to_fds[1], F_SETFL, O_NONBLOCK) < 0) 137 { 138 perror ("save_fd fcntl(O_NONBLOCK) failed"); 139 goto close_and_fail; 140 } 141 event = event_new (state->base, from_fds[0], EV_READ|EV_PERSIST, 142 action_time_set, state); 143 if (!event) 144 { 145 error ("Failed to allocate tlsdate setter event"); 146 goto close_and_fail; 147 } 148 event_priority_set (event, PRI_NET); 149 event_add (event, NULL); 150 /* fork */ 151 state->setter_pid = fork(); 152 if (state->setter_pid < 0) 153 { 154 perror ("fork()ing the time setter failed"); 155 goto close_and_fail; 156 } 157 if (state->setter_pid == 0) 158 { 159 close (to_fds[1]); 160 close (from_fds[0]); 161 time_setter_coprocess (to_fds[0], from_fds[1], state); 162 _exit (1); 163 } 164 close (from_fds[1]); 165 close (to_fds[0]); 166 return 0; 167 168 close_and_fail: 169 close (to_fds[0]); 170 close (to_fds[1]); 171 close (from_fds[0]); 172 close (from_fds[1]); 173 return 1; 174 } 175