54dae24425ef306b9672ceee51be989b7bf0d7cf
[platform/core/connectivity/net-config.git] / src / wifi-config.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 #include <glib.h>
26 #include <unistd.h>
27
28 #include <vconf.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "neterror.h"
33 #include "wifi-config.h"
34
35 #define CONNMAN_STORAGE         "/var/lib/connman"
36 #define WIFI_CONFIG_PREFIX      "wifi_"
37
38 #define WIFI_CONFIG_NAME                                "Name"
39 #define WIFI_CONFIG_SSID                                "SSID"
40 #define WIFI_CONFIG_PASSPHRASE          "Passphrase"
41 #define WIFI_CONFIG_SECURITY_TYPE               "Security"
42 #define WIFI_CONFIG_FAVORITE                    "Favorite"
43 #define WIFI_CONFIG_AUTOCONNECT         "AutoConnect"
44 #define WIFI_CONFIG_HIDDEN                              "Hidden"
45 #define WIFI_CONFIG_FAILURE                     "Failure"
46 #define WIFI_CONFIG_PROXYADDRESS                "ProxyAddress"
47 #define WIFI_CONFIG_PROXY_METHOD                "Proxy.Method"
48 #define WIFI_CONFIG_PROXY_SERVER                "Proxy.Servers"
49
50 #define WIFI_SECURITY_NONE              "none"
51 #define WIFI_SECURITY_WEP               "wep"
52 #define WIFI_SECURITY_WPA_PSK   "psk"
53 #define WIFI_SECURITY_EAP               "ieee8021x"
54
55 #define WIFI_PREFIX_LENGTH      18 // wifi_485a3f2f506a_
56
57 struct wifi_config {
58         gchar *name;
59         gchar *ssid;
60         gchar *passphrase;
61         gchar *security_type;
62         gboolean favorite;
63         gboolean autoconnect;
64         gchar *is_hidden;
65         gchar *proxy_address;
66         gchar *last_error;
67 };
68
69 static gint __netconfig_get_mac_address(gchar **mac_address)
70 {
71         gchar *tmp_mac = NULL;
72         gchar *tmp = NULL;
73         gchar mac[13] = { 0, };
74         gint i = 0, j = 0;
75
76         tmp_mac = vconf_get_str(VCONFKEY_WIFI_BSSID_ADDRESS);
77         if (tmp_mac == NULL) {
78                 ERR("vconf_get_str(WIFI_BSSID_ADDRESS) Failed");
79                 *mac_address = NULL;
80                 return -1;
81         }
82         tmp = g_ascii_strdown(tmp_mac, (gssize)strlen(tmp_mac));
83         g_free(tmp_mac);
84
85         while (tmp[i]) {
86                 if (tmp[i] != ':') {
87                         mac[j++] = tmp[i];
88                 }
89                 i++;
90         }
91         mac[12] = '\0';
92         *mac_address = g_strdup(mac);
93
94         return 0;
95 }
96
97 static gboolean ___netconfig_remove_file(const gchar *pathname, const gchar *filename)
98 {
99         gboolean ret = FALSE;
100         gchar *path;
101
102         path = g_strdup_printf("%s/%s", pathname, filename);
103         if (g_file_test(path, G_FILE_TEST_EXISTS) == FALSE) {
104                 ret = TRUE;
105         } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) == TRUE) {
106                 unlink(path);
107                 ret = TRUE;
108         }
109
110         g_free(path);
111         return ret;
112 }
113
114 static gboolean __netconfig_remove_configuration(const gchar *pathname)
115 {
116         int ret = 0;
117
118         if (___netconfig_remove_file(pathname, "settings") != TRUE) {
119                 ERR("Cannot remove [%s/settings]", pathname);
120                 return FALSE;
121         }
122         if (___netconfig_remove_file(pathname, "data") != TRUE) {
123                 ERR("Cannot remove [%s/data]", pathname);
124                 return FALSE;
125         }
126
127         ret = rmdir(pathname);
128         if (ret == -1) {
129                 ERR("Cannot remove [%s]", pathname);
130                 return FALSE;
131         }
132
133         return TRUE;
134 }
135
136 static gint _netconfig_get_security_type(const gchar *config_id, gchar **type)
137 {
138         int ret = 0;
139
140         if (g_str_has_suffix(config_id, WIFI_SECURITY_NONE) == TRUE) {
141                 *type = g_strdup(WIFI_SECURITY_NONE);
142         } else if (g_str_has_suffix(config_id, WIFI_SECURITY_WEP) == TRUE) {
143                 *type = g_strdup(WIFI_SECURITY_WEP);
144         } else if (g_str_has_suffix(config_id, WIFI_SECURITY_WPA_PSK) == TRUE) {
145                 *type = g_strdup(WIFI_SECURITY_WPA_PSK);
146         } else if (g_str_has_suffix(config_id, WIFI_SECURITY_EAP) == TRUE) {
147                 *type = g_strdup(WIFI_SECURITY_EAP);
148         } else {
149                 *type = NULL;
150                 ret = -1;
151         }
152
153         return ret;
154 }
155
156 static gboolean _netconfig_load_wifi_configuration(const gchar *config_id,
157                 struct wifi_config *config)
158 {
159         GKeyFile *keyfile;
160         gchar *path;
161         gchar *group_name;
162         gchar *mac_address = NULL;
163         gboolean hidden = FALSE;
164
165         __netconfig_get_mac_address(&mac_address);
166         if (strlen(mac_address) == 0) {
167                 ERR("mac_address is NULL");
168                 return FALSE;
169         }
170
171         group_name = g_strdup_printf(WIFI_CONFIG_PREFIX "%s_%s", mac_address, config_id);
172         g_free(mac_address);
173         path = g_strdup_printf("/var/lib/connman/%s/settings", group_name);
174
175         DBG("group_name %s", group_name);
176         DBG("path %s", path);
177
178         keyfile = netconfig_keyfile_load(path);
179         if (keyfile == NULL) {
180                 ERR("keyfile[%s] is NULL", path);
181                 return FALSE;
182         }
183         config->name = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_NAME, NULL);
184         config->passphrase = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, NULL);
185         _netconfig_get_security_type(config_id, &config->security_type);
186         config->proxy_address = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PROXY_SERVER, NULL);
187         hidden = g_key_file_get_boolean(keyfile, group_name, WIFI_CONFIG_HIDDEN, NULL);
188         if (hidden) {
189                 config->is_hidden = g_strdup("TRUE");
190         } else {
191                 config->is_hidden = g_strdup("FALSE");
192         }
193         config->last_error = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_FAILURE, NULL);
194
195         g_free(group_name);
196         g_free(path);
197
198         return TRUE;
199 }
200
201 static gboolean _netconfig_save_wifi_configuration(const gchar *config_id,
202                 const struct wifi_config *config)
203 {
204         GKeyFile *keyfile;
205         gchar *dir;
206         gchar *path;
207         gchar *group_name;
208         gchar *mac_address = NULL;
209
210         __netconfig_get_mac_address(&mac_address);
211         if (mac_address == NULL) {
212                 ERR("mac_address is NULL");
213                 return FALSE;
214         }
215
216         group_name = g_strdup_printf("wifi_%s_%s", mac_address, config_id);
217         g_free(mac_address);
218
219         dir = g_strdup_printf(CONNMAN_STORAGE "/%s", group_name);
220         if (g_file_test(dir, G_FILE_TEST_IS_DIR) == TRUE) {
221                 if (__netconfig_remove_configuration(dir) != TRUE) {
222                         ERR("[%s] is existed, but cannot remove", dir);
223                         g_free(group_name);
224                         g_free(dir);
225                         return FALSE;
226                 }
227         }
228
229         if (mkdir(dir, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) < 0) {
230                 ERR("Cannot mkdir %s", dir);
231                 g_free(group_name);
232                 g_free(dir);
233                 return FALSE;
234         }
235
236         keyfile = g_key_file_new();
237         g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_NAME, config->name);
238         g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_SSID, config->ssid);
239
240         if (config->passphrase != NULL)
241                 g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, config->passphrase);
242
243         g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_FAVORITE, config->favorite);
244         g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_AUTOCONNECT, config->autoconnect);
245
246         // Optional field
247         if (config->proxy_address != NULL) {
248                 g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PROXY_METHOD, "manual");
249                 g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PROXY_SERVER, config->proxy_address);
250         }
251
252         if (config->is_hidden != NULL) {
253                 gboolean hidden = FALSE;
254                 if (g_strcmp0(config->is_hidden, "TRUE") == 0) {
255                         hidden = TRUE;
256                 }
257                 g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_HIDDEN, hidden);
258         }
259
260         path = g_strdup_printf(CONNMAN_STORAGE "/%s/settings", group_name);
261         netconfig_keyfile_save(keyfile, path);
262         g_free(group_name);
263         g_free(dir);
264         g_free(path);
265
266         return TRUE;
267 }
268
269 static gboolean _netconfig_remove_wifi_configuration(const gchar *config_id)
270 {
271         gboolean ret = FALSE;
272         gchar *dir;
273         gchar *group_name;
274         gchar *mac_address = NULL;
275
276         __netconfig_get_mac_address(&mac_address);
277         if (mac_address == NULL) {
278                 ERR("mac_address is NULL");
279                 return FALSE;
280         }
281
282         group_name = g_strdup_printf("wifi_%s_%s", mac_address, config_id);
283         g_free(mac_address);
284
285         dir = g_strdup_printf(CONNMAN_STORAGE "/%s", group_name);
286         if (g_file_test(dir, G_FILE_TEST_IS_DIR) == TRUE) {
287                 if (__netconfig_remove_configuration(dir) != TRUE) {
288                         ERR("[%s] is existed, but cannot remove", dir);
289                         ret = FALSE;
290                 }
291                 INFO("Success to remove [%s]", dir);
292                 ret = TRUE;
293         } else {
294                 ERR("[%s] is not existed", dir);
295                 ret = FALSE;
296         }
297
298         g_free(group_name);
299         g_free(dir);
300
301         return ret;
302 }
303
304 static gboolean _netconfig_set_wifi_config_field(const gchar *config_id,
305                 const gchar *key, const gchar *value)
306 {
307         gboolean ret = TRUE;
308         GKeyFile *keyfile;
309         gchar *path;
310         gchar *group_name;
311         gchar *mac_address = NULL;
312
313         __netconfig_get_mac_address(&mac_address);
314         if (strlen(mac_address) == 0) {
315                 ERR("mac_address is NULL");
316                 return FALSE;
317         }
318
319         group_name = g_strdup_printf(WIFI_CONFIG_PREFIX "%s_%s", mac_address, config_id);
320         g_free(mac_address);
321         path = g_strdup_printf("/var/lib/connman/%s/settings", group_name);
322
323         DBG("group_name %s", group_name);
324         DBG("path %s", path);
325
326         keyfile = netconfig_keyfile_load(path);
327         if (keyfile == NULL) {
328                 ERR("keyfile[%s] is NULL", path);
329                 return FALSE;
330         }
331
332         if (g_strcmp0(key, WIFI_CONFIG_PROXY_METHOD) == 0) {
333                 g_key_file_set_string(keyfile, group_name, key, value);
334         }else if (g_strcmp0(key, WIFI_CONFIG_PROXY_SERVER) == 0) {
335                 g_key_file_set_string(keyfile, group_name, key, value);
336         } else if (g_strcmp0(key, WIFI_CONFIG_HIDDEN) == 0) {
337                 gboolean hidden = FALSE;
338                 if (g_strcmp0(value, "TRUE") == 0) {
339                         hidden = TRUE;
340                 }
341                 g_key_file_set_boolean(keyfile, group_name, key, hidden);
342         } else {
343                 ERR("key[%s] is not supported", key);
344                 ret = FALSE;
345         }
346
347         netconfig_keyfile_save(keyfile, path);
348         g_free(group_name);
349         g_free(path);
350
351         return ret;
352 }
353
354 static GSList *_netconfig_get_wifi_config_list(void)
355 {
356         GSList *list = NULL;
357         struct dirent *d;
358         DIR *dir;
359
360         dir = opendir(CONNMAN_STORAGE);
361         if (dir == NULL) {
362                 ERR("Cannot open dir %s", CONNMAN_STORAGE);
363                 return NULL;
364         }
365
366         while ((d = readdir(dir))) {
367                 if (g_strcmp0(d->d_name, ".") == 0 ||
368                                 g_strcmp0(d->d_name, "..") == 0 ||
369                                 strncmp(d->d_name, WIFI_CONFIG_PREFIX, strlen(WIFI_CONFIG_PREFIX)) != 0) {
370                         continue;
371                 }
372                 gchar *config_id = g_strdup(d->d_name + WIFI_PREFIX_LENGTH);
373                 list = g_slist_append(list, g_strdup(config_id));
374                 g_free(config_id);
375         }
376         closedir(dir);
377
378         return list;
379 }
380
381 gboolean handle_get_config_ids(Wifi *wifi, GDBusMethodInvocation *context)
382 {
383         guint i = 0;
384         GSList *config_ids = NULL;
385         guint length;
386         gchar **result = NULL;
387
388         g_return_val_if_fail(wifi != NULL, FALSE);
389
390         config_ids = _netconfig_get_wifi_config_list();
391         if (config_ids == NULL) {
392                 netconfig_error_no_profile(context);
393                 ERR("Fail to get config list");
394                 return FALSE;
395         }
396
397         length = g_slist_length(config_ids);
398         result = g_new0(gchar *, length + 1);
399         for (i = 0; i < length; i++) {
400                 gchar *config_id = g_slist_nth_data(config_ids, i);
401                 result[i] = g_strdup(config_id);
402         }
403
404         config_ids = g_slist_nth(config_ids, 0);
405         g_slist_free_full(config_ids, g_free);
406
407         wifi_complete_get_config_ids(wifi, context, (const gchar * const*)result);
408         return TRUE;
409 }
410
411 gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
412                 const gchar *config_id)
413 {
414         gboolean ret = FALSE;
415         gchar *name = NULL, *passphrase = NULL, *security_type = NULL;
416         gchar *proxy_address = NULL, *is_hidden = NULL, *last_error = NULL;
417         struct wifi_config *conf = NULL;
418
419         g_return_val_if_fail(wifi != NULL, FALSE);
420
421         conf = g_new0(struct wifi_config, 1);
422
423         ret = _netconfig_load_wifi_configuration(config_id, conf);
424         if (ret != TRUE) {
425                 g_free(conf);
426                 ERR("No wifi configuration");
427                 netconfig_error_no_profile(context);
428                 return FALSE;
429         }
430
431         name = g_strdup(conf->name);
432         passphrase = g_strdup(conf->passphrase);
433         security_type = g_strdup(conf->security_type);
434         is_hidden = g_strdup(conf->is_hidden);
435
436         if (conf->proxy_address != NULL) {
437                 proxy_address = g_strdup(conf->proxy_address);
438                 g_free(conf->proxy_address);
439         } else {
440                 proxy_address = g_strdup("NONE");
441         }
442         if (conf->last_error != NULL) {
443                 last_error = g_strdup(conf->last_error);
444                 g_free(conf->last_error);
445         } else {
446                 last_error = g_strdup("ERROR_NONE");
447         }
448
449         g_free(conf->name);
450         g_free(conf->passphrase);
451         g_free(conf->security_type);
452         g_free(conf->is_hidden);
453         g_free(conf);
454
455         wifi_complete_load_configuration (wifi, context, name,
456                         passphrase, security_type, proxy_address, is_hidden, last_error);
457
458         return TRUE;
459 }
460
461 gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
462                 const gchar *config_id, GVariant *configuration)
463 {
464         gboolean ret = FALSE;
465         struct wifi_config *conf = NULL;
466         GVariantIter *iter;
467         GVariant *value;
468         gchar *field;
469
470         if ((wifi == NULL) || (config_id == NULL) || (configuration == NULL)) {
471                 ERR("Invaliad parameter");
472                 netconfig_error_invalid_parameter(context);
473                 return FALSE;
474         }
475
476         conf = g_new0(struct wifi_config, 1);
477
478         g_variant_get(configuration, "a{sv}", &iter);
479         while (g_variant_iter_loop(iter, "{sv}", &field, &value)) {
480                 if (g_strcmp0(field, WIFI_CONFIG_NAME) == 0) {
481                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
482                                 conf->name = g_strdup(g_variant_get_string(value, NULL));
483                                 ERR("name [%s]", conf->name);
484                         } else {
485                                 conf->name = NULL;
486                         }
487                 } else if (g_strcmp0(field, WIFI_CONFIG_SSID) == 0) {
488                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
489                                 conf->ssid = g_strdup(g_variant_get_string(value, NULL));
490                                 ERR("ssid [%s]", conf->ssid);
491                         } else {
492                                 conf->ssid = NULL;
493                         }
494                 } else if (g_strcmp0(field, WIFI_CONFIG_PASSPHRASE) == 0) {
495                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
496                                 conf->passphrase = g_strdup(g_variant_get_string(value, NULL));
497                                 ERR("passphrase [%s]", conf->passphrase);
498                         } else {
499                                 conf->passphrase = NULL;
500                         }
501                 } else if (g_strcmp0(field, WIFI_CONFIG_HIDDEN) == 0) {
502                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
503                                 conf->is_hidden = g_strdup(g_variant_get_string(value, NULL));
504                                 ERR("is_hidden [%s]", conf->is_hidden);
505                         } else {
506                                 conf->is_hidden = NULL;
507                         }
508                 } else if (g_strcmp0(field, WIFI_CONFIG_PROXYADDRESS) == 0) {
509                         conf->proxy_address = g_strdup(g_variant_get_string(value, NULL));
510                         ERR("proxy_address [%s]", conf->proxy_address);
511                 } else {
512                         conf->proxy_address = NULL;
513                 }
514         }
515         conf->favorite = TRUE;
516         conf->autoconnect = TRUE;
517         ret = _netconfig_save_wifi_configuration(config_id, conf);
518
519         g_free(conf->name);
520         g_free(conf->ssid);
521         g_free(conf->passphrase);
522         g_free(conf->is_hidden);
523         g_free(conf->proxy_address);
524         g_free(conf);
525
526         g_variant_iter_free(iter);
527
528         if (ret == TRUE) {
529                 wifi_complete_save_configuration(wifi, context);
530         } else {
531                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSaveConfiguration");
532         }
533
534         return ret;
535 }
536
537 gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context, const gchar *config_id)
538 {
539         gboolean ret = FALSE;
540
541         if ((wifi == NULL) || (config_id == NULL)) {
542                 ERR("Invaliad parameter");
543                 netconfig_error_invalid_parameter(context);
544                 return FALSE;
545         }
546
547         ret = _netconfig_remove_wifi_configuration(config_id);
548         if (ret != TRUE) {
549                 // no configuration or error
550                 ERR("No [%s] configuration", config_id);
551                 netconfig_error_no_profile(context);
552                 return FALSE;
553         }
554
555         wifi_complete_remove_configuration(wifi, context);
556         return ret;
557 }
558
559 // config field key / value
560 /*
561  * [wifi_macaddress_config_id]
562  * Name=name (mandatory)
563  * SSID=SSID (mandatory)
564  * Frequency=2462 (X)
565  * Favorite=true (X)
566  * AutoConnect=true (Default true)
567  * Modified=2015-03-20 (X)
568  * IPv4.method=manual (O)
569  * IPv4.DHCP.LastAddress=192.0.0.1 (X)
570  * IPv6.method=auto (X)
571  * IPv6.privacy=disabled (X)
572  * IPv4.netmask_prefixlen=24 (X)
573  * IPv4.local_address=192.0.0.1 (O)
574  * IPv4.gateway=192.0.0.1 (O ? X ?)
575  * Nameservers=192.168.43.22; (O)
576  * Proxy.Method=manual (O)
577  * Proxy.Servers=trst.com:8888; (O)
578  */
579 gboolean handle_set_config_field(Wifi *wifi, GDBusMethodInvocation *context,
580                 const gchar *config_id, const gchar *key, const gchar *value)
581 {
582         gboolean ret = FALSE;
583         gchar *keyfile_key = NULL;
584
585         g_return_val_if_fail(wifi != NULL, FALSE);
586         g_return_val_if_fail(config_id != NULL, FALSE);
587         g_return_val_if_fail(key != NULL, FALSE);
588
589         DBG("Key[%s] Value[%d]", key, value);
590
591         if (g_strcmp0(key, WIFI_CONFIG_PROXYADDRESS) == 0) {
592                 ret = _netconfig_set_wifi_config_field(config_id, WIFI_CONFIG_PROXY_METHOD, "manual");
593                 if (!ret) {
594                         ERR("Fail to [%s]set_wifi_config_field(%s/manual)", config_id, WIFI_CONFIG_PROXY_METHOD);
595                         netconfig_error_invalid_parameter(context);
596                         return FALSE;
597                 }
598                 keyfile_key = g_strdup_printf("%s", WIFI_CONFIG_PROXY_SERVER);
599         } else if (g_strcmp0(key, WIFI_CONFIG_HIDDEN) == 0) {
600                 keyfile_key = g_strdup_printf("%s", WIFI_CONFIG_HIDDEN);
601         } else {
602                 ERR("Not supported key[%s]", key);
603                 netconfig_error_invalid_parameter(context);
604                 return FALSE;
605         }
606
607         ret = _netconfig_set_wifi_config_field(config_id, keyfile_key, (const gchar *)value);
608         if (!ret) {
609                 ERR("Fail to [%s]set_wifi_config_field(%s/%s)", config_id, key, value);
610                 ret = FALSE;
611         }
612
613         if (keyfile_key != NULL)
614                 g_free(keyfile_key);
615
616         wifi_complete_set_config_field(wifi,context);
617         return ret;
618 }