File gconf2-predictable-filenames.patch of Package gconf2
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gconf/ChangeLog,v
retrieving revision 1.489.2.31
diff -u -r1.489.2.31 ChangeLog
--- ChangeLog 9 Jul 2004 05:52:17 -0000 1.489.2.31
+++ ChangeLog 5 Aug 2004 15:24:36 -0000
@@ -1,0 +1,14 @@
+2004-08-03 Federico Mena Quintero <federico@ximian.com>
+
+ Fix #141138:
+
+ * gconf/gconf-internals.c (test_safe_lock_dir): New function,
+ stolen from ORBit. Tests the permissions and owner of our lock
+ directory.
+ (scan_lock_dir): New function, stolen from ORBit. Scans a
+ directory for a valid lock directory.
+ (tmpdir_init): New function, stolen from ORBit. Creates the lock
+ directory in /tmp. Modified to use g_random_int() rather than
+ ORBit's UUID generator.
+ (gconf_get_daemon_dir): Use tmpdir_init().
+
Index: gconf/gconf-internals.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-internals.c,v
retrieving revision 1.121.4.2
diff -u -r1.121.4.2 gconf-internals.c
--- gconf/gconf-internals.c 9 Jun 2004 07:13:11 -0000 1.121.4.2
+++ gconf/gconf-internals.c 5 Aug 2004 15:24:36 -0000
@@ -26,7 +26,9 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <dirent.h>
#include <unistd.h>
+#include <utime.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
@@ -2778,22 +2780,161 @@
return ret;
}
-char*
-gconf_get_daemon_dir (void)
-{
- if (gconf_use_local_locks ())
+static gboolean
+test_safe_lock_dir (const char *dirname)
+{
+ struct stat statbuf;
+
+ if (stat (dirname, &statbuf) != 0)
{
- char *s;
- char *subdir;
+ g_warning ("Cannot stat %s\n", dirname);
+ return FALSE;
+ }
- subdir = g_strconcat ("gconfd-", g_get_user_name (), NULL);
-
- s = g_build_filename (g_get_tmp_dir (), subdir, NULL);
+ if (statbuf.st_uid != getuid ())
+ {
+ g_warning ("Owner of %s is not the current user\n", dirname);
+ return FALSE;
+ }
+
+ if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) || !S_ISDIR (statbuf.st_mode))
+ {
+ g_warning ("Wrong permissions for %s, or it is not a directory\n", dirname);
+ return FALSE;
+ }
+
+ return TRUE;
+}
- g_free (subdir);
+static char *
+scan_lock_dir (const char *dir, const char *prefix)
+{
+ int prefix_len;
+ char *cur_dir = NULL;
+ DIR *dirh;
+ struct dirent *dent;
+
+ g_assert (dir != NULL);
+ g_assert (prefix != NULL);
+
+ dirh = opendir (dir);
+ if (!dirh)
+ return NULL;
+ prefix_len = strlen (prefix);
- return s;
+ while ((dent = readdir (dirh)) != NULL)
+ {
+ char *name;
+
+ if (strncmp (dent->d_name, prefix, prefix_len) != 0)
+ continue;
+
+ name = g_strconcat (dir, "/", dent->d_name, NULL);
+
+ /* Check its credentials */
+ if (!test_safe_lock_dir (name))
+ {
+ g_free (name);
+ continue;
+ }
+
+ /* Sort into some repeatable order */
+ if (!cur_dir || strcmp (cur_dir, name) > 0)
+ {
+ g_free (cur_dir);
+ cur_dir = name;
+ }
+ else
+ g_free (name);
}
+ closedir (dirh);
+
+ return cur_dir;
+}
+
+static const char *
+tmpdir_init (void)
+{
+ const char *tmp_root;
+ char *dirname;
+ char *safe_dir = NULL;
+ long iteration = 0;
+ static char *tmp_dir = NULL;
+
+ if (tmp_dir)
+ return tmp_dir;
+
+ tmp_root = g_get_tmp_dir ();
+ dirname = g_strdup_printf ("gconfd-%s", g_get_user_name ());
+ while (!safe_dir)
+ {
+ char *newname;
+
+ safe_dir = scan_lock_dir (tmp_root, dirname);
+ if (safe_dir)
+ {
+ g_free (dirname);
+ tmp_dir = safe_dir;
+ return tmp_dir;
+ }
+
+ if (iteration == 0)
+ newname = g_strconcat (tmp_root, "/", dirname, NULL);
+ else
+ newname = g_strdup_printf ("%s/%s-%4x", tmp_root, dirname, g_random_int ());
+
+ if (mkdir (newname, 0700) < 0)
+ {
+ switch (errno)
+ {
+ case EACCES:
+ g_error ("I can't write to '%s', GConf init failed",
+ newname);
+ break;
+
+ case ENAMETOOLONG:
+ g_error ("Name '%s' too long your unix is broken",
+ newname);
+ break;
+
+ case ENOMEM:
+ case ELOOP:
+ case ENOSPC:
+ case ENOTDIR:
+ case ENOENT:
+ g_error ("Resource problem creating '%s'", newname);
+ break;
+
+ default: /* carry on going */
+ break;
+ }
+ }
+
+ {
+ /* Hide some information ( apparently ) */
+ struct utimbuf utb;
+ memset (&utb, 0, sizeof (utb));
+ utime (newname, &utb);
+ }
+
+ /* Possible race - so we re-scan. */
+
+ iteration++;
+ g_free (newname);
+
+ if (iteration == 1000)
+ g_error ("Cannot find a safe lock path in '%s'", tmp_root);
+ }
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+char*
+gconf_get_daemon_dir (void)
+{
+ if (gconf_use_local_locks ())
+ return g_strdup (tmpdir_init ());
else
return g_strconcat (g_get_home_dir (), "/.gconfd", NULL);
}