kdbus: support for libdbuspolicy 08/53208/5
authorLukasz Skalski <l.skalski@samsung.com>
Wed, 2 Dec 2015 16:57:14 +0000 (17:57 +0100)
committerLukasz Skalski <l.skalski@samsung.com>
Tue, 12 Jan 2016 18:11:25 +0000 (19:11 +0100)
Change-Id: I634ed6d0eeb7a27df504624577de5c22d2806a69

configure.ac
gio/Makefile.am
gio/gkdbus.c
gio/gkdbus.h
packaging/glib2.spec

index 0d707aa..9dbe056 100644 (file)
@@ -245,6 +245,10 @@ AC_ARG_ENABLE(rebuilds,
               [AS_HELP_STRING([--disable-rebuilds],
                               [disable all source autogeneration rules])],,
               [enable_rebuilds=yes])
+AC_ARG_ENABLE(libdbuspolicy,
+              [AS_HELP_STRING([--enable-libdbuspolicy],
+                              [enable libdbuspolicy for kdbus transport [default=no]])],,
+              [enable_libdbuspolicy=no])
 
 GLIB_TESTS
 
@@ -262,6 +266,16 @@ AS_IF([test "x$disable_mem_pools" = "xno"], [
   AC_MSG_RESULT([yes])
 ])
 
