From ce4dbd7daf02c543dfef23c6c478272e15a7b233 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 7 May 2018 10:06:20 +0200 Subject: [PATCH] keyfile: write in-memory connections to /run This is useful for in-memory connections to persist NetworkManager restarts (as opposed to machine restarts). Perhaps most improtantly, this allows generating in-memory connections outside NetworkManager, e.g. passing configuration from early boot firmware in initrd. Note that this does *not* aspire to do more than it says on the tin: Notably, it doesn't touch the problem of provisioning connections in multiple persistent connection directories and thus doesn't have to deal with the problem of deleting or overlaying the connections tha (rh #772414) deals with. --- .../plugins/keyfile/nms-keyfile-connection.c | 1 + .../plugins/keyfile/nms-keyfile-plugin.c | 91 +++++++++++-------- .../plugins/keyfile/nms-keyfile-utils.h | 2 + .../plugins/keyfile/nms-keyfile-writer.c | 16 +++- .../plugins/keyfile/nms-keyfile-writer.h | 1 + 5 files changed, 73 insertions(+), 38 deletions(-) diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index 64e94b2654..12467b2e20 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -66,6 +66,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (!out_logmsg_change || !*out_logmsg_change); if (!nms_keyfile_writer_connection (new_connection, + TRUE, 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), diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index 7d307c52f3..3bb872ca27 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -171,6 +171,7 @@ update_connection (NMSKeyfilePlugin *self, NMSKeyfileConnection *connection_by_uuid; GError *local = NULL; const char *uuid; + int dir_len; g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL); g_return_val_if_fail (full_path || source, NULL); @@ -178,6 +179,22 @@ update_connection (NMSKeyfilePlugin *self, if (full_path) _LOGD ("loading from file \"%s\"...", full_path); + if (g_str_has_prefix (full_path, nms_keyfile_utils_get_path ())) { + dir_len = strlen (nms_keyfile_utils_get_path ()); + } else if (g_str_has_prefix (full_path, NM_CONFIG_KEYFILE_PATH_IN_MEMORY)) { + dir_len = NM_STRLEN (NM_CONFIG_KEYFILE_PATH_IN_MEMORY); + } else { + /* Just make sure the file name is not going go pass the following check. */ + dir_len = strlen (full_path); + } + + if ( full_path[dir_len] != '/' + || strchr (full_path + dir_len + 1, '/') != NULL) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "File not in recognized system-connections directory"); + return FALSE; + } + connection_new = nms_keyfile_connection_new (source, full_path, &local); if (!connection_new) { /* Error; remove the connection */ @@ -410,14 +427,34 @@ _sort_paths (const char **f1, const char **f2, GHashTable *paths) return strcmp (*f1, *f2); } +static void +_read_dir (GPtrArray *filenames, const char *path) +{ + GDir *dir; + const char *item; + GError *error = NULL; + + dir = g_dir_open (path, 0, &error); + if (!dir) { + _LOGD ("cannot read directory '%s': %s", path, error->message); + g_clear_error (&error); + return; + } + + while ((item = g_dir_read_name (dir))) { + if (nms_keyfile_utils_should_ignore_file (item)) + continue; + g_ptr_array_add (filenames, g_build_filename (path, item, NULL)); + } + g_dir_close (dir); +} + + static void read_connections (NMSettingsPlugin *config) { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN (config); NMSKeyfilePluginPrivate *priv = NMS_KEYFILE_PLUGIN_GET_PRIVATE (self); - GDir *dir; - GError *error = NULL; - const char *item; GHashTable *alive_connections; GHashTableIter iter; NMSKeyfileConnection *connection; @@ -426,25 +463,13 @@ read_connections (NMSettingsPlugin *config) GPtrArray *filenames; GHashTable *paths; - dir = g_dir_open (nms_keyfile_utils_get_path (), 0, &error); - if (!dir) { - _LOGW ("cannot read directory '%s': %s", - nms_keyfile_utils_get_path (), - error->message); - g_clear_error (&error); - return; - } + filenames = g_ptr_array_new_with_free_func (g_free); + + _read_dir (filenames, NM_CONFIG_KEYFILE_PATH_IN_MEMORY); + _read_dir (filenames, nms_keyfile_utils_get_path ()); alive_connections = g_hash_table_new (nm_direct_hash, NULL); - filenames = g_ptr_array_new_with_free_func (g_free); - while ((item = g_dir_read_name (dir))) { - if (nms_keyfile_utils_should_ignore_file (item)) - continue; - g_ptr_array_add (filenames, g_build_filename (nms_keyfile_utils_get_path (), item, NULL)); - } - g_dir_close (dir); - /* While reloading, we don't replace connections that we already loaded while * iterating over the files. * @@ -501,14 +526,8 @@ load_connection (NMSettingsPlugin *config, { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN ((NMSKeyfilePlugin *) config); NMSKeyfileConnection *connection; - int dir_len = strlen (nms_keyfile_utils_get_path ()); - if ( strncmp (filename, nms_keyfile_utils_get_path (), dir_len) != 0 - || filename[dir_len] != '/' - || strchr (filename + dir_len + 1, '/') != NULL) - return FALSE; - - if (nms_keyfile_utils_should_ignore_file (filename + dir_len + 1)) + if (nms_keyfile_utils_should_ignore_file (filename)) return FALSE; connection = update_connection (self, NULL, filename, find_by_path (self, filename), TRUE, NULL, NULL); @@ -532,16 +551,16 @@ add_connection (NMSettingsPlugin *config, gs_free char *path = NULL; gs_unref_object NMConnection *reread = NULL; - if (save_to_disk) { - if (!nms_keyfile_writer_connection (connection, - NULL, - FALSE, - &path, - &reread, - NULL, - error)) - return NULL; - } + if (!nms_keyfile_writer_connection (connection, + save_to_disk, + NULL, + FALSE, + &path, + &reread, + NULL, + error)) + return NULL; + return NM_SETTINGS_CONNECTION (update_connection (self, reread ?: connection, path, NULL, FALSE, NULL, error)); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.h b/src/settings/plugins/keyfile/nms-keyfile-utils.h index d5ddb8d536..ec3bd4414a 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-utils.h +++ b/src/settings/plugins/keyfile/nms-keyfile-utils.h @@ -23,6 +23,8 @@ #include "NetworkManagerUtils.h" +#define NM_CONFIG_KEYFILE_PATH_IN_MEMORY NMRUNDIR "/system-connections" + #define NMS_KEYFILE_CONNECTION_LOG_PATH(path) ((path) ?: "in-memory") #define NMS_KEYFILE_CONNECTION_LOG_FMT "%s (%s,\"%s\")" #define NMS_KEYFILE_CONNECTION_LOG_ARG(con) NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_settings_connection_get_uuid ((NMSettingsConnection *) (con)), nm_settings_connection_get_id ((NMSettingsConnection *) (con)) diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index 194b97d4fd..569be76731 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -189,10 +189,14 @@ _internal_write_connection (NMConnection *connection, WriteInfo info = { 0 }; GError *local_err = NULL; int errsv; + gboolean rename = force_rename; g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); + if (existing_path && !g_str_has_prefix (existing_path, keyfile_dir)) + rename = TRUE; + switch (_nm_connection_verify (connection, error)) { case NM_SETTING_VERIFY_NORMALIZABLE: nm_assert_not_reached (); @@ -221,7 +225,7 @@ _internal_write_connection (NMConnection *connection, /* If we have existing file path, use it. Else generate one from * connection's ID. */ - if (existing_path != NULL && !force_rename) { + if (existing_path != NULL && !rename) { path = g_strdup (existing_path); } else { char *filename_escaped = nms_keyfile_utils_escape_filename (id); @@ -337,6 +341,7 @@ _internal_write_connection (NMConnection *connection, gboolean nms_keyfile_writer_connection (NMConnection *connection, + gboolean save_to_disk, const char *existing_path, gboolean force_rename, char **out_path, @@ -344,8 +349,15 @@ nms_keyfile_writer_connection (NMConnection *connection, gboolean *out_reread_same, GError **error) { + const char *keyfile_dir; + + if (save_to_disk) + keyfile_dir = nms_keyfile_utils_get_path (); + else + keyfile_dir = NM_CONFIG_KEYFILE_PATH_IN_MEMORY; + return _internal_write_connection (connection, - nms_keyfile_utils_get_path (), + keyfile_dir, 0, 0, existing_path, force_rename, diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h index ac41dfa2f1..030fb7cc34 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.h +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h @@ -25,6 +25,7 @@ #include "nm-connection.h" gboolean nms_keyfile_writer_connection (NMConnection *connection, + gboolean save_to_disk, const char *existing_path, gboolean force_rename, char **out_path,