[tracker/wip/carlosg/portal: 27/41] portal: Implement filtering endpoint



commit 5e86850cd0be0a12fa2e9cb1f1f1d07605af213a
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Jan 23 12:21:37 2020 +0100

    portal: Implement filtering endpoint
    
    This endpoint is a private subclass that manipulates communication
    so
    1) session endpoints can only be used by their original creator
    2) all update queries are forbidden
    3) GraphUpdated filters down events on disallowed graphs
    4) Queries are prepended CONSTRAINT clauses
    
    This makes sandboxed endpoints restricted so:
    - Updates cannot happen
    - Graphs/Services in queries get filtered down
    - GraphUpdated signals avoid filtered down graphs

 src/portal/meson.build               |   1 +
 src/portal/tracker-portal-endpoint.c | 220 +++++++++++++++++++++++++++++++++++
 src/portal/tracker-portal-endpoint.h |  43 +++++++
 src/portal/tracker-portal.c          |  55 ++++++++-
 4 files changed, 313 insertions(+), 6 deletions(-)
---
diff --git a/src/portal/meson.build b/src/portal/meson.build
index 5c9849844..2a508079d 100644
--- a/src/portal/meson.build
+++ b/src/portal/meson.build
@@ -1,6 +1,7 @@
 sources = [
     'tracker-main.c',
     'tracker-portal.c',
+    'tracker-portal-endpoint.c',
     'tracker-portal-utils.c',
 ]
 
