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