Fix path traversal
[platform/core/connectivity/net-config.git] / src / wifi-config.c
index acf7bf1..88cda23 100755 (executable)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -28,6 +29,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <sys/time.h>
 
 #include <vconf.h>
 
 #define WIFI_SECURITY_EAP              "ieee8021x"
 #define WIFI_SECURITY_SAE              "sae"
 
-#define WIFI_CONFIG_PREFIX      "wifi_"
-#define MAC_ADDRESS_LENGTH             12
-#define WIFI_PREFIX_LENGTH             MAC_ADDRESS_LENGTH + 6  /* wifi_485a3f2f506a_ */
-#define PROFILE_PREFIX_LENGTH  WIFI_PREFIX_LENGTH + 21 /* /net/connman/service/wifi_485a3f2f506a_ */
-
 #define        NET_DNS_ADDR_MAX                2
 
 #define MAX_WIFI_PROFILES              200
@@ -202,6 +199,11 @@ gboolean wifi_config_get_group_name(const gchar *prefix,
        gchar *g_name = NULL;
        gboolean ret = FALSE;
 
+       if (__netconfig_is_valid_config_id(config_id) == FALSE) {
+               ERR("Invalid config_id [%s]", config_id);
+               return FALSE;
+       }
+
        ret = __get_mac_address(interface_name, &mac_address);
        if ((ret != TRUE) || (strlen(mac_address) == 0)) {
                ERR("Cannot get WIFI MAC address");
@@ -288,16 +290,37 @@ static gboolean __remove_file(const gchar *pathname, const gchar *filename)
        return ret;
 }
 
+static gboolean __remove_all_files(const gchar *pathname)
+{
+       DIR *dir_ptr = NULL;
+       struct dirent *file = NULL;
+
+       if ((dir_ptr = opendir(pathname)) == NULL)
+               return TRUE;
+
+       while ((file = readdir(dir_ptr)) != NULL) {
+               if (strncmp(file->d_name, ".", 1) == 0 || strncmp(file->d_name, "..", 2) == 0)
+                       continue;
+
+               if (__remove_file(pathname, file->d_name) != TRUE) {
+                       ERR("Cannot remove [%s/%s]", pathname, file->d_name);
+                       closedir(dir_ptr);
+
+                       return FALSE;
+               }
+       }
+
+       closedir(dir_ptr);
+
+       return TRUE;
+}
+
 static gboolean __remove_configuration(const gchar *pathname)
 {
        int ret = 0;
 
-       if (__remove_file(pathname, "settings") != TRUE) {
-               ERR("Cannot remove [%s/settings]", pathname);
-               return FALSE;
-       }
-       if (__remove_file(pathname, "data") != TRUE) {
-               ERR("Cannot remove [%s/data]", pathname);
+       if (__remove_all_files(pathname) != TRUE) {
+               ERR("Cannot remove [%s] directory", pathname);
                return FALSE;
        }
 
@@ -334,6 +357,13 @@ static gboolean _load_configuration(const gchar *interface_name,
        config->name = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_NAME, NULL);
        DBG("name [%s]", config->name);
 
+       if (config->name == NULL) {
+               ERR("Fail to get Name of [%s]", group_name);
+               g_key_file_free(keyfile);
+               g_free(group_name);
+               return FALSE;
+       }
+
        __get_security_type(config_id, &config->security_type);
        if (config->security_type == NULL) {
                ERR("Fail to _get_security_type");
@@ -522,9 +552,10 @@ static gboolean _remove_configuration(const gchar *interface_name, const gchar *
                if (__remove_configuration(dir) != TRUE) {
                        ERR("[%s] is existed, but cannot remove", dir);
                        ret = FALSE;
+               } else {
+                       INFO("Success to remove [%s]", dir);
+                       ret = TRUE;
                }
-               INFO("Success to remove [%s]", dir);
-               ret = TRUE;
        } else {
                ERR("[%s] is not existed", dir);
                ret = FALSE;
@@ -624,7 +655,14 @@ static gboolean _get_field(const gchar *interface_name,
        if (g_strcmp0(key, WIFI_CONFIG_NAME) == 0) {
                val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_NAME, NULL);
        } else if (g_strcmp0(key, WIFI_CONFIG_PASSPHRASE) == 0) {
-               val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, NULL);
+               gchar *enc_pass = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, NULL);
+               if (enc_pass) {
+                       val = _netconfig_decrypt_passphrase(enc_pass);
+                       g_free(enc_pass);
+
+                       if (!val)
+                               ERR("Failed to decrypt the passphrase");
+               }
        } else if (g_strcmp0(key, WIFI_CONFIG_PROXY_SERVER) == 0) {
                val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PROXY_SERVER, NULL);
        } else if (g_strcmp0(key, WIFI_CONFIG_HIDDEN) == 0) {
@@ -1111,7 +1149,7 @@ gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_SECURITY_TYPE, g_variant_new_string(conf->security_type));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PASSPHRASE, g_variant_new_string(conf->passphrase));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_HIDDEN, g_variant_new_string(conf->is_hidden));
-       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_int32(conf->frequency));
+       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_uint32(conf->frequency));
 
        if (conf->proxy_address != NULL)
                g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PROXYADDRESS, g_variant_new_string(conf->proxy_address));
