commit 18f6f81069a598a6659890dbd857af760d8761ab
Author: Tambet Ingo <tambet@gmail.com>
Date:   Tue Feb 24 09:00:16 2009 +0200

    nm-0.7-cve-2009-0365.patch

diff --git a/libnm-glib/nm-settings.c b/libnm-glib/nm-settings.c
index d4f1b86..33e13e8 100644
--- a/libnm-glib/nm-settings.c
+++ b/libnm-glib/nm-settings.c
@@ -255,10 +255,32 @@ nm_exported_connection_new (NMConnection *wrapped)
 						      NULL);
 }
 
+static GHashTable *
+real_get_settings (NMExportedConnection *exported)
+{
+	NMExportedConnectionPrivate *priv;
+	NMConnection *no_secrets;
+	GHashTable *hash;
+
+	g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (exported), NULL);
+
+	priv = NM_EXPORTED_CONNECTION_GET_PRIVATE (exported);
+
+	/* Secrets should *never* be returned by the GetSettings method, they
+	 * get returned by the GetSecrets method which can be better
+	 * protected against leakage of secrets to unprivileged callers.
+	 */
+	no_secrets = nm_connection_duplicate (priv->wrapped);
+	nm_connection_clear_secrets (no_secrets);
+	hash = nm_connection_to_hash (no_secrets);
+	g_object_unref (G_OBJECT (no_secrets));
+	return hash;
+}
+
 static gboolean
 impl_exported_connection_get_settings (NMExportedConnection *connection,
-							    GHashTable **settings,
-							    GError **error)
+                                       GHashTable **settings,
+                                       GError **error)
 {
 	NMExportedConnectionPrivate *priv;
 
@@ -267,7 +289,7 @@ impl_exported_connection_get_settings (NMExportedConnection *connection,
 	priv = NM_EXPORTED_CONNECTION_GET_PRIVATE (connection);
 
 	if (!EXPORTED_CONNECTION_CLASS (connection)->get_settings)
-		*settings = nm_connection_to_hash (priv->wrapped);
+		*settings = real_get_settings (connection);
 	else
 		*settings = EXPORTED_CONNECTION_CLASS (connection)->get_settings (connection);
 
@@ -351,6 +373,103 @@ impl_exported_connection_delete (NMExportedConnection *connection,
 	return success;
 }
 
+static GValue *
+string_to_gvalue (const char *str)
+{
+	GValue *val;
+
+	val = g_slice_new0 (GValue);
+	g_value_init (val, G_TYPE_STRING);
+	g_value_set_string (val, str);
+
+	return val;
+}
+
+static void
+copy_one_secret (gpointer key, gpointer value, gpointer user_data)
+{
+	const char *value_str = (const char *) value;
+
+	if (value_str) {
+		g_hash_table_insert ((GHashTable *) user_data,
+		                     g_strdup ((char *) key),
+		                     string_to_gvalue (value_str));
+	}
+}
+
+static void
+add_secrets (NMSetting *setting,
+             const char *key,
+             const GValue *value,
+             GParamFlags flags,
+             gpointer user_data)
+{
+	GHashTable *secrets = user_data;
+
+	if (!(flags & NM_SETTING_PARAM_SECRET))
+		return;
+
+	if (G_VALUE_HOLDS_STRING (value)) {
+		const char *tmp;
+
+		tmp = g_value_get_string (value);
+		if (tmp)
+			g_hash_table_insert (secrets, g_strdup (key), string_to_gvalue (tmp));
+	} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
+		/* Flatten the string hash by pulling its keys/values out */
+		g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
+	}
+}
+
+static void
+destroy_gvalue (gpointer data)
+{
+	GValue *value = (GValue *) data;
+
+	g_value_unset (value);
+	g_slice_free (GValue, value);
+}
+
+static void
+real_get_secrets (NMExportedConnection *exported,
+                  const gchar *setting_name,
+                  const gchar **hints,
+                  gboolean request_new,
+                  DBusGMethodInvocation *context)
+{
+	NMConnection *connection;
+	GError *error = NULL;
+	GHashTable *settings = NULL;
+	GHashTable *secrets = NULL;
+	NMSetting *setting;
+
+	connection = nm_exported_connection_get_connection (exported);
+	setting = nm_connection_get_setting_by_name (connection, setting_name);
+	if (!setting) {
+		g_set_error (&error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		             "%s.%d - Connection didn't have requested setting '%s'.",
+		             __FILE__, __LINE__, setting_name);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+		return;
+	}
+
+	/* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
+	 * will contain all the individual settings hashes.
+	 */
+	settings = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                                  g_free, (GDestroyNotify) g_hash_table_destroy);
+
+	/* Add the secrets from this setting to the inner secrets hash for this setting */
+	secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
+	nm_setting_enumerate_values (setting, add_secrets, secrets);
+
+	g_hash_table_insert (settings, g_strdup (setting_name), secrets);
+
+	dbus_g_method_return (context, settings);
+	g_hash_table_destroy (settings);
+}
+
 static void
 impl_exported_connection_get_secrets (NMExportedConnection *connection,
                                       const gchar *setting_name,
@@ -369,16 +488,10 @@ impl_exported_connection_get_secrets (NMExportedConnection *connection,
 		return;
 	}
 
-	if (!EXPORTED_CONNECTION_CLASS (connection)->service_get_secrets) {
-		g_set_error (&error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,
-		             "%s.%d - Missing implementation for ConnectionSettings::GetSecrets.",
-		             __FILE__, __LINE__);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-		return;
-	}
-
-	EXPORTED_CONNECTION_CLASS (connection)->service_get_secrets (connection, setting_name, hints, request_new, context);
+	if (!EXPORTED_CONNECTION_CLASS (connection)->service_get_secrets)
+		real_get_secrets (connection, setting_name, hints, request_new, context);
+	else
+		EXPORTED_CONNECTION_CLASS (connection)->service_get_secrets (connection, setting_name, hints, request_new, context);
 }
 
 static void
