vpn: Resolve vpn hostname if necessary
[platform/upstream/connman.git] / plugins / vpn.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <stdlib.h>
30 #include <glib.h>
31
32 #include <gdbus.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/technology.h>
36 #include <connman/plugin.h>
37 #include <connman/log.h>
38 #include <connman/dbus.h>
39 #include <connman/provider.h>
40 #include <connman/ipaddress.h>
41 #include <connman/vpn-dbus.h>
42 #include <connman/inet.h>
43 #include <gweb/gresolv.h>
44
45 #define DBUS_TIMEOUT 10000
46
47 static DBusConnection *connection;
48
49 static GHashTable *vpn_connections = NULL;
50 static gboolean starting_vpnd = TRUE;
51 static guint watch;
52 static guint added_watch;
53 static guint removed_watch;
54 static guint property_watch;
55
56 struct vpn_route {
57         int family;
58         char *network;
59         char *netmask;
60         char *gateway;
61 };
62
63 struct connection_data {
64         char *path;
65         struct connman_provider *provider;
66         int index;
67         DBusPendingCall *call;
68
69         char *state;
70         char *type;
71         char *name;
72         char *host;
73         char **host_ip;
74         char *domain;
75         char **nameservers;
76
77         GHashTable *server_routes;
78         GHashTable *user_routes;
79         GHashTable *setting_strings;
80
81         struct connman_ipaddress *ip;
82
83         GResolv *resolv;
84         guint resolv_id;
85 };
86
87 static int set_string(struct connman_provider *provider,
88                                         const char *key, const char *value)
89 {
90         struct connection_data *data;
91
92         data = connman_provider_get_data(provider);
93         if (data == NULL)
94                 return -EINVAL;
95
96         DBG("data %p provider %p key %s value %s", data, provider, key, value);
97
98         if (g_str_equal(key, "Type") == TRUE) {
99                 g_free(data->type);
100                 data->type = g_strdup(value);
101         } else if (g_str_equal(key, "Name") == TRUE) {
102                 g_free(data->name);
103                 data->name = g_strdup(value);
104         } else if (g_str_equal(key, "Host") == TRUE) {
105                 g_free(data->host);
106                 data->host = g_strdup(value);
107         } else if (g_str_equal(key, "VPN.Domain") == TRUE ||
108                                 g_str_equal(key, "Domain") == TRUE) {
109                 g_free(data->domain);
110                 data->domain = g_strdup(value);
111         } else
112                 g_hash_table_replace(data->setting_strings,
113                                 g_strdup(key), g_strdup(value));
114         return 0;
115 }
116
117 static const char *get_string(struct connman_provider *provider,
118                                                         const char *key)
119 {
120         struct connection_data *data;
121
122         data = connman_provider_get_data(provider);
123         if (data == NULL)
124                 return NULL;
125
126         DBG("data %p provider %p key %s", data, provider, key);
127
128         if (g_str_equal(key, "Type") == TRUE)
129                 return data->type;
130         else if (g_str_equal(key, "Name") == TRUE)
131                 return data->name;
132         else if (g_str_equal(key, "Host") == TRUE)
133                 return data->host;
134         else if (g_str_equal(key, "HostIP") == TRUE) {
135                 if (data->host_ip == NULL ||
136                                 data->host_ip[0] == NULL)
137                         return data->host;
138                 else
139                         return data->host_ip[0];
140         } else if (g_str_equal(key, "VPN.Domain") == TRUE)
141                 return data->domain;
142
143         return g_hash_table_lookup(data->setting_strings, key);
144 }
145
146 static char *get_ident(const char *path)
147 {
148         char *pos;
149
150         if (*path != '/')
151                 return NULL;
152
153         pos = strrchr(path, '/');
154         if (pos == NULL)
155                 return NULL;
156
157         return pos + 1;
158 }
159
160 static void cancel_host_resolv(struct connection_data *data)
161 {
162         if (data->resolv_id != 0)
163                 g_resolv_cancel_lookup(data->resolv, data->resolv_id);
164
165         data->resolv_id = 0;
166
167         g_resolv_unref(data->resolv);
168         data->resolv = NULL;
169 }
170
171 static gboolean remove_resolv(gpointer user_data)
172 {
173         struct connection_data *data = user_data;
174
175         cancel_host_resolv(data);
176
177         return FALSE;
178 }
179
180 static void resolv_result(GResolvResultStatus status,
181                                         char **results, gpointer user_data)
182 {
183         struct connection_data *data = user_data;
184
185         DBG("status %d", status);
186
187         if (status == G_RESOLV_RESULT_STATUS_SUCCESS && results != NULL &&
188                                                 g_strv_length(results) > 0)
189                 data->host_ip = g_strdupv(results);
190
191         /*
192          * We cannot unref the resolver here as resolv struct is manipulated
193          * by gresolv.c after we return from this callback.
194          */
195         g_timeout_add_seconds(0, remove_resolv, data);
196
197         data->resolv_id = 0;
198 }
199
200 static void resolv_host_addr(struct connection_data *data)
201 {
202         if (data->host == NULL)
203                 return;
204
205         if (connman_inet_check_ipaddress(data->host) > 0)
206                 return;
207
208         if (data->host_ip != NULL)
209                 return;
210
211         data->resolv = g_resolv_new(0);
212         if (data->resolv == NULL) {
213                 DBG("Cannot resolv %s", data->host);
214                 return;
215         }
216
217         DBG("Trying to resolv %s", data->host);
218
219         data->resolv_id = g_resolv_lookup_hostname(data->resolv, data->host,
220                                                 resolv_result, data);
221 }
222
223 static void set_provider_state(struct connection_data *data)
224 {
225         if (g_str_equal(data->state, "ready") == TRUE)
226                 connman_provider_set_state(data->provider,
227                                         CONNMAN_PROVIDER_STATE_READY);
228         else if (g_str_equal(data->state, "configuration") == TRUE)
229                 connman_provider_set_state(data->provider,
230                                         CONNMAN_PROVIDER_STATE_CONNECT);
231         else if (g_str_equal(data->state, "idle") == TRUE)
232                 connman_provider_set_state(data->provider,
233                                         CONNMAN_PROVIDER_STATE_IDLE);
234         else if (g_str_equal(data->state, "disconnect") == TRUE)
235                 connman_provider_set_state(data->provider,
236                                         CONNMAN_PROVIDER_STATE_DISCONNECT);
237         else if (g_str_equal(data->state, "failure") == TRUE)
238                 connman_provider_set_state(data->provider,
239                                         CONNMAN_PROVIDER_STATE_FAILURE);
240         else
241                 connman_provider_set_state(data->provider,
242                                         CONNMAN_PROVIDER_STATE_UNKNOWN);
243 }
244
245 static int create_provider(struct connection_data *data, void *user_data)
246 {
247         struct connman_provider_driver *driver = user_data;
248         char *ident;
249         int err = 0;
250
251         DBG("%s", data->path);
252
253         ident = g_strdup(get_ident(data->path));
254
255         data->provider = connman_provider_get(ident);
256         if (data->provider == NULL) {
257                 err = -ENOMEM;
258                 goto out;
259         }
260
261         DBG("provider %p name %s", data->provider, data->name);
262
263         connman_provider_set_data(data->provider, data);
264         connman_provider_set_driver(data->provider, driver);
265
266         err = connman_provider_create_service(data->provider);
267         if (err == 0) {
268                 if (g_str_equal(data->state, "ready") == TRUE) {
269                         connman_provider_set_index(data->provider,
270                                                         data->index);
271                         if (data->ip != NULL)
272                                 connman_provider_set_ipaddress(data->provider,
273                                                                 data->ip);
274                 }
275
276                 set_provider_state(data);
277         }
278
279 out:
280         g_free(ident);
281         return err;
282 }
283
284 static void destroy_route(gpointer user_data)
285 {
286         struct vpn_route *route = user_data;
287
288         g_free(route->network);
289         g_free(route->netmask);
290         g_free(route->gateway);
291         g_free(route);
292 }
293
294 static struct connection_data *create_connection_data(const char *path)
295 {
296         struct connection_data *data;
297
298         data = g_try_new0(struct connection_data, 1);
299         if (data == NULL)
300                 return NULL;
301
302         DBG("path %s", path);
303
304         data->path = g_strdup(path);
305         data->index = -1;
306
307         data->setting_strings = g_hash_table_new_full(g_str_hash,
308                                                 g_str_equal, g_free, g_free);
309
310         data->server_routes = g_hash_table_new_full(g_direct_hash,
311                                         g_str_equal, g_free, destroy_route);
312         data->user_routes = g_hash_table_new_full(g_str_hash,
313                                         g_str_equal, g_free, destroy_route);
314
315         return data;
316 }
317
318 static int extract_ip(DBusMessageIter *array, int family,
319                                                 struct connection_data *data)
320 {
321         DBusMessageIter dict;
322         char *address = NULL, *gateway = NULL, *netmask = NULL, *peer = NULL;
323         unsigned char prefix_len;
324
325         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
326                 return -EINVAL;
327
328         dbus_message_iter_recurse(array, &dict);
329
330         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
331                 DBusMessageIter entry, value;
332                 const char *key;
333
334                 dbus_message_iter_recurse(&dict, &entry);
335                 dbus_message_iter_get_basic(&entry, &key);
336
337                 dbus_message_iter_next(&entry);
338                 dbus_message_iter_recurse(&entry, &value);
339
340                 if (g_str_equal(key, "Address") == TRUE) {
341                         dbus_message_iter_get_basic(&value, &address);
342                         DBG("address %s", address);
343                 } else if (g_str_equal(key, "Netmask") == TRUE) {
344                         dbus_message_iter_get_basic(&value, &netmask);
345                         DBG("netmask %s", netmask);
346                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
347                         dbus_message_iter_get_basic(&value, &netmask);
348                         DBG("prefix length %s", netmask);
349                 } else if (g_str_equal(key, "Peer") == TRUE) {
350                         dbus_message_iter_get_basic(&value, &peer);
351                         DBG("peer %s", peer);
352                 } else if (g_str_equal(key, "Gateway") == TRUE) {
353                         dbus_message_iter_get_basic(&value, &gateway);
354                         DBG("gateway %s", gateway);
355                 }
356
357                 dbus_message_iter_next(&dict);
358         }
359
360         data->ip = connman_ipaddress_alloc(family);
361         if (data->ip == NULL)
362                 return -ENOMEM;
363
364         switch (family) {
365         case AF_INET:
366                 connman_ipaddress_set_ipv4(data->ip, address, netmask,
367                                                                 gateway);
368                 break;
369         case AF_INET6:
370                 prefix_len = atoi(netmask);
371                 connman_ipaddress_set_ipv6(data->ip, address, prefix_len,
372                                                                 gateway);
373                 break;
374         default:
375                 return -EINVAL;
376         }
377
378         connman_ipaddress_set_peer(data->ip, peer);
379
380         return 0;
381 }
382
383 static int extract_nameservers(DBusMessageIter *array,
384                                                 struct connection_data *data)
385 {
386         DBusMessageIter entry;
387         char **nameservers = NULL;
388         int i = 0;
389
390         dbus_message_iter_recurse(array, &entry);
391
392         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
393                 const char *nameserver;
394
395                 dbus_message_iter_get_basic(&entry, &nameserver);
396
397                 nameservers = g_try_renew(char *, nameservers, i + 2);
398                 if (nameservers == NULL)
399                         return -ENOMEM;
400
401                 DBG("[%d] %s", i, nameserver);
402
403                 nameservers[i] = g_strdup(nameserver);
404                 if (nameservers[i] == NULL)
405                         return -ENOMEM;
406
407                 nameservers[++i] = NULL;
408
409                 dbus_message_iter_next(&entry);
410         }
411
412         g_strfreev(data->nameservers);
413         data->nameservers = nameservers;
414
415         return 0;
416 }
417
418 static void connect_reply(DBusPendingCall *call, void *user_data)
419 {
420         DBusMessage *reply;
421         DBusError error;
422
423         if (dbus_pending_call_get_completed(call) == FALSE)
424                 return;
425
426         DBG("user_data %p", user_data);
427
428         reply = dbus_pending_call_steal_reply(call);
429
430         dbus_error_init(&error);
431
432         if (dbus_set_error_from_message(&error, reply) == TRUE) {
433                 if (dbus_error_has_name(&error, CONNMAN_ERROR_INTERFACE
434                                                 ".InProgress") == FALSE) {
435                         connman_error("Connect reply: %s (%s)", error.message,
436                                                                 error.name);
437                         dbus_error_free(&error);
438                         goto done;
439                 }
440                 dbus_error_free(&error);
441         }
442
443         /*
444          * The vpn connection is up when we get a "ready" state
445          * property so at this point we do nothing for the provider
446          * state.
447          */
448
449 done:
450         dbus_message_unref(reply);
451
452         dbus_pending_call_unref(call);
453 }
454
455 static int connect_provider(struct connection_data *data, void *user_data)
456 {
457         DBusPendingCall *call;
458         DBusMessage *message;
459
460         DBG("data %p", data);
461
462         message = dbus_message_new_method_call(VPN_SERVICE, data->path,
463                                         VPN_CONNECTION_INTERFACE,
464                                         VPN_CONNECT);
465         if (message == NULL)
466                 return -ENOMEM;
467
468         if (dbus_connection_send_with_reply(connection, message,
469                                         &call, DBUS_TIMEOUT) == FALSE) {
470                 connman_error("Unable to call %s.%s()",
471                         VPN_CONNECTION_INTERFACE, VPN_CONNECT);
472                 dbus_message_unref(message);
473                 return -EINVAL;
474         }
475
476         if (call == NULL) {
477                 dbus_message_unref(message);
478                 return -EINVAL;
479         }
480
481         dbus_pending_call_set_notify(call, connect_reply, NULL, NULL);
482
483         dbus_message_unref(message);
484
485         return -EINPROGRESS;
486 }
487
488 static void add_connection(const char *path, DBusMessageIter *properties,
489                         void *user_data)
490 {
491         struct connection_data *data;
492         int err;
493
494         data = g_hash_table_lookup(vpn_connections, path);
495         if (data != NULL)
496                 return;
497
498         data = create_connection_data(path);
499         if (data == NULL)
500                 return;
501
502         DBG("data %p path %s", data, path);
503
504         while (dbus_message_iter_get_arg_type(properties) ==
505                         DBUS_TYPE_DICT_ENTRY) {
506                 DBusMessageIter entry, value;
507                 const char *key;
508                 char *str;
509
510                 dbus_message_iter_recurse(properties, &entry);
511                 dbus_message_iter_get_basic(&entry, &key);
512
513                 dbus_message_iter_next(&entry);
514                 dbus_message_iter_recurse(&entry, &value);
515
516                 if (g_str_equal(key, "State") == TRUE) {
517                         dbus_message_iter_get_basic(&value, &str);
518                         DBG("state %s -> %s", data->state, str);
519                         data->state = g_strdup(str);
520                 } else if (g_str_equal(key, "IPv4") == TRUE) {
521                         extract_ip(&value, AF_INET, data);
522                 } else if (g_str_equal(key, "IPv6") == TRUE) {
523                         extract_ip(&value, AF_INET6, data);
524                 } else if (g_str_equal(key, "Name") == TRUE) {
525                         dbus_message_iter_get_basic(&value, &str);
526                         data->name = g_strdup(str);
527                 } else if (g_str_equal(key, "Type") == TRUE) {
528                         dbus_message_iter_get_basic(&value, &str);
529                         data->type = g_strdup(str);
530                 } else if (g_str_equal(key, "Host") == TRUE) {
531                         dbus_message_iter_get_basic(&value, &str);
532                         data->host = g_strdup(str);
533                 } else if (g_str_equal(key, "Domain") == TRUE) {
534                         dbus_message_iter_get_basic(&value, &str);
535                         data->domain = g_strdup(str);
536                 } else if (g_str_equal(key, "Nameservers") == TRUE) {
537                         extract_nameservers(&value, data);
538                 } else if (g_str_equal(key, "Index") == TRUE) {
539                         dbus_message_iter_get_basic(&value, &data->index);
540                 } else {
541                         if (dbus_message_iter_get_arg_type(&value) ==
542                                                         DBUS_TYPE_STRING) {
543                                 dbus_message_iter_get_basic(&value, &str);
544                                 g_hash_table_replace(data->setting_strings,
545                                                 g_strdup(key), g_strdup(str));
546                         } else {
547                                 DBG("unknown key %s", key);
548                         }
549                 }
550
551                 dbus_message_iter_next(properties);
552         }
553
554         g_hash_table_insert(vpn_connections, g_strdup(path), data);
555
556         err = create_provider(data, user_data);
557         if (err < 0)
558                 goto out;
559
560         resolv_host_addr(data);
561
562         return;
563
564 out:
565         DBG("removing %s", path);
566         g_hash_table_remove(vpn_connections, path);
567 }
568
569 static void get_connections_reply(DBusPendingCall *call, void *user_data)
570 {
571         DBusMessage *reply;
572         DBusError error;
573         DBusMessageIter array, dict;
574         const char *signature = DBUS_TYPE_ARRAY_AS_STRING
575                 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
576                 DBUS_TYPE_OBJECT_PATH_AS_STRING
577                 DBUS_TYPE_ARRAY_AS_STRING
578                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
579                 DBUS_TYPE_STRING_AS_STRING
580                 DBUS_TYPE_VARIANT_AS_STRING
581                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
582                 DBUS_STRUCT_END_CHAR_AS_STRING;
583
584         DBG("");
585
586         reply = dbus_pending_call_steal_reply(call);
587
588         if (dbus_message_has_signature(reply, signature) == FALSE) {
589                 connman_error("vpnd signature \"%s\" does not match "
590                                                         "expected \"%s\"",
591                         dbus_message_get_signature(reply), signature);
592                 goto done;
593         }
594
595         dbus_error_init(&error);
596
597         if (dbus_set_error_from_message(&error, reply) == TRUE) {
598                 connman_error("%s", error.message);
599                 dbus_error_free(&error);
600                 goto done;
601         }
602
603         if (dbus_message_iter_init(reply, &array) == FALSE)
604                 goto done;
605
606         dbus_message_iter_recurse(&array, &dict);
607
608         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
609                 DBusMessageIter value, properties;
610                 const char *path;
611
612                 dbus_message_iter_recurse(&dict, &value);
613                 dbus_message_iter_get_basic(&value, &path);
614
615                 dbus_message_iter_next(&value);
616                 dbus_message_iter_recurse(&value, &properties);
617
618                 add_connection(path, &properties, user_data);
619
620                 dbus_message_iter_next(&dict);
621         }
622
623 done:
624         dbus_message_unref(reply);
625
626         dbus_pending_call_unref(call);
627 }
628
629 static int get_connections(void *user_data)
630 {
631         DBusPendingCall *call;
632         DBusMessage *message;
633
634         DBG("");
635
636         message = dbus_message_new_method_call(VPN_SERVICE, "/",
637                                         VPN_MANAGER_INTERFACE,
638                                         GET_CONNECTIONS);
639         if (message == NULL)
640                 return -ENOMEM;
641
642         if (dbus_connection_send_with_reply(connection, message,
643                                         &call, DBUS_TIMEOUT) == FALSE) {
644                 connman_error("Unable to call %s.%s()", VPN_MANAGER_INTERFACE,
645                                                         GET_CONNECTIONS);
646                 dbus_message_unref(message);
647                 return -EINVAL;
648         }
649
650         if (call == NULL) {
651                 dbus_message_unref(message);
652                 return -EINVAL;
653         }
654
655         dbus_pending_call_set_notify(call, get_connections_reply,
656                                                         user_data, NULL);
657
658         dbus_message_unref(message);
659
660         return -EINPROGRESS;
661 }
662
663 static int provider_probe(struct connman_provider *provider)
664 {
665         return 0;
666 }
667
668 static void remove_connection_reply(DBusPendingCall *call, void *user_data)
669 {
670         DBusMessage *reply;
671         DBusError error;
672
673         DBG("");
674
675         reply = dbus_pending_call_steal_reply(call);
676
677         dbus_error_init(&error);
678
679         if (dbus_set_error_from_message(&error, reply) == TRUE) {
680                 /*
681                  * If the returned error is NotFound, it means that we
682                  * have actually removed the provider in vpnd already.
683                  */
684                 if (dbus_error_has_name(&error, CONNMAN_ERROR_INTERFACE
685                                                 ".NotFound") == FALSE)
686                         connman_error("%s", error.message);
687
688                 dbus_error_free(&error);
689         }
690
691         dbus_message_unref(reply);
692
693         dbus_pending_call_unref(call);
694 }
695
696 static int provider_remove(struct connman_provider *provider)
697 {
698         DBusPendingCall *call;
699         DBusMessage *message;
700         struct connection_data *data;
701
702         data = connman_provider_get_data(provider);
703
704         DBG("provider %p data %p", provider, data);
705
706         /*
707          * When provider.c:provider_remove() calls this function,
708          * it will remove the provider itself after the call.
709          * This means that we cannot use the provider pointer later
710          * as it is no longer valid.
711          */
712         data->provider = NULL;
713
714         message = dbus_message_new_method_call(VPN_SERVICE, "/",
715                                         VPN_MANAGER_INTERFACE,
716                                         VPN_REMOVE);
717         if (message == NULL)
718                 return -ENOMEM;
719
720         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &data->path,
721                                 NULL);
722
723         if (dbus_connection_send_with_reply(connection, message,
724                                         &call, DBUS_TIMEOUT) == FALSE) {
725                 connman_error("Unable to call %s.%s()", VPN_MANAGER_INTERFACE,
726                                                         VPN_REMOVE);
727                 dbus_message_unref(message);
728                 return -EINVAL;
729         }
730
731         if (call == NULL) {
732                 dbus_message_unref(message);
733                 return -EINVAL;
734         }
735
736         dbus_pending_call_set_notify(call, remove_connection_reply,
737                                                         NULL, NULL);
738
739         dbus_message_unref(message);
740
741         return 0;
742 }
743
744 static int provider_connect(struct connman_provider *provider)
745 {
746         struct connection_data *data;
747
748         data = connman_provider_get_data(provider);
749         if (data == NULL)
750                 return -EINVAL;
751
752         return connect_provider(data, NULL);
753
754 }
755
756 static void disconnect_reply(DBusPendingCall *call, void *user_data)
757 {
758         DBusMessage *reply;
759         DBusError error;
760
761         DBG("");
762
763         reply = dbus_pending_call_steal_reply(call);
764
765         dbus_error_init(&error);
766
767         if (dbus_set_error_from_message(&error, reply) == TRUE) {
768                 connman_error("%s", error.message);
769                 dbus_error_free(&error);
770                 goto done;
771         }
772
773 done:
774         dbus_message_unref(reply);
775
776         dbus_pending_call_unref(call);
777 }
778
779 static int disconnect_provider(struct connection_data *data)
780 {
781         DBusPendingCall *call;
782         DBusMessage *message;
783
784         DBG("data %p path %s", data, data->path);
785
786         message = dbus_message_new_method_call(VPN_SERVICE, data->path,
787                                         VPN_CONNECTION_INTERFACE,
788                                         VPN_DISCONNECT);
789         if (message == NULL)
790                 return -ENOMEM;
791
792         if (dbus_connection_send_with_reply(connection, message,
793                                         &call, DBUS_TIMEOUT) == FALSE) {
794                 connman_error("Unable to call %s.%s()",
795                         VPN_CONNECTION_INTERFACE, VPN_DISCONNECT);
796                 dbus_message_unref(message);
797                 return -EINVAL;
798         }
799
800         if (call == NULL) {
801                 dbus_message_unref(message);
802                 return -EINVAL;
803         }
804
805         dbus_pending_call_set_notify(call, disconnect_reply, NULL, NULL);
806
807         dbus_message_unref(message);
808
809         connman_provider_set_state(data->provider,
810                                         CONNMAN_PROVIDER_STATE_DISCONNECT);
811         /*
812          * We return 0 here instead of -EINPROGRESS because
813          * __connman_service_disconnect() needs to return something
814          * to gdbus so that gdbus will not call Disconnect() more
815          * than once. This way we do not need to pass the dbus reply
816          * message around the code.
817          */
818         return 0;
819 }
820
821 static int provider_disconnect(struct connman_provider *provider)
822 {
823         struct connection_data *data;
824
825         DBG("provider %p", provider);
826
827         data = connman_provider_get_data(provider);
828         if (data == NULL)
829                 return -EINVAL;
830
831         if (g_str_equal(data->state, "ready") == TRUE ||
832                         g_str_equal(data->state, "configuration") == TRUE)
833                 return disconnect_provider(data);
834
835         return 0;
836 }
837
838 static void configuration_create_reply(DBusPendingCall *call, void *user_data)
839 {
840         DBusMessage *reply;
841         DBusError error;
842         DBusMessageIter iter;
843         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
844         const char *path;
845
846         DBG("user %p", user_data);
847
848         reply = dbus_pending_call_steal_reply(call);
849
850         if (dbus_message_has_signature(reply, signature) == FALSE) {
851                 connman_error("vpn configuration signature \"%s\" does not "
852                                                 "match expected \"%s\"",
853                         dbus_message_get_signature(reply), signature);
854                 goto done;
855         }
856
857         dbus_error_init(&error);
858
859         if (dbus_set_error_from_message(&error, reply) == TRUE) {
860                 connman_error("dbus error: %s", error.message);
861                 dbus_error_free(&error);
862                 goto done;
863         }
864
865         if (dbus_message_iter_init(reply, &iter) == FALSE)
866                 goto done;
867
868         dbus_message_iter_get_basic(&iter, &path);
869
870         /*
871          * Then try to connect the VPN as expected by ConnectProvider API
872          */
873         // XXX:
874
875 done:
876         dbus_message_unref(reply);
877
878         dbus_pending_call_unref(call);
879 }
880
881 static void set_dbus_ident(char *ident)
882 {
883         int i, len = strlen(ident);
884
885         for (i = 0; i < len; i++) {
886                 if (ident[i] >= '0' && ident[i] <= '9')
887                         continue;
888                 if (ident[i] >= 'a' && ident[i] <= 'z')
889                         continue;
890                 if (ident[i] >= 'A' && ident[i] <= 'Z')
891                         continue;
892                 ident[i] = '_';
893         }
894 }
895
896 static struct vpn_route *parse_user_route(const char *user_route)
897 {
898         char *network, *netmask;
899         struct vpn_route *route = NULL;
900         int family = PF_UNSPEC;
901         char **elems = g_strsplit(user_route, "/", 0);
902
903         if (elems == NULL)
904                 return NULL;
905
906         network = elems[0];
907         if (network == NULL || *network == '\0') {
908                 DBG("no network/netmask set");
909                 goto out;
910         }
911
912         netmask = elems[1];
913         if (netmask != NULL && *netmask == '\0') {
914                 DBG("no netmask set");
915                 goto out;
916         }
917
918         if (g_strrstr(network, ":") != NULL)
919                 family = AF_INET6;
920         else if (g_strrstr(network, ".") != NULL) {
921                 family = AF_INET;
922
923                 if (g_strrstr(netmask, ".") == NULL) {
924                         /* We have netmask length */
925                         in_addr_t addr;
926                         struct in_addr netmask_in;
927                         unsigned char prefix_len = 32;
928
929                         if (netmask != NULL) {
930                                 char *ptr;
931                                 long int value = strtol(netmask, &ptr, 10);
932                                 if (ptr != netmask && *ptr == '\0' &&
933                                                                 value <= 32)
934                                         prefix_len = value;
935                         }
936
937                         addr = 0xffffffff << (32 - prefix_len);
938                         netmask_in.s_addr = htonl(addr);
939                         netmask = inet_ntoa(netmask_in);
940
941                         DBG("network %s netmask %s", network, netmask);
942                 }
943         }
944
945         route = g_try_new(struct vpn_route, 1);
946         if (route == NULL)
947                 goto out;
948
949         route->network = g_strdup(network);
950         route->netmask = g_strdup(netmask);
951         route->gateway = NULL;
952         route->family = family;
953
954 out:
955         g_strfreev(elems);
956         return route;
957 }
958
959 static GSList *get_user_networks(DBusMessageIter *array)
960 {
961         DBusMessageIter entry;
962         GSList *list = NULL;
963
964         dbus_message_iter_recurse(array, &entry);
965
966         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
967                 const char *val;
968                 struct vpn_route *route;
969
970                 dbus_message_iter_get_basic(&entry, &val);
971
972                 route = parse_user_route(val);
973                 if (route != NULL)
974                         list = g_slist_prepend(list, route);
975
976                 dbus_message_iter_next(&entry);
977         }
978
979         return list;
980 }
981
982 static void append_route(DBusMessageIter *iter, void *user_data)
983 {
984         struct vpn_route *route = user_data;
985         DBusMessageIter item;
986         int family = 0;
987
988         connman_dbus_dict_open(iter, &item);
989
990         if (route == NULL)
991                 goto empty_dict;
992
993         if (route->family == AF_INET)
994                 family = 4;
995         else if (route->family == AF_INET6)
996                 family = 6;
997
998         if (family != 0)
999                 connman_dbus_dict_append_basic(&item, "ProtocolFamily",
1000                                         DBUS_TYPE_INT32, &family);
1001
1002         if (route->network != NULL)
1003                 connman_dbus_dict_append_basic(&item, "Network",
1004                                         DBUS_TYPE_STRING, &route->network);
1005
1006         if (route->netmask != NULL)
1007                 connman_dbus_dict_append_basic(&item, "Netmask",
1008                                         DBUS_TYPE_STRING, &route->netmask);
1009
1010         if (route->gateway != NULL)
1011                 connman_dbus_dict_append_basic(&item, "Gateway",
1012                                         DBUS_TYPE_STRING, &route->gateway);
1013
1014 empty_dict:
1015         connman_dbus_dict_close(iter, &item);
1016 }
1017
1018 static void append_routes(DBusMessageIter *iter, void *user_data)
1019 {
1020         GSList *list, *routes = user_data;
1021
1022         DBG("routes %p", routes);
1023
1024         for (list = routes; list != NULL; list = g_slist_next(list)) {
1025                 DBusMessageIter dict;
1026                 struct vpn_route *route = list->data;
1027
1028                 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL,
1029                                                 &dict);
1030                 append_route(&dict, route);
1031                 dbus_message_iter_close_container(iter, &dict);
1032         }
1033 }
1034
1035 static int create_configuration(DBusMessage *msg)
1036 {
1037         DBusMessage *new_msg;
1038         DBusPendingCall *call;
1039         DBusMessageIter iter, array, new_iter, new_dict;
1040         const char *type = NULL, *name = NULL;
1041         const char *host = NULL, *domain = NULL;
1042         char *ident, *me = NULL;
1043         int err = 0;
1044         dbus_bool_t result;
1045         struct connection_data *data;
1046         GSList *networks = NULL;
1047
1048         /*
1049          * We copy the old message data into new message. We cannot
1050          * just use the old message as is because the user route
1051          * information is not in the same format in vpnd.
1052          */
1053         new_msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
1054         dbus_message_iter_init_append(new_msg, &new_iter);
1055         connman_dbus_dict_open(&new_iter, &new_dict);
1056
1057         dbus_message_iter_init(msg, &iter);
1058         dbus_message_iter_recurse(&iter, &array);
1059
1060         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1061                 DBusMessageIter entry, value;
1062                 void *item_value;
1063                 const char *key;
1064                 int value_type;
1065
1066                 dbus_message_iter_recurse(&array, &entry);
1067                 dbus_message_iter_get_basic(&entry, &key);
1068
1069                 dbus_message_iter_next(&entry);
1070                 dbus_message_iter_recurse(&entry, &value);
1071
1072                 value_type = dbus_message_iter_get_arg_type(&value);
1073                 item_value = NULL;
1074
1075                 switch (value_type) {
1076                 case DBUS_TYPE_STRING:
1077                         dbus_message_iter_get_basic(&value, &item_value);
1078
1079                         if (g_str_equal(key, "Type") == TRUE) {
1080                                 type = (const char *)item_value;
1081                         } else if (g_str_equal(key, "Name") == TRUE) {
1082                                 name = (const char *)item_value;
1083                         } else if (g_str_equal(key, "Host") == TRUE) {
1084                                 host = (const char *)item_value;
1085                         } else if (g_str_equal(key, "VPN.Domain") == TRUE) {
1086                                 domain = (const char *)item_value;
1087                         }
1088
1089                         DBG("%s %s", key, (char *)item_value);
1090
1091                         if (item_value != NULL)
1092                                 connman_dbus_dict_append_basic(&new_dict, key,
1093                                                 value_type, &item_value);
1094                         break;
1095                 case DBUS_TYPE_ARRAY:
1096                         if (g_str_equal(key, "Networks") == TRUE) {
1097                                 networks = get_user_networks(&value);
1098                                 connman_dbus_dict_append_array(&new_dict,
1099                                                         "UserRoutes",
1100                                                         DBUS_TYPE_DICT_ENTRY,
1101                                                         append_routes,
1102                                                         networks);
1103                         }
1104                         break;
1105                 }
1106
1107                 dbus_message_iter_next(&array);
1108         }
1109
1110         connman_dbus_dict_close(&new_iter, &new_dict);
1111
1112         DBG("VPN type %s name %s host %s domain %s networks %p",
1113                 type, name, host, domain, networks);
1114
1115         if (host == NULL || domain == NULL) {
1116                 err = -EINVAL;
1117                 goto done;
1118         }
1119
1120         if (type == NULL || name == NULL) {
1121                 err = -EOPNOTSUPP;
1122                 goto done;
1123         }
1124
1125         ident = g_strdup_printf("%s_%s", host, domain);
1126         set_dbus_ident(ident);
1127
1128         DBG("ident %s", ident);
1129
1130         data = g_hash_table_lookup(vpn_connections, ident);
1131         if (data != NULL) {
1132                 if (data->call != NULL) {
1133                         connman_error("Dbus call already pending");
1134                         err = -EINPROGRESS;
1135                         goto done;
1136                 }
1137         } else {
1138                 data = create_connection_data(ident);
1139                 if (data == NULL) {
1140                         err = -ENOMEM;
1141                         goto done;
1142                 }
1143
1144                 g_hash_table_insert(vpn_connections, g_strdup(ident), data);
1145         }
1146
1147         /*
1148          * User called net.connman.Manager.ConnectProvider if we are here.
1149          * So use the data from original message in the new msg.
1150          */
1151         me = g_strdup(dbus_message_get_destination(msg));
1152
1153         dbus_message_set_interface(new_msg, VPN_MANAGER_INTERFACE);
1154         dbus_message_set_path(new_msg, "/");
1155         dbus_message_set_destination(new_msg, VPN_SERVICE);
1156         dbus_message_set_sender(new_msg, me);
1157         dbus_message_set_member(new_msg, "Create");
1158
1159         result = dbus_connection_send_with_reply(connection, new_msg,
1160                                                 &call, DBUS_TIMEOUT);
1161         if (result == FALSE || call == NULL) {
1162                 err = -EIO;
1163                 goto done;
1164         }
1165
1166         dbus_pending_call_set_notify(call, configuration_create_reply,
1167                                                                 NULL, NULL);
1168         data->call = call;
1169
1170 done:
1171         dbus_message_unref(new_msg);
1172
1173         if (networks != NULL)
1174                 g_slist_free_full(networks, destroy_route);
1175
1176
1177         g_free(me);
1178         return err;
1179 }
1180
1181 static connman_bool_t check_host(char **hosts, char *host)
1182 {
1183         int i;
1184
1185         if (hosts == NULL)
1186                 return FALSE;
1187
1188         for (i = 0; hosts[i] != NULL; i++) {
1189                 if (g_strcmp0(hosts[i], host) == 0)
1190                         return TRUE;
1191         }
1192
1193         return FALSE;
1194 }
1195
1196 static void set_route(struct connection_data *data, struct vpn_route *route)
1197 {
1198         /*
1199          * If the VPN administrator/user has given a route to
1200          * VPN server, then we must discard that because the
1201          * server cannot be contacted via VPN tunnel.
1202          */
1203         if (check_host(data->host_ip, route->network) == TRUE) {
1204                 DBG("Discarding VPN route to %s via %s at index %d",
1205                         route->network, route->gateway, data->index);
1206                 return;
1207         }
1208
1209         if (route->family == AF_INET6) {
1210                 unsigned char prefix_len = atoi(route->netmask);
1211
1212                 connman_inet_add_ipv6_network_route(data->index,
1213                                                         route->network,
1214                                                         route->gateway,
1215                                                         prefix_len);
1216         } else {
1217                 connman_inet_add_network_route(data->index, route->network,
1218                                                 route->gateway,
1219                                                 route->netmask);
1220         }
1221 }
1222
1223 static int set_routes(struct connman_provider *provider,
1224                                 enum connman_provider_route_type type)
1225 {
1226         struct connection_data *data;
1227         GHashTableIter iter;
1228         gpointer value, key;
1229
1230         DBG("provider %p", provider);
1231
1232         data = connman_provider_get_data(provider);
1233         if (data == NULL)
1234                 return -EINVAL;
1235
1236         if (type == CONNMAN_PROVIDER_ROUTE_ALL ||
1237                                         type == CONNMAN_PROVIDER_ROUTE_USER) {
1238                 g_hash_table_iter_init(&iter, data->user_routes);
1239
1240                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE)
1241                         set_route(data, value);
1242         }
1243
1244         if (type == CONNMAN_PROVIDER_ROUTE_ALL ||
1245                                 type == CONNMAN_PROVIDER_ROUTE_SERVER) {
1246                 g_hash_table_iter_init(&iter, data->server_routes);
1247
1248                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE)
1249                         set_route(data, value);
1250         }
1251
1252         return 0;
1253 }
1254
1255 static connman_bool_t check_routes(struct connman_provider *provider)
1256 {
1257         struct connection_data *data;
1258
1259         DBG("provider %p", provider);
1260
1261         data = connman_provider_get_data(provider);
1262         if (data == NULL)
1263                 return FALSE;
1264
1265         if (data->user_routes != NULL &&
1266                         g_hash_table_size(data->user_routes) > 0)
1267                 return TRUE;
1268
1269         if (data->server_routes != NULL &&
1270                         g_hash_table_size(data->server_routes) > 0)
1271                 return TRUE;
1272
1273         return FALSE;
1274 }
1275
1276 static struct connman_provider_driver provider_driver = {
1277         .name = "VPN",
1278         .type = CONNMAN_PROVIDER_TYPE_VPN,
1279         .probe = provider_probe,
1280         .remove = provider_remove,
1281         .connect = provider_connect,
1282         .disconnect = provider_disconnect,
1283         .set_property = set_string,
1284         .get_property = get_string,
1285         .create = create_configuration,
1286         .set_routes = set_routes,
1287         .check_routes = check_routes,
1288 };
1289
1290 static void destroy_provider(struct connection_data *data)
1291 {
1292         DBG("data %p", data);
1293
1294         if (g_str_equal(data->state, "ready") == TRUE ||
1295                         g_str_equal(data->state, "configuration") == TRUE)
1296                 connman_provider_disconnect(data->provider);
1297
1298         if (data->call != NULL)
1299                 dbus_pending_call_cancel(data->call);
1300
1301         connman_provider_put(data->provider);
1302
1303         data->provider = NULL;
1304 }
1305
1306 static void connection_destroy(gpointer hash_data)
1307 {
1308         struct connection_data *data = hash_data;
1309
1310         DBG("data %p", data);
1311
1312         if (data->provider != NULL)
1313                 destroy_provider(data);
1314
1315         g_free(data->path);
1316         g_free(data->state);
1317         g_free(data->type);
1318         g_free(data->name);
1319         g_free(data->host);
1320         g_free(data->domain);
1321         g_hash_table_destroy(data->server_routes);
1322         g_hash_table_destroy(data->user_routes);
1323         g_strfreev(data->nameservers);
1324         g_hash_table_destroy(data->setting_strings);
1325         connman_ipaddress_free(data->ip);
1326
1327         cancel_host_resolv(data);
1328
1329         g_free(data);
1330 }
1331
1332 static void vpnd_created(DBusConnection *conn, void *user_data)
1333 {
1334         DBG("connection %p", conn);
1335
1336         if (starting_vpnd == TRUE) {
1337                 vpn_connections = g_hash_table_new_full(g_str_hash,
1338                                                 g_str_equal,
1339                                                 g_free, connection_destroy);
1340                 get_connections(user_data);
1341                 starting_vpnd = FALSE;
1342         }
1343 }
1344
1345 static void vpnd_removed(DBusConnection *conn, void *user_data)
1346 {
1347         DBG("connection %p", conn);
1348
1349         g_hash_table_destroy(vpn_connections);
1350         vpn_connections = NULL;
1351         starting_vpnd = TRUE;
1352 }
1353
1354 static void remove_connection(DBusConnection *conn, const char *path)
1355 {
1356         DBG("path %s", path);
1357
1358         g_hash_table_remove(vpn_connections, path);
1359 }
1360
1361 static gboolean connection_removed(DBusConnection *conn, DBusMessage *message,
1362                                 void *user_data)
1363 {
1364         const char *path;
1365         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
1366
1367         if (dbus_message_has_signature(message, signature) == FALSE) {
1368                 connman_error("vpn removed signature \"%s\" does not match "
1369                                                         "expected \"%s\"",
1370                         dbus_message_get_signature(message), signature);
1371                 return TRUE;
1372         }
1373
1374         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1375                                 DBUS_TYPE_INVALID);
1376         remove_connection(conn, path);
1377         return TRUE;
1378 }
1379
1380 static gboolean connection_added(DBusConnection *conn, DBusMessage *message,
1381                                 void *user_data)
1382 {
1383         DBusMessageIter iter, properties;
1384         const char *path;
1385         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
1386                 DBUS_TYPE_ARRAY_AS_STRING
1387                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1388                 DBUS_TYPE_STRING_AS_STRING
1389                 DBUS_TYPE_VARIANT_AS_STRING
1390                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
1391
1392         if (dbus_message_has_signature(message, signature) == FALSE) {
1393                 connman_error("vpn ConnectionAdded signature \"%s\" does not "
1394                                                 "match expected \"%s\"",
1395                         dbus_message_get_signature(message), signature);
1396                 return TRUE;
1397         }
1398
1399         DBG("");
1400
1401         if (dbus_message_iter_init(message, &iter) == FALSE)
1402                 return TRUE;
1403
1404         dbus_message_iter_get_basic(&iter, &path);
1405
1406         dbus_message_iter_next(&iter);
1407         dbus_message_iter_recurse(&iter, &properties);
1408
1409         add_connection(path, &properties, user_data);
1410
1411         return TRUE;
1412 }
1413
1414 static int save_route(GHashTable *routes, int family, const char *network,
1415                         const char *netmask, const char *gateway)
1416 {
1417         struct vpn_route *route;
1418         char *key = g_strdup_printf("%d/%s/%s", family, network, netmask);
1419
1420         DBG("family %d network %s netmask %s", family, network, netmask);
1421
1422         route = g_hash_table_lookup(routes, key);
1423         if (route == NULL) {
1424                 route = g_try_new0(struct vpn_route, 1);
1425                 if (route == NULL) {
1426                         connman_error("out of memory");
1427                         return -ENOMEM;
1428                 }
1429
1430                 route->family = family;
1431                 route->network = g_strdup(network);
1432                 route->netmask = g_strdup(netmask);
1433                 route->gateway = g_strdup(gateway);
1434
1435                 g_hash_table_replace(routes, key, route);
1436         } else
1437                 g_free(key);
1438
1439         return 0;
1440 }
1441
1442 static int read_route_dict(GHashTable *routes, DBusMessageIter *dicts)
1443 {
1444         DBusMessageIter dict;
1445         const char *network, *netmask, *gateway;
1446         int family;
1447
1448         dbus_message_iter_recurse(dicts, &dict);
1449
1450         network = netmask = gateway = NULL;
1451         family = PF_UNSPEC;
1452
1453         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1454
1455                 DBusMessageIter entry, value;
1456                 const char *key;
1457
1458                 dbus_message_iter_recurse(&dict, &entry);
1459                 dbus_message_iter_get_basic(&entry, &key);
1460
1461                 dbus_message_iter_next(&entry);
1462                 dbus_message_iter_recurse(&entry, &value);
1463
1464                 if (g_str_equal(key, "ProtocolFamily") == TRUE) {
1465                         int pf;
1466                         dbus_message_iter_get_basic(&value, &pf);
1467                         switch (pf) {
1468                         case 4:
1469                                 family = AF_INET;
1470                                 break;
1471                         case 6:
1472                                 family = AF_INET6;
1473                                 break;
1474                         }
1475                         DBG("family %d", family);
1476                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1477                         dbus_message_iter_get_basic(&value, &netmask);
1478                         DBG("netmask %s", netmask);
1479                 } else if (g_str_equal(key, "Network") == TRUE) {
1480                         dbus_message_iter_get_basic(&value, &network);
1481                         DBG("host %s", network);
1482                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1483                         dbus_message_iter_get_basic(&value, &gateway);
1484                         DBG("gateway %s", gateway);
1485                 }
1486
1487                 dbus_message_iter_next(&dict);
1488         }
1489
1490         if (netmask == NULL || network == NULL || gateway == NULL) {
1491                 DBG("Value missing.");
1492                 return -EINVAL;
1493         }
1494
1495         return save_route(routes, family, network, netmask, gateway);
1496 }
1497
1498 static int routes_changed(DBusMessageIter *array, GHashTable *routes)
1499 {
1500         DBusMessageIter entry;
1501         int ret = -EINVAL;
1502
1503         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) {
1504                 DBG("Expecting array, ignoring routes.");
1505                 return -EINVAL;
1506         }
1507
1508         while (dbus_message_iter_get_arg_type(array) == DBUS_TYPE_ARRAY) {
1509
1510                 dbus_message_iter_recurse(array, &entry);
1511
1512                 while (dbus_message_iter_get_arg_type(&entry) ==
1513                                                         DBUS_TYPE_STRUCT) {
1514                         DBusMessageIter dicts;
1515
1516                         dbus_message_iter_recurse(&entry, &dicts);
1517
1518                         while (dbus_message_iter_get_arg_type(&dicts) ==
1519                                                         DBUS_TYPE_ARRAY) {
1520                                 int err = read_route_dict(routes, &dicts);
1521                                 if (ret != 0)
1522                                         ret = err;
1523                                 dbus_message_iter_next(&dicts);
1524                         }
1525
1526                         dbus_message_iter_next(&entry);
1527                 }
1528
1529                 dbus_message_iter_next(array);
1530         }
1531
1532         return ret;
1533 }
1534
1535 static gboolean property_changed(DBusConnection *conn,
1536                                 DBusMessage *message,
1537                                 void *user_data)
1538 {
1539         const char *path = dbus_message_get_path(message);
1540         struct connection_data *data = NULL;
1541         DBusMessageIter iter, value;
1542         connman_bool_t ip_set = FALSE;
1543         int err;
1544         char *str;
1545         const char *key;
1546         const char *signature = DBUS_TYPE_STRING_AS_STRING
1547                 DBUS_TYPE_VARIANT_AS_STRING;
1548
1549         if (dbus_message_has_signature(message, signature) == FALSE) {
1550                 connman_error("vpn property signature \"%s\" does not match "
1551                                                         "expected \"%s\"",
1552                         dbus_message_get_signature(message), signature);
1553                 return TRUE;
1554         }
1555
1556         data = g_hash_table_lookup(vpn_connections, path);
1557         if (data == NULL)
1558                 return TRUE;
1559
1560         if (dbus_message_iter_init(message, &iter) == FALSE)
1561                 return TRUE;
1562
1563         dbus_message_iter_get_basic(&iter, &key);
1564
1565         dbus_message_iter_next(&iter);
1566         dbus_message_iter_recurse(&iter, &value);
1567
1568         DBG("key %s", key);
1569
1570         if (g_str_equal(key, "State") == TRUE) {
1571                 dbus_message_iter_get_basic(&value, &str);
1572
1573                 DBG("%s %s -> %s", data->path, data->state, str);
1574
1575                 if (g_str_equal(data->state, str) == TRUE)
1576                         return TRUE;
1577
1578                 g_free(data->state);
1579                 data->state = g_strdup(str);
1580
1581                 set_provider_state(data);
1582         } else if (g_str_equal(key, "Index") == TRUE) {
1583                 dbus_message_iter_get_basic(&value, &data->index);
1584                 connman_provider_set_index(data->provider, data->index);
1585         } else if (g_str_equal(key, "IPv4") == TRUE) {
1586                 err = extract_ip(&value, AF_INET, data);
1587                 ip_set = TRUE;
1588         } else if (g_str_equal(key, "IPv6") == TRUE) {
1589                 err = extract_ip(&value, AF_INET6, data);
1590                 ip_set = TRUE;
1591         } else if (g_str_equal(key, "ServerRoutes") == TRUE) {
1592                 err = routes_changed(&value, data->server_routes);
1593                 /*
1594                  * Note that the vpnd will delay the route sending a bit
1595                  * (in order to collect the routes from VPN client),
1596                  * so we might have got the State changed property before
1597                  * we got ServerRoutes. This means that we must try to set
1598                  * the routes here because they would be left unset otherwise.
1599                  */
1600                 if (err == 0)
1601                         set_routes(data->provider,
1602                                                 CONNMAN_PROVIDER_ROUTE_SERVER);
1603         } else if (g_str_equal(key, "UserRoutes") == TRUE) {
1604                 err = routes_changed(&value, data->user_routes);
1605                 if (err == 0)
1606                         set_routes(data->provider,
1607                                                 CONNMAN_PROVIDER_ROUTE_USER);
1608         } else if (g_str_equal(key, "Nameservers") == TRUE) {
1609                 extract_nameservers(&value, data);
1610         }
1611
1612         if (ip_set == TRUE && err == 0) {
1613                 err = connman_provider_set_ipaddress(data->provider, data->ip);
1614                 if (err < 0)
1615                         DBG("setting provider IP address failed (%s/%d)",
1616                                 strerror(-err), -err);
1617         }
1618
1619         return TRUE;
1620 }
1621
1622 static int vpn_init(void)
1623 {
1624         int err;
1625
1626         connection = connman_dbus_get_connection();
1627         if (connection == NULL)
1628                 return -EIO;
1629
1630         watch = g_dbus_add_service_watch(connection, VPN_SERVICE,
1631                         vpnd_created, vpnd_removed, &provider_driver, NULL);
1632
1633         added_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1634                                         VPN_MANAGER_INTERFACE,
1635                                         CONNECTION_ADDED, connection_added,
1636                                         &provider_driver, NULL);
1637
1638         removed_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1639                                         VPN_MANAGER_INTERFACE,
1640                                         CONNECTION_REMOVED, connection_removed,
1641                                         NULL, NULL);
1642
1643         property_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1644                                         VPN_CONNECTION_INTERFACE,
1645                                         PROPERTY_CHANGED, property_changed,
1646                                         NULL, NULL);
1647
1648         if (added_watch == 0 || removed_watch == 0 || property_watch == 0) {
1649                 err = -EIO;
1650                 goto remove;
1651         }
1652
1653         err = connman_provider_driver_register(&provider_driver);
1654         if (err == 0)
1655                 vpnd_created(connection, &provider_driver);
1656
1657         return err;
1658
1659 remove:
1660         g_dbus_remove_watch(connection, watch);
1661         g_dbus_remove_watch(connection, added_watch);
1662         g_dbus_remove_watch(connection, removed_watch);
1663         g_dbus_remove_watch(connection, property_watch);
1664
1665         dbus_connection_unref(connection);
1666
1667         return err;
1668 }
1669
1670 static void vpn_exit(void)
1671 {
1672         g_dbus_remove_watch(connection, watch);
1673         g_dbus_remove_watch(connection, added_watch);
1674         g_dbus_remove_watch(connection, removed_watch);
1675         g_dbus_remove_watch(connection, property_watch);
1676
1677         connman_provider_driver_unregister(&provider_driver);
1678
1679         g_hash_table_destroy(vpn_connections);
1680
1681         dbus_connection_unref(connection);
1682 }
1683
1684 CONNMAN_PLUGIN_DEFINE(vpn, "VPN plugin", VERSION,
1685                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, vpn_init, vpn_exit)