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