mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-14 22:40:35 +01:00
libnm: merge branch 'th/keyfile-fixes'
https://github.com/NetworkManager/NetworkManager/pull/273
This commit is contained in:
commit
0fdcbc6bfa
26 changed files with 1551 additions and 551 deletions
|
|
@ -2033,6 +2033,73 @@ nm_connection_for_each_setting_value (NMConnection *connection,
|
|||
nm_setting_enumerate_values (settings[i], func, user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_connection_aggregate:
|
||||
* @connecition: the #NMConnection for which values are to be aggregated.
|
||||
* @type: one of the supported aggrate types.
|
||||
* @arg: the input/output argument that depends on @type.
|
||||
*
|
||||
* For example, with %NM_CONNECTION_AGGREGATE_ANY_SECRETS and
|
||||
* %NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS @arg is a boolean
|
||||
* output argument. It is either %NULL or a pointer to an gboolean
|
||||
* out-argument. The function will always set @arg if given.
|
||||
* Also, the return value of the function is likewise the result
|
||||
* that is set to @arg.
|
||||
*
|
||||
* Returns: a boolean result with the meaning depending on the aggregation
|
||||
* type @type.
|
||||
*/
|
||||
gboolean
|
||||
_nm_connection_aggregate (NMConnection *connection,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg)
|
||||
{
|
||||
NMConnectionPrivate *priv;
|
||||
GHashTableIter iter;
|
||||
NMSetting *setting;
|
||||
gboolean arg_boolean;
|
||||
gboolean completed_early;
|
||||
gpointer my_arg;
|
||||
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
|
||||
|
||||
switch (type) {
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
|
||||
arg_boolean = FALSE;
|
||||
my_arg = &arg_boolean;
|
||||
goto good;
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
|
||||
arg_boolean = FALSE;
|
||||
my_arg = &arg_boolean;
|
||||
goto good;
|
||||
}
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
good:
|
||||
priv = NM_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
completed_early = FALSE;
|
||||
g_hash_table_iter_init (&iter, priv->settings);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
|
||||
if (_nm_setting_aggregate (setting, type, my_arg)) {
|
||||
completed_early = TRUE;
|
||||
break;
|
||||
}
|
||||
nm_assert ( my_arg != &arg_boolean
|
||||
|| !arg_boolean);
|
||||
}
|
||||
|
||||
if (my_arg == &arg_boolean) {
|
||||
nm_assert (completed_early == arg_boolean);
|
||||
if (arg)
|
||||
*((gboolean *) arg) = arg_boolean;
|
||||
return arg_boolean;
|
||||
}
|
||||
|
||||
nm_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_connection_dump:
|
||||
* @connection: the #NMConnection
|
||||
|
|
|
|||
|
|
@ -121,8 +121,6 @@ typedef enum { /*< flags >*/
|
|||
NM_CONNECTION_SERIALIZE_ALL = 0x00000000,
|
||||
NM_CONNECTION_SERIALIZE_NO_SECRETS = 0x00000001,
|
||||
NM_CONNECTION_SERIALIZE_ONLY_SECRETS = 0x00000002,
|
||||
|
||||
/* 0x80000000 is used for a private flag */
|
||||
} NMConnectionSerializationFlags;
|
||||
|
||||
GVariant *nm_connection_to_dbus (NMConnection *connection,
|
||||
|
|
|
|||
|
|
@ -121,11 +121,21 @@
|
|||
*/
|
||||
#define NM_SETTING_COMPARE_FLAG_NONE ((NMSettingCompareFlags) 0)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define NM_SETTING_SECRET_FLAGS_ALL \
|
||||
(NM_SETTING_SECRET_FLAG_NONE | \
|
||||
NM_SETTING_SECRET_FLAG_AGENT_OWNED | \
|
||||
NM_SETTING_SECRET_FLAG_NOT_SAVED | \
|
||||
NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
|
||||
((NMSettingSecretFlags) ( NM_SETTING_SECRET_FLAG_NONE \
|
||||
| NM_SETTING_SECRET_FLAG_AGENT_OWNED \
|
||||
| NM_SETTING_SECRET_FLAG_NOT_SAVED \
|
||||
| NM_SETTING_SECRET_FLAG_NOT_REQUIRED))
|
||||
|
||||
static inline gboolean
|
||||
_nm_setting_secret_flags_valid (NMSettingSecretFlags flags)
|
||||
{
|
||||
return !NM_FLAGS_ANY (flags, ~NM_SETTING_SECRET_FLAGS_ALL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum { /*< skip >*/
|
||||
NM_SETTING_PARSE_FLAGS_NONE = 0,
|
||||
|
|
@ -146,6 +156,26 @@ gpointer _nm_connection_check_main_setting (NMConnection *connection,
|
|||
const char *setting_name,
|
||||
GError **error);
|
||||
|
||||
typedef enum {
|
||||
/* whether the connection has any secrets.
|
||||
*
|
||||
* @arg may be %NULL or a pointer to a gboolean for the result. The return
|
||||
* value of _nm_connection_aggregate() is likewise the boolean result. */
|
||||
NM_CONNECTION_AGGREGATE_ANY_SECRETS,
|
||||
|
||||
/* whether the connection has any secret with flags NM_SETTING_SECRET_FLAG_NONE.
|
||||
* Note that this only cares about the flags, not whether the secret is actually
|
||||
* present.
|
||||
*
|
||||
* @arg may be %NULL or a pointer to a gboolean for the result. The return
|
||||
* value of _nm_connection_aggregate() is likewise the boolean result. */
|
||||
NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS,
|
||||
} NMConnectionAggregateType;
|
||||
|
||||
gboolean _nm_connection_aggregate (NMConnection *connection,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg);
|
||||
|
||||
/**
|
||||
* NMSettingVerifyResult:
|
||||
* @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully
|
||||
|
|
@ -174,13 +204,6 @@ NMSettingPriority _nm_setting_get_setting_priority (NMSetting *setting);
|
|||
|
||||
gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
|
||||
|
||||
/* NM_CONNECTION_SERIALIZE_NO_SYNTH: This flag is passed to _nm_setting_to_dbus()
|
||||
* by nm_setting_to_string() to let it know that it shouldn't serialize the
|
||||
* synthetic properties. It wouldn't be able to do so, since the full connection
|
||||
* is not available, only the setting alone.
|
||||
*/
|
||||
#define NM_CONNECTION_SERIALIZE_NO_SYNTH ((NMConnectionSerializationFlags) 0x80000000)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
GHashTable *_nm_setting_gendata_hash (NMSetting *setting,
|
||||
|
|
@ -589,9 +612,11 @@ typedef struct _NMSettInfoSetting NMSettInfoSetting;
|
|||
|
||||
typedef GVariant *(*NMSettingPropertyGetFunc) (NMSetting *setting,
|
||||
const char *property);
|
||||
typedef GVariant *(*NMSettingPropertySynthFunc) (NMSetting *setting,
|
||||
typedef GVariant *(*NMSettingPropertySynthFunc) (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property);
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags);
|
||||
typedef gboolean (*NMSettingPropertySetFunc) (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
|
|
@ -644,11 +669,39 @@ typedef struct {
|
|||
|
||||
struct _NMSettInfoSetting {
|
||||
NMSettingClass *setting_class;
|
||||
|
||||
/* the properties, sorted by property name. */
|
||||
const NMSettInfoProperty *property_infos;
|
||||
|
||||
/* the @property_infos list is sorted by property name. For some uses we need
|
||||
* a different sort order. If @property_infos_sorted is set, this is the order
|
||||
* instead. It is used for:
|
||||
*
|
||||
* - nm_setting_enumerate_values()
|
||||
* - keyfile writer adding keys to the group.
|
||||
*
|
||||
* Note that currently only NMSettingConnection implements here a sort order
|
||||
* that differs from alphabetical sort of the property names.
|
||||
*/
|
||||
const NMSettInfoProperty *const*property_infos_sorted;
|
||||
|
||||
guint property_infos_len;
|
||||
NMSettInfoSettDetail detail;
|
||||
};
|
||||
|
||||
static inline const NMSettInfoProperty *
|
||||
_nm_sett_info_property_info_get_sorted (const NMSettInfoSetting *sett_info,
|
||||
guint idx)
|
||||
{
|
||||
nm_assert (sett_info);
|
||||
nm_assert (idx < sett_info->property_infos_len);
|
||||
nm_assert (!sett_info->property_infos_sorted || sett_info->property_infos_sorted[idx]);
|
||||
|
||||
return sett_info->property_infos_sorted
|
||||
? sett_info->property_infos_sorted[idx]
|
||||
: &sett_info->property_infos[idx];
|
||||
}
|
||||
|
||||
const NMSettInfoSetting *_nm_sett_info_setting_get (NMSettingClass *setting_class);
|
||||
|
||||
const NMSettInfoProperty *_nm_sett_info_property_get (NMSettingClass *setting_class,
|
||||
|
|
|
|||
|
|
@ -179,11 +179,41 @@ nm_keyfile_plugin_kf_set_##stype (GKeyFile *kf, \
|
|||
}
|
||||
|
||||
DEFINE_KF_WRAPPER(string, char*, const char*);
|
||||
DEFINE_KF_WRAPPER(integer, int, int);
|
||||
DEFINE_KF_WRAPPER(uint64, guint64, guint64);
|
||||
DEFINE_KF_WRAPPER(boolean, gboolean, gboolean);
|
||||
DEFINE_KF_WRAPPER(value, char*, const char*);
|
||||
|
||||
gint64
|
||||
nm_keyfile_plugin_kf_get_int64 (GKeyFile *kf,
|
||||
const char *group,
|
||||
const char *key,
|
||||
guint base,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 fallback,
|
||||
GError **error)
|
||||
{
|
||||
gs_free char *s = NULL;
|
||||
int errsv;
|
||||
gint64 v;
|
||||
|
||||
s = nm_keyfile_plugin_kf_get_value (kf, group, key, error);
|
||||
if (!s) {
|
||||
errno = ENODATA;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
v = _nm_utils_ascii_str_to_int64 (s, base, min, max, fallback);
|
||||
errsv = errno;
|
||||
if ( errsv != 0
|
||||
&& error) {
|
||||
g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
|
||||
_("value is not an integer in range [%lld, %lld]"),
|
||||
(long long) min, (long long) max);
|
||||
errno = errsv;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
char **
|
||||
nm_keyfile_plugin_kf_get_keys (GKeyFile *kf,
|
||||
const char *group,
|
||||
|
|
|
|||
|
|
@ -67,12 +67,19 @@ void nm_keyfile_plugin_kf_set_##stype (GKeyFile *kf, \
|
|||
const char *key, \
|
||||
set_ctype value);
|
||||
DEFINE_KF_WRAPPER_PROTO(string, char*, const char*)
|
||||
DEFINE_KF_WRAPPER_PROTO(integer, int, int)
|
||||
DEFINE_KF_WRAPPER_PROTO(uint64, guint64, guint64)
|
||||
DEFINE_KF_WRAPPER_PROTO(boolean, gboolean, gboolean)
|
||||
DEFINE_KF_WRAPPER_PROTO(value, char*, const char*)
|
||||
|
||||
/* Misc */
|
||||
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,
|
||||
const char *group,
|
||||
gsize *out_length,
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ _handle_warn (KeyfileReaderInfo *info,
|
|||
_info->error == NULL; \
|
||||
})
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_secret_flags_persist_secret (NMSettingSecretFlags flags)
|
||||
{
|
||||
return flags == NM_SETTING_SECRET_FLAG_NONE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Some setting properties also contain setting names, such as
|
||||
* NMSettingConnection's 'type' property (which specifies the base type of the
|
||||
* connection, e.g. ethernet or wifi) or 'slave-type' (specifies type of slave
|
||||
|
|
@ -1375,55 +1384,119 @@ cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
|||
g_object_set (setting, key, bytes, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
_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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
static void
|
||||
parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
||||
{
|
||||
const char *setting_name = nm_setting_get_name (setting);
|
||||
NMSettingSerialParity parity;
|
||||
int int_val;
|
||||
gs_free char *str_val = NULL;
|
||||
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).
|
||||
*/
|
||||
int_val = nm_keyfile_plugin_kf_get_integer (info->keyfile, setting_name, key, NULL);
|
||||
if (!int_val) {
|
||||
str_val = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
|
||||
if (str_val) {
|
||||
if (str_val[0] && !str_val[1])
|
||||
int_val = str_val[0];
|
||||
else {
|
||||
/* This will hit the warning below */
|
||||
int_val = 'X';
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (!int_val)
|
||||
return;
|
||||
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid parity value '%s'"),
|
||||
tmp_str ?: "");
|
||||
return;
|
||||
|
||||
switch (int_val) {
|
||||
case 'E':
|
||||
case 'e':
|
||||
parity = NM_SETTING_SERIAL_PARITY_EVEN;
|
||||
break;
|
||||
case 'O':
|
||||
case 'o':
|
||||
parity = NM_SETTING_SERIAL_PARITY_ODD;
|
||||
break;
|
||||
case 'N':
|
||||
case 'n':
|
||||
parity = NM_SETTING_SERIAL_PARITY_NONE;
|
||||
break;
|
||||
default:
|
||||
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid parity value '%s'"),
|
||||
str_val ?: "");
|
||||
parity_good:
|
||||
nm_g_object_set_property_enum (G_OBJECT (setting), key, NM_TYPE_SETTING_SERIAL_PARITY, parity, &err);
|
||||
|
||||
out_err:
|
||||
if (!err)
|
||||
return;
|
||||
if ( err->domain == G_KEY_FILE_ERROR
|
||||
&& NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
|
||||
G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
|
||||
/* ignore such errors. The key is not present. */
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_set (setting, key, parity, NULL);
|
||||
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid setting: %s"), err->message);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1863,8 +1936,8 @@ write_hash_of_string (GKeyFile *file,
|
|||
|
||||
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;
|
||||
gboolean write_item = TRUE;
|
||||
|
||||
property = keys[i];
|
||||
|
||||
|
|
@ -1875,19 +1948,16 @@ write_hash_of_string (GKeyFile *file,
|
|||
if (vpn_secrets) {
|
||||
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
||||
|
||||
nm_setting_get_secret_flags (setting, property, &secret_flags, NULL);
|
||||
if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
|
||||
write_item = FALSE;
|
||||
if (!nm_setting_get_secret_flags (setting, property, &secret_flags, NULL))
|
||||
nm_assert_not_reached ();
|
||||
if (!_secret_flags_persist_secret (secret_flags))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (write_item) {
|
||||
gs_free char *to_free = NULL;
|
||||
|
||||
data = g_hash_table_lookup (hash, property);
|
||||
nm_keyfile_plugin_kf_set_string (file, group_name,
|
||||
nm_keyfile_key_encode (property, &to_free),
|
||||
data);
|
||||
}
|
||||
data = g_hash_table_lookup (hash, property);
|
||||
nm_keyfile_plugin_kf_set_string (file, group_name,
|
||||
nm_keyfile_key_encode (property, &to_free),
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2518,25 +2588,27 @@ _parse_info_find (NMSetting *setting,
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
read_one_setting_value (NMSetting *setting,
|
||||
const char *key,
|
||||
const GValue *value,
|
||||
GParamFlags flags,
|
||||
gpointer user_data)
|
||||
read_one_setting_value (KeyfileReaderInfo *info,
|
||||
NMSetting *setting,
|
||||
const NMSettInfoProperty *property_info)
|
||||
{
|
||||
KeyfileReaderInfo *info = user_data;
|
||||
GKeyFile *keyfile = info->keyfile;
|
||||
const char *setting_name;
|
||||
int errsv;
|
||||
GType type;
|
||||
gs_free_error GError *err = NULL;
|
||||
const ParseInfoProperty *pip;
|
||||
gs_free char *tmp_str = NULL;
|
||||
const char *setting_name;
|
||||
const char *key;
|
||||
GType type;
|
||||
guint64 u64;
|
||||
gint64 i64;
|
||||
|
||||
if (info->error)
|
||||
nm_assert (!info->error);
|
||||
nm_assert (property_info->param_spec);
|
||||
|
||||
if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
|
||||
return;
|
||||
|
||||
if (!(flags & G_PARAM_WRITABLE))
|
||||
return;
|
||||
key = property_info->param_spec->name;
|
||||
|
||||
pip = _parse_info_find (setting, key, &setting_name);
|
||||
|
||||
|
|
@ -2571,67 +2643,76 @@ read_one_setting_value (NMSetting *setting,
|
|||
return;
|
||||
}
|
||||
|
||||
type = G_VALUE_TYPE (value);
|
||||
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_name, key, NULL);
|
||||
g_object_set (setting, key, str_val, NULL);
|
||||
str_val = nm_keyfile_plugin_kf_get_string (keyfile, 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) {
|
||||
int int_val;
|
||||
|
||||
int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
|
||||
if (int_val < 0) {
|
||||
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid negative value (%i)"),
|
||||
int_val))
|
||||
return;
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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);
|
||||
}
|
||||
g_object_set (setting, key, int_val, NULL);
|
||||
} else if (type == G_TYPE_INT) {
|
||||
int int_val;
|
||||
|
||||
int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
|
||||
g_object_set (setting, key, int_val, NULL);
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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_name, key, NULL);
|
||||
g_object_set (setting, key, bool_val, NULL);
|
||||
bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, 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) {
|
||||
int int_val;
|
||||
|
||||
int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, NULL);
|
||||
if (int_val < G_MININT8 || int_val > G_MAXINT8) {
|
||||
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid char value (%i)"),
|
||||
int_val))
|
||||
return;
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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);
|
||||
}
|
||||
|
||||
g_object_set (setting, key, int_val, NULL);
|
||||
} else if (type == G_TYPE_UINT64) {
|
||||
gs_free char *tmp_str = NULL;
|
||||
guint64 uint_val;
|
||||
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
|
||||
uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
|
||||
g_object_set (setting, key, uint_val, NULL);
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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) {
|
||||
gs_free char *tmp_str = NULL;
|
||||
gint64 int_val;
|
||||
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, NULL);
|
||||
int_val = _nm_utils_ascii_str_to_int64 (tmp_str, 10, G_MININT64, G_MAXINT64, 0);
|
||||
errsv = errno;
|
||||
if (errsv) {
|
||||
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid int64 value (%s)"),
|
||||
tmp_str))
|
||||
return;
|
||||
} else
|
||||
g_object_set (setting, key, int_val, NULL);
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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) {
|
||||
gs_free int *tmp = NULL;
|
||||
GByteArray *array;
|
||||
|
|
@ -2673,32 +2754,40 @@ read_one_setting_value (NMSetting *setting,
|
|||
read_hash_of_string (keyfile, setting, key);
|
||||
} else if (type == G_TYPE_ARRAY) {
|
||||
read_array_of_uint (keyfile, setting, key);
|
||||
} else if (G_VALUE_HOLDS_FLAGS (value)) {
|
||||
guint64 uint_val;
|
||||
|
||||
/* Flags are guint but GKeyFile has no uint reader, just uint64 */
|
||||
uint_val = nm_keyfile_plugin_kf_get_uint64 (keyfile, setting_name, key, &err);
|
||||
} else if (G_TYPE_IS_FLAGS (type)) {
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_name, key, &err);
|
||||
if (!err) {
|
||||
if (uint_val <= G_MAXUINT)
|
||||
g_object_set (setting, key, (guint) uint_val, NULL);
|
||||
else {
|
||||
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("too large FLAGS property '%s' (%llu)"),
|
||||
G_VALUE_TYPE_NAME (value), (unsigned long long) uint_val))
|
||||
return;
|
||||
}
|
||||
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_VALUE_HOLDS_ENUM (value)) {
|
||||
int int_val;
|
||||
} else if (G_TYPE_IS_ENUM (type)) {
|
||||
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, 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 ();
|
||||
|
||||
int_val = nm_keyfile_plugin_kf_get_integer (keyfile, setting_name, key, &err);
|
||||
if (!err)
|
||||
g_object_set (setting, key, (int) int_val, NULL);
|
||||
} else {
|
||||
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("unhandled setting property type '%s'"),
|
||||
G_VALUE_TYPE_NAME (value)))
|
||||
return;
|
||||
if (err) {
|
||||
if ( err->domain == G_KEY_FILE_ERROR
|
||||
&& NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
|
||||
G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
|
||||
/* ignore such errors. The key is not present. */
|
||||
} else {
|
||||
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
||||
_("invalid setting: %s"), err->message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2709,6 +2798,7 @@ _read_setting (KeyfileReaderInfo *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)
|
||||
|
|
@ -2729,7 +2819,7 @@ _read_setting (KeyfileReaderInfo *info)
|
|||
|
||||
if (sett_info->detail.gendata_info) {
|
||||
gs_free char **keys = NULL;
|
||||
gsize i, n_keys;
|
||||
gsize k, n_keys;
|
||||
|
||||
keys = g_key_file_get_keys (info->keyfile, info->group, &n_keys, NULL);
|
||||
if (!keys)
|
||||
|
|
@ -2738,16 +2828,16 @@ _read_setting (KeyfileReaderInfo *info)
|
|||
GHashTable *h = _nm_setting_gendata_hash (setting, TRUE);
|
||||
|
||||
nm_utils_strv_sort (keys, n_keys);
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
gs_free char *key = keys[i];
|
||||
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 ( i + 1 < n_keys
|
||||
&& nm_streq (key, keys[i + 1]))
|
||||
if ( k + 1 < n_keys
|
||||
&& nm_streq (key, keys[k + 1]))
|
||||
continue;
|
||||
|
||||
/* currently, the API is very simple. The setting class just returns
|
||||
|
|
@ -2792,13 +2882,20 @@ _read_setting (KeyfileReaderInfo *info)
|
|||
g_steal_pointer (&key),
|
||||
g_variant_take_ref (variant));
|
||||
}
|
||||
for (; i < n_keys; i++)
|
||||
g_free (keys[i]);
|
||||
for (; k < n_keys; k++)
|
||||
g_free (keys[k]);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
nm_setting_enumerate_values (setting, read_one_setting_value, info);
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
||||
|
||||
if (property_info->param_spec) {
|
||||
read_one_setting_value (info, setting, property_info);
|
||||
if (info->error)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
info->setting = NULL;
|
||||
|
|
@ -2974,23 +3071,23 @@ out_with_info_error:
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
write_setting_value (NMSetting *setting,
|
||||
const char *key,
|
||||
const GValue *value,
|
||||
GParamFlags flag,
|
||||
gpointer user_data)
|
||||
write_setting_value (KeyfileWriterInfo *info,
|
||||
NMSetting *setting,
|
||||
const NMSettInfoProperty *property_info)
|
||||
{
|
||||
KeyfileWriterInfo *info = user_data;
|
||||
const char *setting_name;
|
||||
GType type;
|
||||
const ParseInfoProperty *pip;
|
||||
GParamSpec *pspec;
|
||||
const char *setting_name;
|
||||
const char *key;
|
||||
char numstr[64];
|
||||
GValue value;
|
||||
GType type;
|
||||
|
||||
if (info->error)
|
||||
nm_assert (!info->error);
|
||||
|
||||
if (!property_info->param_spec)
|
||||
return;
|
||||
|
||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key);
|
||||
nm_assert (pspec);
|
||||
key = property_info->param_spec->name;
|
||||
|
||||
pip = _parse_info_find (setting, key, &setting_name);
|
||||
|
||||
|
|
@ -3018,58 +3115,65 @@ write_setting_value (NMSetting *setting,
|
|||
* the secret flags there are in a third-level hash in the 'secrets'
|
||||
* property.
|
||||
*/
|
||||
if ( (pspec->flags & NM_SETTING_PARAM_SECRET)
|
||||
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_assert_not_reached ();
|
||||
if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
|
||||
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 (pspec, (GValue *) value)) {
|
||||
&& g_param_value_defaults (property_info->param_spec, &value)) {
|
||||
nm_assert (!g_key_file_has_key (info->keyfile, setting_name, key, NULL));
|
||||
return;
|
||||
goto out_unset_value;
|
||||
}
|
||||
|
||||
if (pip && pip->writer) {
|
||||
pip->writer (info, setting, key, value);
|
||||
return;
|
||||
pip->writer (info, setting, key, &value);
|
||||
goto out_unset_value;
|
||||
}
|
||||
|
||||
type = G_VALUE_TYPE (value);
|
||||
type = G_VALUE_TYPE (&value);
|
||||
if (type == G_TYPE_STRING) {
|
||||
const char *str;
|
||||
|
||||
str = g_value_get_string (value);
|
||||
str = g_value_get_string (&value);
|
||||
if (str)
|
||||
nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, str);
|
||||
} else if (type == G_TYPE_UINT)
|
||||
nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_uint (value));
|
||||
else if (type == G_TYPE_INT)
|
||||
nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, g_value_get_int (value));
|
||||
else if (type == G_TYPE_UINT64) {
|
||||
char numstr[30];
|
||||
|
||||
nm_sprintf_buf (numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64 (value));
|
||||
} 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_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_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_name, key, numstr);
|
||||
} else if (type == G_TYPE_INT64) {
|
||||
char numstr[30];
|
||||
|
||||
nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (value));
|
||||
nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (&value));
|
||||
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
|
||||
} else if (type == G_TYPE_BOOLEAN) {
|
||||
nm_keyfile_plugin_kf_set_boolean (info->keyfile, setting_name, key, g_value_get_boolean (value));
|
||||
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key,
|
||||
g_value_get_boolean (&value)
|
||||
? "true"
|
||||
: "false");
|
||||
} else if (type == G_TYPE_CHAR) {
|
||||
nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_schar (value));
|
||||
nm_sprintf_buf (numstr, "%d", (int) g_value_get_schar (&value));
|
||||
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_name, key, numstr);
|
||||
} else if (type == G_TYPE_BYTES) {
|
||||
GBytes *bytes;
|
||||
const guint8 *data;
|
||||
gsize len = 0;
|
||||
|
||||
bytes = g_value_get_boxed (value);
|
||||
bytes = g_value_get_boxed (&value);
|
||||
data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
|
||||
|
||||
if (data != NULL && len > 0)
|
||||
|
|
@ -3077,19 +3181,23 @@ write_setting_value (NMSetting *setting,
|
|||
} else if (type == G_TYPE_STRV) {
|
||||
char **array;
|
||||
|
||||
array = (char **) g_value_get_boxed (value);
|
||||
array = (char **) g_value_get_boxed (&value);
|
||||
nm_keyfile_plugin_kf_set_string_list (info->keyfile, 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);
|
||||
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)) {
|
||||
/* Flags are guint but GKeyFile has no uint reader, just uint64 */
|
||||
nm_keyfile_plugin_kf_set_uint64 (info->keyfile, setting_name, key, (guint64) g_value_get_flags (value));
|
||||
} else if (G_VALUE_HOLDS_ENUM (value))
|
||||
nm_keyfile_plugin_kf_set_integer (info->keyfile, setting_name, key, (int) g_value_get_enum (value));
|
||||
else
|
||||
g_warn_if_reached ();
|
||||
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_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_name, key, numstr);
|
||||
} else
|
||||
g_return_if_reached ();
|
||||
|
||||
out_unset_value:
|
||||
g_value_unset (&value);
|
||||
}
|
||||
|
||||
GKeyFile *
|
||||
|
|
@ -3101,7 +3209,7 @@ nm_keyfile_write (NMConnection *connection,
|
|||
gs_unref_keyfile GKeyFile *keyfile = NULL;
|
||||
KeyfileWriterInfo info;
|
||||
gs_free NMSetting **settings = NULL;
|
||||
guint i, n_settings = 0;
|
||||
guint i, j, n_settings = 0;
|
||||
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
||||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
|
|
@ -3159,18 +3267,20 @@ nm_keyfile_write (NMConnection *connection,
|
|||
}
|
||||
}
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
nm_setting_enumerate_values (setting, write_setting_value, &info);
|
||||
for (j = 0; j < sett_info->property_infos_len; j++) {
|
||||
const NMSettInfoProperty *property_info = _nm_sett_info_property_info_get_sorted (sett_info, j);
|
||||
|
||||
next:
|
||||
if (info.error)
|
||||
goto out_with_info_error;
|
||||
write_setting_value (&info, setting, property_info);
|
||||
if (info.error)
|
||||
goto out_with_info_error;
|
||||
}
|
||||
|
||||
nm_assert (!info.error);
|
||||
}
|
||||
|
||||
if (info.error)
|
||||
goto out_with_info_error;
|
||||
nm_assert (!info.error);
|
||||
|
||||
return g_steal_pointer (&keyfile);
|
||||
|
||||
|
|
|
|||
|
|
@ -376,9 +376,11 @@ ip4_addresses_set (NMSetting *setting,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
ip4_address_labels_get (NMSetting *setting,
|
||||
ip4_address_labels_get (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
|
||||
gboolean have_labels = FALSE;
|
||||
|
|
@ -386,6 +388,9 @@ ip4_address_labels_get (NMSetting *setting,
|
|||
GVariant *ret;
|
||||
int num_addrs, i;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
num_addrs = nm_setting_ip_config_get_num_addresses (s_ip);
|
||||
for (i = 0; i < num_addrs; i++) {
|
||||
NMIPAddress *addr = nm_setting_ip_config_get_address (s_ip, i);
|
||||
|
|
@ -414,18 +419,19 @@ ip4_address_labels_get (NMSetting *setting,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
ip4_address_data_get (NMSetting *setting,
|
||||
ip4_address_data_get (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
GVariant *ret;
|
||||
gs_unref_ptrarray GPtrArray *addrs = NULL;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
|
||||
ret = nm_utils_ip_addresses_to_variant (addrs);
|
||||
g_ptr_array_unref (addrs);
|
||||
|
||||
return ret;
|
||||
return nm_utils_ip_addresses_to_variant (addrs);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -486,18 +492,19 @@ ip4_routes_set (NMSetting *setting,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
ip4_route_data_get (NMSetting *setting,
|
||||
ip4_route_data_get (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
GVariant *ret;
|
||||
gs_unref_ptrarray GPtrArray *routes = NULL;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
|
||||
ret = nm_utils_ip_routes_to_variant (routes);
|
||||
g_ptr_array_unref (routes);
|
||||
|
||||
return ret;
|
||||
return nm_utils_ip_routes_to_variant (routes);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -374,18 +374,19 @@ ip6_addresses_set (NMSetting *setting,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
ip6_address_data_get (NMSetting *setting,
|
||||
ip6_address_data_get (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
GVariant *ret;
|
||||
gs_unref_ptrarray GPtrArray *addrs = NULL;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
|
||||
ret = nm_utils_ip_addresses_to_variant (addrs);
|
||||
g_ptr_array_unref (addrs);
|
||||
|
||||
return ret;
|
||||
return nm_utils_ip_addresses_to_variant (addrs);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -446,18 +447,19 @@ ip6_routes_set (NMSetting *setting,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
ip6_route_data_get (NMSetting *setting,
|
||||
ip6_route_data_get (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
GVariant *ret;
|
||||
gs_unref_ptrarray GPtrArray *routes = NULL;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
|
||||
ret = nm_utils_ip_routes_to_variant (routes);
|
||||
g_ptr_array_unref (routes);
|
||||
|
||||
return ret;
|
||||
return nm_utils_ip_routes_to_variant (routes);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@ gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting,
|
|||
|
||||
#define NM_SETTING_PARAM_GENDATA_BACKED (1 << (7 + G_PARAM_USER_SHIFT))
|
||||
|
||||
GVariant *_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
|
||||
GVariant *_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property);
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags);
|
||||
|
||||
NMSettingVerifyResult _nm_setting_verify (NMSetting *setting,
|
||||
NMConnection *connection,
|
||||
|
|
@ -95,6 +97,13 @@ gboolean _nm_setting_verify_secret_string (const char *str,
|
|||
const char *property,
|
||||
GError **error);
|
||||
|
||||
gboolean _nm_setting_aggregate (NMSetting *setting,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg);
|
||||
gboolean _nm_setting_vpn_aggregate (NMSettingVpn *setting,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg);
|
||||
|
||||
gboolean _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_type);
|
||||
|
||||
GVariant *_nm_setting_to_dbus (NMSetting *setting,
|
||||
|
|
@ -107,6 +116,11 @@ NMSetting *_nm_setting_new_from_dbus (GType setting_type,
|
|||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
|
||||
gboolean _nm_setting_property_is_regular_secret (NMSetting *setting,
|
||||
const char *secret_name);
|
||||
gboolean _nm_setting_property_is_regular_secret_flags (NMSetting *setting,
|
||||
const char *secret_flags_name);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline GArray *
|
||||
|
|
|
|||
|
|
@ -461,6 +461,66 @@ nm_setting_vpn_foreach_secret (NMSettingVpn *setting,
|
|||
foreach_item_helper (setting, TRUE, func, user_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_nm_setting_vpn_aggregate (NMSettingVpn *setting,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg)
|
||||
{
|
||||
NMSettingVpnPrivate *priv;
|
||||
NMSettingSecretFlags secret_flags;
|
||||
const char *key_name;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
|
||||
|
||||
priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
|
||||
if (g_hash_table_size (priv->secrets) > 0) {
|
||||
*((gboolean *) arg) = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->secrets);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &key_name, NULL)) {
|
||||
if (!nm_setting_get_secret_flags (NM_SETTING (setting), key_name, &secret_flags, NULL))
|
||||
nm_assert_not_reached ();
|
||||
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
||||
*((gboolean *) arg) = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok, we have no secrets with system-secret flags.
|
||||
* But do we have any secret-flags (without secrets) that indicate system secrets? */
|
||||
g_hash_table_iter_init (&iter, priv->data);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &key_name, NULL)) {
|
||||
gs_free char *secret_name = NULL;
|
||||
|
||||
if (!g_str_has_suffix (key_name, "-flags"))
|
||||
continue;
|
||||
secret_name = g_strndup (key_name, strlen (key_name) - NM_STRLEN ("-flags"));
|
||||
if (secret_name[0] == '\0')
|
||||
continue;
|
||||
if (!nm_setting_get_secret_flags (NM_SETTING (setting), secret_name, &secret_flags, NULL))
|
||||
nm_assert_not_reached ();
|
||||
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
||||
*((gboolean *) arg) = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_vpn_get_timeout:
|
||||
* @setting: the #NMSettingVpn
|
||||
|
|
@ -642,41 +702,52 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError
|
|||
static gboolean
|
||||
get_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags *out_flags,
|
||||
GError **error)
|
||||
{
|
||||
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
||||
gs_free char *flags_key = NULL;
|
||||
gpointer val;
|
||||
unsigned long tmp;
|
||||
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
||||
gs_free char *flags_key_free = NULL;
|
||||
const char *flags_key;
|
||||
const char *flags_val;
|
||||
gint64 i64;
|
||||
|
||||
flags_key = g_strdup_printf ("%s-flags", secret_name);
|
||||
if (g_hash_table_lookup_extended (priv->data, flags_key, NULL, &val)) {
|
||||
errno = 0;
|
||||
tmp = strtoul ((const char *) val, NULL, 10);
|
||||
if ((errno != 0) || (tmp > NM_SETTING_SECRET_FLAGS_ALL)) {
|
||||
g_set_error (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("failed to convert value '%s' to uint"),
|
||||
(const char *) val);
|
||||
flags_key = nm_construct_name_a ("%s-flags", secret_name, &flags_key_free);
|
||||
|
||||
if (!g_hash_table_lookup_extended (priv->data, flags_key, NULL, (gpointer *) &flags_val)) {
|
||||
NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
||||
|
||||
/* having no secret flag for the secret is fine, as long as there
|
||||
* is the secret itself... */
|
||||
if (!g_hash_table_contains (priv->secrets, secret_name)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
||||
_("secret flags property not found"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, flags_key);
|
||||
return FALSE;
|
||||
}
|
||||
flags = (NMSettingSecretFlags) tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (out_flags)
|
||||
*out_flags = flags;
|
||||
i64 = _nm_utils_ascii_str_to_int64 (flags_val, 10, 0, NM_SETTING_SECRET_FLAGS_ALL, -1);
|
||||
if ( i64 == -1
|
||||
|| !_nm_setting_secret_flags_valid (i64)) {
|
||||
/* The flags keys is set to an unexpected value. That is a configuration
|
||||
* error. Note that keys named "*-flags" are reserved for secrets. The user
|
||||
* must not use this for anything but secret flags. Hence, we cannot fail
|
||||
* to read the secret, we pretend that the secret flag is set to the default
|
||||
* NM_SETTING_SECRET_FLAG_NONE. */
|
||||
NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NM_SET_OUT (out_flags, (NMSettingSecretFlags) i64);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1177,53 +1177,56 @@ verify_secrets (NMSetting *setting, NMConnection *connection, GError **error)
|
|||
static gboolean
|
||||
get_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags *out_flags,
|
||||
GError **error)
|
||||
{
|
||||
NMSettingClass *setting_class;
|
||||
gboolean verify_override = verify_secret;
|
||||
NMSettingSecretFlags flags;
|
||||
|
||||
/* There's only one 'flags' property for WEP keys, so alias all the WEP key
|
||||
* property names to that flags property.
|
||||
*/
|
||||
if ( !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
|
||||
secret_name = "wep-key";
|
||||
verify_override = FALSE; /* Already know it's a secret */
|
||||
if (NM_IN_STRSET (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
|
||||
/* There's only one 'flags' property for WEP keys, so alias all the WEP key
|
||||
* property names to that flags property. */
|
||||
nm_assert (_nm_setting_property_is_regular_secret (setting, secret_name));
|
||||
nm_assert (_nm_setting_property_is_regular_secret_flags (setting, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS));
|
||||
|
||||
g_object_get (G_OBJECT (setting),
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
|
||||
&flags,
|
||||
NULL);
|
||||
NM_SET_OUT (out_flags, flags);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Chain up to superclass with modified key name */
|
||||
setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class);
|
||||
return setting_class->get_secret_flags (setting, secret_name, verify_override, out_flags, error);
|
||||
return NM_SETTING_CLASS (nm_setting_wireless_security_parent_class)->get_secret_flags (setting, secret_name, out_flags, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
NMSettingClass *setting_class;
|
||||
gboolean verify_override = verify_secret;
|
||||
if (NM_IN_STRSET (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
|
||||
/* There's only one 'flags' property for WEP keys, so alias all the WEP key
|
||||
* property names to that flags property. */
|
||||
nm_assert (_nm_setting_property_is_regular_secret (setting, secret_name));
|
||||
nm_assert (_nm_setting_property_is_regular_secret_flags (setting, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS));
|
||||
|
||||
/* There's only one 'flags' property for WEP keys, so alias all the WEP key
|
||||
* property names to that flags property.
|
||||
*/
|
||||
if ( !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY1)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY2)
|
||||
|| !g_strcmp0 (secret_name, NM_SETTING_WIRELESS_SECURITY_WEP_KEY3)) {
|
||||
secret_name = "wep-key";
|
||||
verify_override = FALSE; /* Already know it's a secret */
|
||||
if (!nm_g_object_set_property_flags (G_OBJECT (setting),
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS,
|
||||
NM_TYPE_SETTING_SECRET_FLAGS,
|
||||
flags,
|
||||
error))
|
||||
g_return_val_if_reached (FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Chain up to superclass with modified key name */
|
||||
setting_class = NM_SETTING_CLASS (nm_setting_wireless_security_parent_class);
|
||||
return setting_class->set_secret_flags (setting, secret_name, verify_override, flags, error);
|
||||
return NM_SETTING_CLASS (nm_setting_wireless_security_parent_class)->set_secret_flags (setting, secret_name, flags, error);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -949,14 +949,22 @@ compare_property (NMSetting *setting,
|
|||
/*****************************************************************************/
|
||||
|
||||
static GVariant *
|
||||
nm_setting_wireless_get_security (NMSetting *setting,
|
||||
nm_setting_wireless_get_security (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property_name)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
if (nm_connection_get_setting_wireless_security (connection))
|
||||
return g_variant_new_string (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
|
||||
else
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
if (!connection)
|
||||
return NULL;
|
||||
|
||||
if (!nm_connection_get_setting_wireless_security (connection))
|
||||
return NULL;
|
||||
|
||||
return g_variant_new_string (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -354,6 +354,77 @@ _properties_override_add_transform (GArray *properties_override,
|
|||
|
||||
static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM];
|
||||
|
||||
static int
|
||||
_property_infos_sort_cmp_setting_connection (gconstpointer p_a,
|
||||
gconstpointer p_b,
|
||||
gpointer user_data)
|
||||
{
|
||||
const NMSettInfoProperty *a = *((const NMSettInfoProperty *const*) p_a);
|
||||
const NMSettInfoProperty *b = *((const NMSettInfoProperty *const*) p_b);
|
||||
int c_name;
|
||||
|
||||
c_name = strcmp (a->name, b->name);
|
||||
nm_assert (c_name != 0);
|
||||
|
||||
#define CMP_AND_RETURN(n_a, n_b, name) \
|
||||
G_STMT_START { \
|
||||
gboolean _is = nm_streq (n_a, ""name); \
|
||||
\
|
||||
if ( _is \
|
||||
|| nm_streq (n_b, ""name)) \
|
||||
return _is ? -1 : 1; \
|
||||
} G_STMT_END
|
||||
|
||||
/* for [connection], report first id, uuid, type in that order. */
|
||||
if (c_name != 0) {
|
||||
CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_ID);
|
||||
CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_UUID);
|
||||
CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_TYPE);
|
||||
}
|
||||
|
||||
#undef CMP_AND_RETURN
|
||||
|
||||
return c_name;
|
||||
}
|
||||
|
||||
static const NMSettInfoProperty *const*
|
||||
_property_infos_sort (const NMSettInfoProperty *property_infos,
|
||||
guint property_infos_len,
|
||||
NMSettingClass *setting_class)
|
||||
{
|
||||
const NMSettInfoProperty **arr;
|
||||
guint i;
|
||||
|
||||
#if NM_MORE_ASSERTS > 5
|
||||
/* assert that the property names are all unique and sorted. */
|
||||
for (i = 0; i < property_infos_len; i++) {
|
||||
if (property_infos[i].param_spec)
|
||||
nm_assert (nm_streq (property_infos[i].name, property_infos[i].param_spec->name));
|
||||
if (i > 0)
|
||||
nm_assert (strcmp (property_infos[i - 1].name, property_infos[i].name) < 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (property_infos_len <= 1)
|
||||
return NULL;
|
||||
if (G_TYPE_FROM_CLASS (setting_class) != NM_TYPE_SETTING_CONNECTION) {
|
||||
/* we only do something special for certain setting types. This one,
|
||||
* has just alphabetical sorting. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arr = g_new (const NMSettInfoProperty *, property_infos_len);
|
||||
for (i = 0; i < property_infos_len; i++)
|
||||
arr[i] = &property_infos[i];
|
||||
|
||||
g_qsort_with_data (arr,
|
||||
property_infos_len,
|
||||
sizeof (const NMSettInfoProperty *),
|
||||
_property_infos_sort_cmp_setting_connection,
|
||||
NULL);
|
||||
return arr;
|
||||
}
|
||||
|
||||
void
|
||||
_nm_setting_class_commit_full (NMSettingClass *setting_class,
|
||||
NMMetaSettingType meta_type,
|
||||
|
|
@ -387,19 +458,21 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
|
|||
#if NM_MORE_ASSERTS > 10
|
||||
/* assert that properties_override is constructed consistently. */
|
||||
for (i = 0; i < override_len; i++) {
|
||||
guint j;
|
||||
const NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i);
|
||||
gboolean found = FALSE;
|
||||
guint j;
|
||||
|
||||
nm_assert (!_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data,
|
||||
i,
|
||||
p->name));
|
||||
for (j = 0; j < n_property_specs; j++) {
|
||||
if (nm_streq (property_specs[j]->name, p->name)) {
|
||||
nm_assert (p->param_spec == property_specs[j]);
|
||||
break;
|
||||
}
|
||||
if (!nm_streq (property_specs[j]->name, p->name))
|
||||
continue;
|
||||
nm_assert (!found);
|
||||
found = TRUE;
|
||||
nm_assert (p->param_spec == property_specs[j]);
|
||||
}
|
||||
nm_assert ((j == n_property_specs) == (p->param_spec == NULL));
|
||||
nm_assert (found == (p->param_spec != NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -429,6 +502,10 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class,
|
|||
sett_info->property_infos_len = properties_override->len;
|
||||
sett_info->property_infos = (const NMSettInfoProperty *) g_array_free (properties_override,
|
||||
properties_override->len == 0);
|
||||
|
||||
sett_info->property_infos_sorted = _property_infos_sort (sett_info->property_infos,
|
||||
sett_info->property_infos_len,
|
||||
setting_class);
|
||||
}
|
||||
|
||||
const NMSettInfoSetting *
|
||||
|
|
@ -662,10 +739,13 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
|
|||
if (!prop_spec) {
|
||||
if (!property->synth_func)
|
||||
continue;
|
||||
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
continue;
|
||||
} else {
|
||||
|
||||
/* For the moment, properties backed by a GObject property don't
|
||||
* define a synth function. There is no problem supporting that,
|
||||
* however, for now just disallow it. */
|
||||
nm_assert (!property->synth_func);
|
||||
|
||||
if (!(prop_spec->flags & G_PARAM_WRITABLE))
|
||||
continue;
|
||||
|
||||
|
|
@ -685,14 +765,10 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
|
|||
continue;
|
||||
}
|
||||
|
||||
if (property->synth_func) {
|
||||
if (!(flags & NM_CONNECTION_SERIALIZE_NO_SYNTH))
|
||||
dbus_value = property->synth_func (setting, connection, property->name);
|
||||
else
|
||||
dbus_value = NULL;
|
||||
} else {
|
||||
if (property->synth_func)
|
||||
dbus_value = property->synth_func (sett_info, i, connection, setting, flags);
|
||||
else
|
||||
dbus_value = get_property_for_dbus (setting, property, TRUE);
|
||||
}
|
||||
|
||||
if (dbus_value) {
|
||||
/* Allow dbus_value to be either floating or not. */
|
||||
|
|
@ -975,14 +1051,19 @@ _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue
|
|||
}
|
||||
|
||||
static void
|
||||
duplicate_setting (NMSetting *setting,
|
||||
const char *name,
|
||||
const GValue *value,
|
||||
GParamFlags flags,
|
||||
gpointer user_data)
|
||||
_gobject_copy_property (GObject *src,
|
||||
GObject *dst,
|
||||
const char *property_name,
|
||||
GType gtype)
|
||||
{
|
||||
if ((flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE)
|
||||
g_object_set_property (G_OBJECT (user_data), name, value);
|
||||
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
||||
|
||||
nm_assert (G_IS_OBJECT (src));
|
||||
nm_assert (G_IS_OBJECT (dst));
|
||||
|
||||
g_value_init (&value, gtype);
|
||||
g_object_get_property (src, property_name, &value);
|
||||
g_object_set_property (dst, property_name, &value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1023,11 +1104,35 @@ nm_setting_duplicate (NMSetting *setting)
|
|||
g_variant_ref (val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g_object_freeze_notify (dup);
|
||||
nm_setting_enumerate_values (setting, duplicate_setting, dup);
|
||||
g_object_thaw_notify (dup);
|
||||
}
|
||||
|
||||
if (sett_info->property_infos_len > 0) {
|
||||
gboolean frozen = FALSE;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
if ((prop_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
|
||||
continue;
|
||||
|
||||
if (!frozen) {
|
||||
g_object_freeze_notify (dup);
|
||||
frozen = TRUE;
|
||||
}
|
||||
|
||||
_gobject_copy_property (G_OBJECT (setting),
|
||||
dup,
|
||||
prop_spec->name,
|
||||
G_PARAM_SPEC_VALUE_TYPE (prop_spec));
|
||||
}
|
||||
|
||||
if (frozen)
|
||||
g_object_thaw_notify (dup);
|
||||
}
|
||||
|
||||
return NM_SETTING (dup);
|
||||
}
|
||||
|
||||
|
|
@ -1208,9 +1313,6 @@ nm_setting_compare (NMSetting *a,
|
|||
NMSettingCompareFlags flags)
|
||||
{
|
||||
const NMSettInfoSetting *sett_info;
|
||||
GParamSpec **property_specs;
|
||||
guint n_property_specs;
|
||||
int same = TRUE;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SETTING (a), FALSE);
|
||||
|
|
@ -1233,9 +1335,11 @@ nm_setting_compare (NMSetting *a,
|
|||
}
|
||||
|
||||
/* And now all properties */
|
||||
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
|
||||
for (i = 0; i < n_property_specs && same; i++) {
|
||||
GParamSpec *prop_spec = property_specs[i];
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
|
||||
/* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */
|
||||
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY)
|
||||
|
|
@ -1254,11 +1358,11 @@ nm_setting_compare (NMSetting *a,
|
|||
&& NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
|
||||
continue;
|
||||
|
||||
same = NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags);
|
||||
if (!NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags))
|
||||
return FALSE;
|
||||
}
|
||||
g_free (property_specs);
|
||||
|
||||
return same;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
|
|
@ -1447,15 +1551,13 @@ nm_setting_diff (NMSetting *a,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
gs_free GParamSpec **property_specs = NULL;
|
||||
guint n_property_specs;
|
||||
|
||||
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs);
|
||||
|
||||
for (i = 0; i < n_property_specs; i++) {
|
||||
GParamSpec *prop_spec = property_specs[i];
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
|
||||
/* Handle compare flags */
|
||||
if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags))
|
||||
continue;
|
||||
|
|
@ -1540,33 +1642,6 @@ nm_setting_diff (NMSetting *a,
|
|||
}
|
||||
}
|
||||
|
||||
#define CMP_AND_RETURN(n_a, n_b, name) \
|
||||
G_STMT_START { \
|
||||
gboolean _is = (strcmp (n_a, ""name) == 0); \
|
||||
\
|
||||
if (_is || (strcmp (n_b, ""name) == 0)) \
|
||||
return _is ? -1 : 1; \
|
||||
} G_STMT_END
|
||||
|
||||
static int
|
||||
_enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type)
|
||||
{
|
||||
const char *n_a = (*p_a)->name;
|
||||
const char *n_b = (*p_b)->name;
|
||||
int c = strcmp (n_a, n_b);
|
||||
|
||||
if (c) {
|
||||
if (*p_type == NM_TYPE_SETTING_CONNECTION) {
|
||||
/* for [connection], report first id, uuid, type in that order. */
|
||||
CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID);
|
||||
CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID);
|
||||
CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#undef CMP_AND_RETURN
|
||||
|
||||
/**
|
||||
* nm_setting_enumerate_values:
|
||||
* @setting: the #NMSetting
|
||||
|
|
@ -1582,10 +1657,7 @@ nm_setting_enumerate_values (NMSetting *setting,
|
|||
gpointer user_data)
|
||||
{
|
||||
const NMSettInfoSetting *sett_info;
|
||||
GParamSpec **property_specs;
|
||||
guint n_properties;
|
||||
guint i;
|
||||
GType type;
|
||||
|
||||
g_return_if_fail (NM_IS_SETTING (setting));
|
||||
g_return_if_fail (func != NULL);
|
||||
|
|
@ -1594,6 +1666,7 @@ nm_setting_enumerate_values (NMSetting *setting,
|
|||
|
||||
if (sett_info->detail.gendata_info) {
|
||||
const char *const*names;
|
||||
guint n_properties;
|
||||
|
||||
/* the properties of this setting are not real GObject properties.
|
||||
* Hence, this API makes little sense (or does it?). Still, call
|
||||
|
|
@ -1623,25 +1696,87 @@ nm_setting_enumerate_values (NMSetting *setting,
|
|||
return;
|
||||
}
|
||||
|
||||
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_properties);
|
||||
|
||||
/* sort the properties. This has an effect on the order in which keyfile
|
||||
* prints them. */
|
||||
type = G_OBJECT_TYPE (setting);
|
||||
g_qsort_with_data (property_specs, n_properties, sizeof (gpointer),
|
||||
(GCompareDataFunc) _enumerate_values_sort, &type);
|
||||
|
||||
for (i = 0; i < n_properties; i++) {
|
||||
GParamSpec *prop_spec = property_specs[i];
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = _nm_sett_info_property_info_get_sorted (sett_info, i)->param_spec;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
|
||||
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
|
||||
g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
|
||||
func (setting, prop_spec->name, &value, prop_spec->flags, user_data);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (property_specs);
|
||||
/**
|
||||
* _nm_setting_aggregate:
|
||||
* @setting: the #NMSetting to aggregate.
|
||||
* @type: the #NMConnectionAggregateType aggregate type.
|
||||
* @arg: the in/out arguments for aggregation. They depend on @type.
|
||||
*
|
||||
* This is the implementation detail of _nm_connection_aggregate(). It
|
||||
* makes no sense to call this function directly outside of _nm_connection_aggregate().
|
||||
*
|
||||
* Returns: %TRUE if afterwards the aggregation is complete. That means,
|
||||
* the only caller _nm_connection_aggregate() will not visit other settings
|
||||
* after a setting returns %TRUE (indicating that there is nothing further
|
||||
* to aggregate). Note that is very different from the boolean return
|
||||
* argument of _nm_connection_aggregate(), which serves a different purpose.
|
||||
*/
|
||||
gboolean
|
||||
_nm_setting_aggregate (NMSetting *setting,
|
||||
NMConnectionAggregateType type,
|
||||
gpointer arg)
|
||||
{
|
||||
const NMSettInfoSetting *sett_info;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
||||
g_return_val_if_fail (arg, FALSE);
|
||||
g_return_val_if_fail (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS,
|
||||
NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS),
|
||||
FALSE);
|
||||
|
||||
if (NM_IS_SETTING_VPN (setting))
|
||||
return _nm_setting_vpn_aggregate (NM_SETTING_VPN (setting), type, arg);
|
||||
|
||||
sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
||||
NMSettingSecretFlags secret_flags;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
if (!NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
|
||||
continue;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
|
||||
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec));
|
||||
g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
|
||||
if (!g_param_value_defaults (prop_spec, &value)) {
|
||||
*((gboolean *) arg) = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
|
||||
if (!nm_setting_get_secret_flags (setting, prop_spec->name, &secret_flags, NULL))
|
||||
nm_assert_not_reached ();
|
||||
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
||||
*((gboolean *) arg) = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1657,16 +1792,18 @@ nm_setting_enumerate_values (NMSetting *setting,
|
|||
gboolean
|
||||
_nm_setting_clear_secrets (NMSetting *setting)
|
||||
{
|
||||
gs_free GParamSpec **property_specs = NULL;
|
||||
guint n_property_specs;
|
||||
guint i;
|
||||
const NMSettInfoSetting *sett_info;
|
||||
gboolean changed = FALSE;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
||||
|
||||
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
|
||||
for (i = 0; i < n_property_specs; i++) {
|
||||
GParamSpec *prop_spec = property_specs[i];
|
||||
sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
|
||||
if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
|
@ -1731,23 +1868,27 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting,
|
|||
NMSettingClearSecretsWithFlagsFn func,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_free GParamSpec **property_specs = NULL;
|
||||
guint n_property_specs;
|
||||
guint i;
|
||||
const NMSettInfoSetting *sett_info;
|
||||
gboolean changed = FALSE;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (setting, FALSE);
|
||||
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
||||
g_return_val_if_fail (func != NULL, FALSE);
|
||||
|
||||
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
|
||||
for (i = 0; i < n_property_specs; i++) {
|
||||
if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) {
|
||||
changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
|
||||
property_specs[i],
|
||||
func,
|
||||
user_data);
|
||||
}
|
||||
sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting));
|
||||
for (i = 0; i < sett_info->property_infos_len; i++) {
|
||||
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
|
||||
|
||||
if (!prop_spec)
|
||||
continue;
|
||||
|
||||
if (!NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
|
||||
continue;
|
||||
|
||||
changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
|
||||
prop_spec,
|
||||
func,
|
||||
user_data);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
|
@ -1872,52 +2013,72 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro
|
|||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
|
||||
static void
|
||||
_set_error_secret_property_not_found (GError **error,
|
||||
NMSetting *setting,
|
||||
const char *secret_name)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
|
||||
_("not a secret property"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_nm_setting_property_is_regular_secret (NMSetting *setting,
|
||||
const char *secret_name)
|
||||
{
|
||||
const NMSettInfoProperty *property;
|
||||
GParamSpec *pspec;
|
||||
|
||||
nm_assert (NM_IS_SETTING (setting));
|
||||
nm_assert (secret_name);
|
||||
|
||||
property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), secret_name);
|
||||
if (!property) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
|
||||
_("secret is not set"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
|
||||
return FALSE;
|
||||
}
|
||||
return property
|
||||
&& property->param_spec
|
||||
&& NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET);
|
||||
}
|
||||
|
||||
pspec = property->param_spec;
|
||||
if (!pspec || !(pspec->flags & NM_SETTING_PARAM_SECRET)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
||||
_("not a secret property"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name);
|
||||
return FALSE;
|
||||
}
|
||||
gboolean
|
||||
_nm_setting_property_is_regular_secret_flags (NMSetting *setting,
|
||||
const char *secret_flags_name)
|
||||
{
|
||||
const NMSettInfoProperty *property;
|
||||
|
||||
return TRUE;
|
||||
nm_assert (NM_IS_SETTING (setting));
|
||||
nm_assert (secret_flags_name);
|
||||
|
||||
property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), secret_flags_name);
|
||||
return property
|
||||
&& property->param_spec
|
||||
&& !NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET)
|
||||
&& G_PARAM_SPEC_VALUE_TYPE (property->param_spec) == NM_TYPE_SETTING_SECRET_FLAGS;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags *out_flags,
|
||||
GError **error)
|
||||
{
|
||||
gs_free char *name_to_free = NULL;
|
||||
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
||||
gs_free char *secret_flags_name_free = NULL;
|
||||
const char *secret_flags_name;
|
||||
NMSettingSecretFlags flags;
|
||||
|
||||
if (verify_secret && !is_secret_prop (setting, secret_name, error)) {
|
||||
if (!_nm_setting_property_is_regular_secret (setting,
|
||||
secret_name)) {
|
||||
_set_error_secret_property_not_found (error, setting, secret_name);
|
||||
NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free);
|
||||
|
||||
nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name));
|
||||
|
||||
g_object_get (G_OBJECT (setting),
|
||||
nm_construct_name_a ("%s-flags", secret_name, &name_to_free),
|
||||
secret_flags_name,
|
||||
&flags,
|
||||
NULL);
|
||||
NM_SET_OUT (out_flags, flags);
|
||||
|
|
@ -1946,25 +2107,34 @@ nm_setting_get_secret_flags (NMSetting *setting,
|
|||
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
||||
g_return_val_if_fail (secret_name != NULL, FALSE);
|
||||
|
||||
return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error);
|
||||
return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, out_flags, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_secret_flags (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
gs_free char *name_to_free = NULL;
|
||||
gs_free char *secret_flags_name_free = NULL;
|
||||
const char *secret_flags_name;
|
||||
|
||||
if (verify_secret)
|
||||
g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE);
|
||||
if (!_nm_setting_property_is_regular_secret (setting,
|
||||
secret_name)) {
|
||||
_set_error_secret_property_not_found (error, setting, secret_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_set (G_OBJECT (setting),
|
||||
nm_construct_name_a ("%s-flags", secret_name, &name_to_free),
|
||||
flags,
|
||||
NULL);
|
||||
secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free);
|
||||
|
||||
nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name));
|
||||
|
||||
if (!nm_g_object_set_property_flags (G_OBJECT (setting),
|
||||
secret_flags_name,
|
||||
NM_TYPE_SETTING_SECRET_FLAGS,
|
||||
flags,
|
||||
error))
|
||||
g_return_val_if_reached (FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1989,9 +2159,9 @@ nm_setting_set_secret_flags (NMSetting *setting,
|
|||
{
|
||||
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
||||
g_return_val_if_fail (secret_name != NULL, FALSE);
|
||||
g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE);
|
||||
g_return_val_if_fail (_nm_setting_secret_flags_valid (flags), FALSE);
|
||||
|
||||
return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error);
|
||||
return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, flags, error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2018,8 +2188,7 @@ nm_setting_to_string (NMSetting *setting)
|
|||
string = g_string_new (nm_setting_get_name (setting));
|
||||
g_string_append_c (string, '\n');
|
||||
|
||||
variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL
|
||||
| NM_CONNECTION_SERIALIZE_NO_SYNTH);
|
||||
variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL);
|
||||
|
||||
g_variant_iter_init (&iter, variant);
|
||||
while ((child = g_variant_iter_next_value (&iter))) {
|
||||
|
|
@ -2037,9 +2206,11 @@ nm_setting_to_string (NMSetting *setting)
|
|||
}
|
||||
|
||||
GVariant *
|
||||
_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting,
|
||||
_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
NMSettingConnection *s_con;
|
||||
|
||||
|
|
|
|||
|
|
@ -191,13 +191,11 @@ typedef struct {
|
|||
|
||||
gboolean (*get_secret_flags) (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags *out_flags,
|
||||
GError **error);
|
||||
|
||||
gboolean (*set_secret_flags) (NMSetting *setting,
|
||||
const char *secret_name,
|
||||
gboolean verify_secret,
|
||||
NMSettingSecretFlags flags,
|
||||
GError **error);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,9 +56,11 @@ gboolean _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
|
|||
const char *property,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
GVariant * _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
|
||||
GVariant * _nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property);
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags);
|
||||
gboolean _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
|
|
|
|||
|
|
@ -4234,13 +4234,18 @@ _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
|
|||
}
|
||||
|
||||
GVariant *
|
||||
_nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
|
||||
_nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
|
||||
guint property_idx,
|
||||
NMConnection *connection,
|
||||
const char *property)
|
||||
NMSetting *setting,
|
||||
NMConnectionSerializationFlags flags)
|
||||
{
|
||||
gs_free char *addr = NULL;
|
||||
|
||||
nm_assert (nm_streq0 (property, "assigned-mac-address"));
|
||||
if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
|
||||
return NULL;
|
||||
|
||||
nm_assert (nm_streq0 (sett_info->property_infos[property_idx].name, "assigned-mac-address"));
|
||||
|
||||
g_object_get (setting,
|
||||
"cloned-mac-address",
|
||||
|
|
@ -4261,7 +4266,9 @@ _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
|
|||
* To preserve that behavior, serialize "" as NULL.
|
||||
*/
|
||||
|
||||
return addr && addr[0] ? g_variant_new_string (addr) : NULL;
|
||||
return addr && addr[0]
|
||||
? g_variant_new_take_string (g_steal_pointer (&addr))
|
||||
: NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
|||
|
|
@ -755,10 +755,12 @@ vpn_check_empty_func (const char *key, const char *value, gpointer user_data)
|
|||
static void
|
||||
test_setting_vpn_items (void)
|
||||
{
|
||||
gs_unref_object NMSettingVpn *s_vpn = NULL;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMSettingVpn *s_vpn;
|
||||
|
||||
s_vpn = (NMSettingVpn *) nm_setting_vpn_new ();
|
||||
g_assert (s_vpn);
|
||||
connection = nmtst_create_minimal_connection ("vpn-items", NULL, NM_SETTING_VPN_SETTING_NAME, NULL);
|
||||
|
||||
s_vpn = nm_connection_get_setting_vpn (connection);
|
||||
|
||||
nm_setting_vpn_add_data_item (s_vpn, "foobar1", "blahblah1");
|
||||
nm_setting_vpn_add_data_item (s_vpn, "foobar2", "blahblah2");
|
||||
|
|
@ -772,7 +774,14 @@ test_setting_vpn_items (void)
|
|||
nm_setting_vpn_remove_data_item (s_vpn, "foobar3");
|
||||
nm_setting_vpn_remove_data_item (s_vpn, "foobar4");
|
||||
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_add_secret (s_vpn, "foobar1", "blahblah1");
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_add_secret (s_vpn, "foobar2", "blahblah2");
|
||||
nm_setting_vpn_add_secret (s_vpn, "foobar3", "blahblah3");
|
||||
nm_setting_vpn_add_secret (s_vpn, "foobar4", "blahblah4");
|
||||
|
|
@ -782,8 +791,25 @@ test_setting_vpn_items (void)
|
|||
nm_setting_vpn_remove_secret (s_vpn, "foobar1");
|
||||
nm_setting_vpn_remove_secret (s_vpn, "foobar2");
|
||||
nm_setting_vpn_remove_secret (s_vpn, "foobar3");
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_add_data_item (s_vpn, "foobar4-flags", "blahblah4");
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_add_data_item (s_vpn, "foobar4-flags", "2");
|
||||
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_remove_secret (s_vpn, "foobar4");
|
||||
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
nm_setting_vpn_remove_data_item (s_vpn, "foobar4-flags");
|
||||
|
||||
/* Try to add some blank values and make sure they are rejected */
|
||||
NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL));
|
||||
nm_setting_vpn_add_data_item (s_vpn, NULL, NULL);
|
||||
|
|
@ -1632,6 +1658,25 @@ test_connection_to_dbus_setting_name (void)
|
|||
s_wsec = make_test_wsec_setting ("connection-to-dbus-setting-name");
|
||||
nm_connection_add_setting (connection, NM_SETTING (s_wsec));
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
g_object_set (s_wsec,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
||||
NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
|
||||
NULL);
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (!_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
g_object_set (s_wsec,
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, NM_SETTING_SECRET_FLAG_NONE,
|
||||
NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NONE,
|
||||
NULL);
|
||||
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL));
|
||||
g_assert (_nm_connection_aggregate (connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL));
|
||||
|
||||
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
|
||||
|
||||
/* Make sure the keys of the first level dict are setting names, not
|
||||
|
|
|
|||
|
|
@ -45,6 +45,77 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* converts @dict to a connection. In this case, @dict must be good, without warnings, so that
|
||||
* NM_SETTING_PARSE_FLAGS_STRICT and NM_SETTING_PARSE_FLAGS_BEST_EFFORT yield the exact same results. */
|
||||
static NMConnection *
|
||||
_connection_new_from_dbus_strict (GVariant *dict,
|
||||
gboolean normalize)
|
||||
{
|
||||
gs_unref_object NMConnection *con_x_0 = NULL;
|
||||
gs_unref_object NMConnection *con_x_s = NULL;
|
||||
gs_unref_object NMConnection *con_x_e = NULL;
|
||||
gs_unref_object NMConnection *con_n_0 = NULL;
|
||||
gs_unref_object NMConnection *con_n_s = NULL;
|
||||
gs_unref_object NMConnection *con_n_e = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
guint i;
|
||||
|
||||
g_assert (g_variant_is_of_type (dict, NM_VARIANT_TYPE_CONNECTION));
|
||||
|
||||
con_x_0 = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_x_0), error);
|
||||
|
||||
con_x_s = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_STRICT, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_x_s), error);
|
||||
|
||||
con_x_e = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_x_e), error);
|
||||
|
||||
con_n_0 = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_n_0), error);
|
||||
|
||||
con_n_s = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_n_s), error);
|
||||
|
||||
con_n_e = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT | NM_SETTING_PARSE_FLAGS_NORMALIZE, &error);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con_n_e), error);
|
||||
|
||||
nmtst_assert_connection_verifies (con_x_0);
|
||||
nmtst_assert_connection_verifies (con_x_e);
|
||||
nmtst_assert_connection_verifies (con_x_s);
|
||||
|
||||
nmtst_assert_connection_verifies_without_normalization (con_n_0);
|
||||
nmtst_assert_connection_verifies_without_normalization (con_n_e);
|
||||
nmtst_assert_connection_verifies_without_normalization (con_n_s);
|
||||
|
||||
/* randomly compare some pairs that we created. They must all be equal,
|
||||
* after accounting for normalization. */
|
||||
for (i = 0; i < 10; i++) {
|
||||
NMConnection *cons[] = { con_x_0, con_x_s, con_x_e, con_n_0, con_n_s, con_n_e };
|
||||
guint idx_a = (nmtst_get_rand_int () % G_N_ELEMENTS (cons));
|
||||
guint idx_b = (nmtst_get_rand_int () % G_N_ELEMENTS (cons));
|
||||
gboolean normalize_a, normalize_b;
|
||||
|
||||
if (idx_a <= 2 && idx_b <= 2) {
|
||||
normalize_a = nmtst_get_rand_bool ();
|
||||
normalize_b = normalize_a;
|
||||
} else if (idx_a > 2 && idx_b > 2) {
|
||||
normalize_a = nmtst_get_rand_bool ();
|
||||
normalize_b = nmtst_get_rand_bool ();
|
||||
} else {
|
||||
normalize_a = (idx_a <= 2) ? TRUE : nmtst_get_rand_bool ();
|
||||
normalize_b = (idx_b <= 2) ? TRUE : nmtst_get_rand_bool ();
|
||||
}
|
||||
nmtst_assert_connection_equals (cons[idx_a], normalize_a, cons[idx_b], normalize_b);
|
||||
}
|
||||
|
||||
return (normalize)
|
||||
? g_steal_pointer (&con_x_0)
|
||||
: g_steal_pointer (&con_n_0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
compare_blob_data (const char *test,
|
||||
const char *key_path,
|
||||
|
|
@ -1943,6 +2014,176 @@ test_tc_config_dbus (void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_roundtrip_conversion (gconstpointer test_data)
|
||||
{
|
||||
const int MODE = GPOINTER_TO_INT (test_data);
|
||||
const char *ID= nm_sprintf_bufa (100, "roundtip-conversion-%d", MODE);
|
||||
const char *UUID= "63376701-b61e-4318-bf7e-664a1c1eeaab";
|
||||
const char *INTERFACE_NAME = nm_sprintf_bufa (100, "ifname%d", MODE);
|
||||
guint32 ETH_MTU = nmtst_rand_select ((guint32) 0u,
|
||||
nmtst_get_rand_int ());
|
||||
gs_unref_ptrarray GPtrArray *kf_data_arr = g_ptr_array_new_with_free_func (g_free);
|
||||
const NMConnectionSerializationFlags dbus_serialization_flags[] = {
|
||||
NM_CONNECTION_SERIALIZE_ALL,
|
||||
NM_CONNECTION_SERIALIZE_NO_SECRETS,
|
||||
NM_CONNECTION_SERIALIZE_ONLY_SECRETS,
|
||||
};
|
||||
guint dbus_serialization_flags_idx;
|
||||
gs_unref_object NMConnection *con = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
guint kf_data_idx;
|
||||
NMSettingConnection *s_con = NULL;
|
||||
NMSettingWired *s_eth = NULL;
|
||||
|
||||
switch (MODE) {
|
||||
case 0:
|
||||
con = nmtst_create_minimal_connection (ID, UUID, NM_SETTING_WIRED_SETTING_NAME, &s_con);
|
||||
g_object_set (s_con,
|
||||
NM_SETTING_CONNECTION_INTERFACE_NAME,
|
||||
INTERFACE_NAME,
|
||||
NULL);
|
||||
nmtst_connection_normalize (con);
|
||||
|
||||
s_eth = NM_SETTING_WIRED (nm_connection_get_setting (con, NM_TYPE_SETTING_WIRED));
|
||||
g_assert (NM_IS_SETTING_WIRED (s_eth));
|
||||
|
||||
g_object_set (s_eth,
|
||||
NM_SETTING_WIRED_MTU,
|
||||
ETH_MTU,
|
||||
NULL);
|
||||
|
||||
g_ptr_array_add (kf_data_arr,
|
||||
g_strdup_printf ("[connection]\n"
|
||||
"id=%s\n"
|
||||
"uuid=%s\n"
|
||||
"type=ethernet\n"
|
||||
"interface-name=%s\n"
|
||||
"permissions=\n"
|
||||
"\n"
|
||||
"[ethernet]\n"
|
||||
"mac-address-blacklist=\n"
|
||||
"%s" /* mtu */
|
||||
"\n"
|
||||
"[ipv4]\n"
|
||||
"dns-search=\n"
|
||||
"method=auto\n"
|
||||
"\n"
|
||||
"[ipv6]\n"
|
||||
"addr-gen-mode=stable-privacy\n"
|
||||
"dns-search=\n"
|
||||
"method=auto\n"
|
||||
"",
|
||||
ID,
|
||||
UUID,
|
||||
INTERFACE_NAME,
|
||||
(ETH_MTU != 0)
|
||||
? nm_sprintf_bufa (100, "mtu=%u\n", ETH_MTU)
|
||||
: ""));
|
||||
|
||||
g_ptr_array_add (kf_data_arr,
|
||||
g_strdup_printf ("[connection]\n"
|
||||
"id=%s\n"
|
||||
"uuid=%s\n"
|
||||
"type=ethernet\n"
|
||||
"interface-name=%s\n"
|
||||
"permissions=\n"
|
||||
"\n"
|
||||
"[ethernet]\n"
|
||||
"mac-address-blacklist=\n"
|
||||
"%s" /* mtu */
|
||||
"\n"
|
||||
"[ipv4]\n"
|
||||
"dns-search=\n"
|
||||
"method=auto\n"
|
||||
"\n"
|
||||
"[ipv6]\n"
|
||||
"addr-gen-mode=stable-privacy\n"
|
||||
"dns-search=\n"
|
||||
"method=auto\n"
|
||||
"",
|
||||
ID,
|
||||
UUID,
|
||||
INTERFACE_NAME,
|
||||
(ETH_MTU != 0)
|
||||
? nm_sprintf_bufa (100, "mtu=%d\n", (int) ETH_MTU)
|
||||
: ""));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* the first kf_data_arr entry is special: it is the exact result of what we expect
|
||||
* when converting @con to keyfile. Write @con to keyfile and compare the expected result
|
||||
* literally. */
|
||||
{
|
||||
gs_unref_keyfile GKeyFile *kf = NULL;
|
||||
|
||||
kf = nm_keyfile_write (con, NULL, NULL, &error);
|
||||
nmtst_assert_success (kf, error);
|
||||
|
||||
/* the first kf_data_arr entry is special: it must be what the writer would
|
||||
* produce again. */
|
||||
nmtst_keyfile_assert_data (kf, kf_data_arr->pdata[0], -1);
|
||||
}
|
||||
|
||||
/* check that reading any of kf_data_arr yields the same result that we expect. */
|
||||
for (kf_data_idx = 0; kf_data_idx < kf_data_arr->len; kf_data_idx++) {
|
||||
gs_unref_object NMConnection *con2 = NULL;
|
||||
NMSettingWired *s_eth2 = NULL;
|
||||
|
||||
con2 = nmtst_create_connection_from_keyfile (kf_data_arr->pdata[kf_data_idx], "/no/where/file.nmconnection");
|
||||
|
||||
switch (MODE) {
|
||||
case 0:
|
||||
s_eth2 = NM_SETTING_WIRED (nm_connection_get_setting (con2, NM_TYPE_SETTING_WIRED));
|
||||
g_assert (NM_IS_SETTING_WIRED (s_eth2));
|
||||
|
||||
if ( ETH_MTU > (guint32) G_MAXINT
|
||||
&& kf_data_idx == 1) {
|
||||
/* older versions wrote values > 2^21 as signed integers, but the reader would
|
||||
* always reject such negative values for G_TYPE_UINT.
|
||||
*
|
||||
* The test case kf_data_idx #1 still writes the values in the old style.
|
||||
* The behavior was fixed, but such values are still rejected as invalid.
|
||||
*
|
||||
* Patch the setting so that the comparison below succeeds are usual. */
|
||||
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, 0);
|
||||
g_object_set (s_eth2,
|
||||
NM_SETTING_WIRED_MTU,
|
||||
ETH_MTU,
|
||||
NULL);
|
||||
}
|
||||
|
||||
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth), ==, ETH_MTU);
|
||||
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, ETH_MTU);
|
||||
break;
|
||||
}
|
||||
|
||||
nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ());
|
||||
}
|
||||
|
||||
for (dbus_serialization_flags_idx = 0; dbus_serialization_flags_idx < G_N_ELEMENTS (dbus_serialization_flags); dbus_serialization_flags_idx++) {
|
||||
NMConnectionSerializationFlags flag = dbus_serialization_flags[dbus_serialization_flags_idx];
|
||||
gs_unref_variant GVariant *con_var = NULL;
|
||||
gs_unref_object NMConnection *con2 = NULL;
|
||||
|
||||
con_var = nm_connection_to_dbus (con, flag);
|
||||
g_assert (g_variant_is_of_type (con_var, NM_VARIANT_TYPE_CONNECTION));
|
||||
g_assert (g_variant_is_floating (con_var));
|
||||
g_variant_ref_sink (con_var);
|
||||
|
||||
if (flag == NM_CONNECTION_SERIALIZE_ALL) {
|
||||
con2 = _connection_new_from_dbus_strict (con_var, TRUE);
|
||||
nmtst_assert_connection_equals (con, nmtst_get_rand_bool (), con2, nmtst_get_rand_bool ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE ();
|
||||
|
||||
int
|
||||
|
|
@ -2019,5 +2260,7 @@ main (int argc, char **argv)
|
|||
g_test_add_func ("/libnm/settings/team-port/sycn_from_config_full", test_team_port_full_config);
|
||||
#endif
|
||||
|
||||
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ libnm-core/nm-crypto-gnutls.c
|
|||
libnm-core/nm-crypto-nss.c
|
||||
libnm-core/nm-connection.c
|
||||
libnm-core/nm-dbus-utils.c
|
||||
libnm-core/nm-keyfile-utils.c
|
||||
libnm-core/nm-keyfile.c
|
||||
libnm-core/nm-setting-6lowpan.c
|
||||
libnm-core/nm-setting-8021x.c
|
||||
|
|
|
|||
|
|
@ -538,4 +538,28 @@ _nm_g_variant_new_printf (const char *format_string, ...)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#if !GLIB_CHECK_VERSION (2, 47, 1)
|
||||
/* Older versions of g_value_unset() only allowed to unset a GValue which
|
||||
* was initialized previously. This was relaxed ([1], [2], [3]).
|
||||
*
|
||||
* Our nm_auto_unset_gvalue macro requires to be able to call g_value_unset().
|
||||
* Also, it is our general practice to allow for that. Add a compat implementation.
|
||||
*
|
||||
* [1] https://gitlab.gnome.org/GNOME/glib/commit/4b2d92a864f1505f1b08eb639d74293fa32681da
|
||||
* [2] commit "Allow passing unset GValues to g_value_unset()"
|
||||
* [3] https://bugzilla.gnome.org/show_bug.cgi?id=755766
|
||||
*/
|
||||
static inline void
|
||||
_nm_g_value_unset (GValue *value)
|
||||
{
|
||||
g_return_if_fail (value);
|
||||
|
||||
if (value->g_type != 0)
|
||||
g_value_unset (value);
|
||||
}
|
||||
#define g_value_unset _nm_g_value_unset
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NM_GLIB_H__ */
|
||||
|
|
|
|||
|
|
@ -829,6 +829,9 @@ fcn (void) \
|
|||
#define nm_streq(s1, s2) (strcmp (s1, s2) == 0)
|
||||
#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0)
|
||||
|
||||
#define NM_STR_HAS_PREFIX(str, prefix) \
|
||||
(strncmp ((str), ""prefix"", NM_STRLEN (prefix)) == 0)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline GString *
|
||||
|
|
|
|||
|
|
@ -1108,7 +1108,7 @@ nm_utils_error_is_notfound (GError *error)
|
|||
*/
|
||||
gboolean
|
||||
nm_g_object_set_property (GObject *object,
|
||||
const char *property_name,
|
||||
const char *property_name,
|
||||
const GValue *value,
|
||||
GError **error)
|
||||
{
|
||||
|
|
@ -1181,17 +1181,90 @@ nm_g_object_set_property (GObject *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#define _set_property(object, property_name, gtype, gtype_set, value, error) \
|
||||
G_STMT_START { \
|
||||
nm_auto_unset_gvalue GValue gvalue = { 0 }; \
|
||||
\
|
||||
g_value_init (&gvalue, gtype); \
|
||||
gtype_set (&gvalue, (value)); \
|
||||
return nm_g_object_set_property ((object), (property_name), &gvalue, (error)); \
|
||||
} G_STMT_END
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_string (GObject *object,
|
||||
const char *property_name,
|
||||
const char *value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_STRING, g_value_set_string, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_string_static (GObject *object,
|
||||
const char *property_name,
|
||||
const char *value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_string_take (GObject *object,
|
||||
const char *property_name,
|
||||
char *value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_STRING, g_value_take_string, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_boolean (GObject *object,
|
||||
const char *property_name,
|
||||
const char *property_name,
|
||||
gboolean value,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unset_gvalue GValue gvalue = { 0 };
|
||||
_set_property (object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error);
|
||||
}
|
||||
|
||||
g_value_init (&gvalue, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&gvalue, !!value);
|
||||
return nm_g_object_set_property (object, property_name, &gvalue, error);
|
||||
gboolean
|
||||
nm_g_object_set_property_char (GObject *object,
|
||||
const char *property_name,
|
||||
gint8 value,
|
||||
GError **error)
|
||||
{
|
||||
/* glib says about G_TYPE_CHAR:
|
||||
*
|
||||
* The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer.
|
||||
*
|
||||
* This is always a (signed!) char. */
|
||||
_set_property (object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_uchar (GObject *object,
|
||||
const char *property_name,
|
||||
guint8 value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_int (GObject *object,
|
||||
const char *property_name,
|
||||
int value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_INT, g_value_set_int, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_int64 (GObject *object,
|
||||
const char *property_name,
|
||||
gint64 value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_INT64, g_value_set_int64, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -1200,11 +1273,44 @@ nm_g_object_set_property_uint (GObject *object,
|
|||
guint value,
|
||||
GError **error)
|
||||
{
|
||||
nm_auto_unset_gvalue GValue gvalue = { 0 };
|
||||
_set_property (object, property_name, G_TYPE_UINT, g_value_set_uint, value, error);
|
||||
}
|
||||
|
||||
g_value_init (&gvalue, G_TYPE_UINT);
|
||||
g_value_set_uint (&gvalue, value);
|
||||
return nm_g_object_set_property (object, property_name, &gvalue, error);
|
||||
gboolean
|
||||
nm_g_object_set_property_uint64 (GObject *object,
|
||||
const char *property_name,
|
||||
guint64 value,
|
||||
GError **error)
|
||||
{
|
||||
_set_property (object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_flags (GObject *object,
|
||||
const char *property_name,
|
||||
GType gtype,
|
||||
guint value,
|
||||
GError **error)
|
||||
{
|
||||
nm_assert (({
|
||||
nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype);
|
||||
G_IS_FLAGS_CLASS (gtypeclass);
|
||||
}));
|
||||
_set_property (object, property_name, gtype, g_value_set_flags, value, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_object_set_property_enum (GObject *object,
|
||||
const char *property_name,
|
||||
GType gtype,
|
||||
int value,
|
||||
GError **error)
|
||||
{
|
||||
nm_assert (({
|
||||
nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype);
|
||||
G_IS_ENUM_CLASS (gtypeclass);
|
||||
}));
|
||||
_set_property (object, property_name, gtype, g_value_set_enum, value, error);
|
||||
}
|
||||
|
||||
GParamSpec *
|
||||
|
|
|
|||
|
|
@ -697,20 +697,72 @@ nm_utils_error_set_literal (GError **error, int error_code, const char *literal)
|
|||
/*****************************************************************************/
|
||||
|
||||
gboolean nm_g_object_set_property (GObject *object,
|
||||
const char *property_name,
|
||||
const char *property_name,
|
||||
const GValue *value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_string (GObject *object,
|
||||
const char *property_name,
|
||||
const char *value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_string_static (GObject *object,
|
||||
const char *property_name,
|
||||
const char *value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_string_take (GObject *object,
|
||||
const char *property_name,
|
||||
char *value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_boolean (GObject *object,
|
||||
const char *property_name,
|
||||
const char *property_name,
|
||||
gboolean value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_char (GObject *object,
|
||||
const char *property_name,
|
||||
gint8 value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_uchar (GObject *object,
|
||||
const char *property_name,
|
||||
guint8 value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_int (GObject *object,
|
||||
const char *property_name,
|
||||
int value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_int64 (GObject *object,
|
||||
const char *property_name,
|
||||
gint64 value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_uint (GObject *object,
|
||||
const char *property_name,
|
||||
const char *property_name,
|
||||
guint value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_uint64 (GObject *object,
|
||||
const char *property_name,
|
||||
guint64 value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_flags (GObject *object,
|
||||
const char *property_name,
|
||||
GType gtype,
|
||||
guint value,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_g_object_set_property_enum (GObject *object,
|
||||
const char *property_name,
|
||||
GType gtype,
|
||||
int value,
|
||||
GError **error);
|
||||
|
||||
GParamSpec *nm_g_object_class_find_property_from_gtype (GType gtype,
|
||||
const char *property_name);
|
||||
|
||||
|
|
|
|||
|
|
@ -905,6 +905,16 @@ nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
#define _nmtst_rand_select(uniq, v0, ...) \
|
||||
({ \
|
||||
typeof (v0) NM_UNIQ_T (UNIQ, uniq)[1 + NM_NARG (__VA_ARGS__)] = { (v0), __VA_ARGS__ }; \
|
||||
\
|
||||
NM_UNIQ_T (UNIQ, uniq)[nmtst_get_rand_int () % G_N_ELEMENTS (NM_UNIQ_T (UNIQ, uniq))]; \
|
||||
})
|
||||
|
||||
#define nmtst_rand_select(...) \
|
||||
_nmtst_rand_select (NM_UNIQ, __VA_ARGS__)
|
||||
|
||||
static inline void *
|
||||
nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt)
|
||||
{
|
||||
|
|
@ -1966,8 +1976,8 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha
|
|||
static inline NMConnection *
|
||||
nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *full_filename)
|
||||
{
|
||||
GKeyFile *keyfile;
|
||||
GError *error = NULL;
|
||||
gs_unref_keyfile GKeyFile *keyfile = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gboolean success;
|
||||
NMConnection *con;
|
||||
gs_free char *filename = g_path_get_basename (full_filename);
|
||||
|
|
@ -1978,14 +1988,10 @@ nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *full_
|
|||
|
||||
keyfile = g_key_file_new ();
|
||||
success = g_key_file_load_from_data (keyfile, keyfile_str, strlen (keyfile_str), G_KEY_FILE_NONE, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
nmtst_assert_success (success, error);
|
||||
|
||||
con = nm_keyfile_read (keyfile, base_dir, NULL, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (NM_IS_CONNECTION (con));
|
||||
|
||||
g_key_file_unref (keyfile);
|
||||
nmtst_assert_success (NM_IS_CONNECTION (con), error);
|
||||
|
||||
nm_keyfile_read_ensure_id (con, filename);
|
||||
nm_keyfile_read_ensure_uuid (con, full_filename);
|
||||
|
|
@ -2141,4 +2147,50 @@ typedef enum {
|
|||
|
||||
#endif /* __NM_CONNECTION_H__ */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline void
|
||||
nmtst_keyfile_assert_data (GKeyFile *kf, const char *data, gssize data_len)
|
||||
{
|
||||
gs_unref_keyfile GKeyFile *kf2 = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free char *d1 = NULL;
|
||||
gs_free char *d2 = NULL;
|
||||
gboolean success;
|
||||
gsize d1_len;
|
||||
gsize d2_len;
|
||||
|
||||
g_assert (kf);
|
||||
g_assert (data || data_len == 0);
|
||||
g_assert (data_len >= -1);
|
||||
|
||||
d1 = g_key_file_to_data (kf, &d1_len, &error);
|
||||
nmtst_assert_success (d1, error);
|
||||
|
||||
if (data_len == -1) {
|
||||
g_assert_cmpint (strlen (d1), ==, d1_len);
|
||||
data_len = strlen (data);
|
||||
g_assert_cmpstr (d1, ==, data);
|
||||
}
|
||||
|
||||
g_assert_cmpmem (d1, d1_len, data, (gsize) data_len);
|
||||
|
||||
/* also check that we can re-generate the same keyfile from the data. */
|
||||
|
||||
kf2 = g_key_file_new ();
|
||||
success = g_key_file_load_from_data (kf2,
|
||||
d1,
|
||||
d1_len,
|
||||
G_KEY_FILE_NONE,
|
||||
&error);
|
||||
nmtst_assert_success (success, error);
|
||||
|
||||
d2 = g_key_file_to_data (kf2, &d2_len, &error);
|
||||
nmtst_assert_success (d2, error);
|
||||
|
||||
g_assert_cmpmem (d2, d2_len, d1, d1_len);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NM_TEST_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -1058,49 +1058,6 @@ _con_get_request_start_validated (NMAuthChain *chain,
|
|||
nm_auth_chain_destroy (chain);
|
||||
}
|
||||
|
||||
static void
|
||||
has_system_secrets_check (NMSetting *setting,
|
||||
const char *key,
|
||||
const GValue *value,
|
||||
GParamFlags flags,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
||||
gboolean *has_system = user_data;
|
||||
|
||||
if (!(flags & NM_SETTING_PARAM_SECRET))
|
||||
return;
|
||||
|
||||
/* Clear out system-owned or always-ask secrets */
|
||||
if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
|
||||
GHashTableIter iter;
|
||||
const char *secret_name = NULL;
|
||||
|
||||
/* VPNs are special; need to handle each secret separately */
|
||||
g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
|
||||
secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
||||
nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
|
||||
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
|
||||
*has_system = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
|
||||
g_return_if_reached ();
|
||||
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
|
||||
*has_system = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
has_system_secrets (NMConnection *connection)
|
||||
{
|
||||
gboolean has_system = FALSE;
|
||||
|
||||
nm_connection_for_each_setting_value (connection, has_system_secrets_check, &has_system);
|
||||
return has_system;
|
||||
}
|
||||
|
||||
static void
|
||||
_con_get_request_start (Request *req)
|
||||
{
|
||||
|
|
@ -1121,7 +1078,8 @@ _con_get_request_start (Request *req)
|
|||
* unprivileged users.
|
||||
*/
|
||||
if ( (req->con.get.flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE)
|
||||
&& (req->con.get.existing_secrets || has_system_secrets (req->con.connection))) {
|
||||
&& ( req->con.get.existing_secrets
|
||||
|| _nm_connection_aggregate (req->con.connection, NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS, NULL))) {
|
||||
_LOGD (NULL, "("LOG_REQ_FMT") request has system secrets; checking agent %s for MODIFY",
|
||||
LOG_REQ_ARG (req), agent_dbus_owner);
|
||||
|
||||
|
|
|
|||
|
|
@ -1659,38 +1659,6 @@ typedef struct {
|
|||
bool is_update2:1;
|
||||
} UpdateInfo;
|
||||
|
||||
static void
|
||||
has_some_secrets_cb (NMSetting *setting,
|
||||
const char *key,
|
||||
const GValue *value,
|
||||
GParamFlags flags,
|
||||
gpointer user_data)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
|
||||
if (NM_IS_SETTING_VPN (setting)) {
|
||||
if (nm_setting_vpn_get_num_secrets (NM_SETTING_VPN(setting)))
|
||||
*((gboolean *) user_data) = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), key);
|
||||
if (pspec) {
|
||||
if ( (flags & NM_SETTING_PARAM_SECRET)
|
||||
&& !g_param_value_defaults (pspec, (GValue *)value))
|
||||
*((gboolean *) user_data) = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
any_secrets_present (NMConnection *self)
|
||||
{
|
||||
gboolean has_secrets = FALSE;
|
||||
|
||||
nm_connection_for_each_setting_value (self, has_some_secrets_cb, &has_secrets);
|
||||
return has_secrets;
|
||||
}
|
||||
|
||||
static void
|
||||
cached_secrets_to_connection (NMSettingsConnection *self, NMConnection *connection)
|
||||
{
|
||||
|
|
@ -1758,7 +1726,7 @@ update_auth_cb (NMSettingsConnection *self,
|
|||
}
|
||||
|
||||
if (info->new_settings) {
|
||||
if (!any_secrets_present (info->new_settings)) {
|
||||
if (!_nm_connection_aggregate (info->new_settings, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL)) {
|
||||
/* If the new connection has no secrets, we do not want to remove all
|
||||
* secrets, rather we keep all the existing ones. Do that by merging
|
||||
* them in to the new connection.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue