libnm: merge branch 'th/keyfile-fixes'

https://github.com/NetworkManager/NetworkManager/pull/273
This commit is contained in:
Thomas Haller 2019-01-07 11:39:46 +01:00
commit 0fdcbc6bfa
26 changed files with 1551 additions and 551 deletions

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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 *

View file

@ -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)
{

View file

@ -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

View file

@ -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);
}
/**

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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 ();
}

View file

@ -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

View file

@ -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__ */

View file

@ -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 *

View file

@ -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 *

View file

@ -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);

View file

@ -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__ */

View file

@ -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);

View file

@ -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.