Re: Local locks patch, did that go anywhere?



On Mon, Mar 24, 2003 at 02:08:17PM +0000, Michael Meeks wrote:
> 
> On Thu, 2003-03-20 at 17:26, Havoc Pennington wrote:
> > I'm hoping to integrate it into 2.4, but if someone looks at using the
> > linc_get_tmpdir() code before me that'd be cool too. ;-)
> 
> 	If you point me at the existing code; I'll add a call to
> linc_get_tmpdir for you ;-) how about that ?
> 

Cool - here is the patch I have.

Havoc

Index: backends/xml-backend.c
===================================================================
RCS file: /cvs/gnome/gconf/backends/xml-backend.c,v
retrieving revision 1.81
diff -u -p -u -r1.81 xml-backend.c
--- backends/xml-backend.c	21 Mar 2002 23:55:06 -0000	1.81
+++ backends/xml-backend.c	30 Aug 2002 22:55:15 -0000
@@ -206,6 +206,8 @@ static void          destroy_source  (GC
 
 static void          clear_cache     (GConfSource* source);
 
+static void          blow_away_locks (const char *address);
+
 static GConfBackendVTable xml_vtable = {
   x_shutdown,
   resolve_address,
@@ -224,7 +226,8 @@ static GConfBackendVTable xml_vtable = {
   set_schema,
   sync_all,
   destroy_source,
-  clear_cache
+  clear_cache,
+  blow_away_locks
 };
 
 static void          
@@ -267,13 +270,48 @@ writable (GConfSource* source,
   return TRUE;
 }
 
+static char*
+get_dir_from_address (const char *address,
+                      GError    **err)
+{
+  char *root_dir;
+  int len;
+  
+  root_dir = gconf_address_resource (address);
+
+  if (root_dir == NULL)
+    {
+      gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS,
+                       _("Couldn't find the XML root directory in the address `%s'"),
+                       address);
+      return NULL;
+    }
+
+  /* Chop trailing '/' to canonicalize */
+  len = strlen (root_dir);
+
+  if (root_dir[len-1] == '/')
+    root_dir[len-1] = '\0';
+
+  return root_dir;
+}
+
+static char*
+get_lock_dir_from_root_dir (const char *root_dir)
+{
+  gchar* lockdir;
+  
+  lockdir = gconf_concat_dir_and_key (root_dir, "%gconf-xml-backend.lock");
+
+  return lockdir;
+}
+
 static GConfSource*  
 resolve_address (const gchar* address, GError** err)
 {
   gchar* root_dir;
   XMLSource* xsource;
   GConfSource* source;
-  guint len;
   gint flags = 0;
   GConfLock* lock = NULL;
   guint dir_mode = 0700;
@@ -281,20 +319,10 @@ resolve_address (const gchar* address, G
   gchar** address_flags;
   gchar** iter;
   gboolean force_readonly;
-  
-  root_dir = gconf_address_resource(address);
 
+  root_dir = get_dir_from_address (address, err);
   if (root_dir == NULL)
-    {
-      gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Couldn't find the XML root directory in the address `%s'"), address);
-      return NULL;
-    }
-
-  /* Chop trailing '/' to canonicalize */
-  len = strlen(root_dir);
-
-  if (root_dir[len-1] == '/')
-    root_dir[len-1] = '\0';
+    return NULL;
 
   if (mkdir(root_dir, dir_mode) < 0)
     {
@@ -368,13 +396,14 @@ resolve_address (const gchar* address, G
       flags |= GCONF_SOURCE_ALL_WRITEABLE;
 
     /* We only do locking if it's writable,
-       which is sort of broken but close enough
-    */
-    if (writable)
+     * and if not using local locks,
+     * which is sort of broken but close enough
+     */
+    if (writable && !gconf_use_local_locks ())
       {
         gchar* lockdir;
 
-        lockdir = gconf_concat_dir_and_key(root_dir, "%gconf-xml-backend.lock");
+        lockdir = get_lock_dir_from_root_dir (root_dir);
         
         lock = gconf_get_lock(lockdir, err);
 
@@ -712,6 +741,64 @@ clear_cache     (GConfSource* source)
 
   /* clean all entries older than 0 seconds */
   cache_clean(xs->cache, 0);
+}
+
+static void
+blow_away_locks (const char *address)
+{
+  char *root_dir;
+  char *lock_dir;
+  DIR *dp;
+  struct dirent *dent;
+
+  /* /tmp locks should never be stuck, and possible security issue to
+   * blow them away
+   */
+  if (gconf_use_local_locks ())
+    return;
+  
+  root_dir = get_dir_from_address (address, NULL);
+  if (root_dir == NULL)
+    return;
+
+  lock_dir = get_lock_dir_from_root_dir (root_dir);
+
+  dp = opendir (lock_dir);
+  
+  if (dp == NULL)
+    {
+      g_printerr (_("Could not open lock directory for %s to remove locks: %s\n"),
+                  address, g_strerror (errno));
+      goto out;
+    }
+  
+  while ((dent = readdir (dp)) != NULL)
+    {
+      char *path;
+      
+      /* ignore ., .. (and any ..foo as an intentional who-cares bug) */
+      if (dent->d_name[0] == '.' &&
+          (dent->d_name[1] == '\0' || dent->d_name[1] == '.'))
+        continue;
+
+      path = g_build_filename (lock_dir, dent->d_name, NULL);
+
+      if (unlink (path) < 0)
+        {
+          g_printerr (_("Could not remove file %s: %s\n"),
+                      path, g_strerror (errno));
+        }
+
+      g_free (path);
+    }
+
+ out:
+
+  if (dp)
+    closedir (dp);
+  
+  g_free (root_dir);
+  g_free (lock_dir);
 }
 
 /* Initializer */
Index: doc/gconf/tmpl/gconf-backend.sgml
===================================================================
RCS file: /cvs/gnome/gconf/doc/gconf/tmpl/gconf-backend.sgml,v
retrieving revision 1.5
diff -u -p -u -r1.5 gconf-backend.sgml
--- doc/gconf/tmpl/gconf-backend.sgml	11 Sep 2000 02:11:08 -0000	1.5
+++ doc/gconf/tmpl/gconf-backend.sgml	30 Aug 2002 22:55:15 -0000
@@ -249,6 +249,7 @@ Should destroy a source obtained with @r
 @sync_all: 
 @destroy_source: 
 @clear_cache: 
+ blow_away_locks: 
 
 <!-- ##### STRUCT GConfBackend ##### -->
 <para>
Index: gconf/gconf-backend.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-backend.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 gconf-backend.c
--- gconf/gconf-backend.c	4 Dec 2001 22:17:09 -0000	1.21
+++ gconf/gconf-backend.c	30 Aug 2002 22:55:15 -0000
@@ -353,5 +353,15 @@ gconf_backend_resolve_address (GConfBack
   return retval;
 }
 
+void
+gconf_blow_away_locks (const gchar* address)
+{
+  GConfBackend* backend;
 
+  backend = gconf_get_backend (address, NULL);
 
+  if (backend != NULL)
+    {
+      (*backend->vtable->blow_away_locks) (address);
+    }
+}
Index: gconf/gconf-backend.h
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-backend.h,v
retrieving revision 1.29
diff -u -p -u -r1.29 gconf-backend.h
--- gconf/gconf-backend.h	13 Jul 2001 22:07:37 -0000	1.29
+++ gconf/gconf-backend.h	30 Aug 2002 22:55:15 -0000
@@ -127,6 +127,9 @@ struct _GConfBackendVTable {
 
   /* This is basically used by the test suite */
   void                (* clear_cache)     (GConfSource* source);
+
+  /* used by gconf-sanity-check */
+  void                (* blow_away_locks) (const char *address);
 };
 
 struct _GConfBackend {
@@ -161,6 +164,8 @@ void          gconf_backend_unref(GConfB
 GConfSource*  gconf_backend_resolve_address (GConfBackend* backend, 
                                              const gchar* address,
                                              GError** err);
+
+void          gconf_blow_away_locks       (const gchar* address);
 
 #endif
 
Index: gconf/gconf-internals.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-internals.c,v
retrieving revision 1.114
diff -u -p -u -r1.114 gconf-internals.c
--- gconf/gconf-internals.c	4 Aug 2002 17:44:16 -0000	1.114
+++ gconf/gconf-internals.c	30 Aug 2002 22:55:15 -0000
@@ -1067,6 +1067,7 @@ void
 gconf_log(GConfLogPriority pri, const gchar* fmt, ...)
 {
   gchar* msg;
+  gchar* convmsg;
   va_list args;
   int syslog_pri = LOG_DEBUG;
 
@@ -1119,7 +1120,14 @@ gconf_log(GConfLogPriority pri, const gc
           break;
         }
 
-      syslog(syslog_pri, "%s", msg);
+      convmsg = g_locale_from_utf8 (msg, -1, NULL, NULL, NULL);
+      if (!convmsg)
+        syslog (syslog_pri, "%s", msg);
+      else
+        {
+	  syslog (syslog_pri, "%s", convmsg);
+	  g_free (convmsg);
+	}
     }
   else
     {
@@ -2701,6 +2709,24 @@ gconf_get_current_lock_holder  (const gc
   return server;
 }
 
+void
+gconf_daemon_blow_away_locks (void)
+{
+  char *lock_directory;
+  char *iorfile;
+  
+  lock_directory = gconf_get_lock_dir ();
+
+  iorfile = g_strconcat (lock_directory, "/ior", NULL);
+
+  if (unlink (iorfile) < 0)
+    g_printerr (_("Failed to unlink lock file %s: %s\n"),
+                iorfile, g_strerror (errno));
+
+  g_free (iorfile);
+  g_free (lock_directory);
+}
+
 static CORBA_ORB gconf_orb = CORBA_OBJECT_NIL;      
 
 CORBA_ORB
@@ -2755,7 +2781,11 @@ gconf_orb_release (void)
 char*
 gconf_get_daemon_dir (void)
 {
-  return g_strconcat (g_get_home_dir (), "/.gconfd", NULL);
+  if (gconf_use_local_locks ())
+    return g_strdup_printf ("/tmp/gconfd-%s",
+                            g_get_user_name ());
+  else
+    return g_strconcat (g_get_home_dir (), "/.gconfd", NULL);
 }
 
 char*
@@ -2958,4 +2988,25 @@ _gconf_init_i18n (void)
 #endif
       done = TRUE;
     }
+}
+
+enum { UNKNOWN, LOCAL, NORMAL };
+
+gboolean
+gconf_use_local_locks (void)
+{
+  static int local_locks = UNKNOWN;
+  
+  if (local_locks == UNKNOWN)
+    {
+      const char *l =
+        g_getenv ("GCONF_LOCAL_LOCKS");
+
+      if (l && atoi (l) == 1)
+        local_locks = LOCAL;
+      else
+        local_locks = NORMAL;
+    }
+
+  return local_locks == LOCAL;
 }
Index: gconf/gconf-internals.h
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-internals.h,v
retrieving revision 1.74
diff -u -p -u -r1.74 gconf-internals.h
--- gconf/gconf-internals.h	3 Jun 2002 02:36:26 -0000	1.74
+++ gconf/gconf-internals.h	30 Aug 2002 22:55:15 -0000
@@ -190,6 +190,8 @@ GConfLock* gconf_get_lock_or_current_hol
 ConfigServer gconf_get_current_lock_holder  (const gchar *lock_directory,
                                              GString     *failure_log);
 
+void gconf_daemon_blow_away_locks (void);
+
 GError*  gconf_error_new  (GConfError en,
                            const gchar* format, ...) G_GNUC_PRINTF (2, 3);
 
@@ -246,6 +248,8 @@ void gconf_value_set_string_nocopy (GCon
                                     char       *str);
 
 void _gconf_init_i18n (void);
+
+gboolean gconf_use_local_locks (void);
 
 #endif /* GCONF_ENABLE_INTERNALS */
 
Index: gconf/gconf-sanity-check.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconf-sanity-check.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 gconf-sanity-check.c
--- gconf/gconf-sanity-check.c	21 Mar 2002 23:55:09 -0000	1.4
+++ gconf/gconf-sanity-check.c	30 Aug 2002 22:55:15 -0000
@@ -20,6 +20,7 @@
 #include "gconf.h"
 #include "gconf-internals.h"
 #include "gconf-sources.h"
+#include "gconf-backend.h"
 #include <gtk/gtk.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -53,8 +54,9 @@ struct poptOption options[] = {
 static gboolean ensure_gtk (void);
 static void     show_fatal_error_dialog (const char *format,
                                          ...) G_GNUC_PRINTF (1, 2);
+static gboolean offer_delete_locks (void);
 static gboolean check_file_locking (void);
-static gboolean check_gconf (void);
+static gboolean check_gconf (gboolean display_errors);
 
 int 
 main (int argc, char** argv)
@@ -83,8 +85,14 @@ main (int argc, char** argv)
   if (!check_file_locking ())
     return 1;
 
-  if (!check_gconf ())
-    return 1;
+  if (!check_gconf (FALSE))
+    {
+      if (!offer_delete_locks ())
+        return 1;
+  
+      if (!check_gconf (TRUE))
+        return 1;
+    }
   
   return 0;
 }
@@ -115,28 +123,57 @@ check_file_locking (void)
   int fd;
   gboolean retval;
 
-  testfile = g_build_filename (g_get_home_dir (),
-                               ".gconf-test-locking-file",
-                               NULL);
-  
   retval = FALSE;
-
-  /* keep the open from failing due to non-writable old file or something */
-  unlink (testfile);
+  testfile = NULL;
+  fd = -1;
   
-  fd = open (testfile, O_WRONLY | O_CREAT, 0700);
+  if (gconf_use_local_locks ())
+    {
+      GError *err;
 
-  if (fd < 0)
-    {      
-      show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
-                                 "Could not open or create the file \"%s\"; this indicates "
-                                 "that there may be a problem with your configuration, "
-                                 "as many programs will need to create files in your "
-                                 "home directory. The error was \"%s\" (errno = %d)."),
-                               testfile, strerror (errno), errno);
+      err = NULL;
+      fd = g_file_open_tmp ("gconf-test-locking-file-XXXXXX",
+                            &testfile,
+                            &err);
 
-      goto out;
+      if (err != NULL)
+        {
+          show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
+                                     "Could not open or create the file \"%s\"; this indicates "
+                                     "that there may be a problem with your configuration, "
+                                     "as many programs will need to create files in your "
+                                     "home directory. The error was \"%s\" (errno = %d)."),
+                                   testfile, err->message, errno);
+
+          g_error_free (err);
+
+          goto out;
+        }
+    }
+  else
+    {
+      testfile = g_build_filename (g_get_home_dir (),
+                                   ".gconf-test-locking-file",
+                                   NULL);
+      
+      /* keep the open from failing due to non-writable old file or something */
+      unlink (testfile);
+  
+      fd = open (testfile, O_WRONLY | O_CREAT, 0700);
+
+      if (fd < 0)
+        {      
+          show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
+                                     "Could not open or create the file \"%s\"; this indicates "
+                                     "that there may be a problem with your configuration, "
+                                     "as many programs will need to create files in your "
+                                     "home directory. The error was \"%s\" (errno = %d)."),
+                                   testfile, strerror (errno), errno);
+          
+          goto out;
+        }
     }
