From 8a79fb1d41576de785923b0169ba963a6ea88b73 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 12 Apr 2013 16:09:29 -0500 Subject: [PATCH] settings: implement ability to add connections without saving them to disk We don't always want to immediately write new connections to disk, to facilitate "runtime" or "temporary" connections where an interface's runtime config isn't backed by on-disk config. Also, just because an interface's configuration is changed doesn't necessarily mean that new configuration should be written to disk either. Add D-Bus methods for adding new connections and for updating existing connections that don't immediately save the connection to disk. Also add infrastructure to indicate to plugins that the new connection shouldn't be immediately saved if the connection was added with the new method. --- introspection/nm-settings-connection.xml | 26 +++- introspection/nm-settings.xml | 21 ++++ src/nm-manager.c | 1 + src/settings/nm-settings-connection.c | 115 ++++++++++++------ src/settings/nm-settings.c | 91 +++++++++----- src/settings/nm-settings.h | 1 + src/settings/nm-system-config-interface.c | 3 +- src/settings/nm-system-config-interface.h | 7 +- src/settings/plugins/example/plugin.c | 10 +- src/settings/plugins/ifcfg-rh/plugin.c | 17 ++- src/settings/plugins/ifcfg-rh/writer.c | 33 ++++- src/settings/plugins/ifcfg-rh/writer.h | 3 + src/settings/plugins/ifnet/Makefile.am | 4 +- .../plugins/ifnet/connection_parser.c | 76 ++++++++++-- .../plugins/ifnet/connection_parser.h | 2 + src/settings/plugins/ifnet/errors.c | 35 ++++++ src/settings/plugins/ifnet/errors.h | 30 +++++ src/settings/plugins/ifnet/net_utils.c | 11 -- src/settings/plugins/ifnet/net_utils.h | 2 - src/settings/plugins/ifnet/plugin.c | 58 +++------ src/settings/plugins/ifnet/tests/Makefile.am | 3 +- src/settings/plugins/keyfile/plugin.c | 13 +- 22 files changed, 410 insertions(+), 152 deletions(-) create mode 100644 src/settings/plugins/ifnet/errors.c create mode 100644 src/settings/plugins/ifnet/errors.h diff --git a/introspection/nm-settings-connection.xml b/introspection/nm-settings-connection.xml index d7e5dbf033..9cfa935db8 100644 --- a/introspection/nm-settings-connection.xml +++ b/introspection/nm-settings-connection.xml @@ -9,10 +9,11 @@ - Update the connection with new settings and properties, replacing - all previous settings and properties. Secrets may be part of the - update request, and will be either stored in persistent storage or - given to a Secret Agent for storage, depending on the request. + Update the connection with new settings and properties (replacing + all previous settings and properties) and save the connection to + disk. Secrets may be part of the update request, and will be either + stored in persistent storage or sent to a Secret Agent for storage, + depending on the flags associated with each secret. @@ -23,6 +24,23 @@ + + + Update the connection with new settings and properties (replacing + all previous settings and properties) but do not immediately save + the connection to disk. Secrets may be part of the update request + and may sent to a Secret Agent for storage, depending on the the + flags associated with each secret. + + + + + + New connection settings, properties, and (optionally) secrets. + + + + Delete the connection. diff --git a/introspection/nm-settings.xml b/introspection/nm-settings.xml index c791466843..794e302b23 100644 --- a/introspection/nm-settings.xml +++ b/introspection/nm-settings.xml @@ -56,6 +56,27 @@ + + + Add new connection but do not save it to disk immediately. This + operation does not start the network connection unless (1) device is + idle and able to connect to the network described by the new connection, + and (2) the connection is allowed to be started automatically. + + + + + + Connection settings and properties. + + + + + Object path of the new connection that was just added. + + + + Save the hostname to persistent configuration. diff --git a/src/nm-manager.c b/src/nm-manager.c index 170abdae64..21a20945c0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3089,6 +3089,7 @@ add_and_activate_auth_done (PendingActivation *pending, GError *error) /* Basic sender auth checks performed; try to add the connection */ nm_settings_add_connection (priv->settings, pending->connection, + TRUE, pending->context, activation_add_done, pending); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 093bc38fa1..747a66c531 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -52,6 +52,10 @@ static void impl_settings_connection_update (NMSettingsConnection *connection, GHashTable *new_settings, DBusGMethodInvocation *context); +static void impl_settings_connection_update_unsaved (NMSettingsConnection *connection, + GHashTable *new_settings, + DBusGMethodInvocation *context); + static void impl_settings_connection_delete (NMSettingsConnection *connection, DBusGMethodInvocation *context); @@ -1159,8 +1163,26 @@ typedef struct { DBusGMethodInvocation *context; NMAgentManager *agent_mgr; gulong sender_uid; + NMConnection *new_settings; + gboolean save_to_disk; } UpdateInfo; +static void +update_complete (NMSettingsConnection *self, + UpdateInfo *info, + GError *error) +{ + if (error) + dbus_g_method_return_error (info->context, error); + else + dbus_g_method_return (info->context); + + g_clear_object (&info->agent_mgr); + g_clear_object (&info->new_settings); + memset (info, 0, sizeof (*info)); + g_free (info); +} + static void con_update_cb (NMSettingsConnection *self, GError *error, @@ -1169,9 +1191,7 @@ con_update_cb (NMSettingsConnection *self, UpdateInfo *info = user_data; NMConnection *for_agent; - if (error) - dbus_g_method_return_error (info->context, error); - else { + if (!error) { /* Dupe the connection so we can clear out non-agent-owned secrets, * 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. @@ -1186,9 +1206,7 @@ con_update_cb (NMSettingsConnection *self, dbus_g_method_return (info->context); } - g_object_unref (info->agent_mgr); - memset (info, 0, sizeof (*info)); - g_free (info); + update_complete (self, info, error); } static void @@ -1198,32 +1216,36 @@ update_auth_cb (NMSettingsConnection *self, GError *error, gpointer data) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - NMConnection *new_settings = data; - UpdateInfo *info; + UpdateInfo *info = data; + GError *local = NULL; - if (error) - dbus_g_method_return_error (context, error); - else { - info = g_malloc0 (sizeof (*info)); - info->context = context; - info->agent_mgr = g_object_ref (priv->agent_mgr); - info->sender_uid = sender_uid; - - /* 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, new_settings); - - /* Update and commit our settings. */ - nm_settings_connection_replace_and_commit (self, - new_settings, - con_update_cb, - info); + if (error) { + update_complete (self, info, error); + return; } - g_object_unref (new_settings); + info->sender_uid = sender_uid; + + /* 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, + info->new_settings, + con_update_cb, + info); + } else { + /* Do nothing if there's nothing to update */ + if (!nm_connection_compare (NM_CONNECTION (self), info->new_settings, NM_SETTING_COMPARE_FLAG_EXACT)) { + if (!nm_settings_connection_replace_settings (self, info->new_settings, TRUE, &local)) + g_assert (local); + } + con_update_cb (self, local, info); + g_clear_error (&local); + } } static const char * @@ -1253,13 +1275,15 @@ get_modify_permission_update (NMConnection *old, NMConnection *new) } static void -impl_settings_connection_update (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context) +impl_settings_connection_update_helper (NMSettingsConnection *self, + GHashTable *new_settings, + DBusGMethodInvocation *context, + gboolean save_to_disk) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *tmp; GError *error = NULL; + UpdateInfo *info; /* If the connection is read-only, that has to be changed at the source of * the problem (ex a system settings plugin that can't write connections out) @@ -1295,11 +1319,34 @@ impl_settings_connection_update (NMSettingsConnection *self, return; } + info = g_malloc0 (sizeof (*info)); + info->context = context; + info->agent_mgr = g_object_ref (priv->agent_mgr); + info->sender_uid = G_MAXULONG; + info->save_to_disk = save_to_disk; + info->new_settings = tmp; + auth_start (self, context, - get_modify_permission_update (NM_CONNECTION (self), tmp), + get_modify_permission_update (NM_CONNECTION (self), info->new_settings), update_auth_cb, - tmp); + info); +} + +static void +impl_settings_connection_update (NMSettingsConnection *self, + GHashTable *new_settings, + DBusGMethodInvocation *context) +{ + impl_settings_connection_update_helper (self, new_settings, context, TRUE); +} + +static void +impl_settings_connection_update_unsaved (NMSettingsConnection *self, + GHashTable *new_settings, + DBusGMethodInvocation *context) +{ + impl_settings_connection_update_helper (self, new_settings, context, FALSE); } static void diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 9eeee9ead0..9e82003f90 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -100,6 +100,10 @@ static void impl_settings_add_connection (NMSettings *self, GHashTable *settings, DBusGMethodInvocation *context); +static void impl_settings_add_connection_unsaved (NMSettings *self, + GHashTable *settings, + DBusGMethodInvocation *context); + static void impl_settings_save_hostname (NMSettings *self, const char *hostname, DBusGMethodInvocation *context); @@ -894,6 +898,7 @@ remove_default_wired_connection (NMSettings *self, static NMSettingsConnection * add_new_connection (NMSettings *self, NMConnection *connection, + gboolean save_to_disk, GError **error) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); @@ -927,14 +932,20 @@ add_new_connection (NMSettings *self, NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); GError *add_error = NULL; - g_clear_error (error); - added = nm_system_config_interface_add_connection (plugin, connection, &add_error); + added = nm_system_config_interface_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { claim_connection (self, added, TRUE); return added; } - g_propagate_error (error, add_error); + nm_log_dbg (LOGD_SETTINGS, "Failed to add %s/'%s': %s", + nm_connection_get_uuid (connection), + nm_connection_get_id (connection), + add_error ? add_error->message : "(unknown)"); + g_clear_error (&add_error); } + + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_ADD_FAILED, + "No plugin supported adding this connection"); return NULL; } @@ -986,13 +997,14 @@ pk_add_cb (NMAuthChain *chain, NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthCallResult result; - GError *error = NULL, *add_error = NULL; + GError *error = NULL; NMConnection *connection; NMSettingsConnection *added = NULL; NMSettingsAddCallback callback; gpointer callback_data; gulong caller_uid; const char *perm; + gboolean save_to_disk; priv->auths = g_slist_remove (priv->auths, chain); @@ -1013,15 +1025,8 @@ pk_add_cb (NMAuthChain *chain, /* Authorized */ connection = nm_auth_chain_get_data (chain, "connection"); g_assert (connection); - added = add_new_connection (self, connection, &add_error); - if (!added) { - error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_ADD_FAILED, - "Saving connection failed: (%d) %s", - add_error ? add_error->code : -1, - (add_error && add_error->message) ? add_error->message : "(unknown)"); - g_clear_error (&add_error); - } + save_to_disk = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "save-to-disk")); + added = add_new_connection (self, connection, save_to_disk, &error); } callback = nm_auth_chain_get_data (chain, "callback"); @@ -1038,19 +1043,6 @@ pk_add_cb (NMAuthChain *chain, nm_auth_chain_unref (chain); } -static void -add_cb (NMSettings *self, - NMSettingsConnection *connection, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - if (error) - dbus_g_method_return_error (context, error); - else - dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); -} - /* FIXME: remove if/when kernel supports adhoc wpa */ static gboolean is_adhoc_wpa (NMConnection *connection) @@ -1086,6 +1078,7 @@ is_adhoc_wpa (NMConnection *connection) void nm_settings_add_connection (NMSettings *self, NMConnection *connection, + gboolean save_to_disk, DBusGMethodInvocation *context, NMSettingsAddCallback callback, gpointer user_data) @@ -1178,6 +1171,7 @@ nm_settings_add_connection (NMSettings *self, nm_auth_chain_set_data (chain, "callback", callback, NULL); nm_auth_chain_set_data (chain, "callback-data", user_data, NULL); nm_auth_chain_set_data_ulong (chain, "caller-uid", caller_uid); + nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL); } else { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -1188,16 +1182,35 @@ nm_settings_add_connection (NMSettings *self, } static void -impl_settings_add_connection (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context) +impl_settings_add_connection_add_cb (NMSettings *self, + NMSettingsConnection *connection, + GError *error, + DBusGMethodInvocation *context, + gpointer user_data) +{ + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); +} + +static void +impl_settings_add_connection_helper (NMSettings *self, + GHashTable *settings, + gboolean save_to_disk, + DBusGMethodInvocation *context) { NMConnection *connection; GError *error = NULL; connection = nm_connection_new_from_hash (settings, &error); if (connection) { - nm_settings_add_connection (self, connection, context, add_cb, NULL); + nm_settings_add_connection (self, + connection, + save_to_disk, + context, + impl_settings_add_connection_add_cb, + NULL); g_object_unref (connection); } else { g_assert (error); @@ -1206,6 +1219,22 @@ impl_settings_add_connection (NMSettings *self, } } +static void +impl_settings_add_connection (NMSettings *self, + GHashTable *settings, + DBusGMethodInvocation *context) +{ + impl_settings_add_connection_helper (self, settings, TRUE, context); +} + +static void +impl_settings_add_connection_unsaved (NMSettings *self, + GHashTable *settings, + DBusGMethodInvocation *context) +{ + impl_settings_add_connection_helper (self, settings, FALSE, context); +} + static void pk_hostname_cb (NMAuthChain *chain, GError *chain_error, @@ -1406,7 +1435,7 @@ default_wired_try_update (NMDefaultWiredConnection *wired, g_assert (id); remove_default_wired_connection (self, NM_SETTINGS_CONNECTION (wired), FALSE); - added = add_new_connection (self, NM_CONNECTION (wired), &error); + added = add_new_connection (self, NM_CONNECTION (wired), TRUE, &error); if (added) { nm_settings_connection_delete (NM_SETTINGS_CONNECTION (wired), delete_cb, NULL); diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 66dbcac094..351c2931e1 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -94,6 +94,7 @@ typedef void (*NMSettingsAddCallback) (NMSettings *settings, void nm_settings_add_connection (NMSettings *self, NMConnection *connection, + gboolean save_to_disk, DBusGMethodInvocation *context, NMSettingsAddCallback callback, gpointer user_data); diff --git a/src/settings/nm-system-config-interface.c b/src/settings/nm-system-config-interface.c index 45aa6305da..1a9d5d58ed 100644 --- a/src/settings/nm-system-config-interface.c +++ b/src/settings/nm-system-config-interface.c @@ -150,13 +150,14 @@ nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config) NMSettingsConnection * nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error) { g_return_val_if_fail (config != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, error); + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, save_to_disk, error); return NULL; } diff --git a/src/settings/nm-system-config-interface.h b/src/settings/nm-system-config-interface.h index 96a640619e..9648fdb5d9 100644 --- a/src/settings/nm-system-config-interface.h +++ b/src/settings/nm-system-config-interface.h @@ -110,12 +110,14 @@ struct _NMSystemConfigInterface { GSList * (*get_unmanaged_specs) (NMSystemConfigInterface *config); /* - * Save the given connection to backing storage, and return a new + * Initialize the plugin-specific connection and return a new * NMSettingsConnection subclass that contains the same settings as the - * original connection. + * original connection. The connection should only be saved to backing + * storage if @save_to_disk is TRUE. */ NMSettingsConnection * (*add_connection) (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error); /* Signals */ @@ -139,6 +141,7 @@ GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface NMSettingsConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error); G_END_DECLS diff --git a/src/settings/plugins/example/plugin.c b/src/settings/plugins/example/plugin.c index 3a1ea96baa..8d4b627705 100644 --- a/src/settings/plugins/example/plugin.c +++ b/src/settings/plugins/example/plugin.c @@ -503,6 +503,7 @@ get_connections (NMSystemConfigInterface *config) static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error) { SCPluginExample *self = SC_PLUGIN_EXAMPLE (config); @@ -513,10 +514,11 @@ add_connection (NMSystemConfigInterface *config, * way we don't trigger the new NMSettingsConnection subclass' file watch * functions needlessly. */ - if (write_connection (connection, NULL, &path, error)) { - added = _internal_new_connection (self, path, connection, error); - g_free (path); - } + if (save_to_disk && !write_connection (connection, NULL, &path, error)) + return NULL; + + added = _internal_new_connection (self, path, connection, error); + g_free (path); return added; } diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c index d6b3c447c0..13edfb17ea 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.c +++ b/src/settings/plugins/ifcfg-rh/plugin.c @@ -452,17 +452,26 @@ get_unmanaged_specs (NMSystemConfigInterface *config) static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error) { SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); NMIfcfgConnection *added = NULL; char *path = NULL; - /* Write it out first, then add the connection to our internal list */ - if (writer_new_connection (connection, IFCFG_DIR, &path, error)) { - added = _internal_new_connection (self, path, connection, error); - g_free (path); + /* Ensure we reject attempts to add the connection long before we're + * asked to write it to disk. + */ + if (!writer_can_write_connection (connection, error)) + return NULL; + + if (save_to_disk) { + if (!writer_new_connection (connection, IFCFG_DIR, &path, error)) + return NULL; } + + added = _internal_new_connection (self, path, connection, error); + g_free (path); return (NMSettingsConnection *) added; } diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index e393a6da9c..022af1a14b 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -2105,12 +2105,11 @@ write_connection (NMConnection *connection, gboolean no_8021x = FALSE; gboolean wired = FALSE; - s_con = nm_connection_get_setting_connection (connection); - if (!s_con) { - g_set_error (error, IFCFG_PLUGIN_ERROR, 0, - "Missing '%s' setting", NM_SETTING_CONNECTION_SETTING_NAME); + if (!writer_can_write_connection (connection, error)) return FALSE; - } + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); if (filename) { /* For existing connections, 'filename' should be full path to ifcfg file */ @@ -2235,6 +2234,30 @@ out: return success; } +gboolean +writer_can_write_connection (NMConnection *connection, GError **error) +{ + NMSettingConnection *s_con; + + if ( ( nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME) + && !nm_connection_get_setting_pppoe (connection)) + || nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME) + || nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME) + || nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME) + || nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME) + || nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) + return TRUE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_set_error (error, IFCFG_PLUGIN_ERROR, 0, + "The ifcfg-rh plugin cannot write the connection '%s' (type '%s' pppoe %d)", + nm_connection_get_id (connection), + nm_setting_connection_get_connection_type (s_con), + !!nm_connection_get_setting_pppoe (connection)); + return FALSE; +} + gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, diff --git a/src/settings/plugins/ifcfg-rh/writer.h b/src/settings/plugins/ifcfg-rh/writer.h index edeac0cccc..894313dd06 100644 --- a/src/settings/plugins/ifcfg-rh/writer.h +++ b/src/settings/plugins/ifcfg-rh/writer.h @@ -25,6 +25,9 @@ #include #include +gboolean writer_can_write_connection (NMConnection *connection, + GError **error); + gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, char **out_filename, diff --git a/src/settings/plugins/ifnet/Makefile.am b/src/settings/plugins/ifnet/Makefile.am index 234d4adbbb..ed387e583a 100644 --- a/src/settings/plugins/ifnet/Makefile.am +++ b/src/settings/plugins/ifnet/Makefile.am @@ -45,7 +45,9 @@ lib_ifnet_io_la_SOURCES = \ net_utils.h\ net_utils.c\ wpa_parser.h\ - wpa_parser.c + wpa_parser.c \ + errors.h \ + errors.c lib_ifnet_io_la_CPPFLAGS = \ $(GLIB_CFLAGS) \ diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c index 5ccf5b3495..8aed34437b 100644 --- a/src/settings/plugins/ifnet/connection_parser.c +++ b/src/settings/plugins/ifnet/connection_parser.c @@ -43,6 +43,7 @@ #include "wpa_parser.h" #include "connection_parser.h" #include "nm-ifnet-connection.h" +#include "errors.h" static char * connection_id_from_ifnet_name (const char *conn_name) @@ -2806,16 +2807,11 @@ ifnet_update_parsers_by_connection (NMConnection *connection, gboolean wired = FALSE, pppoe = TRUE; const char *new_name = NULL; - s_con = - NM_SETTING_CONNECTION (nm_connection_get_setting - (connection, NM_TYPE_SETTING_CONNECTION)); - if (!s_con) { - g_set_error (error, ifnet_plugin_error_quark (), 0, - "Missing '%s' setting", - NM_SETTING_CONNECTION_SETTING_NAME); + if (!ifnet_can_write_connection (connection, error)) return FALSE; - } + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); type = nm_setting_connection_get_connection_type (s_con); if (!type) { @@ -2910,6 +2906,66 @@ ifnet_delete_connection_in_parsers (const char *conn_name, return result; } +static void +check_unsupported_secrets (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + gboolean *unsupported_secret = user_data; + + 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 (secret_flags != NM_SETTING_SECRET_FLAG_NONE) + *unsupported_secret = TRUE; + } +} + +gboolean +ifnet_can_write_connection (NMConnection *connection, GError **error) +{ + NMSettingConnection *s_con; + gboolean has_unsupported_secrets = FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + /* If the connection is not available for all users, ignore + * it as this plugin only deals with System Connections */ + if (nm_setting_connection_get_num_permissions (s_con)) { + g_set_error_literal (error, IFNET_PLUGIN_ERROR, 0, + "The ifnet plugin does not support non-system-wide connections."); + 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) + && !nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) { + g_set_error (error, IFNET_PLUGIN_ERROR, 0, + "The ifnet plugin cannot write the connection '%s' (type '%s')", + nm_connection_get_id (connection), + nm_setting_connection_get_connection_type (s_con)); + return FALSE; + } + + return TRUE; +} + /* get the available wired name(eth*). */ static gchar * get_wired_name () @@ -3003,6 +3059,9 @@ ifnet_add_new_connection (NMConnection *connection, const char *type; gchar *new_type, *new_name = NULL; + if (!ifnet_can_write_connection (connection, error)) + return FALSE; + s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); type = nm_setting_connection_get_connection_type (s_con); @@ -3053,3 +3112,4 @@ out: *out_new_name = new_name; return success; } + diff --git a/src/settings/plugins/ifnet/connection_parser.h b/src/settings/plugins/ifnet/connection_parser.h index 54046b05a3..74213669de 100644 --- a/src/settings/plugins/ifnet/connection_parser.h +++ b/src/settings/plugins/ifnet/connection_parser.h @@ -24,6 +24,8 @@ #include #include "net_parser.h" +gboolean ifnet_can_write_connection (NMConnection *connection, GError **error); + NMConnection *ifnet_update_connection_from_config_block (const char *conn_name, const char *basepath, GError **error); diff --git a/src/settings/plugins/ifnet/errors.c b/src/settings/plugins/ifnet/errors.c new file mode 100644 index 0000000000..295db18bae --- /dev/null +++ b/src/settings/plugins/ifnet/errors.c @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2013 Red Hat, Inc. + */ + +#include +#include "errors.h" + +GQuark +ifnet_plugin_error_quark (void) +{ + static GQuark error_quark = 0; + + if (G_UNLIKELY (error_quark == 0)) + error_quark = g_quark_from_static_string ("ifnet-plugin-error-quark"); + + return error_quark; +} + + diff --git a/src/settings/plugins/ifnet/errors.h b/src/settings/plugins/ifnet/errors.h new file mode 100644 index 0000000000..52517d007e --- /dev/null +++ b/src/settings/plugins/ifnet/errors.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2013 Red Hat, Inc. + */ + +#ifndef __ERRORS_H__ +#define __ERRORS_H__ + +#include + +#define IFNET_PLUGIN_ERROR (ifnet_plugin_error_quark ()) +GQuark ifnet_plugin_error_quark (void); + +#endif /* __ERRORS_H__ */ + diff --git a/src/settings/plugins/ifnet/net_utils.c b/src/settings/plugins/ifnet/net_utils.c index ae2307f913..672e686bb8 100644 --- a/src/settings/plugins/ifnet/net_utils.c +++ b/src/settings/plugins/ifnet/net_utils.c @@ -95,17 +95,6 @@ is_true (const char *str) return FALSE; } -GQuark -ifnet_plugin_error_quark (void) -{ - static GQuark error_quark = 0; - - if (G_UNLIKELY (error_quark == 0)) - error_quark = - g_quark_from_static_string ("ifnet-plugin-error-quark"); - return error_quark; -} - static char * find_default_gateway_str (char *str) { diff --git a/src/settings/plugins/ifnet/net_utils.h b/src/settings/plugins/ifnet/net_utils.h index 71430c838f..cee71d57e5 100644 --- a/src/settings/plugins/ifnet/net_utils.h +++ b/src/settings/plugins/ifnet/net_utils.h @@ -67,8 +67,6 @@ void set_ip6_dns_servers (NMSettingIP6Config * s_ip6, const char *conn_name); gchar *strip_string (gchar *str, gchar t); gboolean is_managed (const char *conn_name); -GQuark ifnet_plugin_error_quark (void); - gboolean is_hex (const char *value); gboolean is_ascii (const char *value); gboolean is_true (const char *str); diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c index 486f893514..8b056a6701 100644 --- a/src/settings/plugins/ifnet/plugin.c +++ b/src/settings/plugins/ifnet/plugin.c @@ -335,54 +335,36 @@ reload_connections (gpointer config) g_list_free (conn_names); } -static void -check_flagged_secrets (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data) -{ - gboolean *is_system_secret = user_data; - - 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 (secret_flags != NM_SETTING_SECRET_FLAG_NONE) { - *is_system_secret = TRUE; - } - } -} - static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *source, + gboolean save_to_disk, GError **error) { SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); - gboolean has_flagged_secrets = FALSE; - NMSettingConnection *s_con; + NMIfnetConnection *new = NULL; - s_con = nm_connection_get_setting_connection (source); - g_assert (s_con); - - /* If the connection is not available for all users, ignore - * it as this plugin only deals with System Connections */ - if (nm_setting_connection_get_num_permissions (s_con)) + /* Ensure we reject attempts to add the connection long before we're + * asked to write it to disk. + */ + if (!ifnet_can_write_connection (source, error)) return NULL; - /* If the connection has flagged secrets, ignore - * it as this plugin does not deal with user agent service */ - nm_connection_for_each_setting_value (source, check_flagged_secrets, &has_flagged_secrets); - if (has_flagged_secrets) - return NULL; + if (save_to_disk) { + if (!ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL, NULL, error)) + return NULL; + reload_connections (config); + new = g_hash_table_lookup (priv->connections, nm_connection_get_uuid (source)); + } else { + new = nm_ifnet_connection_new (source, NULL); + if (new) { + g_hash_table_insert (priv->connections, + (gpointer) nm_connection_get_uuid (NM_CONNECTION (new)), + new); + } + } - if (!ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL, NULL, error)) - return NULL; - - reload_connections (config); - return g_hash_table_lookup (priv->connections, nm_connection_get_uuid (source)); + return (NMSettingsConnection *) new; } static void diff --git a/src/settings/plugins/ifnet/tests/Makefile.am b/src/settings/plugins/ifnet/tests/Makefile.am index 2c39ed6337..f3dc6cbe27 100644 --- a/src/settings/plugins/ifnet/tests/Makefile.am +++ b/src/settings/plugins/ifnet/tests/Makefile.am @@ -18,7 +18,8 @@ check_ifnet_SOURCES = \ ../connection_parser.c \ ../net_parser.c \ ../net_utils.c \ - ../wpa_parser.c + ../wpa_parser.c \ + ../errors.c check_ifnet_CPPFLAGS = \ $(CHECK_CFLAGS) \ diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c index 5980809d3a..b216eda246 100644 --- a/src/settings/plugins/keyfile/plugin.c +++ b/src/settings/plugins/keyfile/plugin.c @@ -78,8 +78,6 @@ _internal_new_connection (SCPluginKeyfile *self, SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); NMKeyfileConnection *connection; - g_return_val_if_fail (full_path != NULL, NULL); - connection = nm_keyfile_connection_new (source, full_path, error); if (connection) { g_hash_table_insert (priv->connections, @@ -347,17 +345,20 @@ get_connections (NMSystemConfigInterface *config) static NMSettingsConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, + gboolean save_to_disk, GError **error) { SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); NMSettingsConnection *added = NULL; char *path = NULL; - /* Write it out first, then add the connection to our internal list */ - if (nm_keyfile_plugin_write_connection (connection, NULL, &path, error)) { - added = _internal_new_connection (self, path, connection, error); - g_free (path); + if (save_to_disk) { + if (!nm_keyfile_plugin_write_connection (connection, NULL, &path, error)) + return NULL; } + + added = _internal_new_connection (self, path, connection, error); + g_free (path); return added; }