diff --git a/src/portal/tracker-portal-endpoint.c b/src/portal/tracker-portal-endpoint.c
new file mode 100644
index 000000000..cebd6b590
--- /dev/null
+++ b/src/portal/tracker-portal-endpoint.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+#include "config.h"
+
+#include <libtracker-sparql/tracker-sparql.h>
+
+#include "libtracker-sparql/tracker-private.h"
+
+#include "tracker-portal-endpoint.h"
+
+typedef struct _TrackerPortalEndpoint TrackerPortalEndpoint;
+typedef struct _TrackerPortalEndpointClass TrackerPortalEndpointClass;
+
+struct _TrackerPortalEndpoint
+{
+       TrackerEndpointDBus parent_instance;
+       gchar *peer;
+       gchar *prologue;
+       GStrv graphs;
+};
+
+struct _TrackerPortalEndpointClass
+{
+       TrackerEndpointDBusClass parent_class;
+};
+
+enum {
+       PROP_GRAPHS = 1,
+       PROP_PEER,
+       N_PROPS
+};
+
+static GParamSpec *props[N_PROPS] = { 0 };
+
+G_DEFINE_TYPE (TrackerPortalEndpoint, tracker_portal_endpoint, TRACKER_TYPE_ENDPOINT_DBUS)
+
+static gboolean
+tracker_portal_endpoint_forbid_operation (TrackerEndpointDBus   *endpoint_dbus,
+                                          GDBusMethodInvocation *invocation,
+                                          TrackerOperationType   operation_type)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (endpoint_dbus);
+
+       if (operation_type == TRACKER_OPERATION_TYPE_UPDATE)
+               return TRUE;
+       if (g_strcmp0 (endpoint->peer, g_dbus_method_invocation_get_sender (invocation)) != 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean
+tracker_portal_endpoint_filter_graph (TrackerEndpointDBus *endpoint_dbus,
+                                      const gchar         *graph_name)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (endpoint_dbus);
+       gint i;
+
+       for (i = 0; endpoint->graphs[i]; i++) {
+               if (g_strcmp0 (graph_name, endpoint->graphs[i]) == 0) {
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+static gchar *
+tracker_portal_endpoint_add_prologue (TrackerEndpointDBus *endpoint_dbus)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (endpoint_dbus);
+
+       if (!endpoint->prologue) {
+               GString *str;
+               gint i;
+
+               str = g_string_new ("CONSTRAINT SERVICE \n"
+                                   "CONSTRAINT GRAPH ");
+
+               for (i = 0; endpoint->graphs[i]; i++) {
+                       if (i != 0)
+                               g_string_append (str, ", ");
+
+                       g_string_append_printf (str, "<%s>", endpoint->graphs[i]);
+               }
+
+               endpoint->prologue = g_string_free (str, FALSE);
+       }
+
+       return g_strdup (endpoint->prologue);
+}
+
+static void
+tracker_portal_endpoint_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (object);
+
+       switch (prop_id) {
+       case PROP_GRAPHS:
+               endpoint->graphs = g_value_dup_boxed (value);
+               break;
+       case PROP_PEER:
+               endpoint->peer = g_value_dup_string (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+tracker_portal_endpoint_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (object);
+
+       switch (prop_id) {
+       case PROP_GRAPHS:
+               g_value_set_boxed (value, endpoint->graphs);
+               break;
+       case PROP_PEER:
+               g_value_set_string (value, endpoint->peer);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+tracker_portal_endpoint_finalize (GObject *object)
+{
+       TrackerPortalEndpoint *endpoint = TRACKER_PORTAL_ENDPOINT (object);
+
+       g_strfreev (endpoint->graphs);
+       g_free (endpoint->peer);
+       g_free (endpoint->prologue);
+
+       G_OBJECT_CLASS (tracker_portal_endpoint_parent_class)->finalize (object);
+}
+
+static void
+tracker_portal_endpoint_class_init (TrackerPortalEndpointClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       TrackerEndpointDBusClass *endpoint_dbus_class = TRACKER_ENDPOINT_DBUS_CLASS (klass);
+
+       object_class->set_property = tracker_portal_endpoint_set_property;
+       object_class->get_property = tracker_portal_endpoint_get_property;
+       object_class->finalize = tracker_portal_endpoint_finalize;
+
+       endpoint_dbus_class->forbid_operation = tracker_portal_endpoint_forbid_operation;
+       endpoint_dbus_class->filter_graph = tracker_portal_endpoint_filter_graph;
+       endpoint_dbus_class->add_prologue = tracker_portal_endpoint_add_prologue;
+
+       props[PROP_GRAPHS] =
+               g_param_spec_boxed ("graphs",
+                                   "Graphs",
+                                   "Graphs",
+                                   G_TYPE_STRV,
+                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+       props[PROP_PEER] =
+               g_param_spec_string ("peer",
+                                    "DBus peer",
+                                    "DBus peer",
+                                    NULL,
+                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+       g_object_class_install_properties (object_class, N_PROPS, props);
+}
+
+static void
+tracker_portal_endpoint_init (TrackerPortalEndpoint *portal_endpoint)
+{
+}
+
+TrackerEndpoint *
+tracker_portal_endpoint_new (TrackerSparqlConnection  *sparql_connection,
+                             GDBusConnection          *dbus_connection,
+                             const gchar              *object_path,
+                             const gchar              *peer,
+                             const gchar * const      *graphs,
+                             GCancellable             *cancellable,
+                             GError                  **error)
+{
+       g_return_val_if_fail (TRACKER_IS_SPARQL_CONNECTION (sparql_connection), NULL);
+       g_return_val_if_fail (G_IS_DBUS_CONNECTION (dbus_connection), NULL);
+       g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+       g_return_val_if_fail (!error || !*error, NULL);
+
+       return g_initable_new (TRACKER_TYPE_PORTAL_ENDPOINT, cancellable, error,
+                              "dbus-connection", dbus_connection,
+                              "sparql-connection", sparql_connection,
+                              "object-path", object_path,
+                              "peer", peer,
+                              "graphs", graphs,
+                              NULL);
+
+}
diff --git a/src/portal/tracker-portal-endpoint.h b/src/portal/tracker-portal-endpoint.h
new file mode 100644
index 000000000..67b8eee7e
--- /dev/null
+++ b/src/portal/tracker-portal-endpoint.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+#ifndef __TRACKER_PORTAL_ENDPOINT_H__
+#define __TRACKER_PORTAL_ENDPOINT_H__
+
+#include <gio/gio.h>
+
+#define TRACKER_TYPE_PORTAL_ENDPOINT tracker_portal_endpoint_get_type ()
+#define TRACKER_PORTAL_ENDPOINT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_PORTAL_ENDPOINT, 
TrackerPortalEndpoint))
+#define TRACKER_PORTAL_ENDPOINT_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_PORTAL_ENDPOINT, 
TrackerPortalEndpointClass))
+#define TRACKER_IS_PORTAL_ENDPOINT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_PORTAL_ENDPOINT))
+#define TRACKER_IS_PORTAL_ENDPOINT_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c),  TRACKER_TYPE_PORTAL_ENDPOINT))
+#define TRACKER_PORTAL_ENDPOINT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_PORTAL_ENDPOINT, 
TrackerPortalEndpointClass))
+
+typedef struct _TrackerPortalEndpoint TrackerPortalEndpoint;
+
+TrackerEndpoint * tracker_portal_endpoint_new (TrackerSparqlConnection  *sparql_connection,
+                                               GDBusConnection          *dbus_connection,
+                                               const gchar              *object_path,
+                                               const gchar              *peer,
+                                               const gchar * const      *graphs,
+                                               GCancellable             *cancellable,
+                                               GError                  **error);
+
+#endif /* __TRACKER_PORTAL_ENDPOINT_H__ */
diff --git a/src/portal/tracker-portal.c b/src/portal/tracker-portal.c
index 87c2832e3..15c3ec783 100644
--- a/src/portal/tracker-portal.c
+++ b/src/portal/tracker-portal.c
@@ -25,6 +25,8 @@
 #include <libtracker-common/tracker-common.h>
 
 #include "tracker-portal.h"
+#include "tracker-portal-endpoint.h"
+#include "tracker-portal-utils.h"
 
 typedef struct _TrackerPortal TrackerPortal;
 typedef struct _TrackerSession TrackerSession;
@@ -61,6 +63,8 @@ static void tracker_portal_initable_iface_init (GInitableIface *iface);
 G_DEFINE_TYPE_WITH_CODE (TrackerPortal, tracker_portal, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, tracker_portal_initable_iface_init))
 
