aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Rostovtsev <tetromino@gentoo.org>2012-02-06 05:19:08 -0500
committerAlexandre Rostovtsev <tetromino@gentoo.org>2012-02-06 05:19:08 -0500
commit52f4dc6163ecbc334f9ba949d6436f650ecf138d (patch)
tree160fb3e2db97b37ea2e46fada8d279d27967e62c
parentTODO: we need nss-myhostname in portage (diff)
downloadopenrc-settingsd-52f4dc6163ecbc334f9ba949d6436f650ecf138d.tar.gz
openrc-settingsd-52f4dc6163ecbc334f9ba949d6436f650ecf138d.tar.bz2
openrc-settingsd-52f4dc6163ecbc334f9ba949d6436f650ecf138d.zip
Check polkit authorization asynchronously
The other alternative (spawning a thread for each authorization request) seems less elegant, since such requests can take arbitrarily long to complete.
-rw-r--r--src/bus-utils.c137
-rw-r--r--src/bus-utils.h13
-rw-r--r--src/hostnamed.c275
3 files changed, 302 insertions, 123 deletions
diff --git a/src/bus-utils.c b/src/bus-utils.c
index d3bc7b2..aef8037 100644
--- a/src/bus-utils.c
+++ b/src/bus-utils.c
@@ -20,44 +20,115 @@
#include <gio/gio.h>
#include <polkit/polkit.h>
+#include "bus-utils.h"
+
+struct check_polkit_data {
+ const gchar *unique_name;
+ const gchar *action_id;
+ gboolean user_interaction;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+
+ PolkitAuthority *authority;
+ PolkitSubject *subject;
+};
+
+void
+check_polkit_data_free (struct check_polkit_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->subject != NULL)
+ g_object_unref (data->subject);
+ if (data->authority != NULL)
+ g_object_unref (data->authority);
+
+ g_free (data);
+}
+
gboolean
-check_polkit (const gchar *unique_name,
- const gchar *action_id,
- const gboolean user_interaction,
- GError **error)
+check_polkit_finish (GAsyncResult *res,
+ GError **error)
{
- gboolean ret = FALSE;
- GDBusConnection *connection = NULL;
- PolkitAuthority *authority = NULL;
- PolkitSubject *subject = NULL;
- PolkitAuthorizationResult *result = NULL;
-
- if ((authority = polkit_authority_get_sync (NULL, error)) == NULL)
- goto end;
-
- if (unique_name == NULL || action_id == NULL ||
- (subject = polkit_system_bus_name_new (unique_name)) == NULL) {
- g_propagate_error (error,
- g_error_new (POLKIT_ERROR, POLKIT_ERROR_FAILED,
- "Authorizing for '%s': failed sanity check", action_id));
- goto end;
- }
+ GSimpleAsyncResult *simple;
+
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+static void
+check_polkit_authorization_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer _data)
+{
+ struct check_polkit_data *data;
+ PolkitAuthorizationResult *result;
+ GSimpleAsyncResult *simple;
+ GError *err = NULL;
- if ((result = polkit_authority_check_authorization_sync (authority, subject, action_id, NULL, (PolkitCheckAuthorizationFlags) user_interaction, NULL, error)) == NULL)
- goto end;
+ data = (struct check_polkit_data *) _data;
+ if ((result = polkit_authority_check_authorization_finish (data->authority, res, &err)) == NULL) {
+ g_simple_async_report_take_gerror_in_idle (NULL, data->callback, data->user_data, err);
+ goto out;
+ }
- if ((ret = polkit_authorization_result_get_is_authorized (result)) == FALSE) {
- g_propagate_error (error,
- g_error_new (POLKIT_ERROR, POLKIT_ERROR_NOT_AUTHORIZED,
- "Authorizing for '%s': not authorized", action_id));
+ if (!polkit_authorization_result_get_is_authorized (result)) {
+ g_simple_async_report_error_in_idle (NULL, data->callback, data->user_data, POLKIT_ERROR, POLKIT_ERROR_NOT_AUTHORIZED, "Authorizing for '%s': not authorized", data->action_id);
+ goto out;
}
-
- end:
+ simple = g_simple_async_result_new (NULL, data->callback, data->user_data, check_polkit_async);
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+
+ out:
+ check_polkit_data_free (data);
if (result != NULL)
g_object_unref (result);
- if (subject != NULL)
- g_object_unref (subject);
- if (authority != NULL)
- g_object_unref (authority);
- return ret;
+}
+
+static void
+check_polkit_authority_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer _data)
+{
+ struct check_polkit_data *data;
+ GError *err = NULL;
+
+ data = (struct check_polkit_data *) _data;
+ if ((data->authority = polkit_authority_get_finish (res, &err)) == NULL) {
+ g_simple_async_report_take_gerror_in_idle (NULL, data->callback, data->user_data, err);
+ check_polkit_data_free (data);
+ return;
+ }
+ if (data->unique_name == NULL || data->action_id == NULL ||
+ (data->subject = polkit_system_bus_name_new (data->unique_name)) == NULL) {
+ g_simple_async_report_error_in_idle (NULL, data->callback, data->user_data, POLKIT_ERROR, POLKIT_ERROR_FAILED, "Authorizing for '%s': failed sanity check", data->action_id);
+ check_polkit_data_free (data);
+ return;
+ }
+ polkit_authority_check_authorization (data->authority, data->subject, data->action_id, NULL, (PolkitCheckAuthorizationFlags) data->user_interaction, NULL, check_polkit_authorization_cb, data);
+}
+
+void
+check_polkit_async (const gchar *unique_name,
+ const gchar *action_id,
+ const gboolean user_interaction,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ struct check_polkit_data *data;
+
+ data = g_new0 (struct check_polkit_data, 1);
+ data->unique_name = unique_name;
+ data->action_id = action_id;
+ data->user_interaction = user_interaction;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ polkit_authority_get_async (NULL, check_polkit_authority_cb, data);
} \ No newline at end of file
diff --git a/src/bus-utils.h b/src/bus-utils.h
index 31a2ef1..f2e80ea 100644
--- a/src/bus-utils.h
+++ b/src/bus-utils.h
@@ -21,10 +21,15 @@
#include <glib.h>
+void
+check_polkit_async (const gchar *unique_name,
+ const gchar *action_id,
+ const gboolean user_interaction,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
gboolean
-check_polkit (const gchar *unique_name,
- const gchar *action_id,
- const gboolean user_interaction,
- GError **error);
+check_polkit_finish (GAsyncResult *res,
+ GError **error);
#endif \ No newline at end of file
diff --git a/src/hostnamed.c b/src/hostnamed.c
index 4f95d04..c5914bd 100644
--- a/src/hostnamed.c
+++ b/src/hostnamed.c
@@ -36,6 +36,11 @@
#define QUOTE(macro) #macro
#define STR(macro) QUOTE(macro)
+struct invoked_name {
+ GDBusMethodInvocation *invocation;
+ gchar *name; /* newly allocated */
+};
+
guint bus_id = 0;
gboolean read_only = FALSE;
@@ -103,152 +108,250 @@ guess_icon_name ()
icon_name = g_strdup ("computer");
}
-static gboolean
-on_handle_set_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1,
- GDBusMethodInvocation *invocation,
- const gchar *name,
- const gboolean user_interaction,
- gpointer user_data)
+static void
+on_handle_set_hostname_authorized_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
GError *err = NULL;
-
- if (read_only) {
- g_dbus_method_invocation_return_dbus_error (invocation,
- DBUS_ERROR_NOT_SUPPORTED,
- "openrc-settingsd hostnamed is in read-only mode");
- goto end;
- }
-
- if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-hostname", user_interaction, &err)) {
- g_dbus_method_invocation_return_gerror (invocation, err);
- goto end;
+ struct invoked_name *data;
+
+ data = (struct invoked_name *) user_data;
+ if (!check_polkit_finish (res, &err)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
+ goto out;
}
G_LOCK (hostname);
/* Don't allow an empty or invalid hostname */
- if (!hostname_is_valid (name)) {
- name = hostname;
- if (!hostname_is_valid (name))
- name = "localhost";
+ if (!hostname_is_valid (data->name)) {
+ if (data->name != NULL)
+ g_free (data->name);
+
+ if (hostname_is_valid (hostname))
+ data->name = g_strdup (hostname);
+ else
+ data->name = g_strdup ("localhost");
}
- if (sethostname (name, strlen(name))) {
+ if (sethostname (data->name, strlen(data->name))) {
int errsv = errno;
- g_dbus_method_invocation_return_dbus_error (invocation,
+ g_dbus_method_invocation_return_dbus_error (data->invocation,
DBUS_ERROR_FAILED,
strerror (errsv));
G_UNLOCK (hostname);
- goto end;
+ goto out;
}
- g_strlcpy (hostname, name, HOST_NAME_MAX + 1);
- openrc_settingsd_hostnamed_hostname1_complete_set_hostname (hostname1, invocation);
+ g_strlcpy (hostname, data->name, HOST_NAME_MAX + 1);
+ openrc_settingsd_hostnamed_hostname1_complete_set_hostname (hostname1, data->invocation);
openrc_settingsd_hostnamed_hostname1_set_hostname (hostname1, hostname);
G_UNLOCK (hostname);
- end:
- return TRUE;
+ out:
+ g_free (data->name);
+ g_free (data);
+ if (err != NULL)
+ g_error_free (err);
}
static gboolean
-on_handle_set_static_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1,
- GDBusMethodInvocation *invocation,
- const gchar *name,
- const gboolean user_interaction,
- gpointer user_data)
+on_handle_set_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1,
+ GDBusMethodInvocation *invocation,
+ const gchar *name,
+ const gboolean user_interaction,
+ gpointer user_data)
{
- ShellUtilsTrivial *confd_file = NULL;
- GError *err = NULL;
-
- if (read_only) {
+ if (read_only)
g_dbus_method_invocation_return_dbus_error (invocation,
DBUS_ERROR_NOT_SUPPORTED,
"openrc-settingsd hostnamed is in read-only mode");
- goto end;
+ else {
+ struct invoked_name *data;
+ data = g_new0 (struct invoked_name, 1);
+ data->invocation = invocation;
+ data->name = g_strdup (name);
+ check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-hostname", user_interaction, on_handle_set_hostname_authorized_cb, data);
}
- if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-static-hostname", user_interaction, &err)) {
- g_dbus_method_invocation_return_gerror (invocation, err);
- goto end;
+ return TRUE;
+}
+
+static void
+on_handle_set_static_hostname_authorized_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *err = NULL;
+ struct invoked_name *data;
+
+ data = (struct invoked_name *) user_data;
+ if (!check_polkit_finish (res, &err)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
+ goto out;
}
G_LOCK (static_hostname);
/* Don't allow an empty or invalid hostname */
- if (!hostname_is_valid (name))
- name = "localhost";
+ if (!hostname_is_valid (data->name)) {
+ if (data->name != NULL)
+ g_free (data->name);
+
+ data->name = g_strdup ("localhost");
+ }
- if (!shell_utils_trivial_set_and_save (static_hostname_file, &err, "hostname", "HOSTNAME", name, NULL)) {
- g_dbus_method_invocation_return_gerror (invocation, err);
+ if (!shell_utils_trivial_set_and_save (static_hostname_file, &err, "hostname", "HOSTNAME", data->name, NULL)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
G_UNLOCK (static_hostname);
- goto end;
+ goto out;
}
g_free (static_hostname);
- static_hostname = g_strdup (name);
- openrc_settingsd_hostnamed_hostname1_complete_set_static_hostname (hostname1, invocation);
+ static_hostname = data->name; /* data->name is g_strdup-ed already */;
+ openrc_settingsd_hostnamed_hostname1_complete_set_static_hostname (hostname1, data->invocation);
openrc_settingsd_hostnamed_hostname1_set_static_hostname (hostname1, static_hostname);
G_UNLOCK (static_hostname);
- end:
- shell_utils_trivial_free (confd_file);
+ out:
+ g_free (data);
if (err != NULL)
g_error_free (err);
+}
+
+static gboolean
+on_handle_set_static_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1,
+ GDBusMethodInvocation *invocation,
+ const gchar *name,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ if (read_only)
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ DBUS_ERROR_NOT_SUPPORTED,
+ "openrc-settingsd hostnamed is in read-only mode");
+ else {
+ struct invoked_name *data;
+ data = g_new0 (struct invoked_name, 1);
+ data->invocation = invocation;
+ data->name = g_strdup (name);
+ check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-static-hostname", user_interaction, on_handle_set_static_hostname_authorized_cb, data);
+ }
return TRUE; /* Always return TRUE to indicate signal has been handled */
}
-static gboolean
-on_handle_set_machine_info (OpenrcSettingsdHostnamedHostname1 *hostname1,
- GDBusMethodInvocation *invocation,
- const gchar *name,
- const gboolean user_interaction,
- gpointer user_data)
+static void
+on_handle_set_pretty_hostname_authorized_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
- ShellUtilsTrivial *confd_file = NULL;
GError *err = NULL;
- gboolean is_pretty_hostname = GPOINTER_TO_INT(user_data);
+ struct invoked_name *data;
+
+ data = (struct invoked_name *) user_data;
+ if (!check_polkit_finish (res, &err)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
+ goto out;
+ }
+
+ G_LOCK (machine_info);
+ /* Don't allow a null pretty hostname */
+ if (data->name == NULL)
+ data->name = g_strdup ("");
- if (read_only) {
+ if (!shell_utils_trivial_set_and_save (machine_info_file, &err, "PRETTY_HOSTNAME", NULL, data->name, NULL)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
+ G_UNLOCK (machine_info);
+ goto out;
+ }
+
+ g_free (pretty_hostname);
+ pretty_hostname = data->name; /* data->name is g_strdup-ed already */
+ openrc_settingsd_hostnamed_hostname1_complete_set_pretty_hostname (hostname1, data->invocation);
+ openrc_settingsd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname);
+ G_UNLOCK (machine_info);
+
+ out:
+ g_free (data);
+ if (err != NULL)
+ g_error_free (err);
+}
+
+static gboolean
+on_handle_set_pretty_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1,
+ GDBusMethodInvocation *invocation,
+ const gchar *name,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ if (read_only)
g_dbus_method_invocation_return_dbus_error (invocation,
DBUS_ERROR_NOT_SUPPORTED,
"openrc-settingsd hostnamed is in read-only mode");
- goto end;
+ else {
+ struct invoked_name *data;
+ data = g_new0 (struct invoked_name, 1);
+ data->invocation = invocation;
+ data->name = g_strdup (name);
+ check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-machine-info", user_interaction, on_handle_set_pretty_hostname_authorized_cb, data);
}
- if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-machine-info", user_interaction, &err)) {
- g_dbus_method_invocation_return_gerror (invocation, err);
- goto end;
+ return TRUE; /* Always return TRUE to indicate signal has been handled */
+}
+
+static void
+on_handle_set_icon_name_authorized_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *err = NULL;
+ struct invoked_name *data;
+
+ data = (struct invoked_name *) user_data;
+ if (!check_polkit_finish (res, &err)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
+ goto out;
}
G_LOCK (machine_info);
/* Don't allow a null pretty hostname */
- if (name == NULL)
- name = "";
+ if (data->name == NULL)
+ data->name = g_strdup ("");
- if ((is_pretty_hostname &&
- !shell_utils_trivial_set_and_save (machine_info_file, &err, "PRETTY_HOSTNAME", NULL, name, NULL)) ||
- (!is_pretty_hostname &&
- !shell_utils_trivial_set_and_save (machine_info_file, &err, "ICON_NAME", NULL, name, NULL))) {
- g_dbus_method_invocation_return_gerror (invocation, err);
+ if (!shell_utils_trivial_set_and_save (machine_info_file, &err, "ICON_NAME", NULL, data->name, NULL)) {
+ g_dbus_method_invocation_return_gerror (data->invocation, err);
G_UNLOCK (machine_info);
- goto end;
+ goto out;
}
- if (is_pretty_hostname) {
- g_free (pretty_hostname);
- pretty_hostname = g_strdup (name);
- openrc_settingsd_hostnamed_hostname1_complete_set_pretty_hostname (hostname1, invocation);
- openrc_settingsd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname);
- } else {
- g_free (icon_name);
- icon_name = g_strdup (name);
- openrc_settingsd_hostnamed_hostname1_complete_set_icon_name (hostname1, invocation);
- openrc_settingsd_hostnamed_hostname1_set_icon_name (hostname1, icon_name);
- }
+ g_free (icon_name);
+ icon_name = data->name; /* data->name is g_strdup-ed already */
+ openrc_settingsd_hostnamed_hostname1_complete_set_icon_name (hostname1, data->invocation);
+ openrc_settingsd_hostnamed_hostname1_set_icon_name (hostname1, icon_name);
G_UNLOCK (machine_info);
- end:
- shell_utils_trivial_free (confd_file);
+ out:
+ g_free (data);
if (err != NULL)
g_error_free (err);
+}
+
+static gboolean
+on_handle_set_icon_name (OpenrcSettingsdHostnamedHostname1 *hostname1,
+ GDBusMethodInvocation *invocation,
+ const gchar *name,
+ const gboolean user_interaction,
+ gpointer user_data)
+{
+ if (read_only)
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ DBUS_ERROR_NOT_SUPPORTED,
+ "openrc-settingsd hostnamed is in read-only mode");
+ else {
+ struct invoked_name *data;
+ data = g_new0 (struct invoked_name, 1);
+ data->invocation = invocation;
+ data->name = g_strdup (name);
+ check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-machine-info", user_interaction, on_handle_set_icon_name_authorized_cb, data);
+ }
return TRUE; /* Always return TRUE to indicate signal has been handled */
}
@@ -272,8 +375,8 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect (hostname1, "handle-set-hostname", G_CALLBACK (on_handle_set_hostname), NULL);
g_signal_connect (hostname1, "handle-set-static-hostname", G_CALLBACK (on_handle_set_static_hostname), NULL);
- g_signal_connect (hostname1, "handle-set-pretty-hostname", G_CALLBACK (on_handle_set_machine_info), GINT_TO_POINTER(TRUE));
- g_signal_connect (hostname1, "handle-set-icon-name", G_CALLBACK (on_handle_set_machine_info), GINT_TO_POINTER(FALSE));
+ g_signal_connect (hostname1, "handle-set-pretty-hostname", G_CALLBACK (on_handle_set_pretty_hostname), NULL);
+ g_signal_connect (hostname1, "handle-set-icon-name", G_CALLBACK (on_handle_set_icon_name), NULL);
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (hostname1),
connection,