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