+#define TRACKER_GROUP_NAME "Policy Tracker3"
+
 static const gchar portal_xml[] =
        "<node>"
        "  <interface name='org.freedesktop.portal.Tracker'>"
@@ -168,6 +172,33 @@ tracker_portal_init (TrackerPortal *portal)
        g_array_set_clear_func (portal->sessions, clear_session);
 }
 
+static GStrv
+load_client_configuration (GDBusMethodInvocation  *invocation,
+                           const gchar            *service_uri,
+                           GError                **error)
+{
+       g_autoptr (GKeyFile) flatpak_info = NULL;
+       GStrv graphs;
+
+       flatpak_info = tracker_invocation_lookup_app_info_sync (invocation,
+                                                               NULL, error);
+       if (!flatpak_info) {
+               g_debug ("No .flatpak-info found, forbidden access.");
+               return NULL;
+       }
+
+       graphs = g_key_file_get_string_list (flatpak_info,
+                                            TRACKER_GROUP_NAME,
+                                            service_uri,
+                                            NULL, error);
+       if (!graphs) {
+               g_debug ("Service '%s' not found in Tracker policy", service_uri);
+               return NULL;
+       }
+
+       return graphs;
+}
+
 static void
 portal_iface_method_call (GDBusConnection       *connection,
                           const gchar           *sender,
@@ -189,12 +220,21 @@ portal_iface_method_call (GDBusConnection       *connection,
                g_autoptr(TrackerSparqlConnection) connection = NULL;
                g_autoptr(TrackerEndpoint) endpoint = NULL;
                g_autoptr(GError) error = NULL;
+               g_auto(GStrv) graphs = NULL;
+               const gchar *sender;
                GBusType bus_type;
                TrackerSession session;
 
                g_variant_get (parameters, "(s)", &uri);
                g_debug ("Creating session for service URI '%s'", uri);
 
+               graphs = load_client_configuration (invocation, uri, &error);
+               if (!graphs) {
+                       g_debug ("Session rejected by policy");
+                       g_dbus_method_invocation_return_gerror (invocation, error);
+                       return;
+               }
+
                if (!tracker_util_parse_dbus_uri (uri,
                                                  &bus_type,
                                                  &service,
@@ -224,12 +264,15 @@ portal_iface_method_call (GDBusConnection       *connection,
 
                session_object_path = g_strdup_printf ("/org/freedesktop/portal/Tracker/Session_%" 
G_GUINT64_FORMAT,
                                                       portal->session_ids++);
-
-               endpoint = TRACKER_ENDPOINT (tracker_endpoint_dbus_new (connection,
-                                                                       dbus_connection,
-                                                                       session_object_path,
-                                                                       NULL,
-                                                                       &error));
+               sender = g_dbus_method_invocation_get_sender (invocation);
+
+               endpoint = tracker_portal_endpoint_new (connection,
+                                                       dbus_connection,
+                                                       session_object_path,
+                                                       sender,
+                                                       (const gchar * const *) graphs,
+                                                       NULL,
+                                                       &error);
                if (!endpoint) {
                        g_debug ("Could not create endpoint");
                        g_dbus_method_invocation_return_gerror (invocation, error);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]