finish authentication agent integration
authorDavid Zeuthen <davidz@redhat.com>
Wed, 21 Jan 2009 05:27:13 +0000 (00:27 -0500)
committerDavid Zeuthen <davidz@redhat.com>
Wed, 21 Jan 2009 05:27:13 +0000 (00:27 -0500)
Yay, it works!

14 files changed:
data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml
data/org.freedesktop.PolicyKit1.Authority.xml
src/polkit/polkitauthority.c
src/polkit/polkitauthority.h
src/polkitagent/Makefile.am
src/polkitagent/polkitagentauthenticationagent.c
src/polkitagent/polkitagentauthenticationagent.h
src/polkitagent/polkitagentauthenticationsession.c
src/polkitagent/polkitagenthelper.c
src/polkitbackend/Makefile.am
src/polkitbackend/polkitbackendauthority.c
src/polkitbackend/polkitbackendauthority.h
src/polkitbackend/polkitbackendlocalauthority.c
src/polkitbackend/polkitbackendserver.c

index 1a2063c..cf0040b 100644 (file)
@@ -6,7 +6,6 @@
   <interface name="org.freedesktop.PolicyKit1.AuthenticationAgent">
 
     <method name="BeginAuthentication">
-
       <!-- The action id for the action that the user is authentication for -->
       <arg name="action_id" direction="in" type="s"/>
 
 
       <!-- A list of identities of that the user can use for authentication -->
       <arg name="identities" direction="in" type="a(sa{sv})"/>
-
     </method>
 
-    <method name="EndAuthentication">
-
+    <method name="CancelAuthentication">
       <arg name="cookie" direction="in" type="s"/>
-
     </method>
 
   </interface>
index c21fa84..4a15f74 100644 (file)
       </arg>
     </method>
 
+    <method name="AuthenticationAgentResponse">
+      <arg name="cookie" direction="in" type="s">
+        <annotation name="org.gtk.EggDBus.DocString" value="The cookie identifying the authentication request that was passed to the authentication agent"/>
+      </arg>
+
+      <arg name="identity" direction="in" type="(sa{sv})">
+        <annotation name="org.gtk.EggDBus.StructType" value="Identity"/>
+        <annotation name="org.gtk.EggDBus.DocString" value="The identity that was authenticated"/>
+      </arg>
+    </method>
+
   </interface>
 </node>
index 3d36c14..70324fe 100644 (file)
@@ -1046,3 +1046,107 @@ polkit_authority_unregister_authentication_agent_sync (PolkitAuthority     *auth
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+
+static guint
+polkit_authority_authentication_agent_response_async (PolkitAuthority      *authority,
+                                                      const gchar          *cookie,
+                                                      PolkitIdentity       *identity,
+                                                      GCancellable         *cancellable,
+                                                      GAsyncReadyCallback   callback,
+                                                      gpointer              user_data)
+{
+  guint call_id;
+  GSimpleAsyncResult *simple;
+  _PolkitIdentity *real_identity;
+
+  simple = g_simple_async_result_new (G_OBJECT (authority),
+                                      callback,
+                                      user_data,
+                                      polkit_authority_authentication_agent_response_async);
+
+  real_identity = polkit_identity_get_real (identity);
+
+  call_id = _polkit_authority_authentication_agent_response (authority->real,
+                                                             EGG_DBUS_CALL_FLAGS_NONE,
+                                                             cookie,
+                                                             real_identity,
+                                                             cancellable,
+                                                             generic_async_cb,
+                                                             simple);
+
+  g_object_unref (real_identity);
+
+  return call_id;
+}
+
+void
+polkit_authority_authentication_agent_response (PolkitAuthority      *authority,
+                                                const gchar          *cookie,
+                                                PolkitIdentity       *identity,
+                                                GCancellable         *cancellable,
+                                                GAsyncReadyCallback   callback,
+                                                gpointer              user_data)
+{
+  polkit_authority_authentication_agent_response_async (authority,
+                                                        cookie,
+                                                        identity,
+                                                        cancellable,
+                                                        callback,
+                                                        user_data);
+}
+
+gboolean
+polkit_authority_authentication_agent_response_finish (PolkitAuthority *authority,
+                                                       GAsyncResult    *res,
+                                                       GError         **error)
+{
+  GSimpleAsyncResult *simple;
+  GAsyncResult *real_res;
+  gboolean ret;
+
+  simple = G_SIMPLE_ASYNC_RESULT (res);
+  real_res = G_ASYNC_RESULT (g_simple_async_result_get_op_res_gpointer (simple));
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_authority_authentication_agent_response_async);
+
+  ret = _polkit_authority_authentication_agent_response_finish (authority->real,
+                                                                real_res,
+                                                                error);
+
+  if (!ret)
+    goto out;
+
+ out:
+  g_object_unref (real_res);
+  return ret;
+}
+
+
+gboolean
+polkit_authority_authentication_agent_response_sync (PolkitAuthority     *authority,
+                                                     const gchar         *cookie,
+                                                     PolkitIdentity      *identity,
+                                                     GCancellable        *cancellable,
+                                                     GError             **error)
+{
+  guint call_id;
+  GAsyncResult *res;
+  gboolean ret;
+
+  call_id = polkit_authority_authentication_agent_response_async (authority,
+                                                                  cookie,
+                                                                  identity,
+                                                                  cancellable,
+                                                                  generic_cb,
+                                                                  &res);
+
+  egg_dbus_connection_pending_call_block (authority->system_bus, call_id);
+
+  ret = polkit_authority_authentication_agent_response_finish (authority, res, error);
+
+  g_object_unref (res);
+
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
index e6ece8e..db1bb46 100644 (file)
@@ -93,6 +93,12 @@ gboolean                   polkit_authority_unregister_authentication_agent_sync
                                                                                   GCancellable        *cancellable,
                                                                                   GError             **error);
 