@@ -451,6 +564,9 @@ nm_exported_connection_class_init (NMExportedConnectionClass *exported_connectio
 	object_class->get_property = get_property;
 	object_class->dispose = nm_exported_connection_dispose;
 
+	exported_connection_class->get_settings = real_get_settings;
+	exported_connection_class->service_get_secrets = real_get_secrets;
+
 	/* Properties */
 	g_object_class_install_property
 		(object_class, PROP_CONNECTION,
diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
index 14468b0..7d02ba9 100644
--- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
+++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
@@ -315,12 +315,6 @@ nm_ifcfg_connection_get_unmanaged (NMIfcfgConnection *self)
 	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged;
 }
 
-static GHashTable *
-get_settings (NMExportedConnection *exported)
-{
-	return nm_connection_to_hash (nm_exported_connection_get_connection (exported));
-}
-
 static gboolean
 update (NMExportedConnection *exported, GHashTable *new_settings, GError **error)
 {
@@ -444,7 +438,6 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
 	object_class->get_property = get_property;
 	object_class->finalize     = finalize;
 
-	connection_class->get_settings = get_settings;
 	connection_class->update       = update;
 	connection_class->do_delete    = do_delete;
 
diff --git a/system-settings/plugins/ifcfg-suse/nm-suse-connection.c b/system-settings/plugins/ifcfg-suse/nm-suse-connection.c
index ccdcc7f..7063b6d 100644
--- a/system-settings/plugins/ifcfg-suse/nm-suse-connection.c
+++ b/system-settings/plugins/ifcfg-suse/nm-suse-connection.c
@@ -105,12 +105,6 @@ nm_suse_connection_new (const char *iface, NMDeviceType dev_type)
 	return exported;
 }
 
-static GHashTable *
-get_settings (NMExportedConnection *exported)
-{
-	return nm_connection_to_hash (nm_exported_connection_get_connection (exported));
-}
-
 static gboolean
 update (NMExportedConnection *exported,
 	   GHashTable *new_settings,
@@ -169,7 +163,6 @@ nm_suse_connection_class_init (NMSuseConnectionClass *suse_connection_class)
 	/* Virtual methods */
 	object_class->finalize = finalize;
 
-	connection_class->get_settings = get_settings;
 	connection_class->update       = update;
 	connection_class->do_delete    = do_delete;
 }
diff --git a/system-settings/plugins/ifupdown/nm-ifupdown-connection.c b/system-settings/plugins/ifupdown/nm-ifupdown-connection.c
index 0b9bd2a..1ed0fd2 100644
--- a/system-settings/plugins/ifupdown/nm-ifupdown-connection.c
+++ b/system-settings/plugins/ifupdown/nm-ifupdown-connection.c
@@ -67,12 +67,6 @@ nm_ifupdown_connection_new (if_block *block)
 										 NULL);
 }
 
