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
handle_time_setter(struct state * state,int status)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
action_time_set(evutil_socket_t fd,short what,void * arg)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
setup_time_setter(struct state * state)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