summary refs log tree commit diff
path: root/src/settings/plugins/keyfile
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-05-05 17:48:57 +0200
committerMichael Biebl <biebl@debian.org>2015-05-05 17:48:57 +0200
commitf408e27bccfacf347605a8d98649975a68f38a17 (patch)
tree654fd6695c31511baf919b1c0870d119a352ed75 /src/settings/plugins/keyfile
parent2c032d8f1c6292c1338a615e6ec40252889ba85c (diff)
Imported Upstream version 1.0.2 upstream/1.0.2
Diffstat (limited to 'src/settings/plugins/keyfile')
-rw-r--r--src/settings/plugins/keyfile/Makefile.in30
-rw-r--r--src/settings/plugins/keyfile/common.h2
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.c64
-rw-r--r--src/settings/plugins/keyfile/nm-keyfile-connection.h3
-rw-r--r--src/settings/plugins/keyfile/plugin.c377
-rw-r--r--src/settings/plugins/keyfile/reader.c1
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.am1
-rw-r--r--src/settings/plugins/keyfile/tests/Makefile.in32
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Makefile.in24
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main2
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c26
-rw-r--r--src/settings/plugins/keyfile/utils.h7
-rw-r--r--src/settings/plugins/keyfile/writer.c32
13 files changed, 367 insertions, 234 deletions
diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in
index 8c0d11af..21c5577c 100644
--- a/src/settings/plugins/keyfile/Makefile.in
+++ b/src/settings/plugins/keyfile/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,8 +89,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/keyfile
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -194,6 +203,8 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -245,7 +256,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -280,6 +290,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -538,7 +549,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -591,14 +601,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -892,6 +902,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @GNOME_CODE_COVERAGE_RULES@
 
diff --git a/src/settings/plugins/keyfile/common.h b/src/settings/plugins/keyfile/common.h
index db6569e5..7bde4bf3 100644
--- a/src/settings/plugins/keyfile/common.h
+++ b/src/settings/plugins/keyfile/common.h
@@ -24,7 +24,7 @@
 #include <glib.h>
 
 #define KEYFILE_PLUGIN_NAME "keyfile"
-#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2013 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
+#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2015 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
 
 #define KEYFILE_DIR NMCONFDIR "/system-connections"
 
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.c b/src/settings/plugins/keyfile/nm-keyfile-connection.c
index c852f028..8fb94302 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.c
@@ -36,19 +36,12 @@
 
 G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SETTINGS_CONNECTION)
 
-#define NM_KEYFILE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionPrivate))
-
-typedef struct {
-	char *path;
-} NMKeyfileConnectionPrivate;
-
 NMKeyfileConnection *
 nm_keyfile_connection_new (NMConnection *source,
                            const char *full_path,
                            GError **error)
 {
 	GObject *object;
-	NMKeyfileConnectionPrivate *priv;
 	NMConnection *tmp;
 	const char *uuid;
 	gboolean update_unsaved = TRUE;
@@ -75,15 +68,15 @@ nm_keyfile_connection_new (NMConnection *source,
 		update_unsaved = FALSE;
 	}
 
-	object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, NULL);
-
-	priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object);
-	priv->path = g_strdup (full_path);
+	object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION,
+	                                   NM_SETTINGS_CONNECTION_FILENAME, full_path,
+	                                   NULL);
 
 	/* Update our settings with what was read from the file */
 	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
 	                                              tmp,
 	                                              update_unsaved,
