diff options
author | Thomas Haller <thaller@redhat.com> | 2014-10-12 22:25:15 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-10-12 22:25:32 +0200 |
commit | ec84e4f00a9607ccea0139d728d24c2c2d714e6b (patch) | |
tree | 29b02c0c6d066405411a3fa490ad0a138a4b78f3 | |
parent | a7c8e5c6e9aad100b782f0be62916e8d99399aca (diff) | |
parent | 30b1afd73bd3cb7a772e8fadaa99354218fa773f (diff) | |
download | NetworkManager-ec84e4f00a9607ccea0139d728d24c2c2d714e6b.tar.gz |
merge branch 'th/bgo737380_log_connection_diff'
https://bugzilla.gnome.org/show_bug.cgi?id=737380
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | libnm-core/nm-connection.c | 2 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 3 | ||||
-rw-r--r-- | libnm-core/nm-setting-private.h | 2 | ||||
-rw-r--r-- | libnm-core/nm-setting-vpn.c | 10 | ||||
-rw-r--r-- | libnm-core/nm-setting.c | 154 | ||||
-rw-r--r-- | libnm-core/nm-setting.h | 32 | ||||
-rw-r--r-- | libnm-util/nm-setting-private.h | 3 | ||||
-rw-r--r-- | libnm-util/nm-setting-vpn.c | 10 | ||||
-rw-r--r-- | libnm-util/nm-setting.c | 127 | ||||
-rw-r--r-- | libnm-util/nm-setting.h | 24 | ||||
-rw-r--r-- | libnm/libnm.ver | 3 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 248 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 18 | ||||
-rw-r--r-- | src/settings/nm-agent-manager.c | 3 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 22 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 2 | ||||
-rw-r--r-- | src/settings/plugins/ifnet/connection_parser.c | 25 | ||||
-rw-r--r-- | src/settings/plugins/keyfile/writer.c | 3 | ||||
-rw-r--r-- | src/tests/test-general.c | 55 |
20 files changed, 645 insertions, 103 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 23e9f2159c..1e0cdbf934 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1104,7 +1104,7 @@ nm_connection_need_secrets (NMConnection *connection, GPtrArray *secrets; setting = NM_SETTING (iter->data); - secrets = nm_setting_need_secrets (setting); + secrets = _nm_setting_need_secrets (setting); if (secrets) { if (hints) *hints = secrets; diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index c7f31f1957..f83b486c12 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -60,6 +60,9 @@ gboolean _nm_setting_ip4_config_add_address_with_label (NMSettingIP4Config *s NM_SETTING_SECRET_FLAG_NOT_SAVED | \ NM_SETTING_SECRET_FLAG_NOT_REQUIRED) +guint32 _nm_setting_get_setting_priority (NMSetting *setting); + +gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value); GSList * _nm_utils_hash_values_to_slist (GHashTable *hash); diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index f277992481..9f0c51a983 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -158,4 +158,6 @@ void _nm_setting_class_transform_property (NMSettingClass *setting_class, NMSettingPropertyTransformToFunc to_dbus, NMSettingPropertyTransformFromFunc from_dbus); +GPtrArray *_nm_setting_need_secrets (NMSetting *setting); + #endif /* NM_SETTING_PRIVATE_H */ diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index 6ce4145029..667b83d78b 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -539,29 +539,31 @@ get_secret_flags (NMSetting *setting, char *flags_key; gpointer val; unsigned long tmp; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; 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)) { - if (out_flags) - *out_flags = (guint32) tmp; + flags = (NMSettingSecretFlags) tmp; success = TRUE; } else { g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, - "Failed to convert '%s' value '%s' to uint", + _("Failed to convert '%s' value '%s' to uint"), flags_key, (const char *) val); } } else { g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_NOT_FOUND, - "Secret flags property '%s' not found", flags_key); + _("Secret flags property '%s' not found"), flags_key); } g_free (flags_key); + if (out_flags) + *out_flags = flags; return success; } diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index f4ad8bbd16..14c5f404ce 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -28,6 +28,7 @@ #include "nm-setting-private.h" #include "nm-setting-connection.h" #include "nm-utils.h" +#include "nm-core-internal.h" #include "nm-utils-private.h" #include "nm-property-compare.h" @@ -209,6 +210,17 @@ _get_setting_type_priority (GType type) return info->priority; } +guint32 +_nm_setting_get_setting_priority (NMSetting *setting) +{ + NMSettingPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING (setting), G_MAXUINT32); + priv = NM_SETTING_GET_PRIVATE (setting); + _ensure_setting_info (setting, priv); + return priv->info->priority; +} + gboolean _nm_setting_type_is_base_type (GType type) { @@ -279,8 +291,8 @@ _nm_setting_compare_priority (gconstpointer a, gconstpointer b) { guint32 prio_a, prio_b; - prio_a = _get_setting_type_priority (G_OBJECT_TYPE (a)); - prio_b = _get_setting_type_priority (G_OBJECT_TYPE (b)); + prio_a = _nm_setting_get_setting_priority ((NMSetting *) a); + prio_b = _nm_setting_get_setting_priority ((NMSetting *) b); if (prio_a < prio_b) return -1; @@ -872,6 +884,27 @@ _nm_setting_new_from_dbus (GType setting_type, return setting; } +gboolean +_nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value) +{ + GParamSpec *prop_spec; + + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (property_name, FALSE); + g_return_val_if_fail (value, FALSE); + + prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name); + + if (!prop_spec) { + g_value_unset (value); + return FALSE; + } + + g_value_init (value, prop_spec->value_type); + g_object_get_property (G_OBJECT (setting), property_name, value); + return TRUE; +} + static void duplicate_setting (NMSetting *setting, const char *name, @@ -1002,8 +1035,12 @@ compare_property (NMSetting *setting, NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE; NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL); - nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL); + g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + + if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL)) + g_return_val_if_reached (FALSE); + if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL)) + g_return_val_if_reached (FALSE); /* If the secret flags aren't the same the settings aren't the same */ if (a_secret_flags != b_secret_flags) @@ -1108,7 +1145,16 @@ should_compare_prop (NMSetting *setting, if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) return FALSE; - nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL); + if ( NM_IS_SETTING_VPN (setting) + && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) { + /* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET. + * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the + * setting accidently uses a key "secrets". */ + return TRUE; + } + + if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL)) + g_return_val_if_reached (FALSE); if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) @@ -1160,6 +1206,8 @@ nm_setting_diff (NMSetting *a, guint i; NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A; NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B; + NMSettingDiffResult a_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT; + NMSettingDiffResult b_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT; gboolean results_created = FALSE; g_return_val_if_fail (results != NULL, FALSE); @@ -1169,6 +1217,12 @@ nm_setting_diff (NMSetting *a, g_return_val_if_fail (G_OBJECT_TYPE (a) == G_OBJECT_TYPE (b), FALSE); } + if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == + (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) { + /* conflicting flags: default to WITH_DEFAULT (clearing NO_DEFAULT). */ + flags &= ~NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT; + } + /* If the caller is calling this function in a pattern like this to get * complete diffs: * @@ -1181,6 +1235,8 @@ nm_setting_diff (NMSetting *a, if (invert_results) { a_result = NM_SETTING_DIFF_RESULT_IN_B; b_result = NM_SETTING_DIFF_RESULT_IN_A; + a_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT; + b_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT; } if (*results == NULL) { @@ -1193,8 +1249,7 @@ nm_setting_diff (NMSetting *a, for (i = 0; i < n_property_specs; i++) { GParamSpec *prop_spec = property_specs[i]; - NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN, tmp; - gboolean different = TRUE; + NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN; /* Handle compare flags */ if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) @@ -1203,28 +1258,58 @@ nm_setting_diff (NMSetting *a, continue; if (b) { + gboolean different; + different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags); if (different) { + gboolean a_is_default, b_is_default; GValue value = G_VALUE_INIT; g_value_init (&value, prop_spec->value_type); g_object_get_property (G_OBJECT (a), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) - r |= a_result; + a_is_default = g_param_value_defaults (prop_spec, &value); g_value_reset (&value); g_object_get_property (G_OBJECT (b), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) - r |= b_result; + b_is_default = g_param_value_defaults (prop_spec, &value); g_value_unset (&value); + if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) { + if (!a_is_default) + r |= a_result; + if (!b_is_default) + r |= b_result; + } else { + r |= a_result | b_result; + if (a_is_default) + r |= a_result_default; + if (b_is_default) + r |= b_result_default; + } } - } else + } else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0) r = a_result; /* only in A */ + else { + GValue value = G_VALUE_INIT; - if (different) { - tmp = GPOINTER_TO_UINT (g_hash_table_lookup (*results, prop_spec->name)); - g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (tmp | r)); + g_value_init (&value, prop_spec->value_type); + g_object_get_property (G_OBJECT (a), prop_spec->name, &value); + if (!g_param_value_defaults (prop_spec, &value)) + r |= a_result; + else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) + r |= a_result | a_result_default; + + g_value_unset (&value); + } + + if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) { + void *p; + + if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) { + if ((r & GPOINTER_TO_UINT (p)) != r) + g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p))); + } else + g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r)); } } g_free (property_specs); @@ -1274,19 +1359,15 @@ nm_setting_enumerate_values (NMSetting *setting, } /** - * nm_setting_clear_secrets: + * _nm_setting_clear_secrets: * @setting: the #NMSetting * * Resets and clears any secrets in the setting. Secrets should be added to the * setting only when needed, and cleared immediately after use to prevent * leakage of information. + * + * Returns: %TRUE if the setting changed at all **/ -void -nm_setting_clear_secrets (NMSetting *setting) -{ - _nm_setting_clear_secrets (setting); -} - gboolean _nm_setting_clear_secrets (NMSetting *setting) { @@ -1330,8 +1411,12 @@ clear_secrets_with_flags (NMSetting *setting, NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; gboolean changed = FALSE; + g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + /* Clear the secret if the user function says to do so */ - nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL); + if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL)) + g_return_val_if_reached (FALSE); + if (func (setting, pspec->name, flags, user_data) == TRUE) { GValue value = G_VALUE_INIT; @@ -1349,22 +1434,16 @@ clear_secrets_with_flags (NMSetting *setting, } /** - * nm_setting_clear_secrets_with_flags: + * _nm_setting_clear_secrets_with_flags: * @setting: the #NMSetting * @func: (scope call): function to be called to determine whether a * specific secret should be cleared or not * @user_data: caller-supplied data passed to @func * * Clears and frees secrets determined by @func. + * + * Returns: %TRUE if the setting changed at all **/ -void -nm_setting_clear_secrets_with_flags (NMSetting *setting, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) -{ - _nm_setting_clear_secrets_with_flags (setting, func, user_data); -} - gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting, NMSettingClearSecretsWithFlagsFn func, @@ -1394,7 +1473,7 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting, } /** - * nm_setting_need_secrets: + * _nm_setting_need_secrets: * @setting: the #NMSetting * * Returns an array of property names for each secret which may be required @@ -1408,7 +1487,7 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting, * free the elements. **/ GPtrArray * -nm_setting_need_secrets (NMSetting *setting) +_nm_setting_need_secrets (NMSetting *setting) { GPtrArray *secrets = NULL; @@ -1549,8 +1628,11 @@ get_secret_flags (NMSetting *setting, char *flags_prop; NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - if (verify_secret) - g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); + if (verify_secret && !is_secret_prop (setting, secret_name, error)) { + if (out_flags) + *out_flags = NM_SETTING_SECRET_FLAG_NONE; + return FALSE; + } flags_prop = g_strdup_printf ("%s-flags", secret_name); g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL); diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h index 5ed3e6b4f7..8e179f2a4f 100644 --- a/libnm-core/nm-setting.h +++ b/libnm-core/nm-setting.h @@ -125,6 +125,20 @@ typedef enum { /*< flags >*/ * @NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS: ignore secrets for which * the secret's flags indicate the secret should not be saved to persistent * storage (ie, the secret's flag includes @NM_SETTING_SECRET_FLAG_NOT_SAVED) + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT: if this flag is set, + * nm_setting_diff() and nm_connection_diff() will also include properties that + * are set to their default value. See also @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT. + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT: if this flag is set, + * nm_setting_diff() and nm_connection_diff() will not include properties that + * are set to their default value. This is the opposite of + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT. If both flags are set together, + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT wins. If both flags are unset, + * this means to exclude default properties if there is a setting to compare, + * but include all properties, if the setting 'b' is missing. This is the legacy + * behaviour of libnm-util, where nm_setting_diff() behaved differently depending + * on whether the setting 'b' was available. If @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT + * is set, nm_setting_diff() will also set the flags @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT + * and @NM_SETTING_DIFF_RESULT_IN_B_DEFAULT, if the values are default values. * * These flags modify the comparison behavior when comparing two settings or * two connections. @@ -136,7 +150,9 @@ typedef enum { NM_SETTING_COMPARE_FLAG_IGNORE_ID = 0x00000002, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS = 0x00000004, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS = 0x00000008, - NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS = 0x00000010 + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS = 0x00000010, + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT = 0x00000020, + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT = 0x00000040, /* 0x80000000 is used for a private flag */ } NMSettingCompareFlags; @@ -247,6 +263,10 @@ gboolean nm_setting_compare (NMSetting *a, * @NM_SETTING_DIFF_RESULT_UNKNOWN: unknown result * @NM_SETTING_DIFF_RESULT_IN_A: the property is present in setting A * @NM_SETTING_DIFF_RESULT_IN_B: the property is present in setting B + * @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT: the property is present in + * setting A but is set to the default value. This flag is only set, + * if you specify @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT. + * @NM_SETTING_DIFF_RESULT_IN_B_DEFAULT: analog to @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT. * * These values indicate the result of a setting difference operation. **/ @@ -254,6 +274,8 @@ typedef enum { NM_SETTING_DIFF_RESULT_UNKNOWN = 0x00000000, NM_SETTING_DIFF_RESULT_IN_A = 0x00000001, NM_SETTING_DIFF_RESULT_IN_B = 0x00000002, + NM_SETTING_DIFF_RESULT_IN_A_DEFAULT = 0x00000004, + NM_SETTING_DIFF_RESULT_IN_B_DEFAULT = 0x00000004, } NMSettingDiffResult; gboolean nm_setting_diff (NMSetting *a, @@ -269,14 +291,6 @@ void nm_setting_enumerate_values (NMSetting *setting, char *nm_setting_to_string (NMSetting *setting); /* Secrets */ -void nm_setting_clear_secrets (NMSetting *setting); - -void nm_setting_clear_secrets_with_flags (NMSetting *setting, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data); - -GPtrArray *nm_setting_need_secrets (NMSetting *setting); - gboolean nm_setting_get_secret_flags (NMSetting *setting, const char *secret_name, NMSettingSecretFlags *out_flags, diff --git a/libnm-util/nm-setting-private.h b/libnm-util/nm-setting-private.h index 9dad7eada5..1b271d0c76 100644 --- a/libnm-util/nm-setting-private.h +++ b/libnm-util/nm-setting-private.h @@ -55,10 +55,13 @@ void _nm_register_setting (const char *name, gboolean _nm_setting_is_base_type (NMSetting *setting); gboolean _nm_setting_type_is_base_type (GType type); +guint32 _nm_setting_get_setting_priority (NMSetting *setting); GType _nm_setting_lookup_setting_type (const char *name); GType _nm_setting_lookup_setting_type_by_quark (GQuark error_quark); gint _nm_setting_compare_priority (gconstpointer a, gconstpointer b); +gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value); + typedef enum NMSettingUpdateSecretResult { NM_SETTING_UPDATE_SECRET_ERROR = FALSE, NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED = TRUE, diff --git a/libnm-util/nm-setting-vpn.c b/libnm-util/nm-setting-vpn.c index be892da485..70f955b010 100644 --- a/libnm-util/nm-setting-vpn.c +++ b/libnm-util/nm-setting-vpn.c @@ -545,29 +545,31 @@ get_secret_flags (NMSetting *setting, char *flags_key; gpointer val; unsigned long tmp; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; 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)) { - if (out_flags) - *out_flags = (guint32) tmp; + flags = (NMSettingSecretFlags) tmp; success = TRUE; } else { g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, - "Failed to convert '%s' value '%s' to uint", + _("Failed to convert '%s' value '%s' to uint"), flags_key, (const char *) val); } } else { g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_NOT_FOUND, - "Secret flags property '%s' not found", flags_key); + _("Secret flags property '%s' not found"), flags_key); } g_free (flags_key); + if (out_flags) + *out_flags = flags; return success; } diff --git a/libnm-util/nm-setting.c b/libnm-util/nm-setting.c index 2508a401fa..5c3dc1e105 100644 --- a/libnm-util/nm-setting.c +++ b/libnm-util/nm-setting.c @@ -209,6 +209,17 @@ _get_setting_type_priority (GType type) return info->priority; } +guint32 +_nm_setting_get_setting_priority (NMSetting *setting) +{ + NMSettingPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING (setting), G_MAXUINT32); + priv = NM_SETTING_GET_PRIVATE (setting); + _ensure_setting_info (setting, priv); + return priv->info->priority; +} + gboolean _nm_setting_type_is_base_type (GType type) { @@ -260,8 +271,8 @@ _nm_setting_compare_priority (gconstpointer a, gconstpointer b) { guint32 prio_a, prio_b; - prio_a = _get_setting_type_priority (G_OBJECT_TYPE (a)); - prio_b = _get_setting_type_priority (G_OBJECT_TYPE (b)); + prio_a = _nm_setting_get_setting_priority ((NMSetting *) a); + prio_b = _nm_setting_get_setting_priority ((NMSetting *) b); if (prio_a < prio_b) return -1; @@ -412,6 +423,27 @@ nm_setting_new_from_hash (GType setting_type, GHashTable *hash) return setting; } +gboolean +_nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value) +{ + GParamSpec *prop_spec; + + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (property_name, FALSE); + g_return_val_if_fail (value, FALSE); + + prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name); + + if (!prop_spec) { + g_value_unset (value); + return FALSE; + } + + g_value_init (value, prop_spec->value_type); + g_object_get_property (G_OBJECT (setting), property_name, value); + return TRUE; +} + static void duplicate_setting (NMSetting *setting, const char *name, @@ -542,8 +574,12 @@ compare_property (NMSetting *setting, NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE; NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL); - nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL); + g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + + if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL)) + g_return_val_if_reached (FALSE); + if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL)) + g_return_val_if_reached (FALSE); /* If the secret flags aren't the same the settings aren't the same */ if (a_secret_flags != b_secret_flags) @@ -648,7 +684,16 @@ should_compare_prop (NMSetting *setting, if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) return FALSE; - nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL); + if ( NM_IS_SETTING_VPN (setting) + && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) { + /* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET. + * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the + * setting accidently uses a key "secrets". */ + return FALSE; + } + + if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL)) + g_return_val_if_reached (FALSE); if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) @@ -700,6 +745,8 @@ nm_setting_diff (NMSetting *a, guint i; NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A; NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B; + NMSettingDiffResult a_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT; + NMSettingDiffResult b_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT; gboolean results_created = FALSE; g_return_val_if_fail (results != NULL, FALSE); @@ -709,6 +756,12 @@ nm_setting_diff (NMSetting *a, g_return_val_if_fail (G_OBJECT_TYPE (a) == G_OBJECT_TYPE (b), FALSE); } + if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == + (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) { + /* conflicting flags: default to WITH_DEFAULT (clearing NO_DEFAULT). */ + flags &= ~NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT; + } + /* If the caller is calling this function in a pattern like this to get * complete diffs: * @@ -721,6 +774,8 @@ nm_setting_diff (NMSetting *a, if (invert_results) { a_result = NM_SETTING_DIFF_RESULT_IN_B; b_result = NM_SETTING_DIFF_RESULT_IN_A; + a_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT; + b_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT; } if (*results == NULL) { @@ -733,8 +788,7 @@ nm_setting_diff (NMSetting *a, for (i = 0; i < n_property_specs; i++) { GParamSpec *prop_spec = property_specs[i]; - NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN, tmp; - gboolean different = TRUE; + NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN; /* Handle compare flags */ if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) @@ -743,28 +797,58 @@ nm_setting_diff (NMSetting *a, continue; if (b) { + gboolean different; + different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags); if (different) { + gboolean a_is_default, b_is_default; GValue value = G_VALUE_INIT; g_value_init (&value, prop_spec->value_type); g_object_get_property (G_OBJECT (a), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) - r |= a_result; + a_is_default = g_param_value_defaults (prop_spec, &value); g_value_reset (&value); g_object_get_property (G_OBJECT (b), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) - r |= b_result; + b_is_default = g_param_value_defaults (prop_spec, &value); g_value_unset (&value); + if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) { + if (!a_is_default) + r |= a_result; + if (!b_is_default) + r |= b_result; + } else { + r |= a_result | b_result; + if (a_is_default) + r |= a_result_default; + if (b_is_default) + r |= b_result_default; + } } - } else + } else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0) r = a_result; /* only in A */ + else { + GValue value = G_VALUE_INIT; + + g_value_init (&value, prop_spec->value_type); + g_object_get_property (G_OBJECT (a), prop_spec->name, &value); + if (!g_param_value_defaults (prop_spec, &value)) + r |= a_result; + else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) + r |= a_result | a_result_default; - if (different) { - tmp = GPOINTER_TO_UINT (g_hash_table_lookup (*results, prop_spec->name)); - g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (tmp | r)); + g_value_unset (&value); + } + + if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) { + void *p; + + if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) { + if ((r & GPOINTER_TO_UINT (p)) != r) + g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p))); + } else + g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r)); } } g_free (property_specs); @@ -870,8 +954,12 @@ clear_secrets_with_flags (NMSetting *setting, NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; gboolean changed = FALSE; + g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + /* Clear the secret if the user function says to do so */ - nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL); + if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL)) + g_return_val_if_reached (FALSE); + if (func (setting, pspec->name, flags, user_data) == TRUE) { GValue value = G_VALUE_INIT; @@ -1090,8 +1178,11 @@ get_secret_flags (NMSetting *setting, char *flags_prop; NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - if (verify_secret) - g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); + if (verify_secret && !is_secret_prop (setting, secret_name, error)) { + if (out_flags) + *out_flags = NM_SETTING_SECRET_FLAG_NONE; + return FALSE; + } flags_prop = g_strdup_printf ("%s-flags", secret_name); g_object_get (G_OBJECT (setting), flags_prop, &flags, NULL); diff --git a/libnm-util/nm-setting.h b/libnm-util/nm-setting.h index b58137a6e7..28c6975a8d 100644 --- a/libnm-util/nm-setting.h +++ b/libnm-util/nm-setting.h @@ -124,6 +124,20 @@ typedef enum { * @NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS: ignore secrets for which * the secret's flags indicate the secret should not be saved to persistent * storage (ie, the secret's flag includes @NM_SETTING_SECRET_FLAG_NOT_SAVED) + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT: if this flag is set, + * nm_setting_diff() and nm_connection_diff() will also include properties that + * are set to their default value. See also @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT. + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT: if this flag is set, + * nm_setting_diff() and nm_connection_diff() will not include properties that + * are set to their default value. This is the opposite of + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT. If both flags are set together, + * @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT wins. If both flags are unset, + * this means to exclude default properties if there is a setting to compare, + * but include all properties, if the setting 'b' is missing. This is the legacy + * behaviour of libnm-util, where nm_setting_diff() behaved differently depending + * on whether the setting 'b' was available. If @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT + * is set, nm_setting_diff() will also set the flags @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT + * and @NM_SETTING_DIFF_RESULT_IN_B_DEFAULT, if the values are default values. * * These flags modify the comparison behavior when comparing two settings or * two connections. @@ -135,7 +149,9 @@ typedef enum { NM_SETTING_COMPARE_FLAG_IGNORE_ID = 0x00000002, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS = 0x00000004, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS = 0x00000008, - NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS = 0x00000010 + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS = 0x00000010, + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT = 0x00000020, + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT = 0x00000040, /* 0x80000000 is used for a private flag */ } NMSettingCompareFlags; @@ -267,6 +283,10 @@ gboolean nm_setting_compare (NMSetting *a, * @NM_SETTING_DIFF_RESULT_UNKNOWN: unknown result * @NM_SETTING_DIFF_RESULT_IN_A: the property is present in setting A * @NM_SETTING_DIFF_RESULT_IN_B: the property is present in setting B + * @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT: the property is present in + * setting A but is set to the default value. This flag is only set, + * if you specify @NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT. + * @NM_SETTING_DIFF_RESULT_IN_B_DEFAULT: analog to @NM_SETTING_DIFF_RESULT_IN_A_DEFAULT. * * These values indicate the result of a setting difference operation. **/ @@ -274,6 +294,8 @@ typedef enum { NM_SETTING_DIFF_RESULT_UNKNOWN = 0x00000000, NM_SETTING_DIFF_RESULT_IN_A = 0x00000001, NM_SETTING_DIFF_RESULT_IN_B = 0x00000002, + NM_SETTING_DIFF_RESULT_IN_A_DEFAULT = 0x00000004, + NM_SETTING_DIFF_RESULT_IN_B_DEFAULT = 0x00000004, } NMSettingDiffResult; gboolean nm_setting_diff (NMSetting *a, diff --git a/libnm/libnm.ver b/libnm/libnm.ver index ca8283abb4..e0c4795f9e 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -521,8 +521,6 @@ global: nm_setting_cdma_get_type; nm_setting_cdma_get_username; nm_setting_cdma_new; - nm_setting_clear_secrets; - nm_setting_clear_secrets_with_flags; nm_setting_compare; nm_setting_compare_flags_get_type; nm_setting_connection_add_permission; @@ -689,7 +687,6 @@ global: nm_setting_ip6_config_remove_route_by_value; nm_setting_lookup_type; nm_setting_lookup_type_by_quark; - nm_setting_need_secrets; nm_setting_olpc_mesh_error_get_type; nm_setting_olpc_mesh_error_quark; nm_setting_olpc_mesh_get_channel; diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index bdf03557a1..66da861daf 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1881,6 +1881,254 @@ nm_utils_get_monotonic_timestamp_s (void) return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec); } +typedef struct +{ + const char *name; + NMSetting *setting; + NMSetting *diff_base_setting; + GHashTable *setting_diff; +} LogConnectionSettingData; + +typedef struct +{ + const char *item_name; + NMSettingDiffResult diff_result; +} LogConnectionSettingItem; + +static gint +_log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b) +{ + const LogConnectionSettingData *v1 = a; + const LogConnectionSettingData *v2 = b; + guint32 p1, p2; + NMSetting *s1, *s2; + + s1 = v1->setting ? v1->setting : v1->diff_base_setting; + s2 = v2->setting ? v2->setting : v2->diff_base_setting; + + g_assert (s1 && s2); + + p1 = _nm_setting_get_setting_priority (s1); + p2 = _nm_setting_get_setting_priority (s2); + + if (p1 != p2) + return p1 > p2 ? 1 : -1; + + return strcmp (v1->name, v2->name); +} + +static GArray * +_log_connection_sort_hashes (NMConnection *connection, NMConnection *diff_base, GHashTable *connection_diff) +{ + GHashTableIter iter; + GArray *sorted_hashes; + LogConnectionSettingData setting_data; + + sorted_hashes = g_array_sized_new (TRUE, FALSE, sizeof (LogConnectionSettingData), g_hash_table_size (connection_diff)); + + g_hash_table_iter_init (&iter, connection_diff); + while (g_hash_table_iter_next (&iter, (gpointer) &setting_data.name, (gpointer) &setting_data.setting_diff)) { + setting_data.setting = nm_connection_get_setting_by_name (connection, setting_data.name); + setting_data.diff_base_setting = diff_base ? nm_connection_get_setting_by_name (diff_base, setting_data.name) : NULL; + g_assert (setting_data.setting || setting_data.diff_base_setting); + g_array_append_val (sorted_hashes, setting_data); + } + + g_array_sort (sorted_hashes, _log_connection_sort_hashes_fcn); + return sorted_hashes; +} + +static gint +_log_connection_sort_names_fcn (gconstpointer a, gconstpointer b) +{ + const LogConnectionSettingItem *v1 = a; + const LogConnectionSettingItem *v2 = b; + + /* we want to first show the items, that disappeared, then the one that changed and + * then the ones that were added. */ + + if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) != (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A)) + return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) ? -1 : 1; + if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) != (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B)) + return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) ? 1 : -1; + return strcmp (v1->item_name, v2->item_name); +} + +static char * +_log_connection_get_property (NMSetting *setting, const char *name) +{ + GValue val = G_VALUE_INIT; + char *s; + + g_return_val_if_fail (setting, NULL); + + if ( !NM_IS_SETTING_VPN (setting) + && nm_setting_get_secret_flags (setting, name, NULL, NULL)) + return g_strdup ("****"); + + if (!_nm_setting_get_property (setting, name, &val)) + g_return_val_if_reached (FALSE); + + if (G_VALUE_HOLDS_STRING (&val)) { + const char *val_s; + + val_s = g_value_get_string (&val); + if (!val_s) { + /* for NULL, we want to return the unquoted string "NULL". */ + s = g_strdup ("NULL"); + } else { + char *escaped = g_strescape (val_s, "'"); + + s = g_strdup_printf ("'%s'", escaped); + g_free (escaped); + } + } else { + s = g_strdup_value_contents (&val); + if (s == NULL) + s = g_strdup ("NULL"); + else { + char *escaped = g_strescape (s, "'"); + + g_free (s); + s = escaped; + } + } + g_value_unset(&val); + return s; +} + +static void +_log_connection_sort_names (LogConnectionSettingData *setting_data, GArray *sorted_names) +{ + GHashTableIter iter; + LogConnectionSettingItem item; + gpointer p; + + g_array_set_size (sorted_names, 0); + + g_hash_table_iter_init (&iter, setting_data->setting_diff); + while (g_hash_table_iter_next (&iter, (gpointer) &item.item_name, &p)) { + item.diff_result = GPOINTER_TO_UINT (p); + g_array_append_val (sorted_names, item); + } + + g_array_sort (sorted_names, _log_connection_sort_names_fcn); +} + +void +nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix) +{ + GHashTable *connection_diff = NULL; + GArray *sorted_hashes; + GArray *sorted_names = NULL; + int i, j; + gboolean connection_diff_are_same; + gboolean print_header = TRUE; + gboolean print_setting_header; + GString *str1; + + g_return_if_fail (NM_IS_CONNECTION (connection)); + g_return_if_fail (!diff_base || (NM_IS_CONNECTION (diff_base) && diff_base != connection)); + + /* For VPN setting types, this is broken, because we cannot (generically) print the content of data/secrets. Bummer... */ + + if (!nm_logging_enabled (level, domain)) + return; + + if (!prefix) + prefix = ""; + if (!name) + name = ""; + + connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff); + if (connection_diff_are_same) { + if (diff_base) + nm_log (level, domain, "%sconnection '%s' (%p and %p): no difference", prefix, name, connection, diff_base); + else + nm_log (level, domain, "%sconnection '%s' (%p): no properties set", prefix, name, connection); + g_assert (!connection_diff); + return; + } + + /* FIXME: it doesn't nicely show the content of NMSettingVpn, becuase nm_connection_diff() does not + * expand the hash values. */ + + sorted_hashes = _log_connection_sort_hashes (connection, diff_base, connection_diff); + if (sorted_hashes->len <= 0) + goto out; + + sorted_names = g_array_new (FALSE, FALSE, sizeof (LogConnectionSettingItem)); + str1 = g_string_new (NULL); + + for (i = 0; i < sorted_hashes->len; i++) { + LogConnectionSettingData *setting_data = &g_array_index (sorted_hashes, LogConnectionSettingData, i); + + _log_connection_sort_names (setting_data, sorted_names); + print_setting_header = TRUE; + for (j = 0; j < sorted_names->len; j++) { + char *str_conn, *str_diff; + LogConnectionSettingItem *item = &g_array_index (sorted_names, LogConnectionSettingItem, j); + + str_conn = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_A) + ? _log_connection_get_property (setting_data->setting, item->item_name) + : NULL; + str_diff = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_B) + ? _log_connection_get_property (setting_data->diff_base_setting, item->item_name) + : NULL; + + if (print_header) { + GError *err_verify = NULL; + + if (diff_base) + nm_log (level, domain, "%sconnection '%s' (%p < %p):", prefix, name, connection, diff_base); + else + nm_log (level, domain, "%sconnection '%s' (%p):", prefix, name, connection); + print_header = FALSE; + + if (!nm_connection_verify (connection, &err_verify)) { + nm_log (level, domain, "%sconnection %p does not verify: %s", prefix, connection, err_verify->message); + g_clear_error (&err_verify); + } + } +#define _NM_LOG_ALIGN "-25" + if (print_setting_header) { + if (diff_base) { + if (setting_data->setting && setting_data->diff_base_setting) + g_string_printf (str1, "%p < %p", setting_data->setting, setting_data->diff_base_setting); + else if (setting_data->diff_base_setting) + g_string_printf (str1, "*missing* < %p", setting_data->diff_base_setting); + else + g_string_printf (str1, "%p < *missing*", setting_data->setting); + nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %s ]", prefix, setting_data->name, str1->str); + } else + nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s [ %p ]", prefix, setting_data->name, setting_data->setting); + print_setting_header = FALSE; + } + g_string_printf (str1, "%s.%s", setting_data->name, item->item_name); + switch (item->diff_result & (NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B)) { + case NM_SETTING_DIFF_RESULT_IN_B: + nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL"); + break; + case NM_SETTING_DIFF_RESULT_IN_A: + nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL"); + break; + default: + nm_log (level, domain, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL"); + break; +#undef _NM_LOG_ALIGN + } + g_free (str_conn); + g_free (str_diff); + } + } + + g_array_free (sorted_names, TRUE); + g_string_free (str1, TRUE); +out: + g_hash_table_destroy (connection_diff); + g_array_free (sorted_hashes, TRUE); +} + /** * nm_utils_ip6_property_path: diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 88de6dd208..d7fcb53033 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -140,6 +140,8 @@ NMConnection *nm_utils_match_connection (GSList *connections, int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b); +void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); + gint64 nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); #define NM_UTILS_NS_PER_SECOND ((gint64) 1000000000) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 8508097886..6d93833792 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2053,10 +2053,11 @@ need_new_8021x_secrets (NMDeviceWifi *self, s_8021x = nm_connection_get_setting_802_1x (connection); if (s_8021x) { - nm_setting_get_secret_flags (NM_SETTING (s_8021x), - NM_SETTING_802_1X_PASSWORD, - &secret_flags, - NULL); + if (!nm_setting_get_secret_flags (NM_SETTING (s_8021x), + NM_SETTING_802_1X_PASSWORD, + &secret_flags, + NULL)) + g_assert_not_reached (); if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) *setting_name = NM_SETTING_802_1X_SETTING_NAME; return *setting_name ? TRUE : FALSE; @@ -2064,10 +2065,11 @@ need_new_8021x_secrets (NMDeviceWifi *self, s_wsec = nm_connection_get_setting_wireless_security (connection); if (s_wsec) { - nm_setting_get_secret_flags (NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - &secret_flags, - NULL); + if (!nm_setting_get_secret_flags (NM_SETTING (s_wsec), + NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, + &secret_flags, + NULL)) + g_assert_not_reached (); if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; return *setting_name ? TRUE : FALSE; diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 0de63ffb16..1076ae2143 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -1010,7 +1010,8 @@ check_system_secrets_cb (NMSetting *setting, *has_system = TRUE; } } else { - nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + 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; } diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 1e0106d07b..fe3ba3af06 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -144,6 +144,7 @@ typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter, static void for_each_secret (NMConnection *connection, GHashTable *secrets, + gboolean remove_non_secrets, ForEachSecretFunc callback, gpointer callback_data) { @@ -167,6 +168,8 @@ for_each_secret (NMConnection *connection, * each time. */ + g_return_if_fail (callback); + /* Walk through the list of setting hashes */ g_hash_table_iter_init (&iter, secrets); while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) { @@ -175,6 +178,9 @@ for_each_secret (NMConnection *connection, const char *secret_name; GValue *val; + if (g_hash_table_size (setting_hash) == 0) + continue; + /* Get the actual NMSetting from the connection so we can get secret flags * from the connection data, since flags aren't secrets. What we're * iterating here is just the secrets, not a whole connection. @@ -203,7 +209,11 @@ for_each_secret (NMConnection *connection, return; } } else { - nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL); + if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (remove_non_secrets) + g_hash_table_iter_remove (&secret_iter); + continue; + } if (callback (&secret_iter, secret_flags, callback_data) == FALSE) return; } @@ -460,6 +470,8 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, */ g_signal_handlers_block_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE)); + nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, "update connection", "++ "); + nm_connection_replace_settings_from_connection (NM_CONNECTION (self), new_connection); nm_settings_connection_set_flags (self, NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED, @@ -764,7 +776,7 @@ agent_secrets_done_cb (NMAgentManager *manager, * save those system-owned secrets. If not, discard them and use the * existing secrets, or fail the connection. */ - for_each_secret (NM_CONNECTION (self), secrets, has_system_owned_secrets, &agent_had_system); + for_each_secret (NM_CONNECTION (self), secrets, TRUE, has_system_owned_secrets, &agent_had_system); if (agent_had_system) { if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { /* No user interaction was allowed when requesting secrets; the @@ -776,7 +788,7 @@ agent_secrets_done_cb (NMAgentManager *manager, call_id, agent_dbus_owner); - for_each_secret (NM_CONNECTION (self), secrets, clear_nonagent_secrets, NULL); + for_each_secret (NM_CONNECTION (self), secrets, FALSE, clear_nonagent_secrets, NULL); } else if (agent_has_modify == FALSE) { /* Agent didn't successfully authenticate; clear system-owned secrets * from the secrets the agent returned. @@ -786,7 +798,7 @@ agent_secrets_done_cb (NMAgentManager *manager, setting_name, call_id); - for_each_secret (NM_CONNECTION (self), secrets, clear_nonagent_secrets, NULL); + for_each_secret (NM_CONNECTION (self), secrets, FALSE, clear_nonagent_secrets, NULL); } } } else { @@ -805,7 +817,7 @@ agent_secrets_done_cb (NMAgentManager *manager, * came back. Unsaved secrets by definition require user interaction. */ if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) - for_each_secret (NM_CONNECTION (self), secrets, clear_unsaved_secrets, NULL); + for_each_secret (NM_CONNECTION (self), secrets, TRUE, clear_unsaved_secrets, NULL); /* Update the connection with our existing secrets from backing storage */ nm_connection_clear_secrets (NM_CONNECTION (self)); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 5a7bf4159e..e3f0d33f75 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -874,6 +874,8 @@ claim_connection (NMSettings *self, (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), g_object_ref (connection)); + nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ "); + /* Only emit the individual connection-added signal after connections * have been initially loaded. */ diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c index 15dd3874a5..25b958fd4f 100644 --- a/src/settings/plugins/ifnet/connection_parser.c +++ b/src/settings/plugins/ifnet/connection_parser.c @@ -2846,7 +2846,8 @@ check_unsupported_secrets (NMSetting *setting, if (flags & NM_SETTING_PARAM_SECRET) { NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) + g_return_if_reached (); if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) *unsupported_secret = TRUE; } @@ -2869,17 +2870,6 @@ ifnet_can_write_connection (NMConnection *connection, GError **error) return FALSE; } - /* If the connection has flagged secrets, ignore - * it as this plugin does not deal with user agent service */ - nm_connection_for_each_setting_value (connection, - check_unsupported_secrets, - &has_unsupported_secrets); - if (has_unsupported_secrets) { - g_set_error_literal (error, IFNET_PLUGIN_ERROR, 0, - "The ifnet plugin only supports persistent system secrets."); - return FALSE; - } - /* Only support wired, wifi, and PPPoE */ if ( !nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME) && !nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME) @@ -2891,6 +2881,17 @@ ifnet_can_write_connection (NMConnection *connection, GError **error) return FALSE; } + /* If the connection has flagged secrets, ignore + * it as this plugin does not deal with user agent service */ + nm_connection_for_each_setting_value (connection, + check_unsupported_secrets, + &has_unsupported_secrets); + if (has_unsupported_secrets) { + g_set_error_literal (error, IFNET_PLUGIN_ERROR, 0, + "The ifnet plugin only supports persistent system secrets."); + return FALSE; + } + return TRUE; } diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c index ae8f0a912b..2661d50066 100644 --- a/src/settings/plugins/keyfile/writer.c +++ b/src/settings/plugins/keyfile/writer.c @@ -797,7 +797,8 @@ write_setting_value (NMSetting *setting, if (pspec && (pspec->flags & NM_SETTING_PARAM_SECRET) && !NM_IS_SETTING_VPN (setting)) { NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, key, &secret_flags, NULL); + if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) + g_assert_not_reached (); if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) return; } diff --git a/src/tests/test-general.c b/src/tests/test-general.c index ec771bc55b..f61732bb47 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -24,6 +24,7 @@ #include "NetworkManagerUtils.h" #include "nm-logging.h" +#include "nm-utils.h" #include "nm-test-utils.h" @@ -226,6 +227,59 @@ test_nm_utils_ip6_address_clear_host_address (void) g_rand_free (r); } + +static void +test_nm_utils_log_connection_diff() +{ + NMConnection *connection; + NMConnection *connection2; + + /* if logging is disabled (the default), nm_utils_log_connection_diff() returns + * early without doing anything. Hence, in the normal testing, this test does nothing. + * It only gets interesting, when run verbosely with NMTST_DEBUG=debug ... */ + + nm_log (LOGL_DEBUG, LOGD_CORE, "START TEST test_nm_utils_log_connection_diff..."); + + connection = nm_simple_connection_new (); + nm_connection_add_setting (connection, nm_setting_connection_new ()); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> "); + + nm_connection_add_setting (connection, nm_setting_wired_new ()); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> "); + + connection2 = nm_simple_connection_new_clone (connection); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> "); + + g_object_set (nm_connection_get_setting_connection (connection), + NM_SETTING_CONNECTION_ID, "id", + NM_SETTING_CONNECTION_UUID, "uuid", + NULL); + g_object_set (nm_connection_get_setting_connection (connection2), + NM_SETTING_CONNECTION_ID, "id2", + NM_SETTING_CONNECTION_MASTER, "master2", + NULL); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> "); + + nm_connection_add_setting (connection, nm_setting_802_1x_new ()); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> "); + + g_object_set (nm_connection_get_setting_802_1x (connection), + NM_SETTING_802_1X_PASSWORD, "id2", + NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, + NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> "); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> "); + nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> "); + + g_clear_object (&connection); + g_clear_object (&connection2); + + connection = nmtst_create_minimal_connection ("id-vpn-1", NULL, NM_SETTING_VPN_SETTING_NAME, NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test-vpn-1", ">>> "); + + g_clear_object (&connection); +} + /*******************************************/ static NMConnection * @@ -690,6 +744,7 @@ main (int argc, char **argv) g_test_add_func ("/general/nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64); g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address); + g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff); g_test_add_func ("/general/connection-match/basic", test_connection_match_basic); g_test_add_func ("/general/connection-match/ip6-method", test_connection_match_ip6_method); |