summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--NEWS48
-rw-r--r--bus/Makefile.am4
-rw-r--r--bus/Makefile.in49
-rw-r--r--bus/apparmor.c1128
-rw-r--r--bus/apparmor.h66
-rw-r--r--bus/bus.c90
-rw-r--r--bus/bus.h1
-rw-r--r--bus/config-parser-common.c6
-rw-r--r--bus/config-parser-common.h3
-rw-r--r--bus/config-parser.c24
-rw-r--r--bus/connection.c35
-rw-r--r--bus/connection.h1
-rw-r--r--bus/driver.c136
-rw-r--r--bus/main.c8
-rw-r--r--bus/services.c7
-rw-r--r--bus/session.conf.in3
-rw-r--r--bus/signals.c9
-rw-r--r--bus/signals.h2
-rw-r--r--bus/system.conf.in3
-rw-r--r--cmake/CMakeLists.txt2
-rw-r--r--cmake/bus/CMakeLists.txt2
-rw-r--r--cmake/bus/CMakeLists.txt.orig203
-rw-r--r--cmake/config.h.cmake1
-rw-r--r--cmake/doc/CMakeLists.txt3
-rw-r--r--cmake/test/CMakeLists.txt7
-rw-r--r--cmake/tools/CMakeLists.txt15
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure304
-rw-r--r--configure.ac72
-rw-r--r--dbus/Makefile.in4
-rw-r--r--dbus/dbus-asv-util.c54
-rw-r--r--dbus/dbus-asv-util.h4
-rw-r--r--dbus/dbus-auth.c11
-rw-r--r--dbus/dbus-connection-internal.h3
-rw-r--r--dbus/dbus-connection.c26
-rw-r--r--dbus/dbus-credentials.c68
-rw-r--r--dbus/dbus-credentials.h4
-rw-r--r--dbus/dbus-internals.c10
-rw-r--r--dbus/dbus-internals.h2
-rw-r--r--dbus/dbus-shared.h2
-rw-r--r--dbus/dbus-sysdeps-unix.c105
-rw-r--r--dbus/dbus-sysdeps-win.c12
-rw-r--r--dbus/dbus-sysdeps-win.h1
-rw-r--r--dbus/dbus-transport.c27
-rw-r--r--dbus/dbus-transport.h3
-rw-r--r--doc/Makefile.am36
-rw-r--r--doc/Makefile.in50
-rw-r--r--doc/busconfig.dtd7
-rw-r--r--doc/dbus-api-design.duck888
-rw-r--r--doc/dbus-daemon.1.xml.in56
-rw-r--r--doc/dbus-specification.xml70
-rw-r--r--doc/dbus-test-tool.1.xml.in325
-rw-r--r--test/Makefile.am8
-rw-r--r--test/Makefile.in84
-rw-r--r--test/dbus-daemon.c50
-rw-r--r--test/fdpass.c25
-rw-r--r--test/manual-paths.c73
-rw-r--r--test/name-test/Makefile.in4
-rw-r--r--tools/Makefile.am5
-rw-r--r--tools/Makefile.in11
-rw-r--r--tools/dbus-monitor.c111
-rw-r--r--tools/dbus-print-message.c60
63 files changed, 4233 insertions, 205 deletions
diff --git a/Makefile.in b/Makefile.in
index abe54c60..e207e4b0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -256,6 +256,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -310,6 +312,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -399,6 +402,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
diff --git a/NEWS b/NEWS
index 24abd4d9..327069c2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,51 @@
+D-Bus 1.9.12 (2015-02-19)
+==
+
+The “monster lasagna” release.
+
+Dependencies:
+
+• Ducktype and yelp-tools are now required to build complete documentation.
+
+Enhancements:
+
+• D-Bus Specification version 0.26
+ · GetConnectionCredentials can return LinuxSecurityLabel or WindowsSID
+ · document the BecomeMonitor method
+
+• On Linux, add LinuxSecurityLabel to GetConnectionCredentials
+ (fd.o #89041; Tyler Hicks, Simon McVittie)
+
+• On Linux, add support for AppArmor mediation of message sending and
+ receiving and name ownership (paralleling existing SELinux mediation
+ support), and eavesdropping (a new check, currently AppArmor-specific)
+ (fd.o #75113; John Johansen, Tyler Hicks, Simon McVittie)
+
+• In dbus-send and dbus-monitor, pretty-print \0-terminated bytestrings
+ that have printable ASCII contents; we previously only did this for
+ unterminated bytestrings (fd.o #89109, Simon McVittie)
+
+• Add a guide to designing good D-Bus APIs (fd.o #88994, Philip Withnall)
+
+• On Windows, add WindowsSID to GetConnectionCredentials
+ (fd.o #54445, Ralf Habacker)
+
+• Improve clarity of dbus-monitor --profile output and add more columns
+ (fd.o #89165, Ralf Habacker)
+
+• Add a man page for dbus-test-tool, and build it under CMake as well
+ as Autotools (fd.o#89086, Simon McVittie)
+
+• If dbus-daemon was compiled with --enable-verbose, add a D-Bus API
+ to control it at runtime, overriding the DBUS_VERBOSE environment variable
+ (fd.o #88896, Ralf Habacker)
+
+Fixes:
+
+• Reduce the number of file descriptors used in the fd-passing test,
+ avoiding failure under the default Linux fd limit, and automatically
+ skip it if the rlimit is too small (fd.o #88998, Simon McVittie)
+
D-Bus 1.9.10 (2015-02-09)
==
diff --git a/bus/Makefile.am b/bus/Makefile.am
index c0bc1549..9d3cb006 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -4,6 +4,7 @@ dbus_daemon_execdir = $(DBUS_DAEMONDIR)
DBUS_BUS_LIBS = \
$(XML_LIBS) \
$(SELINUX_LIBS) \
+ $(APPARMOR_LIBS) \
$(THREAD_LIBS) \
$(ADT_LIBS) \
$(NETWORK_libs) \
@@ -18,6 +19,7 @@ DBUS_LAUNCHER_LIBS = \
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(XML_CFLAGS) \
+ $(APPARMOR_CFLAGS) \
-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
-DDBUS_COMPILATION \
-DDBUS_STATIC_BUILD \
@@ -69,6 +71,8 @@ BUS_SOURCES= \
activation.c \
activation.h \
activation-exit-codes.h \
+ apparmor.c \
+ apparmor.h \
bus.c \
bus.h \
config-parser.c \
diff --git a/bus/Makefile.in b/bus/Makefile.in
index 6bbcecd6..f162f171 100644
--- a/bus/Makefile.in
+++ b/bus/Makefile.in
@@ -136,21 +136,21 @@ am__installdirs = "$(DESTDIR)$(dbus_daemon_execdir)" \
PROGRAMS = $(dbus_daemon_exec_PROGRAMS) $(libexec_PROGRAMS) \
$(noinst_PROGRAMS)
am__dbus_daemon_SOURCES_DIST = activation.c activation.h \
- activation-exit-codes.h bus.c bus.h config-parser.c \
- config-parser.h config-parser-common.c config-parser-common.h \
- connection.c connection.h desktop-file.c desktop-file.h \
- dir-watch-default.c dir-watch-inotify.c dir-watch-kqueue.c \
- dir-watch.h dispatch.c dispatch.h driver.c driver.h \
- expirelist.c expirelist.h policy.c policy.h selinux.h \
- selinux.c services.c services.h signals.c signals.h stats.c \
- stats.h test.c test.h utils.c utils.h config-loader-expat.c \
- main.c
+ activation-exit-codes.h apparmor.c apparmor.h bus.c bus.h \
+ config-parser.c config-parser.h config-parser-common.c \
+ config-parser-common.h connection.c connection.h \
+ desktop-file.c desktop-file.h dir-watch-default.c \
+ dir-watch-inotify.c dir-watch-kqueue.c dir-watch.h dispatch.c \
+ dispatch.h driver.c driver.h expirelist.c expirelist.h \
+ policy.c policy.h selinux.h selinux.c services.c services.h \
+ signals.c signals.h stats.c stats.h test.c test.h utils.c \
+ utils.h config-loader-expat.c main.c
@DBUS_BUS_ENABLE_INOTIFY_FALSE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@am__objects_1 = dir-watch-default.$(OBJEXT)
@DBUS_BUS_ENABLE_INOTIFY_TRUE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@am__objects_1 = dir-watch-inotify.$(OBJEXT)
@DBUS_BUS_ENABLE_KQUEUE_TRUE@am__objects_1 = \
@DBUS_BUS_ENABLE_KQUEUE_TRUE@ dir-watch-kqueue.$(OBJEXT)
am__objects_2 = config-loader-expat.$(OBJEXT)
-am__objects_3 = activation.$(OBJEXT) bus.$(OBJEXT) \
+am__objects_3 = activation.$(OBJEXT) apparmor.$(OBJEXT) bus.$(OBJEXT) \
config-parser.$(OBJEXT) config-parser-common.$(OBJEXT) \
connection.$(OBJEXT) desktop-file.$(OBJEXT) $(am__objects_1) \
dispatch.$(OBJEXT) driver.$(OBJEXT) expirelist.$(OBJEXT) \
@@ -162,7 +162,7 @@ dbus_daemon_OBJECTS = $(am_dbus_daemon_OBJECTS)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
dbus_daemon_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -195,15 +195,15 @@ dbus_daemon_launch_helper_test_OBJECTS = \
dbus_daemon_launch_helper_test_DEPENDENCIES = \
$(top_builddir)/dbus/libdbus-internal.la $(am__DEPENDENCIES_3)
am__test_bus_SOURCES_DIST = activation.c activation.h \
- activation-exit-codes.h bus.c bus.h config-parser.c \
- config-parser.h config-parser-common.c config-parser-common.h \
- connection.c connection.h desktop-file.c desktop-file.h \
- dir-watch-default.c dir-watch-inotify.c dir-watch-kqueue.c \
- dir-watch.h dispatch.c dispatch.h driver.c driver.h \
- expirelist.c expirelist.h policy.c policy.h selinux.h \
- selinux.c services.c services.h signals.c signals.h stats.c \
- stats.h test.c test.h utils.c utils.h config-loader-expat.c \
- test-main.c
+ activation-exit-codes.h apparmor.c apparmor.h bus.c bus.h \
+ config-parser.c config-parser.h config-parser-common.c \
+ config-parser-common.h connection.c connection.h \
+ desktop-file.c desktop-file.h dir-watch-default.c \
+ dir-watch-inotify.c dir-watch-kqueue.c dir-watch.h dispatch.c \
+ dispatch.h driver.c driver.h expirelist.c expirelist.h \
+ policy.c policy.h selinux.h selinux.c services.c services.h \
+ signals.c signals.h stats.c stats.h test.c test.h utils.c \
+ utils.h config-loader-expat.c test-main.c
am_test_bus_OBJECTS = $(am__objects_3) test-main.$(OBJEXT)
test_bus_OBJECTS = $(am_test_bus_OBJECTS)
test_bus_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la \
@@ -328,6 +328,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -382,6 +384,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -471,6 +474,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -535,6 +539,7 @@ dbus_daemon_execdir = $(DBUS_DAEMONDIR)
DBUS_BUS_LIBS = \
$(XML_LIBS) \
$(SELINUX_LIBS) \
+ $(APPARMOR_LIBS) \
$(THREAD_LIBS) \
$(ADT_LIBS) \
$(NETWORK_libs) \
@@ -549,6 +554,7 @@ DBUS_LAUNCHER_LIBS = \
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(XML_CFLAGS) \
+ $(APPARMOR_CFLAGS) \
-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
-DDBUS_COMPILATION \
-DDBUS_STATIC_BUILD \
@@ -583,6 +589,8 @@ BUS_SOURCES = \
activation.c \
activation.h \
activation-exit-codes.h \
+ apparmor.c \
+ apparmor.h \
bus.c \
bus.h \
config-parser.c \
@@ -976,6 +984,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation-helper-bin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation-helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apparmor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-loader-expat.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-parser-common.Po@am__quote@
diff --git a/bus/apparmor.c b/bus/apparmor.c
new file mode 100644
index 00000000..a1b3621a
--- /dev/null
+++ b/bus/apparmor.c
@@ -0,0 +1,1128 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ * apparmor.c AppArmor security checks for D-Bus
+ *
+ * Based on selinux.c
+ *
+ * Copyright © 2014-2015 Canonical, Ltd.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <config.h>
+#include "apparmor.h"
+
+#ifdef HAVE_APPARMOR
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/apparmor.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBAUDIT
+#include <cap-ng.h>
+#include <libaudit.h>
+#endif /* HAVE_LIBAUDIT */
+
+#include "connection.h"
+#include "utils.h"
+
+/* Store the value telling us if AppArmor D-Bus mediation is enabled. */
+static dbus_bool_t apparmor_enabled = FALSE;
+
+typedef enum {
+ APPARMOR_DISABLED,
+ APPARMOR_ENABLED,
+ APPARMOR_REQUIRED
+} AppArmorConfigMode;
+
+/* Store the value of the AppArmor mediation mode in the bus configuration */
+static AppArmorConfigMode apparmor_config_mode = APPARMOR_ENABLED;
+
+#ifdef HAVE_LIBAUDIT
+static int audit_fd = -1;
+#endif
+
+/* The AppArmor context, consisting of a label and a mode. */
+struct BusAppArmorConfinement
+{
+ int refcount; /* Reference count */
+
+ char *label; /* AppArmor confinement label */
+ const char *mode; /* AppArmor confinement mode (freed by freeing *label) */
+};
+
+static BusAppArmorConfinement *bus_con = NULL;
+
+/**
+ * Callers of this function give up ownership of the *label and *mode
+ * pointers.
+ *
+ * Additionally, the responsibility of freeing *label and *mode becomes the
+ * responsibility of the bus_apparmor_confinement_unref() function. However, it
+ * does not free *mode because libapparmor's aa_getcon(), and libapparmor's
+ * other related functions, allocate a single buffer for *label and *mode and
+ * then separate the two char arrays with a NUL char. See the aa_getcon(2) man
+ * page for more details.
+ */
+static BusAppArmorConfinement*
+bus_apparmor_confinement_new (char *label,
+ const char *mode)
+{
+ BusAppArmorConfinement *confinement;
+
+ confinement = dbus_new0 (BusAppArmorConfinement, 1);
+ if (confinement != NULL)
+ {
+ confinement->refcount = 1;
+ confinement->label = label;
+ confinement->mode = mode;
+ }
+
+ return confinement;
+}
+
+void
+bus_apparmor_audit_init (void)
+{
+#ifdef HAVE_LIBAUDIT
+ audit_fd = audit_open ();
+
+ if (audit_fd < 0)
+ {
+ /* If kernel doesn't support audit, bail out */
+ if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
+ return;
+ /* If user bus, bail out */
+ if (errno == EPERM && getuid () != 0)
+ return;
+ _dbus_warn ("Failed opening connection to the audit subsystem");
+ }
+#endif /* HAVE_LIBAUDIT */
+}
+
+/*
+ * Return TRUE on successful check, FALSE on OOM.
+ * Set *is_supported to whether AA has D-Bus features.
+ */
+static dbus_bool_t
+_bus_apparmor_detect_aa_dbus_support (dbus_bool_t *is_supported)
+{
+ int mask_file;
+ DBusString aa_dbus;
+ char *aa_securityfs = NULL;
+ dbus_bool_t retval = FALSE;
+
+ *is_supported = FALSE;
+
+ if (!_dbus_string_init (&aa_dbus))
+ return FALSE;
+
+ if (aa_find_mountpoint (&aa_securityfs) != 0)
+ goto out;
+
+ /*
+ * John Johansen has confirmed that the mainline kernel will not have
+ * the apparmorfs/features/dbus/mask file until the mainline kernel
+ * has AppArmor getpeersec support.
+ */
+ if (!_dbus_string_append (&aa_dbus, aa_securityfs) ||
+ !_dbus_string_append (&aa_dbus, "/features/dbus/mask"))
+ goto out;
+
+ /* We need to open() the flag file, not just stat() it, because AppArmor
+ * does not mediate stat() in the apparmorfs. If you have a
+ * dbus-daemon inside an LXC container, with insufficiently broad
+ * AppArmor privileges to do its own AppArmor mediation, the desired
+ * result is that it behaves as if AppArmor was not present; but a stat()
+ * here would succeed, and result in it trying and failing to do full
+ * mediation. https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/1238267 */
+ mask_file = open (_dbus_string_get_const_data (&aa_dbus),
+ O_RDONLY | O_CLOEXEC);
+ if (mask_file != -1)
+ {
+ *is_supported = TRUE;
+ close (mask_file);
+ }
+
+ retval = TRUE;
+
+out:
+ free (aa_securityfs);
+ _dbus_string_free (&aa_dbus);
+
+ return retval;
+}
+
+static dbus_bool_t
+modestr_is_complain (const char *mode)
+{
+ if (mode && strcmp (mode, "complain") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static void
+log_message (dbus_bool_t allow, const char *op, DBusString *data)
+{
+ const char *mstr;
+
+ if (allow)
+ mstr = "ALLOWED";
+ else
+ mstr = "DENIED";
+
+#ifdef HAVE_LIBAUDIT
+ if (audit_fd >= 0)
+ {
+ DBusString avc;
+
+ capng_get_caps_process ();
+ if (!capng_have_capability (CAPNG_EFFECTIVE, CAP_AUDIT_WRITE))
+ goto syslog;
+
+ if (!_dbus_string_init (&avc))
+ goto syslog;
+
+ if (!_dbus_string_append_printf (&avc,
+ "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
+ mstr, op, _dbus_string_get_const_data (data)))
+ {
+ _dbus_string_free (&avc);
+ goto syslog;
+ }
+
+ /* FIXME: need to change this to show real user */
+ audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC,
+ _dbus_string_get_const_data (&avc),
+ NULL, NULL, NULL, getuid ());
+ _dbus_string_free (&avc);
+ return;
+ }
+
+syslog:
+#endif /* HAVE_LIBAUDIT */
+
+ syslog (LOG_USER | LOG_NOTICE, "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
+ mstr, op, _dbus_string_get_const_data (data));
+}
+
+static dbus_bool_t
+_dbus_append_pair_uint (DBusString *auxdata, const char *name,
+ unsigned long value)
+{
+ return _dbus_string_append (auxdata, " ") &&
+ _dbus_string_append (auxdata, name) &&
+ _dbus_string_append (auxdata, "=") &&
+ _dbus_string_append_uint (auxdata, value);
+}
+
+static dbus_bool_t
+_dbus_append_pair_str (DBusString *auxdata, const char *name, const char *value)
+{
+ return _dbus_string_append (auxdata, " ") &&
+ _dbus_string_append (auxdata, name) &&
+ _dbus_string_append (auxdata, "=\"") &&
+ _dbus_string_append (auxdata, value) &&
+ _dbus_string_append (auxdata, "\"");
+}
+
+static dbus_bool_t
+_dbus_append_mask (DBusString *auxdata, uint32_t mask)
+{
+ const char *mask_str;
+
+ /* Only one permission bit can be set */
+ if (mask == AA_DBUS_SEND)
+ mask_str = "send";
+ else if (mask == AA_DBUS_RECEIVE)
+ mask_str = "receive";
+ else if (mask == AA_DBUS_BIND)
+ mask_str = "bind";
+ else
+ return FALSE;
+
+ return _dbus_append_pair_str (auxdata, "mask", mask_str);
+}
+
+static dbus_bool_t
+is_unconfined (const char *con, const char *mode)
+{
+ /* treat con == NULL as confined as it is going to result in a denial */
+ if ((!mode && con && strcmp (con, "unconfined") == 0) ||
+ strcmp (mode, "unconfined") == 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static dbus_bool_t
+query_append (DBusString *query, const char *buffer)
+{
+ if (!_dbus_string_append_byte (query, '\0'))
+ return FALSE;
+
+ if (buffer && !_dbus_string_append (query, buffer))
+ return FALSE;
+
+ return TRUE;
+}
+
+static dbus_bool_t
+build_common_query (DBusString *query, const char *con, const char *bustype)
+{
+ /**
+ * libapparmor's aa_query_label() function scribbles over the first
+ * AA_QUERY_CMD_LABEL_SIZE bytes of the query string with a private value.
+ */
+ return _dbus_string_insert_bytes (query, 0, AA_QUERY_CMD_LABEL_SIZE, 0) &&
+ _dbus_string_append (query, con) &&
+ _dbus_string_append_byte (query, '\0') &&
+ _dbus_string_append_byte (query, AA_CLASS_DBUS) &&
+ _dbus_string_append (query, bustype ? bustype : "");
+}
+
+static dbus_bool_t
+build_service_query (DBusString *query,
+ const char *con,
+ const char *bustype,
+ const char *name)
+{
+ return build_common_query (query, con, bustype) &&
+ query_append (query, name);
+}
+
+static dbus_bool_t
+build_message_query (DBusString *query,
+ const char *src_con,
+ const char *bustype,
+ const char *name,
+ const char *dst_con,
+ const char *path,
+ const char *interface,
+ const char *member)
+{
+ return build_common_query (query, src_con, bustype) &&
+ query_append (query, name) &&
+ query_append (query, dst_con) &&
+ query_append (query, path) &&
+ query_append (query, interface) &&
+ query_append (query, member);
+}
+
+static dbus_bool_t
+build_eavesdrop_query (DBusString *query, const char *con, const char *bustype)
+{
+ return build_common_query (query, con, bustype);
+}
+
+static void
+set_error_from_query_errno (DBusError *error, int error_number)
+{
+ dbus_set_error (error, _dbus_error_from_errno (error_number),
+ "Failed to query AppArmor policy: %s",
+ _dbus_strerror (error_number));
+}
+
+static void
+set_error_from_denied_message (DBusError *error,
+ DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination)
+{
+ const char *proposed_recipient_loginfo;
+ const char *unset = "(unset)";
+
+ proposed_recipient_loginfo = proposed_recipient ?
+ bus_connection_get_loginfo (proposed_recipient) :
+ "bus";
+
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "An AppArmor policy prevents this sender from sending this "
+ "message to this recipient; type=\"%s\", "
+ "sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" "
+ "error name=\"%s\" requested_reply=\"%d\" "
+ "destination=\"%s\" (%s)",
+ msgtype,
+ bus_connection_get_name (sender),
+ bus_connection_get_loginfo (sender),
+ interface ? interface : unset,
+ member ? member : unset,
+ error_name ? error_name : unset,
+ requested_reply,
+ destination,
+ proposed_recipient_loginfo);
+}
+#endif /* HAVE_APPARMOR */
+
+/**
+ * Do early initialization; determine whether AppArmor is enabled.
+ * Return TRUE on successful check (whether AppArmor is actually
+ * enabled or not) or FALSE on OOM.
+ */
+dbus_bool_t
+bus_apparmor_pre_init (void)
+{
+#ifdef HAVE_APPARMOR
+ apparmor_enabled = FALSE;
+
+ if (!aa_is_enabled ())
+ return TRUE;
+
+ if (!_bus_apparmor_detect_aa_dbus_support (&apparmor_enabled))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_apparmor_set_mode_from_config (const char *mode, DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ if (mode != NULL)
+ {
+ if (strcmp (mode, "disabled") == 0)
+ apparmor_config_mode = APPARMOR_DISABLED;
+ else if (strcmp (mode, "enabled") == 0)
+ apparmor_config_mode = APPARMOR_ENABLED;
+ else if (strcmp (mode, "required") == 0)
+ apparmor_config_mode = APPARMOR_REQUIRED;
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Mode attribute on <apparmor> must have value "
+ "\"required\", \"enabled\" or \"disabled\", "
+ "not \"%s\"", mode);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+#else
+ if (mode == NULL || strcmp (mode, "disabled") == 0 ||
+ strcmp (mode, "enabled") == 0)
+ return TRUE;
+
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Mode attribute on <apparmor> must have value \"enabled\" or "
+ "\"disabled\" but cannot be \"%s\" when D-Bus is built "
+ "without AppArmor support", mode);
+ return FALSE;
+#endif
+}
+
+/**
+ * Verify that the config mode is compatible with the kernel's AppArmor
+ * support. If AppArmor mediation will be enabled, determine the bus
+ * confinement label.
+ */
+dbus_bool_t
+bus_apparmor_full_init (DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ char *label, *mode;
+
+ if (apparmor_enabled)
+ {
+ if (apparmor_config_mode == APPARMOR_DISABLED)
+ {
+ apparmor_enabled = FALSE;
+ return TRUE;
+ }
+
+ if (bus_con == NULL)
+ {
+ if (aa_getcon (&label, &mode) == -1)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Error getting AppArmor context of bus: %s",
+ _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ bus_con = bus_apparmor_confinement_new (label, mode);
+ if (bus_con == NULL)
+ {
+ BUS_SET_OOM (error);
+ free (label);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (apparmor_config_mode == APPARMOR_REQUIRED)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "AppArmor mediation required but not present");
+ return FALSE;
+ }
+ else if (apparmor_config_mode == APPARMOR_ENABLED)
+ {
+ return TRUE;
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+void
+bus_apparmor_shutdown (void)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_verbose ("AppArmor shutdown\n");
+
+ bus_apparmor_confinement_unref (bus_con);
+ bus_con = NULL;
+
+#ifdef HAVE_LIBAUDIT
+ audit_close (audit_fd);
+#endif /* HAVE_LIBAUDIT */
+
+#endif /* HAVE_APPARMOR */
+}
+
+dbus_bool_t
+bus_apparmor_enabled (void)
+{
+#ifdef HAVE_APPARMOR
+ return apparmor_enabled;
+#else
+ return FALSE;
+#endif
+}
+
+void
+bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_assert (confinement != NULL);
+ _dbus_assert (confinement->refcount > 0);
+
+ confinement->refcount -= 1;
+
+ if (confinement->refcount == 0)
+ {
+ /**
+ * Do not free confinement->mode, as libapparmor does a single malloc for
+ * both confinement->label and confinement->mode.
+ */
+ free (confinement->label);
+ dbus_free (confinement);
+ }
+#endif
+}
+
+void
+bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement)
+{
+#ifdef HAVE_APPARMOR
+ if (!apparmor_enabled)
+ return;
+
+ _dbus_assert (confinement != NULL);
+ _dbus_assert (confinement->refcount > 0);
+
+ confinement->refcount += 1;
+#endif /* HAVE_APPARMOR */
+}
+
+BusAppArmorConfinement*
+bus_apparmor_init_connection_confinement (DBusConnection *connection,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *confinement;
+ char *label, *mode;
+ int fd;
+
+ if (!apparmor_enabled)
+ return NULL;
+
+ _dbus_assert (connection != NULL);
+
+ if (!dbus_connection_get_socket (connection, &fd))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Failed to get socket file descriptor of connection");
+ return NULL;
+ }
+
+ if (aa_getpeercon (fd, &label, &mode) == -1)
+ {
+ if (errno == ENOMEM)
+ BUS_SET_OOM (error);
+ else
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to get AppArmor confinement information of socket peer: %s",
+ _dbus_strerror (errno));
+ return NULL;
+ }
+
+ confinement = bus_apparmor_confinement_new (label, mode);
+ if (confinement == NULL)
+ {
+ BUS_SET_OOM (error);
+ free (label);
+ return NULL;
+ }
+
+ return confinement;
+#else
+ return NULL;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Returns true if the given connection can acquire a service,
+ * using the tasks security context
+ *
+ * @param connection connection that wants to own the service
+ * @param bustype name of the bus
+ * @param service_name the name of the service to acquire
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if acquire is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_acquire_service (DBusConnection *connection,
+ const char *bustype,
+ const char *service_name,
+ DBusError *error)
+{
+
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t free_auxdata = FALSE;
+ dbus_bool_t allow = FALSE, audit = TRUE;
+ unsigned long pid;
+ int res, serrno = 0;
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ _dbus_assert (connection != NULL);
+
+ con = bus_connection_dup_apparmor_confinement (connection);
+
+ if (is_unconfined (con->label, con->mode))
+ {
+ allow = TRUE;
+ audit = FALSE;
+ goto out;
+ }
+
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_service_query (&qstr, con->label, bustype, service_name))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (AA_DBUS_BIND,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &allow, &audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ serrno = errno;
+ set_error_from_query_errno (error, serrno);
+ goto audit;
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (con->mode))
+ allow = TRUE;
+
+ if (!allow)
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to own the service "
+ "\"%s\" due to AppArmor policy",
+ bus_connection_is_active (connection) ?
+ bus_connection_get_name (connection) : "(inactive)",
+ service_name);
+
+ if (!audit)
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (!_dbus_append_pair_str (&auxdata, "name", service_name))
+ goto oom;
+
+ if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
+ goto oom;
+
+ if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
+ goto oom;
+
+ if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
+ goto oom;
+
+ log_message (allow, "bind", &auxdata);
+
+ out:
+ if (con != NULL)
+ bus_apparmor_confinement_unref (con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+ return allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Check if Apparmor security controls allow the message to be sent to a
+ * particular connection based on the security context of the sender and
+ * that of the receiver. The destination connection need not be the
+ * addressed recipient, it could be an "eavesdropper"
+ *
+ * @param sender the sender of the message.
+ * @param proposed_recipient the connection the message is to be sent to.
+ * @param requested_reply TRUE if the message is a reply requested by
+ * proposed_recipient
+ * @param bustype name of the bus
+ * @param msgtype message type (DBUS_MESSAGE_TYPE_METHOD_CALL, etc.)
+ * @param path object path the message should be sent to
+ * @param interface the type of the object instance
+ * @param member the member of the object
+ * @param error_name the name of the error if the message type is error
+ * @param destination name that the message should be sent to
+ * @param source name that the message should be sent from
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if the message is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_send (DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *bustype,
+ int msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination,
+ const char *source,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *src_con = NULL, *dst_con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t src_allow = FALSE, dst_allow = FALSE;
+ dbus_bool_t src_audit = TRUE, dst_audit = TRUE;
+ dbus_bool_t free_auxdata = FALSE;
+ unsigned long pid;
+ int len, res, src_errno = 0, dst_errno = 0;
+ uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE;
+ const char *msgtypestr = dbus_message_type_to_string(msgtype);
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ _dbus_assert (sender != NULL);
+
+ src_con = bus_connection_dup_apparmor_confinement (sender);
+
+ if (proposed_recipient)
+ {
+ dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient);
+ }
+ else
+ {
+ dst_con = bus_con;
+ bus_apparmor_confinement_ref (dst_con);
+ }
+
+ /* map reply messages to initial send and receive permission. That is
+ * permission to receive a message from X grants permission to reply to X.
+ * And permission to send a message to Y grants permission to receive a reply
+ * from Y. Note that this only applies to requested replies. Unrequested
+ * replies still require a policy query.
+ */
+ if (requested_reply)
+ {
+ /* ignore requested reply messages and let dbus reply mapping handle them
+ * as the send was already allowed
+ */
+ src_allow = TRUE;
+ dst_allow = TRUE;
+ goto out;
+ }
+
+ if (is_unconfined (src_con->label, src_con->mode))
+ {
+ src_allow = TRUE;
+ src_audit = FALSE;
+ }
+ else
+ {
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_message_query (&qstr, src_con->label, bustype, destination,
+ dst_con->label, path, interface, member))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (src_perm,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &src_allow, &src_audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ src_errno = errno;
+ set_error_from_query_errno (error, src_errno);
+ goto audit;
+ }
+ }
+
+ if (is_unconfined (dst_con->label, dst_con->mode))
+ {
+ dst_allow = TRUE;
+ dst_audit = FALSE;
+ }
+ else
+ {
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_message_query (&qstr, dst_con->label, bustype, source,
+ src_con->label, path, interface, member))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (dst_perm,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &dst_allow, &dst_audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ dst_errno = errno;
+ set_error_from_query_errno (error, dst_errno);
+ goto audit;
+ }
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (src_con->mode))
+ src_allow = TRUE;
+ if (modestr_is_complain (dst_con->mode))
+ dst_allow = TRUE;
+
+ if (!src_allow || !dst_allow)
+ set_error_from_denied_message (error,
+ sender,
+ proposed_recipient,
+ requested_reply,
+ msgtypestr,
+ path,
+ interface,
+ member,
+ error_name,
+ destination);
+
+ /* Don't audit the message if one of the following conditions is true:
+ * 1) The AppArmor query indicates that auditing should not happen.
+ * 2) The message is a reply type. Reply message are not audited because
+ * the AppArmor policy language does not have the notion of a reply
+ * message. Unrequested replies will be silently discarded if the sender
+ * does not have permission to send to the receiver or if the receiver
+ * does not have permission to receive from the sender.
+ */
+ if ((!src_audit && !dst_audit) ||
+ (msgtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
+ msgtype == DBUS_MESSAGE_TYPE_ERROR))
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (path && !_dbus_append_pair_str (&auxdata, "path", path))
+ goto oom;
+
+ if (interface && !_dbus_append_pair_str (&auxdata, "interface", interface))
+ goto oom;
+
+ if (member && !_dbus_append_pair_str (&auxdata, "member", member))
+ goto oom;
+
+ if (error_name && !_dbus_append_pair_str (&auxdata, "error_name", error_name))
+ goto oom;
+
+ len = _dbus_string_get_length (&auxdata);
+
+ if (src_audit)
+ {
+ if (!_dbus_append_mask (&auxdata, src_perm))
+ goto oom;
+
+ if (destination && !_dbus_append_pair_str (&auxdata, "name", destination))
+ goto oom;
+
+ if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (src_con->label &&
+ !_dbus_append_pair_str (&auxdata, "label", src_con->label))
+ goto oom;
+
+ if (proposed_recipient &&
+ dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
+ goto oom;
+
+ if (dst_con->label &&
+ !_dbus_append_pair_str (&auxdata, "peer_label", dst_con->label))
+ goto oom;
+
+ if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno)))
+ goto oom;
+
+ if (dst_errno &&
+ !_dbus_append_pair_str (&auxdata, "peer_info", strerror (dst_errno)))
+ goto oom;
+
+ log_message (src_allow, msgtypestr, &auxdata);
+ }
+ if (dst_audit)
+ {
+ _dbus_string_set_length (&auxdata, len);
+
+ if (source && !_dbus_append_pair_str (&auxdata, "name", source))
+ goto oom;
+
+ if (!_dbus_append_mask (&auxdata, dst_perm))
+ goto oom;
+
+ if (proposed_recipient &&
+ dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (dst_con->label &&
+ !_dbus_append_pair_str (&auxdata, "label", dst_con->label))
+ goto oom;
+
+ if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
+ goto oom;
+
+ if (src_con->label &&
+ !_dbus_append_pair_str (&auxdata, "peer_label", src_con->label))
+ goto oom;
+
+ if (dst_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (dst_errno)))
+ goto oom;
+
+ if (src_errno &&
+ !_dbus_append_pair_str (&auxdata, "peer_info", strerror (src_errno)))
+ goto oom;
+
+ log_message (dst_allow, msgtypestr, &auxdata);
+ }
+
+ out:
+ if (src_con != NULL)
+ bus_apparmor_confinement_unref (src_con);
+ if (dst_con != NULL)
+ bus_apparmor_confinement_unref (dst_con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+
+ return src_allow && dst_allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ src_allow = FALSE;
+ dst_allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
+
+/**
+ * Check if Apparmor security controls allow the connection to eavesdrop on
+ * other connections.
+ *
+ * @param connection the connection attempting to eavesdrop.
+ * @param bustype name of the bus
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if eavesdropping is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_eavesdropping (DBusConnection *connection,
+ const char *bustype,
+ DBusError *error)
+{
+#ifdef HAVE_APPARMOR
+ BusAppArmorConfinement *con = NULL;
+ DBusString qstr, auxdata;
+ dbus_bool_t allow = FALSE, audit = TRUE;
+ dbus_bool_t free_auxdata = FALSE;
+ unsigned long pid;
+ int res, serrno = 0;
+
+ if (!apparmor_enabled)
+ return TRUE;
+
+ con = bus_connection_dup_apparmor_confinement (connection);
+
+ if (is_unconfined (con->label, con->mode))
+ {
+ allow = TRUE;
+ audit = FALSE;
+ goto out;
+ }
+
+ if (!_dbus_string_init (&qstr))
+ goto oom;
+
+ if (!build_eavesdrop_query (&qstr, con->label, bustype))
+ {
+ _dbus_string_free (&qstr);
+ goto oom;
+ }
+
+ res = aa_query_label (AA_DBUS_EAVESDROP,
+ _dbus_string_get_data (&qstr),
+ _dbus_string_get_length (&qstr),
+ &allow, &audit);
+ _dbus_string_free (&qstr);
+ if (res == -1)
+ {
+ serrno = errno;
+ set_error_from_query_errno (error, serrno);
+ goto audit;
+ }
+
+ /* Don't fail operations on profiles in complain mode */
+ if (modestr_is_complain (con->mode))
+ allow = TRUE;
+
+ if (!allow)
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to eavesdrop due to "
+ "AppArmor policy",
+ bus_connection_is_active (connection) ?
+ bus_connection_get_name (connection) : "(inactive)");
+
+ if (!audit)
+ goto out;
+
+ audit:
+ if (!_dbus_string_init (&auxdata))
+ goto oom;
+ free_auxdata = TRUE;
+
+ if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+ goto oom;
+
+ if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
+ goto oom;
+
+ if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
+ goto oom;
+
+ if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
+ !_dbus_append_pair_uint (&auxdata, "pid", pid))
+ goto oom;
+
+ if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
+ goto oom;
+
+ log_message (allow, "eavesdrop", &auxdata);
+
+ out:
+ if (con != NULL)
+ bus_apparmor_confinement_unref (con);
+ if (free_auxdata)
+ _dbus_string_free (&auxdata);
+
+ return allow;
+
+ oom:
+ if (error != NULL && !dbus_error_is_set (error))
+ BUS_SET_OOM (error);
+ allow = FALSE;
+ goto out;
+
+#else
+ return TRUE;
+#endif /* HAVE_APPARMOR */
+}
diff --git a/bus/apparmor.h b/bus/apparmor.h
new file mode 100644
index 00000000..4a47aecc
--- /dev/null
+++ b/bus/apparmor.h
@@ -0,0 +1,66 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ * apparmor.c AppArmor security checks for D-Bus
+ *
+ * Authors: John Johansen <john.johansen@canonical.com>
+ * Tyler Hicks <tyhicks@canonical.com>
+ * Based on: selinux.h by Matthew Rickard
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef BUS_APPARMOR_H
+#define BUS_APPARMOR_H
+
+#include <dbus/dbus.h>
+#include "bus.h"
+
+void bus_apparmor_audit_init (void);
+dbus_bool_t bus_apparmor_pre_init (void);
+dbus_bool_t bus_apparmor_set_mode_from_config (const char *mode,
+ DBusError *error);
+dbus_bool_t bus_apparmor_full_init (DBusError *error);
+void bus_apparmor_shutdown (void);
+dbus_bool_t bus_apparmor_enabled (void);
+
+void bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement);
+void bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement);
+BusAppArmorConfinement* bus_apparmor_init_connection_confinement (DBusConnection *connection,
+ DBusError *error);
+
+dbus_bool_t bus_apparmor_allows_acquire_service (DBusConnection *connection,
+ const char *bustype,
+ const char *service_name,
+ DBusError *error);
+dbus_bool_t bus_apparmor_allows_send (DBusConnection *sender,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ const char *bustype,
+ int msgtype,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination,
+ const char *source,
+ DBusError *error);
+
+dbus_bool_t bus_apparmor_allows_eavesdropping (DBusConnection *connection,
+ const char *bustype,
+ DBusError *error);
+
+#endif /* BUS_APPARMOR_H */
diff --git a/bus/bus.c b/bus/bus.c
index 091fbe28..68de1b22 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -34,6 +34,7 @@
#include "config-parser.h"
#include "signals.h"
#include "selinux.h"
+#include "apparmor.h"
#include "dir-watch.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
@@ -933,6 +934,20 @@ bus_context_new (const DBusString *config_file,
bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but D-Bus initialization failed; check system log\n");
}
+ if (!bus_apparmor_full_init (error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
+
+ if (bus_apparmor_enabled ())
+ {
+ /* Only print AppArmor mediation message when syslog support is enabled */
+ if (context->syslog)
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "AppArmor D-Bus mediation is enabled\n");
+ }
+
if (!process_config_postinit (context, parser, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
@@ -960,6 +975,9 @@ bus_context_new (const DBusString *config_file,
/* FIXME - why not just put this in full_init() below? */
bus_selinux_audit_init ();
#endif
+#ifdef HAVE_APPARMOR
+ bus_apparmor_audit_init ();
+#endif
}
dbus_server_free_data_slot (&server_data_slot);
@@ -1503,7 +1521,7 @@ bus_context_check_security_policy (BusContext *context,
DBusMessage *message,
DBusError *error)
{
- const char *dest;
+ const char *src, *dest;
BusClientPolicy *sender_policy;
BusClientPolicy *recipient_policy;
dbus_int32_t toggles;
@@ -1512,6 +1530,7 @@ bus_context_check_security_policy (BusContext *context,
dbus_bool_t requested_reply;
type = dbus_message_get_type (message);
+ src = dbus_message_get_sender (message);
dest = dbus_message_get_destination (message);
/* dispatch.c was supposed to ensure these invariants */
@@ -1544,30 +1563,6 @@ bus_context_check_security_policy (BusContext *context,
if (sender != NULL)
{
- /* First verify the SELinux access controls. If allowed then
- * go on with the standard checks.
- */
- if (!bus_selinux_allows_send (sender, proposed_recipient,
- dbus_message_type_to_string (dbus_message_get_type (message)),
- dbus_message_get_interface (message),
- dbus_message_get_member (message),
- dbus_message_get_error_name (message),
- dest ? dest : DBUS_SERVICE_DBUS, error))
- {
- if (error != NULL && !dbus_error_is_set (error))
- {
- /* don't syslog this, just set the error: avc_has_perm should
- * have already written to either the audit log or syslog */
- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
- "An SELinux policy prevents this sender from sending this "
- "message to this recipient",
- 0, message, sender, proposed_recipient, FALSE, FALSE, error);
- _dbus_verbose ("SELinux security check denying send to service\n");
- }
-
- return FALSE;
- }
-
if (bus_connection_is_active (sender))
{
sender_policy = bus_connection_get_policy (sender);
@@ -1598,6 +1593,51 @@ bus_context_check_security_policy (BusContext *context,
}
else
{
+ sender_policy = NULL;
+ }
+
+ /* First verify the SELinux access controls. If allowed then
+ * go on with the standard checks.
+ */
+ if (!bus_selinux_allows_send (sender, proposed_recipient,
+ dbus_message_type_to_string (dbus_message_get_type (message)),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS, error))
+ {
+ if (error != NULL && !dbus_error_is_set (error))
+ {
+ /* don't syslog this, just set the error: avc_has_perm should
+ * have already written to either the audit log or syslog */
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "An SELinux policy prevents this sender from sending this "
+ "message to this recipient",
+ 0, message, sender, proposed_recipient, FALSE, FALSE, error);
+ _dbus_verbose ("SELinux security check denying send to service\n");
+ }
+
+ return FALSE;
+ }
+
+ /* next verify AppArmor access controls. If allowed then
+ * go on with the standard checks.
+ */
+ if (!bus_apparmor_allows_send (sender, proposed_recipient,
+ requested_reply,
+ bus_context_get_type (context),
+ dbus_message_get_type (message),
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_DBUS,
+ src ? src : DBUS_SERVICE_DBUS,
+ error))
+ return FALSE;
+
+ if (!bus_connection_is_active (sender))
+ {
/* Policy for inactive connections is that they can only send
* the hello message to the bus driver
*/
diff --git a/bus/bus.h b/bus/bus.h
index 57ad5c78..3fab59ff 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -38,6 +38,7 @@ typedef struct BusClientPolicy BusClientPolicy;
typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusSELinuxID BusSELinuxID;
+typedef struct BusAppArmorConfinement BusAppArmorConfinement;
typedef struct BusService BusService;
typedef struct BusOwner BusOwner;
typedef struct BusTransaction BusTransaction;
diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
index c522ff49..5db6b289 100644
--- a/bus/config-parser-common.c
+++ b/bus/config-parser-common.c
@@ -127,6 +127,10 @@ bus_config_parser_element_name_to_type (const char *name)
{
return ELEMENT_ALLOW_ANONYMOUS;
}
+ else if (strcmp (name, "apparmor") == 0)
+ {
+ return ELEMENT_APPARMOR;
+ }
return ELEMENT_NONE;
}
@@ -181,6 +185,8 @@ bus_config_parser_element_type_to_name (ElementType type)
return "keep_umask";
case ELEMENT_ALLOW_ANONYMOUS:
return "allow_anonymous";
+ case ELEMENT_APPARMOR:
+ return "apparmor";
}
_dbus_assert_not_reached ("bad element type");
diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
index 186bf4cf..382a0141 100644
--- a/bus/config-parser-common.h
+++ b/bus/config-parser-common.h
@@ -49,7 +49,8 @@ typedef enum
ELEMENT_STANDARD_SYSTEM_SERVICEDIRS,
ELEMENT_KEEP_UMASK,
ELEMENT_SYSLOG,
- ELEMENT_ALLOW_ANONYMOUS
+ ELEMENT_ALLOW_ANONYMOUS,
+ ELEMENT_APPARMOR
} ElementType;
ElementType bus_config_parser_element_name_to_type (const char *element_name);
diff --git a/bus/config-parser.c b/bus/config-parser.c
index ee2d4e7d..58048a50 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -28,6 +28,7 @@
#include "utils.h"
#include "policy.h"
#include "selinux.h"
+#include "apparmor.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-misc.h>
@@ -1136,6 +1137,27 @@ start_busconfig_child (BusConfigParser *parser,
return TRUE;
}
+ else if (element_type == ELEMENT_APPARMOR)
+ {
+ Element *e;
+ const char *mode;
+
+ if ((e = push_element (parser, ELEMENT_APPARMOR)) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!locate_attributes (parser, "apparmor",
+ attribute_names,
+ attribute_values,
+ error,
+ "mode", &mode,
+ NULL))
+ return FALSE;
+
+ return bus_apparmor_set_mode_from_config (mode, error);
+ }
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -2074,6 +2096,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
case ELEMENT_ALLOW_ANONYMOUS:
+ case ELEMENT_APPARMOR:
break;
}
@@ -2373,6 +2396,7 @@ bus_config_parser_content (BusConfigParser *parser,
case ELEMENT_ALLOW_ANONYMOUS:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
+ case ELEMENT_APPARMOR:
if (all_whitespace (content))
return TRUE;
else
diff --git a/bus/connection.c b/bus/connection.c
index 64da1292..690f3a5d 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -30,6 +30,7 @@
#include "signals.h"
#include "expirelist.h"
#include "selinux.h"
+#include "apparmor.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
@@ -99,6 +100,7 @@ typedef struct
char *cached_loginfo_string;
BusSELinuxID *selinux_id;
+ BusAppArmorConfinement *apparmor_confinement;
long connection_tv_sec; /**< Time when we connected (seconds component) */
long connection_tv_usec; /**< Time when we connected (microsec component) */
@@ -439,6 +441,9 @@ free_connection_data (void *data)
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
+
+ if (d->apparmor_confinement)
+ bus_apparmor_confinement_unref (d->apparmor_confinement);
dbus_free (d->cached_loginfo_string);
@@ -714,6 +719,19 @@ bus_connections_setup_connection (BusConnections *connections,
goto out;
}
+ d->apparmor_confinement = bus_apparmor_init_connection_confinement (connection,
+ &error);
+ if (dbus_error_is_set (&error))
+ {
+ /* This is a bit bogus because we pretend all errors
+ * are OOM; this is done because we know that in bus.c
+ * an OOM error disconnects the connection, which is
+ * the same thing we want on any other error.
+ */
+ dbus_error_free (&error);
+ goto out;
+ }
+
if (!dbus_connection_set_watch_functions (connection,
add_connection_watch,
remove_connection_watch,
@@ -801,6 +819,10 @@ bus_connections_setup_connection (BusConnections *connections,
if (d->selinux_id)
bus_selinux_id_unref (d->selinux_id);
d->selinux_id = NULL;
+
+ if (d->apparmor_confinement)
+ bus_apparmor_confinement_unref (d->apparmor_confinement);
+ d->apparmor_confinement = NULL;
if (!dbus_connection_set_watch_functions (connection,
NULL, NULL, NULL,
@@ -1201,6 +1223,19 @@ bus_connection_get_selinux_id (DBusConnection *connection)
return d->selinux_id;
}
+BusAppArmorConfinement*
+bus_connection_dup_apparmor_confinement (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ _dbus_assert (d != NULL);
+
+ bus_apparmor_confinement_ref (d->apparmor_confinement);
+ return d->apparmor_confinement;
+}
+
/**
* Checks whether the connection is registered with the message bus.
*
diff --git a/bus/connection.h b/bus/connection.h
index dca22633..8c68d0a0 100644
--- a/bus/connection.h
+++ b/bus/connection.h
@@ -54,6 +54,7 @@ BusActivation* bus_connection_get_activation (DBusConnection
BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection);
const char * bus_connection_get_loginfo (DBusConnection *connection);
BusSELinuxID* bus_connection_get_selinux_id (DBusConnection *connection);
+BusAppArmorConfinement* bus_connection_dup_apparmor_confinement (DBusConnection *connection);
dbus_bool_t bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
DBusError *error);
diff --git a/bus/driver.c b/bus/driver.c
index ceebb6f2..aab922ae 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -24,6 +24,7 @@
#include <config.h>
#include "activation.h"
+#include "apparmor.h"
#include "connection.h"
#include "driver.h"
#include "dispatch.h"
@@ -34,10 +35,12 @@
#include "utils.h"
#include <dbus/dbus-asv-util.h>
+#include <dbus/dbus-connection-internal.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-message.h>
#include <dbus/dbus-marshal-recursive.h>
+#include <dbus/dbus-marshal-validate.h>
#include <string.h>
static DBusConnection *
@@ -1108,9 +1111,10 @@ bus_driver_handle_add_match (DBusConnection *connection,
DBusError *error)
{
BusMatchRule *rule;
- const char *text;
+ const char *text, *bustype;
DBusString str;
BusMatchmaker *matchmaker;
+ BusContext *context;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1143,6 +1147,12 @@ bus_driver_handle_add_match (DBusConnection *connection,
if (rule == NULL)
goto failed;
+ context = bus_transaction_get_context (transaction);
+ bustype = context ? bus_context_get_type (context) : NULL;
+ if (bus_match_rule_get_client_is_eavesdropping (rule) &&
+ !bus_apparmor_allows_eavesdropping (connection, bustype, error))
+ goto failed;
+
matchmaker = bus_connection_get_matchmaker (connection);
if (!bus_matchmaker_add_rule (matchmaker, rule))
@@ -1646,6 +1656,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
DBusMessageIter reply_iter;
DBusMessageIter array_iter;
unsigned long ulong_val;
+ char *s;
const char *service;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -1680,6 +1691,45 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
goto oom;
}
+ if (dbus_connection_get_windows_user (conn, &s))
+ {
+ DBusString str;
+ dbus_bool_t result;
+
+ if (s == NULL)
+ goto oom;
+
+ _dbus_string_init_const (&str, s);
+ result = _dbus_validate_utf8 (&str, 0, _dbus_string_get_length (&str));
+ _dbus_string_free (&str);
+ if (result)
+ {
+ if (!_dbus_asv_add_string (&array_iter, "WindowsSID", s))
+ {
+ dbus_free (s);
+ goto oom;
+ }
+ }
+ dbus_free (s);
+ }
+
+ if (_dbus_connection_get_linux_security_label (conn, &s))
+ {
+ if (s == NULL)
+ goto oom;
+
+ /* use the GVariant bytestring convention for strings of unknown
+ * encoding: include the \0 in the payload, for zero-copy reading */
+ if (!_dbus_asv_add_byte_array (&array_iter, "LinuxSecurityLabel",
+ s, strlen (s) + 1))
+ {
+ dbus_free (s);
+ goto oom;
+ }
+
+ dbus_free (s);
+ }
+
if (!_dbus_asv_close (&reply_iter, &array_iter))
goto oom;
@@ -1746,6 +1796,72 @@ bus_driver_handle_reload_config (DBusConnection *connection,
return FALSE;
}
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static dbus_bool_t
+bus_driver_handle_enable_verbose (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply = NULL;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
+ if (! bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ _dbus_set_verbose(TRUE);
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+ oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ BUS_SET_OOM (error);
+
+ if (reply)
+ dbus_message_unref (reply);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_disable_verbose (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply = NULL;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto oom;
+
+ if (! bus_transaction_send_from_driver (transaction, connection, reply))
+ goto oom;
+
+ _dbus_set_verbose(FALSE);
+
+ dbus_message_unref (reply);
+ return TRUE;
+
+ oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ BUS_SET_OOM (error);
+
+ if (reply)
+ dbus_message_unref (reply);
+ return FALSE;
+}
+#endif
+
static dbus_bool_t
bus_driver_handle_get_id (DBusConnection *connection,
BusTransaction *transaction,
@@ -1808,6 +1924,8 @@ bus_driver_handle_become_monitor (DBusConnection *connection,
DBusError *error)
{
char **match_rules = NULL;
+ const char *bustype;
+ BusContext *context;
BusMatchRule *rule;
DBusList *rules = NULL;
DBusList *iter;
@@ -1822,6 +1940,11 @@ bus_driver_handle_become_monitor (DBusConnection *connection,
if (!bus_driver_check_message_is_for_us (message, error))
goto out;
+ context = bus_transaction_get_context (transaction);
+ bustype = context ? bus_context_get_type (context) : NULL;
+ if (!bus_apparmor_allows_eavesdropping (connection, bustype, error))
+ goto out;
+
if (!bus_driver_check_caller_is_privileged (connection, transaction,
message, error))
goto out;
@@ -2018,6 +2141,14 @@ static const MessageHandler monitoring_message_handlers[] = {
{ NULL, NULL, NULL, NULL }
};
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static const MessageHandler verbose_message_handlers[] = {
+ { "EnableVerbose", "", "", bus_driver_handle_enable_verbose},
+ { "DisableVerbose", "", "", bus_driver_handle_disable_verbose},
+ { NULL, NULL, NULL, NULL }
+};
+#endif
+
#ifdef DBUS_ENABLE_STATS
static const MessageHandler stats_message_handlers[] = {
{ "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
@@ -2050,6 +2181,9 @@ static InterfaceHandler interface_handlers[] = {
" </signal>\n" },
{ DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
{ DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL },
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL },
+#endif
#ifdef DBUS_ENABLE_STATS
{ BUS_INTERFACE_STATS, stats_message_handlers, NULL },
#endif
diff --git a/bus/main.c b/bus/main.c
index e060baa8..b48f03f3 100644
--- a/bus/main.c
+++ b/bus/main.c
@@ -39,6 +39,7 @@
#include <unistd.h> /* for write() and STDERR_FILENO */
#endif
#include "selinux.h"
+#include "apparmor.h"
static BusContext *context;
@@ -614,6 +615,12 @@ main (int argc, char **argv)
exit (1);
}
+ if (!bus_apparmor_pre_init ())
+ {
+ _dbus_warn ("AppArmor pre-initialization failed: out of memory\n");
+ exit (1);
+ }
+
dbus_error_init (&error);
context = bus_context_new (&config_file, flags,
&print_addr_pipe, &print_pid_pipe,
@@ -649,6 +656,7 @@ main (int argc, char **argv)
bus_context_shutdown (context);
bus_context_unref (context);
bus_selinux_shutdown ();
+ bus_apparmor_shutdown ();
return 0;
}
diff --git a/bus/services.c b/bus/services.c
index 584485b1..8e625867 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -36,6 +36,7 @@
#include "policy.h"
#include "bus.h"
#include "selinux.h"
+#include "apparmor.h"
struct BusService
{
@@ -458,6 +459,12 @@ bus_registry_acquire_service (BusRegistry *registry,
_dbus_string_get_const_data (service_name));
goto out;
}
+
+ if (!bus_apparmor_allows_acquire_service (connection,
+ (registry->context ?
+ bus_context_get_type (registry->context) : NULL),
+ _dbus_string_get_const_data (service_name), error))
+ goto out;
if (!bus_client_policy_check_can_own (policy, service_name))
{
diff --git a/bus/session.conf.in b/bus/session.conf.in
index cfe9544f..d2e3f2d0 100644
--- a/bus/session.conf.in
+++ b/bus/session.conf.in
@@ -25,6 +25,9 @@
<allow own="*"/>
</policy>
+ <!-- Enable AppArmor mediation when it is available -->
+ <apparmor mode="enabled"/>
+
<!-- Config files are placed here that among other things,
further restrict the above policy for specific services. -->
<includedir>session.d</includedir>
diff --git a/bus/signals.c b/bus/signals.c
index 4390028f..260dd243 100644
--- a/bus/signals.c
+++ b/bus/signals.c
@@ -411,6 +411,15 @@ bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
}
dbus_bool_t
+bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule)
+{
+ if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+dbus_bool_t
bus_match_rule_set_path (BusMatchRule *rule,
const char *path,
dbus_bool_t is_namespace)
diff --git a/bus/signals.h b/bus/signals.h
index d19fc7c5..0edfb07e 100644
--- a/bus/signals.h
+++ b/bus/signals.h
@@ -73,6 +73,8 @@ dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule,
void bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
dbus_bool_t is_eavesdropping);
+dbus_bool_t bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule);
+
BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to,
const DBusString *rule_text,
DBusError *error);
diff --git a/bus/system.conf.in b/bus/system.conf.in
index ac78c734..fc472bd7 100644
--- a/bus/system.conf.in
+++ b/bus/system.conf.in
@@ -97,6 +97,9 @@
send_interface="org.freedesktop.DBus.Debug.Stats"/>
</policy>
+ <!-- Enable AppArmor mediation when it is available -->
+ <apparmor mode="enabled"/>
+
<!-- Config files are placed here that among other things, punch
holes in the above policy for specific services. -->
<includedir>system.d</includedir>
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index b997f8b1..45b7d06d 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -63,6 +63,8 @@ if (NOT DBUS_DATADIR)
SET(DBUS_DATADIR ${DATADIR})
endif()
+set(DBUS_PREFIX ${DBUS_INSTALL_DIR})
+
set(prefix ${DBUS_INSTALL_DIR})
set(exec_prefix ${prefix})
set(EXPANDED_LIBDIR ${DBUS_INSTALL_DIR}/lib)
diff --git a/cmake/bus/CMakeLists.txt b/cmake/bus/CMakeLists.txt
index a3528c7f..40f66909 100644
--- a/cmake/bus/CMakeLists.txt
+++ b/cmake/bus/CMakeLists.txt
@@ -37,6 +37,8 @@ endif (DBUS_BUS_ENABLE_INOTIFY)
set (BUS_SOURCES
${BUS_DIR}/activation.c
${BUS_DIR}/activation.h
+ ${BUS_DIR}/apparmor.c
+ ${BUS_DIR}/apparmor.h
${BUS_DIR}/bus.c
${BUS_DIR}/bus.h
${BUS_DIR}/config-parser.c
diff --git a/cmake/bus/CMakeLists.txt.orig b/cmake/bus/CMakeLists.txt.orig
new file mode 100644
index 00000000..a3528c7f
--- /dev/null
+++ b/cmake/bus/CMakeLists.txt.orig
@@ -0,0 +1,203 @@
+add_definitions(-DDBUS_COMPILATION)
+
+SET(EFENCE "")
+SET(BUS_DIR ${CMAKE_SOURCE_DIR}/../bus)
+
+# config files for installation
+CONFIGURE_FILE( "${BUS_DIR}/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/session.conf" IMMEDIATE @ONLY)
+FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/session.d)
+
+if(NOT WIN32)
+ CONFIGURE_FILE( "system.conf.cmake" "${CMAKE_CURRENT_BINARY_DIR}/system.conf" IMMEDIATE @ONLY)
+ FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/system.d)
+endif()
+
+# copy services for local daemon start to local service dir data/dbus-1/services
+SET (SERVICE_FILES test/data/valid-service-files)
+FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../${SERVICE_FILES}/*.service.in" )
+FOREACH(FILE ${FILES})
+ GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME_WE)
+ SET (TARGET ${CMAKE_BINARY_DIR}/data/dbus-1/services/${FILENAME}.service)
+ IF (CONFIG_VERBOSE)
+ MESSAGE("FROM: ${FILE}\nTO: ${TARGET}\n")
+ ENDIF (CONFIG_VERBOSE)
+ configure_file(${FILE} ${TARGET} )
+ENDFOREACH(FILE)
+
+SET (XML_SOURCES ${BUS_DIR}/config-loader-expat.c)
+
+if (DBUS_BUS_ENABLE_INOTIFY)
+ set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-inotify.c)
+elseif (DBUS_BUS_ENABLE_KQUEUE)
+ set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-kqueue.c)
+else (DBUS_BUS_ENABLE_INOTIFY)
+ set (DIR_WATCH_SOURCE ${BUS_DIR}/dir-watch-default.c)
+endif (DBUS_BUS_ENABLE_INOTIFY)
+
+set (BUS_SOURCES
+ ${BUS_DIR}/activation.c
+ ${BUS_DIR}/activation.h
+ ${BUS_DIR}/bus.c
+ ${BUS_DIR}/bus.h
+ ${BUS_DIR}/config-parser.c
+ ${BUS_DIR}/config-parser.h
+ ${BUS_DIR}/config-parser-common.c
+ ${BUS_DIR}/config-parser-common.h
+# ${BUS_DIR}/config-parser-trivial.c
+ ${BUS_DIR}/connection.c
+ ${BUS_DIR}/connection.h
+ ${BUS_DIR}/desktop-file.c
+ ${BUS_DIR}/desktop-file.h
+ ${BUS_DIR}/dir-watch.h
+ ${BUS_DIR}/dispatch.c
+ ${BUS_DIR}/dispatch.h
+ ${BUS_DIR}/driver.c
+ ${BUS_DIR}/driver.h
+ ${BUS_DIR}/expirelist.c
+ ${BUS_DIR}/expirelist.h
+ ${BUS_DIR}/policy.c
+ ${BUS_DIR}/policy.h
+ ${BUS_DIR}/selinux.h
+ ${BUS_DIR}/selinux.c
+ ${BUS_DIR}/services.c
+ ${BUS_DIR}/services.h
+ ${BUS_DIR}/signals.c
+ ${BUS_DIR}/signals.h
+ ${BUS_DIR}/test.c
+ ${BUS_DIR}/test.h
+ ${BUS_DIR}/utils.c
+ ${BUS_DIR}/utils.h
+ ${XML_SOURCES}
+ ${DIR_WATCH_SOURCE}
+)
+if(DBUS_ENABLE_STATS)
+ list(APPEND BUS_SOURCES
+ ${BUS_DIR}/stats.c
+ ${BUS_DIR}/stats.h
+ )
+endif(DBUS_ENABLE_STATS)
+
+include_directories(
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/..
+ ${XML_INCLUDE_DIR}
+)
+
+add_executable(dbus-daemon ${BUS_SOURCES} ${BUS_DIR}/main.c)
+target_link_libraries(dbus-daemon ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
+set_target_properties(dbus-daemon PROPERTIES OUTPUT_NAME ${DBUS_DAEMON_NAME})
+set_target_properties(dbus-daemon PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
+
+install_targets(/bin dbus-daemon)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/session.conf DESTINATION etc/dbus-1)
+install(DIRECTORY DESTINATION etc/dbus-1/session.d)
+install(DIRECTORY DESTINATION share/dbus-1/services)
+
+if(NOT WIN32)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/system.conf DESTINATION etc/dbus-1)
+ install(DIRECTORY DESTINATION etc/dbus-1/system.d)
+ install(DIRECTORY DESTINATION share/dbus-1/system-services)
+ install(DIRECTORY DESTINATION var/run/dbus)
+endif()
+
+if (DBUS_SERVICE)
+ set (dbus_service_SOURCES
+ ${BUS_DIR}/bus-service-win.c
+ # TODO: add additional files
+ # ${BUS_DIR}/service-main.c
+ # ${BUS_SOURCES}
+ )
+
+ add_executable(dbus-service ${dbus_service_SOURCES} )
+ target_link_libraries(dbus-service ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
+ set_target_properties(dbus-service PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
+ install_targets(/bin dbus-service )
+endif (DBUS_SERVICE)
+
+if (DBUS_ENABLE_EMBEDDED_TESTS)
+ set(SOURCES ${BUS_SOURCES} ${BUS_DIR}/test-main.c)
+ add_test_executable(test-bus "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
+ set_target_properties(test-bus PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
+ if (NOT WIN32)
+ set(test_bus_system_SOURCES
+ ${XML_SOURCES}
+ ${BUS_DIR}/config-parser-common.c
+ ${BUS_DIR}/config-parser-trivial.c
+ ${BUS_DIR}/utils.c
+ ${BUS_DIR}/test-system.c
+ )
+ add_test_executable(test-bus-system "${test_bus_system_SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} ${DBUS_BUS_LIBS})
+ endif()
+endif (DBUS_ENABLE_EMBEDDED_TESTS)
+
+if(MSVC)
+ project_source_group(${GROUP_CODE} bus_test_SOURCES dummy)
+endif(MSVC)
+
+## mop up the gcov files
+#clean-local:
+# /bin/rm *.bb *.bbg *.da *.gcov || true
+
+#install-data-hook:
+# $(mkinstalldirs) $(DESTDIR)/$(localstatedir)/run/dbus
+# $(mkinstalldirs) $(DESTDIR)/$(configdir)/system.d
+# $(mkinstalldirs) $(DESTDIR)/$(datadir)/dbus-1/services
+
+##install_file(${configdir}/system.d FILE
+
+
+set(LAUNCH_HELPER_SOURCES ${XML_SOURCES}
+ ${BUS_DIR}/config-parser-common.c
+ ${BUS_DIR}/config-parser-trivial.c
+ ${BUS_DIR}/desktop-file.c
+ ${BUS_DIR}/utils.c
+ ${BUS_DIR}/activation-helper.c
+
+)
+
+if(NOT WIN32)
+# TODO PENDING(kdab) fix build on windows (activation-helper.c)
+ add_executable(dbus-daemon-launch-helper ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/activation-helper-bin.c )
+ target_link_libraries(dbus-daemon-launch-helper ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} )
+
+ add_executable(dbus-daemon-launch-helper-test ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/activation-helper-bin.c)
+ set_target_properties(dbus-daemon-launch-helper-test PROPERTIES COMPILE_FLAGS "-DACTIVATION_LAUNCHER_TEST")
+ target_link_libraries(dbus-daemon-launch-helper-test ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY} )
+
+ set (SOURCES ${LAUNCH_HELPER_SOURCES} ${BUS_DIR}/test-launch-helper.c)
+ add_test_executable(test-bus-launch-helper "${SOURCES}" ${DBUS_INTERNAL_LIBRARIES} ${XML_LIBRARY})
+ set_target_properties(test-bus-launch-helper PROPERTIES COMPILE_FLAGS "-DACTIVATION_LAUNCHER_TEST -DACTIVATION_LAUNCHER_DO_OOM")
+endif(NOT WIN32)
+
+#### Init scripts fun
+#SCRIPT_IN_FILES=messagebus.in
+# rc.messagebus.in
+
+## Red Hat start
+#if DBUS_INIT_SCRIPTS_RED_HAT
+
+#initddir=$(sysconfdir)/rc.d/init.d
+
+#initd_SCRIPTS=
+# messagebus
+
+#endif
+# ## Red Hat end
+
+## Slackware start
+#if DBUS_INIT_SCRIPTS_SLACKWARE
+
+#initddir=$(sysconfdir)/rc.d/
+
+#initd_SCRIPTS=
+# rc.messagebus
+
+#endif
+## Slackware end
+
+#MAN_IN_FILES=dbus-daemon.1.in
+#man_MANS = dbus-daemon.1
+
+#### Extra dist
+
+#EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) $(man_MANS) $(MAN_IN_FILES)
diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake
index f7180528..cd4720c9 100644
--- a/cmake/config.h.cmake
+++ b/cmake/config.h.cmake
@@ -17,6 +17,7 @@
#cmakedefine DBUS_CONSOLE_AUTH_DIR "@DBUS_CONSOLE_AUTH_DIR@"
#cmakedefine DBUS_DATADIR "@DBUS_DATADIR@"
#cmakedefine DBUS_BINDIR "@DBUS_BINDIR@"
+#cmakedefine DBUS_PREFIX "@DBUS_PREFIX@"
#cmakedefine DBUS_SYSTEM_CONFIG_FILE "@DBUS_SYSTEM_CONFIG_FILE@"
#cmakedefine DBUS_SESSION_CONFIG_FILE "@DBUS_SESSION_CONFIG_FILE@"
#cmakedefine DBUS_DAEMON_NAME "@DBUS_DAEMON_NAME@"
diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt
index 807af60c..2bb720bd 100644
--- a/cmake/doc/CMakeLists.txt
+++ b/cmake/doc/CMakeLists.txt
@@ -137,17 +137,20 @@ configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-daemon.1.xml.in ${CMAKE_BINARY_DI
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-launch.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-monitor.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-send.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml)
+configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-test-tool.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml)
configure_file(${CMAKE_SOURCE_DIR}/../doc/dbus-uuidgen.1.xml.in ${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml html-nochunks)
+DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml html-nochunks)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml html-nochunks)
if (UNIX)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-daemon.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-monitor.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-send.1.xml man)
+ DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-test-tool.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-launch.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-uuidgen.1.xml man)
DOCBOOK(${CMAKE_BINARY_DIR}/doc/dbus-cleanup-sockets.1.xml man)
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 477beb40..c5e73bca 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -58,6 +58,10 @@ set (manual-tcp_SOURCES
${CMAKE_SOURCE_DIR}/../test/manual-tcp.c
)
+set (manual-paths_SOURCES
+ ${CMAKE_SOURCE_DIR}/../test/manual-paths.c
+)
+
add_helper_executable(manual-dir-iter ${manual-dir-iter_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-service ${test-service_SOURCES} dbus-testutils)
add_helper_executable(test-names ${test-names_SOURCES} dbus-testutils)
@@ -69,6 +73,9 @@ add_helper_executable(test-exit ${test-exit_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-segfault ${test-segfault_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_helper_executable(test-sleep-forever ${test-sleep-forever_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
add_test_executable(manual-tcp ${manual-tcp_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
+if(WIN32)
+ add_helper_executable(manual-paths ${manual-paths_SOURCES} ${DBUS_INTERNAL_LIBRARIES})
+endif()
if(DBUS_WITH_GLIB)
message(STATUS "with glib test apps")
diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt
index d4eeb708..525dc057 100644
--- a/cmake/tools/CMakeLists.txt
+++ b/cmake/tools/CMakeLists.txt
@@ -4,6 +4,8 @@ set (dbus_send_SOURCES
../../tools/dbus-print-message.c
../../tools/dbus-print-message.h
../../tools/dbus-send.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
)
set (dbus_monitor_SOURCES
@@ -14,6 +16,15 @@ set (dbus_monitor_SOURCES
../../tools/tool-common.h
)
+set (dbus_test_tool_SOURCES
+ ../../tools/dbus-echo.c
+ ../../tools/dbus-spam.c
+ ../../tools/tool-common.c
+ ../../tools/tool-common.h
+ ../../tools/test-tool.c
+ ../../tools/test-tool.h
+)
+
if (WIN32)
set (dbus_launch_SOURCES
../../tools/dbus-launch-win.c
@@ -39,6 +50,10 @@ add_executable(dbus-send ${dbus_send_SOURCES})
target_link_libraries(dbus-send ${DBUS_LIBRARIES})
install_targets(/bin dbus-send )
+add_executable(dbus-test-tool ${dbus_test_tool_SOURCES})
+target_link_libraries(dbus-test-tool ${DBUS_LIBRARIES})
+install_targets(/bin dbus-test-tool )
+
add_executable(dbus-launch ${dbus_launch_SOURCES})
target_link_libraries(dbus-launch )
if (DBUS_BUILD_X11)
diff --git a/config.h.in b/config.h.in
index 78e7a02d..94fb8f96 100644
--- a/config.h.in
+++ b/config.h.in
@@ -156,6 +156,9 @@
/* Define to 1 if you have the <alloca.h> header file. */
#undef HAVE_ALLOCA_H
+/* AppArmor Support */
+#undef HAVE_APPARMOR
+
/* Define to 1 if you have backtrace(). */
#undef HAVE_BACKTRACE
diff --git a/configure b/configure
index 3af1f796..9efc7a75 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for dbus 1.9.10.
+# Generated by GNU Autoconf 2.69 for dbus 1.9.12.
#
# Report bugs to <https://bugs.freedesktop.org/enter_bug.cgi?product=dbus>.
#
@@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='dbus'
PACKAGE_TARNAME='dbus'
-PACKAGE_VERSION='1.9.10'
-PACKAGE_STRING='dbus 1.9.10'
+PACKAGE_VERSION='1.9.12'
+PACKAGE_STRING='dbus 1.9.12'
PACKAGE_BUGREPORT='https://bugs.freedesktop.org/enter_bug.cgi?product=dbus'
PACKAGE_URL=''
@@ -680,6 +680,10 @@ DBUS_CAN_UPLOAD_DOCS_TRUE
DBUS_XML_DOCS_ENABLED_FALSE
DBUS_XML_DOCS_ENABLED_TRUE
XMLTO
+DBUS_DUCKTYPE_DOCS_ENABLED_FALSE
+DBUS_DUCKTYPE_DOCS_ENABLED_TRUE
+YELP_BUILD
+DUCKTYPE
DBUS_HAVE_XSLTPROC_FALSE
DBUS_HAVE_XSLTPROC_TRUE
XSLTPROC
@@ -715,6 +719,8 @@ HAVE_LINUX_EPOLL_FALSE
HAVE_LINUX_EPOLL_TRUE
DBUS_BUS_ENABLE_INOTIFY_FALSE
DBUS_BUS_ENABLE_INOTIFY_TRUE
+APPARMOR_LIBS
+APPARMOR_CFLAGS
HAVE_SELINUX_FALSE
HAVE_SELINUX_TRUE
THREAD_LIBS
@@ -916,8 +922,10 @@ enable_asserts
enable_checks
enable_xml_docs
enable_doxygen_docs
+enable_ducktype_docs
enable_abstract_sockets
enable_selinux
+enable_apparmor
enable_libaudit
enable_inotify
enable_kqueue
@@ -971,6 +979,8 @@ DBUS_GLIB_CFLAGS
DBUS_GLIB_LIBS
PYTHON
THREAD_LIBS
+APPARMOR_CFLAGS
+APPARMOR_LIBS
SYSTEMD_CFLAGS
SYSTEMD_LIBS
VALGRIND_CFLAGS
@@ -1516,7 +1526,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures dbus 1.9.10 to adapt to many kinds of systems.
+\`configure' configures dbus 1.9.12 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1590,7 +1600,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dbus 1.9.10:";;
+ short | recursive ) echo "Configuration of dbus 1.9.12:";;
esac
cat <<\_ACEOF
@@ -1624,9 +1634,11 @@ Optional Features:
--enable-checks include sanity checks on public API
--enable-xml-docs build XML documentation (requires xmlto)
--enable-doxygen-docs build DOXYGEN documentation (requires Doxygen)
+ --enable-ducktype-docs build Ducktype documentation (requires Ducktype)
--enable-abstract-sockets
use abstract socket namespace (linux only)
--enable-selinux build with SELinux support
+ --enable-apparmor build with AppArmor support
--enable-libaudit build audit daemon support for SELinux
--enable-inotify build with inotify support (linux only)
--enable-kqueue build with kqueue support
@@ -1713,6 +1725,10 @@ Some influential environment variables:
linker flags for DBUS_GLIB, overriding pkg-config
PYTHON the Python interpreter
THREAD_LIBS
+ APPARMOR_CFLAGS
+ C compiler flags for APPARMOR, overriding pkg-config
+ APPARMOR_LIBS
+ linker flags for APPARMOR, overriding pkg-config
SYSTEMD_CFLAGS
C compiler flags for SYSTEMD, overriding pkg-config
SYSTEMD_LIBS
@@ -1789,7 +1805,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dbus configure 1.9.10
+dbus configure 1.9.12
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2565,7 +2581,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dbus $as_me 1.9.10, which was
+It was created by dbus $as_me 1.9.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3508,7 +3524,7 @@ fi
# Define the identity of the package.
PACKAGE='dbus'
- VERSION='1.9.10'
+ VERSION='1.9.12'
cat >>confdefs.h <<_ACEOF
@@ -3804,16 +3820,16 @@ _ACEOF
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=14
+LT_CURRENT=15
## increment any time the source changes; set to
## 0 if you increment CURRENT
-LT_REVISION=3
+LT_REVISION=0
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
## precedence over adding, so set to 0 if both happened.
-LT_AGE=11
+LT_AGE=12
@@ -3821,8 +3837,8 @@ LT_AGE=11
DBUS_MAJOR_VERSION=1
DBUS_MINOR_VERSION=9
-DBUS_MICRO_VERSION=10
-DBUS_VERSION=1.9.10
+DBUS_MICRO_VERSION=12
+DBUS_VERSION=1.9.12
@@ -16811,6 +16827,13 @@ else
enable_doxygen_docs=auto
fi
+# Check whether --enable-ducktype-docs was given.
+if test "${enable_ducktype_docs+set}" = set; then :
+ enableval=$enable_ducktype_docs; enable_ducktype_docs=$enableval
+else
+ enable_ducktype_docs=auto
+fi
+
# Check whether --enable-abstract-sockets was given.
if test "${enable_abstract_sockets+set}" = set; then :
enableval=$enable_abstract_sockets; enable_abstract_sockets=$enableval
@@ -16825,6 +16848,13 @@ else
enable_selinux=auto
fi
+# Check whether --enable-apparmor was given.
+if test "${enable_apparmor+set}" = set; then :
+ enableval=$enable_apparmor; enable_apparmor=$enableval
+else
+ enable_apparmor=auto
+fi
+
# Check whether --enable-libaudit was given.
if test "${enable_libaudit+set}" = set; then :
enableval=$enable_libaudit; enable_libaudit=$enableval
@@ -20150,6 +20180,95 @@ else
SELINUX_LIBS=
fi
+# AppArmor detection
+if test x$enable_apparmor = xno; then :
+ have_apparmor=no
+else
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for APPARMOR" >&5
+$as_echo_n "checking for APPARMOR... " >&6; }
+
+if test -n "$APPARMOR_CFLAGS"; then
+ pkg_cv_APPARMOR_CFLAGS="$APPARMOR_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libapparmor >= 2.8.95\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libapparmor >= 2.8.95") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_APPARMOR_CFLAGS=`$PKG_CONFIG --cflags "libapparmor >= 2.8.95" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$APPARMOR_LIBS"; then
+ pkg_cv_APPARMOR_LIBS="$APPARMOR_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libapparmor >= 2.8.95\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libapparmor >= 2.8.95") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_APPARMOR_LIBS=`$PKG_CONFIG --libs "libapparmor >= 2.8.95" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ APPARMOR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libapparmor >= 2.8.95" 2>&1`
+ else
+ APPARMOR_PKG_ERRORS=`$PKG_CONFIG --print-errors "libapparmor >= 2.8.95" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$APPARMOR_PKG_ERRORS" >&5
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_apparmor=no
+elif test $pkg_failed = untried; then
+ have_apparmor=no
+else
+ APPARMOR_CFLAGS=$pkg_cv_APPARMOR_CFLAGS
+ APPARMOR_LIBS=$pkg_cv_APPARMOR_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ have_apparmor=yes
+fi
+
+ if test x$enable_apparmor = xauto && test x$have_apparmor = xno; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sufficiently new AppArmor library not found" >&5
+$as_echo "$as_me: WARNING: Sufficiently new AppArmor library not found" >&2;}
+fi
+ if test x$enable_apparmor != xauto && test x$have_apparmor = xno; then :
+ as_fn_error $? "AppArmor explicitly required, and AppArmor library not found" "$LINENO" 5
+fi
+
+fi
+
+if test x$have_apparmor = xyes; then :
+
+$as_echo "#define HAVE_APPARMOR 1" >>confdefs.h
+
+fi
+
# inotify checks
if test x$enable_inotify = xno ; then
have_inotify=no;
@@ -22211,6 +22330,145 @@ else
fi
+### Ducktype/Yelp documentation
+
+# Extract the first word of "ducktype", so it can be a program name with args.
+set dummy ducktype; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_DUCKTYPE+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $DUCKTYPE in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_DUCKTYPE="$DUCKTYPE" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_DUCKTYPE="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_DUCKTYPE" && ac_cv_path_DUCKTYPE="no"
+ ;;
+esac
+fi
+DUCKTYPE=$ac_cv_path_DUCKTYPE
+if test -n "$DUCKTYPE"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUCKTYPE" >&5
+$as_echo "$DUCKTYPE" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+# Extract the first word of "yelp-build", so it can be a program name with args.
+set dummy yelp-build; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_YELP_BUILD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $YELP_BUILD in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_YELP_BUILD="$YELP_BUILD" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_YELP_BUILD="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_YELP_BUILD" && ac_cv_path_YELP_BUILD="no"
+ ;;
+esac
+fi
+YELP_BUILD=$ac_cv_path_YELP_BUILD
+if test -n "$YELP_BUILD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YELP_BUILD" >&5
+$as_echo "$YELP_BUILD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Ducktype documentation" >&5
+$as_echo_n "checking whether to build Ducktype documentation... " >&6; }
+
+if test "$DUCKTYPE" = "no"; then :
+ have_ducktype=no
+else
+ have_ducktype=yes
+fi
+if test "$YELP_BUILD" = "no"; then :
+ have_yelp_build=no
+else
+ have_yelp_build=yes
+fi
+
+if test "$enable_ducktype_docs" = "auto"; then :
+
+ if test "$have_ducktype" = "no" || test "$have_yelp_build" = "no"; then :
+
+ enable_ducktype_docs=no
+
+else
+
+ enable_ducktype_docs=yes
+
+fi
+
+fi
+
+if test "$enable_ducktype_docs" = "yes"; then :
+
+ if test "$have_ducktype" = "no"; then :
+
+ as_fn_error $? "Building Ducktype docs explicitly required, but ducktype not found" "$LINENO" 5
+
+fi
+ if test "$have_yelp_build" = "no"; then :
+
+ as_fn_error $? "Building Ducktype docs explicitly required, but yelp-build not found" "$LINENO" 5
+
+fi
+
+fi
+
+ if test "$enable_ducktype_docs" = "yes"; then
+ DBUS_DUCKTYPE_DOCS_ENABLED_TRUE=
+ DBUS_DUCKTYPE_DOCS_ENABLED_FALSE='#'
+else
+ DBUS_DUCKTYPE_DOCS_ENABLED_TRUE='#'
+ DBUS_DUCKTYPE_DOCS_ENABLED_FALSE=
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ducktype_docs" >&5
+$as_echo "$enable_ducktype_docs" >&6; }
+
### XML Documentation
# Extract the first word of "xmlto", so it can be a program name with args.
@@ -22289,7 +22547,8 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_xml_docs" >&5
$as_echo "$enable_xml_docs" >&6; }
- if test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes; then
+ if test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes &&
+ test x$enable_ducktype_docs = xyes; then
DBUS_CAN_UPLOAD_DOCS_TRUE=
DBUS_CAN_UPLOAD_DOCS_FALSE='#'
else
@@ -22930,7 +23189,7 @@ $as_echo "#define DBUS_ENABLE_STATS 1" >>confdefs.h
fi
-ac_config_files="$ac_config_files Doxyfile dbus/versioninfo.rc dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/example-system-enable-stats.conf bus/example-session-disable-stats.conf bus/messagebus bus/messagebus-config bus/org.freedesktop.dbus-session.plist bus/rc.messagebus bus/dbus.service bus/dbus.socket Makefile dbus/Makefile bus/Makefile tools/Makefile test/Makefile test/name-test/Makefile doc/Makefile doc/dbus-cleanup-sockets.1.xml doc/dbus-daemon.1.xml doc/dbus-launch.1.xml doc/dbus-monitor.1.xml doc/dbus-run-session.1.xml doc/dbus-send.1.xml doc/dbus-uuidgen.1.xml dbus-1.pc dbus-1-uninstalled.pc"
+ac_config_files="$ac_config_files Doxyfile dbus/versioninfo.rc dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/example-system-enable-stats.conf bus/example-session-disable-stats.conf bus/messagebus bus/messagebus-config bus/org.freedesktop.dbus-session.plist bus/rc.messagebus bus/dbus.service bus/dbus.socket Makefile dbus/Makefile bus/Makefile tools/Makefile test/Makefile test/name-test/Makefile doc/Makefile doc/dbus-cleanup-sockets.1.xml doc/dbus-daemon.1.xml doc/dbus-launch.1.xml doc/dbus-monitor.1.xml doc/dbus-run-session.1.xml doc/dbus-send.1.xml doc/dbus-test-tool.1.xml doc/dbus-uuidgen.1.xml dbus-1.pc dbus-1-uninstalled.pc"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -23146,6 +23405,10 @@ if test -z "${DBUS_HAVE_XSLTPROC_TRUE}" && test -z "${DBUS_HAVE_XSLTPROC_FALSE}"
as_fn_error $? "conditional \"DBUS_HAVE_XSLTPROC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${DBUS_DUCKTYPE_DOCS_ENABLED_TRUE}" && test -z "${DBUS_DUCKTYPE_DOCS_ENABLED_FALSE}"; then
+ as_fn_error $? "conditional \"DBUS_DUCKTYPE_DOCS_ENABLED\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${DBUS_XML_DOCS_ENABLED_TRUE}" && test -z "${DBUS_XML_DOCS_ENABLED_FALSE}"; then
as_fn_error $? "conditional \"DBUS_XML_DOCS_ENABLED\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -23567,7 +23830,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dbus $as_me 1.9.10, which was
+This file was extended by dbus $as_me 1.9.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -23633,7 +23896,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-dbus config.status 1.9.10
+dbus config.status 1.9.12
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -24252,6 +24515,7 @@ do
"doc/dbus-monitor.1.xml") CONFIG_FILES="$CONFIG_FILES doc/dbus-monitor.1.xml" ;;
"doc/dbus-run-session.1.xml") CONFIG_FILES="$CONFIG_FILES doc/dbus-run-session.1.xml" ;;
"doc/dbus-send.1.xml") CONFIG_FILES="$CONFIG_FILES doc/dbus-send.1.xml" ;;
+ "doc/dbus-test-tool.1.xml") CONFIG_FILES="$CONFIG_FILES doc/dbus-test-tool.1.xml" ;;
"doc/dbus-uuidgen.1.xml") CONFIG_FILES="$CONFIG_FILES doc/dbus-uuidgen.1.xml" ;;
"dbus-1.pc") CONFIG_FILES="$CONFIG_FILES dbus-1.pc" ;;
"dbus-1-uninstalled.pc") CONFIG_FILES="$CONFIG_FILES dbus-1-uninstalled.pc" ;;
@@ -25953,7 +26217,9 @@ echo "
32-bit int: ${DBUS_INT32_TYPE}
16-bit int: ${DBUS_INT16_TYPE}
Doxygen: ${DOXYGEN:-not found}
- xmlto: ${XMLTO:-not found}"
+ xmlto: ${XMLTO:-not found}
+ ducktype: ${DUCKTYPE:-not found}
+ yelp-build: ${YELP_BUILD:-not found}"
echo "
Rebuilding generated files: ${USE_MAINTAINER_MODE}
@@ -25968,11 +26234,13 @@ echo "
Building checks: ${enable_checks}
Building bus stats API: ${enable_stats}
Building SELinux support: ${have_selinux}
+ Building AppArmor support: ${have_apparmor}
Building inotify support: ${have_inotify}
Building kqueue support: ${have_kqueue}
Building systemd support: ${have_systemd}
Building X11 code: ${have_x11}
Building Doxygen docs: ${enable_doxygen_docs}
+ Building Ducktype docs: ${enable_ducktype_docs}
Building XML docs: ${enable_xml_docs}
Building launchd support: ${have_launchd}
Init scripts style: ${with_init_scripts}
diff --git a/configure.ac b/configure.ac
index ee87caa0..b393a42f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_PREREQ([2.63])
m4_define([dbus_major_version], [1])
m4_define([dbus_minor_version], [9])
-m4_define([dbus_micro_version], [10])
+m4_define([dbus_micro_version], [12])
m4_define([dbus_version],
[dbus_major_version.dbus_minor_version.dbus_micro_version])
AC_INIT([dbus],[dbus_version],[https://bugs.freedesktop.org/enter_bug.cgi?product=dbus],[dbus])
@@ -33,16 +33,16 @@ AC_DEFINE_UNQUOTED(DBUS_DAEMON_NAME,"dbus-daemon",[Name of executable])
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=14
+LT_CURRENT=15
## increment any time the source changes; set to
## 0 if you increment CURRENT
-LT_REVISION=3
+LT_REVISION=0
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
## precedence over adding, so set to 0 if both happened.
-LT_AGE=11
+LT_AGE=12
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
@@ -150,8 +150,16 @@ AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion chec
AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes)
AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto)
AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto)
+AC_ARG_ENABLE([ducktype-docs],
+ AS_HELP_STRING([--enable-ducktype-docs],
+ [build Ducktype documentation (requires Ducktype)]),
+ [enable_ducktype_docs=$enableval], [enable_ducktype_docs=auto])
AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto)
+AC_ARG_ENABLE([apparmor],
+ [AS_HELP_STRING([--enable-apparmor], [build with AppArmor support])],
+ [enable_apparmor=$enableval],
+ [enable_apparmor=auto])
AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto)
AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify support (linux only)]),enable_inotify=$enableval,enable_inotify=auto)
AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto)
@@ -1041,6 +1049,22 @@ else
SELINUX_LIBS=
fi
+# AppArmor detection
+AS_IF([test x$enable_apparmor = xno],
+ [have_apparmor=no],
+ [
+ PKG_CHECK_MODULES([APPARMOR], [libapparmor >= 2.8.95],
+ [have_apparmor=yes], [have_apparmor=no])
+
+ AS_IF([test x$enable_apparmor = xauto && test x$have_apparmor = xno],
+ [AC_MSG_WARN([Sufficiently new AppArmor library not found])])
+ AS_IF([test x$enable_apparmor != xauto && test x$have_apparmor = xno],
+ [AC_MSG_ERROR([AppArmor explicitly required, and AppArmor library not found])])
+ ])
+
+AS_IF([test x$have_apparmor = xyes],
+ [AC_DEFINE([HAVE_APPARMOR], [1], [AppArmor Support])])
+
# inotify checks
if test x$enable_inotify = xno ; then
have_inotify=no;
@@ -1421,6 +1445,36 @@ AC_MSG_RESULT($enable_doxygen_docs)
AC_CHECK_PROGS([XSLTPROC], [xsltproc])
AM_CONDITIONAL([DBUS_HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
+### Ducktype/Yelp documentation
+
+AC_PATH_PROG([DUCKTYPE],[ducktype],[no])
+AC_PATH_PROG([YELP_BUILD],[yelp-build],[no])
+
+AC_MSG_CHECKING([whether to build Ducktype documentation])
+
+AS_IF([test "$DUCKTYPE" = "no"],[have_ducktype=no],[have_ducktype=yes])
+AS_IF([test "$YELP_BUILD" = "no"],[have_yelp_build=no],[have_yelp_build=yes])
+
+AS_IF([test "$enable_ducktype_docs" = "auto"],[
+ AS_IF([test "$have_ducktype" = "no" || test "$have_yelp_build" = "no"],[
+ enable_ducktype_docs=no
+ ],[
+ enable_ducktype_docs=yes
+ ])
+])
+
+AS_IF([test "$enable_ducktype_docs" = "yes"],[
+ AS_IF([test "$have_ducktype" = "no"],[
+ AC_MSG_ERROR([Building Ducktype docs explicitly required, but ducktype not found])
+ ])
+ AS_IF([test "$have_yelp_build" = "no"],[
+ AC_MSG_ERROR([Building Ducktype docs explicitly required, but yelp-build not found])
+ ])
+])
+
+AM_CONDITIONAL([DBUS_DUCKTYPE_DOCS_ENABLED],[test "$enable_ducktype_docs" = "yes"])
+AC_MSG_RESULT([$enable_ducktype_docs])
+
### XML Documentation
AC_PATH_PROG(XMLTO, xmlto, no)
@@ -1451,7 +1505,8 @@ AM_CONDITIONAL(DBUS_XML_DOCS_ENABLED, test x$enable_xml_docs = xyes)
AC_MSG_RESULT($enable_xml_docs)
AM_CONDITIONAL(DBUS_CAN_UPLOAD_DOCS,
- [test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes])
+ [test x$enable_doxygen_docs = xyes && test x$enable_xml_docs = xyes &&
+ test x$enable_ducktype_docs = xyes])
#### Have to go $localstatedir->$prefix/var->/usr/local/var
@@ -1789,6 +1844,7 @@ doc/dbus-launch.1.xml
doc/dbus-monitor.1.xml
doc/dbus-run-session.1.xml
doc/dbus-send.1.xml
+doc/dbus-test-tool.1.xml
doc/dbus-uuidgen.1.xml
dbus-1.pc
dbus-1-uninstalled.pc
@@ -1817,7 +1873,9 @@ echo "
32-bit int: ${DBUS_INT32_TYPE}
16-bit int: ${DBUS_INT16_TYPE}
Doxygen: ${DOXYGEN:-not found}
- xmlto: ${XMLTO:-not found}"
+ xmlto: ${XMLTO:-not found}
+ ducktype: ${DUCKTYPE:-not found}
+ yelp-build: ${YELP_BUILD:-not found}"
echo "
Rebuilding generated files: ${USE_MAINTAINER_MODE}
@@ -1832,11 +1890,13 @@ echo "
Building checks: ${enable_checks}
Building bus stats API: ${enable_stats}
Building SELinux support: ${have_selinux}
+ Building AppArmor support: ${have_apparmor}
Building inotify support: ${have_inotify}
Building kqueue support: ${have_kqueue}
Building systemd support: ${have_systemd}
Building X11 code: ${have_x11}
Building Doxygen docs: ${enable_doxygen_docs}
+ Building Ducktype docs: ${enable_ducktype_docs}
Building XML docs: ${enable_xml_docs}
Building launchd support: ${have_launchd}
Init scripts style: ${with_init_scripts}
diff --git a/dbus/Makefile.in b/dbus/Makefile.in
index f542c6ab..08136755 100644
--- a/dbus/Makefile.in
+++ b/dbus/Makefile.in
@@ -462,6 +462,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -516,6 +518,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -605,6 +608,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
diff --git a/dbus/dbus-asv-util.c b/dbus/dbus-asv-util.c
index 583e41fa..d3ac5e9c 100644
--- a/dbus/dbus-asv-util.c
+++ b/dbus/dbus-asv-util.c
@@ -258,3 +258,57 @@ _dbus_asv_add_string (DBusMessageIter *arr_iter,
return TRUE;
}
+
+/**
+ * Create a new entry in an a{sv} (map from string to variant)
+ * with a byte array value.
+ *
+ * If this function fails, the a{sv} must be abandoned, for instance
+ * with _dbus_asv_abandon().
+ *
+ * @param arr_iter the iterator which is appending to the array
+ * @param key a UTF-8 key for the map
+ * @param value the value
+ * @param n_elements the number of elements to append
+ * @returns #TRUE on success, or #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
+ const char *key,
+ const void *value,
+ int n_elements)
+{
+ DBusMessageIter entry_iter;
+ DBusMessageIter var_iter;
+ DBusMessageIter byte_array_iter;
+
+ if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, "ay", &var_iter))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container (&var_iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &byte_array_iter))
+ {
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_append_fixed_array (&byte_array_iter, DBUS_TYPE_BYTE,
+ &value, n_elements))
+ {
+ dbus_message_iter_abandon_container (&var_iter, &byte_array_iter);
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container (&var_iter, &byte_array_iter))
+ {
+ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
+ return FALSE;
+ }
+
+ if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/dbus/dbus-asv-util.h b/dbus/dbus-asv-util.h
index 0337260a..277ab807 100644
--- a/dbus/dbus-asv-util.h
+++ b/dbus/dbus-asv-util.h
@@ -42,5 +42,9 @@ dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter,
dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter,
const char *key,
const char *value);
+dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
+ const char *key,
+ const void *value,
+ int n_elements);
#endif
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index 64ad2b06..1503d5f1 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -1102,20 +1102,23 @@ handle_server_data_external_mech (DBusAuth *auth,
auth->desired_identity))
return FALSE;
- /* also copy process ID from the socket credentials
+ /* also copy misc process info from the socket credentials
*/
if (!_dbus_credentials_add_credential (auth->authorized_identity,
DBUS_CREDENTIAL_UNIX_PROCESS_ID,
auth->credentials))
return FALSE;
- /* also copy audit data from the socket credentials
- */
if (!_dbus_credentials_add_credential (auth->authorized_identity,
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
auth->credentials))
return FALSE;
-
+
+ if (!_dbus_credentials_add_credential (auth->authorized_identity,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
+ auth->credentials))
+ return FALSE;
+
if (!send_ok (auth))
return FALSE;
diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
index 28974040..64ef3365 100644
--- a/dbus/dbus-connection-internal.h
+++ b/dbus/dbus-connection-internal.h
@@ -107,6 +107,9 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio
DBusPendingFdsChangeFunction callback,
void *data);
+dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
+ char **label_p);
+
/* if DBUS_ENABLE_STATS */
void _dbus_connection_get_stats (DBusConnection *connection,
dbus_uint32_t *in_messages,
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index b574207d..8952b75f 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -5322,6 +5322,32 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
(* old_free_function) (old_data);
}
+/* Same calling convention as dbus_connection_get_windows_user */
+dbus_bool_t
+_dbus_connection_get_linux_security_label (DBusConnection *connection,
+ char **label_p)
+{
+ dbus_bool_t result;
+
+ _dbus_assert (connection != NULL);
+ _dbus_assert (label_p != NULL);
+
+ CONNECTION_LOCK (connection);
+
+ if (!_dbus_transport_try_to_authenticate (connection->transport))
+ result = FALSE;
+ else
+ result = _dbus_transport_get_linux_security_label (connection->transport,
+ label_p);
+#ifndef __linux__
+ _dbus_assert (!result);
+#endif
+
+ CONNECTION_UNLOCK (connection);
+
+ return result;
+}
+
/**
* Gets the Windows user SID of the connection if known. Returns
* #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c
index 7325125c..151bb00f 100644
--- a/dbus/dbus-credentials.c
+++ b/dbus/dbus-credentials.c
@@ -50,6 +50,7 @@ struct DBusCredentials {
dbus_uid_t unix_uid;
dbus_pid_t pid;
char *windows_sid;
+ char *linux_security_label;
void *adt_audit_data;
dbus_int32_t adt_audit_data_size;
};
@@ -79,6 +80,7 @@ _dbus_credentials_new (void)
creds->unix_uid = DBUS_UID_UNSET;
creds->pid = DBUS_PID_UNSET;
creds->windows_sid = NULL;
+ creds->linux_security_label = NULL;
creds->adt_audit_data = NULL;
creds->adt_audit_data_size = 0;
@@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials *credentials)
if (credentials->refcount == 0)
{
dbus_free (credentials->windows_sid);
+ dbus_free (credentials->linux_security_label);
dbus_free (credentials->adt_audit_data);
dbus_free (credentials);
}
@@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
}
/**
+ * Add a Linux security label, as used by LSMs such as SELinux, Smack and
+ * AppArmor, to the credentials.
+ *
+ * @param credentials the object
+ * @param label the label
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
+ const char *label)
+{
+ char *copy;
+
+ copy = _dbus_strdup (label);
+ if (copy == NULL)
+ return FALSE;
+
+ dbus_free (credentials->linux_security_label);
+ credentials->linux_security_label = copy;
+
+ return TRUE;
+}
+
+/**
* Add ADT audit data to the credentials.
*
* @param credentials the object
@@ -236,6 +263,8 @@ _dbus_credentials_include (DBusCredentials *credentials,
return credentials->unix_uid != DBUS_UID_UNSET;
case DBUS_CREDENTIAL_WINDOWS_SID:
return credentials->windows_sid != NULL;
+ case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL:
+ return credentials->linux_security_label != NULL;
case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
return credentials->adt_audit_data != NULL;
}
@@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials)
}
/**
+ * Gets the Linux security label (as used by LSMs) from the credentials,
+ * or #NULL if the credentials object doesn't contain a security label.
+ *
+ * @param credentials the object
+ * @returns the security label
+ */
+const char *
+_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
+{
+ return credentials->linux_security_label;
+}
+
+/**
* Gets the ADT audit data in the credentials, or #NULL if
* the credentials object doesn't contain ADT audit data.
*
@@ -329,6 +371,10 @@ _dbus_credentials_are_superset (DBusCredentials *credentials,
(possible_subset->windows_sid == NULL ||
(credentials->windows_sid && strcmp (possible_subset->windows_sid,
credentials->windows_sid) == 0)) &&
+ (possible_subset->linux_security_label == NULL ||
+ (credentials->linux_security_label != NULL &&
+ strcmp (possible_subset->linux_security_label,
+ credentials->linux_security_label) == 0)) &&
(possible_subset->adt_audit_data == NULL ||
(credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
credentials->adt_audit_data,
@@ -348,6 +394,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials)
credentials->pid == DBUS_PID_UNSET &&
credentials->unix_uid == DBUS_UID_UNSET &&
credentials->windows_sid == NULL &&
+ credentials->linux_security_label == NULL &&
credentials->adt_audit_data == NULL;
}
@@ -388,6 +435,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials,
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
other_credentials) &&
_dbus_credentials_add_credential (credentials,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
+ other_credentials) &&
+ _dbus_credentials_add_credential (credentials,
DBUS_CREDENTIAL_WINDOWS_SID,
other_credentials);
}
@@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials *credentials,
if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
return FALSE;
}
+ else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
+ other_credentials->linux_security_label != NULL)
+ {
+ if (!_dbus_credentials_add_linux_security_label (credentials,
+ other_credentials->linux_security_label))
+ return FALSE;
+ }
else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
other_credentials->adt_audit_data != NULL)
{
@@ -449,6 +506,8 @@ _dbus_credentials_clear (DBusCredentials *credentials)
credentials->unix_uid = DBUS_UID_UNSET;
dbus_free (credentials->windows_sid);
credentials->windows_sid = NULL;
+ dbus_free (credentials->linux_security_label);
+ credentials->linux_security_label = NULL;
dbus_free (credentials->adt_audit_data);
credentials->adt_audit_data = NULL;
credentials->adt_audit_data_size = 0;
@@ -540,6 +599,15 @@ _dbus_credentials_to_string_append (DBusCredentials *credentials,
else
join = FALSE;
+ if (credentials->linux_security_label != NULL)
+ {
+ if (!_dbus_string_append_printf (string, "%slsm='%s'",
+ join ? " " : "",
+ credentials->linux_security_label))
+ goto oom;
+ join = TRUE;
+ }
+
return TRUE;
oom:
return FALSE;
diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h
index abcc4bb3..ab74eac8 100644
--- a/dbus/dbus-credentials.h
+++ b/dbus/dbus-credentials.h
@@ -34,6 +34,7 @@ typedef enum {
DBUS_CREDENTIAL_UNIX_PROCESS_ID,
DBUS_CREDENTIAL_UNIX_USER_ID,
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
DBUS_CREDENTIAL_WINDOWS_SID
} DBusCredentialType;
@@ -47,6 +48,8 @@ dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials
dbus_uid_t uid);
dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
const char *windows_sid);
+dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
+ const char *label);
dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials,
void *audit_data,
dbus_int32_t size);
@@ -55,6 +58,7 @@ dbus_bool_t _dbus_credentials_include (DBusCredentials
dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials);
dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials);
const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials);
+const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials);
void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials);
dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials);
dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials,
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 575a0875..92a108c8 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -363,6 +363,16 @@ _dbus_is_verbose_real (void)
return verbose;
}
+void _dbus_set_verbose (dbus_bool_t state)
+{
+ verbose = state;
+}
+
+dbus_bool_t _dbus_get_verbose (void)
+{
+ return verbose;
+}
+
/**
* Prints a warning message to stderr
* if the user has enabled verbose mode.
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 6b487f5d..8dea10f1 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -99,6 +99,8 @@ void _dbus_verbose_real (const char *format,
#endif
void _dbus_verbose_reset_real (void);
dbus_bool_t _dbus_is_verbose_real (void);
+dbus_bool_t _dbus_get_verbose (void);
+void _dbus_set_verbose (dbus_bool_t state);
# define _dbus_verbose_reset _dbus_verbose_reset_real
# define _dbus_is_verbose _dbus_is_verbose_real
diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
index 51c3da8f..7ab91035 100644
--- a/dbus/dbus-shared.h
+++ b/dbus/dbus-shared.h
@@ -89,6 +89,8 @@ typedef enum
/** The monitoring interface exported by the dbus-daemon */
#define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring"
+/** The verbose interface exported by the dbus-daemon */
+#define DBUS_INTERFACE_VERBOSE "org.freedesktop.DBus.Verbose"
/** The interface supported by introspectable objects */
#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
/** The interface supported by objects with properties */
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index dcfddd17..8010df13 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -1666,6 +1666,105 @@ write_credentials_byte (int server_fd,
}
}
+/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
+static dbus_bool_t
+add_linux_security_label_to_credentials (int client_fd,
+ DBusCredentials *credentials)
+{
+#if defined(__linux__) && defined(SO_PEERSEC)
+ DBusString buf;
+ socklen_t len = 1024;
+ dbus_bool_t oom = FALSE;
+
+ if (!_dbus_string_init_preallocated (&buf, len) ||
+ !_dbus_string_set_length (&buf, len))
+ return FALSE;
+
+ while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
+ _dbus_string_get_data (&buf), &len) < 0)
+ {
+ int e = errno;
+
+ _dbus_verbose ("getsockopt failed with %s, len now %lu\n",
+ _dbus_strerror (e), (unsigned long) len);
+
+ if (e != ERANGE || len <= _dbus_string_get_length (&buf))
+ {
+ _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
+ _dbus_strerror (e));
+ goto out;
+ }
+
+ /* If not enough space, len is updated to be enough.
+ * Try again with a large enough buffer. */
+ if (!_dbus_string_set_length (&buf, len))
+ {
+ oom = TRUE;
+ goto out;
+ }
+
+ _dbus_verbose ("will try again with %lu\n", (unsigned long) len);
+ }
+
+ if (len <= 0)
+ {
+ _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
+ (unsigned long) len);
+ goto out;
+ }
+
+ if (len > _dbus_string_get_length (&buf))
+ {
+ _dbus_verbose ("%lu > %d", (unsigned long) len,
+ _dbus_string_get_length (&buf));
+ _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
+ }
+
+ if (_dbus_string_get_byte (&buf, len - 1) == 0)
+ {
+ /* the kernel included the trailing \0 in its count,
+ * but DBusString always has an extra \0 after the data anyway */
+ _dbus_verbose ("subtracting trailing \\0\n");
+ len--;
+ }
+
+ if (!_dbus_string_set_length (&buf, len))
+ {
+ _dbus_assert_not_reached ("shortening string should not lead to OOM");
+ oom = TRUE;
+ goto out;
+ }
+
+ if (strlen (_dbus_string_get_const_data (&buf)) != len)
+ {
+ /* LSM people on the linux-security-module@ mailing list say this
+ * should never happen: the label should be a bytestring with
+ * an optional trailing \0 */
+ _dbus_verbose ("security label from kernel had an embedded \\0, "
+ "ignoring it\n");
+ goto out;
+ }
+
+ _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
+ (unsigned long) len,
+ _dbus_string_get_const_data (&buf));
+
+ if (!_dbus_credentials_add_linux_security_label (credentials,
+ _dbus_string_get_const_data (&buf)))
+ {
+ oom = TRUE;
+ goto out;
+ }
+
+out:
+ _dbus_string_free (&buf);
+ return !oom;
+#else
+ /* no error */
+ return TRUE;
+#endif
+}
+
/**
* Reads a single byte which must be nul (an error occurs otherwise),
* and reads unix credentials if available. Clears the credentials
@@ -1993,6 +2092,12 @@ _dbus_read_credentials_socket (int client_fd,
}
}
+ if (!add_linux_security_label_to_credentials (client_fd, credentials))
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
return TRUE;
}
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index dbd9043d..50258151 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -981,10 +981,10 @@ static BOOL is_winxp_sp3_or_lower()
/** Gets our SID
* @param sid points to sid buffer, need to be freed with LocalFree()
- * @param process_id the process id for which the sid should be returned
+ * @param process_id the process id for which the sid should be returned (use 0 for current process)
* @returns process sid
*/
-static dbus_bool_t
+dbus_bool_t
_dbus_getsid(char **sid, dbus_pid_t process_id)
{
HANDLE process_token = INVALID_HANDLE_VALUE;
@@ -993,7 +993,13 @@ _dbus_getsid(char **sid, dbus_pid_t process_id)
PSID psid;
int retval = FALSE;
- HANDLE process_handle = OpenProcess(is_winxp_sp3_or_lower() ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
+ HANDLE process_handle;
+ if (process_id == 0)
+ process_handle = GetCurrentProcess();
+ else if (is_winxp_sp3_or_lower())
+ process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);
+ else
+ process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
if (!OpenProcessToken (process_handle, TOKEN_QUERY, &process_token))
{
diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h
index 02e7a83f..3efdf72e 100644
--- a/dbus/dbus-sysdeps-win.h
+++ b/dbus/dbus-sysdeps-win.h
@@ -88,6 +88,7 @@ dbus_bool_t _dbus_get_install_root(char *prefix, int len);
void _dbus_threads_windows_init_global (void);
void _dbus_threads_windows_ensure_ctor_linked (void);
+dbus_bool_t _dbus_getsid(char **sid, dbus_pid_t process_id);
#endif
/** @} end of sysdeps-win.h */
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index f63e0ced..5ceab0a9 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -1425,6 +1425,33 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
transport->free_unix_user_data = free_data_function;
}
+dbus_bool_t
+_dbus_transport_get_linux_security_label (DBusTransport *transport,
+ char **label_p)
+{
+ DBusCredentials *auth_identity;
+
+ *label_p = NULL;
+
+ if (!transport->authenticated)
+ return FALSE;
+
+ auth_identity = _dbus_auth_get_identity (transport->auth);
+
+ if (_dbus_credentials_include (auth_identity,
+ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
+ {
+ /* If no memory, we are supposed to return TRUE and set NULL */
+ *label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity));
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
/**
* See dbus_connection_get_windows_user().
*
diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
index 39c74c46..843f2312 100644
--- a/dbus/dbus-transport.h
+++ b/dbus/dbus-transport.h
@@ -87,6 +87,9 @@ void _dbus_transport_set_unix_user_function (DBusTransport
DBusFreeFunction *old_free_data_function);
dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
char **windows_sid_p);
+dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport,
+ char **label_p);
+
void _dbus_transport_set_windows_user_function (DBusTransport *transport,
DBusAllowWindowsUserFunction function,
void *data,
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b9a4c106..f875dc25 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -7,6 +7,7 @@ man_pages = \
dbus-monitor.1 \
dbus-run-session.1 \
dbus-send.1 \
+ dbus-test-tool.1 \
dbus-uuidgen.1 \
$(NULL)
@@ -30,6 +31,7 @@ STATIC_DOCS = \
dbus-specification.xml \
dbus-test-plan.xml \
dbus-tutorial.xml \
+ dbus-api-design.duck \
dcop-howto.txt \
introspect.xsl \
$(DTDS)
@@ -50,8 +52,24 @@ STATIC_HTML = \
diagram.svg \
$(NULL)
+# Static HTML helper files generated by yelp-build.
+YELP_STATIC_HTML = \
+ yelp.js \
+ C.css \
+ jquery.js \
+ jquery.syntax.js \
+ jquery.syntax.brush.html.js \
+ jquery.syntax.core.js \
+ jquery.syntax.layout.yelp.js \
+ $(NULL)
+
dist_html_DATA += $(STATIC_HTML)
+# Content HTML files generated by yelp-build.
+YELP_HTML = \
+ dbus-api-design.html \
+ $(NULL)
+
XMLTO_HTML = \
dbus-faq.html \
dbus-specification.html \
@@ -84,6 +102,16 @@ dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
$(XSLTPROC) -o $@ $< api/xml/index.xml
endif
+if DBUS_DUCKTYPE_DOCS_ENABLED
+html_DATA += $(YELP_HTML) $(YELP_STATIC_HTML)
+
+%.page: %.duck
+ $(DUCKTYPE) -o $@ $<
+%.html: %.page
+ $(YELP_BUILD) html $<
+$(YELP_STATIC_HTML): $(YELP_HTML)
+endif
+
# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
# (which it isn't currently)
install-data-local:: doxygen.stamp
@@ -112,13 +140,15 @@ BONUS_FILES = \
$(top_srcdir)/COPYING \
$(top_srcdir)/ChangeLog
-dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML)
+dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML)
$(AM_V_at)rm -rf $@ $@.tmp
$(AM_V_GEN)$(MKDIR_P) $@.tmp/api
$(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp
$(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp
$(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp
+ $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp
+ $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp
$(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp
@@ -142,7 +172,7 @@ maintainer-upload-docs: dbus-docs.tar.gz dbus-docs
else
maintainer-upload-docs:
@echo "Can't upload documentation! Re-run configure with"
- @echo " --enable-doxygen-docs --enable-xml-docs"
+ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs"
@echo "and ensure that man2html is installed."
@false
endif
@@ -151,6 +181,8 @@ CLEANFILES = \
$(man1_MANS) \
$(MAN_XML_FILES) \
$(XMLTO_HTML) \
+ $(YELP_HTML) \
+ $(YELP_STATIC_HTML) \
$(NULL)
clean-local:
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 412da9bc..ab554382 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -80,14 +80,16 @@ build_triplet = @build@
host_triplet = @host@
@DBUS_XML_DOCS_ENABLED_TRUE@am__append_1 = $(XMLTO_HTML)
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@am__append_2 = dbus.devhelp
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@am__append_3 = $(YELP_HTML) $(YELP_STATIC_HTML)
subdir = doc
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(srcdir)/dbus-cleanup-sockets.1.xml.in \
$(srcdir)/dbus-daemon.1.xml.in $(srcdir)/dbus-launch.1.xml.in \
$(srcdir)/dbus-monitor.1.xml.in \
$(srcdir)/dbus-run-session.1.xml.in \
- $(srcdir)/dbus-send.1.xml.in $(srcdir)/dbus-uuidgen.1.xml.in \
- $(dist_doc_DATA) $(dist_html_DATA) TODO
+ $(srcdir)/dbus-send.1.xml.in $(srcdir)/dbus-test-tool.1.xml.in \
+ $(srcdir)/dbus-uuidgen.1.xml.in $(dist_doc_DATA) \
+ $(dist_html_DATA) TODO
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
$(top_srcdir)/m4/compiler.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -102,7 +104,7 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES = dbus-cleanup-sockets.1.xml dbus-daemon.1.xml \
dbus-launch.1.xml dbus-monitor.1.xml dbus-run-session.1.xml \
- dbus-send.1.xml dbus-uuidgen.1.xml
+ dbus-send.1.xml dbus-test-tool.1.xml dbus-uuidgen.1.xml
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -162,6 +164,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -216,6 +220,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -305,6 +310,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -372,6 +378,7 @@ man_pages = \
dbus-monitor.1 \
dbus-run-session.1 \
dbus-send.1 \
+ dbus-test-tool.1 \
dbus-uuidgen.1 \
$(NULL)
@@ -390,6 +397,7 @@ STATIC_DOCS = \
dbus-specification.xml \
dbus-test-plan.xml \
dbus-tutorial.xml \
+ dbus-api-design.duck \
dcop-howto.txt \
introspect.xsl \
$(DTDS)
@@ -399,7 +407,7 @@ EXTRA_DIST = \
doxygen_to_devhelp.xsl \
$(STATIC_DOCS)
-html_DATA = $(am__append_1) $(am__append_2)
+html_DATA = $(am__append_1) $(am__append_2) $(am__append_3)
dist_html_DATA = $(STATIC_HTML)
# diagram.png/diagram.svg aren't really HTML, but must go in the same
@@ -409,6 +417,24 @@ STATIC_HTML = \
diagram.svg \
$(NULL)
+
+# Static HTML helper files generated by yelp-build.
+YELP_STATIC_HTML = \
+ yelp.js \
+ C.css \
+ jquery.js \
+ jquery.syntax.js \
+ jquery.syntax.brush.html.js \
+ jquery.syntax.core.js \
+ jquery.syntax.layout.yelp.js \
+ $(NULL)
+
+
+# Content HTML files generated by yelp-build.
+YELP_HTML = \
+ dbus-api-design.html \
+ $(NULL)
+
XMLTO_HTML = \
dbus-faq.html \
dbus-specification.html \
@@ -433,6 +459,8 @@ CLEANFILES = \
$(man1_MANS) \
$(MAN_XML_FILES) \
$(XMLTO_HTML) \
+ $(YELP_HTML) \
+ $(YELP_STATIC_HTML) \
$(NULL)
all: all-am
@@ -480,6 +508,8 @@ dbus-run-session.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-run-session
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
dbus-send.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-send.1.xml.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+dbus-test-tool.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-test-tool.1.xml.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
dbus-uuidgen.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-uuidgen.1.xml.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
@@ -774,6 +804,12 @@ uninstall-man: uninstall-man1
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@ $(XSLTPROC) -o $@ $< api/xml/index.xml
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.page: %.duck
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(DUCKTYPE) -o $@ $<
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.html: %.page
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(YELP_BUILD) html $<
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@$(YELP_STATIC_HTML): $(YELP_HTML)
+
# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
# (which it isn't currently)
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@install-data-local:: doxygen.stamp
@@ -792,13 +828,15 @@ uninstall-man: uninstall-man1
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir --ignore-fail-on-non-empty $(DESTDIR)$(apidir) || \
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir $(DESTDIR)$(apidir)
-@DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML)
+@DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML)
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)rm -rf $@ $@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_GEN)$(MKDIR_P) $@.tmp/api
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp
+@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp
+@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp
@@ -815,7 +853,7 @@ uninstall-man: uninstall-man1
@DBUS_CAN_UPLOAD_DOCS_TRUE@ cd $(srcdir) && scp -p $(DTDS) $(SPECIFICATION_SERVER):$(SPECIFICATION_PATH)/
@DBUS_CAN_UPLOAD_DOCS_FALSE@maintainer-upload-docs:
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "Can't upload documentation! Re-run configure with"
-@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo " --enable-doxygen-docs --enable-xml-docs"
+@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs"
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "and ensure that man2html is installed."
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @false
diff --git a/doc/busconfig.dtd b/doc/busconfig.dtd
index 0cc519b4..8c5ac334 100644
--- a/doc/busconfig.dtd
+++ b/doc/busconfig.dtd
@@ -11,7 +11,8 @@
include |
policy |
limit |
- selinux)*>
+ selinux |
+ apparmor)*>
<!ELEMENT user (#PCDATA)>
<!ELEMENT listen (#PCDATA)>
@@ -63,3 +64,7 @@
<!ATTLIST associate
own CDATA #REQUIRED
context CDATA #REQUIRED>
+
+<!ELEMENT apparmor EMPTY>
+<!ATTLIST apparmor
+ mode (required|enabled|disabled) "enabled">
diff --git a/doc/dbus-api-design.duck b/doc/dbus-api-design.duck
new file mode 100644
index 00000000..be3ea9fd
--- /dev/null
+++ b/doc/dbus-api-design.duck
@@ -0,0 +1,888 @@
+= D-Bus API Design Guidelines
+@link[guide >index]
+@credit[type="author copyright"]
+ @name Philip Withnall
+ @email philip.withnall@collabora.co.uk
+ @years 2015
+@desc Guidelines for writing high quality D-Bus APIs
+@revision[date=2015-02-05 status=draft]
+
+[synopsis]
+ [title]
+ Summary
+
+ The most common use for D-Bus is in implementing a service which will be
+ consumed by multiple client programs, and hence all interfaces exported on the
+ bus form a public API. Designing a D-Bus API is like designing any other API:
+ there is a lot of flexibility, but there are design patterns to follow and
+ anti-patterns to avoid.
+
+ This guide aims to explain the best practices for writing D-Bus APIs. These
+ have been refined over several years of use of D-Bus in many projects.
+ Pointers will be given for implementing APIs using common D-Bus
+ libraries like
+ $link[>>https://developer.gnome.org/gio/stable/gdbus-convenience.html](GDBus),
+ but detailed implementation instructions are left to the libraries’
+ documentation. Note that you should $em(not) use dbus-glib to implement D-Bus
+ services as it is deprecated and unmaintained. Most services should also avoid
+ libdbus (dbus-1), which is a low-level library and is awkward to use
+ correctly: it is designed to be used via a language binding such as
+ $link[>>http://qt-project.org/doc/qt-4.8/qtdbus.html](QtDBus).
+
+ For documentation on D-Bus itself, see the
+ $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html](D-Bus
+ specification).
+
+[links section]
+
+== APIs
+ [id="apis"]
+
+A D-Bus API is a specification of one or more interfaces, which will be
+implemented by objects exposed by a service on the bus. Typically an API is
+designed as a set of $link[>#interface-files](interface files), and the
+implementation of the service follows those files. Some projects, however,
+choose to define the API in the code for the service, and to export XML
+interface files from the running service
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable](using
+D-Bus introspection). Both are valid approaches.
+
+For simplicity, this document uses the XML descriptions of D-Bus interfaces as
+the canonical representation.
+
+== Interface files
+ [id="interface-files"]
+
+A D-Bus interface file is an XML file which describes one or more D-Bus
+interfaces, and is the best way of describing a D-Bus API in a machine
+readable way. The format is described in the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus
+specification), and is supported by tools such as $cmd(gdbus-codegen).
+
+Interface files for public API should be installed to
+$code($var($$(datadir$))/dbus-1/interfaces) so that other services can load
+them. Private APIs should not be installed. There should be one file installed
+per D-Bus interface, named after the interface, containing a single top-level
+$code(<node>) element with a single $code(<interface>) beneath it. For example,
+interface $code(com.example.MyService1.Manager) would be described by file
+$file($var($$(datadir$))/dbus-1/interfaces/com.example.MyService1.Manager.xml):
+
+[listing]
+ [title]
+ Example D-Bus Interface XML
+ [desc]
+ A brief example interface XML document.
+ [code mime="application/xml"]
+ <!DOCTYPE node PUBLIC
+ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
+ <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="com.example.MyService1.InterestingInterface">
+ <method name="AddContact">
+ <arg name="name" direction="in" type="s">
+ <doc:doc><doc:summary>Name of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="email" direction="in" type="s">
+ <doc:doc><doc:summary>E-mail address of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="id" direction="out" type="u">
+ <doc:doc><doc:summary>ID of newly added contact</doc:summary></doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ Adds a new contact to the address book with their name and
+ e-mail address.
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+ </interface>
+ </node>
+
+If an interface defined by service A needs to be used by client B, client B
+should declare a build time dependency on service A, and use the installed copy
+of the interface file for any code generation it has to do. It should $em(not)
+have a local copy of the interface, as that could then go out of sync with the
+canonical copy in service A’s git repository.
+
+== API versioning
+ [id="api-versioning"]
+
+$link[>>http://ometer.com/parallel.html](Just like C APIs), D-Bus interfaces
+should be designed to be usable in parallel with API-incompatible versions. This
+is achieved by including a version number in each interface name, service name
+and object path which is incremented on every backwards-incompatible change.
+
+Version numbers should be included in all APIs from the first release, as that
+means moving to a new version is as simple as incrementing the number, rather
+than inserting a number everywhere, which takes more effort.
+
+New API can be added to a D-Bus interface without incrementing the version
+number, as such additions are still backwards-compatible. However, clients
+should gracefully handle the $code(org.freedesktop.DBus.Error.UnknownMethod)
+error reply from all D-Bus method calls if they want to run against older
+versions of the service which don’t implement new methods. (This also prevents
+use of generated bindings; any method which a client wants to gracefully fall
+back from should be called using a generic D-Bus method invocation rather than
+a specific generated binding.)
+
+When API is broken, changed or removed, the service’s version number must be
+bumped; for example, from $code(com.example.MyService1)
+to $code(com.example.MyService2). If backwards compatibility is maintained in
+the service by implementing both the old and new interfaces, the service can
+own $em(both) well-known names and clients can use whichever they support.
+
+As discussed in $link[>#annotations], new or deprecated APIs should be marked in
+the interface XML using annotations.
+
+Note, however, that supporting multiple interface versions simultaneously
+requires that $em(object paths) are versioned as well, so objects $em(must not)
+be put on the bus at the root path (‘/’). This is for technical reasons: signals
+sent from a D-Bus service have the originating service name overwritten by its
+unique name (e.g. $code(com.example.MyService2) is overwritten by $code(:1:15)).
+If object paths are shared between objects implementing two versions of the
+service’s interface, client programs cannot tell which object a signal has come
+from. The solution is to include the version number in all object paths, for
+example $code(/com/example/MyService1/Manager) instead of $code(/) or
+$code(/com/example/MyService/Manager).
+
+In summary, version numbers should be included in all service names, interface
+names and object paths:
+[list]
+* $code(com.example.MyService1)
+* $code(com.example.MyService1.InterestingInterface)
+* $code(com.example.MyService1.OtherInterface)
+* $code(/com/example/MyService1/Manager)
+* $code(/com/example/MyService1/OtherObject)
+
+== API design
+ [id="api-design"]
+
+D-Bus API design is broadly the same as C API design, but there are a few
+additional points to bear in mind which arise both from D-Bus’ features
+(explicit errors, signals and properties), and from its implementation as an IPC
+system.
+
+D-Bus method calls are much more expensive than C function calls, typically
+taking on the order of milliseconds to complete a round trip. Therefore, the
+design should minimize the number of method calls needed to perform an
+operation.
+
+The type system is very expressive, especially compared to C’s, and APIs should
+take full advantage of it.
+
+Similarly, its support for signals and properties differentiates it from normal
+C APIs, and well written D-Bus APIs make full use of these features where
+appropriate. They can be coupled with standard interfaces defined in the D-Bus
+specification to allow for consistent access to properties and objects in a
+hierarchy.
+
+=== Minimizing Round Trips
+ [id="round-trips"]
+
+Each D-Bus method call is a round trip from a client program to a service and
+back again, which is expensive — taking on the order of a millisecond. One of
+the top priorities in D-Bus API design is to minimize the number of round trips
+needed by clients. This can be achieved by a combination of providing specific
+convenience APIs and designing APIs which operate on large data sets in a single
+call, rather than requiring as many calls as elements in the data set.
+
+Consider an address book API, $code(com.example.MyService1.AddressBook). It
+might have an $code(AddContact(ss$) → (u$)) method to add a contact (taking name
+and e-mail address parameters and returning a unique contact ID), and a
+$code(RemoveContact(u$)) method to remove one by ID. In the normal case of
+operating on single contacts in the address book, these calls are optimal.
+However, if the user wants to import a list of contacts, or delete multiple
+contacts simultaneously, one call has to be made per contact — this could take
+a long time for large contact lists.
+
+Instead of the $code(AddContact) and $code(RemoveContact) methods, the interface
+could have an $code(UpdateContacts(a(ss$)au$) → (au$)) method, which takes an array
+of structs containing the new contacts’ details, and an array of IDs of the
+contacts to delete, and returns an array of IDs for the new contacts. This
+reduces the number of round trips needed to one.
+
+Adding convenience APIs to replace a series of common method calls with a single
+method call specifically for that task is best done after the API has been
+profiled and bottlenecks identified, otherwise it could lead to premature
+optimization. One area where convenience methods can typically be added
+is during initialization of a client, where multiple method calls are needed to
+establish its state with the service.
+
+=== Taking Advantage of the Type System
+ [id="type-system"]
+
+D-Bus’ type system is similar to Python’s, but with a terser syntax which may be
+unfamiliar to C developers. The key to using the type system effectively is
+to expose as much structure in types as possible. In particular, sending
+structured strings over D-Bus should be avoided, as they need to be built and
+parsed; both are complex operations which are prone to bugs.
+
+For APIs being used in constrained situations, enumerated values should be
+transmitted as unsigned integers. For APIs which need to be extended by third
+parties or which are used in more loosely coupled systems, enumerated values
+should be strings in some defined format.
+
+Transmitting values as integers means string parsing and matching can be
+avoided, the messages are more compact, and typos can be more easily avoided by
+developers (if, for example, C enums are used in the implementation).
+
+Transmitting values as strings means additional values can be defined by third
+parties without fear of conflicting over integer values; for instance by using
+the same reverse-domain-name namespacing as D-Bus interfaces.
+
+In both cases, the interface documentation should describe the meaning of each
+value. It should state whether the type can be extended in future and, if so,
+how the service and client should handle unrecognized values — typically by
+considering them equal to an ‘unknown’ or ‘failure’ value. Conventionally, zero
+is used as the ‘unknown’ value.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: ‘unknown’, ‘ready’, ‘complete’.
+ -->
+ <property name="Status" type="s" access="read" />
+
+ Use:
+ [code style="valid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: 0 = Unknown, 1 = Ready, 2 = Complete.
+ Unrecognized statuses should be considered equal to Unknown.
+ -->
+ <property name="Status" type="u" access="read" />
+
+Similarly, enumerated values should be used instead of booleans, as they allow
+extra values to be added in future, and there is no ambiguity about the sense of
+the boolean value.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: %TRUE to move it up in the list, %FALSE to move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="b" direction="in" />
+ </method>
+
+ Be more explicit than a boolean:
+ [code style="valid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: 0 = Move it up in the list, 1 = Move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+
+ Unrecognized enum values for @direction will result in the address book
+ not moving.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="u" direction="in" />
+ </method>
+
+Enumerated values should also be used instead of $em(human readable) strings,
+which should not be sent over the bus if possible. The service and client could
+be running in different locales, and hence interpret any human readable strings
+differently, or present them to the user in the wrong language. Transmit an
+enumerated value and convert it to a human readable string in the client.
+
+In situations where a service has received a human readable string from
+somewhere else, it should pass it on unmodified to the client, ideally with its
+locale alongside. Passing human readable information to a client is better than
+passing nothing.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_message: Human readable progress message string.
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_message can be displayed in a UI dialogue to
+ please the user.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_message" type="s" />
+ </method>
+
+ The progress should be reported as an enumerated value:
+ [code style="valid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_state: 0 = Preparing, 1 = In progress, 2 = Finished
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_state is typically converted to a human readable
+ string and presented to the user. Unrecognized @progress_state values
+ should be treated as state 1, in progress.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_state" type="u" />
+ </method>
+
+D-Bus has none of the problems of signed versus unsigned integers which C has
+(specifically, it does not do implicit sign conversion), so integer types should
+always be chosen to be an appropriate size and signedness for the data they
+could possibly contain. Typically, unsigned values are more frequently needed
+than signed values.
+
+Structures can be used almost anywhere in a D-Bus type, and arrays of structures
+are particularly useful. Structures should be used wherever data fields are
+related. Note, however, that structures are not extensible in future, so always
+consider $link[>#extensibility].
+
+[example]
+ For example, instead of several identically-indexed arrays containing
+ different properties of the same set of items:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @names: Array of contact names to add.
+ @emails: Corresponding array of contact e-mail addresses.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @names.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses. @names and @emails must be the same length.
+ -->
+ <method name="AddContacts">
+ <arg name="names" type="as" direction="in" />
+ <arg name="emails" type="as" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+ The arrays can be combined into a single array of structures:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @details: Array of (contact name, contact e-mail address) to add.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @details.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses.
+ -->
+ <method name="AddContacts">
+ <arg name="details" type="a(ss)" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+Note that D-Bus arrays are automatically transmitted with their length, so there
+is no need to null-terminate them or encode their length separately.
+
+[comment]
+ FIXME: Mention maybe types and the extended kdbus/GVariant type system once
+ that’s stable and round-trip-ability is no longer a concern.
+
+=== Extensibility
+ [id="extensibility"]
+
+Some D-Bus APIs have very well-defined use cases, and will never need extension.
+Others are used in more loosely coupled systems which may change over time, and
+hence should be designed to be extensible from the beginning without the need
+to break API in future. This is a trade off between having a more complex API,
+and being able to easily extend it in future.
+
+The key tool for extensibility in D-Bus is $code(a{sv}), the dictionary mapping
+strings to variants. If well-defined namespaced strings are used as the
+dictionary keys, arbitrary D-Bus peers can add whatever information they need
+into the dictionary. Any other peer which understands it can query and retrieve
+the information; other peers will ignore it.
+
+The canonical example of an extensible API using $code(a{sv}) is
+$link[>>http://telepathy.freedesktop.org/spec/](Telepathy). It uses $code(a{sv})
+values as the final element in structures to allow them to be extended in
+future.
+
+A secondary tool is the use of flag fields in method calls. The set of accepted
+flags is entirely under the control of the interface designer and, as with
+enumerated types, can be extended in future without breaking API. Adding more
+flags allows the functionality of the method call to be tweaked.
+
+=== Using Signals, Properties and Errors
+ [id="using-the-features"]
+
+D-Bus method calls are explicitly asynchronous due to the latency inherent in
+IPC. This means that peers should not block on receiving a reply from a method
+call; they should schedule other work (in a main loop) and handle the reply when
+it is received. Even though method replies may take a while, the caller is
+$em(guaranteed) to receive exactly one reply eventually. This reply could be the
+return value from the method, an error from the method, or an error from the
+D-Bus daemon indicating the service failed in some way (e.g. due to crashing).
+
+Because of this, service implementations should be careful to always reply
+exactly once to each method call. Replying at the end of a long-running
+operation is correct — the client will patiently wait until the operation has
+finished and the reply is received.
+
+Note that D-Bus client bindings may implement synthetic timeouts of several
+tens of seconds, unless explicitly disabled for a call. For very long-running
+operations, you should disable the client bindings’ timeout and make it clear
+in the client’s UI that the application has not frozen and is simply running a
+long operation.
+
+An anti-pattern to avoid in this situation is to start a long-running operation
+when a method call is received, then to never reply to the method call and
+instead notify the client of completion of the operation via a signal. This
+approach is incorrect as signal emissions do not have a one-to-one relationship
+with method calls — the signal could theoretically be emitted multiple times, or
+never, which the client would not be able to handle.
+
+Similarly, use a D-Bus error reply to signify failure of an operation triggered
+by a method call, rather than using a custom error code in the method’s
+reply. This means that a reply always indicates success, and an error always
+indicates failure — rather than a reply indicating either depending on its
+parameters, and having to return dummy values in the other parameters. Using
+D-Bus error replies also means such failures can be highlighted in debugging
+tools, simplifying debugging.
+
+Clients should handle all possible standard and documented D-Bus errors for each
+method call. IPC inherently has more potential failures than normal C function
+calls, and clients should be prepared to handle all of them gracefully.
+
+=== Using Standard Interfaces
+ [id="standard-interfaces"]
+
+Use standard D-Bus interfaces where possible.
+
+==== Properties
+ [id="interface-properties"]
+
+The D-Bus specification defines the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties]($code(org.freedesktop.DBus.Properties))
+interface, which should be used by all objects to notify clients of changes
+to their property values, with the $code(PropertiesChanged) signal. This signal
+eliminates the need for individual $code($var(PropertyName)Changed) signals, and
+allows multiple properties to be notified in a single signal emission, reducing
+IPC round trips. Similarly, the $code(Get) and $code(Set) methods can be used to
+manipulate properties on an object, eliminating redundant
+$code(Get$var(PropertyName)) and $code(Set$var(PropertyName)) methods.
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.SomeInterface) with methods:
+ [list]
+ * $code(GetName($) → (s$))
+ * $code(SetName(s$) → ($))
+ * $code(GetStatus($) → (u$))
+ * $code(RunOperation(ss$) → (u$))
+ and signals:
+ [list]
+ * $code(NameChanged(u$))
+ * $code(StatusChanged(u$))
+
+ The interface could be cut down to a single method:
+ [list]
+ * $code(RunOperation(ss$) → (u$))
+ The object could then implement the $code(org.freedesktop.DBus.Properties)
+ interface and define properties:
+ [list]
+ * $code(Name) of type $code(s), read–write
+ * $code(Status) of type $code(u), read-only
+
+ The $code(NameChanged) and $code(StatusChanged) signals would be replaced by
+ $code(org.freedesktop.DBus.Properties.PropertiesChanged).
+
+==== Object Manager
+ [id="interface-object-manager"]
+
+The specification also defines the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager]($code(org.freedesktop.DBus.ObjectManager))
+interface, which should be used whenever a service needs to expose a variable
+number of objects of the same class in a flat or tree-like structure, and
+clients are expected to be interested in most or all of the objects. For
+example, this could be used by an address book service which exposes multiple
+address books, each as a separate object. The $code(GetManagedObjects) method
+allows the full object tree to be queried, returning all the objects’ properties
+too, eliminating the need for further IPC round trips to query the properties.
+
+If clients are not expected to be interested in most of the exposed objects,
+$code(ObjectManager) should $em(not) be used, as it will send all of the objects
+to each client anyway, wasting bus bandwidth. A file manager, therefore, should
+not expose the entire file system hierarchy using $code(ObjectManager).
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.AddressBookManager) with methods:
+ [list]
+ * $code(GetAddressBooks($) → (ao$))
+ and signals:
+ [list]
+ * $code(AddressBookAdded(o$))
+ * $code(AddressBookRemoved(o$))
+
+ If the manager object is at path
+ $code(/com/example/MyService1/AddressBookManager), each address book is a
+ child object, e.g.
+ $code(/com/example/MyService1/AddressBookManager/SomeAddressBook).
+
+ The interface could be eliminated, and the
+ $code(org.freedesktop.DBus.ObjectManager) interface implemented on the manager
+ object instead.
+
+ Calls to $code(GetAddressBooks) would become calls to $code(GetManagedObjects)
+ and emissions of the $code(AddressBookAdded) and $code(AddressBookRemoved)
+ signals would become emissions of $code(InterfacesAdded) and
+ $code(InterfacesRemoved).
+
+=== Naming Conventions
+ [id="naming-conventions"]
+
+All D-Bus names, from service names through to method parameters, follow a set
+of conventions. Following these conventions makes APIs more natural to use and
+consistent with all other services on the system.
+
+Services use reverse-domain-name notation, based on the domain name of the
+project providing the service (all in lower case), plus a unique name for the
+service (in camel case).
+
+[example]
+ For example, version 2 of an address book application called $code(ContactDex)
+ provided by a software vendor whose website is $code(chocolateteapot.com)
+ would use service name $code(com.chocolateteapot.ContactDex2).
+
+Almost all names use camel case with no underscores, as in the examples below.
+Method and signal parameters are an exception, using
+$code(lowercase_with_underscores). Type information is never encoded in the
+parameter name (i.e. $em(not)
+$link[>>http://en.wikipedia.org/wiki/Hungarian_notation](Hungarian notation)).
+
+[example]
+ [terms]
+ - Service Name
+ * $code(com.example.MyService1)
+ - Interface Name
+ * $code(com.example.MyService1.SomeInterface)
+ - Object Path (Root Object)
+ * $code(/com/example/MyService1)
+ - Object Path (Child Object)
+ * $code(/com/example/MyService1/SomeChild)
+ - Object Path (Grandchild Object)
+ * $code(/com/example/MyService1/AnotherChild/Grandchild1)
+ - Method Name
+ * $code(com.example.MyService1.SomeInterface.MethodName)
+ - Signal Name
+ * $code(com.example.MyService1.SomeInterface.SignalName)
+ - Property Name
+ * $code(com.example.MyService1.SomeInterface.PropertyName)
+
+See also: $link[>#api-versioning].
+
+== Code generation
+ [id="code-generation"]
+
+Rather than manually implementing both the server and client sides of a D-Bus
+interface, it is often easier to write the interface XML description and use a
+tool such as
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen))
+to generate type-safe C APIs, then build the implementation using those. This
+avoids the tedious and error-prone process of writing code to build and read
+D-Bus parameter variants for each method call.
+
+Use of code generators is beyond the scope of this guide; for more information,
+see the
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)
+manual).
+
+== Annotations
+ [id="annotations"]
+
+Annotations may be added to the interface XML to expose metadata on the API
+which can be used by documentation or code generation tools to modify their
+output. Some standard annotations are given in the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus
+specification), but further annotations may be defined by specific tools.
+
+For example, $cmd(gdbus-codegen) defines several useful annotations, listed on
+its man page.
+
+The following annotations are the most useful:
+
+[terms]
+- $code(org.freedesktop.DBus.Deprecated)
+* Mark a symbol as deprecated. This should be used whenever the API is changed,
+ specifying the version introducing the deprecation, the reason for
+ deprecation, and a replacement symbol to use.
+- $code(org.gtk.GDBus.Since)
+* Mark a symbol as having been added to the API after the initial release. This
+ should include the version the symbol was first added in.
+- $code(org.gtk.GDBus.C.Name) and $code(org.freedesktop.DBus.GLib.CSymbol)
+* Both used interchangeably to hint at a C function name to use when generating
+ code for a symbol. Use of this annotation can make generated bindings a lot
+ more pleasant to use.
+- $code(org.freedesktop.DBus.Property.EmitsChangedSignal)
+* Indicate whether a property is expected to emit change signals. This can
+ affect code generation, but is also useful documentation, as client programs
+ then know when to expect property change notifications and when they have to
+ requery.
+
+== Documentation
+ [id="documentation"]
+
+Also just like C APIs, D-Bus APIs must be documented. There are several methods
+for documenting the interfaces, methods, properties and signals in a D-Bus
+interface XML file, each unfortunately with their own downsides. You should
+choose the method which best matches the tooling and workflow you are using.
+
+=== XML Comments
+
+XML comments containing documentation in the
+$link[>>https://developer.gnome.org/gtk-doc-manual/stable/documenting_syntax.html.en](gtk-doc
+format) is the recommended format for use with
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)).
+Using $cmd(gdbus-codegen), these comments can be extracted, converted to DocBook
+format and included in the project’s API manual. For example:
+
+[listing]
+ [title]
+ Documentation Comments in D-Bus Interface XML
+ [desc]
+ Example gtk-doc–style documentation comments in the introspection XML for
+ the $code(org.freedesktop.DBus.Properties) interface.
+ [code mime="application/xml"]
+ <!--
+ org.freedesktop.DBus.Properties:
+ @short_description: Standard property getter/setter interface
+
+ Interface for all objects which expose properties on the bus, allowing
+ those properties to be got, set, and signals emitted to notify of changes
+ to the property values.
+ -->
+ <interface name="org.freedesktop.DBus.Properties">
+ <!--
+ Get:
+ @interface_name: Name of the interface the property is defined on.
+ @property_name: Name of the property to get.
+ @value: Property value, wrapped in a variant.
+
+ Retrieves the value of the property at @property_name on
+ @interface_name on this object. If @interface_name is an empty string,
+ all interfaces will be searched for @property_name; if multiple
+ properties match, the result is undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned.
+ -->
+ <method name="Get">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="s" name="property_name" direction="in"/>
+ <arg type="v" name="value" direction="out"/>
+ </method>
+
+ <!--
+ PropertiesChanged:
+ @interface_name: Name of the interface the properties changed on.
+ @changed_properties: Map of property name to updated value for the
+ changed properties.
+ @invalidated_properties: List of names of other properties which have
+ changed, but whose updated values are not notified.
+
+ Emitted when one or more properties change values on @interface_name.
+ A property may be listed in @changed_properties or
+ @invalidated_properties depending on whether the service wants to
+ broadcast the property’s new value. If a value is large or infrequently
+ used, the service might not want to broadcast it, and will wait for
+ clients to request it instead.
+ -->
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface_name"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+=== XML Annotations
+
+Documentation can also be added as annotation elements in the XML. This format
+is also supported by $cmd(gdbus-codegen), but gtk-doc comments are preferred.
+For example:
+
+[listing]
+ [title]
+ Documentation Annotations in D-Bus Interface XML
+ [desc]
+ Example GDBus documentation annotations in the introspection XML for
+ the $code(org.freedesktop.DBus.Properties) interface.
+ [code mime="application/xml"]
+ <interface name="org.freedesktop.DBus.Properties">
+ <annotation name="org.gtk.GDBus.DocString" value="Interface for all
+ objects which expose properties on the bus, allowing those properties to
+ be got, set, and signals emitted to notify of changes to the property
+ values."/>
+ <annotation name="org.gtk.GDBus.DocString.Short"
+ value="Standard property getter/setter interface"/>
+
+ <method name="Get">
+ <annotation name="org.gtk.GDBus.DocString" value="Retrieves the value of
+ the property at @property_name on @interface_name on this object. If
+ @interface_name is an empty string, all interfaces will be searched
+ for @property_name; if multiple properties match, the result is
+ undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned."/>
+
+ <arg type="s" name="interface_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the property is defined on."/>
+ </arg>
+
+ <arg type="s" name="property_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the property to get."/>
+ </arg>
+
+ <arg type="v" name="value" direction="out">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Property value, wrapped in a variant."/>
+ </arg>
+ </method>
+
+ <signal name="PropertiesChanged">
+ <annotation name="org.gtk.GDBus.DocString" value="Emitted when one or
+ more properties change values on @interface_name. A property may be
+ listed in @changed_properties or @invalidated_properties depending on
+ whether the service wants to broadcast the property’s new value. If a
+ value is large or infrequently used, the service might not want to
+ broadcast it, and will wait for clients to request it instead."/>
+
+ <arg type="s" name="interface_name">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the properties changed on."/>
+ </arg>
+
+ <arg type="a{sv}" name="changed_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Map of property name to updated value for the changed
+ properties."/>
+ </arg>
+
+ <arg type="as" name="invalidated_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="List of names of other properties which have changed, but
+ whose updated values are not notified."/>
+ </arg>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+== Service files
+ [id="service-files"]
+
+Each D-Bus service must install a $file(.service) file describing its service
+name and the command to run to start the service. This allows for service
+activation (see the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services](D-Bus
+specification)).
+
+Service files must be named after the service’s well-known name, for example
+file $file(com.example.MyService1.service) for well-known name
+$code(com.example.MyService1). Files must be installed in
+$file($var($$(datadir$))/dbus-1/services) for the session bus and
+$file($var($$(datadir$))/dbus-1/system-services) for the system bus. Note, however,
+that services on the system bus almost always need a
+$link[>#security-policies](security policy) as well.
+
+== Security Policies
+ [id="security-policies"]
+
+At a high level, the D-Bus security model is:
+[list]
+* There is a system bus, and zero or more session buses.
+* Any process may connect to the system bus. The system bus limits which can own
+ names or send method calls, and only processes running as privileged users can
+ receive unicast messages not addressed to them. Every process may receive
+ broadcasts.
+* Each session bus has an owner (a user). Only its owner may connect; on
+ general-purpose Linux, a session bus is not treated as a privilege boundary,
+ so there is no further privilege separation between processes on it.
+
+Full coverage of securing D-Bus services is beyond the scope of this guide,
+however there are some steps which you can take when designing an API to ease
+security policy implementation.
+
+D-Bus security policies are written as XML files in
+$file($var($$(sysconfdir$)/dbus-1/system.d)) and
+$file($var($$(sysconfdir$)/dbus-1/session.d)) and use an allow/deny model, where
+each message (method call, signal emission, etc.) can be allowed or denied
+according to the sum of all policy rules which match it. Each $code(<allow>) or
+$code(<deny>) rule in the policy should have the $code(own),
+$code(send_destination) or $code(receive_sender) attribute set.
+
+When designing an API, bear in mind the need to write and install such a
+security policy, and consider splitting up methods or providing more restricted
+versions which accept constrained parameters, so that they can be exposed with
+less restrictive security policies if needed by less trusted clients.
+
+Secondly, the default D-Bus security policy for the system bus is restrictive
+enough to allow sensitive data, such as passwords, to be safely sent over the
+bus in unicast messages (including unicast signals); so there is no need to
+complicate APIs by implementing extra security. Note, however, that sensitive
+data must $em(not) be sent in broadcast signals, as they can be seen by all
+peers on the bus. The default policy for the session bus is not restrictive, but
+it is typically not a security boundary.
+
+== Debugging
+ [id="debugging"]
+
+Debugging services running on D-Bus can be tricky, especially if they are
+launched via service activation and hence in an environment out of your control.
+
+Three main tools are available: D-Bus Monitor, Bustle and D-Feet.
+
+=== D-Bus Monitor
+ [id="dbus-monitor"]
+
+$link[>>http://dbus.freedesktop.org/doc/dbus-monitor.1.html]($cmd(dbus-monitor))
+is a core D-Bus tool, and allows eavesdropping on the session or system bus,
+printing all messages it sees. The messages may be filtered using a standard
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules](D-Bus
+match rule) to make the stream more manageable.
+
+Previous versions of D-Bus have required the security policy for the system bus
+to be manually relaxed to allow eavesdropping on all messages. This meant that
+debugging it was difficult and insecure. The latest versions of D-Bus add
+support for monitor-only connections for the root user, which means that
+$cmd(dbus-monitor) can be run as root to painlessly monitor all messages on the
+system bus without modifying its security policy.
+
+=== Bustle
+ [id="bustle"]
+
+$link[>>http://willthompson.co.uk/bustle/](Bustle) is a graphical version of
+$cmd(dbus-monitor), with a UI focused on profiling D-Bus performance by plotting
+messages on a timeline. It is ideal for finding bottlenecks in IPC performance
+between a service and client.
+
+=== D-Feet
+ [id="d-feet"]
+
+$link[>>https://wiki.gnome.org/Apps/DFeet](D-Feet) is an introspection tool for
+D-Bus, which displays all peers on the bus graphically, with their objects,
+interfaces, methods, signals and properties listed for examination. It is useful
+for debugging all kinds of issues related to presence of services on the bus
+and the objects they expose.
diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in
index 78f0fd08..59cc016f 100644
--- a/doc/dbus-daemon.1.xml.in
+++ b/doc/dbus-daemon.1.xml.in
@@ -809,6 +809,31 @@ Right now the default will be the security context of the bus itself.</para>
<para>If two &lt;associate&gt; elements specify the same name, the element
appearing later in the configuration file will be used.</para>
+<itemizedlist remap='TP'>
+
+ <listitem><para><emphasis remap='I'>&lt;apparmor&gt;</emphasis></para></listitem>
+
+
+</itemizedlist>
+
+<para>The &lt;apparmor&gt; element is used to configure AppArmor mediation on
+the bus. It can contain one attribute that specifies the mediation mode:</para>
+
+<literallayout remap='.nf'>
+ &lt;apparmor mode="(enabled|disabled|required)"/&gt;
+</literallayout> <!-- .fi -->
+
+<para>The default mode is "enabled". In "enabled" mode, AppArmor mediation
+will be performed if AppArmor support is available in the kernel. If it is not
+available, dbus-daemon will start but AppArmor mediation will not occur. In
+"disabled" mode, AppArmor mediation is disabled. In "required" mode, AppArmor
+mediation will be enabled if AppArmor support is available, otherwise
+dbus-daemon will refuse to start.</para>
+
+<para>The AppArmor mediation mode of the bus cannot be changed after the bus
+starts. Modifying the mode in the configuration file and sending a SIGHUP
+signal to the daemon has no effect on the mediation mode.</para>
+
</refsect1>
<refsect1 id='selinux'><title>SELinux</title>
@@ -876,6 +901,37 @@ itself will be used.</para>
</refsect1>
+<refsect1 id='apparmor'><title>AppArmor</title>
+<para>The AppArmor confinement context is stored when applications connect to
+the bus. The confinement context consists of a label and a confinement mode.
+When a security decision is required, the daemon uses the confinement context
+to query the AppArmor policy to determine if the action should be allowed or
+denied and if the action should be audited.</para>
+
+<para>The daemon performs AppArmor security checks in three places.</para>
+
+<para>First, any time a message is routed from one connection to another
+connection, the bus daemon will check permissions with the label of the first
+connection as source, label and/or connection name of the second connection as
+target, along with the bus name, the path name, the interface name, and the
+member name. Reply messages, such as method_return and error messages, are
+implicitly allowed if they are in response to a message that has already been
+allowed.</para>
+
+<para>Second, any time a connection asks to own a name, the bus daemon will
+check permissions with the label of the connection as source, the requested
+name as target, along with the bus name.</para>
+
+<para>Third, any time a connection attempts to eavesdrop, the bus daemon will
+check permissions with the label of the connection as the source, along with
+the bus name.</para>
+
+<para>AppArmor rules for bus mediation are not stored in the bus configuration
+files. They are stored in the application's AppArmor profile. Please see
+<emphasis remap='I'>apparmor.d(5)</emphasis> for more details.</para>
+
+</refsect1>
+
<refsect1 id='debugging'><title>DEBUGGING</title>
<para>If you're trying to figure out where your messages are going or why
you aren't getting messages, there are several things you can try.</para>
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index 2f9fef8b..ce3929e2 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -6,8 +6,8 @@
<article id="index">
<articleinfo>
<title>D-Bus Specification</title>
- <releaseinfo>Version 0.25</releaseinfo>
- <date>(not yet released)</date>
+ <releaseinfo>Version 0.26</releaseinfo>
+ <date>2015-02-19</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@@ -72,10 +72,11 @@
<revhistory>
<revision>
<revnumber>0.26</revnumber>
- <date>(not yet released)</date>
- <authorinitials>n/a</authorinitials>
+ <date>2015-02-19</date>
+ <authorinitials>smcv, rh</authorinitials>
<revremark>
- see <ulink url='http://cgit.freedesktop.org/dbus/dbus/log/doc/dbus-specification.xml'>commit log</ulink>
+ GetConnectionCredentials can return LinuxSecurityLabel or
+ WindowsSID; add privileged BecomeMonitor method
</revremark>
</revision>
<revision>
@@ -6005,6 +6006,65 @@
this concept. On Unix, this is the process ID defined by
POSIX.</entry>
</row>
+ <row>
+ <entry>WindowsSID</entry>
+ <entry>STRING</entry>
+ <entry>The Windows security identifier in its string form,
+ e.g. "S-1-5-21-3623811015-3361044348-30300820-1013" for
+ a domain or local computer user or "S-1-5-18" for the
+ LOCAL_SYSTEM user</entry>
+ </row>
+
+ <row>
+ <entry>LinuxSecurityLabel</entry>
+ <entry>ARRAY of BYTE</entry>
+ <entry>
+ <para>On Linux systems, the security label that would result
+ from the SO_PEERSEC getsockopt call. The array contains
+ the non-zero bytes of the security label in an unspecified
+ ASCII-compatible encoding<footnote>
+ <para>It could be ASCII or UTF-8, but could also be
+ ISO Latin-1 or any other encoding.</para>
+ </footnote>, followed by a single zero byte.</para>
+ <para>
+ For example, the SELinux context
+ <literal>system_u:system_r:init_t:s0</literal>
+ (a string of length 27) would be encoded as 28 bytes
+ ending with ':', 's', '0', '\x00'.<footnote>
+ <para>Note that this is not the same as the older
+ GetConnectionSELinuxContext method, which does
+ not append the zero byte. Always appending the
+ zero byte allows callers to read the string
+ from the message payload without copying.</para>
+ </footnote>
+ </para>
+ <para>
+ On SELinux systems this is the SELinux context, as output
+ by <literal>ps -Z</literal> or <literal>ls -Z</literal>.
+ Typical values might include
+ <literal>system_u:system_r:init_t:s0</literal>,
+ <literal>unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023</literal>,
+ or
+ <literal>unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023</literal>.
+ </para>
+ <para>
+ On Smack systems, this is the Smack label.
+ Typical values might include
+ <literal>_</literal>, <literal>*</literal>,
+ <literal>User</literal>, <literal>System</literal>
+ or <literal>System::Shared</literal>.
+ </para>
+ <para>
+ On AppArmor systems, this is the AppArmor context,
+ a composite string encoding the AppArmor label (one or more
+ profiles) and the enforcement mode.
+ Typical values might include <literal>unconfined</literal>,
+ <literal>/usr/bin/firefox (enforce)</literal> or
+ <literal>user1 (complain)</literal>.
+ </para>
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</informaltable>
diff --git a/doc/dbus-test-tool.1.xml.in b/doc/dbus-test-tool.1.xml.in
new file mode 100644
index 00000000..091dee14
--- /dev/null
+++ b/doc/dbus-test-tool.1.xml.in
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<refentry id="dbus-test-tool.1">
+ <refentryinfo>
+ <copyright>
+ <year>2015</year>
+ <holder>Collabora Ltd.</holder>
+ </copyright>
+ <legalnotice>
+ <para>This man page is distributed under the same terms as
+ dbus-test-tool (GPL-2+). There is NO WARRANTY, to the extent
+ permitted by law.</para>
+ </legalnotice>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>dbus-test-tool</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="source">D-Bus</refmiscinfo>
+ <refmiscinfo class="version">@DBUS_VERSION@</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>dbus-test-tool</refname>
+ <refpurpose>D-Bus traffic generator and test tool</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id="synopsis">
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">black-hole</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--no-read</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">echo</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--sleep=<replaceable>MS</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">spam</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--dest=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--count=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--flood</arg>
+ <arg choice="opt">--ignore-errors</arg>
+ <arg choice="opt">--messages-per-conn=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--no-reply</arg>
+ <arg choice="opt">--queue=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--seed=<replaceable>SEED</replaceable></arg>
+ <group choice="opt">
+ <arg choice="plain">--string</arg>
+ <arg choice="plain">--bytes</arg>
+ <arg choice="plain">--empty</arg>
+ </group>
+ <group choice="opt">
+ <arg choice="plain">--payload=<replaceable>S</replaceable></arg>
+ <arg choice="plain">--stdin</arg>
+ <arg choice="plain">--message-stdin</arg>
+ <arg choice="plain">--random-size</arg>
+ </group>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+ <title>DESCRIPTION</title>
+ <para><command>dbus-test-tool</command> is a multi-purpose tool
+ for debugging and profiling D-Bus.</para>
+
+ <para><command>dbus-test-tool black-hole</command>
+ connects to D-Bus, optionally requests a name, then does not
+ reply to messages. It normally reads and discards messages from
+ its D-Bus socket, but can be configured to sleep forever without
+ reading.</para>
+
+ <para><command>dbus-test-tool echo</command>
+ connects to D-Bus, optionally requests a name, then sends back an
+ empty reply to every method call, after an optional delay.</para>
+
+ <para><command>dbus-test-tool spam</command>
+ connects to D-Bus and makes repeated method calls,
+ normally named <literal>com.example.Spam</literal>.</para>
+ </refsect1>
+
+ <refsect1 id="options">
+ <title>OPTIONS</title>
+ <refsect2>
+ <title>Common options</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--session</option></term>
+ <listitem>
+ <para>Connect to the session bus. This is the default.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--system</option></term>
+ <listitem>
+ <para>Connect to the system bus.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>black-hole mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.NoReply</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-read</option></term>
+ <listitem>
+ <para>Do not read from the D-Bus socket.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>echo mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.Echo</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--sleep=</option><replaceable>MS</replaceable></term>
+ <listitem>
+ <para>Block for <replaceable>MS</replaceable> milliseconds
+ before replying to a method call.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>spam mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--dest=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Send method calls to the well-known or unique
+ bus name <replaceable>NAME</replaceable>.
+ The default is the dbus-daemon,
+ <literal>org.freedesktop.DBus</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--count=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls in total.
+ The default is 1.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--queue=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls before
+ waiting for any replies, then send one new call per reply
+ received, keeping <replaceable>N</replaceable> method calls
+ "in flight" at all times until the number of messages specified
+ with the <option>--count</option> option have been sent.
+ The default is 1, unless <option>--flood</option>
+ is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--flood</option></term>
+ <listitem>
+ <para>Send all messages without waiting for a reply,
+ equivalent to <option>--queue</option> with an arbitrarily
+ large <replaceable>N</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-reply</option></term>
+ <listitem>
+ <para>Set the "no reply desired" flag on the messages.
+ This implies <option>--flood</option>, since it disables
+ the replies that would be used for a finite
+ <option>--queue</option> length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--messages-per-conn=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>If given, send <replaceable>N</replaceable> method calls
+ on the same connection, then disconnect and reconnect.
+ The default is to use the same connection for all method
+ calls.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--string</option></term>
+ <listitem>
+ <para>The payload of each message is a UTF-8 string. This is the
+ default. The actual string used is given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--bytes</option></term>
+ <listitem>
+ <para>The payload of each message is a byte-array.
+ The actual bytes used are given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to the ASCII encoding of
+ "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--empty</option></term>
+ <listitem>
+ <para>The messages have no payload.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--payload=</option><replaceable>S</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>S</replaceable> as the
+ <option>--string</option> or <option>--bytes</option>
+ in the messages. The default is "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--stdin</option></term>
+ <listitem>
+ <para>Read from standard input until end-of-file is reached,
+ and use that as the <option>--string</option> or
+ <option>--bytes</option> in the messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--message-stdin</option></term>
+ <listitem>
+ <para>Read a complete binary D-Bus method call message from
+ standard input, and use that for each method call.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--random-size</option></term>
+ <listitem>
+ <para>Read whitespace-separated ASCII decimal numbers from
+ standard input, choose one at random for each message,
+ and send a message whose payload is a string of that
+ length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--seed=</option><replaceable>SEED</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>SEED</replaceable> as the seed
+ for the pseudorandom number generator, to have somewhat
+ repeatable sequences of random messages.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <refsect1 id="bugs">
+ <title>BUGS</title>
+ <para>Please send bug reports to the D-Bus bug tracker or mailing list.
+ See <ulink url="http://www.freedesktop.org/software/dbus/">http://www.freedesktop.org/software/dbus/</ulink>.</para>
+ </refsect1>
+
+ <refsect1 id="see_also">
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+ </refsect1>
+</refentry>
diff --git a/test/Makefile.am b/test/Makefile.am
index c2a55c9e..5d49b68e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -130,6 +130,10 @@ manual_dir_iter_SOURCES = manual-dir-iter.c
manual_dir_iter_CPPFLAGS = $(static_cppflags)
manual_dir_iter_LDADD = $(top_builddir)/dbus/libdbus-internal.la
+manual_paths_SOURCES = manual-paths.c
+manual_paths_CPPFLAGS = $(static_cppflags)
+manual_paths_LDADD = $(top_builddir)/dbus/libdbus-internal.la
+
manual_tcp_SOURCES = manual-tcp.c
manual_tcp_CPPFLAGS = $(static_cppflags)
manual_tcp_LDADD = $(top_builddir)/dbus/libdbus-internal.la
@@ -151,6 +155,10 @@ installable_manual_tests = \
manual-tcp \
$(NULL)
+if DBUS_WIN
+installable_manual_tests += manual-paths
+endif
+
if DBUS_WITH_GLIB
installable_tests += \
test-corrupt \
diff --git a/test/Makefile.in b/test/Makefile.in
index 01a0879e..afad10f6 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -90,16 +90,17 @@ host_triplet = @host@
# or libdbus-testutils-internal and libdbus-internal - never both in the
# same binary.
@DBUS_WITH_DBUS_GLIB_TRUE@am__append_2 = libdbus-testutils.la
-@DBUS_ENABLE_EMBEDDED_TESTS_FALSE@TESTS = $(am__EXEEXT_8)
+@DBUS_ENABLE_EMBEDDED_TESTS_FALSE@TESTS = $(am__EXEEXT_9)
@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@TESTS = ../bus/test-bus$(EXEEXT) \
@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ ../dbus/test-dbus$(EXEEXT) \
@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ $(am__append_3) \
-@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ $(am__EXEEXT_8)
+@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@ $(am__EXEEXT_9)
@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@am__append_3 = ../bus/test-bus-launch-helper$(EXEEXT) \
@DBUS_ENABLE_EMBEDDED_TESTS_TRUE@@DBUS_UNIX_TRUE@ ../bus/test-bus-system$(EXEEXT)
-noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_6)
-testexec_PROGRAMS = $(am__EXEEXT_7)
-@DBUS_WITH_GLIB_TRUE@am__append_4 = \
+noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_7)
+testexec_PROGRAMS = $(am__EXEEXT_8)
+@DBUS_WIN_TRUE@am__append_4 = manual-paths
+@DBUS_WITH_GLIB_TRUE@am__append_5 = \
@DBUS_WITH_GLIB_TRUE@ test-corrupt \
@DBUS_WITH_GLIB_TRUE@ test-dbus-daemon \
@DBUS_WITH_GLIB_TRUE@ test-dbus-daemon-eavesdrop \
@@ -115,16 +116,16 @@ testexec_PROGRAMS = $(am__EXEEXT_7)
@DBUS_WITH_GLIB_TRUE@ test-uid-permissions \
@DBUS_WITH_GLIB_TRUE@ $(NULL)
-@DBUS_WITH_GLIB_TRUE@am__append_5 = \
+@DBUS_WITH_GLIB_TRUE@am__append_6 = \
@DBUS_WITH_GLIB_TRUE@ manual-authz \
@DBUS_WITH_GLIB_TRUE@ $(NULL)
-@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_6 = $(installable_tests)
@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_7 = $(installable_tests)
-@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_8 = $(installable_tests) $(installable_manual_tests)
-@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_9 = $(installable_test_meta) \
+@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_8 = $(installable_tests)
+@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_9 = $(installable_tests) $(installable_manual_tests)
+@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_10 = $(installable_test_meta) \
@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(installable_test_meta_with_config)
-@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_10 = $(installable_tests) $(installable_manual_tests)
+@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__append_11 = $(installable_tests) $(installable_manual_tests)
subdir = test
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp $(top_srcdir)/test-driver
@@ -188,13 +189,14 @@ libdbus_testutils_la_OBJECTS = $(am_libdbus_testutils_la_OBJECTS)
@DBUS_WITH_GLIB_TRUE@ test-uid-permissions$(EXEEXT)
am__EXEEXT_3 = test-shell$(EXEEXT) test-printf$(EXEEXT) \
$(am__EXEEXT_2)
-@DBUS_WITH_GLIB_TRUE@am__EXEEXT_4 = manual-authz$(EXEEXT)
-am__EXEEXT_5 = manual-dir-iter$(EXEEXT) manual-tcp$(EXEEXT) \
- $(am__EXEEXT_4)
-@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_6 = $(am__EXEEXT_3) \
-@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_5)
-@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_7 = $(am__EXEEXT_3) \
-@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_5)
+@DBUS_WIN_TRUE@am__EXEEXT_4 = manual-paths$(EXEEXT)
+@DBUS_WITH_GLIB_TRUE@am__EXEEXT_5 = manual-authz$(EXEEXT)
+am__EXEEXT_6 = manual-dir-iter$(EXEEXT) manual-tcp$(EXEEXT) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5)
+@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_7 = $(am__EXEEXT_3) \
+@DBUS_ENABLE_INSTALLED_TESTS_FALSE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_6)
+@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_8 = $(am__EXEEXT_3) \
+@DBUS_ENABLE_INSTALLED_TESTS_TRUE@@DBUS_ENABLE_MODULAR_TESTS_TRUE@ $(am__EXEEXT_6)
am__installdirs = "$(DESTDIR)$(testexecdir)" \
"$(DESTDIR)$(testmetadir)"
PROGRAMS = $(noinst_PROGRAMS) $(testexec_PROGRAMS)
@@ -207,6 +209,9 @@ am_manual_dir_iter_OBJECTS = \
manual_dir_iter_OBJECTS = $(am_manual_dir_iter_OBJECTS)
manual_dir_iter_DEPENDENCIES = \
$(top_builddir)/dbus/libdbus-internal.la
+am_manual_paths_OBJECTS = manual_paths-manual-paths.$(OBJEXT)
+manual_paths_OBJECTS = $(am_manual_paths_OBJECTS)
+manual_paths_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la
am_manual_tcp_OBJECTS = manual_tcp-manual-tcp.$(OBJEXT)
manual_tcp_OBJECTS = $(am_manual_tcp_OBJECTS)
manual_tcp_DEPENDENCIES = $(top_builddir)/dbus/libdbus-internal.la
@@ -331,8 +336,9 @@ am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libdbus_testutils_internal_la_SOURCES) \
$(libdbus_testutils_la_SOURCES) $(manual_authz_SOURCES) \
- $(manual_dir_iter_SOURCES) $(manual_tcp_SOURCES) \
- $(test_corrupt_SOURCES) $(test_dbus_daemon_SOURCES) \
+ $(manual_dir_iter_SOURCES) $(manual_paths_SOURCES) \
+ $(manual_tcp_SOURCES) $(test_corrupt_SOURCES) \
+ $(test_dbus_daemon_SOURCES) \
$(test_dbus_daemon_eavesdrop_SOURCES) test-exit.c \
$(test_fdpass_SOURCES) $(test_loopback_SOURCES) \
$(test_marshal_SOURCES) $(test_monitor_SOURCES) test-names.c \
@@ -345,8 +351,8 @@ SOURCES = $(libdbus_testutils_internal_la_SOURCES) \
DIST_SOURCES = $(am__libdbus_testutils_internal_la_SOURCES_DIST) \
$(am__libdbus_testutils_la_SOURCES_DIST) \
$(manual_authz_SOURCES) $(manual_dir_iter_SOURCES) \
- $(manual_tcp_SOURCES) $(test_corrupt_SOURCES) \
- $(test_dbus_daemon_SOURCES) \
+ $(manual_paths_SOURCES) $(manual_tcp_SOURCES) \
+ $(test_corrupt_SOURCES) $(test_dbus_daemon_SOURCES) \
$(test_dbus_daemon_eavesdrop_SOURCES) test-exit.c \
$(test_fdpass_SOURCES) $(test_loopback_SOURCES) \
$(test_marshal_SOURCES) $(test_monitor_SOURCES) test-names.c \
@@ -580,7 +586,7 @@ am__set_TESTS_bases = \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
RECHECK_LOGS = $(TEST_LOGS)
-@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_8 = $(am__EXEEXT_3)
+@DBUS_ENABLE_MODULAR_TESTS_TRUE@am__EXEEXT_9 = $(am__EXEEXT_3)
TEST_SUITE_LOG = test-suite.log
TEST_EXTENSIONS = @EXEEXT@ .test
LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
@@ -631,6 +637,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -685,6 +693,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -774,6 +783,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -916,19 +926,22 @@ test_syslog_LDADD = libdbus-testutils-internal.la $(GLIB_LIBS)
manual_dir_iter_SOURCES = manual-dir-iter.c
manual_dir_iter_CPPFLAGS = $(static_cppflags)
manual_dir_iter_LDADD = $(top_builddir)/dbus/libdbus-internal.la
+manual_paths_SOURCES = manual-paths.c
+manual_paths_CPPFLAGS = $(static_cppflags)
+manual_paths_LDADD = $(top_builddir)/dbus/libdbus-internal.la
manual_tcp_SOURCES = manual-tcp.c
manual_tcp_CPPFLAGS = $(static_cppflags)
manual_tcp_LDADD = $(top_builddir)/dbus/libdbus-internal.la
EXTRA_DIST = dbus-test-runner $(in_data) $(static_data)
testexecdir = $(libexecdir)/installed-tests/dbus
testmetadir = $(datadir)/installed-tests/dbus
-testmeta_DATA = $(am__append_9)
-installable_tests = test-shell test-printf $(NULL) $(am__append_4)
+testmeta_DATA = $(am__append_10)
+installable_tests = test-shell test-printf $(NULL) $(am__append_5)
installable_manual_tests = manual-dir-iter manual-tcp $(NULL) \
- $(am__append_5)
+ $(am__append_4) $(am__append_6)
installable_test_meta = $(installable_tests:=.test)
installable_test_meta_with_config = $(installable_tests:=_with_config.test)
-installcheck_tests = $(am__append_7)
+installcheck_tests = $(am__append_8)
installcheck_environment = \
XDG_RUNTIME_DIR=@abs_top_builddir@/test/XDG_RUNTIME_DIR \
DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT) \
@@ -1274,6 +1287,10 @@ manual-dir-iter$(EXEEXT): $(manual_dir_iter_OBJECTS) $(manual_dir_iter_DEPENDENC
@rm -f manual-dir-iter$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(manual_dir_iter_OBJECTS) $(manual_dir_iter_LDADD) $(LIBS)
+manual-paths$(EXEEXT): $(manual_paths_OBJECTS) $(manual_paths_DEPENDENCIES) $(EXTRA_manual_paths_DEPENDENCIES)
+ @rm -f manual-paths$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(manual_paths_OBJECTS) $(manual_paths_LDADD) $(LIBS)
+
manual-tcp$(EXEEXT): $(manual_tcp_OBJECTS) $(manual_tcp_DEPENDENCIES) $(EXTRA_manual_tcp_DEPENDENCIES)
@rm -f manual-tcp$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(manual_tcp_OBJECTS) $(manual_tcp_LDADD) $(LIBS)
@@ -1389,6 +1406,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdbus_testutils_internal_la-test-utils.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual_authz-manual-authz.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual_dir_iter-manual-dir-iter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual_paths-manual-paths.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manual_tcp-manual-tcp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-exit.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-segfault.Po@am__quote@
@@ -1481,6 +1499,20 @@ manual_dir_iter-manual-dir-iter.obj: manual-dir-iter.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_dir_iter_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o manual_dir_iter-manual-dir-iter.obj `if test -f 'manual-dir-iter.c'; then $(CYGPATH_W) 'manual-dir-iter.c'; else $(CYGPATH_W) '$(srcdir)/manual-dir-iter.c'; fi`
+manual_paths-manual-paths.o: manual-paths.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_paths_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT manual_paths-manual-paths.o -MD -MP -MF $(DEPDIR)/manual_paths-manual-paths.Tpo -c -o manual_paths-manual-paths.o `test -f 'manual-paths.c' || echo '$(srcdir)/'`manual-paths.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/manual_paths-manual-paths.Tpo $(DEPDIR)/manual_paths-manual-paths.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='manual-paths.c' object='manual_paths-manual-paths.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_paths_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o manual_paths-manual-paths.o `test -f 'manual-paths.c' || echo '$(srcdir)/'`manual-paths.c
+
+manual_paths-manual-paths.obj: manual-paths.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_paths_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT manual_paths-manual-paths.obj -MD -MP -MF $(DEPDIR)/manual_paths-manual-paths.Tpo -c -o manual_paths-manual-paths.obj `if test -f 'manual-paths.c'; then $(CYGPATH_W) 'manual-paths.c'; else $(CYGPATH_W) '$(srcdir)/manual-paths.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/manual_paths-manual-paths.Tpo $(DEPDIR)/manual_paths-manual-paths.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='manual-paths.c' object='manual_paths-manual-paths.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_paths_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o manual_paths-manual-paths.obj `if test -f 'manual-paths.c'; then $(CYGPATH_W) 'manual-paths.c'; else $(CYGPATH_W) '$(srcdir)/manual-paths.c'; fi`
+
manual_tcp-manual-tcp.o: manual-tcp.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(manual_tcp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT manual_tcp-manual-tcp.o -MD -MP -MF $(DEPDIR)/manual_tcp-manual-tcp.Tpo -c -o manual_tcp-manual-tcp.o `test -f 'manual-tcp.c' || echo '$(srcdir)/'`manual-tcp.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/manual_tcp-manual-tcp.Tpo $(DEPDIR)/manual_tcp-manual-tcp.Po
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c
index 6b0e9b8a..26786fc2 100644
--- a/test/dbus-daemon.c
+++ b/test/dbus-daemon.c
@@ -28,6 +28,8 @@
#include "test-utils-glib.h"
+#include <string.h>
+
#ifdef DBUS_UNIX
# include <unistd.h>
# include <sys/types.h>
@@ -305,7 +307,8 @@ test_creds (Fixture *f,
enum {
SEEN_UNIX_USER = 1,
SEEN_PID = 2,
- SEEN_WINDOWS_SID = 4
+ SEEN_WINDOWS_SID = 4,
+ SEEN_LINUX_SECURITY_LABEL = 8
} seen = 0;
if (m == NULL)
@@ -371,6 +374,28 @@ test_creds (Fixture *f,
g_assert_not_reached ();
#endif
}
+ else if (g_strcmp0 (name, "WindowsSID") == 0)
+ {
+#ifdef G_OS_WIN32
+ gchar *sid;
+ guint32 result;
+ char *self_sid;
+
+ g_assert (!(seen & SEEN_WINDOWS_SID));
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
+ DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic (&var_iter, &sid);
+ g_message ("%s of this process is %s", name, sid);
+ if (_dbus_getsid (&self_sid, 0))
+ {
+ g_assert_cmpstr (self_sid, ==, sid);
+ LocalFree(self_sid);
+ }
+ seen |= SEEN_WINDOWS_SID;
+#else
+ g_assert_not_reached ();
+#endif
+ }
else if (g_strcmp0 (name, "ProcessID") == 0)
{
guint32 u32;
@@ -389,6 +414,27 @@ test_creds (Fixture *f,
#endif
seen |= SEEN_PID;
}
+ else if (g_strcmp0 (name, "LinuxSecurityLabel") == 0)
+ {
+#ifdef __linux__
+ gchar *label;
+ int len;
+ DBusMessageIter ay_iter;
+
+ g_assert (!(seen & SEEN_LINUX_SECURITY_LABEL));
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&var_iter), ==,
+ DBUS_TYPE_ARRAY);
+ dbus_message_iter_recurse (&var_iter, &ay_iter);
+ g_assert_cmpuint (dbus_message_iter_get_arg_type (&ay_iter), ==,
+ DBUS_TYPE_BYTE);
+ dbus_message_iter_get_fixed_array (&ay_iter, &label, &len);
+ g_message ("%s of this process is %s", name, label);
+ g_assert_cmpuint (strlen (label) + 1, ==, len);
+ seen |= SEEN_LINUX_SECURITY_LABEL;
+#else
+ g_assert_not_reached ();
+#endif
+ }
dbus_message_iter_next (&arr_iter);
}
@@ -402,9 +448,7 @@ test_creds (Fixture *f,
#endif
#ifdef G_OS_WIN32
- /* FIXME: when implemented:
g_assert (seen & SEEN_WINDOWS_SID);
- */
#endif
}
diff --git a/test/fdpass.c b/test/fdpass.c
index fa958da8..96f9427f 100644
--- a/test/fdpass.c
+++ b/test/fdpass.c
@@ -57,9 +57,11 @@ _DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS <= 253);
/* Arbitrary; included here to avoid relying on the default. */
#define MAX_INCOMING_UNIX_FDS (MAX_MESSAGE_UNIX_FDS * 4)
-/* Arbitrary, except that MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES must be
+/* Arbitrary, except that MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES should be
* less than the process's file descriptor limit. */
-#define SOME_MESSAGES 50
+#define SOME_MESSAGES 20
+/* To cover some situations on Linux we want this to be true. */
+_DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES > 256);
/* Linux won't allow more than 253 fds per sendmsg(). */
#define TOO_MANY_FDS 255
@@ -809,6 +811,25 @@ main (int argc,
{
test_init (&argc, &argv);
+#ifdef HAVE_GETRLIMIT
+ {
+ struct rlimit lim;
+
+ if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
+ g_error ("Failed to get RLIMIT_NOFILE limit: %s", g_strerror (errno));
+
+ if (lim.rlim_cur != RLIM_INFINITY &&
+ /* only run if we have a fairly generous margin of error
+ * for stdout, stderr, duplicates, the D-Bus connection, etc. */
+ lim.rlim_cur < 2 * MAX_MESSAGE_UNIX_FDS * SOME_MESSAGES)
+ {
+ g_message ("not enough RLIMIT_NOFILE to run this test");
+ /* Autotools exit code for "all skipped" */
+ return 77;
+ }
+ }
+#endif
+
g_test_add ("/relay", Fixture, NULL, setup,
test_relay, teardown);
g_test_add ("/limit", Fixture, NULL, setup,
diff --git a/test/manual-paths.c b/test/manual-paths.c
new file mode 100644
index 00000000..4ce3ffc7
--- /dev/null
+++ b/test/manual-paths.c
@@ -0,0 +1,73 @@
+/*
+ * Simple manual paths check
+ *
+ * syntax: manual-paths
+ *
+*/
+
+#include "config.h"
+#include "dbus/dbus-list.h"
+#include "dbus/dbus-internals.h"
+#include "dbus/dbus-sysdeps.h"
+
+#include <stdio.h>
+
+dbus_bool_t print_install_root()
+{
+ char runtime_prefix[1000];
+
+ if (!_dbus_get_install_root(runtime_prefix, sizeof(runtime_prefix)))
+ {
+ fprintf(stderr, "dbus_get_install_root() failed\n");
+ return FALSE;
+ }
+ fprintf(stdout, "dbus_get_install_root() returned '%s'\n", runtime_prefix);
+ return TRUE;
+}
+
+dbus_bool_t print_service_dirs()
+{
+ DBusList *dirs;
+ DBusList *link;
+ dirs = NULL;
+
+ if (!_dbus_get_standard_session_servicedirs (&dirs))
+ _dbus_assert_not_reached ("couldn't get standard dirs");
+
+ while ((link = _dbus_list_pop_first_link (&dirs)))
+ {
+ printf ("default service dir: %s\n", (char *)link->data);
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ }
+ dbus_free (dirs);
+ return TRUE;
+}
+
+dbus_bool_t print_replace_install_prefix(const char *s)
+{
+ const char *s2 = _dbus_replace_install_prefix(s);
+ if (!s2)
+ return FALSE;
+
+ fprintf(stdout, "replaced '%s' by '%s'\n", s, s2);
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ if (!print_install_root())
+ return -1;
+
+ if (!print_service_dirs())
+ return -2;
+
+ if (!print_replace_install_prefix(DBUS_BINDIR "/dbus-daemon"))
+ return -3;
+
+ if (!print_replace_install_prefix("c:\\Windows\\System32\\testfile"))
+ return -4;
+
+ return 0;
+}
diff --git a/test/name-test/Makefile.in b/test/name-test/Makefile.in
index 62357838..0b6ba20a 100644
--- a/test/name-test/Makefile.in
+++ b/test/name-test/Makefile.in
@@ -410,6 +410,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -464,6 +466,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -553,6 +556,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 294bbc63..80025b82 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -29,7 +29,10 @@ endif
dbus_send_SOURCES= \
dbus-print-message.c \
dbus-print-message.h \
- dbus-send.c
+ dbus-send.c \
+ tool-common.c \
+ tool-common.h \
+ $(NULL)
dbus_monitor_SOURCES = \
dbus-monitor.c \
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 2d8a1ea6..054d17a1 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -136,7 +136,7 @@ dbus_run_session_OBJECTS = $(am_dbus_run_session_OBJECTS)
@DBUS_WIN_FALSE@dbus_run_session_DEPENDENCIES = \
@DBUS_WIN_FALSE@ $(top_builddir)/dbus/libdbus-1.la
am_dbus_send_OBJECTS = dbus-print-message.$(OBJEXT) \
- dbus-send.$(OBJEXT)
+ dbus-send.$(OBJEXT) tool-common.$(OBJEXT)
dbus_send_OBJECTS = $(am_dbus_send_OBJECTS)
dbus_send_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la
am_dbus_test_tool_OBJECTS = dbus-echo.$(OBJEXT) dbus-spam.$(OBJEXT) \
@@ -245,6 +245,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -299,6 +301,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -388,6 +391,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -462,7 +466,10 @@ AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
dbus_send_SOURCES = \
dbus-print-message.c \
dbus-print-message.h \
- dbus-send.c
+ dbus-send.c \
+ tool-common.c \
+ tool-common.h \
+ $(NULL)
dbus_monitor_SOURCES = \
dbus-monitor.c \
diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c
index ad776904..14ceae90 100644
--- a/tools/dbus-monitor.c
+++ b/tools/dbus-monitor.c
@@ -74,7 +74,7 @@ GetSystemTimeAsFileTime (LPFILETIME ftp)
static int
gettimeofday (struct timeval *__p,
- void *__t)
+ void *__t)
{
union {
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
@@ -91,8 +91,8 @@ gettimeofday (struct timeval *__p,
static DBusHandlerResult
monitor_filter_func (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+ DBusMessage *message,
+ void *user_data)
{
print_message (message, FALSE);
@@ -107,14 +107,6 @@ monitor_filter_func (DBusConnection *connection,
return DBUS_HANDLER_RESULT_HANDLED;
}
-#ifdef __APPLE__
-#define PROFILE_TIMED_FORMAT "%s\t%lu\t%d"
-#elif defined(__NetBSD__)
-#include <inttypes.h>
-#define PROFILE_TIMED_FORMAT "%s\t%" PRId64 "\t%d"
-#else
-#define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu"
-#endif
#define TRAP_NULL_STRING(str) ((str) ? (str) : "<none>")
typedef enum
@@ -130,23 +122,30 @@ typedef enum
} ProfileAttributeFlags;
static void
+profile_print_headers (void)
+{
+ printf ("#type\ttimestamp\tserial\tsender\tdestination\tpath\tinterface\tmember\n");
+ printf ("#\t\t\t\t\tin_reply_to\n");
+}
+
+static void
profile_print_with_attrs (const char *type, DBusMessage *message,
struct timeval *t, ProfileAttributeFlags attrs)
{
- printf (PROFILE_TIMED_FORMAT, type, t->tv_sec, t->tv_usec);
+ printf ("%s\t%lu.%06lu", type, (unsigned long) t->tv_sec, (unsigned long) t->tv_usec);
if (attrs & PROFILE_ATTRIBUTE_FLAG_SERIAL)
printf ("\t%u", dbus_message_get_serial (message));
- if (attrs & PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL)
- printf ("\t%u", dbus_message_get_reply_serial (message));
-
if (attrs & PROFILE_ATTRIBUTE_FLAG_SENDER)
printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_sender (message)));
if (attrs & PROFILE_ATTRIBUTE_FLAG_DESTINATION)
printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_destination (message)));
+ if (attrs & PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL)
+ printf ("\t%u", dbus_message_get_reply_serial (message));
+
if (attrs & PROFILE_ATTRIBUTE_FLAG_PATH)
printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_path (message)));
@@ -165,6 +164,7 @@ profile_print_with_attrs (const char *type, DBusMessage *message,
static void
print_message_profile (DBusMessage *message)
{
+ static dbus_bool_t first = TRUE;
struct timeval t;
if (gettimeofday (&t, NULL) < 0)
@@ -173,45 +173,56 @@ print_message_profile (DBusMessage *message)
return;
}
+ if (first)
+ {
+ profile_print_headers ();
+ first = FALSE;
+ }
+
switch (dbus_message_get_type (message))
{
case DBUS_MESSAGE_TYPE_METHOD_CALL:
- profile_print_with_attrs ("mc", message, &t,
- PROFILE_ATTRIBUTE_FLAG_SERIAL |
- PROFILE_ATTRIBUTE_FLAG_SENDER |
- PROFILE_ATTRIBUTE_FLAG_PATH |
- PROFILE_ATTRIBUTE_FLAG_INTERFACE |
- PROFILE_ATTRIBUTE_FLAG_MEMBER);
- break;
+ profile_print_with_attrs ("mc", message, &t,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ PROFILE_ATTRIBUTE_FLAG_PATH |
+ PROFILE_ATTRIBUTE_FLAG_INTERFACE |
+ PROFILE_ATTRIBUTE_FLAG_MEMBER);
+ break;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- profile_print_with_attrs ("mr", message, &t,
- PROFILE_ATTRIBUTE_FLAG_SERIAL |
- PROFILE_ATTRIBUTE_FLAG_DESTINATION |
- PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL);
- break;
+ profile_print_with_attrs ("mr", message, &t,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL);
+ break;
case DBUS_MESSAGE_TYPE_ERROR:
- profile_print_with_attrs ("err", message, &t,
- PROFILE_ATTRIBUTE_FLAG_SERIAL |
- PROFILE_ATTRIBUTE_FLAG_DESTINATION |
- PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL);
- break;
+ profile_print_with_attrs ("err", message, &t,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL);
+ break;
case DBUS_MESSAGE_TYPE_SIGNAL:
- profile_print_with_attrs ("sig", message, &t,
- PROFILE_ATTRIBUTE_FLAG_SERIAL |
- PROFILE_ATTRIBUTE_FLAG_PATH |
- PROFILE_ATTRIBUTE_FLAG_INTERFACE |
- PROFILE_ATTRIBUTE_FLAG_MEMBER);
- break;
+ profile_print_with_attrs ("sig", message, &t,
+ PROFILE_ATTRIBUTE_FLAG_SERIAL |
+ PROFILE_ATTRIBUTE_FLAG_SENDER |
+ PROFILE_ATTRIBUTE_FLAG_DESTINATION |
+ PROFILE_ATTRIBUTE_FLAG_PATH |
+ PROFILE_ATTRIBUTE_FLAG_INTERFACE |
+ PROFILE_ATTRIBUTE_FLAG_MEMBER);
+ break;
default:
- printf (PROFILE_TIMED_FORMAT "\n", "tun", t.tv_sec, t.tv_usec);
- break;
+ printf ("%s\t%lu.%06lu", "tun", (unsigned long) t.tv_sec, (unsigned long) t.tv_usec);
+ break;
}
}
static DBusHandlerResult
-profile_filter_func (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+profile_filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
print_message_profile (message);
@@ -431,7 +442,7 @@ main (int argc, char *argv[])
usage (argv[0], 1);
}
else if (!strcmp (arg, "--help"))
- usage (argv[0], 0);
+ usage (argv[0], 0);
else if (!strcmp (arg, "--monitor"))
{
filter_func = monitor_filter_func;
@@ -453,9 +464,9 @@ main (int argc, char *argv[])
binary_mode = BINARY_MODE_PCAP;
}
else if (!strcmp (arg, "--"))
- continue;
+ continue;
else if (arg[0] == '-')
- usage (argv[0], 1);
+ usage (argv[0], 1);
else {
unsigned int filter_len;
numFilters++;
@@ -483,12 +494,12 @@ main (int argc, char *argv[])
if (connection)
{
if (!dbus_bus_register (connection, &error))
- {
+ {
fprintf (stderr, "Failed to register connection to bus at %s: %s\n",
- address, error.message);
+ address, error.message);
dbus_error_free (&error);
exit (1);
- }
+ }
}
}
else
@@ -548,7 +559,7 @@ main (int argc, char *argv[])
dbus_bus_add_match (connection, filters[i] + offset, &error);
}
- if (dbus_error_is_set (&error))
+ if (dbus_error_is_set (&error))
{
fprintf (stderr, "Failed to setup match \"%s\": %s\n",
filters[i], error.message);
diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c
index 6f02ea38..216ebaeb 100644
--- a/tools/dbus-print-message.c
+++ b/tools/dbus-print-message.c
@@ -37,6 +37,8 @@
#include <stdlib.h>
#include "config.h"
+#include "tool-common.h"
+
static const char*
type_to_name (int message_type)
{
@@ -65,7 +67,9 @@ indent (int depth)
}
static void
-print_hex (unsigned char *bytes, unsigned int len, int depth)
+print_hex (const unsigned char *bytes,
+ int len,
+ int depth)
{
unsigned int i, columns;
@@ -110,47 +114,45 @@ print_hex (unsigned char *bytes, unsigned int len, int depth)
static void
print_ay (DBusMessageIter *iter, int depth)
{
- /* Not using DBusString because it's not public API. It's 2009, and I'm
- * manually growing a string chunk by chunk.
- */
- unsigned char *bytes = malloc (DEFAULT_SIZE + 1);
- unsigned int len = 0;
- unsigned int max = DEFAULT_SIZE;
+ /* True if every byte in the bytestring (so far) is printable
+ * ASCII, with one exception: the last byte is also allowed to be \0. */
dbus_bool_t all_ascii = TRUE;
- int current_type;
-
- while ((current_type = dbus_message_iter_get_arg_type (iter))
- != DBUS_TYPE_INVALID)
- {
- unsigned char val;
-
- dbus_message_iter_get_basic (iter, &val);
- bytes[len] = val;
- len++;
+ const unsigned char *bytes;
+ int len;
+ int i;
- if (val < 32 || val > 126)
- all_ascii = FALSE;
+ dbus_message_iter_get_fixed_array (iter, &bytes, &len);
- if (len == max)
+ for (i = 0; i < len; i++)
+ {
+ if ((bytes[i] < 32 || bytes[i] > 126) &&
+ (i < len - 1 || bytes[i] != '\0'))
{
- max *= 2;
- bytes = realloc (bytes, max + 1);
+ all_ascii = FALSE;
+ break;
}
-
- dbus_message_iter_next (iter);
}
- if (all_ascii)
+ if (all_ascii && len > 0 && bytes[len - 1] == '\0')
+ {
+ printf ("array of bytes \"%s\" + \\0\n", bytes);
+ }
+ else if (all_ascii)
{
- bytes[len] = '\0';
- printf ("array of bytes \"%s\"\n", bytes);
+ unsigned char *copy = dbus_malloc (len + 1);
+
+ if (copy == NULL)
+ tool_oom ("copying bytestring");
+
+ memcpy (copy, bytes, len);
+ copy[len] = '\0';
+ printf ("array of bytes \"%s\"\n", copy);
+ dbus_free (copy);
}
else
{
print_hex (bytes, len, depth);
}
-
- free (bytes);
}
static void