inotify: Move inotify code into its own file
[platform/upstream/connman.git] / src / config.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-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 <errno.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <sys/vfs.h>
31 #include <sys/inotify.h>
32 #include <glib.h>
33
34 #include <connman/provision.h>
35 #include "connman.h"
36
37 struct connman_config_service {
38         char *ident;
39         char *name;
40         char *type;
41         void *ssid;
42         unsigned int ssid_len;
43         char *eap;
44         char *identity;
45         char *ca_cert_file;
46         char *client_cert_file;
47         char *private_key_file;
48         char *private_key_passphrase;
49         char *private_key_passphrase_type;
50         char *phase2;
51         char *passphrase;
52         GSList *service_identifiers;
53         char *config_ident; /* file prefix */
54         char *config_entry; /* entry name */
55         connman_bool_t hidden;
56 };
57
58 struct connman_config {
59         char *ident;
60         char *name;
61         char *description;
62         connman_bool_t protected;
63         GHashTable *service_table;
64 };
65
66 static GHashTable *config_table = NULL;
67 static GSList *protected_services = NULL;
68
69 static connman_bool_t cleanup = FALSE;
70
71 #define INTERNAL_CONFIG_PREFIX           "__internal"
72
73 /* Definition of possible strings in the .config files */
74 #define CONFIG_KEY_NAME                "Name"
75 #define CONFIG_KEY_DESC                "Description"
76 #define CONFIG_KEY_PROT                "Protected"
77
78 #define SERVICE_KEY_TYPE               "Type"
79 #define SERVICE_KEY_NAME               "Name"
80 #define SERVICE_KEY_SSID               "SSID"
81 #define SERVICE_KEY_EAP                "EAP"
82 #define SERVICE_KEY_CA_CERT            "CACertFile"
83 #define SERVICE_KEY_CL_CERT            "ClientCertFile"
84 #define SERVICE_KEY_PRV_KEY            "PrivateKeyFile"
85 #define SERVICE_KEY_PRV_KEY_PASS       "PrivateKeyPassphrase"
86 #define SERVICE_KEY_PRV_KEY_PASS_TYPE  "PrivateKeyPassphraseType"
87 #define SERVICE_KEY_IDENTITY           "Identity"
88 #define SERVICE_KEY_PHASE2             "Phase2"
89 #define SERVICE_KEY_PASSPHRASE         "Passphrase"
90 #define SERVICE_KEY_HIDDEN             "Hidden"
91
92 static const char *config_possible_keys[] = {
93         CONFIG_KEY_NAME,
94         CONFIG_KEY_DESC,
95         CONFIG_KEY_PROT,
96         NULL,
97 };
98
99 static const char *service_possible_keys[] = {
100         SERVICE_KEY_TYPE,
101         SERVICE_KEY_NAME,
102         SERVICE_KEY_SSID,
103         SERVICE_KEY_EAP,
104         SERVICE_KEY_CA_CERT,
105         SERVICE_KEY_CL_CERT,
106         SERVICE_KEY_PRV_KEY,
107         SERVICE_KEY_PRV_KEY_PASS,
108         SERVICE_KEY_PRV_KEY_PASS_TYPE,
109         SERVICE_KEY_IDENTITY,
110         SERVICE_KEY_PHASE2,
111         SERVICE_KEY_PASSPHRASE,
112         SERVICE_KEY_HIDDEN,
113         NULL,
114 };
115
116 static void unregister_config(gpointer data)
117 {
118         struct connman_config *config = data;
119
120         connman_info("Removing configuration %s", config->ident);
121
122         g_hash_table_destroy(config->service_table);
123
124         g_free(config->description);
125         g_free(config->name);
126         g_free(config->ident);
127         g_free(config);
128 }
129
130 static void unregister_service(gpointer data)
131 {
132         struct connman_config_service *config_service = data;
133         struct connman_service *service;
134         char *service_id;
135         GSList *list;
136
137         if (cleanup == TRUE)
138                 goto free_only;
139
140         connman_info("Removing service configuration %s",
141                                                 config_service->ident);
142
143         protected_services = g_slist_remove(protected_services,
144                                                 config_service);
145
146         for (list = config_service->service_identifiers; list != NULL;
147                                                         list = list->next) {
148                 service_id = list->data;
149
150                 service = __connman_service_lookup_from_ident(service_id);
151                 if (service != NULL) {
152                         __connman_service_set_immutable(service, FALSE);
153                         __connman_service_remove(service);
154                 }
155
156                 if (__connman_storage_remove_service(service_id) == FALSE)
157                         DBG("Could not remove all files for service %s",
158                                                                 service_id);
159         }
160
161 free_only:
162         g_free(config_service->ident);
163         g_free(config_service->type);
164         g_free(config_service->name);
165         g_free(config_service->ssid);
166         g_free(config_service->eap);
167         g_free(config_service->identity);
168         g_free(config_service->ca_cert_file);
169         g_free(config_service->client_cert_file);
170         g_free(config_service->private_key_file);
171         g_free(config_service->private_key_passphrase);
172         g_free(config_service->private_key_passphrase_type);
173         g_free(config_service->phase2);
174         g_free(config_service->passphrase);
175         g_slist_free_full(config_service->service_identifiers, g_free);
176         g_free(config_service->config_ident);
177         g_free(config_service->config_entry);
178         g_free(config_service);
179 }
180
181 static void check_keys(GKeyFile *keyfile, const char *group,
182                         const char **possible_keys)
183 {
184         char **avail_keys;
185         gsize nb_avail_keys, i, j;
186
187         avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
188         if (avail_keys == NULL)
189                 return;
190
191         /*
192          * For each key in the configuration file,
193          * verify it is understood by connman
194          */
195         for (i = 0 ; i < nb_avail_keys; i++) {
196                 for (j = 0; possible_keys[j] ; j++)
197                         if (g_strcmp0(avail_keys[i], possible_keys[j]) == 0)
198                                 break;
199
200                 if (possible_keys[j] == NULL)
201                         connman_warn("Unknown configuration key %s in [%s]",
202                                         avail_keys[i], group);
203         }
204
205         g_strfreev(avail_keys);
206 }
207
208 static connman_bool_t
209 is_protected_service(struct connman_config_service *service)
210 {
211         GSList *list;
212
213         DBG("ident %s", service->ident);
214
215         for (list = protected_services; list; list = list->next) {
216                 struct connman_config_service *s = list->data;
217
218                 if (g_strcmp0(s->type, service->type) != 0)
219                         continue;
220
221                 if (s->ssid == NULL || service->ssid == NULL)
222                         continue;
223
224                 if (s->ssid_len != service->ssid_len)
225                         continue;
226
227                 if (g_strcmp0(service->type, "wifi") == 0 &&
228                         strncmp(s->ssid, service->ssid, s->ssid_len) == 0) {
229                         return TRUE;
230                 }
231         }
232
233         return FALSE;
234 }
235
236 static int load_service(GKeyFile *keyfile, const char *group,
237                                                 struct connman_config *config)
238 {
239         struct connman_config_service *service;
240         const char *ident;
241         char *str, *hex_ssid;
242         gboolean service_created = FALSE;
243         int err;
244
245         /* Strip off "service_" prefix */
246         ident = group + 8;
247
248         if (strlen(ident) < 1)
249                 return -EINVAL;
250
251         /* Verify that provided keys are good */
252         check_keys(keyfile, group, service_possible_keys);
253
254         service = g_hash_table_lookup(config->service_table, ident);
255         if (service == NULL) {
256                 service = g_try_new0(struct connman_config_service, 1);
257                 if (service == NULL)
258                         return -ENOMEM;
259
260                 service->ident = g_strdup(ident);
261
262                 service_created = TRUE;
263         }
264
265         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_TYPE, NULL);
266         if (str != NULL) {
267                 g_free(service->type);
268                 service->type = str;
269         }
270
271         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_NAME, NULL);
272         if (str != NULL) {
273                 g_free(service->name);
274                 service->name = str;
275         }
276
277         hex_ssid = g_key_file_get_string(keyfile, group, SERVICE_KEY_SSID,
278                                          NULL);
279         if (hex_ssid != NULL) {
280                 char *ssid;
281                 unsigned int i, j = 0, hex;
282                 size_t hex_ssid_len = strlen(hex_ssid);
283
284                 ssid = g_try_malloc0(hex_ssid_len / 2);
285                 if (ssid == NULL) {
286                         err = -ENOMEM;
287                         g_free(hex_ssid);
288                         goto err;
289                 }
290
291                 for (i = 0; i < hex_ssid_len; i += 2) {
292                         if (sscanf(hex_ssid + i, "%02x", &hex) <= 0) {
293                                 connman_warn("Invalid SSID %s", hex_ssid);
294                                 g_free(ssid);
295                                 g_free(hex_ssid);
296                                 err = -EILSEQ;
297                                 goto err;
298                         }
299                         ssid[j++] = hex;
300                 }
301
302                 g_free(hex_ssid);
303
304                 g_free(service->ssid);
305                 service->ssid = ssid;
306                 service->ssid_len = hex_ssid_len / 2;
307         } else if (service->name != NULL) {
308                 char *ssid;
309                 unsigned int ssid_len;
310
311                 ssid_len = strlen(service->name);
312                 ssid = g_try_malloc0(ssid_len);
313                 if (ssid == NULL) {
314                         err = -ENOMEM;
315                         goto err;
316                 }
317
318                 memcpy(ssid, service->name, ssid_len);
319                 g_free(service->ssid);
320                 service->ssid = ssid;
321                 service->ssid_len = ssid_len;
322         }
323
324         if (is_protected_service(service) == TRUE) {
325                 connman_error("Trying to provision a protected service");
326                 err = -EACCES;
327                 goto err;
328         }
329
330         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_EAP, NULL);
331         if (str != NULL) {
332                 g_free(service->eap);
333                 service->eap = str;
334         }
335
336         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_CA_CERT, NULL);
337         if (str != NULL) {
338                 g_free(service->ca_cert_file);
339                 service->ca_cert_file = str;
340         }
341
342         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_CL_CERT, NULL);
343         if (str != NULL) {
344                 g_free(service->client_cert_file);
345                 service->client_cert_file = str;
346         }
347
348         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PRV_KEY, NULL);
349         if (str != NULL) {
350                 g_free(service->private_key_file);
351                 service->private_key_file = str;
352         }
353
354         str = g_key_file_get_string(keyfile, group,
355                                                 SERVICE_KEY_PRV_KEY_PASS, NULL);
356         if (str != NULL) {
357                 g_free(service->private_key_passphrase);
358                 service->private_key_passphrase = str;
359         }
360
361         str = g_key_file_get_string(keyfile, group,
362                                         SERVICE_KEY_PRV_KEY_PASS_TYPE, NULL);
363         if (str != NULL) {
364                 g_free(service->private_key_passphrase_type);
365                 service->private_key_passphrase_type = str;
366         }
367
368         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_IDENTITY, NULL);
369         if (str != NULL) {
370                 g_free(service->identity);
371                 service->identity = str;
372         }
373
374         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PHASE2, NULL);
375         if (str != NULL) {
376                 g_free(service->phase2);
377                 service->phase2 = str;
378         }
379
380         str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PASSPHRASE,
381                                         NULL);
382         if (str != NULL) {
383                 g_free(service->passphrase);
384                 service->passphrase = str;
385         }
386
387         service->config_ident = g_strdup(config->ident);
388         service->config_entry = g_strdup_printf("service_%s", service->ident);
389
390         service->hidden = g_key_file_get_boolean(keyfile, group,
391                                                 SERVICE_KEY_HIDDEN, NULL);
392
393         if (service_created)
394                 g_hash_table_insert(config->service_table, service->ident,
395                                         service);
396
397         if (config->protected == TRUE)
398                 protected_services =
399                         g_slist_prepend(protected_services, service);
400
401         connman_info("Adding service configuration %s", service->ident);
402
403         return 0;
404
405 err:
406         if (service_created == TRUE) {
407                 g_free(service->ident);
408                 g_free(service->type);
409                 g_free(service->name);
410                 g_free(service->ssid);
411                 g_free(service);
412         }
413
414         return err;
415 }
416
417 static int load_config(struct connman_config *config)
418 {
419         GKeyFile *keyfile;
420         GError *error = NULL;
421         gsize length;
422         char **groups;
423         char *str;
424         gboolean protected, found = FALSE;
425         int i;
426
427         DBG("config %p", config);
428
429         keyfile = __connman_storage_load_config(config->ident);
430         if (keyfile == NULL)
431                 return -EIO;
432
433         /* Verify keys validity of the global section */
434         check_keys(keyfile, "global", config_possible_keys);
435
436         str = g_key_file_get_string(keyfile, "global", CONFIG_KEY_NAME, NULL);
437         if (str != NULL) {
438                 g_free(config->name);
439                 config->name = str;
440         }
441
442         str = g_key_file_get_string(keyfile, "global", CONFIG_KEY_DESC, NULL);
443         if (str != NULL) {
444                 g_free(config->description);
445                 config->description = str;
446         }
447
448         protected = g_key_file_get_boolean(keyfile, "global",
449                                         CONFIG_KEY_PROT, &error);
450         if (error == NULL)
451                 config->protected = protected;
452         else
453                 config->protected = TRUE;
454         g_clear_error(&error);
455
456         groups = g_key_file_get_groups(keyfile, &length);
457
458         for (i = 0; groups[i] != NULL; i++) {
459                 if (g_str_has_prefix(groups[i], "service_") == TRUE) {
460                         if (load_service(keyfile, groups[i], config) == 0)
461                                 found = TRUE;
462                 }
463         }
464
465         if (found == FALSE)
466                 connman_warn("Config file %s/%s.config does not contain any "
467                         "configuration that can be provisioned!",
468                         STORAGEDIR, config->ident);
469
470         g_strfreev(groups);
471
472         g_key_file_free(keyfile);
473
474         return 0;
475 }
476
477 static struct connman_config *create_config(const char *ident)
478 {
479         struct connman_config *config;
480
481         DBG("ident %s", ident);
482
483         if (g_hash_table_lookup(config_table, ident) != NULL)
484                 return NULL;
485
486         config = g_try_new0(struct connman_config, 1);
487         if (config == NULL)
488                 return NULL;
489
490         config->ident = g_strdup(ident);
491
492         config->service_table = g_hash_table_new_full(g_str_hash, g_str_equal,
493                                                 NULL, unregister_service);
494
495         g_hash_table_insert(config_table, config->ident, config);
496
497         connman_info("Adding configuration %s", config->ident);
498
499         return config;
500 }
501
502 static connman_bool_t validate_ident(const char *ident)
503 {
504         unsigned int i;
505
506         if (ident == NULL)
507                 return FALSE;
508
509         for (i = 0; i < strlen(ident); i++)
510                 if (g_ascii_isprint(ident[i]) == FALSE)
511                         return FALSE;
512
513         return TRUE;
514 }
515
516 static int read_configs(void)
517 {
518         GDir *dir;
519
520         DBG("");
521
522         dir = g_dir_open(STORAGEDIR, 0, NULL);
523         if (dir != NULL) {
524                 const gchar *file;
525
526                 while ((file = g_dir_read_name(dir)) != NULL) {
527                         GString *str;
528                         gchar *ident;
529
530                         if (g_str_has_suffix(file, ".config") == FALSE)
531                                 continue;
532
533                         ident = g_strrstr(file, ".config");
534                         if (ident == NULL)
535                                 continue;
536
537                         str = g_string_new_len(file, ident - file);
538                         if (str == NULL)
539                                 continue;
540
541                         ident = g_string_free(str, FALSE);
542
543                         if (validate_ident(ident) == TRUE) {
544                                 struct connman_config *config;
545
546                                 config = create_config(ident);
547                                 if (config != NULL)
548                                         load_config(config);
549                         } else {
550                                 connman_error("Invalid config ident %s", ident);
551                         }
552                         g_free(ident);
553                 }
554
555                 g_dir_close(dir);
556         }
557
558         return 0;
559 }
560
561 static void config_notify_handler(struct inotify_event *event,
562                                         const char *ident)
563 {
564         char *ext;
565
566         if (ident == NULL)
567                 return;
568
569         if (g_str_has_suffix(ident, ".config") == FALSE)
570                 return;
571
572         ext = g_strrstr(ident, ".config");
573         if (ext == NULL)
574                 return;
575
576         *ext = '\0';
577
578         if (validate_ident(ident) == FALSE) {
579                 connman_error("Invalid config ident %s", ident);
580                 return;
581         }
582
583         if (event->mask & IN_CREATE)
584                 create_config(ident);
585
586         if (event->mask & IN_MODIFY) {
587                 struct connman_config *config;
588
589                 config = g_hash_table_lookup(config_table, ident);
590                 if (config != NULL) {
591                         int ret;
592
593                         g_hash_table_remove_all(config->service_table);
594                         load_config(config);
595                         ret = __connman_service_provision_changed(ident);
596                         if (ret > 0) {
597                                 /*
598                                  * Re-scan the config file for any
599                                  * changes
600                                  */
601                                 g_hash_table_remove_all(config->service_table);
602                                 load_config(config);
603                                 __connman_service_provision_changed(ident);
604                         }
605                 }
606         }
607
608         if (event->mask & IN_DELETE)
609                 g_hash_table_remove(config_table, ident);
610 }
611
612 int __connman_config_init(void)
613 {
614         DBG("");
615
616         config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
617                                                 NULL, unregister_config);
618
619         connman_inotify_register(STORAGEDIR, config_notify_handler);
620
621         return read_configs();
622 }
623
624 void __connman_config_cleanup(void)
625 {
626         DBG("");
627
628         cleanup = TRUE;
629
630         connman_inotify_unregister(STORAGEDIR, config_notify_handler);
631
632         g_hash_table_destroy(config_table);
633         config_table = NULL;
634
635         cleanup = FALSE;
636 }
637
638 static char *config_pem_fsid(const char *pem_file)
639 {
640         struct statfs buf;
641         unsigned *fsid = (unsigned *) &buf.f_fsid;
642         unsigned long long fsid64;
643
644         if (pem_file == NULL)
645                 return NULL;
646
647         if (statfs(pem_file, &buf) < 0) {
648                 connman_error("statfs error %s for %s",
649                                                 strerror(errno), pem_file);
650                 return NULL;
651         }
652
653         fsid64 = ((unsigned long long) fsid[0] << 32) | fsid[1];
654
655         return g_strdup_printf("%llx", fsid64);
656 }
657
658 static void provision_service(gpointer key, gpointer value, gpointer user_data)
659 {
660         struct connman_service *service = user_data;
661         struct connman_config_service *config = value;
662         struct connman_network *network;
663         const void *ssid, *service_id;
664         unsigned int ssid_len;
665
666         /* For now only WiFi service entries are supported */
667         if (g_strcmp0(config->type, "wifi") != 0)
668                 return;
669
670         network = __connman_service_get_network(service);
671         if (network == NULL) {
672                 connman_error("Service has no network set");
673                 return;
674         }
675
676         ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
677         if (ssid == NULL) {
678                 connman_error("Network SSID not set");
679                 return;
680         }
681
682         if (config->ssid == NULL || ssid_len != config->ssid_len)
683                 return;
684
685         if (memcmp(config->ssid, ssid, ssid_len) != 0)
686                 return;
687
688         service_id = __connman_service_get_ident(service);
689         config->service_identifiers =
690                 g_slist_prepend(config->service_identifiers,
691                                 g_strdup(service_id));
692
693         __connman_service_set_immutable(service, TRUE);
694
695         __connman_service_set_favorite_delayed(service, TRUE, TRUE);
696
697         __connman_service_set_config(service, config->config_ident,
698                                                 config->config_entry);
699
700         if (config->eap != NULL)
701                 __connman_service_set_string(service, "EAP", config->eap);
702
703         if (config->identity != NULL)
704                 __connman_service_set_string(service, "Identity",
705                                                         config->identity);
706
707         if (config->ca_cert_file != NULL)
708                 __connman_service_set_string(service, "CACertFile",
709                                                         config->ca_cert_file);
710
711         if (config->client_cert_file != NULL)
712                 __connman_service_set_string(service, "ClientCertFile",
713                                                 config->client_cert_file);
714
715         if (config->private_key_file != NULL)
716                 __connman_service_set_string(service, "PrivateKeyFile",
717                                                 config->private_key_file);
718
719         if (g_strcmp0(config->private_key_passphrase_type, "fsid") == 0 &&
720                                         config->private_key_file != NULL) {
721                 char *fsid;
722
723                 fsid = config_pem_fsid(config->private_key_file);
724                 if (fsid == NULL)
725                         return;
726
727                 g_free(config->private_key_passphrase);
728                 config->private_key_passphrase = fsid;
729         }
730
731         if (config->private_key_passphrase != NULL) {
732                 __connman_service_set_string(service, "PrivateKeyPassphrase",
733                                                 config->private_key_passphrase);
734                 /*
735                  * TODO: Support for PEAP with both identity and key passwd.
736                  * In that case, we should check if both of them are found
737                  * from the config file. If not, we should not set the
738                  * service passphrase in order for the UI to request for an
739                  * additional passphrase.
740                  */
741         }
742
743         if (config->phase2 != NULL)
744                 __connman_service_set_string(service, "Phase2", config->phase2);
745
746         if (config->passphrase != NULL)
747                 __connman_service_set_string(service, "Passphrase", config->passphrase);
748
749         if (config->hidden == TRUE)
750                 __connman_service_set_hidden(service);
751
752         __connman_service_mark_dirty();
753
754         __connman_service_save(service);
755 }
756
757 int __connman_config_provision_service(struct connman_service *service)
758 {
759         enum connman_service_type type;
760         GHashTableIter iter;
761         gpointer value, key;
762
763         DBG("service %p", service);
764
765         /* For now only WiFi services are supported */
766         type = connman_service_get_type(service);
767         if (type != CONNMAN_SERVICE_TYPE_WIFI)
768                 return -ENOSYS;
769
770         g_hash_table_iter_init(&iter, config_table);
771
772         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
773                 struct connman_config *config = value;
774
775                 g_hash_table_foreach(config->service_table,
776                                                 provision_service, service);
777         }
778
779         return 0;
780 }
781
782 int __connman_config_provision_service_ident(struct connman_service *service,
783                         const char *ident, const char *file, const char *entry)
784 {
785         enum connman_service_type type;
786         struct connman_config *config;
787         int ret = 0;
788
789         DBG("service %p", service);
790
791         /* For now only WiFi services are supported */
792         type = connman_service_get_type(service);
793         if (type != CONNMAN_SERVICE_TYPE_WIFI)
794                 return -ENOSYS;
795
796         config = g_hash_table_lookup(config_table, ident);
797         if (config != NULL) {
798                 GHashTableIter iter;
799                 gpointer value, key;
800                 gboolean found = FALSE;
801
802                 g_hash_table_iter_init(&iter, config->service_table);
803
804                 /*
805                  * Check if we need to remove individual service if it
806                  * is missing from config file.
807                  */
808                 if (file != NULL && entry != NULL) {
809                         while (g_hash_table_iter_next(&iter, &key,
810                                                         &value) == TRUE) {
811                                 struct connman_config_service *config_service;
812
813                                 config_service = value;
814
815                                 if (g_strcmp0(config_service->config_ident,
816                                                                 file) != 0)
817                                         continue;
818
819                                 if (g_strcmp0(config_service->config_entry,
820                                                                 entry) != 0)
821                                         continue;
822
823                                 found = TRUE;
824                                 break;
825                         }
826
827                         DBG("found %d ident %s file %s entry %s", found, ident,
828                                                                 file, entry);
829
830                         if (found == FALSE) {
831                                 /*
832                                  * The entry+8 will skip "service_" prefix
833                                  */
834                                 g_hash_table_remove(config->service_table,
835                                                 entry + 8);
836                                 ret = 1;
837                         }
838                 }
839
840                 g_hash_table_foreach(config->service_table,
841                                                 provision_service, service);
842         }
843
844         return ret;
845 }
846
847 struct connman_config_entry **connman_config_get_entries(void)
848 {
849         GHashTableIter iter_file, iter_config;
850         gpointer value, key;
851         struct connman_config_entry **entries = NULL;
852         int i = 0, count;
853
854         g_hash_table_iter_init(&iter_file, config_table);
855         while (g_hash_table_iter_next(&iter_file, &key, &value) == TRUE) {
856                 struct connman_config *config_file = value;
857
858                 count = g_hash_table_size(config_file->service_table);
859
860                 entries = g_try_realloc(entries, (i + count + 1) *
861                                         sizeof(struct connman_config_entry *));
862                 if (entries == NULL)
863                         return NULL;
864
865                 g_hash_table_iter_init(&iter_config,
866                                                 config_file->service_table);
867                 while (g_hash_table_iter_next(&iter_config, &key,
868                                                         &value) == TRUE) {
869                         struct connman_config_service *config = value;
870
871                         entries[i] = g_try_new0(struct connman_config_entry,
872                                                 1);
873                         if (entries[i] == NULL)
874                                 goto cleanup;
875
876                         entries[i]->ident = g_strdup(config->ident);
877                         entries[i]->name = g_strdup(config->name);
878                         entries[i]->ssid = g_try_malloc0(config->ssid_len + 1);
879                         if (entries[i]->ssid == NULL)
880                                 goto cleanup;
881
882                         memcpy(entries[i]->ssid, config->ssid,
883                                                         config->ssid_len);
884                         entries[i]->ssid_len = config->ssid_len;
885                         entries[i]->hidden = config->hidden;
886
887                         i++;
888                 }
889         }
890
891         if (entries != NULL) {
892                 entries = g_try_realloc(entries, (i + 1) *
893                                         sizeof(struct connman_config_entry *));
894                 if (entries == NULL)
895                         return NULL;
896
897                 entries[i] = NULL;
898
899                 DBG("%d provisioned AP found", i);
900         }
901
902         return entries;
903
904 cleanup:
905         connman_config_free_entries(entries);
906         return NULL;
907 }
908
909 void connman_config_free_entries(struct connman_config_entry **entries)
910 {
911         int i;
912
913         if (entries == NULL)
914                 return;
915
916         for (i = 0; entries[i]; i++) {
917                 g_free(entries[i]->ident);
918                 g_free(entries[i]->name);
919                 g_free(entries[i]->ssid);
920                 g_free(entries[i]);
921         }
922
923         g_free(entries);
924         return;
925 }