Protect Connect and Disconnect with security policy
[connman] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 struct connman_network {
33         struct connman_element element;
34         enum connman_network_type type;
35         enum connman_network_protocol protocol;
36         connman_bool_t connected;
37         connman_bool_t remember;
38         connman_uint8_t strength;
39         char *identifier;
40         char *name;
41         char *node;
42
43         struct connman_network_driver *driver;
44         void *driver_data;
45
46         connman_bool_t registered;
47
48         struct connman_device *device;
49
50         struct {
51                 void *ssid;
52                 int ssid_len;
53                 char *mode;
54                 char *security;
55                 char *passphrase;
56         } wifi;
57 };
58
59 static const char *type2string(enum connman_network_type type)
60 {
61         switch (type) {
62         case CONNMAN_NETWORK_TYPE_UNKNOWN:
63         case CONNMAN_NETWORK_TYPE_VENDOR:
64                 break;
65         case CONNMAN_NETWORK_TYPE_WIFI:
66                 return "wifi";
67         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
68         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
69                 return "bluetooth";
70         case CONNMAN_NETWORK_TYPE_HSO:
71                 return "cellular";
72         }
73
74         return NULL;
75 }
76
77 static DBusMessage *get_properties(DBusConnection *conn,
78                                         DBusMessage *msg, void *data)
79 {
80         struct connman_network *network = data;
81         DBusMessage *reply;
82         DBusMessageIter array, dict;
83
84         DBG("conn %p", conn);
85
86         reply = dbus_message_new_method_return(msg);
87         if (reply == NULL)
88                 return NULL;
89
90         dbus_message_iter_init_append(reply, &array);
91
92         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
93                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
94                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
95                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
96
97         if (network->device) {
98                 const char *path = connman_device_get_path(network->device);
99                 if (path != NULL)
100                         connman_dbus_dict_append_variant(&dict, "Device",
101                                                 DBUS_TYPE_OBJECT_PATH, &path);
102         }
103
104         if (network->name != NULL)
105                 connman_dbus_dict_append_variant(&dict, "Name",
106                                         DBUS_TYPE_STRING, &network->name);
107
108         connman_dbus_dict_append_variant(&dict, "Connected",
109                                 DBUS_TYPE_BOOLEAN, &network->connected);
110
111         connman_dbus_dict_append_variant(&dict, "Remember",
112                                 DBUS_TYPE_BOOLEAN, &network->remember);
113
114         if (network->strength > 0)
115                 connman_dbus_dict_append_variant(&dict, "Strength",
116                                         DBUS_TYPE_BYTE, &network->strength);
117
118         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
119                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
120                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
121                                                 network->wifi.ssid_len);
122
123         if (network->wifi.mode != NULL)
124                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
125                                 DBUS_TYPE_STRING, &network->wifi.mode);
126
127         if (network->wifi.security != NULL)
128                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
129                                 DBUS_TYPE_STRING, &network->wifi.security);
130
131         if (network->wifi.passphrase != NULL)
132                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
133                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
134
135         dbus_message_iter_close_container(&array, &dict);
136
137         return reply;
138 }
139
140 static DBusMessage *set_property(DBusConnection *conn,
141                                         DBusMessage *msg, void *data)
142 {
143         struct connman_network *network = data;
144         DBusMessageIter iter, value;
145         const char *name;
146
147         DBG("conn %p", conn);
148
149         if (dbus_message_iter_init(msg, &iter) == FALSE)
150                 return __connman_error_invalid_arguments(msg);
151
152         dbus_message_iter_get_basic(&iter, &name);
153         dbus_message_iter_next(&iter);
154         dbus_message_iter_recurse(&iter, &value);
155
156         if (__connman_security_check_privileges(msg) < 0)
157                 return __connman_error_permission_denied(msg);
158
159         if (g_str_equal(name, "Remember") == TRUE) {
160                 connman_bool_t remember;
161
162                 dbus_message_iter_get_basic(&value, &remember);
163
164                 if (network->remember == remember)
165                         return __connman_error_invalid_arguments(msg);
166         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
167                 const char *passphrase;
168
169                 dbus_message_iter_get_basic(&value, &passphrase);
170
171                 g_free(network->wifi.passphrase);
172                 network->wifi.passphrase = g_strdup(passphrase);
173         }
174
175         __connman_storage_save_network(network);
176
177         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
178 }
179
180 static DBusMessage *do_connect(DBusConnection *conn,
181                                         DBusMessage *msg, void *data)
182 {
183         struct connman_network *network = data;
184         int err;
185
186         DBG("conn %p", conn);
187
188         if (__connman_security_check_privileges(msg) < 0)
189                 return __connman_error_permission_denied(msg);
190
191         if (network->connected == TRUE)
192                 return __connman_error_failed(msg);
193
194         if (network->driver && network->driver->connect) {
195                 err = network->driver->connect(network);
196                 if (err < 0 && err != -EINPROGRESS)
197                         return __connman_error_failed(msg);
198         } else
199                 network->connected = TRUE;
200
201         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
202 }
203
204 static DBusMessage *do_disconnect(DBusConnection *conn,
205                                         DBusMessage *msg, void *data)
206 {
207         struct connman_network *network = data;
208         int err;
209
210         DBG("conn %p", conn);
211
212         if (__connman_security_check_privileges(msg) < 0)
213                 return __connman_error_permission_denied(msg);
214
215         if (network->connected == FALSE)
216                 return __connman_error_failed(msg);
217
218         connman_element_unregister_children(&network->element);
219
220         if (network->driver && network->driver->disconnect) {
221                 err = network->driver->disconnect(network);
222                 if (err < 0 && err != -EINPROGRESS)
223                         return __connman_error_failed(msg);
224         } else
225                 network->connected = FALSE;
226
227         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
228 }
229
230 static GDBusMethodTable network_methods[] = {
231         { "GetProperties", "",   "a{sv}", get_properties },
232         { "SetProperty",   "sv", "",      set_property   },
233         { "Connect",       "",   "",      do_connect     },
234         { "Disconnect",    "",   "",      do_disconnect  },
235         { },
236 };
237
238 static GDBusSignalTable network_signals[] = {
239         { "PropertyChanged", "sv" },
240         { },
241 };
242
243 static DBusConnection *connection;
244
245 static void append_networks(struct connman_device *device,
246                                                 DBusMessageIter *entry)
247 {
248         DBusMessageIter value, iter;
249         const char *key = "Networks";
250
251         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
252
253         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
254                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
255                                                                 &value);
256
257         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
258                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
259         __connman_element_list((struct connman_element *) device,
260                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
261         dbus_message_iter_close_container(&value, &iter);
262
263         dbus_message_iter_close_container(entry, &value);
264 }
265
266 static void emit_networks_signal(struct connman_device *device)
267 {
268         DBusMessage *signal;
269         DBusMessageIter entry;
270
271         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
272                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
273         if (signal == NULL)
274                 return;
275
276         dbus_message_iter_init_append(signal, &entry);
277
278         append_networks(device, &entry);
279
280         g_dbus_send_message(connection, signal);
281 }
282
283 static int register_interface(struct connman_element *element)
284 {
285         struct connman_network *network = element->network;
286
287         DBG("element %p name %s", element, element->name);
288
289         if (g_dbus_register_interface(connection, element->path,
290                                         CONNMAN_NETWORK_INTERFACE,
291                                         network_methods, network_signals,
292                                         NULL, network, NULL) == FALSE) {
293                 connman_error("Failed to register %s network", element->path);
294                 return -EIO;
295         }
296
297         network->registered = TRUE;
298
299         emit_networks_signal(network->device);
300
301         return 0;
302 }
303
304 static void unregister_interface(struct connman_element *element)
305 {
306         struct connman_network * network = element->network;
307
308         DBG("element %p name %s", element, element->name);
309
310         network->registered = FALSE;
311
312         emit_networks_signal(network->device);
313
314         g_dbus_unregister_interface(connection, element->path,
315                                                 CONNMAN_NETWORK_INTERFACE);
316 }
317
318 connman_bool_t __connman_network_has_driver(struct connman_network *network)
319 {
320         if (network == NULL || network->driver == NULL)
321                 return FALSE;
322
323         return network->registered;
324 }
325
326 static GSList *driver_list = NULL;
327
328 static gint compare_priority(gconstpointer a, gconstpointer b)
329 {
330         const struct connman_network_driver *driver1 = a;
331         const struct connman_network_driver *driver2 = b;
332
333         return driver2->priority - driver1->priority;
334 }
335
336 /**
337  * connman_network_driver_register:
338  * @driver: network driver definition
339  *
340  * Register a new network driver
341  *
342  * Returns: %0 on success
343  */
344 int connman_network_driver_register(struct connman_network_driver *driver)
345 {
346         DBG("driver %p name %s", driver, driver->name);
347
348         driver_list = g_slist_insert_sorted(driver_list, driver,
349                                                         compare_priority);
350
351         return 0;
352 }
353
354 /**
355  * connman_network_driver_unregister:
356  * @driver: network driver definition
357  *
358  * Remove a previously registered network driver
359  */
360 void connman_network_driver_unregister(struct connman_network_driver *driver)
361 {
362         DBG("driver %p name %s", driver, driver->name);
363
364         driver_list = g_slist_remove(driver_list, driver);
365 }
366
367 static void network_destruct(struct connman_element *element)
368 {
369         struct connman_network *network = element->network;
370
371         DBG("element %p name %s", element, element->name);
372
373         g_free(network->wifi.ssid);
374         g_free(network->wifi.mode);
375         g_free(network->wifi.security);
376         g_free(network->wifi.passphrase);
377
378         g_free(network->node);
379         g_free(network->name);
380         g_free(network->identifier);
381 }
382
383 /**
384  * connman_network_create:
385  * @identifier: network identifier (for example an unqiue name)
386  *
387  * Allocate a new network and assign the #identifier to it.
388  *
389  * Returns: a newly-allocated #connman_network structure
390  */
391 struct connman_network *connman_network_create(const char *identifier,
392                                                 enum connman_network_type type)
393 {
394         struct connman_network *network;
395         connman_uint8_t strength = 0;
396         const char *str;
397
398         DBG("identifier %s type %d", identifier, type);
399
400         network = g_try_new0(struct connman_network, 1);
401         if (network == NULL)
402                 return NULL;
403
404         DBG("network %p", network);
405
406         network->element.refcount = 1;
407
408         network->element.name = g_strdup(identifier);
409         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
410         network->element.index = -1;
411
412         network->element.network = network;
413         network->element.destruct = network_destruct;
414
415         str = type2string(type);
416         if (str != NULL)
417                 connman_element_add_static_property(&network->element,
418                                         "Type", DBUS_TYPE_STRING, &str);
419
420         connman_element_add_static_property(&network->element,
421                                         "Strength", DBUS_TYPE_BYTE, &strength);
422
423         network->type = type;
424         network->identifier = g_strdup(identifier);
425
426         return network;
427 }
428
429 /**
430  * connman_network_ref:
431  * @network: network structure
432  *
433  * Increase reference counter of  network
434  */
435 struct connman_network *connman_network_ref(struct connman_network *network)
436 {
437         if (connman_element_ref(&network->element) == NULL)
438                 return NULL;
439
440         return network;
441 }
442
443 /**
444  * connman_network_unref:
445  * @network: network structure
446  *
447  * Decrease reference counter of network
448  */
449 void connman_network_unref(struct connman_network *network)
450 {
451         connman_element_unref(&network->element);
452 }
453
454 /**
455  * connman_network_get_identifier:
456  * @network: network structure
457  *
458  * Get identifier of network
459  */
460 const char *connman_network_get_identifier(struct connman_network *network)
461 {
462         return network->identifier;
463 }
464
465 /**
466  * connman_network_get_path:
467  * @network: network structure
468  *
469  * Get path name of network
470  */
471 const char *connman_network_get_path(struct connman_network *network)
472 {
473         return network->element.path;
474 }
475
476 /**
477  * connman_network_set_index:
478  * @network: network structure
479  * @index: index number
480  *
481  * Set index number of network
482  */
483 void connman_network_set_index(struct connman_network *network, int index)
484 {
485         network->element.index = index;
486 }
487
488 /**
489  * connman_network_get_index:
490  * @network: network structure
491  *
492  * Get index number of network
493  */
494 int connman_network_get_index(struct connman_network *network)
495 {
496         return network->element.index;
497 }
498
499 /**
500  * connman_network_set_protocol:
501  * @network: network structure
502  * @protocol: network protocol
503  *
504  * Change protocol of network
505  */
506 void connman_network_set_protocol(struct connman_network *network,
507                                         enum connman_network_protocol protocol)
508 {
509         network->protocol = protocol;
510 }
511
512 /**
513  * connman_network_set_connected:
514  * @network: network structure
515  * @connected: connected state
516  *
517  * Change connected state of network
518  */
519 int connman_network_set_connected(struct connman_network *network,
520                                                 connman_bool_t connected)
521 {
522         DBG("network %p connected %d", network, connected);
523
524         if (network->connected == connected)
525                 return -EALREADY;
526
527         network->connected = connected;
528
529         if (connected == TRUE) {
530                 struct connman_element *element;
531                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
532
533                 switch (network->protocol) {
534                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
535                         return 0;
536                 case CONNMAN_NETWORK_PROTOCOL_IP:
537                         type = CONNMAN_ELEMENT_TYPE_DHCP;
538                         break;
539                 case CONNMAN_NETWORK_PROTOCOL_PPP:
540                         type = CONNMAN_ELEMENT_TYPE_PPP;
541                         break;
542                 }
543
544                 __connman_device_increase_connections(network->device);
545
546                 element = connman_element_create(NULL);
547                 if (element != NULL) {
548                         element->type  = type;
549                         element->index = network->element.index;
550
551                         if (connman_element_register(element,
552                                                 &network->element) < 0)
553                                 connman_element_unref(element);
554                 }
555         } else {
556                 connman_element_unregister_children(&network->element);
557
558                 __connman_device_decrease_connections(network->device);
559         }
560
561         return 0;
562 }
563
564 /**
565  * connman_network_get_remember:
566  * @network: network structure
567  *
568  * Get network remember setting
569  */
570 connman_bool_t connman_network_get_remember(struct connman_network *network)
571 {
572         return network->remember;
573 }
574
575 /**
576  * connman_network_connect:
577  * @network: network structure
578  *
579  * Connect network
580  */
581 int connman_network_connect(struct connman_network *network)
582 {
583         if (network->connected == TRUE)
584                 return -EALREADY;
585
586         if (network->driver && network->driver->connect)
587                 return network->driver->connect(network);
588
589         network->connected = TRUE;
590
591         return 0;
592 }
593
594 /**
595  * connman_network_set_string:
596  * @network: network structure
597  * @key: unique identifier
598  * @value: string value
599  *
600  * Set string value for specific key
601  */
602 int connman_network_set_string(struct connman_network *network,
603                                         const char *key, const char *value)
604 {
605         DBG("network %p key %s value %s", network, key, value);
606
607         if (g_str_equal(key, "Name") == TRUE) {
608                 g_free(network->name);
609                 network->name = g_strdup(value);
610         } else if (g_str_equal(key, "Node") == TRUE) {
611                 g_free(network->node);
612                 network->node = g_strdup(value);
613         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
614                 g_free(network->wifi.mode);
615                 network->wifi.mode = g_strdup(value);
616         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
617                 g_free(network->wifi.security);
618                 network->wifi.security = g_strdup(value);
619         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
620                 g_free(network->wifi.passphrase);
621                 network->wifi.passphrase = g_strdup(value);
622         }
623
624         return 0;
625 }
626
627 /**
628  * connman_network_get_string:
629  * @network: network structure
630  * @key: unique identifier
631  *
632  * Get string value for specific key
633  */
634 const char *connman_network_get_string(struct connman_network *network,
635                                                         const char *key)
636 {
637         DBG("network %p key %s", network, key);
638
639         if (g_str_equal(key, "Name") == TRUE)
640                 return network->name;
641         else if (g_str_equal(key, "Node") == TRUE)
642                 return network->node;
643         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
644                 return network->wifi.mode;
645         else if (g_str_equal(key, "WiFi.Security") == TRUE)
646                 return network->wifi.security;
647         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
648                 return network->wifi.passphrase;
649
650         return NULL;
651 }
652
653 /**
654  * connman_network_set_uint8:
655  * @network: network structure
656  * @key: unique identifier
657  * @value: integer value
658  *
659  * Set integer value for specific key
660  */
661 int connman_network_set_uint8(struct connman_network *network,
662                                         const char *key, connman_uint8_t value)
663 {
664         DBG("network %p key %s value %d", network, key, value);
665
666         if (g_str_equal(key, "Strength") == TRUE) {
667                 network->strength = value;
668                 connman_element_set_static_property(&network->element,
669                                         "Strength", DBUS_TYPE_BYTE, &value);
670         }
671
672         return 0;
673 }
674
675 /**
676  * connman_network_set_blob:
677  * @network: network structure
678  * @key: unique identifier
679  * @data: blob data
680  * @size: blob size
681  *
682  * Set binary blob value for specific key
683  */
684 int connman_network_set_blob(struct connman_network *network,
685                         const char *key, const void *data, unsigned int size)
686 {
687         DBG("network %p key %s size %d", network, key, size);
688
689         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
690                 g_free(network->wifi.ssid);
691                 network->wifi.ssid = g_try_malloc(size);
692                 if (network->wifi.ssid != NULL) {
693                         memcpy(network->wifi.ssid, data, size);
694                         network->wifi.ssid_len = size;
695                 } else
696                         network->wifi.ssid_len = 0;
697         }
698
699         return 0;
700 }
701
702 /**
703  * connman_network_get_blob:
704  * @network: network structure
705  * @key: unique identifier
706  * @size: pointer to blob size
707  *
708  * Get binary blob value for specific key
709  */
710 const void *connman_network_get_blob(struct connman_network *network,
711                                         const char *key, unsigned int *size)
712 {
713         DBG("network %p key %s", network, key);
714
715         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
716                 if (size != NULL)
717                         *size = network->wifi.ssid_len;
718                 return network->wifi.ssid;
719         }
720
721         return NULL;
722 }
723
724 void __connman_network_set_device(struct connman_network *network,
725                                         struct connman_device *device)
726 {
727         network->device = device;
728 }
729
730 /**
731  * connman_network_get_device:
732  * @network: network structure
733  *
734  * Get parent device of network
735  */
736 struct connman_device *connman_network_get_device(struct connman_network *network)
737 {
738         return network->device;
739 }
740
741 /**
742  * connman_network_get_data:
743  * @network: network structure
744  *
745  * Get private network data pointer
746  */
747 void *connman_network_get_data(struct connman_network *network)
748 {
749         return network->driver_data;
750 }
751
752 /**
753  * connman_network_set_data:
754  * @network: network structure
755  * @data: data pointer
756  *
757  * Set private network data pointer
758  */
759 void connman_network_set_data(struct connman_network *network, void *data)
760 {
761         network->driver_data = data;
762 }
763
764 static gboolean match_driver(struct connman_network *network,
765                                         struct connman_network_driver *driver)
766 {
767         if (network->type == driver->type ||
768                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
769                 return TRUE;
770
771         return FALSE;
772 }
773
774 static int network_probe(struct connman_element *element)
775 {
776         struct connman_network *network = element->network;
777         GSList *list;
778         int err;
779
780         DBG("element %p name %s", element, element->name);
781
782         if (network == NULL)
783                 return -ENODEV;
784
785         for (list = driver_list; list; list = list->next) {
786                 struct connman_network_driver *driver = list->data;
787
788                 if (match_driver(network, driver) == FALSE)
789                         continue;
790
791                 DBG("driver %p name %s", driver, driver->name);
792
793                 if (driver->probe(network) == 0) {
794                         network->driver = driver;
795                         break;
796                 }
797         }
798
799         if (network->driver == NULL)
800                 return -ENODEV;
801
802         err = register_interface(element);
803         if (err < 0) {
804                 if (network->driver->remove)
805                         network->driver->remove(network);
806                 return err;
807         }
808
809         return 0;
810 }
811
812 static void network_remove(struct connman_element *element)
813 {
814         struct connman_network *network = element->network;
815
816         DBG("element %p name %s", element, element->name);
817
818         if (network == NULL)
819                 return;
820
821         if (network->driver == NULL)
822                 return;
823
824         unregister_interface(element);
825
826         if (network->driver->remove)
827                 network->driver->remove(network);
828 }
829
830 static struct connman_driver network_driver = {
831         .name           = "network",
832         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
833         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
834         .probe          = network_probe,
835         .remove         = network_remove,
836 };
837
838 static int network_load(struct connman_network *network)
839 {
840         GKeyFile *keyfile;
841         gchar *pathname, *data = NULL;
842         gsize length;
843         const char *name;
844
845         DBG("network %p", network);
846
847         name = connman_device_get_name(network->device);
848         if (name == NULL)
849                 return -EINVAL;
850
851         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
852         if (pathname == NULL)
853                 return -ENOMEM;
854
855         keyfile = g_key_file_new();
856
857         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
858                 g_free(pathname);
859                 return -ENOENT;
860         }
861
862         g_free(pathname);
863
864         if (g_key_file_load_from_data(keyfile, data, length,
865                                                         0, NULL) == FALSE) {
866                 g_free(data);
867                 return -EILSEQ;
868         }
869
870         g_free(data);
871
872         network->remember = g_key_file_get_boolean(keyfile,
873                                         network->identifier, "Remember", NULL);
874
875         g_free(network->wifi.security);
876         network->wifi.security = g_key_file_get_string(keyfile,
877                                 network->identifier, "WiFi.Security", NULL);
878
879         g_free(network->wifi.passphrase);
880         network->wifi.passphrase = g_key_file_get_string(keyfile,
881                                 network->identifier, "WiFi.Passphrase", NULL);
882
883         g_key_file_free(keyfile);
884
885         return 0;
886 }
887
888 static int network_save(struct connman_network *network)
889 {
890         GKeyFile *keyfile;
891         gchar *pathname, *data = NULL;
892         gsize length;
893         const char *name;
894
895         DBG("network %p", network);
896
897         name = connman_device_get_name(network->device);
898         if (name == NULL)
899                 return -EINVAL;
900
901         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
902         if (pathname == NULL)
903                 return -ENOMEM;
904
905         keyfile = g_key_file_new();
906
907         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
908                 goto update;
909
910         if (length > 0) {
911                 if (g_key_file_load_from_data(keyfile, data, length,
912                                                         0, NULL) == FALSE)
913                         goto done;
914         }
915
916         g_free(data);
917
918 update:
919         g_key_file_set_boolean(keyfile, network->identifier,
920                                         "Remember", network->remember);
921
922         if (network->wifi.security != NULL)
923                 g_key_file_set_string(keyfile, network->identifier,
924                                 "WiFi.Security", network->wifi.security);
925
926         if (network->wifi.passphrase != NULL)
927                 g_key_file_set_string(keyfile, network->identifier,
928                                 "WiFi.Passphrase", network->wifi.passphrase);
929
930         data = g_key_file_to_data(keyfile, &length, NULL);
931
932         g_file_set_contents(pathname, data, length, NULL);
933
934 done:
935         g_free(data);
936
937         g_key_file_free(keyfile);
938
939         g_free(pathname);
940
941         return 0;
942 }
943
944 static struct connman_storage network_storage = {
945         .name           = "network",
946         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
947         .network_load   = network_load,
948         .network_save   = network_save,
949 };
950
951 int __connman_network_init(void)
952 {
953         DBG("");
954
955         connection = connman_dbus_get_connection();
956
957         if (connman_storage_register(&network_storage) < 0)
958                 connman_error("Failed to register network storage");
959
960         return connman_driver_register(&network_driver);
961 }
962
963 void __connman_network_cleanup(void)
964 {
965         DBG("");
966
967         connman_driver_unregister(&network_driver);
968
969         connman_storage_unregister(&network_storage);
970
971         dbus_connection_unref(connection);
972 }