/* * tlsdate_status.c - handles tlsdate-monitor responses * Copyright (c) 2013 The Chromium Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "config.h" #include <errno.h> #include <fcntl.h> #include <stdbool.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <event2/event.h> #include "src/conf.h" #include "src/util.h" #include "src/tlsdate.h" /* Returns < 0 on error, > 0 on eagain, and 0 on success */ int read_tlsdate_response (int fd, time_t *t) { /* TLS passes time as a 32-bit value. */ uint32_t server_time = 0; ssize_t ret = IGNORE_EINTR (read (fd, &server_time, sizeof (server_time))); if (ret == -1 && errno == EAGAIN) { /* Full response isn't ready yet. */ return 1; } if (ret != sizeof (server_time)) { /* End of pipe (0) or truncated: death probable. */ error ("[event:(%s)] invalid time read from tlsdate (rd:%d,ret:%zd).", __func__, server_time, ret); return -1; } /* uint32_t moves to signed long so there is room for silliness. */ *t = server_time; return 0; } void action_tlsdate_timeout (evutil_socket_t fd, short what, void *arg) { struct state *state = arg; info ("[event:%s] tlsdate timed out", __func__); /* Force kill it and let action_sigchld rerun. */ if (state->tlsdate_pid) kill (state->tlsdate_pid, SIGKILL); } void action_tlsdate_status (evutil_socket_t fd, short what, void *arg) { struct state *state = arg; time_t t = 0; int ret = read_tlsdate_response (fd, &t); verb_debug ("[event:%s] fired", __func__); if (ret < 0) { verb_debug ("[event:%s] forcibly timing out tlsdate", __func__); trigger_event (state, E_TLSDATE_TIMEOUT, 0); return; } if (ret) { /* EAGAIN'd: wait for the rest. */ trigger_event (state, E_TLSDATE_STATUS, -1); return; } if (is_sane_time (t)) { /* Note that last_time is from an online source */ state->last_sync_type = SYNC_TYPE_NET; state->last_time = t; trigger_event (state, E_SAVE, -1); } else { error ("[event:%s] invalid time received from tlsdate: %ld", __func__, t); } /* Restore the backoff and tries count on success, insane or not. * On failure, the event handler does it. */ state->tries = 0; state->backoff = state->opts.wait_between_tries; return; } /* Returns 0 on success and populates |fds| */ int new_tlsdate_monitor_pipe (int fds[2]) { if (pipe (fds) < 0) { perror ("pipe failed"); return -1; } /* TODO(wad): CLOEXEC, Don't leak these into tlsdate proper. */ return 0; } /* Create a fd pair that the tlsdate runner will communicate over */ int setup_tlsdate_status (struct state *state) { int fds[2] = { -1, -1 }; /* One pair of pipes are reused along with the event. */ if (new_tlsdate_monitor_pipe (fds)) { return -1; } verb_debug ("[%s] monitor fd pair (%d, %d)", __func__, fds[0], fds[1]); /* The fd that the monitor process will write to */ state->tlsdate_monitor_fd = fds[1]; /* Make the reader fd non-blocking and not leak into tlsdate. */ if (fcntl (fds[0], F_SETFL, O_NONBLOCK|O_CLOEXEC) < 0) { perror ("pipe[0] fcntl(O_NONBLOCK) failed"); return 1; } state->events[E_TLSDATE_STATUS] = event_new (state->base, fds[0], EV_READ, action_tlsdate_status, state); if (!state->events[E_TLSDATE_STATUS]) { error ("Failed to allocate tlsdate status event"); return 1; } event_priority_set (state->events[E_TLSDATE_STATUS], PRI_NET); state->events[E_TLSDATE_TIMEOUT] = event_new (state->base, -1, EV_TIMEOUT, action_tlsdate_timeout, state); if (!state->events[E_TLSDATE_TIMEOUT]) { error ("Failed to allocate tlsdate timeout event"); return 1; } event_priority_set (state->events[E_TLSDATE_TIMEOUT], PRI_SAVE); return 0; }