[gnome-color-manager] Make gcm-install-system-wide a little more paranoid from users that might want to be horrible



commit db69e22109905521756eae42f7fa4f204145f54a
Author: Richard Hughes <richard hughsie com>
Date:   Tue Mar 16 10:59:10 2010 +0000

    Make gcm-install-system-wide a little more paranoid from users that might want to be horrible
    
    We can't actually see any problems here, although it's probably a good idea
    to be super paranoid given we're running as the root user.

 src/gcm-install-system-wide.c |  135 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 128 insertions(+), 7 deletions(-)
---
diff --git a/src/gcm-install-system-wide.c b/src/gcm-install-system-wide.c
index 0e5c90b..58d71ca 100644
--- a/src/gcm-install-system-wide.c
+++ b/src/gcm-install-system-wide.c
@@ -28,11 +28,70 @@
 #include <gio/gio.h>
 #include <locale.h>
 
-#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_SUCCESS			0
+#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_SUCCESS		0
 #define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_FAILED			1
-#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_ARGUMENTS_INVALID		3
-#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_CONTENT_TYPE_INVALID		4
+#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_ARGUMENTS_INVALID	3
+#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_CONTENT_TYPE_INVALID	4
 #define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_FAILED_TO_COPY		5
+#define GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_INVALID_USER		6
+
+/**
+ * gcm_install_system_wide_is_alphanum_lcase:
+ **/
+static gboolean
+gcm_install_system_wide_is_alphanum_lcase (const gchar *data)
+{
+	guint i;
+	gboolean ret = TRUE;
+
+	/* find chars that should not be in the id */
+	for (i=0; data[i] != '\0'; i++) {
+		if (data[i] == '_')
+			continue;
+		if (g_ascii_isalnum (data[i]))
+			continue;
+		if (g_ascii_islower (data[i]))
+			continue;
+		ret = FALSE;
+		break;
+	}
+	return ret;
+}
+
+/**
+ * egg_strtouint:
+ * @text: The text the convert
+ * @value: The return numeric return value
+ *
+ * Converts a string into a unsigned integer value in a safe way.
+ *
+ * Return value: %TRUE if the string was converted correctly
+ **/
+static gboolean
+egg_strtouint (const gchar *text, guint *value)
+{
+	gchar *endptr = NULL;
+	guint64 value_raw;
+
+	/* invalid */
+	if (text == NULL)
+		return FALSE;
+
+	/* parse */
+	value_raw = g_ascii_strtoull (text, &endptr, 10);
+
+	/* parsing error */
+	if (endptr == text)
+		return FALSE;
+
+	/* out of range */
+	if (value_raw > G_MAXINT)
+		return FALSE;
+
+	/* cast back down to value */
+	*value = (guint) value_raw;
+	return TRUE;
+}
 
 /**
  * main:
@@ -46,11 +105,15 @@ main (gint argc, gchar *argv[])
 	gint uid;
 	gint euid;
 	guint retval = 0;
+	gchar *filename_dest = NULL;
 	gchar *dest = NULL;
 	GFile *file = NULL;
 	GFile *file_dest = NULL;
 	GFileInfo *info = NULL;
 	const gchar *type;
+	const gchar *pkexec_uid_str;
+	guint pkexec_uid;
+	guint file_uid;
 	GError *error = NULL;
 	gboolean ret = FALSE;
 
@@ -96,6 +159,15 @@ main (gint argc, gchar *argv[])
 		goto out;
 	}
 
+	/* no id */
+	ret = gcm_install_system_wide_is_alphanum_lcase (id);
+	if (!ret) {
+		/* TRANSLATORS: user did not specify a valid device ID */
+		g_print ("%s\n", _("The device ID has invalid characters"));
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_ARGUMENTS_INVALID;
+		goto out;
+	}
+
 	/* get calling process */
 	uid = getuid ();
 	euid = geteuid ();
@@ -106,9 +178,19 @@ main (gint argc, gchar *argv[])
 		goto out;
 	}
 
+	/* absolute source filenames only */
+	ret = g_path_is_absolute (filenames[0]);
+	if (!ret) {
+		/* TRANSLATORS: only able to install profiles with an absolute path */
+		g_print ("%s\n", _("The source filename must be absolute"));
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_ARGUMENTS_INVALID;
+		goto out;
+	}
+
 	/* get content type for file */
 	file = g_file_new_for_path (filenames[0]);
-	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error);
+	info = g_file_query_info (file, "standard::content-type,unix::uid",
+				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &error);
 	if (info == NULL) {
 		/* TRANSLATORS: error details */
 		g_print ("%s: %s\n", _("Failed to get content type"), error->message);
@@ -126,11 +208,48 @@ main (gint argc, gchar *argv[])
 		goto out;
 	}
 
-	/* get new location */
-	dest = g_strdup_printf ("%s/%s.icc", GCM_SYSTEM_PROFILES_DIR, id);
-	file_dest = g_file_new_for_path (dest);
+	/* only copy files that are really owned by the calling user */
+	pkexec_uid_str = g_getenv ("PKEXEC_UID");
+	if (pkexec_uid_str == NULL) {
+		/* TRANSLATORS: the program must never be directly run */
+		g_print ("%s: %s\n", _("This program must only be run through pkexec"), type);
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_INVALID_USER;
+		goto out;
+	}
+
+	/* convert the uid to a number */
+	ret = egg_strtouint (pkexec_uid_str, &pkexec_uid);
+	if (!ret) {
+		/* TRANSLATORS: PolicyKit has gone all insane on us, and we refuse to parse junk */
+		g_print ("%s: %s\n", _("PKEXEC_UID must be set to an integer value"), type);
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_INVALID_USER;
+		goto out;
+	}
+
+	/* check is owned by the correct user */
+	file_uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
+	if (file_uid != pkexec_uid) {
+		/* TRANSLATORS: we are complaining that a file must be really owned by the user who called this program */
+		g_print ("%s: %s\n", _("The ICC profile must be owned by you"), type);
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_INVALID_USER;
+		goto out;
+	}
+
+	/* create the basename of the new file */
+	filename_dest = g_strconcat (id, ".icc", NULL);
+
+	/* absolute source filenames only */
+	dest = g_build_filename (GCM_SYSTEM_PROFILES_DIR, filename_dest, NULL);
+	ret = g_path_is_absolute (dest);
+	if (!ret) {
+		/* TRANSLATORS: only able to install profiles with an absolute path */
+		g_print ("%s\n", _("The destination filename must be absolute"));
+		retval = GCM_INSTALL_SYSTEM_WIDE_EXIT_CODE_ARGUMENTS_INVALID;
+		goto out;
+	}
 
 	/* do the copy */
+	file_dest = g_file_new_for_path (dest);
 	ret = g_file_copy (file, file_dest, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
 	if (!ret) {
 		/* TRANSLATORS: error details */
@@ -150,6 +269,8 @@ out:
 	if (file_dest != NULL)
 		g_object_unref (file_dest);
 	g_strfreev (filenames);
+	g_free (filename_dest);
+	g_free (dest);
 	g_free (id);
 	return retval;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]