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