begin writing the implementation of the local authorization backend
authorDavid Zeuthen <davidz@redhat.com>
Mon, 19 Jan 2009 21:29:35 +0000 (16:29 -0500)
committerDavid Zeuthen <davidz@redhat.com>
Mon, 19 Jan 2009 21:29:35 +0000 (16:29 -0500)
src/polkitbackend/polkitbackendlocalauthority.c

index b9f3e98..ba726ff 100644 (file)
@@ -36,8 +36,44 @@ typedef struct
 
   PolkitBackendSessionMonitor *session_monitor;
 
+  GHashTable *hash_identity_to_authority_store;
+
 } PolkitBackendLocalAuthorityPrivate;
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct AuthorizationStore;
+typedef struct AuthorizationStore AuthorizationStore;
+
+static AuthorizationStore *authorization_store_new (PolkitIdentity *identity);
+
+static void                authorization_store_free (AuthorizationStore *store);
+
+static GList              *authorization_store_get_all_authorizations (AuthorizationStore *store);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static AuthorizationStore *get_authorization_store_for_identity (PolkitBackendLocalAuthority *authority,
+                                                                 PolkitIdentity *identity);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean check_authorization_for_identity (PolkitBackendLocalAuthority *authority,
+                                                  PolkitIdentity              *identity,
+                                                  const gchar                 *action_id);
+
+static gboolean check_temporary_authorization_for_subject (PolkitBackendLocalAuthority *authority,
+                                                           PolkitSubject               *subject,
+                                                           const gchar                 *action_id);
+
+static GList *get_groups_for_user (PolkitBackendLocalAuthority *authority,
+                                   PolkitIdentity              *user);
+
+static GList *get_authorizations_for_identity (PolkitBackendLocalAuthority *authority,
+                                               PolkitIdentity              *identity);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void polkit_backend_local_authority_enumerate_actions  (PolkitBackendAuthority   *authority,
                                                                const gchar              *locale,
                                                                PolkitBackendPendingCall *pending_call);
@@ -74,6 +110,8 @@ static void polkit_backend_local_authority_remove_authorization (PolkitBackendAu
                                                                  PolkitAuthorization      *authorization,
                                                                  PolkitBackendPendingCall *pending_call);
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 G_DEFINE_TYPE (PolkitBackendLocalAuthority, polkit_backend_local_authority, POLKIT_BACKEND_TYPE_AUTHORITY);
 
 #define POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), POLKIT_BACKEND_TYPE_LOCAL_AUTHORITY, PolkitBackendLocalAuthorityPrivate))
@@ -90,6 +128,11 @@ polkit_backend_local_authority_init (PolkitBackendLocalAuthority *local_authorit
   priv->action_pool = polkit_backend_action_pool_new (action_desc_directory);
   g_object_unref (action_desc_directory);
 
+  priv->hash_identity_to_authority_store = g_hash_table_new_full ((GHashFunc) polkit_identity_hash,
+                                                                  (GEqualFunc) polkit_identity_equal,
+                                                                  (GDestroyNotify) g_object_unref,
+                                                                  (GDestroyNotify) authorization_store_free);
+
   priv->session_monitor = polkit_backend_session_monitor_new ();
 }
 
@@ -108,6 +151,8 @@ polkit_backend_local_authority_finalize (GObject *object)
   if (priv->session_monitor != NULL)
     g_object_unref (priv->session_monitor);
 
+  g_hash_table_unref (priv->hash_identity_to_authority_store);
+
   G_OBJECT_CLASS (polkit_backend_local_authority_parent_class)->finalize (object);
 }
 
@@ -328,13 +373,12 @@ polkit_backend_local_authority_check_authorization (PolkitBackendAuthority
     {
       /* TODO */
       result = POLKIT_AUTHORIZATION_RESULT_NOT_AUTHORIZED;
-#if 0
+
       result = check_authorization_sync (authority,
-                                         user_of_inquirer,
+                                         inquirer,
                                          "org.freedesktop.policykit.read",
                                          POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, /* no user interaction */
                                          &error);
-#endif
 
       if (error != NULL)
         {
@@ -348,7 +392,7 @@ polkit_backend_local_authority_check_authorization (PolkitBackendAuthority
                                                     POLKIT_ERROR,
                                                     POLKIT_ERROR_NOT_AUTHORIZED,
                                                     "%s is not authorized to know about authorizations for %s (requires org.freedesktop.policykit.read authorization)",
-                                                    user_of_inquirer_str,
+                                                    inquirer_str,
                                                     subject_str);
           goto out;
         }
@@ -393,12 +437,16 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
   PolkitAuthorizationResult result;
   PolkitIdentity *user_of_subject;
   gchar *subject_str;
+  GList *groups_of_user;
+  GList *l;
 
   local_authority = POLKIT_BACKEND_LOCAL_AUTHORITY (authority);
   priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (local_authority);
 
   result = POLKIT_AUTHORIZATION_RESULT_NOT_AUTHORIZED;
+
   user_of_subject = NULL;
+  groups_of_user = NULL;
   subject_str = NULL;
 
   subject_str = polkit_subject_to_string (subject);
@@ -407,19 +455,49 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
            subject_str,
            action_id);
 
+  /* every subject has a user */
   user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
                                                                          subject,
                                                                          error);
   if (user_of_subject == NULL)
       goto out;
 
