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