summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--actions/org.freedesktop.policykit.policy.in11
-rw-r--r--data/org.freedesktop.PolicyKit1.Authority.xml2
-rw-r--r--docs/man/Makefile.am2
-rw-r--r--docs/man/pklalockdown.xml136
-rw-r--r--docs/man/pklocalauthority.xml21
-rw-r--r--docs/polkit/polkit-1-docs.xml3
-rw-r--r--docs/polkit/polkit-1-sections.txt1
-rw-r--r--src/polkit/polkitauthorizationresult.c25
-rw-r--r--src/polkit/polkitauthorizationresult.h1
-rw-r--r--src/polkitbackend/polkitbackendinteractiveauthority.c14
-rw-r--r--src/polkitbackend/polkitbackendinteractiveauthority.h6
-rw-r--r--src/polkitbackend/polkitbackendlocalauthority.c12
-rw-r--r--src/polkitbackend/polkitbackendlocalauthorizationstore.c61
-rw-r--r--src/polkitbackend/polkitbackendlocalauthorizationstore.h3
-rw-r--r--src/programs/Makefile.am15
-rw-r--r--src/programs/pklalockdown.c243
16 files changed, 537 insertions, 19 deletions
diff --git a/actions/org.freedesktop.policykit.policy.in b/actions/org.freedesktop.policykit.policy.in
index d44a0c1..3961001 100644
--- a/actions/org.freedesktop.policykit.policy.in
+++ b/actions/org.freedesktop.policykit.policy.in
@@ -58,4 +58,15 @@
<allow_active>auth_admin</allow_active>
</defaults>
</action>
+
+ <action id="org.freedesktop.policykit.localauthority.lockdown">
+ <_description>Configure lockdown on the Local Authority</_description>
+ <_message>Authentication is required to configure lock down policy</_message>
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.exec.path">/usr/bin/pklalockdown</annotate>
+ </action>
</policyconfig>
diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml
index 7854a96..e71dc20 100644
--- a/data/org.freedesktop.PolicyKit1.Authority.xml
+++ b/data/org.freedesktop.PolicyKit1.Authority.xml
@@ -129,7 +129,7 @@
</annotation>
<annotation name="org.gtk.EggDBus.Struct.Member" value="Dict<String,String>:details">
- <annotation name="org.gtk.EggDBus.DocString" value="Details for the result or empty if not authorized. Known key/value-pairs include <literal>polkit.temporary_authorization_id</literal> (if the authorization is temporary, this is set to the opaque temporary authorization id) and <literal>polkit.retains_authorization_after_challenge</literal> (Set to a non-empty string if the authorization will be retained after authentication (if is_challenge is TRUE))."/>
+ <annotation name="org.gtk.EggDBus.DocString" value="Details for the result or empty if not authorized. Known key/value-pairs include <literal>polkit.temporary_authorization_id</literal> (if the authorization is temporary, this is set to the opaque temporary authorization id), <literal>polkit.retains_authorization_after_challenge</literal> (Set to a non-empty string if the authorization will be retained after authentication (if is_challenge is TRUE)) and <literal>polkit.localauthority.lockdown</literal> (set to a non-empty string if the action is locked down via pklalockdown(1))."/>
</annotation>
</annotation>
diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am
index 076608b..6f164c9 100644
--- a/docs/man/Makefile.am
+++ b/docs/man/Makefile.am
@@ -10,6 +10,7 @@ man_MANS = \
pkexec.1 \
pkcheck.1 \
pkaction.1 \
+ pklalockdown.1 \
$(NULL)
%.8 %.1 : %.xml
@@ -24,6 +25,7 @@ EXTRA_DIST = \
pkexec.xml \
pkcheck.xml \
pkaction.xml \
+ pklalockdown.xml \
$(NULL)
clean-local:
diff --git a/docs/man/pklalockdown.xml b/docs/man/pklalockdown.xml
new file mode 100644
index 0000000..74e4f5d
--- /dev/null
+++ b/docs/man/pklalockdown.xml
@@ -0,0 +1,136 @@
+<?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>
diff --git a/docs/man/pklocalauthority.xml b/docs/man/pklocalauthority.xml
index 52dded2..495aa41 100644
--- a/docs/man/pklocalauthority.xml
+++ b/docs/man/pklocalauthority.xml
@@ -155,7 +155,7 @@
<para>
Each group in a <filename>.pkla</filename> must have a name that
is unique within the file it belongs to. The following keys are
- required in each group
+ are processed.
</para>
<variablelist>
<varlistentry>
@@ -214,12 +214,23 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><emphasis>ReturnValue</emphasis></term>
+ <listitem>
+ <para>
+ A semi-colon separated list of key/value pairs (of the
+ form key=value) that are add to the details of
+ authorization result on positive matches.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>
All keys specified above are required except that only at least
one
of <emphasis>RequireAny</emphasis>, <emphasis>RequireInactive</emphasis>
- and <emphasis>RequireActive</emphasis> is present.
+ and <emphasis>RequireActive</emphasis> is
+ present. The <emphasis>ReturnValue</emphasis> key is optional.
</para>
</refsect1>
@@ -240,8 +251,10 @@
authorization check matches the data from the authorization
check, then the authorization result
from <emphasis>RequireAny</emphasis>, <emphasis>RequireInactive</emphasis>
- or <emphasis>RequireActive</emphasis> is used. Finally, the
- authorization entries are consulted using the user identity.
+ or <emphasis>RequireActive</emphasis> is used
+ and <emphasis>ReturnValue</emphasis> is added to the
+ authorization result. Finally, the authorization entries are
+ consulted using the user identity in the same manner.
</para>
<para>
Note that processing continues even after a match. This allows
diff --git a/docs/polkit/polkit-1-docs.xml b/docs/polkit/polkit-1-docs.xml
index f09954b..357efdf 100644
--- a/docs/polkit/polkit-1-docs.xml
+++ b/docs/polkit/polkit-1-docs.xml
@@ -110,10 +110,11 @@
<title>Manual Pages</title>
<xi:include href="../man/polkit.xml"/>
<xi:include href="../man/polkitd.xml"/>
- <xi:include href="../man/pklocalauthority.xml"/>
<xi:include href="../man/pkcheck.xml"/>
<xi:include href="../man/pkaction.xml"/>
<xi:include href="../man/pkexec.xml"/>
+ <xi:include href="../man/pklocalauthority.xml"/>
+ <xi:include href="../man/pklalockdown.xml"/>
</part>
<chapter id="polkit-hierarchy">
diff --git a/docs/polkit/polkit-1-sections.txt b/docs/polkit/polkit-1-sections.txt
index 333e2c8..f5bc3a8 100644
--- a/docs/polkit/polkit-1-sections.txt
+++ b/docs/polkit/polkit-1-sections.txt
@@ -64,6 +64,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_details
<SUBSECTION Standard>
PolkitAuthorizationResultClass
diff --git a/src/polkit/polkitauthorizationresult.c b/src/polkit/polkitauthorizationresult.c
index 40abed1..e55ae88 100644
--- a/src/polkit/polkitauthorizationresult.c
+++ b/src/polkit/polkitauthorizationresult.c
@@ -276,3 +276,28 @@ polkit_authorization_result_get_temporary_authorization_id (PolkitAuthorizationR
return ret;
}
+
+/**
+ * polkit_authorization_result_get_local_authority_lock_down:
+ * @result: A #PolkitAuthorizationResult.
+ *
+ * Gets whether the action is locked down in the Local Authority via pklalockdown(1).
+ *
+ * This method simply reads the value of the key/value pair in @details with the
+ * key <literal>polkit.localauthority.lockdown</literal>.
+ *
+ * Returns: %TRUE if the authorization is or will be temporary.
+ */
+gboolean
+polkit_authorization_result_get_local_authority_lock_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)
+ ret = TRUE;
+
+ return ret;
+}
diff --git a/src/polkit/polkitauthorizationresult.h b/src/polkit/polkitauthorizationresult.h
index ea479fe..ae00f83 100644
--- a/src/polkit/polkitauthorizationresult.h
+++ b/src/polkit/polkitauthorizationresult.h
@@ -52,6 +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);
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index bf88c2b..add7a60 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -715,7 +715,8 @@ check_authorization_sync (PolkitBackendAuthority *authority,
session_is_active,
action_id,
details,
- implicit_authorization);
+ implicit_authorization,
+ result_details);
/* first see if there's an implicit authorization for subject available */
if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED)
@@ -844,9 +845,12 @@ polkit_backend_interactive_authority_get_admin_identities (PolkitBackendInteract
* @action_id: The action we are checking an authorization for.
* @details: Details about the action.
* @implicit: A #PolkitImplicitAuthorization value computed from the policy file and @subject.
+ * @out_details: A #PolkitDetails object that will be return to @caller.
*
* Checks whether @subject is authorized to perform the action
- * specified by @action_id and @details.
+ * specified by @action_id and @details. The implementation may
+ * append key/value pairs to @out_details to return extra information
+ * to @caller.
*
* The default implementation of this method simply returns @implicit.
*
@@ -862,7 +866,8 @@ polkit_backend_interactive_authority_check_authorization_sync (PolkitBackendInte
gboolean subject_is_active,
const gchar *action_id,
PolkitDetails *details,
- PolkitImplicitAuthorization implicit)
+ PolkitImplicitAuthorization implicit,
+ PolkitDetails *out_details)
{
PolkitBackendInteractiveAuthorityClass *klass;
PolkitImplicitAuthorization ret;
@@ -883,7 +888,8 @@ polkit_backend_interactive_authority_check_authorization_sync (PolkitBackendInte
subject_is_active,
action_id,
details,
- implicit);
+ implicit,
+ out_details);
}
return ret;
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.h b/src/polkitbackend/polkitbackendinteractiveauthority.h
index 9820dac..408c3e4 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.h
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.h
@@ -83,7 +83,8 @@ struct _PolkitBackendInteractiveAuthorityClass
gboolean subject_is_active,
const gchar *action_id,
PolkitDetails *details,
- PolkitImplicitAuthorization implicit);
+ PolkitImplicitAuthorization implicit,
+ PolkitDetails *out_details);
/*< private >*/
/* Padding for future expansion */
@@ -138,7 +139,8 @@ PolkitImplicitAuthorization polkit_backend_interactive_authority_check_authoriza
gboolean subject_is_active,
const gchar *action_id,
PolkitDetails *details,
- PolkitImplicitAuthorization implicit);
+ PolkitImplicitAuthorization implicit,
+ PolkitDetails *out_details);
G_END_DECLS
diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c
index a3fb7f2..932706e 100644
--- a/src/polkitbackend/polkitbackendlocalauthority.c
+++ b/src/polkitbackend/polkitbackendlocalauthority.c
@@ -79,7 +79,8 @@ static PolkitImplicitAuthorization polkit_backend_local_authority_check_authoriz
gboolean subject_is_active,
const gchar *action_id,
PolkitDetails *details,
- PolkitImplicitAuthorization implicit);
+ PolkitImplicitAuthorization implicit,
+ PolkitDetails *out_details);
G_DEFINE_TYPE_WITH_CODE (PolkitBackendLocalAuthority,
@@ -257,7 +258,8 @@ polkit_backend_local_authority_check_authorization_sync (PolkitBackendInteractiv
gboolean subject_is_active,
const gchar *action_id,
PolkitDetails *details,
- PolkitImplicitAuthorization implicit)
+ PolkitImplicitAuthorization implicit,
+ PolkitDetails *out_details)
{
PolkitBackendLocalAuthority *local_authority;
PolkitBackendLocalAuthorityPrivate *priv;
@@ -296,7 +298,8 @@ polkit_backend_local_authority_check_authorization_sync (PolkitBackendInteractiv
details,
&ret_any,
&ret_inactive,
- &ret_active))
+ &ret_active,
+ out_details))
{
if (subject_is_local && subject_is_active)
{
@@ -330,7 +333,8 @@ polkit_backend_local_authority_check_authorization_sync (PolkitBackendInteractiv
details,
&ret_any,
&ret_inactive,
- &ret_active))
+ &ret_active,
+ out_details))
{
if (subject_is_local && subject_is_active)
{
diff --git a/src/polkitbackend/polkitbackendlocalauthorizationstore.c b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
index 1c898f7..bdd0103 100644
--- a/src/polkitbackend/polkitbackendlocalauthorizationstore.c
+++ b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
@@ -21,6 +21,7 @@
#include "config.h"
+#include <string.h>
#include <polkit/polkit.h>
#include "polkitbackendlocalauthorizationstore.h"
@@ -79,6 +80,8 @@ typedef struct
PolkitImplicitAuthorization result_any;
PolkitImplicitAuthorization result_inactive;
PolkitImplicitAuthorization result_active;
+
+ GHashTable *return_value;
} LocalAuthorization;
static void
@@ -89,6 +92,8 @@ local_authorization_free (LocalAuthorization *authorization)
g_list_free (authorization->identity_specs);
g_list_foreach (authorization->action_specs, (GFunc) g_pattern_spec_free, NULL);
g_list_free (authorization->action_specs);
+ if (authorization->return_value != NULL)
+ g_hash_table_unref (authorization->return_value);
g_free (authorization);
}
@@ -105,6 +110,7 @@ local_authorization_new (GKeyFile *key_file,
gchar *result_any_string;
gchar *result_inactive_string;
gchar *result_active_string;
+ gchar **return_value_strings;
guint n;
identity_strings = NULL;
@@ -112,6 +118,7 @@ local_authorization_new (GKeyFile *key_file,
result_any_string = NULL;
result_inactive_string = NULL;
result_active_string = NULL;
+ return_value_strings = NULL;
authorization = g_new0 (LocalAuthorization, 1);
@@ -221,6 +228,42 @@ local_authorization_new (GKeyFile *key_file,
goto out;
}
+ return_value_strings = g_key_file_get_string_list (key_file,
+ group,
+ "ReturnValue",
+ NULL,
+ error);
+ if (return_value_strings != NULL)
+ {
+ for (n = 0; return_value_strings[n] != NULL; n++)
+ {
+ gchar *p;
+ const gchar *key;
+ const gchar *value;
+
+ p = strchr (return_value_strings[n], '=');
+ if (p == NULL)
+ {
+ g_warning ("Item `%s' in ReturnValue is malformed. Ignoring.",
+ return_value_strings[n]);
+ continue;
+ }
+
+ *p = '\0';
+ key = return_value_strings[n];
+ value = p + 1;
+
+ if (authorization->return_value == NULL)
+ {
+ authorization->return_value = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+ }
+ g_hash_table_insert (authorization->return_value, g_strdup (key), g_strdup (value));
+ }
+ }
+
authorization->id = g_strdup_printf ("%s::%s", filename, group);
out:
@@ -229,6 +272,7 @@ local_authorization_new (GKeyFile *key_file,
g_free (result_any_string);
g_free (result_inactive_string);
g_free (result_active_string);
+ g_strfreev (return_value_strings);
return authorization;
}
@@ -605,6 +649,7 @@ polkit_backend_local_authorization_store_ensure (PolkitBackendLocalAuthorization
* @out_result_any: Return location for the result for any subjects if the look up matched.
* @out_result_inactive: Return location for the result for subjects in local inactive sessions if the look up matched.
* @out_result_active: Return location for the result for subjects in local active sessions if the look up matched.
+ * @out_details: %NULL or a #PolkitDetails object to append key/value pairs to on a positive match.
*
* Checks if an authorization entry from @store matches @identity, @action_id and @details.
*
@@ -618,7 +663,8 @@ polkit_backend_local_authorization_store_lookup (PolkitBackendLocalAuthorization
PolkitDetails *details,
PolkitImplicitAuthorization *out_result_any,
PolkitImplicitAuthorization *out_result_inactive,
- PolkitImplicitAuthorization *out_result_active)
+ PolkitImplicitAuthorization *out_result_active,
+ PolkitDetails *out_details)
{
GList *l, *ll;
gboolean ret;
@@ -667,6 +713,19 @@ polkit_backend_local_authorization_store_lookup (PolkitBackendLocalAuthorization
*out_result_active = authorization->result_active;
ret = TRUE;
+ if (out_details != NULL && authorization->return_value != NULL)
+ {
+ GHashTableIter iter;
+ const gchar *key;
+ const gchar *value;
+
+ g_hash_table_iter_init (&iter, authorization->return_value);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value))
+ {
+ polkit_details_insert (out_details, key, value);
+ }
+ }
+
#if 0
g_debug ("authorization with id `%s' matched action_id `%s' for identity `%s'",
authorization->id,
diff --git a/src/polkitbackend/polkitbackendlocalauthorizationstore.h b/src/polkitbackend/polkitbackendlocalauthorizationstore.h
index 2f2b452..865bf22 100644
--- a/src/polkitbackend/polkitbackendlocalauthorizationstore.h
+++ b/src/polkitbackend/polkitbackendlocalauthorizationstore.h
@@ -77,7 +77,8 @@ gboolean polkit_backend_local_authorization_store_lookup (PolkitBackendLocalA
PolkitDetails *details,
PolkitImplicitAuthorization *out_result_any,
PolkitImplicitAuthorization *out_result_inactive,
- PolkitImplicitAuthorization *out_result_active);
+ PolkitImplicitAuthorization *out_result_active,
+ PolkitDetails *out_details);
G_END_DECLS
diff --git a/src/programs/Makefile.am b/src/programs/Makefile.am
index 074fb39..226c9f3 100644
--- a/src/programs/Makefile.am
+++ b/src/programs/Makefile.am
@@ -17,7 +17,7 @@ INCLUDES = \
# ----------------------------------------------------------------------------------------------------
-bin_PROGRAMS = pkexec pkcheck pkaction
+bin_PROGRAMS = pkexec pkcheck pkaction pklalockdown
# ----------------------------------------------------------------------------------------------------
@@ -82,6 +82,19 @@ pkaction_LDADD = \
# ----------------------------------------------------------------------------------------------------
+pklalockdown_SOURCES = pklalockdown.c
+
+pklalockdown_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(NULL)
+
+pklalockdown_LDADD = \
+ $(GLIB_LDADD) \
+ $(top_builddir)/src/polkit/libpolkit-gobject-1.la \
+ $(NULL)
+
+# ----------------------------------------------------------------------------------------------------
+
clean-local :
rm -f *~
diff --git a/src/programs/pklalockdown.c b/src/programs/pklalockdown.c
new file mode 100644
index 0000000..88ce660
--- /dev/null
+++ b/src/programs/pklalockdown.c
@@ -0,0 +1,243 @@
+/*
+ * 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>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <errno.h>
+#include <glib/gstdio.h>
+
+#include <polkit/polkit.h>
+
+static gchar *get_lockdown_filename (const gchar *action_id);
+static gboolean lockdown_exists (const gchar *action_id);
+
+
+static void
+usage (int argc, char *argv[])
+{
+ GError *error;
+
+ error = NULL;
+ if (!g_spawn_command_line_sync ("man pklalockdown",
+ NULL,
+ NULL,
+ NULL,
+ &error))
+ {
+ g_printerr ("Cannot show manual page: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ guint n;
+ guint ret;
+ gboolean opt_show_help;
+ gboolean opt_show_version;
+ gchar *opt_lockdown;
+ gchar *opt_remove_lockdown;
+
+ ret = 1;
+
+ opt_show_help = FALSE;
+ opt_show_version = FALSE;
+ opt_lockdown = NULL;
+ opt_remove_lockdown = NULL;
+
+ /* if we are not yet uid 0, make us uid 0 through pkexec */
+ if (getuid () != 0)
+ {
+ gchar **exec_argv;
+
+ exec_argv = g_new0 (gchar *, argc + 2);
+ exec_argv[0] = PACKAGE_BIN_DIR "/pkexec";
+ memcpy (exec_argv + 1, argv, argc * sizeof (gchar *));
+
+ if (execv (PACKAGE_BIN_DIR "/pkexec", exec_argv) != 0)
+ {
+ g_printerr ("Error executing " PACKAGE_BIN_DIR "/pkexec: %s\n", g_strerror (errno));
+ goto out;
+ }
+
+ g_assert_not_reached ();
+ }
+
+ /* We are now uid 0 (by default, the user had to authenticate to get
+ * here) - be careful to check all incoming args
+ */
+ for (n = 1; n < (guint) argc; n++)
+ {
+ if (strcmp (argv[n], "--help") == 0)
+ {
+ opt_show_help = TRUE;
+ }
+ else if (strcmp (argv[n], "--version") == 0)
+ {
+ opt_show_version = TRUE;
+ }
+ else if (strcmp (argv[n], "--lockdown") == 0 || strcmp (argv[n], "-l") == 0)
+ {
+ n++;
+ if (n >= (guint) argc)
+ {
+ usage (argc, argv);
+ goto out;
+ }
+
+ opt_lockdown = g_strdup (argv[n]);
+ }
+ else if (strcmp (argv[n], "--remove-lockdown") == 0 || strcmp (argv[n], "-r") == 0)
+ {
+ n++;
+ if (n >= (guint) argc)
+ {
+ usage (argc, argv);
+ goto out;
+ }
+
+ opt_remove_lockdown = g_strdup (argv[n]);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (opt_show_help)
+ {
+ usage (argc, argv);
+ ret = 0;
+ goto out;
+ }
+ else if (opt_show_version)
+ {
+ g_print ("pkexec version %s\n", PACKAGE_VERSION);
+ ret = 0;
+ goto out;
+ }
+ else if (opt_lockdown != NULL)
+ {
+ gchar *filename;
+ gchar *contents;
+ GError *error;
+
+ if (lockdown_exists (opt_lockdown))
+ {
+ g_printerr ("Error: action %s is already locked down\n", opt_lockdown);
+ goto out;
+ }
+
+ filename = get_lockdown_filename (opt_lockdown);
+ 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.localauthority.lockdown=1",
+ opt_lockdown);
+ error = NULL;
+ if (!g_file_set_contents (filename,
+ contents,
+ -1,
+ &error))
+ {
+ g_printerr ("Error: Cannot write to file %s: %s\n", filename, error->message);
+ g_error_free (error);
+ g_free (filename);
+ g_free (contents);
+ goto out;
+ }
+ g_free (filename);
+ g_free (contents);
+ ret = 0;
+ goto out;
+ }
+ else if (opt_remove_lockdown != NULL)
+ {
+ gchar *filename;
+
+ if (!lockdown_exists (opt_remove_lockdown))
+ {
+ g_printerr ("Error: action %s is not locked down\n", opt_remove_lockdown);
+ goto out;
+ }
+
+ filename = get_lockdown_filename (opt_remove_lockdown);
+ if (g_unlink (filename) != 0)
+ {
+ g_printerr ("Error: Cannot unlink file %s: %s\n", filename, g_strerror (errno));
+ g_free (filename);
+ goto out;
+ }
+ g_free (filename);
+
+ ret = 0;
+ goto out;
+ }
+
+ usage (argc, argv);
+
+ out:
+ g_free (opt_lockdown);
+ g_free (opt_remove_lockdown);
+ return ret;
+}
+
+static gchar *
+get_lockdown_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 = get_lockdown_filename (action_id);
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
+ ret = TRUE;
+ g_free (filename);
+
+ return ret;
+}
+