summaryrefslogtreecommitdiff
path: root/src/polkitagent
diff options
context:
space:
mode:
Diffstat (limited to 'src/polkitagent')
-rw-r--r--src/polkitagent/polkitagentlistener.c415
1 files changed, 250 insertions, 165 deletions
diff --git a/src/polkitagent/polkitagentlistener.c b/src/polkitagent/polkitagentlistener.c
index c2ab69a..d7bd5f0 100644
--- a/src/polkitagent/polkitagentlistener.c
+++ b/src/polkitagent/polkitagentlistener.c
@@ -44,27 +44,15 @@
* To register a #PolkitAgentListener with the PolicyKit daemon, use polkit_agent_register_listener().
*/
-/* private class for exporting a D-Bus interface */
-
-#define TYPE_SERVER (server_get_type ())
-#define SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_SERVER, Server))
-#define SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_AGENT_TYPE_LISTENER, ServerClass))
-#define SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_SERVER, ServerClass))
-#define IS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_SERVER))
-#define IS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TYPE_SERVER))
-
-typedef struct _Server Server;
-typedef struct _ServerClass ServerClass;
-
-struct _Server
+typedef struct
{
GObject parent_instance;
- EggDBusConnection *system_bus;
-
- EggDBusObjectProxy *authority_proxy;
+ GDBusConnection *system_bus;
+ guint auth_agent_registration_id;
PolkitAuthority *authority;
+ gulong notify_owner_handler_id;
gboolean is_registered;
@@ -74,23 +62,46 @@ struct _Server
gchar *object_path;
GHashTable *cookie_to_pending_auth;
+} Server;
-};
-
-struct _ServerClass
+static void
+server_free (Server *server)
{
- GObjectClass parent_class;
+ if (server->is_registered)
+ {
+ GError *error;
+ error = NULL;
+ if (!polkit_authority_unregister_authentication_agent_sync (server->authority,
+ server->subject,
+ server->object_path,
+ NULL,
+ &error))
+ {
+ g_warning ("Error unregistering authentication agent: %s", error->message);
+ g_error_free (error);
+ }
+ }
-};
+ if (server->auth_agent_registration_id > 0)
+ g_dbus_connection_unregister_object (server->system_bus, server->auth_agent_registration_id);
+
+ if (server->notify_owner_handler_id > 0)
+ g_signal_handler_disconnect (server->authority, server->notify_owner_handler_id);
-static GType server_get_type (void) G_GNUC_CONST;
+ if (server->authority != NULL)
+ g_object_unref (server->authority);
-static void authentication_agent_iface_init (_PolkitAuthenticationAgentIface *agent_iface);
+ if (server->system_bus != NULL)
+ g_object_unref (server->system_bus);
-G_DEFINE_TYPE_WITH_CODE (Server, server, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (_POLKIT_TYPE_AUTHENTICATION_AGENT,
- authentication_agent_iface_init)
- );
+ if (server->cookie_to_pending_auth != NULL)
+ g_hash_table_unref (server->cookie_to_pending_auth);
+
+ if (server->subject != NULL)
+ g_object_unref (server->subject);
+
+ g_free (server->object_path);
+}
static gboolean
server_register (Server *server,
@@ -122,15 +133,14 @@ server_register (Server *server,
}
static void
-name_owner_notify (EggDBusObjectProxy *object_proxy,
- GParamSpec *pspec,
- gpointer user_data)
+on_notify_authority_owner (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
{
- Server *server = SERVER (user_data);
+ Server *server = user_data;
gchar *owner;
- owner = egg_dbus_object_proxy_get_name_owner (server->authority_proxy);
-
+ owner = polkit_authority_get_owner (server->authority);
if (owner == NULL)
{
g_printerr ("PolicyKit daemon disconnected from the bus.\n");
@@ -162,85 +172,129 @@ name_owner_notify (EggDBusObjectProxy *object_proxy,
}
}
}
-
g_free (owner);
}
-static void
-server_init (Server *server)
+static gboolean
+server_init_sync (Server *server,
+ GCancellable *cancellable,
+ GError **error)
{
- server->cookie_to_pending_auth = g_hash_table_new (g_str_hash, g_str_equal);
+ gboolean ret;
+
+ ret = FALSE;
- server->system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM);
+ server->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
+ if (server->system_bus == NULL)
+ goto out;
server->authority = polkit_authority_get ();
+ if (server->authority == NULL)
+ goto out;
/* the only use of this proxy is to re-register with the polkit daemon
* if it jumps off the bus and comes back (which is useful for debugging)
*/
- server->authority_proxy = egg_dbus_connection_get_object_proxy (server->system_bus,
- "org.freedesktop.PolicyKit1",
- "/org/freedesktop/PolicyKit1/Authority");
-
- g_signal_connect (server->authority_proxy,
- "notify::name-owner",
- G_CALLBACK (name_owner_notify),
- server);
+ server->notify_owner_handler_id = g_signal_connect (server->authority,
+ "notify::owner",
+ G_CALLBACK (on_notify_authority_owner),
+ server);
+
+ ret = TRUE;
+
+ out:
+ return ret;
}
-static void
-server_finalize (GObject *object)
+static Server *
+server_new (PolkitSubject *subject,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error)
{
- Server *server = SERVER (object);
+ Server *server;
- if (server->is_registered)
- {
- GError *error;
+ server = g_new0 (Server, 1);
+ server->subject = g_object_ref (subject);
+ server->object_path = object_path != NULL ? g_strdup (object_path) :
+ g_strdup ("/org/freedesktop/PolicyKit1/AuthenticationAgent");
+ server->cookie_to_pending_auth = g_hash_table_new (g_str_hash, g_str_equal);
- error = NULL;
- if (!polkit_authority_unregister_authentication_agent_sync (server->authority,
- server->subject,
- server->object_path,
- NULL,
- &error))
- {
- g_warning ("Error unregistering authentication agent: %s", error->message);
- g_error_free (error);
- }
+ if (!server_init_sync (server, cancellable, error))
+ {
+ server_free (server);
+ goto out;
}
- g_object_unref (server->subject);
- g_free (server->object_path);
-
- g_object_unref (server->authority);
-
- g_object_unref (server->authority_proxy);
-
- g_object_unref (server->system_bus);
-
- g_hash_table_unref (server->cookie_to_pending_auth);
-
- if (G_OBJECT_CLASS (server_parent_class)->finalize != NULL)
- G_OBJECT_CLASS (server_parent_class)->finalize (object);
+ out:
+ return server;
}
static void
-server_class_init (ServerClass *klass)
+listener_died (gpointer user_data,
+ GObject *where_the_object_was)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ Server *server = user_data;
- gobject_class->finalize = server_finalize;
+ server_free (server);
}
+static void auth_agent_handle_begin_authentication (Server *server,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation);
+
+static void auth_agent_handle_cancel_authentication (Server *server,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation);
+
static void
-listener_died (gpointer user_data,
- GObject *where_the_object_was)
+auth_agent_handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
{
- Server *server = SERVER (user_data);
+ Server *server = user_data;
+
+ /* The shipped D-Bus policy also ensures that only uid 0 can invoke
+ * methods on our interface. So no need to check the caller.
+ */
- g_object_unref (server);
+ if (g_strcmp0 (method_name, "BeginAuthentication") == 0)
+ auth_agent_handle_begin_authentication (server, parameters, invocation);
+ else if (g_strcmp0 (method_name, "CancelAuthentication") == 0)
+ auth_agent_handle_cancel_authentication (server, parameters, invocation);
+ else
+ g_assert_not_reached ();
}
+static const gchar *auth_agent_introspection_data =
+ "<node>"
+ " <interface name='org.freedesktop.PolicyKit1.AuthenticationAgent'>"
+ " <method name='BeginAuthentication'>"
+ " <arg type='s' name='action_id' direction='in'/>"
+ " <arg type='s' name='message' direction='in'/>"
+ " <arg type='s' name='icon_name' direction='in'/>"
+ " <arg type='a{ss}' name='details' direction='in'/>"
+ " <arg type='s' name='cookie' direction='in'/>"
+ " <arg type='a(sa{sv})' name='identities' direction='in'/>"
+ " </method>"
+ " <method name='CancelAuthentication'>"
+ " <arg type='s' name='cookie' direction='in'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+static const GDBusInterfaceVTable auth_agent_vtable =
+{
+ auth_agent_handle_method_call,
+ NULL, /* _handle_get_property */
+ NULL /* _handle_set_property */
+};
+
/**
* polkit_agent_register_listener:
* @listener: An instance of a class that is derived from #PolkitAgentListener.
@@ -270,66 +324,69 @@ polkit_agent_register_listener (PolkitAgentListener *listener,
GError **error)
{
Server *server;
+ gboolean ret;
+ GDBusNodeInfo *node_info;
- server = SERVER (g_object_new (TYPE_SERVER, NULL));
- server->subject = g_object_ref (subject);
- server->object_path = object_path != NULL ? g_strdup (object_path) :
- g_strdup ("/org/freedesktop/PolicyKit1/AuthenticationAgent");
- server->listener = listener;
+ ret = FALSE;
+
+ server = server_new (subject, object_path, NULL, error);
+ if (server == NULL)
+ goto out;
- egg_dbus_connection_register_interface (server->system_bus,
- server->object_path,
- _POLKIT_TYPE_AUTHENTICATION_AGENT,
- G_OBJECT (server),
- G_TYPE_INVALID);
+ node_info = g_dbus_node_info_new_for_xml (auth_agent_introspection_data, error);
+ if (node_info == NULL)
+ goto out;
+
+ server->listener = listener;
+ server->auth_agent_registration_id = g_dbus_connection_register_object (server->system_bus,
+ server->object_path,
+ g_dbus_node_info_lookup_interface (node_info, "org.freedesktop.PolicyKit1.AuthenticationAgent"),
+ &auth_agent_vtable,
+ server,
+ NULL, /* user_data GDestroyNotify */
+ error);
+ g_dbus_node_info_unref (node_info);
+
+ if (server->auth_agent_registration_id == 0)
+ {
+ server_free (server);
+ goto out;
+ }
if (!server_register (server, error))
{
- g_object_unref (server);
- return FALSE;
+ server_free (server);
+ goto out;
}
/* take a weak ref and kill server when listener dies */
g_object_weak_ref (G_OBJECT (server->listener), listener_died, server);
- return TRUE;
+ ret = TRUE;
+
+ out:
+ return ret;
}
typedef struct
{
Server *server;
gchar *cookie;
- EggDBusMethodInvocation *method_invocation;
+ GDBusMethodInvocation *invocation;
GCancellable *cancellable;
} AuthData;
-static AuthData *
-auth_data_new (Server *server,
- const gchar *cookie,
- EggDBusMethodInvocation *method_invocation,
- GCancellable *cancellable)
-{
- AuthData *data;
-
- data = g_new0 (AuthData, 1);
- data->server = g_object_ref (server);
- data->cookie = g_strdup (cookie);
- data->method_invocation = g_object_ref (method_invocation);
- data->cancellable = g_object_ref (cancellable);
-
- return data;
-}
-
static void
auth_data_free (AuthData *data)
{
- g_object_unref (data->server);
g_free (data->cookie);
- g_object_unref (data->method_invocation);
+ g_object_unref (data->invocation);
g_object_unref (data->cancellable);
g_free (data);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
auth_cb (GObject *source_object,
GAsyncResult *res,
@@ -343,12 +400,12 @@ auth_cb (GObject *source_object,
res,
&error))
{
- egg_dbus_method_invocation_return_gerror (data->method_invocation, error);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
g_error_free (error);
}
else
{
- _polkit_authentication_agent_handle_begin_authentication_finish (data->method_invocation);
+ g_dbus_method_invocation_return_value (data->invocation, NULL);
}
g_hash_table_remove (data->server->cookie_to_pending_auth, data->cookie);
@@ -357,89 +414,117 @@ auth_cb (GObject *source_object,
}
static void
-handle_begin_authentication (_PolkitAuthenticationAgent *instance,
- const gchar *action_id,
- const gchar *message,
- const gchar *icon_name,
- EggDBusHashMap *details,
- const gchar *cookie,
- EggDBusArraySeq *identities,
- EggDBusMethodInvocation *method_invocation)
+auth_agent_handle_begin_authentication (Server *server,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- Server *server = SERVER (instance);
- AuthData *data;
- GList *list;
+ const gchar *action_id;
+ const gchar *message;
+ const gchar *icon_name;
+ GVariant *details_gvariant;
+ const gchar *cookie;
+ GVariant *identities_gvariant;
+ GList *identities;
+ PolkitDetails *details;
+ GVariantIter iter;
+ GVariant *child;
guint n;
- GCancellable *cancellable;
- PolkitDetails *_details;
+ AuthData *data;
+
+ identities = NULL;
+ details = NULL;
+
+ g_variant_get (parameters,
+ "(&s&s&s@a{ss}&s@a(sa{sv}))",
+ &action_id,
+ &message,
+ &icon_name,
+ &details_gvariant,
+ &cookie,
+ &identities_gvariant);
- list = NULL;
- for (n = 0; n < identities->size; n++)
+ details = polkit_details_new_for_gvariant (details_gvariant);
+
+ g_variant_iter_init (&iter, identities_gvariant);
+ n = 0;
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
{
- _PolkitIdentity *real_identity = _POLKIT_IDENTITY (identities->data.v_ptr[n]);
+ PolkitIdentity *identity;
+ GError *error;
+ error = NULL;
+ identity = polkit_identity_new_for_gvariant (child, &error);
+ g_variant_unref (child);
- list = g_list_prepend (list, polkit_identity_new_for_real (real_identity));
- }
+ if (identity == NULL)
+ {
+ g_prefix_error (&error, "Error extracting identity %d: ", n);
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+ n++;
- list = g_list_reverse (list);
+ identities = g_list_prepend (identities, identity);
+ }
+ identities = g_list_reverse (identities);
- cancellable = g_cancellable_new ();
- data = auth_data_new (server,
- cookie,
- method_invocation,
- cancellable);
- g_object_unref (cancellable);
+ data = g_new0 (AuthData, 1);
+ data->server = server;
+ data->cookie = g_strdup (cookie);
+ data->invocation = g_object_ref (invocation);
+ data->cancellable = g_cancellable_new ();
g_hash_table_insert (server->cookie_to_pending_auth, (gpointer) cookie, data);
- _details = polkit_details_new_for_hash (details->data);
-
polkit_agent_listener_initiate_authentication (server->listener,
action_id,
message,
icon_name,
- _details,
+ details,
cookie,
- list,
+ identities,
data->cancellable,
auth_cb,
data);
- g_list_free (list);
- g_object_unref (_details);
+ out:
+ g_list_foreach (identities, (GFunc) g_object_unref, NULL);
+ g_list_free (identities);
+ g_object_unref (details);
+ g_variant_unref (details_gvariant);
+ g_variant_unref (identities_gvariant);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
-handle_cancel_authentication (_PolkitAuthenticationAgent *instance,
- const gchar *cookie,
- EggDBusMethodInvocation *method_invocation)
+auth_agent_handle_cancel_authentication (Server *server,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation)
{
- Server *server = SERVER (instance);
AuthData *data;
+ const gchar *cookie;
+
+ g_variant_get (parameters,
+ "(&s)",
+ &cookie);
data = g_hash_table_lookup (server->cookie_to_pending_auth, cookie);
if (data == NULL)
{
- egg_dbus_method_invocation_return_error (method_invocation,
- POLKIT_ERROR,
- POLKIT_ERROR_FAILED,
- "No pending authentication request for cookie '%s'",
- cookie);
+ g_dbus_method_invocation_return_error (invocation,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "No pending authentication request for cookie '%s'",
+ cookie);
}
else
{
g_cancellable_cancel (data->cancellable);
- _polkit_authentication_agent_handle_cancel_authentication_finish (method_invocation);
+ g_dbus_method_invocation_return_value (invocation, NULL);
}
}
-static void
-authentication_agent_iface_init (_PolkitAuthenticationAgentIface *agent_iface)
-{
- agent_iface->handle_begin_authentication = handle_begin_authentication;
- agent_iface->handle_cancel_authentication = handle_cancel_authentication;
-}
-
/* ---------------------------------------------------------------------------------------------------- */
G_DEFINE_ABSTRACT_TYPE (PolkitAgentListener, polkit_agent_listener, G_TYPE_OBJECT);