about summary refs log tree commit diff
path: root/src/settings/plugins/keyfile
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/keyfile')
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-connection.c20
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-connection.h3
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-plugin.c199
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.c93
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.h6
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.c100
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.h20
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.c43
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.h1
-rw-r--r--src/settings/plugins/keyfile/tests/meson.build1
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c444
11 files changed, 435 insertions, 495 deletions
diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c
index 5f72a9fa..7511f206 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),
@@ -75,9 +76,7 @@ commit_changes (NMSettingsConnection *connection,
 	                                    error))
 		return FALSE;
 
-	/* Update the filename if it changed */
-	if (   path
-	    && g_strcmp0 (path, nm_settings_connection_get_filename (connection)) != 0) {
+	if (!nm_streq0 (path, nm_settings_connection_get_filename (connection))) {
 		gs_free char *old_path = g_strdup (nm_settings_connection_get_filename (connection));
 
 		nm_settings_connection_set_filename (connection, path);
@@ -125,6 +124,7 @@ nms_keyfile_connection_init (NMSKeyfileConnection *connection)
 NMSKeyfileConnection *
 nms_keyfile_connection_new (NMConnection *source,
                             const char *full_path,
+                            const char *profile_dir,
                             GError **error)
 {
 	GObject *object;
@@ -132,17 +132,19 @@ nms_keyfile_connection_new (NMConnection *source,
 	const char *uuid;
 	gboolean update_unsaved = TRUE;
 
-	g_assert (source || full_path);
+	nm_assert (source || full_path);
+	nm_assert (!full_path || full_path[0] == '/');
+	nm_assert (!profile_dir || profile_dir[0] == '/');
 
 	/* If we're given a connection already, prefer that instead of re-reading */
 	if (source)
 		tmp = g_object_ref (source);
 	else {
-		tmp = nms_keyfile_reader_from_file (full_path, error);
+		tmp = nms_keyfile_reader_from_file (full_path, profile_dir, error);
 		if (!tmp)
 			return NULL;
 
-		uuid = nm_connection_get_uuid (NM_CONNECTION (tmp));
+		uuid = nm_connection_get_uuid (tmp);
 		if (!uuid) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Connection in file %s had no UUID", full_path);
@@ -154,9 +156,9 @@ nms_keyfile_connection_new (NMConnection *source,
 		update_unsaved = FALSE;
 	}
 
-	object = (GObject *) g_object_new (NMS_TYPE_KEYFILE_CONNECTION,
-	                                   NM_SETTINGS_CONNECTION_FILENAME, full_path,
-	                                   NULL);
+	object = g_object_new (NMS_TYPE_KEYFILE_CONNECTION,
+	                       NM_SETTINGS_CONNECTION_FILENAME, full_path,
+	                       NULL);
 
 	/* Update our settings with what was read from the file */
 	if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object),
diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.h b/src/settings/plugins/keyfile/nms-keyfile-connection.h
index f96d7590..0773ced0 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-connection.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-connection.h
@@ -37,7 +37,8 @@ typedef struct _NMSKeyfileConnectionClass NMSKeyfileConnectionClass;
 GType nms_keyfile_connection_get_type (void);
 
 NMSKeyfileConnection *nms_keyfile_connection_new (NMConnection *source,
-                                                  const char *filename,
+                                                  const char *full_path,
+                                                  const char *profile_dir,
                                                   GError **error);
 
 #endif /* __NMS_KEYFILE_CONNECTION_H__ */
diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
index 3723db94..346b78c0 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -56,19 +56,15 @@ typedef struct {
 } NMSKeyfilePluginPrivate;
 
 struct _NMSKeyfilePlugin {
-	GObject parent;
+	NMSettingsPlugin parent;
 	NMSKeyfilePluginPrivate _priv;
 };
 
 struct _NMSKeyfilePluginClass {
-	GObjectClass parent;
+	NMSettingsPluginClass parent;
 };
 
-static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface);
-
-G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN,
-                                               settings_plugin_interface_init))
+G_DEFINE_TYPE (NMSKeyfilePlugin, nms_keyfile_plugin, NM_TYPE_SETTINGS_PLUGIN)
 
 #define NMS_KEYFILE_PLUGIN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSKeyfilePlugin, NMS_IS_KEYFILE_PLUGIN)
 
@@ -85,10 +81,10 @@ G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0,
 /*****************************************************************************/
 
 static void
-connection_removed_cb (NMSettingsConnection *obj, gpointer user_data)
+connection_removed_cb (NMSettingsConnection *sett_conn, NMSKeyfilePlugin *self)
 {
-	g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE ((NMSKeyfilePlugin *) user_data)->connections,
-	                     nm_connection_get_uuid (NM_CONNECTION (obj)));
+	g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE (self)->connections,
+	                     nm_settings_connection_get_uuid (sett_conn));
 }
 
 /* Monitoring */
@@ -106,7 +102,7 @@ remove_connection (NMSKeyfilePlugin *self, NMSKeyfileConnection *connection)
 	g_object_ref (connection);
 	g_signal_handlers_disconnect_by_func (connection, connection_removed_cb, self);
 	removed = g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE (self)->connections,
-	                               nm_connection_get_uuid (NM_CONNECTION (connection)));
+	                               nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection)));
 	nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
 	g_object_unref (connection);
 
@@ -175,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);
@@ -182,7 +179,23 @@ update_connection (NMSKeyfilePlugin *self,
 	if (full_path)
 		_LOGD ("loading from file \"%s\"...", full_path);
 
-	connection_new = nms_keyfile_connection_new (source, full_path, &local);
+	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, nms_keyfile_utils_get_path (), &local);
 	if (!connection_new) {
 		/* Error; remove the connection */
 		if (source)
@@ -197,7 +210,7 @@ update_connection (NMSKeyfilePlugin *self,
 		return NULL;
 	}
 
-	uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new));
+	uuid = nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection_new));
 	connection_by_uuid = g_hash_table_lookup (priv->connections, uuid);
 
 	if (   connection
@@ -240,8 +253,8 @@ update_connection (NMSKeyfilePlugin *self,
 
 		old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid));
 
-		if (nm_connection_compare (NM_CONNECTION (connection_by_uuid),
-		                           NM_CONNECTION (connection_new),
+		if (nm_connection_compare (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_by_uuid)),
+		                           nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)),
 		                           NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
 		                           NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
 			/* Nothing to do... except updating the path. */
@@ -259,7 +272,7 @@ update_connection (NMSKeyfilePlugin *self,
 				_LOGI ("update and persist "NMS_KEYFILE_CONNECTION_LOG_FMT, NMS_KEYFILE_CONNECTION_LOG_ARG (connection_new));
 
 			if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid),
-			                                    NM_CONNECTION (connection_new),
+			                                    nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)),
 			                                    NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED,
 			                                    NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
 			                                    "keyfile-update",
@@ -287,8 +300,10 @@ update_connection (NMSKeyfilePlugin *self,
 		if (!source) {
 			/* Only raise the signal if we were called without source, i.e. if we read the connection from file.
 			 * Otherwise, we were called by add_connection() which does not expect the signal. */
-			g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_new);
+			_nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self),
+			                                                  NM_SETTINGS_CONNECTION (connection_new));
 		}
