Commit 8f7727e1 authored by David Zeuthen's avatar David Zeuthen

Port lockdown from pklalockdown(1) to D-Bus methods

Also rename the action from org.freedesktop.policykit.localauthority.lockdown
to org.freedesktop.policykit.lockdown since any authority implementation
can now implement this.

This changes only ABI/API used by e.g. polkit-gnome. This is fine
since we're not at 1.0 yet.
parent 00c00948
......@@ -59,8 +59,8 @@
</defaults>
</action>
<action id="org.freedesktop.policykit.localauthority.lockdown">
<_description>Configure lockdown on the Local Authority</_description>
<action id="org.freedesktop.policykit.lockdown">
<_description>Configure lock down for an action</_description>
<_message>Authentication is required to configure lock down policy</_message>
<defaults>
<allow_any>no</allow_any>
......
......@@ -10,7 +10,6 @@ man_MANS = \
pkexec.1 \
pkcheck.1 \
pkaction.1 \
pklalockdown.1 \
$(NULL)
%.8 %.1 : %.xml
......@@ -25,7 +24,6 @@ EXTRA_DIST = \
pkexec.xml \
pkcheck.xml \
pkaction.xml \
pklalockdown.xml \
$(NULL)
clean-local:
......
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY version SYSTEM "../version.xml">
]>
<refentry id="pklalockdown.1" xmlns:xi="http://www.w3.org/2003/XInclude">
<refentryinfo>
<title>pklalockdown</title>
<date>May 2009</date>
<productname>polkit</productname>
</refentryinfo>
<refmeta>
<refentrytitle>pklalockdown</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="version"></refmiscinfo>
</refmeta>
<refnamediv>
<refname>pklalockdown</refname>
<refpurpose>Configure lockdown for the Local Authority</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>pklalockdown</command>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>pklalockdown</command>
<arg choice="plain">
<option>--lockdown</option>
<replaceable>action</replaceable>
</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>pklalockdown</command>
<arg choice="plain">
<option>--remove-lockdown</option>
<replaceable>action</replaceable>
</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="pklalockdown-description">
<title>DESCRIPTION</title>
<para>
<command>pklalockdown</command> is used to configure lockdown
for the Local Authority.
</para>
<para>
The effect of locking down an action is that administrator
authentication is always needed in order for subjects to acquire
the authorization for the action in question (and the subject
has to be in an active session on a local console). The obtained
authorization is temporary and as such typically expires five
minutes after being obtained.
</para>
<para>
To lock down <replaceable>action</replaceable> use the <option>--lockdown</option> option.
To remove a lockdown for <replaceable>action</replaceable> use the <option>--remove-lockdown</option> option.
</para>
</refsect1>
<refsect1 id="pklalockdown-required-auhtz">
<title>REQUIRED AUTHORIZATIONS</title>
<para>
The <emphasis>org.freedesktop.policykit.localauthority.lockdown</emphasis>
authorization is needed to add or remove lockdown. By default,
this authorization requires administrator authentication and
cannot be retained.
</para>
</refsect1>
<refsect1 id="pklalockdown-impl-details">
<title>IMPLEMENTATION DETAILS</title>
<para>
Lockdown is implemented through <filename>.pkla</filename>
files. Locked down actions supersede other most other Local
Authority configuration as the <filename>.pkla</filename> files
are placed
in <filename>/var/lib/polkit-1/localauthority90-mandatory.d</filename>.
<para>
</para>
Programs checking authorizations can check whether an action is
locked down via by checking
the <emphasis>polkit.localauthority.lockdown</emphasis> key/value pair in
the details of the authorization response.
</para>
</refsect1>
<refsect1 id="pklalockdown-return-values">
<title>RETURN VALUE</title>
<para>
On success <command>pklalockdown</command> returns 0. Otherwise a
non-zero value is returned and a diagnostic message is printed
on standard error.
</para>
</refsect1>
<refsect1 id="pklalockdown-author"><title>AUTHOR</title>
<para>
Written by David Zeuthen <email>davidz@redhat.com</email> with
a lot of help from many others.
</para>
</refsect1>
<refsect1 id="pklalockdown-bugs">
<title>BUGS</title>
<para>
Please send bug reports to either the distribution or the
polkit-devel mailing list,
see the link <ulink url="http://lists.freedesktop.org/mailman/listinfo/polkit-devel"/>
on how to subscribe.
</para>
</refsect1>
<refsect1 id="pklalockdown-see-also">
<title>SEE ALSO</title>
<para>
<citerefentry>
<refentrytitle>polkit</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pkcheck</refentrytitle><manvolnum>1</manvolnum>
</citerefentry>,
<citerefentry>
<refentrytitle>pklocalauthority</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>
......@@ -74,7 +74,7 @@ polkit_authorization_result_get_is_authorized
polkit_authorization_result_get_is_challenge
polkit_authorization_result_get_retains_authorization
polkit_authorization_result_get_temporary_authorization_id
polkit_authorization_result_get_local_authority_lock_down
polkit_authorization_result_get_locked_down
polkit_authorization_result_get_details
<SUBSECTION Standard>
PolkitAuthorizationResultClass
......
......@@ -1312,7 +1312,7 @@ polkit_authority_revoke_temporary_authorizations (PolkitAuthority *authority
* @res: A #GAsyncResult obtained from the callback.
* @error: Return location for error or %NULL.
*
* Finished revoking temporary authorizations.
* Finishes revoking temporary authorizations.
*
* Returns: %TRUE if all the temporary authorizations was revoked, %FALSE if error is set.
**/
......@@ -1431,7 +1431,7 @@ polkit_authority_revoke_temporary_authorization_by_id (PolkitAuthority *auth
* @res: A #GAsyncResult obtained from the callback.
* @error: Return location for error or %NULL.
*
* Finished revoking a temporary authorization by id.
* Finishes revoking a temporary authorization by id.
*
* Returns: %TRUE if the temporary authorization was revoked, %FALSE if error is set.
**/
......@@ -1550,7 +1550,7 @@ polkit_authority_add_lockdown_for_action (PolkitAuthority *authority,
* @res: A #GAsyncResult obtained from the callback.
* @error: Return location for error or %NULL.
*
* Finished locking down an action.
* Finishes locking down an action.
*
* Returns: %TRUE if the action was locked down, %FALSE if error is set.
**/
......
......@@ -278,25 +278,26 @@ polkit_authorization_result_get_temporary_authorization_id (PolkitAuthorizationR
}
/**
* polkit_authorization_result_get_local_authority_lock_down:
* polkit_authorization_result_get_locked_down:
* @result: A #PolkitAuthorizationResult.
*
* Gets whether the action is locked down in the Local Authority via pklalockdown(1).
* Gets whether the action is locked down via
* e.g. polkit_authority_add_lockdown_for_action().
*
* This method simply reads the value of the key/value pair in @details with the
* key <literal>polkit.localauthority.lockdown</literal>.
* key <literal>polkit.lockdown</literal>.
*
* Returns: %TRUE if the authorization is or will be temporary.
* Returns: %TRUE if the action for the authorization is locked down.
*/
gboolean
polkit_authorization_result_get_local_authority_lock_down (PolkitAuthorizationResult *result)
polkit_authorization_result_get_locked_down (PolkitAuthorizationResult *result)
{
gboolean ret;
PolkitDetails *details;
ret = FALSE;
details = polkit_authorization_result_get_details (result);
if (details != NULL && polkit_details_lookup (details, "polkit.localauthority.lockdown") != NULL)
if (details != NULL && polkit_details_lookup (details, "polkit.lockdown") != NULL)
ret = TRUE;
return ret;
......
......@@ -52,7 +52,7 @@ gboolean polkit_authorization_result_get_is_authorized (P
gboolean polkit_authorization_result_get_is_challenge (PolkitAuthorizationResult *result);
gboolean polkit_authorization_result_get_retains_authorization (PolkitAuthorizationResult *result);
const gchar *polkit_authorization_result_get_temporary_authorization_id (PolkitAuthorizationResult *result);
gboolean polkit_authorization_result_get_local_authority_lock_down (PolkitAuthorizationResult *result);
gboolean polkit_authorization_result_get_locked_down (PolkitAuthorizationResult *result);
/* ---------------------------------------------------------------------------------------------------- */
......
......@@ -481,6 +481,15 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
user_data,
polkit_backend_interactive_authority_check_authorization);
/* handle being called from ourselves */
if (caller == NULL)
{
EggDBusConnection *system_bus;
system_bus = egg_dbus_connection_get_for_bus (EGG_DBUS_BUS_TYPE_SYSTEM);
caller = polkit_system_bus_name_new (egg_dbus_connection_get_unique_name (system_bus));
g_object_unref (system_bus);
}
caller_str = polkit_subject_to_string (caller);
subject_str = polkit_subject_to_string (subject);
......
......@@ -26,11 +26,13 @@
#include <string.h>
#include <glib/gstdio.h>
#include <locale.h>
#include <glib/gi18n-lib.h>
#include <polkit/polkit.h>
#include "polkitbackendconfigsource.h"
#include "polkitbackendlocalauthority.h"
#include "polkitbackendlocalauthorizationstore.h"
#include "polkitbackendactionlookup.h"
#include <polkit/polkitprivate.h>
......@@ -40,8 +42,11 @@
* @short_description: Local Authority
* @stability: Unstable
*
* An implementation of #PolkitBackendAuthority that stores authorizations on the local file system
* and supports interaction with authentication agents.
* An implementation of #PolkitBackendAuthority that stores
* authorizations on the local file system, supports interaction with
* authentication agents (virtue of being based on
* #PolkitBackendInteractiveAuthority), and implements support for
* lock down.
*/
/* ---------------------------------------------------------------------------------------------------- */
......@@ -51,6 +56,8 @@ static GList *get_users_in_group (PolkitIdentity *group,
static GList *get_groups_for_user (PolkitIdentity *user);
static void register_extensions (void);
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
......@@ -82,6 +89,26 @@ static PolkitImplicitAuthorization polkit_backend_local_authority_check_authoriz
PolkitImplicitAuthorization implicit,
PolkitDetails *out_details);
static void polkit_backend_local_authority_add_lockdown_for_action (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *action_id,
GAsyncReadyCallback callback,
gpointer user_data);
static gboolean polkit_backend_local_authority_add_lockdown_for_action_finish (PolkitBackendAuthority *authority,
GAsyncResult *res,
GError **error);
static void polkit_backend_local_authority_remove_lockdown_for_action (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *action_id,
GAsyncReadyCallback callback,
gpointer user_data);
static gboolean polkit_backend_local_authority_remove_lockdown_for_action_finish (PolkitBackendAuthority *authority,
GAsyncResult *res,
GError **error);
G_DEFINE_TYPE_WITH_CODE (PolkitBackendLocalAuthority,
polkit_backend_local_authority,
......@@ -194,10 +221,16 @@ polkit_backend_local_authority_class_init (PolkitBackendLocalAuthorityClass *kla
authority_class->get_name = polkit_backend_local_authority_get_name;
authority_class->get_version = polkit_backend_local_authority_get_version;
authority_class->get_features = polkit_backend_local_authority_get_features;
authority_class->add_lockdown_for_action = polkit_backend_local_authority_add_lockdown_for_action;
authority_class->add_lockdown_for_action_finish = polkit_backend_local_authority_add_lockdown_for_action_finish;
authority_class->remove_lockdown_for_action = polkit_backend_local_authority_remove_lockdown_for_action;
authority_class->remove_lockdown_for_action_finish = polkit_backend_local_authority_remove_lockdown_for_action_finish;
interactive_authority_class->get_admin_identities = polkit_backend_local_authority_get_admin_auth_identities;
interactive_authority_class->check_authorization_sync = polkit_backend_local_authority_check_authorization_sync;
g_type_class_add_private (klass, sizeof (PolkitBackendLocalAuthorityPrivate));
register_extensions ();
}
static GList *
......@@ -470,3 +503,469 @@ get_groups_for_user (PolkitIdentity *user)
}
/* ---------------------------------------------------------------------------------------------------- */
static gchar *
lockdown_get_filename (const gchar *action_id)
{
return g_strdup_printf (PACKAGE_LOCALSTATE_DIR
"/lib/polkit-1/localauthority/90-mandatory.d/"
"org.freedesktop.policykit.localauthority.lockdown.action-%s.pkla",
action_id);
}
static gboolean
lockdown_exists (const gchar *action_id)
{
gchar *filename;
gboolean ret;
ret = FALSE;
filename = lockdown_get_filename (action_id);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
ret = TRUE;
g_free (filename);
return ret;
}
static gboolean
lockdown_add (const gchar *action_id,
GError **error)
{
gboolean ret;
gchar *filename;
gchar *contents;
ret = FALSE;
filename = lockdown_get_filename (action_id);
contents = g_strdup_printf ("# Added by pklalockdown(1)\n"
"#\n"
"[Lockdown]\n"
"Identity=unix-user:*\n"
"Action=%s\n"
"ResultAny=no\n"
"ResultInactive=no\n"
"ResultActive=auth_admin_keep\n"
"ReturnValue=polkit.lockdown=1",
action_id);
if (!g_file_set_contents (filename,
contents,
-1,
error))
goto out;
ret = TRUE;
out:
g_free (filename);
g_free (contents);
return ret;
}
static gboolean
lockdown_remove (const gchar *action_id,
GError **error)
{
gboolean ret;
gchar *filename;
ret = FALSE;
filename = lockdown_get_filename (action_id);
if (g_unlink (filename) != 0)
{
g_set_error (error,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Cannot unlink file %s: %s\n",
filename,
g_strerror (errno));
goto out;
}
ret = TRUE;
out:
g_free (filename);
return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
add_lockdown_check_auth_cb (PolkitBackendAuthority *authority,
GAsyncResult *res,
gpointer user_data)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
PolkitAuthorizationResult *result;
GError *error;
result = polkit_backend_authority_check_authorization_finish (authority,
res,
&error);
if (result == NULL)
{
g_simple_async_result_set_from_error (simple, error);
g_error_free (error);
}
else
{
if (polkit_authorization_result_get_is_authorized (result))
{
const gchar *action_id;
action_id = g_object_get_data (G_OBJECT (simple), "lock-down-action-id");
if (lockdown_exists (action_id))
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Action %s is already locked down",
action_id);
}
else
{
GError *error;
error = NULL;
if (!lockdown_add (action_id, &error))
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Error adding lock down for action %s: %s",
action_id,
error->message);
g_error_free (error);
}
}
}
else
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_NOT_AUTHORIZED,
"Not authorized to add lock down for the requested action");
}
g_object_unref (result);
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
polkit_backend_local_authority_add_lockdown_for_action (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *action_id,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
PolkitDetails *details;
GCancellable *cancellable;
simple = g_simple_async_result_new (G_OBJECT (authority),
callback,
user_data,
polkit_backend_local_authority_add_lockdown_for_action);
g_object_set_data_full (G_OBJECT (simple), "lock-down-action-id", g_strdup (action_id), g_free);
details = polkit_details_new ();
polkit_details_insert (details, "action-id", action_id);
polkit_details_insert (details, "add-lockdown", "1");
cancellable = g_cancellable_new ();
/* first check if caller is authorized for this */
polkit_backend_authority_check_authorization (POLKIT_BACKEND_AUTHORITY (authority),
NULL,
caller,
"org.freedesktop.policykit.lockdown",
details,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
cancellable,
(GAsyncReadyCallback) add_lockdown_check_auth_cb,
simple);
g_object_unref (details);
g_object_unref (cancellable);
}
static gboolean
polkit_backend_local_authority_add_lockdown_for_action_finish (PolkitBackendAuthority *authority,
GAsyncResult *res,
GError **error)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_backend_local_authority_add_lockdown_for_action);
if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
remove_lockdown_check_auth_cb (PolkitBackendAuthority *authority,
GAsyncResult *res,
gpointer user_data)
{
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
PolkitAuthorizationResult *result;
GError *error;
result = polkit_backend_authority_check_authorization_finish (authority,
res,
&error);
if (result == NULL)
{
g_simple_async_result_set_from_error (simple, error);
g_error_free (error);
}
else
{
if (polkit_authorization_result_get_is_authorized (result))
{
const gchar *action_id;
action_id = g_object_get_data (G_OBJECT (simple), "lock-down-action-id");
if (!lockdown_exists (action_id))
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Action %s is not locked down",
action_id);
}
else
{
GError *error;
error = NULL;
if (!lockdown_remove (action_id, &error))
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_FAILED,
"Error removing lock down for action %s: %s",
action_id,
error->message);
g_error_free (error);
}
}
}
else
{
g_simple_async_result_set_error (simple,
POLKIT_ERROR,
POLKIT_ERROR_NOT_AUTHORIZED,
"Not authorized to remove lock down for the requested action");
}
g_object_unref (result);
}
g_simple_async_result_complete (simple);
g_object_unref (simple);
}
static void
polkit_backend_local_authority_remove_lockdown_for_action (PolkitBackendAuthority *authority,
PolkitSubject *caller,
const gchar *action_id,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *simple;
PolkitDetails *details;
GCancellable *cancellable;
simple = g_simple_async_result_new (G_OBJECT (authority),
callback,
user_data,
polkit_backend_local_authority_remove_lockdown_for_action);
g_object_set_data_full (G_OBJECT (simple), "lock-down-action-id", g_strdup (action_id), g_free);
details = polkit_details_new ();
polkit_details_insert (details, "action-id", action_id);
polkit_details_insert (details, "remove-lockdown", "1");
cancellable = g_cancellable_new ();