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