+
 		return connection_new;
 	}
 }
@@ -307,7 +322,7 @@ dir_changed (GFileMonitor *monitor,
 	gboolean exists;
 
 	full_path = g_file_get_path (file);
-	if (nms_keyfile_utils_should_ignore_file (full_path)) {
+	if (nms_keyfile_utils_should_ignore_file (full_path, FALSE)) {
 		g_free (full_path);
 		return;
 	}
@@ -341,13 +356,14 @@ config_changed_cb (NMConfig *config,
                    NMConfigData *old_data,
                    NMSKeyfilePlugin *self)
 {
-	gs_free char *old_value = NULL, *new_value = NULL;
+	gs_free char *old_value = NULL;
+	gs_free char *new_value = NULL;
 
 	old_value = nm_config_data_get_value (old_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC);
 	new_value = nm_config_data_get_value (config_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC);
 
-	if (g_strcmp0 (old_value, new_value) != 0)
-		g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED);
+	if (!nm_streq0 (old_value, new_value))
+		_nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self));
 }
 
 static void
@@ -412,13 +428,35 @@ _sort_paths (const char **f1, const char **f2, GHashTable *paths)
 }
 
 static void
+_read_dir (GPtrArray *filenames,
+           const char *path,
+           gboolean require_extension)
+{
+	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, require_extension))
+			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;
@@ -427,24 +465,12 @@ 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);
 
-	alive_connections = g_hash_table_new (nm_direct_hash, NULL);
+	_read_dir (filenames, NM_CONFIG_KEYFILE_PATH_IN_MEMORY, TRUE);
+	_read_dir (filenames, nms_keyfile_utils_get_path (), FALSE);
 
-	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);
+	alive_connections = g_hash_table_new (nm_direct_hash, NULL);
 
 	/* While reloading, we don't replace connections that we already loaded while
 	 * iterating over the files.
@@ -497,19 +523,61 @@ get_connections (NMSettingsPlugin *config)
 }
 
 static gboolean
+_file_is_in_path (const char *abs_filename,
+                  const char *abs_path)
+{
+	gsize l;
+
+	/* FIXME: ensure that both paths are at least normalized (coalescing ".",
+	 * duplicate '/', and trailing '/'). */
+
+	nm_assert (abs_filename && abs_filename[0] == '/');
+	nm_assert (abs_path && abs_path[0] == '/');
+
+	l = strlen (abs_path);
+	if (strncmp (abs_filename, abs_path, l) != 0)
+		return FALSE;
+
+	abs_filename += l;
+	while (abs_filename[0] == '/')
+		abs_filename++;
+
+	if (!abs_filename[0])
+		return FALSE;
+
+	if (strchr (abs_filename, '/'))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
 load_connection (NMSettingsPlugin *config,
                  const char *filename)
 {
 	NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN ((NMSKeyfilePlugin *) config);
 	NMSKeyfileConnection *connection;
-	int dir_len = strlen (nms_keyfile_utils_get_path ());
+	gboolean require_extension;
 
-	if (   strncmp (filename, nms_keyfile_utils_get_path (), dir_len) != 0
-	    || filename[dir_len] != '/'
-	    || strchr (filename + dir_len + 1, '/') != NULL)
+	/* the test whether to require a file extension tries to figure out whether
+	 * the provided filename is inside /etc or /run.
+	 *
+	 * However, on Posix a filename just resolves to an Inode, and there can
+	 * be any kind of paths that point to the same Inode. It's not generally possible
+	 * to check for that (unless, we would stat all files in the target directory
+	 * and see whether their inode matches).
+	 *
+	 * So, when loading the file do something simpler: require that the path
+	 * starts with the well-known prefix. This rejects symlinks or hard links
+	 * which would actually also point to the same file. */
+	if (_file_is_in_path (filename, nms_keyfile_utils_get_path ()))
+		require_extension = FALSE;
+	else if (_file_is_in_path (filename, NM_CONFIG_KEYFILE_PATH_IN_MEMORY))
+		require_extension = TRUE;
+	else
 		return FALSE;
 
-	if (nms_keyfile_utils_should_ignore_file (filename + dir_len + 1))
+	if (nms_keyfile_utils_should_ignore_file (filename, require_extension))
 		return FALSE;
 
 	connection = update_connection (self, NULL, filename, find_by_path (self, filename), TRUE, NULL, NULL);
@@ -533,16 +601,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));
 }
 
@@ -616,20 +684,17 @@ dispose (GObject *object)
 }
 
 static void
-nms_keyfile_plugin_class_init (NMSKeyfilePluginClass *req_class)
+nms_keyfile_plugin_class_init (NMSKeyfilePluginClass *klass)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass);
 
 	object_class->constructed = constructed;
-	object_class->dispose = dispose;
-}
+	object_class->dispose     = dispose;
 
-static void
-settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface)
-{
-	plugin_iface->get_connections = get_connections;
-	plugin_iface->load_connection = load_connection;
-	plugin_iface->reload_connections = reload_connections;
-	plugin_iface->add_connection = add_connection;
-	plugin_iface->get_unmanaged_specs = get_unmanaged_specs;
+	plugin_class->get_connections     = get_connections;
+	plugin_class->load_connection     = load_connection;
+	plugin_class->reload_connections  = reload_connections;
+	plugin_class->add_connection      = add_connection;
+	plugin_class->get_unmanaged_specs = get_unmanaged_specs;
 }
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c
index cb4b8379..580a857a 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c
@@ -28,6 +28,7 @@
 #include "nm-keyfile-internal.h"
 
 #include "NetworkManagerUtils.h"
+#include "nms-keyfile-utils.h"
 
 /*****************************************************************************/
 
@@ -102,53 +103,87 @@ _handler_read (GKeyFile *keyfile,
 NMConnection *
 nms_keyfile_reader_from_keyfile (GKeyFile *key_file,
                                  const char *filename,
+                                 const char *base_dir,
+                                 const char *profile_dir,
                                  gboolean verbose,
                                  GError **error)
 {
+	NMConnection *connection;
 	HandlerReadData data = {
 		.verbose = verbose,
 	};
+	gs_free char *base_dir_free = NULL;
+	gs_free char *profile_filename_free = NULL;
+	gs_free char *filename_id = NULL;
+	const char *profile_filename = NULL;
+
+	nm_assert (filename && filename[0]);
+	nm_assert (!base_dir || base_dir[0] == '/');
+	nm_assert (!profile_dir || profile_dir[0] == '/');
+
+	if (base_dir)
+		nm_assert (!strchr (filename, '/'));
+	else {
+		const char *s;
+
+		nm_assert (filename[0] == '/');
+
+		/* @base_dir may be NULL, in which case @filename must be an absolute path,
+		 * and the directory is taken as the @base_dir. */
+		s = strrchr (filename, '/');
+		base_dir = nm_strndup_a (255, filename, s - filename, &base_dir_free);
+		if (   !profile_dir
+		    || nm_streq (base_dir, profile_dir))
+			profile_filename = filename;
+		filename = &s[1];
+	}
+
+	connection = nm_keyfile_read (key_file, base_dir, _handler_read, &data, error);
+	if (!connection)
+		return NULL;
+
+	if (g_str_has_suffix (filename, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)) {
+		gsize l = strlen (filename);
 
-	return nm_keyfile_read (key_file, filename, NULL, _handler_read, &data, error);
+		if (l > NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION))
+			filename_id = g_strndup (filename, l - NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION));
+	}
+
+	nm_keyfile_read_ensure_id (connection, filename_id ?: filename);
+
+	if (!profile_filename) {
+		profile_filename_free = g_build_filename (profile_dir ?: base_dir, filename, NULL);
+		profile_filename = profile_filename_free;
+	}
+	nm_keyfile_read_ensure_uuid (connection, profile_filename);
+
+	return connection;
 }
 
 NMConnection *
