Re: Local locks patch, did that go anywhere?
- From: Havoc Pennington <hp redhat com>
- To: Michael Meeks <michael ximian com>
- Cc: Aaron Stone <aaron engr Paly NET>, gconf <gconf-list gnome org>
- Subject: Re: Local locks patch, did that go anywhere?
- Date: Mon, 24 Mar 2003 12:40:13 -0500
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]