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
get_valid_hostport(const char * hostport,char * out,size_t len)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
canonicalize_pac(const char * pac_fmt,char * proxy_url,size_t len)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
handle_service_change(DBusConnection * connection,DBusMessage * message,struct platform_state * ctx)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
handle_manager_change(DBusConnection * connection,DBusMessage * message,struct platform_state * ctx)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
handle_suspend_done(DBusConnection * connection,DBusMessage * message,struct platform_state * ctx)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
handle_proxy_change(DBusConnection * connection,DBusMessage * message,struct platform_state * ctx)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
handle_dbus_change(DBusConnection * connection,DBusMessage * message,struct platform_state * ctx)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
action_resolve_proxy(evutil_socket_t fd,short what,void * arg)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
dbus_filter(DBusConnection * connection,DBusMessage * message,void * data)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
add_match(DBusConnection * conn,const char * interface,const char * member,const char * arg0)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 *
new_resolver_message(const struct source * src)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
platform_init_cros(struct state * state)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