-nms_keyfile_reader_from_file (const char *filename, GError **error)
+nms_keyfile_reader_from_file (const char *full_filename,
+                              const char *profile_dir,
+                              GError **error)
 {
-	GKeyFile *key_file;
-	struct stat statbuf;
+	gs_unref_keyfile GKeyFile *key_file = NULL;
 	NMConnection *connection = NULL;
 	GError *verify_error = NULL;
 
-	if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) {
-		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		                     "File did not exist or was not a regular file");
-		return NULL;
-	}
+	nm_assert (full_filename && full_filename[0] == '/');
+	nm_assert (!profile_dir || profile_dir[0] == '/');
 
-	if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) {
-		if (statbuf.st_mode & 0077) {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "File permissions (%o) were insecure",
-			             statbuf.st_mode);
-			return NULL;
-		}
-
-		if (statbuf.st_uid != 0) {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "File owner (%o) is insecure",
-			             statbuf.st_mode);
-			return NULL;
-		}
-	}
+	if (!nms_keyfile_utils_check_file_permissions (full_filename,
+	                                               NULL,
+	                                               error))
+		return NULL;
 
 	key_file = g_key_file_new ();
-	if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error))
-		goto out;
+	if (!g_key_file_load_from_file (key_file, full_filename, G_KEY_FILE_NONE, error))
+		return NULL;
 
-	connection = nms_keyfile_reader_from_keyfile (key_file, filename, TRUE, error);
+	connection = nms_keyfile_reader_from_keyfile (key_file, full_filename, NULL, profile_dir, TRUE, error);
 	if (!connection)
-		goto out;
+		return NULL;
 
 	/* Normalize and verify the connection */
 	if (!nm_connection_normalize (connection, NULL, NULL, &verify_error)) {
@@ -160,8 +195,6 @@ nms_keyfile_reader_from_file (const char *filename, GError **error)
 		connection = NULL;
 	}
 
-out:
-	g_key_file_free (key_file);
 	return connection;
 }
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h
index b60c1e69..c0fb06d1 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h
@@ -26,9 +26,13 @@
 
 NMConnection *nms_keyfile_reader_from_keyfile (GKeyFile *key_file,
                                                const char *filename,
+                                               const char *base_dir,
+                                               const char *profile_dir,
                                                gboolean verbose,
                                                GError **error);
 
-NMConnection *nms_keyfile_reader_from_file (const char *filename, GError **error);
+NMConnection *nms_keyfile_reader_from_file (const char *full_filename,
+                                            const char *profile_dir,
+                                            GError **error);
 
 #endif /* __NMS_KEYFILE_READER_H__ */
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c
index 03f06670..c3bfcdee 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c
@@ -24,6 +24,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 
 #include "nm-setting-wired.h"
 #include "nm-setting-wireless.h"
@@ -55,18 +56,11 @@ check_mkstemp_suffix (const char *path)
 }
 
 static gboolean
-check_prefix (const char *base, const char *tag)
+check_prefix_dot (const char *base)
 {
-	int len, tag_len;
+	nm_assert (base && base[0]);
 
-	g_return_val_if_fail (base != NULL, TRUE);
-	g_return_val_if_fail (tag != NULL, TRUE);
-
-	len = strlen (base);
-	tag_len = strlen (tag);
-	if ((len > tag_len) && !g_ascii_strncasecmp (base, tag, tag_len))
-		return TRUE;
-	return FALSE;
+	return base[0] == '.';
 }
 
 static gboolean
@@ -90,7 +84,7 @@ check_suffix (const char *base, const char *tag)
 #define DER_TAG ".der"
 
 gboolean
-nms_keyfile_utils_should_ignore_file (const char *filename)
+nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension)
 {
 	gs_free char *base = NULL;
 
@@ -101,7 +95,7 @@ nms_keyfile_utils_should_ignore_file (const char *filename)
 
 	/* Ignore hidden and backup files */
 	/* should_ignore_file() must mirror escape_filename() */
-	if (check_prefix (base, ".") || check_suffix (base, "~"))
+	if (check_prefix_dot (base) || check_suffix (base, "~"))
 		return TRUE;
 	/* Ignore temporary files */
 	if (check_mkstemp_suffix (base))
@@ -110,18 +104,87 @@ nms_keyfile_utils_should_ignore_file (const char *filename)
 	if (check_suffix (base, PEM_TAG) || check_suffix (base, DER_TAG))
 		return TRUE;
 
+	if (require_extension) {
+		gsize l = strlen (base);
+
+		if (   l <= NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)
+		    || !g_str_has_suffix (base, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION))
+			return TRUE;
+	}
+
 	return FALSE;
 }
 
+/*****************************************************************************/
+
+gboolean
+nms_keyfile_utils_check_file_permissions_stat (const struct stat *st,
+                                               GError **error)
+{
+	g_return_val_if_fail (st, FALSE);
+
+	if (!S_ISREG (st->st_mode)) {
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		                     "file is not a regular file");
+		return FALSE;
+	}
+
+	if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) {
+		if (st->st_uid != 0) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "File owner (%lld) is insecure",
+			             (long long) st->st_uid);
+			return FALSE;
+		}
+
+		if (st->st_mode & 0077) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "File permissions (%03o) are insecure",
+			             st->st_mode);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+gboolean
+nms_keyfile_utils_check_file_permissions (const char *filename,
+                                          struct stat *out_st,
+                                          GError **error)
+{
+	struct stat st;
+	int errsv;
+
+	g_return_val_if_fail (filename && filename[0] == '/', FALSE);
+
+	if (stat (filename, &st) != 0) {
+		errsv = errno;
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		             "cannot access file: %s", g_strerror (errsv));
+		return FALSE;
+	}
+
+	if (!nms_keyfile_utils_check_file_permissions_stat (&st, error))
+		return FALSE;
+
+	NM_SET_OUT (out_st, st);
+	return TRUE;
+}
+
+/*****************************************************************************/
+
 char *