+	                                              NULL,
 	                                              error)) {
 		g_object_unref (object);
 		object = NULL;
@@ -93,38 +86,16 @@ nm_keyfile_connection_new (NMConnection *source,
 	return (NMKeyfileConnection *) object;
 }
 
-const char *
-nm_keyfile_connection_get_path (NMKeyfileConnection *self)
-{
-	g_return_val_if_fail (NM_IS_KEYFILE_CONNECTION (self), NULL);
-
-	return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->path;
-}
-
-void
-nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path)
-{
-	NMKeyfileConnectionPrivate *priv;
-
-	g_return_if_fail (NM_IS_KEYFILE_CONNECTION (self));
-	g_return_if_fail (path != NULL);
-
-	priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (self);
-	g_free (priv->path);
-	priv->path = g_strdup (path);
-}
-
 static void
 commit_changes (NMSettingsConnection *connection,
                 NMSettingsConnectionCommitFunc callback,
                 gpointer user_data)
 {
-	NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection);
 	char *path = NULL;
 	GError *error = NULL;
 
 	if (!nm_keyfile_plugin_write_connection (NM_CONNECTION (connection),
-	                                         priv->path,
+	                                         nm_settings_connection_get_filename (connection),
 	                                         &path,
 	                                         &error)) {
 		callback (connection, error, user_data);
@@ -133,10 +104,8 @@ commit_changes (NMSettingsConnection *connection,
 	}
 
 	/* Update the filename if it changed */
-	if (path) {
-		g_free (priv->path);
-		priv->path = path;
-	}
+	if (path)
+		nm_settings_connection_set_filename (connection, path);
 
 	NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->commit_changes (connection,
 	                                                                                   callback,
@@ -148,10 +117,11 @@ do_delete (NMSettingsConnection *connection,
            NMSettingsConnectionDeleteFunc callback,
            gpointer user_data)
 {
-	NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection);
+	const char *path;
 
-	if (priv->path)
-		g_unlink (priv->path);
+	path = nm_settings_connection_get_filename (connection);
+	if (path)
+		g_unlink (path);
 
 	NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->delete (connection,
 	                                                                           callback,
@@ -166,23 +136,11 @@ nm_keyfile_connection_init (NMKeyfileConnection *connection)
 }
 
 static void
-finalize (GObject *object)
-{
-	g_free (NM_KEYFILE_CONNECTION_GET_PRIVATE (object)->path);
-
-	G_OBJECT_CLASS (nm_keyfile_connection_parent_class)->finalize (object);
-}
-
-static void
 nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class);
 	NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class);
 
-	g_type_class_add_private (keyfile_connection_class, sizeof (NMKeyfileConnectionPrivate));
-
 	/* Virtual methods */
-	object_class->finalize = finalize;
 	settings_class->commit_changes = commit_changes;
 	settings_class->delete = do_delete;
 }
diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.h b/src/settings/plugins/keyfile/nm-keyfile-connection.h
index 135bb49f..f6fa432b 100644
--- a/src/settings/plugins/keyfile/nm-keyfile-connection.h
+++ b/src/settings/plugins/keyfile/nm-keyfile-connection.h
@@ -47,9 +47,6 @@ NMKeyfileConnection *nm_keyfile_connection_new (NMConnection *source,
                                                 const char *filename,
                                                 GError **error);
 
-const char *nm_keyfile_connection_get_path (NMKeyfileConnection *self);
-void        nm_keyfile_connection_set_path (NMKeyfileConnection *self, const char *path);
-
 G_END_DECLS
 
 #endif /* __NETWORKMANAGER_KEYFILE_CONNECTION_H__ */
diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c
index 371fa47a..fcdb3c3c 100644
--- a/src/settings/plugins/keyfile/plugin.c
+++ b/src/settings/plugins/keyfile/plugin.c
@@ -45,6 +45,7 @@
 #include "writer.h"
 #include "common.h"
 #include "utils.h"
+#include "gsystem-local-alloc.h"
 
 static char *plugin_get_hostname (SCPluginKeyfile *plugin);
 static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
@@ -87,7 +88,7 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection)
 
 	g_return_if_fail (connection != NULL);
 
-	nm_log_info (LOGD_SETTINGS, "removed %s.", nm_keyfile_connection_get_path (connection));
+	nm_log_info (LOGD_SETTINGS, "keyfile: removed " NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection));
 
 	/* Removing from the hash table should drop the last reference */
 	g_object_ref (connection);
@@ -100,102 +101,182 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection)
 	g_return_if_fail (removed);
 }
 
-static void
-update_connection (SCPluginKeyfile *self,
-                   NMKeyfileConnection *connection,
-                   const char *name)
-{
-	NMKeyfileConnection *tmp;
-	GError *error = NULL;
-
-	tmp = nm_keyfile_connection_new (NULL, name, &error);
-	if (!tmp) {
-		/* Error; remove the connection */
-		nm_log_warn (LOGD_SETTINGS, "    error in connection %s: %s", name,
-		             (error && error->message) ? error->message : "(unknown)");
-		g_clear_error (&error);
-		remove_connection (self, connection);
-		return;
-	}
-
-	if (!nm_connection_compare (NM_CONNECTION (connection),
-	                            NM_CONNECTION (tmp),
-	                            NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
-		                          NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
-		nm_log_info (LOGD_SETTINGS, "updating %s", name);
-		if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
-		                                              NM_CONNECTION (tmp),
-		                                              FALSE,  /* don't set Unsaved */
-		                                              &error)) {
-			/* Shouldn't ever get here as 'new' was verified by the reader already */
-			g_assert_no_error (error);
-		}
-	}
-	g_object_unref (tmp);
-}
-
 static NMKeyfileConnection *
 find_by_path (SCPluginKeyfile *self, const char *path)
 {
 	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
 	GHashTableIter iter;
-	NMKeyfileConnection *candidate = NULL;
+	NMSettingsConnection *candidate = NULL;
 
 	g_return_val_if_fail (path != NULL, NULL);
 
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
-		if (g_strcmp0 (path, nm_keyfile_connection_get_path (candidate)) == 0)
-			return candidate;
+		if (g_strcmp0 (path, nm_settings_connection_get_filename (candidate)) == 0)
+			return NM_KEYFILE_CONNECTION (candidate);
 	}
 	return NULL;
 }
 