+      
 
   if (lock_entire_file (fd) < 0)
     {      
@@ -164,7 +201,7 @@ check_file_locking (void)
 }
 
 static gboolean
-check_gconf (void)
+check_gconf (gboolean display_errors)
 {
   GSList* addresses;
   GSList* tmp;
@@ -192,11 +229,12 @@ check_gconf (void)
 
   if (addresses == NULL)
     {
-      show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
-                                 "No configuration sources in the configuration file \"%s\"; this means that preferences and other settings can't be saved. %s%s"),
-                               conffile,
-                               error ? _("Error reading the file: ") : "",
-                               error ? error->message : "");
+      if (display_errors)
+        show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
+                                   "No configuration sources in the configuration file \"%s\"; this means that preferences and other settings can't be saved. %s%s"),
+                                 conffile,
+                                 error ? _("Error reading the file: ") : "",
+                                 error ? error->message : "");
 
       if (error)
         g_error_free (error);
@@ -217,9 +255,10 @@ check_gconf (void)
 
       if (error)
         {
-          show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
-                                     "Could not resolve the address \"%s\" in the configuration file \"%s\": %s"),
-                                   address, conffile, error->message);
+          if (display_errors)
+            show_fatal_error_dialog (_("Please contact your system administrator to resolve the following problem:\n"
+                                       "Could not resolve the address \"%s\" in the configuration file \"%s\": %s"),
+                                     address, conffile, error->message);
           g_error_free (error);
           goto out;
         }
