diff options
Diffstat (limited to 'src/settings/plugins/keyfile/reader.c')
| -rw-r--r-- | src/settings/plugins/keyfile/reader.c | 1266 |
1 files changed, 0 insertions, 1266 deletions
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c deleted file mode 100644 index a8eaaa8e..00000000 --- a/src/settings/plugins/keyfile/reader.c +++ /dev/null @@ -1,1266 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - keyfile plugin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2008 - 2010 Red Hat, Inc. - */ - -#include <errno.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/types.h> -#include <dbus/dbus-glib.h> -#include <nm-setting.h> -#include <nm-setting-ip4-config.h> -#include <nm-setting-ip6-config.h> -#include <nm-setting-vpn.h> -#include <nm-setting-connection.h> -#include <nm-setting-wired.h> -#include <nm-setting-wireless.h> -#include <nm-setting-bluetooth.h> -#include <nm-setting-8021x.h> -#include <arpa/inet.h> -#include <netinet/ether.h> -#include <string.h> -#include <ctype.h> - -#include "nm-dbus-glib-types.h" -#include "reader.h" -#include "common.h" - -static gboolean -read_array_of_uint (GKeyFile *file, - NMSetting *setting, - const char *key) -{ - GArray *array = NULL; - gsize length; - int i; - gint *tmp; - - tmp = g_key_file_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL); - array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length); - for (i = 0; i < length; i++) - g_array_append_val (array, tmp[i]); - - if (array) { - g_object_set (setting, key, array, NULL); - g_array_free (array, TRUE); - } - - return TRUE; -} - -static gboolean -get_one_int (const char *str, guint32 max_val, const char *key_name, guint32 *out) -{ - long tmp; - - errno = 0; - tmp = strtol (str, NULL, 10); - if (errno || (tmp < 0) || (tmp > max_val)) { - g_warning ("%s: ignoring invalid IP %s item '%s'", __func__, key_name, str); - return FALSE; - } - - *out = (guint32) tmp; - return TRUE; -} - -static void -free_one_ip4_address (gpointer data, gpointer user_data) -{ - g_array_free ((GArray *) data, TRUE); -} - -static GPtrArray * -read_ip4_addresses (GKeyFile *file, - const char *setting_name, - const char *key) -{ - GPtrArray *addresses; - int i = 0; - - addresses = g_ptr_array_sized_new (3); - - /* Look for individual addresses */ - while (i++ < 1000) { - gchar **tmp, **iter; - char *key_name; - gsize length = 0; - int ret; - GArray *address; - guint32 empty = 0; - int j; - - key_name = g_strdup_printf ("%s%d", key, i); - tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL); - g_free (key_name); - - if (!tmp || !length) - break; /* all done */ - - if ((length < 2) || (length > 3)) { - g_warning ("%s: ignoring invalid IPv4 address item '%s'", __func__, key_name); - goto next; - } - - /* convert the string array into IP addresses */ - address = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3); - for (iter = tmp, j = 0; *iter; iter++, j++) { - struct in_addr addr; - - if (j == 1) { - guint32 prefix = 0; - - /* prefix */ - if (!get_one_int (*iter, 32, key_name, &prefix)) { - g_array_free (address, TRUE); - goto next; - } - - g_array_append_val (address, prefix); - } else { - /* address and gateway */ - ret = inet_pton (AF_INET, *iter, &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter); - g_array_free (address, TRUE); - goto next; - } - g_array_append_val (address, addr.s_addr); - } - } - - /* fill in blank gateway if not specified */ - if (address->len == 2) - g_array_append_val (address, empty); - - g_ptr_array_add (addresses, address); - -next: - g_strfreev (tmp); - } - - if (addresses->len < 1) { - g_ptr_array_free (addresses, TRUE); - addresses = NULL; - } - - return addresses; -} - -static void -ip4_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - GPtrArray *addresses; - const char *setting_name = nm_setting_get_name (setting); - - addresses = read_ip4_addresses (keyfile, setting_name, key); - - /* Work around for previous syntax */ - if (!addresses && !strcmp (key, NM_SETTING_IP4_CONFIG_ADDRESSES)) - addresses = read_ip4_addresses (keyfile, setting_name, "address"); - - if (addresses) { - g_object_set (setting, key, addresses, NULL); - g_ptr_array_foreach (addresses, free_one_ip4_address, NULL); - g_ptr_array_free (addresses, TRUE); - } -} - -static void -free_one_ip4_route (gpointer data, gpointer user_data) -{ - g_array_free ((GArray *) data, TRUE); -} - -static GPtrArray * -read_ip4_routes (GKeyFile *file, - const char *setting_name, - const char *key) -{ - GPtrArray *routes; - int i = 0; - - routes = g_ptr_array_sized_new (3); - - /* Look for individual routes */ - while (i++ < 1000) { - gchar **tmp, **iter; - char *key_name; - gsize length = 0; - int ret; - GArray *route; - int j; - - key_name = g_strdup_printf ("%s%d", key, i); - tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL); - g_free (key_name); - - if (!tmp || !length) - break; /* all done */ - - if (length != 4) { - g_warning ("%s: ignoring invalid IPv4 route item '%s'", __func__, key_name); - goto next; - } - - /* convert the string array into IP addresses */ - route = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4); - for (iter = tmp, j = 0; *iter; iter++, j++) { - struct in_addr addr; - - if (j == 1) { - guint32 prefix = 0; - - /* prefix */ - if (!get_one_int (*iter, 32, key_name, &prefix)) { - g_array_free (route, TRUE); - goto next; - } - - g_array_append_val (route, prefix); - } else if (j == 3) { - guint32 metric = 0; - - /* metric */ - if (!get_one_int (*iter, G_MAXUINT32, key_name, &metric)) { - g_array_free (route, TRUE); - goto next; - } - - g_array_append_val (route, metric); - } else { - /* address and next hop */ - ret = inet_pton (AF_INET, *iter, &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv4 %s element '%s'", __func__, key_name, *iter); - g_array_free (route, TRUE); - goto next; - } - g_array_append_val (route, addr.s_addr); - } - } - g_ptr_array_add (routes, route); - -next: - g_strfreev (tmp); - } - - if (routes->len < 1) { - g_ptr_array_free (routes, TRUE); - routes = NULL; - } - - return routes; -} - -static void -ip4_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - GPtrArray *routes; - const char *setting_name = nm_setting_get_name (setting); - - routes = read_ip4_routes (keyfile, setting_name, key); - if (routes) { - g_object_set (setting, key, routes, NULL); - g_ptr_array_foreach (routes, free_one_ip4_route, NULL); - g_ptr_array_free (routes, TRUE); - } -} - -static void -ip4_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - const char *setting_name = nm_setting_get_name (setting); - GArray *array = NULL; - gsize length; - char **list, **iter; - int ret; - - list = g_key_file_get_string_list (keyfile, setting_name, key, &length, NULL); - if (!list || !g_strv_length (list)) - return; - - array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length); - for (iter = list; *iter; iter++) { - struct in_addr addr; - - ret = inet_pton (AF_INET, *iter, &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid DNS server address '%s'", __func__, *iter); - continue; - } - - g_array_append_val (array, addr.s_addr); - } - g_strfreev (list); - - if (array) { - g_object_set (setting, key, array, NULL); - g_array_free (array, TRUE); - } -} - -static void -free_one_ip6_address (gpointer data, gpointer user_data) -{ - g_value_array_free ((GValueArray *) data); -} - -static char * -split_prefix (char *addr) -{ - char *slash; - - g_return_val_if_fail (addr != NULL, NULL); - - /* Find the prefix and split the string */ - slash = strchr (addr, '/'); - if (slash && slash > addr) { - slash++; - *(slash - 1) = '\0'; - } - - return slash; -} - -static char * -split_gw (char *str) -{ - char *comma; - - g_return_val_if_fail (str != NULL, NULL); - - /* Find the prefix and split the string */ - comma = strchr (str, ','); - if (comma && comma > str) { - comma++; - *(comma - 1) = '\0'; - return comma; - } - return NULL; -} - -static GPtrArray * -read_ip6_addresses (GKeyFile *file, - const char *setting_name, - const char *key) -{ - GPtrArray *addresses; - struct in6_addr addr, gw; - guint32 prefix; - int i = 0; - - addresses = g_ptr_array_sized_new (3); - - /* Look for individual addresses */ - while (i++ < 1000) { - char *tmp, *key_name, *str_prefix, *str_gw; - int ret; - GValueArray *values; - GByteArray *address; - GByteArray *gateway; - GValue value = { 0 }; - - key_name = g_strdup_printf ("%s%d", key, i); - tmp = g_key_file_get_string (file, setting_name, key_name, NULL); - g_free (key_name); - - if (!tmp) - break; /* all done */ - - /* convert the string array into IPv6 addresses */ - values = g_value_array_new (2); /* NMIP6Address has 2 items */ - - /* Split the address and prefix */ - str_prefix = split_prefix (tmp); - - /* address */ - ret = inet_pton (AF_INET6, tmp, &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp); - g_value_array_free (values); - goto next; - } - - address = g_byte_array_new (); - g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); - g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_take_boxed (&value, address); - g_value_array_append (values, &value); - g_value_unset (&value); - - /* prefix */ - prefix = 0; - if (str_prefix) { - if (!get_one_int (str_prefix, 128, key_name, &prefix)) { - g_value_array_free (values); - goto next; - } - } else { - /* Missing prefix defaults to /64 */ - prefix = 64; - } - - g_value_init (&value, G_TYPE_UINT); - g_value_set_uint (&value, prefix); - g_value_array_append (values, &value); - g_value_unset (&value); - - /* Gateway (optional) */ - str_gw = split_gw (str_prefix); - if (str_gw) { - ret = inet_pton (AF_INET6, str_gw, &gw); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp); - g_value_array_free (values); - goto next; - } - - if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) { - gateway = g_byte_array_new (); - g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16); - g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_take_boxed (&value, gateway); - g_value_array_append (values, &value); - g_value_unset (&value); - } - } - - g_ptr_array_add (addresses, values); - -next: - g_free (tmp); - } - - if (addresses->len < 1) { - g_ptr_array_free (addresses, TRUE); - addresses = NULL; - } - - return addresses; -} - -static void -ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - GPtrArray *addresses; - const char *setting_name = nm_setting_get_name (setting); - - addresses = read_ip6_addresses (keyfile, setting_name, key); - if (addresses) { - g_object_set (setting, key, addresses, NULL); - g_ptr_array_foreach (addresses, free_one_ip6_address, NULL); - g_ptr_array_free (addresses, TRUE); - } -} - -static void -free_one_ip6_route (gpointer data, gpointer user_data) -{ - g_value_array_free ((GValueArray *) data); -} - -static GPtrArray * -read_ip6_routes (GKeyFile *file, - const char *setting_name, - const char *key) -{ - GPtrArray *routes; - struct in6_addr addr; - guint32 prefix, metric; - int i = 0; - - routes = g_ptr_array_sized_new (3); - - /* Look for individual routes */ - while (i++ < 1000) { - gchar **tmp; - char *key_name, *str_prefix; - gsize length = 0; - int ret; - GValueArray *values; - GByteArray *address; - GValue value = { 0 }; - - key_name = g_strdup_printf ("%s%d", key, i); - tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL); - g_free (key_name); - - if (!tmp || !length) - break; /* all done */ - - if (length != 3) { - g_warning ("%s: ignoring invalid IPv6 address item '%s'", __func__, key_name); - goto next; - } - - /* convert the string array into IPv6 routes */ - values = g_value_array_new (4); /* NMIP6Route has 4 items */ - - /* Split the route and prefix */ - str_prefix = split_prefix (tmp[0]); - - /* destination address */ - ret = inet_pton (AF_INET6, tmp[0], &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[0]); - g_value_array_free (values); - goto next; - } - address = g_byte_array_new (); - g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); - g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_take_boxed (&value, address); - g_value_array_append (values, &value); - g_value_unset (&value); - - /* prefix */ - prefix = 0; - if (str_prefix) { - if (!get_one_int (str_prefix, 128, key_name, &prefix)) { - g_value_array_free (values); - goto next; - } - } else { - /* default to 64 if unspecified */ - prefix = 64; - } - g_value_init (&value, G_TYPE_UINT); - g_value_set_uint (&value, prefix); - g_value_array_append (values, &value); - g_value_unset (&value); - - /* next hop address */ - ret = inet_pton (AF_INET6, tmp[1], &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[1]); - g_value_array_free (values); - goto next; - } - address = g_byte_array_new (); - g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); - g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_take_boxed (&value, address); - g_value_array_append (values, &value); - g_value_unset (&value); - - /* metric */ - metric = 0; - if (!get_one_int (tmp[2], G_MAXUINT32, key_name, &metric)) { - g_value_array_free (values); - goto next; - } - g_value_init (&value, G_TYPE_UINT); - g_value_set_uint (&value, metric); - g_value_array_append (values, &value); - g_value_unset (&value); - - g_ptr_array_add (routes, values); - -next: - g_strfreev (tmp); - } - - if (routes->len < 1) { - g_ptr_array_free (routes, TRUE); - routes = NULL; - } - - return routes; -} - -static void -ip6_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - GPtrArray *routes; - const char *setting_name = nm_setting_get_name (setting); - - routes = read_ip6_routes (keyfile, setting_name, key); - - if (routes) { - g_object_set (setting, key, routes, NULL); - g_ptr_array_foreach (routes, free_one_ip6_route, NULL); - g_ptr_array_free (routes, TRUE); - } -} - -static void -free_one_ip6_dns (gpointer data, gpointer user_data) -{ - g_byte_array_free ((GByteArray *) data, TRUE); -} - -static void -ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - const char *setting_name = nm_setting_get_name (setting); - GPtrArray *array = NULL; - gsize length; - char **list, **iter; - int ret; - - list = g_key_file_get_string_list (keyfile, setting_name, key, &length, NULL); - if (!list || !g_strv_length (list)) - return; - - array = g_ptr_array_sized_new (length); - for (iter = list; *iter; iter++) { - GByteArray *byte_array; - struct in6_addr addr; - - ret = inet_pton (AF_INET6, *iter, &addr); - if (ret <= 0) { - g_warning ("%s: ignoring invalid DNS server IPv6 address '%s'", __func__, *iter); - continue; - } - byte_array = g_byte_array_new (); - g_byte_array_append (byte_array, (guint8 *) addr.s6_addr, 16); - - g_ptr_array_add (array, byte_array); - } - g_strfreev (list); - - if (array) { - g_object_set (setting, key, array, NULL); - g_ptr_array_foreach (array, free_one_ip6_dns, NULL); - g_ptr_array_free (array, TRUE); - } -} - -static void -mac_address_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - const char *setting_name = nm_setting_get_name (setting); - struct ether_addr *eth; - char *tmp_string = NULL, *p; - gint *tmp_list; - GByteArray *array = NULL; - gsize length; - int i; - - p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL); - if (tmp_string) { - /* Look for enough ':' characters to signify a MAC address */ - i = 0; - while (*p) { - if (*p == ':') - i++; - p++; - } - if (i == 5) { - /* parse as a MAC address */ - eth = ether_aton (tmp_string); - if (eth) { - g_free (tmp_string); - array = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (array, eth->ether_addr_octet, ETH_ALEN); - goto done; - } - } - } - g_free (tmp_string); - - /* Old format; list of ints */ - tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL); - array = g_byte_array_sized_new (length); - for (i = 0; i < length; i++) { - int val = tmp_list[i]; - unsigned char v = (unsigned char) (val & 0xFF); - - if (val < 0 || val > 255) { - g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not " - " between 0 and 255 inclusive)", __func__, setting_name, - key, val); - } else - g_byte_array_append (array, (const unsigned char *) &v, sizeof (v)); - } - g_free (tmp_list); - -done: - if (array->len == ETH_ALEN) { - g_object_set (setting, key, array, NULL); - } else { - g_warning ("%s: ignoring invalid MAC address for %s / %s", - __func__, setting_name, key); - } - g_byte_array_free (array, TRUE); -} - -static void -read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key) -{ - char **keys, **iter; - char *value; - const char *setting_name = nm_setting_get_name (setting); - - keys = g_key_file_get_keys (file, setting_name, NULL, NULL); - if (!keys || !*keys) - return; - - for (iter = keys; *iter; iter++) { - value = g_key_file_get_string (file, setting_name, *iter, NULL); - if (!value) - continue; - - if (NM_IS_SETTING_VPN (setting)) { - if (strcmp (*iter, NM_SETTING_VPN_SERVICE_TYPE)) - nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), *iter, value); - } - g_free (value); - } - g_strfreev (keys); -} - -static GByteArray * -get_uchar_array (GKeyFile *keyfile, - const char *setting_name, - const char *key) -{ - GByteArray *array = NULL; - char *p, *tmp_string; - gint *tmp_list; - gsize length; - int i; - - /* New format: just a string. We try parsing the new format if there are - * no ';' in the string or it's not just numbers. - */ - p = tmp_string = g_key_file_get_string (keyfile, setting_name, key, NULL); - if (tmp_string) { - gboolean new_format = FALSE; - - if (strchr (p, ';') == NULL) - new_format = TRUE; - else { - new_format = TRUE; - while (p && *p) { - if (!isdigit (*p++)) { - new_format = FALSE; - break; - } - } - } - - if (new_format) { - array = g_byte_array_sized_new (strlen (tmp_string)); - g_byte_array_append (array, (guint8 *) tmp_string, strlen (tmp_string)); - } - g_free (tmp_string); - } - - if (!array) { - /* Old format; list of ints */ - tmp_list = g_key_file_get_integer_list (keyfile, setting_name, key, &length, NULL); - array = g_byte_array_sized_new (length); - for (i = 0; i < length; i++) { - int val = tmp_list[i]; - unsigned char v = (unsigned char) (val & 0xFF); - - if (val < 0 || val > 255) { - g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not " - " between 0 and 255 inclusive)", __func__, setting_name, - key, val); - } else - g_byte_array_append (array, (const unsigned char *) &v, sizeof (v)); - } - g_free (tmp_list); - } - - if (array->len == 0) { - g_byte_array_free (array, TRUE); - array = NULL; - } - return array; -} - -static void -ssid_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - const char *setting_name = nm_setting_get_name (setting); - GByteArray *array; - - array = get_uchar_array (keyfile, setting_name, key); - if (array) { - g_object_set (setting, key, array, NULL); - g_byte_array_free (array, TRUE); - } else { - g_warning ("%s: ignoring invalid SSID for %s / %s", - __func__, setting_name, key); - } -} - -static char * -get_cert_path (const char *keyfile_path, GByteArray *cert_path) -{ - const char *base; - char *p = NULL, *path, *dirname, *tmp; - - g_return_val_if_fail (keyfile_path != NULL, NULL); - g_return_val_if_fail (cert_path != NULL, NULL); - - base = path = g_malloc0 (cert_path->len + 1); - memcpy (path, cert_path->data, cert_path->len); - - if (path[0] == '/') - return path; - - p = strrchr (path, '/'); - if (p) - base = p + 1; - - dirname = g_path_get_dirname (keyfile_path); - tmp = g_build_path ("/", dirname, base, NULL); - g_free (dirname); - g_free (path); - return tmp; -} - -#define SCHEME_PATH "file://" - -static void -cert_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path) -{ - const char *setting_name = nm_setting_get_name (setting); - GByteArray *array; - gboolean success = FALSE; - - array = get_uchar_array (keyfile, setting_name, key); - if (array) { - /* Value could be either: - * 1) the raw key/cert data as a blob - * 2) a path scheme (ie, starts with "file://") - * 3) a plain path - */ - if ( (array->len > strlen (SCHEME_PATH)) - && g_str_has_prefix ((const char *) array->data, SCHEME_PATH) - && (array->data[array->len - 1] == '\0')) { - /* It's the PATH scheme, can just set plain data */ - g_object_set (setting, key, array, NULL); - success = TRUE; - } else if ( (array->len < 500) - && g_utf8_validate ((const char *) array->data, array->len, NULL)) { - GByteArray *val; - char *path; - - path = get_cert_path (keyfile_path, array); - if (g_file_test (path, G_FILE_TEST_EXISTS)) { - /* Construct the proper value as required for the PATH scheme */ - val = g_byte_array_sized_new (strlen (SCHEME_PATH) + array->len + 1); - g_byte_array_append (val, (const guint8 *) SCHEME_PATH, strlen (SCHEME_PATH)); - g_byte_array_append (val, array->data, array->len); - g_byte_array_append (val, (const guint8 *) "\0", 1); - g_object_set (setting, key, val, NULL); - g_byte_array_free (val, TRUE); - success = TRUE; - } - g_free (path); - } - - if (!success) { - /* Assume it's a simple blob value of the certificate or private key's data */ - g_object_set (setting, key, array, NULL); - } - - g_byte_array_free (array, TRUE); - } else { - g_warning ("%s: ignoring invalid SSID for %s / %s", - __func__, setting_name, key); - } -} - -typedef struct { - const char *setting_name; - const char *key; - gboolean check_for_key; - void (*parser) (NMSetting *setting, const char *key, GKeyFile *keyfile, const char *keyfile_path); -} KeyParser; - -/* A table of keys that require further parsing/conversion because they are - * stored in a format that can't be automatically read using the key's type. - * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are - * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored - * in struct in6_addr internally, but as string in keyfiles. - */ -static KeyParser key_parsers[] = { - { NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP4_CONFIG_ADDRESSES, - FALSE, - ip4_addr_parser }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_ADDRESSES, - FALSE, - ip6_addr_parser }, - { NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP4_CONFIG_ROUTES, - FALSE, - ip4_route_parser }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_ROUTES, - FALSE, - ip6_route_parser }, - { NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP4_CONFIG_DNS, - FALSE, - ip4_dns_parser }, - { NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_DNS, - FALSE, - ip6_dns_parser }, - { NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_MAC_ADDRESS, - TRUE, - mac_address_parser }, - { NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_CLONED_MAC_ADDRESS, - TRUE, - mac_address_parser }, - { NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_MAC_ADDRESS, - TRUE, - mac_address_parser }, - { NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, - TRUE, - mac_address_parser }, - { NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_BSSID, - TRUE, - mac_address_parser }, - { NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_SETTING_BLUETOOTH_BDADDR, - TRUE, - mac_address_parser }, - { NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_SSID, - TRUE, - ssid_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_CA_CERT, - TRUE, - cert_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_CLIENT_CERT, - TRUE, - cert_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_PRIVATE_KEY, - TRUE, - cert_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_PHASE2_CA_CERT, - TRUE, - cert_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - TRUE, - cert_parser }, - { NM_SETTING_802_1X_SETTING_NAME, - NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - TRUE, - cert_parser }, - { NULL, NULL, FALSE } -}; - -typedef struct { - GKeyFile *keyfile; - const char *keyfile_path; -} ReadInfo; - -static void -read_one_setting_value (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data) -{ - ReadInfo *info = user_data; - const char *setting_name; - GType type; - GError *err = NULL; - gboolean check_for_key = TRUE; - KeyParser *parser = &key_parsers[0]; - - /* Property is not writable */ - if (!(flags & G_PARAM_WRITABLE)) - return; - - /* Setting name gets picked up from the keyfile's section name instead */ - if (!strcmp (key, NM_SETTING_NAME)) - return; - - /* Don't read the NMSettingConnection object's 'read-only' property */ - if ( NM_IS_SETTING_CONNECTION (setting) - && !strcmp (key, NM_SETTING_CONNECTION_READ_ONLY)) - return; - - setting_name = nm_setting_get_name (setting); - - /* Look through the list of handlers for non-standard format key values */ - while (parser->setting_name) { - if (!strcmp (parser->setting_name, setting_name) && !strcmp (parser->key, key)) { - check_for_key = parser->check_for_key; - break; - } - parser++; - } - - /* VPN properties don't have the exact key name */ - if (NM_IS_SETTING_VPN (setting)) - check_for_key = FALSE; - - /* Check for the exact key in the GKeyFile if required. Most setting - * properties map 1:1 to a key in the GKeyFile, but for those properties - * like IP addresses and routes where more than one value is actually - * encoded by the setting property, this won't be true. - */ - if (check_for_key && !g_key_file_has_key (info->keyfile, setting_name, key, &err)) { - /* Key doesn't exist or an error ocurred, thus nothing to do. */ - if (err) { - g_warning ("Error loading setting '%s' value: %s", setting_name, err->message); - g_error_free (err); - } - return; - } - - /* If there's a custom parser for this key, handle that before the generic - * parsers below. - */ - if (parser && parser->setting_name) { - (*parser->parser) (setting, key, info->keyfile, info->keyfile_path); - return; - } - - type = G_VALUE_TYPE (value); - - if (type == G_TYPE_STRING) { - char *str_val; - - str_val = g_key_file_get_string (info->keyfile, setting_name, key, NULL); - g_object_set (setting, key, str_val, NULL); - g_free (str_val); - } else if (type == G_TYPE_UINT) { - int int_val; - - int_val = g_key_file_get_integer (info->keyfile, setting_name, key, NULL); - if (int_val < 0) - g_warning ("Casting negative value (%i) to uint", int_val); - g_object_set (setting, key, int_val, NULL); - } else if (type == G_TYPE_INT) { - int int_val; - - int_val = g_key_file_get_integer (info->keyfile, setting_name, key, NULL); - g_object_set (setting, key, int_val, NULL); - } else if (type == G_TYPE_BOOLEAN) { - gboolean bool_val; - - bool_val = g_key_file_get_boolean (info->keyfile, setting_name, key, NULL); - g_object_set (setting, key, bool_val, NULL); - } else if (type == G_TYPE_CHAR) { - int int_val; - - int_val = g_key_file_get_integer (info->keyfile, setting_name, key, NULL); - if (int_val < G_MININT8 || int_val > G_MAXINT8) - g_warning ("Casting value (%i) to char", int_val); - - g_object_set (setting, key, int_val, NULL); - } else if (type == G_TYPE_UINT64) { - char *tmp_str; - guint64 uint_val; - - tmp_str = g_key_file_get_value (info->keyfile, setting_name, key, NULL); - uint_val = g_ascii_strtoull (tmp_str, NULL, 10); - g_free (tmp_str); - g_object_set (setting, key, uint_val, NULL); - } else if (type == DBUS_TYPE_G_UCHAR_ARRAY) { - gint *tmp; - GByteArray *array; - gsize length; - int i; - - tmp = g_key_file_get_integer_list (info->keyfile, setting_name, key, &length, NULL); - - array = g_byte_array_sized_new (length); - for (i = 0; i < length; i++) { - int val = tmp[i]; - unsigned char v = (unsigned char) (val & 0xFF); - - if (val < 0 || val > 255) { - g_warning ("%s: %s / %s ignoring invalid byte element '%d' (not " - " between 0 and 255 inclusive)", __func__, setting_name, - key, val); - } else - g_byte_array_append (array, (const unsigned char *) &v, sizeof (v)); - } - - g_object_set (setting, key, array, NULL); - g_byte_array_free (array, TRUE); - g_free (tmp); - } else if (type == DBUS_TYPE_G_LIST_OF_STRING) { - gchar **sa; - gsize length; - int i; - GSList *list = NULL; - - sa = g_key_file_get_string_list (info->keyfile, setting_name, key, &length, NULL); - for (i = 0; i < length; i++) - list = g_slist_prepend (list, sa[i]); - - list = g_slist_reverse (list); - g_object_set (setting, key, list, NULL); - - g_slist_free (list); - g_strfreev (sa); - } else if (type == DBUS_TYPE_G_MAP_OF_STRING) { - read_hash_of_string (info->keyfile, setting, key); - } else if (type == DBUS_TYPE_G_UINT_ARRAY) { - if (!read_array_of_uint (info->keyfile, setting, key)) { - g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'", - setting_name, key, G_VALUE_TYPE_NAME (value)); - } - } else { - g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'", - setting_name, key, G_VALUE_TYPE_NAME (value)); - } -} - -static NMSetting * -read_setting (GKeyFile *file, const char *keyfile_path, const char *setting_name) -{ - NMSetting *setting; - ReadInfo info = { file, keyfile_path }; - - setting = nm_connection_create_setting (setting_name); - if (setting) - nm_setting_enumerate_values (setting, read_one_setting_value, &info); - else - g_warning ("Invalid setting name '%s'", setting_name); - - return setting; -} - -static void -read_vpn_secrets (GKeyFile *file, NMSettingVPN *s_vpn) -{ - char **keys, **iter; - - keys = g_key_file_get_keys (file, VPN_SECRETS_GROUP, NULL, NULL); - for (iter = keys; *iter; iter++) { - char *secret; - - secret = g_key_file_get_string (file, VPN_SECRETS_GROUP, *iter, NULL); - if (secret) { - nm_setting_vpn_add_secret (s_vpn, *iter, secret); - g_free (secret); - } - } - g_strfreev (keys); -} - -NMConnection * -nm_keyfile_plugin_connection_from_file (const char *filename, GError **error) -{ - GKeyFile *key_file; - struct stat statbuf; - gboolean bad_owner, bad_permissions; - NMConnection *connection = NULL; - NMSettingConnection *s_con; - NMSetting *setting; - gchar **groups; - gsize length; - int i; - gboolean vpn_secrets = FALSE; - const char *ctype; - GError *verify_error = NULL; - - if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) { - g_set_error_literal (error, KEYFILE_PLUGIN_ERROR, 0, - "File did not exist or was not a regular file"); - return NULL; - } - - bad_owner = getuid () != statbuf.st_uid; - bad_permissions = statbuf.st_mode & 0077; - - if (bad_owner || bad_permissions) { - g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, - "File permissions (%o) or owner (%d) were insecure", - statbuf.st_mode, statbuf.st_uid); - return NULL; - } - - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) - goto out; - - connection = nm_connection_new (); - - groups = g_key_file_get_groups (key_file, &length); - for (i = 0; i < length; i++) { - /* Only read out secrets when needed */ - if (!strcmp (groups[i], VPN_SECRETS_GROUP)) { - vpn_secrets = TRUE; - continue; - } - - setting = read_setting (key_file, filename, groups[i]); - if (setting) - nm_connection_add_setting (connection, setting); - } - - /* Make sure that we have the base device type setting even if - * the keyfile didn't include it, which can happen when the base - * device type setting is all default values (like ethernet). - */ - s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); - if (s_con) { - ctype = nm_setting_connection_get_connection_type (s_con); - setting = nm_connection_get_setting_by_name (connection, ctype); - if (ctype) { - if (!setting && !strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME)) - nm_connection_add_setting (connection, nm_setting_wired_new ()); - } - } - - /* Handle vpn secrets after the 'vpn' setting was read */ - if (vpn_secrets) { - NMSettingVPN *s_vpn; - - s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); - if (s_vpn) - read_vpn_secrets (key_file, s_vpn); - } - - g_strfreev (groups); - - /* Verify the connection */ - if (!nm_connection_verify (connection, &verify_error)) { - g_set_error (error, KEYFILE_PLUGIN_ERROR, 0, - "invalid or missing connection property '%s'", - (verify_error && verify_error->message) ? verify_error->message : "(unknown)"); - g_clear_error (&verify_error); - g_object_unref (connection); - connection = NULL; - } - -out: - g_key_file_free (key_file); - return connection; -} |