-nms_keyfile_utils_escape_filename (const char *filename)
+nms_keyfile_utils_escape_filename (const char *filename,
+                                   gboolean with_extension)
 {
 	GString *str;
 	const char *f = filename;
-	const char ESCAPE_CHAR = '*';
-
 	/* keyfile used to escape with '*', do not change that behavior.
-	 * But for newly added escapings, use '_' instead. */
+	 *
+	 * But for newly added escapings, use '_' instead.
+	 * Also, @with_extension is new-style. */
+	const char ESCAPE_CHAR = with_extension ? '_' : '*';
 	const char ESCAPE_CHAR2 = '_';
 
 	g_return_val_if_fail (filename && filename[0], NULL);
@@ -138,7 +201,7 @@ nms_keyfile_utils_escape_filename (const char *filename)
 
 	/* escape_filename() must avoid anything that should_ignore_file() would reject.
 	 * We can escape here more aggressivly then what we would read back. */
-	if (check_prefix (str->str, "."))
+	if (check_prefix_dot (str->str))
 		str->str[0] = ESCAPE_CHAR2;
 	if (check_suffix (str->str, "~"))
 		str->str[str->len - 1] = ESCAPE_CHAR2;
@@ -147,6 +210,9 @@ nms_keyfile_utils_escape_filename (const char *filename)
 	    || check_suffix (str->str, DER_TAG))
 		g_string_append_c (str, ESCAPE_CHAR2);
 
+	if (with_extension)
+		g_string_append (str, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION);
+
 	return g_string_free (str, FALSE);;
 }
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.h b/src/settings/plugins/keyfile/nms-keyfile-utils.h
index cd3f42b9..297dd4ea 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.h
@@ -23,16 +23,28 @@
 
 #include "NetworkManagerUtils.h"
 
+#define NM_CONFIG_KEYFILE_PATH_IN_MEMORY NMRUNDIR "/system-connections"
+
+#define NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION      ".nmconnection"
+
 #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_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con))
+#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))
 #define NMS_KEYFILE_CONNECTION_LOG_FMTD        "%s (%s,\"%s\",%p)"
-#define NMS_KEYFILE_CONNECTION_LOG_ARGD(con)   NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con)
+#define NMS_KEYFILE_CONNECTION_LOG_ARGD(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)), (con)
 
-gboolean nms_keyfile_utils_should_ignore_file (const char *filename);
+gboolean nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension);
 
-char *nms_keyfile_utils_escape_filename (const char *filename);
+char *nms_keyfile_utils_escape_filename (const char *filename, gboolean with_extension);
 
 const char *nms_keyfile_utils_get_path (void);
 
+struct stat;
+gboolean nms_keyfile_utils_check_file_permissions_stat (const struct stat *st,
+                                                        GError **error);
+
+gboolean nms_keyfile_utils_check_file_permissions (const char *filename,
+                                                   struct stat *out_st,
+                                                   GError **error);
+
 #endif /* __NMS_KEYFILE_UTILS_H__ */
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c
index 270a217e..df26ea60 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -34,6 +34,8 @@
 #include "nms-keyfile-utils.h"
 #include "nms-keyfile-reader.h"
 
