Home | History | Annotate | Download | only in events
      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
     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
     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
     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
     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
    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