1 /*
2 * tlsdate_status.c - handles tlsdate-monitor responses
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 <errno.h>
11 #include <fcntl.h>
12 #include <stdbool.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17
18 #include <event2/event.h>
19
20 #include "src/conf.h"
21 #include "src/util.h"
22 #include "src/tlsdate.h"
23
24 /* Returns < 0 on error, > 0 on eagain, and 0 on success */
25 int
read_tlsdate_response(int fd,time_t * t)26 read_tlsdate_response (int fd, time_t *t)
27 {
28 /* TLS passes time as a 32-bit value. */
29 uint32_t server_time = 0;
30 ssize_t ret = IGNORE_EINTR (read (fd, &server_time, sizeof (server_time)));
31 if (ret == -1 && errno == EAGAIN)
32 {
33 /* Full response isn't ready yet. */
34 return 1;
35 }
36 if (ret != sizeof (server_time))
37 {
38 /* End of pipe (0) or truncated: death probable. */
39 error ("[event:(%s)] invalid time read from tlsdate (rd:%d,ret:%zd).",
40 __func__, server_time, ret);
41 return -1;
42 }
43 /* uint32_t moves to signed long so there is room for silliness. */
44 *t = server_time;
45 return 0;
46 }
47
48 void
action_tlsdate_timeout(evutil_socket_t fd,short what,void * arg)49 action_tlsdate_timeout (evutil_socket_t fd, short what, void *arg)
50 {
51 struct state *state = arg;
52 info ("[event:%s] tlsdate timed out", __func__);
53 /* Force kill it and let action_sigchld rerun. */
54 if (state->tlsdate_pid)
55 kill (state->tlsdate_pid, SIGKILL);
56 }
57
58 void
action_tlsdate_status(evutil_socket_t fd,short what,void * arg)59 action_tlsdate_status (evutil_socket_t fd, short what, void *arg)
60 {
61 struct state *state = arg;
62 time_t t = 0;
63 int ret = read_tlsdate_response (fd, &t);
64 verb_debug ("[event:%s] fired", __func__);
65 if (ret < 0)
66 {
67 verb_debug ("[event:%s] forcibly timing out tlsdate", __func__);
68 trigger_event (state, E_TLSDATE_TIMEOUT, 0);
69 return;
70 }
71 if (ret)
72 {
73 /* EAGAIN'd: wait for the rest. */
74 trigger_event (state, E_TLSDATE_STATUS, -1);
75 return;
76 }
77 if (is_sane_time (t))
78 {
79 /* Note that last_time is from an online source */
80 state->last_sync_type = SYNC_TYPE_NET;
81 state->last_time = t;
82 trigger_event (state, E_SAVE, -1);
83 }
84 else
85 {
86 error ("[event:%s] invalid time received from tlsdate: %ld",
87 __func__, t);
88 }
89 /* Restore the backoff and tries count on success, insane or not.
90 * On failure, the event handler does it.
91 */
92 state->tries = 0;
93 state->backoff = state->opts.wait_between_tries;
94 return;
95 }
96
97 /* Returns 0 on success and populates |fds| */
98 int
new_tlsdate_monitor_pipe(int fds[2])99 new_tlsdate_monitor_pipe (int fds[2])
100 {
101 if (pipe (fds) < 0)
102 {
103 perror ("pipe failed");
104 return -1;
105 }
106 /* TODO(wad): CLOEXEC, Don't leak these into tlsdate proper. */
107 return 0;
108 }
109
110 /* Create a fd pair that the tlsdate runner will communicate over */
111 int
setup_tlsdate_status(struct state * state)112 setup_tlsdate_status (struct state *state)
113 {
114 int fds[2] = { -1, -1 };
115 /* One pair of pipes are reused along with the event. */
116 if (new_tlsdate_monitor_pipe (fds))
117 {
118 return -1;
119 }
120 verb_debug ("[%s] monitor fd pair (%d, %d)", __func__, fds[0], fds[1]);
121 /* The fd that the monitor process will write to */
122 state->tlsdate_monitor_fd = fds[1];
123 /* Make the reader fd non-blocking and not leak into tlsdate. */
124 if (fcntl (fds[0], F_SETFL, O_NONBLOCK|O_CLOEXEC) < 0)
125 {
126 perror ("pipe[0] fcntl(O_NONBLOCK) failed");
127 return 1;
128 }
129 state->events[E_TLSDATE_STATUS] = event_new (state->base, fds[0],
130 EV_READ,
131 action_tlsdate_status, state);
132 if (!state->events[E_TLSDATE_STATUS])
133 {
134 error ("Failed to allocate tlsdate status event");
135 return 1;
136 }
137 event_priority_set (state->events[E_TLSDATE_STATUS], PRI_NET);
138 state->events[E_TLSDATE_TIMEOUT] = event_new (state->base, -1,
139 EV_TIMEOUT,
140 action_tlsdate_timeout, state);
141 if (!state->events[E_TLSDATE_TIMEOUT])
142 {
143 error ("Failed to allocate tlsdate timeout event");
144 return 1;
145 }
146 event_priority_set (state->events[E_TLSDATE_TIMEOUT], PRI_SAVE);
147 return 0;
148 }
149