+#include "nm-utils/nm-io-utils.h"
+
 /*****************************************************************************/
 
 typedef struct {
@@ -127,7 +129,7 @@ cert_writer (NMConnection *connection,
 		new_path = g_strdup_printf ("%s/%s-%s.%s", info->keyfile_dir, nm_connection_get_uuid (connection),
 		                            cert_data->vtable->file_suffix, ext);
 
-		success = nm_utils_file_set_contents (new_path, (const gchar *) blob_data,
+		success = nm_utils_file_set_contents (new_path, (const char *) blob_data,
 		                                      blob_len, 0600, &local);
 		if (success) {
 			/* Write the path value to the keyfile.
@@ -170,6 +172,8 @@ _handler_write (NMConnection *connection,
 static gboolean
 _internal_write_connection (NMConnection *connection,
                             const char *keyfile_dir,
+                            const char *profile_dir,
+                            gboolean with_extension,
                             uid_t owner_uid,
                             pid_t owner_grp,
                             const char *existing_path,
@@ -187,10 +191,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 ();
@@ -219,10 +227,10 @@ _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);
+		char *filename_escaped = nms_keyfile_utils_escape_filename (id, with_extension);
 
 		path = g_build_filename (keyfile_dir, filename_escaped, NULL);
 		g_free (filename_escaped);
@@ -248,7 +256,7 @@ _internal_write_connection (NMConnection *connection,
 			else
 				filename = g_strdup_printf ("%s-%s-%u", id, nm_connection_get_uuid (connection), i);
 
-			filename_escaped = nms_keyfile_utils_escape_filename (filename);
+			filename_escaped = nms_keyfile_utils_escape_filename (filename, with_extension);
 
 			g_free (path);
 			path = g_strdup_printf ("%s/%s", keyfile_dir, filename_escaped);
@@ -297,17 +305,12 @@ _internal_write_connection (NMConnection *connection,
 		return FALSE;
 	}
 
-	if (out_path && g_strcmp0 (existing_path, path)) {
-		*out_path = path;  /* pass path out to caller */
-		path = NULL;
-	}
-
 	if (out_reread || out_reread_same)
 	{
 		gs_unref_object NMConnection *reread = NULL;
 		gboolean reread_same = FALSE;
 
-		reread = nms_keyfile_reader_from_keyfile (key_file, path, FALSE, NULL);
+		reread = nms_keyfile_reader_from_keyfile (key_file, path, NULL, profile_dir, FALSE, NULL);
 
 		nm_assert (NM_IS_CONNECTION (reread));
 
@@ -333,11 +336,14 @@ _internal_write_connection (NMConnection *connection,
 		NM_SET_OUT (out_reread_same, reread_same);
 	}
 
+	NM_SET_OUT (out_path, g_steal_pointer (&path));
+
 	return TRUE;
 }
 
 gboolean
 nms_keyfile_writer_connection (NMConnection *connection,
+                               gboolean save_to_disk,
                                const char *existing_path,
                                gboolean force_rename,
                                char **out_path,
@@ -345,9 +351,19 @@ 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,
+	                                   keyfile_dir,
 	                                   nms_keyfile_utils_get_path (),
-	                                   0, 0,
+	                                   TRUE,
+	                                   0,
+	                                   0,
 	                                   existing_path,
 	                                   force_rename,
 	                                   out_path,
@@ -368,7 +384,10 @@ nms_keyfile_writer_test_connection (NMConnection *connection,
 {
 	return _internal_write_connection (connection,
 	                                   keyfile_dir,
-	                                   owner_uid, owner_grp,
+	                                   keyfile_dir,
+	                                   FALSE,
+	                                   owner_uid,
+	                                   owner_grp,
 	                                   NULL,
 	                                   FALSE,
 	                                   out_path,
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h
index ac41dfa2..030fb7cc 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,
diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build
index 33aaa264..8b94b256 100644
--- a/src/settings/plugins/keyfile/tests/meson.build
+++ b/src/settings/plugins/keyfile/tests/meson.build
@@ -6,7 +6,6 @@ exe = executable(
   test_unit,
   test_unit + '.c',
   dependencies: test_nm_dep,
-  c_args: nm_build_cflags,
 )
 
 test(
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index a3045f7d..4a0e01b3 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -65,37 +65,32 @@ check_ip_route (NMSettingIPConfig *config, int idx, const char *destination, int
 	g_assert_cmpint (nm_ip_route_get_metric (route), ==, metric);
 }
 
-static NMConnection *
-keyfile_read_connection_from_file (const char *filename)
-{
-	gs_free_error GError *error = NULL;
-	NMConnection *connection;
-
-	g_assert (filename);
-
-	connection = nms_keyfile_reader_from_file (filename, &error);
-	g_assert_no_error (error);
-
-	nmtst_assert_connection_verifies_without_normalization (connection);
-
-	return connection;
-}
+#define keyfile_read_connection_from_file(full_filename) \
+({ \
+	gs_free_error GError *_error = NULL; \
+	NMConnection *_connection; \
+	\
+	g_assert (full_filename && full_filename[0] == '/'); \
+	\
+	_connection = nms_keyfile_reader_from_file (full_filename, \
+	                                            NULL, \
+	                                            (nmtst_get_rand_int () % 2) ? &_error : NULL); \
+	nmtst_assert_success (_connection, _error); \
+	nmtst_assert_connection_verifies_without_normalization (_connection); \
+	\
+	_connection; \
+})
 
 static void
 assert_reread (NMConnection *connection, gboolean normalize_connection, const char *testfile)
 {
 	gs_unref_object NMConnection *reread = NULL;
 	gs_unref_object NMConnection *connection_clone = NULL;
-	GError *error = NULL;
-	GError **p_error = (nmtst_get_rand_int () % 2) ? &error : NULL;
 	NMSettingConnection *s_con;
 
 	g_assert (NM_IS_CONNECTION (connection));
-	g_assert (testfile && testfile[0]);
 
-	reread = nms_keyfile_reader_from_file (testfile, p_error);
-	g_assert_no_error (error);
-	g_assert (NM_IS_CONNECTION (reread));
+	reread = keyfile_read_connection_from_file (testfile);
 
 	if (   !normalize_connection
 	    && (s_con = nm_connection_get_setting_connection (connection))
@@ -229,10 +224,8 @@ test_read_valid_wired_connection (void)
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
 	NMIPRoute *route;
-	gs_free_error GError *error = NULL;
 	const char *mac;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
-	gboolean success;
 
 	NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses1*");
 	NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses2*");
@@ -249,16 +242,9 @@ test_read_valid_wired_connection (void)
 	NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address7*");
 	NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*");
 	NMTST_EXPECT_NM_INFO ("*ipv6.route*semicolon at the end*route6*");
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection", &error);
-	g_assert_no_error (error);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection");
 	g_test_assert_expected_messages ();
-	g_assert (connection);
-
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
 
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection");
@@ -266,7 +252,6 @@ test_read_valid_wired_connection (void)
 	g_assert_cmpuint (nm_setting_connection_get_timestamp (s_con), ==, 6654332);
 	g_assert (nm_setting_connection_get_autoconnect (s_con));
 
-	/* ===== WIRED SETTING ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 
@@ -275,7 +260,6 @@ test_read_valid_wired_connection (void)
 	g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac_address, sizeof (expected_mac_address)));
 	g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1400);
 
-	/* ===== IPv4 SETTING ===== */
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
@@ -324,7 +308,6 @@ test_read_valid_wired_connection (void)
 	nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE);
 	nmtst_assert_route_attribute_string  (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7");
 
-	/* ===== IPv6 SETTING ===== */
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	g_assert (s_ip6);
 
@@ -535,32 +518,22 @@ test_read_ip6_wired_connection (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_IP6", NULL);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_IP6");
 
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection IP6");
 	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "4e80a56d-c99f-4aad-a6dd-b449bc398c57");
 
-	/* ===== WIRED SETTING ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 
-	/* ===== IPv4 SETTING ===== */
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
 	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 0);
 
-	/* ===== IPv6 SETTING ===== */
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	g_assert (s_ip6);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
@@ -638,28 +611,20 @@ test_read_wired_mac_case (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
-	gs_free_error GError *error = NULL;
 	const char *mac;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 };
-	gboolean success;
 
 	NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses1*");
 	NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses2*");
 	NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*");
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case", NULL);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case");
 	g_test_assert_expected_messages ();
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
 
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection MAC Case");
 	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "4e80a56d-c99f-4aad-a6dd-b449bc398c57");
 
-	/* ===== WIRED SETTING ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 	mac = nm_setting_wired_get_mac_address (s_wired);
@@ -672,29 +637,19 @@ test_read_mac_old_format (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWired *s_wired;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 	const char *mac;
 	char expected_mac[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 };
 	char expected_cloned_mac[ETH_ALEN] = { 0x00, 0x16, 0xaa, 0xbb, 0xcc, 0xfe };
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_MAC_Old_Format", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_MAC_Old_Format");
 
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 
-	/* MAC address */
 	mac = nm_setting_wired_get_mac_address (s_wired);
 	g_assert (mac);
 	g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac, ETH_ALEN));
 
-	/* Cloned MAC address */
 	mac = nm_setting_wired_get_cloned_mac_address (s_wired);
 	g_assert (mac);
 	g_assert (nm_utils_hwaddr_matches (mac, -1, expected_cloned_mac, ETH_ALEN));
@@ -705,20 +660,12 @@ test_read_mac_ib_old_format (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingInfiniband *s_ib;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 	const char *mac;
 	guint8 expected_mac[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
-		0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
-		0x90 };
+	    0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
+	    0x90 };
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_MAC_IB_Old_Format", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_MAC_IB_Old_Format");
 
 	s_ib = nm_connection_get_setting_infiniband (connection);
 	g_assert (s_ib);
@@ -736,18 +683,11 @@ test_read_valid_wireless_connection (void)
 	NMSettingConnection *s_con;
 	NMSettingWireless *s_wireless;
 	NMSettingIPConfig *s_ip4;
-	gs_free_error GError *error = NULL;
 	const char *bssid;
 	const guint8 expected_bssid[ETH_ALEN] = { 0x00, 0x1a, 0x33, 0x44, 0x99, 0x82 };
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wireless_Connection", NULL);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wireless_Connection");
 
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wireless Connection");
@@ -755,14 +695,12 @@ test_read_valid_wireless_connection (void)
 	g_assert_cmpuint (nm_setting_connection_get_timestamp (s_con), ==, 1226604314);
 	g_assert (nm_setting_connection_get_autoconnect (s_con) == FALSE);
 
-	/* ===== WIRELESS SETTING ===== */
 	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wireless);
 	bssid = nm_setting_wireless_get_bssid (s_wireless);
 	g_assert (bssid);
 	g_assert (nm_utils_hwaddr_matches (bssid, -1, expected_bssid, sizeof (expected_bssid)));
 
-	/* ===== IPv4 SETTING ===== */
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
@@ -838,24 +776,19 @@ test_read_string_ssid (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWireless *s_wireless;
-	gs_free_error GError *error = NULL;
 	GBytes *ssid;
 	const guint8 *ssid_data;
 	gsize ssid_len;
 	const char *expected_ssid = "blah blah ssid 1234";
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_String_SSID", NULL);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_String_SSID");
 
-	/* ===== WIRELESS SETTING ===== */
 	s_wireless = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wireless);
+
 	ssid = nm_setting_wireless_get_ssid (s_wireless);
 	g_assert (ssid);