-static void
-new_connection (SCPluginKeyfile *self,
-                const char *name,
-                char **out_old_path)
+/* update_connection:
+ * @self: the plugin instance
+ * @source: if %NULL, this re-reads the connection from @full_path
+ *   and updates it. When passing @source, this adds a connection from
+ *   memory.
+ * @full_path: the filename of the keyfile to be loaded
+ * @connection: an existing connection that might be updated.
+ *   If given, @connection must be an existing connection that is currently
+ *   owned by the plugin.
+ * @protect_existing_connection: if %TRUE, and !@connection, we don't allow updating
+ *   an existing connection with the same UUID.
+ *   If %TRUE and @connection, allow updating only if the reload would modify
+ *   @connection (without changing its UUID) or if we would create a new connection.
+ *   In other words, if this paramter is %TRUE, we only allow creating a
+ *   new connection (with an unseen UUID) or updating the passed in @connection
+ *   (whereas the UUID cannot change).
+ *   Note, that this allows for @connection to be replaced by a new connection.
+ * @protected_connections: (allow-none): if given, we only update an
+ *   existing connection if it is not contained in this hash.
+ * @error: error in case of failure
+ *
+ * Loads a connection from file @full_path. This can both be used to
+ * load a connection initially or to update an existing connection.
+ *
+ * If you pass in an existing connection and the reloaded file happens
+ * to have a different UUID, the connection is deleted.
+ * Beware, that means that after the function, you have a dangling pointer
+ * if the returned connection is different from @connection.
+ *
+ * Returns: the updated connection.
+ * */
+static NMKeyfileConnection *
+update_connection (SCPluginKeyfile *self,
+                   NMConnection *source,
+                   const char *full_path,
+                   NMKeyfileConnection *connection,
+                   gboolean protect_existing_connection,
+                   GHashTable *protected_connections,
+                   GError **error)
 {
 	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
-	NMKeyfileConnection *tmp, *connection;
-	GError *error = NULL;
+	NMKeyfileConnection *connection_new;
+	NMKeyfileConnection *connection_by_uuid;
+	GError *local = NULL;
 	const char *uuid;
 
-	if (out_old_path)
-		*out_old_path = NULL;
+	g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL);
+	g_return_val_if_fail (full_path || source, NULL);
 
-	tmp = nm_keyfile_connection_new (NULL, name, &error);
-	if (!tmp) {
-		nm_log_warn (LOGD_SETTINGS, "    error in connection %s: %s", name,
-		             (error && error->message) ? error->message : "(unknown)");
-		g_clear_error (&error);
-		return;
+	if (full_path)
+		nm_log_dbg (LOGD_SETTINGS, "keyfile: loading from file \"%s\"...", full_path);
+
+	connection_new = nm_keyfile_connection_new (source, full_path, &local);
+	if (!connection_new) {
+		/* Error; remove the connection */
+		if (source)
+			nm_log_warn (LOGD_SETTINGS, "keyfile: error creating connection %s: %s", nm_connection_get_uuid (source), local->message);
+		else
+			nm_log_warn (LOGD_SETTINGS, "keyfile: error loading connection from file %s: %s", full_path, local->message);
+		if (   connection
+		    && !protect_existing_connection
+		    && (!protected_connections || !g_hash_table_contains (protected_connections, connection)))
+			remove_connection (self, connection);
+		g_propagate_error (error, local);
+		return NULL;
+	}
+
+	uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new));
+	connection_by_uuid = g_hash_table_lookup (priv->connections, uuid);
+
+	if (   connection
+	    && connection != connection_by_uuid) {
+
+		if (   (protect_existing_connection && connection_by_uuid != NULL)
+		    || (protected_connections && g_hash_table_contains (protected_connections, connection))) {
+			NMKeyfileConnection *conflicting = (protect_existing_connection && connection_by_uuid != NULL) ? connection_by_uuid : connection;
+
+			if (source)
+				nm_log_warn (LOGD_SETTINGS, "keyfile: cannot update protected "NM_KEYFILE_CONNECTION_LOG_FMT" connection due to conflicting UUID %s", NM_KEYFILE_CONNECTION_LOG_ARG (conflicting), uuid);
+			else
+				nm_log_warn (LOGD_SETTINGS, "keyfile: cannot load %s due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, full_path, NM_KEYFILE_CONNECTION_LOG_ARG (conflicting));
+			g_object_unref (connection_new);
+			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+			                      "Cannot update protected connection due to conflicting UUID");
+			return NULL;
+		}
+
+		/* The new connection has a different UUID then the original one.
+		 * Remove @connection. */
+		remove_connection (self, connection);
 	}
 
