diff options
Diffstat (limited to 'libnm-core/nm-keyfile')
| -rw-r--r-- | libnm-core/nm-keyfile/nm-keyfile-internal.h | 181 | ||||
| -rw-r--r-- | libnm-core/nm-keyfile/nm-keyfile-utils.c | 1061 | ||||
| -rw-r--r-- | libnm-core/nm-keyfile/nm-keyfile-utils.h | 112 | ||||
| -rw-r--r-- | libnm-core/nm-keyfile/nm-keyfile.c | 7547 |
4 files changed, 4366 insertions, 4535 deletions
diff --git a/libnm-core/nm-keyfile/nm-keyfile-internal.h b/libnm-core/nm-keyfile/nm-keyfile-internal.h index b6ac71d6..77372f3a 100644 --- a/libnm-core/nm-keyfile/nm-keyfile-internal.h +++ b/libnm-core/nm-keyfile/nm-keyfile-internal.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2008 Novell, Inc. * Copyright (C) 2015 Red Hat, Inc. @@ -7,8 +7,8 @@ #ifndef __NM_KEYFILE_INTERNAL_H__ #define __NM_KEYFILE_INTERNAL_H__ -#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) -#error Cannot use this header. +#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + #error Cannot use this header. #endif #include <sys/types.h> @@ -21,23 +21,23 @@ /*****************************************************************************/ -#define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://" +#define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://" #define NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11 "pkcs11:" -#define NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB "data:;base64," +#define NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB "data:;base64," -char *nm_keyfile_detect_unqualified_path_scheme (const char *base_dir, - gconstpointer pdata, - gsize data_len, - gboolean consider_exists, - gboolean *out_exists); +char *nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, + gconstpointer pdata, + gsize data_len, + gboolean consider_exists, + gboolean * out_exists); typedef enum { /*< flags >*/ - NM_KEYFILE_HANDLER_FLAGS_NONE = 0, + NM_KEYFILE_HANDLER_FLAGS_NONE = 0, } NMKeyfileHandlerFlags; typedef enum { - NM_KEYFILE_HANDLER_TYPE_WARN = 1, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2, + NM_KEYFILE_HANDLER_TYPE_WARN = 1, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2, } NMKeyfileHandlerType; typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData; @@ -52,31 +52,29 @@ typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData; * a default action will be performed that depends on the @handler_type. * For %NM_KEYFILE_HANDLER_TYPE_WARN handler_type, the default action is doing nothing. */ -typedef gboolean (*NMKeyfileReadHandler) (GKeyFile *keyfile, - NMConnection *connection, - NMKeyfileHandlerType handler_type, - NMKeyfileHandlerData *handler_data, - void *user_data); +typedef gboolean (*NMKeyfileReadHandler)(GKeyFile * keyfile, + NMConnection * connection, + NMKeyfileHandlerType handler_type, + NMKeyfileHandlerData *handler_data, + void * user_data); typedef enum { - NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000, - NM_KEYFILE_WARN_SEVERITY_INFO = 2000, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901, - NM_KEYFILE_WARN_SEVERITY_WARN = 3000, + NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000, + NM_KEYFILE_WARN_SEVERITY_INFO = 2000, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901, + NM_KEYFILE_WARN_SEVERITY_WARN = 3000, } NMKeyfileWarnSeverity; -NMConnection *nm_keyfile_read (GKeyFile *keyfile, - const char *base_dir, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileReadHandler handler, - void *user_data, - GError **error); +NMConnection *nm_keyfile_read(GKeyFile * keyfile, + const char * base_dir, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileReadHandler handler, + void * user_data, + GError ** error); -gboolean nm_keyfile_read_ensure_id (NMConnection *connection, - const char *fallback_id); +gboolean nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id); -gboolean nm_keyfile_read_ensure_uuid (NMConnection *connection, - const char *fallback_uuid_seed); +gboolean nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed); /*****************************************************************************/ @@ -103,17 +101,17 @@ gboolean nm_keyfile_read_ensure_uuid (NMConnection *connection, * a default action will be performed. This might be raise an error, * do some fallback parsing, or do nothing. */ -typedef gboolean (*NMKeyfileWriteHandler) (NMConnection *connection, - GKeyFile *keyfile, - NMKeyfileHandlerType handler_type, - NMKeyfileHandlerData *handler_data, - void *user_data); - -GKeyFile *nm_keyfile_write (NMConnection *connection, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileWriteHandler handler, - void *user_data, - GError **error); +typedef gboolean (*NMKeyfileWriteHandler)(NMConnection * connection, + GKeyFile * keyfile, + NMKeyfileHandlerType handler_type, + NMKeyfileHandlerData *handler_data, + void * user_data); + +GKeyFile *nm_keyfile_write(NMConnection * connection, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileWriteHandler handler, + void * user_data, + GError ** error); /*****************************************************************************/ @@ -124,10 +122,10 @@ GKeyFile *nm_keyfile_write (NMConnection *connection, * handler_type %NM_KEYFILE_HANDLER_TYPE_WARN. */ typedef struct { - NMKeyfileWarnSeverity severity; - char *message; - const char *fmt; - va_list ap; + NMKeyfileWarnSeverity severity; + char * message; + const char * fmt; + va_list ap; } NMKeyfileHandlerDataWarn; /** @@ -137,76 +135,79 @@ typedef struct { * handler_type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT. */ typedef struct { - const NMSetting8021xSchemeVtable *vtable; + const NMSetting8021xSchemeVtable *vtable; } NMKeyfileHandlerDataWriteCert; struct _NMKeyfileHandlerData { - NMKeyfileHandlerType type; + NMKeyfileHandlerType type; - GError **p_error; + GError **p_error; - const char *kf_group_name; - const char *kf_key; + const char *kf_group_name; + const char *kf_key; - NMSetting *cur_setting; - const char *cur_property; + NMSetting * cur_setting; + const char *cur_property; - union { - NMKeyfileHandlerDataWarn warn; - NMKeyfileHandlerDataWriteCert write_cert; - }; + union { + NMKeyfileHandlerDataWarn warn; + NMKeyfileHandlerDataWriteCert write_cert; + }; }; /*****************************************************************************/ -void nm_keyfile_handler_data_fail_with_error (NMKeyfileHandlerData *handler_data, - GError *src); +void nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src); -void nm_keyfile_handler_data_get_context (const NMKeyfileHandlerData *handler_data, - const char **out_kf_group_name, - const char **out_kf_key_name, - NMSetting **out_cur_setting, - const char **out_cur_property_name); +void nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, + const char ** out_kf_group_name, + const char ** out_kf_key_name, + NMSetting ** out_cur_setting, + const char ** out_cur_property_name); -void nm_keyfile_handler_data_warn_get (const NMKeyfileHandlerData *handler_data, - const char **out_message, - NMKeyfileWarnSeverity *out_severity); +void nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, + const char ** out_message, + NMKeyfileWarnSeverity * out_severity); -const char *_nm_keyfile_handler_data_warn_get_message (const NMKeyfileHandlerData *handler_data); +const char *_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data); /*****************************************************************************/ -char *nm_keyfile_plugin_kf_get_string (GKeyFile *kf, const char *group, const char *key, GError **error); -void nm_keyfile_plugin_kf_set_string (GKeyFile *kf, const char *group, const char *key, const char *value); +char * +nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); +void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, + const char *group, + const char *key, + const char *value); -int nm_key_file_get_boolean (GKeyFile *kf, const char *group, const char *key, int default_value); +int nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value); -void _nm_keyfile_copy (GKeyFile *dst, GKeyFile *src); -gboolean _nm_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b); -gboolean _nm_keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order); -gboolean _nm_keyfile_has_values (GKeyFile *keyfile); +void _nm_keyfile_copy(GKeyFile *dst, GKeyFile *src); +gboolean _nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b); +gboolean _nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order); +gboolean _nm_keyfile_has_values(GKeyFile *keyfile); /*****************************************************************************/ -#define NM_KEYFILE_GROUP_NMMETA ".nmmeta" -#define NM_KEYFILE_KEY_NMMETA_NM_GENERATED "nm-generated" -#define NM_KEYFILE_KEY_NMMETA_VOLATILE "volatile" -#define NM_KEYFILE_KEY_NMMETA_EXTERNAL "external" -#define NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE "shadowed-storage" -#define NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED "shadowed-owned" +#define NM_KEYFILE_GROUP_NMMETA ".nmmeta" +#define NM_KEYFILE_KEY_NMMETA_NM_GENERATED "nm-generated" +#define NM_KEYFILE_KEY_NMMETA_VOLATILE "volatile" +#define NM_KEYFILE_KEY_NMMETA_EXTERNAL "external" +#define NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE "shadowed-storage" +#define NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED "shadowed-owned" -#define NM_KEYFILE_PATH_NAME_LIB NMLIBDIR "/system-connections" -#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT NMCONFDIR "/system-connections" -#define NM_KEYFILE_PATH_NAME_RUN NMRUNDIR "/system-connections" +#define NM_KEYFILE_PATH_NAME_LIB NMLIBDIR "/system-connections" +#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT NMCONFDIR "/system-connections" +#define NM_KEYFILE_PATH_NAME_RUN NMRUNDIR "/system-connections" -#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" +#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" -#define NM_KEYFILE_PATH_SUFFIX_NMMETA ".nmmeta" +#define NM_KEYFILE_PATH_SUFFIX_NMMETA ".nmmeta" -#define NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL "/dev/null" +#define NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL "/dev/null" -gboolean nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension); +gboolean nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension); -char *nm_keyfile_utils_create_filename (const char *filename, gboolean with_extension); +char *nm_keyfile_utils_create_filename(const char *filename, gboolean with_extension); #endif /* __NM_KEYFILE_INTERNAL_H__ */ diff --git a/libnm-core/nm-keyfile/nm-keyfile-utils.c b/libnm-core/nm-keyfile/nm-keyfile-utils.c index 01b42ac7..be12f8a8 100644 --- a/libnm-core/nm-keyfile/nm-keyfile-utils.c +++ b/libnm-core/nm-keyfile/nm-keyfile-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2010 Red Hat, Inc. */ @@ -41,661 +41,642 @@ * 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) +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; + 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; + 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" }, + {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) +nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name) { - guint i; + guint i; - g_return_val_if_fail (setting_name != NULL, NULL); + 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; + 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) +nm_keyfile_plugin_get_setting_name_for_alias(const char *alias) { - guint i; + guint i; - g_return_val_if_fail (alias != NULL, NULL); + 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; + 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) +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; + 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) +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; + 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); + 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); + 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); + 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; + if (key_file_error) + g_propagate_error(error, key_file_error); + if (!values) + return NULL; - int_values = g_new (guint, num_ints); + int_values = g_new(guint, num_ints); - for (i = 0; i < num_ints; i++) { - gint64 v; + 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; - } + 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; - } + int_values[i] = v; + } - NM_SET_OUT (out_length, num_ints); - return g_steal_pointer (&int_values); + 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) +nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, + const char * group, + const char * key, + const char *const *list, + gsize length) { - const char *alias; + 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); + 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_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)); + 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_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)); + 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); +#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) +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; + 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) +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; + 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) +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; + 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) +_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); - } - } + 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) +_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; + 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) +_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; + 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) +_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); - } + 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) +_nm_keyfile_has_values(GKeyFile *keyfile) { - gs_strfreev char **groups = NULL; + gs_strfreev char **groups = NULL; - g_return_val_if_fail (keyfile, FALSE); + g_return_val_if_fail(keyfile, FALSE); - groups = g_key_file_get_groups (keyfile, NULL); - return groups && groups[0]; + 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) +_keyfile_key_encode(const char *name, char **out_to_free) { - gsize len, i; - GString *str; - - 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 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)); - str = g_string_sized_new (len + 15); - - if (name[0] == ' ') { - nm_assert (i == 0); - g_string_append (str, "\\20"); - i = 1; - } else - g_string_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')) - g_string_append_printf (str, "\\%02X", ch); - else - g_string_append_c (str, (char) ch); - } - - return (*out_to_free = g_string_free (str, FALSE)); + 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) +_keyfile_key_decode(const char *key, char **out_to_free) { - gsize i, len; - GString *str; - - 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)); - str = g_string_sized_new (len + 3); - - g_string_append_len (str, key, 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) { - g_string_append_c (str, (char) v); - i += 3; - continue; - } - } - g_string_append_c (str, ch); - i++; - } - - return (*out_to_free = g_string_free (str, FALSE)); + 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) +nm_keyfile_key_encode(const char *name, char **out_to_free) { - const char *key; + const char *key; - key = _keyfile_key_encode (name, out_to_free); + 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)); - } + 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; + return key; } const char * -nm_keyfile_key_decode (const char *key, - char **out_to_free) +nm_keyfile_key_decode(const char *key, char **out_to_free) { - const char *name; + const char *name; - name = _keyfile_key_decode (key, out_to_free); + 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 idential - * 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); - } + 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; + return name; } diff --git a/libnm-core/nm-keyfile/nm-keyfile-utils.h b/libnm-core/nm-keyfile/nm-keyfile-utils.h index 4764311b..efad8317 100644 --- a/libnm-core/nm-keyfile/nm-keyfile-utils.h +++ b/libnm-core/nm-keyfile/nm-keyfile-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2010 - 2015 Red Hat, Inc. */ @@ -6,8 +6,8 @@ #ifndef __NM_KEYFILE_UTILS_H__ #define __NM_KEYFILE_UTILS_H__ -#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) -#error Cannot use this header. +#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + #error Cannot use this header. #endif /*****************************************************************************/ @@ -19,55 +19,77 @@ #define NM_KEYFILE_GROUP_VPN_SECRETS "vpn-secrets" #define NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER "wireguard-peer." -#define nm_keyfile_error_is_not_found(error) \ - nm_g_error_matches (error, \ - G_KEY_FILE_ERROR, \ - G_KEY_FILE_ERROR_GROUP_NOT_FOUND, \ - G_KEY_FILE_ERROR_KEY_NOT_FOUND) +#define nm_keyfile_error_is_not_found(error) \ + nm_g_error_matches(error, \ + G_KEY_FILE_ERROR, \ + G_KEY_FILE_ERROR_GROUP_NOT_FOUND, \ + G_KEY_FILE_ERROR_KEY_NOT_FOUND) -const char *nm_keyfile_plugin_get_alias_for_setting_name (const char *setting_name); +const char *nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name); -const char *nm_keyfile_plugin_get_setting_name_for_alias (const char *alias); +const char *nm_keyfile_plugin_get_setting_name_for_alias(const char *alias); /*****************************************************************************/ -guint *nm_keyfile_plugin_kf_get_integer_list_uint (GKeyFile *kf, const char *group, const char *key, gsize *out_length, GError **error); -char **nm_keyfile_plugin_kf_get_string_list (GKeyFile *kf, const char *group, const char *key, gsize *out_length, GError **error); -char *nm_keyfile_plugin_kf_get_string (GKeyFile *kf, const char *group, const char *key, GError **error); -gboolean nm_keyfile_plugin_kf_get_boolean (GKeyFile *kf, const char *group, const char *key, GError **error); -char *nm_keyfile_plugin_kf_get_value (GKeyFile *kf, const char *group, const char *key, GError **error); - -void nm_keyfile_plugin_kf_set_integer_list_uint8 (GKeyFile *kf, const char *group, const char *key, const guint8 *list, gsize length); -void nm_keyfile_plugin_kf_set_integer_list_uint (GKeyFile *kf, const char *group, const char *key, const guint *list, gsize length); -void nm_keyfile_plugin_kf_set_string_list (GKeyFile *kf, const char *group, const char *key, const char *const*list, gsize length); - -void nm_keyfile_plugin_kf_set_string (GKeyFile *kf, const char *group, const char *key, const char *value); -void nm_keyfile_plugin_kf_set_boolean (GKeyFile *kf, const char *group, const char *key, gboolean value); -void nm_keyfile_plugin_kf_set_value (GKeyFile *kf, const char *group, const char *key, const char *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); - -char **nm_keyfile_plugin_kf_get_keys (GKeyFile *kf, +guint *nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * kf, + const char *group, + const char *key, + gsize * out_length, + GError ** error); +char **nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, + const char *group, + const char *key, + gsize * out_length, + GError ** error); +char * +nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); +gboolean +nm_keyfile_plugin_kf_get_boolean(GKeyFile *kf, const char *group, const char *key, GError **error); +char * +nm_keyfile_plugin_kf_get_value(GKeyFile *kf, const char *group, const char *key, GError **error); + +void nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, + const char * group, + const char * key, + const guint8 *list, + gsize length); +void nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, + const char * group, + const char * key, + const guint *list, + gsize length); +void nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, + const char * group, + const char * key, + const char *const *list, + gsize length); + +void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, + const char *group, + const char *key, + const char *value); +void +nm_keyfile_plugin_kf_set_boolean(GKeyFile *kf, const char *group, const char *key, gboolean value); +void +nm_keyfile_plugin_kf_set_value(GKeyFile *kf, const char *group, const char *key, const char *value); + +gint64 nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, const char *group, - gsize *out_length, - GError **error); + const char *key, + guint base, + gint64 min, + gint64 max, + gint64 fallback, + GError ** error); -gboolean nm_keyfile_plugin_kf_has_key (GKeyFile *kf, - const char *group, - const char *key, - GError **error); +char ** +nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error); -const char *nm_keyfile_key_encode (const char *name, - char **out_to_free); +gboolean +nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, const char *key, GError **error); -const char *nm_keyfile_key_decode (const char *key, - char **out_to_free); +const char *nm_keyfile_key_encode(const char *name, char **out_to_free); -#endif /* __NM_KEYFILE_UTILS_H__ */ +const char *nm_keyfile_key_decode(const char *key, char **out_to_free); + +#endif /* __NM_KEYFILE_UTILS_H__ */ diff --git a/libnm-core/nm-keyfile/nm-keyfile.c b/libnm-core/nm-keyfile/nm-keyfile.c index 79f9c5f9..395af1db 100644 --- a/libnm-core/nm-keyfile/nm-keyfile.c +++ b/libnm-core/nm-keyfile/nm-keyfile.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2008 - 2009 Novell, Inc. * Copyright (C) 2008 - 2017 Red Hat, Inc. @@ -16,6 +16,7 @@ #include <arpa/inet.h> #include <linux/pkt_sched.h> +#include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-secret-utils.h" #include "systemd/nm-sd-utils-shared.h" #include "nm-libnm-core-intern/nm-common-macros.h" @@ -29,137 +30,131 @@ typedef struct _ParseInfoProperty ParseInfoProperty; typedef struct { - NMConnection *connection; - GKeyFile *keyfile; - const char *base_dir; - NMKeyfileReadHandler read_handler; - void *user_data; - GError *error; - const char *group; - NMSetting *setting; + NMConnection * connection; + GKeyFile * keyfile; + const char * base_dir; + NMKeyfileReadHandler read_handler; + void * user_data; + GError * error; + const char * group; + NMSetting * setting; } KeyfileReaderInfo; typedef struct { - NMConnection *connection; - GKeyFile *keyfile; - GError *error; - NMKeyfileWriteHandler write_handler; - void *user_data; + NMConnection * connection; + GKeyFile * keyfile; + GError * error; + NMKeyfileWriteHandler write_handler; + void * user_data; } KeyfileWriterInfo; /*****************************************************************************/ static void -_key_file_handler_data_init (NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - const char *kf_group_name, - const char *kf_key, - NMSetting *cur_setting, - const char *cur_property, - GError **p_error) +_key_file_handler_data_init(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + const char * kf_group_name, + const char * kf_key, + NMSetting * cur_setting, + const char * cur_property, + GError ** p_error) { - nm_assert (handler_data); - nm_assert (p_error && !*p_error); - - handler_data->type = handler_type; - handler_data->p_error = p_error; - handler_data->kf_group_name = kf_group_name; - handler_data->kf_key = kf_key; - handler_data->cur_setting = cur_setting; - handler_data->cur_property = cur_property; + nm_assert(handler_data); + nm_assert(p_error && !*p_error); + + handler_data->type = handler_type; + handler_data->p_error = p_error; + handler_data->kf_group_name = kf_group_name; + handler_data->kf_key = kf_key; + handler_data->cur_setting = cur_setting; + handler_data->cur_property = cur_property; } static void -_key_file_handler_data_init_read (NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - KeyfileReaderInfo *info, - const char *kf_key, - const char *cur_property) +_key_file_handler_data_init_read(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + KeyfileReaderInfo * info, + const char * kf_key, + const char * cur_property) { - _key_file_handler_data_init (handler_data, - handler_type, - info->group, - kf_key, - info->setting, - cur_property, - &info->error); + _key_file_handler_data_init(handler_data, + handler_type, + info->group, + kf_key, + info->setting, + cur_property, + &info->error); } static void -_key_file_handler_data_init_write (NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - KeyfileWriterInfo *info, - const char *kf_group, - const char *kf_key, - NMSetting *cur_setting, - const char *cur_property) +_key_file_handler_data_init_write(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + KeyfileWriterInfo * info, + const char * kf_group, + const char * kf_key, + NMSetting * cur_setting, + const char * cur_property) { - _key_file_handler_data_init (handler_data, - handler_type, - kf_group, - kf_key, - cur_setting, - cur_property, - &info->error); + _key_file_handler_data_init(handler_data, + handler_type, + kf_group, + kf_key, + cur_setting, + cur_property, + &info->error); } -_nm_printf (5, 6) -static void -_handle_warn (KeyfileReaderInfo *info, - const char *kf_key, - const char *cur_property, - NMKeyfileWarnSeverity severity, - const char *fmt, - ...) +_nm_printf(5, 6) static void _handle_warn(KeyfileReaderInfo * info, + const char * kf_key, + const char * cur_property, + NMKeyfileWarnSeverity severity, + const char * fmt, + ...) { - NMKeyfileHandlerData handler_data; - - _key_file_handler_data_init_read (&handler_data, - NM_KEYFILE_HANDLER_TYPE_WARN, - info, - kf_key, - cur_property); - handler_data.warn = (NMKeyfileHandlerDataWarn) { - .severity = severity, - .message = NULL, - .fmt = fmt, - }; - - va_start (handler_data.warn.ap, fmt); - - info->read_handler (info->keyfile, - info->connection, - NM_KEYFILE_HANDLER_TYPE_WARN, - &handler_data, - info->user_data); - - va_end (handler_data.warn.ap); - - g_free (handler_data.warn.message); + NMKeyfileHandlerData handler_data; + + _key_file_handler_data_init_read(&handler_data, + NM_KEYFILE_HANDLER_TYPE_WARN, + info, + kf_key, + cur_property); + handler_data.warn = (NMKeyfileHandlerDataWarn){ + .severity = severity, + .message = NULL, + .fmt = fmt, + }; + + va_start(handler_data.warn.ap, fmt); + + info->read_handler(info->keyfile, + info->connection, + NM_KEYFILE_HANDLER_TYPE_WARN, + &handler_data, + info->user_data); + + va_end(handler_data.warn.ap); + + g_free(handler_data.warn.message); } -#define handle_warn(arg_info, arg_kf_key, arg_property_name, arg_severity, ...) \ - ({ \ - KeyfileReaderInfo *_info = (arg_info); \ - \ - nm_assert (!_info->error); \ - \ - if (_info->read_handler) { \ - _handle_warn (_info, \ - (arg_kf_key), \ - (arg_property_name), \ - (arg_severity), \ - __VA_ARGS__); \ - } \ - _info->error == NULL; \ - }) +#define handle_warn(arg_info, arg_kf_key, arg_property_name, arg_severity, ...) \ + ({ \ + KeyfileReaderInfo *_info = (arg_info); \ + \ + nm_assert(!_info->error); \ + \ + if (_info->read_handler) { \ + _handle_warn(_info, (arg_kf_key), (arg_property_name), (arg_severity), __VA_ARGS__); \ + } \ + _info->error == NULL; \ + }) /*****************************************************************************/ static gboolean -_secret_flags_persist_secret (NMSettingSecretFlags flags) +_secret_flags_persist_secret(NMSettingSecretFlags flags) { - return flags == NM_SETTING_SECRET_FLAG_NONE; + return flags == NM_SETTING_SECRET_FLAG_NONE; } /*****************************************************************************/ @@ -170,231 +165,214 @@ _secret_flags_persist_secret (NMSettingSecretFlags flags) * properties' values to the real setting name if they are an alias. */ static void -setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +setting_alias_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - const char *key_setting_name; - gs_free char *s = NULL; - - s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); - if (!s) - return; - - key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias (s); - g_object_set (G_OBJECT (setting), - key, - key_setting_name ?: s, - NULL); + const char * setting_name = nm_setting_get_name(setting); + const char * key_setting_name; + gs_free char *s = NULL; + + s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!s) + return; + + key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias(s); + g_object_set(G_OBJECT(setting), key, key_setting_name ?: s, NULL); } static void -sriov_vfs_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +sriov_vfs_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_ptrarray GPtrArray *vfs = NULL; - gs_strfreev char **keys = NULL; - gsize n_keys = 0; - int i; + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *vfs = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; - vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref); + vfs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_sriov_vf_unref); - for (i = 0; i < n_keys; i++) { - gs_free char *value = NULL; - NMSriovVF *vf; - const char *rest; + for (i = 0; i < n_keys; i++) { + gs_free char *value = NULL; + NMSriovVF * vf; + const char * rest; - if (!g_str_has_prefix (keys[i], "vf.")) - continue; + if (!g_str_has_prefix(keys[i], "vf.")) + continue; - rest = &keys[i][3]; + rest = &keys[i][3]; - if (!NM_STRCHAR_ALL (rest, ch, g_ascii_isdigit (ch))) - continue; + if (!NM_STRCHAR_ALL(rest, ch, g_ascii_isdigit(ch))) + continue; - value = nm_keyfile_plugin_kf_get_string (info->keyfile, - setting_name, - keys[i], - NULL); + value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); - vf = _nm_utils_sriov_vf_from_strparts (rest, value, TRUE, NULL); - if (vf) - g_ptr_array_add (vfs, vf); - } + vf = _nm_utils_sriov_vf_from_strparts(rest, value, TRUE, NULL); + if (vf) + g_ptr_array_add(vfs, vf); + } - g_object_set (G_OBJECT (setting), - key, vfs, - NULL); + g_object_set(G_OBJECT(setting), key, vfs, NULL); } static void -read_array_of_uint (GKeyFile *file, - NMSetting *setting, - const char *key) +read_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key) { - gs_unref_array GArray *array = NULL; - gs_free_error GError *error = NULL; - gs_free guint *tmp = NULL; - gsize length; - - tmp = nm_keyfile_plugin_kf_get_integer_list_uint (file, nm_setting_get_name (setting), key, &length, &error); - if (error) - return; - - array = g_array_sized_new (FALSE, FALSE, sizeof (guint), length); - g_array_append_vals (array, tmp, length); - g_object_set (setting, key, array, NULL); + gs_unref_array GArray *array = NULL; + gs_free_error GError *error = NULL; + gs_free guint *tmp = NULL; + gsize length; + + tmp = nm_keyfile_plugin_kf_get_integer_list_uint(file, + nm_setting_get_name(setting), + key, + &length, + &error); + if (error) + return; + + array = g_array_sized_new(FALSE, FALSE, sizeof(guint), length); + g_array_append_vals(array, tmp, length); + g_object_set(setting, key, array, NULL); } static gboolean -get_one_int (KeyfileReaderInfo *info, - const char *kf_key, - const char *property_name, - const char *str, - guint32 max_val, - guint32 *out) +get_one_int(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + const char * str, + guint32 max_val, + guint32 * out) { - gint64 tmp; - - nm_assert ((!info) == (!property_name)); - nm_assert ((!info) == (!kf_key)); - - if (!str || !str[0]) { - if (info) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring missing number")); - } - return FALSE; - } - - tmp = _nm_utils_ascii_str_to_int64 (str, 10, 0, max_val, -1); - if (tmp == -1) { - if (info) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid number '%s'"), - str); - } - return FALSE; - } - - *out = (guint32) tmp; - return TRUE; + gint64 tmp; + + nm_assert((!info) == (!property_name)); + nm_assert((!info) == (!kf_key)); + + if (!str || !str[0]) { + if (info) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring missing number")); + } + return FALSE; + } + + tmp = _nm_utils_ascii_str_to_int64(str, 10, 0, max_val, -1); + if (tmp == -1) { + if (info) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid number '%s'"), + str); + } + return FALSE; + } + + *out = (guint32) tmp; + return TRUE; } static gpointer -build_address (KeyfileReaderInfo *info, - const char *kf_key, - const char *property_name, - int family, - const char *address_str, - guint32 plen) +build_address(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + int family, + const char * address_str, + guint32 plen) { - NMIPAddress *addr; - GError *error = NULL; - - g_return_val_if_fail (address_str, NULL); - - addr = nm_ip_address_new (family, address_str, plen, &error); - if (!addr) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid %s address: %s"), - family == AF_INET ? "IPv4" : "IPv6", - error->message); - g_error_free (error); - } - - return addr; + NMIPAddress *addr; + GError * error = NULL; + + g_return_val_if_fail(address_str, NULL); + + addr = nm_ip_address_new(family, address_str, plen, &error); + if (!addr) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid %s address: %s"), + family == AF_INET ? "IPv4" : "IPv6", + error->message); + g_error_free(error); + } + + return addr; } static gpointer -build_route (KeyfileReaderInfo *info, - const char *kf_key, - const char *property_name, - int family, - const char *dest_str, - guint32 plen, - const char *gateway_str, - const char *metric_str) +build_route(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + int family, + const char * dest_str, + guint32 plen, + const char * gateway_str, + const char * metric_str) { - NMIPRoute *route; - guint32 u32; - gint64 metric = -1; - GError *error = NULL; - - g_return_val_if_fail (dest_str, NULL); - - /* Next hop */ - if (gateway_str && gateway_str[0]) { - if (!nm_utils_ipaddr_is_valid (family, gateway_str)) { - /* Try workaround for routes written by broken keyfile writer. - * Due to bug bgo#719851, an older version of writer would have - * written "a:b:c:d::/plen,metric" if the gateway was ::, instead - * of "a:b:c:d::/plen,,metric" or "a:b:c:d::/plen,::,metric" - * Try workaround by interpreting gateway_str as metric to accept such - * invalid routes. This broken syntax should not be not officially - * supported. - **/ - if ( family == AF_INET6 - && !metric_str - && get_one_int (NULL, NULL, NULL, gateway_str, G_MAXUINT32, &u32)) { - metric = u32; - gateway_str = NULL; - } else { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid gateway '%s' for %s route"), - gateway_str, - family == AF_INET ? "IPv4" : "IPv6"); - return NULL; - } - } - } else - gateway_str = NULL; - - /* parse metric, default to -1 */ - if (metric_str) { - if (!get_one_int (info, - kf_key, - property_name, - metric_str, - G_MAXUINT32, - &u32)) - return NULL; - metric = u32; - } - - route = nm_ip_route_new (family, - dest_str, - plen, - gateway_str, - metric, - &error); - if (!route) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid %s route: %s"), - family == AF_INET ? "IPv4" : "IPv6", - error->message); - g_error_free (error); - } - - return route; + NMIPRoute *route; + guint32 u32; + gint64 metric = -1; + GError * error = NULL; + + g_return_val_if_fail(dest_str, NULL); + + /* Next hop */ + if (gateway_str && gateway_str[0]) { + if (!nm_utils_ipaddr_is_valid(family, gateway_str)) { + /* Try workaround for routes written by broken keyfile writer. + * Due to bug bgo#719851, an older version of writer would have + * written "a:b:c:d::/plen,metric" if the gateway was ::, instead + * of "a:b:c:d::/plen,,metric" or "a:b:c:d::/plen,::,metric" + * Try workaround by interpreting gateway_str as metric to accept such + * invalid routes. This broken syntax should not be not officially + * supported. + **/ + if (family == AF_INET6 && !metric_str + && get_one_int(NULL, NULL, NULL, gateway_str, G_MAXUINT32, &u32)) { + metric = u32; + gateway_str = NULL; + } else { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid gateway '%s' for %s route"), + gateway_str, + family == AF_INET ? "IPv4" : "IPv6"); + return NULL; + } + } + } else + gateway_str = NULL; + + /* parse metric, default to -1 */ + if (metric_str) { + if (!get_one_int(info, kf_key, property_name, metric_str, G_MAXUINT32, &u32)) + return NULL; + metric = u32; + } + + route = nm_ip_route_new(family, dest_str, plen, gateway_str, metric, &error); + if (!route) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid %s route: %s"), + family == AF_INET ? "IPv4" : "IPv6", + error->message); + g_error_free(error); + } + + return route; } /* On success, returns pointer to the zero-terminated field (original @current). @@ -409,47 +387,47 @@ build_route (KeyfileReaderInfo *info, * leaving the @current target %NULL end setting @error to %NULL; */ static const char * -read_field (char **current, const char **out_err_str, const char *characters, const char *delimiters) +read_field(char **current, const char **out_err_str, const char *characters, const char *delimiters) { - const char *start; - - nm_assert (current); - nm_assert (out_err_str); - nm_assert (characters); - nm_assert (delimiters); - - *out_err_str = NULL; - - if (!*current) { - /* graceful failure, leave '*current' NULL */ - return NULL; - } - - /* fail on empty input */ - if (!**current) - return NULL; - - /* remember beginning of input */ - start = *current; - - while (**current && strchr (characters, **current)) - (*current)++; - if (**current) - if (strchr (delimiters, **current)) { - /* success, more data available */ - *(*current)++ = '\0'; - return start; - } else { - /* error, bad character */ - *out_err_str = *current; - *current = (char *) start; - return NULL; - } - else { - /* success, end of input */ - *current = NULL; - return start; - } + const char *start; + + nm_assert(current); + nm_assert(out_err_str); + nm_assert(characters); + nm_assert(delimiters); + + *out_err_str = NULL; + + if (!*current) { + /* graceful failure, leave '*current' NULL */ + return NULL; + } + + /* fail on empty input */ + if (!**current) + return NULL; + + /* remember beginning of input */ + start = *current; + + while (**current && strchr(characters, **current)) + (*current)++; + if (**current) + if (strchr(delimiters, **current)) { + /* success, more data available */ + *(*current)++ = '\0'; + return start; + } else { + /* error, bad character */ + *out_err_str = *current; + *current = (char *) start; + return NULL; + } + else { + /* success, end of input */ + *current = NULL; + return start; + } } /*****************************************************************************/ @@ -464,44 +442,44 @@ read_field (char **current, const char **out_err_str, const char *characters, co #define NM_OPENCONNECT_KEY_CERTSIGS "certsigs" static void -openconnect_fix_secret_flags (NMSetting *setting) +openconnect_fix_secret_flags(NMSetting *setting) { - NMSettingVpn *s_vpn; - NMSettingSecretFlags flags; - - /* Huge hack. There were some openconnect changes that needed to happen - * pretty late, too late to get into distros. Migration has already - * happened for many people, and their secret flags are wrong. But we - * don't want to requrie re-migration, so we have to fix it up here. Ugh. - */ - - if (!NM_IS_SETTING_VPN (setting)) - return; - - s_vpn = NM_SETTING_VPN (setting); - - if (!nm_streq0 (nm_setting_vpn_get_service_type (s_vpn), NM_DBUS_SERVICE_OPENCONNECT)) - return; - - /* These are different for every login session, and should not be stored */ - flags = NM_SETTING_SECRET_FLAG_NOT_SAVED; - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL); - - /* These are purely internal data for the auth-dialog, and should be stored */ - flags = 0; - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL); + NMSettingVpn * s_vpn; + NMSettingSecretFlags flags; + + /* Huge hack. There were some openconnect changes that needed to happen + * pretty late, too late to get into distros. Migration has already + * happened for many people, and their secret flags are wrong. But we + * don't want to require re-migration, so we have to fix it up here. Ugh. + */ + + if (!NM_IS_SETTING_VPN(setting)) + return; + + s_vpn = NM_SETTING_VPN(setting); + + if (!nm_streq0(nm_setting_vpn_get_service_type(s_vpn), NM_DBUS_SERVICE_OPENCONNECT)) + return; + + /* These are different for every login session, and should not be stored */ + flags = NM_SETTING_SECRET_FLAG_NOT_SAVED; + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL); + + /* These are purely internal data for the auth-dialog, and should be stored */ + flags = 0; + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL); } /*****************************************************************************/ #define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%" -#define DIGITS "0123456789" -#define DELIMITERS "/;," +#define DIGITS "0123456789" +#define DELIMITERS "/;," /* The following IPv4 and IPv6 address formats are supported: * @@ -528,1465 +506,1457 @@ openconnect_fix_secret_flags (NMSetting *setting) * match the iproute2 defaults (32 for IPv4 and 128 for IPv6). */ static gpointer -read_one_ip_address_or_route (KeyfileReaderInfo *info, - const char *property_name, - const char *setting_name, - const char *kf_key, - gboolean ipv6, - gboolean route, - char **out_gateway, - NMSetting *setting) +read_one_ip_address_or_route(KeyfileReaderInfo *info, + const char * property_name, + const char * setting_name, + const char * kf_key, + gboolean ipv6, + gboolean route, + char ** out_gateway, + NMSetting * setting) { - guint plen; - gpointer result; - const char *address_str; - const char *plen_str; - const char *gateway_str; - const char *metric_str; - const char *err_str = NULL; - char *current; - gs_free char *value = NULL; - gs_free char *value_orig = NULL; - -#define VALUE_ORIG() (value_orig ?: (value_orig = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, kf_key, NULL))) - - value = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, kf_key, NULL); - if (!value) - return NULL; - - current = value; - - /* get address field */ - address_str = read_field (¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); - if (err_str) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' for address %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG (), - err_str - current); - return NULL; - } - /* get prefix length field (skippable) */ - plen_str = read_field (¤t, &err_str, DIGITS, DELIMITERS); - /* get gateway field */ - gateway_str = read_field (¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); - if (err_str) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' for %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG (), - err_str - current); - return NULL; - } - /* for routes, get metric */ - if (route) { - metric_str = read_field (¤t, &err_str, DIGITS, DELIMITERS); - if (err_str) { - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' in prefix length for %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG (), - err_str - current); - return NULL; - } - } else - metric_str = NULL; - if (current) { - /* there is still some data */ - if (*current) { - /* another field follows */ - handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("garbage at the end of value %s: '%s'"), - kf_key, - VALUE_ORIG ()); - return NULL; - } else { - /* semicolon at the end of input */ - if (!handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_INFO, - _("deprecated semicolon at the end of value %s: '%s'"), - kf_key, - VALUE_ORIG ())) - return NULL; - } - } - -#define DEFAULT_PREFIX(for_route, for_ipv6) ( (for_route) ? ( (for_ipv6) ? 128 : 24 ) : ( (for_ipv6) ? 64 : 24 ) ) - - /* parse plen, fallback to defaults */ - if (plen_str) { - if (!get_one_int (info, - kf_key, - property_name, - plen_str, - ipv6 ? 128 : 32, - &plen)) { - plen = DEFAULT_PREFIX (route, ipv6); - if ( info->error - || !handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid prefix length for %s '%s', defaulting to %d"), - kf_key, - VALUE_ORIG (), - plen)) - return NULL; - } - } else { - plen = DEFAULT_PREFIX (route, ipv6); - if (!handle_warn (info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("missing prefix length for %s '%s', defaulting to %d"), - kf_key, - VALUE_ORIG (), - plen)) - return NULL; - } - - /* build the appropriate data structure for NetworkManager settings */ - if (route) { - result = build_route (info, - kf_key, - property_name, - ipv6 ? AF_INET6 : AF_INET, - address_str, - plen, - gateway_str, - metric_str); - } else { - result = build_address (info, - kf_key, - property_name, - ipv6 ? AF_INET6 : AF_INET, - address_str, - plen); - if (!result) - return NULL; - if (gateway_str) - NM_SET_OUT (out_gateway, g_strdup (gateway_str)); - } + guint plen; + gpointer result; + const char * address_str; + const char * plen_str; + const char * gateway_str; + const char * metric_str; + const char * err_str = NULL; + char * current; + gs_free char *value = NULL; + gs_free char *value_orig = NULL; + +#define VALUE_ORIG() \ + (value_orig \ + ?: (value_orig = \ + nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL))) + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL); + if (!value) + return NULL; + + current = value; + + /* get address field */ + address_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' for address %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + /* get prefix length field (skippable) */ + plen_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); + /* get gateway field */ + gateway_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' for %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + /* for routes, get metric */ + if (route) { + metric_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' in prefix length for %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + } else + metric_str = NULL; + if (current) { + /* there is still some data */ + if (*current) { + /* another field follows */ + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("garbage at the end of value %s: '%s'"), + kf_key, + VALUE_ORIG()); + return NULL; + } else { + /* semicolon at the end of input */ + if (!handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_INFO, + _("deprecated semicolon at the end of value %s: '%s'"), + kf_key, + VALUE_ORIG())) + return NULL; + } + } + +#define DEFAULT_PREFIX(for_route, for_ipv6) \ + ((for_route) ? ((for_ipv6) ? 128 : 24) : ((for_ipv6) ? 64 : 24)) + + /* parse plen, fallback to defaults */ + if (plen_str) { + if (!get_one_int(info, kf_key, property_name, plen_str, ipv6 ? 128 : 32, &plen)) { + plen = DEFAULT_PREFIX(route, ipv6); + if (info->error + || !handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid prefix length for %s '%s', defaulting to %d"), + kf_key, + VALUE_ORIG(), + plen)) + return NULL; + } + } else { + plen = DEFAULT_PREFIX(route, ipv6); + if (!handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("missing prefix length for %s '%s', defaulting to %d"), + kf_key, + VALUE_ORIG(), + plen)) + return NULL; + } + + /* build the appropriate data structure for NetworkManager settings */ + if (route) { + result = build_route(info, + kf_key, + property_name, + ipv6 ? AF_INET6 : AF_INET, + address_str, + plen, + gateway_str, + metric_str); + } else { + result = build_address(info, + kf_key, + property_name, + ipv6 ? AF_INET6 : AF_INET, + address_str, + plen); + if (!result) + return NULL; + if (gateway_str) + NM_SET_OUT(out_gateway, g_strdup(gateway_str)); + } #undef VALUE_ORIG - return result; + return result; } static void -fill_route_attributes (GKeyFile *kf, NMIPRoute *route, const char *setting, const char *key, int family) +fill_route_attributes(GKeyFile * kf, + NMIPRoute * route, + const char *setting, + const char *key, + int family) { - gs_free char *value = NULL; - gs_unref_hashtable GHashTable *hash = NULL; - GHashTableIter iter; - char *name; - GVariant *variant; - - value = nm_keyfile_plugin_kf_get_string (kf, setting, key, NULL); - if (!value || !value[0]) - return; - - hash = nm_utils_parse_variant_attributes (value, ',', '=', TRUE, - nm_ip_route_get_variant_attribute_spec (), - NULL); - if (hash) { - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) { - if (nm_ip_route_attribute_validate (name, variant, family, NULL, NULL)) - nm_ip_route_set_attribute (route, name, g_variant_ref (variant)); - } - } + gs_free char * value = NULL; + gs_unref_hashtable GHashTable *hash = NULL; + GHashTableIter iter; + char * name; + GVariant * variant; + + value = nm_keyfile_plugin_kf_get_string(kf, setting, key, NULL); + if (!value || !value[0]) + return; + + hash = nm_utils_parse_variant_attributes(value, + ',', + '=', + TRUE, + nm_ip_route_get_variant_attribute_spec(), + NULL); + if (hash) { + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + if (nm_ip_route_attribute_validate(name, variant, family, NULL, NULL)) + nm_ip_route_set_attribute(route, name, g_variant_ref(variant)); + } + } } typedef struct { - const char *s_key; - gint32 key_idx; - gint8 key_type; + const char *s_key; + gint32 key_idx; + gint8 key_type; } BuildListData; typedef enum { - BUILD_LIST_TYPE_ADDRESSES, - BUILD_LIST_TYPE_ROUTES, - BUILD_LIST_TYPE_ROUTING_RULES, + BUILD_LIST_TYPE_ADDRESSES, + BUILD_LIST_TYPE_ROUTES, + BUILD_LIST_TYPE_ROUTING_RULES, } BuildListType; static int -_build_list_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +_build_list_data_cmp(gconstpointer p_a, gconstpointer p_b, gpointer user_data) { - const BuildListData *a = p_a; - const BuildListData *b = p_b; + const BuildListData *a = p_a; + const BuildListData *b = p_b; - NM_CMP_FIELD (a, b, key_idx); - NM_CMP_FIELD (a, b, key_type); - NM_CMP_FIELD_STR (a, b, s_key); - return 0; + NM_CMP_FIELD(a, b, key_idx); + NM_CMP_FIELD(a, b, key_type); + NM_CMP_FIELD_STR(a, b, s_key); + return 0; } static gboolean -_build_list_data_is_shadowed (const BuildListData *build_list, - gsize build_list_len, - gsize idx) +_build_list_data_is_shadowed(const BuildListData *build_list, gsize build_list_len, gsize idx) { - /* the keyfile contains duplicate keys, which are both returned - * by g_key_file_get_keys() (WHY??). - * - * Skip the earlier one. */ - return idx + 1 < build_list_len - && build_list[idx].key_idx == build_list[idx + 1].key_idx - && build_list[idx].key_type == build_list[idx + 1].key_type - && nm_streq (build_list[idx].s_key, build_list[idx + 1].s_key); + /* the keyfile contains duplicate keys, which are both returned + * by g_key_file_get_keys() (WHY??). + * + * Skip the earlier one. */ + return idx + 1 < build_list_len && build_list[idx].key_idx == build_list[idx + 1].key_idx + && build_list[idx].key_type == build_list[idx + 1].key_type + && nm_streq(build_list[idx].s_key, build_list[idx + 1].s_key); } static gboolean -_build_list_match_key_w_name_impl (const char *key, - const char *base_name, - gsize base_name_l, - gint32 *out_key_idx) +_build_list_match_key_w_name_impl(const char *key, + const char *base_name, + gsize base_name_l, + gint32 * out_key_idx) { - gint64 v; - - /* some very strict parsing. */ - - /* the key must start with base_name. */ - if (strncmp (key, base_name, base_name_l) != 0) - return FALSE; - - key += base_name_l; - if (key[0] == '\0') { - /* if key is identical to base_name, that's good. */ - NM_SET_OUT (out_key_idx, -1); - return TRUE; - } - - /* if base_name is followed by a zero, then it must be - * only a zero, nothing else. */ - if (key[0] == '0') { - if (key[1] != '\0') - return FALSE; - NM_SET_OUT (out_key_idx, 0); - return TRUE; - } - - /* otherwise, it can only be followed by a non-zero decimal. */ - if (!(key[0] >= '1' && key[0] <= '9')) - return FALSE; - /* and all remaining chars must be decimals too. */ - if (!NM_STRCHAR_ALL (&key[1], ch, g_ascii_isdigit (ch))) - return FALSE; - - /* and it must be convertible to a (positive) int. */ - v = _nm_utils_ascii_str_to_int64 (key, 10, 0, G_MAXINT32, -1); - if (v < 0) - return FALSE; - - /* good */ - NM_SET_OUT (out_key_idx, v); - return TRUE; + gint64 v; + + /* some very strict parsing. */ + + /* the key must start with base_name. */ + if (strncmp(key, base_name, base_name_l) != 0) + return FALSE; + + key += base_name_l; + if (key[0] == '\0') { + /* if key is identical to base_name, that's good. */ + NM_SET_OUT(out_key_idx, -1); + return TRUE; + } + + /* if base_name is followed by a zero, then it must be + * only a zero, nothing else. */ + if (key[0] == '0') { + if (key[1] != '\0') + return FALSE; + NM_SET_OUT(out_key_idx, 0); + return TRUE; + } + + /* otherwise, it can only be followed by a non-zero decimal. */ + if (!(key[0] >= '1' && key[0] <= '9')) + return FALSE; + /* and all remaining chars must be decimals too. */ + if (!NM_STRCHAR_ALL(&key[1], ch, g_ascii_isdigit(ch))) + return FALSE; + + /* and it must be convertible to a (positive) int. */ + v = _nm_utils_ascii_str_to_int64(key, 10, 0, G_MAXINT32, -1); + if (v < 0) + return FALSE; + + /* good */ + NM_SET_OUT(out_key_idx, v); + return TRUE; } #define _build_list_match_key_w_name(key, base_name, out_key_idx) \ - _build_list_match_key_w_name_impl (key, base_name, NM_STRLEN (base_name), out_key_idx) + _build_list_match_key_w_name_impl(key, base_name, NM_STRLEN(base_name), out_key_idx) static BuildListData * -_build_list_create (GKeyFile *keyfile, - const char *group_name, - BuildListType build_list_type, - gsize *out_build_list_len, - char ***out_keys_strv) +_build_list_create(GKeyFile * keyfile, + const char * group_name, + BuildListType build_list_type, + gsize * out_build_list_len, + char *** out_keys_strv) { - gs_strfreev char **keys = NULL; - gsize i_keys, n_keys; - gs_free BuildListData *build_list = NULL; - gsize build_list_len = 0; - - nm_assert (out_build_list_len && *out_build_list_len == 0); - nm_assert (out_keys_strv && !*out_keys_strv); - - keys = nm_keyfile_plugin_kf_get_keys (keyfile, group_name, &n_keys, NULL); - if (n_keys == 0) - return NULL; - - for (i_keys = 0; i_keys < n_keys; i_keys++) { - const char *s_key = keys[i_keys]; - gint32 key_idx; - gint8 key_type = 0; - - switch (build_list_type) { - case BUILD_LIST_TYPE_ROUTES: - if (_build_list_match_key_w_name (s_key, "route", &key_idx)) - key_type = 0; - else if (_build_list_match_key_w_name (s_key, "routes", &key_idx)) - key_type = 1; - else - continue; - break; - case BUILD_LIST_TYPE_ADDRESSES: - if (_build_list_match_key_w_name (s_key, "address", &key_idx)) - key_type = 0; - else if (_build_list_match_key_w_name (s_key, "addresses", &key_idx)) - key_type = 1; - else - continue; - break; - case BUILD_LIST_TYPE_ROUTING_RULES: - if (_build_list_match_key_w_name (s_key, "routing-rule", &key_idx)) - key_type = 0; - else - continue; - break; - default: - nm_assert_not_reached (); - break; - } - - if (G_UNLIKELY (!build_list)) - build_list = g_new (BuildListData, n_keys - i_keys); - - build_list[build_list_len++] = (BuildListData) { - .s_key = s_key, - .key_idx = key_idx, - .key_type = key_type, - }; - } - - if (build_list_len == 0) - return NULL; - - if (build_list_len > 1) { - g_qsort_with_data (build_list, - build_list_len, - sizeof (BuildListData), - _build_list_data_cmp, - NULL); - } - - *out_build_list_len = build_list_len; - *out_keys_strv = g_steal_pointer (&keys); - return g_steal_pointer (&build_list); + gs_strfreev char **keys = NULL; + gsize i_keys, n_keys; + gs_free BuildListData *build_list = NULL; + gsize build_list_len = 0; + + nm_assert(out_build_list_len && *out_build_list_len == 0); + nm_assert(out_keys_strv && !*out_keys_strv); + + keys = nm_keyfile_plugin_kf_get_keys(keyfile, group_name, &n_keys, NULL); + if (n_keys == 0) + return NULL; + + for (i_keys = 0; i_keys < n_keys; i_keys++) { + const char *s_key = keys[i_keys]; + gint32 key_idx; + gint8 key_type = 0; + + switch (build_list_type) { + case BUILD_LIST_TYPE_ROUTES: + if (_build_list_match_key_w_name(s_key, "route", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name(s_key, "routes", &key_idx)) + key_type = 1; + else + continue; + break; + case BUILD_LIST_TYPE_ADDRESSES: + if (_build_list_match_key_w_name(s_key, "address", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name(s_key, "addresses", &key_idx)) + key_type = 1; + else + continue; + break; + case BUILD_LIST_TYPE_ROUTING_RULES: + if (_build_list_match_key_w_name(s_key, "routing-rule", &key_idx)) + key_type = 0; + else + continue; + break; + default: + nm_assert_not_reached(); + break; + } + + if (G_UNLIKELY(!build_list)) + build_list = g_new(BuildListData, n_keys - i_keys); + + build_list[build_list_len++] = (BuildListData){ + .s_key = s_key, + .key_idx = key_idx, + .key_type = key_type, + }; + } + + if (build_list_len == 0) + return NULL; + + if (build_list_len > 1) { + g_qsort_with_data(build_list, + build_list_len, + sizeof(BuildListData), + _build_list_data_cmp, + NULL); + } + + *out_build_list_len = build_list_len; + *out_keys_strv = g_steal_pointer(&keys); + return g_steal_pointer(&build_list); } static void -ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *setting_key) +ip_address_or_route_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *setting_key) { - const char *setting_name = nm_setting_get_name (setting); - gboolean is_ipv6 = nm_streq (setting_name, "ipv6"); - gboolean is_routes = nm_streq (setting_key, "routes"); - gs_free char *gateway = NULL; - gs_unref_ptrarray GPtrArray *list = NULL; - gs_strfreev char **keys = NULL; - gs_free BuildListData *build_list = NULL; - gsize i_build_list, build_list_len = 0; - - build_list = _build_list_create (info->keyfile, - setting_name, - is_routes - ? BUILD_LIST_TYPE_ROUTES - : BUILD_LIST_TYPE_ADDRESSES, - &build_list_len, - &keys); - if (!build_list) - return; - - list = g_ptr_array_new_with_free_func (is_routes - ? (GDestroyNotify) nm_ip_route_unref - : (GDestroyNotify) nm_ip_address_unref); - - for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { - const char *s_key; - gpointer item; - - if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list)) - continue; - - s_key = build_list[i_build_list].s_key; - item = read_one_ip_address_or_route (info, - setting_key, - setting_name, - s_key, - is_ipv6, - is_routes, - gateway ? NULL : &gateway, - setting); - if (item && is_routes) { - char options_key[128]; - - nm_sprintf_buf (options_key, "%s_options", s_key); - fill_route_attributes (info->keyfile, - item, - setting_name, - options_key, - is_ipv6 ? AF_INET6 : AF_INET); - } - - if (info->error) - return; - - if (item) - g_ptr_array_add (list, item); - } - - if (list->len >= 1) - g_object_set (setting, setting_key, list, NULL); - - if (gateway) - g_object_set (setting, "gateway", gateway, NULL); + const char * setting_name = nm_setting_get_name(setting); + gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); + gboolean is_routes = nm_streq(setting_key, "routes"); + gs_free char * gateway = NULL; + gs_unref_ptrarray GPtrArray *list = NULL; + gs_strfreev char ** keys = NULL; + gs_free BuildListData *build_list = NULL; + gsize i_build_list, build_list_len = 0; + + build_list = _build_list_create(info->keyfile, + setting_name, + is_routes ? BUILD_LIST_TYPE_ROUTES : BUILD_LIST_TYPE_ADDRESSES, + &build_list_len, + &keys); + if (!build_list) + return; + + list = g_ptr_array_new_with_free_func(is_routes ? (GDestroyNotify) nm_ip_route_unref + : (GDestroyNotify) nm_ip_address_unref); + + for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { + const char *s_key; + gpointer item; + + if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) + continue; + + s_key = build_list[i_build_list].s_key; + item = read_one_ip_address_or_route(info, + setting_key, + setting_name, + s_key, + is_ipv6, + is_routes, + gateway ? NULL : &gateway, + setting); + if (item && is_routes) { + char options_key[128]; + + nm_sprintf_buf(options_key, "%s_options", s_key); + fill_route_attributes(info->keyfile, + item, + setting_name, + options_key, + is_ipv6 ? AF_INET6 : AF_INET); + } + + if (info->error) + return; + + if (item) + g_ptr_array_add(list, item); + } + + if (list->len >= 1) + g_object_set(setting, setting_key, list, NULL); + + if (gateway) + g_object_set(setting, "gateway", gateway, NULL); } static void -ip_routing_rule_parser_full (KeyfileReaderInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +ip_routing_rule_parser_full(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) { - const char *setting_name = nm_setting_get_name (setting); - gboolean is_ipv6 = nm_streq (setting_name, "ipv6"); - gs_strfreev char **keys = NULL; - gs_free BuildListData *build_list = NULL; - gsize i_build_list, build_list_len = 0; - - build_list = _build_list_create (info->keyfile, - setting_name, - BUILD_LIST_TYPE_ROUTING_RULES, - &build_list_len, - &keys); - if (!build_list) - return; - - for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { - nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL; - gs_free char *value = NULL; - gs_free_error GError *local = NULL; - - if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list)) - continue; - - value = nm_keyfile_plugin_kf_get_string (info->keyfile, - setting_name, - build_list[i_build_list].s_key, - NULL); - if (!value) - continue; - - rule = nm_ip_routing_rule_from_string (value, - ( NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE - | ( is_ipv6 - ? NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6 - : NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET)), - NULL, - &local); - if (!rule) { - if (!handle_warn (info, - build_list[i_build_list].s_key, - property_info->name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid value for \"%s\": %s"), - build_list[i_build_list].s_key, - local->message)) - return; - continue; - } - - nm_setting_ip_config_add_routing_rule (NM_SETTING_IP_CONFIG (setting), rule); - } + const char * setting_name = nm_setting_get_name(setting); + gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); + gs_strfreev char **keys = NULL; + gs_free BuildListData *build_list = NULL; + gsize i_build_list, build_list_len = 0; + + build_list = _build_list_create(info->keyfile, + setting_name, + BUILD_LIST_TYPE_ROUTING_RULES, + &build_list_len, + &keys); + if (!build_list) + return; + + for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { + nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL; + gs_free char * value = NULL; + gs_free_error GError *local = NULL; + + if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) + continue; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, + setting_name, + build_list[i_build_list].s_key, + NULL); + if (!value) + continue; + + rule = nm_ip_routing_rule_from_string( + value, + (NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE + | (is_ipv6 ? NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6 + : NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET)), + NULL, + &local); + if (!rule) { + if (!handle_warn(info, + build_list[i_build_list].s_key, + property_info->name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid value for \"%s\": %s"), + build_list[i_build_list].s_key, + local->message)) + return; + continue; + } + + nm_setting_ip_config_add_routing_rule(NM_SETTING_IP_CONFIG(setting), rule); + } } static void -ip_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - int addr_family; - gs_strfreev char **list = NULL; - gsize i, n, length; - - nm_assert (NM_IS_SETTING_IP4_CONFIG (setting) || NM_IS_SETTING_IP6_CONFIG (setting)); - - list = nm_keyfile_plugin_kf_get_string_list (info->keyfile, - nm_setting_get_name (setting), - key, - &length, - NULL); - nm_assert (length == NM_PTRARRAY_LEN (list)); - if (length == 0) - return; - - addr_family = NM_IS_SETTING_IP4_CONFIG (setting) ? AF_INET : AF_INET6; - - n = 0; - for (i = 0; i < length; i++) { - NMIPAddr addr; - - if (inet_pton (addr_family, list[i], &addr) <= 0) { - if (!handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid DNS server IPv%c address '%s'"), - nm_utils_addr_family_to_char (addr_family), - list[i])) { - do { - nm_clear_g_free (&list[i]); - } while (++i < length); - return; - } - nm_clear_g_free (&list[i]); - continue; - } - - if (n != i) - list[n] = g_steal_pointer (&list[i]); - n++; - } - - g_object_set (setting, key, list, NULL); + int addr_family; + gs_strfreev char **list = NULL; + gsize i, n, length; + + nm_assert(NM_IS_SETTING_IP4_CONFIG(setting) || NM_IS_SETTING_IP6_CONFIG(setting)); + + list = nm_keyfile_plugin_kf_get_string_list(info->keyfile, + nm_setting_get_name(setting), + key, + &length, + NULL); + nm_assert(length == NM_PTRARRAY_LEN(list)); + if (length == 0) + return; + + addr_family = NM_IS_SETTING_IP4_CONFIG(setting) ? AF_INET : AF_INET6; + + n = 0; + for (i = 0; i < length; i++) { + NMIPAddr addr; + + if (inet_pton(addr_family, list[i], &addr) <= 0) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid DNS server IPv%c address '%s'"), + nm_utils_addr_family_to_char(addr_family), + list[i])) { + do { + nm_clear_g_free(&list[i]); + } while (++i < length); + return; + } + nm_clear_g_free(&list[i]); + continue; + } + + if (n != i) + list[n] = g_steal_pointer(&list[i]); + n++; + } + + g_object_set(setting, key, list, NULL); } static void -ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - NMSettingIP6ConfigAddrGenMode addr_gen_mode; - const char *setting_name = nm_setting_get_name (setting); - gs_free char *s = NULL; - - s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); - if (s) { - if (!nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), s, - (int *) &addr_gen_mode, NULL)) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid option '%s', use one of [%s]"), - s, - "eui64,stable-privacy"); - return; - } - } else - addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; - - g_object_set (G_OBJECT (setting), key, (int) addr_gen_mode, NULL); + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + const char * setting_name = nm_setting_get_name(setting); + gs_free char * s = NULL; + + s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (s) { + if (!nm_utils_enum_from_str(nm_setting_ip6_config_addr_gen_mode_get_type(), + s, + (int *) &addr_gen_mode, + NULL)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid option '%s', use one of [%s]"), + s, + "eui64,stable-privacy"); + return; + } + } else + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + + g_object_set(G_OBJECT(setting), key, (int) addr_gen_mode, NULL); } static void -mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize addr_len, gboolean cloned_mac_addr) +mac_address_parser(KeyfileReaderInfo *info, + NMSetting * setting, + const char * key, + gsize addr_len, + gboolean cloned_mac_addr) { - const char *setting_name = nm_setting_get_name (setting); - char addr_str[NM_UTILS_HWADDR_LEN_MAX * 3]; - guint8 addr_bin[NM_UTILS_HWADDR_LEN_MAX]; - gs_free char *tmp_string = NULL; - gs_free guint *int_list = NULL; - const char *mac_str; - gsize int_list_len; - gsize i; - - nm_assert (addr_len > 0); - nm_assert (addr_len <= NM_UTILS_HWADDR_LEN_MAX); - - tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); - - if ( cloned_mac_addr - && NM_CLONED_MAC_IS_SPECIAL (tmp_string)) { - mac_str = tmp_string; - goto out; - } - - if ( tmp_string - && nm_utils_hwaddr_aton (tmp_string, addr_bin, addr_len)) - goto good_addr_bin; - - /* Old format; list of ints */ - int_list = nm_keyfile_plugin_kf_get_integer_list_uint (info->keyfile, setting_name, key, &int_list_len, NULL); - if (int_list_len == addr_len) { - for (i = 0; i < addr_len; i++) { - const guint val = int_list[i]; - - if (val > 255) - break; - addr_bin[i] = (guint8) val; - } - if (i == addr_len) - goto good_addr_bin; - } - - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid MAC address")); - return; + const char * setting_name = nm_setting_get_name(setting); + char addr_str[NM_UTILS_HWADDR_LEN_MAX * 3]; + guint8 addr_bin[NM_UTILS_HWADDR_LEN_MAX]; + gs_free char *tmp_string = NULL; + gs_free guint *int_list = NULL; + const char * mac_str; + gsize int_list_len; + gsize i; + + nm_assert(addr_len > 0); + nm_assert(addr_len <= NM_UTILS_HWADDR_LEN_MAX); + + tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + + if (cloned_mac_addr && NM_CLONED_MAC_IS_SPECIAL(tmp_string)) { + mac_str = tmp_string; + goto out; + } + + if (tmp_string && nm_utils_hwaddr_aton(tmp_string, addr_bin, addr_len)) + goto good_addr_bin; + + /* Old format; list of ints */ + int_list = nm_keyfile_plugin_kf_get_integer_list_uint(info->keyfile, + setting_name, + key, + &int_list_len, + NULL); + if (int_list_len == addr_len) { + for (i = 0; i < addr_len; i++) { + const guint val = int_list[i]; + + if (val > 255) + break; + addr_bin[i] = (guint8) val; + } + if (i == addr_len) + goto good_addr_bin; + } + + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid MAC address")); + return; good_addr_bin: - nm_utils_bin2hexstr_full (addr_bin, addr_len, ':', TRUE, addr_str); - mac_str = addr_str; + nm_utils_bin2hexstr_full(addr_bin, addr_len, ':', TRUE, addr_str); + mac_str = addr_str; out: - g_object_set (setting, key, mac_str, NULL); + g_object_set(setting, key, mac_str, NULL); } static void -mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +mac_address_parser_ETHER(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - mac_address_parser (info, setting, key, ETH_ALEN, FALSE); + mac_address_parser(info, setting, key, ETH_ALEN, FALSE); } static void -mac_address_parser_ETHER_cloned (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +mac_address_parser_ETHER_cloned(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - mac_address_parser (info, setting, key, ETH_ALEN, TRUE); + mac_address_parser(info, setting, key, ETH_ALEN, TRUE); } static void -mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +mac_address_parser_INFINIBAND(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - mac_address_parser (info, setting, key, INFINIBAND_ALEN, FALSE); + mac_address_parser(info, setting, key, INFINIBAND_ALEN, FALSE); } static void -read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key) +read_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key) { - gs_strfreev char **keys = NULL; - const char *const*iter; - const char *setting_name = nm_setting_get_name (setting); - gboolean is_vpn; - gsize n_keys; - - nm_assert ( (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_DATA)) - || (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_SECRETS)) - || (NM_IS_SETTING_BOND (setting) && nm_streq (key, NM_SETTING_BOND_OPTIONS)) - || (NM_IS_SETTING_USER (setting) && nm_streq (key, NM_SETTING_USER_DATA))); - - keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - if ( (is_vpn = NM_IS_SETTING_VPN (setting)) - || NM_IS_SETTING_BOND (setting)) { - for (iter = (const char *const*) keys; *iter; iter++) { - gs_free char *to_free = NULL; - gs_free char *value = NULL; - const char *name; - - value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); - if (!value) - continue; - - name = nm_keyfile_key_decode (*iter, &to_free); - - if (is_vpn) { - /* Add any item that's not a class property to the data hash */ - if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), name)) - nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), name, value); - } else { - if (!nm_streq (name, "interface-name")) - nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value); - } - } - openconnect_fix_secret_flags (setting); - return; - } - - if (NM_IS_SETTING_USER (setting)) { - gs_unref_hashtable GHashTable *data = NULL; - - data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - for (iter = (const char *const*) keys; *iter; iter++) { - gs_free char *to_free = NULL; - char *value = NULL; - const char *name; - - value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); - if (!value) - continue; - name = nm_keyfile_key_decode (*iter, &to_free); - g_hash_table_insert (data, - g_steal_pointer (&to_free) ?: g_strdup (name), - value); - } - g_object_set (setting, NM_SETTING_USER_DATA, data, NULL); - return; - } - - nm_assert_not_reached (); + gs_strfreev char **keys = NULL; + const char *const *iter; + const char * setting_name = nm_setting_get_name(setting); + gboolean is_vpn; + gsize n_keys; + + nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_DATA)) + || (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) + || (NM_IS_SETTING_BOND(setting) && nm_streq(key, NM_SETTING_BOND_OPTIONS)) + || (NM_IS_SETTING_USER(setting) && nm_streq(key, NM_SETTING_USER_DATA))); + + keys = nm_keyfile_plugin_kf_get_keys(file, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + if ((is_vpn = NM_IS_SETTING_VPN(setting)) || NM_IS_SETTING_BOND(setting)) { + for (iter = (const char *const *) keys; *iter; iter++) { + gs_free char *to_free = NULL; + gs_free char *value = NULL; + const char * name; + + value = nm_keyfile_plugin_kf_get_string(file, setting_name, *iter, NULL); + if (!value) + continue; + + name = nm_keyfile_key_decode(*iter, &to_free); + + if (is_vpn) { + /* Add any item that's not a class property to the data hash */ + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(setting), name)) + nm_setting_vpn_add_data_item(NM_SETTING_VPN(setting), name, value); + } else { + if (!nm_streq(name, "interface-name")) + nm_setting_bond_add_option(NM_SETTING_BOND(setting), name, value); + } + } + openconnect_fix_secret_flags(setting); + return; + } + + if (NM_IS_SETTING_USER(setting)) { + gs_unref_hashtable GHashTable *data = NULL; + + data = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); + for (iter = (const char *const *) keys; *iter; iter++) { + gs_free char *to_free = NULL; + char * value = NULL; + const char * name; + + value = nm_keyfile_plugin_kf_get_string(file, setting_name, *iter, NULL); + if (!value) + continue; + name = nm_keyfile_key_decode(*iter, &to_free); + g_hash_table_insert(data, g_steal_pointer(&to_free) ?: g_strdup(name), value); + } + g_object_set(setting, NM_SETTING_USER_DATA, data, NULL); + return; + } + + nm_assert_not_reached(); } static gsize -unescape_semicolons (char *str) +unescape_semicolons(char *str) { - gsize i, j; - - for (i = 0, j = 0; str[i]; ) { - if (str[i] == '\\' && str[i+1] == ';') - i++; - str[j++] = str[i++];; - } - nm_explicit_bzero (&str[j], i - j); - return j; + gsize i, j; + + for (i = 0, j = 0; str[i];) { + if (str[i] == '\\' && str[i + 1] == ';') + i++; + str[j++] = str[i++]; + } + nm_explicit_bzero(&str[j], i - j); + return j; } static GBytes * -get_bytes (KeyfileReaderInfo *info, - const char *setting_name, - const char *key, - gboolean zero_terminate, - gboolean unescape_semicolon) +get_bytes(KeyfileReaderInfo *info, + const char * setting_name, + const char * key, + gboolean zero_terminate, + gboolean unescape_semicolon) { - nm_auto_free_secret char *tmp_string = NULL; - gboolean may_be_int_list = TRUE; - gsize length; - GBytes *result; - - /* New format: just a string - * Old format: integer list; e.g. 11;25;38; - */ - tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); - if (!tmp_string) - return NULL; - - /* if the string is empty, we return an empty GBytes array. - * Note that for NM_SETTING_802_1X_PASSWORD_RAW both %NULL and - * an empty GBytes are valid, and shall be destinguished. */ - if (!tmp_string[0]) { - /* note that even if @zero_terminate is TRUE, we return an empty - * byte-array. The reason is that zero_terminate is there to terminate - * *valid* strings. It's not there to terminated invalid (empty) strings. - */ - return g_bytes_new_static ("", 0); - } - - for (length = 0; tmp_string[length]; length++) { - const char ch = tmp_string[length]; - - if ( !g_ascii_isspace (ch) - && !g_ascii_isdigit (ch) - && ch != ';') { - may_be_int_list = FALSE; - length += strlen (&tmp_string[length]); - break; - } - } - - /* Try to parse the string as a integer list. */ - if (may_be_int_list && length > 0) { - nm_auto_free_secret_buf NMSecretBuf *bin = NULL; - const char *const s = tmp_string; - gsize i, d; - - bin = nm_secret_buf_new (length / 2 + 3); + nm_auto_free_secret char *tmp_string = NULL; + gboolean may_be_int_list = TRUE; + gsize length; + GBytes * result; + + /* New format: just a string + * Old format: integer list; e.g. 11;25;38; + */ + tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!tmp_string) + return NULL; + + /* if the string is empty, we return an empty GBytes array. + * Note that for NM_SETTING_802_1X_PASSWORD_RAW both %NULL and + * an empty GBytes are valid, and shall be destinguished. */ + if (!tmp_string[0]) { + /* note that even if @zero_terminate is TRUE, we return an empty + * byte-array. The reason is that zero_terminate is there to terminate + * *valid* strings. It's not there to terminated invalid (empty) strings. + */ + return g_bytes_new_static("", 0); + } + + for (length = 0; tmp_string[length]; length++) { + const char ch = tmp_string[length]; + + if (!g_ascii_isspace(ch) && !g_ascii_isdigit(ch) && ch != ';') { + may_be_int_list = FALSE; + length += strlen(&tmp_string[length]); + break; + } + } + + /* Try to parse the string as a integer list. */ + if (may_be_int_list && length > 0) { + nm_auto_free_secret_buf NMSecretBuf *bin = NULL; + const char *const s = tmp_string; + gsize i, d; + + bin = nm_secret_buf_new(length / 2 + 3); #define DIGIT(c) ((c) - '0') - i = 0; - d = 0; - while (TRUE) { - int n; - - /* leading whitespace */ - while (g_ascii_isspace (s[i])) - i++; - if (s[i] == '\0') - break; - /* then expect 1 to 3 digits */ - if (!g_ascii_isdigit (s[i])) { - d = 0; - break; - } - n = DIGIT (s[i]); - i++; - if (g_ascii_isdigit (s[i])) { - n = 10 * n + DIGIT (s[i]); - i++; - if (g_ascii_isdigit (s[i])) { - n = 10 * n + DIGIT (s[i]); - i++; - } - } - if (n > 255) { - d = 0; - break; - } - - nm_assert (d < bin->len); - bin->bin[d++] = n; - - /* allow whitespace after the digit. */ - while (g_ascii_isspace (s[i])) - i++; - /* need a semicolon as separator. */ - if (s[i] != ';') { - d = 0; - break; - } - i++; - } + i = 0; + d = 0; + while (TRUE) { + int n; + + /* leading whitespace */ + while (g_ascii_isspace(s[i])) + i++; + if (s[i] == '\0') + break; + /* then expect 1 to 3 digits */ + if (!g_ascii_isdigit(s[i])) { + d = 0; + break; + } + n = DIGIT(s[i]); + i++; + if (g_ascii_isdigit(s[i])) { + n = 10 * n + DIGIT(s[i]); + i++; + if (g_ascii_isdigit(s[i])) { + n = 10 * n + DIGIT(s[i]); + i++; + } + } + if (n > 255) { + d = 0; + break; + } + + nm_assert(d < bin->len); + bin->bin[d++] = n; + + /* allow whitespace after the digit. */ + while (g_ascii_isspace(s[i])) + i++; + /* need a semicolon as separator. */ + if (s[i] != ';') { + d = 0; + break; + } + i++; + } #undef DIGIT - /* Old format; list of ints. We already did a strict validation of the - * string format before. We expect that this conversion cannot fail. */ - if (d > 0) { - /* note that @zero_terminate does not add a terminating '\0' to - * binary data as an integer list. If the bytes are expressed as - * an integer list, all potential NUL characters are supposed to - * be included there explicitly. - * - * However, in the spirit of defensive programming, we do append a - * NUL character to the buffer, although this character is hidden - * and only a mitigation for bugs. */ - - if (d + 10 < bin->len) { - /* hm, too much unused memory. Copy the memory to a suitable - * sized buffer. */ - return nm_secret_copy_to_gbytes (bin->bin, d); - } - - nm_assert (d < bin->len); - bin->bin[d] = '\0'; - return nm_secret_buf_to_gbytes_take (g_steal_pointer (&bin), d); - } - } - - /* Handle as a simple string (ie, new format) */ - if (unescape_semicolon) - length = unescape_semicolons (tmp_string); - if (zero_terminate) - length++; - if (length == 0) - return NULL; - - result = g_bytes_new_with_free_func (tmp_string, - length, - (GDestroyNotify) nm_free_secret, - tmp_string); - tmp_string = NULL; - return result; + /* Old format; list of ints. We already did a strict validation of the + * string format before. We expect that this conversion cannot fail. */ + if (d > 0) { + /* note that @zero_terminate does not add a terminating '\0' to + * binary data as an integer list. If the bytes are expressed as + * an integer list, all potential NUL characters are supposed to + * be included there explicitly. + * + * However, in the spirit of defensive programming, we do append a + * NUL character to the buffer, although this character is hidden + * and only a mitigation for bugs. */ + + if (d + 10 < bin->len) { + /* hm, too much unused memory. Copy the memory to a suitable + * sized buffer. */ + return nm_secret_copy_to_gbytes(bin->bin, d); + } + + nm_assert(d < bin->len); + bin->bin[d] = '\0'; + return nm_secret_buf_to_gbytes_take(g_steal_pointer(&bin), d); + } + } + + /* Handle as a simple string (ie, new format) */ + if (unescape_semicolon) + length = unescape_semicolons(tmp_string); + if (zero_terminate) + length++; + if (length == 0) + return NULL; + + result = + g_bytes_new_with_free_func(tmp_string, length, (GDestroyNotify) nm_free_secret, tmp_string); + tmp_string = NULL; + return result; } static void -ssid_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +ssid_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_bytes GBytes *bytes = NULL; - - bytes = get_bytes (info, setting_name, key, FALSE, TRUE); - if (!bytes) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid SSID")); - return; - } - g_object_set (setting, key, bytes, NULL); + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + + bytes = get_bytes(info, setting_name, key, FALSE, TRUE); + if (!bytes) { + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid SSID")); + return; + } + g_object_set(setting, key, bytes, NULL); } static void -password_raw_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +password_raw_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_bytes GBytes *bytes = NULL; - - bytes = get_bytes (info, setting_name, key, FALSE, TRUE); - if (!bytes) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid raw password")); - return; - } - g_object_set (setting, key, bytes, NULL); + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + + bytes = get_bytes(info, setting_name, key, FALSE, TRUE); + if (!bytes) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid raw password")); + return; + } + g_object_set(setting, key, bytes, NULL); } static char * -get_cert_path (const char *base_dir, const guint8 *cert_path, gsize cert_path_len) +get_cert_path(const char *base_dir, const guint8 *cert_path, gsize cert_path_len) { - const char *base; - char *p = NULL, *path, *tmp; + const char *base; + char * p = NULL, *path, *tmp; - g_return_val_if_fail (base_dir != NULL, NULL); - g_return_val_if_fail (cert_path != NULL, NULL); + g_return_val_if_fail(base_dir != NULL, NULL); + g_return_val_if_fail(cert_path != NULL, NULL); - path = g_strndup ((char *) cert_path, cert_path_len); + path = g_strndup((char *) cert_path, cert_path_len); - if (path[0] == '/') - return path; + if (path[0] == '/') + return path; - base = path; - p = strrchr (path, '/'); - if (p) - base = p + 1; + base = path; + p = strrchr(path, '/'); + if (p) + base = p + 1; - tmp = g_build_path ("/", base_dir, base, NULL); - g_free (path); - return tmp; + tmp = g_build_path("/", base_dir, base, NULL); + g_free(path); + return tmp; } -static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" }; +static const char *certext[] = {".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key"}; static gboolean -has_cert_ext (const char *path) +has_cert_ext(const char *path) { - int i; + int i; - for (i = 0; i < G_N_ELEMENTS (certext); i++) { - if (g_str_has_suffix (path, certext[i])) - return TRUE; - } - return FALSE; + for (i = 0; i < G_N_ELEMENTS(certext); i++) { + if (g_str_has_suffix(path, certext[i])) + return TRUE; + } + return FALSE; } char * -nm_keyfile_detect_unqualified_path_scheme (const char *base_dir, - gconstpointer pdata, - gsize data_len, - gboolean consider_exists, - gboolean *out_exists) +nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, + gconstpointer pdata, + gsize data_len, + gboolean consider_exists, + gboolean * out_exists) { - const char *data = pdata; - gboolean exists = FALSE; - gsize validate_len; - gsize path_len, pathuri_len; - gs_free char *path = NULL; - gs_free char *pathuri = NULL; - - g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL); - - if (!pdata) - return NULL; - if (data_len == -1) - data_len = strlen (data); - if (data_len > 500 || data_len < 1) - return NULL; - - /* If there's a trailing zero tell g_utf8_validate() to validate until the zero */ - if (data[data_len - 1] == '\0') { - /* setting it to -1, would mean we accept data to contain NUL characters before the - * end. Don't accept any NUL in [0 .. data_len-1[ . */ - validate_len = data_len - 1; - } else - validate_len = data_len; - if ( validate_len == 0 - || g_utf8_validate ((const char *) data, validate_len, NULL) == FALSE) - return NULL; - - /* Might be a bare path without the file:// prefix; in that case - * if it's an absolute path, use that, otherwise treat it as a - * relative path to the current directory. - */ - - path = get_cert_path (base_dir, (const guint8 *) data, data_len); - - /* FIXME(keyfile-parse-in-memory): it is wrong that keyfile reader makes decisions based on - * the file systems content. The serialization/parsing should be entirely in-memory. */ - if ( !memchr (data, '/', data_len) - && !has_cert_ext (path)) { - if (!consider_exists) - return NULL; - exists = g_file_test (path, G_FILE_TEST_EXISTS); - if (!exists) - return NULL; - } else if (out_exists) - exists = g_file_test (path, G_FILE_TEST_EXISTS); - - /* Construct the proper value as required for the PATH scheme. - * - * When returning TRUE, we must also be sure that @data_len does not look like - * the deprecated format of list of integers. With this implementation that is the - * case, as long as @consider_exists is FALSE. */ - path_len = strlen (path); - pathuri_len = (NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + 1) + path_len; - pathuri = g_new (char, pathuri_len); - memcpy (pathuri, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)); - memcpy (&pathuri[NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)], path, path_len + 1); - if (nm_setting_802_1x_check_cert_scheme (pathuri, pathuri_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_PATH) - return NULL; - - NM_SET_OUT (out_exists, exists); - return g_steal_pointer (&pathuri); + const char * data = pdata; + gboolean exists = FALSE; + gsize validate_len; + gsize path_len, pathuri_len; + gs_free char *path = NULL; + gs_free char *pathuri = NULL; + + g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); + + if (!pdata) + return NULL; + if (data_len == -1) + data_len = strlen(data); + if (data_len > 500 || data_len < 1) + return NULL; + + /* If there's a trailing zero tell g_utf8_validate() to validate until the zero */ + if (data[data_len - 1] == '\0') { + /* setting it to -1, would mean we accept data to contain NUL characters before the + * end. Don't accept any NUL in [0 .. data_len-1[ . */ + validate_len = data_len - 1; + } else + validate_len = data_len; + if (validate_len == 0 || g_utf8_validate((const char *) data, validate_len, NULL) == FALSE) + return NULL; + + /* Might be a bare path without the file:// prefix; in that case + * if it's an absolute path, use that, otherwise treat it as a + * relative path to the current directory. + */ + + path = get_cert_path(base_dir, (const guint8 *) data, data_len); + + /* FIXME(keyfile-parse-in-memory): it is wrong that keyfile reader makes decisions based on + * the file systems content. The serialization/parsing should be entirely in-memory. */ + if (!memchr(data, '/', data_len) && !has_cert_ext(path)) { + if (!consider_exists) + return NULL; + exists = g_file_test(path, G_FILE_TEST_EXISTS); + if (!exists) + return NULL; + } else if (out_exists) + exists = g_file_test(path, G_FILE_TEST_EXISTS); + + /* Construct the proper value as required for the PATH scheme. + * + * When returning TRUE, we must also be sure that @data_len does not look like + * the deprecated format of list of integers. With this implementation that is the + * case, as long as @consider_exists is FALSE. */ + path_len = strlen(path); + pathuri_len = (NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + 1) + path_len; + pathuri = g_new(char, pathuri_len); + memcpy(pathuri, + NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, + NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)); + memcpy(&pathuri[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)], path, path_len + 1); + if (nm_setting_802_1x_check_cert_scheme(pathuri, pathuri_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PATH) + return NULL; + + NM_SET_OUT(out_exists, exists); + return g_steal_pointer(&pathuri); } -#define HAS_SCHEME_PREFIX(bin, bin_len, scheme) \ - ({ \ - const char *const _bin = (bin); \ - const gsize _bin_len = (bin_len); \ - \ - nm_assert (_bin && _bin_len > 0); \ - \ - ( _bin_len > NM_STRLEN (scheme) + 1 \ - && _bin[_bin_len - 1] == '\0' \ - && memcmp (_bin, scheme, NM_STRLEN (scheme)) == 0); \ - }) +#define HAS_SCHEME_PREFIX(bin, bin_len, scheme) \ + ({ \ + const char *const _bin = (bin); \ + const gsize _bin_len = (bin_len); \ + \ + nm_assert(_bin &&_bin_len > 0); \ + \ + (_bin_len > NM_STRLEN(scheme) + 1 && _bin[_bin_len - 1] == '\0' \ + && memcmp(_bin, scheme, NM_STRLEN(scheme)) == 0); \ + }) static void -cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_bytes GBytes *bytes = NULL; - const char *bin = NULL; - gsize bin_len = 0; - char *path; - gboolean path_exists; - - bytes = get_bytes (info, setting_name, key, TRUE, FALSE); - if (bytes) - bin = g_bytes_get_data (bytes, &bin_len); - if (bin_len == 0) { - if (!info->error) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value")); - } - return; - } - - if (HAS_SCHEME_PREFIX (bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) { - const char *path2 = &bin[NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)]; - gs_free char *path2_free = NULL; - - if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_PATH) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value path \"%s\""), - bin); - return; - } - - g_object_set (setting, key, bytes, NULL); - - if (path2[0] != '/') { - /* we want to read absolute paths because we use keyfile as exchange - * between different processes which might not have the same cwd. */ - path2_free = get_cert_path (info->base_dir, (const guint8 *) path2, - bin_len - NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) - 1); - path2 = path2_free; - } - - /* FIXME(keyfile-parse-in-memory): keyfile reader must not access the file system and - * (in a first step) only operate in memory-only. If the presence of files should be checked, - * then by invoking a callback (and possibly keyfile settings plugin would - * collect the file names to be checked and check them later). */ - if (!g_file_test (path2, G_FILE_TEST_EXISTS)) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, - _("certificate or key file '%s' does not exist"), - path2); - } - return; - } - - if (HAS_SCHEME_PREFIX (bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11)) { - if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid PKCS#11 URI \"%s\""), - bin); - return; - } - - g_object_set (setting, key, bytes, NULL); - return; - } - - if (HAS_SCHEME_PREFIX (bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) { - const char *cdata = bin + NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB); - gsize cdata_len = bin_len - NM_STRLEN (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB) - 1; - gs_free guchar *bin_decoded = NULL; - gsize bin_decoded_len = 0; - gsize i; - gboolean valid_base64; - gs_unref_bytes GBytes *val = NULL; - - /* Let's be strict here. We expect valid base64, no funny stuff!! - * We didn't write such invalid data ourselfes and refuse to read it as blob. */ - if ((valid_base64 = (cdata_len % 4 == 0))) { - for (i = 0; i < cdata_len; i++) { - char c = cdata[i]; - - if (!( (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || (c == '+' || c == '/'))) { - if (c != '=' || i < cdata_len - 2) - valid_base64 = FALSE; - else { - for (; i < cdata_len; i++) { - if (cdata[i] != '=') - valid_base64 = FALSE; - } - } - break; - } - } - } - if (valid_base64) - bin_decoded = g_base64_decode (cdata, &bin_decoded_len); - - if (bin_decoded_len == 0) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value data:;base64, is not base64")); - return; - } - - if (nm_setting_802_1x_check_cert_scheme (bin_decoded, bin_decoded_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) { - /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x. - * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start - * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */ - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value data:;base64,file://")); - return; - } - - val = g_bytes_new_take (g_steal_pointer (&bin_decoded), bin_decoded_len); - g_object_set (setting, key, val, NULL); - return; - } - - /* If not, it might be a plain path */ - path = nm_keyfile_detect_unqualified_path_scheme (info->base_dir, bin, bin_len, TRUE, &path_exists); - if (path) { - gs_unref_bytes GBytes *val = NULL; - - /* Construct the proper value as required for the PATH scheme */ - val = g_bytes_new_take (path, strlen (path) + 1); - g_object_set (setting, key, val, NULL); - - /* Warn if the certificate didn't exist */ - if (!path_exists) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, - _("certificate or key file '%s' does not exist"), - path); - } - return; - } - - if (nm_setting_802_1x_check_cert_scheme (bin, bin_len, NULL) != NM_SETTING_802_1X_CK_SCHEME_BLOB) { - /* The blob probably starts with "file://" but contains invalid characters for a path. - * Setting the cert data will confuse NMSetting8021x. - * In fact, NMSetting8021x does not support setting such binary data, so just warn and - * continue. */ - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value is not a valid blob")); - return; - } - - g_object_set (setting, key, bytes, NULL); + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + const char * bin = NULL; + gsize bin_len = 0; + char * path; + gboolean path_exists; + + bytes = get_bytes(info, setting_name, key, TRUE, FALSE); + if (bytes) + bin = g_bytes_get_data(bytes, &bin_len); + if (bin_len == 0) { + if (!info->error) { + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("invalid key/cert value")); + } + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) { + const char * path2 = &bin[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)]; + gs_free char *path2_free = NULL; + + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PATH) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value path \"%s\""), + bin); + return; + } + + g_object_set(setting, key, bytes, NULL); + + if (path2[0] != '/') { + /* we want to read absolute paths because we use keyfile as exchange + * between different processes which might not have the same cwd. */ + path2_free = get_cert_path(info->base_dir, + (const guint8 *) path2, + bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) - 1); + path2 = path2_free; + } + + /* FIXME(keyfile-parse-in-memory): keyfile reader must not access the file system and + * (in a first step) only operate in memory-only. If the presence of files should be checked, + * then by invoking a callback (and possibly keyfile settings plugin would + * collect the file names to be checked and check them later). */ + if (!g_file_test(path2, G_FILE_TEST_EXISTS)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path2); + } + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11)) { + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid PKCS#11 URI \"%s\""), + bin); + return; + } + + g_object_set(setting, key, bytes, NULL); + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) { + const char *cdata = bin + NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB); + gsize cdata_len = bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB) - 1; + gs_free guchar *bin_decoded = NULL; + gsize bin_decoded_len = 0; + gsize i; + gboolean valid_base64; + gs_unref_bytes GBytes *val = NULL; + + /* Let's be strict here. We expect valid base64, no funny stuff!! + * We didn't write such invalid data ourselfes and refuse to read it as blob. */ + if ((valid_base64 = (cdata_len % 4 == 0))) { + for (i = 0; i < cdata_len; i++) { + char c = cdata[i]; + + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || (c == '+' || c == '/'))) { + if (c != '=' || i < cdata_len - 2) + valid_base64 = FALSE; + else { + for (; i < cdata_len; i++) { + if (cdata[i] != '=') + valid_base64 = FALSE; + } + } + break; + } + } + } + if (valid_base64) + bin_decoded = g_base64_decode(cdata, &bin_decoded_len); + + if (bin_decoded_len == 0) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64, is not base64")); + return; + } + + if (nm_setting_802_1x_check_cert_scheme(bin_decoded, bin_decoded_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x. + * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start + * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */ + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64,file://")); + return; + } + + val = g_bytes_new_take(g_steal_pointer(&bin_decoded), bin_decoded_len); + g_object_set(setting, key, val, NULL); + return; + } + + /* If not, it might be a plain path */ + path = + nm_keyfile_detect_unqualified_path_scheme(info->base_dir, bin, bin_len, TRUE, &path_exists); + if (path) { + gs_unref_bytes GBytes *val = NULL; + + /* Construct the proper value as required for the PATH scheme */ + val = g_bytes_new_take(path, strlen(path) + 1); + g_object_set(setting, key, val, NULL); + + /* Warn if the certificate didn't exist */ + if (!path_exists) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path); + } + return; + } + + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* The blob probably starts with "file://" but contains invalid characters for a path. + * Setting the cert data will confuse NMSetting8021x. + * In fact, NMSetting8021x does not support setting such binary data, so just warn and + * continue. */ + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value is not a valid blob")); + return; + } + + g_object_set(setting, key, bytes, NULL); } static int -_parity_from_char (int ch) +_parity_from_char(int ch) { #if NM_MORE_ASSERTS > 5 - { - static char check = 0; - - if (check == 0) { - nm_auto_unref_gtypeclass GEnumClass *klass = g_type_class_ref (NM_TYPE_SETTING_SERIAL_PARITY); - guint i; - - check = 1; - - /* In older versions, parity was G_TYPE_CHAR/gint8, and the character - * value was stored as integer. - * For example parity=69 equals parity=E, meaning NM_SETTING_SERIAL_PARITY_EVEN. - * - * That means, certain values are reserved. Assert that these numbers - * are not reused when we extend NMSettingSerialParity enum. - * Actually, since NM_SETTING_SERIAL_PARITY is g_param_spec_enum(), - * we anyway cannot extend the enum without breaking API... - * - * [1] commit "a91e60902e libnm-core: make NMSettingSerial:parity an enum" - * [2] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=a91e60902eabae1de93d61323dae6ac894b5d40f - */ - g_assert (G_IS_ENUM_CLASS (klass)); - for (i = 0; i < klass->n_values; i++) { - const GEnumValue *v = &klass->values[i]; - int num = v->value; - - g_assert (_parity_from_char (num) == -1); - g_assert (!NM_IN_SET (num, 'e', 'E', 'o', 'O', 'n', 'N')); - } - } - } + { + static char check = 0; + + if (check == 0) { + nm_auto_unref_gtypeclass GEnumClass *klass = + g_type_class_ref(NM_TYPE_SETTING_SERIAL_PARITY); + guint i; + + check = 1; + + /* In older versions, parity was G_TYPE_CHAR/gint8, and the character + * value was stored as integer. + * For example parity=69 equals parity=E, meaning NM_SETTING_SERIAL_PARITY_EVEN. + * + * That means, certain values are reserved. Assert that these numbers + * are not reused when we extend NMSettingSerialParity enum. + * Actually, since NM_SETTING_SERIAL_PARITY is g_param_spec_enum(), + * we anyway cannot extend the enum without breaking API... + * + * [1] commit "a91e60902e libnm-core: make NMSettingSerial:parity an enum" + * [2] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=a91e60902eabae1de93d61323dae6ac894b5d40f + */ + g_assert(G_IS_ENUM_CLASS(klass)); + for (i = 0; i < klass->n_values; i++) { + const GEnumValue *v = &klass->values[i]; + int num = v->value; + + g_assert(_parity_from_char(num) == -1); + g_assert(!NM_IN_SET(num, 'e', 'E', 'o', 'O', 'n', 'N')); + } + } + } #endif - switch (ch) { - case 'E': - case 'e': - return NM_SETTING_SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return NM_SETTING_SERIAL_PARITY_ODD; - case 'N': - case 'n': - return NM_SETTING_SERIAL_PARITY_NONE; - } - - return -1; + switch (ch) { + case 'E': + case 'e': + return NM_SETTING_SERIAL_PARITY_EVEN; + case 'O': + case 'o': + return NM_SETTING_SERIAL_PARITY_ODD; + case 'N': + case 'n': + return NM_SETTING_SERIAL_PARITY_NONE; + } + + return -1; } static void -parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +parity_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_free_error GError *err = NULL; - int parity; - gs_free char *tmp_str = NULL; - gint64 i64; - - /* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'. - * We now accept either that or the (case-insensitive) character itself (but - * still always write it the old way, for backward compatibility). - */ - tmp_str = nm_keyfile_plugin_kf_get_value (info->keyfile, setting_name, key, &err); - if (err) - goto out_err; - - if ( tmp_str - && tmp_str[0] != '\0' - && tmp_str[1] == '\0') { - /* the ASCII characters like 'E' are taken directly... */ - parity = _parity_from_char (tmp_str[0]); - if (parity >= 0) - goto parity_good; - } - - i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); - if ( i64 != G_MININT64 - && errno == 0) { - - if ((parity = _parity_from_char (i64)) >= 0) { - /* another oddity: the string is a valid number. However, if the numeric values - * is one of the supported ASCII codes, accept it (like 69 for 'E'). - */ - goto parity_good; - } - - /* Finally, take the numeric value as is. */ - parity = i64; - goto parity_good; - } - - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid parity value '%s'"), - tmp_str ?: ""); - return; + const char * setting_name = nm_setting_get_name(setting); + gs_free_error GError *err = NULL; + int parity; + gs_free char * tmp_str = NULL; + gint64 i64; + + /* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'. + * We now accept either that or the (case-insensitive) character itself (but + * still always write it the old way, for backward compatibility). + */ + tmp_str = nm_keyfile_plugin_kf_get_value(info->keyfile, setting_name, key, &err); + if (err) + goto out_err; + + if (tmp_str && tmp_str[0] != '\0' && tmp_str[1] == '\0') { + /* the ASCII characters like 'E' are taken directly... */ + parity = _parity_from_char(tmp_str[0]); + if (parity >= 0) + goto parity_good; + } + + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); + if (i64 != G_MININT64 && errno == 0) { + if ((parity = _parity_from_char(i64)) >= 0) { + /* another oddity: the string is a valid number. However, if the numeric values + * is one of the supported ASCII codes, accept it (like 69 for 'E'). + */ + goto parity_good; + } + + /* Finally, take the numeric value as is. */ + parity = i64; + goto parity_good; + } + + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid parity value '%s'"), + tmp_str ?: ""); + return; parity_good: - nm_g_object_set_property_enum (G_OBJECT (setting), key, NM_TYPE_SETTING_SERIAL_PARITY, parity, &err); + nm_g_object_set_property_enum(G_OBJECT(setting), + key, + NM_TYPE_SETTING_SERIAL_PARITY, + parity, + &err); out_err: - if (!err) - return; - if (nm_keyfile_error_is_not_found (err)) { - /* ignore such errors. The key is not present. */ - return; - } - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting: %s"), - err->message); + if (!err) + return; + if (nm_keyfile_error_is_not_found(err)) { + /* ignore such errors. The key is not present. */ + return; + } + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); } static void -team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +team_config_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_free char *conf = NULL; - gs_free_error GError *error = NULL; - - conf = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); - - g_object_set (G_OBJECT (setting), key, conf, NULL); - - if ( conf - && !nm_setting_verify (setting, NULL, &error)) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid team configuration: %s"), - error->message); - g_object_set (G_OBJECT (setting), key, NULL, NULL); - } + const char * setting_name = nm_setting_get_name(setting); + gs_free char *conf = NULL; + gs_free_error GError *error = NULL; + + conf = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + + g_object_set(G_OBJECT(setting), key, conf, NULL); + + if (conf && !nm_setting_verify(setting, NULL, &error)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid team configuration: %s"), + error->message); + g_object_set(G_OBJECT(setting), key, NULL, NULL); + } } static void -bridge_vlan_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +bridge_vlan_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - gs_unref_ptrarray GPtrArray *vlans = NULL; - gs_free char *value = NULL; - gs_free const char **strv = NULL; - const char *const *iter; - GError *local = NULL; - NMBridgeVlan *vlan; - - value = nm_keyfile_plugin_kf_get_string (info->keyfile, - nm_setting_get_name (setting), - key, - NULL); - if (!value || !value[0]) - return; - - vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref); - - strv = nm_utils_escaped_tokens_split (value, ","); - if (strv) { - for (iter = strv; *iter; iter++) { - vlan = nm_bridge_vlan_from_str (*iter, &local); - if (!vlan) { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - "invalid bridge VLAN: %s", - local->message); - g_clear_error (&local); - continue; - } - g_ptr_array_add (vlans, vlan); - } - } - - if (vlans->len > 0) - g_object_set (setting, key, vlans, NULL); + gs_unref_ptrarray GPtrArray *vlans = NULL; + gs_free char * value = NULL; + gs_free const char ** strv = NULL; + const char *const * iter; + GError * local = NULL; + NMBridgeVlan * vlan; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, nm_setting_get_name(setting), key, NULL); + if (!value || !value[0]) + return; + + vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref); + + strv = nm_utils_escaped_tokens_split(value, ","); + if (strv) { + for (iter = strv; *iter; iter++) { + vlan = nm_bridge_vlan_from_str(*iter, &local); + if (!vlan) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + "invalid bridge VLAN: %s", + local->message); + g_clear_error(&local); + continue; + } + g_ptr_array_add(vlans, vlan); + } + } + + if (vlans->len > 0) + g_object_set(setting, key, vlans, NULL); } static void -qdisc_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +qdisc_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_ptrarray GPtrArray *qdiscs = NULL; - gs_strfreev char **keys = NULL; - gsize n_keys = 0; - int i; - - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref); - - for (i = 0; i < n_keys; i++) { - NMTCQdisc *qdisc; - const char *qdisc_parent; - gs_free char *qdisc_rest = NULL; - gs_free char *qdisc_str = NULL; - gs_free_error GError *err = NULL; - - if (!g_str_has_prefix (keys[i], "qdisc.")) - continue; - - qdisc_parent = keys[i] + sizeof ("qdisc.") - 1; - qdisc_rest = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, keys[i], NULL); - qdisc_str = g_strdup_printf ("%s%s %s", - _nm_utils_parse_tc_handle (qdisc_parent, NULL) != TC_H_UNSPEC ? "parent " : "", - qdisc_parent, - qdisc_rest); - - qdisc = nm_utils_tc_qdisc_from_str (qdisc_str, &err); - if (!qdisc) { - handle_warn (info, - keys[i], - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid qdisc: %s"), - err->message); - } else { - g_ptr_array_add (qdiscs, qdisc); - } - } - - if (qdiscs->len >= 1) - g_object_set (setting, key, qdiscs, NULL); + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *qdiscs = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + qdiscs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_qdisc_unref); + + for (i = 0; i < n_keys; i++) { + NMTCQdisc * qdisc; + const char * qdisc_parent; + gs_free char *qdisc_rest = NULL; + gs_free char *qdisc_str = NULL; + gs_free_error GError *err = NULL; + + if (!g_str_has_prefix(keys[i], "qdisc.")) + continue; + + qdisc_parent = keys[i] + sizeof("qdisc.") - 1; + qdisc_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); + qdisc_str = g_strdup_printf( + "%s%s %s", + _nm_utils_parse_tc_handle(qdisc_parent, NULL) != TC_H_UNSPEC ? "parent " : "", + qdisc_parent, + qdisc_rest); + + qdisc = nm_utils_tc_qdisc_from_str(qdisc_str, &err); + if (!qdisc) { + handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid qdisc: %s"), + err->message); + } else { + g_ptr_array_add(qdiscs, qdisc); + } + } + + if (qdiscs->len >= 1) + g_object_set(setting, key, qdiscs, NULL); } static void -tfilter_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) +tfilter_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { - const char *setting_name = nm_setting_get_name (setting); - gs_unref_ptrarray GPtrArray *tfilters = NULL; - gs_strfreev char **keys = NULL; - gsize n_keys = 0; - int i; - - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref); - - for (i = 0; i < n_keys; i++) { - NMTCTfilter *tfilter; - const char *tfilter_parent; - gs_free char *tfilter_rest = NULL; - gs_free char *tfilter_str = NULL; - gs_free_error GError *err = NULL; - - if (!g_str_has_prefix (keys[i], "tfilter.")) - continue; - - tfilter_parent = keys[i] + sizeof ("tfilter.") - 1; - tfilter_rest = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, keys[i], NULL); - tfilter_str = g_strdup_printf ("%s%s %s", - _nm_utils_parse_tc_handle (tfilter_parent, NULL) != TC_H_UNSPEC ? "parent " : "", - tfilter_parent, - tfilter_rest); - - tfilter = nm_utils_tc_tfilter_from_str (tfilter_str, &err); - if (!tfilter) { - handle_warn (info, - keys[i], - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid tfilter: %s"), - err->message); - } else { - g_ptr_array_add (tfilters, tfilter); - } - } - - if (tfilters->len >= 1) - g_object_set (setting, key, tfilters, NULL); + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *tfilters = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + tfilters = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_tfilter_unref); + + for (i = 0; i < n_keys; i++) { + NMTCTfilter * tfilter; + const char * tfilter_parent; + gs_free char *tfilter_rest = NULL; + gs_free char *tfilter_str = NULL; + gs_free_error GError *err = NULL; + + if (!g_str_has_prefix(keys[i], "tfilter.")) + continue; + + tfilter_parent = keys[i] + sizeof("tfilter.") - 1; + tfilter_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); + tfilter_str = g_strdup_printf( + "%s%s %s", + _nm_utils_parse_tc_handle(tfilter_parent, NULL) != TC_H_UNSPEC ? "parent " : "", + tfilter_parent, + tfilter_rest); + + tfilter = nm_utils_tc_tfilter_from_str(tfilter_str, &err); + if (!tfilter) { + handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid tfilter: %s"), + err->message); + } else { + g_ptr_array_add(tfilters, tfilter); + } + } + + if (tfilters->len >= 1) + g_object_set(setting, key, tfilters, NULL); } /*****************************************************************************/ @@ -1999,1757 +1969,1610 @@ tfilter_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) * from the real setting name to the more-readable alias. */ static void -setting_alias_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +setting_alias_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) { - const char *str, *alias; - - str = g_value_get_string (value); - alias = nm_keyfile_plugin_get_alias_for_setting_name (str); - nm_keyfile_plugin_kf_set_string (info->keyfile, - nm_setting_get_name (setting), - key, - alias ?: str); + const char *str, *alias; + + str = g_value_get_string(value); + alias = nm_keyfile_plugin_get_alias_for_setting_name(str); + nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, alias ?: str); } static void -sriov_vfs_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +sriov_vfs_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - GPtrArray *vfs; - guint i; + GPtrArray *vfs; + guint i; - vfs = g_value_get_boxed (value); - if (!vfs) - return; + vfs = g_value_get_boxed(value); + if (!vfs) + return; - for (i = 0; i < vfs->len; i++) { - const NMSriovVF *vf = vfs->pdata[i]; - gs_free char *kf_value = NULL; - char kf_key[32]; + for (i = 0; i < vfs->len; i++) { + const NMSriovVF *vf = vfs->pdata[i]; + gs_free char * kf_value = NULL; + char kf_key[32]; - kf_value = nm_utils_sriov_vf_to_str (vf, TRUE, NULL); - if (!kf_value) - continue; + kf_value = nm_utils_sriov_vf_to_str(vf, TRUE, NULL); + if (!kf_value) + continue; - nm_sprintf_buf (kf_key, "vf.%u", nm_sriov_vf_get_index (vf)); + nm_sprintf_buf(kf_key, "vf.%u", nm_sriov_vf_get_index(vf)); - nm_keyfile_plugin_kf_set_string (info->keyfile, - nm_setting_get_name (setting), - kf_key, - kf_value); - } + nm_keyfile_plugin_kf_set_string(info->keyfile, + nm_setting_get_name(setting), + kf_key, + kf_value); + } } static void -write_array_of_uint (GKeyFile *file, - NMSetting *setting, - const char *key, - const GValue *value) +write_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) { - GArray *array; + GArray *array; - array = g_value_get_boxed (value); + array = g_value_get_boxed(value); - nm_assert (!array || g_array_get_element_size (array) == sizeof (guint)); + nm_assert(!array || g_array_get_element_size(array) == sizeof(guint)); - if (!array || !array->len) - return; + if (!array || !array->len) + return; - nm_keyfile_plugin_kf_set_integer_list_uint (file, - nm_setting_get_name (setting), - key, - (const guint *) array->data, - array->len); + nm_keyfile_plugin_kf_set_integer_list_uint(file, + nm_setting_get_name(setting), + key, + (const guint *) array->data, + array->len); } static void -dns_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +dns_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - char **list; - - list = g_value_get_boxed (value); - if (list && list[0]) { - nm_keyfile_plugin_kf_set_string_list (info->keyfile, nm_setting_get_name (setting), key, - (const char **) list, g_strv_length (list)); - } + char **list; + + list = g_value_get_boxed(value); + if (list && list[0]) { + nm_keyfile_plugin_kf_set_string_list(info->keyfile, + nm_setting_get_name(setting), + key, + (const char **) list, + g_strv_length(list)); + } } static void -ip6_addr_gen_mode_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +ip6_addr_gen_mode_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) { - NMSettingIP6ConfigAddrGenMode addr_gen_mode; - gs_free char *str = NULL; - - addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int (value); - str = nm_utils_enum_to_str (nm_setting_ip6_config_addr_gen_mode_get_type (), - addr_gen_mode); - nm_keyfile_plugin_kf_set_string (info->keyfile, - nm_setting_get_name (setting), - key, - str); + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + gs_free char * str = NULL; + + addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int(value); + str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode); + nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str); } static void -write_ip_values (GKeyFile *file, - const char *setting_name, - GPtrArray *array, - const char *gateway, - gboolean is_route) +write_ip_values(GKeyFile * file, + const char *setting_name, + GPtrArray * array, + const char *gateway, + gboolean is_route) { - nm_auto_free_gstring GString *output = NULL; - int addr_family; - guint i; - const char *addr; - const char *gw; - guint32 plen; - char key_name[64]; - char *key_name_idx; - - if (!array->len) - return; - - addr_family = nm_streq (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) - ? AF_INET - : AF_INET6; - - strcpy (key_name, is_route ? "route" : "address"); - key_name_idx = key_name + strlen (key_name); - - output = g_string_sized_new (2*INET_ADDRSTRLEN + 10); - for (i = 0; i < array->len; i++) { - gint64 metric = -1; - - if (is_route) { - NMIPRoute *route = array->pdata[i]; - - addr = nm_ip_route_get_dest (route); - plen = nm_ip_route_get_prefix (route); - gw = nm_ip_route_get_next_hop (route); - metric = nm_ip_route_get_metric (route); - } else { - NMIPAddress *address = array->pdata[i]; - - addr = nm_ip_address_get_address (address); - plen = nm_ip_address_get_prefix (address); - gw = (i == 0) - ? gateway - : NULL; - } - - g_string_set_size (output, 0); - g_string_append_printf (output, "%s/%u", addr, plen); - if ( metric != -1 - || gw) { - /* Older versions of the plugin do not support the form - * "a.b.c.d/plen,,metric", so, we always have to write the - * gateway, even if there isn't one. - * The current version supports reading of the above form. - */ - if (!gw) { - if (addr_family == AF_INET) - gw = "0.0.0.0"; - else - gw = "::"; - } - - g_string_append_printf (output, ",%s", gw); - if ( is_route - && metric != -1) - g_string_append_printf (output, ",%lu", (unsigned long) metric); - } - - sprintf (key_name_idx, "%u", i + 1); - nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str); - - if (is_route) { - gs_free char *attributes = NULL; - - attributes = nm_utils_format_variant_attributes (_nm_ip_route_get_attributes (array->pdata[i]), - ',', '='); - if (attributes) { - g_strlcat (key_name, "_options", sizeof (key_name)); - nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes); - } - } - } + if (array->len > 0) { + nm_auto_str_buf NMStrBuf output = NM_STR_BUF_INIT(2 * INET_ADDRSTRLEN + 10, FALSE); + int addr_family; + guint i; + const char * addr; + const char * gw; + guint32 plen; + char key_name[64]; + char * key_name_idx; + + addr_family = + nm_streq(setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) ? AF_INET : AF_INET6; + + strcpy(key_name, is_route ? "route" : "address"); + key_name_idx = key_name + strlen(key_name); + + for (i = 0; i < array->len; i++) { + gint64 metric = -1; + + if (is_route) { + NMIPRoute *route = array->pdata[i]; + + addr = nm_ip_route_get_dest(route); + plen = nm_ip_route_get_prefix(route); + gw = nm_ip_route_get_next_hop(route); + metric = nm_ip_route_get_metric(route); + } else { + NMIPAddress *address = array->pdata[i]; + + addr = nm_ip_address_get_address(address); + plen = nm_ip_address_get_prefix(address); + gw = (i == 0) ? gateway : NULL; + } + + nm_str_buf_set_size(&output, 0, FALSE, FALSE); + nm_str_buf_append_printf(&output, "%s/%u", addr, plen); + if (metric != -1 || gw) { + /* Older versions of the plugin do not support the form + * "a.b.c.d/plen,,metric", so, we always have to write the + * gateway, even if there isn't one. + * The current version supports reading of the above form. + */ + if (!gw) { + if (addr_family == AF_INET) + gw = "0.0.0.0"; + else + gw = "::"; + } + + nm_str_buf_append_c(&output, ','); + nm_str_buf_append(&output, gw); + if (is_route && metric != -1) + nm_str_buf_append_printf(&output, ",%lu", (unsigned long) metric); + } + + sprintf(key_name_idx, "%u", i + 1); + nm_keyfile_plugin_kf_set_string(file, + setting_name, + key_name, + nm_str_buf_get_str(&output)); + + if (is_route) { + gs_free char *attributes = NULL; + + attributes = + nm_utils_format_variant_attributes(_nm_ip_route_get_attributes(array->pdata[i]), + ',', + '='); + if (attributes) { + g_strlcat(key_name, "_options", sizeof(key_name)); + nm_keyfile_plugin_kf_set_string(file, setting_name, key_name, attributes); + } + } + } + } } static void -addr_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +addr_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - GPtrArray *array; - const char *setting_name = nm_setting_get_name (setting); - const char *gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting)); + GPtrArray * array; + const char *setting_name = nm_setting_get_name(setting); + const char *gateway = nm_setting_ip_config_get_gateway(NM_SETTING_IP_CONFIG(setting)); - array = (GPtrArray *) g_value_get_boxed (value); - if (array && array->len) - write_ip_values (info->keyfile, setting_name, array, gateway, FALSE); + array = (GPtrArray *) g_value_get_boxed(value); + if (array && array->len) + write_ip_values(info->keyfile, setting_name, array, gateway, FALSE); } static void -route_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +route_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - GPtrArray *array; - const char *setting_name = nm_setting_get_name (setting); + GPtrArray * array; + const char *setting_name = nm_setting_get_name(setting); - array = (GPtrArray *) g_value_get_boxed (value); - if (array && array->len) - write_ip_values (info->keyfile, setting_name, array, NULL, TRUE); + array = (GPtrArray *) g_value_get_boxed(value); + if (array && array->len) + write_ip_values(info->keyfile, setting_name, array, NULL, TRUE); } static void -bridge_vlan_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +bridge_vlan_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) { - NMBridgeVlan *vlan; - GPtrArray *vlans; - GString *string; - guint i; - - vlans = (GPtrArray *) g_value_get_boxed (value); - if (!vlans || !vlans->len) - return; - - string = g_string_new (""); - for (i = 0; i < vlans->len; i++) { - gs_free char *vlan_str = NULL; - - vlan = vlans->pdata[i]; - vlan_str = nm_bridge_vlan_to_str (vlan, NULL); - if (!vlan_str) - continue; - if (string->len > 0) - g_string_append (string, ","); - nm_utils_escaped_tokens_escape_gstr_assert (vlan_str, ",", string); - } - - nm_keyfile_plugin_kf_set_string (info->keyfile, - nm_setting_get_name (setting), - "vlans", - string->str); - - g_string_free (string, TRUE); + GPtrArray *vlans; + + vlans = g_value_get_boxed(value); + if (vlans && vlans->len > 0) { + const guint string_initial_size = vlans->len * 10u; + nm_auto_str_buf NMStrBuf string = NM_STR_BUF_INIT(string_initial_size, FALSE); + guint i; + + for (i = 0; i < vlans->len; i++) { + gs_free char *vlan_str = NULL; + + vlan_str = nm_bridge_vlan_to_str(vlans->pdata[i], NULL); + if (i > 0) + nm_str_buf_append_c(&string, ','); + nm_utils_escaped_tokens_escape_strbuf_assert(vlan_str, ",", &string); + } + + nm_keyfile_plugin_kf_set_string(info->keyfile, + nm_setting_get_name(setting), + "vlans", + nm_str_buf_get_str(&string)); + } } - #define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options" static void -wired_s390_options_parser_full (KeyfileReaderInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +wired_s390_options_parser_full(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) { - NMSettingWired *s_wired = NM_SETTING_WIRED (setting); - gs_strfreev char **keys = NULL; - gsize n_keys; - gsize i; - - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, ETHERNET_S390_OPTIONS_GROUP_NAME, &n_keys, NULL); - for (i = 0; i < n_keys; i++) { - gs_free char *value = NULL; - gs_free char *key_to_free = NULL; - - value = nm_keyfile_plugin_kf_get_string (info->keyfile, - ETHERNET_S390_OPTIONS_GROUP_NAME, - keys[i], - NULL); - if (!value) - continue; - - nm_setting_wired_add_s390_option (s_wired, - nm_keyfile_key_decode (keys[i], - &key_to_free), - value); - } + NMSettingWired * s_wired = NM_SETTING_WIRED(setting); + gs_strfreev char **keys = NULL; + gsize n_keys; + gsize i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + &n_keys, + NULL); + for (i = 0; i < n_keys; i++) { + gs_free char *value = NULL; + gs_free char *key_to_free = NULL; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + keys[i], + NULL); + if (!value) + continue; + + nm_setting_wired_add_s390_option(s_wired, + nm_keyfile_key_decode(keys[i], &key_to_free), + value); + } } static void -wired_s390_options_writer_full (KeyfileWriterInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +wired_s390_options_writer_full(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) { - NMSettingWired *s_wired = NM_SETTING_WIRED (setting); - guint i, n; - - n = nm_setting_wired_get_num_s390_options (s_wired); - for (i = 0; i < n; i++) { - gs_free char *key_to_free = NULL; - const char *opt_key; - const char *opt_val; - - nm_setting_wired_get_s390_option (s_wired, i, &opt_key, &opt_val); - nm_keyfile_plugin_kf_set_string (info->keyfile, - ETHERNET_S390_OPTIONS_GROUP_NAME, - nm_keyfile_key_encode (opt_key, &key_to_free), - opt_val); - } + NMSettingWired *s_wired = NM_SETTING_WIRED(setting); + guint i, n; + + n = nm_setting_wired_get_num_s390_options(s_wired); + for (i = 0; i < n; i++) { + gs_free char *key_to_free = NULL; + const char * opt_key; + const char * opt_val; + + nm_setting_wired_get_s390_option(s_wired, i, &opt_key, &opt_val); + nm_keyfile_plugin_kf_set_string(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + nm_keyfile_key_encode(opt_key, &key_to_free), + opt_val); + } } static void -ip_routing_rule_writer_full (KeyfileWriterInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting) +ip_routing_rule_writer_full(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) { - const char *setting_name = nm_setting_get_name (setting); - NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); - guint i, j, n; - char key_name_full[100] = "routing-rule"; - char *key_name_num = &key_name_full[NM_STRLEN ("routing-rule")]; - - n = nm_setting_ip_config_get_num_routing_rules (s_ip); - j = 0; - for (i = 0; i < n; i++) { - NMIPRoutingRule *rule = nm_setting_ip_config_get_routing_rule (s_ip, i); - gs_free char *str = NULL; - - str = nm_ip_routing_rule_to_string (rule, - NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE, - NULL, - NULL); - if (!str) - continue; - - sprintf (key_name_num, "%u", ++j); - nm_keyfile_plugin_kf_set_string (info->keyfile, - setting_name, - key_name_full, - str); - } + const char * setting_name = nm_setting_get_name(setting); + NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG(setting); + guint i, j, n; + char key_name_full[100] = "routing-rule"; + char * key_name_num = &key_name_full[NM_STRLEN("routing-rule")]; + + n = nm_setting_ip_config_get_num_routing_rules(s_ip); + j = 0; + for (i = 0; i < n; i++) { + NMIPRoutingRule *rule = nm_setting_ip_config_get_routing_rule(s_ip, i); + gs_free char * str = NULL; + + str = + nm_ip_routing_rule_to_string(rule, NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE, NULL, NULL); + if (!str) + continue; + + sprintf(key_name_num, "%u", ++j); + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key_name_full, str); + } } static void -qdisc_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +qdisc_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - gsize i; - GPtrArray *array; - - array = (GPtrArray *) g_value_get_boxed (value); - if (!array || !array->len) - return; - - for (i = 0; i < array->len; i++) { - NMTCQdisc *qdisc = array->pdata[i]; - GString *key_name = g_string_sized_new (16); - GString *value_str = g_string_sized_new (60); - - g_string_append (key_name, "qdisc."); - _nm_utils_string_append_tc_parent (key_name, NULL, - nm_tc_qdisc_get_parent (qdisc)); - _nm_utils_string_append_tc_qdisc_rest (value_str, qdisc); - - nm_keyfile_plugin_kf_set_string (info->keyfile, - NM_SETTING_TC_CONFIG_SETTING_NAME, - key_name->str, - value_str->str); - - g_string_free (key_name, TRUE); - g_string_free (value_str, TRUE); - } + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; + GPtrArray * array; + guint i; + + array = g_value_get_boxed(value); + if (!array || !array->len) + return; + + for (i = 0; i < array->len; i++) { + NMTCQdisc *qdisc = array->pdata[i]; + + nm_gstring_prepare(&key_name); + nm_gstring_prepare(&value_str); + + g_string_append(key_name, "qdisc."); + _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_qdisc_get_parent(qdisc)); + _nm_utils_string_append_tc_qdisc_rest(value_str, qdisc); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + NM_SETTING_TC_CONFIG_SETTING_NAME, + key_name->str, + value_str->str); + } } static void -tfilter_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +tfilter_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - gsize i; - GPtrArray *array; - - array = (GPtrArray *) g_value_get_boxed (value); - if (!array || !array->len) - return; - - for (i = 0; i < array->len; i++) { - NMTCTfilter *tfilter = array->pdata[i]; - GString *key_name = g_string_sized_new (16); - GString *value_str = g_string_sized_new (60); - - g_string_append (key_name, "tfilter."); - _nm_utils_string_append_tc_parent (key_name, NULL, - nm_tc_tfilter_get_parent (tfilter)); - _nm_utils_string_append_tc_tfilter_rest (value_str, tfilter, NULL); - - nm_keyfile_plugin_kf_set_string (info->keyfile, - NM_SETTING_TC_CONFIG_SETTING_NAME, - key_name->str, - value_str->str); - - g_string_free (key_name, TRUE); - g_string_free (value_str, TRUE); - } + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; + GPtrArray * array; + guint i; + + array = g_value_get_boxed(value); + if (!array || !array->len) + return; + + for (i = 0; i < array->len; i++) { + NMTCTfilter *tfilter = array->pdata[i]; + + nm_gstring_prepare(&key_name); + nm_gstring_prepare(&value_str); + + g_string_append(key_name, "tfilter."); + _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_tfilter_get_parent(tfilter)); + _nm_utils_string_append_tc_tfilter_rest(value_str, tfilter, NULL); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + NM_SETTING_TC_CONFIG_SETTING_NAME, + key_name->str, + value_str->str); + } } static void -write_hash_of_string (GKeyFile *file, - NMSetting *setting, - const char *key, - const GValue *value) +write_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) { - GHashTable *hash; - const char *group_name = nm_setting_get_name (setting); - gboolean vpn_secrets = FALSE; - gs_free const char **keys = NULL; - guint i, l; - - nm_assert ( (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_DATA)) - || (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_SECRETS)) - || (NM_IS_SETTING_BOND (setting) && nm_streq (key, NM_SETTING_BOND_OPTIONS)) - || (NM_IS_SETTING_USER (setting) && nm_streq (key, NM_SETTING_USER_DATA))); - - /* Write VPN secrets out to a different group to keep them separate */ - if ( NM_IS_SETTING_VPN (setting) - && nm_streq (key, NM_SETTING_VPN_SECRETS)) { - group_name = NM_KEYFILE_GROUP_VPN_SECRETS; - vpn_secrets = TRUE; - } - - hash = g_value_get_boxed (value); - - keys = nm_utils_strdict_get_keys (hash, TRUE, &l); - for (i = 0; i < l; i++) { - gs_free char *to_free = NULL; - const char *property, *data; - - property = keys[i]; - - /* Handle VPN secrets specially; they are nested in the property's hash; - * we don't want to write them if the secret is not saved, not required, - * or owned by a user's secret agent. - */ - if (vpn_secrets) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - if (!nm_setting_get_secret_flags (setting, property, &secret_flags, NULL)) - nm_assert_not_reached (); - if (!_secret_flags_persist_secret (secret_flags)) - continue; - } - - data = g_hash_table_lookup (hash, property); - nm_keyfile_plugin_kf_set_string (file, group_name, - nm_keyfile_key_encode (property, &to_free), - data); - } + GHashTable * hash; + const char * group_name = nm_setting_get_name(setting); + gboolean vpn_secrets = FALSE; + gs_free const char **keys = NULL; + guint i, l; + + nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_DATA)) + || (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) + || (NM_IS_SETTING_BOND(setting) && nm_streq(key, NM_SETTING_BOND_OPTIONS)) + || (NM_IS_SETTING_USER(setting) && nm_streq(key, NM_SETTING_USER_DATA))); + + /* Write VPN secrets out to a different group to keep them separate */ + if (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) { + group_name = NM_KEYFILE_GROUP_VPN_SECRETS; + vpn_secrets = TRUE; + } + + hash = g_value_get_boxed(value); + + keys = nm_utils_strdict_get_keys(hash, TRUE, &l); + for (i = 0; i < l; i++) { + gs_free char *to_free = NULL; + const char * property, *data; + + property = keys[i]; + + /* Handle VPN secrets specially; they are nested in the property's hash; + * we don't want to write them if the secret is not saved, not required, + * or owned by a user's secret agent. + */ + if (vpn_secrets) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags(setting, property, &secret_flags, NULL)) + nm_assert_not_reached(); + if (!_secret_flags_persist_secret(secret_flags)) + continue; + } + + data = g_hash_table_lookup(hash, property); + nm_keyfile_plugin_kf_set_string(file, + group_name, + nm_keyfile_key_encode(property, &to_free), + data); + } } static void -ssid_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +ssid_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - GBytes *bytes; - const guint8 *ssid_data; - gsize ssid_len; - const char *setting_name = nm_setting_get_name (setting); - gboolean new_format = TRUE; - gsize semicolons = 0; - gsize i; - - g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES)); - - bytes = g_value_get_boxed (value); - if (!bytes) - return; - ssid_data = g_bytes_get_data (bytes, &ssid_len); - if (!ssid_data || !ssid_len) { - nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, ""); - return; - } - - /* Check whether each byte is printable. If not, we have to use an - * integer list, otherwise we can just use a string. - */ - for (i = 0; i < ssid_len; i++) { - const char c = ssid_data[i]; - - if (!g_ascii_isprint (c)) { - new_format = FALSE; - break; - } - if (c == ';') - semicolons++; - } - - if (new_format) { - gs_free char *ssid = NULL; - - if (semicolons == 0) - ssid = g_strndup ((char *) ssid_data, ssid_len); - else { - /* Escape semicolons with backslashes to make strings - * containing ';', such as '16;17;' unambiguous */ - gsize j = 0; - - ssid = g_malloc (ssid_len + semicolons + 1); - for (i = 0; i < ssid_len; i++) { - if (ssid_data[i] == ';') - ssid[j++] = '\\'; - ssid[j++] = ssid_data[i]; - } - ssid[j] = '\0'; - } - nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, ssid); - } else - nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, ssid_data, ssid_len); + GBytes * bytes; + const guint8 *ssid_data; + gsize ssid_len; + const char * setting_name = nm_setting_get_name(setting); + gboolean new_format = TRUE; + gsize semicolons = 0; + gsize i; + + g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); + + bytes = g_value_get_boxed(value); + if (!bytes) + return; + ssid_data = g_bytes_get_data(bytes, &ssid_len); + if (!ssid_data || !ssid_len) { + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ""); + return; + } + + /* Check whether each byte is printable. If not, we have to use an + * integer list, otherwise we can just use a string. + */ + for (i = 0; i < ssid_len; i++) { + const char c = ssid_data[i]; + + if (!g_ascii_isprint(c)) { + new_format = FALSE; + break; + } + if (c == ';') + semicolons++; + } + + if (new_format) { + gs_free char *ssid = NULL; + + if (semicolons == 0) + ssid = g_strndup((char *) ssid_data, ssid_len); + else { + /* Escape semicolons with backslashes to make strings + * containing ';', such as '16;17;' unambiguous */ + gsize j = 0; + + ssid = g_malloc(ssid_len + semicolons + 1); + for (i = 0; i < ssid_len; i++) { + if (ssid_data[i] == ';') + ssid[j++] = '\\'; + ssid[j++] = ssid_data[i]; + } + ssid[j] = '\0'; + } + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ssid); + } else + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, + setting_name, + key, + ssid_data, + ssid_len); } static void -password_raw_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +password_raw_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) { - const char *setting_name = nm_setting_get_name (setting); - GBytes *array; - gsize len; - const guint8 *data; - - g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES)); - - array = (GBytes *) g_value_get_boxed (value); - if (!array) - return; - data = g_bytes_get_data (array, &len); - if (!data) - len = 0; - nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, data, len); + const char * setting_name = nm_setting_get_name(setting); + GBytes * array; + gsize len; + const guint8 *data; + + g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); + + array = (GBytes *) g_value_get_boxed(value); + if (!array) + return; + data = g_bytes_get_data(array, &len); + if (!data) + len = 0; + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, setting_name, key, data, len); } /*****************************************************************************/ static void -cert_writer_default (NMConnection *connection, - GKeyFile *file, - NMSetting8021x *setting, - const char *setting_name, - const NMSetting8021xSchemeVtable *vtable) +cert_writer_default(NMConnection * connection, + GKeyFile * file, + NMSetting8021x * setting, + const char * setting_name, + const NMSetting8021xSchemeVtable *vtable) { - NMSetting8021xCKScheme scheme; - - scheme = vtable->scheme_func (setting); - if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - gs_free char *path_free = NULL; - gs_free char *base_dir = NULL; - gs_free char *tmp = NULL; - const char *path; - - path = vtable->path_func (setting); - g_assert (path); - - /* If the path is relative, make it an absolute path. - * Relative paths make a keyfile not easily usable in another - * context. */ - if (path[0] && path[0] != '/') { - base_dir = g_get_current_dir (); - path_free = g_strconcat (base_dir, "/", path, NULL); - path = path_free; - } else - base_dir = g_path_get_dirname (path); - - /* path cannot start with "file://" or "data:;base64,", because it is an absolute path. - * Still, make sure that a prefix-less path will be recognized. This can happen - * for example if the path is longer then 500 chars. */ - tmp = nm_keyfile_detect_unqualified_path_scheme (base_dir, path, -1, FALSE, NULL); - if (tmp) - nm_clear_g_free (&tmp); - else { - tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); - path = tmp; - } - - /* Path contains at least a '/', hence it cannot be recognized as the old - * binary format consisting of a list of integers. */ - - nm_keyfile_plugin_kf_set_string (file, setting_name, vtable->setting_key, path); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - GBytes *blob; - const guint8 *blob_data; - gsize blob_len; - gs_free char *blob_base64 = NULL; - gs_free char *val = NULL; - - blob = vtable->blob_func (setting); - g_assert (blob); - blob_data = g_bytes_get_data (blob, &blob_len); - - blob_base64 = g_base64_encode (blob_data, blob_len); - val = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL); - - nm_keyfile_plugin_kf_set_string (file, setting_name, vtable->setting_key, val); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - nm_keyfile_plugin_kf_set_string (file, setting_name, vtable->setting_key, - vtable->uri_func (setting)); - } else { - /* scheme_func() returns UNKNOWN in all other cases. The only valid case - * where a scheme is allowed to be UNKNOWN, is unsetting the value. In this - * case, we don't expect the writer to be called, because the default value - * will not be serialized. - * The only other reason for the scheme to be UNKNOWN is an invalid cert. - * But our connection verifies, so that cannot happen either. */ - g_return_if_reached (); - } + NMSetting8021xCKScheme scheme; + + scheme = vtable->scheme_func(setting); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + gs_free char *path_free = NULL; + gs_free char *base_dir = NULL; + gs_free char *tmp = NULL; + const char * path; + + path = vtable->path_func(setting); + g_assert(path); + + /* If the path is relative, make it an absolute path. + * Relative paths make a keyfile not easily usable in another + * context. */ + if (path[0] && path[0] != '/') { + base_dir = g_get_current_dir(); + path_free = g_strconcat(base_dir, "/", path, NULL); + path = path_free; + } else + base_dir = g_path_get_dirname(path); + + /* path cannot start with "file://" or "data:;base64,", because it is an absolute path. + * Still, make sure that a prefix-less path will be recognized. This can happen + * for example if the path is longer then 500 chars. */ + tmp = nm_keyfile_detect_unqualified_path_scheme(base_dir, path, -1, FALSE, NULL); + if (tmp) + nm_clear_g_free(&tmp); + else { + tmp = g_strconcat(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); + path = tmp; + } + + /* Path contains at least a '/', hence it cannot be recognized as the old + * binary format consisting of a list of integers. */ + + nm_keyfile_plugin_kf_set_string(file, setting_name, vtable->setting_key, path); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + GBytes * blob; + const guint8 *blob_data; + gsize blob_len; + gs_free char *blob_base64 = NULL; + gs_free char *val = NULL; + + blob = vtable->blob_func(setting); + g_assert(blob); + blob_data = g_bytes_get_data(blob, &blob_len); + + blob_base64 = g_base64_encode(blob_data, blob_len); + val = g_strconcat(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL); + + nm_keyfile_plugin_kf_set_string(file, setting_name, vtable->setting_key, val); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + nm_keyfile_plugin_kf_set_string(file, + setting_name, + vtable->setting_key, + vtable->uri_func(setting)); + } else { + /* scheme_func() returns UNKNOWN in all other cases. The only valid case + * where a scheme is allowed to be UNKNOWN, is unsetting the value. In this + * case, we don't expect the writer to be called, because the default value + * will not be serialized. + * The only other reason for the scheme to be UNKNOWN is an invalid cert. + * But our connection verifies, so that cannot happen either. */ + g_return_if_reached(); + } } static void -cert_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +cert_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - const NMSetting8021xSchemeVtable *vtable = NULL; - const char *setting_name; - guint i; - - for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) { - if (nm_streq0 (nm_setting_8021x_scheme_vtable[i].setting_key, key)) { - vtable = &nm_setting_8021x_scheme_vtable[i]; - break; - } - } - if (!vtable) - g_return_if_reached (); - - setting_name = nm_setting_get_name (NM_SETTING (setting)); - - if (info->write_handler) { - NMKeyfileHandlerData handler_data; - - _key_file_handler_data_init_write (&handler_data, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, - info, - setting_name, - vtable->setting_key, - setting, - key); - handler_data.write_cert = (NMKeyfileHandlerDataWriteCert) { - .vtable = vtable, - }; - - if (info->write_handler (info->connection, - info->keyfile, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, - &handler_data, - info->user_data)) - return; - if (info->error) - return; - } - - cert_writer_default (info->connection, - info->keyfile, - NM_SETTING_802_1X (setting), - setting_name, - vtable); + const NMSetting8021xSchemeVtable *vtable = NULL; + const char * setting_name; + guint i; + + for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) { + if (nm_streq0(nm_setting_8021x_scheme_vtable[i].setting_key, key)) { + vtable = &nm_setting_8021x_scheme_vtable[i]; + break; + } + } + if (!vtable) + g_return_if_reached(); + + setting_name = nm_setting_get_name(NM_SETTING(setting)); + + if (info->write_handler) { + NMKeyfileHandlerData handler_data; + + _key_file_handler_data_init_write(&handler_data, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, + info, + setting_name, + vtable->setting_key, + setting, + key); + handler_data.write_cert = (NMKeyfileHandlerDataWriteCert){ + .vtable = vtable, + }; + + if (info->write_handler(info->connection, + info->keyfile, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, + &handler_data, + info->user_data)) + return; + if (info->error) + return; + } + + cert_writer_default(info->connection, + info->keyfile, + NM_SETTING_802_1X(setting), + setting_name, + vtable); } /*****************************************************************************/ struct _ParseInfoProperty { - const char *property_name; - union { - void (*parser) (KeyfileReaderInfo *info, - NMSetting *setting, - const char *key); - void (*parser_full) (KeyfileReaderInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting); - }; - union { - void (*writer) (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value); - void (*writer_full) (KeyfileWriterInfo *info, - const NMMetaSettingInfo *setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty *pip, - NMSetting *setting); - }; - bool parser_skip; - bool parser_no_check_key:1; - bool writer_skip:1; - bool has_writer_full:1; - bool has_parser_full:1; - - /* usually, we skip to write values that have their - * default value. By setting this flag to TRUE, also - * default values are written. */ - bool writer_persist_default:1; + const char *property_name; + union { + void (*parser)(KeyfileReaderInfo *info, NMSetting *setting, const char *key); + void (*parser_full)(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting); + }; + union { + void (*writer)(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value); + void (*writer_full)(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting); + }; + bool parser_skip; + bool parser_no_check_key : 1; + bool writer_skip : 1; + bool has_writer_full : 1; + bool has_parser_full : 1; + + /* usually, we skip to write values that have their + * default value. By setting this flag to TRUE, also + * default values are written. */ + bool writer_persist_default : 1; }; #define PARSE_INFO_PROPERTY(_property_name, ...) \ - (&((const ParseInfoProperty) { \ - .property_name = _property_name, \ - __VA_ARGS__ \ - })) + (&((const ParseInfoProperty){.property_name = _property_name, __VA_ARGS__})) -#define PARSE_INFO_PROPERTIES(...) \ - .properties = ((const ParseInfoProperty*const[]) { \ - __VA_ARGS__ \ - NULL, \ - }) +#define PARSE_INFO_PROPERTIES(...) \ + .properties = ((const ParseInfoProperty *const[]){ \ + __VA_ARGS__ NULL, \ + }) typedef struct { - const ParseInfoProperty*const*properties; + const ParseInfoProperty *const *properties; } ParseInfoSetting; #define PARSE_INFO_SETTING(setting_type, ...) \ - [setting_type] = (&((const ParseInfoSetting) { \ - __VA_ARGS__ \ - })) + [setting_type] = (&((const ParseInfoSetting){__VA_ARGS__})) static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIRELESS, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_WIRELESS_BSSID, - .parser = mac_address_parser_ETHER, - ), - PARSE_INFO_PROPERTY (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, - .parser = mac_address_parser_ETHER_cloned, - ), - PARSE_INFO_PROPERTY (NM_SETTING_WIRELESS_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, - ), - PARSE_INFO_PROPERTY (NM_SETTING_WIRELESS_SSID, - .parser = ssid_parser, - .writer = ssid_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_802_1X, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_CA_CERT, - .parser = cert_parser, - .writer = cert_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_CLIENT_CERT, - .parser = cert_parser, - .writer = cert_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_PASSWORD_RAW, - .parser = password_raw_parser, - .writer = password_raw_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_PHASE2_CA_CERT, - .parser = cert_parser, - .writer = cert_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - .parser = cert_parser, - .writer = cert_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - .parser = cert_parser, - .writer = cert_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_802_1X_PRIVATE_KEY, - .parser = cert_parser, - .writer = cert_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIRED, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_WIRED_CLONED_MAC_ADDRESS, - .parser = mac_address_parser_ETHER_cloned, - ), - PARSE_INFO_PROPERTY (NM_SETTING_WIRED_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, - ), - PARSE_INFO_PROPERTY (NM_SETTING_WIRED_S390_OPTIONS, - .parser_no_check_key = TRUE, - .parser_full = wired_s390_options_parser_full, - .writer_full = wired_s390_options_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BLUETOOTH, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_BLUETOOTH_BDADDR, - .parser = mac_address_parser_ETHER, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BOND, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_BOND_OPTIONS, - .parser_no_check_key = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BRIDGE, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_BRIDGE_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, - ), - PARSE_INFO_PROPERTY (NM_SETTING_BRIDGE_VLANS, - .parser_no_check_key = TRUE, - .parser = bridge_vlan_parser, - .writer = bridge_vlan_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BRIDGE_PORT, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_BRIDGE_PORT_VLANS, - .parser_no_check_key = TRUE, - .parser = bridge_vlan_parser, - .writer = bridge_vlan_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_CONNECTION, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_CONNECTION_READ_ONLY, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_CONNECTION_TYPE, - .parser = setting_alias_parser, - .writer = setting_alias_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_INFINIBAND, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_INFINIBAND_MAC_ADDRESS, - .parser = mac_address_parser_INFINIBAND, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_IP4_CONFIG, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ADDRESSES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = addr_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_DNS, - .parser_no_check_key = TRUE, - .parser = ip_dns_parser, - .writer = dns_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_GATEWAY, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = route_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTING_RULES, - .parser_no_check_key = TRUE, - .parser_full = ip_routing_rule_parser_full, - .writer_full = ip_routing_rule_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_IP6_CONFIG, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - .parser_no_check_key = TRUE, - .parser = ip6_addr_gen_mode_parser, - .writer = ip6_addr_gen_mode_writer, - .writer_persist_default = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ADDRESSES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = addr_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_DNS, - .parser_no_check_key = TRUE, - .parser = ip_dns_parser, - .writer = dns_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_GATEWAY, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = route_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTING_RULES, - .parser_no_check_key = TRUE, - .parser_full = ip_routing_rule_parser_full, - .writer_full = ip_routing_rule_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_SERIAL, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_SERIAL_PARITY, - .parser = parity_parser, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_SRIOV, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_SRIOV_VFS, - .parser_no_check_key = TRUE, - .parser = sriov_vfs_parser, - .writer = sriov_vfs_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TC_CONFIG, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_TC_CONFIG_QDISCS, - .parser_no_check_key = TRUE, - .parser = qdisc_parser, - .writer = qdisc_writer, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TC_CONFIG_TFILTERS, - .parser_no_check_key = TRUE, - .parser = tfilter_parser, - .writer = tfilter_writer, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TEAM, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_CONFIG, - .parser = team_config_parser, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_LINK_WATCHERS, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_MCAST_REJOIN_COUNT, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_ACTIVE, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_FAST_RATE, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_MIN_PORTS, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_SYS_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_BALANCER, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_HASH, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TEAM_PORT, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_CONFIG, - .parser = team_config_parser, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LACP_KEY, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LACP_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LINK_WATCHERS, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_QUEUE_ID, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_STICKY, - .parser_skip = TRUE, - .writer_skip = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_USER, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_USER_DATA, - .parser_no_check_key = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_VLAN, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_VLAN_FLAGS, - .writer_persist_default = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_VPN, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_VPN_DATA, - .parser_no_check_key = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_VPN_PERSISTENT, - .parser_no_check_key = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_VPN_SECRETS, - .parser_no_check_key = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_VPN_SERVICE_TYPE, - .parser_no_check_key = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_VPN_TIMEOUT, - .parser_no_check_key = TRUE, - ), - PARSE_INFO_PROPERTY (NM_SETTING_VPN_USER_NAME, - .parser_no_check_key = TRUE, - ), - ), - ), - PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIMAX, - PARSE_INFO_PROPERTIES ( - PARSE_INFO_PROPERTY (NM_SETTING_WIMAX_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, - ), - ), - ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIRELESS, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_BSSID, .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + .parser = mac_address_parser_ETHER_cloned, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SSID, + .parser = ssid_parser, + .writer = ssid_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_802_1X, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CA_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CLIENT_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PASSWORD_RAW, + .parser = password_raw_parser, + .writer = password_raw_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CA_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PRIVATE_KEY, + .parser = cert_parser, + .writer = cert_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIRED, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + .parser = mac_address_parser_ETHER_cloned, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_MAC_ADDRESS, .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_S390_OPTIONS, + .parser_no_check_key = TRUE, + .parser_full = wired_s390_options_parser_full, + .writer_full = wired_s390_options_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BLUETOOTH, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BLUETOOTH_BDADDR, + .parser = mac_address_parser_ETHER, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BOND, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_BOND_OPTIONS, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BRIDGE, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_VLANS, + .parser_no_check_key = TRUE, + .parser = bridge_vlan_parser, + .writer = bridge_vlan_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BRIDGE_PORT, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_PORT_VLANS, + .parser_no_check_key = TRUE, + .parser = bridge_vlan_parser, + .writer = bridge_vlan_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_CONNECTION, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_READ_ONLY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_TYPE, + .parser = setting_alias_parser, + .writer = setting_alias_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_INFINIBAND, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_INFINIBAND_MAC_ADDRESS, + .parser = mac_address_parser_INFINIBAND, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP4_CONFIG, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = addr_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, + .parser_no_check_key = TRUE, + .parser = ip_dns_parser, + .writer = dns_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = route_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, + .parser_no_check_key = TRUE, + .parser_full = ip_routing_rule_parser_full, + .writer_full = ip_routing_rule_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP6_CONFIG, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, + .parser_no_check_key = TRUE, + .parser = ip6_addr_gen_mode_parser, + .writer = ip6_addr_gen_mode_writer, + .writer_persist_default = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = addr_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, + .parser_no_check_key = TRUE, + .parser = ip_dns_parser, + .writer = dns_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = route_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, + .parser_no_check_key = TRUE, + .parser_full = ip_routing_rule_parser_full, + .writer_full = ip_routing_rule_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_SERIAL, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SERIAL_PARITY, + .parser = parity_parser, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_SRIOV, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SRIOV_VFS, + .parser_no_check_key = TRUE, + .parser = sriov_vfs_parser, + .writer = sriov_vfs_writer, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TC_CONFIG, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_QDISCS, + .parser_no_check_key = TRUE, + .parser = qdisc_parser, + .writer = qdisc_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_TFILTERS, + .parser_no_check_key = TRUE, + .parser = tfilter_parser, + .writer = tfilter_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_TEAM, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, .parser = team_config_parser, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_LINK_WATCHERS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_COUNT, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER, .parser_skip = TRUE, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_ACTIVE, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_FAST_RATE, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_MIN_PORTS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_SYS_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_HASH, + .parser_skip = TRUE, + .writer_skip = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TEAM_PORT, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, + .parser = team_config_parser, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_KEY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LINK_WATCHERS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_QUEUE_ID, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_STICKY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_USER, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_USER_DATA, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_VLAN, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_VLAN_FLAGS, .writer_persist_default = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_VPN, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_VPN_DATA, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_PERSISTENT, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_SECRETS, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_SERVICE_TYPE, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_TIMEOUT, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_USER_NAME, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIMAX, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_WIMAX_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), ), ), }; static void -_parse_info_find (NMSetting *setting, - const char *property_name, - const NMMetaSettingInfo **out_setting_info, - const ParseInfoSetting **out_parse_info_setting, - const ParseInfoProperty **out_parse_info_property) +_parse_info_find(NMSetting * setting, + const char * property_name, + const NMMetaSettingInfo **out_setting_info, + const ParseInfoSetting ** out_parse_info_setting, + const ParseInfoProperty **out_parse_info_property) { - const NMMetaSettingInfo *setting_info; - const ParseInfoSetting *pis; - const ParseInfoProperty *pip; + const NMMetaSettingInfo *setting_info; + const ParseInfoSetting * pis; + const ParseInfoProperty *pip; #if NM_MORE_ASSERTS > 10 - { - guint i, j; - static int asserted = FALSE; - - if (!asserted) { - for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) { - pis = parse_infos[i]; - - if (!pis) - continue; - if (!pis->properties) - continue; - - g_assert (pis->properties[0]); - for (j = 0; pis->properties[j]; j++) { - const ParseInfoProperty *pip0; - const ParseInfoProperty *pipj = pis->properties[j]; - - g_assert (pipj->property_name); - if ( j > 0 - && (pip0 = pis->properties[j - 1]) - && strcmp (pip0->property_name, pipj->property_name) >= 0) { - g_error ("Wrong order at index #%d.%d: \"%s.%s\" before \"%s.%s\"", - i, j - 1, - nm_meta_setting_infos[i].setting_name, pip0->property_name, - nm_meta_setting_infos[i].setting_name, pipj->property_name); - } - } - } - asserted = TRUE; - } - } + { + guint i, j; + static int asserted = FALSE; + + if (!asserted) { + for (i = 0; i < G_N_ELEMENTS(parse_infos); i++) { + pis = parse_infos[i]; + + if (!pis) + continue; + if (!pis->properties) + continue; + + g_assert(pis->properties[0]); + for (j = 0; pis->properties[j]; j++) { + const ParseInfoProperty *pip0; + const ParseInfoProperty *pipj = pis->properties[j]; + + g_assert(pipj->property_name); + if (j > 0 && (pip0 = pis->properties[j - 1]) + && strcmp(pip0->property_name, pipj->property_name) >= 0) { + g_error("Wrong order at index #%d.%d: \"%s.%s\" before \"%s.%s\"", + i, + j - 1, + nm_meta_setting_infos[i].setting_name, + pip0->property_name, + nm_meta_setting_infos[i].setting_name, + pipj->property_name); + } + } + } + asserted = TRUE; + } + } #endif - if ( !NM_IS_SETTING (setting) - || !(setting_info = NM_SETTING_GET_CLASS (setting)->setting_info)) { - /* handle invalid setting objects gracefully. */ - NM_SET_OUT (out_setting_info, NULL); - NM_SET_OUT (out_parse_info_setting, NULL); - NM_SET_OUT (out_parse_info_property, NULL); - return; - } - - nm_assert (setting_info->setting_name); - nm_assert (_NM_INT_NOT_NEGATIVE (setting_info->meta_type)); - nm_assert (setting_info->meta_type < G_N_ELEMENTS (parse_infos)); - - pis = parse_infos[setting_info->meta_type]; - - pip = NULL; - if ( pis - && property_name) { - gssize idx; - - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (ParseInfoProperty, property_name) == 0); - - idx = nm_utils_ptrarray_find_binary_search ((gconstpointer *) pis->properties, - NM_PTRARRAY_LEN (pis->properties), - &property_name, - nm_strcmp_p_with_data, - NULL, - NULL, - NULL); - if (idx >= 0) - pip = pis->properties[idx]; - } - - NM_SET_OUT (out_setting_info, setting_info); - NM_SET_OUT (out_parse_info_setting, pis); - NM_SET_OUT (out_parse_info_property, pip); + if (!NM_IS_SETTING(setting) || !(setting_info = NM_SETTING_GET_CLASS(setting)->setting_info)) { + /* handle invalid setting objects gracefully. */ + NM_SET_OUT(out_setting_info, NULL); + NM_SET_OUT(out_parse_info_setting, NULL); + NM_SET_OUT(out_parse_info_property, NULL); + return; + } + + nm_assert(setting_info->setting_name); + nm_assert(_NM_INT_NOT_NEGATIVE(setting_info->meta_type)); + nm_assert(setting_info->meta_type < G_N_ELEMENTS(parse_infos)); + + pis = parse_infos[setting_info->meta_type]; + + pip = NULL; + if (pis && property_name) { + gssize idx; + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(ParseInfoProperty, property_name) == 0); + + idx = nm_utils_ptrarray_find_binary_search((gconstpointer *) pis->properties, + NM_PTRARRAY_LEN(pis->properties), + &property_name, + nm_strcmp_p_with_data, + NULL, + NULL, + NULL); + if (idx >= 0) + pip = pis->properties[idx]; + } + + NM_SET_OUT(out_setting_info, setting_info); + NM_SET_OUT(out_parse_info_setting, pis); + NM_SET_OUT(out_parse_info_property, pip); } /*****************************************************************************/ static void -read_one_setting_value (KeyfileReaderInfo *info, - NMSetting *setting, - const NMSettInfoProperty *property_info) +read_one_setting_value(KeyfileReaderInfo * info, + NMSetting * setting, + const NMSettInfoProperty *property_info) { - GKeyFile *keyfile = info->keyfile; - gs_free_error GError *err = NULL; - const NMMetaSettingInfo *setting_info; - const ParseInfoProperty *pip; - gs_free char *tmp_str = NULL; - const char *key; - GType type; - guint64 u64; - gint64 i64; - - nm_assert (!info->error); - nm_assert ( !property_info->param_spec - || nm_streq (property_info->param_spec->name, property_info->name)); - - key = property_info->name; - - _parse_info_find (setting, key, &setting_info, NULL, &pip); - - nm_assert (setting_info); - - if (!pip) { - if (nm_streq (key, NM_SETTING_NAME)) - return; - if (!property_info->param_spec) - return; - if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE) - return; - } else { - if (pip->parser_skip) - return; - if (pip->has_parser_full) { - pip->parser_full (info, setting_info, property_info, pip, setting); - return; - } - } - - nm_assert (property_info->param_spec); - nm_assert ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE); - - /* 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 ( (!pip || !pip->parser_no_check_key) - && !nm_keyfile_plugin_kf_has_key (keyfile, setting_info->setting_name, key, &err)) { - /* Key doesn't exist or an error occurred, thus nothing to do. */ - if (err) { - if (!handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("error loading setting value: %s"), - err->message)) - return; - } - return; - } - - if ( pip - && pip->parser) { - pip->parser (info, setting, key); - return; - } - - type = G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec); - - if (type == G_TYPE_STRING) { - gs_free char *str_val = NULL; - - str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_info->setting_name, key, &err); - if (!err) - nm_g_object_set_property_string_take (G_OBJECT (setting), key, g_steal_pointer (&str_val), &err); - } else if (type == G_TYPE_UINT) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); - if ( u64 == G_MAXUINT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_uint (G_OBJECT (setting), key, u64, &err); - } - } else if (type == G_TYPE_INT) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); - if ( i64 == G_MININT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_int (G_OBJECT (setting), key, i64, &err); - } - } else if (type == G_TYPE_BOOLEAN) { - gboolean bool_val; - - bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, setting_info->setting_name, key, &err); - if (!err) - nm_g_object_set_property_boolean (G_OBJECT (setting), key, bool_val, &err); - } else if (type == G_TYPE_CHAR) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - /* As documented by glib, G_TYPE_CHAR is really a (signed!) gint8. */ - i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT8, G_MAXINT8, G_MININT64); - if ( i64 == G_MININT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_char (G_OBJECT (setting), key, i64, &err); - } - } else if (type == G_TYPE_UINT64) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT64, G_MAXUINT64); - if ( u64 == G_MAXUINT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_uint64 (G_OBJECT (setting), key, u64, &err); - } - } else if (type == G_TYPE_INT64) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT64, G_MAXINT64, G_MAXINT64); - if ( i64 == G_MAXINT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_int64 (G_OBJECT (setting), key, i64, &err); - } - } else if (type == G_TYPE_BYTES) { - nm_auto_unref_bytearray GByteArray *array = NULL; - gs_unref_bytes GBytes *bytes= NULL; - gs_free guint *tmp = NULL; - gsize length; - int i; - gboolean already_warned = FALSE; - - tmp = nm_keyfile_plugin_kf_get_integer_list_uint (keyfile, setting_info->setting_name, key, &length, NULL); - - array = g_byte_array_sized_new (length); - for (i = 0; i < length; i++) { - const guint val = tmp[i]; - unsigned char v = (unsigned char) (val & 0xFF); - - if (val > 255u) { - if ( !already_warned - && !handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid byte element '%u' (not between 0 and 255 inclusive)"), - val)) - return; - already_warned = TRUE; - } else - g_byte_array_append (array, (const unsigned char *) &v, sizeof (v)); - } - - bytes = g_byte_array_free_to_bytes (g_steal_pointer (&array)); - g_object_set (setting, key, bytes, NULL); - } else if (type == G_TYPE_STRV) { - gs_strfreev char **sa = NULL; - gsize length; - - sa = nm_keyfile_plugin_kf_get_string_list (keyfile, setting_info->setting_name, key, &length, NULL); - g_object_set (setting, key, sa, NULL); - } else if (type == G_TYPE_HASH_TABLE) { - read_hash_of_string (keyfile, setting, key); - } else if (type == G_TYPE_ARRAY) { - read_array_of_uint (keyfile, setting, key); - } else if (G_TYPE_IS_FLAGS (type)) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64 (tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); - if ( u64 == G_MAXUINT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_flags (G_OBJECT (setting), key, type, u64, &err); - } - } else if (G_TYPE_IS_ENUM (type)) { - tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64 (tmp_str, 0, G_MININT, G_MAXINT, G_MAXINT64); - if ( i64 == G_MAXINT64 - && errno != 0) { - g_set_error_literal (&err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_enum (G_OBJECT (setting), key, type, i64, &err); - } - } else - g_return_if_reached (); - - if (err) { - if (nm_keyfile_error_is_not_found (err)) { - /* ignore such errors. The key is not present. */ - } else { - handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting: %s"), - err->message); - } - } + GKeyFile * keyfile = info->keyfile; + gs_free_error GError * err = NULL; + const NMMetaSettingInfo *setting_info; + const ParseInfoProperty *pip; + gs_free char * tmp_str = NULL; + const char * key; + GType type; + guint64 u64; + gint64 i64; + + nm_assert(!info->error); + nm_assert(!property_info->param_spec + || nm_streq(property_info->param_spec->name, property_info->name)); + + key = property_info->name; + + _parse_info_find(setting, key, &setting_info, NULL, &pip); + + nm_assert(setting_info); + + if (!pip) { + if (nm_streq(key, NM_SETTING_NAME)) + return; + if (!property_info->param_spec) + return; + if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) + != G_PARAM_WRITABLE) + return; + } else { + if (pip->parser_skip) + return; + if (pip->has_parser_full) { + pip->parser_full(info, setting_info, property_info, pip, setting); + return; + } + } + + nm_assert(property_info->param_spec); + nm_assert((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) + == G_PARAM_WRITABLE); + + /* 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 ((!pip || !pip->parser_no_check_key) + && !nm_keyfile_plugin_kf_has_key(keyfile, setting_info->setting_name, key, &err)) { + /* Key doesn't exist or an error occurred, thus nothing to do. */ + if (err) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("error loading setting value: %s"), + err->message)) + return; + } + return; + } + + if (pip && pip->parser) { + pip->parser(info, setting, key); + return; + } + + type = G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec); + + if (type == G_TYPE_STRING) { + gs_free char *str_val = NULL; + + str_val = nm_keyfile_plugin_kf_get_string(keyfile, setting_info->setting_name, key, &err); + if (!err) + nm_g_object_set_property_string_take(G_OBJECT(setting), + key, + g_steal_pointer(&str_val), + &err); + } else if (type == G_TYPE_UINT) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_uint(G_OBJECT(setting), key, u64, &err); + } + } else if (type == G_TYPE_INT) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); + if (i64 == G_MININT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_int(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_BOOLEAN) { + gboolean bool_val; + + bool_val = nm_keyfile_plugin_kf_get_boolean(keyfile, setting_info->setting_name, key, &err); + if (!err) + nm_g_object_set_property_boolean(G_OBJECT(setting), key, bool_val, &err); + } else if (type == G_TYPE_CHAR) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + /* As documented by glib, G_TYPE_CHAR is really a (signed!) gint8. */ + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT8, G_MAXINT8, G_MININT64); + if (i64 == G_MININT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_char(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_UINT64) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT64, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_uint64(G_OBJECT(setting), key, u64, &err); + } + } else if (type == G_TYPE_INT64) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT64, G_MAXINT64, G_MAXINT64); + if (i64 == G_MAXINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_int64(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_BYTES) { + nm_auto_unref_bytearray GByteArray *array = NULL; + gs_unref_bytes GBytes *bytes = NULL; + gs_free guint *tmp = NULL; + gsize length; + int i; + gboolean already_warned = FALSE; + + tmp = nm_keyfile_plugin_kf_get_integer_list_uint(keyfile, + setting_info->setting_name, + key, + &length, + NULL); + + array = g_byte_array_sized_new(length); + for (i = 0; i < length; i++) { + const guint val = tmp[i]; + unsigned char v = (unsigned char) (val & 0xFF); + + if (val > 255u) { + if (!already_warned + && !handle_warn( + info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid byte element '%u' (not between 0 and 255 inclusive)"), + val)) + return; + already_warned = TRUE; + } else + g_byte_array_append(array, (const unsigned char *) &v, sizeof(v)); + } + + bytes = g_byte_array_free_to_bytes(g_steal_pointer(&array)); + g_object_set(setting, key, bytes, NULL); + } else if (type == G_TYPE_STRV) { + gs_strfreev char **sa = NULL; + gsize length; + + sa = nm_keyfile_plugin_kf_get_string_list(keyfile, + setting_info->setting_name, + key, + &length, + NULL); + g_object_set(setting, key, sa, NULL); + } else if (type == G_TYPE_HASH_TABLE) { + read_hash_of_string(keyfile, setting, key); + } else if (type == G_TYPE_ARRAY) { + read_array_of_uint(keyfile, setting, key); + } else if (G_TYPE_IS_FLAGS(type)) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_flags(G_OBJECT(setting), key, type, u64, &err); + } + } else if (G_TYPE_IS_ENUM(type)) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MAXINT64); + if (i64 == G_MAXINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_enum(G_OBJECT(setting), key, type, i64, &err); + } + } else + g_return_if_reached(); + + if (err) { + if (nm_keyfile_error_is_not_found(err)) { + /* ignore such errors. The key is not present. */ + } else { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); + } + } } static void -_read_setting (KeyfileReaderInfo *info) +_read_setting(KeyfileReaderInfo *info) { - const NMSettInfoSetting *sett_info; - gs_unref_object NMSetting *setting = NULL; - const char *alias; - GType type; - guint i; - - alias = nm_keyfile_plugin_get_setting_name_for_alias (info->group); - if (!alias) - alias = info->group; - - type = nm_setting_lookup_type (alias); - if (!type) { - handle_warn (info, - NULL, - NULL, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting name '%s'"), - info->group); - return; - } - - setting = g_object_new (type, NULL); - - info->setting = setting; - - sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); - - if (sett_info->detail.gendata_info) { - gs_free char **keys = NULL; - gsize k, n_keys; - - keys = g_key_file_get_keys (info->keyfile, info->group, &n_keys, NULL); - if (!keys) - n_keys = 0; - if (n_keys > 0) { - GHashTable *h = _nm_setting_option_hash (setting, TRUE); - - nm_utils_strv_sort (keys, n_keys); - for (k = 0; k < n_keys; k++) { - gs_free char *key = keys[k]; - gs_free_error GError *local = NULL; - const GVariantType *variant_type; - GVariant *variant; - - /* a GKeyFile can return duplicate keys, there is just no API to make sense - * of them. Skip them. */ - if ( k + 1 < n_keys - && nm_streq (key, keys[k + 1])) - continue; - - /* currently, the API is very simple. The setting class just returns - * the desired variant type, and keyfile reader will try to parse - * it accordingly. Note, that this does currently not allow, that - * a particular key can contain different variant types, nor is it - * very flexible in general. - * - * We add flexibility when we need it. Keep it simple for now. */ - variant_type = sett_info->detail.gendata_info->get_variant_type (sett_info, - key, - &local); - if (!variant_type) { - if (!handle_warn (info, - key, - NULL, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key '%s.%s'"), - info->group, - key)) - break; - continue; - } - - if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN)) { - gboolean v; - - v = g_key_file_get_boolean (info->keyfile, - info->group, - key, - &local); - if (local) { - if (!handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not boolean"), - info->group, - key)) - break; - continue; - } - variant = g_variant_new_boolean (v); - } else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32)) { - guint64 v; - - v = g_key_file_get_uint64 (info->keyfile, - info->group, - key, - &local); - - if (local) { - if (!handle_warn (info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a uint32"), - info->group, - key)) - break; - continue; - } - variant = g_variant_new_uint32 ((guint32) v); - } else { - nm_assert_not_reached (); - continue; - } - - g_hash_table_insert (h, - g_steal_pointer (&key), - g_variant_take_ref (variant)); - } - for (; k < n_keys; k++) - g_free (keys[k]); - } - } - - for (i = 0; i < sett_info->property_infos_len; i++) { - read_one_setting_value (info, - setting, - &sett_info->property_infos[i]); - if (info->error) - goto out; - } + const NMSettInfoSetting *sett_info; + gs_unref_object NMSetting *setting = NULL; + const char * alias; + GType type; + guint i; + + alias = nm_keyfile_plugin_get_setting_name_for_alias(info->group); + if (!alias) + alias = info->group; + + type = nm_setting_lookup_type(alias); + if (!type) { + handle_warn(info, + NULL, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting name '%s'"), + info->group); + return; + } + + setting = g_object_new(type, NULL); + + info->setting = setting; + + sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); + + if (sett_info->detail.gendata_info) { + gs_free char **keys = NULL; + gsize k, n_keys; + + keys = g_key_file_get_keys(info->keyfile, info->group, &n_keys, NULL); + if (!keys) + n_keys = 0; + if (n_keys > 0) { + GHashTable *h = _nm_setting_option_hash(setting, TRUE); + + nm_utils_strv_sort(keys, n_keys); + for (k = 0; k < n_keys; k++) { + gs_free char *key = keys[k]; + gs_free_error GError *local = NULL; + const GVariantType * variant_type; + GVariant * variant; + + /* a GKeyFile can return duplicate keys, there is just no API to make sense + * of them. Skip them. */ + if (k + 1 < n_keys && nm_streq(key, keys[k + 1])) + continue; + + /* currently, the API is very simple. The setting class just returns + * the desired variant type, and keyfile reader will try to parse + * it accordingly. Note, that this does currently not allow, that + * a particular key can contain different variant types, nor is it + * very flexible in general. + * + * We add flexibility when we need it. Keep it simple for now. */ + variant_type = + sett_info->detail.gendata_info->get_variant_type(sett_info, key, &local); + if (!variant_type) { + if (!handle_warn(info, + key, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key '%s.%s'"), + info->group, + key)) + break; + continue; + } + + if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_BOOLEAN)) { + gboolean v; + + v = g_key_file_get_boolean(info->keyfile, info->group, key, &local); + if (local) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not boolean"), + info->group, + key)) + break; + continue; + } + variant = g_variant_new_boolean(v); + } else if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_UINT32)) { + guint64 v; + + v = g_key_file_get_uint64(info->keyfile, info->group, key, &local); + + if (local) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a uint32"), + info->group, + key)) + break; + continue; + } + variant = g_variant_new_uint32((guint32) v); + } else { + nm_assert_not_reached(); + continue; + } + + g_hash_table_insert(h, g_steal_pointer(&key), g_variant_take_ref(variant)); + } + for (; k < n_keys; k++) + g_free(keys[k]); + } + } + + for (i = 0; i < sett_info->property_infos_len; i++) { + read_one_setting_value(info, setting, &sett_info->property_infos[i]); + if (info->error) + goto out; + } out: - info->setting = NULL; - if (!info->error) - nm_connection_add_setting (info->connection, g_steal_pointer (&setting)); + info->setting = NULL; + if (!info->error) + nm_connection_add_setting(info->connection, g_steal_pointer(&setting)); } static void -_read_setting_wireguard_peer (KeyfileReaderInfo *info) +_read_setting_wireguard_peer(KeyfileReaderInfo *info) { - gs_unref_object NMSettingWireGuard *s_wg_new = NULL; - nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; - gs_free_error GError *error = NULL; - NMSettingWireGuard *s_wg; - gs_free char *str = NULL; - const char *cstr = NULL; - const char *key; - gint64 i64; - gs_strfreev char **sa = NULL; - gsize n_sa; - - peer = nm_wireguard_peer_new (); - - nm_assert (g_str_has_prefix (info->group, NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)); - cstr = &info->group[NM_STRLEN (NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)]; - if ( !nm_utils_base64secret_normalize (cstr, NM_WIREGUARD_PUBLIC_KEY_LEN, &str) - || !nm_streq0 (str, cstr)) { - /* the group name must be identical to the normalized(!) key, so that it - * is uniquely identified. */ - handle_warn (info, - NULL, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid peer public key in section '%s'"), - info->group); - return; - } - nm_wireguard_peer_set_public_key (peer, cstr, TRUE); - nm_clear_g_free (&str); - - key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY; - str = nm_keyfile_plugin_kf_get_string (info->keyfile, info->group, key, NULL); - if (str) { - if (!nm_wireguard_peer_set_preshared_key (peer, str, FALSE)) { - if (!handle_warn (info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid 256 bit key in base64 encoding"), - info->group, - key)) - return; - } - nm_clear_g_free (&str); - } - - key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS; - i64 = nm_keyfile_plugin_kf_get_int64 (info->keyfile, info->group, key, 0, 0, NM_SETTING_SECRET_FLAG_ALL, -1, NULL); - if (errno != ENODATA) { - if ( i64 == -1 - || !_nm_setting_secret_flags_valid (i64)) { - if (!handle_warn (info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid secret flag"), - info->group, - key)) - return; - } else - nm_wireguard_peer_set_preshared_key_flags (peer, i64); - } - - key = NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE; - i64 = nm_keyfile_plugin_kf_get_int64 (info->keyfile, info->group, key, 0, 0, G_MAXUINT32, -1, NULL); - if (errno != ENODATA) { - if (i64 == -1) { - if (!handle_warn (info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a integer in range 0 to 2^32"), - info->group, - key)) - return; - } else - nm_wireguard_peer_set_persistent_keepalive (peer, i64); - } - - key = NM_WIREGUARD_PEER_ATTR_ENDPOINT; - str = nm_keyfile_plugin_kf_get_string (info->keyfile, info->group, key, NULL); - if (str && str[0]) { - if (!nm_wireguard_peer_set_endpoint (peer, str, FALSE)) { - if (!handle_warn (info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid endpoint"), - info->group, - key)) - return; - } - } - nm_clear_g_free (&str); - - key = NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS; - sa = nm_keyfile_plugin_kf_get_string_list (info->keyfile, info->group, key, &n_sa, NULL); - if (n_sa > 0) { - gboolean has_error = FALSE; - gsize i; - - for (i = 0; i < n_sa; i++) { - if (!nm_utils_parse_inaddr_prefix_bin (AF_UNSPEC, sa[i], NULL, NULL, NULL)) { - has_error = TRUE; - continue; - } - nm_wireguard_peer_append_allowed_ip (peer, sa[i], TRUE); - } - if (has_error) { - if (!handle_warn (info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' has invalid allowed-ips"), - info->group, - key)) - return; - } - } - - if (info->error) - return; - - if (!nm_wireguard_peer_is_valid (peer, TRUE, TRUE, &error)) { - handle_warn (info, - NULL, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("peer '%s' is invalid: %s"), - info->group, - error->message); - return; - } - - s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (info->connection, NM_TYPE_SETTING_WIREGUARD)); - if (!s_wg) { - s_wg_new = NM_SETTING_WIREGUARD (nm_setting_wireguard_new ()); - s_wg = s_wg_new; - } - - nm_setting_wireguard_append_peer (s_wg, peer); - - if (s_wg_new) { - nm_connection_add_setting (info->connection, - NM_SETTING (g_steal_pointer (&s_wg_new))); - } + gs_unref_object NMSettingWireGuard *s_wg_new = NULL; + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + gs_free_error GError *error = NULL; + NMSettingWireGuard * s_wg; + gs_free char * str = NULL; + const char * cstr = NULL; + const char * key; + gint64 i64; + gs_strfreev char ** sa = NULL; + gsize n_sa; + + peer = nm_wireguard_peer_new(); + + nm_assert(g_str_has_prefix(info->group, NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)); + cstr = &info->group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)]; + if (!nm_utils_base64secret_normalize(cstr, NM_WIREGUARD_PUBLIC_KEY_LEN, &str) + || !nm_streq0(str, cstr)) { + /* the group name must be identical to the normalized(!) key, so that it + * is uniquely identified. */ + handle_warn(info, + NULL, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid peer public key in section '%s'"), + info->group); + return; + } + nm_wireguard_peer_set_public_key(peer, cstr, TRUE); + nm_clear_g_free(&str); + + key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY; + str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); + if (str) { + if (!nm_wireguard_peer_set_preshared_key(peer, str, FALSE)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid 256 bit key in base64 encoding"), + info->group, + key)) + return; + } + nm_clear_g_free(&str); + } + + key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS; + i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, + info->group, + key, + 0, + 0, + NM_SETTING_SECRET_FLAG_ALL, + -1, + NULL); + if (errno != ENODATA) { + if (i64 == -1 || !_nm_setting_secret_flags_valid(i64)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid secret flag"), + info->group, + key)) + return; + } else + nm_wireguard_peer_set_preshared_key_flags(peer, i64); + } + + key = NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE; + i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, + info->group, + key, + 0, + 0, + G_MAXUINT32, + -1, + NULL); + if (errno != ENODATA) { + if (i64 == -1) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a integer in range 0 to 2^32"), + info->group, + key)) + return; + } else + nm_wireguard_peer_set_persistent_keepalive(peer, i64); + } + + key = NM_WIREGUARD_PEER_ATTR_ENDPOINT; + str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); + if (str && str[0]) { + if (!nm_wireguard_peer_set_endpoint(peer, str, FALSE)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid endpoint"), + info->group, + key)) + return; + } + } + nm_clear_g_free(&str); + + key = NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS; + sa = nm_keyfile_plugin_kf_get_string_list(info->keyfile, info->group, key, &n_sa, NULL); + if (n_sa > 0) { + gboolean has_error = FALSE; + gsize i; + + for (i = 0; i < n_sa; i++) { + if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, sa[i], NULL, NULL, NULL)) { + has_error = TRUE; + continue; + } + nm_wireguard_peer_append_allowed_ip(peer, sa[i], TRUE); + } + if (has_error) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' has invalid allowed-ips"), + info->group, + key)) + return; + } + } + + if (info->error) + return; + + if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, &error)) { + handle_warn(info, + NULL, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("peer '%s' is invalid: %s"), + info->group, + error->message); + return; + } + + s_wg = NM_SETTING_WIREGUARD( + nm_connection_get_setting(info->connection, NM_TYPE_SETTING_WIREGUARD)); + if (!s_wg) { + s_wg_new = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); + s_wg = s_wg_new; + } + + nm_setting_wireguard_append_peer(s_wg, peer); + + if (s_wg_new) { + nm_connection_add_setting(info->connection, NM_SETTING(g_steal_pointer(&s_wg_new))); + } } static void -_read_setting_vpn_secrets (KeyfileReaderInfo *info) +_read_setting_vpn_secrets(KeyfileReaderInfo *info) { - gs_strfreev char **keys = NULL; - gsize i, n_keys; - NMSettingVpn *s_vpn; - - s_vpn = nm_connection_get_setting_vpn (info->connection); - if (!s_vpn) { - /* if we don't also have a [vpn] section (which must be parsed earlier), - * we don't do anything. */ - nm_assert (!g_key_file_has_group (info->keyfile, "vpn")); - return; - } - - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL); - for (i = 0; i < n_keys; i++) { - gs_free char *secret = NULL; - - secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, keys[i], NULL); - if (secret) - nm_setting_vpn_add_secret (s_vpn, keys[i], secret); - } + gs_strfreev char **keys = NULL; + gsize i, n_keys; + NMSettingVpn * s_vpn; + + s_vpn = nm_connection_get_setting_vpn(info->connection); + if (!s_vpn) { + /* if we don't also have a [vpn] section (which must be parsed earlier), + * we don't do anything. */ + nm_assert(!g_key_file_has_group(info->keyfile, "vpn")); + return; + } + + keys = + nm_keyfile_plugin_kf_get_keys(info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL); + for (i = 0; i < n_keys; i++) { + gs_free char *secret = NULL; + + secret = nm_keyfile_plugin_kf_get_string(info->keyfile, + NM_KEYFILE_GROUP_VPN_SECRETS, + keys[i], + NULL); + if (secret) + nm_setting_vpn_add_secret(s_vpn, keys[i], secret); + } } gboolean -nm_keyfile_read_ensure_id (NMConnection *connection, - const char *fallback_id) +nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id) { - NMSettingConnection *s_con; + NMSettingConnection *s_con; - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (fallback_id, FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(fallback_id, FALSE); - s_con = nm_connection_get_setting_connection (connection); - g_return_val_if_fail (NM_IS_SETTING_CONNECTION (s_con), FALSE); + s_con = nm_connection_get_setting_connection(connection); + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); - if (nm_setting_connection_get_id (s_con)) - return FALSE; + if (nm_setting_connection_get_id(s_con)) + return FALSE; - g_object_set (s_con, NM_SETTING_CONNECTION_ID, fallback_id, NULL); - return TRUE; + g_object_set(s_con, NM_SETTING_CONNECTION_ID, fallback_id, NULL); + return TRUE; } gboolean -nm_keyfile_read_ensure_uuid (NMConnection *connection, - const char *fallback_uuid_seed) +nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed) { - NMSettingConnection *s_con; - gs_free char *hashed_uuid = NULL; + NMSettingConnection *s_con; + gs_free char * hashed_uuid = NULL; - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (fallback_uuid_seed, FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(fallback_uuid_seed, FALSE); - s_con = nm_connection_get_setting_connection (connection); - g_return_val_if_fail (NM_IS_SETTING_CONNECTION (s_con), FALSE); + s_con = nm_connection_get_setting_connection(connection); + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); - if (nm_setting_connection_get_uuid (s_con)) - return FALSE; + if (nm_setting_connection_get_uuid(s_con)) + return FALSE; - hashed_uuid = _nm_utils_uuid_generate_from_strings ("keyfile", fallback_uuid_seed, NULL); - g_object_set (s_con, NM_SETTING_CONNECTION_UUID, hashed_uuid, NULL); - return TRUE; + hashed_uuid = _nm_utils_uuid_generate_from_strings("keyfile", fallback_uuid_seed, NULL); + g_object_set(s_con, NM_SETTING_CONNECTION_UUID, hashed_uuid, NULL); + return TRUE; } /** @@ -3769,586 +3592,590 @@ nm_keyfile_read_ensure_uuid (NMConnection *connection, * Returns: (transfer full): on success, returns the created connection. */ NMConnection * -nm_keyfile_read (GKeyFile *keyfile, - const char *base_dir, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileReadHandler handler, - void *user_data, - GError **error) +nm_keyfile_read(GKeyFile * keyfile, + const char * base_dir, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileReadHandler handler, + void * user_data, + GError ** error) { - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection *s_con; - gs_strfreev char **groups = NULL; - gsize n_groups; - gsize i; - gboolean vpn_secrets = FALSE; - KeyfileReaderInfo info; - - g_return_val_if_fail (keyfile, NULL); - g_return_val_if_fail (!error || !*error, NULL); - g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL); - g_return_val_if_fail (handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); - - connection = nm_simple_connection_new (); - - info = (KeyfileReaderInfo) { - .connection = connection, - .keyfile = keyfile, - .base_dir = base_dir, - .read_handler = handler, - .user_data = user_data, - }; - - groups = g_key_file_get_groups (keyfile, &n_groups); - if (!groups) - n_groups = 0; - - for (i = 0; i < n_groups; i++) { - - info.group = groups[i]; - - if (nm_streq (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) { - /* Only read out secrets when needed */ - vpn_secrets = TRUE; - } else if (NM_STR_HAS_PREFIX (groups[i], NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)) - _read_setting_wireguard_peer (&info); - else if (NM_IN_STRSET (groups[i], NM_KEYFILE_GROUP_NMMETA, - ETHERNET_S390_OPTIONS_GROUP_NAME)) { - /* pass */ - } else - _read_setting (&info); - - info.group = NULL; - - if (info.error) - goto out_with_info_error; - } - - s_con = nm_connection_get_setting_connection (connection); - if (!s_con) { - s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); - nm_connection_add_setting (connection, NM_SETTING (s_con)); - } - - /* Make sure that we have 'interface-name' even if it was specified in the - * "wrong" (ie, deprecated) group. - */ - if ( !nm_setting_connection_get_interface_name (s_con) - && nm_setting_connection_get_connection_type (s_con)) { - gs_free char *interface_name = NULL; - - interface_name = g_key_file_get_string (keyfile, - nm_setting_connection_get_connection_type (s_con), - "interface-name", - NULL); - if (interface_name) - g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); - } - - if (vpn_secrets) { - info.group = NM_KEYFILE_GROUP_VPN_SECRETS; - _read_setting_vpn_secrets (&info); - info.group = NULL;; - if (info.error) - goto out_with_info_error; - } - - return g_steal_pointer (&connection); + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection * s_con; + gs_strfreev char ** groups = NULL; + gsize n_groups; + gsize i; + gboolean vpn_secrets = FALSE; + KeyfileReaderInfo info; + + g_return_val_if_fail(keyfile, NULL); + g_return_val_if_fail(!error || !*error, NULL); + g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); + g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); + + connection = nm_simple_connection_new(); + + info = (KeyfileReaderInfo){ + .connection = connection, + .keyfile = keyfile, + .base_dir = base_dir, + .read_handler = handler, + .user_data = user_data, + }; + + groups = g_key_file_get_groups(keyfile, &n_groups); + if (!groups) + n_groups = 0; + + for (i = 0; i < n_groups; i++) { + info.group = groups[i]; + + if (nm_streq(groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) { + /* Only read out secrets when needed */ + vpn_secrets = TRUE; + } else if (NM_STR_HAS_PREFIX(groups[i], NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)) + _read_setting_wireguard_peer(&info); + else if (NM_IN_STRSET(groups[i], + NM_KEYFILE_GROUP_NMMETA, + ETHERNET_S390_OPTIONS_GROUP_NAME)) { + /* pass */ + } else + _read_setting(&info); + + info.group = NULL; + + if (info.error) + goto out_with_info_error; + } + + s_con = nm_connection_get_setting_connection(connection); + if (!s_con) { + s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + } + + /* Make sure that we have 'interface-name' even if it was specified in the + * "wrong" (ie, deprecated) group. + */ + if (!nm_setting_connection_get_interface_name(s_con) + && nm_setting_connection_get_connection_type(s_con)) { + gs_free char *interface_name = NULL; + + interface_name = g_key_file_get_string(keyfile, + nm_setting_connection_get_connection_type(s_con), + "interface-name", + NULL); + if (interface_name) + g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); + } + + if (vpn_secrets) { + info.group = NM_KEYFILE_GROUP_VPN_SECRETS; + _read_setting_vpn_secrets(&info); + info.group = NULL; + if (info.error) + goto out_with_info_error; + } + + return g_steal_pointer(&connection); out_with_info_error: - g_propagate_error (error, info.error); - return NULL; + g_propagate_error(error, info.error); + return NULL; } /*****************************************************************************/ static void -write_setting_value (KeyfileWriterInfo *info, - NMSetting *setting, - const NMSettInfoProperty *property_info) +write_setting_value(KeyfileWriterInfo * info, + NMSetting * setting, + const NMSettInfoProperty *property_info) { - const NMMetaSettingInfo *setting_info; - const ParseInfoProperty *pip; - const char *key; - char numstr[64]; - GValue value; - GType type; - - nm_assert (!info->error); - nm_assert ( !property_info->param_spec - || nm_streq (property_info->param_spec->name, property_info->name)); - - key = property_info->name; - - _parse_info_find (setting, key, &setting_info, NULL, &pip); - - if (!pip) { - if (!setting_info) { - /* the setting type is unknown. That is highly unexpected - * (and as this is currently only called from NetworkManager - * daemon, not possible). - * - * Still, handle it gracefully, because later keyfile writer will become - * public API of libnm, where @setting is (untrusted) user input. - * - * Gracefully here just means: ignore the setting. */ - return; - } - if (!property_info->param_spec) - return; - if (nm_streq (key, NM_SETTING_NAME)) - return; - } else { - if (pip->has_writer_full) { - pip->writer_full (info, setting_info, property_info, pip, setting); - return; - } - if (pip->writer_skip) - return; - } - - nm_assert (property_info->param_spec); - - /* Don't write secrets that are owned by user secret agents or aren't - * supposed to be saved. VPN secrets are handled specially though since - * the secret flags there are in a third-level hash in the 'secrets' - * property. - */ - if ( (property_info->param_spec->flags & NM_SETTING_PARAM_SECRET) - && !NM_IS_SETTING_VPN (setting)) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) - g_return_if_reached (); - if (!_secret_flags_persist_secret (secret_flags)) - return; - } - - value = (GValue) { 0 }; - - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec)); - g_object_get_property (G_OBJECT (setting), property_info->param_spec->name, &value); - - if ( (!pip || !pip->writer_persist_default) - && g_param_value_defaults (property_info->param_spec, &value)) { - nm_assert (!g_key_file_has_key (info->keyfile, setting_info->setting_name, key, NULL)); - goto out_unset_value; - } - - if ( pip - && pip->writer) { - pip->writer (info, setting, key, &value); - goto out_unset_value; - } - - type = G_VALUE_TYPE (&value); - if (type == G_TYPE_STRING) { - const char *str; - - str = g_value_get_string (&value); - if (str) - nm_keyfile_plugin_kf_set_string (info->keyfile, setting_info->setting_name, key, str); - } else if (type == G_TYPE_UINT) { - nm_sprintf_buf (numstr, "%u", g_value_get_uint (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_INT) { - nm_sprintf_buf (numstr, "%d", g_value_get_int (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_UINT64) { - nm_sprintf_buf (numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64 (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_INT64) { - nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_BOOLEAN) { - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, - g_value_get_boolean (&value) - ? "true" - : "false"); - } else if (type == G_TYPE_CHAR) { - nm_sprintf_buf (numstr, "%d", (int) g_value_get_schar (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_BYTES) { - GBytes *bytes; - const guint8 *data; - gsize len = 0; - - bytes = g_value_get_boxed (&value); - data = bytes ? g_bytes_get_data (bytes, &len) : NULL; - - if (data != NULL && len > 0) - nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_info->setting_name, key, data, len); - } else if (type == G_TYPE_STRV) { - char **array; - - array = (char **) g_value_get_boxed (&value); - nm_keyfile_plugin_kf_set_string_list (info->keyfile, setting_info->setting_name, key, (const char **const) array, g_strv_length (array)); - } else if (type == G_TYPE_HASH_TABLE) { - write_hash_of_string (info->keyfile, setting, key, &value); - } else if (type == G_TYPE_ARRAY) { - write_array_of_uint (info->keyfile, setting, key, &value); - } else if (G_VALUE_HOLDS_FLAGS (&value)) { - nm_sprintf_buf (numstr, "%u", g_value_get_flags (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else if (G_VALUE_HOLDS_ENUM (&value)) { - nm_sprintf_buf (numstr, "%d", g_value_get_enum (&value)); - nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr); - } else - g_return_if_reached (); + const NMMetaSettingInfo *setting_info; + const ParseInfoProperty *pip; + const char * key; + char numstr[64]; + GValue value; + GType type; + + nm_assert(!info->error); + nm_assert(!property_info->param_spec + || nm_streq(property_info->param_spec->name, property_info->name)); + + key = property_info->name; + + _parse_info_find(setting, key, &setting_info, NULL, &pip); + + if (!pip) { + if (!setting_info) { + /* the setting type is unknown. That is highly unexpected + * (and as this is currently only called from NetworkManager + * daemon, not possible). + * + * Still, handle it gracefully, because later keyfile writer will become + * public API of libnm, where @setting is (untrusted) user input. + * + * Gracefully here just means: ignore the setting. */ + return; + } + if (!property_info->param_spec) + return; + if (nm_streq(key, NM_SETTING_NAME)) + return; + } else { + if (pip->has_writer_full) { + pip->writer_full(info, setting_info, property_info, pip, setting); + return; + } + if (pip->writer_skip) + return; + } + + nm_assert(property_info->param_spec); + + /* Don't write secrets that are owned by user secret agents or aren't + * supposed to be saved. VPN secrets are handled specially though since + * the secret flags there are in a third-level hash in the 'secrets' + * property. + */ + if ((property_info->param_spec->flags & NM_SETTING_PARAM_SECRET) + && !NM_IS_SETTING_VPN(setting)) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags(setting, key, &secret_flags, NULL)) + g_return_if_reached(); + if (!_secret_flags_persist_secret(secret_flags)) + return; + } + + value = (GValue){0}; + + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec)); + g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &value); + + if ((!pip || !pip->writer_persist_default) + && g_param_value_defaults(property_info->param_spec, &value)) { + nm_assert(!g_key_file_has_key(info->keyfile, setting_info->setting_name, key, NULL)); + goto out_unset_value; + } + + if (pip && pip->writer) { + pip->writer(info, setting, key, &value); + goto out_unset_value; + } + + type = G_VALUE_TYPE(&value); + if (type == G_TYPE_STRING) { + const char *str; + + str = g_value_get_string(&value); + if (str) + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_info->setting_name, key, str); + } else if (type == G_TYPE_UINT) { + nm_sprintf_buf(numstr, "%u", g_value_get_uint(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_INT) { + nm_sprintf_buf(numstr, "%d", g_value_get_int(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_UINT64) { + nm_sprintf_buf(numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_INT64) { + nm_sprintf_buf(numstr, "%" G_GINT64_FORMAT, g_value_get_int64(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_BOOLEAN) { + nm_keyfile_plugin_kf_set_value(info->keyfile, + setting_info->setting_name, + key, + g_value_get_boolean(&value) ? "true" : "false"); + } else if (type == G_TYPE_CHAR) { + nm_sprintf_buf(numstr, "%d", (int) g_value_get_schar(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_BYTES) { + GBytes * bytes; + const guint8 *data; + gsize len = 0; + + bytes = g_value_get_boxed(&value); + data = bytes ? g_bytes_get_data(bytes, &len) : NULL; + + if (data != NULL && len > 0) + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, + setting_info->setting_name, + key, + data, + len); + } else if (type == G_TYPE_STRV) { + char **array; + + array = (char **) g_value_get_boxed(&value); + nm_keyfile_plugin_kf_set_string_list(info->keyfile, + setting_info->setting_name, + key, + (const char **const) array, + g_strv_length(array)); + } else if (type == G_TYPE_HASH_TABLE) { + write_hash_of_string(info->keyfile, setting, key, &value); + } else if (type == G_TYPE_ARRAY) { + write_array_of_uint(info->keyfile, setting, key, &value); + } else if (G_VALUE_HOLDS_FLAGS(&value)) { + nm_sprintf_buf(numstr, "%u", g_value_get_flags(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (G_VALUE_HOLDS_ENUM(&value)) { + nm_sprintf_buf(numstr, "%d", g_value_get_enum(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else + g_return_if_reached(); out_unset_value: - g_value_unset (&value); + g_value_unset(&value); } static void -_write_setting_wireguard (NMSetting *setting, KeyfileWriterInfo *info) +_write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info) { - NMSettingWireGuard *s_wg; - guint i_peer, n_peers; - - s_wg = NM_SETTING_WIREGUARD (setting); - - n_peers = nm_setting_wireguard_get_peers_len (s_wg); - for (i_peer = 0; i_peer < n_peers; i_peer++) { - NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i_peer); - const char *public_key; - char group[NM_STRLEN (NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER) + 200]; - NMSettingSecretFlags secret_flags; - gboolean any_key = FALSE; - guint i_aip, n_aip; - const char *cstr; - guint32 u32; - - public_key = nm_wireguard_peer_get_public_key (peer); - if ( !public_key - || !public_key[0] - || !NM_STRCHAR_ALL (public_key, ch, nm_sd_utils_unbase64char (ch, TRUE) >= 0)) { - /* invalid peer. Skip it */ - continue; - } - - if (g_snprintf (group, - sizeof (group), - "%s%s", - NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER, - nm_wireguard_peer_get_public_key (peer)) >= sizeof (group)) { - /* Too long. Not a valid public key. Skip the peer. */ - continue; - } - - cstr = nm_wireguard_peer_get_endpoint (peer); - if (cstr) { - g_key_file_set_string (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, cstr); - any_key = TRUE; - } - - secret_flags = nm_wireguard_peer_get_preshared_key_flags (peer); - if (_secret_flags_persist_secret (secret_flags)) { - cstr = nm_wireguard_peer_get_preshared_key (peer); - if (cstr) { - g_key_file_set_string (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, cstr); - any_key = TRUE; - } - } - - /* usually, we don't persist the secret-flags 0 (because they are the default). - * For WireGuard peers, the default secret-flags for preshared-key are 4 (not-required). - * So, in this case behave differently: a missing preshared-key-flag setting means - * "not-required". */ - if (secret_flags != NM_SETTING_SECRET_FLAG_NOT_REQUIRED) { - g_key_file_set_int64 (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS, secret_flags); - any_key = TRUE; - } - - u32 = nm_wireguard_peer_get_persistent_keepalive (peer); - if (u32) { - g_key_file_set_uint64 (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE, u32); - any_key = TRUE; - } - - n_aip = nm_wireguard_peer_get_allowed_ips_len (peer); - if (n_aip > 0) { - gs_free const char **strv = NULL; - - strv = g_new (const char *, ((gsize) n_aip) + 1); - for (i_aip = 0; i_aip < n_aip; i_aip++) - strv[i_aip] = nm_wireguard_peer_get_allowed_ip (peer, i_aip, NULL); - strv[n_aip] = NULL; - g_key_file_set_string_list (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS, - strv, n_aip); - any_key = TRUE; - } - - if (!any_key) { - /* we cannot omit all keys. At an empty endpoint. */ - g_key_file_set_string (info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, ""); - } - } + NMSettingWireGuard *s_wg; + guint i_peer, n_peers; + + s_wg = NM_SETTING_WIREGUARD(setting); + + n_peers = nm_setting_wireguard_get_peers_len(s_wg); + for (i_peer = 0; i_peer < n_peers; i_peer++) { + NMWireGuardPeer * peer = nm_setting_wireguard_get_peer(s_wg, i_peer); + const char * public_key; + char group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER) + 200]; + NMSettingSecretFlags secret_flags; + gboolean any_key = FALSE; + guint i_aip, n_aip; + const char * cstr; + guint32 u32; + + public_key = nm_wireguard_peer_get_public_key(peer); + if (!public_key || !public_key[0] + || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) { + /* invalid peer. Skip it */ + continue; + } + + if (g_snprintf(group, + sizeof(group), + "%s%s", + NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER, + nm_wireguard_peer_get_public_key(peer)) + >= sizeof(group)) { + /* Too long. Not a valid public key. Skip the peer. */ + continue; + } + + cstr = nm_wireguard_peer_get_endpoint(peer); + if (cstr) { + g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, cstr); + any_key = TRUE; + } + + secret_flags = nm_wireguard_peer_get_preshared_key_flags(peer); + if (_secret_flags_persist_secret(secret_flags)) { + cstr = nm_wireguard_peer_get_preshared_key(peer); + if (cstr) { + g_key_file_set_string(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, + cstr); + any_key = TRUE; + } + } + + /* usually, we don't persist the secret-flags 0 (because they are the default). + * For WireGuard peers, the default secret-flags for preshared-key are 4 (not-required). + * So, in this case behave differently: a missing preshared-key-flag setting means + * "not-required". */ + if (secret_flags != NM_SETTING_SECRET_FLAG_NOT_REQUIRED) { + g_key_file_set_int64(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS, + secret_flags); + any_key = TRUE; + } + + u32 = nm_wireguard_peer_get_persistent_keepalive(peer); + if (u32) { + g_key_file_set_uint64(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE, + u32); + any_key = TRUE; + } + + n_aip = nm_wireguard_peer_get_allowed_ips_len(peer); + if (n_aip > 0) { + gs_free const char **strv = NULL; + + strv = g_new(const char *, ((gsize) n_aip) + 1); + for (i_aip = 0; i_aip < n_aip; i_aip++) + strv[i_aip] = nm_wireguard_peer_get_allowed_ip(peer, i_aip, NULL); + strv[n_aip] = NULL; + g_key_file_set_string_list(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS, + strv, + n_aip); + any_key = TRUE; + } + + if (!any_key) { + /* we cannot omit all keys. At an empty endpoint. */ + g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, ""); + } + } } GKeyFile * -nm_keyfile_write (NMConnection *connection, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileWriteHandler handler, - void *user_data, - GError **error) +nm_keyfile_write(NMConnection * connection, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileWriteHandler handler, + void * user_data, + GError ** error) { - gs_unref_keyfile GKeyFile *keyfile = NULL; - KeyfileWriterInfo info; - gs_free NMSetting **settings = NULL; - guint i, j, n_settings = 0; - - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (!error || !*error, NULL); - g_return_val_if_fail (handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); - - if (!nm_connection_verify (connection, error)) - return NULL; - - keyfile = g_key_file_new (); - - info = (KeyfileWriterInfo) { - .connection = connection, - .keyfile = keyfile, - .error = NULL, - .write_handler = handler, - .user_data = user_data, - }; - - settings = nm_connection_get_settings (connection, &n_settings); - for (i = 0; i < n_settings; i++) { - const NMSettInfoSetting *sett_info; - NMSetting *setting = settings[i]; - const char *setting_name; - const char *setting_alias; - - sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); - - setting_name = sett_info->setting_class->setting_info->setting_name; - - if (sett_info->detail.gendata_info) { - guint k, n_keys; - const char *const*keys; - - nm_assert (!nm_keyfile_plugin_get_alias_for_setting_name (sett_info->setting_class->setting_info->setting_name)); - - n_keys = _nm_setting_option_get_all (setting, &keys, NULL); - - if (n_keys > 0) { - GHashTable *h = _nm_setting_option_hash (setting, FALSE); - - for (k = 0; k < n_keys; k++) { - const char *key = keys[k]; - GVariant *v; - - v = g_hash_table_lookup (h, key); - - if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) { - g_key_file_set_boolean (info.keyfile, - setting_name, - key, - g_variant_get_boolean (v)); - } else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32)) { - g_key_file_set_uint64 (info.keyfile, - setting_name, - key, - (guint64) g_variant_get_uint32 (v)); - } else { - /* BUG: The variant type is not implemented. Since the connection - * verifies, this can only mean we either wrongly didn't reject - * the connection as invalid, or we didn't properly implement the - * variant type. */ - nm_assert_not_reached (); - continue; - } - } - } - } - - for (j = 0; j < sett_info->property_infos_len; j++) { - const NMSettInfoProperty *property_info = _nm_sett_info_property_info_get_sorted (sett_info, j); - - write_setting_value (&info, setting, property_info); - if (info.error) - goto out_with_info_error; - } - - setting_alias = nm_keyfile_plugin_get_alias_for_setting_name (setting_name); - if ( ( setting_alias - && g_key_file_has_group (info.keyfile, setting_alias)) - || g_key_file_has_group (info.keyfile, setting_name)) { - /* we have a section for the setting. Nothing to do. */ - } else { - /* ensure the group is present. There is no API for that, so add and remove - * a dummy key. */ - g_key_file_set_value (info.keyfile, setting_alias ?: setting_name, ".X", "1"); - g_key_file_remove_key (info.keyfile, setting_alias ?: setting_name, ".X", NULL); - } - - if (NM_IS_SETTING_WIREGUARD (setting)) { - _write_setting_wireguard (setting, &info); - if (info.error) - goto out_with_info_error; - } - - nm_assert (!info.error); - } - - nm_assert (!info.error); - - return g_steal_pointer (&keyfile); + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + KeyfileWriterInfo info; + gs_free NMSetting **settings = NULL; + guint i, j, n_settings = 0; + + g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL); + g_return_val_if_fail(!error || !*error, NULL); + g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); + + if (!nm_connection_verify(connection, error)) + return NULL; + + keyfile = g_key_file_new(); + + info = (KeyfileWriterInfo){ + .connection = connection, + .keyfile = keyfile, + .error = NULL, + .write_handler = handler, + .user_data = user_data, + }; + + settings = nm_connection_get_settings(connection, &n_settings); + for (i = 0; i < n_settings; i++) { + const NMSettInfoSetting *sett_info; + NMSetting * setting = settings[i]; + const char * setting_name; + const char * setting_alias; + + sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); + + setting_name = sett_info->setting_class->setting_info->setting_name; + + if (sett_info->detail.gendata_info) { + guint k, n_keys; + const char *const *keys; + + nm_assert(!nm_keyfile_plugin_get_alias_for_setting_name( + sett_info->setting_class->setting_info->setting_name)); + + n_keys = _nm_setting_option_get_all(setting, &keys, NULL); + + if (n_keys > 0) { + GHashTable *h = _nm_setting_option_hash(setting, FALSE); + + for (k = 0; k < n_keys; k++) { + const char *key = keys[k]; + GVariant * v; + + v = g_hash_table_lookup(h, key); + + if (g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) { + g_key_file_set_boolean(info.keyfile, + setting_name, + key, + g_variant_get_boolean(v)); + } else if (g_variant_is_of_type(v, G_VARIANT_TYPE_UINT32)) { + g_key_file_set_uint64(info.keyfile, + setting_name, + key, + (guint64) g_variant_get_uint32(v)); + } else { + /* BUG: The variant type is not implemented. Since the connection + * verifies, this can only mean we either wrongly didn't reject + * the connection as invalid, or we didn't properly implement the + * variant type. */ + nm_assert_not_reached(); + continue; + } + } + } + } + + for (j = 0; j < sett_info->property_infos_len; j++) { + const NMSettInfoProperty *property_info = + _nm_sett_info_property_info_get_sorted(sett_info, j); + + write_setting_value(&info, setting, property_info); + if (info.error) + goto out_with_info_error; + } + + setting_alias = nm_keyfile_plugin_get_alias_for_setting_name(setting_name); + if ((setting_alias && g_key_file_has_group(info.keyfile, setting_alias)) + || g_key_file_has_group(info.keyfile, setting_name)) { + /* we have a section for the setting. Nothing to do. */ + } else { + /* ensure the group is present. There is no API for that, so add and remove + * a dummy key. */ + g_key_file_set_value(info.keyfile, setting_alias ?: setting_name, ".X", "1"); + g_key_file_remove_key(info.keyfile, setting_alias ?: setting_name, ".X", NULL); + } + + if (NM_IS_SETTING_WIREGUARD(setting)) { + _write_setting_wireguard(setting, &info); + if (info.error) + goto out_with_info_error; + } + + nm_assert(!info.error); + } + + nm_assert(!info.error); + + return g_steal_pointer(&keyfile); out_with_info_error: - g_propagate_error (error, info.error); - return NULL; + g_propagate_error(error, info.error); + return NULL; } /*****************************************************************************/ -static const char temp_letters[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +static const char temp_letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /* * Check '.[a-zA-Z0-9]{6}' file suffix used for temporary files by g_file_set_contents() (mkstemp()). */ static gboolean -check_mkstemp_suffix (const char *path) +check_mkstemp_suffix(const char *path) { - const char *ptr; + const char *ptr; - nm_assert (path); + nm_assert(path); - /* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */ - ptr = strrchr (path, '.'); - if ( ptr - && strspn (&ptr[1], temp_letters) == 6 - && ptr[7] == '\0') - return TRUE; - return FALSE; + /* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */ + ptr = strrchr(path, '.'); + if (ptr && strspn(&ptr[1], temp_letters) == 6 && ptr[7] == '\0') + return TRUE; + return FALSE; } -static gboolean -_check_suffix_impl (const char *base, const char *tag, gsize tag_len) -{ - gsize len; - - nm_assert (base); - nm_assert (tag); - nm_assert (strlen (tag) == tag_len); - - len = strlen (base); - if ( len > tag_len - && !g_ascii_strcasecmp (base + len - tag_len, tag)) - return TRUE; - return FALSE; -} -#define check_suffix(base, tag) _check_suffix_impl ((base), ""tag"", NM_STRLEN (tag)) - -#define SWP_TAG ".swp" +#define SWP_TAG ".swp" #define SWPX_TAG ".swpx" -#define PEM_TAG ".pem" -#define DER_TAG ".der" +#define PEM_TAG ".pem" +#define DER_TAG ".der" gboolean -nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension) +nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension) { - const char *base; - gsize l; - - /* ignore_filename() must mirror nm_keyfile_utils_create_filename() */ - - g_return_val_if_fail (filename, TRUE); - - base = strrchr (filename, '/'); - if (base) - base++; - else - base = filename; - - if (!base[0]) { - /* this check above with strrchr() also rejects "/some/path/with/trailing/slash/", - * but that is fine, because such a path would name a directory, and we are not - * interested in directories. */ - return TRUE; - } - - if (base[0] == '.') { - /* don't allow hidden files */ - return TRUE; - } - - l = strlen (base); - - if (require_extension) { - if ( l <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION) - || !NM_STR_HAS_SUFFIX (base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) - return TRUE; - return FALSE; - } - - /* Ignore backup files */ - if (base[l - 1] == '~') - return TRUE; - - /* Ignore temporary files - * - * This check is also important to ignore .nmload files (see - * %NM_KEYFILE_PATH_SUFFIX_NMMETA). */ - if (check_mkstemp_suffix (base)) - return TRUE; - - /* Ignore 802.1x certificates and keys */ - if ( check_suffix (base, PEM_TAG) - || check_suffix (base, DER_TAG)) - return TRUE; - - return FALSE; + const char *base; + gsize l; + + /* ignore_filename() must mirror nm_keyfile_utils_create_filename() */ + + g_return_val_if_fail(filename, TRUE); + + base = strrchr(filename, '/'); + if (base) + base++; + else + base = filename; + + if (!base[0]) { + /* this check above with strrchr() also rejects "/some/path/with/trailing/slash/", + * but that is fine, because such a path would name a directory, and we are not + * interested in directories. */ + return TRUE; + } + + if (base[0] == '.') { + /* don't allow hidden files */ + return TRUE; + } + + if (require_extension) { + if (!NM_STR_HAS_SUFFIX_WITH_MORE(base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) + return TRUE; + return FALSE; + } + + l = strlen(base); + + /* Ignore backup files */ + if (base[l - 1] == '~') + return TRUE; + + /* Ignore temporary files + * + * This check is also important to ignore .nmload files (see + * %NM_KEYFILE_PATH_SUFFIX_NMMETA). */ + if (check_mkstemp_suffix(base)) + return TRUE; + + /* Ignore 802.1x certificates and keys */ + if (NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, PEM_TAG) + || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, DER_TAG)) + return TRUE; + + return FALSE; } char * -nm_keyfile_utils_create_filename (const char *name, - gboolean with_extension) +nm_keyfile_utils_create_filename(const char *name, gboolean with_extension) { - GString *str; - const char *f = name; - /* keyfile used to escape with '*', do not change that behavior. - * - * But for newly added escapings, use '_' instead. - * Also, @with_extension is new-style. */ - const char ESCAPE_CHAR = with_extension ? '_' : '*'; - const char ESCAPE_CHAR2 = '_'; - - g_return_val_if_fail (name && name[0], NULL); - - str = g_string_sized_new (60); - - /* Convert '/' to ESCAPE_CHAR */ - for (f = name; f[0]; f++) { - if (f[0] == '/') - g_string_append_c (str, ESCAPE_CHAR); - else - g_string_append_c (str, f[0]); - } - - /* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject. - * We can escape here more aggressivly then what we would read back. */ - if (str->str[0] == '.') - str->str[0] = ESCAPE_CHAR2; - if (str->str[str->len - 1] == '~') - str->str[str->len - 1] = ESCAPE_CHAR2; - if ( check_mkstemp_suffix (str->str) - || check_suffix (str->str, PEM_TAG) - || check_suffix (str->str, DER_TAG)) - g_string_append_c (str, ESCAPE_CHAR2); - - if (with_extension) - g_string_append (str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); - - /* nm_keyfile_utils_create_filename() must mirror ignore_filename() */ - nm_assert (!strchr (str->str, '/')); - nm_assert (!nm_keyfile_utils_ignore_filename (str->str, with_extension)); - - return g_string_free (str, FALSE);; + /* keyfile used to escape with '*', do not change that behavior. + * + * But for newly added escapings, use '_' instead. + * Also, @with_extension is new-style. */ + const char ESCAPE_CHAR = with_extension ? '_' : '*'; + const char ESCAPE_CHAR2 = '_'; + NMStrBuf str; + char * p; + gsize len; + gsize i; + + g_return_val_if_fail(name && name[0], NULL); + + nm_str_buf_init(&str, 0, FALSE); + + len = strlen(name); + + p = nm_str_buf_append_len0(&str, name, len); + + /* Convert '/' to ESCAPE_CHAR */ + for (i = 0; i < len; i++) { + if (p[i] == '/') + p[i] = ESCAPE_CHAR; + } + + /* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject. + * We can escape here more aggressively then what we would read back. */ + if (p[0] == '.') + p[0] = ESCAPE_CHAR2; + if (p[str.len - 1] == '~') + p[str.len - 1] = ESCAPE_CHAR2; + + if (check_mkstemp_suffix(p) || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, PEM_TAG) + || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, DER_TAG)) + nm_str_buf_append_c(&str, ESCAPE_CHAR2); + + if (with_extension) + nm_str_buf_append(&str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); + + p = nm_str_buf_finalize(&str, NULL); + + /* nm_keyfile_utils_create_filename() must mirror ignore_filename() */ + nm_assert(!strchr(p, '/')); + nm_assert(!nm_keyfile_utils_ignore_filename(p, with_extension)); + + return p; } /*****************************************************************************/ @@ -4368,14 +4195,13 @@ nm_keyfile_utils_create_filename (const char *name, * after calling this function on it. */ void -nm_keyfile_handler_data_fail_with_error (NMKeyfileHandlerData *handler_data, - GError *src) +nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src) { - g_return_if_fail (handler_data); - g_return_if_fail (handler_data->p_error && !*handler_data->p_error); - g_return_if_fail (src); + g_return_if_fail(handler_data); + g_return_if_fail(handler_data->p_error && !*handler_data->p_error); + g_return_if_fail(src); - *handler_data->p_error = src; + *handler_data->p_error = src; } /** @@ -4393,36 +4219,37 @@ nm_keyfile_handler_data_fail_with_error (NMKeyfileHandlerData *handler_data, * on all events, but the context information may be unset. */ void -nm_keyfile_handler_data_get_context (const NMKeyfileHandlerData *handler_data, - const char **out_kf_group_name, - const char **out_kf_key_name, - NMSetting **out_cur_setting, - const char **out_cur_property_name) +nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, + const char ** out_kf_group_name, + const char ** out_kf_key_name, + NMSetting ** out_cur_setting, + const char ** out_cur_property_name) { - g_return_if_fail (handler_data); + g_return_if_fail(handler_data); - NM_SET_OUT (out_kf_group_name, handler_data->kf_group_name); - NM_SET_OUT (out_kf_key_name, handler_data->kf_key); - NM_SET_OUT (out_cur_setting, handler_data->cur_setting); - NM_SET_OUT (out_cur_property_name, handler_data->cur_property); + NM_SET_OUT(out_kf_group_name, handler_data->kf_group_name); + NM_SET_OUT(out_kf_key_name, handler_data->kf_key); + NM_SET_OUT(out_cur_setting, handler_data->cur_setting); + NM_SET_OUT(out_cur_property_name, handler_data->cur_property); } const char * -_nm_keyfile_handler_data_warn_get_message (const NMKeyfileHandlerData *handler_data) +_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data) { - nm_assert (handler_data); - nm_assert (handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); - - if (!handler_data->warn.message) { - /* we cast the const away. @handler_data is const w.r.t. visible mutations - * from POV of the user. Internally, we construct the message in - * a lazy manner. It's like a mutable field in C++. */ - NM_PRAGMA_WARNING_DISABLE ("-Wformat-nonliteral") - ((NMKeyfileHandlerData *) handler_data)->warn.message = g_strdup_vprintf (handler_data->warn.fmt, - ((NMKeyfileHandlerData *) handler_data)->warn.ap); - NM_PRAGMA_WARNING_REENABLE - } - return handler_data->warn.message; + nm_assert(handler_data); + nm_assert(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); + + if (!handler_data->warn.message) { + /* we cast the const away. @handler_data is const w.r.t. visible mutations + * from POV of the user. Internally, we construct the message in + * a lazy manner. It's like a mutable field in C++. */ + NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") + ((NMKeyfileHandlerData *) handler_data)->warn.message = + g_strdup_vprintf(handler_data->warn.fmt, + ((NMKeyfileHandlerData *) handler_data)->warn.ap); + NM_PRAGMA_WARNING_REENABLE + } + return handler_data->warn.message; } /** @@ -4433,13 +4260,13 @@ _nm_keyfile_handler_data_warn_get_message (const NMKeyfileHandlerData *handler_d * @out_severity: (out) (allow-none): the #NMKeyfileWarnSeverity warning severity. */ void -nm_keyfile_handler_data_warn_get (const NMKeyfileHandlerData *handler_data, - const char **out_message, - NMKeyfileWarnSeverity *out_severity) +nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, + const char ** out_message, + NMKeyfileWarnSeverity * out_severity) { - g_return_if_fail (handler_data); - g_return_if_fail (handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); + g_return_if_fail(handler_data); + g_return_if_fail(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); - NM_SET_OUT (out_message, _nm_keyfile_handler_data_warn_get_message (handler_data)); - NM_SET_OUT (out_severity, handler_data->warn.severity); + NM_SET_OUT(out_message, _nm_keyfile_handler_data_warn_get_message(handler_data)); + NM_SET_OUT(out_severity, handler_data->warn.severity); } |