66f67ebb091eb6e233b144692fc22ba50b78b3b7
[platform/core/connectivity/net-config.git] / src / wifi-eap-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 <errno.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24
25 #include "log.h"
26 #include "util.h"
27 #include "netdbus.h"
28 #include "wifi-agent.h"
29 #include "wifi-state.h"
30 #include "wifi-config.h"
31 #include "wifi-eap-config.h"
32 #include "neterror.h"
33
34 #define CONNMAN_CONFIG_FIELD_TYPE                       "Type"
35 #define CONNMAN_CONFIG_FIELD_NAME                       "Name"
36 #define CONNMAN_CONFIG_FIELD_SSID                       "SSID"
37 #define CONNMAN_CONFIG_FIELD_EAP_METHOD         "EAP"
38 #define CONNMAN_CONFIG_FIELD_IDENTITY           "Identity"
39 #define CONNMAN_CONFIG_FIELD_PASSPHRASE         "Passphrase"
40 #define CONNMAN_CONFIG_FIELD_PHASE2                     "Phase2"
41 #define CONNMAN_CONFIG_FIELD_CA_CERT_FILE                       "CACertFile"
42 #define CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE           "ClientCertFile"
43 #define CONNMAN_CONFIG_FIELD_PVT_KEY_FILE                       "PrivateKeyFile"
44 #define CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE         "PrivateKeyPassphrase"
45 #define CONNMAN_CONFIG_FIELD_KEYMGMT_TYPE                       "KeymgmtType"
46
47 static char *__get_encoded_ssid(const char *name)
48 {
49         char *str = NULL;
50         char *pstr = NULL;
51         int i = 0, len = 0;
52
53         if (name == NULL)
54                 return NULL;
55
56         len = strlen(name);
57
58         str = g_try_malloc0(len * 2 + 1);
59         if (str == NULL)
60                 return NULL;
61
62         pstr = str;
63         for (i = 0; i < len; i++) {
64                 g_snprintf(pstr, 3, "%02x", name[i]);
65                 pstr += 2;
66         }
67
68         return str;
69 }
70
71 static int __config_save(const char *ssid, GKeyFile *keyfile)
72 {
73         gchar *data = NULL;
74         gchar *config_file = NULL;
75         gsize length = 0;
76         FILE *file = NULL;
77         int err = 0;
78
79         config_file = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR, ssid);
80         if (config_file == NULL) {
81                 err = -ENOMEM;
82                 goto out;
83         }
84
85         data = g_key_file_to_data(keyfile, &length, NULL);
86
87         file = fopen(config_file, "w");
88         if (file == NULL) {
89                 ERR("Failed to open %s", config_file);
90
91                 err = -EIO;
92                 goto out;
93         }
94
95         /* Do POSIX file operation to create and remove config files,
96          * Do not use g_file_set_contents, it breaks inotify operations */
97         if (data && fputs(data, file) < 0) {
98                 ERR("Failed to write %s", config_file);
99
100                 err = -EIO;
101                 goto out;
102         }
103
104 out:
105         if (file != NULL)
106                 fclose(file);
107
108         g_free(data);
109         g_free(config_file);
110
111         return err;
112 }
113
114 static int __config_delete(const char *ssid)
115 {
116         int err = 0;
117         gchar *group_name = NULL;
118         gchar *config_file = NULL;
119         gchar *dirname = NULL;
120         gchar *cert_path = NULL;
121         GKeyFile *keyfile = NULL;
122         GError *error = NULL;
123
124         config_file = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR, ssid);
125         if (config_file == NULL)
126                 return -ENOMEM;
127
128         keyfile = g_key_file_new();
129
130         if (g_key_file_load_from_file(keyfile, config_file, 0, &error) != TRUE) {
131                 ERR("Unable to load %s[%s]", config_file, error->message);
132                 g_clear_error(&error);
133
134                 err = -EIO;
135                 goto out;
136         }
137
138         group_name = g_strdup_printf("service_%s", ssid);
139
140         cert_path = g_key_file_get_string(keyfile, group_name,
141                         CONNMAN_CONFIG_FIELD_CA_CERT_FILE, NULL);
142         DBG("Temporal %s", cert_path);
143         if (cert_path != NULL && remove(cert_path) != 0)
144                 ERR("Failed to remove %s", cert_path);
145         g_free(cert_path);
146
147         cert_path = g_key_file_get_string(keyfile, group_name,
148                         CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE, NULL);
149         DBG("Temporal %s", cert_path);
150         if (cert_path != NULL && remove(cert_path) != 0)
151                 ERR("Failed to remove %s", cert_path);
152         g_free(cert_path);
153
154         cert_path = g_key_file_get_string(keyfile, group_name,
155                         CONNMAN_CONFIG_FIELD_PVT_KEY_FILE, NULL);
156         DBG("Temporal %s", cert_path);
157         if (cert_path != NULL && remove(cert_path) != 0)
158                 ERR("Failed to remove %s", cert_path);
159         g_free(cert_path);
160
161         cert_path = g_key_file_get_string(keyfile, group_name,
162                         CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE, NULL);
163         DBG("Temporal %s", cert_path);
164         if (cert_path != NULL && remove(cert_path) != 0)
165                 ERR("Failed to remove %s", cert_path);
166         g_free(cert_path);
167
168         dirname = g_strdup_printf("%s/%s", WIFI_CERT_STORAGEDIR, ssid);
169         if (dirname != NULL) {
170                 if (g_file_test(dirname, G_FILE_TEST_EXISTS) == TRUE)
171                         if (g_file_test(dirname, G_FILE_TEST_IS_DIR) == TRUE)
172                                 rmdir(dirname);
173
174                 g_free(dirname);
175         }
176
177         if (remove(config_file) != 0) {
178                 err = -EIO;
179                 goto out;
180         }
181
182 out:
183         g_key_file_free(keyfile);
184         g_free(config_file);
185         g_free(group_name);
186
187         return err;
188 }
189
190 static gboolean __netconfig_copy_config(const char *src, const char *dst)
191 {
192         gchar *buf = NULL;
193         gsize length = 0;
194         GError *error = NULL;
195         gboolean result;
196
197         result = g_file_get_contents(src, &buf, &length, &error);
198         if (result != TRUE) {
199                 ERR("Failed to read %s[%s]", error->message);
200                 g_error_free(error);
201
202                 return result;
203         }
204
205         result = g_file_set_contents(dst, buf, length, &error);
206         if (result != TRUE) {
207                 ERR("Failed to write %s[%s]", error->message);
208                 g_error_free(error);
209         }
210
211         INFO("Successfully installed[%d]", length);
212         g_free(buf);
213
214         if (remove(src) != 0)
215                 WARN("Failed to remove %s", src);
216
217         return result;
218 }
219
220 static gboolean __netconfig_create_config(GVariant *fields)
221 {
222         GKeyFile *keyfile = NULL;
223         GVariantIter *iter;
224         gchar *encoded_ssid = NULL;
225         gchar *dirname = NULL;
226         gchar *group_name = NULL;
227         gchar *field, *value;
228         gboolean updated = FALSE;
229         gchar *cert_file = NULL;
230         gchar *cert_path = NULL;
231         int err = 0;
232
233         g_variant_get(fields, "a{ss}", &iter);
234         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
235                 if (value != NULL) {
236                         if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0) {
237                                 encoded_ssid = __get_encoded_ssid(value);
238
239                                 g_free(value);
240                                 g_free(field);
241                                 break;
242                         } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0) {
243                                 encoded_ssid = g_strdup(value);
244
245                                 g_free(field);
246                                 g_free(value);
247                                 break;
248                         }
249                 }
250         }
251
252         if (encoded_ssid == NULL) {
253                 ERR("Failed to fetch SSID");
254                 goto out;
255         }
256
257         /* Create unique service group name */
258         group_name = g_strdup_printf("service_%s", encoded_ssid);
259         if (group_name == NULL) {
260                 ERR("Failed to create service group name");
261                 goto out;
262         }
263
264         keyfile = g_key_file_new();
265         if (keyfile == NULL) {
266                 ERR("Failed to g_key_file_new");
267                 goto out;
268         }
269
270         g_variant_iter_free(iter);
271
272         g_variant_get(fields, "a{ss}", &iter);
273         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
274                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0 ||
275                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_EAP_METHOD) == 0 ||
276                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE2) ||
277                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_KEYMGMT_TYPE) == 0) {
278                         DBG("field: %s, value: %s", field, value);
279
280                         if (value != NULL)
281                                 g_key_file_set_string(keyfile, group_name, field, value);
282                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CA_CERT_FILE) == 0 ||
283                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE) == 0 ||
284                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_FILE) == 0 ||
285                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE) == 0) {
286                         if (value != NULL) {
287                                 cert_file = strrchr(value, '/');
288                                 if (cert_file == NULL) {
289                                         ERR("Failed to get cert file: %s", value);
290                                         goto out;
291                                 }
292
293                                 cert_file++;
294                                 DBG("field: %s, value: %s", field, cert_file);
295
296                                 dirname = g_strdup_printf("%s/%s",
297                                                 WIFI_CERT_STORAGEDIR, encoded_ssid);
298                                 if (dirname == NULL) {
299                                         ERR("Failed to create dirname");
300                                         goto out;
301                                 }
302                                 if (g_file_test(dirname, G_FILE_TEST_IS_DIR) != TRUE) {
303                                         if (mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
304                                                         S_IXGRP | S_IROTH | S_IXOTH) < 0) {
305                                                 if (errno != EEXIST) {
306                                                         g_free(dirname);
307                                                         goto out;
308                                                 }
309                                         }
310                                 }
311                                 g_free(dirname);
312
313                                 cert_path = g_strdup_printf("%s/%s/%s",
314                                                 WIFI_CERT_STORAGEDIR, encoded_ssid, cert_file);
315                                 if (cert_path == NULL) {
316                                         ERR("Failed to create cert path");
317                                         goto out;
318                                 }
319                                 if (__netconfig_copy_config(value, cert_path) != TRUE) {
320                                         ERR("Failed to read cert file %s", value);
321                                         g_free(cert_path);
322                                         goto out;
323                                 }
324
325                                 g_key_file_set_string(keyfile, group_name, field, cert_path);
326                                 g_free(cert_path);
327                         }
328                 } else {
329                         DBG("field: %s, value: %s", field, value);
330
331                         if (value != NULL)
332                                 g_key_file_set_string(keyfile, group_name, field, value);
333                 }
334         }
335
336         err = __config_save((const char *)encoded_ssid, keyfile);
337         if (err < 0)
338                 ERR("Failed to create configuration %s[%d]", encoded_ssid, err);
339         else {
340                 DBG("Successfully created %s", encoded_ssid);
341                 updated = TRUE;
342         }
343
344 out:
345         if (keyfile)
346                 g_key_file_free(keyfile);
347
348         g_variant_iter_free(iter);
349
350         g_free(group_name);
351         g_free(encoded_ssid);
352
353         return updated;
354 }
355
356 static gboolean _delete_configuration(const gchar *profile)
357 {
358         gboolean ret = FALSE;
359         gchar *config_id = NULL;
360
361         ret = wifi_config_get_config_id(profile, &config_id);
362         if (ret != TRUE) {
363                 ERR("Fail to get config_id from [%s]", profile);
364                 return ret;
365         }
366         ERR("get config_id [%s] from [%s]", config_id, profile);
367
368         ret = wifi_config_remove_configuration(config_id);
369         if (ret != TRUE)
370                 ERR("Fail to wifi_config_remove_configuration [%s]", config_id);
371
372         if (config_id != NULL)
373                 g_free(config_id);
374
375         return ret;
376 }
377
378 static gboolean __netconfig_delete_config(const char *profile)
379 {
380         char *wifi_ident = NULL;
381         char *essid = NULL;
382         char *mode = NULL;
383         char *ssid = NULL;
384         int ssid_len = 0;
385         int err = 0;
386
387         if (NULL == profile) {
388                 ERR("Invalid profile name");
389                 return FALSE;
390         }
391
392         if (_delete_configuration(profile) != TRUE)
393                 ERR("Fail to delete configuration [%s]", profile);
394
395         wifi_ident = strstr(profile, "wifi_");
396         if (wifi_ident == NULL) {
397                 ERR("Invalid profile name");
398                 return FALSE;
399         }
400
401         essid = strchr(wifi_ident + 5, '_');
402         if (essid == NULL) {
403                 ERR("Invalid profile name");
404                 return FALSE;
405         }
406
407         essid++;
408         mode = strchr(essid, '_');
409
410         ssid_len = mode - essid;
411
412         ssid = g_try_malloc0(ssid_len + 1);
413         if (ssid == NULL) {
414                 ERR("Memory allocation failed");
415                 return FALSE;
416         }
417
418         g_strlcpy(ssid, essid, ssid_len + 1); /* include NULL-terminated */
419         err = __config_delete((const char *)ssid);
420         if (err < 0) {
421                 ERR("Failed to delete configuration %s[%d]", ssid, err);
422                 g_free(ssid);
423                 return FALSE;
424         }
425
426         DBG("Successfully deleted %s with length %d", ssid, ssid_len);
427
428         g_free(ssid);
429         return TRUE;
430 }
431
432 static void __netconfig_eap_state(
433                 wifi_service_state_e state, void *user_data);
434
435 static wifi_state_notifier netconfig_eap_notifier = {
436                 .wifi_state_changed = __netconfig_eap_state,
437                 .user_data = NULL,
438 };
439
440 static void __netconfig_eap_state(
441                 wifi_service_state_e state, void *user_data)
442 {
443         const char *wifi_profile = (const char *)user_data;
444
445         if (wifi_profile == NULL) {
446                 wifi_state_notifier_unregister(&netconfig_eap_notifier);
447                 return;
448         }
449
450         if (state != NETCONFIG_WIFI_CONNECTED && state != NETCONFIG_WIFI_FAILURE)
451                 return;
452
453         if (state == NETCONFIG_WIFI_FAILURE)
454                 __netconfig_delete_config(wifi_profile);
455
456         g_free(netconfig_eap_notifier.user_data);
457         netconfig_eap_notifier.user_data = NULL;
458
459         wifi_state_notifier_unregister(&netconfig_eap_notifier);
460 }
461
462 gboolean handle_create_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
463                 const gchar *service, GVariant *fields)
464 {
465         gboolean updated = FALSE;
466         gboolean result = FALSE;
467
468         g_return_val_if_fail(wifi != NULL, TRUE);
469
470         DBG("Set agent fields for %s", service);
471
472         if (netconfig_is_wifi_profile(service) != TRUE) {
473                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
474                 return TRUE;
475         }
476
477         updated = __netconfig_create_config(fields);
478         if (updated == TRUE) {
479                 wifi_complete_create_eap_config(wifi, context);
480
481                 if (g_strstr_len(service, strlen(service), "_hidden_") != NULL) {
482                         GVariantIter *iter;
483                         char *field, *value;
484                         const char *name = NULL;
485                         const char *identity = NULL;
486                         const char *passphrase = NULL;
487
488                         g_variant_get(fields, "a{ss}", &iter);
489
490                         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
491                                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0)
492                                         name = (const char *)value;
493                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0)
494                                         name = (const char *)value;
495                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0)
496                                         identity = (const char *)value;
497                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0)
498                                         passphrase = (const char *)value;
499                         }
500
501                         netconfig_wifi_set_agent_field_for_eap_network(
502                                                                         name, identity, passphrase);
503
504                         g_variant_iter_free(iter);
505                 }
506
507                 result = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
508                                 service, CONNMAN_SERVICE_INTERFACE, "Connect",
509                                 NULL, __netconfig_wifi_connect_reply);
510
511                 if (netconfig_eap_notifier.user_data != NULL) {
512                         g_free(netconfig_eap_notifier.user_data);
513                         netconfig_eap_notifier.user_data = NULL;
514
515                         wifi_state_notifier_unregister(&netconfig_eap_notifier);
516                 }
517
518                 netconfig_eap_notifier.user_data = g_strdup(service);
519                 wifi_state_notifier_register(&netconfig_eap_notifier);
520         } else {
521                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INVALID_PARAMETER, "InvalidArguments");
522         }
523
524         if (result != TRUE)
525                 ERR("Fail to connect %s", service);
526
527         return TRUE;
528 }
529
530 gboolean handle_delete_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
531                 const gchar *profile)
532 {
533         g_return_val_if_fail(wifi != NULL, TRUE);
534
535         wifi_complete_delete_eap_config(wifi, context);
536
537         __netconfig_delete_config((const char *)profile);
538
539         return TRUE;
540 }