-	/* Connection renames will show as different paths but same UUID */
-	uuid = nm_connection_get_uuid (NM_CONNECTION (tmp));
-	connection = g_hash_table_lookup (priv->connections, uuid);
-	if (connection) {
-		nm_log_info (LOGD_SETTINGS, "rename %s -> %s", nm_keyfile_connection_get_path (connection), name);
-		if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
-		                                              NM_CONNECTION (tmp),
-		                                              FALSE,  /* don't set Unsaved */
-		                                              &error)) {
-			/* Shouldn't ever get here as 'tmp' was verified by the reader already */
-			g_assert_no_error (error);
+	if (   connection_by_uuid
+	    && (   (!connection && protect_existing_connection)
+	        || (protected_connections && g_hash_table_contains (protected_connections, connection_by_uuid)))) {
+		if (source)
+			nm_log_warn (LOGD_SETTINGS, "keyfile: cannot update connection due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_by_uuid));
+		else
+			nm_log_warn (LOGD_SETTINGS, "keyfile: cannot load %s due to conflicting UUID for "NM_KEYFILE_CONNECTION_LOG_FMT, full_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_by_uuid));
+		g_object_unref (connection_new);
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		                      "Skip updating protected connection during reload");
+		return NULL;
+	}
+
+	if (connection_by_uuid) {
+		const char *old_path;
+
+		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),
+		                           NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+		                           NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+			/* Nothing to do... except updating the path. */
+			if (old_path && g_strcmp0 (old_path, full_path) != 0)
+				nm_log_info (LOGD_SETTINGS, "keyfile: rename \"%s\" to "NM_KEYFILE_CONNECTION_LOG_FMT" without other changes", old_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		} else {
+			/* An existing connection changed. */
+			if (source)
+				nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT" from %s", NM_KEYFILE_CONNECTION_LOG_ARG (connection_new), NM_KEYFILE_CONNECTION_LOG_PATH (old_path));
+			else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new))))
+				nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+			else if (old_path)
+				nm_log_info (LOGD_SETTINGS, "keyfile: rename \"%s\" to "NM_KEYFILE_CONNECTION_LOG_FMT, old_path, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+			else
+				nm_log_info (LOGD_SETTINGS, "keyfile: update and persist "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+
+			if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid),
+			                                              NM_CONNECTION (connection_new),
+			                                              FALSE,  /* don't set Unsaved */
+			                                              "keyfile-update",
+			                                              &local)) {
+				/* Shouldn't ever get here as 'connection_new' was verified by the reader already
+				 * and the UUID did not change. */
+				g_assert_not_reached ();
+			}
+			g_assert_no_error (local);
 		}
-		g_object_unref (tmp);
-		if (out_old_path)
-			*out_old_path = g_strdup (nm_keyfile_connection_get_path (connection));
-		nm_keyfile_connection_set_path (connection, name);
+		nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path);
+		g_object_unref (connection_new);
+		return connection_by_uuid;
 	} else {
-		nm_log_info (LOGD_SETTINGS, "new connection %s", name);
-		g_hash_table_insert (priv->connections, g_strdup (uuid), tmp);
-		g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, tmp);
+		if (source)
+			nm_log_info (LOGD_SETTINGS, "keyfile: add connection "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		else
+			nm_log_info (LOGD_SETTINGS, "keyfile: new connection "NM_KEYFILE_CONNECTION_LOG_FMT, NM_KEYFILE_CONNECTION_LOG_ARG (connection_new));
+		g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new);
 
-		g_signal_connect (tmp, NM_SETTINGS_CONNECTION_REMOVED,
+		g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED,
 		                  G_CALLBACK (connection_removed_cb),
 		                  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_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new);
+		}
+		return connection_new;
 	}
 }
 
