[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