Commit 84a83a87 authored by David Zeuthen's avatar David Zeuthen

Move authentication agent bits to separate authority subclass

parent 20d1288f
......@@ -90,6 +90,7 @@
<part id="ref-backend-api">
<title>Backend API Reference</title>
<xi:include href="xml/polkitbackendauthority.xml"/>
<xi:include href="xml/polkitbackendinteractiveauthority.xml"/>
<xi:include href="xml/polkitbackendlocalauthority.xml"/>
<xi:include href="xml/polkitbackendactionpool.xml"/>
<xi:include href="xml/polkitbackendsessionmonitor.xml"/>
......
......@@ -291,7 +291,6 @@ POLKIT_BACKEND_ACTION_LOOKUP_GET_IFACE
<TITLE>PolkitBackendLocalAuthority</TITLE>
PolkitBackendLocalAuthority
PolkitBackendLocalAuthorityClass
polkit_backend_local_authority_new
<SUBSECTION Standard>
POLKIT_BACKEND_LOCAL_AUTHORITY
POLKIT_BACKEND_IS_LOCAL_AUTHORITY
......@@ -302,6 +301,23 @@ POLKIT_BACKEND_IS_LOCAL_AUTHORITY_CLASS
POLKIT_BACKEND_LOCAL_AUTHORITY_GET_CLASS
</SECTION>
<SECTION>
<FILE>polkitbackendinteractiveauthority</FILE>
<TITLE>PolkitBackendInteractiveAuthority</TITLE>
PolkitBackendInteractiveAuthority
PolkitBackendInteractiveAuthorityClass
polkit_backend_interactive_authority_get_admin_identities
polkit_backend_interactive_authority_check_authorization_sync
<SUBSECTION Standard>
POLKIT_BACKEND_INTERACTIVE_AUTHORITY
POLKIT_BACKEND_IS_INTERACTIVE_AUTHORITY
POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY
polkit_backend_interactive_authority_get_type
POLKIT_BACKEND_INTERACTIVE_AUTHORITY_CLASS
POLKIT_BACKEND_IS_INTERACTIVE_AUTHORITY_CLASS
POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_CLASS
</SECTION>
<SECTION>
<FILE>polkitbackendactionpool</FILE>
<TITLE>PolkitBackendActionPool</TITLE>
......
......@@ -14,8 +14,9 @@ polkit_error_get_type
polkit_authorization_result_get_type
polkit_backend_authority_get_type
polkit_backend_action_lookup_get_type
polkit_backend_interactive_authority_get_type
polkit_backend_local_authority_get_type
polkit_backend_action_lookup_get_type
polkit_backend_action_pool_get_type
polkit_backend_session_monitor_get_type
polkit_backend_config_source_get_type
......
......@@ -41,6 +41,7 @@ libpolkit_backend_1include_HEADERS = \
polkitbackend.h \
polkitbackendtypes.h \
polkitbackendauthority.h \
polkitbackendinteractiveauthority.h \
polkitbackendlocalauthority.h \
polkitbackendactionpool.h \
polkitbackendsessionmonitor.h \
......@@ -55,6 +56,7 @@ libpolkit_backend_1_la_SOURCES = \
polkitbackendtypes.h \
polkitbackendprivate.h \
polkitbackendauthority.h polkitbackendauthority.c \
polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \
polkitbackendlocalauthority.h polkitbackendlocalauthority.c \
polkitbackendactionpool.h polkitbackendactionpool.c \
polkitbackendsessionmonitor.h polkitbackendsessionmonitor.c \
......
......@@ -31,6 +31,7 @@
#define _POLKIT_BACKEND_INSIDE_POLKIT_BACKEND_H 1
#include <polkitbackend/polkitbackendtypes.h>
#include <polkitbackend/polkitbackendauthority.h>
#include <polkitbackend/polkitbackendinteractiveauthority.h>
#include <polkitbackend/polkitbackendlocalauthority.h>
#include <polkitbackend/polkitbackendactionpool.h>
#include <polkitbackend/polkitbackendsessionmonitor.h>
......
/*
* 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@redhat.com>
*/
#include "config.h"
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <glib/gstdio.h>
#include <locale.h>
#include <polkit/polkit.h>
#include "polkitbackendinteractiveauthority.h"
#include "polkitbackendactionpool.h"
#include "polkitbackendsessionmonitor.h"
#include "polkitbackendconfigsource.h"
#include "polkitbackendactionlookup.h"
#include <polkit/polkitprivate.h>
/**
* SECTION:polkitbackendinteractiveauthority
* @title: PolkitBackendInteractiveAuthority
* @short_description: Interactive Authority
* @stability: Unstable
*
* An subclass of #PolkitBackendAuthority that supports interaction
* with authentication agents.
*/
/* ---------------------------------------------------------------------------------------------------- */
typedef struct TemporaryAuthorizationStore TemporaryAuthorizationStore;
static TemporaryAuthorizationStore *temporary_authorization_store_new (void);
static void temporary_authorization_store_free (TemporaryAuthorizationStore *store);
static gboolean temporary_authorization_store_has_authorization (TemporaryAuthorizationStore *store,
PolkitSubject *subject,
const gchar *action_id);
static void temporary_authorization_store_add_authorization (TemporaryAuthorizationStore *store,
PolkitSubject *subject,
const gchar *action_id);
/* ---------------------------------------------------------------------------------------------------- */
struct AuthenticationAgent;
typedef struct AuthenticationAgent AuthenticationAgent;
struct AuthenticationSession;
typedef struct AuthenticationSession AuthenticationSession;
typedef void (*AuthenticationAgentCallback) (AuthenticationAgent *agent,
PolkitSubject *subject,
PolkitIdentity *user_of_subject,
PolkitBackendInteractiveAuthority *authority,
const gchar *action_id,
PolkitImplicitAuthorization implicit_authorization,
gboolean authentication_success,
gpointer user_data);
static void authentication_agent_free (AuthenticationAgent *agent);
static void authentication_agent_initiate_challenge (AuthenticationAgent *agent,
PolkitSubject *subject,
PolkitIdentity *user_of_subject,
PolkitBackendInteractiveAuthority *authority,
const gchar *action_id,
PolkitDetails *details,
PolkitSubject *caller,
PolkitImplicitAuthorization implicit_authorization,
GCancellable *cancellable,
AuthenticationAgentCallback callback,
gpointer user_data);
static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authority,
PolkitSubject *subject);
static AuthenticationSession *get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *authority,
const gchar *cookie);
static GList *get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendInteractiveAuthority *authority,
const gchar *system_bus_unique_name);
static void authentication_session_cancel (AuthenticationSession *session);
/* ---------------------------------------------------------------------------------------------------- */
static void polkit_backend_interactive_authority_system_bus_name_owner_changed (PolkitBackendAuthority *authority,
const gchar *name,
const gchar *old_owner,
const gchar *new_owner);
static GList *polkit_backend_interactive_authority_enumerate_actions (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *locale,
GError **error);
static void polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority,
PolkitSubject *caller,
PolkitSubject *subject,
const gchar *action_id,
PolkitDetails *details,
PolkitCheckAuthorizationFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
static PolkitAuthorizationResult *polkit_backend_interactive_authority_check_authorization_finish (
PolkitBackendAuthority *authority,
GAsyncResult *res,
GError **error);
static PolkitAuthorizationResult *check_authorization_sync (PolkitBackendAuthority *authority,
PolkitSubject *caller,
PolkitSubject *subject,
const gchar *action_id,
PolkitDetails *details,
PolkitCheckAuthorizationFlags flags,
PolkitImplicitAuthorization *out_implicit_authorization,
GError **error);
static gboolean polkit_backend_interactive_authority_register_authentication_agent (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *session_id,
const gchar *locale,
const gchar *object_path,
GError **error);
static gboolean polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *session_id,
const gchar *object_path,
GError **error);
static gboolean polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *cookie,
PolkitIdentity *identity,
GError **error);
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
PolkitBackendActionPool *action_pool;
PolkitBackendSessionMonitor *session_monitor;
TemporaryAuthorizationStore *temporary_authorization_store;
GHashTable *hash_session_to_authentication_agent;
} PolkitBackendInteractiveAuthorityPrivate;
/* ---------------------------------------------------------------------------------------------------- */
G_DEFINE_TYPE (PolkitBackendInteractiveAuthority,
polkit_backend_interactive_authority,
POLKIT_BACKEND_TYPE_AUTHORITY);
#define POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY, PolkitBackendInteractiveAuthorityPrivate))
/* ---------------------------------------------------------------------------------------------------- */
static void
action_pool_changed (PolkitBackendActionPool *action_pool,
PolkitBackendInteractiveAuthority *authority)
{
g_signal_emit_by_name (authority, "changed");
}
/* ---------------------------------------------------------------------------------------------------- */
static void
polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *authority)
{
PolkitBackendInteractiveAuthorityPrivate *priv;
GFile *directory;
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
directory = g_file_new_for_path (PACKAGE_DATA_DIR "/polkit-1/actions");
priv->action_pool = polkit_backend_action_pool_new (directory);
g_object_unref (directory);
g_signal_connect (priv->action_pool,
"changed",
(GCallback) action_pool_changed,
authority);
priv->temporary_authorization_store = temporary_authorization_store_new ();
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->session_monitor = polkit_backend_session_monitor_new ();
}
static void
polkit_backend_interactive_authority_finalize (GObject *object)
{
PolkitBackendInteractiveAuthority *interactive_authority;
PolkitBackendInteractiveAuthorityPrivate *priv;
interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (object);
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
if (priv->action_pool != NULL)
g_object_unref (priv->action_pool);
if (priv->session_monitor != NULL)
g_object_unref (priv->session_monitor);
temporary_authorization_store_free (priv->temporary_authorization_store);
g_hash_table_unref (priv->hash_session_to_authentication_agent);
G_OBJECT_CLASS (polkit_backend_interactive_authority_parent_class)->finalize (object);
}
static void
polkit_backend_interactive_authority_class_init (PolkitBackendInteractiveAuthorityClass *klass)
{
GObjectClass *gobject_class;
PolkitBackendAuthorityClass *authority_class;
gobject_class = G_OBJECT_CLASS (klass);
authority_class = POLKIT_BACKEND_AUTHORITY_CLASS (klass);
gobject_class->finalize = polkit_backend_interactive_authority_finalize;
authority_class->system_bus_name_owner_changed = polkit_backend_interactive_authority_system_bus_name_owner_changed;
authority_class->enumerate_actions = polkit_backend_interactive_authority_enumerate_actions;
authority_class->check_authorization = polkit_backend_interactive_authority_check_authorization;
authority_class->check_authorization_finish = polkit_backend_interactive_authority_check_authorization_finish;
authority_class->register_authentication_agent = polkit_backend_interactive_authority_register_authentication_agent;
authority_class->unregister_authentication_agent = polkit_backend_interactive_authority_unregister_authentication_agent;
authority_class->authentication_agent_response = polkit_backend_interactive_authority_authentication_agent_response;
g_type_class_add_private (klass, sizeof (PolkitBackendInteractiveAuthorityPrivate));
}
/* ---------------------------------------------------------------------------------------------------- */
static GList *
polkit_backend_interactive_authority_enumerate_actions (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *interactivee,
GError **error)
{
PolkitBackendInteractiveAuthority *interactive_authority;
PolkitBackendInteractiveAuthorityPrivate *priv;
GList *actions;
interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
actions = polkit_backend_action_pool_get_all_actions (priv->action_pool, interactivee);
return actions;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
check_authorization_challenge_cb (AuthenticationAgent *agent,
PolkitSubject *subject,
PolkitIdentity *user_of_subject,
PolkitBackendInteractiveAuthority *authority,
const gchar *action_id,
PolkitImplicitAuthorization implicit_authorization,
gboolean authentication_success,
gpointer user_data)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
PolkitBackendInteractiveAuthorityPrivate *priv;
PolkitAuthorizationResult *result;
gchar *subject_str;
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
result = NULL;
subject_str = polkit_subject_to_string (subject);
g_debug ("In check_authorization_challenge_cb\n"
" subject %s\n"
" action_id %s\n"
" authentication_success %d\n",
subject_str,
action_id,
authentication_success);
if (authentication_success)
{
result = polkit_authorization_result_new (TRUE, FALSE, NULL);
/* 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)
{
temporary_authorization_store_add_authorization (priv->temporary_authorization_store,
subject,
action_id);
}
}
else
{
/* TODO: maybe return set is_challenge? */
result = polkit_authorization_result_new (FALSE, FALSE, NULL);
}
g_simple_async_result_set_op_res_gpointer (simple,
result,
g_object_unref);
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_free (subject_str);
}
static PolkitAuthorizationResult *
polkit_backend_interactive_authority_check_authorization_finish (PolkitBackendAuthority *authority,
GAsyncResult *res,
GError **error)
{
GSimpleAsyncResult *simple;
PolkitAuthorizationResult *result;
simple = G_SIMPLE_ASYNC_RESULT (res);
g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_backend_interactive_authority_check_authorization);
result = NULL;
if (g_simple_async_result_propagate_error (simple, error))
goto out;
result = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
out:
return result;
}
static void
polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority,
PolkitSubject *caller,
PolkitSubject *subject,
const gchar *action_id,
PolkitDetails *details,
PolkitCheckAuthorizationFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
PolkitBackendInteractiveAuthority *interactive_authority;
PolkitBackendInteractiveAuthorityPrivate *priv;
gchar *caller_str;
gchar *subject_str;
PolkitIdentity *user_of_caller;
PolkitIdentity *user_of_subject;
gchar *user_of_caller_str;
gchar *user_of_subject_str;
PolkitAuthorizationResult *result;
PolkitImplicitAuthorization implicit_authorization;
GError *error;
GSimpleAsyncResult *simple;
interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
error = NULL;
caller_str = NULL;
subject_str = NULL;
user_of_caller = NULL;
user_of_subject = NULL;
user_of_caller_str = NULL;
user_of_subject_str = NULL;
result = NULL;
simple = g_simple_async_result_new (G_OBJECT (authority),
callback,
user_data,
polkit_backend_interactive_authority_check_authorization);
caller_str = polkit_subject_to_string (caller);
subject_str = polkit_subject_to_string (subject);
g_debug ("%s is inquiring whether %s is authorized for %s",
caller_str,
subject_str,
action_id);
user_of_caller = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
caller,
&error);
if (error != NULL)
{
g_simple_async_result_set_from_error (simple, error);
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_error_free (error);
goto out;
}
user_of_caller_str = polkit_identity_to_string (user_of_caller);
g_debug (" user of caller is %s", user_of_caller_str);
/* we only allow trusted callers (uid 0 + others) to check authorizations */
if (!POLKIT_IS_UNIX_USER (user_of_caller) ||
polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0) /* TODO: allow other uids like 'haldaemon'? */
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_NOT_AUTHORIZED,
"Only trusted callers can use CheckAuthorization(), %s is not trusted",
user_of_caller_str);
g_simple_async_result_complete (simple);
g_object_unref (simple);
goto out;
}
user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
subject,
&error);
if (error != NULL)
{
g_simple_async_result_set_from_error (simple, error);
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_error_free (error);
goto out;
}
user_of_subject_str = polkit_identity_to_string (user_of_subject);
g_debug (" user of subject is %s", user_of_subject_str);
implicit_authorization = POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED;
result = check_authorization_sync (authority,
caller,
subject,
action_id,
details,
flags,
&implicit_authorization,
&error);
if (error != NULL)
{
g_simple_async_result_set_from_error (simple, error);
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_error_free (error);
goto out;
}
/* Caller is up for a challenge! With light sabers! Use an authentication agent if one exists... */
if (polkit_authorization_result_get_is_challenge (result) &&
(flags & POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION))
{
AuthenticationAgent *agent;
agent = get_authentication_agent_for_subject (interactive_authority, subject);
if (agent != NULL)
{
g_object_unref (result);
result = NULL;
g_debug (" using authentication agent for challenge");
authentication_agent_initiate_challenge (agent,
subject,
user_of_subject,
interactive_authority,
action_id,
details,
caller,
implicit_authorization,
cancellable,
check_authorization_challenge_cb,
simple);
/* keep going */
goto out;
}
}
/* Otherwise just return the result */
g_simple_async_result_set_op_res_gpointer (simple,
result,
g_object_unref);
g_simple_async_result_complete (simple);
g_object_unref (simple);
out:
if (user_of_caller != NULL)
g_object_unref (user_of_caller);
if (user_of_subject != NULL)
g_object_unref (user_of_subject);
g_free (caller_str);
g_free (subject_str);
g_free (user_of_caller_str);
g_free (user_of_subject_str);
}