@@ -210,26 +291,28 @@ dir_changed (GFileMonitor *monitor,
 	SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
 	NMKeyfileConnection *connection;
 	char *full_path;
+	gboolean exists;
 
 	full_path = g_file_get_path (file);
 	if (nm_keyfile_plugin_utils_should_ignore_file (full_path)) {
 		g_free (full_path);
 		return;
 	}
+	exists = g_file_test (full_path, G_FILE_TEST_EXISTS);
+
+	nm_log_dbg (LOGD_SETTINGS, "dir_changed(%s) = %d; file %s", full_path, event_type, exists ? "exists" : "does not exist");
 
 	connection = find_by_path (self, full_path);
 
 	switch (event_type) {
 	case G_FILE_MONITOR_EVENT_DELETED:
-		if (connection)
+		if (!exists && connection)
 			remove_connection (SC_PLUGIN_KEYFILE (config), connection);
 		break;
 	case G_FILE_MONITOR_EVENT_CREATED:
 	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
-		if (connection)
-			update_connection (SC_PLUGIN_KEYFILE (config), connection, full_path);
-		else
-			new_connection (SC_PLUGIN_KEYFILE (config), full_path, NULL);
+		if (exists)
+			update_connection (SC_PLUGIN_KEYFILE (config), NULL, full_path, connection, TRUE, NULL, NULL);
 		break;
 	default:
 		break;
@@ -305,6 +388,43 @@ setup_monitoring (NMSystemConfigInterface *config)
 	}
 }
 
+static GHashTable *
+_paths_from_connections (GHashTable *connections)
+{
+	GHashTableIter iter;
+	NMKeyfileConnection *connection;
+	GHashTable *paths = g_hash_table_new (g_str_hash, g_str_equal);
+
+	g_hash_table_iter_init (&iter, connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		const char *path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection));
+
+		if (path)
+			g_hash_table_add (paths, (void *) path);
+	}
+	return paths;
+}
+
+static int
+_sort_paths (const char **f1, const char **f2, GHashTable *paths)
+{
+	struct stat st;
+	gboolean c1, c2;
+	gint64 m1, m2;
+
+	c1 = !!g_hash_table_contains (paths, *f1);
+	c2 = !!g_hash_table_contains (paths, *f2);
+	if (c1 != c2)
+		return c1 ? -1 : 1;
+
+	m1 = stat (*f1, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	m2 = stat (*f2, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+	if (m1 != m2)
+		return m1 > m2 ? -1 : 1;
+
+	return strcmp (*f1, *f2);
+}
+
 static void
 read_connections (NMSystemConfigInterface *config)
 {
@@ -313,13 +433,17 @@ read_connections (NMSystemConfigInterface *config)
 	GDir *dir;
 	GError *error = NULL;
 	const char *item;
-	GHashTable *oldconns;
+	GHashTable *alive_connections;
 	GHashTableIter iter;
-	gpointer data;
+	NMKeyfileConnection *connection;
+	GPtrArray *dead_connections = NULL;
+	guint i;
+	GPtrArray *filenames;
+	GHashTable *paths;
 
 	dir = g_dir_open (KEYFILE_DIR, 0, &error);
 	if (!dir) {
-		nm_log_warn (LOGD_SETTINGS, "Cannot read directory '%s': (%d) %s",
+		nm_log_warn (LOGD_SETTINGS, "keyfile: cannot read directory '%s': (%d) %s",
 		             KEYFILE_DIR,
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
@@ -327,45 +451,49 @@ read_connections (NMSystemConfigInterface *config)
 		return;
 	}
 
-	oldconns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	g_hash_table_iter_init (&iter, priv->connections);
-	while (g_hash_table_iter_next (&iter, NULL, &data)) {
-		const char *con_path = nm_keyfile_connection_get_path (data);
-		if (con_path)
-			g_hash_table_insert (oldconns, g_strdup (con_path), data);
-	}
+	alive_connections = g_hash_table_new (NULL, NULL);
 
+	filenames = g_ptr_array_new_with_free_func (g_free);
 	while ((item = g_dir_read_name (dir))) {
-		NMKeyfileConnection *connection;
-		char *full_path, *old_path;
-
 		if (nm_keyfile_plugin_utils_should_ignore_file (item))
 			continue;
+		g_ptr_array_add (filenames, g_build_filename (KEYFILE_DIR, item, NULL));
+	}
+	g_dir_close (dir);
 
-		full_path = g_build_filename (KEYFILE_DIR, item, NULL);
+	/* While reloading, we don't replace connections that we already loaded while
+	 * iterating over the files.
+	 *
+	 * To have sensible, reproducible behavior, sort the paths by last modification
+	 * time prefering older files.
+	 */
+	paths = _paths_from_connections (priv->connections);
+	g_ptr_array_sort_with_data (filenames, (GCompareDataFunc) _sort_paths, paths);
+	g_hash_table_destroy (paths);
+
+	for (i = 0; i < filenames->len; i++) {
+		connection = update_connection (self, NULL, filenames->pdata[i], NULL, FALSE, alive_connections, NULL);
+		if (connection)
+			g_hash_table_add (alive_connections, connection);
+	}
+	g_ptr_array_free (filenames, TRUE);
 
-		connection = g_hash_table_lookup (oldconns, full_path);
-		if (connection) {
-			g_hash_table_remove (oldconns, full_path);
-			update_connection (self, connection, full_path);
-		} else {
-			new_connection (self, full_path, &old_path);
-			if (old_path) {
-				g_hash_table_remove (oldconns, old_path);
-				g_free (old_path);
-			}
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+		if (   !g_hash_table_contains (alive_connections, connection)
+		    && nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection))) {
+			if (!dead_connections)
+				dead_connections = g_ptr_array_new ();
+			g_ptr_array_add (dead_connections, connection);
 		}
-
-		g_free (full_path);
 	}
-	g_dir_close (dir);
+	g_hash_table_destroy (alive_connections);
 
-	g_hash_table_iter_init (&iter, oldconns);
-	while (g_hash_table_iter_next (&iter, NULL, &data)) {
-		g_hash_table_iter_remove (&iter);
-		remove_connection (self, data);
+	if (dead_connections) {
+		for (i = 0; i < dead_connections->len; i++)
+			remove_connection (self, dead_connections->pdata[i]);
+		g_ptr_array_free (dead_connections, TRUE);
 	}
-	g_hash_table_destroy (oldconns);
 }
 
 /* Plugin */
@@ -399,13 +527,7 @@ load_connection (NMSystemConfigInterface *config,
 	if (nm_keyfile_plugin_utils_should_ignore_file (filename + dir_len + 1))
 		return FALSE;
 
-	connection = find_by_path (self, filename);
-	if (connection)
-		update_connection (self, connection, filename);
-	else {
-		new_connection (self, filename, NULL);
-		connection = find_by_path (self, filename);
-	}
+	connection = update_connection (self, NULL, filename, find_by_path (self, filename), TRUE, NULL, NULL);
 
 	return (connection != NULL);
 }
@@ -423,26 +545,13 @@ add_connection (NMSystemConfigInterface *config,
                 GError **error)
 {
 	SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
-	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
-	NMSettingsConnection *added = NULL;
-	char *path = NULL;
+	gs_free char *path = NULL;
 
 	if (save_to_disk) {
 		if (!nm_keyfile_plugin_write_connection (connection, NULL, &path, error))
 			return NULL;
 	}
-
-	added = (NMSettingsConnection *) nm_keyfile_connection_new (connection, path, error);
-	if (added) {
-		g_hash_table_insert (priv->connections,
-		                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (added))),
-		                     added);
-		g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED,
-		                  G_CALLBACK (connection_removed_cb),
-		                  self);
-	}
-	g_free (path);
-	return added;
+	return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
 }
 
 static gboolean
