Merge "Use libnl-3.0 in place of libnl-2.0" into tizen
[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]", 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]", error->message);
208                 g_error_free(error);
209         }
210
211         INFO("Successfully installed[%zd]", 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                                         g_free(field);
291                                         g_free(value);
292                                         goto out;
293                                 }
294
295                                 cert_file++;
296                                 DBG("field: %s, value: %s", field, cert_file);
297
298                                 dirname = g_strdup_printf("%s/%s",
299                                                 WIFI_CERT_STORAGEDIR, encoded_ssid);
300                                 if (dirname == NULL) {
301                                         ERR("Failed to create dirname");
302                                         g_free(field);
303                                         g_free(value);
304                                         goto out;
305                                 }
306                                 if (g_file_test(dirname, G_FILE_TEST_IS_DIR) != TRUE) {
307                                         if (mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
308                                                         S_IXGRP | S_IROTH | S_IXOTH) < 0) {
309                                                 if (errno != EEXIST) {
310                                                         g_free(dirname);
311                                                         g_free(field);
312                                                         g_free(value);
313                                                         goto out;
314                                                 }
315                                         }
316                                 }
317                                 g_free(dirname);
318
319                                 cert_path = g_strdup_printf("%s/%s/%s",
320                                                 WIFI_CERT_STORAGEDIR, encoded_ssid, cert_file);
321                                 if (cert_path == NULL) {
322                                         ERR("Failed to create cert path");
323                                         g_free(field);
324                                         g_free(value);
325                                         goto out;
326                                 }
327                                 if (__netconfig_copy_config(value, cert_path) != TRUE) {
328                                         ERR("Failed to read cert file %s", value);
329                                         g_free(cert_path);
330                                         g_free(field);
331                                         g_free(value);
332                                         goto out;
333                                 }
334
335                                 g_key_file_set_string(keyfile, group_name, field, cert_path);
336                                 g_free(cert_path);
337                         }
338                 } else {
339                         DBG("field: %s, value: %s", field, value);
340
341                         if (value != NULL)
342                                 g_key_file_set_string(keyfile, group_name, field, value);
343                 }
344         }
345
346         err = __config_save((const char *)encoded_ssid, keyfile);
347         if (err < 0)
348                 ERR("Failed to create configuration %s[%d]", encoded_ssid, err);
349         else {
350                 DBG("Successfully created %s", encoded_ssid);
351                 updated = TRUE;
352         }
353
354 out:
355         if (keyfile)
356                 g_key_file_free(keyfile);
357
358         g_variant_iter_free(iter);
359
360         g_free(group_name);
361         g_free(encoded_ssid);
362
363         return updated;
364 }
365
366 static gboolean _delete_configuration(const gchar *profile)
367 {
368         gboolean ret = FALSE;
369         gchar *config_id = NULL;
370
371         ret = wifi_config_get_config_id(profile, &config_id);
372         if (ret != TRUE) {
373                 ERR("Fail to get config_id from [%s]", profile);
374                 return ret;
375         }
376         ERR("get config_id [%s] from [%s]", config_id, profile);
377
378         ret = wifi_config_remove_configuration(config_id);
379         if (ret != TRUE)
380                 ERR("Fail to wifi_config_remove_configuration [%s]", config_id);
381
382         if (config_id != NULL)
383                 g_free(config_id);
384
385         return ret;
386 }
387
388 static gboolean __netconfig_delete_config(const char *profile)
389 {
390         char *wifi_ident = NULL;
391         char *essid = NULL;
392         char *mode = NULL;
393         char *ssid = NULL;
394         int ssid_len = 0;
395         int err = 0;
396
397         if (NULL == profile) {
398                 ERR("Invalid profile name");
399                 return FALSE;
400         }
401
402         if (_delete_configuration(profile) != TRUE)
403                 ERR("Fail to delete configuration [%s]", profile);
404
405         wifi_ident = strstr(profile, "wifi_");
406         if (wifi_ident == NULL) {
407                 ERR("Invalid profile name");
408                 return FALSE;
409         }
410
411         essid = strchr(wifi_ident + 5, '_');
412         if (essid == NULL) {
413                 ERR("Invalid profile name");
414                 return FALSE;
415         }
416
417         essid++;
418         mode = strchr(essid, '_');
419
420         ssid_len = mode - essid;
421
422         ssid = g_try_malloc0(ssid_len + 1);
423         if (ssid == NULL) {
424                 ERR("Memory allocation failed");
425                 return FALSE;
426         }
427
428         g_strlcpy(ssid, essid, ssid_len + 1); /* include NULL-terminated */
429         err = __config_delete((const char *)ssid);
430         if (err < 0) {
431                 ERR("Failed to delete configuration %s[%d]", ssid, err);
432                 g_free(ssid);
433                 return FALSE;
434         }
435
436         DBG("Successfully deleted %s with length %d", ssid, ssid_len);
437
438         g_free(ssid);
439         return TRUE;
440 }
441
442 static void __netconfig_eap_state(
443                 wifi_service_state_e state, void *user_data);
444
445 static wifi_state_notifier netconfig_eap_notifier = {
446                 .wifi_state_changed = __netconfig_eap_state,
447                 .user_data = NULL,
448 };
449
450 static void __netconfig_eap_state(
451                 wifi_service_state_e state, void *user_data)
452 {
453         const char *wifi_profile = (const char *)user_data;
454
455         if (wifi_profile == NULL) {
456                 wifi_state_notifier_unregister(&netconfig_eap_notifier);
457                 return;
458         }
459
460         if (state != NETCONFIG_WIFI_CONNECTED && state != NETCONFIG_WIFI_FAILURE)
461                 return;
462
463         if (state == NETCONFIG_WIFI_FAILURE)
464                 __netconfig_delete_config(wifi_profile);
465
466         g_free(netconfig_eap_notifier.user_data);
467         netconfig_eap_notifier.user_data = NULL;
468
469         wifi_state_notifier_unregister(&netconfig_eap_notifier);
470 }
471
472 gboolean handle_create_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
473                 const gchar *service, GVariant *fields)
474 {
475         gboolean updated = FALSE;
476         gboolean result = FALSE;
477
478         g_return_val_if_fail(wifi != NULL, TRUE);
479
480         DBG("Set agent fields for %s", service);
481
482         if (netconfig_is_wifi_profile(service) != TRUE) {
483                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
484                 return TRUE;
485         }
486
487         updated = __netconfig_create_config(fields);
488         if (updated == TRUE) {
489                 wifi_complete_create_eap_config(wifi, context);
490
491                 if (g_strstr_len(service, strlen(service), "_hidden_") != NULL) {
492                         GVariantIter *iter;
493                         char *field, *value;
494                         const char *name = NULL;
495                         const char *identity = NULL;
496                         const char *passphrase = NULL;
497
498                         g_variant_get(fields, "a{ss}", &iter);
499
500                         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
501                                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0)
502                                         name = (const char *)value;
503                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0)
504                                         name = (const char *)value;
505                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0)
506                                         identity = (const char *)value;
507                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0)
508                                         passphrase = (const char *)value;
509                         }
510
511                         netconfig_wifi_set_agent_field_for_eap_network(
512                                                                         name, identity, passphrase);
513
514                         g_variant_iter_free(iter);
515                 }
516
517                 result = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
518                                 service, CONNMAN_SERVICE_INTERFACE, "Connect",
519                                 NULL, __netconfig_wifi_connect_reply);
520
521                 if (netconfig_eap_notifier.user_data != NULL) {
522                         g_free(netconfig_eap_notifier.user_data);
523                         netconfig_eap_notifier.user_data = NULL;
524
525                         wifi_state_notifier_unregister(&netconfig_eap_notifier);
526                 }
527
528                 netconfig_eap_notifier.user_data = g_strdup(service);
529                 wifi_state_notifier_register(&netconfig_eap_notifier);
530         } else {
531                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INVALID_PARAMETER, "InvalidArguments");
532         }
533
534         if (result != TRUE)
535                 ERR("Fail to connect %s", service);
536
537         return TRUE;
538 }
539
540 gboolean handle_delete_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
541                 const gchar *profile)
542 {
543         g_return_val_if_fail(wifi != NULL, TRUE);
544
545         wifi_complete_delete_eap_config(wifi, context);
546
547         __netconfig_delete_config((const char *)profile);
548
549         return TRUE;
550 }