Home | History | Annotate | Download | only in src
      1 /*
      2  * platform-cros.c - CrOS platform DBus integration
      3  * Copyright (c) 2013 The Chromium OS 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 #include "config.h"
      8 
      9 #include <ctype.h>
     10 #include <dbus/dbus.h>
     11 #include <errno.h>
     12 #include <signal.h>
     13 #include <stdbool.h>
     14 #include <stdint.h>
     15 #include <string.h>
     16 #include <time.h>
     17 
     18 #include <event2/event.h>
     19 
     20 #include "src/dbus.h"
     21 #include "src/platform.h"
     22 #include "src/tlsdate.h"
     23 #include "src/util.h"
     24 
     25 static const char kMatchFormatData[] = "interface='%s',member='%s',arg0='%s'";
     26 static const char *kMatchFormat = kMatchFormatData;
     27 static const char kMatchNoArgFormatData[] = "interface='%s',member='%s'";
     28 static const char *kMatchNoArgFormat = kMatchNoArgFormatData;
     29 
     30 static const char kLibCrosDestData[] = "org.chromium.LibCrosService";
     31 static const char *kLibCrosDest = kLibCrosDestData;
     32 static const char kLibCrosInterfaceData[] = "org.chromium.LibCrosServiceInterface";
     33 static const char *kLibCrosInterface = kLibCrosInterfaceData;
     34 static const char kLibCrosPathData[] = "/org/chromium/LibCrosService";
     35 static const char *kLibCrosPath = kLibCrosPathData;
     36 static const char kResolveNetworkProxyData[] = "ResolveNetworkProxy";
     37 static const char *kResolveNetworkProxy = kResolveNetworkProxyData;
     38 
     39 static const char kDBusInterfaceData[] = "org.freedesktop.DBus";
     40 static const char *kDBusInterface = kDBusInterfaceData;
     41 static const char kNameOwnerChangedData[] = "NameOwnerChanged";
     42 static const char *kNameOwnerChanged = kNameOwnerChangedData;
     43 static const char kNameAcquiredData[] = "NameAcquired";
     44 static const char *kNameAcquired = kNameAcquiredData;
     45 
     46 static const char kManagerInterfaceData[] = "org.chromium.flimflam.Manager";
     47 static const char *kManagerInterface = kManagerInterfaceData;
     48 
     49 static const char kServiceInterfaceData[] = "org.chromium.flimflam.Service";
     50 static const char *kServiceInterface = kServiceInterfaceData;
     51 static const char kMemberData[] = "PropertyChanged";
     52 static const char *kMember = kMemberData;
     53 
     54 static const char kProxyConfigData[] = "ProxyConfig";
     55 static const char *kProxyConfig = kProxyConfigData;
     56 static const char kDefaultServiceData[] = "DefaultService";
     57 static const char *kDefaultService = kDefaultServiceData;
     58 
     59 static const char kResolveInterfaceData[] = "org.torproject.tlsdate.Resolver";
     60 static const char *kResolveInterface = kResolveInterfaceData;
     61 static const char kResolveMemberData[] = "ProxyChange";
     62 static const char *kResolveMember = kResolveMemberData;
     63 
     64 /* TODO(wad) Integrate with cros_system_api/dbus/service_constants.h */
     65 static const char kPowerManagerInterfaceData[] = "org.chromium.PowerManager";
     66 static const char *kPowerManagerInterface = kPowerManagerInterfaceData;
     67 static const char kSuspendDoneData[] = "SuspendDone";
     68 static const char *kSuspendDone = kSuspendDoneData;
     69 
     70 static const char kErrorServiceUnknownData[] = "org.freedesktop.DBus.Error.ServiceUnknown";
     71 static const char *kErrorServiceUnknown = kErrorServiceUnknownData;
     72 
     73 struct platform_state
     74 {
     75   struct event_base *base;
     76   struct state *state;
     77   DBusMessage **resolve_msg;
     78   int resolve_msg_count;
     79   uint32_t resolve_network_proxy_serial;
     80 };
     81 
     82 static
     83 bool
     84 get_valid_hostport (const char *hostport, char *out, size_t len)
     85 {
     86   bool host = true;
     87   const char *end = hostport + strlen (hostport);
     88   const char *c;
     89   *out = '\0';
     90   /* Hosts begin with alphanumeric only. */
     91   if (!isalnum (*hostport))
     92     {
     93       info ("Host does not start with alnum");
     94       return false;
     95     }
     96   *out++ = *hostport;
     97   for (c = hostport + 1;  c < end && len > 0; ++c, ++out, --len)
     98     {
     99       *out = *c;
    100       if (host)
    101         {
    102           if (isalnum (*c) || *c == '-' || *c == '.')
    103             {
    104               continue;
    105             }
    106           if (*c == ':')
    107             {
    108               host = false;
    109               continue;
    110             }
    111         }
    112       else
    113         {
    114           if (isdigit (*c))
    115             continue;
    116         }
    117       *out = '\0';
    118       return false;
    119     }
    120   *out = '\0';
    121   return true;
    122 }
    123 
    124 /* Convert PAC return format to tlsdated url format */
    125 /* TODO(wad) support multiple proxies when Chromium does:
    126  * PROXY x.x.x.x:yyyy; PROXY z.z.z.z:aaaaa
    127  */
    128 static
    129 void
    130 canonicalize_pac (const char *pac_fmt, char *proxy_url, size_t len)
    131 {
    132   size_t type_len;
    133   int copied = 0;
    134   const char *space;
    135   /* host[255]:port[6]\0 */
    136   char hostport[6 + 255 + 2];
    137   proxy_url[0] = '\0';
    138   if (len < 1)
    139     return;
    140   if (!strcmp (pac_fmt, "DIRECT"))
    141     {
    142       return;
    143     }
    144   /* Find type */
    145   space = strchr (pac_fmt, ' ');
    146   if (!space)
    147     return;
    148   type_len = space - pac_fmt;
    149   if (!get_valid_hostport (space + 1, hostport, sizeof (hostport)))
    150     {
    151       error ("invalid host:port: %s", space + 1);
    152       return;
    153     }
    154   proxy_url[0] = '\0';
    155   if (!strncmp (pac_fmt, "PROXY", type_len))
    156     {
    157       copied = snprintf (proxy_url, len, "http://%s", hostport);
    158     }
    159   else if (!strncmp (pac_fmt, "SOCKS", type_len))
    160     {
    161       copied = snprintf (proxy_url, len, "socks4://%s", hostport);
    162     }
    163   else if (!strncmp (pac_fmt, "SOCKS5", type_len))
    164     {
    165       copied = snprintf (proxy_url, len, "socks5://%s", hostport);
    166     }
    167   else if (!strncmp (pac_fmt, "HTTPS", type_len))
    168     {
    169       copied = snprintf (proxy_url, len, "https://%s", hostport);
    170     }
    171   else
    172     {
    173       error ("pac_fmt unmatched: '%s' %zu", pac_fmt, type_len);
    174     }
    175   if (copied < 0 || ((size_t) copied) >= len)
    176     {
    177       error ("canonicalize_pac: truncation '%s'", proxy_url);
    178       proxy_url[0] = '\0';
    179       return;
    180     }
    181 }
    182 
    183 static
    184 DBusHandlerResult
    185 handle_service_change (DBusConnection *connection,
    186                        DBusMessage *message,
    187                        struct platform_state *ctx)
    188 {
    189   DBusMessageIter iter, subiter;
    190   DBusError error;
    191   const char *pname;
    192   const char *pval;
    193   const char *service;
    194   dbus_error_init (&error);
    195   verb_debug ("[event:cros:%s]: fired", __func__);
    196   /* TODO(wad) Track the current DefaultService only fire when it changes */
    197   service = dbus_message_get_path (message);
    198   if (!service)
    199     return DBUS_HANDLER_RESULT_HANDLED;
    200   /* Shill emits string:ProxyConfig variant string:"..." */
    201   if (!dbus_message_iter_init (message, &iter))
    202     return DBUS_HANDLER_RESULT_HANDLED;
    203   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
    204     return DBUS_HANDLER_RESULT_HANDLED;
    205   dbus_message_iter_get_basic (&iter, &pname);
    206   /* Make sure we are only firing on a ProxyConfig property change. */
    207   if (strcmp (pname, kProxyConfig))
    208     return DBUS_HANDLER_RESULT_HANDLED;
    209   if (!dbus_message_iter_next (&iter))
    210     return DBUS_HANDLER_RESULT_HANDLED;
    211   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
    212     return DBUS_HANDLER_RESULT_HANDLED;
    213   dbus_message_iter_recurse (&iter, &subiter);
    214   if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_STRING)
    215     return DBUS_HANDLER_RESULT_HANDLED;
    216   dbus_message_iter_get_basic (&subiter, &pval);
    217   /* Right now, nothing is done with the Shill proxy value because
    218    * Chromium handles .pac resolution.  This may be more useful for
    219    * ignoring incomplete proxy values sent while a user is typing.
    220    */
    221   action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
    222   return DBUS_HANDLER_RESULT_HANDLED;
    223 }
    224 
    225 static
    226 DBusHandlerResult
    227 handle_manager_change (DBusConnection *connection,
    228                        DBusMessage *message,
    229                        struct platform_state *ctx)
    230 {
    231   DBusMessageIter iter, subiter;
    232   DBusError error;
    233   const char *pname;
    234   const char *pval;
    235   verb_debug ("[event:cros:%s]: fired", __func__);
    236   dbus_error_init (&error);
    237   if (!dbus_message_iter_init (message, &iter))
    238     return DBUS_HANDLER_RESULT_HANDLED;
    239   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
    240     return DBUS_HANDLER_RESULT_HANDLED;
    241   dbus_message_iter_get_basic (&iter, &pname);
    242   /* Make sure we caught the right property. */
    243   if (strcmp (pname, kDefaultService))
    244     return DBUS_HANDLER_RESULT_HANDLED;
    245   if (!dbus_message_iter_next (&iter))
    246     return DBUS_HANDLER_RESULT_HANDLED;
    247   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
    248     return DBUS_HANDLER_RESULT_HANDLED;
    249   dbus_message_iter_recurse (&iter, &subiter);
    250   if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_OBJECT_PATH)
    251     return DBUS_HANDLER_RESULT_HANDLED;
    252   dbus_message_iter_get_basic (&subiter, &pval);
    253   /* TODO(wad) Filter on the currently active service in pval. */
    254   verb_debug ("[event:cros:%s] service change on path %s",
    255          __func__, pval);
    256   action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
    257   return DBUS_HANDLER_RESULT_HANDLED;
    258 }
    259 
    260 static
    261 DBusHandlerResult
    262 handle_suspend_done (DBusConnection *connection,
    263                      DBusMessage *message,
    264                      struct platform_state *ctx)
    265 {
    266   verb_debug ("[event:cros:%s]: fired", __func__);
    267   /* Coming back from resume, trigger a continuity and time
    268    * check just in case none of the other events happen.
    269    */
    270   action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
    271   return DBUS_HANDLER_RESULT_HANDLED;
    272 }
    273 
    274 static
    275 DBusHandlerResult
    276 handle_proxy_change (DBusConnection *connection,
    277                      DBusMessage *message,
    278                      struct platform_state *ctx)
    279 {
    280   DBusMessageIter iter;
    281   DBusError error;
    282   const char *pname;
    283   const char *pval;
    284   char time_host[MAX_PROXY_URL];
    285   int url_len = 0;
    286   struct source *src = ctx->state->opts.sources;
    287   verb_debug ("[event:cros:%s]: fired", __func__);
    288   if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
    289     src = ctx->state->opts.cur_source->next;
    290   if (!ctx->state->resolving)
    291     {
    292       info ("[event:cros:%s] Unexpected ResolveNetworkProxy signal seen",
    293             __func__);
    294       return DBUS_HANDLER_RESULT_HANDLED;
    295     }
    296   dbus_error_init (&error);
    297   /* Shill emits string:ProxyConfig variant string:"..." */
    298   if (!dbus_message_iter_init (message, &iter))
    299     return DBUS_HANDLER_RESULT_HANDLED;
    300   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
    301     return DBUS_HANDLER_RESULT_HANDLED;
    302   dbus_message_iter_get_basic (&iter, &pname);
    303   /* Make sure this was the resolution we asked for */
    304   url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
    305                       src->host, src->port);
    306   if (url_len < 0 || ((size_t) url_len) >= sizeof (time_host))
    307     {
    308       error ("[event:cros:%s]: current source url is too long",
    309              __func__);
    310     }
    311   if (strcmp (pname, time_host))
    312     {
    313       error ("[event:cros:%s]: resolved host mismatch: %s v %s",
    314              __func__, pname, time_host);
    315       return DBUS_HANDLER_RESULT_HANDLED;
    316     }
    317   if (!dbus_message_iter_next (&iter))
    318     return DBUS_HANDLER_RESULT_HANDLED;
    319   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
    320     return DBUS_HANDLER_RESULT_HANDLED;
    321   dbus_message_iter_get_basic (&iter, &pval);
    322   ctx->state->resolving = 0;
    323   canonicalize_pac (pval, ctx->state->dynamic_proxy, sizeof (ctx->state->dynamic_proxy));
    324   trigger_event (ctx->state, E_TLSDATE, 1);
    325   return DBUS_HANDLER_RESULT_HANDLED;
    326 }
    327 
    328 static
    329 DBusHandlerResult
    330 handle_dbus_change (DBusConnection *connection,
    331                     DBusMessage *message,
    332                     struct platform_state *ctx)
    333 {
    334   DBusMessageIter iter;
    335   DBusError error;
    336   const char *pname;
    337   verb_debug ("[event:cros:%s]: fired", __func__);
    338   dbus_error_init (&error);
    339   if (!dbus_message_iter_init (message, &iter))
    340     return DBUS_HANDLER_RESULT_HANDLED;
    341   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
    342     return DBUS_HANDLER_RESULT_HANDLED;
    343   dbus_message_iter_get_basic (&iter, &pname);
    344   /* Make sure we caught the right property. */
    345   if (strcmp (pname, kLibCrosDest))
    346     return DBUS_HANDLER_RESULT_HANDLED;
    347   action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
    348   return DBUS_HANDLER_RESULT_HANDLED;
    349 }
    350 
    351 static
    352 void
    353 action_resolve_proxy (evutil_socket_t fd, short what, void *arg)
    354 {
    355   struct platform_state *ctx = arg;
    356   struct dbus_state *dbus_state = ctx->state->dbus;
    357   DBusConnection *conn = dbus_state->conn;
    358   struct source *src = ctx->state->opts.sources;
    359   verb_debug ("[event:%s] fired", __func__);
    360   /* Emulate tlsdate-monitor.c:build_argv and choose the next source */
    361   if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
    362     src = ctx->state->opts.cur_source->next;
    363   if (ctx->state->resolving || ctx->resolve_network_proxy_serial)
    364     {
    365       /* Note, this is not the same as the response signal. It just avoids
    366        * multiple requests in a single dispatch window.
    367        */
    368       info ("[event:%s] no resolve_proxy sent; pending method_reply",
    369             __func__);
    370       return;
    371     }
    372   ctx->state->dynamic_proxy[0] = '\0';
    373   if (ctx->resolve_msg[src->id] == NULL)
    374     {
    375       info ("[event:%s] no dynamic proxy for %s:%s", __func__,
    376             src->host, src->port);
    377       trigger_event (ctx->state, E_TLSDATE, 1);
    378       return;
    379     }
    380   info ("[event:%s] resolving proxy for %s:%s", __func__,
    381         src->host, src->port);
    382   ctx->state->resolving = 1;
    383   if (!dbus_connection_send (conn,
    384                              ctx->resolve_msg[src->id],
    385                              &ctx->resolve_network_proxy_serial))
    386     {
    387       error ("[event:%s] cannot send ResolveNetworkProxy query!", __func__);
    388       return;
    389     }
    390 }
    391 
    392 static
    393 DBusHandlerResult
    394 dbus_filter (DBusConnection *connection, DBusMessage *message, void *data)
    395 {
    396   struct platform_state *state = data;
    397   /* Terminate gracefully if DBus goes away. */
    398   if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
    399     {
    400       error ("[cros] DBus system bus has become inaccessible. Terminating.");
    401       /* Trigger a graceful teardown. */
    402       kill (getpid(), SIGINT);
    403       return DBUS_HANDLER_RESULT_HANDLED;
    404     }
    405   /* Hand it over to the service dispatcher. */
    406   if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
    407     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    408 
    409   /* Handle explicitly defined signals only. */
    410   if (dbus_message_is_signal (message, kDBusInterface, kNameAcquired))
    411     {
    412       info ("[cros] DBus name acquired successfully");
    413       return DBUS_HANDLER_RESULT_HANDLED;
    414     }
    415   if (dbus_message_is_signal (message, kServiceInterface, kMember))
    416     return handle_service_change (connection, message, state);
    417   if (dbus_message_is_signal (message, kManagerInterface, kMember))
    418     return handle_manager_change (connection, message, state);
    419   if (dbus_message_is_signal (message, kResolveInterface, kResolveMember))
    420     return handle_proxy_change (connection, message, state);
    421   if (dbus_message_is_signal (message, kDBusInterface, kNameOwnerChanged))
    422     return handle_dbus_change (connection, message, state);
    423   if (dbus_message_is_signal (message, kPowerManagerInterface, kSuspendDone))
    424     return handle_suspend_done (connection, message, state);
    425   if (dbus_message_is_error (message, kErrorServiceUnknown))
    426     {
    427       info ("[cros] org.chromium.LibCrosService.ResolveNetworkProxy is missing");
    428       info ("[cros] skipping proxy resolution for now");
    429       /* Fire off tlsdate rather than letting it fail silently. */
    430       state->resolve_network_proxy_serial = 0;
    431       state->state->resolving = 0;
    432       trigger_event (state->state, E_TLSDATE, 1);
    433       return DBUS_HANDLER_RESULT_HANDLED;
    434     }
    435   /* Indicates a successful resolve request was issued. */
    436   if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
    437     {
    438       uint32_t serial = dbus_message_get_reply_serial (message);
    439       if (serial == state->resolve_network_proxy_serial)
    440         {
    441           state->resolve_network_proxy_serial = 0;
    442           return DBUS_HANDLER_RESULT_HANDLED;
    443         }
    444       info ("[cros] unknown DBus METHOD_RETURN seen: %u", serial);
    445       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    446     }
    447   verb_debug ("[cros] unknown message received: "
    448          "type=%s dest=%s interface=%s member=%s path=%s sig=%s error_name=%s",
    449          dbus_message_type_to_string (dbus_message_get_type (message)),
    450          dbus_message_get_destination (message),
    451          dbus_message_get_interface (message),
    452          dbus_message_get_member (message),
    453          dbus_message_get_path (message),
    454          dbus_message_get_signature (message),
    455          dbus_message_get_error_name (message));
    456   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    457 }
    458 
    459 int
    460 add_match (DBusConnection *conn, const char *interface, const char *member,
    461            const char *arg0)
    462 {
    463   char match[1024];
    464   DBusError error;
    465   int len;
    466   dbus_error_init (&error);
    467   if (arg0)
    468     {
    469       len = snprintf (match, sizeof (match), kMatchFormat,
    470                       interface, member, arg0);
    471     }
    472   else
    473     {
    474       len = snprintf (match, sizeof (match), kMatchNoArgFormat,
    475                       interface, member);
    476     }
    477   if (len < 0 || ((size_t) len) >= sizeof (match))
    478     {
    479       error ("[dbus] match truncated for '%s,%s'", interface, member);
    480       return 1;
    481     }
    482   dbus_bus_add_match (conn, match, &error);
    483   if (dbus_error_is_set (&error))
    484     {
    485       error ("[dbus] failed to add_match for '%s,%s'; error: %s, %s",
    486              interface, member, error.name, error.message);
    487       dbus_error_free (&error);
    488       return 1;
    489     }
    490   return 0;
    491 }
    492 
    493 DBusMessage *
    494 new_resolver_message(const struct source *src)
    495 {
    496   char time_host[MAX_PROXY_URL];
    497   void *time_host_ptr = &time_host;
    498   int url_len;
    499   DBusMessage *res;
    500   DBusMessageIter args;
    501   if (!src->proxy || strcmp (src->proxy, "dynamic"))
    502     {
    503       return NULL;
    504     }
    505   res = dbus_message_new_method_call (kLibCrosDest, kLibCrosPath,
    506                                       kLibCrosInterface, kResolveNetworkProxy);
    507   if (!res)
    508     {
    509       error ("[cros] could not setup dynamic proxy for source %d", src->id);
    510       return NULL;
    511     }
    512   /* Build the time_host */
    513   url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
    514                       src->host, src->port);
    515   if (url_len < 0 || ((size_t) url_len) >= sizeof (time_host))
    516     {
    517       fatal ("[cros] source %d url is too long! (%d)", src->id, url_len);
    518     }
    519   /* Finish the message */
    520   dbus_message_iter_init_append (res, &args);
    521   if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &time_host_ptr) ||
    522       !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveInterface) ||
    523       !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveMember))
    524     {
    525       fatal ("[cros could not append arguments for resolver message");
    526     }
    527   return res;
    528 }
    529 
    530 int
    531 platform_init_cros (struct state *state)
    532 {
    533   /* Watch for per-service ProxyConfig property changes */
    534   struct event_base *base = state->base;
    535   struct dbus_state *dbus_state = state->dbus;
    536   if (!dbus_state)
    537     {
    538       info ("[cros] DBus not connected, skipping platform initialization.");
    539       return 0;
    540     }
    541   struct source *src = NULL;
    542   int sources = 0;
    543   DBusConnection *conn = dbus_state->conn;
    544   DBusError error;
    545   struct platform_state *platform_state =
    546       calloc (1, sizeof (struct platform_state));
    547   if (!platform_state)
    548     {
    549       error ("[cros] could not allocate platform_state");
    550       return -1;
    551     }
    552   /* TODO(wad) Follow up with dbus_error_free() where needed. */
    553   dbus_error_init (&error);
    554   /* Add watches for: proxy changes, default service changes, proxy resolution,
    555    * LibCrosService ownership, and power state changes.
    556    */
    557   if (add_match (conn, kServiceInterface, kMember, kProxyConfig) ||
    558       add_match (conn, kManagerInterface, kMember, kDefaultService) ||
    559       add_match (conn, kResolveInterface, kResolveMember, NULL) ||
    560       add_match (conn, kDBusInterface, kNameOwnerChanged, kLibCrosDest) ||
    561       add_match (conn, kPowerManagerInterface, kSuspendDone, NULL))
    562     return 1;
    563 
    564   /* Allocate one per source */
    565   for (src = state->opts.sources; src; src = src->next, ++sources);
    566   platform_state->resolve_msg_count = sources;
    567   platform_state->resolve_msg = calloc (sources, sizeof (DBusMessage *));
    568   if (!platform_state->resolve_msg)
    569     {
    570       error ("[cros] cannot allocate resolver messages");
    571       free (platform_state);
    572       return -1;
    573     }
    574   for (src = state->opts.sources; src; src = src->next)
    575     {
    576       if (src->id >= sources)
    577         fatal ("Source ID is greater than available sources!");
    578       platform_state->resolve_msg[src->id] = new_resolver_message (src);
    579       if (platform_state->resolve_msg[src->id])
    580         src->proxy = state->dynamic_proxy;
    581     }
    582   state->dynamic_proxy[0] = '\0';
    583   if (state->opts.proxy && !strcmp (state->opts.proxy, "dynamic"))
    584     {
    585       info ("[cros] default dynamic proxy support");
    586       state->opts.proxy = state->dynamic_proxy;
    587     }
    588   platform_state->base = base;
    589   platform_state->state = state;
    590   /* Add the dynamic resolver if tlsdate doesn't already have one. */
    591   if (!state->events[E_RESOLVER])
    592     {
    593       state->events[E_RESOLVER] = event_new (base, -1, EV_TIMEOUT,
    594                                              action_resolve_proxy,
    595                                              platform_state);
    596       if (!state->events[E_RESOLVER])
    597         /* Let's not clean up DBus. */
    598         fatal ("Could not allocated resolver event");
    599       /* Wake up as a NET event since it'll self-block until DBus has a chance
    600        * to send it.
    601        */
    602       event_priority_set (state->events[E_RESOLVER], PRI_NET);
    603     }
    604   /* Each platform can attach their own filter, but the filter func needs to be
    605    * willing to DBUS_HANDLER_RESULT_NOT_YET_HANDLED on unexpected events.
    606    */
    607   /* TODO(wad) add the clean up function as the callback. */
    608   if (!dbus_connection_add_filter (conn,
    609                                    dbus_filter, platform_state, NULL))
    610     {
    611       error ("Failed to register signal handler callback");
    612       return 1;
    613     }
    614   return 0;
    615 }
    616