-static GHashTable *
-get_settings (NMExportedConnection *exported)
-{
-	return nm_connection_to_hash (nm_exported_connection_get_connection (exported));
-}
-
 static gboolean
 update (NMExportedConnection *exported,
 	   GHashTable *new_settings,
@@ -185,7 +179,6 @@ nm_ifupdown_connection_class_init (NMIfupdownConnectionClass *ifupdown_connectio
 	object_class->get_property = get_property;
 	object_class->finalize     = finalize;
 
-	connection_class->get_settings = get_settings;
 	connection_class->update       = update;
 	connection_class->do_delete    = do_delete;
 	connection_class->service_get_secrets = service_get_secrets;
@@ -206,54 +199,14 @@ service_get_secrets (NMExportedConnection *exported,
                      gboolean request_new,
                      DBusGMethodInvocation *context)
 {
-	NMConnection *connection;
 	GError *error = NULL;
-	GHashTable *settings = NULL;
-	GHashTable *secrets = NULL;
-	NMSetting *setting;
 
 	PLUGIN_PRINT ("SCPlugin-Ifupdown", "get_secrets for setting_name:'%s')", setting_name);
 
-	connection = nm_exported_connection_get_connection (exported);
-	setting = nm_connection_get_setting_by_name (connection, setting_name);
-
-	if (!setting) {
-		g_set_error (&error, NM_SETTINGS_ERROR,
-				   NM_SETTINGS_ERROR_INVALID_CONNECTION,
-				   "%s.%d - Connection didn't have requested setting '%s'.",
-				   __FILE__, __LINE__, setting_name);
-		PLUGIN_PRINT ("SCPlugin-Ifupdown", "%s", error->message);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-		return;
-	}
-
-	settings = g_hash_table_new_full (g_str_hash, g_str_equal,
-							    g_free, (GDestroyNotify) g_hash_table_destroy);
-
-	if (!settings) {
-		g_set_error (&error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INTERNAL_ERROR,
-				   "%s.%d - failed to hash setting (OOM?)",
-				   __FILE__, __LINE__);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-		return;
-	}
-
-	if (!strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME)) {
-		secrets = nm_setting_to_hash (setting);
-		if (secrets) {
-			g_hash_table_insert(settings, g_strdup(setting_name), secrets);
-			dbus_g_method_return (context, settings);
-		} else {
-			g_set_error (&error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INTERNAL_ERROR,
-					   "%s.%d - nm_setting_to_hash failed (OOM?)",
-					   __FILE__, __LINE__);
-			dbus_g_method_return_error (context, error);
-			g_error_free (error);
-			g_hash_table_destroy (settings);
-		}
-	} else {
+	/* FIXME: Only wifi secrets are supported for now */
+	if (!strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME))
+		NM_EXPORTED_CONNECTION_CLASS (nm_ifupdown_connection_parent_class)->service_get_secrets (exported, setting_name, hints, request_new, context);
+	else {
 		g_set_error (&error, NM_SETTING_WIRELESS_SECURITY_ERROR, 1,
 				   "%s.%d - security setting name not supported '%s'.",
 				   __FILE__, __LINE__, setting_name);
diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.c b/system-settings/plugins/keyfile/nm-keyfile-connection.c
index 2f4ded7..80e1670 100644
--- a/system-settings/plugins/keyfile/nm-keyfile-connection.c
+++ b/system-settings/plugins/keyfile/nm-keyfile-connection.c
@@ -64,162 +64,6 @@ nm_keyfile_connection_get_filename (NMKeyfileConnection *self)
 	return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->filename;
 }
 
-static GHashTable *
-get_settings (NMExportedConnection *exported)
-{
-	return nm_connection_to_hash (nm_exported_connection_get_connection (exported));
-}
-
-static GValue *
-string_to_gvalue (const char *str)
-{
-	GValue *val;
-
-	val = g_slice_new0 (GValue);
-	g_value_init (val, G_TYPE_STRING);
-	g_value_set_string (val, str);
-
-	return val;
-}
-
-static void
-copy_one_secret (gpointer key, gpointer value, gpointer user_data)
-{
-	const char *value_str = (const char *) value;
-
-	if (value_str)
-		g_hash_table_insert ((GHashTable *) user_data,
-							 g_strdup ((char *) key),
-							 string_to_gvalue (value_str));
-}
-
-static void
-add_secrets (NMSetting *setting,
-             const char *key,
-             const GValue *value,
-             GParamFlags flags,
-             gpointer user_data)
-{
-	GHashTable *secrets = user_data;
-
-	if (!(flags & NM_SETTING_PARAM_SECRET))
-		return;
-
-	if (G_VALUE_HOLDS_STRING (value)) {
-		const char *tmp;
-
-		tmp = g_value_get_string (value);
-		if (tmp)
-			g_hash_table_insert (secrets, g_strdup (key), string_to_gvalue (tmp));
-	} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
-		/* Flatten the string hash by pulling its keys/values out */
-		g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
-	} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)) {
-		const GByteArray *array;
-
-		array = (GByteArray *) g_value_get_boxed (value);
-		if (array && array->len > 0) {
-			GValue *v;
-
-			v = g_slice_new0 (GValue);
-			g_value_init (v, DBUS_TYPE_G_UCHAR_ARRAY);
-			g_value_copy (value, v);
-			g_hash_table_insert (secrets, g_strdup (key), v);
-		}
-	} else
-		g_message ("%s: unhandled secret %s type %s", __func__, key, G_VALUE_TYPE_NAME (value));
-}
-
-static void
-destroy_gvalue (gpointer data)
-{
-	GValue *value = (GValue *) data;
-
-	g_value_unset (value);
-	g_slice_free (GValue, value);
-}
-
-static GHashTable *
-extract_secrets (NMKeyfileConnection *exported,
-                 const char *setting_name,
-                 GError **error)
-{
-	NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (exported);
-	NMConnection *tmp;
-	GHashTable *secrets;
-	NMSetting *setting;
-
-	tmp = connection_from_file (priv->filename, TRUE);
-	if (!tmp) {
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,
-		             "%s.%d - Could not read secrets from file %s.",
-		             __FILE__, __LINE__, priv->filename);
-		return NULL;
-	}
-
-	setting = nm_connection_get_setting_by_name (tmp, setting_name);
-	if (!setting) {
-		g_object_unref (tmp);
-		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_SECRETS_UNAVAILABLE,
-		             "%s.%d - Could not read secrets from file %s.",
-		             __FILE__, __LINE__, priv->filename);
-		return NULL;
-	}
-
-	/* Add the secrets from this setting to the secrets hash */
-	secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
-	nm_setting_enumerate_values (setting, add_secrets, secrets);
-
-	g_object_unref (tmp);
-
-	return secrets;
-}
-
-static void
-service_get_secrets (NMExportedConnection *exported,
-                     const gchar *setting_name,
-                     const gchar **hints,
-                     gboolean request_new,
-                     DBusGMethodInvocation *context)
-{
-	NMConnection *connection;
-	GError *error = NULL;
-	GHashTable *settings = NULL;
-	GHashTable *secrets = NULL;
-	NMSetting *setting;
-
-	connection = nm_exported_connection_get_connection (exported);
-	setting = nm_connection_get_setting_by_name (connection, setting_name);
-	if (!setting) {
-		g_set_error (&error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-		             "%s.%d - Connection didn't have requested setting '%s'.",
-		             __FILE__, __LINE__, setting_name);
-		goto error;
-	}
-
-	/* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
-	 * will contain all the individual settings hashes.
-	 */
-	settings = g_hash_table_new_full (g_str_hash, g_str_equal,
-	                                  g_free, (GDestroyNotify) g_hash_table_destroy);
-
-	/* Read in a temporary connection and just extract the secrets */
-	secrets = extract_secrets (NM_KEYFILE_CONNECTION (exported), setting_name, &error);
-	if (!secrets)
-		goto error;
-
-	g_hash_table_insert (settings, g_strdup (setting_name), secrets);
-
-	dbus_g_method_return (context, settings);
-	g_hash_table_destroy (settings);
-	return;
-
-error:
-	nm_warning ("%s", error->message);
-	dbus_g_method_return_error (context, error);
-	g_error_free (error);
-}
-
 static gboolean
 update (NMExportedConnection *exported,
         GHashTable *new_settings,
@@ -292,7 +136,7 @@ constructor (GType type,
 		goto err;
 	}
 
-	wrapped = connection_from_file (priv->filename, FALSE);
+	wrapped = connection_from_file (priv->filename);
 	if (!wrapped)
 		goto err;
 
@@ -382,8 +226,6 @@ nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_c
 	object_class->get_property = get_property;
 	object_class->finalize     = finalize;
 
-	connection_class->get_settings = get_settings;
-	connection_class->service_get_secrets  = service_get_secrets;
 	connection_class->update       = update;
 	connection_class->do_delete    = do_delete;
 
diff --git a/system-settings/plugins/keyfile/reader.c b/system-settings/plugins/keyfile/reader.c
index b8c4099..81d547e 100644
--- a/system-settings/plugins/keyfile/reader.c
+++ b/system-settings/plugins/keyfile/reader.c
@@ -388,11 +388,6 @@ read_certificate (NMSetting *setting, GKeyFile *file, const char *key)
 	g_free (value);
 }
 