@@ -500,7 +609,7 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
 			} else if (!strncmp (udis[i], "interface-name:", 15) && nm_utils_iface_valid_name (udis[i] + 15)) {
 				specs = g_slist_append (specs, udis[i]);
 			} else {
-				nm_log_warn (LOGD_SETTINGS, "Error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, udis[i]);
+				nm_log_warn (LOGD_SETTINGS, "keyfile: error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, udis[i]);
 				g_free (udis[i]);
 			}
 		}
@@ -510,7 +619,7 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message);
 		g_error_free (error);
 	}
 	if (key_file)
@@ -538,7 +647,7 @@ plugin_get_hostname (SCPluginKeyfile *plugin)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error getting hostname: %s", error->message);
 		g_error_free (error);
 	}
 	if (key_file)
@@ -585,7 +694,7 @@ plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname)
 
  out:
 	if (error) {
-		nm_log_warn (LOGD_SETTINGS, "%s", error->message);
+		nm_log_warn (LOGD_SETTINGS, "keyfile: error setting hostname: %s", error->message);
 		g_error_free (error);
 	}
 	g_free (data);
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index 1d2ecdad..1f0953e0 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -870,6 +870,7 @@ parity_parser (NMSetting *setting, const char *key, GKeyFile *keyfile, const cha
 				int_val = 'X';
 			}
 		}
+		g_free (str_val);
 	}
 
 	if (!int_val)
diff --git a/src/settings/plugins/keyfile/tests/Makefile.am b/src/settings/plugins/keyfile/tests/Makefile.am
index 20b9820c..a79e20b5 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.am
+++ b/src/settings/plugins/keyfile/tests/Makefile.am
@@ -34,6 +34,7 @@ test_keyfile_LDADD = \
 	$(DBUS_LIBS) \
 	$(CODE_COVERAGE_LDFLAGS)
 