+AC_MSG_CHECKING([whether to enable libdbuspolicy for kdbus transport])
+AM_CONDITIONAL(LIBDBUSPOLICY, [test "x$enable_libdbuspolicy" = "xyes"])
+AS_IF([test "x$enable_libdbuspolicy" = "xyes"], [
+  PKG_CHECK_MODULES(LIBDBUSPOLICY1, libdbuspolicy1 >= 1)
+  AC_SUBST(LIBDBUSPOLICY1_CFLAGS)
+  AC_SUBST(LIBDBUSPOLICY1_LIBS)
+  AC_DEFINE(LIBDBUSPOLICY, 1, [Whether to enable libdbuspolicy for kdbus transport])
+  AC_MSG_RESULT([yes])
+], [ AC_MSG_RESULT([no]) ])
+
 dnl location to install runtime libraries, e.g. ../../lib to install
 dnl to /lib if libdir is /usr/lib
 AC_ARG_WITH(runtime-libdir,
index 3be62b1..2c9db28 100644 (file)
@@ -217,6 +217,10 @@ platform_libadd =
 platform_deps =
 appinfo_sources =
 
+if LIBDBUSPOLICY
+platform_libadd += $(LIBDBUSPOLICY1_LIBS)
+endif
+
 if HAVE_INOTIFY
 SUBDIRS += inotify
 platform_libadd += inotify/libinotify.la
@@ -535,6 +539,10 @@ libgio_2_0_la_CFLAGS += -xobjective-c
 libgio_2_0_la_LDFLAGS += -Wl,-framework,Foundation
 endif
 
+if LIBDBUSPOLICY
+libgio_2_0_la_CPPFLAGS += $(LIBDBUSPOLICY1_CFLAGS)
+endif
+
 libgio_2_0_la_DEPENDENCIES = $(gio_win32_res) $(gio_def) $(platform_deps)
 
 gio-win32-res.o: gio.rc
index 271ad08..a3a5949 100644 (file)
 #include <sys/uio.h>
 #endif
 
+#ifdef LIBDBUSPOLICY
+#include <dbuspolicy/libdbuspolicy1.h>
+#endif
+
 #define DBUS_DAEMON_EMULATION
 #ifdef DBUS_DAEMON_EMULATION
 #include "gkdbusfakedaemon.h"
@@ -158,6 +162,10 @@ struct _GKDBusWorker
 
   GList             *matches;
 
+#ifdef LIBDBUSPOLICY
+  void              *dbuspolicy;
+#endif
+
   GDBusCapabilityFlags                     capabilities;
   GDBusWorkerMessageReceivedCallback       message_received_callback;
   GDBusWorkerMessageAboutToBeSentCallback  message_about_to_be_sent_callback;
@@ -536,14 +544,48 @@ _g_kdbus_open (GKDBusWorker  *worker,
                GError       **error)
 {
   g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
   worker->fd = g_open(address, O_RDWR|O_NOCTTY|O_CLOEXEC, 0);
   if (worker->fd<0)
     {
-      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Can't open kdbus endpoint"));
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot open kdbus endpoint"));
       return FALSE;
     }
 
+#ifdef LIBDBUSPOLICY
+  {
+    gint bus_type;
+
+    bus_type = -1;
+
+    if (g_str_has_prefix (address, "/sys/fs/kdbus/"))
+      {
+        if (g_str_has_suffix (address, "-system/bus"))
+          bus_type = SYSTEM_BUS;
+        else if (g_str_has_suffix (address, "-user/bus"))
+          bus_type = SESSION_BUS;
+      }
+
+    if ((bus_type == SYSTEM_BUS) || (bus_type == SESSION_BUS))
+      {
+        worker->dbuspolicy = dbuspolicy1_init (bus_type);
+        if (worker->dbuspolicy == NULL)
+          {
+            g_warning ("kdbus: cannot load dbus policy for kdbus transport");
+            close (worker->fd);
+            worker->fd = -1;
+
+            return FALSE;
+          }
+      }
+    else
+      {
+        g_warning ("kdbus: cannot load dbus policy for custom bus");
+      }
+  }
+#endif
+
   worker->closed = FALSE;
 
   return TRUE;
@@ -818,6 +860,21 @@ _g_kdbus_RequestName (GKDBusWorker        *worker,
       return G_BUS_REQUEST_NAME_FLAGS_ERROR;
     }
 
+#ifdef LIBDBUSPOLICY
+  if (worker->dbuspolicy != NULL)
+    {
+      if (dbuspolicy1_can_own (worker->dbuspolicy, name) != 1)
+        {
+          g_set_error (error,
+                       G_DBUS_ERROR,
+                       G_DBUS_ERROR_ACCESS_DENIED,
+                       "Connection \"%s\" is not allowed to own the "
+                       "service \"%s\" due to security policies", worker->unique_name, name);
+          return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+        }
+    }
+#endif
+
   g_kdbus_translate_nameowner_flags (flags, &kdbus_flags);
 
   len = strlen(name) + 1;
@@ -2582,31 +2639,36 @@ g_kdbus_decode_kernel_msg (GKDBusWorker      *worker,
 /*
  * g_kdbus_decode_dbus_msg
  */
-static GDBusMessage *
+static GKDBusMessage *
 g_kdbus_decode_dbus_msg (GKDBusWorker      *worker,
                          struct kdbus_msg  *msg)
 {
-  GDBusMessage *message;
+  GKDBusMessage *kmsg;
   struct kdbus_item *item;
   gssize data_size = 0;
   GArray *body_vectors;
   gsize body_size;
-  GVariant *body;
+  GVariant *body, *value;
   gchar *sender;
   guint i;
   GVariant *parts[2];
   GVariantIter *fields_iter;
+  GString *owned_name;
   guint8 endianness, type, flags, version;
-  guint64 key;
-  GVariant *value;
-  guint64 serial;
+  guint64 key, serial;
 
-  message = g_dbus_message_new ();
+  kmsg = g_new0 (GKDBusMessage, 1);
+  kmsg->message = g_dbus_message_new();
+  kmsg->sender_euid = (uid_t) -1;
+  kmsg->sender_egid = (gid_t) -1;
+  kmsg->sender_seclabel = NULL;
+  kmsg->sender_names = NULL;
 
   body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
 
   item = msg->items;
   body_size = 0;
+  owned_name = NULL;
 
   KDBUS_ITEM_FOREACH(item, msg, items)
     {
@@ -2691,16 +2753,44 @@ g_kdbus_decode_dbus_msg (GKDBusWorker      *worker,
             GUnixFDList *fd_list;
 
             fd_list = g_unix_fd_list_new_from_array (item->fds, data_size / sizeof (int));
-            g_dbus_message_set_unix_fd_list (message, fd_list);
+            g_dbus_message_set_unix_fd_list (kmsg->message, fd_list);
             g_object_unref (fd_list);
           }
           break;
 
-        /* All of the following items, like CMDLINE,
-           CGROUP, etc. need some GDBUS API extensions and
-           should be implemented in the future */
-        case KDBUS_ITEM_TIMESTAMP:
+        /* [libdbuspolicy] read euid and egid values */
         case KDBUS_ITEM_CREDS:
+
+          if ((uid_t) item->creds.euid != (uid_t) -1)
+            kmsg->sender_euid = (uid_t) item->creds.euid;
+
+          if ((gid_t) item->creds.egid != (gid_t) -1)
+            kmsg->sender_egid = (gid_t) item->creds.egid;
+
+          break;
+
+        /* [libdbuspolicy] read security label value */
+        case KDBUS_ITEM_SECLABEL:
+
+          if (item->str != NULL)
+            kmsg->sender_seclabel = g_strdup (item->str);
+
+          break;
+
+        /* [libdbuspolicy] read all owned well-known names */
+        case KDBUS_ITEM_OWNED_NAME:
+
+          if (g_dbus_is_name (item->name.name))
+            {
+              if (owned_name == NULL)
+                owned_name = g_string_new (item->name.name);
+              else
+                g_string_append_printf (owned_name, " %s", item->name.name);
+            }
+
+          break;
+
+        case KDBUS_ITEM_TIMESTAMP:
         case KDBUS_ITEM_PIDS:
         case KDBUS_ITEM_PID_COMM:
         case KDBUS_ITEM_TID_COMM:
@@ -2709,10 +2799,8 @@ g_kdbus_decode_dbus_msg (GKDBusWorker      *worker,
         case KDBUS_ITEM_CGROUP:
         case KDBUS_ITEM_AUDIT:
         case KDBUS_ITEM_CAPS:
-        case KDBUS_ITEM_SECLABEL:
         case KDBUS_ITEM_CONN_DESCRIPTION:
         case KDBUS_ITEM_AUXGROUPS:
-        case KDBUS_ITEM_OWNED_NAME:
         case KDBUS_ITEM_NAME:
         case KDBUS_ITEM_DST_ID:
         case KDBUS_ITEM_BLOOM_FILTER:
@@ -2746,36 +2834,40 @@ g_kdbus_decode_dbus_msg (GKDBusWorker      *worker,
       switch (key)
         {
           case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
-            g_dbus_message_set_reply_serial (message, (guint32) g_variant_get_uint64 (value));
+            g_dbus_message_set_reply_serial (kmsg->message, (guint32) g_variant_get_uint64 (value));
             continue;
 
           default:
-            g_dbus_message_set_header (message, key, value);
+            g_dbus_message_set_header (kmsg->message, key, value);
             continue;
         }
     }
 
   g_variant_iter_free (fields_iter);
 
-  g_dbus_message_set_flags (message, flags);
-  g_dbus_message_set_serial (message, serial);
-  g_dbus_message_set_message_type (message, type);
+  g_dbus_message_set_flags (kmsg->message, flags);
+  g_dbus_message_set_serial (kmsg->message, serial);
+  g_dbus_message_set_message_type (kmsg->message, type);
 
   body = g_variant_get_variant (parts[1]);
   if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
-    g_dbus_message_set_body (message, body);
+    g_dbus_message_set_body (kmsg->message, body);
   else
-    g_dbus_message_set_body (message, NULL);
+    g_dbus_message_set_body (kmsg->message, NULL);
 
   g_variant_unref (body);
   g_variant_unref (parts[1]);
 
   /* set 'sender' field */
   sender = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
-  g_dbus_message_set_sender (message, sender);
+  g_dbus_message_set_sender (kmsg->message, sender);
   g_free (sender);
 
-  return message;
+  /* owned name */
+  if (owned_name != NULL)
+    kmsg->sender_names = g_string_free (owned_name, FALSE);
+
+  return kmsg;
 }
 
 
@@ -2788,8 +2880,10 @@ _g_kdbus_receive (GKDBusWorker  *worker,
 {
   struct kdbus_cmd_recv recv;
   struct kdbus_msg *msg;
+  gboolean can_receive;
   gint ret;
 
+  can_receive = TRUE;
   memset (&recv, 0, sizeof recv);
   recv.size = sizeof (recv);
 
@@ -2814,16 +2908,59 @@ again:
         return;
       }
 
-   msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + recv.msg.offset);
+    msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + recv.msg.offset);
 
-   if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
-     {
-       GDBusMessage *message;
+    if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
+      {
+        GKDBusMessage *kmsg;
+
+        kmsg = g_kdbus_decode_dbus_msg (worker, msg);
+
+#ifdef LIBDBUSPOLICY
+    if (worker->dbuspolicy != NULL)
+      {
+        if (g_dbus_message_get_message_type (kmsg->message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
+          {
+            if ((kmsg->sender_euid != (uid_t) -1) && (kmsg->sender_egid != (gid_t) -1) &&
+                (kmsg->sender_seclabel != NULL) && (kmsg->sender_names != NULL))
+              {
+                gint check;
+
+                check = dbuspolicy1_check_in (worker->dbuspolicy,
+                                              g_dbus_message_get_destination (kmsg->message),
+                                              kmsg->sender_names,
+                                              kmsg->sender_seclabel,
+                                              kmsg->sender_euid,
+                                              kmsg->sender_egid,
+                                              g_dbus_message_get_path (kmsg->message),
+                                              g_dbus_message_get_interface (kmsg->message),
+                                              g_dbus_message_get_member (kmsg->message),
+                                              g_dbus_message_get_message_type (kmsg->message),
+                                              NULL, 0, 0);
+                if (check != 1)
+                  {
+                    can_receive = FALSE;
+                  }
+              }
+            else
+              {
+                can_receive = FALSE;
+              }
+          }
+      }
+#endif
+
+       if (can_receive)
+         (* worker->message_received_callback) (kmsg->message, worker->user_data);
+
+       if (kmsg->sender_seclabel != NULL)
+         g_free (kmsg->sender_seclabel);
 
-       message = g_kdbus_decode_dbus_msg (worker, msg);
-       (* worker->message_received_callback) (message, worker->user_data);
+       if (kmsg->sender_names != NULL)
+         g_free (kmsg->sender_names);
 
-       g_object_unref (message);
+       g_object_unref (kmsg->message);
+       g_free (kmsg);
      }
    else if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
      g_kdbus_decode_kernel_msg (worker, msg);
@@ -3210,6 +3347,32 @@ _g_kdbus_send (GKDBusWorker  *worker,
     }
 
   /*
+   * check policy
+   */
+#ifdef LIBDBUSPOLICY
+  if (worker->dbuspolicy != NULL)
+    {
+      gint check;
+
+      check = dbuspolicy1_check_out (worker->dbuspolicy,
+                                     g_dbus_message_get_destination (message),
+                                     g_dbus_message_get_sender (message),
+                                     g_dbus_message_get_path (message),
+                                     g_dbus_message_get_interface (message),
+                                     g_dbus_message_get_member (message),
+                                     g_dbus_message_get_message_type (message),
+                                     NULL, 0, 0);
+      if (check != 1)
+        {
+          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+                       "Cannot send message - message rejected due to security policies");
+          result = FALSE;
+          goto out;
+        }
+    }
+#endif
+
+  /*
    * send message
    */
   if (ioctl(worker->fd, KDBUS_CMD_SEND, send))
@@ -3254,12 +3417,23 @@ _g_kdbus_send (GKDBusWorker  *worker,
     }
   else if (out_reply != NULL)
     {
-      struct kdbus_msg *kmsg;
+      GKDBusMessage *kmsg;
+      struct kdbus_msg *kdbus_msg;
+
+      kdbus_msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
+
+      kmsg = g_kdbus_decode_dbus_msg (worker, kdbus_msg);
+      g_kdbus_close_msg (worker, kdbus_msg);
+
+      *out_reply = kmsg->message;
+
+      if (kmsg->sender_seclabel != NULL)
+        g_free (kmsg->sender_seclabel);
 
-      kmsg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
+      if (kmsg->sender_names != NULL)
+        g_free (kmsg->sender_names);
 
-      *out_reply = g_kdbus_decode_dbus_msg (worker, kmsg);
-      g_kdbus_close_msg (worker, kmsg);
+      g_free (kmsg);
 
       if (G_UNLIKELY (_g_dbus_debug_message ()))
         {
@@ -3275,6 +3449,8 @@ _g_kdbus_send (GKDBusWorker  *worker,
         }
     }
 
+out:
+
   if (cancel_fd != -1)
     g_cancellable_release_fd (cancellable);
 
@@ -3318,6 +3494,11 @@ g_kdbus_worker_finalize (GObject *object)
     match_free (match->data);
   g_list_free (worker->matches);
 
+#ifdef LIBDBUSPOLICY
+  if (worker->dbuspolicy != NULL)
+    dbuspolicy1_free (worker->dbuspolicy);
+#endif
+
   if (worker->fd != -1 && !worker->closed)
     _g_kdbus_close (worker);
 
@@ -3351,6 +3532,10 @@ g_kdbus_worker_init (GKDBusWorker *worker)
   worker->bloom_size = 0;
   worker->bloom_n_hash = 0;
   worker->matches = NULL;
+
+#ifdef LIBDBUSPOLICY
+  worker->dbuspolicy = NULL;
+#endif
 }
 
 static gpointer
index 967360c..8a4a831 100644 (file)
@@ -58,6 +58,15 @@ typedef struct
   gchar  *sec_label;
 } GDBusCredentials;
 
+typedef struct
+{
+  GDBusMessage  *message;
+  uid_t          sender_euid;
+  gid_t          sender_egid;
+  gchar         *sender_seclabel;
+  gchar         *sender_names;
+} GKDBusMessage;
+
 typedef struct _GKDBusWorker                                  GKDBusWorker;
 
 void                  _g_kdbus_worker_associate              (GKDBusWorker                             *worker,
index e66f3ba..f464e4e 100644 (file)
@@ -1,3 +1,4 @@
+%bcond_with dbuspolicy
 %define baseline 2.40
 %define with_systemtap 0
 %define keepstatic 1
@@ -37,6 +38,11 @@ BuildRequires:  pkgconfig(libelf) >= 0.8.12
 BuildRequires:  pkgconfig(libffi)
 BuildRequires:  pkgconfig(libpcre)
 BuildRequires:  pkgconfig(zlib)
+# Enable support for libdbuspolicy (only for kdbus transport)
+%if %{with dbuspolicy}
+BuildRequires:  pkgconfig(libdbuspolicy1)
+BuildRequires:  pkgconfig(cynara-client)
+%endif
 
 %description
 GLib is a general-purpose utility library, which provides many useful
@@ -186,6 +192,9 @@ NOCONFIGURE=1 ./autogen.sh
 %if 0%{?with_systemtap}
     --enable-systemtap \
 %endif
+%if %{with dbuspolicy}
+    --enable-libdbuspolicy \
+%endif
     --with-pcre=system
 
 %{__make} %{?_smp_mflags} V=1