summaryrefslogtreecommitdiff
path: root/gconf/gconf-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'gconf/gconf-backend.c')
-rw-r--r--gconf/gconf-backend.c129
1 files changed, 123 insertions, 6 deletions
diff --git a/gconf/gconf-backend.c b/gconf/gconf-backend.c
index 3aa55c35..07e63340 100644
--- a/gconf/gconf-backend.c
+++ b/gconf/gconf-backend.c
@@ -26,6 +26,46 @@
#include <sys/stat.h>
#include <unistd.h>
+
+/* Don't allow special characters in configuration source addresses.
+ * The important one here is not to allow ';' because we use that
+ * internally as a list delimiter. See GCONF_DATABASE_LIST_DELIM
+ */
+static const char invalid_chars[] = " \t\r\n\"$&<>,+=#!()'|{}[]?~`;%\\";
+
+static gboolean
+gconf_address_valid (const char *address,
+ char **why_invalid)
+{
+ const char *s;
+
+ g_return_val_if_fail (address != NULL, FALSE);
+
+ if (why_invalid)
+ *why_invalid = NULL;
+
+ s = address;
+ while (*s)
+ {
+ const char *inv = invalid_chars;
+
+ while (*inv)
+ {
+ if (*inv == *s)
+ {
+ if (why_invalid)
+ *why_invalid = g_strdup_printf(_("`%c' is an invalid character in a configuration storage address"), *s);
+ return FALSE;
+ }
+ ++inv;
+ }
+
+ ++s;
+ }
+
+ return TRUE;
+}
+
gchar*
gconf_address_backend(const gchar* address)
{
@@ -178,16 +218,84 @@ gconf_backend_file(const gchar* address)
static GHashTable* loaded_backends = NULL;
+static gboolean
+gconf_backend_verify_vtable (GConfBackendVTable *vtable,
+ GConfBackendVTable *vtable_copy,
+ const char *backend_name,
+ GError **err)
+{
+ int i;
+ struct
+ {
+ char *name;
+ gsize offset;
+ } required_vtable_functions[] = {
+ { "shutdown", G_STRUCT_OFFSET(GConfBackendVTable, shutdown) },
+ { "resolve_address", G_STRUCT_OFFSET(GConfBackendVTable, resolve_address) },
+ { "query_value", G_STRUCT_OFFSET(GConfBackendVTable, query_value) },
+ { "query_metainfo", G_STRUCT_OFFSET(GConfBackendVTable, query_metainfo) },
+ { "set_value", G_STRUCT_OFFSET(GConfBackendVTable, set_value) },
+ { "all_entries", G_STRUCT_OFFSET(GConfBackendVTable, all_entries) },
+ { "all_subdirs", G_STRUCT_OFFSET(GConfBackendVTable, all_subdirs) },
+ { "unset_value", G_STRUCT_OFFSET(GConfBackendVTable, unset_value) },
+ { "dir_exists", G_STRUCT_OFFSET(GConfBackendVTable, dir_exists) },
+ { "remove_dir", G_STRUCT_OFFSET(GConfBackendVTable, remove_dir) },
+ { "set_schema", G_STRUCT_OFFSET(GConfBackendVTable, set_schema) },
+ { "sync_all", G_STRUCT_OFFSET(GConfBackendVTable, sync_all) },
+ { "destroy_source", G_STRUCT_OFFSET(GConfBackendVTable, destroy_source) },
+ { "blow_away_locks", G_STRUCT_OFFSET(GConfBackendVTable, blow_away_locks) }
+ };
+
+ if (!vtable)
+ {
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Backend `%s' failed return a vtable\n"),
+ backend_name);
+ return FALSE;
+ }
+
+ /* Create a copy in case vtable size doesn't match */
+ memcpy(vtable_copy, vtable, MIN(vtable->vtable_size, sizeof(GConfBackendVTable)));
+
+ vtable_copy->vtable_size = sizeof(GConfBackendVTable);
+
+ for (i = 0; i < G_N_ELEMENTS(required_vtable_functions); i++)
+ {
+ if (G_STRUCT_MEMBER_P(vtable_copy, required_vtable_functions[i].offset) == NULL)
+ {
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Backend `%s' missing required vtable member `%s'\n"),
+ backend_name,
+ required_vtable_functions[i].name);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
GConfBackend*
gconf_get_backend(const gchar* address, GError** err)
{
GConfBackend* backend;
gchar* name;
+ gchar* why_invalid;
if (loaded_backends == NULL)
{
loaded_backends = g_hash_table_new(g_str_hash, g_str_equal);
}
+
+ why_invalid = NULL;
+ if (!gconf_address_valid (address, &why_invalid))
+ {
+ g_assert (why_invalid != NULL);
+ gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS, _("Bad address `%s': %s"),
+ address, why_invalid);
+ g_free (why_invalid);
+ return NULL;
+ }
+
name = gconf_address_backend(address);
if (name == NULL)
@@ -225,10 +333,9 @@ gconf_get_backend(const gchar* address, GError** err)
if (module == NULL)
{
- const gchar* error = g_module_error();
gconf_set_error(err,
GCONF_ERROR_FAILED, _("Error opening module `%s': %s\n"),
- name, error);
+ name, g_module_error());
g_free(name);
return NULL;
}
@@ -237,6 +344,10 @@ gconf_get_backend(const gchar* address, GError** err)
"gconf_backend_get_vtable",
(gpointer*)&get_vtable))
{
+ gconf_set_error(err,
+ GCONF_ERROR_FAILED, _("Error initializing module `%s': %s\n"),
+ name, g_module_error());
+ g_module_close(module);
g_free(name);
return NULL;
}
@@ -245,7 +356,13 @@ gconf_get_backend(const gchar* address, GError** err)
backend->module = module;
- backend->vtable = (*get_vtable)();
+ if (!gconf_backend_verify_vtable((*get_vtable)(), &backend->vtable, name, err))
+ {
+ g_module_close(module);
+ g_free(name);
+ g_free(backend);
+ return NULL;
+ }
backend->name = name;
@@ -287,7 +404,7 @@ gconf_backend_unref(GConfBackend* backend)
{
GError* error = NULL;
- (*backend->vtable->shutdown)(&error);
+ (*backend->vtable.shutdown)(&error);
if (error != NULL)
{
@@ -319,7 +436,7 @@ gconf_backend_resolve_address (GConfBackend* backend,
gchar** iter;
GConfSource* retval;
- retval = (*backend->vtable->resolve_address)(address, err);
+ retval = (*backend->vtable.resolve_address)(address, err);
if (retval == NULL)
return NULL;
@@ -362,6 +479,6 @@ gconf_blow_away_locks (const gchar* address)
if (backend != NULL)
{
- (*backend->vtable->blow_away_locks) (address);
+ (*backend->vtable.blow_away_locks) (address);
}
}