@@ -269,6 +308,97 @@ show_fatal_error_dialog (const char *for
   gtk_dialog_run (GTK_DIALOG (d));
 
   gtk_widget_destroy (d);
+}
+
+static gboolean
+offer_delete_locks (void)
+{
+  gboolean delete_locks;
+  const char *question;
+
+  delete_locks = FALSE;
+  question = _("Your preferences files are currently in use. "
+               "(If you are logged in to this same account from "
+               "another computer, the other login session is probably using "
+               "your preferences files.) "
+               "You can choose to continue, but be aware that other login "
+               "sessions may become temporarily confused. "
+               "If you are not logged in elsewhere, it should be harmless to "
+               "continue.");
+      
+  if (ensure_gtk ())
+    {
+      GtkWidget *d;
+      int response;
+      
+      d = gtk_message_dialog_new (NULL, 0,
+                                  GTK_MESSAGE_ERROR,
+                                  GTK_BUTTONS_NONE,
+                                  "%s", question);
+
+      gtk_dialog_add_buttons (GTK_DIALOG (d),
+                              GTK_STOCK_CANCEL,
+                              GTK_RESPONSE_REJECT,
+                              _("Continue"),
+                              GTK_RESPONSE_ACCEPT,
+                              NULL);
+      
+      response = gtk_dialog_run (GTK_DIALOG (d));
+
+      gtk_widget_destroy (d);
+
+      if (response == GTK_RESPONSE_ACCEPT)
+        delete_locks = TRUE;
+    }
+  else
+    {
+      g_print (_("%s Continue (y/n)?"), question);
+      switch (getchar ())
+        {
+        case 'y':
+        case 'Y':
+          delete_locks = TRUE;
+          break;
+        }
+    }
+
+  if (delete_locks)
+    {
+      GSList* addresses;
+      GSList* tmp;
+      char *conffile;
+      
+      conffile = g_strconcat (GCONF_CONFDIR, "/path", NULL);
+      
+      addresses = gconf_load_source_path (conffile, NULL);
+
+      g_free (conffile);
+      
+      if (addresses == NULL)
+        g_printerr ("Failed to load addresses to delete locks\n");
+
+      tmp = addresses;
+      while (tmp != NULL)
+        {
+          const char *address;
+          
+          address = tmp->data;
+          
+          gconf_blow_away_locks (address);
+
+          g_free (tmp->data);
+          
+          tmp = tmp->next;
+        }
+
+      g_slist_free (addresses);
+      
+      gconf_daemon_blow_away_locks ();
+
+      return TRUE;
+    }
+
+  return FALSE;
 }
 
 /* this is because setting up gtk is kind of slow, no point doing it
Index: gconf/gconfd.c
===================================================================
RCS file: /cvs/gnome/gconf/gconf/gconfd.c,v
retrieving revision 1.131
diff -u -p -u -r1.131 gconfd.c
--- gconf/gconfd.c	12 Jul 2002 14:15:57 -0000	1.131
+++ gconf/gconfd.c	30 Aug 2002 22:55:16 -0000
@@ -463,6 +463,52 @@ log_handler (const gchar   *log_domain,
   gconf_log (pri, "%s", message);
 }
 
+/* From ORBit2 */
+/* There is a DOS attack if another user creates
+ * the given directory and keeps us from creating
+ * it - one reason GCONF_LOCAL_LOCKS is not the default.
+ */
+static gboolean
+test_safe_tmp_dir (const char *dirname)
+{
+  struct stat statbuf;
+  int fd;
+
+  fd = open (dirname, O_RDONLY);  
+  if (fd < 0)
+    {
+      gconf_log (GCL_WARNING, _("Failed to open %s: %s"),
+                 dirname, g_strerror (errno));
+      return FALSE;
+    }
+  
+  if (fstat (fd, &statbuf) != 0)
+    {
+      gconf_log (GCL_WARNING, _("Failed to stat %s: %s"),
+                 dirname, g_strerror (errno));
+      close (fd);
+      return FALSE;
+    }
+  close (fd);
+  
+  if (statbuf.st_uid != getuid ())
+    {
+      gconf_log (GCL_WARNING, _("Owner of %s is not the current user"),
+                 dirname);
+      return FALSE;
+    }
+  
+  if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) ||
+      !S_ISDIR (statbuf.st_mode))
+    {
+      gconf_log (GCL_WARNING, _("Bad permissions %o on dir %s"),
+                 statbuf.st_mode & 07777, dirname);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
 int 
 main(int argc, char** argv)
 {
@@ -595,10 +641,21 @@ main(int argc, char** argv)
   if (mkdir (gconfd_dir, 0700) < 0 && errno != EEXIST)
     gconf_log (GCL_WARNING, _("Failed to create %s: %s"),
                gconfd_dir, g_strerror (errno));
-  
-  err = NULL;
 
-  daemon_lock = gconf_get_lock (lock_dir, &err);
+  if (!test_safe_tmp_dir (gconfd_dir))
+    {
+      err = g_error_new (GCONF_ERROR,
+                         GCONF_ERROR_LOCK_FAILED,
+                         _("Directory %s has a problem, gconfd can't use it"),
+                         gconfd_dir);
+      daemon_lock = NULL;
+    }
+  else
+    {
+      err = NULL;
+      
+      daemon_lock = gconf_get_lock (lock_dir, &err);
+    }
 
   if (daemon_lock != NULL)
     {


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