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