Add libdbuspolicy library 31/54131/4
authorArek Antoniak <a.antoniak2@samsung.com>
Fri, 11 Dec 2015 14:23:27 +0000 (15:23 +0100)
committerKazimierz Krosman <k.krosman@samsung.com>
Tue, 15 Dec 2015 14:41:18 +0000 (15:41 +0100)
Library implements dbus-daemon policy checking logic as standalone
library, it complies with dbus-daemon policy specification and supports
Tizen's Cynara extensions ("check" tag).

libdbuspolicy uses kdbus directly to gain peer credentials.

Authors:
    Kazimierz Krosman <k.krosman@samsung.com>
    Arek Antoniak <a.antoniak2@samsung.com>

Change-Id: I7e637000a90b4194350b69d460ddb0da2b02b983

20 files changed:
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
m4/.gitignore [new file with mode: 0644]
packaging/libdbuspolicy.spec [new file with mode: 0644]
src/.gitignore [new file with mode: 0644]
src/dbuspolicy1/libdbuspolicy1.h [new file with mode: 0644]
src/internal/cynara.hpp [new file with mode: 0644]
src/internal/internal.cpp [new file with mode: 0644]
src/internal/internal.h [new file with mode: 0644]
src/internal/libdbuspolicy1-private.hpp [new file with mode: 0644]
src/internal/timer.hpp [new file with mode: 0644]
src/internal/tslog.hpp [new file with mode: 0644]
src/internal/xml_parser.hpp [new file with mode: 0644]
src/internal/xml_policy.hpp [new file with mode: 0644]
src/libdbuspolicy1-private.h [new file with mode: 0644]
src/libdbuspolicy1.c [new file with mode: 0644]
src/libdbuspolicy1.pc.in [new file with mode: 0644]
src/libdbuspolicy1.sym [new file with mode: 0644]

diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..d457aaa
--- /dev/null
@@ -0,0 +1,68 @@
+EXTRA_DIST =
+CLEANFILES =
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+AM_MAKEFLAGS = --no-print-directory
+
+AM_CXXFLAGS = ${my_CXXFLAGS}
+
+AM_CPPFLAGS = \
+       -include $(top_builddir)/config.h \
+       -DSYSCONFDIR=\""$(sysconfdir)"\" \
+        $(CYNARA_CFLAGS) \
+       -I${top_srcdir}/src
+
+AM_CFLAGS = ${my_CFLAGS} \
+       -fvisibility=hidden \
+       -ffunction-sections \
+        $(CYNARA_CFLAGS) \
+       -fdata-sections
+
+AM_LDFLAGS = \
+       -Wl,--gc-sections \
+       -Wl,--as-needed \
+        $(CYNARA_CFLAGS) \
+$(CYNARA_LIBS)\
+    -pthread
+
+SED_PROCESS = \
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \
+       -e 's,@VERSION\@,$(VERSION),g' \
+       -e 's,@prefix\@,$(prefix),g' \
+       -e 's,@exec_prefix\@,$(exec_prefix),g' \
+       -e 's,@libdir\@,$(libdir),g' \
+       -e 's,@includedir\@,$(includedir),g' \
+       < $< > $@ || rm $@
+
+%.pc: %.pc.in Makefile
+       $(SED_PROCESS)
+
+LIBDBUSPOLICY1_CURRENT=1
+LIBDBUSPOLICY1_REVISION=0
+LIBDBUSPOLICY1_AGE=0
+
+pkginclude_HEADERS = src/dbuspolicy1/libdbuspolicy1.h
+lib_LTLIBRARIES = src/libdbuspolicy1.la
+
+src_libdbuspolicy1_la_SOURCES =\
+       src/libdbuspolicy1-private.h \
+       src/libdbuspolicy1.c \
+    src/internal/internal.cpp
+
+EXTRA_DIST += src/libdbuspolicy1.sym
+
+src_libdbuspolicy1_la_LDFLAGS = $(AM_LDFLAGS) \
+       -version-info $(LIBDBUSPOLICY1_CURRENT):$(LIBDBUSPOLICY1_REVISION):$(LIBDBUSPOLICY1_AGE) \
+        $(CYNARA_LIBS) \
+       -Wl,--version-script=$(top_srcdir)/src/libdbuspolicy1.sym
+src_libdbuspolicy1_la_DEPENDENCIES = ${top_srcdir}/src/libdbuspolicy1.sym
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = src/libdbuspolicy1.pc
+EXTRA_DIST += src/libdbuspolicy1.pc.in
+CLEANFILES += src/libdbuspolicy1.pc
+
+TESTS = src/test-libdbuspolicy1
+
+check_PROGRAMS = src/test-libdbuspolicy1
+src_test_libdbuspolicy1_SOURCES = src/test-libdbuspolicy1.c
+src_test_libdbuspolicy1_LDADD = src/libdbuspolicy1.la $(CYNARA_LIBS)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..39b4067
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+Authors:
+    Kazimierz Krosman <k.krosman@samsung.com>
+    Arek Antoniak <a.antoniak2@samsung.com>
+
+Library libdbuspolicy adds functionality of DBUS policy utilization in KDBUS, it complies with DBUS policy specification and supports Cynara check directive.
+
+Usage:
+    ./autogen.sh
+    ./configure
+    make
+    make install
+
+The library delivers following API:
+
+    /*!
+      libdbuspolicy init
+      \param bus_type bus type (SYSTEM or SESSION)
+     */
+    void* dbuspolicy1_init(unsigned int bus_type);
+
+    /*!
+      libdbuspolicy free
+      \param configuration pointer with policy configuration acquired using dbuspolicy1_init
+     */
+    void dbuspolicy1_free(void* configuration);
+
+    /*!
+      Check policy for outgoing message
+      \param configuration pointer with policy configuration
+      \param destination list of message destinations
+      \param sender list of message sender names
+      \param path path
+      \param interface interface name
+      \param member member name
+      \param message_type message type
+      \param error_name (future implementation)
+      \param reply_serial (future implementation)
+      \param requested_reply (future implementation)
+     */
+    int dbuspolicy1_check_out(void* configuration,
+            const char        *destination,
+            const char        *sender,
+            const char        *path,
+            const char        *interface,
+            const char        *member,
+            int               message_type,
+            const char        *error_name,
+            int               reply_serial,
+            int               requested_reply);
+
+    /*!
+      Check policy for incoming message
+      \param configuration pointer with policy configuration
+      \param destination list of message destinations
+      \param sender list of message sender names
+      \param sender_label sender label (should be manually extracted from incomming message)
+      \param sender_uid sender uid (should be manually extracted from incomming message)
+      \param sender_gid sender gid (should be manually extracted from incomming message)
+      \param path path
+      \param interface interface name
+      \param member member name
+      \param message_type message type
+      \param error_name (future implementation)
+      \param reply_serial (future implementation)
+      \param requested_reply (future implementation)
+     */
+    int dbuspolicy1_check_in(void* configuration,
+            const char        *destination,
+            const char        *sender,
+            const char        *sender_label,
+            uid_t             sender_uid,
+            gid_t             sender_gid,
+            const char        *path,
+            const char        *interface,
+            const char        *member,
+            int               message_type,
+            const char        *error_name,
+            int               reply_serial,
+            int               requested_reply);
+
+    /*!
+      Check policy for service ownership
+      \param configuration pointer with policy configuration
+      \param service service name
+     */
+    int dbuspolicy1_can_own(void* configuration, const char* const service);
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..16c0eb3
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+set -e
+
+if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
+        cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \
+        chmod +x .git/hooks/pre-commit && \
+        echo "Activated pre-commit hook."
+fi
+
+autoreconf --install --symlink
+
+libdir() {
+        echo $(cd $1/$(gcc -print-multi-os-directory); pwd)
+}
+
+args="--prefix=/usr \
+--sysconfdir=/etc \
+--libdir=$(libdir /usr/lib)"
+
+echo
+echo "----------------------------------------------------------------"
+echo "Initialized build system. For a common configuration please run:"
+echo "----------------------------------------------------------------"
+echo
+echo "./configure CFLAGS='-g -O0' $args"
+echo
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..440b0c2
--- /dev/null
@@ -0,0 +1,104 @@
+AC_PREREQ(2.60)
+AC_INIT([dbuspolicy],
+        [1],
+        [dev@lists.tizen.org],
+        [dbuspolicy],
+        [http://review.tizen.org])
+AC_CONFIG_SRCDIR([src/libdbuspolicy1.c])
+AC_CONFIG_AUX_DIR([build-aux])
+AM_INIT_AUTOMAKE([
+       check-news
+       foreign
+       1.11
+       -Wall
+       -Wno-portability
+       silent-rules
+       tar-pax
+       no-dist-gzip
+       dist-xz
+       subdir-objects
+])
+AC_PROG_CC_STDC
+AC_PROG_CXX
+AC_USE_SYSTEM_EXTENSIONS
+AC_SYS_LARGEFILE
+AC_CONFIG_MACRO_DIR([m4])
+AM_SILENT_RULES([yes])
+LT_INIT([
+       disable-static
+       pic-only
+])
+AC_PREFIX_DEFAULT([/usr])
+
+AC_PROG_SED
+AC_PROG_MKDIR_P
+
+AC_ARG_ENABLE([logging],
+        AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]),
+        [], enable_logging=yes)
+AS_IF([test "x$enable_logging" = "xyes"], [
+        AC_DEFINE(ENABLE_LOGGING, [1], [System logging.])
+])
+
+AC_ARG_ENABLE([debug],
+        AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]),
+        [], [enable_debug=no])
+AS_IF([test "x$enable_debug" = "xyes"], [
+        AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.])
+])
+
+AC_CHECK_FUNCS([ \
+       __secure_getenv \
+       secure_getenv\
+])
+
+my_CFLAGS="\
+-Wall \
+-Wchar-subscripts \
+-Wformat-security \
+-Wmissing-declarations \
+-Wmissing-prototypes \
+-Wnested-externs \
+-Wpointer-arith \
+-Wshadow \
+-Wsign-compare \
+-Wstrict-prototypes \
+-Wtype-limits \
+"
+AC_SUBST([my_CFLAGS])
+
+my_CXXFLAGS="\
+-Wall \
+-std=c++11 \
+"
+
+AC_SUBST([my_CXXFLAGS])
+PKG_CHECK_MODULES([CYNARA], [cynara-client >= 0.4.2 cynara-session >= 0.4.2],
+     [AC_DEFINE([ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in libdbuspolicy])],
+     [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
+
+AC_SUBST([CYNARA_CFLAGS])
+AC_SUBST([CYNARA_LIBS])
+
+AC_CONFIG_HEADERS(config.h)
+AC_CONFIG_FILES([
+        Makefile
+])
+
+AC_OUTPUT
+AC_MSG_RESULT([
+        $PACKAGE $VERSION
+        =====
+
+        prefix:                 ${prefix}
+        sysconfdir:             ${sysconfdir}
+        libdir:                 ${libdir}
+        includedir:             ${includedir}
+
+        compiler:               ${CC}
+        cflags:                 ${CFLAGS} ${CYNARA_CFLAGS}
+        ldflags:                ${LDFLAGS} ${CYMARA_LIBS}
+
+        logging:                ${enable_logging}
+        debug:                  ${enable_debug}
+])
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644 (file)
index 0000000..38066dd
--- /dev/null
@@ -0,0 +1,5 @@
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
diff --git a/packaging/libdbuspolicy.spec b/packaging/libdbuspolicy.spec
new file mode 100644 (file)
index 0000000..f38aadc
--- /dev/null
@@ -0,0 +1,43 @@
+Name:           libdbuspolicy
+Summary:        Helper library for fine-grained userspace policy handling
+License:        Apache-2.0
+Group:          Base/IPC
+Version:        1.0.0
+Release:        0
+
+Source: %{name}-%{version}.tar.gz
+BuildRequires:  boost-devel
+BuildRequires:  pkgconfig(cynara-client)
+
+
+%description
+libdbuspolicy is a helper library for fine-grained userspace
+policy handling (with SMACK support)
+
+%prep
+%setup -q
+
+%build
+./autogen.sh
+./configure \
+    --libdir=%{_libdir}        \
+    --prefix=/usr
+
+make
+
+%install
+make DESTDIR=%{buildroot} install-strip
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root)
+%{_includedir}/*
+
+%{_libdir}/pkgconfig/*
+%{_libdir}/libdbuspolicy1.so.*
+%{_libdir}/libdbuspolicy1.la
+%{_libdir}/libdbuspolicy1.so
+
+%changelog
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..1a03cff
--- /dev/null
@@ -0,0 +1,7 @@
+.dirstamp
+.deps/
+.libs/
+*.la
+*.lo
+libdbuspolicy1.pc
+test-libdbuspolicy1
diff --git a/src/dbuspolicy1/libdbuspolicy1.h b/src/dbuspolicy1/libdbuspolicy1.h
new file mode 100644 (file)
index 0000000..d135e50
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _LIBDBUSPOLICY1_H_
+#define _LIBDBUSPOLICY1_H_
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SYSTEM_BUS_CONF_FILE  "/etc/dbus-1/system.conf"
+#define SESSION_BUS_CONF_FILE "/etc/dbus-1/session.conf"
+
+#define SYSTEM_BUS   1
+#define SESSION_BUS  2
+
+/** used when check policy for message prepared to send */
+#define DBUSPOLICY_DIRECTION_SENDING 0
+
+ /** used when check policy for message read from bus */
+#define DBUSPOLICY_DIRECTION_RECEIVING 1
+
+#define DBUSPOLICY_MESSAGE_TYPE_METHOD_CALL     1
+#define DBUSPOLICY_MESSAGE_TYPE_METHOD_RETURN   2
+#define DBUSPOLICY_MESSAGE_TYPE_ERROR           3
+#define DBUSPOLICY_MESSAGE_TYPE_SIGNAL          4
+
+struct udesc;
+
+/*!
+  libdbuspolicy init
+  \param bus_type bus type (SYSTEM or SESSION)
+ */
+void* dbuspolicy1_init(unsigned int bus_type);
+
+/*!
+  libdbuspolicy free
+  \param configuration pointer with policy configuration acquired using dbuspolicy1_init
+ */
+void dbuspolicy1_free(void* configuration);
+
+/*!
+  Check policy for outgoing message
+  \param configuration pointer with policy configuration
+  \param destination list of message destinations
+  \param sender list of message sender names
+  \param path path
+  \param interface interface name
+  \param member member name
+  \param message_type message type
+  \param error_name (future implementation)
+  \param reply_serial (future implementation)
+  \param requested_reply (future implementation)
+ */
+int dbuspolicy1_check_out(void* configuration,
+        const char        *destination,
+        const char        *sender,
+        const char        *path,
+        const char        *interface,
+        const char        *member,
+        int               message_type,
+        const char        *error_name,
+        int               reply_serial,
+        int               requested_reply);
+
+/*!
+  Check policy for incoming message
+  \param configuration pointer with policy configuration
+  \param destination list of message destinations
+  \param sender list of message sender names
+  \param sender_label sender label (should be manually extracted from incomming message)
+  \param sender_uid sender uid (should be manually extracted from incomming message)
+  \param sender_gid sender gid (should be manually extracted from incomming message)
+  \param path path
+  \param interface interface name
+  \param member member name
+  \param message_type message type
+  \param error_name (future implementation)
+  \param reply_serial (future implementation)
+  \param requested_reply (future implementation)
+ */
+int dbuspolicy1_check_in(void* configuration,
+        const char        *destination,
+        const char        *sender,
+        const char        *sender_label,
+        uid_t             sender_uid,
+        gid_t             sender_gid,
+        const char        *path,
+        const char        *interface,
+        const char        *member,
+        int               message_type,
+        const char        *error_name,
+        int               reply_serial,
+        int               requested_reply);
+
+/*!
+  Check policy for service ownership
+  \param configuration pointer with policy configuration
+  \param service service name
+ */
+int dbuspolicy1_can_own(void* configuration, const char* const service);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/internal/cynara.hpp b/src/internal/cynara.hpp
new file mode 100644 (file)
index 0000000..7f74f35
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _CYNARA_HPP
+#define _CYNARA_HPP
+
+#include <cynara-client.h>
+#include <cynara-session.h>
+
+namespace _ldp_cynara {
+    class Cynara {
+        private:
+            cynara* __cynara;
+            std::string __session;
+
+            Cynara() {
+                int r = cynara_initialize(&__cynara, NULL);
+                if (r != CYNARA_API_SUCCESS)
+                    throw std::runtime_error("Cynara initialization failed");
+
+                __session = cynara_session_from_pid(getpid());
+            }
+
+            ~Cynara() {
+                int r = cynara_finish(__cynara);
+                if (r != CYNARA_API_SUCCESS) {
+                    //TODO: reaction
+                }
+            }
+
+            static Cynara& get_instance() {
+                static Cynara __self;
+                return __self;
+            }
+
+        public:
+            static std::string get_session() {
+                Cynara& c = Cynara::get_instance();
+                c.__session = cynara_session_from_pid(getpid());
+                return c.__session;
+            }
+
+            static bool check(std::string label, std::string privilege, std::string uid, std::string session = "") {
+                Cynara& c = Cynara::get_instance();
+                const char* _label="";
+                const char* _session="";
+                const char* _uid="";
+                const char* _privilege="";
+
+                /**
+                workaround. C-str() returns wrong pointer to str
+                when std::string == ""
+                */
+                if (!label.empty())
+                    _label=label.c_str();
+
+                if (session == "")
+                    session =  c.__session;
+                if (!session.empty())
+                    _session=session.c_str();
+
+                if (!privilege.empty())
+                    _privilege=privilege.c_str();
+
+                if (!uid.empty())
+                    _uid=uid.c_str();
+
+                int r = cynara_check (c.__cynara, _label, _session, _uid, _privilege);
+                if (r == CYNARA_API_ACCESS_ALLOWED)
+                    return true;
+                else if (r == CYNARA_API_ACCESS_DENIED)
+                    return false;
+                else
+                    throw std::runtime_error("Cynara check failed");
+            }
+    };
+} //namespace
+#endif
diff --git a/src/internal/internal.cpp b/src/internal/internal.cpp
new file mode 100644 (file)
index 0000000..e5e5a18
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include <iostream>
+#include <string>
+#include <dbuspolicy1/libdbuspolicy1.h>
+#include "xml_parser.hpp"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char* get_bus(int bus_type) {
+    return (bus_type == SYSTEM_BUS) ? "SYSTEM" : "SESSION";
+}
+
+static const char* get_str(const char* const szstr) {
+    return (szstr != NULL) ? szstr : "";
+}
+
+static const char* get_message_type(int type) {
+    const char* sztype;
+    switch(type) {
+        case DBUSPOLICY_MESSAGE_TYPE_METHOD_CALL:   sztype = "method_call";     break;
+        case DBUSPOLICY_MESSAGE_TYPE_METHOD_RETURN: sztype = "method_return";   break;
+        case DBUSPOLICY_MESSAGE_TYPE_ERROR:         sztype = "error";           break;
+        case DBUSPOLICY_MESSAGE_TYPE_SIGNAL:        sztype = "signal";          break;
+        default:                                    sztype = "";                break;
+    }
+    return sztype;
+}
+
+int __internal_init(unsigned int bus_type, const char* const config_name)
+{
+    _ldp_xml_parser::XmlAsyncParser p;
+    auto err = p.parse_policy(get_bus(bus_type), get_str(config_name), std::chrono::milliseconds(10000));
+    return err.get();
+}
+
+int __internal_can_send(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const label,
+                            const char* const destination,
+                            const char* const path,
+                            const char* const interface,
+                            const char* const member,
+                            int type)
+{
+    _ldp_xml_parser::XmlAsyncParser p;
+    auto err = p.can_send(get_bus(bus_type), get_str(user), get_str(group), get_str(label), get_str(destination), get_str(path), get_str(interface), get_str(member), get_message_type(type));
+    return err.get();
+}
+
+int __internal_can_recv(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const label,
+                            const char* const sender,
+                            const char* const path,
+                            const char* const interface,
+                            const char* const member,
+                            int type)
+{
+    _ldp_xml_parser::XmlAsyncParser p;
+    auto err = p.can_recv(get_bus(bus_type), get_str(user), get_str(group), get_str(label), get_str(sender), get_str(path), get_str(interface), get_str(member), get_message_type(type));
+    return err.get();
+}
+
+int __internal_can_own(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const service)
+{
+    _ldp_xml_parser::XmlAsyncParser p;
+    auto err = p.can_own(get_bus(bus_type), get_str(user), get_str(group), get_str(service));
+    return err.get();
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/src/internal/internal.h b/src/internal/internal.h
new file mode 100644 (file)
index 0000000..84a1069
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _LIBDBUSPOLICY1_INTERNAL_H_
+#define _LIBDBUSPOLICY1_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int __internal_init(unsigned int bus_type, const char* const config_name);
+
+int __internal_can_send(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const label,
+                            const char* const destination,
+                            const char* const path,
+                            const char* const interface,
+                            const char* const member,
+                            int type);
+
+int __internal_can_recv(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const label,
+                            const char* const sender,
+                            const char* const path,
+                            const char* const interface,
+                            const char* const member,
+                            int type);
+
+int __internal_can_own(unsigned int bus_type,
+                            const char* const user,
+                            const char* const group,
+                            const char* const service);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/internal/libdbuspolicy1-private.hpp b/src/internal/libdbuspolicy1-private.hpp
new file mode 100644 (file)
index 0000000..4b467b4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _LIBDBUSPOLICY1_PRIVATE_HPP
+#define _LIBDBUSPOLICY1_PRIVATE_HPP
+
+#include <string>
+
+namespace {
+    class ErrCode {
+        int m_err;
+        std::string m_err_str;
+        ErrCode(int e, const std::string& s) : m_err(e), m_err_str(s) {}
+        public:
+            ErrCode() : m_err(0), m_err_str("") {}
+            virtual ~ErrCode() {}
+
+            static ErrCode ok() {
+                return ErrCode(0, "OK");
+            }
+
+            template<typename T>
+            static ErrCode ok(T e) {
+                return ErrCode((e > 0) ? e : 0, "OK");
+            }
+
+            static ErrCode error(const std::string& what) {
+                return ErrCode(-1, what);
+            }
+
+            static ErrCode timeout(const std::string& what) {
+                return ErrCode(-99, std::string("Timeout: ") + what);
+            }
+
+            int get() const {
+                return m_err;
+            }
+
+            const std::string& get_str() const {
+                return m_err_str;
+            }
+
+            bool is_ok() const {
+                return (m_err >= 0);
+            }
+
+            bool is_true() const {
+                return (m_err > 0);
+            }
+
+            bool is_false() const {
+                return (m_err == 0);
+            }
+
+            bool is_error() const {
+                return (m_err < 0);
+            }
+
+    };
+} //namespace
+
+#endif
diff --git a/src/internal/timer.hpp b/src/internal/timer.hpp
new file mode 100644 (file)
index 0000000..fe46cc6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _TIMER_HPP
+#define _TIMER_HPP
+
+namespace _ldp_timer
+{
+    template<typename BaseTimeUnit = std::chrono::nanoseconds>
+        class Duration : public BaseTimeUnit {
+            public:
+                void setNanoTime(std::chrono::nanoseconds nano) {
+                    BaseTimeUnit d = std::chrono::duration_cast<BaseTimeUnit>(nano);
+                    BaseTimeUnit::operator =(d);
+                }
+
+                double getSeconds() {
+                    typename BaseTimeUnit::period p;
+                    return 1.0 * BaseTimeUnit::count() * p.num/p.den;
+                }
+
+                uint64_t getNativeTime() {
+                    return BaseTimeUnit::count();
+                }
+
+                friend std::ostream& operator<< (std::ostream& os,
+                        const Duration<BaseTimeUnit>& d) {
+                    typename BaseTimeUnit::period p;
+                    std::string unit;
+                    switch(p.den/p.num) {
+                        case 1000000000:    unit = "ns"; break;
+                        case 1000000:       unit = "us"; break;
+                        case 1000:          unit = "ms"; break;
+                        case 1:             unit = "s";  break;
+                    }
+
+                    os << d.count() << " " << unit;
+                    return os;
+                }
+        };
+
+    typedef Duration<std::chrono::nanoseconds> nanosec;
+    typedef Duration<std::chrono::microseconds> microsec;
+    typedef Duration<std::chrono::milliseconds> millisec;
+    typedef Duration<std::chrono::seconds> sec;
+
+    template<typename _T = nanosec>
+        class Timer {
+            typedef std::chrono::steady_clock CLK;
+            CLK::time_point tbegin;
+            _T* const pOT;
+            public:
+            Timer(_T* const pTP)
+                : tbegin(CLK::now()), pOT(pTP) {}
+
+            virtual ~Timer() {
+                if(pOT)
+                    pOT->setNanoTime(CLK::now() - tbegin);
+            }
+        };
+}
+
+#endif // _TIMER_HPP
diff --git a/src/internal/tslog.hpp b/src/internal/tslog.hpp
new file mode 100644 (file)
index 0000000..f1fdeaa
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _TSLOG_HPP
+#define _TSLOG_HPP
+
+#include <iostream>
+#include <thread>
+#include <mutex>
+
+namespace _ldp_tslog
+{
+    typedef std::ostream& (*t_ManFun)(std::ostream&);
+
+    namespace {
+        static constexpr bool LOG_ENABLE = false;
+        static constexpr bool LOG_VERBOSE = false;
+    }
+
+    const bool get_verbose() {
+        return LOG_VERBOSE;
+    }
+
+    const bool get_enable() {
+        return LOG_ENABLE;
+    }
+
+    class TsLog
+    {
+        private:
+            static bool m_verbose;
+            static std::mutex m_mtx;
+            std::ostream& m_os;
+            bool m_enable;
+
+            template<typename T>
+                TsLog& lckLog(const T& t) {
+                    if(m_enable) {
+                        std::unique_lock<std::mutex> lck(m_mtx);
+                        m_os << t;
+                    }
+                    return *this;
+                }
+
+        public:
+            TsLog() = delete;
+
+            explicit TsLog(std::ostream& os, bool enable = true)
+                : m_os(os), m_enable(enable) {}
+
+            virtual ~TsLog() {}
+
+            template<typename T>
+                TsLog& operator<< (const T& t) {
+                    return lckLog<T>(t);
+                }
+
+            TsLog& operator<< (t_ManFun f) {
+                return lckLog<t_ManFun>(f);
+            }
+
+    };
+    std::mutex TsLog::m_mtx;
+}
+
+namespace {
+    //Thread-safe loggers
+    _ldp_tslog::TsLog tout(std::cout, _ldp_tslog::get_enable());
+    _ldp_tslog::TsLog terr(std::cerr, _ldp_tslog::get_enable());
+
+    namespace verbose {
+        _ldp_tslog::TsLog tout(std::cout, _ldp_tslog::get_enable() && _ldp_tslog::get_verbose());
+        _ldp_tslog::TsLog terr(std::cerr, _ldp_tslog::get_enable() && _ldp_tslog::get_verbose());
+    }
+} //namespace
+
+#endif
diff --git a/src/internal/xml_parser.hpp b/src/internal/xml_parser.hpp
new file mode 100644 (file)
index 0000000..8d3eb43
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _XML_PARSER_HPP
+#define _XML_PARSER_HPP
+
+#include <map>
+#include <thread>
+#include <future>
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/functional/hash.hpp>
+#include <dirent.h>
+#include <libgen.h>
+#include "timer.hpp"
+#include "xml_policy.hpp"
+
+namespace _ldp_xml_parser
+{
+    class XmlAsyncParser : boost::noncopyable
+    {
+        public:
+            XmlAsyncParser() {
+            }
+
+            virtual ~XmlAsyncParser() {
+            }
+
+            ErrCode parse_policy(const std::string bus, const std::string fname, const std::chrono::milliseconds timeout) {
+                set_policy_bus_filename(bus, fname);
+                m_xml_policy.init();
+                ErrCode err = parse(timeout);
+                return err;
+            }
+
+            ErrCode can_send(const std::string bus,
+                    const std::string user,
+                    const std::string group,
+                    const std::string label,
+                    const std::string destination,
+                    const std::string path,
+                    const std::string interface,
+                    const std::string member,
+                    const std::string type) {
+                std::vector<std::string> idx_v = { user, group, destination, path, interface, member, type };
+                return m_xml_policy.can_send_to(bus, idx_v, label);
+            }
+
+            ErrCode can_recv(const std::string bus,
+                    const std::string user,
+                    const std::string group,
+                    const std::string label,
+                    const std::string sender,
+                    const std::string path,
+                    const std::string interface,
+                    const std::string member,
+                    const std::string type) {
+                std::vector<std::string> idx_v = { user, group, sender, path, interface, member, type };
+                return m_xml_policy.can_recv_from(bus, idx_v, label);
+            }
+
+            ErrCode can_own(const std::string bus,
+                    const std::string user,
+                    const std::string group,
+                    const std::string service) {
+                std::vector<std::string> idx_v = { user, group, service };
+                return m_xml_policy.can_own_what(bus, idx_v);
+            }
+
+
+        private:
+            //IO operation
+            std::string m_bus;
+            std::string m_filename;
+            static std::map<std::string, std::size_t> m_hashes;
+            static std::mutex m_io_xml_mtx;
+
+            //Data obtained from XML
+            static XmlPolicy m_xml_policy;
+
+            //Called by calling user thread
+            void set_policy_bus_filename(const std::string& bus, const std::string& fname) {
+                m_filename = fname;
+                m_bus = bus;
+            }
+
+            const std::string& get_policy_bus() const {
+                return m_bus;
+            }
+
+            const std::string& get_policy_filename() const {
+                return m_filename;
+            }
+
+            ErrCode parse(const std::chrono::milliseconds timeout) {
+                ErrCode err;
+                std::vector<std::string> incl_files;
+
+                err = parse(get_policy_filename(), incl_files, timeout);
+                if(err.is_ok()) {
+                    for(const auto& x : incl_files) {
+                        err = parse(x, incl_files, timeout);
+                        if(err.is_error()) { break; }
+                    }
+                }
+
+                if(err.is_ok()) {
+                    m_xml_policy.print_decision_trees();
+                }
+
+                return err;
+            }
+
+            ErrCode parse(const std::string& filename, std::vector<std::string>& included_files, const std::chrono::milliseconds timeout) {
+                std::pair<ErrCode, std::string> errparam;
+
+                verbose::tout << "=== XML PARSING BEGIN === : " << filename << std::endl;
+
+                auto fut = std::async(std::launch::async, &XmlAsyncParser::async_xml_parse, this, filename);
+
+                auto r = fut.wait_for(timeout);
+                if(r == std::future_status::ready) {
+                    errparam = fut.get();
+                    if(errparam.first.get() >= 0) {
+                        get_included_files(filename, errparam.second, included_files);
+                    }
+                } else if(r == std::future_status::timeout) {
+                    errparam.first = ErrCode::timeout("XML parsing timeout");
+                }
+
+                verbose::tout << "=== XML PARSING END ===" << std::endl << std::endl;
+                tout << "Processing of " << filename << " -> [" << errparam.first.get() << ", " << errparam.first.get_str() << "]" << std::endl;
+                return errparam.first;
+            }
+
+            //Get all the .conf files within included subdirectory, POSIX style as boost::filesystem is not header-only
+            void get_included_files(const std::string& filename, const std::string& incldir, std::vector<std::string>& files) {
+                if(get_policy_filename() == filename && incldir != "") {
+                    DIR *dir;
+                    struct dirent *ent;
+                    std::string fname;
+                    std::copy(filename.begin(), filename.end(), fname.begin());
+                    std::string dname = dirname(const_cast<char*>(fname.c_str()));
+                    dname += (std::string("/") + incldir);
+                    files.clear();
+                    if((dir = opendir(dname.c_str())) != NULL) {
+                        while((ent = readdir(dir)) != NULL) {
+                            std::string s(ent->d_name);
+                            if(s.find(".conf") != std::string::npos) {
+                                files.push_back(dname + std::string("/") + s);
+                            }
+                        }
+                        closedir(dir);
+
+                        tout << std::endl << "includedir for " << filename << " is " << incldir << ", " << files.size() << " included files found:" << std::endl;
+                        if(_ldp_tslog::get_enable()) { std::copy(files.begin(), files.end(), std::ostream_iterator<std::string>(std::cout, "\n")); }
+                        tout << std::endl;
+                    } else {
+                        terr << "could not open directory " << dname << std::endl;
+                    }
+                }
+            }
+
+            //All 'async_*' methods are executed in library's internal worker threads
+            std::pair<ErrCode, std::string> async_xml_parse(const std::string& filename) {
+                std::pair<ErrCode, std::string> ret;
+                _ldp_timer::microsec latency;
+
+                try {
+                    boost::property_tree::ptree pt;
+
+                    //XML file IO critical section
+                    {
+                        std::unique_lock<std::mutex> lck(m_io_xml_mtx);
+                        _ldp_timer::Timer<_ldp_timer::microsec> t(&latency);
+
+                        std::size_t hash;
+                        if(async_xml_parsing_needed(filename, hash)) {
+                            read_xml(filename, pt);
+                            async_xml_hash_update(filename, hash);
+                        }
+                    }
+
+                    m_xml_policy.update(get_policy_bus(), pt);
+
+                    ret.second = pt.get("busconfig.includedir", "");
+
+                    ret.first = ErrCode::ok();
+                } catch(const boost::property_tree::xml_parser::xml_parser_error& ex) {
+                    ret.first = ErrCode::error(ex.what());
+                } catch(const boost::property_tree::ptree_error& ex) {
+                    ret.first = ErrCode::error(ex.what());
+                } catch(...) {
+                    ret.first = ErrCode::error(filename + std::string(": unknown error while parsing XML"));
+                }
+
+                tout << "XML processing latency: " << latency << std::endl;
+                return ret;
+            }
+
+            std::size_t async_xml_hash(const std::string& filename) {
+                std::size_t seed = 0;
+                std::ifstream ifs(filename);
+                for(std::string line; getline(ifs, line); ) {
+                    boost::hash_combine(seed, line);
+                }
+                ifs.close();
+
+                return seed;
+            }
+
+            void async_xml_hash_update(const std::string& filename, const std::size_t hash) {
+                auto r = m_hashes.insert(std::pair<std::string, std::size_t>(filename, hash));
+                if(r.second == false) {
+                    auto it = r.first;
+                    it->second = hash;
+                }
+            }
+
+            bool async_xml_parsing_needed(const std::string& filename, std::size_t& hash) {
+                bool ret = false;
+                hash = async_xml_hash(filename);
+                auto it = m_hashes.find(filename);
+                if(it != m_hashes.end()) {
+                    if(hash == it->second) {
+                        ret = false;
+                    } else {
+                        ret = true;
+                    }
+                } else {
+                    ret = true;
+                }
+                return ret;
+            }
+
+    };
+    std::map<std::string, std::size_t> XmlAsyncParser::m_hashes;
+    std::mutex XmlAsyncParser::m_io_xml_mtx;
+    XmlPolicy XmlAsyncParser::m_xml_policy;
+} //namespace
+
+#endif
diff --git a/src/internal/xml_policy.hpp b/src/internal/xml_policy.hpp
new file mode 100644 (file)
index 0000000..f00a879
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _XML_POLICY_HPP
+#define _XML_POLICY_HPP
+
+#include <boost/noncopyable.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include "libdbuspolicy1-private.hpp"
+#include "timer.hpp"
+#include "tslog.hpp"
+#include "cynara.hpp"
+
+namespace _ldp_xml_parser
+{
+    namespace {
+        static const std::string ROOT_FIELD = "busconfig";
+        static const std::string ROOT_POLICY = "policy";
+    } //namespace
+
+    class XmlPolicy : boost::noncopyable
+    {
+        enum class CtxType { DEFAULT, SPECIFIC, MANDATORY };
+
+        class Key {
+            public:
+                static constexpr const char* ANY = "__";
+                static constexpr const char* MRY = "!!";
+                static constexpr const char* DEF = "??";
+                static constexpr const char DELIM = '\\';
+                static const size_t IDX_USER = 0;
+                static const size_t IDX_GROUP = 1;
+                static const size_t IDX_DEST = 2;
+                static const size_t IDX_SENDER = IDX_DEST;
+                static const size_t IDX_SERVICE = IDX_DEST;
+                static const size_t IDX_PATH = 3;
+                static const size_t IDX_IFACE = 4;
+                static const size_t IDX_MEMBER = 5;
+                static const size_t IDX_TYPE = 6;
+
+                static const size_t IDX_TOTAL_LENGTH = IDX_TYPE + 1;
+                static const size_t IDX_OWN_LENGTH = IDX_SERVICE + 1;
+                static const size_t IDX_DEFAULT = IDX_GROUP + 1;
+
+                std::string m_bus;
+                std::vector<std::string> m_path_content;
+                std::string m_privilege;
+                bool m_bsend;
+                bool m_brecv;
+                bool m_bown;
+                bool m_bcheck;
+                bool m_ballow;
+                static size_t m_weight;
+
+                Key(const std::string& bus)
+                    : m_bus(bus),
+                    m_path_content(std::vector<std::string>(IDX_TOTAL_LENGTH, ANY)),
+                    m_bsend(false),
+                    m_brecv(false),
+                    m_bown(false),
+                    m_bcheck(false),
+                    m_ballow(false) {}
+
+                ~Key() {}
+
+                void reset_attributes() {
+                    m_bsend = m_brecv = m_bown = m_bcheck = m_ballow = false;
+                    std::fill(m_path_content.begin() + IDX_DEFAULT, m_path_content.end(), ANY);
+                }
+
+                const std::string get_path() const {
+                    std::string path = "R";
+                    auto it_cend = m_bown ? m_path_content.cbegin() + IDX_OWN_LENGTH : m_path_content.cend();
+                    for(auto it = m_path_content.cbegin(); it != it_cend; ++it) {
+                        path += (std::string(1, Key::DELIM) + *it);
+                    }
+                    return path;
+                }
+        };
+
+        class Leaf {
+            bool m_decision;
+            bool m_check;
+            std::string m_privilege;
+            size_t m_weight;
+
+            public:
+            Leaf() : m_decision(false), m_check(false), m_privilege(""), m_weight(0) {};
+
+            Leaf(bool decision, bool check, const std::string& privilege, size_t weight)
+                : m_decision(decision), m_check(check), m_privilege(privilege), m_weight(weight) {}
+
+            bool get_decision() const {
+                return m_decision;
+            }
+
+            bool get_check() const {
+                return m_check;
+            }
+
+            const std::string& get_privilege() const {
+                return m_privilege;
+            }
+
+            size_t get_weight() const {
+                return m_weight;
+            }
+
+            friend std::ostream& operator<<(std::ostream& os, const Leaf& lf) {
+                if(lf.m_check) {
+                    os << "check," << lf.m_privilege << "," << lf.m_weight;
+                } else {
+                    os << (lf.m_decision ? "true" : "false") << "," << lf.m_weight;
+                }
+                return os;
+            }
+
+            friend std::istream& operator>>(std::istream& is, Leaf& lf) {
+                std::string s;
+                is >> s;
+                boost::char_separator<char> sep(",");
+                boost::tokenizer<boost::char_separator<char>> tokens(s, sep);
+                const auto size = std::distance(tokens.begin(), tokens.end());
+                for(auto it = tokens.begin(); it != tokens.end(); ++it) {
+                    const auto it_last = std::next(tokens.begin(), size - 1);
+                    if(it == tokens.begin()) {
+                        if(size > 2) {
+                            lf.m_check = (*it == "check") ? true : false;
+                        } else {
+                            lf.m_decision = (*it == "true") ? true : false;
+                        }
+                    } else if(it == it_last) {
+                        lf.m_weight = std::stoul(*it);
+                    } else {
+                        if(size > 2) {
+                            lf.m_privilege = *it;
+                        }
+                    }
+                }
+                return is;
+            }
+        };
+
+        static const std::string get_context_str(const CtxType& ctx_type) {
+            switch(ctx_type) {
+                case CtxType::DEFAULT: return "(default)"; break;
+                case CtxType::SPECIFIC: return "(specific)"; break;
+                case CtxType::MANDATORY: return "(mandatory)"; break;
+                default: return ""; break;
+            }
+        }
+
+        static const std::string get_field_str(const std::string& field) {
+            return (field == "") ? Key::ANY : field;
+        }
+
+        //Data obtained from XML parsing - decision trees
+        typedef std::map<std::string, boost::property_tree::ptree> Trees_t;
+        std::map<std::string, Trees_t> m_dec_trees;
+        std::mutex m_xml_policy_mtx;
+
+        boost::property_tree::ptree* get_decision_tree(const std::string& bus, const std::string& tree_type) {
+            boost::property_tree::ptree* p_tree = NULL;
+
+            auto it1 = m_dec_trees.find(bus);
+            if(it1 != m_dec_trees.end()) {
+                auto it2 = it1->second.find(tree_type);
+                if(it2 != it1->second.end()) {
+                    p_tree = &it2->second;
+                }
+            }
+            return p_tree;
+        }
+
+        boost::property_tree::ptree* get_decision_tree(const Key& key) {
+            std::string tree_type;
+            if(key.m_bsend) { tree_type = "SEND"; }
+            else if(key.m_brecv) { tree_type = "RECV"; }
+            else if(key.m_bown) { tree_type = "OWN"; }
+
+            return get_decision_tree(key.m_bus, tree_type);
+        }
+
+        void print_decision_tree(const boost::property_tree::ptree& pt, int level = 0) {
+            for(const auto& v : pt) {
+                print_field(v, level);
+                print_decision_tree(v.second, level + 1);
+            }
+        }
+
+        void print_decision_key(const Key& key) {
+            if(_ldp_tslog::get_verbose()) {
+                std::string s = key.m_bus + " ";
+                if(key.m_bsend && !key.m_brecv) { s += "--> #"; }
+                if(!key.m_bsend && key.m_brecv) { s += "<-- #"; }
+                if(!key.m_bsend && !key.m_brecv && key.m_bown) { s += "OWN #"; }
+                std::string prv = key.m_bcheck ? key.m_privilege : "";
+                verbose::tout << s
+                    << (key.m_bcheck ? "check " : std::to_string(key.m_ballow))
+                    << prv
+                    << " : "
+                    << key.get_path()
+                    << "    (weight: "
+                    << key.m_weight
+                    << ")"
+                    << std::endl;
+            }
+        }
+
+        void update_decision_tree(const Key& key) {
+            if(!key.get_path().empty()) {
+                print_decision_key(key);
+
+                //update
+                boost::property_tree::ptree* const p_tree = get_decision_tree(key);
+                if(p_tree) {
+                    boost::property_tree::ptree::path_type tpath(key.get_path(), Key::DELIM);
+                    p_tree->put(tpath, Leaf(key.m_ballow, key.m_bcheck, key.m_privilege, key.m_weight));
+                }
+            }
+        }
+
+        void update_decision_path(const boost::property_tree::ptree::value_type& v,
+                Key& key,
+                CtxType& current_ctx,
+                bool& allden,
+                bool& bcheck,
+                bool& attr) {
+            if(v.first == "allow") {
+                allden = true;
+                bcheck = false;
+                attr = false;
+                key.reset_attributes();
+            } else if(v.first == "deny") {
+                allden = false;
+                bcheck = false;
+                attr = false;
+                key.reset_attributes();
+            } else if(v.first == "check") {
+                allden = false;
+                bcheck = true;
+                attr = false;
+                key.reset_attributes();
+            } else if(v.first == "<xmlattr>") {
+                attr = true;
+                ++key.m_weight;
+            } else {
+                if(attr) {
+                    std::string data_str = (v.second.data() == "*") ? Key::ANY : v.second.data();
+                    if(v.first == "context") {
+                        if(data_str == "mandatory") {
+                            key.m_path_content[Key::IDX_USER] = Key::MRY;
+                            key.m_path_content[Key::IDX_GROUP] = Key::MRY;
+                            current_ctx = CtxType::MANDATORY;
+                        } else if(data_str == "default") {
+                            key.m_path_content[Key::IDX_USER] = Key::DEF;
+                            key.m_path_content[Key::IDX_GROUP] = Key::DEF;
+                            current_ctx = CtxType::DEFAULT;
+                        }
+                    } else if(v.first == "user") {
+                        if(current_ctx == CtxType::SPECIFIC) {
+                            key.m_path_content[Key::IDX_USER] = data_str;
+                        }
+                    } else if(v.first == "group") {
+                        if(current_ctx == CtxType::SPECIFIC) {
+                            key.m_path_content[Key::IDX_GROUP] = data_str;
+                        }
+                    } else {
+                        if(field_has(v, "send_")) {
+                            key.m_bsend = true;
+                        }
+                        if(field_has(v, "receive_")) {
+                            key.m_brecv = true;
+                        }
+                        if(v.first == "own") {
+                            key.m_bown = true;
+                            key.m_path_content[Key::IDX_SERVICE] = data_str;
+                        }
+                        if(field_has(v, "_destination")) {
+                            key.m_path_content[Key::IDX_DEST] = data_str;
+                        }
+                        if(field_has(v, "_sender")) {
+                            key.m_path_content[Key::IDX_SENDER] = data_str;
+                        }
+                        if(field_has(v, "_path")) {
+                            key.m_path_content[Key::IDX_PATH] = data_str;
+                        }
+                        if(field_has(v, "_interface")) {
+                            key.m_path_content[Key::IDX_IFACE] = data_str;
+                        }
+                        if(field_has(v, "_member")) {
+                            key.m_path_content[Key::IDX_MEMBER] = data_str;
+                        }
+                        if(field_has(v, "_type")) {
+                            key.m_path_content[Key::IDX_TYPE] = data_str;
+                        }
+                        if(v.first == "privilege") {
+                            key.m_privilege = data_str;
+                        }
+
+                        key.m_bcheck = bcheck;
+                        key.m_ballow = allden;
+                    }
+                }
+            }
+        }
+
+        bool field_has(const boost::property_tree::ptree::value_type& v, const std::string& substr) {
+            return (v.first.find(substr) != std::string::npos);
+        }
+
+        void print_field(const boost::property_tree::ptree::value_type& v, int level) {
+            verbose::tout    << ((level > 0) ? std::string((level - 1) * 8, ' ') + std::string(8, '.') : "")
+                << v.first
+                << " : "
+                << v.second.data()
+                << std::endl;
+        }
+
+        void xml_traversal(const boost::property_tree::ptree& pt,
+                Key& key,
+                CtxType& current_ctx,
+                bool allden = false,
+                bool bcheck = false,
+                bool attr = false,
+                int level = 0) {
+            static const int Q_XML_MAX_LEVEL = 10;
+
+            if(level < Q_XML_MAX_LEVEL) {
+                for(const auto& v : pt) {
+                    if(v.first == "<xmlcomment>") { continue; }
+
+                    update_decision_path(v, key, current_ctx, allden, bcheck, attr);
+                    //print_field(v, level);
+                    xml_traversal(v.second, key, current_ctx, allden, bcheck, attr, level + 1);
+                }
+
+                if(!pt.empty() && attr && level > 1) {
+                    update_decision_tree(key);
+                }
+            } else {
+                terr << "XML traversal max level reached: " << level << std::endl;
+            }
+        }
+
+        void print_indexing_path(size_t idx, const std::string& path, const Leaf& leaf = Leaf(), bool empty = true) {
+            if(_ldp_tslog::get_verbose()) {
+                std::string s;
+                if(!empty) {
+                    s = "    : <";
+                    s += (leaf.get_check()
+                        ? std::string("check: ") + std::to_string(leaf.get_check()) + ", privilege: " + leaf.get_privilege()
+                        : std::string("decision: ") + std::to_string(leaf.get_decision()));
+                    s += (std::string(", weight: ") + std::to_string(leaf.get_weight()));
+                    s += std::string(">");
+                }
+
+                verbose::tout << "path #"
+                    << idx
+                    << " : "
+                    << path
+                    << s
+                    << std::endl;
+            }
+        }
+
+        void prepare_indexing_path(const std::vector<std::string>& idx_v,
+                const size_t pattern,
+                const size_t obfuscate_order,
+                const CtxType& ctx_type,
+                std::string& path) {
+
+            const size_t offset = Key::IDX_DEFAULT;
+            path = "R";
+
+            if(ctx_type == CtxType::SPECIFIC) {
+                switch(obfuscate_order) {
+                    case 0:
+                        path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_USER]));
+                        path += (std::string(1, Key::DELIM) + Key::ANY);
+                    break;
+                    case 1:
+                        path += (std::string(1, Key::DELIM) + Key::ANY);
+                        path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_GROUP]));
+                    break;
+                    case 2:
+                        path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_USER]));
+                        path += (std::string(1, Key::DELIM) + get_field_str(idx_v[Key::IDX_GROUP]));
+                    break;
+                    case 3:
+                    default:
+                        path += (std::string(1, Key::DELIM) + Key::ANY);
+                        path += (std::string(1, Key::DELIM) + Key::ANY);
+                    break;
+                }
+            } else {
+                for(size_t i = 0; i < offset; ++i) {
+                    const std::string as = (ctx_type == CtxType::MANDATORY) ? Key::MRY : Key::DEF;
+                    path += (std::string(1, Key::DELIM) + as);
+                }
+            }
+
+            const size_t m = 1;
+            const size_t n = idx_v.size() - offset;
+            for(size_t i = 0; i < n; ++i) {
+                std::string s = get_field_str(idx_v[i + offset]);
+                path += Key::DELIM;
+                if(pattern & (m << i)) {
+                    path += Key::ANY;
+                } else {
+                    path += s;
+                }
+            }
+        }
+
+        ErrCode index_decision_tree(const boost::property_tree::ptree& pt,
+            const std::vector<std::string>& idx_v,
+            const std::string& label,
+            const CtxType& ctx_type) {
+            ErrCode err;
+            bool found = false;
+            size_t weight = 0;
+            const size_t offset = Key::IDX_DEFAULT;
+            const size_t m = (ctx_type == CtxType::SPECIFIC) ? (1 << offset) : 1;
+            for(size_t ob_or = 0; ob_or < m; ++ob_or) {
+                Leaf leaf_found;
+                const size_t n = 1 << (idx_v.size() - offset);
+                for(size_t p = 0; p < n; ++p) {
+                    std::string path;
+                    try {
+                        prepare_indexing_path(idx_v, p, ob_or, ctx_type, path);
+                        boost::property_tree::ptree::path_type tpath(path, Key::DELIM);
+
+                        auto dec = pt.get<Leaf>(tpath);
+
+                        print_indexing_path(p, path, dec, false);
+                        found = true;
+                        if(dec.get_weight() >= weight) {
+                            weight = dec.get_weight();
+                            leaf_found = dec;
+                        }
+                    } catch(const boost::property_tree::ptree_error& ex) {
+                        //Path doesn't exist, continue
+                        print_indexing_path(p, path);
+                        if(!found) { err = ErrCode::error("No path"); }
+                    } catch(...) {
+                        print_indexing_path(p, path);
+                        verbose::tout << "Unknown exception while indexing decision tree!" << std::endl;
+                        if(!found) { err = ErrCode::error("Unknown err, no path"); }
+                    }
+                }
+
+                if(found) {
+                    if(leaf_found.get_check()) {
+                        verbose::tout << __func__
+                            << ": cynara check needed for privilege " << leaf_found.get_privilege()
+                            << ", weight " << leaf_found.get_weight()
+                            << std::endl;
+
+                        //cynara check
+                        try {
+                            bool br = _ldp_cynara::Cynara::check(label, leaf_found.get_privilege(), idx_v[Key::IDX_USER]);
+                            err = ErrCode::ok(br);
+                        } catch(const std::runtime_error& ex) {
+                            err = ErrCode::error(ex.what());
+                        }
+                    } else {
+                        err = ErrCode::ok(leaf_found.get_decision());
+                    }
+
+                    verbose::tout << __func__ << ": returning decision #" << err.get() << " " << err.get_str() << ", weight " << leaf_found.get_weight() << std::endl;
+                    break;
+                }
+            }
+
+            return err;
+        }
+
+        ErrCode index_decision_tree_lat(const boost::property_tree::ptree& pt,
+            const std::vector<std::string>& idx_v,
+            const std::string& label,
+            const CtxType& ctx_type) {
+            ErrCode err;
+
+            tout << "context: " << get_context_str(ctx_type) << ",  indexing arguments: ";
+            if(_ldp_tslog::get_enable()) { std::copy(idx_v.begin(), idx_v.end(), std::ostream_iterator<std::string>(std::cout, ", ")); }
+            tout << std::endl;
+
+            //Examine policy data and make decision
+            _ldp_timer::microsec latency;
+            {
+                _ldp_timer::Timer<_ldp_timer::microsec> t(&latency);
+                err = index_decision_tree(pt, idx_v, label, ctx_type);
+            }
+
+            tout << __func__ << ": #" << err.get() << " " << err.get_str() << " " << get_context_str(ctx_type) << std::endl;
+            tout << "tree indexing latency: " << latency << std::endl;
+            return err;
+        }
+
+        ErrCode can_do_action(const std::string& bus, const std::string& tree_type, const std::vector<std::string>& idx_v, const std::string& label = "") {
+            std::unique_lock<std::mutex> lck(m_xml_policy_mtx);
+            ErrCode err;
+            boost::property_tree::ptree* const p_tree = get_decision_tree(bus, tree_type);
+            if(p_tree) {
+                err = index_decision_tree_lat(*p_tree, idx_v, label, CtxType::MANDATORY);
+                if(!err.is_ok()) {
+                    err = index_decision_tree_lat(*p_tree, idx_v, label, CtxType::SPECIFIC);
+                    if(!err.is_ok()) {
+                        err = index_decision_tree_lat(*p_tree, idx_v, label, CtxType::DEFAULT);
+                    }
+                }
+            } else {
+                err = ErrCode::error("Get decision tree returned NULL ptr");
+            }
+            tout << __func__ << ": #" << err.get()  << " " << err.get_str() << std::endl;
+            return err;
+        }
+
+        public:
+        XmlPolicy() {
+            Trees_t t;
+            t.emplace("SEND", typename Trees_t::mapped_type());
+            t.emplace("RECV", typename Trees_t::mapped_type());
+            t.emplace("OWN", typename Trees_t::mapped_type());
+            m_dec_trees.emplace("SYSTEM", t);
+            m_dec_trees.emplace("SESSION", t);
+        }
+
+        virtual ~XmlPolicy() {}
+
+        void init() {
+            std::unique_lock<std::mutex> lck(m_xml_policy_mtx);
+            Key::m_weight = 0;
+        }
+
+        void update(const std::string& bus, const boost::property_tree::ptree& pt) {
+            if(!pt.empty()) {
+                std::unique_lock<std::mutex> lck(m_xml_policy_mtx);
+                const auto& children = pt.get_child(ROOT_FIELD);
+                for(const auto& x : children) {
+                    if(x.first == ROOT_POLICY) {
+                        Key key(bus);
+                        CtxType current_ctx = CtxType::SPECIFIC;
+                        xml_traversal(x.second, key, current_ctx);
+                    }
+                }
+            }
+        }
+
+        ErrCode can_send_to(const std::string bus, const std::vector<std::string>& idx_v, const std::string label) {
+            return can_do_action(bus, "SEND", idx_v, label);
+        }
+
+        ErrCode can_recv_from(const std::string bus, const std::vector<std::string>& idx_v, const std::string label) {
+            return can_do_action(bus, "RECV", idx_v, label);
+        }
+
+        ErrCode can_own_what(const std::string bus, const std::vector<std::string>& idx_v) {
+            return can_do_action(bus, "OWN", idx_v);
+        }
+
+        void print_decision_trees() {
+            if(_ldp_tslog::get_verbose()) {
+                std::unique_lock<std::mutex> lck(m_xml_policy_mtx);
+
+                for(const auto& x : m_dec_trees) {
+                    for(const auto& y : x.second) {
+                        verbose::tout << x.first << " " << y.first << " " << (y.second.empty() ? "(empty)" : "") << std::endl;
+                        print_decision_tree(y.second);
+                    }
+                }
+            }
+        }
+
+    }; //XmlPolicy
+    size_t XmlPolicy::Key::m_weight = 0;
+} //namespace
+
+#endif
diff --git a/src/libdbuspolicy1-private.h b/src/libdbuspolicy1-private.h
new file mode 100644 (file)
index 0000000..58e27bd
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#ifndef _LIBDBUSPOLICY1_PRIVATE_H_
+#define _LIBDBUSPOLICY1_PRIVATE_H_
+
+#include <stdbool.h>
+#include <syslog.h>
+
+#include <dbuspolicy1/libdbuspolicy1.h>
+#include "kdbus.h"
+
+
+#define DBUSPOLICY1_EXPORT __attribute__ ((visibility("default")))
+
+#endif
diff --git a/src/libdbuspolicy1.c b/src/libdbuspolicy1.c
new file mode 100644 (file)
index 0000000..01d586a
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <dbuspolicy1/libdbuspolicy1.h>
+#include "libdbuspolicy1-private.h"
+#include "internal/internal.h"
+
+#define KDBUS_SYSTEM_BUS_PATH "/sys/fs/kdbus/0-system/bus"
+#define KDBUS_POOL_SIZE (16 * 1024UL * 1024UL)
+
+#define ALIGN8(l) (((l) + 7) & ~7)
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+
+#define FOREACH_STRV(i,l, s, os)\
+for(\
+({\
+i=0;\
+l = strlen(s);\
+name = malloc(sizeof(char*)*(l+1));\
+strcpy(os, s);\
+});\
+i < l;\
+i++)
+
+#define GET_NEXT_STR(i,s,os)\
+        os = s+i;\
+        for(;s[i] && s[i] != ' ';i++);\
+        s[i] = 0;
+
+
+
+/** A process ID */
+typedef unsigned long dbus_pid_t;
+/** A user ID */
+typedef unsigned long dbus_uid_t;
+/** A group ID */
+typedef unsigned long dbus_gid_t;
+
+struct kcreds {
+    uid_t uid;
+    gid_t gid;
+    char* label;
+    char** names;
+};
+
+struct kconn {
+    int fd;
+    uint64_t id;
+    char *pool;
+};
+struct udesc {
+    unsigned int bus_type;
+    char user[256];
+    dbus_uid_t uid;
+    char group[256];
+    dbus_gid_t gid;
+    char label[256];
+    struct kconn* conn;
+};
+
+static void print_udesc(const char* const entry, const struct udesc* const p_udesc) {
+}
+
+static int kdbus_open_system_bus(void)
+{
+    return  open(KDBUS_SYSTEM_BUS_PATH, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC );
+}
+
+static int kdbus_hello(struct kconn *kc, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv)
+{
+    struct kdbus_cmd_hello kcmd_hello;
+    int r;
+
+    memset(&kcmd_hello, 0, sizeof(kcmd_hello));
+    kcmd_hello.flags = hello_flags;
+    kcmd_hello.attach_flags_send = attach_flags_send;
+    kcmd_hello.attach_flags_recv = attach_flags_recv;
+    kcmd_hello.size = sizeof(kcmd_hello);
+    kcmd_hello.pool_size = KDBUS_POOL_SIZE;
+
+    r = ioctl(kc->fd, KDBUS_CMD_HELLO, &kcmd_hello);
+    if (r < 0)
+        return -errno;
+
+    kc->id = (uint64_t)kcmd_hello.id;
+    kc->pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kc->fd, 0);
+    if (kc->pool == MAP_FAILED)
+        return -errno;
+
+    return 0;
+}
+
+static int kdbus_get_creds_from_name(struct kconn* kc, struct kcreds* kcr, const char* name)
+{
+    struct kdbus_cmd_info* cmd;
+    struct kdbus_info* conn_info;
+    struct kdbus_item *item;
+    char** tmp_names;
+    int j,size,r,l,counter;
+
+    counter = 0;
+    kcr->names = calloc(counter+1, sizeof(char *));
+
+    kcr->uid = UID_INVALID;
+    kcr->gid = GID_INVALID;
+    kcr->label = NULL;
+
+
+    l = strlen(name) + 1;
+
+    size = offsetof(struct kdbus_cmd_info, items) + ALIGN8((l) + offsetof(struct kdbus_item, data));//ietms+aligned(l+ITEM_HEADER_SIZE)
+    cmd = aligned_alloc(8, size);
+    memset(cmd, 0, sizeof(struct kdbus_cmd_info));
+    cmd->items[0].size =  l + offsetof(struct kdbus_item, data) ;
+    cmd->items[0].type = KDBUS_ITEM_NAME;
+    memcpy(cmd->items[0].str, name, l);
+    cmd->size = size;
+    cmd->attach_flags  = KDBUS_ATTACH_CREDS | KDBUS_ATTACH_SECLABEL | KDBUS_ATTACH_NAMES ;
+
+    r = ioctl(kc->fd, KDBUS_CMD_CONN_INFO, cmd);
+    if (r < 0)
+        return -errno;
+
+    conn_info = (struct kdbus_info *) ((uint8_t *) kc->pool + cmd->offset);
+
+    for(item = conn_info->items;
+        ((uint8_t *)(item) < (uint8_t *)(conn_info) + (conn_info)->size) &&
+        ((uint8_t *) item >= (uint8_t *) conn_info);
+        item = ((typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))) )
+        {
+            switch (item->type)
+            {
+                case KDBUS_ITEM_CREDS:
+                    if (item->creds.euid != UID_INVALID)
+                    {
+                         kcr->uid = (uid_t) item->creds.euid;
+                    }
+                    if (item->creds.egid != GID_INVALID)
+                    {
+                        kcr->gid = (gid_t) item->creds.egid;
+                    }
+                break;
+            case KDBUS_ITEM_SECLABEL:
+                kcr->label = strdup(item->str);
+            break;
+            case KDBUS_ITEM_OWNED_NAME:
+                counter++;
+                tmp_names = calloc(counter+1, sizeof(char*));
+                for (j = 0;kcr->names[j]; j++)
+                {
+                    tmp_names[j] = kcr->names[j];
+                }
+                tmp_names[j] = strdup(item->name.name);
+                free(kcr->names);
+                kcr->names = tmp_names;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static void kcreds_free(struct kcreds* kcr)
+{
+    int i = 0;
+    if (kcr == NULL)
+        return;
+
+    free(kcr->label);
+    for (i=0; kcr->names[i];i++)
+        free(kcr->names[i]);
+    free(kcr->names[i]);
+    free(kcr->names);
+    free(kcr);
+}
+/**
+ * dbuspolicy1_init
+ * @config_name: name of the XML configuration file
+ *
+ * Set the configuration file used by the calling application
+ **/
+DBUSPOLICY1_EXPORT void* dbuspolicy1_init(unsigned int bus_type)
+{
+    struct kconn* kc;
+    uint64_t hello_flags = 0;
+    uint64_t attach_flags_send =  _KDBUS_ATTACH_ANY;
+    uint64_t attach_flags_recv =  _KDBUS_ATTACH_ALL;
+    int r,fdl;
+    struct udesc* p_udesc;
+
+    kc = (struct kconn*) calloc(1, sizeof(struct kconn));
+    if (!kc)
+        return NULL;
+
+    kc->fd = kdbus_open_system_bus();
+    r = kdbus_hello(kc, hello_flags, attach_flags_send, attach_flags_recv);
+    if (r < 0) {
+        free(kc);
+        return NULL;
+    }
+
+    r = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE : SESSION_BUS_CONF_FILE);
+    if(r >= 0) {
+        p_udesc = (struct udesc*)malloc(sizeof(struct udesc));
+        if(p_udesc) {
+            p_udesc->bus_type = bus_type;
+            p_udesc->uid = getuid();
+            p_udesc->gid = getgid();
+            struct passwd* pwd = getpwuid(p_udesc->uid);
+            strcpy(p_udesc->user, pwd->pw_name);
+            struct group* gg = getgrgid(p_udesc->gid);
+            strcpy(p_udesc->group, gg->gr_name);
+            p_udesc->conn = kc;
+
+            fdl = open("/proc/self/attr/current", 0, S_IRUSR);
+            if (fdl < 0)
+            {
+                fprintf(stderr,"Cannot open /proc/self/attr/current\n");
+                dbuspolicy1_free(p_udesc);
+                return NULL;
+            }
+
+            r = read(fdl, p_udesc->label, 256);
+            if (r < 0)
+            {
+                fprintf(stderr, "Cannot read from /proc/self/attr/current\n");
+                close(fdl);
+                dbuspolicy1_free(p_udesc);
+                return NULL;
+            }
+            close(fdl);
+
+
+            print_udesc("New configuration", p_udesc);
+        }
+    } else {
+        p_udesc = NULL;
+    }
+    return p_udesc;
+}
+
+DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
+{
+    struct udesc* p_udesc = (struct udesc*)configuration;
+    if(p_udesc) {
+        print_udesc("Freeing configuration", p_udesc);
+        free(p_udesc->conn);
+        free(p_udesc);
+        p_udesc = NULL;
+    }
+}
+
+/**
+ * dbuspolicy1_can_send
+ * @param: <>
+ * @return: <>
+ *
+ * Description.
+ **/
+DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
+        const char        *destination,
+        const char        *sender,
+        const char        *path,
+        const char        *interface,
+        const char        *member,
+        int               message_type,
+        const char        *error_name,
+        int               reply_serial,
+        int               requested_reply)
+{
+    struct udesc* const p_udesc = (struct udesc*)configuration;
+    int i, rs, rr, l,  r = 0;
+    struct kcreds* p_creds = NULL;
+    char gid[25], uid[25];
+    char* name = NULL;
+    char  empty_names = 1;
+
+    rs = 0;
+    rr = 1;
+
+    if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL || (destination != NULL && *destination != '\0') ) {
+        p_creds = calloc(1, sizeof(struct kcreds));
+        r = kdbus_get_creds_from_name(p_udesc->conn, p_creds, destination);
+        if(r < 0) {
+            kcreds_free(p_creds);
+            return 0;
+        }
+
+        snprintf(uid, 24, "%lu", (unsigned long int)p_creds->uid);
+        snprintf(gid, 24, "%lu", (unsigned long int)p_creds->gid);
+        if (!p_creds->names[0])
+            empty_names = 0;
+
+        for (i=0;p_creds->names[i];i++)
+        {
+            rs = __internal_can_send(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, p_creds->names[i], path, interface, member, message_type);
+            if (rs > 0)
+                break;
+        }
+    }
+
+    if (empty_names)
+        rs = __internal_can_send(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, destination, path, interface, member, message_type);
+
+    if (message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) {
+        rr = 0;
+
+        if (!sender)
+            rr = __internal_can_recv(p_udesc->bus_type, uid, gid, p_creds->label, sender, path, interface, member, message_type);
+        else
+            FOREACH_STRV(i, l, sender, name) {
+                char* source;
+                GET_NEXT_STR(i, name, source);
+                rr = __internal_can_recv(p_udesc->bus_type, uid, gid, p_creds->label, source, path, interface, member, message_type);
+                if (rr > 0)
+                    break;
+            }
+    }
+
+    free(name);
+    kcreds_free(p_creds);
+
+    if(rs > 0 && rr > 0) { r = 1; }
+    if(rs < 0 || rr < 0) { r = -1; }
+    return r;
+}
+/**
+ * dbuspolicy1_can_send
+ * @param: <>
+ * @return: <>
+ *
+ * Description.
+ **/
+DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
+        const char        *destination,
+        const char        *sender,
+        const char        *sender_label,
+        uid_t             sender_uid,
+        gid_t             sender_gid,
+        const char        *path,
+        const char        *interface,
+        const char        *member,
+        int               message_type,
+        const char        *error_name,
+        int               reply_serial,
+        int               requested_reply)
+{
+    struct udesc* const p_udesc = (struct udesc*)configuration;
+    int i, rs, rr, l, r = 0;
+    struct kcreds* p_creds = NULL;
+    char gid[25], uid[25];
+    char* name = NULL;
+
+    rs = 0;
+    rr = 1;
+
+    snprintf(uid, 24, "%lu", (unsigned long int)sender_uid);
+    snprintf(gid, 24, "%lu", (unsigned long int)sender_gid);
+
+    if (!destination)
+         rs = __internal_can_send(p_udesc->bus_type, uid, gid, sender_label, destination, path, interface, member, message_type);
+    else
+        FOREACH_STRV(i, l, destination, name) {
+            char* dest;
+            GET_NEXT_STR(i, name, dest);
+
+            rs = __internal_can_send(p_udesc->bus_type, uid, gid, sender_label, dest, path, interface, member, message_type);
+            if (rs > 0)
+                break;
+        }
+    free(name);
+
+    if(message_type != DBUSPOLICY_MESSAGE_TYPE_SIGNAL) {
+        rr = 0;
+
+        if (!sender)
+            rr = __internal_can_recv(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, sender, path, interface, member, message_type);
+        else
+            FOREACH_STRV(i, l, sender, name) {
+                char* source;
+                GET_NEXT_STR(i, name, source);
+                rr = __internal_can_recv(p_udesc->bus_type, p_udesc->user, p_udesc->group, p_udesc->label, source, path, interface, member, message_type);
+                if(rr > 0)
+                    break;
+            }
+        free(name);
+    }
+    kcreds_free(p_creds);
+
+    if(rs > 0 && rr > 0) { r = 1; }
+    if(rs < 0 || rr < 0) { r = -1; }
+    return r;
+}
+
+
+/**
+ * dbuspolicy1_can_send
+ * @param: <>
+ * @return: <>
+ *
+ * Description.
+ **/
+DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service)
+{
+    struct udesc* const p_udesc = (struct udesc*)configuration;
+    return  __internal_can_own(p_udesc->bus_type, p_udesc->user, p_udesc->group, service);
+}
diff --git a/src/libdbuspolicy1.pc.in b/src/libdbuspolicy1.pc.in
new file mode 100644 (file)
index 0000000..2e04c48
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdbuspolicy1
+Description: Library for something with dbuspolicy1
+Version: @VERSION@
+Libs: -L${libdir} -ldbuspolicy1
+Libs.private:
+Cflags: -I${includedir}
diff --git a/src/libdbuspolicy1.sym b/src/libdbuspolicy1.sym
new file mode 100644 (file)
index 0000000..051e64e
--- /dev/null
@@ -0,0 +1,19 @@
+LIBDBUSPOLICY1_1 {
+global:
+        dbuspolicy1_init;
+        dbuspolicy1_free;
+        dbuspolicy1_check_in;
+        dbuspolicy1_check_out;
+        dbuspolicy1_can_own;
+local:
+        *;
+};
+
+LIBDBUSPOLICY1_3 {
+global:
+        dbuspolicy1_thing_ref;
+        dbuspolicy1_thing_unref;
+        dbuspolicy1_thing_get_ctx;
+        dbuspolicy1_thing_new_from_string;
+        dbuspolicy1_thing_get_some_list_entry;
+} LIBDBUSPOLICY1_1;