diff options
author | Ryan Lortie <desrt@desrt.ca> | 2011-05-06 12:10:23 +0200 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2011-05-06 12:10:23 +0200 |
commit | a2c4601f2650e83bff2fec3f1a13dc46cdf3a070 (patch) | |
tree | 8e7afddf533c0b3a8ac59113ffd909689fd84b7f | |
parent | e7dcf8d6e9e5c184b1302d0c731f632ab8466f1d (diff) | |
download | dconf-a2c4601f2650e83bff2fec3f1a13dc46cdf3a070.tar.gz |
client-side lockdown support
Support lockdown on the client side for GSettings.
For performance reasons only lockdown of specific keys (not entire
subpaths) is supported at the moment. This may change in the future if
we can find a way to make large numbers of related GVDB lookups
sufficiently performant.
-rw-r--r-- | engine/dconf-engine.c | 126 | ||||
-rw-r--r-- | engine/dconf-engine.h | 6 | ||||
-rw-r--r-- | gsettings/dconfsettingsbackend.c | 18 |
3 files changed, 114 insertions, 36 deletions
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c index 9181fc2..2878b06 100644 --- a/engine/dconf-engine.c +++ b/engine/dconf-engine.c @@ -128,6 +128,7 @@ struct _DConfEngine guint8 *shm; GvdbTable **gvdbs; + GvdbTable **lock_tables; gchar **object_paths; gchar *bus_types; gchar **names; @@ -230,6 +231,8 @@ dconf_engine_refresh_system (DConfEngine *engine) if (engine->gvdbs[i] == NULL) g_error ("Unable to open '%s', specified in dconf profile\n", filename); + engine->lock_tables[i] = gvdb_table_get_table (engine->gvdbs[i], + ".locks"); g_free (filename); engine->state++; } @@ -360,6 +363,7 @@ dconf_engine_new (const gchar *profile) engine->object_paths = g_new (gchar *, engine->n_dbs); engine->gvdbs = g_new0 (GvdbTable *, engine->n_dbs); + engine->lock_tables = g_new0 (GvdbTable *, engine->n_dbs); engine->bus_types = g_strdup ("eyyyyyyyyyyyyy"); engine->state = 0; @@ -390,6 +394,9 @@ dconf_engine_free (DConfEngine *engine) if (engine->gvdbs[i]) gvdb_table_unref (engine->gvdbs[i]); + + if (engine->lock_tables[i]) + gvdb_table_unref (engine->lock_tables[i]); } if (engine->shm) @@ -403,67 +410,76 @@ dconf_engine_free (DConfEngine *engine) g_free (engine->bus_types); g_free (engine->names); g_free (engine->gvdbs); + g_free (engine->lock_tables); g_slice_free (DConfEngine, engine); } -GVariant * -dconf_engine_read (DConfEngine *engine, - const gchar *key) +static GVariant * +dconf_engine_read_internal (DConfEngine *engine, + const gchar *key, + gboolean user, + gboolean system) { GVariant *value = NULL; + gint lowest; + gint limit; gint i; g_static_mutex_lock (&engine->lock); dconf_engine_refresh (engine); - if (engine->gvdbs[0]) - value = gvdb_table_get_value (engine->gvdbs[0], key); - - for (i = 1; i < engine->n_dbs && value == NULL; i++) - value = gvdb_table_get_value (engine->gvdbs[i], key); + /* Bound the search space depending on the databases that we are + * interested in. + */ + limit = system ? engine->n_dbs : 1; + lowest = user ? 0 : 1; + + /* We want i equal to the index of the highest database containing a + * lock, or i == lowest if there is no lock. For that reason, we + * don't actually check the lowest database for a lock. That makes + * sense, because even if it had a lock, it would not change our + * search policy (which would be to check the lowest one first). + * + * Note that we intentionally dishonour 'limit' here -- we want to + * ensure that values in the user database are always ignored when + * locks are present. + */ + for (i = engine->n_dbs - 1; lowest < i; i--) + if (engine->lock_tables[i] != NULL && + gvdb_table_has_value (engine->lock_tables[i], key)) + break; + + while (i < limit && value == NULL) + value = gvdb_table_get_value (engine->gvdbs[i++], key); g_static_mutex_unlock (&engine->lock); + g_print ("you read %s, i say %s\n", key, value ? g_variant_print (value, TRUE) : "(null)"); + return value; } GVariant * +dconf_engine_read (DConfEngine *engine, + const gchar *key) +{ + return dconf_engine_read_internal (engine, key, TRUE, TRUE); +} + +GVariant * dconf_engine_read_default (DConfEngine *engine, const gchar *key) { - GVariant *value = NULL; - gint i; - - g_static_mutex_lock (&engine->lock); - - dconf_engine_refresh (engine); - - for (i = 1; i < engine->n_dbs && value == NULL; i++) - value = gvdb_table_get_value (engine->gvdbs[i], key); - - g_static_mutex_unlock (&engine->lock); - - return value; + return dconf_engine_read_internal (engine, key, FALSE, TRUE); } GVariant * dconf_engine_read_no_default (DConfEngine *engine, const gchar *key) { - GVariant *value = NULL; - - g_static_mutex_lock (&engine->lock); - - dconf_engine_refresh (engine); - - if (engine->gvdbs[0]) - value = gvdb_table_get_value (engine->gvdbs[0], key); - - g_static_mutex_unlock (&engine->lock); - - return value; + return dconf_engine_read_internal (engine, key, TRUE, FALSE); } static void @@ -518,10 +534,30 @@ dconf_engine_unwatch (DConfEngine *engine, } gboolean -dconf_engine_is_writable (DConfEngine *engine, - const gchar *name) +dconf_engine_is_writable (DConfEngine *engine, + const gchar *name) { - return TRUE; + gboolean writable = TRUE; + gint i; + + g_static_mutex_lock (&engine->lock); + + dconf_engine_refresh (engine); + + /* Don't check for locks in the user database. + * If there is only a user database then the loop won't run at all. + */ + for (i = engine->n_dbs - 1; 0 < i; i--) + if (engine->lock_tables[i] != NULL && + gvdb_table_has_value (engine->lock_tables[i], name)) + { + writable = FALSE; + break; + } + + g_static_mutex_unlock (&engine->lock); + + return writable; } static GVariant * @@ -672,6 +708,24 @@ dconf_engine_decode_notify (DConfEngine *engine, } gboolean +dconf_engine_decode_writability_notify (const gchar **path, + const gchar *iface, + const gchar *method, + GVariant *body) +{ + if (strcmp (iface, "ca.desrt.dconf.Writer") || + strcmp (method, "WritabilityNotify")) + return FALSE; + + if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)"))) + return FALSE; + + g_variant_get_child (body, 0, "&s", path); + + return TRUE; +} + +gboolean dconf_engine_interpret_reply (DConfEngineMessage *dcem, const gchar *sender, GVariant *body, diff --git a/engine/dconf-engine.h b/engine/dconf-engine.h index d2058d5..0bde8f0 100644 --- a/engine/dconf-engine.h +++ b/engine/dconf-engine.h @@ -144,6 +144,12 @@ gboolean dconf_engine_decode_notify (DConfEn const gchar *member, GVariant *body); G_GNUC_INTERNAL +gboolean dconf_engine_decode_writability_notify (const gchar **path, + const gchar *iface, + const gchar *method, + GVariant *body); + +G_GNUC_INTERNAL void dconf_engine_set_locked (DConfEngine *engine, const gchar *path, gboolean locked, diff --git a/gsettings/dconfsettingsbackend.c b/gsettings/dconfsettingsbackend.c index d978646..77d9358 100644 --- a/gsettings/dconfsettingsbackend.c +++ b/gsettings/dconfsettingsbackend.c @@ -101,6 +101,24 @@ dconf_settings_backend_signal (GDBusConnection *connection, g_free (rels); } + + if (dconf_engine_decode_writability_notify (&path, interface_name, + signal_name, parameters)) + { + GSettingsBackend *backend = G_SETTINGS_BACKEND (dcsb); + + if (g_str_has_suffix (path, "/")) + { + g_settings_backend_path_writable_changed (backend, path); + g_settings_backend_path_changed (backend, path, NULL); + } + + else + { + g_settings_backend_writable_changed (backend, path); + g_settings_backend_changed (backend, path, NULL); + } + } } static void |