+
 	ssid_data = g_bytes_get_data (ssid, &ssid_len);
 	g_assert_cmpmem (ssid_data, ssid_len, expected_ssid, strlen (expected_ssid));
 }
@@ -922,22 +855,13 @@ test_read_intlist_ssid (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWireless *s_wifi;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 	GBytes *ssid;
 	const guint8 *ssid_data;
 	gsize ssid_len;
 	const char *expected_ssid = "blah1234";
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlist_SSID", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlist_SSID");
 
-	/* SSID */
 	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
@@ -960,7 +884,7 @@ test_write_intlist_ssid (void)
 	unsigned char tmpssid[] = { 65, 49, 50, 51, 0, 50, 50 };
 	gs_free_error GError *error = NULL;
 	gs_unref_keyfile GKeyFile *keyfile = NULL;
-	gint *intlist;
+	int *intlist;
 	gsize len = 0, i;
 
 	connection = nm_simple_connection_new ();
@@ -1015,30 +939,17 @@ test_read_intlike_ssid (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWireless *s_wifi;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 	GBytes *ssid;
-	const guint8 *ssid_data;
-	gsize ssid_len;
 	const char *expected_ssid = "101";
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID");
 
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
-
-	/* SSID */
 	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
 	ssid = nm_setting_wireless_get_ssid (s_wifi);
-	g_assert (ssid != NULL);
-	ssid_data = g_bytes_get_data (ssid, &ssid_len);
-	g_assert_cmpint (ssid_len, ==, strlen (expected_ssid));
-	g_assert_cmpint (memcmp (ssid_data, expected_ssid, strlen (expected_ssid)), ==, 0);
+	g_assert (ssid);
+	g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid)));
 }
 
 static void
@@ -1046,30 +957,17 @@ test_read_intlike_ssid_2 (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWireless *s_wifi;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 	GBytes *ssid;
-	const guint8 *ssid_data;
-	gsize ssid_len;
 	const char *expected_ssid = "11;12;13;";
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID_2", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID_2");
 
-	/* SSID */
 	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
 	ssid = nm_setting_wireless_get_ssid (s_wifi);
-	g_assert (ssid != NULL);
-	ssid_data = g_bytes_get_data (ssid, &ssid_len);
-	g_assert_cmpint (ssid_len, ==, strlen (expected_ssid));
-	g_assert_cmpint (memcmp (ssid_data, expected_ssid, strlen (expected_ssid)), ==, 0);
+	g_assert (ssid);
+	g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid)));
 }
 
 static void
@@ -1197,24 +1095,16 @@ test_read_bt_dun_connection (void)
 	NMSettingBluetooth *s_bluetooth;
 	NMSettingSerial *s_serial;
 	NMSettingGsm *s_gsm;
-	gs_free_error GError *error = NULL;
 	const char *bdaddr;
 	const guint8 expected_bdaddr[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_BT", NULL);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_BT");
 
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "AT&T Data Connect BT");
 	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "089130ab-ce28-46e4-ad77-d44869b03d19");
 
-	/* ===== BLUETOOTH SETTING ===== */
 	s_bluetooth = nm_connection_get_setting_bluetooth (connection);
 	g_assert (s_bluetooth);
 	bdaddr = nm_setting_bluetooth_get_bdaddr (s_bluetooth);
@@ -1222,14 +1112,12 @@ test_read_bt_dun_connection (void)
 	g_assert (nm_utils_hwaddr_matches (bdaddr, -1, expected_bdaddr, sizeof (expected_bdaddr)));
 	g_assert_cmpstr (nm_setting_bluetooth_get_connection_type (s_bluetooth), ==, NM_SETTING_BLUETOOTH_TYPE_DUN);
 
-	/* ===== GSM SETTING ===== */
 	s_gsm = nm_connection_get_setting_gsm (connection);
 	g_assert (s_gsm);
 	g_assert_cmpstr (nm_setting_gsm_get_apn (s_gsm), ==, "ISP.CINGULAR");
 	g_assert_cmpstr (nm_setting_gsm_get_username (s_gsm), ==, "ISP@CINGULARGPRS.COM");
 	g_assert_cmpstr (nm_setting_gsm_get_password (s_gsm), ==, "CINGULAR1");
 
-	/* ===== SERIAL SETTING ===== */
 	s_serial = nm_connection_get_setting_serial (connection);
 	g_assert (s_serial);
 	g_assert (nm_setting_serial_get_parity (s_serial) == NM_SETTING_SERIAL_PARITY_ODD);
@@ -1302,28 +1190,17 @@ test_read_gsm_connection (void)
 	NMSettingConnection *s_con;
 	NMSettingSerial *s_serial;
 	NMSettingGsm *s_gsm;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_Plain", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_Plain");
 
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
-
-	/* ===== CONNECTION SETTING ===== */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "AT&T Data Connect");
 	g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_GSM_SETTING_NAME);
 
-	/* ===== BLUETOOTH SETTING ===== */
 	/* Plain GSM, so no BT setting expected */
 	g_assert (nm_connection_get_setting_bluetooth (connection) == NULL);
 
-	/* ===== GSM SETTING ===== */
 	s_gsm = nm_connection_get_setting_gsm (connection);
 	g_assert (s_gsm);
 	g_assert_cmpstr (nm_setting_gsm_get_apn (s_gsm), ==, "ISP.CINGULAR");
@@ -1335,7 +1212,6 @@ test_read_gsm_connection (void)
 	g_assert_cmpstr (nm_setting_gsm_get_sim_id (s_gsm), ==, "89148000000060671234");
 	g_assert_cmpstr (nm_setting_gsm_get_sim_operator_id (s_gsm), ==, "310260");
 
-	/* ===== SERIAL SETTING ===== */
 	s_serial = nm_connection_get_setting_serial (connection);
 	g_assert (s_serial);
 	g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_ODD);
