dbus: Add SELinux support
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Fri, 2 Nov 2012 16:26:13 +0000 (17:26 +0100)
committerDaniel Wagner <daniel.wagner@bmw-carit.de>
Fri, 23 Nov 2012 12:47:22 +0000 (13:47 +0100)
ConnMan needs to identify application in a secure way when they are
using the Session API. The current D-Bus server implemention supports
two types of LSM, POSIX and SELinux. In order to support SMACK or
TOMOYO the D-Bus code base needs to be patch. This is the initial work
to support at least POSIX and SELinux. Maybe in the future we are able
to support also the other LSMs.

The idea behind gsec is to keep the LSM related code together in one
directory. The API introduces in this patch is not any way final. It
will need some more time figuring out how are able to intregrate this
in a nice way.

The current API introduces g_sec_get_selinux_label() which will return
the SELinux context. The function will issuing a
GetConnectionSELinuxSecurityContext method call.

Note, that this function is not documented in the D-Bus
specification. See for more details the source code dbus/bus/drivers.c
and dbus/bus/selinux.c in the D-Bus reference implementation.

include/dbus.h
src/dbus.c

index bf5f8c1..c00488e 100644 (file)
@@ -171,6 +171,14 @@ static inline void connman_dbus_dict_append_fixed_array(DBusMessageIter *dict,
 dbus_bool_t connman_dbus_validate_ident(const char *ident);
 char *connman_dbus_encode_string(const char *value);
 
+typedef void (* connman_dbus_get_context_cb_t) (const unsigned char *context,
+                                               void *user_data, int err);
+
+int connman_dbus_get_selinux_context(DBusConnection *connection,
+                               const char *service,
+                               connman_dbus_get_context_cb_t func,
+                               void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index 9d19f94..70af617 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <string.h>
+#include <errno.h>
 #include <gdbus.h>
 
 #include "connman.h"
@@ -405,6 +406,140 @@ dbus_bool_t __connman_dbus_append_objpath_dict_array(DBusMessage *msg,
        return TRUE;
 }
 
+struct selinux_data {
+       connman_dbus_get_context_cb_t func;
+       void *user_data;
+};
+
+static unsigned char *parse_context(DBusMessage *msg)
+{
+       DBusMessageIter iter, array;
+       unsigned char *ctx, *p;
+       int size = 0;
+
+       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_recurse(&iter, &array);
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
+               size++;
+
+               dbus_message_iter_next(&array);
+       }
+
+       if (size == 0)
+               return NULL;
+
+       ctx = g_try_malloc0(size + 1);
+       if (ctx == NULL)
+               return NULL;
+
+       p = ctx;
+
+       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_recurse(&iter, &array);
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_BYTE) {
+               dbus_message_iter_get_basic(&array, p);
+
+               p++;
+               dbus_message_iter_next(&array);
+       }
+
+       return ctx;
+}
+
+static void selinux_get_context_reply(DBusPendingCall *call, void *user_data)
+{
+       struct selinux_data *data = user_data;
+       DBusMessage *reply;
+       unsigned char *context = NULL;
+       int err = 0;
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+               DBG("Failed to retrieve SELinux context");
+               err = -EIO;
+               goto done;
+       }
+
+       if (dbus_message_has_signature(reply, "ay") == FALSE) {
+               DBG("Message signature is wrong");
+               err = -EINVAL;
+               goto done;
+       }
+
+       context = parse_context(reply);
+
+done:
+       (*data->func)(context, data->user_data, err);
+
+       g_free(context);
+
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+int connman_dbus_get_selinux_context(DBusConnection *connection,
+                               const char *service,
+                               connman_dbus_get_context_cb_t func,
+                               void *user_data)
+{
+       struct selinux_data *data;
+       DBusPendingCall *call;
+       DBusMessage *msg = NULL;
+       int err;
+
+       if (func == NULL)
+               return -EINVAL;
+
+       data = g_try_new0(struct selinux_data, 1);
+       if (data == NULL) {
+               DBG("Can't allocate data structure");
+               return -ENOMEM;
+       }
+
+       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+                                       DBUS_INTERFACE_DBUS,
+                                       "GetConnectionSELinuxSecurityContext");
+       if (msg == NULL) {
+               DBG("Can't allocate new message");
+               err = -ENOMEM;
+               goto err;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
+                                       DBUS_TYPE_INVALID);
+
+       if (dbus_connection_send_with_reply(connection, msg,
+                                               &call, -1) == FALSE) {
+               DBG("Failed to execute method call");
+               err = -EINVAL;
+               goto err;
+       }
+
+       if (call == NULL) {
+               DBG("D-Bus connection not available");
+               err = -EINVAL;
+               goto err;
+       }
+
+       data->func = func;
+       data->user_data = user_data;
+
+       dbus_pending_call_set_notify(call, selinux_get_context_reply,
+                                                       data, g_free);
+
+       dbus_message_unref(msg);
+
+       return 0;
+
+err:
+       dbus_message_unref(msg);
+       g_free(data);
+
+       return err;
+}
+
 DBusConnection *connman_dbus_get_connection(void)
 {
        if (connection == NULL)