3abd47550e7a7be686b41163f3472b74f27b2d95
[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 *ssid, 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, ssid);
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 *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, ssid);
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", WIFI_CERT_STORAGEDIR, 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(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         int err = 0;
233
234         g_variant_get(fields, "a{ss}", &iter);
235         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
236                 if (value != NULL) {
237                         if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0) {
238                                 encoded_ssid = __get_encoded_ssid(value);
239
240                                 g_free(value);
241                                 g_free(field);
242                                 break;
243                         } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0) {
244                                 encoded_ssid = g_strdup(value);
245
246                                 g_free(field);
247                                 g_free(value);
248                                 break;
249                         }
250                 }
251         }
252
253         if (encoded_ssid == NULL) {
254                 ERR("Failed to fetch SSID");
255                 goto out;
256         }
257
258         /* Create unique service group name */
259         group_name = g_strdup_printf("service_%s", encoded_ssid);
260         if (group_name == NULL) {
261                 ERR("Failed to create service group name");
262                 goto out;
263         }
264
265         keyfile = g_key_file_new();
266         if (keyfile == NULL) {
267                 ERR("Failed to g_key_file_new");
268                 goto out;
269         }
270
271         g_variant_iter_free(iter);
272
273         g_variant_get(fields, "a{ss}", &iter);
274         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
275                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0 ||
276                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_EAP_METHOD) == 0 ||
277                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE2) ||
278                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_KEYMGMT_TYPE) == 0) {
279                         if (value != NULL)
280                                 g_key_file_set_string(keyfile, group_name, field, value);
281                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CA_CERT_FILE) == 0 ||
282                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE) == 0 ||
283                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_FILE) == 0 ||
284                                 g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE) == 0) {
285                         if (value != NULL) {
286                                 cert_file = strrchr(value, '/');
287                                 if (cert_file == NULL) {
288                                         ERR("Failed to get cert file: %s", value);
289                                         g_free(field);
290                                         g_free(value);
291                                         goto out;
292                                 }
293
294                                 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                                         g_free(field);
301                                         g_free(value);
302                                         goto out;
303                                 }
304                                 if (g_file_test(dirname, G_FILE_TEST_IS_DIR) != TRUE) {
305                                         if (mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
306                                                         S_IXGRP | S_IROTH | S_IXOTH) < 0) {
307                                                 if (errno != EEXIST) {
308                                                         g_free(dirname);
309                                                         g_free(field);
310                                                         g_free(value);
311                                                         goto out;
312                                                 }
313                                         }
314                                 }
315                                 g_free(dirname);
316
317                                 cert_path = g_strdup_printf("%s/%s/%s",
318                                                 WIFI_CERT_STORAGEDIR, encoded_ssid, cert_file);
319                                 if (cert_path == NULL) {
320                                         ERR("Failed to create cert path");
321                                         g_free(field);
322                                         g_free(value);
323                                         goto out;
324                                 }
325                                 if (__netconfig_copy_config(value, cert_path) != TRUE) {
326                                         ERR("Failed to read cert file %s", value);
327                                         g_free(cert_path);
328                                         g_free(field);
329                                         g_free(value);
330                                         goto out;
331                                 }
332
333                                 g_key_file_set_string(keyfile, group_name, field, cert_path);
334                                 g_free(cert_path);
335                         }
336                 } else {
337                         if (value != NULL)
338                                 g_key_file_set_string(keyfile, group_name, field, value);
339                 }
340         }
341
342         err = __config_save((const char *)encoded_ssid, keyfile);
343         if (err < 0)
344                 ERR("Failed to create configuration %s[%d]", encoded_ssid, err);
345         else {
346                 DBG("Successfully created %s", encoded_ssid);
347                 updated = TRUE;
348         }
349
350 out:
351         if (keyfile)
352                 g_key_file_free(keyfile);
353
354         g_variant_iter_free(iter);
355
356         g_free(group_name);
357         g_free(encoded_ssid);
358
359         return updated;
360 }
361
362 static gboolean _delete_configuration(const char *interface_name, const char *profile)
363 {
364         gboolean ret = FALSE;
365         gchar *config_id = NULL;
366
367         ret = wifi_config_get_config_id(profile, &config_id);
368         if (ret != TRUE) {
369                 ERR("Fail to get config_id from [%s]", profile);
370                 return ret;
371         }
372         ERR("get config_id [%s] from [%s]", config_id, profile);
373
374         ret = wifi_config_remove_configuration(interface_name, config_id);
375         if (ret != TRUE)
376                 ERR("Fail to wifi_config_remove_configuration [%s]", config_id);
377
378         if (config_id != NULL)
379                 g_free(config_id);
380
381         return ret;
382 }
383
384 static gboolean __netconfig_delete_config(const char *profile)
385 {
386         char *wifi_ident = NULL;
387         char *essid = NULL;
388         char *mode = NULL;
389         char *ssid = NULL;
390         int ssid_len = 0;
391         int err = 0;
392         const char *interface_name = NULL;
393
394         if (NULL == profile) {
395                 ERR("Invalid profile name");
396                 return FALSE;
397         }
398
399         interface_name = netconfig_get_ifname(profile);
400         if (interface_name == NULL) {
401                 ERR("Invalid profile name");
402                 return FALSE;
403         }
404
405         if (_delete_configuration(interface_name, profile) != TRUE)
406                 ERR("Fail to delete configuration [%s]", profile);
407
408         wifi_ident = strstr(profile, "wifi_");
409         if (wifi_ident == NULL) {
410                 ERR("Invalid profile name");
411                 return FALSE;
412         }
413
414         essid = strchr(wifi_ident + 5, '_');
415         if (essid == NULL) {
416                 ERR("Invalid profile name");
417                 return FALSE;
418         }
419
420         essid++;
421         mode = strchr(essid, '_');
422
423         ssid_len = mode - essid;
424
425         ssid = g_try_malloc0(ssid_len + 1);
426         if (ssid == NULL) {
427                 ERR("Memory allocation failed");
428                 return FALSE;
429         }
430
431         g_strlcpy(ssid, essid, ssid_len + 1); /* include NULL-terminated */
432         err = __config_delete((const char *)ssid);
433         if (err < 0) {
434                 ERR("Failed to delete configuration %s[%d]", ssid, err);
435                 g_free(ssid);
436                 return FALSE;
437         }
438
439         DBG("Successfully deleted %s with length %d", ssid, ssid_len);
440
441         g_free(ssid);
442         return TRUE;
443 }
444
445 static void __netconfig_eap_state(wifi_state_notifier_s *notifier,
446                 char *service, wifi_service_state_e state, void *user_data)
447 {
448         if (notifier == NULL)
449                 return;
450
451         if (service == NULL) {
452                 wifi_state_notifier_unregister(notifier);
453                 g_free(notifier->service);
454                 g_free(notifier->user_data);
455                 g_free(notifier);
456                 return;
457         }
458
459         if (state != NETCONFIG_WIFI_CONNECTED && state != NETCONFIG_WIFI_FAILURE)
460                 return;
461
462         if (state == NETCONFIG_WIFI_FAILURE)
463                 __netconfig_delete_config(service);
464
465         wifi_state_notifier_unregister(notifier);
466         g_free(notifier->service);
467         g_free(notifier->user_data);
468         g_free(notifier->service);
469 }
470
471 gboolean handle_create_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
472                 const gchar *service, GVariant *fields)
473 {
474         gboolean updated = FALSE;
475         gboolean result = FALSE;
476         wifi_state_notifier_s *state_notifier = NULL;
477         const char *interface_name = NULL;
478
479         g_return_val_if_fail(wifi != NULL, TRUE);
480
481         DBG("Set agent fields for %s", service);
482
483         if (netconfig_is_wifi_profile(service) != TRUE) {
484                 netconfig_error_dbus_method_return(context,
485                         NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
486                 return TRUE;
487         }
488
489         interface_name = netconfig_get_ifname(service);
490         if (interface_name == NULL) {
491                 netconfig_error_dbus_method_return(context,
492                         NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
493                 return TRUE;
494         }
495
496         updated = __netconfig_create_config(fields);
497         if (updated == TRUE) {
498                 wifi_complete_create_eap_config(wifi, context);
499
500                 if (g_strstr_len(service, strlen(service), "_hidden_") != NULL) {
501                         GVariantIter *iter;
502                         char *field, *value;
503                         const char *name = NULL;
504                         const char *identity = NULL;
505                         const char *passphrase = NULL;
506
507                         g_variant_get(fields, "a{ss}", &iter);
508
509                         while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
510                                 if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0)
511                                         name = (const char *)value;
512                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0)
513                                         name = (const char *)value;
514                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0)
515                                         identity = (const char *)value;
516                                 else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0)
517                                         passphrase = (const char *)value;
518                         }
519
520                         netconfig_wifi_set_agent_field_for_eap_network(interface_name,
521                                 name, identity, passphrase);
522
523                         g_variant_iter_free(iter);
524                 }
525
526                 result = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
527                                 service, CONNMAN_SERVICE_INTERFACE, "Connect",
528                                 NULL, __netconfig_wifi_connect_reply,
529                                 g_strdup(interface_name));
530
531                 state_notifier = g_try_malloc0(sizeof(wifi_state_notifier_s));
532                 if (state_notifier) {
533                         state_notifier->notifier = state_notifier;
534                         state_notifier->service = g_strdup(service);
535                         state_notifier->wifi_state_changed = __netconfig_eap_state;
536                         wifi_state_notifier_register(state_notifier);
537                 }
538         } else {
539                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INVALID_PARAMETER, "InvalidArguments");
540         }
541
542         if (result != TRUE)
543                 ERR("Fail to connect %s", service);
544
545         return TRUE;
546 }
547
548 gboolean handle_delete_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
549                 const gchar *profile)
550 {
551         g_return_val_if_fail(wifi != NULL, TRUE);
552
553         __netconfig_delete_config(profile);
554
555         wifi_complete_delete_eap_config(wifi, context);
556
557         return TRUE;
558 }