Fix VPN nameservers parsing
[platform/upstream/connman.git] / src / provider.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 <stdio.h>
27 #include <string.h>
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 static DBusConnection *connection = NULL;
33
34 static GHashTable *provider_hash = NULL;
35
36 static GSList *driver_list = NULL;
37
38 struct connman_provider {
39         struct connman_element element;
40         struct connman_service *vpn_service;
41         char *identifier;
42         char *name;
43         char *type;
44         char *host;
45         char *dns;
46         char *domain;
47         struct connman_provider_driver *driver;
48         void *driver_data;
49 };
50
51 void __connman_provider_append_properties(struct connman_provider *provider,
52                                                         DBusMessageIter *iter)
53 {
54         if (provider->host != NULL)
55                 connman_dbus_dict_append_basic(iter, "Host",
56                                         DBUS_TYPE_STRING, &provider->host);
57
58         if (provider->domain != NULL)
59                 connman_dbus_dict_append_basic(iter, "Domain",
60                                         DBUS_TYPE_STRING, &provider->domain);
61
62         if (provider->type != NULL)
63                 connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
64                                                  &provider->type);
65 }
66
67 static struct connman_provider *connman_provider_lookup(const char *identifier)
68 {
69         struct connman_provider *provider = NULL;
70
71         provider = g_hash_table_lookup(provider_hash, identifier);
72
73         return provider;
74 }
75
76 static int connman_provider_setup_vpn_ipv4(struct connman_provider *provider,
77                                                 struct connman_element *element)
78 {
79         if (element == NULL || provider == NULL)
80                 return -EINVAL;
81
82         DBG("set vpn type %d", element->type);
83
84         g_free(element->ipv4.address);
85         element->ipv4.address = g_strdup(provider->element.ipv4.address);
86
87         g_free(element->ipv4.netmask);
88         element->ipv4.netmask = g_strdup(provider->element.ipv4.netmask);
89
90         g_free(element->ipv4.gateway);
91         element->ipv4.gateway = g_strdup(provider->element.ipv4.gateway);
92
93         g_free(element->ipv4.broadcast);
94         element->ipv4.broadcast = g_strdup(provider->element.ipv4.broadcast);
95
96         g_free(element->ipv4.pac);
97         element->ipv4.pac = g_strdup(provider->element.ipv4.pac);
98
99         return connman_element_register(element, &provider->element);
100 }
101
102 struct connman_provider *connman_provider_ref(struct connman_provider *provider)
103 {
104         DBG("provider %p", provider);
105
106         if (connman_element_ref(&provider->element) == NULL)
107                 return NULL;
108
109         return provider;
110 }
111
112 void connman_provider_unref(struct connman_provider *provider)
113 {
114         DBG("provider %p", provider);
115
116         connman_element_unref(&provider->element);
117 }
118
119 static gboolean match_driver(struct connman_provider *provider,
120                                 struct connman_provider_driver *driver)
121 {
122         if (g_strcmp0(driver->name, provider->type) == 0)
123                 return TRUE;
124
125         return FALSE;
126 }
127
128 static int provider_probe(struct connman_provider *provider)
129 {
130         GSList *list;
131
132         DBG("provider %p name %s", provider, provider->name);
133
134         if (provider->driver != NULL)
135                 return -EALREADY;
136
137         for (list = driver_list; list; list = list->next) {
138                 struct connman_provider_driver *driver = list->data;
139
140                 if (match_driver(provider, driver) == FALSE)
141                         continue;
142
143                 DBG("driver %p name %s", driver, driver->name);
144
145                 if (driver->probe != NULL && driver->probe(provider) == 0) {
146                         provider->driver = driver;
147                         break;
148                 }
149         }
150
151         if (provider->driver == NULL)
152                 return -ENODEV;
153
154         return 0;
155 }
156
157 int __connman_provider_disconnect(struct connman_provider *provider)
158 {
159         int err;
160
161         DBG("provider %p", provider);
162
163         if (provider->driver != NULL && provider->driver->disconnect != NULL)
164                 err = provider->driver->disconnect(provider);
165         else
166                 return -EOPNOTSUPP;
167
168         __connman_service_indicate_state(provider->vpn_service,
169                                         CONNMAN_SERVICE_STATE_DISCONNECT);
170         if (err < 0) {
171                 if (err != -EINPROGRESS)
172                         return err;
173
174                 return -EINPROGRESS;
175         }
176
177         return 0;
178 }
179
180 int __connman_provider_connect(struct connman_provider *provider)
181 {
182         int err;
183
184         DBG("provider %p", provider);
185
186         g_free(provider->element.ipv4.address);
187         g_free(provider->element.ipv4.netmask);
188         g_free(provider->element.ipv4.gateway);
189         g_free(provider->element.ipv4.broadcast);
190         g_free(provider->element.ipv4.pac);
191
192         provider->element.ipv4.address = NULL;
193         provider->element.ipv4.netmask = NULL;
194         provider->element.ipv4.gateway = NULL;
195         provider->element.ipv4.broadcast = NULL;
196         provider->element.ipv4.pac = NULL;
197
198         if (provider->driver != NULL && provider->driver->connect != NULL)
199                 err = provider->driver->connect(provider);
200         else
201                 return -EOPNOTSUPP;
202
203         if (err < 0) {
204                 if (err != -EINPROGRESS)
205                         return err;
206
207                 __connman_service_indicate_state(provider->vpn_service,
208                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
209                 return -EINPROGRESS;
210         }
211
212         return 0;
213 }
214
215 int __connman_provider_remove(const char *path)
216 {
217         struct connman_provider *provider;
218
219         DBG("path %s", path);
220
221         provider = g_hash_table_lookup(provider_hash, path);
222         if (provider == NULL) {
223                 DBG("patch %s not found", path);
224                 return -ENXIO;
225         }
226
227         g_hash_table_remove(provider_hash, path);
228
229         return 0;
230 }
231
232 static int set_connected(struct connman_provider *provider,
233                                         connman_bool_t connected)
234 {
235         struct connman_service *service = provider->vpn_service;
236
237         if (service == NULL)
238                 return -ENODEV;
239
240         if (connected == TRUE) {
241                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
242                 struct connman_element *element;
243                 char *nameservers = NULL, *name = NULL;
244                 const char *value;
245                 char *second_ns;
246                 int err;
247
248                 __connman_service_indicate_state(provider->vpn_service,
249                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
250
251                 type = CONNMAN_ELEMENT_TYPE_IPV4;
252
253                 element = connman_element_create(NULL);
254                 if (element == NULL)
255                         return -ENOMEM;
256
257                 element->type  = type;
258                 element->index = provider->element.index;
259
260                 err = connman_provider_setup_vpn_ipv4(provider, element);
261                 if (err < 0) {
262                         connman_element_unref(element);
263
264                         __connman_service_indicate_state(service,
265                                                 CONNMAN_SERVICE_STATE_FAILURE);
266
267                         return err;
268                 }
269
270                 __connman_service_indicate_state(service,
271                                                 CONNMAN_SERVICE_STATE_READY);
272
273                 __connman_service_set_domainname(service, provider->domain);
274
275                 name = connman_inet_ifname(provider->element.index);
276
277                 nameservers = g_strdup(provider->dns);
278                 value = nameservers;
279                 second_ns = strchr(value, ' ');
280                 if (second_ns)
281                         *(second_ns++) = 0;
282                 __connman_service_append_nameserver(service, value);
283                 value = second_ns;
284
285                 while (value) {
286                         char *next = strchr(value, ' ');
287                         if (next)
288                                 *(next++) = 0;
289
290                         connman_resolver_append(name, provider->domain, value);
291                         value = next;
292                 }
293
294                 g_free(nameservers);
295                 g_free(name);
296
297         } else {
298                 connman_element_unregister_children(&provider->element);
299                 __connman_service_indicate_state(service,
300                                                 CONNMAN_SERVICE_STATE_IDLE);
301         }
302
303         return 0;
304 }
305
306 int connman_provider_set_state(struct connman_provider *provider,
307                                         enum connman_provider_state state)
308 {
309         if (provider == NULL || provider->vpn_service == NULL)
310                 return -EINVAL;
311
312         switch (state) {
313         case CONNMAN_PROVIDER_STATE_UNKNOWN:
314                 return -EINVAL;
315         case CONNMAN_PROVIDER_STATE_IDLE:
316                 return set_connected(provider, FALSE);
317         case CONNMAN_PROVIDER_STATE_CONNECT:
318                 return __connman_service_indicate_state(provider->vpn_service,
319                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
320         case CONNMAN_PROVIDER_STATE_READY:
321                 return set_connected(provider, TRUE);
322         case CONNMAN_PROVIDER_STATE_DISCONNECT:
323                 return __connman_service_indicate_state(provider->vpn_service,
324                                         CONNMAN_SERVICE_STATE_DISCONNECT);
325         case CONNMAN_PROVIDER_STATE_FAILURE:
326                 return __connman_service_indicate_state(provider->vpn_service,
327                                         CONNMAN_SERVICE_STATE_FAILURE);
328         }
329
330         return -EINVAL;
331 }
332
333 static void unregister_provider(gpointer data)
334 {
335         struct connman_provider *provider = data;
336
337         DBG("provider %p", provider);
338
339         __connman_service_put(provider->vpn_service);
340
341         connman_element_unregister(&provider->element);
342         connman_provider_unref(provider);
343 }
344
345 static void provider_destruct(struct connman_element *element)
346 {
347         struct connman_provider *provider = element->private;
348
349         DBG("provider %p", provider);
350
351         g_free(provider->name);
352         g_free(provider->type);
353         g_free(provider->domain);
354         g_free(provider->identifier);
355         g_free(provider->dns);
356 }
357
358 static void provider_initialize(struct connman_provider *provider)
359 {
360         DBG("provider %p", provider);
361
362         __connman_element_initialize(&provider->element);
363
364         provider->element.private = provider;
365         provider->element.destruct = provider_destruct;
366
367         provider->element.ipv4.address = NULL;
368         provider->element.ipv4.netmask = NULL;
369         provider->element.ipv4.gateway = NULL;
370         provider->element.ipv4.broadcast = NULL;
371         provider->element.ipv4.pac = NULL;
372
373         provider->name = NULL;
374         provider->type = NULL;
375         provider->dns = NULL;
376         provider->domain = NULL;
377         provider->identifier = NULL;
378 }
379
380 static struct connman_provider *connman_provider_new(void)
381 {
382         struct connman_provider *provider;
383
384         provider = g_try_new0(struct connman_provider, 1);
385         if (provider == NULL)
386                 return NULL;
387
388         DBG("provider %p", provider);
389         provider_initialize(provider);
390
391         return provider;
392 }
393
394 static struct connman_provider *connman_provider_get(const char *identifier)
395 {
396         struct connman_provider *provider;
397
398         provider = g_hash_table_lookup(provider_hash, identifier);
399         if (provider != NULL)
400                 return provider;
401
402         provider = connman_provider_new();
403         if (provider == NULL)
404                 return NULL;
405
406         DBG("provider %p", provider);
407
408         provider->identifier = g_strdup(identifier);
409
410         g_hash_table_insert(provider_hash, provider->identifier, provider);
411
412         provider->element.name = g_strdup(identifier);
413         connman_element_register(&provider->element, NULL);
414
415         return provider;
416 }
417
418 static void provider_dbus_ident(char *ident)
419 {
420         int i, len = strlen(ident);
421
422         for (i = 0; i < len; i++)
423                 if (ident[i] == '.')
424                         ident[i] = '_';
425 }
426
427 int __connman_provider_create_and_connect(DBusMessage *msg)
428 {
429         struct connman_provider *provider;
430         DBusMessageIter iter, array;
431         const char *type = NULL, *name = NULL, *service_path = NULL;
432         const char *host = NULL, *domain = NULL;
433         char *ident;
434         gboolean created = FALSE;
435         int err;
436
437         dbus_message_iter_init(msg, &iter);
438         dbus_message_iter_recurse(&iter, &array);
439
440         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
441                 DBusMessageIter entry, value;
442                 const char *key;
443
444                 dbus_message_iter_recurse(&array, &entry);
445                 dbus_message_iter_get_basic(&entry, &key);
446
447                 dbus_message_iter_next(&entry);
448                 dbus_message_iter_recurse(&entry, &value);
449
450                 switch (dbus_message_iter_get_arg_type(&value)) {
451                 case DBUS_TYPE_STRING:
452                         if (g_str_equal(key, "Type") == TRUE)
453                                 dbus_message_iter_get_basic(&value, &type);
454                         else if (g_str_equal(key, "Name") == TRUE)
455                                 dbus_message_iter_get_basic(&value, &name);
456                         else if (g_str_equal(key, "Host") == TRUE)
457                                 dbus_message_iter_get_basic(&value, &host);
458                         else if (g_str_equal(key, "VPN.Domain") == TRUE)
459                                 dbus_message_iter_get_basic(&value, &domain);
460                         break;
461                 }
462
463                 dbus_message_iter_next(&array);
464         }
465
466         if (host == NULL || domain == NULL) {
467                 err = -EINVAL;
468                 goto failed;
469         }
470
471         DBG("Type %s name %s", type, name);
472
473         if (type == NULL || name == NULL) {
474                 err = -EOPNOTSUPP;
475                 goto failed;
476         }
477
478         ident = g_strdup_printf("%s_%s", host, domain);
479         provider_dbus_ident(ident);
480
481         DBG("ident %s", ident);
482
483         provider = connman_provider_lookup(ident);
484
485         if (provider == NULL) {
486                 created = TRUE;
487                 provider = connman_provider_get(ident);
488                 if (provider) {
489                         provider->host = g_strdup(host);
490                         provider->domain = g_strdup(domain);
491                         provider->name = g_strdup(name);
492                         provider->type = g_strdup(type);
493                 }
494         }
495
496         if (provider == NULL) {
497                 DBG("can not create provider");
498                 err = -EOPNOTSUPP;
499                 goto failed;
500         }
501         dbus_message_iter_init(msg, &iter);
502         dbus_message_iter_recurse(&iter, &array);
503
504         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
505                 DBusMessageIter entry, value;
506                 const char *key, *str;
507
508                 dbus_message_iter_recurse(&array, &entry);
509                 dbus_message_iter_get_basic(&entry, &key);
510
511                 dbus_message_iter_next(&entry);
512                 dbus_message_iter_recurse(&entry, &value);
513
514                 switch (dbus_message_iter_get_arg_type(&value)) {
515                 case DBUS_TYPE_STRING:
516                         dbus_message_iter_get_basic(&value, &str);
517                         connman_provider_set_string(provider, key, str);
518                         break;
519                 }
520
521                 dbus_message_iter_next(&array);
522         }
523
524         g_free(ident);
525
526         if (provider == NULL) {
527                 err = -EOPNOTSUPP;
528                 goto failed;
529         }
530
531         if (created == TRUE)
532                 provider_probe(provider);
533
534         provider->vpn_service =
535                         __connman_service_create_from_provider(provider);
536         if (provider->vpn_service == NULL) {
537                 err = -EOPNOTSUPP;
538                 goto failed;
539         }
540
541         err = __connman_service_connect(provider->vpn_service);
542         if (err < 0 && err != -EINPROGRESS)
543                 goto failed;
544
545         service_path = __connman_service_get_path(provider->vpn_service);
546         g_dbus_send_reply(connection, msg,
547                                 DBUS_TYPE_OBJECT_PATH, &service_path,
548                                                         DBUS_TYPE_INVALID);
549         return 0;
550
551 failed:
552         if (provider != NULL && created == TRUE) {
553                 DBG("can not connect delete provider");
554                 connman_provider_unref(provider);
555
556                 if (provider->vpn_service != NULL)
557                         __connman_service_put(provider->vpn_service);
558         }
559
560         return err;
561 }
562
563 const char * __connman_provider_get_ident(struct connman_provider *provider)
564 {
565         if (provider == NULL)
566                 return NULL;
567
568         return provider->identifier;
569 }
570
571 int connman_provider_set_string(struct connman_provider *provider,
572                                         const char *key, const char *value)
573 {
574         DBG("provider %p key %s value %s", provider, key, value);
575
576         if (g_str_equal(key, "Type") == TRUE) {
577                 g_free(provider->type);
578                 provider->type = g_strdup(value);
579         } else if (g_str_equal(key, "Name") == TRUE) {
580                 g_free(provider->name);
581                 provider->name = g_strdup(value);
582         } else if (g_str_equal(key, "Gateway") == TRUE) {
583                 g_free(provider->element.ipv4.gateway);
584                 provider->element.ipv4.gateway = g_strdup(value);
585         } else if (g_str_equal(key, "Address") == TRUE) {
586                 g_free(provider->element.ipv4.address);
587                 provider->element.ipv4.address = g_strdup(value);
588         } else if (g_str_equal(key, "Netmask") == TRUE) {
589                 g_free(provider->element.ipv4.netmask);
590                 provider->element.ipv4.netmask = g_strdup(value);
591         } else if (g_str_equal(key, "PAC") == TRUE) {
592                 g_free(provider->element.ipv4.pac);
593                 provider->element.ipv4.pac = g_strdup(value);
594                 __connman_service_set_proxy_autoconfig(provider->vpn_service,
595                                                                         value);
596         } else if (g_str_equal(key, "DNS") == TRUE) {
597                 g_free(provider->dns);
598                 provider->dns = g_strdup(value);
599         } else if (g_str_equal(key, "Domain") == TRUE) {
600                 g_free(provider->domain);
601                 provider->domain = g_strdup(value);
602         }
603
604         return connman_element_set_string(&provider->element, key, value);
605 }
606
607 const char *connman_provider_get_string(struct connman_provider *provider,
608                                                         const char *key)
609 {
610         DBG("provider %p key %s", provider, key);
611
612         if (g_str_equal(key, "Type") == TRUE)
613                 return provider->type;
614         else if (g_str_equal(key, "Name") == TRUE)
615                 return provider->name;
616
617         return connman_element_get_string(&provider->element, key);
618 }
619
620 void *connman_provider_get_data(struct connman_provider *provider)
621 {
622         return provider->driver_data;
623 }
624
625 void connman_provider_set_data(struct connman_provider *provider, void *data)
626 {
627         provider->driver_data = data;
628 }
629
630 void connman_provider_set_index(struct connman_provider *provider, int index)
631 {
632         struct connman_service *service = provider->vpn_service;
633         struct connman_ipconfig *ipconfig;
634
635         DBG("");
636
637         ipconfig = __connman_service_get_ipconfig(service);
638
639         if (ipconfig == NULL) {
640                 __connman_service_create_ipconfig(service, index);
641
642                 ipconfig = __connman_service_get_ipconfig(service);
643                 if (ipconfig == NULL) {
644                         DBG("Couldnt create ipconfig");
645                         goto done;
646                 }
647         }
648
649         connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_FIXED);
650         __connman_ipconfig_set_index(ipconfig, index);
651
652
653 done:
654         provider->element.index = index;
655 }
656
657 int connman_provider_get_index(struct connman_provider *provider)
658 {
659         return provider->element.index;
660 }
661
662 static gint compare_priority(gconstpointer a, gconstpointer b)
663 {
664         return 0;
665 }
666
667 static void clean_provider(gpointer key, gpointer value, gpointer user_data)
668 {
669         struct connman_provider *provider = value;
670
671         if (provider->driver != NULL && provider->driver->remove)
672                 provider->driver->remove(provider);
673 }
674
675 int connman_provider_driver_register(struct connman_provider_driver *driver)
676 {
677         DBG("driver %p name %s", driver, driver->name);
678
679         driver_list = g_slist_insert_sorted(driver_list, driver,
680                                                         compare_priority);
681         return 0;
682 }
683
684 void connman_provider_driver_unregister(struct connman_provider_driver *driver)
685 {
686         DBG("driver %p name %s", driver, driver->name);
687
688         driver_list = g_slist_remove(driver_list, driver);
689 }
690
691 static void provider_disconnect(gpointer key, gpointer value,
692                                                 gpointer user_data)
693 {
694         struct connman_provider *provider = value;
695
696         __connman_provider_disconnect(provider);
697 }
698
699 static void provider_offline_mode(connman_bool_t enabled)
700 {
701         DBG("enabled %d", enabled);
702
703         if (enabled == TRUE)
704                 g_hash_table_foreach(provider_hash, provider_disconnect, NULL);
705
706 }
707
708 static struct connman_notifier provider_notifier = {
709         .name                   = "provider",
710         .offline_mode           = provider_offline_mode,
711 };
712
713 int __connman_provider_init(void)
714 {
715         int err;
716
717         DBG("");
718
719         connection = connman_dbus_get_connection();
720
721         provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
722                                                 NULL, unregister_provider);
723
724         err = connman_notifier_register(&provider_notifier);
725         if (err < 0) {
726                 g_hash_table_destroy(provider_hash);
727                 dbus_connection_unref(connection);
728         }
729
730         return err;
731 }
732
733 void __connman_provider_cleanup(void)
734 {
735         DBG("");
736
737         connman_notifier_unregister(&provider_notifier);
738
739         g_hash_table_foreach(provider_hash, clean_provider, NULL);
740
741         g_hash_table_destroy(provider_hash);
742         provider_hash = NULL;
743
744         dbus_connection_unref(connection);
745 }