+gboolean                   polkit_authority_authentication_agent_response_sync (PolkitAuthority     *authority,
+                                                                                const gchar         *cookie,
+                                                                                PolkitIdentity      *identity,
+                                                                                GCancellable        *cancellable,
+                                                                                GError             **error);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 void                       polkit_authority_enumerate_actions (PolkitAuthority     *authority,
@@ -188,6 +194,17 @@ gboolean                   polkit_authority_unregister_authentication_agent_fini
                                                                                     GAsyncResult    *res,
                                                                                     GError         **error);
 
+void                       polkit_authority_authentication_agent_response (PolkitAuthority     *authority,
+                                                                           const gchar         *cookie,
+                                                                           PolkitIdentity      *identity,
+                                                                           GCancellable        *cancellable,
+                                                                           GAsyncReadyCallback  callback,
+                                                                           gpointer             user_data);
+
+gboolean                   polkit_authority_authentication_agent_response_finish (PolkitAuthority *authority,
+                                                                                  GAsyncResult    *res,
+                                                                                  GError         **error);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 G_END_DECLS
index d227661..b792f93 100644 (file)
@@ -65,7 +65,8 @@ libpolkit_agent_1_la_LIBADD =                                         \
 libexec_PROGRAMS = polkit-agent-helper-1
 
 polkit_agent_helper_1_SOURCES = polkitagenthelper.c
-polkit_agent_helper_1_LDADD = $(AUTH_LIBS)
+polkit_agent_helper_1_CFLAGS  = $(GLIB_CFLAGS)
+polkit_agent_helper_1_LDADD   = $(AUTH_LIBS) $(top_builddir)/src/polkit/libpolkit-gobject-1.la
 
 # polkit-agent-helper-1 need to be setuid root because it's used to
 # authenticate not only the invoking user, but possibly also root
index 844a32e..5014b37 100644 (file)
@@ -35,7 +35,7 @@ struct _PolkitAgentAuthenticationAgent
   PolkitAuthority *authority;
 
   PolkitAgentAuthenticationAgentBeginFunc begin_func;
-  PolkitAgentAuthenticationAgentEndFunc end_func;
+  PolkitAgentAuthenticationAgentCancelFunc cancel_func;
   gpointer user_data;
 };
 
