diff options
Diffstat (limited to 'defaults/gconf-defaults.c')
-rw-r--r-- | defaults/gconf-defaults.c | 1119 |
1 files changed, 722 insertions, 397 deletions
diff --git a/defaults/gconf-defaults.c b/defaults/gconf-defaults.c index e477435c..11a38ad4 100644 --- a/defaults/gconf-defaults.c +++ b/defaults/gconf-defaults.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * - * Copyright (C) 2008 Matthias Clasen <mclasen@redhat.com> + * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,6 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <polkit-dbus/polkit-dbus.h> #include <polkit/polkit.h> #define GCONF_ENABLE_INTERNALS @@ -50,34 +49,61 @@ static gboolean do_exit (gpointer user_data) { - g_debug ("Exiting due to inactivity"); - exit (1); - return FALSE; + g_debug ("Exiting due to inactivity"); + exit (1); + return FALSE; } static guint timer_id = 0; +gboolean disable_killtimer = FALSE; static void stop_killtimer (void) { - if (timer_id > 0) { - g_source_remove (timer_id); + if (disable_killtimer) + return; + + if (timer_id > 0) { + g_source_remove (timer_id); timer_id = 0; - } + } } static void start_killtimer (void) { - g_debug ("Setting killtimer to 30 seconds..."); - timer_id = g_timeout_add_seconds (30, do_exit, NULL); + if (disable_killtimer) + return; + + if (timer_id == 0) { + g_debug ("Setting killtimer to 30 seconds..."); + timer_id = g_timeout_add_seconds (30, do_exit, NULL); + } +} + +static gint operations = 0; + +static void +start_operation (void) +{ + if (operations == 0) + stop_killtimer (); + operations++; +} + +static void +stop_operation (void) +{ + if (operations == 1) + start_killtimer (); + operations --; } struct GConfDefaultsPrivate { - DBusGConnection *system_bus_connection; - DBusGProxy *system_bus_proxy; - PolKitContext *pol_ctx; + DBusGConnection *system_bus_connection; + DBusGProxy *system_bus_proxy; + PolkitAuthority *auth; }; static void gconf_defaults_finalize (GObject *object); @@ -89,13 +115,13 @@ G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT) GQuark gconf_defaults_error_quark (void) { - static GQuark ret = 0; + static GQuark ret = 0; - if (ret == 0) { - ret = g_quark_from_static_string ("gconf_defaults_error"); - } + if (ret == 0) { + ret = g_quark_from_static_string ("gconf_defaults_error"); + } - return ret; + return ret; } @@ -104,21 +130,23 @@ gconf_defaults_error_quark (void) GType gconf_defaults_error_get_type (void) { - static GType etype = 0; + static GType etype = 0; - if (etype == 0) { - static const GEnumValue values[] = { - ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"), - ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"), - { 0, 0, 0 } - }; + if (etype == 0) + { + static const GEnumValue values[] = + { + ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"), + ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"), + { 0, 0, 0 } + }; - g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1); + g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1); - etype = g_enum_register_static ("GConfDefaultsError", values); - } + etype = g_enum_register_static ("GConfDefaultsError", values); + } - return etype; + return etype; } @@ -127,17 +155,17 @@ gconf_defaults_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { - GConfDefaults *mechanism; - GConfDefaultsClass *klass; + GConfDefaults *mechanism; + GConfDefaultsClass *klass; - klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS)); + klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS)); - mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor ( - type, - n_construct_properties, - construct_properties)); + mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor ( + type, + n_construct_properties, + construct_properties)); - return G_OBJECT (mechanism); + return G_OBJECT (mechanism); } enum { @@ -150,10 +178,10 @@ static guint signals[LAST_SIGNAL] = { 0 }; static void gconf_defaults_class_init (GConfDefaultsClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->constructor = gconf_defaults_constructor; - object_class->finalize = gconf_defaults_finalize; + object_class->constructor = gconf_defaults_constructor; + object_class->finalize = gconf_defaults_finalize; signals[SYSTEM_SET] = g_signal_new ("system-set", G_OBJECT_CLASS_TYPE (object_class), @@ -162,149 +190,114 @@ gconf_defaults_class_init (GConfDefaultsClass *klass) NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_STRV); + + g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate)); - g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate)); + dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info); - dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info); + dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR); - dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR); } static void gconf_defaults_init (GConfDefaults *mechanism) { - mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism); + mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism); } static void gconf_defaults_finalize (GObject *object) { - GConfDefaults *mechanism; + GConfDefaults *mechanism; - g_return_if_fail (object != NULL); - g_return_if_fail (GCONF_IS_DEFAULTS (object)); + g_return_if_fail (object != NULL); + g_return_if_fail (GCONF_IS_DEFAULTS (object)); - mechanism = GCONF_DEFAULTS (object); + mechanism = GCONF_DEFAULTS (object); - g_return_if_fail (mechanism->priv != NULL); + g_return_if_fail (mechanism->priv != NULL); - g_object_unref (mechanism->priv->system_bus_proxy); + g_object_unref (mechanism->priv->auth); + g_object_unref (mechanism->priv->system_bus_proxy); - G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object); -} - -static gboolean -pk_io_watch_have_data (GIOChannel *channel, - GIOCondition condition, - gpointer user_data) -{ - int fd; - PolKitContext *pk_context = user_data; - fd = g_io_channel_unix_get_fd (channel); - polkit_context_io_func (pk_context, fd); - return TRUE; -} - -static int -pk_io_add_watch (PolKitContext *pk_context, int fd) -{ - guint id = 0; - GIOChannel *channel; - channel = g_io_channel_unix_new (fd); - if (channel == NULL) - goto out; - id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context); - if (id == 0) { - g_io_channel_unref (channel); - goto out; - } - g_io_channel_unref (channel); -out: - return id; -} - -static void -pk_io_remove_watch (PolKitContext *pk_context, int watch_id) -{ - g_source_remove (watch_id); + G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object); } static gboolean register_mechanism (GConfDefaults *mechanism) { - GError *error = NULL; + GError *error = NULL; - mechanism->priv->pol_ctx = polkit_context_new (); - polkit_context_set_io_watch_functions (mechanism->priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch); - if (!polkit_context_init (mechanism->priv->pol_ctx, NULL)) { - g_critical ("cannot initialize libpolkit"); - goto error; - } + mechanism->priv->auth = polkit_authority_get (); - error = NULL; - mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - if (mechanism->priv->system_bus_connection == NULL) { - if (error != NULL) { - g_critical ("error getting system bus: %s", error->message); - g_error_free (error); - } - goto error; - } + error = NULL; + mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (mechanism->priv->system_bus_connection == NULL) { + if (error != NULL) { + g_critical ("error getting system bus: %s", error->message); + g_error_free (error); + } + goto error; + } - dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", - G_OBJECT (mechanism)); + dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", + G_OBJECT (mechanism)); - mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS); + mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); - start_killtimer (); + start_killtimer (); - return TRUE; + return TRUE; error: - return FALSE; + return FALSE; } GConfDefaults * gconf_defaults_new (void) { - GObject *object; - gboolean res; + GObject *object; + gboolean res; - object = g_object_new (GCONF_TYPE_DEFAULTS, NULL); + object = g_object_new (GCONF_TYPE_DEFAULTS, NULL); - res = register_mechanism (GCONF_DEFAULTS (object)); - if (! res) { - g_object_unref (object); - return NULL; - } + res = register_mechanism (GCONF_DEFAULTS (object)); + if (! res) { + g_object_unref (object); + return NULL; + } - return GCONF_DEFAULTS (object); + return GCONF_DEFAULTS (object); } static const char * polkit_action_for_gconf_path (GConfDefaults *mechanism, + GList *action_descriptions, const char *annotation_key, const char *path) { - PolKitPolicyCache *cache; - PolKitPolicyFileEntry *entry; char *prefix, *p; const char *action; + GList *l; + PolkitActionDescription *action_description; + const gchar *annotation; - cache = polkit_context_get_policy_cache (mechanism->priv->pol_ctx); prefix = g_strdup (path); while (1) { - entry = polkit_policy_cache_get_entry_by_annotation (cache, - annotation_key, - prefix); - if (entry) { - action = polkit_policy_file_entry_get_id (entry); - break; + for (l = action_descriptions; l; l = l->next) { + action_description = l->data; + + annotation = polkit_action_description_get_annotation (action_description, annotation_key); + if (g_strcmp0 (prefix, annotation) == 0) { + action = polkit_action_description_get_action_id (action_description); + g_debug ("action for path '%s': '%s'\n", action, path); + break; + } } p = strrchr (prefix, '/'); @@ -322,56 +315,160 @@ polkit_action_for_gconf_path (GConfDefaults *mechanism, return action; } -static gboolean -check_polkit_for_action (GConfDefaults *mechanism, - DBusGMethodInvocation *context, - const char *action) +static void +throw_error (DBusGMethodInvocation *context, + gint error_code, + const gchar *format, + ...) { - const char *sender; GError *error; - DBusError dbus_error; - PolKitCaller *pk_caller; - PolKitAction *pk_action; - PolKitResult pk_result; + va_list args; + gchar *message; + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + error = g_error_new (GCONF_DEFAULTS_ERROR, + error_code, + "%s", message); + dbus_g_method_return_error (context, error); + g_error_free (error); + g_free (message); +} - error = NULL; +typedef void (*AuthObtainedCallback) (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gpointer user_data); + +typedef struct +{ + GConfDefaults *mechanism; + DBusGMethodInvocation *context; + gchar **actions; + gint id; + gint flags; + AuthObtainedCallback auth_obtained_callback; + GAsyncReadyCallback check_auth_callback; + gpointer user_data; + GDestroyNotify destroy; + PolkitSubject *subject; + gboolean challenge; +} CheckAuthData; + +static void +check_auth_data_free (CheckAuthData *data) +{ + g_object_unref (data->mechanism); + g_strfreev (data->actions); + if (data->destroy) + data->destroy (data->user_data); + g_object_unref (data->subject); + g_free (data); +} + +static void check_next_action (CheckAuthData *data); + +static void +check_authorization_callback (PolkitAuthority *authority, + GAsyncResult *res, + gpointer user_data) +{ + CheckAuthData *data = user_data; + PolkitAuthorizationResult *result; + GError *error; + gboolean is_authorized; + + is_authorized = FALSE; - /* Check that caller is privileged */ - sender = dbus_g_method_get_sender (context); - dbus_error_init (&dbus_error); - pk_caller = polkit_caller_new_from_dbus_name ( - dbus_g_connection_get_connection (mechanism->priv->system_bus_connection), - sender, - &dbus_error); - if (pk_caller == NULL) { - error = g_error_new (GCONF_DEFAULTS_ERROR, - GCONF_DEFAULTS_ERROR_GENERAL, - "Error getting information about caller: %s: %s", - dbus_error.name, dbus_error.message); - dbus_error_free (&dbus_error); - dbus_g_method_return_error (context, error); + error = NULL; + result = polkit_authority_check_authorization_finish (authority, + res, + &error); + if (error != NULL) { + g_debug ("error checking action '%s'\n", error->message); + throw_error (data->context, + GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, + "Not Authorized: %s", error->message); g_error_free (error); - return FALSE; + } + else { + if (polkit_authorization_result_get_is_authorized (result)) { + g_debug ("result for '%s': authorized\n", + data->actions[data->id]); + is_authorized = TRUE; + } + else if (polkit_authorization_result_get_is_challenge (result)) { + g_debug ("result for '%s': challenge\n", + data->actions[data->id]); + throw_error (data->context, + GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, + "Authorization is required"); + } + else { + g_debug ("result for '%s': not authorized\n", + data->actions[data->id]); + throw_error (data->context, + GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, + "Not Authorized"); + } } - pk_action = polkit_action_new (); - polkit_action_set_action_id (pk_action, action); - pk_result = polkit_context_is_caller_authorized (mechanism->priv->pol_ctx, pk_action, pk_caller, TRUE, NULL); - polkit_caller_unref (pk_caller); - - if (pk_result != POLKIT_RESULT_YES) { - dbus_error_init (&dbus_error); - polkit_dbus_error_generate (pk_action, pk_result, &dbus_error); - dbus_set_g_error (&error, &dbus_error); - dbus_g_method_return_error (context, error); - dbus_error_free (&dbus_error); - g_error_free (error); - polkit_action_unref (pk_action); - return FALSE; + if (is_authorized) { + data->id++; + if (data->actions[data->id] == NULL) + data->auth_obtained_callback (data->mechanism, + data->context, + data->user_data); + else { + check_next_action (data); + return; /* continue operation */ + } } - polkit_action_unref (pk_action); - return TRUE; + check_auth_data_free (data); + g_object_unref (result); + stop_operation (); +} + +static void +check_next_action (CheckAuthData *data) +{ + g_debug ("checking action '%s'\n", data->actions[data->id]); + polkit_authority_check_authorization (data->mechanism->priv->auth, + data->subject, + data->actions[data->id], + NULL, + data->flags, + NULL, + data->check_auth_callback, + data); +} + +static void +check_polkit_for_actions (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gchar **actions, + AuthObtainedCallback auth_obtained_callback, + gpointer user_data, + GDestroyNotify destroy) +{ + CheckAuthData *data; + + data = g_new0 (CheckAuthData, 1); + data->mechanism = g_object_ref (mechanism); + data->context = context; + data->actions = actions; + data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION; + data->id = 0; + data->auth_obtained_callback = auth_obtained_callback; + data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback; + data->user_data = user_data; + data->destroy = destroy; + data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context)); + data->challenge = FALSE; + + check_next_action (data); } static char * @@ -379,7 +476,7 @@ gconf_address_for_caller (GConfDefaults *mechanism, DBusGMethodInvocation *context, GError **gerror) { - char *sender; + char *sender; DBusConnection *conn; uid_t uid; struct passwd *pwd; @@ -387,7 +484,7 @@ gconf_address_for_caller (GConfDefaults *mechanism, DBusError error; conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection); - sender = dbus_g_method_get_sender (context); + sender = dbus_g_method_get_sender (context); dbus_error_init (&error); uid = dbus_bus_get_unix_user (conn, sender, &error); @@ -470,56 +567,56 @@ copy_entry (GConfClient *src, } } +typedef void (*ChangeSetCallback) (GConfDefaults *mechanism, + GConfChangeSet *changes, + gpointer data); + +typedef struct +{ + GConfDefaults *mechanism; + DBusGMethodInvocation *context; + const char *dest_address; + char **actions; + char **includes; + char **excludes; + GConfValue *value; + ChangeSetCallback changeset_callback; + gpointer user_data; + GDestroyNotify destroy; +} CopyData; static void -do_copy (GConfDefaults *mechanism, - gboolean mandatory, - const char **includes, - const char **excludes, - DBusGMethodInvocation *context, - GConfChangeSet **changeset_out) +copy_data_free (gpointer user_data) { - char *address = NULL; + CopyData *data = user_data; + + g_object_unref (data->mechanism); + g_strfreev (data->includes); + g_strfreev (data->excludes); + g_strfreev (data->actions); + if (data->value) + gconf_value_free (data->value); + if (data->destroy) + data->destroy (data->user_data); + g_free (data); +} + +static void +do_copy_authorized (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gpointer user_data) +{ + CopyData *data = user_data; GConfClient *source = NULL; GConfClient *dest = NULL; GConfChangeSet *changes = NULL; GConfEngine *engine; + char *address = NULL; + gint i; GError *error; - GError *error2; - const char *action; - const char *annotation_key; - const char *default_action; - const char *dest_address; - int i; - - if (changeset_out) - *changeset_out = NULL; - - stop_killtimer (); - - /* check privileges for each include */ - if (mandatory) { - annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; - default_action = "org.gnome.gconf.defaults.set-mandatory"; - dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory"; - } - else { - annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; - default_action = "org.gnome.gconf.defaults.set-system"; - dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system"; - } - - for (i = 0; includes[i]; i++) { - action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]); - if (action == NULL) - action = default_action; - - if (!check_polkit_for_action (mechanism, context, action)) - goto out; - } error = NULL; - engine = gconf_engine_get_local (dest_address, &error); + engine = gconf_engine_get_local (data->dest_address, &error); if (error) goto cleanup; @@ -527,7 +624,7 @@ do_copy (GConfDefaults *mechanism, gconf_engine_unref (engine); /* find the address to from the caller id */ - address = gconf_address_for_caller (mechanism, context, &error); + address = gconf_address_for_caller (data->mechanism, data->context, &error); if (error) goto cleanup; @@ -540,20 +637,27 @@ do_copy (GConfDefaults *mechanism, changes = gconf_change_set_new (); - /* recursively copy each include, leaving out the excludes */ - for (i = 0; includes[i]; i++) { - if (gconf_client_dir_exists (source, includes[i], NULL)) - copy_tree (source, includes[i], changes, excludes); - else - copy_entry (source, includes[i], changes, excludes); + if (data->value) { + g_assert (data->includes[1] == NULL); + g_assert (data->excludes == NULL); + + gconf_change_set_set (changes, data->includes[0], data->value); + } + else { + /* recursively copy each include, leaving out the excludes */ + for (i = 0; data->includes[i]; i++) { + if (gconf_client_dir_exists (source, data->includes[i], NULL)) + copy_tree (source, data->includes[i], changes, (const char **)data->excludes); + else + copy_entry (source, data->includes[i], changes, (const char **)data->excludes); + } } gconf_client_commit_change_set (dest, changes, FALSE, &error); gconf_client_suggest_sync (dest, NULL); - if (changeset_out) { - *changeset_out = changes; - changes = NULL; + if (data->changeset_callback) { + data->changeset_callback (data->mechanism, changes, data->user_data); } cleanup: @@ -566,20 +670,153 @@ cleanup: g_object_unref (source); if (error) { - g_print ("failed to set GConf values: %s\n", error->message); - error2 = g_error_new_literal (GCONF_DEFAULTS_ERROR, - GCONF_DEFAULTS_ERROR_GENERAL, - error->message); + throw_error (data->context, + GCONF_DEFAULTS_ERROR_GENERAL, + "%s", error->message); g_error_free (error); - - dbus_g_method_return_error (context, error2); - g_error_free (error2); } else - dbus_g_method_return (context); + dbus_g_method_return (data->context); +} -out: - start_killtimer (); +typedef void (*ActionsReadyCallback) (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gchar **actions, + AuthObtainedCallback auth_obtained_callback, + gpointer data, + GDestroyNotify destroy); + +typedef struct +{ + GConfDefaults *mechanism; + DBusGMethodInvocation *context; + char **includes; + const char *default_action; + const char *annotation_key; + ActionsReadyCallback actions_ready_callback; + AuthObtainedCallback auth_obtained_callback; + gpointer data; + GDestroyNotify destroy; +} ActionData; + +static void +action_data_free (ActionData *data) +{ + g_object_unref (data->mechanism); + g_strfreev (data->includes); + if (data->destroy) + data->destroy (data->data); + g_free (data); +} + +static void +actions_ready_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + ActionData *data = user_data; + GList *action_descriptions; + GError *error = NULL; + int i; + GHashTable *obtained; + GHashTableIter iter; + const gchar *action; + gchar **actions; + gpointer key, value; + + action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error); + + if (error) { + throw_error (data->context, + GCONF_DEFAULTS_ERROR_GENERAL, + "Failed to get action descriptions: %s", error->message); + g_error_free (error); + action_data_free (data); + stop_operation (); + return; + } + + obtained = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0; data->includes[i]; i++) { + action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]); + if (action == NULL) { + g_debug ("using default action '%s' for path '%s'", + data->default_action, data->includes[i]); + action = data->default_action; + } + + g_hash_table_insert (obtained, (gpointer)action, (gpointer)action); + } + actions = g_new0 (char *, g_hash_table_size (obtained) + 1); + g_hash_table_iter_init (&iter, obtained); + i = 0; + while (g_hash_table_iter_next (&iter, &key, &value)) { + actions[i] = g_strdup ((char *)key); + i++; + } + g_hash_table_destroy (obtained); + g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL); + g_list_free (action_descriptions); + + data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy); + + data->destroy = NULL; + action_data_free (data); +} + +static void +do_copy (GConfDefaults *mechanism, + gboolean mandatory, + const gchar **includes, + const gchar **excludes, + GConfValue *value, + DBusGMethodInvocation *context, + ChangeSetCallback changeset_callback, + gpointer user_data, + GDestroyNotify destroy) +{ + CopyData *cdata; + ActionData *adata; + + start_operation (); + + cdata = g_new0 (CopyData, 1); + cdata->mechanism = g_object_ref (mechanism); + cdata->context = context; + cdata->includes = g_strdupv ((gchar **)includes); + cdata->excludes = g_strdupv ((gchar **)excludes); + cdata->value = value; + cdata->actions = NULL; + cdata->changeset_callback = changeset_callback; + cdata->user_data = user_data; + cdata->destroy = destroy; + + adata = g_new0 (ActionData, 1); + adata->mechanism = g_object_ref (mechanism); + adata->context = context; + adata->includes = g_strdupv ((gchar **)includes); + adata->actions_ready_callback = check_polkit_for_actions; + adata->auth_obtained_callback = do_copy_authorized; + adata->data = cdata; + adata->destroy = copy_data_free; + + /* check privileges for each include */ + if (mandatory) { + adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; + adata->default_action = "org.gnome.gconf.defaults.set-mandatory"; + cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory"; + } + else { + adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; + adata->default_action = "org.gnome.gconf.defaults.set-system"; + cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system"; + } + + polkit_authority_enumerate_actions (mechanism->priv->auth, + NULL, + actions_ready_cb, + adata); } static void @@ -594,14 +831,12 @@ append_key (GConfChangeSet *cs, } static void -emit_system_set_signal (GConfDefaults *mechanism, - GConfChangeSet *changes) +set_system_changes (GConfDefaults *mechanism, + GConfChangeSet *changes, + gpointer data) { GPtrArray *keys; - if (!changes) - return; - keys = g_ptr_array_new (); gconf_change_set_foreach (changes, append_key, keys); g_ptr_array_add (keys, NULL); @@ -617,12 +852,7 @@ gconf_defaults_set_system (GConfDefaults *mechanism, const char **excludes, DBusGMethodInvocation *context) { - GConfChangeSet *changes = NULL; - - do_copy (mechanism, FALSE, includes, excludes, context, &changes); - - emit_system_set_signal (mechanism, changes); - gconf_change_set_unref (changes); + do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL); } void @@ -631,120 +861,7 @@ gconf_defaults_set_mandatory (GConfDefaults *mechanism, const char **excludes, DBusGMethodInvocation *context) { - do_copy (mechanism, FALSE, includes, excludes, context, NULL); -} - -static void -do_set_value (GConfDefaults *mechanism, - gboolean mandatory, - const char *path, - const char *value, - DBusGMethodInvocation *context, - GConfChangeSet **changeset_out) -{ - GConfClient *dest = NULL; - GConfChangeSet *changes = NULL; - GConfEngine *engine; - GConfValue *gvalue; - GError *error; - GError *error2; - const char *action; - const char *annotation_key; - const char *default_action; - const char *dest_address; - - if (changeset_out) - *changeset_out = NULL; - - stop_killtimer (); - - if (mandatory) { - annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; - default_action = "org.gnome.gconf.defaults.set-mandatory"; - dest_address = "xml:merged:/etc/gconf/gconf.xml.mandatory"; - } - else { - annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; - default_action = "org.gnome.gconf.defaults.set-system"; - dest_address = "xml:merged:/etc/gconf/gconf.xml.system"; - } - - action = polkit_action_for_gconf_path (mechanism, annotation_key, path); - if (action == NULL) - action = default_action; - - if (!check_polkit_for_action (mechanism, context, action)) - goto out; - - error = NULL; - engine = gconf_engine_get_local (dest_address, &error); - if (error) - goto cleanup; - - dest = gconf_client_get_for_engine (engine); - gconf_engine_unref (engine); - - changes = gconf_change_set_new (); - - gvalue = gconf_value_decode (value); - if (!gvalue) - goto cleanup; - - gconf_change_set_set (changes, path, gvalue); - gconf_value_free (gvalue); - - gconf_client_commit_change_set (dest, changes, FALSE, &error); - gconf_client_suggest_sync (dest, NULL); - - if (changeset_out) { - *changeset_out = changes; - changes = NULL; - } - -cleanup: - if (changes) - gconf_change_set_unref (changes); - if (dest) - g_object_unref (dest); - - if (error) { - g_print ("failed to set GConf values: %s\n", error->message); - error2 = g_error_new_literal (GCONF_DEFAULTS_ERROR, - GCONF_DEFAULTS_ERROR_GENERAL, - error->message); - g_error_free (error); - - dbus_g_method_return_error (context, error2); - g_error_free (error2); - } - else - dbus_g_method_return (context); - -out: - start_killtimer (); -} - -void -gconf_defaults_set_system_value (GConfDefaults *mechanism, - const char *path, - const char *value, - DBusGMethodInvocation *context) -{ - GConfChangeSet *changes = NULL; - - do_set_value (mechanism, FALSE, path, value, context, &changes); - - emit_system_set_signal (mechanism, changes); - gconf_change_set_unref (changes); -} - -void -gconf_defaults_set_mandatory_value (GConfDefaults *mechanism, - const char *path, - const char *value, - DBusGMethodInvocation *context) -{ - do_set_value (mechanism, TRUE, path, value, context, NULL); + do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL); } static void @@ -756,13 +873,13 @@ unset_tree (GConfClient *dest, GSList *list, *l; GConfEntry *entry; - if (path_is_excluded (path, excludes)) + if (path_is_excluded (path, excludes)) return; list = gconf_client_all_entries (dest, path, NULL); for (l = list; l; l = l->next) { entry = l->data; - if (!path_is_excluded (entry->key, excludes)) + if (!path_is_excluded (entry->key, excludes)) gconf_change_set_unset (changes, entry->key); } g_slist_foreach (list, (GFunc)gconf_entry_free, NULL); @@ -774,25 +891,25 @@ unset_tree (GConfClient *dest, g_slist_foreach (list, (GFunc)g_free, NULL); g_slist_free (list); } - + static void unset_entry (GConfClient *dest, const char *path, GConfChangeSet *changes, const char **excludes) { - if (path_is_excluded (path, excludes)) + if (path_is_excluded (path, excludes)) return; gconf_change_set_unset (changes, path); } - + static void -unset_in_db (GConfDefaults *mechanism, - const char *address, - const char **includes, - const char **excludes, - GError **error) +unset_in_db (GConfDefaults *mechanism, + const gchar *address, + const gchar **includes, + const gchar **excludes, + GError **error) { GConfEngine *engine; GConfClient *dest = NULL; @@ -800,7 +917,7 @@ unset_in_db (GConfDefaults *mechanism, int i; engine = gconf_engine_get_local (address, error); - if (*error) + if (*error) goto out; dest = gconf_client_get_for_engine (engine); @@ -826,48 +943,256 @@ out: gconf_change_set_unref (changes); } +typedef struct +{ + GConfDefaults *mechanism; + DBusGMethodInvocation *context; + char **includes; + char **excludes; +} UnsetData; + +static void +unset_data_free (gpointer user_data) +{ + UnsetData *data = user_data; + + g_object_unref (data->mechanism); + g_strfreev (data->includes); + g_strfreev (data->excludes); + g_free (data); +} + +static void +do_unset_authorized (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gpointer user_data) +{ + UnsetData *data = user_data; + GError *error; + + error = NULL; + unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory", + (const gchar **)data->includes, + (const gchar **)data->excludes, &error); + + if (error) { + throw_error (data->context, + GCONF_DEFAULTS_ERROR, + GCONF_DEFAULTS_ERROR_GENERAL, + "%s", error->message); + g_error_free (error); + } + else + dbus_g_method_return (data->context); +} + void gconf_defaults_unset_mandatory (GConfDefaults *mechanism, const char **includes, const char **excludes, DBusGMethodInvocation *context) { - const char *annotation_key; - const char *default_action; - int i; - const char *action; + UnsetData *udata; + ActionData *adata; + + start_operation (); + + udata = g_new0 (UnsetData, 1); + udata->mechanism = g_object_ref (mechanism); + udata->context = context; + udata->includes = g_strdupv ((gchar **)includes); + udata->excludes = g_strdupv ((gchar **)excludes); + + adata = g_new0 (ActionData, 1); + adata->mechanism = g_object_ref (mechanism); + adata->context = context; + adata->includes = g_strdupv ((gchar **)includes); + adata->auth_obtained_callback = do_unset_authorized; + adata->data = udata; + adata->destroy = unset_data_free; + + adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; + adata->default_action = "org.gnome.gconf.defaults.set-mandatory"; + + polkit_authority_enumerate_actions (mechanism->priv->auth, + NULL, + actions_ready_cb, + adata); +} + +static void +check_authorization_only_callback (PolkitAuthority *authority, + GAsyncResult *res, + gpointer user_data) +{ + CheckAuthData *data = user_data; + PolkitAuthorizationResult *result; GError *error; - GError *error2; + gboolean is_authorized; - stop_killtimer (); + is_authorized = FALSE; - annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; - default_action = "org.gnome.gconf.defaults.set-mandatory"; + error = NULL; + result = polkit_authority_check_authorization_finish (authority, + res, + &error); + if (error != NULL) { + g_debug ("error checking action '%s'\n", error->message); + throw_error (data->context, + GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, + "Not Authorized: %s", error->message); + g_error_free (error); + goto out; + } + else { + if (polkit_authorization_result_get_is_authorized (result)) { + g_debug ("result for '%s': authorized\n", + data->actions[data->id]); + is_authorized = TRUE; + } + else if (polkit_authorization_result_get_is_challenge (result)) { + g_debug ("result for '%s': challenge\n", + data->actions[data->id]); + is_authorized = TRUE; + data->challenge = TRUE; + } + else { + g_debug ("result for '%s': not authorized\n", + data->actions[data->id]); + is_authorized = FALSE; + } + } - for (i = 0; includes[i]; i++) { - action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]); - if (action == NULL) - action = default_action; + if (is_authorized) { + data->id++; + if (data->actions[data->id] == NULL) { + gint result; - if (!check_polkit_for_action (mechanism, context, action)) - goto out; + result = data->challenge ? 1 : 2; + g_debug ("return %d\n", result); + dbus_g_method_return (data->context, result); + } + else { + check_next_action (data); + return; /* continue operation */ + } + } + else { + g_debug ("return 0\n"); + dbus_g_method_return (data->context, 0); } - error = NULL; - unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory", - includes, excludes, &error); +out: + check_auth_data_free (data); + g_object_unref (result); + stop_operation (); +} - if (error) { - error2 = g_error_new_literal (GCONF_DEFAULTS_ERROR, - GCONF_DEFAULTS_ERROR_GENERAL, - error->message); - g_error_free (error); +static void +check_permissions_only (GConfDefaults *mechanism, + DBusGMethodInvocation *context, + gchar **actions, + AuthObtainedCallback auth_obtained_callback, + gpointer user_data, + GDestroyNotify destroy) +{ + CheckAuthData *data; + + data = g_new0 (CheckAuthData, 1); + data->mechanism = g_object_ref (mechanism); + data->context = context; + data->actions = actions; + data->flags = 0; + data->id = 0; + data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback; + data->auth_obtained_callback = NULL; + data->user_data = NULL; + data->destroy = NULL; + data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context)); + data->challenge = FALSE; + + check_next_action (data); +} + +static void +do_check (GConfDefaults *mechanism, + gboolean mandatory, + const gchar **includes, + DBusGMethodInvocation *context) +{ + ActionData *adata; + + start_operation (); - dbus_g_method_return_error (context, error2); - g_error_free (error2); + adata = g_new0 (ActionData, 1); + adata->mechanism = g_object_ref (mechanism); + adata->context = context; + adata->includes = g_strdupv ((gchar **)includes); + adata->actions_ready_callback = check_permissions_only; + adata->auth_obtained_callback = NULL; + adata->data = NULL; + adata->destroy = NULL; + + if (mandatory) { + adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; + adata->default_action = "org.gnome.gconf.defaults.set-mandatory"; + } + else { + adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; + adata->default_action = "org.gnome.gconf.defaults.set-system"; + } + + polkit_authority_enumerate_actions (mechanism->priv->auth, + NULL, + actions_ready_cb, + adata); +} + +void +gconf_defaults_can_set_system (GConfDefaults *mechanism, + const char **includes, + DBusGMethodInvocation *context) +{ + do_check (mechanism, FALSE, includes, context); +} + +void +gconf_defaults_can_set_mandatory (GConfDefaults *mechanism, + const char **includes, + DBusGMethodInvocation *context) +{ + do_check (mechanism, TRUE, includes, context); +} + +void +gconf_defaults_set_system_value (GConfDefaults *mechanism, + const char *path, + const char *value, + DBusGMethodInvocation *context) +{ + GConfValue *gvalue; + const char *includes[] = { NULL, NULL }; + + gvalue = gconf_value_decode (value); + if (gvalue) { + includes[0] = path; + do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL); + } +} + +void +gconf_defaults_set_mandatory_value (GConfDefaults *mechanism, + const char *path, + const char *value, + DBusGMethodInvocation *context) +{ + GConfValue *gvalue; + const char *includes[] = { NULL, NULL }; + + gvalue = gconf_value_decode (value); + if (gvalue) { + includes[0] = path; + do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL); } - else - dbus_g_method_return (context); -out: - start_killtimer(); } + |