diff options
| author | Michael Biebl <biebl@debian.org> | 2015-01-22 00:29:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2015-01-22 00:29:39 +0100 |
| commit | 2c032d8f1c6292c1338a615e6ec40252889ba85c (patch) | |
| tree | 1f77182220b2b0264288ba4a476ab47e5bc48716 /src/settings/nm-settings-connection.c | |
| parent | 33491bc4279481db8ae47213e34a6d695a0e8830 (diff) | |
Imported Upstream version 1.0.0 upstream/1.0.0
Diffstat (limited to 'src/settings/nm-settings-connection.c')
| -rw-r--r-- | src/settings/nm-settings-connection.c | 644 |
1 files changed, 409 insertions, 235 deletions
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index d20dbc98..529f4d8f 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -15,32 +15,29 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2008 Novell, Inc. - * (C) Copyright 2008 - 2013 Red Hat, Inc. + * Copyright 2008 Novell, Inc. + * Copyright 2008 - 2014 Red Hat, Inc. */ #include "config.h" #include <string.h> -#include <netinet/ether.h> -#include <NetworkManager.h> +#include <nm-dbus-interface.h> #include <dbus/dbus-glib-lowlevel.h> -#include <nm-setting-connection.h> -#include <nm-setting-vpn.h> -#include <nm-setting-wireless.h> -#include <nm-utils.h> #include "nm-settings-connection.h" #include "nm-session-monitor.h" #include "nm-dbus-manager.h" -#include "nm-settings-error.h" #include "nm-dbus-glib-types.h" #include "nm-logging.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" +#include "nm-auth-subject.h" #include "nm-agent-manager.h" #include "NetworkManagerUtils.h" #include "nm-properties-changed-signal.h" +#include "nm-core-internal.h" +#include "nm-glib-compat.h" #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" @@ -66,9 +63,16 @@ static void impl_settings_connection_get_secrets (NMSettingsConnection *connecti const gchar *setting_name, DBusGMethodInvocation *context); +static void impl_settings_connection_clear_secrets (NMSettingsConnection *connection, + DBusGMethodInvocation *context); + #include "nm-settings-connection-glue.h" -G_DEFINE_TYPE (NMSettingsConnection, nm_settings_connection, NM_TYPE_CONNECTION) +static void nm_settings_connection_connection_interface_init (NMConnectionInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_settings_connection_connection_interface_init) + ) #define NM_SETTINGS_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_SETTINGS_CONNECTION, \ @@ -78,6 +82,7 @@ enum { PROP_0 = 0, PROP_VISIBLE, PROP_UNSAVED, + PROP_FLAGS, }; enum { @@ -89,21 +94,11 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - gboolean disposed; - NMAgentManager *agent_mgr; NMSessionMonitor *session_monitor; guint session_changed_id; - /* TRUE if the connection has not yet been saved to disk, - * or if it contains changes that have not been saved to disk. - */ - gboolean unsaved; - - /* TRUE if the connection was generated by NetworkManager and has - * not been saved or modified by the user. - */ - gboolean nm_generated; + NMSettingsConnectionFlags flags; guint updated_idle_id; @@ -146,6 +141,7 @@ typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter, static void for_each_secret (NMConnection *connection, GHashTable *secrets, + gboolean remove_non_secrets, ForEachSecretFunc callback, gpointer callback_data) { @@ -169,6 +165,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)) { @@ -177,6 +175,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. @@ -205,7 +206,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; } @@ -355,7 +360,7 @@ update_system_secrets_cache (NMSettingsConnection *self) if (priv->system_secrets) g_object_unref (priv->system_secrets); - priv->system_secrets = nm_connection_duplicate (NM_CONNECTION (self)); + priv->system_secrets = nm_simple_connection_new_clone (NM_CONNECTION (self)); /* Clear out non-system-owned and not-saved secrets */ nm_connection_clear_secrets_with_flags (priv->system_secrets, @@ -371,7 +376,7 @@ update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new) if (priv->agent_secrets) g_object_unref (priv->agent_secrets); - priv->agent_secrets = nm_connection_duplicate (new ? new : NM_CONNECTION (self)); + priv->agent_secrets = nm_simple_connection_new_clone (new ? new : NM_CONNECTION (self)); /* Clear out non-system-owned secrets */ nm_connection_clear_secrets_with_flags (priv->agent_secrets, @@ -403,14 +408,17 @@ emit_updated (NMSettingsConnection *self) static void set_unsaved (NMSettingsConnection *self, gboolean now_unsaved) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - - if (priv->unsaved != now_unsaved) { - priv->unsaved = now_unsaved; - if (!priv->unsaved) - priv->nm_generated = FALSE; + NMSettingsConnectionFlags flags = nm_settings_connection_get_flags (self); - g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_UNSAVED); + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != !!now_unsaved) { + if (now_unsaved) + flags |= NM_SETTINGS_CONNECTION_FLAGS_UNSAVED; + else { + flags &= ~(NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED); + } + nm_settings_connection_set_flags_all (self, flags); } } @@ -437,7 +445,6 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, GError **error) { NMSettingsConnectionPrivate *priv; - GHashTable *hash = NULL; gboolean success = FALSE; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); @@ -445,8 +452,7 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - nm_utils_normalize_connection (new_connection, TRUE); - if (!nm_connection_verify (new_connection, error)) + if (!nm_connection_normalize (new_connection, NULL, NULL, error)) return FALSE; /* Do nothing if there's nothing to update */ @@ -461,37 +467,40 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, */ g_signal_handlers_block_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE)); - if (nm_connection_replace_settings_from_connection (NM_CONNECTION (self), - new_connection, - error)) { - priv->nm_generated = FALSE; + nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, "update connection", "++ "); - /* Cache the just-updated system secrets in case something calls - * nm_connection_clear_secrets() and clears them. - */ - update_system_secrets_cache (self); - success = TRUE; + 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, + FALSE); - /* Add agent and always-ask secrets back; they won't necessarily be - * in the replacement connection data if it was eg reread from disk. - */ - if (priv->agent_secrets) { - hash = nm_connection_to_hash (priv->agent_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS); - if (hash) { - (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, NULL); - g_hash_table_destroy (hash); - } + /* Cache the just-updated system secrets in case something calls + * nm_connection_clear_secrets() and clears them. + */ + update_system_secrets_cache (self); + success = TRUE; + + /* Add agent and always-ask secrets back; they won't necessarily be + * in the replacement connection data if it was eg reread from disk. + */ + if (priv->agent_secrets) { + GVariant *dict; + + dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (dict) { + (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); + g_variant_unref (dict); } + } - nm_settings_connection_recheck_visibility (self); + nm_settings_connection_recheck_visibility (self); - /* Manually emit changed signal since we disconnected the handler, but - * only update Unsaved if the caller wanted us to. - */ - changed_cb (self, GUINT_TO_POINTER (update_unsaved)); + /* Manually emit changed signal since we disconnected the handler, but + * only update Unsaved if the caller wanted us to. + */ + changed_cb (self, GUINT_TO_POINTER (update_unsaved)); - g_signal_emit (self, signals[UPDATED_BY_USER], 0); - } + g_signal_emit (self, signals[UPDATED_BY_USER], 0); g_signal_handlers_unblock_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE)); @@ -558,7 +567,7 @@ nm_settings_connection_commit_changes (NMSettingsConnection *connection, user_data); } else { GError *error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR_FAILED, "%s: %s:%d commit_changes() unimplemented", __func__, __FILE__, __LINE__); if (callback) callback (connection, error, user_data); @@ -579,7 +588,7 @@ nm_settings_connection_delete (NMSettingsConnection *connection, user_data); } else { GError *error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INTERNAL_ERROR, + NM_SETTINGS_ERROR_FAILED, "%s: %s:%d delete() unimplemented", __func__, __FILE__, __LINE__); if (callback) callback (connection, error, user_data); @@ -635,7 +644,7 @@ do_delete (NMSettingsConnection *connection, set_visible (connection, FALSE); /* Tell agents to remove secrets for this connection */ - for_agents = nm_connection_duplicate (NM_CONNECTION (connection)); + for_agents = nm_simple_connection_new_clone (NM_CONNECTION (connection)); nm_connection_clear_secrets (for_agents); nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents); g_object_unref (for_agents); @@ -714,7 +723,7 @@ agent_secrets_done_cb (NMAgentManager *manager, const char *agent_username, gboolean agent_has_modify, const char *setting_name, - NMSettingsGetSecretsFlags flags, + NMSecretAgentGetSecretsFlags flags, GHashTable *secrets, GError *error, gpointer user_data, @@ -726,7 +735,7 @@ agent_secrets_done_cb (NMAgentManager *manager, NMSettingsConnectionSecretsFunc callback = other_data2; gpointer callback_data = other_data3; GError *local = NULL; - GHashTable *hash; + GVariant *dict; gboolean agent_had_system = FALSE; if (error) { @@ -742,7 +751,7 @@ agent_secrets_done_cb (NMAgentManager *manager, } if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { - local = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_SETTING, + local = g_error_new (NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "%s.%d - Connection didn't have requested setting '%s'.", __FILE__, __LINE__, setting_name); callback (self, call_id, NULL, setting_name, local, callback_data); @@ -764,9 +773,9 @@ 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_SETTINGS_GET_SECRETS_FLAG_NONE) { + if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { /* No user interaction was allowed when requesting secrets; the * agent is being bad. Remove system-owned secrets. */ @@ -776,7 +785,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 +795,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 { @@ -804,19 +813,22 @@ agent_secrets_done_cb (NMAgentManager *manager, /* If no user interaction was allowed, make sure that no "unsaved" secrets * came back. Unsaved secrets by definition require user interaction. */ - if (flags == NM_SETTINGS_GET_SECRETS_FLAG_NONE) - for_each_secret (NM_CONNECTION (self), secrets, clear_unsaved_secrets, NULL); + if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) + 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)); - hash = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS); - if (!hash || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, hash, &local)) { + dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (!dict || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, dict, &local)) { + GVariant *secrets_dict; + /* Update the connection with the agent's secrets; by this point if any * system-owned secrets exist in 'secrets' the agent that provided them * will have been authenticated, so those secrets can replace the existing * system secrets. */ - if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets, &local)) { + secrets_dict = nm_utils_connection_hash_to_dict (secrets); + if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets_dict, &local)) { /* Now that all secrets are updated, copy and cache new secrets, * then save them to backing storage. */ @@ -849,6 +861,7 @@ agent_secrets_done_cb (NMAgentManager *manager, local ? local->code : -1, (local && local->message) ? local->message : "(unknown)"); } + g_variant_unref (secrets_dict); } else { nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with existing secrets: (%d) %s", nm_connection_get_uuid (NM_CONNECTION (self)), @@ -860,8 +873,8 @@ agent_secrets_done_cb (NMAgentManager *manager, callback (self, call_id, agent_username, setting_name, local, callback_data); g_clear_error (&local); - if (hash) - g_hash_table_destroy (hash); + if (dict) + g_variant_unref (dict); } /** @@ -884,14 +897,15 @@ guint32 nm_settings_connection_get_secrets (NMSettingsConnection *self, NMAuthSubject *subject, const char *setting_name, - NMSettingsGetSecretsFlags flags, + NMSecretAgentGetSecretsFlags flags, const char **hints, NMSettingsConnectionSecretsFunc callback, gpointer callback_data, GError **error) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - GHashTable *existing_secrets; + GVariant *existing_secrets; + GHashTable *existing_secrets_hash; guint32 call_id = 0; char *joined_hints = NULL; @@ -899,7 +913,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, * will clear secrets on this object's settings. */ if (!priv->system_secrets) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "%s.%d - Internal error; secrets cache invalid.", __FILE__, __LINE__); return 0; @@ -907,17 +921,18 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, /* Make sure the request actually requests something we can return */ if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_SETTING, + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "%s.%d - Connection didn't have requested setting '%s'.", __FILE__, __LINE__, setting_name); return 0; } - existing_secrets = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS); + existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + existing_secrets_hash = nm_utils_connection_dict_to_hash (existing_secrets); call_id = nm_agent_manager_get_secrets (priv->agent_mgr, NM_CONNECTION (self), subject, - existing_secrets, + existing_secrets_hash, setting_name, flags, hints, @@ -925,8 +940,10 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, self, callback, callback_data); + if (existing_secrets_hash) + g_hash_table_unref (existing_secrets_hash); if (existing_secrets) - g_hash_table_unref (existing_secrets); + g_variant_unref (existing_secrets); if (nm_logging_enabled (LOGL_DEBUG, LOGD_SETTINGS)) { if (hints) @@ -989,7 +1006,7 @@ pk_auth_cb (NMAuthChain *chain, /* If our NMSettingsConnection is already gone, do nothing */ if (chain_error) { error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_GENERAL, + NM_SETTINGS_ERROR_FAILED, "Error checking authorization: %s", chain_error->message ? chain_error->message : "(unknown)"); } else if (result != NM_AUTH_CALL_RESULT_YES) { @@ -1021,7 +1038,7 @@ _new_auth_subject (DBusGMethodInvocation *context, GError **error) { NMAuthSubject *subject; - subject = nm_auth_subject_new_from_context (context); + subject = nm_auth_subject_new_unix_process_from_context (context); if (!subject) { g_set_error_literal (error, NM_SETTINGS_ERROR, @@ -1049,10 +1066,10 @@ auth_start (NMSettingsConnection *self, g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); /* Ensure the caller can view this connection */ - if (!nm_auth_uid_in_acl (NM_CONNECTION (self), - priv->session_monitor, - nm_auth_subject_get_uid (subject), - &error_desc)) { + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self), + priv->session_monitor, + subject, + &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, error_desc); @@ -1131,14 +1148,15 @@ get_settings_auth_cb (NMSettingsConnection *self, if (error) dbus_g_method_return_error (context, error); else { - GHashTable *settings; + GVariant *settings; + GHashTable *settings_hash; NMConnection *dupl_con; NMSettingConnection *s_con; NMSettingWireless *s_wifi; guint64 timestamp = 0; - GSList *bssid_list; + char **bssids; - dupl_con = nm_connection_duplicate (NM_CONNECTION (self)); + dupl_con = nm_simple_connection_new_clone (NM_CONNECTION (self)); g_assert (dupl_con); /* Timestamp is not updated in connection's 'timestamp' property, @@ -1157,33 +1175,22 @@ get_settings_auth_cb (NMSettingsConnection *self, * from the same reason as timestamp. Thus we put it here to GetSettings() * return settings too. */ - bssid_list = nm_settings_connection_get_seen_bssids (self); + bssids = nm_settings_connection_get_seen_bssids (self); s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (dupl_con)); - if (bssid_list && s_wifi) { - g_object_set (s_wifi, NM_SETTING_WIRELESS_SEEN_BSSIDS, bssid_list, NULL); - g_slist_free_full (bssid_list, g_free); - } - - /* 802-11-wireless.security property is deprecated. But we set it here so that - * we don't disturb old clients that might expect it being properly set for - * secured Wi-Fi connections. - */ - if (nm_connection_get_setting_wireless_security (NM_CONNECTION (dupl_con))) { - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (dupl_con)); - g_assert (s_wifi); - g_object_set (s_wifi, - NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NULL); - } + if (bssids && bssids[0] && s_wifi) + g_object_set (s_wifi, NM_SETTING_WIRELESS_SEEN_BSSIDS, bssids, NULL); + g_free (bssids); /* Secrets should *never* be returned by the GetSettings method, they * get returned by the GetSecrets method which can be better * protected against leakage of secrets to unprivileged callers. */ - settings = nm_connection_to_hash (NM_CONNECTION (dupl_con), NM_SETTING_HASH_FLAG_NO_SECRETS); + settings = nm_connection_to_dbus (NM_CONNECTION (dupl_con), NM_CONNECTION_SERIALIZE_NO_SECRETS); g_assert (settings); - dbus_g_method_return (context, settings); - g_hash_table_destroy (settings); + settings_hash = nm_utils_connection_dict_to_hash (settings); + dbus_g_method_return (context, settings_hash); + g_hash_table_destroy (settings_hash); + g_variant_unref (settings); g_object_unref (dupl_con); } } @@ -1214,6 +1221,60 @@ typedef struct { } 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 *connection) +{ + gboolean has_secrets = FALSE; + + nm_connection_for_each_setting_value (connection, has_some_secrets_cb, &has_secrets); + return has_secrets; +} + +static void +cached_secrets_to_connection (NMSettingsConnection *self, NMConnection *connection) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + GVariant *secrets_dict; + + if (priv->agent_secrets) { + secrets_dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (secrets_dict) { + (void) nm_connection_update_secrets (connection, NULL, secrets_dict, NULL); + g_variant_unref (secrets_dict); + } + } + if (priv->system_secrets) { + secrets_dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (secrets_dict) { + (void) nm_connection_update_secrets (connection, NULL, secrets_dict, NULL); + g_variant_unref (secrets_dict); + } + } +} + +static void update_complete (NMSettingsConnection *self, UpdateInfo *info, GError *error) @@ -1243,7 +1304,7 @@ con_update_cb (NMSettingsConnection *self, * as agent-owned secrets are the only ones we send back be saved. * Only send secrets to agents of the same UID that called update too. */ - for_agent = nm_connection_duplicate (NM_CONNECTION (self)); + for_agent = nm_simple_connection_new_clone (NM_CONNECTION (self)); nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); @@ -1269,11 +1330,19 @@ update_auth_cb (NMSettingsConnection *self, return; } - /* Cache the new secrets from the agent, as stuff like inotify-triggered - * changes to connection's backing config files will blow them away if - * they're in the main connection. - */ - update_agent_secrets_cache (self, info->new_settings); + if (!any_secrets_present (info->new_settings)) { + /* 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. + */ + cached_secrets_to_connection (self, info->new_settings); + } else { + /* Cache the new secrets from the agent, as stuff like inotify-triggered + * changes to connection's backing config files will blow them away if + * they're in the main connection. + */ + update_agent_secrets_cache (self, info->new_settings); + } if (info->save_to_disk) { nm_settings_connection_replace_and_commit (self, @@ -1342,7 +1411,10 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, /* Check if the settings are valid first */ if (new_settings) { - tmp = nm_connection_new_from_hash (new_settings, &error); + GVariant *new_settings_dict = nm_utils_connection_hash_to_dict (new_settings); + + tmp = nm_simple_connection_new_from_dbus (new_settings_dict, &error); + g_variant_unref (new_settings_dict); if (!tmp) { g_assert (error); goto error; @@ -1357,10 +1429,10 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, * that's sending the update request. You can't make a connection * invisible to yourself. */ - if (!nm_auth_uid_in_acl (tmp ? tmp : NM_CONNECTION (self), - priv->session_monitor, - nm_auth_subject_get_uid (subject), - &error_desc)) { + if (!nm_auth_is_subject_in_acl (tmp ? tmp : NM_CONNECTION (self), + priv->session_monitor, + subject, + &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, error_desc); @@ -1411,7 +1483,7 @@ impl_settings_connection_save (NMSettingsConnection *self, DBusGMethodInvocation *context) { /* Do nothing if the connection is already synced with disk */ - if (NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->unsaved == TRUE) + if (nm_settings_connection_get_unsaved (self)) impl_settings_connection_update_helper (self, NULL, context, TRUE); else dbus_g_method_return (context); @@ -1497,6 +1569,7 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self, { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); DBusGMethodInvocation *context = user_data; + GVariant *dict; GHashTable *hash; priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id)); @@ -1509,20 +1582,24 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self, * secrets from backing storage and those returned from the agent * by the time we get here. */ - hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS); - if (!hash) + dict = nm_connection_to_dbus (NM_CONNECTION (self), NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (dict) + hash = nm_utils_connection_dict_to_hash (dict); + else hash = g_hash_table_new (NULL, NULL); dbus_g_method_return (context, hash); g_hash_table_destroy (hash); + if (dict) + g_variant_unref (dict); } } static void -dbus_secrets_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data) +dbus_get_secrets_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + NMAuthSubject *subject, + GError *error, + gpointer user_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); char *setting_name = user_data; @@ -1533,7 +1610,8 @@ dbus_secrets_auth_cb (NMSettingsConnection *self, call_id = nm_settings_connection_get_secrets (self, subject, setting_name, - NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED, + NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED + | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS, NULL, dbus_get_agent_secrets_cb, context, @@ -1566,7 +1644,7 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self, context, subject, get_modify_permission_basic (self), - dbus_secrets_auth_cb, + dbus_get_secrets_auth_cb, g_strdup (setting_name)); g_object_unref (subject); } else { @@ -1575,6 +1653,67 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self, } } +static void +clear_secrets_cb (NMSettingsConnection *self, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +dbus_clear_secrets_auth_cb (NMSettingsConnection *self, + DBusGMethodInvocation *context, + NMAuthSubject *subject, + GError *error, + gpointer user_data) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (error) + dbus_g_method_return_error (context, error); + else { + /* Clear secrets in connection and caches */ + nm_connection_clear_secrets (NM_CONNECTION (self)); + if (priv->system_secrets) + nm_connection_clear_secrets (priv->system_secrets); + if (priv->agent_secrets) + nm_connection_clear_secrets (priv->agent_secrets); + + /* Tell agents to remove secrets for this connection */ + nm_agent_manager_delete_secrets (priv->agent_mgr, NM_CONNECTION (self)); + + nm_settings_connection_commit_changes (self, clear_secrets_cb, context); + } +} + +static void +impl_settings_connection_clear_secrets (NMSettingsConnection *self, + DBusGMethodInvocation *context) +{ + NMAuthSubject *subject; + GError *error = NULL; + + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, + context, + subject, + get_modify_permission_basic (self), + dbus_clear_secrets_auth_cb, + NULL); + g_object_unref (subject); + } else { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + /**************************************************************/ void @@ -1592,11 +1731,57 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self) gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->unsaved; + return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_UNSAVED); } /**************************************************************/ +NMSettingsConnectionFlags +nm_settings_connection_get_flags (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->flags; +} + +NMSettingsConnectionFlags +nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set) +{ + NMSettingsConnectionFlags new_flags; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); + g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, NM_SETTINGS_CONNECTION_FLAGS_NONE); + + new_flags = NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->flags; + if (set) + new_flags |= flags; + else + new_flags &= ~flags; + return nm_settings_connection_set_flags_all (self, new_flags); +} + +NMSettingsConnectionFlags +nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags) +{ + NMSettingsConnectionPrivate *priv; + NMSettingsConnectionFlags old_flags; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); + g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, NM_SETTINGS_CONNECTION_FLAGS_NONE); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + old_flags = priv->flags; + if (old_flags != flags) { + priv->flags = flags; + g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_FLAGS); + if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED)) + g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_UNSAVED); + } + return old_flags; +} + +/*************************************************************/ + /** * nm_settings_connection_get_timestamp: * @connection: the #NMSettingsConnection @@ -1714,59 +1899,34 @@ nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection g_key_file_free (timestamps_file); } -static guint -mac_hash (gconstpointer v) -{ - const guint8 *p = v; - guint32 i, h = 5381; - - for (i = 0; i < ETH_ALEN; i++) - h = (h << 5) + h + p[i]; - return h; -} - -static gboolean -mac_equal (gconstpointer a, gconstpointer b) -{ - return memcmp (a, b, ETH_ALEN) == 0; -} - -static guint8 * -mac_dup (const struct ether_addr *old) -{ - guint8 *new; - - g_return_val_if_fail (old != NULL, NULL); - - new = g_malloc0 (ETH_ALEN); - memcpy (new, old, ETH_ALEN); - return new; -} - /** * nm_settings_connection_get_seen_bssids: * @connection: the #NMSettingsConnection * * Returns current list of seen BSSIDs for the connection. * - * Returns: (transfer full) list of seen BSSIDs (in the standard hex-digits-and-colons notation). - * The caller is responsible for freeing the list. + * Returns: (transfer container) list of seen BSSIDs (in the standard hex-digits-and-colons notation). + * The caller is responsible for freeing the list, but not the content. **/ -GSList * +char ** nm_settings_connection_get_seen_bssids (NMSettingsConnection *connection) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); GHashTableIter iter; - char *bssid_str; - GSList *bssid_list = NULL; + char **bssids, *bssid; + int i; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL); + bssids = g_new (char *, g_hash_table_size (priv->seen_bssids) + 1); + + i = 0; g_hash_table_iter_init (&iter, priv->seen_bssids); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &bssid_str)) - bssid_list = g_slist_prepend (bssid_list, g_strdup (bssid_str)); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &bssid)) + bssids[i++] = bssid; + bssids[i] = NULL; - return bssid_list; + return bssids; } /** @@ -1778,7 +1938,7 @@ nm_settings_connection_get_seen_bssids (NMSettingsConnection *connection) **/ gboolean nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection, - const struct ether_addr *bssid) + const char *bssid) { g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE); g_return_val_if_fail (bssid != NULL, FALSE); @@ -1796,7 +1956,7 @@ nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection, **/ void nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection, - const struct ether_addr *seen_bssid) + const char *seen_bssid) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); const char *connection_uuid; @@ -1814,8 +1974,8 @@ nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection, return; /* Already in the list */ /* Add the new BSSID; let the hash take ownership of the allocated BSSID string */ - bssid_str = nm_utils_hwaddr_ntoa (seen_bssid, ARPHRD_ETHER); - g_hash_table_insert (priv->seen_bssids, mac_dup (seen_bssid), bssid_str); + bssid_str = g_strdup (seen_bssid); + g_hash_table_insert (priv->seen_bssids, bssid_str, bssid_str); /* Build up a list of all the BSSIDs in string form */ n = 0; @@ -1853,19 +2013,6 @@ nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection, } } -static void -add_seen_bssid_string (NMSettingsConnection *self, const char *bssid) -{ - struct ether_addr mac; - - g_return_if_fail (bssid != NULL); - if (ether_aton_r (bssid, &mac)) { - g_hash_table_insert (NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->seen_bssids, - mac_dup (&mac), - g_strdup (bssid)); - } -} - /** * nm_settings_connection_read_and_fill_seen_bssids: * @connection: the #NMSettingsConnection @@ -1896,8 +2043,8 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connecti if (tmp_strv) { g_hash_table_remove_all (priv->seen_bssids); for (i = 0; i < len; i++) - add_seen_bssid_string (connection, tmp_strv[i]); - g_strfreev (tmp_strv); + g_hash_table_insert (priv->seen_bssids, tmp_strv[i], tmp_strv[i]); + g_free (tmp_strv); } else { /* If this connection didn't have an entry in the seen-bssids database, * maybe this is the first time we've read it in, so populate the @@ -1907,8 +2054,11 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connecti s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (connection)); if (s_wifi) { len = nm_setting_wireless_get_num_seen_bssids (s_wifi); - for (i = 0; i < len; i++) - add_seen_bssid_string (connection, nm_setting_wireless_get_seen_bssid (s_wifi, i)); + for (i = 0; i < len; i++) { + char *bssid_dup = g_strdup (nm_setting_wireless_get_seen_bssid (s_wifi, i)); + + g_hash_table_insert (priv->seen_bssids, bssid_dup, bssid_dup); + } } } } @@ -1992,30 +2142,28 @@ nm_settings_connection_can_autoconnect (NMSettingsConnection *connection) * Gets the "nm-generated" flag on @connection. * * A connection is "nm-generated" if it was generated by - * nm_device_generate_connection() and then assumed by #NMManager, and - * it has not been modified or saved by the user since then. In other - * words, an "nm-generated" connection reflects state that is entirely - * external to NetworkManager. + * nm_device_generate_connection() and has not been modified or + * saved by the user since then. */ gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *connection) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->nm_generated; + return NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED); } /** - * nm_settings_connection_set_nm_generated: + * nm_settings_connection_get_nm_generated_assumed: * @connection: an #NMSettingsConnection * - * Sets the "nm-generated" flag on @connection; see - * nm_settings_connection_get_nm_generated(). + * Gets the "nm-generated-assumed" flag on @connection. + * + * The connection is a generated connection especially + * generated for connection assumption. */ -void -nm_settings_connection_set_nm_generated (NMSettingsConnection *connection) +gboolean +nm_settings_connection_get_nm_generated_assumed (NMSettingsConnection *connection) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection); - - priv->nm_generated = TRUE; + return NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED_ASSUMED); } /**************************************************************/ @@ -2035,7 +2183,7 @@ nm_settings_connection_init (NMSettingsConnection *self) priv->agent_mgr = nm_agent_manager_get (); - priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free); + priv->seen_bssids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); priv->autoconnect_retries = AUTOCONNECT_RETRIES_DEFAULT; priv->autoconnect_blocked_reason = NM_DEVICE_STATE_REASON_NONE; @@ -2051,40 +2199,42 @@ dispose (GObject *object) NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); GSList *iter; - if (priv->disposed) - goto out; - priv->disposed = TRUE; - if (priv->updated_idle_id) { g_source_remove (priv->updated_idle_id); priv->updated_idle_id = 0; } - if (priv->system_secrets) - g_object_unref (priv->system_secrets); - if (priv->agent_secrets) - g_object_unref (priv->agent_secrets); + /* Disconnect handlers. + * changed_cb() has to be disconnected *before* nm_connection_clear_secrets(), + * because nm_connection_clear_secrets() emits NM_CONNECTION_CHANGED signal. + */ + g_signal_handlers_disconnect_by_func (self, G_CALLBACK (secrets_cleared_cb), NULL); + g_signal_handlers_disconnect_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE)); + + nm_connection_clear_secrets (NM_CONNECTION (self)); + g_clear_object (&priv->system_secrets); + g_clear_object (&priv->agent_secrets); /* Cancel PolicyKit requests */ - for (iter = priv->pending_auths; iter; iter = g_slist_next (iter)) - nm_auth_chain_unref ((NMAuthChain *) iter->data); - g_slist_free (priv->pending_auths); + g_slist_free_full (priv->pending_auths, (GDestroyNotify) nm_auth_chain_unref); priv->pending_auths = NULL; /* Cancel in-progress secrets requests */ for (iter = priv->reqs; iter; iter = g_slist_next (iter)) nm_agent_manager_cancel_secrets (priv->agent_mgr, GPOINTER_TO_UINT (iter->data)); g_slist_free (priv->reqs); + priv->reqs = NULL; - g_hash_table_destroy (priv->seen_bssids); + g_clear_pointer (&priv->seen_bssids, (GDestroyNotify) g_hash_table_destroy); set_visible (self, FALSE); - if (priv->session_changed_id) + if (priv->session_changed_id) { g_signal_handler_disconnect (priv->session_monitor, priv->session_changed_id); - g_object_unref (priv->agent_mgr); + priv->session_changed_id = 0; + } + g_clear_object (&priv->agent_mgr); -out: G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object); } @@ -2092,14 +2242,18 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (object); + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); switch (prop_id) { case PROP_VISIBLE: g_value_set_boolean (value, priv->visible); break; case PROP_UNSAVED: - g_value_set_boolean (value, priv->unsaved); + g_value_set_boolean (value, nm_settings_connection_get_unsaved (self)); + break; + case PROP_FLAGS: + g_value_set_uint (value, nm_settings_connection_get_flags (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2111,7 +2265,16 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); + + switch (prop_id) { + case PROP_FLAGS: + nm_settings_connection_set_flags_all (self, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -2133,21 +2296,26 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) /* Properties */ g_object_class_install_property (object_class, PROP_VISIBLE, - g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, - "Visible", - "Visible", + g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, "", "", FALSE, - G_PARAM_READABLE)); + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_UNSAVED, - g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, - "Unsaved", - "TRUE when the connection has not yet been saved " - "to permanent storage (eg disk) or when it " - "has been changed but not yet saved.", + g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "", FALSE, - G_PARAM_READABLE)); + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_FLAGS, + g_param_spec_uint (NM_SETTINGS_CONNECTION_FLAGS, "", "", + NM_SETTINGS_CONNECTION_FLAGS_NONE, + NM_SETTINGS_CONNECTION_FLAGS_ALL, + NM_SETTINGS_CONNECTION_FLAGS_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); /* Signals */ @@ -2183,3 +2351,9 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) G_TYPE_FROM_CLASS (class), &dbus_glib_nm_settings_connection_object_info); } + +static void +nm_settings_connection_connection_interface_init (NMConnectionInterface *iface) +{ +} + |