commit f87110fd2341e4c5f5ba23a370f957b62b69c1e9 Author: Christopher James Halse Rogers Date: Mon Sep 12 16:54:42 2011 -0500 Add an 'owner' user to actions. 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 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@a{ss})", + "(sssssssuuu@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);