[RFC PATCH] Add an 'owner' user to actions.
Christopher James Halse Rogers
christopher.halse.rogers at canonical.com
Tue Sep 13 12:33:43 PDT 2011
From: Christopher James Halse Rogers <raof at ubuntu.com>
This allows specifying a PolkitIdentity 'owner' in the action definition.
A process running with that identity may query whether other users are
authorized for that action.
This allows non-root services to use PolicyKit for access control
---
This is prompted by colord, which has some D-Bus API which wants to be protected
by a PolicyKit access control, but colord itself doesn't need to run as root.
This patch needs some cleanup - it needs documentation fixes, copying identities
via identity->string->identity is ugly (and leaks at the moment), and we probably
want to allow default owners in the configuration.
src/polkit/polkitactiondescription.c | 38 ++++++++++++++++++-
src/polkit/polkitactiondescription.h | 1 +
src/polkit/polkitprivate.h | 1 +
src/polkitbackend/polkitbackendactionpool.c | 37 +++++++++++++++++++
.../polkitbackendinteractiveauthority.c | 33 +++++++++++++++--
5 files changed, 104 insertions(+), 6 deletions(-)
diff --git a/src/polkit/polkitactiondescription.c b/src/polkit/polkitactiondescription.c
index 4bd9604..1019daa 100644
--- a/src/polkit/polkitactiondescription.c
+++ b/src/polkit/polkitactiondescription.c
@@ -29,6 +29,8 @@
#include "polkitprivate.h"
+#include "polkitidentity.h"
+
/**
* SECTION:polkitactiondescription
* @title: PolkitActionDescription
@@ -51,6 +53,7 @@ struct _PolkitActionDescription
gchar *vendor_name;
gchar *vendor_url;
gchar *icon_name;
+ PolkitIdentity *owner;
PolkitImplicitAuthorization implicit_any;
PolkitImplicitAuthorization implicit_inactive;
PolkitImplicitAuthorization implicit_active;
@@ -87,6 +90,7 @@ polkit_action_description_finalize (GObject *object)
g_free (action_description->vendor_name);
g_free (action_description->vendor_url);
g_free (action_description->icon_name);
+ g_object_unref (action_description->owner);
g_hash_table_unref (action_description->annotations);
g_strfreev (action_description->annotation_keys);
@@ -241,6 +245,27 @@ polkit_action_description_get_icon_name (PolkitActionDescription *action_descrip
}
/**
+ * polkit_action_description_get_owner:
+ * @action_description: A #PolkitActionDescription.
+ *
+ * Gets the #PolkitIdentity of the user that own this action.
+ * The owner of an action can query whether a subject is authorised to
+ * perform this action, and can request an authentication dialog.
+ *
+ * Returns: transfer-full: The #PolkitIdentity of the owner of @action_description.
+ * Free with g_object_unref().
+ */
+
+PolkitIdentity *
+polkit_action_description_get_owner (PolkitActionDescription *action_description)
+{
+ g_return_val_if_fail (POLKIT_IS_ACTION_DESCRIPTION (action_description), NULL);
+ return polkit_identity_from_string (polkit_identity_to_string (action_description->owner),
+ NULL);
+}
+
+
+/**
* polkit_action_description_get_annotation:
* @action_description: A #PolkitActionDescription.
* @key: An annotation key.
@@ -299,6 +324,7 @@ polkit_action_description_new (const gchar *action_id,
const gchar *vendor_name,
const gchar *vendor_url,
const gchar *icon_name,
+ PolkitIdentity *owner,
PolkitImplicitAuthorization implicit_any,
PolkitImplicitAuthorization implicit_inactive,
PolkitImplicitAuthorization implicit_active,
@@ -313,6 +339,7 @@ polkit_action_description_new (const gchar *action_id,
ret->vendor_name = g_strdup (vendor_name);
ret->vendor_url = g_strdup (vendor_url);
ret->icon_name = g_strdup (icon_name);
+ ret->owner = g_object_ref (owner);
ret->implicit_any = implicit_any;
ret->implicit_inactive = implicit_inactive;
ret->implicit_active = implicit_active;
@@ -328,22 +355,28 @@ polkit_action_description_new_for_gvariant (GVariant *value)
PolkitActionDescription *action_description;
GVariantIter iter;
GVariant *annotations_dict;
+ gchar *user_str;
gchar *a_key;
gchar *a_value;
action_description = POLKIT_ACTION_DESCRIPTION (g_object_new (POLKIT_TYPE_ACTION_DESCRIPTION, NULL));
g_variant_get (value,
- "(ssssssuuu at a{ss})",
+ "(sssssssuuu at a{ss})",
&action_description->action_id,
&action_description->description,
&action_description->message,
&action_description->vendor_name,
&action_description->vendor_url,
&action_description->icon_name,
+ &user_str,
&action_description->implicit_any,
&action_description->implicit_inactive,
&action_description->implicit_active,
&annotations_dict);
+
+ action_description->owner = polkit_identity_from_string (user_str, NULL);
+ g_free (user_str);
+
g_variant_iter_init (&iter, annotations_dict);
while (g_variant_iter_next (&iter, "{ss}", &a_key, &a_value))
g_hash_table_insert (action_description->annotations, a_key, a_value); /* adopts a_key and a_value */
@@ -368,13 +401,14 @@ polkit_action_description_to_gvariant (PolkitActionDescription *action_descripti
g_variant_builder_add (&builder, "{ss}", a_key, a_value);
/* TODO: note 'foo ? : ""' is a gcc specific extension (it's a short-hand for 'foo ? foo : ""') */
- value = g_variant_new ("(ssssssuuua{ss})",
+ value = g_variant_new ("(sssssssuuua{ss})",
action_description->action_id ? : "",
action_description->description ? : "",
action_description->message ? : "",
action_description->vendor_name ? : "",
action_description->vendor_url ? : "",
action_description->icon_name ? : "",
+ polkit_identity_to_string (action_description->owner),
action_description->implicit_any,
action_description->implicit_inactive,
action_description->implicit_active,
diff --git a/src/polkit/polkitactiondescription.h b/src/polkit/polkitactiondescription.h
index c900624..d238e42 100644
--- a/src/polkit/polkitactiondescription.h
+++ b/src/polkit/polkitactiondescription.h
@@ -51,6 +51,7 @@ const gchar *polkit_action_description_get_message (PolkitActi
const gchar *polkit_action_description_get_vendor_name (PolkitActionDescription *action_description);
const gchar *polkit_action_description_get_vendor_url (PolkitActionDescription *action_description);
const gchar *polkit_action_description_get_icon_name (PolkitActionDescription *action_description);
+PolkitIdentity *polkit_action_description_get_owner (PolkitActionDescription *action_description);
PolkitImplicitAuthorization polkit_action_description_get_implicit_any (PolkitActionDescription *action_description);
PolkitImplicitAuthorization polkit_action_description_get_implicit_inactive (PolkitActionDescription *action_description);
diff --git a/src/polkit/polkitprivate.h b/src/polkit/polkitprivate.h
index 579cc25..1983098 100644
--- a/src/polkit/polkitprivate.h
+++ b/src/polkit/polkitprivate.h
@@ -54,6 +54,7 @@ polkit_action_description_new (const gchar *action_id,
const gchar *vendor_name,
const gchar *vendor_url,
const gchar *icon_name,
+ PolkitIdentity *owner,
PolkitImplicitAuthorization implicit_any,
PolkitImplicitAuthorization implicit_inactive,
PolkitImplicitAuthorization implicit_active,
diff --git a/src/polkitbackend/polkitbackendactionpool.c b/src/polkitbackend/polkitbackendactionpool.c
index e3ed38d..32a399d 100644
--- a/src/polkitbackend/polkitbackendactionpool.c
+++ b/src/polkitbackend/polkitbackendactionpool.c
@@ -47,6 +47,8 @@ typedef struct
gchar *description;
gchar *message;
+ PolkitIdentity *owner;
+
PolkitImplicitAuthorization implicit_authorization_any;
PolkitImplicitAuthorization implicit_authorization_inactive;
PolkitImplicitAuthorization implicit_authorization_active;
@@ -69,6 +71,8 @@ parsed_action_free (ParsedAction *action)
g_free (action->description);
g_free (action->message);
+ g_object_unref (action->owner);
+
g_hash_table_unref (action->localized_description);
g_hash_table_unref (action->localized_message);
@@ -398,6 +402,7 @@ polkit_backend_action_pool_get_action (PolkitBackendActionPool *pool,
parsed_action->vendor_name,
parsed_action->vendor_url,
parsed_action->icon_name,
+ parsed_action->owner,
parsed_action->implicit_authorization_any,
parsed_action->implicit_authorization_inactive,
parsed_action->implicit_authorization_active,
@@ -573,6 +578,7 @@ enum {
STATE_IN_ACTION_VENDOR,
STATE_IN_ACTION_VENDOR_URL,
STATE_IN_ACTION_ICON_NAME,
+ STATE_IN_ACTION_OWNER,
STATE_IN_DEFAULTS,
STATE_IN_DEFAULTS_ALLOW_ANY,
STATE_IN_DEFAULTS_ALLOW_INACTIVE,
@@ -597,6 +603,8 @@ typedef struct {
char *vendor_url;
char *icon_name;
+ PolkitIdentity *owner;
+
PolkitImplicitAuthorization implicit_authorization_any;
PolkitImplicitAuthorization implicit_authorization_inactive;
PolkitImplicitAuthorization implicit_authorization_active;
@@ -629,6 +637,12 @@ pd_unref_action_data (ParserData *pd)
g_free (pd->icon_name);
pd->icon_name = NULL;
+ if (pd->owner != NULL)
+ {
+ g_object_unref (pd->owner);
+ pd->owner = NULL;
+ }
+
g_free (pd->policy_description_nolang);
pd->policy_description_nolang = NULL;
g_free (pd->policy_message_nolang);
@@ -761,6 +775,10 @@ _start (void *data, const char *el, const char **attr)
{
state = STATE_IN_ACTION_ICON_NAME;
}
+ else if (strcmp (el, "owner") == 0)
+ {
+ state = STATE_IN_ACTION_OWNER;
+ }
else if (strcmp (el, "annotate") == 0)
{
if (num_attr != 2 || strcmp (attr[0], "key") != 0)
@@ -923,6 +941,22 @@ _cdata (void *data, const char *s, int len)
str = NULL;
break;
+ case STATE_IN_ACTION_OWNER:
+ {
+ PolkitIdentity *owner = polkit_identity_from_string (str, NULL);
+ if (owner == NULL)
+ {
+ g_warning ("Owner identity '%s' is invalid", str);
+ goto error;
+ }
+ if (pd->owner != NULL)
+ {
+ g_object_unref (pd->owner);
+ }
+ pd->owner = owner;
+ break;
+ }
+
case STATE_IN_DEFAULTS_ALLOW_ANY:
if (!polkit_implicit_authorization_from_string (str, &pd->implicit_authorization_any))
goto error;
@@ -992,6 +1026,9 @@ _end (void *data, const char *el)
action->vendor_name = g_strdup (vendor);
action->vendor_url = g_strdup (vendor_url);
action->icon_name = g_strdup (icon_name);
+ if (pd->owner == NULL)
+ pd->owner = polkit_unix_user_new (0);
+ action->owner = g_object_ref (pd->owner);
action->description = g_strdup (pd->policy_description_nolang);
action->message = g_strdup (pd->policy_message_nolang);
diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
index 8b32459..7c2fbb7 100644
--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
+++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
@@ -765,12 +765,14 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
gchar *subject_str;
PolkitIdentity *user_of_caller;
PolkitIdentity *user_of_subject;
+ PolkitIdentity *owner_of_action;
gchar *user_of_caller_str;
gchar *user_of_subject_str;
PolkitAuthorizationResult *result;
PolkitImplicitAuthorization implicit_authorization;
GError *error;
GSimpleAsyncResult *simple;
+ PolkitActionDescription *action_desc;
gboolean has_details;
gchar **detail_keys;
@@ -782,6 +784,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
subject_str = NULL;
user_of_caller = NULL;
user_of_subject = NULL;
+ owner_of_action = NULL;
user_of_caller_str = NULL;
user_of_subject_str = NULL;
result = NULL;
@@ -839,6 +842,26 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
user_of_subject_str = polkit_identity_to_string (user_of_subject);
g_debug (" user of subject is %s", user_of_subject_str);
+ /* get the action description */
+ action_desc = polkit_backend_action_pool_get_action (priv->action_pool,
+ action_id,
+ NULL);
+
+ if (action_desc == NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ POLKIT_ERROR,
+ POLKIT_ERROR_NOT_AUTHORIZED,
+ "Action %s is not registered",
+ action_id);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+
+ owner_of_action = polkit_action_description_get_owner (action_desc);
+ g_debug (" owner of action is %s", polkit_identity_to_string (owner_of_action));
+
has_details = FALSE;
if (details != NULL)
{
@@ -852,13 +875,12 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
}
if (!polkit_identity_equal (user_of_caller, user_of_subject) || has_details)
{
- /* we only allow trusted callers (uid 0 + others) to check authorizations for subjects
+ /* we only allow trusted callers (uid 0 or the owner) to check authorizations for subjects
* they don't own - and only if there are no details passed (to avoid spoofing dialogs).
- *
- * TODO: allow other uids like 'haldaemon'?
*/
if (!POLKIT_IS_UNIX_USER (user_of_caller) ||
- polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0)
+ (polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0 &&
+ !polkit_identity_equal (user_of_caller, owner_of_action)))
{
if (has_details)
{
@@ -948,6 +970,9 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority
if (user_of_subject != NULL)
g_object_unref (user_of_subject);
+ if (action_desc != NULL)
+ g_object_unref (action_desc);
+
g_free (caller_str);
g_free (subject_str);
g_free (user_of_caller_str);
--
1.7.5.4
More information about the polkit-devel
mailing list