@@ -1182,6 +1220,27 @@ static unsigned char __netconfig_convert_netmask_to_prefixlen(
        return bits;
 }
 
+gboolean __netconfig_is_valid_config_id(const gchar *config_id)
+{
+       int length;
+
+       if (!config_id)
+               return FALSE;
+
+       length = strlen(config_id);
+       if (length < 1 || length > WIFI_CONFIG_ID_LENGTH)
+               return FALSE;
+
+       for (int i = 0; i < length; i++) {
+               if (!(islower(config_id[i])) &&
+                               !(isdigit(config_id[i])) &&
+                               config_id[i] != '_')
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
 gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                const gchar *ifname, const gchar *config_id, GVariant *configuration)
 {
@@ -1193,8 +1252,12 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        gchar *field;
        gchar *group_name = NULL;
        int order = 0;
+       int rv;
+       struct timeval modified_time;
 
-       if ((wifi == NULL) || (config_id == NULL) || (configuration == NULL)) {
+       if ((wifi == NULL) ||
+                       (__netconfig_is_valid_config_id(config_id) == FALSE) ||
+                       (configuration == NULL)) {
                ERR("Invalid parameter");
                netconfig_error_invalid_parameter(context);
                return TRUE;
@@ -1234,8 +1297,8 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                                conf->is_hidden = NULL;
                        }
                } else if (g_strcmp0(field, WIFI_CONFIG_FREQUENCY) == 0) {
-                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
-                               conf->frequency = g_variant_get_int32(value);
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+                               conf->frequency = g_variant_get_uint32(value);
                                DBG("frequency [%d]", conf->frequency);
                        } else {
                                conf->frequency = 0;
@@ -1344,31 +1407,22 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_FAVORITE, conf->favorite);
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_AUTOCONNECT, conf->autoconnect);
 
-#if GLIB_CHECK_VERSION(2,62,0)
-       gint64 real_time = 0;
-       GDateTime *dt_real_time = NULL;
-
-       real_time = g_get_real_time();
-       dt_real_time = g_date_time_new_from_unix_utc(real_time);
-       if (dt_real_time) {
-               gchar *str = g_date_time_format_iso8601(dt_real_time);
-               g_date_time_unref(dt_real_time);
-               if (str) {
-                       g_key_file_set_string(keyfile, group_name,
-                                             WIFI_CONFIG_MODIFIED, str);
-                       g_free(str);
+       rv = gettimeofday(&modified_time, NULL);
+       if (!rv) {
+               struct tm modified_tm;
+               char time_buf[255];
+               time_t modified_t = modified_time.tv_sec;
+
+               if (localtime_r(&modified_t, &modified_tm)) {
+                       if (strftime(time_buf, sizeof(time_buf), "%FT%TZ", &modified_tm)) {
+                               field = g_strdup(time_buf);
+                               if (field) {
+                                       g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_MODIFIED, field);
+                                       g_free(field);
+                               }
+                       }
                }
        }
-#else /* GLIB_CHECK_VERSION(2,62,0) */
-       GTimeVal modified;
-       g_get_current_time(&modified);
-       gchar *str = g_time_val_to_iso8601(&modified);
-       if (str) {
-               g_key_file_set_string(keyfile, group_name,
-                                     WIFI_CONFIG_MODIFIED, str);
-               g_free(str);
-       }
-#endif /* GLIB_CHECK_VERSION(2,62,0) */
 
        /* Optional field */
        if (conf->proxy_address != NULL) {
@@ -1485,7 +1539,7 @@ gboolean handle_load_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_NAME, g_variant_new_string(conf->name));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_SECURITY_TYPE, g_variant_new_string(conf->security_type));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_HIDDEN, g_variant_new_string(conf->is_hidden));
-       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_int32(conf->frequency));
+       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_uint32(conf->frequency));
 
        if (conf->proxy_address != NULL)
                g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PROXYADDRESS, g_variant_new_string(conf->proxy_address));
