[gnome-color-manager] Make gcm-install-system-wide a little more paranoid from users that might want to be horrible
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-color-manager] Make gcm-install-system-wide a little more paranoid from users that might want to be horrible
- Date: Tue, 16 Mar 2010 10:59:51 +0000 (UTC)
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]