@@ -100,7 +100,7 @@ polkit_agent_authentication_agent_class_init (PolkitAgentAuthenticationAgentClas
 
 PolkitAgentAuthenticationAgent *
 polkit_agent_authentication_agent_new (PolkitAgentAuthenticationAgentBeginFunc begin_func,
-                                       PolkitAgentAuthenticationAgentEndFunc end_func,
+                                       PolkitAgentAuthenticationAgentCancelFunc cancel_func,
                                        gpointer user_data,
                                        GError **error)
 {
@@ -109,7 +109,7 @@ polkit_agent_authentication_agent_new (PolkitAgentAuthenticationAgentBeginFunc b
   agent = POLKIT_AGENT_AUTHENTICATION_AGENT (g_object_new (POLKIT_AGENT_TYPE_AUTHENTICATION_AGENT, NULL));
 
   agent->begin_func = begin_func;
-  agent->end_func = end_func;
+  agent->cancel_func = cancel_func;
   agent->user_data = user_data;
 
   if (!polkit_authority_register_authentication_agent_sync (agent->authority,
@@ -147,41 +147,51 @@ handle_begin_authentication (_PolkitAgentAuthenticationAgent *instance,
   list = g_list_reverse (list);
 
   error = NULL;
-  if (!agent->begin_func (agent,
-                          action_id,
-                          cookie,
-                          list,
-                          &error,
-                          agent->user_data))
+
+  agent->begin_func (agent,
+                     action_id,
+                     cookie,
+                     list,
+                     (gpointer) method_invocation);
+
+  g_list_free (list);
+}
+
+void
+polkit_agent_authentication_agent_finish (PolkitAgentAuthenticationAgent *agent,
+                                          gpointer                        pending_call,
+                                          GError                         *error)
+{
+  EggDBusMethodInvocation *method_invocation = EGG_DBUS_METHOD_INVOCATION (pending_call);
+
+  if (error != NULL)
     {
       egg_dbus_method_invocation_return_gerror (method_invocation, error);
-      g_error_free (error);
     }
   else
     {
       _polkit_agent_authentication_agent_handle_begin_authentication_finish (method_invocation);
     }
-
-  g_list_free (list);
 }
 
+
 static void
-handle_end_authentication (_PolkitAgentAuthenticationAgent *instance,
-                           const gchar *cookie,
-                           EggDBusMethodInvocation *method_invocation)
+handle_cancel_authentication (_PolkitAgentAuthenticationAgent *instance,
+                              const gchar *cookie,
+                              EggDBusMethodInvocation *method_invocation)
 {
   PolkitAgentAuthenticationAgent *agent = POLKIT_AGENT_AUTHENTICATION_AGENT (instance);
 
-  agent->end_func (agent,
-                   cookie,
-                   agent->user_data);
+  agent->cancel_func (agent,
+                      cookie,
+                      agent->user_data);
 
-  _polkit_agent_authentication_agent_handle_end_authentication_finish (method_invocation);
+  _polkit_agent_authentication_agent_handle_cancel_authentication_finish (method_invocation);
 }
 
 static void
 authentication_agent_iface_init (_PolkitAgentAuthenticationAgentIface *agent_iface)
 {
   agent_iface->handle_begin_authentication = handle_begin_authentication;
-  agent_iface->handle_end_authentication = handle_end_authentication;
+  agent_iface->handle_cancel_authentication = handle_cancel_authentication;
 }
index 9d315ff..96d009b 100644 (file)
@@ -19,8 +19,8 @@
  * Author: David Zeuthen <davidz@redhat.com>
  */
 
-#ifndef __POLKIT_AGENT_AUTHENTICATION_SESSION_H
-#define __POLKIT_AGENT_AUTHENTICATION_SESSION_H
+#ifndef __POLKIT_AGENT_AUTHENTICATION_AGENT_H
+#define __POLKIT_AGENT_AUTHENTICATION_AGENT_H
 
 #include <polkit/polkit.h>
 #include <polkitagent/polkitagenttypes.h>
@@ -41,25 +41,29 @@ typedef struct _PolkitAgentAuthenticationAgentClass    PolkitAgentAuthentication
 
 /* TODO: we probably want to express this interface in another way but this is good enough for now */
 
-typedef gboolean (*PolkitAgentAuthenticationAgentBeginFunc) (PolkitAgentAuthenticationAgent *agent,
-                                                             const gchar                    *action_id,
-                                                             const gchar                    *cookie,
-                                                             GList                          *identities,
-                                                             GError                        **error,
-                                                             gpointer                        user_data);
-
-typedef void (*PolkitAgentAuthenticationAgentEndFunc)   (PolkitAgentAuthenticationAgent *agent,
+typedef void (*PolkitAgentAuthenticationAgentBeginFunc) (PolkitAgentAuthenticationAgent *agent,
+                                                         const gchar                    *action_id,
                                                          const gchar                    *cookie,
-                                                         gpointer                        user_data);
+                                                         GList                          *identities,
+                                                         gpointer                        pending_call);
+
+typedef void (*PolkitAgentAuthenticationAgentCancelFunc)   (PolkitAgentAuthenticationAgent *agent,
+                                                            const gchar                    *cookie,
+                                                            gpointer                        user_data);
 
 GType                           polkit_agent_authentication_agent_get_type (void) G_GNUC_CONST;
+
 PolkitAgentAuthenticationAgent *polkit_agent_authentication_agent_new (PolkitAgentAuthenticationAgentBeginFunc begin_func,
-                                                                       PolkitAgentAuthenticationAgentEndFunc end_func,
+                                                                       PolkitAgentAuthenticationAgentCancelFunc cancel_func,
                                                                        gpointer user_data,
                                                                        GError **error);
 
+void                            polkit_agent_authentication_agent_finish (PolkitAgentAuthenticationAgent *agent,
+                                                                          gpointer                        pending_call,
+                                                                          GError                         *error);
+
 /* --- */
 
 G_END_DECLS
 
-#endif /* __POLKIT_AGENT_AUTHENTICATION_SESSION_H */
+#endif /* __POLKIT_AGENT_AUTHENTICATION_AGENT_H */
index 2c6bc65..993313c 100644 (file)
@@ -286,7 +286,7 @@ polkit_agent_authentication_session_initiate_auth (PolkitAgentAuthenticationSess
       goto error;
     }
 
-  helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-session-helper-1";
+  helper_argv[0] = PACKAGE_LIBEXEC_DIR "/polkit-agent-helper-1";
   helper_argv[1] = passwd->pw_name;
   helper_argv[2] = session->cookie;
   helper_argv[3] = NULL;
index df59f18..d5844e5 100644 (file)
@@ -29,6 +29,8 @@
 #include <syslog.h>
 #include <security/pam_appl.h>
 
+#include <polkit/polkit.h>
+
 #ifdef HAVE_SOLARIS
 #  define LOG_AUTHPRIV    (10<<3)
 #endif
@@ -38,7 +40,9 @@
  * sensitive information.
  */
 #undef PAH_DEBUG
-#define PAH_DEBUG
+//#define PAH_DEBUG
+
+static gboolean send_dbus_message (const char *cookie, const char *user);
 
 static int conversation_function (int n, const struct pam_message **msg, struct pam_response **resp, void *data);
 
@@ -154,9 +158,11 @@ main (int argc, char *argv[])
   fprintf (stderr, "polkit-agent-helper-1: successfully authenticated user '%s'.\n", user_to_auth);
 #endif /* PAH_DEBUG */
 
-  /* TODO: now send a D-Bus message to the PolicyKit daemon that
-   *       includes a) the cookie; and b) the user we authenticated
+  /* now send a D-Bus message to the PolicyKit daemon that
+   * includes a) the cookie; and b) the user we authenticated
    */
+  if (!send_dbus_message (cookie, user_to_auth))
+    goto error;
 
   fprintf (stdout, "SUCCESS\n");
   fflush (stdout);
@@ -253,3 +259,51 @@ error:
   *resp = NULL;
   return PAM_CONV_ERR;
 }
+
+static gboolean
+send_dbus_message (const char *cookie, const char *user)
+{
+  PolkitAuthority *authority;
+  PolkitIdentity *identity;
+  GError *error;
+  gboolean ret;
+
+  ret = FALSE;
+
+  error = NULL;
+
+  g_type_init ();
+
+  authority = polkit_authority_get ();
+
+  identity = polkit_unix_user_new_for_name (user, &error);
+  if (identity == NULL)
+    {
+      g_printerr ("Error constructing identity: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  if (!polkit_authority_authentication_agent_response_sync (authority,
+                                                            cookie,
+                                                            identity,
+                                                            NULL,
+                                                            &error))
+    {
+      g_printerr ("Error sending response to PolicyKit daemon: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  ret = TRUE;
+
+ out:
+
+  if (identity != NULL)
+    g_object_unref (identity);
+
+  if (authority != NULL)
+    g_object_unref (authority);
+
+  return ret;
+}
index 5b6d7ea..da6f2a3 100644 (file)
@@ -15,23 +15,33 @@ INCLUDES =                                                      \
        -DEGG_DBUS_I_KNOW_API_IS_SUBJECT_TO_CHANGE              \
         $(NULL)
 
-BUILT_SOURCES =                                                                                \
-       ckmanager.c                             ckmanager.h                             \
-       cksession.c                             cksession.h                             \
-       ckseat.c                                ckseat.h                                \
-       ckdevice.c                              ckdevice.h                              \
-       ckbindings.c                            ckbindings.h                            \
-       ckbindingsmarshal.list                                                          \
-       ckbindingsmarshal.c                     ckbindingsmarshal.h                     \
-       ckbindingstypes.h                                                               \
-       ckerror.c                               ckerror.h                               \
+BUILT_SOURCES =                                                                                        \
+       ckmanager.c                                     ckmanager.h                             \
+       cksession.c                                     cksession.h                             \
+       ckseat.c                                        ckseat.h                                \
+       ckdevice.c                                      ckdevice.h                              \
+       ckbindings.c                                    ckbindings.h                            \
+       ckbindingsmarshal.list                                                                  \
+       ckbindingsmarshal.c                             ckbindingsmarshal.h                     \
+       ckbindingstypes.h                                                                       \
+       ckerror.c                                       ckerror.h                               \
+       _polkitagentauthenticationagent.c               _polkitagentauthenticationagent.h       \
+       _polkitagentbindings.c                          _polkitagentbindings.h                  \
+       _polkitagentbindingsmarshal.list                                                        \
+       _polkitagentbindingsmarshal.c                   _polkitagentbindingsmarshal.h           \
+       _polkitagentbindingstypes.h                                                             \
        $(NULL)
 
-$(BUILT_SOURCES) : Makefile.am $(top_srcdir)/src/polkitbackend/org.freedesktop.ConsoleKit.xml
-       eggdbus-binding-tool                                                                    \
-         --namespace       "Ck"                                                                \
-         --dbus-namespace  "org.freedesktop.ConsoleKit"                                        \
-         --introspection-xml $(top_srcdir)/src/polkitbackend/org.freedesktop.ConsoleKit.xml    \
+$(BUILT_SOURCES) : Makefile.am $(top_srcdir)/src/polkitbackend/org.freedesktop.ConsoleKit.xml $(top_srcdir)/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml
+       eggdbus-binding-tool                                                                            \
+         --namespace       "Ck"                                                                        \
+         --dbus-namespace  "org.freedesktop.ConsoleKit"                                                \
+         --introspection-xml $(top_srcdir)/src/polkitbackend/org.freedesktop.ConsoleKit.xml            \
+         $(NULL)
+       eggdbus-binding-tool                                                                            \
+         --namespace       "_PolkitAgent"                                                              \
+         --dbus-namespace  "org.freedesktop.PolicyKit1"                                                \
+         --introspection-xml $(top_srcdir)/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml     \
          $(NULL)
 
 lib_LTLIBRARIES=libpolkit-backend-1.la
index 399b4c7..5f06e10 100644 (file)
@@ -161,3 +161,16 @@ polkit_backend_authority_unregister_authentication_agent (PolkitBackendAuthority
   klass->unregister_authentication_agent (authority, object_path, pending_call);
 }
 
+void
+polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority    *authority,
+                                                        const gchar               *cookie,
+                                                        PolkitIdentity            *identity,
+                                                        PolkitBackendPendingCall  *pending_call)
+{
+  PolkitBackendAuthorityClass *klass;
+
+  klass = POLKIT_BACKEND_AUTHORITY_GET_CLASS (authority);
+
+  klass->authentication_agent_response (authority, cookie, identity, pending_call);
+}
+
index a35ad7e..06f54fa 100644 (file)
@@ -95,6 +95,11 @@ struct _PolkitBackendAuthorityClass
                                            const gchar              *object_path,
                                            PolkitBackendPendingCall *pending_call);
 
+  void (*authentication_agent_response) (PolkitBackendAuthority   *authority,
+                                         const gchar              *cookie,
+                                         PolkitIdentity           *identity,
+                                         PolkitBackendPendingCall *pending_call);
+
   /*< private >*/
   /* Padding for future expansion */
   void (*_polkit_reserved1) (void);
@@ -154,6 +159,11 @@ void     polkit_backend_authority_unregister_authentication_agent (PolkitBackend
                                                                    const gchar               *object_path,
                                                                    PolkitBackendPendingCall  *pending_call);
 
+void     polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority    *authority,
+                                                                 const gchar               *cookie,
+                                                                 PolkitIdentity            *identity,
+                                                                 PolkitBackendPendingCall  *pending_call);
+
 /* --- */
 
 void     polkit_backend_authority_enumerate_actions_finish        (PolkitBackendPendingCall  *pending_call,
@@ -176,8 +186,11 @@ void     polkit_backend_authority_add_authorization_finish        (PolkitBackend
 void     polkit_backend_authority_remove_authorization_finish     (PolkitBackendPendingCall  *pending_call);
 
 void     polkit_backend_authority_register_authentication_agent_finish   (PolkitBackendPendingCall  *pending_call);
+
 void     polkit_backend_authority_unregister_authentication_agent_finish (PolkitBackendPendingCall  *pending_call);
 
+void     polkit_backend_authority_authentication_agent_response_finish (PolkitBackendPendingCall  *pending_call);
+
 
 G_END_DECLS
 
index d97da1d..3cb6c46 100644 (file)
 #include "polkitbackendpendingcall.h"
 #include "polkitbackendsessionmonitor.h"
 
+#include "_polkitagentbindings.h"
+#include <polkit/polkitprivate.h>
+
+
 typedef struct
 {
   PolkitBackendActionPool *action_pool;
@@ -59,8 +63,13 @@ static AuthorizationStore *get_authorization_store_for_identity (PolkitBackendLo
 struct AuthenticationAgent;
 typedef struct AuthenticationAgent AuthenticationAgent;
 
+struct AuthenticationSession;
+typedef struct AuthenticationSession AuthenticationSession;
+
 typedef void (*AuthenticationAgentCallback) (AuthenticationAgent         *agent,
                                              PolkitSubject               *subject,
+                                             PolkitIdentity              *user_of_subject,
+                                             PolkitBackendLocalAuthority *authority,
                                              const gchar                 *action_id,
                                              PolkitImplicitAuthorization  implicit_authorization,
                                              gboolean                     authentication_success,
@@ -70,7 +79,10 @@ static void                authentication_agent_free (AuthenticationAgent *agent
 
 static void                authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
                                                                     PolkitSubject               *subject,
+                                                                    PolkitIdentity              *user_of_subject,
+                                                                    PolkitBackendLocalAuthority *authority,
                                                                     const gchar                 *action_id,
+                                                                    PolkitSubject               *caller,
                                                                     PolkitImplicitAuthorization  implicit_authorization,
                                                                     AuthenticationAgentCallback  callback,
                                                                     gpointer                     user_data);
@@ -78,6 +90,14 @@ static void                authentication_agent_initiate_challenge (Authenticati
 static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendLocalAuthority *authority,
                                                                   PolkitSubject *subject);
 
+static AuthenticationSession *get_authentication_session_for_cookie (PolkitBackendLocalAuthority *authority,
+                                                                     const gchar *cookie);
+
+static GList *get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendLocalAuthority *authority,
+                                                                               const gchar *system_bus_unique_name);
+
+static void authentication_session_cancel (AuthenticationSession *session);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean check_authorization_for_identity (PolkitBackendLocalAuthority *authority,
@@ -157,6 +177,11 @@ static void polkit_backend_local_authority_unregister_authentication_agent (Polk
                                                                             const gchar              *object_path,
                                                                             PolkitBackendPendingCall *pending_call);
 
+static void polkit_backend_local_authority_authentication_agent_response (PolkitBackendAuthority   *authority,
+                                                                          const gchar              *cookie,
+                                                                          PolkitIdentity           *identity,
+                                                                          PolkitBackendPendingCall *pending_call);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 G_DEFINE_TYPE (PolkitBackendLocalAuthority, polkit_backend_local_authority, POLKIT_BACKEND_TYPE_AUTHORITY);
@@ -231,6 +256,8 @@ polkit_backend_local_authority_class_init (PolkitBackendLocalAuthorityClass *kla
   authority_class->remove_authorization            = polkit_backend_local_authority_remove_authorization;
   authority_class->register_authentication_agent   = polkit_backend_local_authority_register_authentication_agent;
   authority_class->unregister_authentication_agent = polkit_backend_local_authority_unregister_authentication_agent;
+  authority_class->authentication_agent_response   = polkit_backend_local_authority_authentication_agent_response;
+
 
   g_type_class_add_private (klass, sizeof (PolkitBackendLocalAuthorityPrivate));
 }
@@ -359,6 +386,8 @@ polkit_backend_local_authority_enumerate_groups (PolkitBackendAuthority   *autho
 static void
 check_authorization_challenge_cb (AuthenticationAgent         *agent,
                                   PolkitSubject               *subject,
+                                  PolkitIdentity              *user_of_subject,
+                                  PolkitBackendLocalAuthority *authority,
                                   const gchar                 *action_id,
                                   PolkitImplicitAuthorization  implicit_authorization,
                                   gboolean                     authentication_success,
@@ -382,7 +411,30 @@ check_authorization_challenge_cb (AuthenticationAgent         *agent,
     {
       result = POLKIT_AUTHORIZATION_RESULT_AUTHORIZED;
 
-      /* TODO: store temporary authorization depending on value of implicit_authorization */
+      /* store temporary authorization depending on value of implicit_authorization */
+      if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED ||
+          implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_ADMINISTRATOR_AUTHENTICATION_REQUIRED_RETAINED)
+        {
+          GError *error;
+          PolkitAuthorization *authorization;
+
+          authorization = polkit_authorization_new (action_id,
+                                                    subject,
+                                                    FALSE);
+
+          if (!add_authorization_for_identity (authority,
+                                               user_of_subject,
+                                               authorization,
+                                               &error))
+            {
+              g_warning ("Error adding temporary authorization gained from authentication: %s",
+                         error->message);
+
+              g_error_free (error);
+            }
+
+          g_object_unref (authorization);
+        }
     }
   else
     {
@@ -529,7 +581,10 @@ polkit_backend_local_authority_check_authorization (PolkitBackendAuthority
 
           authentication_agent_initiate_challenge (agent,
                                                    subject,
+                                                   user_of_subject,
+                                                   local_authority,
                                                    action_id,
+                                                   inquirer,
                                                    implicit_authorization,
                                                    check_authorization_challenge_cb,
                                                    pending_call);
@@ -891,11 +946,120 @@ struct AuthenticationAgent
 
   gchar *object_path;
   gchar *unique_system_bus_name;
+
+  EggDBusObjectProxy *object_proxy;
+
+  GList *active_sessions;
+};
+
+struct AuthenticationSession
+{
+  AuthenticationAgent         *agent;
+
+  gchar                       *cookie;
+
+  PolkitSubject               *subject;
+
+  PolkitIdentity              *user_of_subject;
+
+  PolkitBackendLocalAuthority *authority;
+
+  GList                       *identities;
+
+  gchar                       *action_id;
+
+  gchar                       *initiated_by_system_bus_unique_name;
+
+  PolkitImplicitAuthorization  implicit_authorization;
+
+  AuthenticationAgentCallback  callback;
+
+  gpointer                     user_data;
+
+  guint                        call_id;
+
+  gboolean                     is_authenticated;
 };
 
+static AuthenticationSession *
+authentication_session_new (AuthenticationAgent         *agent,
+                            const gchar                 *cookie,
+                            PolkitSubject               *subject,
+                            PolkitIdentity              *user_of_subject,
+                            PolkitBackendLocalAuthority *authority,
+                            GList                       *identities,
+                            const gchar                 *action_id,
+                            const gchar                 *initiated_by_system_bus_unique_name,
+                            PolkitImplicitAuthorization  implicit_authorization,
+                            AuthenticationAgentCallback  callback,
+                            gpointer                     user_data)
+{
+  AuthenticationSession *session;
+
+  session = g_new0 (AuthenticationSession, 1);
+  session->agent = agent;
+  session->cookie = g_strdup (cookie);
+  session->subject = g_object_ref (subject);
+  session->user_of_subject = g_object_ref (user_of_subject);
+  session->authority = g_object_ref (authority);
+  session->identities = g_list_copy (identities);
+  g_list_foreach (session->identities, (GFunc) g_object_ref, NULL);
+  session->action_id = g_strdup (action_id);
+  session->initiated_by_system_bus_unique_name = g_strdup (initiated_by_system_bus_unique_name);
+  session->implicit_authorization = implicit_authorization;
+  session->callback = callback;
+  session->user_data = user_data;
+
+  return session;
+}
+
+static void
+authentication_session_free (AuthenticationSession *session)
+{
+  g_free (session->cookie);
+  g_list_foreach (session->identities, (GFunc) g_object_unref, NULL);
+  g_list_free (session->identities);
+  g_object_unref (session->subject);
+  g_object_unref (session->user_of_subject);
+  g_object_unref (session->authority);
+  g_free (session->action_id);
+  g_free (session->initiated_by_system_bus_unique_name);
+  g_free (session);
+}
+
+static gchar *
+authentication_agent_new_cookie (AuthenticationAgent *agent)
+{
+  static gint counter = 0;
+
+  /* TODO: use a more random-looking cookie */
+
+  return g_strdup_printf ("cookie%d", counter++);
+}
+
 static void
 authentication_agent_free (AuthenticationAgent *agent)
 {
+  /* cancel all active authentication sessions; use a copy of the list since
+   * callbacks will modify the list
+   */
+  if (agent->active_sessions != NULL)
+    {
+      GList *l;
+      GList *active_sessions;
+
+      active_sessions = g_list_copy (agent->active_sessions);
+      for (l = active_sessions; l != NULL; l = l->next)
+        {
+          AuthenticationSession *session = l->data;
+
+          authentication_session_cancel (session);
+        }
+      g_list_free (active_sessions);
+    }
+
+  g_object_unref (agent->object_proxy);
+
   g_object_unref (agent->session);
   g_free (agent->object_path);
   g_free (agent->unique_system_bus_name);
@@ -908,6 +1072,7 @@ authentication_agent_new (PolkitSubject *session,
                           const gchar *object_path)
 {
   AuthenticationAgent *agent;
+  EggDBusConnection *system_bus;
 
   agent = g_new0 (AuthenticationAgent, 1);
 
@@ -915,6 +1080,14 @@ authentication_agent_new (PolkitSubject *session,
   agent->object_path = g_strdup (object_path);
   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
 
+  system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM);
+
+  agent->object_proxy = egg_dbus_connection_get_object_proxy (system_bus,
+                                                              agent->unique_system_bus_name,
+                                                              agent->object_path);
+
+  g_object_unref (system_bus);
+
   return agent;
 }
 
@@ -946,6 +1119,77 @@ get_authentication_agent_for_subject (PolkitBackendLocalAuthority *authority,
   return agent;
 }
 
+static AuthenticationSession *
+get_authentication_session_for_cookie (PolkitBackendLocalAuthority *authority,
+                                       const gchar *cookie)
+{
+  PolkitBackendLocalAuthorityPrivate *priv;
+  GHashTableIter hash_iter;
+  AuthenticationAgent *agent;
+  AuthenticationSession *result;
+
+  result = NULL;
+
+  /* TODO: perhaps use a hash on the cookie to speed this up */
+
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+  g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+  while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
+    {
+      GList *l;
+
+      for (l = agent->active_sessions; l != NULL; l = l->next)
+        {
+          AuthenticationSession *session = l->data;
+
+          if (strcmp (session->cookie, cookie) == 0)
+            {
+              result = session;
+              goto out;
+            }
+        }
+    }
+
+ out:
+  return result;
+}
+
+static GList *
+get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendLocalAuthority *authority,
+                                                                 const gchar *system_bus_unique_name)
+{
+  PolkitBackendLocalAuthorityPrivate *priv;
+  GHashTableIter hash_iter;
+  AuthenticationAgent *agent;
+  GList *result;
+
+  result = NULL;
+
+  /* TODO: perhaps use a hash on the cookie to speed this up */
+
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+  g_hash_table_iter_init (&hash_iter, priv->hash_session_to_authentication_agent);
+  while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &agent))
+    {
+      GList *l;
+
+      for (l = agent->active_sessions; l != NULL; l = l->next)
+        {
+          AuthenticationSession *session = l->data;
+
+          if (strcmp (session->initiated_by_system_bus_unique_name, system_bus_unique_name) == 0)
+            {
+              result = g_list_prepend (result, session);
+            }
+        }
+    }
+
+   return result;
+}
+
+
 static AuthenticationAgent *
 get_authentication_agent_by_unique_system_bus_name (PolkitBackendLocalAuthority *authority,
                                                     const gchar *unique_system_bus_name)
@@ -970,21 +1214,139 @@ get_authentication_agent_by_unique_system_bus_name (PolkitBackendLocalAuthority
 }
 
 static void
+authentication_agent_begin_callback (GObject *source_object,
+                                     GAsyncResult *res,
+                                     gpointer user_data)
+{
+  _PolkitAgentAuthenticationAgent *agent_dbus = _POLKIT_AGENT_AUTHENTICATION_AGENT (source_object);
+  AuthenticationSession *session = user_data;
+  GError *error;
+  gboolean gained_authorization;
+
+  error = NULL;
+  if (!_polkit_agent_authentication_agent_begin_authentication_finish (agent_dbus,
+                                                                       res,
+                                                                       &error))
+    {
+      g_warning ("Error performing authentication: %s", error->message);
+      g_error_free (error);
+
+      gained_authorization = FALSE;
+    }
+  else
+    {
+      gained_authorization = session->is_authenticated;
+
+      g_debug ("Authentication complete, is_authenticated = %d", session->is_authenticated);
+    }
+
+  session->agent->active_sessions = g_list_remove (session->agent->active_sessions, session);
+
+  session->callback (session->agent,
+                     session->subject,
+                     session->user_of_subject,
+                     session->authority,
+                     session->action_id,
+                     session->implicit_authorization,
+                     gained_authorization,
+                     session->user_data);
+
+  authentication_session_free (session);
+}
+
+static void
 authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
                                          PolkitSubject               *subject,
+                                         PolkitIdentity              *user_of_subject,
+                                         PolkitBackendLocalAuthority *authority,
                                          const gchar                 *action_id,
+                                         PolkitSubject               *caller,
                                          PolkitImplicitAuthorization  implicit_authorization,
                                          AuthenticationAgentCallback  callback,
                                          gpointer                     user_data)
 {
-  /* TODO */
-
-  callback (agent,
-            subject,
-            action_id,
-            implicit_authorization,
-            FALSE,
-            user_data);
+  AuthenticationSession *session;
+  _PolkitAgentAuthenticationAgent *agent_dbus;
+  gchar *cookie;
+  GList *l;
+  GList *identities;
+  EggDBusArraySeq *real_identities;
+
+  cookie = authentication_agent_new_cookie (agent);
+
+  /* TODO: add uid 0 OR users in wheel group depending on value of @implicit_authorization */
+  identities = g_list_prepend (NULL, g_object_ref (user_of_subject));
+
+  session = authentication_session_new (agent,
+                                        cookie,
+                                        subject,
+                                        user_of_subject,
+                                        authority,
+                                        identities,
+                                        action_id,
+                                        polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
+                                        implicit_authorization,
+                                        callback,
+                                        user_data);
+
+  agent->active_sessions = g_list_prepend (agent->active_sessions, session);
+
+  agent_dbus = _POLKIT_AGENT_QUERY_INTERFACE_AUTHENTICATION_AGENT (agent->object_proxy);
+
+  real_identities = egg_dbus_array_seq_new (EGG_DBUS_TYPE_STRUCTURE, g_object_unref, NULL, NULL);
+  for (l = identities; l != NULL; l = l->next)
+    {
+      PolkitIdentity *identity = POLKIT_IDENTITY (l->data);
+      egg_dbus_array_seq_add (real_identities, polkit_identity_get_real (identity));
+    }
+
+  session->call_id = _polkit_agent_authentication_agent_begin_authentication (agent_dbus,
+                                                                              EGG_DBUS_CALL_FLAGS_NONE,
+                                                                              action_id,
+                                                                              session->cookie,
+                                                                              real_identities,
+                                                                              NULL,
+                                                                              authentication_agent_begin_callback,
+                                                                              session);
+
+  g_list_foreach (identities, (GFunc) g_object_unref, NULL);
+  g_list_free (identities);
+  g_object_unref (real_identities);
+  g_free (cookie);
+}
+
+static void
+authentication_agent_cancel_callback (GObject *source_object,
+                                      GAsyncResult *res,
+                                      gpointer user_data)
+{
+  _PolkitAgentAuthenticationAgent *agent_dbus = _POLKIT_AGENT_AUTHENTICATION_AGENT (source_object);
+
+  _polkit_agent_authentication_agent_cancel_authentication_finish (agent_dbus,
+                                                                   res,
+                                                                   NULL);
+}
+
+static void
+authentication_session_cancel (AuthenticationSession *session)
+{
+  EggDBusConnection *system_bus;
+  _PolkitAgentAuthenticationAgent *agent_dbus;
+
+  system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM);
+
+  agent_dbus = _POLKIT_AGENT_QUERY_INTERFACE_AUTHENTICATION_AGENT (session->agent->object_proxy);
+
+  _polkit_agent_authentication_agent_cancel_authentication (agent_dbus,
+                                                            EGG_DBUS_CALL_FLAGS_NONE,
+                                                            session->cookie,
+                                                            NULL,
+                                                            authentication_agent_cancel_callback,
+                                                            NULL);
+
+  egg_dbus_connection_pending_call_cancel (system_bus, session->call_id);
+
+  g_object_unref (system_bus);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -1127,6 +1489,97 @@ polkit_backend_local_authority_unregister_authentication_agent (PolkitBackendAut
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
+polkit_backend_local_authority_authentication_agent_response (PolkitBackendAuthority   *authority,
+                                                              const gchar              *cookie,
+                                                              PolkitIdentity           *identity,
+                                                              PolkitBackendPendingCall *pending_call)
+{
+  PolkitBackendLocalAuthority *local_authority;
+  PolkitBackendLocalAuthorityPrivate *priv;
+  PolkitSubject *caller;
+  PolkitIdentity *user_of_caller;
+  gchar *identity_str;
+  GError *error;
+  AuthenticationSession *session;
+  GList *l;
+
+  local_authority = POLKIT_BACKEND_LOCAL_AUTHORITY (authority);
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (local_authority);
+
+  error = NULL;
+  user_of_caller = NULL;
+
+  identity_str = polkit_identity_to_string (identity);
+
+  g_debug ("In authentication_agent_response for cookie '%s' and identity %s",
+           cookie,
+           identity_str);
+
+  caller = polkit_backend_pending_call_get_caller (pending_call);
+
+  user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
+                                                                        caller,
+                                                                        &error);
+  if (error != NULL)
+    {
+      polkit_backend_pending_call_return_gerror (pending_call, error);
+      g_error_free (error);
+      goto out;
+    }
+
+  /* only uid 0 is allowed to invoke this method */
+  if (!POLKIT_IS_UNIX_USER (user_of_caller) || polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0)
+    {
+      polkit_backend_pending_call_return_error (pending_call,
+                                                POLKIT_ERROR,
+                                                POLKIT_ERROR_FAILED,
+                                                "Only uid 0 may invoke this method. This incident has been logged.");
+      goto out;
+    }
+
+  /* find the authentication session */
+  session = get_authentication_session_for_cookie (local_authority, cookie);
+  if (session == NULL)
+    {
+      polkit_backend_pending_call_return_error (pending_call,
+                                                POLKIT_ERROR,
+                                                POLKIT_ERROR_FAILED,
+                                                "No session for cookie");
+      goto out;
+    }
+
+  /* check that the authentication identity was one of the possibilities we allowed */
+  for (l = session->identities; l != NULL; l = l->next)
+    {
+      PolkitIdentity *i = POLKIT_IDENTITY (l->data);
+
+      if (polkit_identity_equal (i, identity))
+        break;
+    }
+  if (l == NULL)
+    {
+      polkit_backend_pending_call_return_error (pending_call,
+                                                POLKIT_ERROR,
+                                                POLKIT_ERROR_FAILED,
+                                                "The authenticated identity is wrong");
+      goto out;
+    }
+
+  /* checks out, mark the session as authenticated */
+  session->is_authenticated = TRUE;
+
+  polkit_backend_authority_authentication_agent_response_finish (pending_call);
+
+ out:
+  g_free (identity_str);
+
+  if (user_of_caller != NULL)
+    g_object_unref (user_of_caller);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
 polkit_backend_local_authority_system_bus_name_owner_changed (PolkitBackendAuthority   *authority,
                                                               const gchar              *name,
                                                               const gchar              *old_owner,
@@ -1134,15 +1587,18 @@ polkit_backend_local_authority_system_bus_name_owner_changed (PolkitBackendAutho
 {
   PolkitBackendLocalAuthority *local_authority;
   PolkitBackendLocalAuthorityPrivate *priv;
-  AuthenticationAgent *agent;
 
   local_authority = POLKIT_BACKEND_LOCAL_AUTHORITY (authority);
   priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (local_authority);
 
-  //g_debug ("name-owner-changed: '%s' '%s' '%s'", name, old_owner, new_owner);
+  g_debug ("name-owner-changed: '%s' '%s' '%s'", name, old_owner, new_owner);
 
   if (name[0] == ':' && strlen (new_owner) == 0)
     {
+      AuthenticationAgent *agent;
+      GList *sessions;
+      GList *l;
+
       agent = get_authentication_agent_by_unique_system_bus_name (local_authority, name);
       if (agent != NULL)
         {
@@ -1154,6 +1610,15 @@ polkit_backend_local_authority_system_bus_name_owner_changed (PolkitBackendAutho
           /* this works because we have exactly one agent per session */
           g_hash_table_remove (priv->hash_session_to_authentication_agent, agent->session);
         }
+
+      sessions = get_authentication_sessions_initiated_by_system_bus_unique_name (local_authority, name);
+      for (l = sessions; l != NULL; l = l->next)
+        {
+          AuthenticationSession *session = l->data;
+
+          authentication_session_cancel (session);
+        }
+      g_list_free (sessions);
     }
 
 }
index 2414bde..d89cb37 100644 (file)
@@ -473,6 +473,37 @@ polkit_backend_authority_unregister_authentication_agent_finish (PolkitBackendPe
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
+authority_handle_authentication_agent_response (_PolkitAuthority               *instance,
+                                                const gchar                    *cookie,
+                                                _PolkitIdentity                *real_identity,
+                                                EggDBusMethodInvocation        *method_invocation)
+{
+  PolkitBackendServer *server = POLKIT_BACKEND_SERVER (instance);
+  PolkitBackendPendingCall *pending_call;
+  PolkitIdentity *identity;
+
+  pending_call = _polkit_backend_pending_call_new (method_invocation, server);
+
+  identity = polkit_identity_new_for_real (real_identity);
+
+  g_object_set_data_full (G_OBJECT (pending_call), "identity", identity, (GDestroyNotify) g_object_unref);
+
+  polkit_backend_authority_authentication_agent_response (server->authority,
+                                                          cookie,
+                                                          identity,
+                                                          pending_call);
+}
+
+void
+polkit_backend_authority_authentication_agent_response_finish (PolkitBackendPendingCall  *pending_call)
+{
+  _polkit_authority_handle_authentication_agent_response_finish (_polkit_backend_pending_call_get_method_invocation (pending_call));
+  g_object_unref (pending_call);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
 authority_iface_init (_PolkitAuthorityIface *authority_iface)
 {
   authority_iface->handle_enumerate_actions               = authority_handle_enumerate_actions;
@@ -484,4 +515,5 @@ authority_iface_init (_PolkitAuthorityIface *authority_iface)
   authority_iface->handle_remove_authorization            = authority_handle_remove_authorization;
   authority_iface->handle_register_authentication_agent   = authority_handle_register_authentication_agent;
   authority_iface->handle_unregister_authentication_agent = authority_handle_unregister_authentication_agent;
+  authority_iface->handle_authentication_agent_response   = authority_handle_authentication_agent_response;
 }