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