-typedef struct {
-	GKeyFile *keyfile;
-	gboolean secrets;
-} ReadSettingInfo;
-
 static void
 read_one_setting_value (NMSetting *setting,
                         const char *key,
@@ -400,8 +395,7 @@ read_one_setting_value (NMSetting *setting,
                         GParamFlags flags,
                         gpointer user_data)
 {
-	ReadSettingInfo *info = (ReadSettingInfo *) user_data;
-	GKeyFile *file = info->keyfile;
+	GKeyFile *file = user_data;
 	const char *setting_name;
 	GType type;
 	GError *err = NULL;
@@ -415,10 +409,6 @@ read_one_setting_value (NMSetting *setting,
 	if (!strcmp (key, NM_SETTING_NAME))
 		return;
 
-	/* Don't read in secrets unless we want to */
-	if ((flags & NM_SETTING_PARAM_SECRET) && !info->secrets)
-		return;
-
 	/* Don't read the NMSettingConnection object's 'read-only' property */
 	if (   NM_IS_SETTING_CONNECTION (setting)
 	    && !strcmp (key, NM_SETTING_CONNECTION_READ_ONLY))
@@ -524,17 +514,13 @@ read_one_setting_value (NMSetting *setting,
 }
 
 static NMSetting *
-read_setting (GKeyFile *file, const char *name, gboolean secrets)
+read_setting (GKeyFile *file, const char *name)
 {
 	NMSetting *setting;
-	ReadSettingInfo info;
-
-	info.keyfile = file;
-	info.secrets = secrets;
 
 	setting = nm_connection_create_setting (name);
 	if (setting)
-		nm_setting_enumerate_values (setting, read_one_setting_value, &info);
+		nm_setting_enumerate_values (setting, read_one_setting_value, file);
 	else
 		g_warning ("Invalid setting name '%s'", name);
 
@@ -560,7 +546,7 @@ read_vpn_secrets (GKeyFile *file, NMSettingVPN *s_vpn)
 }
 
 NMConnection *
-connection_from_file (const char *filename, gboolean secrets)
+connection_from_file (const char *filename)
 {
 	GKeyFile *key_file;
 	struct stat statbuf;
@@ -598,13 +584,13 @@ connection_from_file (const char *filename, gboolean secrets)
 				continue;
 			}
 
-			setting = read_setting (key_file, groups[i], secrets);
+			setting = read_setting (key_file, groups[i]);
 			if (setting)
 				nm_connection_add_setting (connection, setting);
 		}
 
 		/* Handle vpn secrets after the 'vpn' setting was read */
-		if (secrets && vpn_secrets) {
+		if (vpn_secrets) {
 			NMSettingVPN *s_vpn;
 
 			s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
diff --git a/system-settings/plugins/keyfile/reader.h b/system-settings/plugins/keyfile/reader.h
index 5c40462..beac866 100644
--- a/system-settings/plugins/keyfile/reader.h
+++ b/system-settings/plugins/keyfile/reader.h
@@ -27,6 +27,6 @@
 #include <glib.h>
 #include <nm-connection.h>
 
-NMConnection *connection_from_file (const char *filename, gboolean secrets);
+NMConnection *connection_from_file (const char *filename);
 
 #endif /* _KEYFILE_PLUGIN_READER_H */
diff --git a/system-settings/src/nm-system-settings.conf b/system-settings/src/nm-system-settings.conf
index ab239ce..d09bc48 100644
--- a/system-settings/src/nm-system-settings.conf
+++ b/system-settings/src/nm-system-settings.conf
@@ -14,7 +14,7 @@
 
 		<!-- Only root can get secrets -->
 		<deny send_destination="org.freedesktop.NetworkManagerSystemSettings"
-		      send_interface="org.freedesktop.NetworkManagerSettings.Secrets"/>
+		      send_interface="org.freedesktop.NetworkManagerSettings.Connection.Secrets"/>
 	</policy>
 
         <limit name="max_replies_per_connection">512</limit>