@@ -1401,25 +1277,16 @@ test_read_wired_8021x_tls_blob_connection (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
-	gs_free_error GError *error = NULL;
 	const char *tmp;
-	gboolean success;
 	GBytes *blob;
 
 	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
 	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob");
 
-	/* ===== Wired Setting ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
-	/* ===== 802.1x Setting ===== */
 	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
@@ -1459,25 +1326,16 @@ test_read_wired_8021x_tls_bad_path_connection (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
-	gs_free_error GError *error = NULL;
 	const char *tmp;
 	char *tmp2;
-	gboolean success;
 
 	NMTST_EXPECT_NM_WARN ("*does not exist*");
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing", &error);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing");
 	g_test_assert_expected_messages ();
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
 
-	/* ===== Wired Setting ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
-	/* ===== 802.1x Setting ===== */
 	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
@@ -1513,25 +1371,16 @@ test_read_wired_8021x_tls_old_connection (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
-	gs_free_error GError *error = NULL;
 	const char *tmp;
-	gboolean success;
 
 	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*");
 	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
 	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old");
 
-	/* ===== Wired Setting ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
-	/* ===== 802.1x Setting ===== */
 	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
@@ -1561,23 +1410,14 @@ test_read_wired_8021x_tls_new_connection (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingWired *s_wired;
 	NMSetting8021x *s_8021x;
-	gs_free_error GError *error = NULL;
 	const char *tmp;
 	char *tmp2;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_New", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_New");
 
-	/* ===== Wired Setting ===== */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired != NULL);
 
-	/* ===== 802.1x Setting ===== */
 	s_8021x = nm_connection_get_setting_802_1x (connection);
 	g_assert (s_8021x != NULL);
 
@@ -1698,7 +1538,6 @@ test_write_wired_8021x_tls_connection_path (void)
 	char *tmp, *tmp2;
 	gboolean success;
 	gs_free char *testfile = NULL;
-	gs_free_error GError *error = NULL;
 	gs_unref_keyfile GKeyFile *keyfile = NULL;
 	gboolean relative = FALSE;
 	gboolean reread_same = FALSE;
@@ -1715,12 +1554,7 @@ test_write_wired_8021x_tls_connection_path (void)
 	g_clear_object (&reread);
 
 	/* Read the connection back in and compare it to the one we just wrote out */
-	reread = nms_keyfile_reader_from_file (testfile, &error);
-	if (!reread) {
-		g_assert (error);
-		g_warning ("Failed to re-read test connection: %s", error->message);
-		g_assert (reread);
-	}
+	reread = keyfile_read_connection_from_file (testfile);
 
 	success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
 	if (!reread) {
@@ -1786,8 +1620,8 @@ test_write_wired_8021x_tls_connection_blob (void)
 	char *new_priv_key;
 	const char *uuid;
 	gboolean reread_same = FALSE;
-	gs_free_error GError *error = NULL;
-	GBytes *password_raw = NULL;
+	GBytes *password_raw;
+
 #define PASSWORD_RAW "password-raw\0test"
 
 	connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_BLOB);
@@ -1830,12 +1664,7 @@ test_write_wired_8021x_tls_connection_blob (void)
 	g_assert (g_file_test (new_priv_key, G_FILE_TEST_EXISTS));
 
 	/* Read the connection back in and compare it to the one we just wrote out */
-	reread = nms_keyfile_reader_from_file (testfile, &error);
-	if (!reread) {
-		g_assert (error);
-		g_warning ("Failed to re-read test connection: %s", error->message);
-		g_assert (reread);
-	}
+	reread = keyfile_read_connection_from_file (testfile);
 
 	/* Ensure the re-read connection's certificates use the path scheme */
 	s_8021x = nm_connection_get_setting_802_1x (reread);
@@ -1846,8 +1675,7 @@ test_write_wired_8021x_tls_connection_blob (void)
 
 	password_raw = nm_setting_802_1x_get_password_raw (s_8021x);
 	g_assert (password_raw);
-	g_assert (g_bytes_get_size (password_raw) == NM_STRLEN (PASSWORD_RAW));
-	g_assert (!memcmp (g_bytes_get_data (password_raw, NULL), PASSWORD_RAW, NM_STRLEN (PASSWORD_RAW)));
+	g_assert (nm_utils_gbytes_equal_mem (password_raw, PASSWORD_RAW, NM_STRLEN (PASSWORD_RAW)));
 
 	unlink (testfile);
 
@@ -1876,29 +1704,20 @@ test_read_infiniband_connection (void)
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
 	NMSettingInfiniband *s_ib;
-	gs_free_error GError *error = NULL;
 	const char *mac;
 	guint8 expected_mac[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
-		0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
-		0x90 };
+	    0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89,
+	    0x90 };
 	const char *expected_id = "Test InfiniBand Connection";
 	const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57";
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_InfiniBand_Connection", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_InfiniBand_Connection");
 
-	/* Connection setting */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
 	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid);
 
-	/* InfiniBand setting */
 	s_ib = nm_connection_get_setting_infiniband (connection);
 	g_assert (s_ib);
 
@@ -1966,31 +1785,21 @@ test_read_bridge_main (void)
 	NMSettingConnection *s_con;
 	NMSettingIPConfig *s_ip4;
 	NMSettingBridge *s_bridge;
-	gs_free_error GError *error = NULL;
 	const char *expected_id = "Test Bridge Main";
 	const char *expected_uuid = "8f061643-fe41-4d4c-a8d9-097d26e2ad3a";
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Main", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Main");
 
-	/* Connection setting */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
 	g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid);
 	g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "br0");
 
-	/* IPv4 setting */
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
 
-	/* Bridge setting */
 	s_bridge = nm_connection_get_setting_bridge (connection);
 	g_assert (s_bridge);
 	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 2);
@@ -2063,19 +1872,11 @@ test_read_bridge_component (void)
 	NMSettingWired *s_wired;
 	const char *mac;
 	guint8 expected_mac[ETH_ALEN] = { 0x00, 0x22, 0x15, 0x59, 0x62, 0x97 };
-	gs_free_error GError *error = NULL;
 	const char *expected_id = "Test Bridge Component";
 	const char *expected_uuid = "d7b4f96c-c45e-4298-bef8-f48574f8c1c0";
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Component", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Component");
 
-	/* Connection setting */
 	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 	g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id);
@@ -2083,14 +1884,12 @@ test_read_bridge_component (void)
 	g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, "br0");
 	g_assert (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME));
 
-	/* Wired setting */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 	mac = nm_setting_wired_get_mac_address (s_wired);
 	g_assert (mac);
 	g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac, sizeof (expected_mac)));
 
-	/* BridgePort setting */
 	s_port = nm_connection_get_setting_bridge_port (connection);
 	g_assert (s_port);
 	g_assert (nm_setting_bridge_port_get_hairpin_mode (s_port));
@@ -2155,17 +1954,9 @@ test_read_new_wired_group_name (void)
 	NMSettingWired *s_wired;
 	const char *mac;
 	guint8 expected_mac[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_New_Wired_Group_Name", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_New_Wired_Group_Name");
 
-	/* Wired setting */
 	s_wired = nm_connection_get_setting_wired (connection);
 	g_assert (s_wired);
 	g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1400);
@@ -2186,7 +1977,7 @@ test_write_new_wired_group_name (void)
 	gs_free char *testfile = NULL;
 	gs_free_error GError *error = NULL;
 	char *s;
-	gint mtu;
+	int mtu;
 
 	connection = nm_simple_connection_new ();
 	g_assert (connection);
@@ -2234,32 +2025,19 @@ test_read_new_wireless_group_names (void)
 	NMSettingWireless *s_wifi;
 	NMSettingWirelessSecurity *s_wsec;
 	GBytes *ssid;
-	const guint8 *ssid_data;
-	gsize ssid_len;
 	const char *expected_ssid = "foobar";
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_New_Wireless_Group_Names", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_New_Wireless_Group_Names");
 
-	/* Wifi setting */
 	s_wifi = nm_connection_get_setting_wireless (connection);
 	g_assert (s_wifi);
 
 	ssid = nm_setting_wireless_get_ssid (s_wifi);
 	g_assert (ssid);
-	ssid_data = g_bytes_get_data (ssid, &ssid_len);
-	g_assert_cmpint (ssid_len, ==, strlen (expected_ssid));
-	g_assert_cmpint (memcmp (ssid_data, expected_ssid, ssid_len), ==, 0);
+	g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid)));
 
 	g_assert_cmpstr (nm_setting_wireless_get_mode (s_wifi), ==, NM_SETTING_WIRELESS_MODE_INFRA);
 