@@ -1602,8 +1656,8 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
                                conf->is_hidden = NULL;
                        }
                } else if (g_strcmp0(field, WIFI_CONFIG_FREQUENCY) == 0) {
-                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
-                               conf->frequency = g_variant_get_int32(value);
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+                               conf->frequency = g_variant_get_uint32(value);
                                DBG("frequency [%d]", conf->frequency);
                        } else {
                                conf->frequency = 0;
@@ -1816,6 +1870,52 @@ gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        return TRUE;
 }
 
+gboolean handle_reset_wifi_config(Wifi *wifi, GDBusMethodInvocation *context)
+{
+       DIR *dir_ptr = NULL;
+       struct dirent *file = NULL;
+       struct stat buf;
+       char dir_name[512] = { 0, };
+       char file_name[1024] = { 0, };
+
+       g_return_val_if_fail(wifi != NULL, TRUE);
+
+       DBG("Try to remove connman Wi-Fi config files...");
+
+       if ((dir_ptr = opendir(CONNMAN_STORAGE)) != NULL) {
+               while ((file = readdir(dir_ptr)) != NULL) {
+                       if (strncmp(file->d_name, ".", 1) == 0 || strncmp(file->d_name, "..", 2) == 0 ||
+                                       strncmp(file->d_name, WIFI_CONFIG_PREFIX, strlen(WIFI_CONFIG_PREFIX)) != 0) {
+                               continue;
+                       }
+
+                       snprintf(dir_name, 512, CONNMAN_STORAGE"/%s", file->d_name);
+
+                       if (lstat(dir_name, &buf) == -1)
+                               continue;
+
+                       DBG("Remove wifi config: %s", file->d_name);
+
+                       if (S_ISDIR(buf.st_mode)) {
+                               memset(file_name, 0, 1024);
+                               snprintf(file_name, 1024, "%s/data", dir_name);
+                               unlink(file_name);
+                               memset(file_name, 0, 1024);
+                               snprintf(file_name, 1024, "%s/settings", dir_name);
+                               unlink(file_name);
+                       }
+                       rmdir(dir_name);
+               }
+
+               closedir(dir_ptr);
+               sync();
+       }
+
+       wifi_complete_reset_wifi_config(wifi, context);
+
+       return TRUE;
+}
+
 /* config field key / value */
 /*
  * [wifi_macaddress_config_id]
@@ -1898,7 +1998,7 @@ gboolean handle_get_config_passphrase(Wifi *wifi, GDBusMethodInvocation *context
        gboolean ret = FALSE;
        gchar *passphrase = NULL;
 
-       if ((wifi == NULL) || (config_id == NULL)) {
+       if ((wifi == NULL) || (ifname == NULL) || (config_id == NULL)) {
                ERR("Invalid parameter");
                netconfig_error_invalid_parameter(context);
                return TRUE;