+@VALGRIND_RULES@
 TESTS = test-keyfile
 
 endif
diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in
index 8530bf8c..c4d12459 100644
--- a/src/settings/plugins/keyfile/tests/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -81,8 +91,6 @@ host_triplet = @host@
 @ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-keyfile$(EXEEXT)
 @ENABLE_TESTS_TRUE@TESTS = test-keyfile$(EXEEXT)
 subdir = src/settings/plugins/keyfile/tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/build-aux/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -99,6 +107,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -217,6 +226,8 @@ am__tty_colors = { \
   fi; \
 }
 DIST_SUBDIRS = keyfiles
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/build-aux/depcomp
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -268,7 +279,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -303,6 +313,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -548,7 +559,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -596,14 +606,14 @@ distclean-compile:
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
 
 .c.obj:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
 .c.lo:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1031,9 +1041,13 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@
 
+@ENABLE_TESTS_TRUE@@VALGRIND_RULES@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
index bc522b1b..f7a0c45e 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,7 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = src/settings/plugins/keyfile/tests/keyfiles
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/compiler_warnings.m4 \
@@ -95,6 +104,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
 	$(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
@@ -119,6 +129,7 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -145,7 +156,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DATADIRNAME = @DATADIRNAME@
 DBUS_CFLAGS = @DBUS_CFLAGS@
 DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@
 DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@
@@ -180,6 +190,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
 GNUTLS_LIBS = @GNUTLS_LIBS@
 GREP = @GREP@
 GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
 GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
 GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
 GTKDOC_MKPDF = @GTKDOC_MKPDF@
@@ -434,7 +445,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/keyfiles/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --gnu src/settings/plugins/keyfile/tests/keyfiles/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -611,6 +621,8 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 check-local:
 	@for f in $(KEYFILES); do \
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
index 7fbbfe22..3b9fcb28 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main
@@ -6,7 +6,7 @@ type=bridge
 [bridge]
 interface-name=br0
 stp=true
-forward-delay=0
+forward-delay=2
 priority=32744
 hello-time=7
 max-age=39
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index 33e3863c..edece1b2 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -1515,6 +1515,7 @@ test_write_intlike_ssid (void)
 	g_assert_no_error (error);
 	g_assert (tmp);
 	g_assert_cmpstr (tmp, ==, "101");
+	g_free (tmp);
 
 	g_key_file_free (keyfile);
 
@@ -1601,6 +1602,7 @@ test_write_intlike_ssid_2 (void)
 	g_assert_no_error (error);
 	g_assert (tmp);
 	g_assert_cmpstr (tmp, ==, "11\\;12\\;13\\;");
+	g_free (tmp);
 
 	g_key_file_free (keyfile);
 
@@ -2511,6 +2513,7 @@ test_write_wired_8021x_tls_connection_path (void)
 	tmp2 = g_path_get_dirname (testfile);
 	if (g_strcmp0 (tmp2, TEST_KEYFILES_DIR) == 0)
 		relative = TRUE;
+	g_free (tmp2);
 
 	/* CA cert */
 	tmp = g_key_file_get_string (keyfile,
@@ -2564,10 +2567,22 @@ test_write_wired_8021x_tls_connection_blob (void)
 	char *new_priv_key;
 	const char *uuid;
 	GError *error = NULL;
+	GBytes *password_raw = NULL;
+#define PASSWORD_RAW "password-raw\0test"
 
 	connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_BLOB);
 	g_assert (connection != NULL);
 
+	s_8021x = nm_connection_get_setting_802_1x (connection);
+	g_assert (s_8021x);
+
+	password_raw = g_bytes_new (PASSWORD_RAW, STRLEN (PASSWORD_RAW));
+	g_object_set (s_8021x,
+	              NM_SETTING_802_1X_PASSWORD_RAW,
+	              password_raw,
+	              NULL);
+	g_bytes_unref (password_raw);
+
 	/* Write out the connection */
 	success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, geteuid (), getegid (), &testfile, &error);
 	if (!success) {
@@ -2610,6 +2625,11 @@ test_write_wired_8021x_tls_connection_blob (void)
 	g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
 	g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
 
+	password_raw = nm_setting_802_1x_get_password_raw (s_8021x);
+	g_assert (password_raw);
+	g_assert (g_bytes_get_size (password_raw) == STRLEN (PASSWORD_RAW));
+	g_assert (!memcmp (g_bytes_get_data (password_raw, NULL), PASSWORD_RAW, STRLEN (PASSWORD_RAW)));
+
 	unlink (testfile);
 	g_free (testfile);
 
@@ -2784,7 +2804,7 @@ test_read_bridge_main (void)
 	/* 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), ==, 0);
+	g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 2);
 	g_assert_cmpuint (nm_setting_bridge_get_stp (s_bridge), ==, TRUE);
 	g_assert_cmpuint (nm_setting_bridge_get_priority (s_bridge), ==, 32744);
 	g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7);
@@ -3098,6 +3118,7 @@ test_write_new_wired_group_name (void)
 	unlink (testfile);
 	g_free (testfile);
 
+	g_key_file_unref (kf);
 	g_object_unref (reread);
 	g_object_unref (connection);
 }
@@ -3236,6 +3257,7 @@ test_write_new_wireless_group_names (void)
 	unlink (testfile);
 	g_free (testfile);
 
+	g_key_file_unref (kf);
 	g_object_unref (reread);
 	g_object_unref (connection);
 }
@@ -3548,7 +3570,7 @@ NMTST_DEFINE ();
 
 int main (int argc, char **argv)
 {
-	nmtst_init_assert_logging (&argc, &argv);
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
 	/* The tests */
 	g_test_add_func ("/keyfile/test_read_valid_wired_connection ", test_read_valid_wired_connection);
diff --git a/src/settings/plugins/keyfile/utils.h b/src/settings/plugins/keyfile/utils.h
index 1a7c2502..d1533671 100644
--- a/src/settings/plugins/keyfile/utils.h
+++ b/src/settings/plugins/keyfile/utils.h
@@ -23,6 +23,13 @@
 
 #include <glib.h>
 #include "common.h"
+#include "NetworkManagerUtils.h"
+
+#define NM_KEYFILE_CONNECTION_LOG_PATH(path)  str_if_set (path,"in-memory")
+#define NM_KEYFILE_CONNECTION_LOG_FMT         "%s (%s,\"%s\")"
+#define NM_KEYFILE_CONNECTION_LOG_ARG(con)    NM_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con))
+#define NM_KEYFILE_CONNECTION_LOG_FMTD        "%s (%s,\"%s\",%p)"
+#define NM_KEYFILE_CONNECTION_LOG_ARGD(con)   NM_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con)
 
 gboolean nm_keyfile_plugin_utils_should_ignore_file (const char *filename);
 
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index d342e3f7..7aa5bfb0 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -27,7 +27,6 @@
 #include <stdio.h>
 #include <errno.h>
 
-#include <dbus/dbus-glib.h>
 #include <nm-setting.h>
 #include <nm-setting-connection.h>
 #include <nm-setting-ip4-config.h>
@@ -42,7 +41,6 @@
 #include <string.h>
 #include <arpa/inet.h>
 
-#include "nm-dbus-glib-types.h"
 #include "nm-glib-compat.h"
 #include "nm-logging.h"
 #include "writer.h"
@@ -345,19 +343,24 @@ password_raw_writer (GKeyFile *file,
                      const GValue *value)
 {
 	const char *setting_name = nm_setting_get_name (setting);
-	GByteArray *array;
-	int i, *tmp_array;
+	GBytes *array;
+	int *tmp_array;
+	gsize i, len;
+	const char *data;
 
-	g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY));
+	g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES));
 
