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