-	/* Wifi security setting */
 	s_wsec = nm_connection_get_setting_wireless_security (connection);
 	g_assert (s_wsec);
 	g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-psk");
@@ -2344,17 +2122,9 @@ test_read_missing_vlan_setting (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingVlan *s_vlan;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Setting", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Setting");
 
-	/* Ensure the VLAN setting exists */
 	s_vlan = nm_connection_get_setting_vlan (connection);
 	g_assert (s_vlan);
 	g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 0);
@@ -2366,17 +2136,9 @@ test_read_missing_vlan_flags (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingVlan *s_vlan;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Flags", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Flags");
 
-	/* Ensure the VLAN setting exists */
 	s_vlan = nm_connection_get_setting_vlan (connection);
 	g_assert (s_vlan);
 
@@ -2389,19 +2151,15 @@ static void
 test_read_missing_id_uuid (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
-	gs_free_error GError *error = NULL;
-	gboolean success;
+	gs_free char *expected_uuid = NULL;
+	const char *FILENAME = TEST_KEYFILES_DIR"/Test_Missing_ID_UUID";
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_ID_UUID", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	expected_uuid = _nm_utils_uuid_generate_from_strings ("keyfile", FILENAME, NULL);
+
+	connection = keyfile_read_connection_from_file (FILENAME);
 
-	/* Ensure the ID and UUID properties are there */
 	g_assert_cmpstr (nm_connection_get_id (connection), ==, "Test_Missing_ID_UUID");
-	g_assert (nm_connection_get_uuid (connection));
+	g_assert_cmpstr (nm_connection_get_uuid (connection), ==, expected_uuid);
 }
 
 static void
@@ -2489,17 +2247,9 @@ test_read_enum_property (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingIPConfig *s_ip6;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Enum_Property", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Enum_Property");
 
-	/* IPv6 setting */
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	g_assert (s_ip6);
 	g_assert_cmpint (nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
@@ -2549,17 +2299,9 @@ test_read_flags_property (void)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingGsm *s_gsm;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Flags_Property", &error);
-	g_assert_no_error (error);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Flags_Property");
 
-	/* GSM setting */
 	s_gsm = nm_connection_get_setting_gsm (connection);
 	g_assert (s_gsm);
 	g_assert_cmpint (nm_setting_gsm_get_password_flags (s_gsm), ==,
@@ -2612,14 +2354,8 @@ test_read_tc_config (void)
 	NMTCQdisc *qdisc1, *qdisc2;
 	NMTCAction *action1, *action2;
 	NMTCTfilter *tfilter1, *tfilter2;
-	gs_free_error GError *error = NULL;
-	gboolean success;
 
-	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_TC_Config", NULL);
-	g_assert (connection);
-	success = nm_connection_verify (connection, &error);
-	g_assert_no_error (error);
-	g_assert (success);
+	connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_TC_Config");
 
 	s_tc = nm_connection_get_setting_tc_config (connection);
 	g_assert (s_tc);
@@ -2724,49 +2460,51 @@ test_write_tc_config (void)
 /*****************************************************************************/
 
 static void
-_escape_filename (const char *filename, gboolean would_be_ignored)
+_escape_filename (gboolean with_extension, const char *filename, gboolean would_be_ignored)
 {
 	gs_free char *esc = NULL;
 
 	g_assert (filename && filename[0]);
 
-	if (!!would_be_ignored != !!nms_keyfile_utils_should_ignore_file (filename)) {
+	if (!!would_be_ignored != !!nms_keyfile_utils_should_ignore_file (filename, with_extension)) {
 		if (would_be_ignored)
 			g_error ("We expect filename \"%s\" to be ignored, but it isn't", filename);
 		else
 			g_error ("We expect filename \"%s\" not to be ignored, but it is", filename);
 	}
 
-	esc = nms_keyfile_utils_escape_filename (filename);
+	esc = nms_keyfile_utils_escape_filename (filename, with_extension);
 	g_assert (esc && esc[0]);
 	g_assert (!strchr (esc, '/'));
 
-	if (nms_keyfile_utils_should_ignore_file (esc))
+	if (nms_keyfile_utils_should_ignore_file (esc, with_extension))
 		g_error ("Escaping filename \"%s\" yielded \"%s\", but this is ignored", filename, esc);
 }
 
 static void
 test_nm_keyfile_plugin_utils_escape_filename (void)
 {
-	_escape_filename ("ab", FALSE);
-	_escape_filename (".vim-file.swp", TRUE);
-	_escape_filename (".vim-file.Swp", TRUE);
-	_escape_filename (".vim-file.SWP", TRUE);
-	_escape_filename (".vim-file.swpx", TRUE);
-	_escape_filename (".vim-file.Swpx", TRUE);
-	_escape_filename (".vim-file.SWPX", TRUE);
-	_escape_filename (".pem-file.pem", TRUE);
-	_escape_filename (".pem-file.Pem", TRUE);
-	_escape_filename (".pem-file.PEM", TRUE);
-	_escape_filename (".pem-file.der", TRUE);
-	_escape_filename (".pem-file.Der", TRUE);
-	_escape_filename (".mkstemp.ABCEDF", TRUE);
-	_escape_filename (".mkstemp.abcdef", TRUE);
-	_escape_filename (".mkstemp.123456", TRUE);
-	_escape_filename (".mkstemp.A23456", TRUE);
-	_escape_filename (".#emacs-locking", TRUE);
-	_escape_filename ("file-with-tilde~", TRUE);
-	_escape_filename (".file-with-dot", TRUE);
+	_escape_filename (FALSE, "ab", FALSE);
+	_escape_filename (FALSE, ".vim-file.swp", TRUE);
+	_escape_filename (FALSE, ".vim-file.Swp", TRUE);
+	_escape_filename (FALSE, ".vim-file.SWP", TRUE);
+	_escape_filename (FALSE, ".vim-file.swpx", TRUE);
+	_escape_filename (FALSE, ".vim-file.Swpx", TRUE);
+	_escape_filename (FALSE, ".vim-file.SWPX", TRUE);
+	_escape_filename (FALSE, ".pem-file.pem", TRUE);
+	_escape_filename (FALSE, ".pem-file.Pem", TRUE);
+	_escape_filename (FALSE, ".pem-file.PEM", TRUE);
+	_escape_filename (FALSE, ".pem-file.der", TRUE);
+	_escape_filename (FALSE, ".pem-file.Der", TRUE);
+	_escape_filename (FALSE, ".mkstemp.ABCEDF", TRUE);
+	_escape_filename (FALSE, ".mkstemp.abcdef", TRUE);
+	_escape_filename (FALSE, ".mkstemp.123456", TRUE);
+	_escape_filename (FALSE, ".mkstemp.A23456", TRUE);
+	_escape_filename (FALSE, ".#emacs-locking", TRUE);
+	_escape_filename (FALSE, "file-with-tilde~", TRUE);
+	_escape_filename (FALSE, ".file-with-dot", TRUE);
+
+	_escape_filename (TRUE, "lala", TRUE);
 }
 
 /*****************************************************************************/