-	array = (GByteArray *) g_value_get_boxed (value);
-	if (!array || !array->len)
+	array = (GBytes *) g_value_get_boxed (value);
+	if (!array)
+		return;
+	data = g_bytes_get_data (array, &len);
+	if (!data || !len)
 		return;
 
-	tmp_array = g_new (gint, array->len);
-	for (i = 0; i < array->len; i++)
-		tmp_array[i] = (int) array->data[i];
-	nm_keyfile_plugin_kf_set_integer_list (file, setting_name, key, tmp_array, array->len);
+	tmp_array = g_new (gint, len);
+	for (i = 0; i < len; i++)
+		tmp_array[i] = (int) data[i];
+	nm_keyfile_plugin_kf_set_integer_list (file, setting_name, key, tmp_array, len);
 	g_free (tmp_array);
 }
 
@@ -813,13 +816,10 @@ _internal_write_connection (NMConnection *connection,
 	WriteInfo info;
 	GError *local_err = NULL;
 
-	if (out_path)
-		g_return_val_if_fail (*out_path == NULL, FALSE);
+	g_return_val_if_fail (!out_path || !*out_path, FALSE);
 
-	if (!nm_connection_verify (connection, error)) {
+	if (!nm_connection_verify (connection, error))
 		g_return_val_if_reached (FALSE);
-		return FALSE;
-	}
 
 	id = nm_connection_get_id (connection);
 	g_assert (id && *id);