diff options
Diffstat (limited to 'libnm-core/nm-keyfile-utils.c')
| -rw-r--r-- | libnm-core/nm-keyfile-utils.c | 684 |
1 files changed, 0 insertions, 684 deletions
diff --git a/libnm-core/nm-keyfile-utils.c b/libnm-core/nm-keyfile-utils.c deleted file mode 100644 index 8de4b0d2..00000000 --- a/libnm-core/nm-keyfile-utils.c +++ /dev/null @@ -1,684 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2010 Red Hat, Inc. - */ - -#include "libnm-core/nm-default-libnm-core.h" - -#include "nm-keyfile-utils.h" - -#include <stdlib.h> - -#include "nm-glib-aux/nm-str-buf.h" - -#include "nm-keyfile.h" -#include "nm-setting-wired.h" -#include "nm-setting-wireless.h" -#include "nm-setting-wireless-security.h" - -#include "nm-keyfile-internal.h" - -/*****************************************************************************/ - -/** - * nm_key_file_get_boolean: - * @kf: the #GKeyFile - * @group: the group - * @key: the key - * @default_value: the default value if the value is set or not parsable as a boolean. - * - * Replacement for g_key_file_get_boolean() (which uses g_key_file_parse_value_as_boolean()). - * g_key_file_get_boolean() seems odd to me, because it accepts trailing ASCII whitespace, - * but not leading. - * This uses _nm_utils_ascii_str_to_bool(), which accepts trailing and leading whitespace, - * case-insensitive words, and also strings like "on" and "off". - * _nm_utils_ascii_str_to_bool() is our way to parse booleans from string, and we should - * use that one consistently. - * - * Also, it doesn't have g_key_file_get_boolean()'s odd API to require an error argument - * to detect parsing failures. - * - * Returns: either %TRUE or %FALSE if the key exists and is parsable as a boolean. - * Otherwise, @default_value. Sets errno to ENODATA, EINVAL or 0, depending on whether - * the key exists, whether the value is invalid, or success. - */ -int -nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value) -{ - int v; - gs_free char *value = NULL; - - value = g_key_file_get_value(kf, group, key, NULL); - - if (!value) { - errno = ENODATA; - return default_value; - } - v = _nm_utils_ascii_str_to_bool(value, -1); - if (v != -1) { - errno = 0; - return v; - } - errno = EINVAL; - return default_value; -} - -/*****************************************************************************/ - -typedef struct { - const char *setting; - const char *alias; -} SettingAlias; - -static const SettingAlias alias_list[] = { - {NM_SETTING_WIRED_SETTING_NAME, "ethernet"}, - {NM_SETTING_WIRELESS_SETTING_NAME, "wifi"}, - {NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-security"}, -}; - -const char * -nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name) -{ - guint i; - - g_return_val_if_fail(setting_name != NULL, NULL); - - for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { - if (nm_streq(setting_name, alias_list[i].setting)) - return alias_list[i].alias; - } - return NULL; -} - -const char * -nm_keyfile_plugin_get_setting_name_for_alias(const char *alias) -{ - guint i; - - g_return_val_if_fail(alias != NULL, NULL); - - for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { - if (nm_streq(alias, alias_list[i].alias)) - return alias_list[i].setting; - } - return NULL; -} - -/*****************************************************************************/ - -char ** -nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, - const char *group, - const char *key, - gsize * out_length, - GError ** error) -{ - char ** list; - const char *alias; - GError * local = NULL; - gsize l; - - list = g_key_file_get_string_list(kf, group, key, &l, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - list = g_key_file_get_string_list(kf, alias, key, &l, &local); - } - } - if (local) - g_propagate_error(error, local); - if (!list) - l = 0; - NM_SET_OUT(out_length, l); - return list; -} - -guint * -nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * key_file, - const char *group_name, - const char *key, - gsize * out_length, - GError ** error) -{ - GError * key_file_error = NULL; - gs_strfreev char **values = NULL; - gs_free guint *int_values = NULL; - gsize i, num_ints; - - NM_SET_OUT(out_length, 0); - - g_return_val_if_fail(key_file != NULL, NULL); - g_return_val_if_fail(group_name != NULL, NULL); - g_return_val_if_fail(key != NULL, NULL); - - values = - nm_keyfile_plugin_kf_get_string_list(key_file, group_name, key, &num_ints, &key_file_error); - - if (key_file_error) - g_propagate_error(error, key_file_error); - if (!values) - return NULL; - - int_values = g_new(guint, num_ints); - - for (i = 0; i < num_ints; i++) { - gint64 v; - - G_STATIC_ASSERT_EXPR(sizeof(v) > sizeof(guint)); - v = _nm_utils_ascii_str_to_int64(values[i], 10, 0, G_MAXUINT, -1); - if (v == -1) { - g_set_error(error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("Value cannot be interpreted as a list of numbers.")); - return NULL; - } - - int_values[i] = v; - } - - NM_SET_OUT(out_length, num_ints); - return g_steal_pointer(&int_values); -} - -void -nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, - const char * group, - const char * key, - const char *const *list, - gsize length) -{ - const char *alias; - - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - g_key_file_set_string_list(kf, alias ?: group, key, list, length); -} - -void -nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, - const char * group, - const char * key, - const guint *data, - gsize length) -{ - nm_auto_str_buf NMStrBuf strbuf = {}; - gsize i; - - g_return_if_fail(kf); - g_return_if_fail(!length || data); - g_return_if_fail(group && group[0]); - g_return_if_fail(key && key[0]); - - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); - for (i = 0; i < length; i++) - nm_str_buf_append_printf(&strbuf, "%u;", data[i]); - nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); -} - -void -nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, - const char * group, - const char * key, - const guint8 *data, - gsize length) -{ - nm_auto_str_buf NMStrBuf strbuf = {}; - gsize i; - - g_return_if_fail(kf); - g_return_if_fail(!length || data); - g_return_if_fail(group && group[0]); - g_return_if_fail(key && key[0]); - - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); - for (i = 0; i < length; i++) - nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]); - nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); -} - -#define DEFINE_KF_WRAPPER_GET(fcn_name, get_ctype, key_file_get_fcn) \ - get_ctype fcn_name(GKeyFile *kf, const char *group, const char *key, GError **error) \ - { \ - get_ctype val; \ - const char *alias; \ - GError * local = NULL; \ - \ - val = key_file_get_fcn(kf, group, key, &local); \ - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \ - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ - if (alias) { \ - g_clear_error(&local); \ - val = key_file_get_fcn(kf, alias, key, &local); \ - } \ - } \ - if (local) \ - g_propagate_error(error, local); \ - return val; \ - } - -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_string, char *, g_key_file_get_string); -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_boolean, gboolean, g_key_file_get_boolean); -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_value, char *, g_key_file_get_value); - -#define DEFINE_KF_WRAPPER_SET(fcn_name, set_ctype, key_file_set_fcn) \ - void fcn_name(GKeyFile *kf, const char *group, const char *key, set_ctype value) \ - { \ - const char *alias; \ - \ - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ - key_file_set_fcn(kf, alias ?: group, key, value); \ - } - -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_string, const char *, g_key_file_set_string); -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_boolean, gboolean, g_key_file_set_boolean); -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_value, const char *, g_key_file_set_value); - -gint64 -nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, - const char *group, - const char *key, - guint base, - gint64 min, - gint64 max, - gint64 fallback, - GError ** error) -{ - gs_free char *s = NULL; - int errsv; - gint64 v; - - s = nm_keyfile_plugin_kf_get_value(kf, group, key, error); - if (!s) { - errno = ENODATA; - return fallback; - } - - v = _nm_utils_ascii_str_to_int64(s, base, min, max, fallback); - errsv = errno; - if (errsv != 0 && error) { - g_set_error(error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value is not an integer in range [%lld, %lld]"), - (long long) min, - (long long) max); - errno = errsv; - } - return v; -} - -char ** -nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error) -{ - char ** keys; - const char *alias; - GError * local = NULL; - gsize l; - - keys = g_key_file_get_keys(kf, group, &l, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - keys = g_key_file_get_keys(kf, alias, &l, error ? &local : NULL); - } - } - nm_assert((!local) != (!keys)); - if (!keys) - l = 0; - nm_assert(l == NM_PTRARRAY_LEN(keys)); - NM_SET_OUT(out_length, l); - if (local) - g_propagate_error(error, local); - return keys; -} - -gboolean -nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, const char *key, GError **error) -{ - gboolean has; - const char *alias; - GError * local = NULL; - - has = g_key_file_has_key(kf, group, key, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - has = g_key_file_has_key(kf, alias, key, &local); - } - } - if (local) - g_propagate_error(error, local); - return has; -} - -/*****************************************************************************/ - -void -_nm_keyfile_copy(GKeyFile *dst, GKeyFile *src) -{ - gs_strfreev char **groups = NULL; - guint g, k; - - groups = g_key_file_get_groups(src, NULL); - for (g = 0; groups && groups[g]; g++) { - const char * group = groups[g]; - gs_strfreev char **keys = NULL; - - keys = g_key_file_get_keys(src, group, NULL, NULL); - if (!keys) - continue; - - for (k = 0; keys[k]; k++) { - const char * key = keys[k]; - gs_free char *value = NULL; - - value = g_key_file_get_value(src, group, key, NULL); - if (value) - g_key_file_set_value(dst, group, key, value); - else - g_key_file_remove_key(dst, group, key, NULL); - } - } -} - -/*****************************************************************************/ - -gboolean -_nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b) -{ - gs_strfreev char **groups = NULL; - guint i, j; - - if (kf_a == kf_b) - return TRUE; - if (!kf_a || !kf_b) - return FALSE; - - groups = g_key_file_get_groups(kf_a, NULL); - for (i = 0; groups && groups[i]; i++) { - gs_strfreev char **keys = NULL; - - keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); - if (!keys) - continue; - - for (j = 0; keys[j]; j++) { - gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); - gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); - - if (g_strcmp0(key_a, key_b) != 0) - return FALSE; - } - } - return TRUE; -} - -static gboolean -_nm_keyfile_equals_ordered(GKeyFile *kf_a, GKeyFile *kf_b) -{ - gs_strfreev char **groups = NULL; - gs_strfreev char **groups_b = NULL; - guint i, j; - - if (kf_a == kf_b) - return TRUE; - if (!kf_a || !kf_b) - return FALSE; - - groups = g_key_file_get_groups(kf_a, NULL); - groups_b = g_key_file_get_groups(kf_b, NULL); - if (!groups && !groups_b) - return TRUE; - if (!groups || !groups_b) - return FALSE; - for (i = 0; groups[i] && groups_b[i] && !strcmp(groups[i], groups_b[i]); i++) - ; - if (groups[i] || groups_b[i]) - return FALSE; - - for (i = 0; groups[i]; i++) { - gs_strfreev char **keys = NULL; - gs_strfreev char **keys_b = NULL; - - keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); - keys_b = g_key_file_get_keys(kf_b, groups[i], NULL, NULL); - - if ((!keys) != (!keys_b)) - return FALSE; - if (!keys) - continue; - - for (j = 0; keys[j] && keys_b[j] && !strcmp(keys[j], keys_b[j]); j++) - ; - if (keys[j] || keys_b[j]) - return FALSE; - - for (j = 0; keys[j]; j++) { - gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); - gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); - - if (g_strcmp0(key_a, key_b) != 0) - return FALSE; - } - } - return TRUE; -} - -gboolean -_nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order) -{ - if (!consider_order) { - return _nm_keyfile_a_contains_all_in_b(kf_a, kf_b) - && _nm_keyfile_a_contains_all_in_b(kf_b, kf_a); - } else { - return _nm_keyfile_equals_ordered(kf_a, kf_b); - } -} - -gboolean -_nm_keyfile_has_values(GKeyFile *keyfile) -{ - gs_strfreev char **groups = NULL; - - g_return_val_if_fail(keyfile, FALSE); - - groups = g_key_file_get_groups(keyfile, NULL); - return groups && groups[0]; -} - -/*****************************************************************************/ - -static const char * -_keyfile_key_encode(const char *name, char **out_to_free) -{ - NMStrBuf str; - gsize len; - gsize i; - - nm_assert(name); - nm_assert(out_to_free && !*out_to_free); - - /* See g_key_file_is_key_name(). - * - * GKeyFile allows all UTF-8 characters (even non-well formed sequences), - * except: - * - no empty keys - * - no leading/trailing ' ' - * - no '=', '[', ']' - * - * We do something more strict here. All non-ASCII characters, all non-printable - * characters, and all invalid characters are escaped with "\\XX". - * - * We don't escape \\, unless it is followed by two hex digits. - */ - - if (!name[0]) { - /* empty keys are backslash encoded. Note that usually - * \\00 is not a valid encode, the only exception is the empty - * word. */ - return "\\00"; - } - - /* find the first character that needs escaping. */ - i = 0; - if (name[0] != ' ') { - for (;; i++) { - const guchar ch = (guchar) name[i]; - - if (ch == '\0') - return name; - - if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']') - || (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2])) - || (ch == ' ' && name[i + 1] == '\0')) - break; - } - } else if (name[1] == '\0') - return "\\20"; - - len = i + strlen(&name[i]); - nm_assert(len == strlen(name)); - - nm_str_buf_init(&str, len + 15u, FALSE); - - if (name[0] == ' ') { - nm_assert(i == 0); - nm_str_buf_append(&str, "\\20"); - i = 1; - } else - nm_str_buf_append_len(&str, name, i); - - for (;; i++) { - const guchar ch = (guchar) name[i]; - - if (ch == '\0') - break; - - if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']') - || (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2])) - || (ch == ' ' && name[i + 1] == '\0')) { - nm_str_buf_append_c(&str, '\\'); - nm_str_buf_append_c_hex(&str, ch, TRUE); - } else - nm_str_buf_append_c(&str, (char) ch); - } - - return (*out_to_free = nm_str_buf_finalize(&str, NULL)); -} - -static const char * -_keyfile_key_decode(const char *key, char **out_to_free) -{ - char *out; - gsize len; - gsize i; - gsize j; - - nm_assert(key); - nm_assert(out_to_free && !*out_to_free); - - if (!key[0]) - return ""; - - for (i = 0; TRUE; i++) { - const char ch = key[i]; - - if (ch == '\0') - return key; - if (ch == '\\' && g_ascii_isxdigit(key[i + 1]) && g_ascii_isxdigit(key[i + 2])) - break; - } - - len = i + strlen(&key[i]); - - if (len == 3 && nm_streq(key, "\\00")) - return ""; - - nm_assert(len == strlen(key)); - - out = g_new(char, len + 1u); - - memcpy(out, key, sizeof(char) * i); - - j = i; - for (;;) { - const char ch = key[i]; - char ch1, ch2; - unsigned v; - - if (ch == '\0') - break; - - if (ch == '\\' && g_ascii_isxdigit((ch1 = key[i + 1])) - && g_ascii_isxdigit((ch2 = key[i + 2]))) { - v = (g_ascii_xdigit_value(ch1) << 4) + g_ascii_xdigit_value(ch2); - if (v != 0) { - out[j++] = (char) v; - i += 3; - continue; - } - } - out[j++] = ch; - i++; - } - - nm_assert(j <= len); - out[j] = '\0'; - return (*out_to_free = out); -} - -/*****************************************************************************/ - -const char * -nm_keyfile_key_encode(const char *name, char **out_to_free) -{ - const char *key; - - key = _keyfile_key_encode(name, out_to_free); -#if NM_MORE_ASSERTS > 5 - nm_assert(key); - nm_assert(!*out_to_free || key == *out_to_free); - nm_assert(!*out_to_free || !nm_streq0(name, key)); - { - gs_free char *to_free2 = NULL; - const char * name2; - - name2 = _keyfile_key_decode(key, &to_free2); - /* name2, the result of encode()+decode() is identical to name. - * That is because - * - encode() is a injective function. - * - decode() is a surjective function, however for output - * values of encode() is behaves injective too. */ - nm_assert(nm_streq0(name2, name)); - } -#endif - return key; -} - -const char * -nm_keyfile_key_decode(const char *key, char **out_to_free) -{ - const char *name; - - name = _keyfile_key_decode(key, out_to_free); -#if NM_MORE_ASSERTS > 5 - nm_assert(name); - nm_assert(!*out_to_free || name == *out_to_free); - { - gs_free char *to_free2 = NULL; - const char * key2; - - key2 = _keyfile_key_encode(name, &to_free2); - /* key2, the result of decode+encode may not be identical - * to the original key. That is, decode() is a surjective - * function mapping different keys to the same name. - * However, decode() behaves injective for input that - * are valid output of encode(). */ - nm_assert(key2); - } -#endif - return name; -} |