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