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