/*
* Network Configuration Module
*
- * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
*/
+#include <errno.h>
#include <stdio.h>
#include <unistd.h>
+#include <sys/stat.h>
-#include "wifi-eap-config.h"
#include "log.h"
-#include "wifi.h"
-
-static char *__get_ssid(const char *name)
+#include "util.h"
+#include "netdbus.h"
+#include "wifi-agent.h"
+#include "wifi-state.h"
+#include "wifi-config.h"
+#include "wifi-eap-config.h"
+#include "network-state.h"
+#include "neterror.h"
+
+#define CONNMAN_CONFIG_FIELD_TYPE "Type"
+#define CONNMAN_CONFIG_FIELD_NAME "Name"
+#define CONNMAN_CONFIG_FIELD_SSID "SSID"
+#define CONNMAN_CONFIG_FIELD_EAP_METHOD "EAP"
+#define CONNMAN_CONFIG_FIELD_IDENTITY "Identity"
+#define CONNMAN_CONFIG_FIELD_PASSPHRASE "Passphrase"
+#define CONNMAN_CONFIG_FIELD_PHASE2 "Phase2"
+#define CONNMAN_CONFIG_FIELD_CA_CERT_FILE "CACertFile"
+#define CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE "ClientCertFile"
+#define CONNMAN_CONFIG_FIELD_PVT_KEY_FILE "PrivateKeyFile"
+#define CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE "PrivateKeyPassphrase"
+#define CONNMAN_CONFIG_FIELD_KEYMGMT_TYPE "KeymgmtType"
+
+static char *__get_encoded_ssid(const char *name)
{
- char *buf = NULL;
- char buf_tmp[32] = {0,};
- int i = 0;
- int len = 0;
+ char *str = NULL;
+ char *pstr = NULL;
+ int i = 0, len = 0;
- if (NULL == name)
+ if (name == NULL)
return NULL;
len = strlen(name);
- buf = g_try_malloc0(len * 2 + 1);
- if (buf == NULL)
+ str = g_try_malloc0(len * 2 + 1);
+ if (str == NULL)
return NULL;
+ pstr = str;
for (i = 0; i < len; i++) {
- snprintf(buf_tmp, 3, "%02x", name[i]);
- strcat(buf, buf_tmp);
+ g_snprintf(pstr, 3, "%02x", name[i]);
+ pstr += 2;
}
- DBG("SSID - [%s]\n", buf);
-
- return buf;
+ return str;
}
-static gboolean __config_save(GKeyFile *keyfile, char *file_name)
+static int __config_save(const char *mac_addr, GKeyFile *keyfile)
{
gchar *data = NULL;
+ gchar *config_file = NULL;
gsize length = 0;
FILE *file = NULL;
- int ret = TRUE;
+ int err = 0;
+
+ config_file = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR, mac_addr);
+ if (config_file == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
data = g_key_file_to_data(keyfile, &length, NULL);
- DBG("Data lenght-[%d]", length);
- file = fopen(file_name, "w");
- if (NULL == file) {
- DBG("fopen() fails!");
- ret = FALSE;
- } else {
- fputs(data, file);
- fclose(file);
- DBG("Wrote data successfully to [%s] file!", file_name);
+ file = fopen(config_file, "w");
+ if (file == NULL) {
+ ERR("Failed to open %s", config_file);
+
+ err = -EIO;
+ goto out;
}
+ /* Do POSIX file operation to create and remove config files,
+ * Do not use g_file_set_contents, it breaks inotify operations */
+ if (data && fputs(data, file) < 0) {
+ ERR("Failed to write %s", config_file);
+
+ err = -EIO;
+ goto out;
+ }
+
+out:
+ if (file != NULL)
+ fclose(file);
+
g_free(data);
+ g_free(config_file);
- return ret;
+ return err;
}
-static gboolean __config_delete(const char *ssid)
+static int __config_delete(const char *mac_addr, const char *ssid)
{
+ int err = 0;
+ gchar *group_name = NULL;
gchar *config_file = NULL;
- gboolean ret = FALSE;
+ gchar *dirname = NULL;
+ gchar *cert_path = NULL;
+ GKeyFile *keyfile = NULL;
+ GError *error = NULL;
- config_file = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR,
- ssid);
- if(config_file == NULL)
- return FALSE;
+ config_file = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR, mac_addr);
+ if (config_file == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
- if (g_file_test(config_file, G_FILE_TEST_EXISTS) == FALSE) {
- ret = TRUE;
- } else if (g_file_test(config_file, G_FILE_TEST_IS_REGULAR) == TRUE) {
- unlink(config_file);
- ret = TRUE;
+ if (g_key_file_load_from_file(keyfile, config_file, 0, &error) != TRUE) {
+ ERR("Unable to load %s[%s]", config_file, error->message);
+ g_clear_error(&error);
+
+ err = -EIO;
+ goto out;
+ }
+
+ group_name = g_strdup_printf("service_%s", ssid);
+
+ cert_path = g_key_file_get_string(keyfile, group_name,
+ CONNMAN_CONFIG_FIELD_CA_CERT_FILE, NULL);
+ DBG("Temporal %s", cert_path);
+ if (cert_path != NULL && remove(cert_path) != 0)
+ ERR("Failed to remove %s", cert_path);
+ g_free(cert_path);
+
+ cert_path = g_key_file_get_string(keyfile, group_name,
+ CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE, NULL);
+ DBG("Temporal %s", cert_path);
+ if (cert_path != NULL && remove(cert_path) != 0)
+ ERR("Failed to remove %s", cert_path);
+ g_free(cert_path);
+
+ cert_path = g_key_file_get_string(keyfile, group_name,
+ CONNMAN_CONFIG_FIELD_PVT_KEY_FILE, NULL);
+ DBG("Temporal %s", cert_path);
+ if (cert_path != NULL && remove(cert_path) != 0)
+ ERR("Failed to remove %s", cert_path);
+ g_free(cert_path);
+
+ cert_path = g_key_file_get_string(keyfile, group_name,
+ CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE, NULL);
+ DBG("Temporal %s", cert_path);
+ if (cert_path != NULL && remove(cert_path) != 0)
+ ERR("Failed to remove %s", cert_path);
+ g_free(cert_path);
+
+ dirname = g_strdup_printf("%s/%s_%s", WIFI_CERT_STORAGEDIR, mac_addr, ssid);
+ if (dirname != NULL) {
+ if (g_file_test(dirname, G_FILE_TEST_EXISTS) == TRUE)
+ if (g_file_test(dirname, G_FILE_TEST_IS_DIR) == TRUE)
+ rmdir(dirname);
+
+ g_free(dirname);
}
+ if (remove(config_file) != 0) {
+ err = -EIO;
+ goto out;
+ }
+
+out:
+ g_key_file_free(keyfile);
g_free(config_file);
+ g_free(group_name);
- return ret;
+ return err;
}
-gboolean netconfig_iface_wifi_create_config(NetconfigWifi *wifi,
- GHashTable *fields, GError **error)
+static gboolean __netconfig_copy_config(const char *src, const char *dst)
{
- DBG("netconfig_iface_wifi_create_config");
- g_return_val_if_fail(wifi != NULL, FALSE);
+ gchar *buf = NULL;
+ gsize length = 0;
+ GError *error = NULL;
+ gboolean result;
+
+ result = g_file_get_contents(src, &buf, &length, &error);
+ if (result != TRUE) {
+ ERR("Failed to read [%s]", error->message);
+ g_error_free(error);
+
+ return result;
+ }
+
+ result = g_file_set_contents(dst, buf, length, &error);
+ if (result != TRUE) {
+ ERR("Failed to write [%s]", error->message);
+ g_error_free(error);
+ }
+
+ INFO("Successfully installed[%zd]", length);
+ g_free(buf);
- gboolean ret = TRUE;
+ if (remove(src) != 0)
+ WARN("Failed to remove %s", src);
+
+ return result;
+}
+
+static gboolean __netconfig_create_config(const char *profile, GVariant *fields)
+{
GKeyFile *keyfile = NULL;
- GHashTableIter iter;
- gpointer field, value;
- gchar *file_name = NULL;
- gchar *ssid_hex = NULL;
- gchar *grp_name = NULL;
-
- g_hash_table_iter_init(&iter, fields);
- while (g_hash_table_iter_next(&iter, &field, &value)) {
- if (NULL != value) {
- if (!strcmp(field, CONNMAN_CONFIG_FIELD_NAME)) {
- ssid_hex = __get_ssid(value);
+ GVariantIter *iter;
+ gchar *encoded_ssid = NULL;
+ gchar *dirname = NULL;
+ gchar *group_name = NULL;
+ gchar *field, *value;
+ gboolean updated = FALSE;
+ gchar *cert_file = NULL;
+ gchar *cert_path = NULL;
+ char mac_str[13] = { 0, };
+ int err = 0;
+
+ g_variant_get(fields, "a{ss}", &iter);
+ while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
+ if (value != NULL) {
+ if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0) {
+ encoded_ssid = __get_encoded_ssid(value);
+
+ g_free(value);
+ g_free(field);
break;
- } else if (!strcmp(field, CONNMAN_CONFIG_FIELD_SSID)) {
- ssid_hex = g_strdup_printf("%s",
- (gchar *)value);
+ } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0) {
+ encoded_ssid = g_strdup(value);
+
+ g_free(field);
+ g_free(value);
break;
}
}
}
- if (NULL == ssid_hex) {
- DBG("Fail! Could not fetch the ssid");
- return FALSE;
+ if (encoded_ssid == NULL) {
+ ERR("Failed to fetch SSID");
+ goto out;
}
+ memcpy(mac_str, &profile[strlen(CONNMAN_WIFI_SERVICE_PROFILE_PREFIX)], 12);
+ mac_str[12] = '\0';
+
/* Create unique service group name */
- grp_name = g_strdup_printf("service_%s", ssid_hex);
- if(NULL == grp_name) {
- DBG("Fail! Could not create the service group name");
- g_free(ssid_hex);
- return FALSE;
+ group_name = g_strdup_printf("service_%s", encoded_ssid);
+ if (group_name == NULL) {
+ ERR("Failed to create service group name");
+ goto out;
}
keyfile = g_key_file_new();
- if (NULL == keyfile) {
- DBG("g_key_file_new() fails!");
- g_free(grp_name);
- g_free(ssid_hex);
- return FALSE;
+ if (keyfile == NULL) {
+ ERR("Failed to g_key_file_new");
+ goto out;
}
- g_hash_table_iter_init(&iter, fields);
- while (g_hash_table_iter_next(&iter, &field, &value)) {
- DBG("Field - [%s] Value - [%s]", field, value);
+ g_variant_iter_free(iter);
+
+ g_variant_get(fields, "a{ss}", &iter);
+ while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
+ if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0 ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_EAP_METHOD) == 0 ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE2) ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_KEYMGMT_TYPE) == 0) {
+ if (value != NULL)
+ g_key_file_set_string(keyfile, group_name, field, value);
+ } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CA_CERT_FILE) == 0 ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE) == 0 ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_FILE) == 0 ||
+ g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE) == 0) {
+ if (value != NULL) {
+ cert_file = strrchr(value, '/');
+ if (cert_file == NULL) {
+ ERR("Failed to get cert file: %s", value);
+ g_free(field);
+ g_free(value);
+ goto out;
+ }
+
+ cert_file++;
+
+ dirname = g_strdup_printf("%s/%s_%s", WIFI_CERT_STORAGEDIR,
+ mac_str, encoded_ssid);
+ if (dirname == NULL) {
+ ERR("Failed to create dirname");
+ g_free(field);
+ g_free(value);
+ goto out;
+ }
+ if (g_file_test(dirname, G_FILE_TEST_IS_DIR) != TRUE) {
+ if (mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
+ S_IXGRP | S_IROTH | S_IXOTH) < 0) {
+ if (errno != EEXIST) {
+ g_free(dirname);
+ g_free(field);
+ g_free(value);
+ goto out;
+ }
+ }
+ }
+ g_free(dirname);
+
+ cert_path = g_strdup_printf("%s/%s_%s/%s", WIFI_CERT_STORAGEDIR,
+ mac_str, encoded_ssid, cert_file);
+ if (cert_path == NULL) {
+ ERR("Failed to create cert path");
+ g_free(field);
+ g_free(value);
+ goto out;
+ }
+ if (__netconfig_copy_config(value, cert_path) != TRUE) {
+ ERR("Failed to read cert file %s", value);
+ g_free(cert_path);
+ g_free(field);
+ g_free(value);
+ goto out;
+ }
+
+ g_key_file_set_string(keyfile, group_name, field, cert_path);
+ g_free(cert_path);
+ }
+ } else {
+ if (value != NULL)
+ g_key_file_set_string(keyfile, group_name, field, value);
+ }
+ }
- if (NULL != value)
- g_key_file_set_string(keyfile, grp_name, field, value);
+ err = __config_save(mac_str, keyfile);
+ if (err < 0)
+ ERR("Failed to create configuration %s[%d]", mac_str, err);
+ else {
+ DBG("Successfully created %s", mac_str);
+ updated = TRUE;
}
- file_name = g_strdup_printf("%s/%s.config", CONNMAN_STORAGEDIR,
- ssid_hex);
- if(NULL == file_name) {
- DBG("g_strdup_printf() fails. Could not save config!");
+out:
+ if (keyfile)
g_key_file_free(keyfile);
- g_free(grp_name);
- g_free(ssid_hex);
- return FALSE;
+
+ g_variant_iter_free(iter);
+
+ g_free(group_name);
+ g_free(encoded_ssid);
+
+ return updated;
+}
+
+static gboolean _delete_configuration(const char *interface_name, const char *profile)
+{
+ gboolean ret = FALSE;
+ gchar *config_id = NULL;
+
+ ret = wifi_config_get_config_id(profile, &config_id);
+ if (ret != TRUE) {
+ ERR("Fail to get config_id from [%s]", profile);
+ return ret;
}
+ ERR("get config_id [%s] from [%s]", config_id, profile);
- ret = __config_save(keyfile, file_name);
- if (FALSE == ret)
- DBG("Could not save config!");
- else
- DBG("Saved config in [%s] successfully", file_name);
+ ret = wifi_config_remove_configuration(interface_name, config_id);
+ if (ret != TRUE)
+ ERR("Fail to wifi_config_remove_configuration [%s]", config_id);
- g_key_file_free(keyfile);
- g_free(file_name);
- g_free(grp_name);
- g_free(ssid_hex);
+ if (config_id != NULL)
+ g_free(config_id);
return ret;
}
-gboolean netconfig_iface_wifi_delete_config(NetconfigWifi *wifi,
- gchar *profile, GError **error)
+static gboolean __netconfig_delete_config(const char *profile)
{
- DBG("netconfig_iface_wifi_delete_config");
- g_return_val_if_fail(wifi != NULL, FALSE);
-
- gboolean ret = TRUE;
- char *str1 = NULL;
- char *str2 = NULL;
- char *str3 = NULL;
- char ssid[512] = "";
+ char *wifi_ident = NULL;
+ char *essid = NULL;
+ char *mode = NULL;
+ char *ssid = NULL;
int ssid_len = 0;
+ int err = 0;
+ const char *interface_name = NULL;
+ char mac_str[13] = { 0, };
- str1 = strstr(profile, "wifi_");
- if (NULL != str1) {
- str2 = strchr(str1 + 5, '_');
- if (NULL != str2) {
- str3 = strchr(str2 + 1, '_');
- ssid_len = str3 - str2 - 1;
- strncpy(ssid, str2 + 1, ssid_len);
- DBG("ssid_len - [%d] SSID - [%s]", ssid_len, ssid);
-
- ret = __config_delete(ssid);
- if (TRUE == ret)
- DBG("Deleted the config file successfully");
- else
- DBG("Deletion of config file failed");
- } else {
- DBG("Fetching of SSID fails");
+ if (NULL == profile) {
+ ERR("Invalid profile name");
+ return FALSE;
+ }
+
+ interface_name = netconfig_get_ifname(profile);
+ if (interface_name == NULL) {
+ ERR("Invalid profile name");
+ return FALSE;
+ }
+
+ if (_delete_configuration(interface_name, profile) != TRUE)
+ ERR("Fail to delete configuration [%s]", profile);
+
+ wifi_ident = strstr(profile, "wifi_");
+ if (wifi_ident == NULL) {
+ ERR("Invalid profile name");
+ return FALSE;
+ }
+
+ essid = strchr(wifi_ident + 5, '_');
+ if (essid == NULL) {
+ ERR("Invalid profile name");
+ return FALSE;
+ }
+
+ essid++;
+ mode = strchr(essid, '_');
+
+ ssid_len = mode - essid;
+
+ ssid = g_try_malloc0(ssid_len + 1);
+ if (ssid == NULL) {
+ ERR("Memory allocation failed");
+ return FALSE;
+ }
+
+ g_strlcpy(ssid, essid, ssid_len + 1); /* include NULL-terminated */
+
+ memcpy(mac_str, &profile[strlen(CONNMAN_WIFI_SERVICE_PROFILE_PREFIX)], 12);
+ mac_str[12] = '\0';
+
+ err = __config_delete(mac_str, ssid);
+ if (err < 0) {
+ ERR("Failed to delete configuration %s[%d]", ssid, err);
+ g_free(ssid);
+ return FALSE;
+ }
+
+ DBG("Successfully deleted %s with length %d", ssid, ssid_len);
+
+ g_free(ssid);
+ return TRUE;
+}
+
+static void __netconfig_eap_state(wifi_state_notifier_s *notifier,
+ char *service, wifi_service_state_e state, void *user_data)
+{
+ if (notifier == NULL)
+ return;
+
+ if (service == NULL) {
+ wifi_state_notifier_unregister(notifier);
+ g_free(notifier->service);
+ g_free(notifier->user_data);
+ g_free(notifier);
+ return;
+ }
+
+ if (state != NETCONFIG_WIFI_CONNECTED && state != NETCONFIG_WIFI_FAILURE)
+ return;
+
+ if (state == NETCONFIG_WIFI_FAILURE)
+ __netconfig_delete_config(service);
+
+ wifi_state_notifier_unregister(notifier);
+ g_free(notifier->service);
+ g_free(notifier->user_data);
+ g_free(notifier);
+}
+
+gboolean handle_create_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
+ const gchar *service, GVariant *fields)
+{
+ gboolean updated = FALSE;
+ gboolean result = FALSE;
+ wifi_state_notifier_s *state_notifier = NULL;
+ const char *interface_name = NULL;
+
+ g_return_val_if_fail(wifi != NULL, TRUE);
+
+ DBG("Set agent fields for %s", service);
+
+ if (netconfig_is_wifi_profile(service) != TRUE) {
+ netconfig_error_dbus_method_return(context,
+ NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
+ return TRUE;
+ }
+
+ interface_name = netconfig_get_ifname(service);
+ if (interface_name == NULL) {
+ netconfig_error_dbus_method_return(context,
+ NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
+ return TRUE;
+ }
+
+ updated = __netconfig_create_config(service, fields);
+ if (updated == TRUE) {
+ wifi_complete_create_eap_config(wifi, context);
+
+ if (g_strstr_len(service, strlen(service), "_hidden_") != NULL) {
+ GVariantIter *iter;
+ char *field, *value;
+ const char *name = NULL;
+ const char *identity = NULL;
+ const char *passphrase = NULL;
+
+ g_variant_get(fields, "a{ss}", &iter);
+
+ while (g_variant_iter_loop(iter, "{ss}", &field, &value)) {
+ if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_NAME) == 0)
+ name = (const char *)value;
+ else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_SSID) == 0)
+ name = (const char *)value;
+ else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0)
+ identity = (const char *)value;
+ else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0)
+ passphrase = (const char *)value;
+ }
+
+ netconfig_wifi_set_agent_field_for_eap_network(interface_name,
+ name, identity, passphrase);
+
+ g_variant_iter_free(iter);
+ }
+
+ result = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
+ service, CONNMAN_SERVICE_INTERFACE, "Connect",
+ NULL, __netconfig_wifi_connect_reply,
+ g_strdup(interface_name));
+
+ state_notifier = g_try_malloc0(sizeof(wifi_state_notifier_s));
+ if (state_notifier) {
+ state_notifier->notifier = state_notifier;
+ state_notifier->service = g_strdup(service);
+ state_notifier->wifi_state_changed = __netconfig_eap_state;
+ wifi_state_notifier_register(state_notifier);
}
} else {
- DBG("Fetching of SSID fails");
+ netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INVALID_PARAMETER, "InvalidArguments");
}
- return ret;
+ if (result != TRUE)
+ ERR("Fail to connect %s", service);
+
+ return TRUE;
+}
+
+gboolean handle_delete_eap_config(Wifi *wifi, GDBusMethodInvocation *context,
+ const gchar *profile)
+{
+ g_return_val_if_fail(wifi != NULL, TRUE);
+
+ __netconfig_delete_config(profile);
+
+ wifi_complete_delete_eap_config(wifi, context);
+
+ return TRUE;
}