diff options
author | Thomas Haller <thaller@redhat.com> | 2017-10-25 14:06:52 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-10-25 14:06:52 +0200 |
commit | fda635f5e971d7713cf0d38257c3687fd080b432 (patch) | |
tree | 406255092c958b3e6635901061506b66fb51aa04 | |
parent | c4f74fcfb6aeff95d6ce697f705438e63e8a52a9 (diff) | |
parent | 7028818a8302be6e2b31dbcdc914b9020403f64e (diff) | |
download | NetworkManager-fda635f5e971d7713cf0d38257c3687fd080b432.tar.gz |
ifcfg-rh: merge branch 'th/ifcfg-rule-write-rh1384799'
https://bugzilla.redhat.com/show_bug.cgi?id=1384799
22 files changed, 940 insertions, 877 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 5d81d059d2..b6be4794e8 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -431,4 +431,16 @@ gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, g /*****************************************************************************/ +static inline int +nm_setting_ip_config_get_addr_family (NMSettingIPConfig *s_ip) +{ + if (NM_IS_SETTING_IP4_CONFIG (s_ip)) + return AF_INET; + if (NM_IS_SETTING_IP6_CONFIG (s_ip)) + return AF_INET6; + g_return_val_if_reached (AF_UNSPEC); +} + +/*****************************************************************************/ + #endif diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 573cb44e78..182527d9f5 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -1219,7 +1219,7 @@ dispose (GObject *object) if (to_delete) { nm_log_dbg (LOGD_BT, "bluez[%s] removing Bluetooth connection for NAP device: '%s' (%s)", priv->path, nm_connection_get_id (to_delete), nm_connection_get_uuid (to_delete)); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL, NULL); + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL); g_object_unref (to_delete); } diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 2dd76d590f..c3a2e74360 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -259,8 +259,8 @@ activate: nm_connection_replace_settings_from_connection (NM_CONNECTION (connection), dev_checkpoint->settings_connection); nm_settings_connection_commit_changes (connection, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, NULL, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, NULL); } } else { @@ -343,7 +343,7 @@ next_dev: nm_settings_connection_get_uuid (con))) { _LOGD ("rollback: deleting new connection %s", nm_settings_connection_get_uuid (con)); - nm_settings_connection_delete (con, NULL, NULL); + nm_settings_connection_delete (con, NULL); } } } diff --git a/src/nm-manager.c b/src/nm-manager.c index fa67ee7842..46214130b3 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -339,7 +339,7 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) if (nm_settings_has_connection (priv->settings, connection)) { _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); - nm_settings_connection_delete (connection, NULL, NULL); + nm_settings_connection_delete (connection, NULL); } g_object_unref (connection); } @@ -1990,7 +1990,7 @@ recheck_assume_connection (NMManager *self, if (generated) { _LOG2D (LOGD_DEVICE, device, "assume: deleting generated connection after assuming failed"); - nm_settings_connection_delete (connection, NULL, NULL); + nm_settings_connection_delete (connection, NULL); } else { if (nm_device_sys_iface_state_get (device) == NM_DEVICE_SYS_IFACE_STATE_ASSUME) nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); @@ -4035,8 +4035,9 @@ activation_add_done (NMSettings *settings, if (_internal_activate_generic (self, active, &local)) { nm_settings_connection_commit_changes (new_connection, + NULL, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED, - NULL, NULL); + NULL); g_dbus_method_invocation_return_value ( context, g_variant_new ("(oo)", @@ -4056,7 +4057,7 @@ activation_add_done (NMSettings *settings, g_assert (error); _internal_activation_failed (self, active, error->message); if (new_connection) - nm_settings_connection_delete (new_connection, NULL, NULL); + nm_settings_connection_delete (new_connection, NULL); g_dbus_method_invocation_return_gerror (context, error); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, NULL, diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 768f55f8cb..8dec0bde32 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -510,18 +510,12 @@ connection_changed_cb (NMSettingsConnection *self, gpointer unused) _emit_updated (self, FALSE); } -/* Update the settings of this connection to match that of 'new_connection', - * taking care to make a private copy of secrets. - */ gboolean -nm_settings_connection_replace_settings (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error) +nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, + NMConnection *new_connection, + GError **error) { NMSettingsConnectionPrivate *priv; - gboolean success = FALSE; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE); @@ -540,6 +534,30 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, return FALSE; } + return TRUE; +} + +gboolean +nm_settings_connection_replace_settings_full (NMSettingsConnection *self, + NMConnection *new_connection, + gboolean prepare_new_connection, + gboolean update_unsaved, + const char *log_diff_name, + GError **error) +{ + NMSettingsConnectionPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if ( prepare_new_connection + && !nm_settings_connection_replace_settings_prepare (self, + new_connection, + error)) + return FALSE; + /* Do nothing if there's nothing to update */ if (nm_connection_compare (NM_CONNECTION (self), new_connection, @@ -567,7 +585,6 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, * 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. @@ -594,114 +611,101 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, _emit_updated (self, TRUE); - return success; -} - -static void -ignore_cb (NMSettingsConnection *self, - GError *error, - gpointer user_data) -{ + return TRUE; } -/* Replaces the settings in this connection with those in 'new_connection'. If - * any changes are made, commits them to permanent storage and to any other - * subsystems watching this connection. Before returning, 'callback' is run - * with the given 'user_data' along with any errors encountered. +/* Update the settings of this connection to match that of 'new_connection', + * taking care to make a private copy of secrets. */ -static void -replace_and_commit (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) +gboolean +nm_settings_connection_replace_settings (NMSettingsConnection *self, + NMConnection *new_connection, + gboolean update_unsaved, + const char *log_diff_name, + GError **error) { - GError *error = NULL; - NMSettingsConnectionCommitReason commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; - - if (g_strcmp0 (nm_connection_get_id (NM_CONNECTION (self)), - nm_connection_get_id (new_connection)) != 0) - commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; - - if (nm_settings_connection_replace_settings (self, new_connection, TRUE, "replace-and-commit-disk", &error)) - nm_settings_connection_commit_changes (self, commit_reason, callback, user_data); - else { - g_assert (error); - if (callback) - callback (self, error, user_data); - g_clear_error (&error); - } + return nm_settings_connection_replace_settings_full (self, + new_connection, + TRUE, + update_unsaved, + log_diff_name, + error); } -void -nm_settings_connection_replace_and_commit (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) +gboolean +nm_settings_connection_commit_changes (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionCommitReason commit_reason, + GError **error) { - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); - g_return_if_fail (NM_IS_CONNECTION (new_connection)); + NMSettingsConnectionClass *klass; + gs_free_error GError *local = NULL; + gs_unref_object NMConnection *reread_connection = NULL; + gs_free char *logmsg_change = NULL; - NM_SETTINGS_CONNECTION_GET_CLASS (self)->replace_and_commit (self, new_connection, callback, user_data); -} + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); -static void -commit_changes (NMSettingsConnection *self, - NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) -{ - /* Subclasses only call this function if the save was successful, so at - * this point the connection is synced to disk and no longer unsaved. - */ - set_unsaved (self, FALSE); + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + if (!klass->commit_changes) { + _LOGW ("write: setting plugin %s does not support to write connection", + G_OBJECT_TYPE_NAME (self)); + g_set_error (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "writing settings not supported"); + return FALSE; + } - g_object_ref (self); - callback (self, NULL, user_data); - g_object_unref (self); -} + if ( new_connection + && !nm_settings_connection_replace_settings_prepare (self, + new_connection, + &local)) { + _LOGW ("write: failed to prepare connection for writing: %s", + local->message); + g_propagate_error (error, g_steal_pointer (&local)); + return FALSE; + } -void -nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) -{ - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + if (!klass->commit_changes (self, + new_connection, + commit_reason, + &reread_connection, + &logmsg_change, + &local)) { + _LOGW ("write: failure to write setting: %s", + local->message); + g_propagate_error (error, g_steal_pointer (&local)); + return FALSE; + } - if (NM_SETTINGS_CONNECTION_GET_CLASS (self)->commit_changes) { - NM_SETTINGS_CONNECTION_GET_CLASS (self)->commit_changes (self, - commit_reason, - callback ? callback : ignore_cb, - user_data); - } else { - GError *error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "%s: %s:%d commit_changes() unimplemented", __func__, __FILE__, __LINE__); - if (callback) - callback (self, error, user_data); - g_error_free (error); + if (reread_connection || new_connection) { + if (!nm_settings_connection_replace_settings_full (self, + reread_connection ?: new_connection, + !reread_connection, + FALSE, + new_connection + ? "update-during-write" + : "replace-and-commit-disk", + &local)) { + /* this can't really happen, because at this point replace-settings + * is no longer supposed to fail. It's a bug. */ + _LOGE ("write: replacing setting failed: %s", + local->message); + g_propagate_error (error, g_steal_pointer (&local)); + g_return_val_if_reached (FALSE); + } } -} -void -nm_settings_connection_delete (NMSettingsConnection *self, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) -{ - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + set_unsaved (self, FALSE); - if (NM_SETTINGS_CONNECTION_GET_CLASS (self)->delete) { - NM_SETTINGS_CONNECTION_GET_CLASS (self)->delete (self, - callback ? callback : ignore_cb, - user_data); - } else { - GError *error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "%s: %s:%d delete() unimplemented", __func__, __FILE__, __LINE__); - if (callback) - callback (self, error, user_data); - g_error_free (error); - } + if (reread_connection) + _LOGI ("write: successfully updated (%s), connection was modified in the process", logmsg_change); + else if (new_connection) + _LOGI ("write: successfully updated (%s)", logmsg_change); + else + _LOGI ("write: successfully commited (%s)", logmsg_change); + + return TRUE; } static void @@ -740,15 +744,32 @@ remove_entry_from_db (NMSettingsConnection *self, const char* db_name) g_key_file_free (key_file); } -static void -do_delete (NMSettingsConnection *self, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) +gboolean +nm_settings_connection_delete (NMSettingsConnection *self, + GError **error) { + gs_unref_object NMSettingsConnection *self_keep_alive = NULL; + NMSettingsConnectionClass *klass; NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *for_agents; - g_object_ref (self); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); + + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + + self_keep_alive = g_object_ref (self); + + if (!klass->delete) { + g_set_error (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "delete not supported"); + return FALSE; + } + if (!klass->delete (self, + error)) + return FALSE; + set_visible (self, FALSE); /* Tell agents to remove secrets for this connection */ @@ -766,12 +787,10 @@ do_delete (NMSettingsConnection *self, remove_entry_from_db (self, "seen-bssids"); nm_settings_connection_signal_remove (self, FALSE); - - callback (self, NULL, user_data); - - g_object_unref (self); + return TRUE; } + /*****************************************************************************/ @@ -887,15 +906,6 @@ secret_is_system_owned (NMSettingSecretFlags flags, } static void -new_secrets_commit_cb (NMSettingsConnection *self, - GError *error, - gpointer user_data) -{ - if (error) - _LOGW ("Error saving new secrets to backing storage: %s", error->message); -} - -static void get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ GetSecretsInfo *info, /* only needed for logging */ NMConnection *connection, @@ -993,9 +1003,11 @@ nm_settings_connection_new_secrets (NMSettingsConnection *self, update_system_secrets_cache (self); update_agent_secrets_cache (self, NULL); - nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - new_secrets_commit_cb, NULL); + nm_settings_connection_commit_changes (self, + NULL, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL); return TRUE; } @@ -1109,7 +1121,10 @@ get_secrets_done_cb (NMAgentManager *manager, setting_name, info); - nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, new_secrets_commit_cb, NULL); + nm_settings_connection_commit_changes (self, + NULL, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL); } else { _LOGD ("(%s:%p) new agent secrets processed", setting_name, @@ -1570,11 +1585,6 @@ typedef struct { char *audit_args; } UpdateInfo; -typedef struct { - GDBusMethodInvocation *context; - NMAuthSubject *subject; -} CallbackInfo; - static void has_some_secrets_cb (NMSetting *setting, const char *key, @@ -1651,33 +1661,6 @@ update_complete (NMSettingsConnection *self, } static void -con_update_cb (NMSettingsConnection *self, - GError *error, - gpointer user_data) -{ - UpdateInfo *info = user_data; - NMConnection *for_agent; - - 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. - */ - 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)); - nm_agent_manager_save_secrets (info->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), - for_agent, - info->subject); - g_object_unref (for_agent); - } - - update_complete (self, info, error); -} - -static void update_auth_cb (NMSettingsConnection *self, GDBusMethodInvocation *context, NMAuthSubject *subject, @@ -1685,63 +1668,93 @@ update_auth_cb (NMSettingsConnection *self, gpointer data) { UpdateInfo *info = data; - GError *local = NULL; + NMSettingsConnectionCommitReason commit_reason; + gs_free_error GError *local = NULL; if (error) { update_complete (self, info, error); return; } - if (!info->new_settings) { - /* We're just calling Save(). Just commit the existing connection. */ - if (info->save_to_disk) { - nm_settings_connection_commit_changes (self, - NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION, - con_update_cb, - info); + if (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); } - return; - } - 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 (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) { + gs_unref_hashtable GHashTable *diff = NULL; + gboolean same; + + same = nm_connection_diff (NM_CONNECTION (self), info->new_settings, + NM_SETTING_COMPARE_FLAG_EXACT | + NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, + &diff); + if (!same && diff) + info->audit_args = nm_utils_format_con_diff_for_audit (diff); + } } - if (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) { - gs_unref_hashtable GHashTable *diff = NULL; - gboolean same; + if (!info->save_to_disk) { + if (info->new_settings) { + nm_settings_connection_replace_settings (self, + info->new_settings, + TRUE, + "replace-unsaved", + &local); + } + goto out; + } - same = nm_connection_diff (NM_CONNECTION (self), info->new_settings, - NM_SETTING_COMPARE_FLAG_EXACT | - NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, - &diff); - if (!same && diff) - info->audit_args = nm_utils_format_con_diff_for_audit (diff); + if (info->new_settings) { + if (!nm_settings_connection_replace_settings_prepare (self, + info->new_settings, + &local)) + goto out; } - if (info->save_to_disk) { - nm_settings_connection_replace_and_commit (self, - info->new_settings, - con_update_cb, - info); - } else { - if (!nm_settings_connection_replace_settings (self, info->new_settings, TRUE, "replace-and-commit-memory", &local)) - g_assert (local); - con_update_cb (self, local, info); - g_clear_error (&local); + commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; + if ( info->new_settings + && !nm_streq0 (nm_connection_get_id (NM_CONNECTION (self)), + nm_connection_get_id (info->new_settings))) + commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; + + nm_settings_connection_commit_changes (self, + info->new_settings, + commit_reason, + &local); + +out: + if (!local) { + gs_unref_object NMConnection *for_agent = NULL; + + /* 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. + */ + 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)); + nm_agent_manager_save_secrets (info->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + for_agent, + info->subject); } + + update_complete (self, info, local); } + static const char * get_update_modify_permission (NMConnection *old, NMConnection *new) { @@ -1865,30 +1878,13 @@ impl_settings_connection_save (NMSettingsConnection *self, } static void -con_delete_cb (NMSettingsConnection *self, - GError *error, - gpointer user_data) -{ - CallbackInfo *info = user_data; - - if (error) - g_dbus_method_invocation_return_gerror (info->context, error); - else - g_dbus_method_invocation_return_value (info->context, NULL); - - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, - !error, NULL, info->subject, error ? error->message : NULL); - g_free (info); -} - -static void delete_auth_cb (NMSettingsConnection *self, GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer data) { - CallbackInfo *info; + gs_free_error GError *local = NULL; if (error) { nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, NULL, subject, @@ -1897,11 +1893,15 @@ delete_auth_cb (NMSettingsConnection *self, return; } - info = g_malloc0 (sizeof (*info)); - info->context = context; - info->subject = subject; + nm_settings_connection_delete (self, &local); + + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, + !local, NULL, subject, local ? local->message : NULL); - nm_settings_connection_delete (self, con_delete_cb, info); + if (local) + g_dbus_method_invocation_return_gerror (context, local); + else + g_dbus_method_invocation_return_value (context, NULL); } static const char * @@ -2021,23 +2021,6 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self, } static void -clear_secrets_cb (NMSettingsConnection *self, - GError *error, - gpointer user_data) -{ - CallbackInfo *info = user_data; - - if (error) - g_dbus_method_invocation_return_gerror (info->context, error); - else - g_dbus_method_invocation_return_value (info->context, NULL); - - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, - !error, NULL, info->subject, error ? error->message : NULL); - g_free (info); -} - -static void dbus_clear_secrets_auth_cb (NMSettingsConnection *self, GDBusMethodInvocation *context, NMAuthSubject *subject, @@ -2045,31 +2028,39 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, gpointer user_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - CallbackInfo *info; + gs_free_error GError *local = NULL; if (error) { g_dbus_method_invocation_return_gerror (context, error); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, FALSE, NULL, subject, error->message); - } 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); + return; + } - /* Tell agents to remove secrets for this connection */ - nm_agent_manager_delete_secrets (priv->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), - NM_CONNECTION (self)); + /* 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); - info = g_malloc0 (sizeof (*info)); - info->context = context; - info->subject = subject; + /* Tell agents to remove secrets for this connection */ + nm_agent_manager_delete_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + NM_CONNECTION (self)); - nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, clear_secrets_cb, info); - } + nm_settings_connection_commit_changes (self, + NULL, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + &local); + + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, + !local, NULL, subject, local ? local->message : NULL); + + if (local) + g_dbus_method_invocation_return_gerror (context, local); + else + g_dbus_method_invocation_return_value (context, NULL); } static void @@ -2902,9 +2893,6 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) object_class->get_property = get_property; object_class->set_property = set_property; - class->replace_and_commit = replace_and_commit; - class->commit_changes = commit_changes; - class->delete = do_delete; class->supports_secrets = supports_secrets; obj_properties[PROP_VISIBLE] = diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index ecfac07905..67b3d9b92f 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -94,14 +94,6 @@ typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; -typedef void (*NMSettingsConnectionCommitFunc) (NMSettingsConnection *self, - GError *error, - gpointer user_data); - -typedef void (*NMSettingsConnectionDeleteFunc) (NMSettingsConnection *self, - GError *error, - gpointer user_data); - struct _NMSettingsConnectionPrivate; struct _NMSettingsConnection { @@ -112,20 +104,15 @@ struct _NMSettingsConnection { struct _NMSettingsConnectionClass { NMExportedObjectClass parent; - /* virtual methods */ - void (*replace_and_commit) (NMSettingsConnection *self, + gboolean (*commit_changes) (NMSettingsConnection *self, NMConnection *new_connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data); + NMSettingsConnectionCommitReason commit_reason, + NMConnection **out_reread_connection, + char **out_logmsg_change, + GError **error); - void (*commit_changes) (NMSettingsConnection *self, - NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data); - - void (*delete) (NMSettingsConnection *self, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data); + gboolean (*delete) (NMSettingsConnection *self, + GError **error); gboolean (*supports_secrets) (NMSettingsConnection *self, const char *setting_name); @@ -137,10 +124,14 @@ gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsCon NMConnection *applied_connection, NMSettingCompareFlags compare_flage); -void nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data); +gboolean nm_settings_connection_commit_changes (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionCommitReason commit_reason, + GError **error); + +gboolean nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, + NMConnection *new_connection, + GError **error); gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self, NMConnection *new_connection, @@ -148,14 +139,15 @@ gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self, const char *log_diff_name, GError **error); -void nm_settings_connection_replace_and_commit (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data); +gboolean nm_settings_connection_replace_settings_full (NMSettingsConnection *self, + NMConnection *new_connection, + gboolean prepare_new_connection, + gboolean update_unsaved, + const char *log_diff_name, + GError **error); -void nm_settings_connection_delete (NMSettingsConnection *self, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data); +gboolean nm_settings_connection_delete (NMSettingsConnection *self, + GError **error); typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self, NMSettingsConnectionCallId call_id, diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 10c160cbc8..e2b467a24c 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -91,7 +91,6 @@ EXPORT(nm_inotify_helper_remove_watch) EXPORT(nm_settings_connection_get_type) EXPORT(nm_settings_connection_replace_settings) -EXPORT(nm_settings_connection_replace_and_commit) /*****************************************************************************/ @@ -1774,7 +1773,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin * remains up and can be assumed if NM starts again. */ if (quitting == FALSE) - nm_settings_connection_delete (connection, NULL, NULL); + nm_settings_connection_delete (connection, NULL); } } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index b54f9549a6..4c1d02ae08 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -306,75 +306,52 @@ nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self) return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unrecognized_spec; } -static void -replace_and_commit (NMSettingsConnection *connection, - NMConnection *new_connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) -{ - const char *filename; - GError *error = NULL; - - filename = nm_settings_connection_get_filename (connection); - if (filename && utils_has_complex_routes (filename)) { - if (callback) { - error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Cannot modify a connection that has an associated 'rule-' or 'rule6-' file"); - callback (connection, error, user_data); - g_clear_error (&error); - } - return; - } - - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->replace_and_commit (connection, new_connection, callback, user_data); -} - -static void +static gboolean commit_changes (NMSettingsConnection *connection, + NMConnection *new_connection, NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) + NMConnection **out_reread_connection, + char **out_logmsg_change, + GError **error) { - GError *error = NULL; - gboolean success = FALSE; - char *ifcfg_path = NULL; const char *filename; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = TRUE; + const char *operation_message; + gs_free char *ifcfg_path = NULL; - filename = nm_settings_connection_get_filename (connection); - if (filename) { - success = writer_update_connection (NM_CONNECTION (connection), - IFCFG_DIR, - filename, - NULL, - NULL, - &error); - } else { - success = writer_new_connection (NM_CONNECTION (connection), - IFCFG_DIR, - &ifcfg_path, - NULL, - NULL, - &error); - if (success) { - nm_settings_connection_set_filename (connection, ifcfg_path); - g_free (ifcfg_path); - } - } + nm_assert (out_reread_connection && !*out_reread_connection); + nm_assert (!out_logmsg_change || !*out_logmsg_change); - if (success) { - /* Chain up to parent to handle success */ - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); - } else { - /* Otherwise immediate error */ - callback (connection, error, user_data); - g_error_free (error); - } + filename = nm_settings_connection_get_filename (connection); + if (!nms_ifcfg_rh_writer_write_connection (new_connection ?: NM_CONNECTION (connection), + IFCFG_DIR, + filename, + &ifcfg_path, + &reread, + &reread_same, + error)) + return FALSE; + + nm_assert ((!filename && ifcfg_path) || (filename && !ifcfg_path)); + if (ifcfg_path) { + nm_settings_connection_set_filename (connection, ifcfg_path); + operation_message = "persist"; + } else + operation_message = "update"; + + if (reread && !reread_same) + *out_reread_connection = g_steal_pointer (&reread); + + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("ifcfg-rh: %s %s", + operation_message, filename)); + return TRUE; } -static void -do_delete (NMSettingsConnection *connection, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) +static gboolean +delete (NMSettingsConnection *connection, + GError **error) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE ((NMIfcfgConnection *) connection); const char *filename; @@ -390,7 +367,7 @@ do_delete (NMSettingsConnection *connection, g_unlink (priv->route6file); } - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->delete (connection, callback, user_data); + return TRUE; } /*****************************************************************************/ @@ -529,8 +506,7 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class) object_class->get_property = get_property; object_class->dispose = dispose; - settings_class->delete = do_delete; - settings_class->replace_and_commit = replace_and_commit; + settings_class->delete = delete; settings_class->commit_changes = commit_changes; obj_properties[PROP_UNMANAGED_SPEC] = diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index f51a760d9c..1b69ab49d5 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -683,11 +683,11 @@ add_connection (NMSettingsPlugin *config, /* 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)) + if (!nms_ifcfg_rh_writer_can_write_connection (connection, error)) return NULL; if (save_to_disk) { - if (!writer_new_connection (connection, IFCFG_DIR, &path, NULL, NULL, error)) + if (!nms_ifcfg_rh_writer_write_connection (connection, IFCFG_DIR, NULL, &path, NULL, NULL, error)) return NULL; } return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index fcc0d6313b..9dca4fb83f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1175,6 +1175,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) static NMSetting * make_ip4_setting (shvarFile *ifcfg, const char *network_file, + gboolean routes_read, gboolean *out_has_defroute, GError **error) { @@ -1196,6 +1197,7 @@ make_ip4_setting (shvarFile *ifcfg, gint priority; char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; const char *const *item; + guint32 route_table; nm_assert (out_has_defroute && !*out_has_defroute); @@ -1281,6 +1283,15 @@ make_ip4_setting (shvarFile *ifcfg, return NULL; } + /* the route table (policy routing) is ignored if we don't handle routes. */ + route_table = svGetValueInt64 (ifcfg, "IPV4_ROUTE_TABLE", 10, + 0, G_MAXUINT32, 0); + if ( route_table != 0 + && !routes_read) { + PARSE_WARNING ("'rule-' or 'rule6-' files are present; Policy routing (IPV4_ROUTE_TABLE) is ignored"); + route_table = 0; + } + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "PEERDNS", TRUE), @@ -1289,8 +1300,7 @@ make_ip4_setting (shvarFile *ifcfg, NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", FALSE), NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10, -1, G_MAXUINT32, -1), - NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) svGetValueInt64 (ifcfg, "IPV4_ROUTE_TABLE", 10, - 0, G_MAXUINT32, 0), + NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, NULL); if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) @@ -1326,7 +1336,7 @@ make_ip4_setting (shvarFile *ifcfg, * added to the automatic ones. Note that this is not currently supported by * the legacy 'network' service (ifup-eth). */ - for (i = -1; i < 256; i++) { + for (i = -1;; i++) { NMIPAddress *addr = NULL; /* gateway will only be set if still unset. Hence, we don't leak gateway @@ -1424,13 +1434,13 @@ make_ip4_setting (shvarFile *ifcfg, /* Static routes - route-<name> file */ route_path = utils_get_route_path (svFileGetName (ifcfg)); - if (utils_has_complex_routes (route_path)) { - PARSE_WARNING ("'rule-' or 'rule6-' file is present; you will need to use a dispatcher script to apply these routes"); + if (!routes_read) { + /* NOP */ } else if (utils_has_route_file_new_syntax (route_path)) { /* Parse route file in new syntax */ route_ifcfg = utils_get_route_ifcfg (svFileGetName (ifcfg), FALSE); if (route_ifcfg) { - for (i = 0; i < 256; i++) { + for (i = 0;; i++) { NMIPRoute *route = NULL; if (!read_one_ip4_route (route_ifcfg, i, &route, error)) { @@ -1591,6 +1601,7 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file static NMSetting * make_ip6_setting (shvarFile *ifcfg, const char *network_file, + gboolean routes_read, GError **error) { NMSettingIPConfig *s_ip6 = NULL; @@ -1612,6 +1623,7 @@ make_ip6_setting (shvarFile *ifcfg, gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; + guint32 route_table; s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); @@ -1713,6 +1725,15 @@ make_ip6_setting (shvarFile *ifcfg, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; g_free (str_value); + /* the route table (policy routing) is ignored if we don't handle routes. */ + route_table = svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10, + 0, G_MAXUINT32, 0); + if ( route_table != 0 + && !routes_read) { + PARSE_WARNING ("'rule-' or 'rule6-' files are present; Policy routing (IPV6_ROUTE_TABLE) is ignored"); + route_table = 0; + } + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, method, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "IPV6_PEERDNS", TRUE), @@ -1721,8 +1742,7 @@ make_ip6_setting (shvarFile *ifcfg, NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV6_FAILURE_FATAL", FALSE), NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10, -1, G_MAXUINT32, -1), - NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10, - 0, G_MAXUINT32, 0), + NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val, NULL); @@ -1847,12 +1867,13 @@ make_ip6_setting (shvarFile *ifcfg, /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */ - if (!utils_has_complex_routes (svFileGetName (ifcfg))) { + if (!routes_read) { + /* NOP */ + } else { /* Read static routes from route6-<interface> file */ route6_path = utils_get_route6_path (svFileGetName (ifcfg)); if (!read_route_file (AF_INET6, route6_path, s_ip6, error)) goto error; - g_free (route6_path); } @@ -5158,6 +5179,8 @@ connection_from_file_full (const char *filename, NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user; const char *ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; + gboolean has_complex_routes_v4; + gboolean has_complex_routes_v6; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL); @@ -5369,13 +5392,32 @@ connection_from_file_full (const char *filename, if (!connection) return NULL; - s_ip6 = make_ip6_setting (parsed, network_file, error); + has_complex_routes_v4 = utils_has_complex_routes (filename, AF_INET); + has_complex_routes_v6 = utils_has_complex_routes (filename, AF_INET6); + + if (has_complex_routes_v4 || has_complex_routes_v6) { + if (has_complex_routes_v4 && !has_complex_routes_v6) + PARSE_WARNING ("'rule-' file is present; you will need to use a dispatcher script to apply these routes"); + else if (has_complex_routes_v6 && !has_complex_routes_v4) + PARSE_WARNING ("'rule6-' file is present; you will need to use a dispatcher script to apply these routes"); + else + PARSE_WARNING ("'rule-' and 'rule6-' files are present; you will need to use a dispatcher script to apply these routes"); + } + + s_ip6 = make_ip6_setting (parsed, + network_file, + !has_complex_routes_v4 && !has_complex_routes_v6, + error); if (!s_ip6) return NULL; else nm_connection_add_setting (connection, s_ip6); - s_ip4 = make_ip4_setting (parsed, network_file, &has_ip4_defroute, error); + s_ip4 = make_ip4_setting (parsed, + network_file, + !has_complex_routes_v4 && !has_complex_routes_v6, + &has_ip4_defroute, + error); if (!s_ip4) return NULL; else { @@ -5433,11 +5475,11 @@ connection_from_file (const char *filename, } NMConnection * -connection_from_file_test (const char *filename, - const char *network_file, - const char *test_type, - char **out_unhandled, - GError **error) +nmtst_connection_from_file (const char *filename, + const char *network_file, + const char *test_type, + char **out_unhandled, + GError **error) { return connection_from_file_full (filename, network_file, @@ -5451,7 +5493,6 @@ guint devtimeout_from_file (const char *filename) { shvarFile *ifcfg; - char *devtimeout_str; guint devtimeout; g_return_val_if_fail (filename != NULL, 0); @@ -5460,14 +5501,7 @@ devtimeout_from_file (const char *filename) if (!ifcfg) return 0; - devtimeout_str = svGetValueStr_cp (ifcfg, "DEVTIMEOUT"); - if (devtimeout_str) { - devtimeout = _nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0); - g_free (devtimeout_str); - } else - devtimeout = 0; - + devtimeout = svGetValueInt64 (ifcfg, "DEVTIMEOUT", 10, 0, G_MAXUINT, 0); svCloseFile (ifcfg); - return devtimeout; } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h index 4c519a0835..a8937ac868 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.h @@ -30,11 +30,10 @@ NMConnection *connection_from_file (const char *filename, guint devtimeout_from_file (const char *filename); -/* for test-ifcfg-rh */ -NMConnection *connection_from_file_test (const char *filename, - const char *network_file, - const char *test_type, - char **out_unhandled, - GError **error); +NMConnection *nmtst_connection_from_file (const char *filename, + const char *network_file, + const char *test_type, + char **out_unhandled, + GError **error); #endif /* __READER_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index e82ef60c63..c58169e4c3 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -280,25 +280,22 @@ gone: } gboolean -utils_has_complex_routes (const char *filename) +utils_has_complex_routes (const char *filename, int addr_family) { - char *rules; + g_return_val_if_fail (filename, TRUE); - g_return_val_if_fail (filename != NULL, TRUE); + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) { + gs_free char *rules = utils_get_extra_path (filename, RULE_TAG); - rules = utils_get_extra_path (filename, RULE_TAG); - if (g_file_test (rules, G_FILE_TEST_EXISTS)) { - g_free (rules); - return TRUE; + if (g_file_test (rules, G_FILE_TEST_EXISTS)) + return TRUE; } - g_free (rules); - rules = utils_get_extra_path (filename, RULE6_TAG); - if (g_file_test (rules, G_FILE_TEST_EXISTS)) { - g_free (rules); - return TRUE; + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) { + gs_free char *rules = utils_get_extra_path (filename, RULE6_TAG); + if (g_file_test (rules, G_FILE_TEST_EXISTS)) + return TRUE; } - g_free (rules); return FALSE; } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 8e003ccf89..e7abf4d8d7 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -48,7 +48,7 @@ shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create); shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create); gboolean utils_has_route_file_new_syntax (const char *filename); -gboolean utils_has_complex_routes (const char *filename); +gboolean utils_has_complex_routes (const char *filename, int addr_family); gboolean utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 60db801ccd..68eed84c87 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -108,45 +108,75 @@ save_secret_flags (shvarFile *ifcfg, static void set_secret (shvarFile *ifcfg, + GHashTable *secrets, const char *key, const char *value, const char *flags_key, NMSettingSecretFlags flags) { - shvarFile *keyfile; - GError *error = NULL; - /* Clear the secret from the ifcfg and the associated "keys" file */ svUnsetValue (ifcfg, key); /* Save secret flags */ save_secret_flags (ifcfg, flags_key, flags); + /* Only write the secret if it's system owned and supposed to be saved */ + if (flags != NM_SETTING_SECRET_FLAG_NONE) + value = NULL; + + g_hash_table_replace (secrets, g_strdup (key), g_strdup (value)); +} + +static gboolean +write_secrets (shvarFile *ifcfg, + GHashTable *secrets, + GError **error) +{ + nm_auto_shvar_file_close shvarFile *keyfile = NULL; + gs_free const char **secrets_keys = NULL; + guint i, secrets_keys_n; + GError *local = NULL; + gboolean any_secrets = FALSE; + keyfile = utils_get_keys_ifcfg (svFileGetName (ifcfg), TRUE); if (!keyfile) { - _LOGW ("could not create ifcfg file for '%s'", svFileGetName (ifcfg)); - goto error; + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Failure to create secrets file for '%s'", svFileGetName (ifcfg)); + return FALSE; } - /* Only write the secret if it's system owned and supposed to be saved */ - if (flags == NM_SETTING_SECRET_FLAG_NONE) - svSetValueStr (keyfile, key, value); - else - svUnsetValue (keyfile, key); + /* we purge all existing secrets. */ + svUnsetAll (keyfile, SV_KEY_TYPE_ANY); - if (!svWriteFile (keyfile, 0600, &error)) { - _LOGW ("could not update ifcfg file '%s': %s", - svFileGetName (keyfile), error->message); - g_clear_error (&error); - svCloseFile (keyfile); - goto error; + /* sort the keys. */ + secrets_keys = (const char **) g_hash_table_get_keys_as_array (secrets, &secrets_keys_n); + if (secrets_keys) { + g_qsort_with_data (secrets_keys, + secrets_keys_n, + sizeof (const char *), + nm_strcmp_p_with_data, + NULL); } - svCloseFile (keyfile); - return; -error: - /* Try setting the secret in the actual ifcfg */ - svSetValueStr (ifcfg, key, value); + for (i = 0; i < secrets_keys_n; i++) { + const char *k = secrets_keys[i]; + const char *v = g_hash_table_lookup (secrets, k); + + if (v) { + svSetValueStr (keyfile, k, v); + any_secrets = TRUE; + } + } + + if (!any_secrets) + (void) unlink (svFileGetName (keyfile)); + else if (!svWriteFile (keyfile, 0600, &local)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Failure to write secrets to '%s': %s", svFileGetName (keyfile), local->message); + return FALSE; + } + + return TRUE; } typedef struct { @@ -184,6 +214,8 @@ static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = { static gboolean write_object (NMSetting8021x *s_8021x, shvarFile *ifcfg, + GHashTable *secrets, + GHashTable *blobs, const Setting8021xSchemeVtable *objtype, GError **error) { @@ -222,7 +254,7 @@ write_object (NMSetting8021x *s_8021x, secret_flags = g_strdup_printf ("%s_PASSWORD_FLAGS", objtype->ifcfg_rh_key); password = (*(objtype->vtable->passwd_func))(s_8021x); flags = (*(objtype->vtable->pwflag_func))(s_8021x); - set_secret (ifcfg, secret_name, password, secret_flags, flags); + set_secret (ifcfg, secrets, secret_name, password, secret_flags, flags); g_free (secret_name); g_free (secret_flags); @@ -238,7 +270,6 @@ write_object (NMSetting8021x *s_8021x, */ if (!value && !blob) { char *standard_file; - int ignored; /* Since no cert/private key is now being used, delete any standard file * that was created for this connection, but leave other files alone. @@ -247,10 +278,7 @@ write_object (NMSetting8021x *s_8021x, * will be deleted, but /etc/pki/tls/cert.pem will not. */ standard_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension); - if (g_file_test (standard_file, G_FILE_TEST_EXISTS)) - ignored = unlink (standard_file); - g_free (standard_file); - + g_hash_table_replace (blobs, standard_file, NULL); svUnsetValue (ifcfg, objtype->ifcfg_rh_key); return TRUE; } @@ -265,46 +293,60 @@ write_object (NMSetting8021x *s_8021x, /* If it's raw certificate data, write the data out to the standard file */ if (blob) { - gboolean success; char *new_file; - GError *write_error = NULL; new_file = utils_cert_path (svFileGetName (ifcfg), objtype->vtable->file_suffix, extension); - if (!new_file) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not create file path for %s / %s", - NM_SETTING_802_1X_SETTING_NAME, objtype->vtable->setting_key); - return FALSE; + g_hash_table_replace (blobs, new_file, g_bytes_ref (blob)); + svSetValueStr (ifcfg, objtype->ifcfg_rh_key, new_file); + return TRUE; + } + + return TRUE; +} + +static gboolean +write_blobs (GHashTable *blobs, GError **error) +{ + GHashTableIter iter; + const char *filename; + GBytes *blob; + + if (!blobs) + return TRUE; + + g_hash_table_iter_init (&iter, blobs); + while (g_hash_table_iter_next (&iter, (gpointer *) &filename, (gpointer *) &blob)) { + GError *write_error = NULL; + + if (!blob) { + (void) unlink (filename); + continue; } /* Write the raw certificate data out to the standard file so that we * can use paths from now on instead of pushing around the certificate * data itself. */ - success = nm_utils_file_set_contents (new_file, - (const char *) g_bytes_get_data (blob, NULL), - g_bytes_get_size (blob), - 0600, - &write_error); - if (success) { - svSetValueStr (ifcfg, objtype->ifcfg_rh_key, new_file); - g_free (new_file); - return TRUE; - } else { + if (!nm_utils_file_set_contents (filename, + (const char *) g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob), + 0600, + &write_error)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not write certificate/key for %s / %s: %s", - NM_SETTING_802_1X_SETTING_NAME, objtype->vtable->setting_key, - (write_error && write_error->message) ? write_error->message : "(unknown)"); - g_clear_error (&write_error); + "Could not write certificate to file \"%s\": %s", + filename, + write_error->message); + return FALSE; } - g_free (new_file); } - return FALSE; + return TRUE; } static gboolean write_8021x_certs (NMSetting8021x *s_8021x, + GHashTable *secrets, + GHashTable *blobs, gboolean phase2, shvarFile *ifcfg, GError **error) @@ -312,7 +354,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, const Setting8021xSchemeVtable *otype = NULL; /* CA certificate */ - if (!write_object (s_8021x, ifcfg, + if (!write_object (s_8021x, ifcfg, secrets, blobs, phase2 ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT], @@ -326,7 +368,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, otype = &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY]; /* Save the private key */ - if (!write_object (s_8021x, ifcfg, otype, error)) + if (!write_object (s_8021x, ifcfg, secrets, blobs, otype, error)) return FALSE; /* Client certificate */ @@ -339,7 +381,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, NULL); } else { /* Save the client certificate */ - if (!write_object (s_8021x, ifcfg, + if (!write_object (s_8021x, ifcfg, secrets, blobs, phase2 ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], @@ -353,6 +395,8 @@ write_8021x_certs (NMSetting8021x *s_8021x, static gboolean write_8021x_setting (NMConnection *connection, shvarFile *ifcfg, + GHashTable *secrets, + GHashTable *blobs, gboolean wired, GError **error) { @@ -393,6 +437,7 @@ write_8021x_setting (NMConnection *connection, nm_setting_802_1x_get_anonymous_identity (s_8021x)); set_secret (ifcfg, + secrets, "IEEE_8021X_PASSWORD", nm_setting_802_1x_get_password (s_8021x), "IEEE_8021X_PASSWORD_FLAGS", @@ -506,11 +551,11 @@ write_8021x_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IEEE_8021X_AUTH_TIMEOUT"); - if (!write_8021x_certs (s_8021x, FALSE, ifcfg, error)) + if (!write_8021x_certs (s_8021x, secrets, blobs, FALSE, ifcfg, error)) return FALSE; /* phase2/inner certs */ - if (!write_8021x_certs (s_8021x, TRUE, ifcfg, error)) + if (!write_8021x_certs (s_8021x, secrets, blobs, TRUE, ifcfg, error)) return FALSE; return TRUE; @@ -519,6 +564,7 @@ write_8021x_setting (NMConnection *connection, static gboolean write_wireless_security_setting (NMConnection *connection, shvarFile *ifcfg, + GHashTable *secrets, gboolean adhoc, gboolean *no_8021x, GError **error) @@ -573,6 +619,7 @@ write_wireless_security_setting (NMConnection *connection, svSetValueStr (ifcfg, "IEEE_8021X_IDENTITY", nm_setting_wireless_security_get_leap_username (s_wsec)); set_secret (ifcfg, + secrets, "IEEE_8021X_PASSWORD", nm_setting_wireless_security_get_leap_password (s_wsec), "IEEE_8021X_PASSWORD_FLAGS", @@ -591,17 +638,17 @@ write_wireless_security_setting (NMConnection *connection, /* WEP keys */ /* Clear any default key */ - set_secret (ifcfg, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); /* Clear existing keys */ for (i = 0; i < 4; i++) { char tag[64]; numbered_tag (tag, "KEY_PASSPHRASE", i + 1); - set_secret (ifcfg, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); numbered_tag (tag, "KEY", i + 1); - set_secret (ifcfg, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); } /* And write the new ones out */ @@ -647,6 +694,7 @@ write_wireless_security_setting (NMConnection *connection, if (key_valid) { set_secret (ifcfg, + secrets, tag, key, "WEP_KEY_FLAGS", @@ -710,6 +758,7 @@ write_wireless_security_setting (NMConnection *connection, psk = nm_setting_wireless_security_get_psk (s_wsec); set_secret (ifcfg, + secrets, "WPA_PSK", psk, "WPA_PSK_FLAGS", @@ -729,6 +778,7 @@ write_wireless_security_setting (NMConnection *connection, static gboolean write_wireless_setting (NMConnection *connection, shvarFile *ifcfg, + GHashTable *secrets, gboolean *no_8021x, GError **error) { @@ -862,27 +912,25 @@ write_wireless_setting (NMConnection *connection, svUnsetValue (ifcfg, "SECURITYMODE"); if (nm_connection_get_setting_wireless_security (connection)) { - if (!write_wireless_security_setting (connection, ifcfg, adhoc, no_8021x, error)) + if (!write_wireless_security_setting (connection, ifcfg, secrets, adhoc, no_8021x, error)) return FALSE; } else { - char *keys_path; - /* Clear out wifi security keys */ svUnsetValue (ifcfg, "KEY_MGMT"); svUnsetValue (ifcfg, "IEEE_8021X_IDENTITY"); - set_secret (ifcfg, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE); svUnsetValue (ifcfg, "SECURITYMODE"); /* Clear existing keys */ - set_secret (ifcfg, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); for (i = 0; i < 4; i++) { char tag[64]; numbered_tag (tag, "KEY_PASSPHRASE", i + 1); - set_secret (ifcfg, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); numbered_tag (tag, "KEY", i + 1); - set_secret (ifcfg, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); + set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); } svUnsetValue (ifcfg, "DEFAULTKEY"); @@ -890,12 +938,7 @@ write_wireless_setting (NMConnection *connection, svUnsetValue (ifcfg, "WPA_ALLOW_WPA2"); svUnsetValue (ifcfg, "CIPHER_PAIRWISE"); svUnsetValue (ifcfg, "CIPHER_GROUP"); - set_secret (ifcfg, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE); - - /* Kill any old keys file */ - keys_path = utils_get_keys_path (svFileGetName (ifcfg)); - (void) unlink (keys_path); - g_free (keys_path); + set_secret (ifcfg, secrets, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE); } svSetValueStr (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL); @@ -1886,35 +1929,86 @@ get_route_attributes_string (NMIPRoute *route, int family) return g_string_free (str, FALSE); } -static gboolean -write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error) +static shvarFile * +write_route_file_svformat (const char *filename, NMSettingIPConfig *s_ip4) { - nm_auto_free_gstring GString *contents = NULL; - NMIPRoute *route; - guint32 i, num; + shvarFile *routefile; + guint i, num; - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (s_ip4 != NULL, FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); + routefile = utils_get_route_ifcfg (filename, TRUE); + + svUnsetAll (routefile, SV_KEY_TYPE_ROUTE_SVFORMAT); num = nm_setting_ip_config_get_num_routes (s_ip4); - if (num == 0) { - unlink (filename); - return TRUE; + for (i = 0; i < num; i++) { + char buf[INET_ADDRSTRLEN]; + NMIPRoute *route; + guint32 netmask; + gint64 metric; + char addr_key[64]; + char gw_key[64]; + char netmask_key[64]; + char metric_key[64]; + char options_key[64]; + gs_free char *options = NULL; + + numbered_tag (addr_key, "ADDRESS", i); + numbered_tag (netmask_key, "NETMASK", i); + numbered_tag (gw_key, "GATEWAY", i); + + route = nm_setting_ip_config_get_route (s_ip4, i); + + svSetValueStr (routefile, addr_key, nm_ip_route_get_dest (route)); + + netmask = _nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route)); + svSetValueStr (routefile, netmask_key, + nm_utils_inet4_ntop (netmask, buf)); + + svSetValueStr (routefile, gw_key, nm_ip_route_get_next_hop (route)); + + metric = nm_ip_route_get_metric (route); + if (metric != -1) { + svSetValueInt64 (routefile, + numbered_tag (metric_key, "METRIC", i), + metric); + } + + options = get_route_attributes_string (route, AF_INET); + if (options) { + svSetValueStr (routefile, + numbered_tag (options_key, "OPTIONS", i), + options); + } } + return routefile; +} + +static GString * +write_route_file (NMSettingIPConfig *s_ip) +{ + GString *contents; + NMIPRoute *route; + guint32 i, num; + int addr_family; + + addr_family = nm_setting_ip_config_get_addr_family (s_ip); + + num = nm_setting_ip_config_get_num_routes (s_ip); + if (num == 0) + return NULL; + contents = g_string_new (""); for (i = 0; i < num; i++) { - const char *next_hop; gs_free char *options = NULL; + const char *next_hop; gint64 metric; - route = nm_setting_ip_config_get_route (s_ip4, i); + route = nm_setting_ip_config_get_route (s_ip, i); next_hop = nm_ip_route_get_next_hop (route); metric = nm_ip_route_get_metric (route); - options = get_route_attributes_string (route, AF_INET); + options = get_route_attributes_string (route, addr_family); g_string_append_printf (contents, "%s/%u", nm_ip_route_get_dest (route), @@ -1931,13 +2025,7 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError g_string_append_c (contents, '\n'); } - if (!g_file_set_contents (filename, contents->str, contents->len, NULL)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Writing route file '%s' failed", filename); - return FALSE; - } - - return TRUE; + return contents; } static gboolean @@ -1988,7 +2076,7 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) s_user = NM_SETTING_USER (nm_connection_get_setting (connection, NM_TYPE_SETTING_USER)); - svUnsetValuesWithPrefix (ifcfg, "NM_USER_"); + svUnsetAll (ifcfg, SV_KEY_TYPE_USER); if (!s_user) return TRUE; @@ -2013,13 +2101,16 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) } static gboolean -write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +write_ip4_setting (NMConnection *connection, + shvarFile *ifcfg, + shvarFile **out_route_content_svformat, + GString **out_route_content, + GError **error) { NMSettingIPConfig *s_ip4; const char *value; char *tmp; char tag[64]; - char *route_path = NULL; gint j; guint i, num, n; gint64 route_metric; @@ -2030,6 +2121,9 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) const char *method = NULL; gboolean has_netmask; + NM_SET_OUT (out_route_content_svformat, NULL); + NM_SET_OUT (out_route_content, NULL); + s_ip4 = nm_connection_get_setting_ip4_config (connection); if (!s_ip4) { /* slave-type: clear IPv4 settings. @@ -2037,13 +2131,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) * Some IPv4 setting related options are not cleared, * for no strong reason. */ svUnsetValue (ifcfg, "BOOTPROTO"); - - for (j = -1; j < 256; j++) { - svUnsetValue (ifcfg, numbered_tag (tag, "IPADDR", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "PREFIX", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "NETMASK", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "GATEWAY", j)); - } + svUnsetAll (ifcfg, SV_KEY_TYPE_IP4_ADDRESS); return TRUE; } @@ -2054,8 +2142,6 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { - int result; - /* IPv4 disabled, clear IPv4 related parameters */ svUnsetValue (ifcfg, "BOOTPROTO"); for (j = -1; j < 256; j++) { @@ -2064,10 +2150,6 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (ifcfg, numbered_tag (tag, "NETMASK", j)); svUnsetValue (ifcfg, numbered_tag (tag, "GATEWAY", j)); } - - route_path = utils_get_route_path (svFileGetName (ifcfg)); - result = unlink (route_path); - g_free (route_path); return TRUE; } @@ -2207,16 +2289,18 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr (ifcfg, "DHCP_CLIENT_ID", value); timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip4); - tmp = timeout ? g_strdup_printf ("%d", timeout) : NULL; - svSetValueStr (ifcfg, "IPV4_DHCP_TIMEOUT", tmp); - g_free (tmp); + svSetValueInt64_cond (ifcfg, + "IPV4_DHCP_TIMEOUT", + timeout != 0, + timeout); svSetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", !nm_setting_ip_config_get_may_fail (s_ip4)); route_metric = nm_setting_ip_config_get_route_metric (s_ip4); - tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL; - svSetValueStr (ifcfg, "IPV4_ROUTE_METRIC", tmp); - g_free (tmp); + svSetValueInt64_cond (ifcfg, + "IPV4_ROUTE_METRIC", + route_metric != -1, + route_metric); route_table = nm_setting_ip_config_get_route_table (s_ip4); svSetValueInt64_cond (ifcfg, @@ -2224,87 +2308,8 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) route_table != 0, route_table); - /* Static routes - route-<name> file */ - route_path = utils_get_route_path (svFileGetName (ifcfg)); - if (!route_path) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not get route file path for '%s'", svFileGetName (ifcfg)); - return FALSE; - } - - if (utils_has_route_file_new_syntax (route_path)) { - shvarFile *routefile; - - routefile = utils_get_route_ifcfg (svFileGetName (ifcfg), TRUE); - if (!routefile) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not create route file '%s'", route_path); - g_free (route_path); - return FALSE; - } - g_free (route_path); - - num = nm_setting_ip_config_get_num_routes (s_ip4); - for (i = 0; i < 256; i++) { - char buf[INET_ADDRSTRLEN]; - NMIPRoute *route; - guint32 netmask; - gint64 metric; - char addr_key[64]; - char gw_key[64]; - char netmask_key[64]; - char metric_key[64]; - char options_key[64]; - - numbered_tag (addr_key, "ADDRESS", i); - numbered_tag (netmask_key, "NETMASK", i); - numbered_tag (gw_key, "GATEWAY", i); - numbered_tag (metric_key, "METRIC", i); - numbered_tag (options_key, "OPTIONS", i); - - if (i >= num) { - svUnsetValue (routefile, addr_key); - svUnsetValue (routefile, netmask_key); - svUnsetValue (routefile, gw_key); - svUnsetValue (routefile, metric_key); - svUnsetValue (routefile, options_key); - } else { - gs_free char *options = NULL; - - route = nm_setting_ip_config_get_route (s_ip4, i); - - svSetValueStr (routefile, addr_key, nm_ip_route_get_dest (route)); - - memset (buf, 0, sizeof (buf)); - netmask = _nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route)); - inet_ntop (AF_INET, (const void *) &netmask, &buf[0], sizeof (buf)); - svSetValueStr (routefile, netmask_key, &buf[0]); - - svSetValueStr (routefile, gw_key, nm_ip_route_get_next_hop (route)); - - memset (buf, 0, sizeof (buf)); - metric = nm_ip_route_get_metric (route); - if (metric == -1) - svUnsetValue (routefile, metric_key); - else - svSetValueInt64 (routefile, metric_key, (guint32) metric); - - options = get_route_attributes_string (route, AF_INET); - if (options) - svSetValueStr (routefile, options_key, options); - } - } - if (!svWriteFile (routefile, 0644, error)) { - svCloseFile (routefile); - return FALSE; - } - svCloseFile (routefile); - } else { - write_route_file_legacy (route_path, s_ip4, error); - g_free (route_path); - if (error && *error) - return FALSE; - } + NM_SET_OUT (out_route_content_svformat, write_route_file_svformat (svFileGetName (ifcfg), s_ip4)); + NM_SET_OUT (out_route_content, write_route_file (s_ip4)); timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); if (timeout < 0) @@ -2409,59 +2414,6 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path) } } -static gboolean -write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) -{ - nm_auto_free_gstring GString *contents = NULL; - NMIPRoute *route; - guint32 i, num; - - g_return_val_if_fail (filename, FALSE); - g_return_val_if_fail (s_ip6, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - num = nm_setting_ip_config_get_num_routes (s_ip6); - if (num == 0) { - unlink (filename); - return TRUE; - } - - contents = g_string_new (""); - - for (i = 0; i < num; i++) { - gs_free char *options = NULL; - const char *next_hop; - gint64 metric; - - route = nm_setting_ip_config_get_route (s_ip6, i); - next_hop = nm_ip_route_get_next_hop (route); - metric = nm_ip_route_get_metric (route); - options = get_route_attributes_string (route, AF_INET6); - - g_string_append_printf (contents, "%s/%u", - nm_ip_route_get_dest (route), - nm_ip_route_get_prefix (route)); - if (next_hop) - g_string_append_printf (contents, " via %s", next_hop); - if (metric >= 0) - g_string_append_printf (contents, " metric %u", (guint) metric); - if (options) { - g_string_append_c (contents, ' '); - g_string_append (contents, options); - } - - g_string_append_c (contents, '\n'); - } - - if (!g_file_set_contents (filename, contents->str, contents->len, NULL)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Writing route6 file '%s' failed", filename); - return FALSE; - } - - return TRUE; -} - static void write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg) { @@ -2480,12 +2432,14 @@ write_ip6_setting_dhcp_hostname (NMSettingIPConfig *s_ip6, shvarFile *ifcfg) } static gboolean -write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +write_ip6_setting (NMConnection *connection, + shvarFile *ifcfg, + GString **out_route6_content, + GError **error) { NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip4; const char *value; - char *tmp; guint i, num, num4; gint priority; NMIPAddress *addr; @@ -2493,9 +2447,10 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) gint64 route_metric; NMIPRouteTableSyncMode route_table; GString *ip_str1, *ip_str2, *ip_ptr; - char *route6_path; NMSettingIP6ConfigAddrGenMode addr_gen_mode; + NM_SET_OUT (out_route6_content, NULL); + s_ip6 = nm_connection_get_setting_ip6_config (connection); if (!s_ip6) { /* slave-type: clear IPv6 settings @@ -2620,9 +2575,10 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) nm_setting_ip_config_get_may_fail (s_ip6) ? "no" : "yes"); route_metric = nm_setting_ip_config_get_route_metric (s_ip6); - tmp = route_metric != -1 ? g_strdup_printf ("%"G_GINT64_FORMAT, route_metric) : NULL; - svSetValueStr (ifcfg, "IPV6_ROUTE_METRIC", tmp); - g_free (tmp); + svSetValueInt64_cond (ifcfg, + "IPV6_ROUTE_METRIC", + route_metric != -1, + route_metric); route_table = nm_setting_ip_config_get_route_table (s_ip6); svSetValueInt64_cond (ifcfg, @@ -2667,17 +2623,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) else svUnsetValue (ifcfg, "IPV6_DNS_PRIORITY"); - /* Static routes go to route6-<dev> file */ - route6_path = utils_get_route6_path (svFileGetName (ifcfg)); - if (!route6_path) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not get route6 file path for '%s'", svFileGetName (ifcfg)); - return FALSE; - } - write_route6_file (route6_path, s_ip6, error); - g_free (route6_path); - if (error && *error) - return FALSE; + NM_SET_OUT (out_route6_content, write_route_file (s_ip6)); return TRUE; } @@ -2759,14 +2705,14 @@ escape_id (const char *id) return escaped; } -static gboolean -write_connection (NMConnection *connection, - const char *ifcfg_dir, - const char *filename, - char **out_filename, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error) +gboolean +nms_ifcfg_rh_writer_write_connection (NMConnection *connection, + const char *ifcfg_dir, + const char *filename, + char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { NMSettingConnection *s_con; nm_auto_shvar_file_close shvarFile *ifcfg = NULL; @@ -2774,12 +2720,23 @@ write_connection (NMConnection *connection, const char *type; gboolean no_8021x = FALSE; gboolean wired = FALSE; + gboolean route_path_is_svformat; + gs_free char *route_path = NULL; + gs_free char *route6_path = NULL; + nm_auto_free_gstring GString *route_content = NULL; + gboolean route_ignore = FALSE; + gboolean has_complex_routes_v4; + gboolean has_complex_routes_v6; + nm_auto_shvar_file_close shvarFile *route_content_svformat = NULL; + nm_auto_free_gstring GString *route6_content = NULL; + gs_unref_hashtable GHashTable *secrets = NULL; + gs_unref_hashtable GHashTable *blobs = NULL; nm_assert (NM_IS_CONNECTION (connection)); nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS); nm_assert (!out_reread || !*out_reread); - if (!writer_can_write_connection (connection, error)) + if (!nms_ifcfg_rh_writer_can_write_connection (connection, error)) return FALSE; s_con = nm_connection_get_setting_connection (connection); @@ -2825,6 +2782,20 @@ write_connection (NMConnection *connection, ifcfg = svCreateFile (ifcfg_name); } + route_path = utils_get_route_path (svFileGetName (ifcfg)); + if (!route_path) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Could not get route file path for '%s'", svFileGetName (ifcfg)); + return FALSE; + } + + route6_path = utils_get_route6_path (svFileGetName (ifcfg)); + if (!route6_path) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Could not get route6 file path for '%s'", svFileGetName (ifcfg)); + return FALSE; + } + type = nm_setting_connection_get_connection_type (s_con); if (!type) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -2832,6 +2803,8 @@ write_connection (NMConnection *connection, return FALSE; } + secrets = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { // FIXME: can't write PPPoE at this time if (nm_connection_get_setting_pppoe (connection)) { @@ -2848,7 +2821,7 @@ write_connection (NMConnection *connection, if (!write_vlan_setting (connection, ifcfg, &wired, error)) return FALSE; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { - if (!write_wireless_setting (connection, ifcfg, &no_8021x, error)) + if (!write_wireless_setting (connection, ifcfg, secrets, &no_8021x, error)) return FALSE; } else if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { if (!write_infiniband_setting (connection, ifcfg, error)) @@ -2869,7 +2842,8 @@ write_connection (NMConnection *connection, } if (!no_8021x) { - if (!write_8021x_setting (connection, ifcfg, wired, error)) + blobs = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_bytes_unref); + if (!write_8021x_setting (connection, ifcfg, secrets, blobs, wired, error)) return FALSE; } @@ -2891,11 +2865,48 @@ write_connection (NMConnection *connection, svUnsetValue (ifcfg, "DHCP_HOSTNAME"); svUnsetValue (ifcfg, "DHCP_FQDN"); - if (!write_ip4_setting (connection, ifcfg, error)) + route_path_is_svformat = utils_has_route_file_new_syntax (route_path); + + has_complex_routes_v4 = utils_has_complex_routes (ifcfg_name, AF_INET); + has_complex_routes_v6 = utils_has_complex_routes (ifcfg_name, AF_INET6); + + if (has_complex_routes_v4 || has_complex_routes_v6) { + NMSettingIPConfig *s_ip4, *s_ip6; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if ( ( s_ip4 + && nm_setting_ip_config_get_num_routes (s_ip4) > 0) + || ( s_ip6 + && nm_setting_ip_config_get_num_routes (s_ip6) > 0)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Cannot configure static routes on a connection that has an associated 'rule%s-' file", + has_complex_routes_v4 ? "" : "6"); + return FALSE; + } + if ( ( s_ip4 + && nm_setting_ip_config_get_route_table (s_ip4) != 0) + || ( s_ip6 + && nm_setting_ip_config_get_route_table (s_ip6) != 0)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Cannot configure a route table for policy routing on a connection that has an associated 'rule%s-' file", + has_complex_routes_v4 ? "" : "6"); + return FALSE; + } + route_ignore = TRUE; + } + + if (!write_ip4_setting (connection, + ifcfg, + !route_ignore && route_path_is_svformat ? &route_content_svformat : NULL, + !route_ignore && route_path_is_svformat ? NULL :&route_content, + error)) return FALSE; - write_ip4_aliases (connection, ifcfg_name); - if (!write_ip6_setting (connection, ifcfg, error)) + if (!write_ip6_setting (connection, + ifcfg, + !route_ignore ? &route6_content : NULL, + error)) return FALSE; if (!write_res_options (connection, ifcfg, error)) @@ -2903,9 +2914,57 @@ write_connection (NMConnection *connection, write_connection_setting (s_con, ifcfg); + /* From here on, we persist data to disk. Before, it was all in-memory + * only. But we loaded the ifcfg files from disk, and managled our + * new settings (in-momory). */ + if (!svWriteFile (ifcfg, 0644, error)) return FALSE; + write_ip4_aliases (connection, ifcfg_name); + + if (!write_blobs (blobs, error)) + return FALSE; + + if (!write_secrets (ifcfg, secrets, error)) + return FALSE; + + if (!route_ignore) { + if (!route_content && !route_content_svformat) + (void) unlink (route_path); + else { + if (route_path_is_svformat) { + if (!svWriteFile (route_content_svformat, 0644, error)) + return FALSE; + } else { + if (!g_file_set_contents (route_path, route_content->str, route_content->len, NULL)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Writing route file '%s' failed", route_path); + return FALSE; + } + } + } + } + + if (!route_ignore) { + if (!route6_content) + (void) unlink (route6_path); + else { + if (!g_file_set_contents (route6_path, route6_content->str, route6_content->len, NULL)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Writing route6 file '%s' failed", route6_path); + return FALSE; + } + } + } + + /* Note that we just wrote the connection to disk, and re-read it from there. + * That is racy if somebody else modifies the connection. + * + * A better solution might be, to re-read the connection only based on the + * in-memory representation of what we collected above. But the reader + * does not yet allow to inject the configuration. */ + if (out_reread || out_reread_same) { gs_unref_object NMConnection *reread = NULL; gs_free_error GError *local = NULL; @@ -2948,7 +3007,7 @@ write_connection (NMConnection *connection, } gboolean -writer_can_write_connection (NMConnection *connection, GError **error) +nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, GError **error) { NMSettingConnection *s_con; @@ -2972,31 +3031,3 @@ writer_can_write_connection (NMConnection *connection, GError **error) return FALSE; } -gboolean -writer_new_connection (NMConnection *connection, - const char *ifcfg_dir, - char **out_filename, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error) -{ - return write_connection (connection, ifcfg_dir, NULL, out_filename, out_reread, out_reread_same, error); -} - -gboolean -writer_update_connection (NMConnection *connection, - const char *ifcfg_dir, - const char *filename, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error) -{ - if (utils_has_complex_routes (filename)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Cannot modify a connection that has an associated 'rule-' or 'rule6-' file"); - return FALSE; - } - - return write_connection (connection, ifcfg_dir, filename, NULL, out_reread, out_reread_same, error); -} - diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h index 9cd9513ec2..d7a255a9fd 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h @@ -18,26 +18,20 @@ * Copyright (C) 2009 Red Hat, Inc. */ -#ifndef _WRITER_H_ -#define _WRITER_H_ +#ifndef __NMS_IFCFG_RH_WRITER_H__ +#define __NMS_IFCFG_RH_WRITER_H__ #include "nm-connection.h" -gboolean writer_can_write_connection (NMConnection *connection, - GError **error); +gboolean nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, + GError **error); -gboolean writer_new_connection (NMConnection *connection, - const char *ifcfg_dir, - char **out_filename, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error); +gboolean nms_ifcfg_rh_writer_write_connection (NMConnection *connection, + const char *ifcfg_dir, + const char *filename, + char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error); -gboolean writer_update_connection (NMConnection *connection, - const char *ifcfg_dir, - const char *filename, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error); - -#endif /* _WRITER_H_ */ +#endif /* __NMS_IFCFG_RH_WRITER_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 911da73a05..df03bf654c 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -794,7 +794,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) int errsv = 0; char *arena; const char *p, *q; - GError *local = NULL; + gs_free_error GError *local = NULL; nm_auto_close int fd = -1; if (create) @@ -824,11 +824,13 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) &arena, NULL, &local) < 0) { + if (create) + return svFile_new (name); + g_set_error (error, G_FILE_ERROR, local->domain == G_FILE_ERROR ? local->code : G_FILE_ERROR_FAILED, "Could not read file '%s': %s", name, local->message); - g_error_free (local); return NULL; } @@ -1118,6 +1120,71 @@ svGetValueEnum (shvarFile *s, const char *key, /*****************************************************************************/ +static gboolean +_is_all_digits (const char *str) +{ + return str[0] + && NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); +} + +#define IS_NUMBERED_TAG(key, tab_name) \ + ({ \ + const char *_key = (key); \ + \ + ( (strncmp (_key, tab_name, NM_STRLEN (tab_name)) == 0) \ + && _is_all_digits (&_key[NM_STRLEN (tab_name)])); \ + }) + +gboolean +svUnsetAll (shvarFile *s, SvKeyType match_key_type) +{ + CList *current; + shvarLine *line; + gboolean changed = FALSE; + + g_return_val_if_fail (s, FALSE); + + c_list_for_each (current, &s->lst_head) { + line = c_list_entry (current, shvarLine, lst); + ASSERT_shvarLine (line); + if (!line->key) + continue; + + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY)) + goto do_clear; + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) { + if ( IS_NUMBERED_TAG (line->key, "ADDRESS") + || IS_NUMBERED_TAG (line->key, "NETMASK") + || IS_NUMBERED_TAG (line->key, "GATEWAY") + || IS_NUMBERED_TAG (line->key, "METRIC") + || IS_NUMBERED_TAG (line->key, "OPTIONS")) + goto do_clear; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) { + if ( IS_NUMBERED_TAG (line->key, "IPADDR") + || IS_NUMBERED_TAG (line->key, "PREFIX") + || IS_NUMBERED_TAG (line->key, "NETMASK") + || IS_NUMBERED_TAG (line->key, "GATEWAY")) + goto do_clear; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) { + if (g_str_has_prefix (line->key, "NM_USER_")) + goto do_clear; + } + + continue; +do_clear: + if (nm_clear_g_free (&line->line)) { + ASSERT_shvarLine (line); + changed = TRUE; + } + } + + if (changed) + s->modified = TRUE; + return changed; +} + /* Same as svSetValueStr() but it preserves empty @value -- contrary to * svSetValueStr() for which "" effectively means to remove the value. */ gboolean @@ -1216,27 +1283,6 @@ svUnsetValue (shvarFile *s, const char *key) return svSetValue (s, key, NULL); } -void -svUnsetValuesWithPrefix (shvarFile *s, const char *prefix) -{ - CList *current; - - g_return_if_fail (s); - g_return_if_fail (prefix); - - c_list_for_each (current, &s->lst_head) { - shvarLine *line = c_list_entry (current, shvarLine, lst); - - ASSERT_shvarLine (line); - if ( line->key - && g_str_has_prefix (line->key, prefix)) { - if (nm_clear_g_free (&line->line)) - s->modified = TRUE; - } - ASSERT_shvarLine (line); - } -} - /*****************************************************************************/ /* Write the current contents iff modified. Returns FALSE on error diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index 8fbc14808e..c48bbfd331 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -86,7 +86,14 @@ gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value); gboolean svUnsetValue (shvarFile *s, const char *key); -void svUnsetValuesWithPrefix (shvarFile *s, const char *prefix); +typedef enum { + SV_KEY_TYPE_ANY = (1LL << 0), + SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1), + SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2), + SV_KEY_TYPE_USER = (1LL << 3), +} SvKeyType; + +gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); /* Write the current contents iff modified. Returns FALSE on error * and TRUE on success. Do not write if no values have been modified. diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 3d3b672c6a..3c4d76726f 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -232,7 +232,7 @@ _assert_expected_content (NMConnection *connection, const char *filename, const g_assert (_ifcfg_dir && _ifcfg_dir[0]); \ g_assert (_filename && _filename[0]); \ \ - _success = writer_update_connection (_connection, _ifcfg_dir, _filename, _out_reread, _out_reread_same, &_error); \ + _success = nms_ifcfg_rh_writer_write_connection (_connection, _ifcfg_dir, _filename, NULL, _out_reread, _out_reread_same, &_error); \ nmtst_assert_success (_success, _error); \ _assert_expected_content (_connection, _filename, _expected); \ } G_STMT_END @@ -260,8 +260,8 @@ _connection_from_file (const char *filename, g_assert (!out_unhandled || !*out_unhandled); - connection = connection_from_file_test (filename, network_file, test_type, - out_unhandled ?: &unhandled_fallback, &error); + connection = nmtst_connection_from_file (filename, network_file, test_type, + out_unhandled ?: &unhandled_fallback, &error); g_assert_no_error (error); g_assert (!unhandled_fallback); @@ -282,7 +282,7 @@ _connection_from_file_fail (const char *filename, GError *local = NULL; char *unhandled = NULL; - connection = connection_from_file_test (filename, network_file, test_type, &unhandled, &local); + connection = nmtst_connection_from_file (filename, network_file, test_type, &unhandled, &local); g_assert (!connection); g_assert (local); @@ -310,12 +310,13 @@ _writer_new_connection_reread (NMConnection *connection, con_verified = nmtst_connection_duplicate_and_normalize (connection); - success = writer_new_connection (con_verified, - ifcfg_dir, - &filename, - reread, - out_reread_same, - &error); + success = nms_ifcfg_rh_writer_write_connection (con_verified, + ifcfg_dir, + NULL, + &filename, + reread, + out_reread_same, + &error); nmtst_assert_success (success, error); g_assert (filename && filename[0]); @@ -384,12 +385,13 @@ _writer_new_connection_fail (NMConnection *connection, connection_normalized = nmtst_connection_duplicate_and_normalize (connection); - success = writer_new_connection (connection_normalized, - ifcfg_dir, - &filename, - &reread, - NULL, - &local); + success = nms_ifcfg_rh_writer_write_connection (connection_normalized, + ifcfg_dir, + NULL, + &filename, + &reread, + NULL, + &local); nmtst_assert_no_success (success, local); g_assert (!filename); g_assert (!reread); diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.c b/src/settings/plugins/ifnet/nms-ifnet-connection.c index ba87d46c4a..5dbb124c30 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-connection.c +++ b/src/settings/plugins/ifnet/nms-ifnet-connection.c @@ -74,89 +74,81 @@ nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection) return NM_IFNET_CONNECTION_GET_PRIVATE (connection)->conn_name; } -static void +static gboolean commit_changes (NMSettingsConnection *connection, + NMConnection *new_connection, NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) + NMConnection **out_reread_connection, + char **out_logmsg_change, + GError **error) { - GError *error = NULL; NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection); - gchar *new_name = NULL; + char *new_name = NULL; gboolean success = FALSE; + gboolean added = FALSE; + + nm_assert (out_reread_connection && !*out_reread_connection); + nm_assert (!out_logmsg_change || !*out_logmsg_change); g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); if (priv->conn_name) { - /* Existing connection; update it */ success = ifnet_update_parsers_by_connection (NM_CONNECTION (connection), priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, &new_name, NULL, - &error); + error); } else { - /* New connection, add it */ + added = TRUE; success = ifnet_add_new_connection (NM_CONNECTION (connection), CONF_NET_FILE, WPA_SUPPLICANT_CONF, &new_name, NULL, - &error); - if (success) - reload_parsers (); + error); } + g_assert (!!success == (new_name != NULL)); if (success) { - /* update connection name */ - g_assert (new_name); g_free (priv->conn_name); priv->conn_name = new_name; - - NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); - nm_log_info (LOGD_SETTINGS, "Successfully updated %s", priv->conn_name); - } else { - nm_log_warn (LOGD_SETTINGS, "Failed to update %s", - priv->conn_name ? priv->conn_name : - nm_connection_get_id (NM_CONNECTION (connection))); - reload_parsers (); - callback (connection, error, user_data); - g_error_free (error); } + reload_parsers (); + g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); + + if (success) { + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("ifcfg-rh: %s %s", + added ? "persist" : "updated", + new_name)); + } + return success; } -static void -do_delete (NMSettingsConnection *connection, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) +static gboolean +delete (NMSettingsConnection *connection, + GError **error) { - GError *error = NULL; NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection); - g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); - /* Only connections which exist in /etc/conf.d/net will have a conn_name */ if (priv->conn_name) { + g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); + if (!ifnet_delete_connection_in_parsers (priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL)) { nm_log_warn (LOGD_SETTINGS, "Failed to delete %s", priv->conn_name); reload_parsers (); - callback (connection, error, user_data); - g_error_free (error); - g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); - return; + /* let's not return an error. */ } - } - - NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->delete (connection, callback, user_data); - g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); + g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); + } - nm_log_info (LOGD_SETTINGS, "Successfully deleted %s", - priv->conn_name ? priv->conn_name : - nm_connection_get_id (NM_CONNECTION (connection))); + return TRUE; } /*****************************************************************************/ @@ -222,7 +214,7 @@ nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class) object_class->finalize = finalize; - settings_class->delete = do_delete; + settings_class->delete = delete; settings_class->commit_changes = commit_changes; signals[IFNET_SETUP_MONITORS] = diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.c b/src/settings/plugins/ifnet/nms-ifnet-plugin.c index 802988c19a..998b04b47a 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-plugin.c +++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.c @@ -138,9 +138,9 @@ monitor_file_changes (const char *filename, info->callback = callback; info->user_data = user_data; g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free, - info); + info); g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), - info); + info); } else { nm_log_warn (LOGD_SETTINGS, "Monitoring %s failed, error: %s", filename, error == NULL ? "nothing" : (*error)->message); @@ -150,34 +150,38 @@ monitor_file_changes (const char *filename, } static void -setup_monitors (NMIfnetConnection * connection, gpointer user_data) +setup_monitors (NMIfnetConnection *connection, gpointer user_data) { SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); - if (nm_config_get_monitor_connection_files (nm_config_get ())) { - priv->net_monitor = - monitor_file_changes (CONF_NET_FILE, (FileChangedFn) reload_connections, - user_data); - priv->wpa_monitor = - monitor_file_changes (WPA_SUPPLICANT_CONF, (FileChangedFn) reload_connections, - user_data); - } + if (!nm_config_get_monitor_connection_files (nm_config_get ())) + return; + + if (priv->net_monitor || priv->wpa_monitor) + return; + + priv->net_monitor = monitor_file_changes (CONF_NET_FILE, + (FileChangedFn) reload_connections, + user_data); + priv->wpa_monitor = monitor_file_changes (WPA_SUPPLICANT_CONF, + (FileChangedFn) reload_connections, + user_data); } static void -cancel_monitors (NMIfnetConnection * connection, gpointer user_data) +cancel_monitors (NMIfnetConnection *connection, gpointer user_data) { SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); if (priv->net_monitor) { g_file_monitor_cancel (priv->net_monitor); - g_object_unref (priv->net_monitor); + g_clear_object (&priv->net_monitor); } if (priv->wpa_monitor) { g_file_monitor_cancel (priv->wpa_monitor); - g_object_unref (priv->wpa_monitor); + g_clear_object (&priv->wpa_monitor); } } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index b718a3f831..0928772afa 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -139,7 +139,10 @@ bind_device_to_connection (SettingsPluginIfupdown *self, g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL); } - nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, NULL, NULL); + nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), + NULL, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL); } static void @@ -409,7 +412,7 @@ init (NMSettingsPlugin *config) exported = g_hash_table_lookup (priv->connections, block->name); if (exported) { nm_log_info (LOGD_SETTINGS, "deleting %s from connections", block->name); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (exported), NULL, NULL); + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (exported), NULL); g_hash_table_remove (priv->connections, block->name); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index bd07d263c1..300aa9f7b3 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -50,29 +50,30 @@ G_DEFINE_TYPE (NMSKeyfileConnection, nms_keyfile_connection, NM_TYPE_SETTINGS_CO /*****************************************************************************/ -static void +static gboolean commit_changes (NMSettingsConnection *connection, + NMConnection *new_connection, NMSettingsConnectionCommitReason commit_reason, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) + NMConnection **out_reread_connection, + char **out_logmsg_change, + GError **error) { - char *path = NULL; - GError *error = NULL; + gs_free char *path = NULL; gs_unref_object NMConnection *reread = NULL; gboolean reread_same = FALSE; - if (!nms_keyfile_writer_connection (NM_CONNECTION (connection), + nm_assert (out_reread_connection && !*out_reread_connection); + nm_assert (!out_logmsg_change || !*out_logmsg_change); + + if (!nms_keyfile_writer_connection (new_connection ?: NM_CONNECTION (connection), nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), &path, &reread, &reread_same, - &error)) { - callback (connection, error, user_data); - g_clear_error (&error); - return; - } + error)) + return FALSE; /* Update the filename if it changed */ if ( path @@ -81,52 +82,37 @@ commit_changes (NMSettingsConnection *connection, nm_settings_connection_set_filename (connection, path); if (old_path) { - nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" and rename from \"%s\"", - NMS_KEYFILE_CONNECTION_LOG_ARG (connection), - old_path); + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" and rename from \"%s\"", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection), + old_path)); } else { - nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" and persist connection", - NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" and persist connection", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection))); } } else { - nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT, - NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); - } - - if (reread && !reread_same) { - gs_free_error GError *local = NULL; - - if (!nm_settings_connection_replace_settings (connection, reread, FALSE, "update-during-write", &local)) { - nm_log_warn (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection failed: %s", - NMS_KEYFILE_CONNECTION_LOG_ARG (connection), local->message); - } else { - nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection", - NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); - } + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT, + NMS_KEYFILE_CONNECTION_LOG_ARG (connection))); } - g_free (path); + if (reread && !reread_same) + *out_reread_connection = g_steal_pointer (&reread); - NM_SETTINGS_CONNECTION_CLASS (nms_keyfile_connection_parent_class)->commit_changes (connection, - commit_reason, - callback, - user_data); + return TRUE; } -static void -do_delete (NMSettingsConnection *connection, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) +static gboolean +delete (NMSettingsConnection *connection, + GError **error) { const char *path; path = nm_settings_connection_get_filename (connection); if (path) g_unlink (path); - - NM_SETTINGS_CONNECTION_CLASS (nms_keyfile_connection_parent_class)->delete (connection, - callback, - user_data); + return TRUE; } /*****************************************************************************/ @@ -192,5 +178,5 @@ nms_keyfile_connection_class_init (NMSKeyfileConnectionClass *keyfile_connection NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class); settings_class->commit_changes = commit_changes; - settings_class->delete = do_delete; + settings_class->delete = delete; } |