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