PolicyKit: Branch 'master' - 2 commits
David Zeuthen
david at kemper.freedesktop.org
Thu Aug 12 13:57:17 PDT 2010
docs/polkit/polkit-1-docs.xml | 1
docs/polkit/polkit-1-sections.txt | 19
docs/polkit/polkit-1.types | 1
src/polkit/polkitsubject.c | 22
src/polkitagent/Makefile.am | 15
src/polkitagent/polkitagent.h | 2
src/polkitagent/polkitagentenumtypes.c.template | 39 +
src/polkitagent/polkitagentenumtypes.h.template | 24
src/polkitagent/polkitagenthelper-pam.c | 19
src/polkitagent/polkitagenthelperprivate.h | 2
src/polkitagent/polkitagentlistener.c | 244 ++++++-
src/polkitagent/polkitagentlistener.h | 60 +
src/polkitagent/polkitagentsession.c | 28
src/polkitagent/polkitagenttextlistener.c | 565 ++++++++++++++++++
src/polkitagent/polkitagenttextlistener.h | 45 +
src/polkitagent/polkitagenttypes.h | 3
src/polkitbackend/polkitbackendinteractiveauthority.c | 395 ++++++++----
src/programs/Makefile.am | 1
src/programs/pkcheck.c | 2
src/programs/pkexec.c | 46 +
20 files changed, 1324 insertions(+), 209 deletions(-)
New commits:
commit 42177383585e1e01cd6150f891176afcd4538a82
Author: David Zeuthen <davidz at redhat.com>
Date: Thu Aug 12 16:51:51 2010 -0400
Add textual authentication agent and use it in pkexec(1)
This makes pkexec(1) work when e.g. logging in via ssh(1) or the linux
console but also when using `su -'. Example:
[davidz at x61 ~]$ su - bateman
Password:
[bateman at x61 ~]$ pkexec bash
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ===
Authentication is needed to run `/bin/bash' as the super user
Authenticating as: root
Password:
==== AUTHENTICATION COMPLETE ===
[root at x61 ~]#
Summary of changes
- Added a PolkitAgentTextListener class
- Add new polkit_agent_listener_register() (and _unregister()) API
- Deprecate polkit_agent_register_listener API
- Allow registering authentication agents for PolkitUnixProcess subjects
and prefer such agents to ones governing the session
- Make PolkitAgentSession use the thread-default GMainContext - otherwise
it won't work in spawned threads
- (finally) use PolkitAgentTextListener in pkexec(1) if authorization
via authentication is possible but no authentication agent was
found
Signed-off-by: David Zeuthen <davidz at redhat.com>
diff --git a/docs/polkit/polkit-1-docs.xml b/docs/polkit/polkit-1-docs.xml
index 19c228a..06510ca 100644
--- a/docs/polkit/polkit-1-docs.xml
+++ b/docs/polkit/polkit-1-docs.xml
@@ -100,6 +100,7 @@
<part id="ref-authentication-agent-api">
<title>Authentication Agent API Reference</title>
<xi:include href="xml/polkitagentlistener.xml"/>
+ <xi:include href="xml/polkitagenttextlistener.xml"/>
<xi:include href="xml/polkitagentsession.xml"/>
</part>
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
index ef72acb..85b5d59 100644
--- a/docs/polkit/polkit-1-sections.txt
+++ b/docs/polkit/polkit-1-sections.txt
@@ -369,7 +369,9 @@ PolkitAgentListener
PolkitAgentListenerClass
polkit_agent_listener_initiate_authentication
polkit_agent_listener_initiate_authentication_finish
-polkit_agent_register_listener
+PolkitAgentRegisterFlags
+polkit_agent_listener_register
+polkit_agent_listener_unregister
<SUBSECTION Standard>
POLKIT_AGENT_LISTENER
POLKIT_AGENT_IS_LISTENER
@@ -381,6 +383,21 @@ POLKIT_AGENT_LISTENER_GET_CLASS
</SECTION>
<SECTION>
+<FILE>polkitagenttextlistener</FILE>
+<TITLE>PolkitAgentTextListener</TITLE>
+PolkitAgentTextListener
+polkit_agent_text_listener_new
+<SUBSECTION Standard>
+POLKIT_AGENT_TEXT_LISTENER
+POLKIT_AGENT_IS_TEXT_LISTENER
+POLKIT_AGENT_TYPE_TEXT_LISTENER
+polkit_agent_text_listener_get_type
+POLKIT_AGENT_TEXT_LISTENER_CLASS
+POLKIT_AGENT_IS_TEXT_LISTENER_CLASS
+POLKIT_AGENT_TEXT_LISTENER_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>polkittemporaryauthorization</FILE>
<TITLE>PolkitTemporaryAuthorization</TITLE>
PolkitTemporaryAuthorization
diff --git a/docs/polkit/polkit-1.types b/docs/polkit/polkit-1.types
index 2cab12a..e50812b 100644
--- a/docs/polkit/polkit-1.types
+++ b/docs/polkit/polkit-1.types
@@ -26,3 +26,4 @@ polkit_backend_local_authorization_store_get_type
polkit_agent_session_get_type
polkit_agent_listener_get_type
+polkit_agent_text_listener_get_type
diff --git a/src/polkitagent/Makefile.am b/src/polkitagent/Makefile.am
index 8776599..733da72 100644
--- a/src/polkitagent/Makefile.am
+++ b/src/polkitagent/Makefile.am
@@ -18,8 +18,21 @@ INCLUDES = \
BUILT_SOURCES = \
marshal.stamp \
+ polkitagentenumtypes.c polkitagentenumtypes.h \
$(NULL)
+enum_headers = polkitagentlistener.h
+
+polkitagentenumtypes.h: $(enum_headers) polkitagentenumtypes.h.template
+ ( top_builddir=`cd $(top_builddir) && pwd`; \
+ cd $(srcdir) && glib-mkenums --template polkitagentenumtypes.h.template $(enum_headers)) > \
+ polkitagentenumtypes.h.tmp && mv polkitagentenumtypes.h.tmp polkitagentenumtypes.h
+
+polkitagentenumtypes.c: $(enum_headers) polkitagentenumtypes.c.template
+ ( top_builddir=`cd $(top_builddir) && pwd`; \
+ cd $(srcdir) && glib-mkenums --template polkitagentenumtypes.c.template $(enum_headers)) > \
+ polkitagentenumtypes.c.tmp && mv polkitagentenumtypes.c.tmp polkitagentenumtypes.c
+
marshal.stamp : Makefile.am $(srcdir)/polkitagentmarshal.list
glib-genmarshal --prefix=_polkit_agent_marshal $(srcdir)/polkitagentmarshal.list --header > polkitagentmarshal.h.tmp && mv polkitagentmarshal.h.tmp polkitagentmarshal.h
(echo "#include \"polkitagentmarshal.h\""; glib-genmarshal --prefix=_polkit_agent_marshal $(srcdir)/polkitagentmarshal.list --body) > polkitagentmarshal.c.tmp && mv polkitagentmarshal.c.tmp polkitagentmarshal.c
@@ -36,6 +49,7 @@ libpolkit_agent_1include_HEADERS = \
polkitagenttypes.h \
polkitagentsession.h \
polkitagentlistener.h \
+ polkitagenttextlistener.h \
$(NULL)
libpolkit_agent_1_la_SOURCES = \
@@ -45,6 +59,7 @@ libpolkit_agent_1_la_SOURCES = \
polkitagenttypes.h \
polkitagentsession.h polkitagentsession.c \
polkitagentlistener.h polkitagentlistener.c \
+ polkitagenttextlistener.h polkitagenttextlistener.c \
$(NULL)
libpolkit_agent_1_la_CFLAGS = \
diff --git a/src/polkitagent/polkitagent.h b/src/polkitagent/polkitagent.h
index 5045d67..6f163d1 100644
--- a/src/polkitagent/polkitagent.h
+++ b/src/polkitagent/polkitagent.h
@@ -28,7 +28,9 @@
#define _POLKIT_AGENT_INSIDE_POLKIT_AGENT_H 1
#include <polkitagent/polkitagenttypes.h>
+#include <polkitagent/polkitagentenumtypes.h>
#include <polkitagent/polkitagentlistener.h>
+#include <polkitagent/polkitagenttextlistener.h>
#include <polkitagent/polkitagentsession.h>
#undef _POLKIT_AGENT_INSIDE_POLKIT_AGENT_H
diff --git a/src/polkitagent/polkitagentenumtypes.c.template b/src/polkitagent/polkitagentenumtypes.c.template
new file mode 100644
index 0000000..e6cb139
--- /dev/null
+++ b/src/polkitagent/polkitagentenumtypes.c.template
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include <polkitagent/polkitagent.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ at enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ static const G at Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ GType g_define_type_id =
+ g_ at type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/src/polkitagent/polkitagentenumtypes.h.template b/src/polkitagent/polkitagentenumtypes.h.template
new file mode 100644
index 0000000..24d6f90
--- /dev/null
+++ b/src/polkitagent/polkitagentenumtypes.h.template
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef __POLKIT_AGENT_ENUM_TYPES_H__
+#define __POLKIT_AGENT_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name at _get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX at _TYPE_@ENUMSHORT@ (@enum_name at _get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __POLKIT_AGENT_ENUM_TYPES_H__ */
+/*** END file-tail ***/
diff --git a/src/polkitagent/polkitagenthelper-pam.c b/src/polkitagent/polkitagenthelper-pam.c
index 5e8b54c..d1eed85 100644
--- a/src/polkitagent/polkitagenthelper-pam.c
+++ b/src/polkitagent/polkitagenthelper-pam.c
@@ -204,15 +204,32 @@ conversation_function (int n, const struct pam_message **msg, struct pam_respons
{
case PAM_PROMPT_ECHO_OFF:
+#ifdef PAH_DEBUG
+ fprintf (stderr, "polkit-agent-helper-1: writing `PAM_PROMPT_ECHO_OFF ' to stdout\n");
+#endif /* PAH_DEBUG */
fprintf (stdout, "PAM_PROMPT_ECHO_OFF ");
goto conv1;
case PAM_PROMPT_ECHO_ON:
+#ifdef PAH_DEBUG
+ fprintf (stderr, "polkit-agent-helper-1: writing `PAM_PROMPT_ECHO_ON ' to stdout\n");
+#endif /* PAH_DEBUG */
fprintf (stdout, "PAM_PROMPT_ECHO_ON ");
conv1:
+#ifdef PAH_DEBUG
+ fprintf (stderr, "polkit-agent-helper-1: writing `%s' to stdout\n", msg[i]->msg);
+#endif /* PAH_DEBUG */
fputs (msg[i]->msg, stdout);
if (strlen (msg[i]->msg) > 0 && msg[i]->msg[strlen (msg[i]->msg) - 1] != '\n')
- fputc ('\n', stdout);
+ {
+#ifdef PAH_DEBUG
+ fprintf (stderr, "polkit-agent-helper-1: writing newline to stdout\n");
+#endif /* PAH_DEBUG */
+ fputc ('\n', stdout);
+ }
+#ifdef PAH_DEBUG
+ fprintf (stderr, "polkit-agent-helper-1: flushing stdout\n");
+#endif /* PAH_DEBUG */
fflush (stdout);
if (fgets (buf, sizeof buf, stdin) == NULL)
diff --git a/src/polkitagent/polkitagenthelperprivate.h b/src/polkitagent/polkitagenthelperprivate.h
index 7294d46..aeca2c7 100644
--- a/src/polkitagent/polkitagenthelperprivate.h
+++ b/src/polkitagent/polkitagenthelperprivate.h
@@ -30,7 +30,7 @@
* sensitive information.
*/
#undef PAH_DEBUG
-// #define PAH_DEBUG
+/* #define PAH_DEBUG */
#ifdef HAVE_SOLARIS
# define LOG_AUTHPRIV (10<<3)
diff --git a/src/polkitagent/polkitagentlistener.c b/src/polkitagent/polkitagentlistener.c
index f8321f4..52d71ff 100644
--- a/src/polkitagent/polkitagentlistener.c
+++ b/src/polkitagent/polkitagentlistener.c
@@ -51,6 +51,8 @@ typedef struct
GDBusConnection *system_bus;
guint auth_agent_registration_id;
+ GDBusInterfaceInfo *interface_info;
+
PolkitAuthority *authority;
gulong notify_owner_handler_id;
@@ -62,6 +64,12 @@ typedef struct
gchar *object_path;
GHashTable *cookie_to_pending_auth;
+
+ GThread *thread;
+ GError *thread_initialization_error;
+ gboolean thread_initialized;
+ GMainContext *thread_context;
+ GMainLoop *thread_loop;
} Server;
static void
@@ -82,6 +90,21 @@ server_free (Server *server)
}
}
+ if (server->thread_initialization_error != NULL)
+ g_error_free (server->thread_initialization_error);
+
+ if (server->thread_context != NULL)
+ g_main_context_unref (server->thread_context);
+
+ if (server->thread_loop != NULL)
+ g_main_loop_unref (server->thread_loop);
+
+ if (server->interface_info != NULL)
+ g_dbus_interface_info_unref (server->interface_info);
+
+ if (server->listener != NULL)
+ g_object_unref (server->listener);
+
if (server->auth_agent_registration_id > 0)
g_dbus_connection_unregister_object (server->system_bus, server->auth_agent_registration_id);
@@ -109,13 +132,18 @@ server_register (Server *server,
{
GError *local_error;
gboolean ret;
+ const gchar *locale;
ret = FALSE;
+ locale = g_getenv ("LANG");
+ if (locale == NULL)
+ locale = "en_US.UTF-8";
+
local_error = NULL;
if (!polkit_authority_register_authentication_agent_sync (server->authority,
server->subject,
- g_getenv ("LANG"),
+ locale,
server->object_path,
NULL,
&local_error))
@@ -230,15 +258,6 @@ server_new (PolkitSubject *subject,
return server;
}
-static void
-listener_died (gpointer user_data,
- GObject *where_the_object_was)
-{
- Server *server = user_data;
-
- server_free (server);
-}
-
static void auth_agent_handle_begin_authentication (Server *server,
GVariant *parameters,
GDBusMethodInvocation *invocation);
@@ -295,75 +314,202 @@ static const GDBusInterfaceVTable auth_agent_vtable =
NULL /* _handle_set_property */
};
+static gboolean
+server_export_object (Server *server,
+ GError **error)
+{
+ gboolean ret;
+ ret = FALSE;
+ server->auth_agent_registration_id = g_dbus_connection_register_object (server->system_bus,
+ server->object_path,
+ server->interface_info,
+ &auth_agent_vtable,
+ server,
+ NULL, /* user_data GDestroyNotify */
+ error);
+ if (server->auth_agent_registration_id > 0)
+ ret = TRUE;
+ return ret;
+}
+
+static gpointer
+server_thread_func (gpointer user_data)
+{
+ Server *server = user_data;
+
+ server->thread_context = g_main_context_new ();
+ server->thread_loop = g_main_loop_new (server->thread_context, FALSE);
+
+ g_main_context_push_thread_default (server->thread_context);
+
+ if (!server_export_object (server, &server->thread_initialization_error))
+ {
+ server->thread_initialized = TRUE;
+ goto out;
+ }
+
+ server->thread_initialized = TRUE;
+
+ g_main_loop_run (server->thread_loop);
+
+ out:
+ g_main_context_pop_thread_default (server->thread_context);
+ return NULL;
+}
+
/**
- * polkit_agent_register_listener:
- * @listener: An instance of a class that is derived from #PolkitAgentListener.
+ * polkit_agent_listener_register:
+ * @listener: A #PolkitAgentListener.
+ * @flags: A set of flags from the #PolkitAgentRegisterFlags enumeration.
* @subject: The subject to become an authentication agent for, typically a #PolkitUnixSession object.
* @object_path: The D-Bus object path to use for the authentication agent or %NULL for the default object path.
+ * @cancellable: A #GCancellable or %NULL.
* @error: Return location for error.
*
- * Registers @listener with the PolicyKit daemon as an authentication agent for @subject. This
- * is implemented by registering a D-Bus object at @object_path on the unique name assigned by the
- * system message bus.
- *
- * Whenever the PolicyKit daemon needs to authenticate a processes that is related @subject, the methods
- * polkit_agent_listener_initiate_authentication() and polkit_agent_listener_initiate_authentication_finish()
- * will be invoked on @listener.
+ * Registers @listener with the PolicyKit daemon as an authentication
+ * agent for @subject. This is implemented by registering a D-Bus
+ * object at @object_path on the unique name assigned by the system
+ * message bus.
*
- * Note that registration of an authentication agent can fail; for example another authentication agent may
- * already be registered.
+ * Whenever the PolicyKit daemon needs to authenticate a processes
+ * that is related to @subject, the methods
+ * polkit_agent_listener_initiate_authentication() and
+ * polkit_agent_listener_initiate_authentication_finish() will be
+ * invoked on @listener.
*
- * To unregister @listener, simply free it with g_object_unref().
+ * Note that registration of an authentication agent can fail; for
+ * example another authentication agent may already be registered for
+ * @subject.
*
- * Returns: %TRUE if @listener has been registered, %FALSE if @error is set.
- **/
-gboolean
-polkit_agent_register_listener (PolkitAgentListener *listener,
- PolkitSubject *subject,
- const gchar *object_path,
- GError **error)
+ * Returns: %NULL if @error is set, otherwise a registration handle
+ * that can be used with polkit_agent_listener_unregister().
+ */
+gpointer
+polkit_agent_listener_register (PolkitAgentListener *listener,
+ PolkitAgentRegisterFlags flags,
+ PolkitSubject *subject,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error)
{
Server *server;
- gboolean ret;
GDBusNodeInfo *node_info;
- g_return_val_if_fail (POLKIT_AGENT_IS_LISTENER (listener), FALSE);
- g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), FALSE);
- g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (POLKIT_AGENT_IS_LISTENER (listener), NULL);
+ g_return_val_if_fail (POLKIT_IS_SUBJECT (subject), NULL);
+ g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- ret = FALSE;
+ if (object_path == NULL)
+ object_path = "/org/freedesktop/PolicyKit1/AuthenticationAgent";
- server = server_new (subject, object_path, NULL, error);
+ server = server_new (subject, object_path, cancellable, error);
if (server == NULL)
goto out;
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);
+ server = NULL;
goto out;
}
+ server->interface_info = g_dbus_interface_info_ref (g_dbus_node_info_lookup_interface (node_info, "org.freedesktop.PolicyKit1.AuthenticationAgent"));
+ g_dbus_node_info_unref (node_info);
+
+ server->listener = g_object_ref (listener);
+
+ if (flags & POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD)
+ {
+ server->thread = g_thread_create (server_thread_func,
+ server,
+ TRUE,
+ error);
+ if (server->thread == NULL)
+ {
+ server_free (server);
+ server = NULL;
+ goto out;
+ }
+
+ /* wait for the thread to export and object (TODO: probably use a condition variable instead) */
+ while (!server->thread_initialized)
+ g_thread_yield ();
+ if (server->thread_initialization_error != NULL)
+ {
+ g_propagate_error (error, server->thread_initialization_error);
+ server->thread_initialization_error = NULL;
+ g_thread_join (server->thread);
+ server_free (server);
+ goto out;
+ }
+ }
+ else
+ {
+ if (!server_export_object (server, error))
+ {
+ server_free (server);
+ server = NULL;
+ goto out;
+ }
+ }
if (!server_register (server, error))
{
server_free (server);
+ server = NULL;
goto out;
}
+ out:
+ return server;
+}
+
+/**
+ * polkit_agent_listener_unregister:
+ * @registration_handle: A handle obtained from polkit_agent_listener_register().
+ *
+ * Unregisters @listener.
+ */
+void
+polkit_agent_listener_unregister (gpointer registration_handle)
+{
+ Server *server = registration_handle;
+ if (server->thread != NULL)
+ {
+ g_main_loop_quit (server->thread_loop);
+ g_thread_join (server->thread);
+ }
+ server_free (server);
+}
+
+
+static void
+listener_died (gpointer user_data,
+ GObject *where_the_object_was)
+{
+ Server *server = user_data;
+ server_free (server);
+}
+
+gboolean
+polkit_agent_register_listener (PolkitAgentListener *listener,
+ PolkitSubject *subject,
+ const gchar *object_path,
+ GError **error)
+{
+ Server *server;
+ gboolean ret;
+
+ ret = FALSE;
+
+ server = polkit_agent_listener_register (listener, POLKIT_AGENT_REGISTER_FLAGS_NONE, subject, object_path, NULL, error);
+ if (server == NULL)
+ goto out;
+
+ /* drop the ref that server took */
+ g_object_unref (server->listener);
/* take a weak ref and kill server when listener dies */
g_object_weak_ref (G_OBJECT (server->listener), listener_died, server);
diff --git a/src/polkitagent/polkitagentlistener.h b/src/polkitagent/polkitagentlistener.h
index a20feb8..191b265 100644
--- a/src/polkitagent/polkitagentlistener.h
+++ b/src/polkitagent/polkitagentlistener.h
@@ -94,25 +94,47 @@ struct _PolkitAgentListenerClass
GType polkit_agent_listener_get_type (void) G_GNUC_CONST;
-void polkit_agent_listener_initiate_authentication (PolkitAgentListener *listener,
- const gchar *action_id,
- const gchar *message,
- const gchar *icon_name,
- PolkitDetails *details,
- const gchar *cookie,
- GList *identities,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
-gboolean polkit_agent_listener_initiate_authentication_finish (PolkitAgentListener *listener,
- GAsyncResult *res,
- GError **error);
-
-gboolean polkit_agent_register_listener (PolkitAgentListener *listener,
- PolkitSubject *subject,
- const gchar *object_path,
- GError **error);
+void polkit_agent_listener_initiate_authentication (PolkitAgentListener *listener,
+ const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean polkit_agent_listener_initiate_authentication_finish (PolkitAgentListener *listener,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean polkit_agent_register_listener (PolkitAgentListener *listener,
+ PolkitSubject *subject,
+ const gchar *object_path,
+ GError **error) G_GNUC_DEPRECATED_FOR (polkit_authority_listener_register);
+
+/**
+ * PolkitAgentRegisterFlags:
+ * @POLKIT_AGENT_REGISTER_FLAGS_NONE: No flags are set.
+ * @POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD: Run the listener in a dedicated thread.
+ *
+ * Flags used in polkit_agent_listener_register().
+ */
+typedef enum
+{
+ POLKIT_AGENT_REGISTER_FLAGS_NONE = 0,
+ POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD = (1<<0)
+} PolkitAgentRegisterFlags;
+
+gpointer polkit_agent_listener_register (PolkitAgentListener *listener,
+ PolkitAgentRegisterFlags flags,
+ PolkitSubject *subject,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error);
+
+void polkit_agent_listener_unregister (gpointer registration_handle);
G_END_DECLS
diff --git a/src/polkitagent/polkitagentsession.c b/src/polkitagent/polkitagentsession.c
index 1c17c84..3780b7c 100644
--- a/src/polkitagent/polkitagentsession.c
+++ b/src/polkitagent/polkitagentsession.c
@@ -78,8 +78,8 @@ struct _PolkitAgentSession
int child_stdout;
GPid child_pid;
- int child_watch_id;
- int child_stdout_watch_id;
+ GSource *child_watch_source;
+ GSource *child_stdout_watch_source;
GIOChannel *child_stdout_channel;
gboolean success;
@@ -269,16 +269,18 @@ kill_helper (PolkitAgentSession *session)
session->child_pid = 0;
}
- if (session->child_watch_id > 0)
+ if (session->child_watch_source != NULL)
{
- g_source_remove (session->child_watch_id);
- session->child_watch_id = 0;
+ g_source_destroy (session->child_watch_source);
+ g_source_unref (session->child_watch_source);
+ session->child_watch_source = NULL;
}
- if (session->child_stdout_watch_id > 0)
+ if (session->child_stdout_watch_source != NULL)
{
- g_source_remove (session->child_stdout_watch_id);
- session->child_stdout_watch_id = 0;
+ g_source_destroy (session->child_stdout_watch_source);
+ g_source_unref (session->child_stdout_watch_source);
+ session->child_stdout_watch_source = NULL;
}
if (session->child_stdout_channel != NULL)
@@ -487,9 +489,15 @@ polkit_agent_session_initiate (PolkitAgentSession *session)
goto error;
}
- session->child_watch_id = g_child_watch_add (session->child_pid, child_watch_func, session);
+ session->child_watch_source = g_child_watch_source_new (session->child_pid);
+ g_source_set_callback (session->child_watch_source, (GSourceFunc) child_watch_func, session, NULL);
+ g_source_attach (session->child_watch_source, g_main_context_get_thread_default ());
+
session->child_stdout_channel = g_io_channel_unix_new (session->child_stdout);
- session->child_stdout_watch_id = g_io_add_watch (session->child_stdout_channel, G_IO_IN, io_watch_have_data, session);
+ session->child_stdout_watch_source = g_io_create_watch (session->child_stdout_channel, G_IO_IN);
+ g_source_set_callback (session->child_stdout_watch_source, (GSourceFunc) io_watch_have_data, session, NULL);
+ g_source_attach (session->child_stdout_watch_source, g_main_context_get_thread_default ());
+
session->success = FALSE;
diff --git a/src/polkitagent/polkitagenttextlistener.c b/src/polkitagent/polkitagenttextlistener.c
new file mode 100644
index 0000000..b5c8a3f
--- /dev/null
+++ b/src/polkitagent/polkitagenttextlistener.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz at redhat.com>
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <termios.h>
+#include <unistd.h>
+
+#include <polkit/polkitprivate.h>
+
+#include "polkitagentlistener.h"
+#include "polkitagenttextlistener.h"
+#include "polkitagentsession.h"
+
+/**
+ * SECTION:polkitagenttextlistener
+ * @title: PolkitAgentTextListener
+ * @short_description: Text-based Authentication Agent
+ * @stability: Unstable
+ *
+ * #PolkitAgentTextListener is an #PolkitAgentListener implementation
+ * that interacts with the user using a textual interface.
+ */
+
+/**
+ * PolkitAgentTextListener:
+ *
+ * The #PolkitAgentTextListener struct should not be accessed directly.
+ */
+struct _PolkitAgentTextListener
+{
+ PolkitAgentListener parent_instance;
+
+ GSimpleAsyncResult *simple;
+ PolkitAgentSession *active_session;
+ gulong cancel_id;
+ GCancellable *cancellable;
+
+ FILE *tty;
+};
+
+typedef struct
+{
+ PolkitAgentListenerClass parent_class;
+} PolkitAgentTextListenerClass;
+
+static void polkit_agent_text_listener_initiate_authentication (PolkitAgentListener *_listener,
+ const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static gboolean polkit_agent_text_listener_initiate_authentication_finish (PolkitAgentListener *_listener,
+ GAsyncResult *res,
+ GError **error);
+
+static void initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (PolkitAgentTextListener, polkit_agent_text_listener, POLKIT_AGENT_TYPE_LISTENER,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init));
+
+static void
+polkit_agent_text_listener_init (PolkitAgentTextListener *listener)
+{
+}
+
+static void
+polkit_agent_text_listener_finalize (GObject *object)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (object);
+
+ if (listener->tty != NULL)
+ fclose (listener->tty);
+
+ if (listener->active_session != NULL)
+ g_object_unref (listener->active_session);
+
+ if (G_OBJECT_CLASS (polkit_agent_text_listener_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (polkit_agent_text_listener_parent_class)->finalize (object);
+}
+
+static void
+polkit_agent_text_listener_class_init (PolkitAgentTextListenerClass *klass)
+{
+ GObjectClass *gobject_class;
+ PolkitAgentListenerClass *listener_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = polkit_agent_text_listener_finalize;
+
+ listener_class = POLKIT_AGENT_LISTENER_CLASS (klass);
+ listener_class->initiate_authentication = polkit_agent_text_listener_initiate_authentication;
+ listener_class->initiate_authentication_finish = polkit_agent_text_listener_initiate_authentication_finish;
+}
+
+/**
+ * polkit_agent_text_listener_new:
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Creates a new #PolkitAgentTextListener for authenticating the user
+ * via an textual interface on the controlling terminal
+ * (e.g. <filename>/dev/tty</filename>). This can fail if e.g. the
+ * current process has no controlling terminal.
+ *
+ * Returns: A #PolkitAgentTextListener or %NULL if @error is set. Free with g_object_unref() when done with it.
+ */
+PolkitAgentListener *
+polkit_agent_text_listener_new (GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ return POLKIT_AGENT_LISTENER (g_initable_new (POLKIT_AGENT_TYPE_TEXT_LISTENER,
+ cancellable,
+ error,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (initable);
+ gboolean ret;
+ const gchar *tty_name;
+
+ ret = FALSE;
+
+ tty_name = ctermid (NULL);
+ if (tty_name == NULL)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Cannot determine pathname for current controlling terminal for the process: %s",
+ strerror (errno));
+ goto out;
+ }
+
+ listener->tty = fopen (tty_name, "r+");
+ if (listener->tty == NULL)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Error opening current controlling terminal for the process (`%s'): %s",
+ tty_name,
+ strerror (errno));
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+ initable_iface->init = initable_init;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_completed (PolkitAgentSession *session,
+ gboolean gained_authorization,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (user_data);
+
+ fprintf (listener->tty, "\x1B[1;31m");
+ if (gained_authorization)
+ fprintf (listener->tty, "==== AUTHENTICATION COMPLETE ===\n");
+ else
+ fprintf (listener->tty, "==== AUTHENTICATION FAILED ===\n");
+ fprintf (listener->tty, "\x1B[0m");
+ fflush (listener->tty);
+
+ g_simple_async_result_complete_in_idle (listener->simple);
+
+ g_object_unref (listener->simple);
+ g_object_unref (listener->active_session);
+ g_cancellable_disconnect (listener->cancellable, listener->cancel_id);
+ g_object_unref (listener->cancellable);
+
+ listener->simple = NULL;
+ listener->active_session = NULL;
+ listener->cancel_id = 0;
+}
+
+static void
+on_request (PolkitAgentSession *session,
+ const gchar *request,
+ gboolean echo_on,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (user_data);
+ struct termios ts, ots;
+ GString *str;
+
+ fprintf (listener->tty, "%s", request);
+ fflush (listener->tty);
+
+ setbuf (listener->tty, NULL);
+
+ /* TODO: We really ought to block SIGINT and STGSTP (and probably
+ * other signals too) so we can restore the terminal (since we
+ * turn off echoing). See e.g. Advanced Programming in the
+ * UNIX Environment 2nd edition (Steves and Rago) section
+ * 18.10, pg 660 where this is suggested. See also various
+ * getpass(3) implementations
+ *
+ * However, since we are a library routine the user could have
+ * multiple threads - in fact, typical usage of
+ * PolkitAgentTextListener is to run it in a thread. And
+ * unfortunately threads and POSIX signals is a royal PITA.
+ *
+ * Maybe we could fork(2) and ask for the password in the
+ * child and send it back to the parent over a pipe? (we are
+ * guaranteed that there is only one thread in the child
+ * process).
+ *
+ * (Side benefit of doing this in a child process is that we
+ * could avoid blocking the thread where the
+ * PolkitAgentTextListener object is being serviced from. But
+ * since this class is normally used in a dedicated thread
+ * it doesn't really matter *anyway*.)
+ *
+ * Anyway, On modern Linux not doing this doesn't seem to be a
+ * problem - looks like modern shells restore echoing anyway
+ * on the first input. So maybe it's not even worth solving
+ * the problem.
+ */
+
+ tcgetattr (fileno (listener->tty), &ts);
+ ots = ts;
+ ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ tcsetattr (fileno (listener->tty), TCSAFLUSH, &ts);
+
+ str = g_string_new (NULL);
+ while (TRUE)
+ {
+ gint c;
+ c = getc (listener->tty);
+ if (c == '\n')
+ {
+ /* ok, done */
+ break;
+ }
+ else if (c == EOF)
+ {
+ tcsetattr (fileno (listener->tty), TCSAFLUSH, &ots);
+ g_error ("Got unexpected EOF while reading from controlling terminal.");
+ abort ();
+ break;
+ }
+ else
+ {
+ g_string_append_c (str, c);
+ }
+ }
+ tcsetattr (fileno (listener->tty), TCSAFLUSH, &ots);
+ putc ('\n', listener->tty);
+
+ polkit_agent_session_response (session, str->str);
+ memset (str->str, '\0', str->len);
+ g_string_free (str, TRUE);
+}
+
+static void
+on_show_error (PolkitAgentSession *session,
+ const gchar *text,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (user_data);
+ fprintf (listener->tty, "Error: %s\n", text);
+ fflush (listener->tty);
+}
+
+static void
+on_show_info (PolkitAgentSession *session,
+ const gchar *text,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (user_data);
+ fprintf (listener->tty, "Info: %s\n", text);
+ fflush (listener->tty);
+}
+
+static void
+on_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (user_data);
+ fprintf (listener->tty, "Cancelled\n");
+ fflush (listener->tty);
+ polkit_agent_session_cancel (listener->active_session);
+}
+
+static gchar *
+identity_to_human_readable_string (PolkitIdentity *identity)
+{
+ gchar *ret;
+
+ g_return_val_if_fail (POLKIT_IS_IDENTITY (identity), NULL);
+
+ ret = NULL;
+ if (POLKIT_IS_UNIX_USER (identity))
+ {
+ struct passwd pw;
+ struct passwd *ppw;
+ char buf[2048];
+ int res;
+
+ res = getpwuid_r (polkit_unix_user_get_uid (POLKIT_UNIX_USER (identity)),
+ &pw,
+ buf,
+ sizeof buf,
+ &ppw);
+ if (res != 0)
+ {
+ g_warning ("Error calling getpwuid_r: %s", strerror (res));
+ }
+ else
+ {
+ if (ppw->pw_gecos == NULL || strlen (ppw->pw_gecos) == 0 || strcmp (ppw->pw_gecos, ppw->pw_name) == 0)
+ {
+ ret = g_strdup_printf ("%s", ppw->pw_name);
+ }
+ else
+ {
+ ret = g_strdup_printf ("%s (%s)", ppw->pw_gecos, ppw->pw_name);
+ }
+ }
+ }
+ if (ret == NULL)
+ ret = polkit_identity_to_string (identity);
+ return ret;
+}
+
+static PolkitIdentity *
+choose_identity (PolkitAgentTextListener *listener,
+ GList *identities)
+{
+ GList *l;
+ guint n;
+ guint num_identities;
+ GString *str;
+ PolkitIdentity *ret;
+ guint num;
+ gchar *endp;
+
+ ret = NULL;
+
+ fprintf (listener->tty, "Multiple identities can be used for authentication:\n");
+ for (l = identities, n = 0; l != NULL; l = l->next, n++)
+ {
+ PolkitIdentity *identity = POLKIT_IDENTITY (l->data);
+ gchar *s;
+ s = identity_to_human_readable_string (identity);
+ fprintf (listener->tty, " %d. %s\n", n + 1, s);
+ g_free (s);
+ }
+ num_identities = n;
+ fprintf (listener->tty, "Choose identity to authenticate as (1-%d): ", num_identities);
+ fflush (listener->tty);
+
+ str = g_string_new (NULL);
+ while (TRUE)
+ {
+ gint c;
+ c = getc (listener->tty);
+ if (c == '\n')
+ {
+ /* ok, done */
+ break;
+ }
+ else if (c == EOF)
+ {
+ g_error ("Got unexpected EOF while reading from controlling terminal.");
+ abort ();
+ break;
+ }
+ else
+ {
+ g_string_append_c (str, c);
+ }
+ }
+
+ num = strtol (str->str, &endp, 10);
+ if (str->len == 0 || *endp != '\0' || (num < 1 || num > num_identities))
+ {
+ fprintf (listener->tty, "Invalid response `%s'.\n", str->str);
+ goto out;
+ }
+
+ ret = g_list_nth_data (identities, num-1);
+
+ out:
+ g_string_free (str, TRUE);
+ return ret;
+}
+
+
+static void
+polkit_agent_text_listener_initiate_authentication (PolkitAgentListener *_listener,
+ const gchar *action_id,
+ const gchar *message,
+ const gchar *icon_name,
+ PolkitDetails *details,
+ const gchar *cookie,
+ GList *identities,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (_listener);
+ GSimpleAsyncResult *simple;
+ PolkitIdentity *identity;
+
+ simple = g_simple_async_result_new (G_OBJECT (listener),
+ callback,
+ user_data,
+ polkit_agent_text_listener_initiate_authentication);
+ if (listener->active_session != NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "An authentication session is already underway.");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+
+ g_assert (g_list_length (identities) >= 1);
+
+ fprintf (listener->tty, "\x1B[1;31m");
+ fprintf (listener->tty,
+ "==== AUTHENTICATING FOR %s ===\n",
+ action_id);
+ fprintf (listener->tty, "\x1B[0m");
+ fprintf (listener->tty,
+ "%s\n",
+ message);
+
+ /* handle multiple identies by asking which one to use */
+ if (g_list_length (identities) > 1)
+ {
+ identity = choose_identity (listener, identities);
+ if (identity == NULL)
+ {
+ fprintf (listener->tty, "\x1B[1;31m");
+ fprintf (listener->tty, "==== AUTHENTICATION CANCELED ===\n");
+ fprintf (listener->tty, "\x1B[0m");
+ fflush (listener->tty);
+ g_simple_async_result_set_error (simple,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Authentication was canceled.");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+ }
+ else
+ {
+ gchar *s;
+ identity = identities->data;
+ s = identity_to_human_readable_string (identity);
+ fprintf (listener->tty,
+ "Authenticating as: %s\n",
+ s);
+ g_free (s);
+ }
+
+ listener->active_session = polkit_agent_session_new (identity, cookie);
+ g_signal_connect (listener->active_session,
+ "completed",
+ G_CALLBACK (on_completed),
+ listener);
+ g_signal_connect (listener->active_session,
+ "request",
+ G_CALLBACK (on_request),
+ listener);
+ g_signal_connect (listener->active_session,
+ "show-info",
+ G_CALLBACK (on_show_info),
+ listener);
+ g_signal_connect (listener->active_session,
+ "show-error",
+ G_CALLBACK (on_show_error),
+ listener);
+
+ listener->simple = simple;
+ listener->cancellable = g_object_ref (cancellable);
+ listener->cancel_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (on_cancelled),
+ listener,
+ NULL);
+
+ polkit_agent_session_initiate (listener->active_session);
+
+ out:
+ ;
+}
+
+static gboolean
+polkit_agent_text_listener_initiate_authentication_finish (PolkitAgentListener *_listener,
+ GAsyncResult *res,
+ GError **error)
+{
+ PolkitAgentTextListener *listener = POLKIT_AGENT_TEXT_LISTENER (_listener);
+ gboolean ret;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (res)) ==
+ polkit_agent_text_listener_initiate_authentication);
+ g_assert (listener->active_session == NULL);
+
+ ret = FALSE;
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ goto out;
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
diff --git a/src/polkitagent/polkitagenttextlistener.h b/src/polkitagent/polkitagenttextlistener.h
new file mode 100644
index 0000000..87aa503
--- /dev/null
+++ b/src/polkitagent/polkitagenttextlistener.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz at redhat.com>
+ */
+
+#if !defined(_POLKIT_AGENT_INSIDE_POLKIT_AGENT_H) && !defined (_POLKIT_AGENT_COMPILATION)
+#error "Only <polkitagent/polkitagent.h> can be included directly, this file may disappear or change contents"
+#endif
+
+#ifndef __POLKIT_AGENT_TEXT_LISTENER_H
+#define __POLKIT_AGENT_TEXT_LISTENER_H
+
+#include <polkit/polkit.h>
+#include <polkitagent/polkitagenttypes.h>
+
+G_BEGIN_DECLS
+
+#define POLKIT_AGENT_TYPE_TEXT_LISTENER (polkit_agent_text_listener_get_type())
+#define POLKIT_AGENT_TEXT_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_AGENT_TYPE_TEXT_LISTENER, PolkitAgentTextListener))
+#define POLKIT_AGENT_IS_TEXT_LISTENER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_AGENT_TYPE_TEXT_LISTENER))
+
+GType polkit_agent_text_listener_get_type (void) G_GNUC_CONST;
+PolkitAgentListener *polkit_agent_text_listener_new (GCancellable *cancellable,
+ GError **error);
+
+
+G_END_DECLS
+
+#endif /* __POLKIT_AGENT_TEXT_LISTENER_H */
diff --git a/src/polkitagent/polkitagenttypes.h b/src/polkitagent/polkitagenttypes.h
index 8847c91..1de03c6 100644
--- a/src/polkitagent/polkitagenttypes.h
+++ b/src/polkitagent/polkitagenttypes.h
@@ -33,6 +33,9 @@ G_BEGIN_DECLS
struct _PolkitAgentListener;
typedef struct _PolkitAgentListener PolkitAgentListener;
+struct _PolkitAgentTextListener;
+typedef struct _PolkitAgentTextListener PolkitAgentTextListener;
+
struct _PolkitAgentSession;
typedef struct _PolkitAgentSession PolkitAgentSession;
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index ab783b4..31e60df 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -85,7 +85,8 @@ typedef void (*AuthenticationAgentCallback) (AuthenticationAgent *agent,
PolkitIdentity *authenticated_identity,
gpointer user_data);
-static void authentication_agent_free (AuthenticationAgent *agent);
+static AuthenticationAgent *authentication_agent_ref (AuthenticationAgent *agent);
+static void authentication_agent_unref (AuthenticationAgent *agent);
static void authentication_agent_initiate_challenge (AuthenticationAgent *agent,
PolkitSubject *subject,
@@ -99,7 +100,7 @@ static void authentication_agent_initiate_challenge (Authenticati
AuthenticationAgentCallback callback,
gpointer user_data);
-static PolkitSubject *authentication_agent_get_session (AuthenticationAgent *agent);
+static PolkitSubject *authentication_agent_get_scope (AuthenticationAgent *agent);
static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authority,
PolkitSubject *subject);
@@ -195,7 +196,17 @@ typedef struct
TemporaryAuthorizationStore *temporary_authorization_store;
- GHashTable *hash_session_to_authentication_agent;
+ /* Maps from PolkitSubject* to AuthenticationAgent* - currently the
+ * following PolkitSubject-derived types are used
+ *
+ * - PolkitSystemBusName - for authentication agents handling interaction for a single well-known name
+ * - typically pkexec(1) launched via e.g. ssh(1) or login(1)
+ *
+ * - PolkitUnixSession - for authentication agents handling interaction for a whole login session
+ * - typically a desktop environment session
+ *
+ */
+ GHashTable *hash_scope_to_authentication_agent;
GDBusConnection *system_bus_connection;
guint name_owner_changed_signal_id;
@@ -276,10 +287,10 @@ polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *au
priv->temporary_authorization_store = temporary_authorization_store_new (authority);
- priv->hash_session_to_authentication_agent = g_hash_table_new_full ((GHashFunc) polkit_subject_hash,
- (GEqualFunc) polkit_subject_equal,
- (GDestroyNotify) g_object_unref,
- (GDestroyNotify) authentication_agent_free);
+ priv->hash_scope_to_authentication_agent = g_hash_table_new_full ((GHashFunc) polkit_subject_hash,
+ (GEqualFunc) polkit_subject_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) authentication_agent_unref);
priv->session_monitor = polkit_backend_session_monitor_new ();
g_signal_connect (priv->session_monitor,
@@ -334,7 +345,7 @@ polkit_backend_interactive_authority_finalize (GObject *object)
temporary_authorization_store_free (priv->temporary_authorization_store);
- g_hash_table_unref (priv->hash_session_to_authentication_agent);
+ g_hash_table_unref (priv->hash_scope_to_authentication_agent);
G_OBJECT_CLASS (polkit_backend_interactive_authority_parent_class)->finalize (object);
}
@@ -410,7 +421,9 @@ polkit_backend_interactive_authority_enumerate_actions (PolkitBackendAuthority
struct AuthenticationAgent
{
- PolkitSubject *session;
+ volatile gint ref_count;
+
+ PolkitSubject *scope;
gchar *locale;
gchar *object_path;
@@ -457,9 +470,9 @@ _polkit_subject_get_cmdline (PolkitSubject *subject)
&error);
if (process == NULL)
{
- g_warning ("Error getting process for system bus name `%s': %s",
- polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
- error->message);
+ g_printerr ("Error getting process for system bus name `%s': %s\n",
+ polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
+ error->message);
g_error_free (error);
goto out;
}
@@ -479,9 +492,9 @@ _polkit_subject_get_cmdline (PolkitSubject *subject)
&contents_len,
&error))
{
- g_warning ("Error opening `%s': %s",
- filename,
- error->message);
+ g_printerr ("Error opening `%s': %s\n",
+ filename,
+ error->message);
g_error_free (error);
goto out;
}
@@ -575,7 +588,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
PolkitBackendInteractiveAuthorityPrivate *priv;
PolkitAuthorizationResult *result;
- gchar *session_str;
+ gchar *scope_str;
gchar *subject_str;
gchar *user_of_subject_str;
gchar *authenticated_identity_str;
@@ -586,7 +599,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
result = NULL;
- session_str = polkit_subject_to_string (agent->session);
+ scope_str = polkit_subject_to_string (agent->scope);
subject_str = polkit_subject_to_string (subject);
user_of_subject_str = polkit_identity_to_string (user_of_subject);
authenticated_identity_str = NULL;
@@ -622,7 +635,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
id = temporary_authorization_store_add_authorization (priv->temporary_authorization_store,
subject,
- authentication_agent_get_session (agent),
+ authentication_agent_get_scope (agent),
action_id);
polkit_details_insert (details, "polkit.temporary_authorization_id", id);
@@ -648,7 +661,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
"Operator of %s successfully authenticated as %s to gain "
"TEMPORARY authorization for action %s for %s [%s] (owned by %s)",
- session_str,
+ scope_str,
authenticated_identity_str,
action_id,
subject_str,
@@ -660,7 +673,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
"Operator of %s successfully authenticated as %s to gain "
"ONE-SHOT authorization for action %s for %s [%s] (owned by %s)",
- session_str,
+ scope_str,
authenticated_identity_str,
action_id,
subject_str,
@@ -673,7 +686,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
"Operator of %s FAILED to authenticate to gain "
"authorization for action %s for %s [%s] (owned by %s)",
- session_str,
+ scope_str,
action_id,
subject_str,
subject_cmdline,
@@ -692,7 +705,7 @@ check_authorization_challenge_cb (AuthenticationAgent *agent,
g_free (authenticated_identity_str);
g_free (user_of_subject_str);
g_free (subject_str);
- g_free (session_str);
+ g_free (scope_str);
}
static PolkitAuthorizationResult *
@@ -1282,7 +1295,7 @@ authentication_session_new (AuthenticationAgent *agent,
AuthenticationSession *session;
session = g_new0 (AuthenticationSession, 1);
- session->agent = agent;
+ session->agent = authentication_agent_ref (agent);
session->cookie = g_strdup (cookie);
session->subject = g_object_ref (subject);
session->user_of_subject = g_object_ref (user_of_subject);
@@ -1311,6 +1324,7 @@ authentication_session_new (AuthenticationAgent *agent,
static void
authentication_session_free (AuthenticationSession *session)
{
+ authentication_agent_unref (session->agent);
g_free (session->cookie);
g_list_foreach (session->identities, (GFunc) g_object_unref, NULL);
g_list_free (session->identities);
@@ -1340,13 +1354,13 @@ authentication_agent_new_cookie (AuthenticationAgent *agent)
}
static PolkitSubject *
-authentication_agent_get_session (AuthenticationAgent *agent)
+authentication_agent_get_scope (AuthenticationAgent *agent)
{
- return agent->session;
+ return agent->scope;
}
static void
-authentication_agent_free (AuthenticationAgent *agent)
+authentication_agent_cancel_all_sessions (AuthenticationAgent *agent)
{
/* cancel all active authentication sessions; use a copy of the list since
* callbacks will modify the list
@@ -1360,24 +1374,37 @@ authentication_agent_free (AuthenticationAgent *agent)
for (l = active_sessions; l != NULL; l = l->next)
{
AuthenticationSession *session = l->data;
-
authentication_session_cancel (session);
}
g_list_free (active_sessions);
}
+}
- if (agent->proxy != NULL)
- g_object_unref (agent->proxy);
+static AuthenticationAgent *
+authentication_agent_ref (AuthenticationAgent *agent)
+{
+ g_atomic_int_inc (&agent->ref_count);
+ return agent;
+}
- g_object_unref (agent->session);
- g_free (agent->locale);
- g_free (agent->object_path);
- g_free (agent->unique_system_bus_name);
- g_free (agent);
+static void
+authentication_agent_unref (AuthenticationAgent *agent)
+{
+ if (g_atomic_int_dec_and_test (&agent->ref_count))
+ {
+ if (agent->proxy != NULL)
+ g_object_unref (agent->proxy);
+
+ g_object_unref (agent->scope);
+ g_free (agent->locale);
+ g_free (agent->object_path);
+ g_free (agent->unique_system_bus_name);
+ g_free (agent);
+ }
}
static AuthenticationAgent *
-authentication_agent_new (PolkitSubject *session,
+authentication_agent_new (PolkitSubject *scope,
const gchar *unique_system_bus_name,
const gchar *locale,
const gchar *object_path)
@@ -1387,7 +1414,8 @@ authentication_agent_new (PolkitSubject *session,
agent = g_new0 (AuthenticationAgent, 1);
- agent->session = g_object_ref (session);
+ agent->ref_count = 1;
+ agent->scope = g_object_ref (scope);
agent->object_path = g_strdup (object_path);
agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
agent->locale = g_strdup (locale);
@@ -1425,13 +1453,41 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori
agent = NULL;
session_for_subject = NULL;
+ agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
+ if (agent != NULL)
+ goto out;
+
+ if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
+ {
+ PolkitSubject *process;
+ process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject),
+ NULL,
+ NULL);
+ if (process != NULL)
+ {
+ agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, process);
+ if (agent != NULL)
+ {
+ g_object_unref (process);
+ goto out;
+ }
+ g_object_unref (process);
+ }
+ }
+
+ /* Now, we should also cover the case where @subject is a
+ * UnixProcess but the agent is a SystemBusName. However, this can't
+ * happen because we only allow registering agents for UnixProcess
+ * and UnixSession subjects!
+ */
+
session_for_subject = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
subject,
NULL);
if (session_for_subject == NULL)
goto out;
- agent = g_hash_table_lookup (priv->hash_session_to_authentication_agent, session_for_subject);
+ agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, session_for_subject);
out:
if (session_for_subject != NULL)
@@ -1455,7 +1511,7 @@ get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *author
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
- g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+ g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
{
GList *l;
@@ -1491,7 +1547,7 @@ get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendIn
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
- g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+ g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
{
GList *l;
@@ -1525,7 +1581,7 @@ get_authentication_sessions_for_system_bus_unique_name_subject (PolkitBackendInt
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
- g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+ g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
{
GList *l;
@@ -1557,7 +1613,7 @@ get_authentication_agent_by_unique_system_bus_name (PolkitBackendInteractiveAuth
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
- g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+ g_hash_table_iter_init (&hash_iter, priv->hash_scope_to_authentication_agent);
while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
{
if (strcmp (agent->unique_system_bus_name, unique_system_bus_name) == 0)
@@ -1584,7 +1640,7 @@ authentication_agent_begin_cb (GDBusProxy *proxy,
res,
&error))
{
- g_warning ("Error performing authentication: %s", error->message);
+ g_printerr ("Error performing authentication: %s\n", error->message);
g_error_free (error);
gained_authorization = FALSE;
}
@@ -1681,7 +1737,7 @@ get_localized_data_for_challenge (PolkitBackendInteractiveAuthority *authority,
/* Set LANG and locale so gettext() + friends work when running the code in the extensions */
if (setlocale (LC_ALL, locale) == NULL)
{
- g_warning ("Invalid locale '%s'", locale);
+ g_printerr ("Invalid locale '%s'\n", locale);
}
g_setenv ("LANG", locale, TRUE);
@@ -1861,7 +1917,7 @@ authentication_agent_cancel_cb (GDBusProxy *proxy,
error = NULL;
if (!g_dbus_proxy_call_finish (proxy, res, &error))
{
- g_warning ("Error cancelling authentication: %s", error->message);
+ g_printerr ("Error cancelling authentication: %s\n", error->message);
g_error_free (error);
}
}
@@ -1892,93 +1948,145 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
PolkitBackendInteractiveAuthority *interactive_authority;
PolkitBackendInteractiveAuthorityPrivate *priv;
PolkitSubject *session_for_caller;
+ PolkitIdentity *user_of_caller;
+ PolkitIdentity *user_of_subject;
AuthenticationAgent *agent;
gboolean ret;
- gchar *agent_cmdline;
+ gchar *caller_cmdline;
+ gchar *subject_as_string;
- session_for_caller = NULL;
ret = FALSE;
+ session_for_caller = NULL;
+ user_of_caller = NULL;
+ user_of_subject = NULL;
+ subject_as_string = NULL;
+ caller_cmdline = NULL;
+ agent = NULL;
+
+ /* TODO: validate that object path is well-formed */
+
interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
- if (!POLKIT_IS_UNIX_SESSION (subject))
+ if (POLKIT_IS_UNIX_SESSION (subject))
+ {
+ session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
+ caller,
+ NULL);
+ if (session_for_caller == NULL)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Cannot determine session the caller is in");
+ goto out;
+ }
+ if (!polkit_subject_equal (session_for_caller, subject))
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Passed session and the session the caller is in differs. They must be equal for now.");
+ goto out;
+ }
+ }
+ else if (POLKIT_IS_UNIX_PROCESS (subject))
+ {
+ /* explicitly OK */
+ }
+ else
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Can only register PolkitUnixSession objects for now.");
+ "Only unix-process and unix-session subjects can be used for authentication agents.");
goto out;
}
- session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
- caller,
- NULL);
- if (session_for_caller == NULL)
+ user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL);
+ if (user_of_caller == NULL)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Cannot determine session the caller is in");
+ "Cannot determine user of caller");
goto out;
}
-
- if (!polkit_subject_equal (session_for_caller, subject))
+ user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL);
+ if (user_of_subject == NULL)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Passed session and the session the caller is in differs. They must be equal for now.");
+ "Cannot determine user of subject");
goto out;
}
+ if (!polkit_identity_equal (user_of_caller, user_of_subject))
+ {
+ if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0)
+ {
+ /* explicitly allow uid 0 to register for other users */
+ }
+ else
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "User of caller and user of subject differs.");
+ goto out;
+ }
+ }
- agent = g_hash_table_lookup (priv->hash_session_to_authentication_agent, session_for_caller);
+ agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
if (agent != NULL)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "An authentication agent already exists for session");
+ "An authentication agent already exists for the given subject");
goto out;
}
- /* TODO: validate that object path is well-formed */
-
- agent = authentication_agent_new (session_for_caller,
+ agent = authentication_agent_new (subject,
polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
locale,
object_path);
- g_hash_table_insert (priv->hash_session_to_authentication_agent,
- g_object_ref (session_for_caller),
+ g_hash_table_insert (priv->hash_scope_to_authentication_agent,
+ g_object_ref (subject),
agent);
- agent_cmdline = _polkit_subject_get_cmdline (caller);
- if (agent_cmdline == NULL)
- agent_cmdline = g_strdup ("<unknown>");
+ caller_cmdline = _polkit_subject_get_cmdline (caller);
+ if (caller_cmdline == NULL)
+ caller_cmdline = g_strdup ("<unknown>");
- g_debug ("Added authentication agent for session %s at name %s [%s], object path %s, locale %s",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (session_for_caller)),
+ subject_as_string = polkit_subject_to_string (subject);
+
+ g_debug ("Added authentication agent for %s at name %s [%s], object path %s, locale %s",
+ subject_as_string,
polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
- agent_cmdline,
+ caller_cmdline,
object_path,
locale);
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
- "Registered Authentication Agent for session %s "
+ "Registered Authentication Agent for %s "
"(system bus name %s [%s], object path %s, locale %s)",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (session_for_caller)),
+ subject_as_string,
polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
- agent_cmdline,
+ caller_cmdline,
object_path,
locale);
-
- g_free (agent_cmdline);
-
-
ret = TRUE;
out:
+ g_free (caller_cmdline);
+ g_free (subject_as_string);
+ if (user_of_caller != NULL)
+ g_object_unref (user_of_caller);
+ if (user_of_subject != NULL)
+ g_object_unref (user_of_subject);
if (session_for_caller != NULL)
g_object_unref (session_for_caller);
@@ -1995,46 +2103,91 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack
PolkitBackendInteractiveAuthority *interactive_authority;
PolkitBackendInteractiveAuthorityPrivate *priv;
PolkitSubject *session_for_caller;
+ PolkitIdentity *user_of_caller;
+ PolkitIdentity *user_of_subject;
AuthenticationAgent *agent;
gboolean ret;
+ gchar *scope_str;
interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
ret = FALSE;
session_for_caller = NULL;
+ user_of_caller = NULL;
+ user_of_subject = NULL;
- if (!POLKIT_IS_UNIX_SESSION (subject))
+ if (POLKIT_IS_UNIX_SESSION (subject))
+ {
+ session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
+ caller,
+ NULL);
+ if (session_for_caller == NULL)
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Cannot determine session the caller is in");
+ goto out;
+ }
+
+ if (!polkit_subject_equal (session_for_caller, subject))
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Passed session and the session the caller is in differs. They must be equal for now.");
+ goto out;
+ }
+ }
+ else if (POLKIT_IS_UNIX_PROCESS (subject))
+ {
+ /* explicitly OK */
+ }
+ else
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Can only unregister PolkitUnixSession objects for now.");
+ "Only unix-process and unix-session subjects can be used for authentication agents.");
goto out;
}
- session_for_caller = polkit_backend_session_monitor_get_session_for_subject (priv->session_monitor,
- caller,
- NULL);
- if (session_for_caller == NULL)
+ user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, caller, NULL);
+ if (user_of_caller == NULL)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Cannot determine session the caller is in");
+ "Cannot determine user of caller");
goto out;
}
-
- if (!polkit_subject_equal (session_for_caller, subject))
+ user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor, subject, NULL);
+ if (user_of_subject == NULL)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Passed session and the session the caller is in differs. They must be equal for now.");
+ "Cannot determine user of subject");
goto out;
}
+ if (!polkit_identity_equal (user_of_caller, user_of_subject))
+ {
+ if (POLKIT_IS_UNIX_USER (user_of_caller) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) == 0)
+ {
+ /* explicitly allow uid 0 to register for other users */
+ }
+ else
+ {
+ g_set_error (error,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "User of caller and user of subject differs.");
+ goto out;
+ }
+ }
- agent = g_hash_table_lookup (priv->hash_session_to_authentication_agent, session_for_caller);
+ agent = g_hash_table_lookup (priv->hash_scope_to_authentication_agent, subject);
if (agent == NULL)
{
g_set_error (error,
@@ -2044,8 +2197,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack
goto out;
}
- if (strcmp (agent->unique_system_bus_name,
- polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller))) != 0)
+ if (g_strcmp0 (agent->unique_system_bus_name, polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller))) != 0)
{
g_set_error (error,
POLKIT_ERROR,
@@ -2054,7 +2206,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack
goto out;
}
- if (strcmp (agent->object_path, object_path) != 0)
+ if (g_strcmp0 (agent->object_path, object_path) != 0)
{
g_set_error (error,
POLKIT_ERROR,
@@ -2063,27 +2215,34 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack
goto out;
}
-
- g_debug ("Removing authentication agent for session %s at name %s, object path %s, locale %s",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (agent->session)),
+ scope_str = polkit_subject_to_string (agent->scope);
+ g_debug ("Removing authentication agent for %s at name %s, object path %s, locale %s",
+ scope_str,
agent->unique_system_bus_name,
agent->object_path,
agent->locale);
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
- "Unregistered Authentication Agent for session %s "
+ "Unregistered Authentication Agent for %s "
"(system bus name %s, object path %s, locale %s)",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (agent->session)),
+ scope_str,
agent->unique_system_bus_name,
agent->object_path,
agent->locale);
+ g_free (scope_str);
+ authentication_agent_cancel_all_sessions (agent);
/* this works because we have exactly one agent per session */
- g_hash_table_remove (priv->hash_session_to_authentication_agent, agent->session);
+ /* this frees agent... */
+ g_hash_table_remove (priv->hash_scope_to_authentication_agent, agent->scope);
ret = TRUE;
out:
+ if (user_of_caller != NULL)
+ g_object_unref (user_of_caller);
+ if (user_of_subject != NULL)
+ g_object_unref (user_of_subject);
if (session_for_caller != NULL)
g_object_unref (session_for_caller);
return ret;
@@ -2204,21 +2363,27 @@ polkit_backend_interactive_authority_system_bus_name_owner_changed (PolkitBacken
agent = get_authentication_agent_by_unique_system_bus_name (interactive_authority, name);
if (agent != NULL)
{
- g_debug ("Removing authentication agent for session %s at name %s, object path %s (disconnected from bus)",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (agent->session)),
+ gchar *scope_str;
+
+ scope_str = polkit_subject_to_string (agent->scope);
+ g_debug ("Removing authentication agent for %s at name %s, object path %s (disconnected from bus)",
+ scope_str,
agent->unique_system_bus_name,
agent->object_path);
polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
- "Unregistered Authentication Agent for session %s "
+ "Unregistered Authentication Agent for %s "
"(system bus name %s, object path %s, locale %s) (disconnected from bus)",
- polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (agent->session)),
+ scope_str,
agent->unique_system_bus_name,
agent->object_path,
agent->locale);
+ g_free (scope_str);
+ authentication_agent_cancel_all_sessions (agent);
/* this works because we have exactly one agent per session */
- g_hash_table_remove (priv->hash_session_to_authentication_agent, agent->session);
+ /* this frees agent... */
+ g_hash_table_remove (priv->hash_scope_to_authentication_agent, agent->scope);
}
/* cancel all authentication sessions initiated by the process owning the vanished name */
@@ -2266,7 +2431,7 @@ struct TemporaryAuthorization
{
TemporaryAuthorizationStore *store;
PolkitSubject *subject;
- PolkitSubject *session;
+ PolkitSubject *scope;
gchar *id;
gchar *action_id;
guint64 time_granted;
@@ -2280,7 +2445,7 @@ temporary_authorization_free (TemporaryAuthorization *authorization)
{
g_free (authorization->id);
g_object_unref (authorization->subject);
- g_object_unref (authorization->session);
+ g_object_unref (authorization->scope);
g_free (authorization->action_id);
if (authorization->expiration_timeout_id > 0)
g_source_remove (authorization->expiration_timeout_id);
@@ -2333,9 +2498,9 @@ temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *st
&error);
if (subject_to_use == NULL)
{
- g_warning ("Error getting process for system bus name `%s': %s",
- polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
- error->message);
+ g_printerr ("Error getting process for system bus name `%s': %s\n",
+ polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
+ error->message);
g_error_free (error);
subject_to_use = g_object_ref (subject);
}
@@ -2403,7 +2568,7 @@ on_unix_process_check_vanished_timeout (gpointer user_data)
{
if (error != NULL)
{
- g_warning ("Error checking if process exists: %s", error->message);
+ g_printerr ("Error checking if process exists: %s\n", error->message);
g_error_free (error);
}
else
@@ -2472,7 +2637,7 @@ temporary_authorization_store_remove_authorizations_for_system_bus_name (Tempora
static const gchar *
temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store,
PolkitSubject *subject,
- PolkitSubject *session,
+ PolkitSubject *scope,
const gchar *action_id)
{
TemporaryAuthorization *authorization;
@@ -2494,9 +2659,9 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st
&error);
if (subject_to_use == NULL)
{
- g_warning ("Error getting process for system bus name `%s': %s",
- polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
- error->message);
+ g_printerr ("Error getting process for system bus name `%s': %s\n",
+ polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject)),
+ error->message);
g_error_free (error);
subject_to_use = g_object_ref (subject);
}
@@ -2517,7 +2682,7 @@ temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *st
authorization->id = g_strdup_printf ("tmpauthz%" G_GUINT64_FORMAT, store->serial++);
authorization->store = store;
authorization->subject = g_object_ref (subject_to_use);
- authorization->session = g_object_ref (session);
+ authorization->scope = g_object_ref (scope);
authorization->action_id = g_strdup (action_id);
authorization->time_granted = time (NULL);
authorization->time_expires = authorization->time_granted + expiration_seconds;
@@ -2617,7 +2782,7 @@ polkit_backend_interactive_authority_enumerate_temporary_authorizations (PolkitB
TemporaryAuthorization *ta = l->data;
PolkitTemporaryAuthorization *tmp_authz;
- if (!polkit_subject_equal (ta->session, subject))
+ if (!polkit_subject_equal (ta->scope, subject))
continue;
tmp_authz = polkit_temporary_authorization_new (ta->id,
@@ -2695,7 +2860,7 @@ polkit_backend_interactive_authority_revoke_temporary_authorizations (PolkitBack
ll = l->next;
- if (!polkit_subject_equal (ta->session, subject))
+ if (!polkit_subject_equal (ta->scope, subject))
continue;
priv->temporary_authorization_store->authorizations = g_list_remove (priv->temporary_authorization_store->authorizations, ta);
@@ -2760,7 +2925,7 @@ polkit_backend_interactive_authority_revoke_temporary_authorization_by_id (Polki
if (strcmp (ta->id, id) != 0)
continue;
- if (!polkit_subject_equal (session_for_caller, ta->session))
+ if (!polkit_subject_equal (session_for_caller, ta->scope))
{
g_set_error (error,
POLKIT_ERROR,
diff --git a/src/programs/Makefile.am b/src/programs/Makefile.am
index 5c8a26f..99bd299 100644
--- a/src/programs/Makefile.am
+++ b/src/programs/Makefile.am
@@ -31,6 +31,7 @@ pkexec_CFLAGS = \
pkexec_LDADD = \
$(GLIB_LIBS) \
$(top_builddir)/src/polkit/libpolkit-gobject-1.la \
+ $(top_builddir)/src/polkitagent/libpolkit-agent-1.la \
$(NULL)
polkitmodulesdir = $(libdir)/polkit-1/extensions
diff --git a/src/programs/pkcheck.c b/src/programs/pkcheck.c
index fb61b33..cda9e8e 100644
--- a/src/programs/pkcheck.c
+++ b/src/programs/pkcheck.c
@@ -198,7 +198,7 @@ main (int argc, char *argv[])
}
else if (opt_show_version)
{
- g_print ("pkexec version %s\n", PACKAGE_VERSION);
+ g_print ("pkcheck version %s\n", PACKAGE_VERSION);
ret = 0;
goto out;
}
diff --git a/src/programs/pkexec.c b/src/programs/pkexec.c
index 4a3d55d..f4480ff 100644
--- a/src/programs/pkexec.c
+++ b/src/programs/pkexec.c
@@ -43,6 +43,8 @@
#include <stdarg.h>
#include <polkit/polkit.h>
+#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
+#include <polkitagent/polkitagent.h>
static gchar *original_user_name = NULL;
static gchar *original_cwd = NULL;
@@ -361,6 +363,7 @@ validate_environment_variable (const gchar *key,
return ret;
}
+
/* ---------------------------------------------------------------------------------------------------- */
int
@@ -417,6 +420,7 @@ main (int argc, char *argv[])
gchar *opt_user;
pid_t pid_of_caller;
uid_t uid_of_caller;
+ gpointer local_agent_handle;
ret = 127;
authority = NULL;
@@ -428,6 +432,7 @@ main (int argc, char *argv[])
path = NULL;
command_line = NULL;
opt_user = NULL;
+ local_agent_handle = NULL;
/* check for correct invocation */
if (geteuid () != 0)
@@ -642,6 +647,7 @@ main (int argc, char *argv[])
action_id = find_action_for_path (authority, path);
g_assert (action_id != NULL);
+ try_again:
error = NULL;
result = polkit_authority_check_authorization_sync (authority,
subject,
@@ -664,8 +670,40 @@ main (int argc, char *argv[])
}
else if (polkit_authorization_result_get_is_challenge (result))
{
- g_printerr ("Error executing command as another user: No authentication agent was found.\n");
- goto out;
+ if (local_agent_handle == NULL)
+ {
+ PolkitAgentListener *listener;
+ error = NULL;
+ /* this will fail if we can't find a controlling terminal */
+ listener = polkit_agent_text_listener_new (NULL, &error);
+ if (listener == NULL)
+ {
+ g_printerr ("Error creating textual authentication agent: %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
+ local_agent_handle = polkit_agent_listener_register (listener,
+ POLKIT_AGENT_REGISTER_FLAGS_RUN_IN_THREAD,
+ subject,
+ NULL, /* object_path */
+ NULL, /* GCancellable */
+ &error);
+ g_object_unref (listener);
+ if (local_agent_handle == NULL)
+ {
+ g_printerr ("Error registering local authentication agent: %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
+ g_object_unref (result);
+ result = NULL;
+ goto try_again;
+ }
+ else
+ {
+ g_printerr ("Error executing command as another user.\n");
+ goto out;
+ }
}
else
{
@@ -802,6 +840,10 @@ main (int argc, char *argv[])
g_assert_not_reached ();
out:
+ /* if applicable, nuke the local authentication agent */
+ if (local_agent_handle != NULL)
+ polkit_agent_listener_unregister (local_agent_handle);
+
if (result != NULL)
g_object_unref (result);
commit 17f0600529dc926ae4a0c85dc56c393cc09e4011
Author: David Zeuthen <davidz at redhat.com>
Date: Thu Aug 12 16:49:25 2010 -0400
Fix scanning of unix-process subjects
In particular accept both "unix-process:<pid>,<starttime>" and
"unix-process:<pid>". For the latter, return an error if we cannot
lookup the starttime (for example if the given pid references a
non-existing process).
Signed-off-by: David Zeuthen <davidz at redhat.com>
diff --git a/src/polkit/polkitsubject.c b/src/polkit/polkitsubject.c
index 19d60b9..51e60e0 100644
--- a/src/polkit/polkitsubject.c
+++ b/src/polkit/polkitsubject.c
@@ -24,6 +24,7 @@
#endif
#include <string.h>
+#include <stdio.h>
#include "polkitsubject.h"
#include "polkitunixprocess.h"
@@ -222,8 +223,6 @@ polkit_subject_from_string (const gchar *str,
GError **error)
{
PolkitSubject *subject;
- guint64 val;
- gchar *endptr;
g_return_val_if_fail (str != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
@@ -234,12 +233,15 @@ polkit_subject_from_string (const gchar *str,
if (g_str_has_prefix (str, "unix-process:"))
{
- val = g_ascii_strtoull (str + sizeof "unix-process:" - 1,
- &endptr,
- 10);
- if (*endptr == '\0')
+ gint scanned_pid;
+ guint64 scanned_starttime;
+ if (sscanf (str, "unix-process:%d:%" G_GUINT64_FORMAT, &scanned_pid, &scanned_starttime) == 2)
{
- subject = polkit_unix_process_new ((gint) val);
+ subject = polkit_unix_process_new_full (scanned_pid, scanned_starttime);
+ }
+ else if (sscanf (str, "unix-process:%d", &scanned_pid) == 1)
+ {
+ subject = polkit_unix_process_new_full (scanned_pid, 0);
if (polkit_unix_process_get_start_time (POLKIT_UNIX_PROCESS (subject)) == 0)
{
g_object_unref (subject);
@@ -247,8 +249,8 @@ polkit_subject_from_string (const gchar *str,
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "No process with pid %" G_GUINT64_FORMAT,
- val);
+ "Unable to determine start time for process with pid %d",
+ scanned_pid);
}
}
}
@@ -266,7 +268,7 @@ polkit_subject_from_string (const gchar *str,
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
- "Malformed subject string '%s'",
+ "Malformed subject string `%s'",
str);
}
More information about the hal-commit
mailing list