Added support of WPA3-SAE security mode.
[platform/upstream/connman.git] / src / storage.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <dirent.h>
31
32 #include <connman/storage.h>
33
34 #include "connman.h"
35
36 #define SETTINGS        "settings"
37 #define DEFAULT         "default.profile"
38
39 #define MODE            (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
40                         S_IXGRP | S_IROTH | S_IXOTH)
41
42 static GKeyFile *storage_load(const char *pathname)
43 {
44         GKeyFile *keyfile = NULL;
45         GError *error = NULL;
46
47         keyfile = g_key_file_new();
48
49         if (!g_key_file_load_from_file(keyfile, pathname, 0, &error)) {
50                 DBG("Unable to load %s: %s", pathname, error->message);
51                 g_clear_error(&error);
52
53                 g_key_file_free(keyfile);
54                 keyfile = NULL;
55         }
56
57         return keyfile;
58 }
59
60 static int storage_save(GKeyFile *keyfile, char *pathname)
61 {
62         gchar *data = NULL;
63         gsize length = 0;
64         GError *error = NULL;
65         int ret = 0;
66
67         data = g_key_file_to_data(keyfile, &length, NULL);
68
69         if (!g_file_set_contents(pathname, data, length, &error)) {
70                 DBG("Failed to store information: %s", error->message);
71                 g_error_free(error);
72                 ret = -EIO;
73         }
74
75 #if defined TIZEN_EXT
76         {
77                 FILE *fp = NULL;
78                 fp = fopen(pathname, "a+");
79                 if(fp){
80                         fflush(fp);
81                         fsync(fp->_fileno);
82                         fclose(fp);
83                         DBG("sync the file to disk");
84                 }
85         }
86 #endif
87
88         g_free(data);
89
90         return ret;
91 }
92
93 static void storage_delete(const char *pathname)
94 {
95         DBG("file path %s", pathname);
96
97         if (unlink(pathname) < 0)
98                 connman_error("Failed to remove %s", pathname);
99 }
100
101 GKeyFile *__connman_storage_load_global(void)
102 {
103         gchar *pathname;
104         GKeyFile *keyfile = NULL;
105
106         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
107         if (!pathname)
108                 return NULL;
109
110         keyfile = storage_load(pathname);
111
112         g_free(pathname);
113
114         return keyfile;
115 }
116
117 int __connman_storage_save_global(GKeyFile *keyfile)
118 {
119         gchar *pathname;
120         int ret;
121
122         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
123         if (!pathname)
124                 return -ENOMEM;
125
126         ret = storage_save(keyfile, pathname);
127
128         g_free(pathname);
129
130         return ret;
131 }
132
133 void __connman_storage_delete_global(void)
134 {
135         gchar *pathname;
136
137         pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
138         if (!pathname)
139                 return;
140
141         storage_delete(pathname);
142
143         g_free(pathname);
144 }
145
146 GKeyFile *__connman_storage_load_config(const char *ident)
147 {
148         gchar *pathname;
149         GKeyFile *keyfile = NULL;
150
151         pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
152         if (!pathname)
153                 return NULL;
154
155         keyfile = storage_load(pathname);
156
157         g_free(pathname);
158
159         return keyfile;
160 }
161
162 GKeyFile *__connman_storage_load_provider_config(const char *ident)
163 {
164         gchar *pathname;
165         GKeyFile *keyfile = NULL;
166
167         pathname = g_strdup_printf("%s/%s.config", VPN_STORAGEDIR, ident);
168         if (!pathname)
169                 return NULL;
170
171         keyfile = storage_load(pathname);
172
173         g_free(pathname);
174
175         return keyfile;
176 }
177
178 GKeyFile *__connman_storage_open_service(const char *service_id)
179 {
180         gchar *pathname;
181         GKeyFile *keyfile = NULL;
182
183         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
184         if (!pathname)
185                 return NULL;
186
187         keyfile =  storage_load(pathname);
188         if (keyfile) {
189                 g_free(pathname);
190                 return keyfile;
191         }
192
193         g_free(pathname);
194
195         keyfile = g_key_file_new();
196
197         return keyfile;
198 }
199
200 gchar **connman_storage_get_services(void)
201 {
202         struct dirent *d;
203         gchar *str;
204         DIR *dir;
205         GString *result;
206         gchar **services = NULL;
207         struct stat buf;
208         int ret;
209
210         dir = opendir(STORAGEDIR);
211         if (!dir)
212                 return NULL;
213
214         result = g_string_new(NULL);
215
216         while ((d = readdir(dir))) {
217                 if (strcmp(d->d_name, ".") == 0 ||
218                                 strcmp(d->d_name, "..") == 0 ||
219                                 strncmp(d->d_name, "provider_", 9) == 0)
220                         continue;
221
222                 switch (d->d_type) {
223                 case DT_DIR:
224                 case DT_UNKNOWN:
225                         /*
226                          * If the settings file is not found, then
227                          * assume this directory is not a services dir.
228                          */
229                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
230                                                                 d->d_name);
231                         ret = stat(str, &buf);
232                         g_free(str);
233                         if (ret < 0)
234                                 continue;
235
236                         g_string_append_printf(result, "%s/", d->d_name);
237                         break;
238                 }
239         }
240
241         closedir(dir);
242
243         str = g_string_free(result, FALSE);
244         if (str && str[0] != '\0') {
245                 /*
246                  * Remove the trailing separator so that services doesn't end up
247                  * with an empty element.
248                  */
249                 str[strlen(str) - 1] = '\0';
250                 services = g_strsplit(str, "/", -1);
251         }
252         g_free(str);
253
254         return services;
255 }
256
257 GKeyFile *connman_storage_load_service(const char *service_id)
258 {
259         gchar *pathname;
260         GKeyFile *keyfile = NULL;
261
262         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
263         if (!pathname)
264                 return NULL;
265
266         keyfile =  storage_load(pathname);
267         g_free(pathname);
268
269         return keyfile;
270 }
271
272 int __connman_storage_save_service(GKeyFile *keyfile, const char *service_id)
273 {
274         int ret = 0;
275         gchar *pathname, *dirname;
276
277         dirname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
278         if (!dirname)
279                 return -ENOMEM;
280
281         /* If the dir doesn't exist, create it */
282         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
283                 if (mkdir(dirname, MODE) < 0) {
284                         if (errno != EEXIST) {
285                                 g_free(dirname);
286                                 return -errno;
287                         }
288                 }
289         }
290
291         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
292
293         g_free(dirname);
294
295         ret = storage_save(keyfile, pathname);
296
297         g_free(pathname);
298
299         return ret;
300 }
301
302 static bool remove_file(const char *service_id, const char *file)
303 {
304         gchar *pathname;
305         bool ret = false;
306
307         pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, file);
308         if (!pathname)
309                 return false;
310
311         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
312                 ret = true;
313         } else if (g_file_test(pathname, G_FILE_TEST_IS_REGULAR)) {
314                 unlink(pathname);
315                 ret = true;
316         }
317
318         g_free(pathname);
319         return ret;
320 }
321
322 static bool remove_dir(const char *service_id)
323 {
324         gchar *pathname;
325         bool ret = false;
326
327         pathname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
328         if (!pathname)
329                 return false;
330
331         if (!g_file_test(pathname, G_FILE_TEST_EXISTS)) {
332                 ret = true;
333         } else if (g_file_test(pathname, G_FILE_TEST_IS_DIR)) {
334                 rmdir(pathname);
335                 ret = true;
336         }
337
338         g_free(pathname);
339         return ret;
340 }
341
342 bool __connman_storage_remove_service(const char *service_id)
343 {
344         bool removed;
345
346         /* Remove service configuration file */
347         removed = remove_file(service_id, SETTINGS);
348         if (!removed)
349                 return false;
350
351         /* Remove the statistics file also */
352         removed = remove_file(service_id, "data");
353         if (!removed)
354                 return false;
355
356         removed = remove_dir(service_id);
357         if (!removed)
358                 return false;
359
360         DBG("Removed service dir %s/%s", STORAGEDIR, service_id);
361
362         return true;
363 }
364
365 GKeyFile *__connman_storage_load_provider(const char *identifier)
366 {
367         gchar *pathname;
368         GKeyFile *keyfile;
369
370         pathname = g_strdup_printf("%s/%s_%s/%s", STORAGEDIR, "provider",
371                         identifier, SETTINGS);
372         if (!pathname)
373                 return NULL;
374
375         keyfile = storage_load(pathname);
376         g_free(pathname);
377
378         return keyfile;
379 }
380
381 void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier)
382 {
383         gchar *pathname, *dirname;
384
385         dirname = g_strdup_printf("%s/%s_%s", STORAGEDIR,
386                         "provider", identifier);
387         if (!dirname)
388                 return;
389
390         if (!g_file_test(dirname, G_FILE_TEST_IS_DIR) &&
391                         mkdir(dirname, MODE) < 0) {
392                 g_free(dirname);
393                 return;
394         }
395
396         pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
397         g_free(dirname);
398
399         storage_save(keyfile, pathname);
400         g_free(pathname);
401 }
402
403 static bool remove_all(const char *id)
404 {
405         bool removed;
406
407         remove_file(id, SETTINGS);
408         remove_file(id, "data");
409
410         removed = remove_dir(id);
411         if (!removed)
412                 return false;
413
414         return true;
415 }
416
417 bool __connman_storage_remove_provider(const char *identifier)
418 {
419         bool removed;
420         gchar *id;
421
422         id = g_strdup_printf("%s_%s", "provider", identifier);
423         if (!id)
424                 return false;
425
426         if (remove_all(id))
427                 DBG("Removed provider dir %s/%s", STORAGEDIR, id);
428
429         g_free(id);
430
431         id = g_strdup_printf("%s_%s", "vpn", identifier);
432         if (!id)
433                 return false;
434
435         if ((removed = remove_all(id)))
436                 DBG("Removed vpn dir %s/%s", STORAGEDIR, id);
437
438         g_free(id);
439
440         return removed;
441 }
442
443 gchar **__connman_storage_get_providers(void)
444 {
445         GSList *list = NULL;
446         int num = 0, i = 0;
447         struct dirent *d;
448         gchar *str;
449         DIR *dir;
450         struct stat buf;
451         int ret;
452         char **providers;
453         GSList *iter;
454
455         dir = opendir(STORAGEDIR);
456         if (!dir)
457                 return NULL;
458
459         while ((d = readdir(dir))) {
460                 if (strcmp(d->d_name, ".") == 0 ||
461                                 strcmp(d->d_name, "..") == 0 ||
462                                 strncmp(d->d_name, "provider_", 9) != 0)
463                         continue;
464
465                 if (d->d_type == DT_DIR) {
466                         str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
467                                         d->d_name);
468                         ret = stat(str, &buf);
469                         g_free(str);
470                         if (ret < 0)
471                                 continue;
472                         list = g_slist_prepend(list, g_strdup(d->d_name));
473                         num += 1;
474                 }
475         }
476
477         closedir(dir);
478
479         providers = g_try_new0(char *, num + 1);
480         for (iter = list; iter; iter = g_slist_next(iter)) {
481                 if (providers)
482                         providers[i] = iter->data;
483                 else
484                         g_free(iter->data);
485                 i += 1;
486         }
487         g_slist_free(list);
488
489         return providers;
490 }