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