+  /* special case: uid 0, root, is _always_ authorized for anything */
   if (POLKIT_IS_UNIX_USER (user_of_subject) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_subject)) == 0)
     {
-      /* uid 0, root, is _always_ authorized for anything */
       result = POLKIT_AUTHORIZATION_RESULT_AUTHORIZED;
       goto out;
     }
 
+  /* TODO: first see if there's an implicit authorization for subject available */
+
+  /* then see if there's a temporary authorization for the subject */
+  if (check_temporary_authorization_for_subject (local_authority, subject, action_id))
+    {
+      result = POLKIT_AUTHORIZATION_RESULT_AUTHORIZED;
+      goto out;
+    }
+
+  /* then see if we have an authorization for the user */
+  if (check_authorization_for_identity (local_authority, user_of_subject, action_id))
+    {
+      result = POLKIT_AUTHORIZATION_RESULT_AUTHORIZED;
+      goto out;
+    }
+
+  /* then see if we have an authorization for any of the groups the user is in */
+  groups_of_user = get_groups_for_user (local_authority, user_of_subject);
+  for (l = groups_of_user; l != NULL; l = l->next)
+    {
+      PolkitIdentity *group = POLKIT_IDENTITY (l->data);
+
+      if (check_authorization_for_identity (local_authority, group, action_id))
+        {
+          result = POLKIT_AUTHORIZATION_RESULT_AUTHORIZED;
+          goto out;
+        }
+    }
+
 #if 0
   g_set_error (error,
                POLKIT_ERROR,
@@ -429,11 +507,13 @@ check_authorization_sync (PolkitBackendAuthority         *authority,
 #endif
 
   /* TODO */
-  result = POLKIT_AUTHORIZATION_RESULT_NOT_AUTHORIZED;
 
  out:
   g_free (subject_str);
 
+  g_list_foreach (groups_of_user, (GFunc) g_object_unref, NULL);
+  g_list_free (groups_of_user);
+
   if (user_of_subject != NULL)
     g_object_unref (user_of_subject);
 
@@ -458,10 +538,11 @@ polkit_backend_local_authority_enumerate_authorizations (PolkitBackendAuthority
 
   g_debug ("enumerating authorizations for %s", identity_str);
 
-  polkit_backend_pending_call_return_error (pending_call,
-                                            POLKIT_ERROR,
-                                            POLKIT_ERROR_NOT_SUPPORTED,
-                                            "Not implemented (identity=%s)", identity_str);
+  /* TODO: check caller is authorized */
+
+  polkit_backend_authority_enumerate_authorizations_finish (pending_call,
+                                                            get_authorizations_for_identity (local_authority,
+                                                                                             identity));
 
   g_free (identity_str);
 }
@@ -549,3 +630,223 @@ polkit_backend_local_authority_remove_authorization (PolkitBackendAuthority   *a
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+
+struct AuthorizationStore
+{
+  PolkitIdentity *identity;
+
+  gchar *path;
+
+  GList *authorizations;
+
+  GList *temporary_authorizations;
+
+};
+
+/* private */
+static void  authorization_store_reload_permanent_authorizations (AuthorizationStore *store);
+
+static void
+authorization_store_free (AuthorizationStore *store)
+{
+  g_object_unref (store->identity);
+  g_list_foreach (store->authorizations, (GFunc) g_object_unref, NULL);
+  g_list_free (store->authorizations);
+  g_list_foreach (store->temporary_authorizations, (GFunc) g_object_unref, NULL);
+  g_list_free (store->temporary_authorizations);
+  g_free (store->path);
+  g_free (store);
+}
+
+static AuthorizationStore *
+authorization_store_new (PolkitIdentity *identity)
+{
+  AuthorizationStore *store;
+  gchar *filename;
+  gchar *identity_str;
+
+  store = NULL;
+  filename = NULL;
+
+  identity_str = polkit_identity_to_string (identity);
+
+  if (POLKIT_IS_UNIX_USER (identity))
+    {
+      filename = g_strdup_printf ("unix-user-%s.authz", identity_str + sizeof ("unix-user:") - 1);
+    }
+  else if (POLKIT_IS_UNIX_GROUP (identity))
+    {
+      filename = g_strdup_printf ("unix-group-%s.authz", identity_str + sizeof ("unix-group:") - 1);
+    }
+  else
+    {
+      g_error ("Unknown identity %s", identity_str);
+      goto out;
+    }
+
+  store = g_new0 (AuthorizationStore, 1);
+  store->identity = g_object_ref (identity);
+
+  if (filename != NULL)
+    store->path = g_strdup_printf (PACKAGE_LOCALSTATE_DIR "/lib/polkit-1/%s", filename);
+
+  authorization_store_reload_permanent_authorizations (store);
+
+ out:
+  g_free (filename);
+  g_free (identity_str);
+  return store;
+}
+
+static void
+authorization_store_reload_permanent_authorizations (AuthorizationStore *store)
+{
+  GError *error;
+  gchar *data;
+  gchar **lines;
+  gint n;
+
+  error = NULL;
+  data = NULL;
+
+  g_list_foreach (store->authorizations, (GFunc) g_object_unref, NULL);
+  g_list_free (store->authorizations);
+  store->authorizations = NULL;
+
+  if (store->path == NULL)
+    goto out;
+
+  if (!g_file_get_contents (store->path,
+                            &data,
+                            NULL,
+                            &error))
+    {
+      /* it's not a bug if the file doesn't exist */
+      if (error->code != G_FILE_ERROR_NOENT)
+        {
+          g_warning ("Error loading authorizations file at %s: %s", store->path, error->message);
+        }
+      g_error_free (error);
+      goto out;
+    }
+
+  lines = g_strsplit (data, "\n", 0);
+  for (n = 0; lines[n] != NULL; n++)
+    {
+      gchar *line = lines[n];
+      gchar **tokens;
+      guint num_tokens;
+      const gchar *action_id;
+      gboolean is_negative;
+      PolkitAuthorization *authorization;
+
+      tokens = g_strsplit (line, " ", 0);
+      num_tokens = g_strv_length (tokens);
+
+      if (num_tokens != 2)
+        {
+          g_warning ("Malformed authorizations line '%s' in file %s at line %d", line, store->path, n);
+          g_strfreev (tokens);
+          continue;
+        }
+
+      action_id = tokens[0];
+      is_negative = (strcmp (tokens[1], "1") == 0);
+
+      authorization = polkit_authorization_new (action_id, NULL, is_negative);
+
+      store->authorizations = g_list_prepend (store->authorizations, authorization);
+    }
+  g_strfreev (lines);
+
+ out:
+  g_free (data);
+}
+
+/* caller must free list after unreffing all elements */
+static GList *
+authorization_store_get_all_authorizations (AuthorizationStore *store)
+{
+  GList *result;
+
+  result = g_list_copy (store->authorizations);
+  result = g_list_concat (result, g_list_copy (store->temporary_authorizations));
+
+  g_list_foreach (result, (GFunc) g_object_ref, NULL);
+
+  return result;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static AuthorizationStore *
+get_authorization_store_for_identity (PolkitBackendLocalAuthority *authority,
+                                      PolkitIdentity *identity)
+{
+  PolkitBackendLocalAuthorityPrivate *priv;
+  AuthorizationStore *store;
+
+  priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
+
+  store = g_hash_table_lookup (priv->hash_identity_to_authority_store, identity);
+  if (store != NULL)
+    goto out;
+
+  store = authorization_store_new (identity);
+  if (store == NULL)
+    goto out;
+
+  g_hash_table_insert (priv->hash_identity_to_authority_store,
+                       g_object_ref (identity),
+                       store);
+
+ out:
+  return store;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+check_authorization_for_identity (PolkitBackendLocalAuthority *authority,
+                                  PolkitIdentity              *identity,
+                                  const gchar                 *action_id)
+{
+  /* TODO */
+  return FALSE;
+}
+
+static gboolean
+check_temporary_authorization_for_subject (PolkitBackendLocalAuthority *authority,
+                                           PolkitSubject               *subject,
+                                           const gchar                 *action_id)
+{
+  /* TODO */
+  return FALSE;
+}
+
+static GList *
+get_groups_for_user (PolkitBackendLocalAuthority *authority,
+                     PolkitIdentity              *user)
+{
+  /* TODO */
+  return NULL;
+}
+
+static GList *
+get_authorizations_for_identity (PolkitBackendLocalAuthority *authority,
+                                 PolkitIdentity              *identity)
+{
+  AuthorizationStore *store;
+  GList *result;
+
+  store = get_authorization_store_for_identity (authority, identity);
+  if (store == NULL)
+    goto out;
+
+  result = authorization_store_get_all_authorizations (store);
+
+ out:
+  return result;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */