[pulseaudio] 01/02: Add Ubuntu touch trust store patch set
David Henningsson
diwic-guest at moszumanska.debian.org
Thu Aug 27 17:13:35 UTC 2015
This is an automated email from the git hooks/post-receive script.
diwic-guest pushed a commit to branch ubuntu
in repository pulseaudio.
commit e9f74032ae55de6f68d5ab1e1cdcc0e9b2c0416a
Author: David Henningsson <david.henningsson at canonical.com>
Date: Thu Aug 27 19:10:14 2015 +0200
Add Ubuntu touch trust store patch set
---
debian/changelog | 17 +
debian/control | 29 +
.../patches/0406-tagstruct-add-copy-method.patch | 48 ++
.../0407-access-Add-access-control-hooks.patch | 181 ++++++
.../0408-protocol-native-add-access-checks.patch | 495 ++++++++++++++++
debian/patches/0409-Trust-store-patch.patch | 627 +++++++++++++++++++++
...-thread-to-activate-trust-store-interface.patch | 111 ++++
.../0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch | 62 ++
.../0417-increase-timeout-check-apparmor.patch | 92 +++
debian/patches/series | 10 +
10 files changed, 1672 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index d6e7e38..31575b8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+pulseaudio (1:6.0-0ubuntu9) UNRELEASED; urgency=medium
+
+ [ Alfonso Sanchez-Beato (email Canonical) ]
+ * debian/patches/0401-access-Add-access-control-hooks.patch
+ * debian/patches/0402-protocol-native-add-access-checks.patch
+ * debian/patches/0403-Trust-store-patch.patch
+ * debian/patches/0404-Add-thread-to-activate-trust-store-interface.patch
+ * debian/patches/0406-tagstruct-add-copy-method.patch
+ * debian/patches/0407-access-Add-access-control-hooks.patch
+ * debian/patches/0408-protocol-native-add-access-checks.patch
+ * debian/patches/0409-Trust-store-patch.patch
+ * debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch
+ * debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch
+ Add support for trust-store in Ubuntu touch
+
+ -- Alfonso Sanchez-Beato (email Canonical) <alfonso.sanchez-beato at canonical.com> Fri, 07 Aug 2015 09:26:24 +0200
+
pulseaudio (1:6.0-0ubuntu8) wily; urgency=medium
* 0311-tests-add-tolerant-variation-for-comparing-the-rewin.patch:
diff --git a/debian/control b/debian/control
index 59a1963..8651669 100644
--- a/debian/control
+++ b/debian/control
@@ -13,6 +13,7 @@ Build-Depends: debhelper (>= 9),
check,
dh-autoreconf,
intltool,
+ libapparmor-dev [linux-any],
libasound2-dev (>= 1.0.24) [linux-any],
libasyncns-dev,
libatomic-ops-dev,
@@ -20,6 +21,7 @@ Build-Depends: debhelper (>= 9),
libbluetooth-dev (>= 4.40) [linux-any],
libsbc-dev [linux-any],
libcap-dev [linux-any],
+ libdbus-cpp-dev [armhf i386 amd64],
libfftw3-dev,
libgconf2-dev,
libglib2.0-dev,
@@ -38,6 +40,7 @@ Build-Depends: debhelper (>= 9),
libssl-dev,
libsystemd-dev [linux-any],
libtdb-dev [!hurd-any],
+ libtrust-store-dev [armhf i386 amd64],
libudev-dev (>= 143) [linux-any],
libwebrtc-audio-processing-dev,
libwrap0-dev,
@@ -313,6 +316,32 @@ Description: Android Audio HAL module for PulseAudio sound server (debugging)
.
This package contains debugging symbols for the PulseAudio droid module.
+Package: pulseaudio-module-trust-store
+Architecture: armhf i386 amd64
+Priority: extra
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Conflicts: pulseaudio (<< 0.9.14-2)
+Description: trust-store module for PulseAudio sound server
+ PulseAudio, previously known as Polypaudio, is a sound server for POSIX and
+ WIN32 systems. It is a drop in replacement for the ESD sound server with
+ much better latency, mixing/re-sampling quality and overall architecture.
+ .
+ This module enables PulseAudio to use the trust-store in Ubuntu touch systems.
+ .
+ The module is called module-trust-store.
+
+Package: pulseaudio-module-trust-store-dbg
+Architecture: armhf i386 amd64
+Priority: extra
+Section: debug
+Depends: ${misc:Depends}, pulseaudio-module-trust-store (= ${binary:Version})
+Description: trust-store module for PulseAudio sound server (debugging)
+ PulseAudio, previously known as Polypaudio, is a sound server for POSIX and
+ WIN32 systems. It is a drop in replacement for the ESD sound server with
+ much better latency, mixing/re-sampling quality and overall architecture.
+ .
+ This package contains debugging symbols for the PulseAudio trust-store module.
+
Package: pulseaudio-module-bluetooth
Architecture: linux-any
Priority: extra
diff --git a/debian/patches/0406-tagstruct-add-copy-method.patch b/debian/patches/0406-tagstruct-add-copy-method.patch
new file mode 100644
index 0000000..0ad1c6c
--- /dev/null
+++ b/debian/patches/0406-tagstruct-add-copy-method.patch
@@ -0,0 +1,48 @@
+From 3560cafb03fc62745874077fb1153ec8d0cc59ac Mon Sep 17 00:00:00 2001
+From: David Henningsson <david.henningsson at canonical.com>
+Date: Thu, 27 Aug 2015 15:27:16 +0200
+Subject: [PATCH] Add tagstruct copy method
+
+Originally by Wim Taymans, backported by David Henningsson
+---
+ src/pulsecore/tagstruct.c | 14 ++++++++++++++
+ src/pulsecore/tagstruct.h | 2 ++
+ 2 files changed, 16 insertions(+)
+
+Index: pulseaudio/src/pulsecore/tagstruct.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/tagstruct.c 2015-08-27 17:06:31.000000000 +0200
++++ pulseaudio/src/pulsecore/tagstruct.c 2015-08-27 17:10:53.302118854 +0200
+@@ -83,6 +83,19 @@
+ return p;
+ }
+
++pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t) {
++ pa_tagstruct*tc;
++
++ tc = pa_xnew(pa_tagstruct, 1);
++ tc->data = pa_xmemdup(t->data, t->length);
++ tc->allocated = t->length;
++ tc->length = t->length;
++ tc->rindex = 0;
++ tc->dynamic = true;
++
++ return tc;
++}
++
+ static void extend(pa_tagstruct*t, size_t l) {
+ pa_assert(t);
+ pa_assert(t->dynamic);
+Index: pulseaudio/src/pulsecore/tagstruct.h
+===================================================================
+--- pulseaudio.orig/src/pulsecore/tagstruct.h 2015-08-27 17:06:31.000000000 +0200
++++ pulseaudio/src/pulsecore/tagstruct.h 2015-08-27 17:06:39.000000000 +0200
+@@ -64,6 +64,8 @@
+ void pa_tagstruct_free(pa_tagstruct*t);
+ uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l);
+
++pa_tagstruct *pa_tagstruct_copy(pa_tagstruct*t);
++
+ int pa_tagstruct_eof(pa_tagstruct*t);
+ const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l);
+
diff --git a/debian/patches/0407-access-Add-access-control-hooks.patch b/debian/patches/0407-access-Add-access-control-hooks.patch
new file mode 100644
index 0000000..17f3bce
--- /dev/null
+++ b/debian/patches/0407-access-Add-access-control-hooks.patch
@@ -0,0 +1,181 @@
+From d25ec7bc401be4df1df53158ccacd5026366f38d Mon Sep 17 00:00:00 2001
+From: Alfonso Sanchez-Beato <alfonso.sanchez-beato at canonical.com>
+Date: Fri, 7 Aug 2015 12:19:50 +0200
+Subject: [PATCH 1/4] access: Add access control hooks
+
+Add hooks to core to check if certain operations are allowed.
+---
+ src/Makefile.am | 1 +
+ src/pulsecore/access.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++++
+ src/pulsecore/core.c | 5 +++
+ src/pulsecore/core.h | 3 ++
+ 4 files changed, 111 insertions(+)
+ create mode 100644 src/pulsecore/access.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index f96f527..f6897de 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -637,6 +637,7 @@ pkglib_LTLIBRARIES = \
+ # to the existing libpulse being linked to libpulsecommon). Duplicating the
+ # code allows us to prevent this circular linking.
+ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
++ pulsecore/access.h \
+ pulse/client-conf.c pulse/client-conf.h \
+ pulse/fork-detect.c pulse/fork-detect.h \
+ pulse/format.c pulse/format.h \
+diff --git a/src/pulsecore/access.h b/src/pulsecore/access.h
+new file mode 100644
+index 0000000..7cd2751
+--- /dev/null
++++ b/src/pulsecore/access.h
+@@ -0,0 +1,102 @@
++#ifndef fooaccesshfoo
++#define fooaccesshfoo
++
++/***
++ This file is part of PulseAudio.
++
++ Copyright 2004-2006 Lennart Poettering
++ 2015 Wim Taymans <wtaymans at redhat.com>
++
++ PulseAudio is free software; you can redistribute it and/or modify
++ it under the terms of the GNU Lesser General Public License as
++ published by the Free Software Foundation; either version 2.1 of the
++ License, or (at your option) any later version.
++
++ PulseAudio 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
++***/
++
++#include <sys/types.h>
++
++#include <pulsecore/client.h>
++
++typedef enum pa_access_hook {
++ /* context */
++ PA_ACCESS_HOOK_EXIT_DAEMON,
++ PA_ACCESS_HOOK_SET_DEFAULT_SINK,
++ PA_ACCESS_HOOK_SET_DEFAULT_SOURCE,
++
++ /* introspection */
++ PA_ACCESS_HOOK_GET_SINK_INFO,
++ PA_ACCESS_HOOK_SET_SINK_VOLUME,
++ PA_ACCESS_HOOK_SET_SINK_MUTE,
++ PA_ACCESS_HOOK_SUSPEND_SINK,
++ PA_ACCESS_HOOK_SET_SINK_PORT,
++
++ PA_ACCESS_HOOK_GET_SOURCE_INFO,
++ PA_ACCESS_HOOK_SET_SOURCE_VOLUME,
++ PA_ACCESS_HOOK_SET_SOURCE_MUTE,
++ PA_ACCESS_HOOK_SUSPEND_SOURCE,
++ PA_ACCESS_HOOK_SET_SOURCE_PORT,
++
++ PA_ACCESS_HOOK_GET_SERVER_INFO,
++
++ PA_ACCESS_HOOK_GET_MODULE_INFO,
++ PA_ACCESS_HOOK_LOAD_MODULE,
++ PA_ACCESS_HOOK_UNLOAD_MODULE,
++
++ PA_ACCESS_HOOK_GET_CLIENT_INFO,
++ PA_ACCESS_HOOK_KILL_CLIENT,
++
++ PA_ACCESS_HOOK_GET_CARD_INFO,
++ PA_ACCESS_HOOK_SET_CARD_PROFILE,
++ PA_ACCESS_HOOK_SET_PORT_LATENCY_OFFSET,
++
++ PA_ACCESS_HOOK_GET_SINK_INPUT_INFO,
++ PA_ACCESS_HOOK_MOVE_SINK_INPUT,
++ PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME,
++ PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE,
++ PA_ACCESS_HOOK_KILL_SINK_INPUT,
++
++ PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO,
++ PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT,
++ PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME,
++ PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE,
++ PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT,
++
++ PA_ACCESS_HOOK_STAT,
++
++ PA_ACCESS_HOOK_GET_SAMPLE_INFO,
++ /* sample cache */
++ PA_ACCESS_HOOK_CONNECT_UPLOAD,
++ PA_ACCESS_HOOK_REMOVE_SAMPLE,
++ PA_ACCESS_HOOK_PLAY_SAMPLE,
++ /* stream */
++ PA_ACCESS_HOOK_CONNECT_PLAYBACK,
++ PA_ACCESS_HOOK_CONNECT_RECORD,
++ /* extension */
++ PA_ACCESS_HOOK_EXTENSION,
++
++ PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT,
++
++ PA_ACCESS_HOOK_MAX
++} pa_access_hook_t;
++
++typedef struct pa_access_data pa_access_data;
++
++struct pa_access_data {
++ pa_access_hook_t hook;
++ uint32_t client_index;
++ uint32_t object_index;
++ pa_subscription_event_type_t event;
++ const char *name;
++
++ void (*async_finish_cb) (pa_access_data *data, bool res);
++};
++
++#endif
+diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
+index 0e63bac..9135311 100644
+--- a/src/pulsecore/core.c
++++ b/src/pulsecore/core.c
+@@ -151,6 +151,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) {
+ for (j = 0; j < PA_CORE_HOOK_MAX; j++)
+ pa_hook_init(&c->hooks[j], c);
+
++ for (j = 0; j < PA_ACCESS_HOOK_MAX; j++)
++ pa_hook_init(&c->access[j], c);
++
+ pa_random(&c->cookie, sizeof(c->cookie));
+
+ #ifdef SIGPIPE
+@@ -222,6 +225,8 @@ static void core_free(pa_object *o) {
+
+ for (j = 0; j < PA_CORE_HOOK_MAX; j++)
+ pa_hook_done(&c->hooks[j]);
++ for (j = 0; j < PA_ACCESS_HOOK_MAX; j++)
++ pa_hook_done(&c->access[j]);
+
+ pa_xfree(c);
+ }
+diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
+index e69a130..6e7feb4 100644
+--- a/src/pulsecore/core.h
++++ b/src/pulsecore/core.h
+@@ -50,6 +50,7 @@ typedef enum pa_suspend_cause {
+ #include <pulsecore/source.h>
+ #include <pulsecore/core-subscribe.h>
+ #include <pulsecore/msgobject.h>
++#include <pulsecore/access.h>
+
+ typedef enum pa_server_type {
+ PA_SERVER_TYPE_UNSET,
+@@ -199,6 +200,8 @@ struct pa_core {
+
+ /* hooks */
+ pa_hook hooks[PA_CORE_HOOK_MAX];
++ /* access hooks */
++ pa_hook access[PA_ACCESS_HOOK_MAX];
+ };
+
+ PA_DECLARE_PUBLIC_CLASS(pa_core);
+--
+2.1.4
+
diff --git a/debian/patches/0408-protocol-native-add-access-checks.patch b/debian/patches/0408-protocol-native-add-access-checks.patch
new file mode 100644
index 0000000..282249d
--- /dev/null
+++ b/debian/patches/0408-protocol-native-add-access-checks.patch
@@ -0,0 +1,495 @@
+From 1a7e06f33c2c7a684eaebc79ce77c6efce29af1d Mon Sep 17 00:00:00 2001
+From: Wim Taymans <wim.taymans at gmail.com>
+Date: Tue, 7 Apr 2015 17:13:16 +0200
+Subject: [PATCH 3/5] protocol-native: add access checks
+
+Call the hooks in various places to check if an action is allowed or
+not.
+
+The hook can return PA_HOOK_OK to allow an action, PA_HOOK_STOP to
+deny an action.
+
+Returning PA_HOOK_CANCEL will handle the result asynchronously.
+This is implemented by saving the state of the current command and
+exiting the command (going back to the mainloop) without reply.
+When the access check completes, it will call async_finish_cb, which
+will use the saved state to call the original command again. The access
+check will eventually return OK or STOP and the command can complete
+and send a reply.
+---
+ src/pulsecore/protocol-native.c | 219 +++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 217 insertions(+), 2 deletions(-)
+
+Index: pulseaudio/src/pulsecore/protocol-native.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/protocol-native.c 2015-08-27 15:32:07.566841210 +0200
++++ pulseaudio/src/pulsecore/protocol-native.c 2015-08-27 15:33:18.854410782 +0200
+@@ -300,6 +300,7 @@
+ static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+ static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+ static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
++static pa_hook_result_t check_access(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata, uint32_t idx, pa_subscription_event_type_t event, const char *name);
+
+ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
+ [PA_COMMAND_ERROR] = NULL,
+@@ -2014,6 +2015,23 @@
+ } \
+ } while(0);
+
++#define CHECK_ACCESS_STMT(c, command, tag, idx, name, async, denied) { \
++ pa_hook_result_t res = check_access(pd, command, tag, t, userdata, idx, 0, name); \
++ if (res == PA_HOOK_STOP) { \
++ denied; \
++ } else if (res == PA_HOOK_CANCEL) { \
++ async; \
++ } \
++};
++
++#define CHECK_ACCESS_GOTO(c, command, tag, idx, name, label) \
++ CHECK_ACCESS_STMT(c, command, tag, idx, name, \
++ goto label, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); goto label)
++
++#define CHECK_ACCESS(c, command, tag, idx, name) \
++ CHECK_ACCESS_STMT(c, command, tag, idx, name, \
++ return, pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); return)
++
+ static pa_tagstruct *reply_new(uint32_t tag) {
+ pa_tagstruct *reply;
+
+@@ -2091,6 +2109,8 @@
+ CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
+ CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
+
++ CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish);
++
+ p = pa_proplist_new();
+
+ if (name)
+@@ -2412,6 +2432,8 @@
+ CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
+ CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
+
++ CHECK_ACCESS_GOTO(c, command, tag, PA_INVALID_INDEX, NULL, finish);
++
+ p = pa_proplist_new();
+
+ if (name)
+@@ -2617,6 +2639,7 @@
+ }
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
+ ret = pa_core_exit(c->protocol->core, false, 0);
+ CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
+
+@@ -2935,6 +2958,7 @@
+ }
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
+
+ stat = pa_mempool_get_stat(c->protocol->core->mempool);
+
+@@ -3061,6 +3085,8 @@
+ CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
+
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
++
+ p = pa_proplist_new();
+
+ if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
+@@ -3159,6 +3185,8 @@
+
+ CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, sink->index, name);
++
+ p = pa_proplist_new();
+
+ if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
+@@ -3202,6 +3230,8 @@
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+ CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
+
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, name);
++
+ if (pa_scache_remove_item(c->protocol->core, name) < 0) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
+ return;
+@@ -3650,6 +3680,8 @@
+ return;
+ }
+
++ CHECK_ACCESS(c, command, tag, idx, name);
++
+ reply = reply_new(tag);
+ if (sink)
+ sink_fill_tagstruct(c, reply, sink);
+@@ -3710,6 +3742,8 @@
+
+ if (i) {
+ PA_IDXSET_FOREACH(p, i, idx) {
++ CHECK_ACCESS_STMT(c, command, tag, idx, NULL, goto async, continue);
++
+ if (command == PA_COMMAND_GET_SINK_INFO_LIST)
+ sink_fill_tagstruct(c, reply, p);
+ else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
+@@ -3732,6 +3766,11 @@
+ }
+
+ pa_pstream_send_tagstruct(c->pstream, reply);
++ return;
++
++async:
++ pa_tagstruct_free(reply);
++ return;
+ }
+
+ static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+@@ -3752,6 +3791,15 @@
+
+ CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, NULL);
++
++ def_sink = pa_namereg_get_default_sink(c->protocol->core);
++ if (def_sink)
++ CHECK_ACCESS_STMT(c, PA_COMMAND_GET_SINK_INFO, tag, def_sink->index, NULL, return, def_sink = NULL);
++ def_source = pa_namereg_get_default_source(c->protocol->core);
++ if (def_source)
++ CHECK_ACCESS_STMT(c, PA_COMMAND_GET_SOURCE_INFO, tag, def_source->index, NULL, return, def_source = NULL);
++
+ reply = reply_new(tag);
+ pa_tagstruct_puts(reply, PACKAGE_NAME);
+ pa_tagstruct_puts(reply, PACKAGE_VERSION);
+@@ -3767,9 +3815,7 @@
+ fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
+ pa_tagstruct_put_sample_spec(reply, &fixed_ss);
+
+- def_sink = pa_namereg_get_default_sink(c->protocol->core);
+ pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
+- def_source = pa_namereg_get_default_source(c->protocol->core);
+ pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
+
+ pa_tagstruct_putu32(reply, c->protocol->core->cookie);
+@@ -3786,6 +3832,9 @@
+
+ pa_native_connection_assert_ref(c);
+
++ if (check_access (NULL, PA_COMMAND_SUBSCRIBE_EVENT, 0, NULL, userdata, idx, e, NULL) != PA_HOOK_OK)
++ return;
++
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
+ pa_tagstruct_putu32(t, (uint32_t) -1);
+@@ -3888,6 +3937,8 @@
+
+ client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
+
++ CHECK_ACCESS(c, command, tag, idx, name);
++
+ if (sink) {
+ CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
+
+@@ -3983,6 +4034,8 @@
+
+ CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, idx, name);
++
+ client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
+
+ if (sink) {
+@@ -4446,6 +4499,7 @@
+
+ source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
+ CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, source->index, s);
+
+ pa_namereg_set_default_source(c->protocol->core, source);
+ } else {
+@@ -4454,6 +4508,7 @@
+
+ sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
+ CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, sink->index, s);
+
+ pa_namereg_set_default_sink(c->protocol->core, sink);
+ }
+@@ -4521,6 +4576,7 @@
+
+ client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
+ CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, idx, NULL);
+
+ pa_native_connection_ref(c);
+ pa_client_kill(client);
+@@ -4530,6 +4586,7 @@
+
+ s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+ CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, idx, NULL);
+
+ pa_native_connection_ref(c);
+ pa_sink_input_kill(s);
+@@ -4540,6 +4597,7 @@
+
+ s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
+ CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, idx, NULL);
+
+ pa_native_connection_ref(c);
+ pa_source_output_kill(s);
+@@ -4569,6 +4627,8 @@
+ CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
+ CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
+
++ CHECK_ACCESS(c, command, tag, PA_INVALID_INDEX, name);
++
+ if (!(m = pa_module_load(c->protocol->core, name, argument))) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
+ return;
+@@ -4597,6 +4657,8 @@
+ m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
+ CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, idx, NULL);
++
+ pa_module_unload_request(m, false);
+ pa_pstream_send_simple_ack(c->pstream, tag);
+ }
+@@ -4635,6 +4697,7 @@
+ sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
+
+ CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, idx, sink->name);
+
+ if (pa_sink_input_move_to(si, sink, true) < 0) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+@@ -4654,6 +4717,7 @@
+ source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
+
+ CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
++ CHECK_ACCESS(c, command, tag, idx, source->name);
+
+ if (pa_source_output_move_to(so, source, true) < 0) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+@@ -4689,6 +4753,8 @@
+
+ if (idx == PA_INVALID_INDEX && name && !*name) {
+
++ CHECK_ACCESS(c, command, tag, idx, name);
++
+ pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
+
+ if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
+@@ -4705,6 +4771,8 @@
+
+ CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, sink->index, name);
++
+ pa_log_debug("%s of sink %s requested by client %" PRIu32 ".",
+ b ? "Suspending" : "Resuming", sink->name, c->client->index);
+
+@@ -4719,6 +4787,8 @@
+
+ if (idx == PA_INVALID_INDEX && name && !*name) {
+
++ CHECK_ACCESS(c, command, tag, idx, name);
++
+ pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
+
+ if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
+@@ -4736,6 +4806,8 @@
+
+ CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, source->index, name);
++
+ pa_log_debug("%s of source %s requested by client %" PRIu32 ".",
+ b ? "Suspending" : "Resuming", source->name, c->client->index);
+
+@@ -4779,6 +4851,8 @@
+ CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
+ CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
+
++ CHECK_ACCESS(c, command, tag, m->index, name);
++
+ cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
+ CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
+
+@@ -4821,6 +4895,8 @@
+
+ CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, card->index, profile_name);
++
+ if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
+ pa_pstream_send_error(c->pstream, tag, -ret);
+ return;
+@@ -4861,6 +4937,8 @@
+
+ CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, sink->index, name);
++
+ if ((ret = pa_sink_set_port(sink, port, true)) < 0) {
+ pa_pstream_send_error(c->pstream, tag, -ret);
+ return;
+@@ -4877,6 +4955,8 @@
+
+ CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, source->index, name);
++
+ if ((ret = pa_source_set_port(source, port, true)) < 0) {
+ pa_pstream_send_error(c->pstream, tag, -ret);
+ return;
+@@ -4921,6 +5001,8 @@
+ port = pa_hashmap_get(card->ports, port_name);
+ CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
+
++ CHECK_ACCESS(c, command, tag, card->index, port_name);
++
+ pa_device_port_set_latency_offset(port, offset);
+
+ pa_pstream_send_simple_ack(c->pstream, tag);
+@@ -5461,3 +5543,136 @@
+
+ return c->client;
+ }
++
++static const pa_access_hook_t map_table[PA_COMMAND_MAX] = {
++ /* CLIENT -> SERVER */
++ [PA_COMMAND_EXIT] = PA_ACCESS_HOOK_EXIT_DAEMON,
++ [PA_COMMAND_SET_DEFAULT_SINK] = PA_ACCESS_HOOK_SET_DEFAULT_SINK,
++ [PA_COMMAND_SET_DEFAULT_SOURCE] = PA_ACCESS_HOOK_SET_DEFAULT_SOURCE,
++
++ [PA_COMMAND_GET_SINK_INFO] = PA_ACCESS_HOOK_GET_SINK_INFO,
++ [PA_COMMAND_GET_SINK_INFO_LIST] = PA_ACCESS_HOOK_GET_SINK_INFO,
++ [PA_COMMAND_SET_SINK_VOLUME] = PA_ACCESS_HOOK_SET_SINK_VOLUME,
++ [PA_COMMAND_SET_SINK_MUTE] = PA_ACCESS_HOOK_SET_SINK_MUTE,
++ [PA_COMMAND_SUSPEND_SINK] = PA_ACCESS_HOOK_SUSPEND_SINK,
++ [PA_COMMAND_SET_SINK_PORT] = PA_ACCESS_HOOK_SET_SINK_PORT,
++
++ [PA_COMMAND_GET_SOURCE_INFO] = PA_ACCESS_HOOK_GET_SOURCE_INFO,
++ [PA_COMMAND_GET_SOURCE_INFO_LIST] = PA_ACCESS_HOOK_GET_SOURCE_INFO,
++ [PA_COMMAND_SET_SOURCE_VOLUME] = PA_ACCESS_HOOK_SET_SOURCE_VOLUME,
++ [PA_COMMAND_SET_SOURCE_MUTE] = PA_ACCESS_HOOK_SET_SOURCE_MUTE,
++ [PA_COMMAND_SUSPEND_SOURCE] = PA_ACCESS_HOOK_SUSPEND_SOURCE,
++ [PA_COMMAND_SET_SOURCE_PORT] = PA_ACCESS_HOOK_SET_SOURCE_PORT,
++
++ [PA_COMMAND_GET_SERVER_INFO] = PA_ACCESS_HOOK_GET_SERVER_INFO,
++
++ [PA_COMMAND_GET_MODULE_INFO] = PA_ACCESS_HOOK_GET_MODULE_INFO,
++ [PA_COMMAND_GET_MODULE_INFO_LIST] = PA_ACCESS_HOOK_GET_MODULE_INFO,
++ [PA_COMMAND_LOAD_MODULE] = PA_ACCESS_HOOK_LOAD_MODULE,
++ [PA_COMMAND_UNLOAD_MODULE] = PA_ACCESS_HOOK_UNLOAD_MODULE,
++
++ [PA_COMMAND_GET_CLIENT_INFO] = PA_ACCESS_HOOK_GET_CLIENT_INFO,
++ [PA_COMMAND_GET_CLIENT_INFO_LIST] = PA_ACCESS_HOOK_GET_CLIENT_INFO,
++ [PA_COMMAND_KILL_CLIENT] = PA_ACCESS_HOOK_KILL_CLIENT,
++
++ [PA_COMMAND_GET_CARD_INFO] = PA_ACCESS_HOOK_GET_CARD_INFO,
++ [PA_COMMAND_GET_CARD_INFO_LIST] = PA_ACCESS_HOOK_GET_CARD_INFO,
++ [PA_COMMAND_SET_CARD_PROFILE] = PA_ACCESS_HOOK_SET_CARD_PROFILE,
++ [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = PA_ACCESS_HOOK_SET_PORT_LATENCY_OFFSET,
++
++ [PA_COMMAND_GET_SINK_INPUT_INFO] = PA_ACCESS_HOOK_GET_SINK_INPUT_INFO,
++ [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = PA_ACCESS_HOOK_GET_SINK_INPUT_INFO,
++ [PA_COMMAND_MOVE_SINK_INPUT] = PA_ACCESS_HOOK_MOVE_SINK_INPUT,
++ [PA_COMMAND_SET_SINK_INPUT_VOLUME] = PA_ACCESS_HOOK_SET_SINK_INPUT_VOLUME,
++ [PA_COMMAND_SET_SINK_INPUT_MUTE] = PA_ACCESS_HOOK_SET_SINK_INPUT_MUTE,
++ [PA_COMMAND_KILL_SINK_INPUT] = PA_ACCESS_HOOK_KILL_SINK_INPUT,
++
++ [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO,
++ [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = PA_ACCESS_HOOK_GET_SOURCE_OUTPUT_INFO,
++ [PA_COMMAND_MOVE_SOURCE_OUTPUT] = PA_ACCESS_HOOK_MOVE_SOURCE_OUTPUT,
++ [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_VOLUME,
++ [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = PA_ACCESS_HOOK_SET_SOURCE_OUTPUT_MUTE,
++ [PA_COMMAND_KILL_SOURCE_OUTPUT] = PA_ACCESS_HOOK_KILL_SOURCE_OUTPUT,
++
++ [PA_COMMAND_STAT] = PA_ACCESS_HOOK_STAT,
++
++ [PA_COMMAND_GET_SAMPLE_INFO] = PA_ACCESS_HOOK_GET_SAMPLE_INFO,
++ [PA_COMMAND_GET_SAMPLE_INFO_LIST] = PA_ACCESS_HOOK_GET_SAMPLE_INFO,
++
++ [PA_COMMAND_CREATE_UPLOAD_STREAM] = PA_ACCESS_HOOK_CONNECT_UPLOAD,
++ [PA_COMMAND_REMOVE_SAMPLE] = PA_ACCESS_HOOK_REMOVE_SAMPLE,
++ [PA_COMMAND_PLAY_SAMPLE] = PA_ACCESS_HOOK_PLAY_SAMPLE,
++
++ [PA_COMMAND_CREATE_PLAYBACK_STREAM] = PA_ACCESS_HOOK_CONNECT_PLAYBACK,
++ [PA_COMMAND_CREATE_RECORD_STREAM] = PA_ACCESS_HOOK_CONNECT_RECORD,
++
++ [PA_COMMAND_EXTENSION] = PA_ACCESS_HOOK_EXTENSION,
++
++ /* SERVER -> CLIENT */
++ [PA_COMMAND_SUBSCRIBE_EVENT] = PA_ACCESS_HOOK_FILTER_SUBSCRIBE_EVENT
++};
++
++typedef struct pa_protocol_native_access_data {
++ pa_access_data d;
++
++ pa_pdispatch *pd;
++ uint32_t command;
++ uint32_t tag;
++ pa_tagstruct *tc;
++ void *userdata;
++} pa_protocol_native_access_data;
++
++static void check_access_finish_cb(pa_access_data *data, bool res) {
++ pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
++ pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
++
++ if (!res) {
++ pa_pstream_send_error(c->pstream, d->tag, PA_ERR_ACCESS); \
++ goto finish;
++ }
++
++ /* call the dispatcher again, hopefully this time, the access check will
++ * fail or succeed immediately */
++ command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
++
++finish:
++ pa_xfree((char *)d->d.name);
++ if (d->pd)
++ pa_pdispatch_unref(d->pd);
++ if (d->tc)
++ pa_tagstruct_free(d->tc);
++ pa_xfree(d);
++}
++
++static pa_hook_result_t check_access(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata, uint32_t idx, pa_subscription_event_type_t event, const char *name) {
++ pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
++ pa_hook_result_t res;
++
++ if (map_table[command]) {
++ pa_protocol_native_access_data *data;
++
++ data = pa_xnew0 (pa_protocol_native_access_data, 1);
++ data->d.client_index = c->client->index;
++ data->d.object_index = idx;
++ data->d.event = event;
++ data->d.name = name;
++ data->d.hook = map_table[command];
++
++ res = pa_hook_fire(&c->protocol->core->access[data->d.hook], data);
++ if (res == PA_HOOK_CANCEL) {
++ /* async */
++ data->d.name = pa_xstrdup(name);
++ data->d.async_finish_cb = check_access_finish_cb;
++ data->pd = pd ? pa_pdispatch_ref (pd) : NULL;
++ data->command = command;
++ data->tag = tag;
++ data->tc = t ? pa_tagstruct_copy (t) : NULL;
++ data->userdata = userdata;
++ } else {
++ pa_xfree(data);
++ }
++ } else
++ res = PA_HOOK_OK;
++
++ return res;
++}
diff --git a/debian/patches/0409-Trust-store-patch.patch b/debian/patches/0409-Trust-store-patch.patch
new file mode 100644
index 0000000..bed2290
--- /dev/null
+++ b/debian/patches/0409-Trust-store-patch.patch
@@ -0,0 +1,627 @@
+From ff36148e002232842ea0f07b148e5844c5d44ceb Mon Sep 17 00:00:00 2001
+From: David Henningsson <david.henningsson at canonical.com>
+Date: Wed, 22 Jul 2015 16:37:19 +0200
+Subject: [PATCH 4/5] Trust-store patch
+
+...includes some fixes elsewhere as well.
+
+Signed-off-by: David Henningsson <david.henningsson at canonical.com>
+---
+ configure.ac | 15 ++
+ src/Makefile.am | 24 +++
+ src/modules/trust-store/module-trust-store.c | 221 +++++++++++++++++++++++++++
+ src/modules/trust-store/truststore.cc | 74 +++++++++
+ src/modules/trust-store/truststore.h | 41 +++++
+ src/pulsecore/client.c | 6 +-
+ src/pulsecore/client.h | 4 +
+ src/pulsecore/creds.h | 1 +
+ src/pulsecore/iochannel.c | 2 +
+ src/pulsecore/protocol-native.c | 13 ++
+ src/pulsecore/tagstruct.c | 1 +
+ src/tests/connect-stress.c | 4 +-
+ 12 files changed, 399 insertions(+), 7 deletions(-)
+ create mode 100644 src/modules/trust-store/module-trust-store.c
+ create mode 100644 src/modules/trust-store/truststore.cc
+ create mode 100644 src/modules/trust-store/truststore.h
+
+Index: pulseaudio/configure.ac
+===================================================================
+--- pulseaudio.orig/configure.ac 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/configure.ac 2015-08-27 15:41:43.815252328 +0200
+@@ -1384,6 +1384,19 @@
+ [HAVE_ADRIAN_EC=1])
+ AM_CONDITIONAL([HAVE_ADRIAN_EC], [test "x$HAVE_ADRIAN_EC" = "x1"])
+
++# Ubuntu touch trust store
++
++AC_ARG_ENABLE([trust-store],
++ AS_HELP_STRING([--enable-trust-store], [Enable Ubuntu touch trust store]))
++
++AS_IF([test "x$enable_trust_store" != "xno"],
++ [PKG_CHECK_MODULES(TRUST_STORE, [ trust-store ], [HAVE_TRUST_STORE=1], [HAVE_TRUST_STORE=0])],
++ [HAVE_WEBRTC=0])
++
++AS_IF([test "x$enable_trust_store" = "xyes" && test "x$HAVE_TRUST_STORE" = "x0"],
++ [AC_MSG_ERROR([*** Ubuntu touch trust store library not found])])
++
++AM_CONDITIONAL([HAVE_TRUST_STORE], [test "x$HAVE_TRUST_STORE" = "x1"])
+
+
+ ###################################
+@@ -1544,6 +1557,7 @@
+ AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"], ENABLE_ADRIAN_EC=yes, ENABLE_ADRIAN_EC=no)
+ AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no)
+ AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no)
++AS_IF([test "x$HAVE_TRUST_STORE" = "x1"], ENABLE_TRUST_STORE=yes, ENABLE_TRUST_STORE=no)
+ AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no)
+ AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no)
+ AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no)
+@@ -1606,6 +1620,7 @@
+ Enable Adrian echo canceller: ${ENABLE_ADRIAN_EC}
+ Enable speex (resampler, AEC): ${ENABLE_SPEEX}
+ Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
++ Enable Ubuntu trust store: ${ENABLE_TRUST_STORE}
+ Enable gcov coverage: ${ENABLE_GCOV}
+ Enable unit tests: ${ENABLE_TESTS}
+ Database
+Index: pulseaudio/src/Makefile.am
+===================================================================
+--- pulseaudio.orig/src/Makefile.am 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/Makefile.am 2015-08-27 16:41:19.000000000 +0200
+@@ -1064,6 +1064,10 @@
+ modlibexec_LTLIBRARIES += libwebrtc-util.la
+ endif
+
++if HAVE_TRUST_STORE
++modlibexec_LTLIBRARIES += libtruststore-util.la
++endif
++
+ if HAVE_ESOUND
+ modlibexec_LTLIBRARIES += \
+ libprotocol-esound.la
+@@ -1188,6 +1192,11 @@
+ module-filter-heuristics.la \
+ module-role-ducking.la
+
++if HAVE_TRUST_STORE
++modlibexec_LTLIBRARIES += \
++ module-trust-store.la
++endif
++
+ if HAVE_ESOUND
+ modlibexec_LTLIBRARIES += \
+ module-esound-protocol-tcp.la \
+@@ -1513,6 +1522,7 @@
+ module-intended-roles-symdef.h \
+ module-suspend-on-idle-symdef.h \
+ module-echo-cancel-symdef.h \
++ module-trust-store-symdef.h \
+ module-hal-detect-symdef.h \
+ module-udev-detect-symdef.h \
+ module-systemd-login-symdef.h \
+@@ -2103,6 +2113,20 @@
+ module_echo_cancel_la_LIBADD += libwebrtc-util.la
+ endif
+
++if HAVE_TRUST_STORE
++# Separate helper library to keep C and C++ code apart, like we do for webrtc
++libtruststore_util_la_SOURCES = modules/trust-store/truststore.cc
++libtruststore_util_la_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 $(SERVER_CFLAGS) $(TRUST_STORE_CFLAGS) \
++ $(DBUS_CFLAGS) -DHAVE_TRUST_STORE=1
++libtruststore_util_la_LIBADD = libpulsecore- at PA_MAJORMINOR@.la $(TRUST_STORE_LIBS) $(DBUS_LIBS)
++libtruststore_util_la_LDFLAGS = -avoid-version
++
++module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
++module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
++module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
++module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
++endif
++
+ # RTP modules
+ module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
+ module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)
+Index: pulseaudio/src/modules/trust-store/module-trust-store.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pulseaudio/src/modules/trust-store/module-trust-store.c 2015-08-27 16:47:51.491242361 +0200
+@@ -0,0 +1,225 @@
++/***
++ This file is part of PulseAudio.
++
++ Copyright 2015 Canonical Ltd.
++ Written by David Henningsson <david.henningsson at canonical.com>
++
++ PulseAudio is free software; you can redistribute it and/or modify
++ it under the terms of the GNU Lesser General Public License as published
++ by the Free Software Foundation; either version 2.1 of the License,
++ or (at your option) any later version.
++
++ PulseAudio 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 Lesser General Public License
++ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
++***/
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <pulsecore/i18n.h>
++#include <pulsecore/core.h>
++#include <pulsecore/module.h>
++#include <pulse/xmalloc.h>
++#include <pulsecore/fdsem.h>
++#include <pulsecore/thread.h>
++#include <pulsecore/core-util.h>
++#include <pulse/mainloop-api.h>
++
++#include "module-trust-store-symdef.h"
++
++PA_MODULE_AUTHOR("David Henningsson");
++PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration");
++PA_MODULE_VERSION(PACKAGE_VERSION);
++PA_MODULE_LOAD_ONCE(true);
++
++#include "truststore.h"
++
++#define REQUEST_GRANTED 1
++#define REQUEST_DENIED -1
++#define REQUEST_PENDING 0
++
++struct userdata;
++
++struct per_client {
++ uint32_t index;
++ char *appname;
++ uid_t uid;
++ pid_t pid;
++ struct userdata *userdata;
++ pa_dynarray *pending_requests;
++ pa_atomic_t result;
++};
++
++struct userdata {
++ pa_core *core;
++ pa_trust_store *ts;
++ pa_hashmap *per_clients;
++ pa_thread *thread;
++ pa_fdsem *fdsem;
++ pa_io_event *io_event;
++ pa_hook_slot *connect_hook_slot;
++};
++
++static struct per_client *per_client_new(struct userdata *u, uint32_t client_index) {
++ struct per_client *pc;
++ pa_client *client = pa_idxset_get_by_index(u->core->clients, client_index);
++
++ pa_assert(client);
++ if (!client->creds_valid) {
++ pa_log_warn("Client %d has no creds, cannot authenticate", client_index);
++ return NULL;
++ }
++
++ pc = pa_xnew0(struct per_client, 1);
++ // TODO: Do we need something else than the application name here -
++ // the application can probably spoof it
++ pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
++ pc->index = client_index;
++ pc->uid = client->creds.uid;
++ pc->pid = client->creds.pid;
++ pc->pending_requests = pa_dynarray_new(NULL);
++ pc->userdata = u;
++
++ pa_hashmap_put(u->per_clients, (void *) (size_t) client_index, pc);
++
++ return pc;
++}
++
++static void per_client_free_from_hashmap(void *data) {
++ struct per_client *pc = data;
++ if (!pc)
++ return;
++ pa_xfree(pc->appname);
++ pa_dynarray_free(pc->pending_requests);
++ pa_xfree(pc);
++}
++
++static void thread_func(void *data) {
++ struct per_client *pc = data;
++
++ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
++ _("%1% wants to record audio."));
++
++ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
++ pa_fdsem_post(pc->userdata->fdsem);
++}
++
++static void check_queue(struct userdata *u) {
++ struct per_client *pc;
++ void *dummy;
++
++ pa_log_debug("Checking queue, size: %d, thread object: %s",
++ pa_hashmap_size(u->per_clients), pa_yes_no(u->thread));
++ if (u->thread) {
++ pa_access_data *ad;
++ unsigned i;
++ int result;
++ pc = pa_thread_get_data(u->thread);
++ result = pa_atomic_load(&pc->result);
++ if (result == REQUEST_PENDING)
++ return; /* Still processing */
++ pa_thread_free(u->thread);
++ u->thread = NULL;
++
++ pa_log_debug("Letting client %d (%s) know the result (%s)",
++ pc->index, pc->appname, result == REQUEST_GRANTED ? "granted" : "rejected");
++ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) {
++ ad->async_finish_cb(ad, result == REQUEST_GRANTED);
++ }
++ pa_hashmap_remove(u->per_clients, (void*) (size_t) pc->index);
++ }
++
++ /* Find a client that needs asking */
++ PA_HASHMAP_FOREACH(pc, u->per_clients, dummy) {
++ if (u->thread)
++ return;
++ pa_assert(pa_atomic_load(&pc->result) == REQUEST_PENDING);
++ pa_log_debug("Starting thread to ask about client %d (%s)", pc->index,
++ pc->appname);
++ u->thread = pa_thread_new("trust-store", thread_func, pc);
++ }
++}
++
++static void check_fdsem(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t ee,
++ void *userdata) {
++ struct userdata *u = userdata;
++ pa_fdsem_after_poll(u->fdsem);
++ check_queue(u);
++ pa_fdsem_before_poll(u->fdsem);
++}
++
++static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) {
++ struct per_client *pc = pa_hashmap_get(u->per_clients, (void*) (size_t) d->client_index);
++ int r;
++ if (!pc)
++ pc = per_client_new(u, d->client_index);
++
++ r = pa_atomic_load(&pc->result);
++ pa_log_debug("Checking permission to record for client %d (%s) ", d->client_index,
++ r == REQUEST_GRANTED ? "granted" : r != REQUEST_PENDING ? "rejected" : "unknown");
++ if (r == REQUEST_GRANTED) return PA_HOOK_OK;
++ if (r != REQUEST_PENDING) return PA_HOOK_STOP;
++
++ pa_dynarray_append(pc->pending_requests, d);
++ check_queue(u);
++ return PA_HOOK_CANCEL;
++}
++
++/* Test code - remove from final product */
++static void test(struct userdata *u) {
++ uint32_t dummy;
++ pa_client *client;
++
++ PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
++ if (client->creds_valid)
++ pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
++ client->creds.pid, "%1% wants to eat your laundry.");
++ }
++}
++
++int pa__init(pa_module *m) {
++ struct userdata *u;
++ pa_trust_store *ts = pa_trust_store_new();
++ if (ts == NULL)
++ return -1;
++ u = pa_xnew0(struct userdata, 1);
++ u->ts = ts;
++ u->core = m->core;
++ u->per_clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func,
++ NULL, per_client_free_from_hashmap);
++ m->userdata = u;
++ u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD],
++ PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u);
++
++ pa_assert_se(u->fdsem = pa_fdsem_new());
++ pa_assert_se(u->io_event = m->core->mainloop->io_new(m->core->mainloop,
++ pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
++ pa_fdsem_before_poll(u->fdsem);
++
++ test(u);
++ return 0;
++}
++
++void pa__done(pa_module *m) {
++ struct userdata *u = m->userdata;
++ if (u) {
++ if (u->connect_hook_slot)
++ pa_hook_slot_free(u->connect_hook_slot);
++ if (u->thread)
++ pa_thread_free(u->thread);
++ if (u->io_event)
++ m->core->mainloop->io_free(u->io_event);
++ if (u->fdsem)
++ pa_fdsem_free(u->fdsem);
++ if (u->per_clients)
++ pa_hashmap_free(u->per_clients);
++ if (u->ts)
++ pa_trust_store_free(u->ts);
++ pa_xfree(u);
++ }
++}
+Index: pulseaudio/src/modules/trust-store/truststore.cc
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pulseaudio/src/modules/trust-store/truststore.cc 2015-08-27 16:41:21.000000000 +0200
+@@ -0,0 +1,74 @@
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <memory>
++#include <core/dbus/bus.h>
++#include <core/trust/dbus_agent.h>
++#include <core/trust/agent.h>
++
++#include <pulse/cdecl.h>
++
++PA_C_DECL_BEGIN
++#include <pulsecore/core-util.h>
++#include <pulse/xmalloc.h>
++#include <pulsecore/log.h>
++
++#include "truststore.h"
++PA_C_DECL_END
++
++class TrustStore {
++public:
++ std::shared_ptr<core::trust::Agent> agent;
++};
++
++pa_trust_store* pa_trust_store_new() {
++ try {
++ auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
++ auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
++ auto ts = new TrustStore();
++ ts->agent = agent;
++ return (pa_trust_store *) ts;
++ } catch(const std::exception &e) {
++ pa_log_error("Could not create Ubuntu touch trust store connection: %s",
++ e.what());
++ } catch(...) {
++ pa_log_error("Could not create Ubuntu touch trust store connection");
++ return NULL;
++ }
++}
++
++void pa_trust_store_free(pa_trust_store *t) {
++ pa_assert(t != NULL);
++ auto ts = (TrustStore*) t;
++ delete ts;
++}
++
++bool pa_trust_store_check(pa_trust_store *t, const char *appname,
++ uid_t uid, pid_t pid, const char *description) {
++ auto ts = (TrustStore*) t;
++ try {
++
++ core::trust::Agent::RequestParameters params {
++ core::trust::Uid{uid},
++ core::trust::Pid{pid},
++ appname,
++ core::trust::Feature{0},
++ description
++ };
++ pa_log_debug("Asking Ubuntu touch trust store for permission (app: %s)",
++ params.application.id.c_str());
++ auto answer = ts->agent->authenticate_request_with_parameters(params);
++ if (answer == core::trust::Request::Answer::granted) {
++ pa_log_debug("Request granted.");
++ return true;
++ }
++ pa_log_info("Request denied.");
++ } catch(const std::exception &e) {
++ pa_log_error("Could not ask Ubuntu touch trust store for permission: %s",
++ e.what());
++ } catch(...) {
++ pa_log_error("Could not ask Ubuntu touch trust store for permission");
++ }
++ return false;
++}
+Index: pulseaudio/src/modules/trust-store/truststore.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ pulseaudio/src/modules/trust-store/truststore.h 2015-08-27 15:41:43.819252213 +0200
+@@ -0,0 +1,41 @@
++/***
++ This file is part of PulseAudio.
++
++ Copyright 2015 Canonical Ltd.
++ Written by David Henningsson <david.henningsson at canonical.com>
++
++ PulseAudio is free software; you can redistribute it and/or modify
++ it under the terms of the GNU Lesser General Public License as published
++ by the Free Software Foundation; either version 2.1 of the License,
++ or (at your option) any later version.
++
++ PulseAudio 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 Lesser General Public License
++ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
++***/
++
++#ifndef footruststorehfoo
++#define footruststorehfoo
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <pulsecore/creds.h>
++
++#ifdef HAVE_TRUST_STORE
++PA_C_DECL_BEGIN
++typedef struct pa_trust_store pa_trust_store;
++
++pa_trust_store* pa_trust_store_new();
++void pa_trust_store_free(pa_trust_store *ts);
++bool pa_trust_store_check(pa_trust_store *ts, const char *appname,
++ uid_t uid, pid_t pid, const char *description);
++PA_C_DECL_END
++#endif
++
++#endif
+Index: pulseaudio/src/pulsecore/client.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/client.c 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/pulsecore/client.c 2015-08-27 15:41:43.819252213 +0200
+@@ -60,7 +60,7 @@
+ if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
+ return NULL;
+
+- c = pa_xnew(pa_client, 1);
++ c = pa_xnew0(pa_client, 1);
+ c->core = core;
+ c->proplist = pa_proplist_copy(data->proplist);
+ c->driver = pa_xstrdup(pa_path_get_filename(data->driver));
+@@ -69,10 +69,6 @@
+ c->sink_inputs = pa_idxset_new(NULL, NULL);
+ c->source_outputs = pa_idxset_new(NULL, NULL);
+
+- c->userdata = NULL;
+- c->kill = NULL;
+- c->send_event = NULL;
+-
+ pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);
+
+ pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
+Index: pulseaudio/src/pulsecore/client.h
+===================================================================
+--- pulseaudio.orig/src/pulsecore/client.h 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/pulsecore/client.h 2015-08-27 15:41:43.819252213 +0200
+@@ -27,6 +27,7 @@
+ #include <pulse/proplist.h>
+ #include <pulsecore/core.h>
+ #include <pulsecore/module.h>
++#include <pulsecore/creds.h>
+
+ /* Every connection to the server should have a pa_client
+ * attached. That way the user may generate a listing of all connected
+@@ -36,6 +37,9 @@
+ uint32_t index;
+ pa_core *core;
+
++ pa_creds creds;
++ bool creds_valid;
++
+ pa_proplist *proplist;
+ pa_module *module;
+ char *driver;
+Index: pulseaudio/src/pulsecore/creds.h
+===================================================================
+--- pulseaudio.orig/src/pulsecore/creds.h 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/pulsecore/creds.h 2015-08-27 15:41:43.819252213 +0200
+@@ -41,6 +41,7 @@
+ struct pa_creds {
+ gid_t gid;
+ uid_t uid;
++ pid_t pid;
+ };
+
+ /* Struct for handling ancillary data, i e, extra data that can be sent together with a message
+Index: pulseaudio/src/pulsecore/iochannel.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/iochannel.c 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/pulsecore/iochannel.c 2015-08-27 15:41:43.819252213 +0200
+@@ -323,6 +323,7 @@
+
+ u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
+
++ /* FIXME: Check whether ucred->pid should be used */
+ u->pid = getpid();
+ if (ucred) {
+ u->uid = ucred->uid;
+@@ -437,6 +438,7 @@
+
+ ancil_data->creds.gid = u.gid;
+ ancil_data->creds.uid = u.uid;
++ ancil_data->creds.pid = u.pid;
+ ancil_data->creds_valid = true;
+ }
+ else if (cmh->cmsg_type == SCM_RIGHTS) {
+Index: pulseaudio/src/pulsecore/protocol-native.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/protocol-native.c 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/pulsecore/protocol-native.c 2015-08-27 15:41:43.823252098 +0200
+@@ -2811,6 +2811,13 @@
+ do_shm = false;
+
+ #ifdef HAVE_CREDS
++ {
++ const pa_creds *creds;
++ if ((creds = pa_pdispatch_creds(pd))) {
++ c->client->creds = *creds;
++ c->client->creds_valid = true;
++ }
++ }
+ if (do_shm) {
+ /* Only enable SHM if both sides are owned by the same
+ * user. This is a security measure because otherwise data
+@@ -5623,6 +5630,7 @@
+ } pa_protocol_native_access_data;
+
+ static void check_access_finish_cb(pa_access_data *data, bool res) {
++ uint32_t command, tag;
+ pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
+ pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
+
+@@ -5631,6 +5639,11 @@
+ goto finish;
+ }
+
++ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0);
++ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0);
++ pa_assert(command == d->command);
++ pa_assert(tag == d->tag);
++
+ /* call the dispatcher again, hopefully this time, the access check will
+ * fail or succeed immediately */
+ command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
+Index: pulseaudio/src/tests/connect-stress.c
+===================================================================
+--- pulseaudio.orig/src/tests/connect-stress.c 2015-08-27 15:41:43.827251983 +0200
++++ pulseaudio/src/tests/connect-stress.c 2015-08-27 15:41:43.823252098 +0200
+@@ -63,7 +63,7 @@
+
+ static void context_state_callback(pa_context *c, void *userdata);
+
+-static void connect(const char *name, int *try) {
++static void connect2(const char *name, int *try) {
+ int ret;
+ pa_mainloop_api *api;
+
+@@ -201,7 +201,7 @@
+ streams[i] = NULL;
+
+ for (i = 0; i < NTESTS; i++) {
+- connect(bname, &i);
++ connect2(bname, &i);
+ usleep(rand() % 500000);
+ disconnect();
+ usleep(rand() % 500000);
+Index: pulseaudio/po/POTFILES.in
+===================================================================
+--- pulseaudio.orig/po/POTFILES.in 2015-08-27 10:22:25.000000000 +0200
++++ pulseaudio/po/POTFILES.in 2015-08-27 15:55:27.000097715 +0200
+@@ -23,6 +23,7 @@
+ src/modules/jack/module-jack-sink.c
+ src/modules/jack/module-jack-source.c
+ src/modules/macosx/module-coreaudio-device.c
++src/modules/trust-store/module-trust-store.c
+ src/modules/module-always-sink.c
+ src/modules/module-cli.c
+ src/modules/module-combine.c
diff --git a/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch b/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch
new file mode 100644
index 0000000..5fc4249
--- /dev/null
+++ b/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch
@@ -0,0 +1,111 @@
+From 90dbf1d25e12b9cfc86aecbd02f14a05fd5dca8c Mon Sep 17 00:00:00 2001
+From: Alfonso Sanchez-Beato <alfonso.sanchez-beato at canonical.com>
+Date: Fri, 7 Aug 2015 09:08:02 +0200
+Subject: [PATCH] Add thread to activate trust-store interface
+
+---
+ src/modules/trust-store/module-trust-store.c | 14 +-------------
+ src/modules/trust-store/truststore.cc | 19 +++++++++++++++++++
+ 2 files changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/src/modules/trust-store/module-trust-store.c b/src/modules/trust-store/module-trust-store.c
+index 5a3dd0b..0fb27e0 100644
+--- a/src/modules/trust-store/module-trust-store.c
++++ b/src/modules/trust-store/module-trust-store.c
+@@ -27,6 +27,7 @@
+ #include <pulsecore/fdsem.h>
+ #include <pulsecore/thread.h>
+ #include <pulsecore/core-util.h>
++#include <pulsecore/dynarray.h>
+ #include <pulse/mainloop-api.h>
+
+ #include "module-trust-store-symdef.h"
+@@ -168,18 +169,6 @@ static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, st
+ return PA_HOOK_CANCEL;
+ }
+
+-/* Test code - remove from final product */
+-static void test(struct userdata *u) {
+- uint32_t dummy;
+- pa_client *client;
+-
+- PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
+- if (client->creds_valid)
+- pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
+- client->creds.pid, "%1% wants to eat your laundry.");
+- }
+-}
+-
+ int pa__init(pa_module *m) {
+ struct userdata *u;
+ pa_trust_store *ts = pa_trust_store_new();
+@@ -199,7 +188,6 @@ int pa__init(pa_module *m) {
+ pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
+ pa_fdsem_before_poll(u->fdsem);
+
+- test(u);
+ return 0;
+ }
+
+diff --git a/src/modules/trust-store/truststore.cc b/src/modules/trust-store/truststore.cc
+index ee09038..8645ce5 100644
+--- a/src/modules/trust-store/truststore.cc
++++ b/src/modules/trust-store/truststore.cc
+@@ -4,6 +4,7 @@
+
+ #include <memory>
+ #include <core/dbus/bus.h>
++#include <core/dbus/asio/executor.h>
+ #include <core/trust/dbus_agent.h>
+ #include <core/trust/agent.h>
+
+@@ -13,6 +14,7 @@ PA_C_DECL_BEGIN
+ #include <pulsecore/core-util.h>
+ #include <pulse/xmalloc.h>
+ #include <pulsecore/log.h>
++#include <pulsecore/thread.h>
+
+ #include "truststore.h"
+ PA_C_DECL_END
+@@ -20,14 +22,27 @@ PA_C_DECL_END
+ class TrustStore {
+ public:
+ std::shared_ptr<core::trust::Agent> agent;
++ std::shared_ptr<core::dbus::Bus> bus;
++ pa_thread *thread;
+ };
+
++static void thread_func(void *data) {
++ class TrustStore *ts = (class TrustStore *) data;
++
++ ts->bus->run();
++}
++
+ pa_trust_store* pa_trust_store_new() {
+ try {
+ auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
++ bus->install_executor(core::dbus::asio::make_executor(bus));
++
+ auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
+ auto ts = new TrustStore();
+ ts->agent = agent;
++ ts->bus = bus;
++ ts->thread = pa_thread_new("trust-store-bus", thread_func, ts);
++
+ return (pa_trust_store *) ts;
+ } catch(const std::exception &e) {
+ pa_log_error("Could not create Ubuntu touch trust store connection: %s",
+@@ -41,6 +56,10 @@ pa_trust_store* pa_trust_store_new() {
+ void pa_trust_store_free(pa_trust_store *t) {
+ pa_assert(t != NULL);
+ auto ts = (TrustStore*) t;
++ if (ts->thread) {
++ ts->bus->stop();
++ pa_thread_free(ts->thread);
++ }
+ delete ts;
+ }
+
+--
+2.1.4
+
diff --git a/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch b/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch
new file mode 100644
index 0000000..459d9a8
--- /dev/null
+++ b/debian/patches/0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch
@@ -0,0 +1,62 @@
+From 360cb6550e6558606091ac8c64028ed9872ba6f9 Mon Sep 17 00:00:00 2001
+From: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
+Date: Wed, 7 Jan 2015 16:56:50 +0200
+Subject: [PATCH 4/4] dynarray: Add PA_DYNARRAY_FOREACH
+
+The PA_DYNARRAY_FOREACH macro requires that pa_dynarray_get() returns
+NULL if the index is out of bounds.
+---
+ src/pulsecore/dynarray.c | 4 +++-
+ src/pulsecore/dynarray.h | 5 +++++
+ src/pulsecore/tokenizer.c | 3 ---
+ 3 files changed, 8 insertions(+), 4 deletions(-)
+
+Index: pulseaudio/src/pulsecore/dynarray.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/dynarray.c 2015-08-27 17:22:56.068175130 +0200
++++ pulseaudio/src/pulsecore/dynarray.c 2015-08-27 17:22:56.060175027 +0200
+@@ -72,7 +72,9 @@
+
+ void *pa_dynarray_get(pa_dynarray *array, unsigned i) {
+ pa_assert(array);
+- pa_assert(i < array->n_entries);
++
++ if (i >= array->n_entries)
++ return NULL;
+
+ return array->data[i];
+ }
+Index: pulseaudio/src/pulsecore/dynarray.h
+===================================================================
+--- pulseaudio.orig/src/pulsecore/dynarray.h 2015-08-27 17:22:56.068175130 +0200
++++ pulseaudio/src/pulsecore/dynarray.h 2015-08-27 17:22:56.060175027 +0200
+@@ -46,6 +46,8 @@
+ void pa_dynarray_free(pa_dynarray *array);
+
+ void pa_dynarray_append(pa_dynarray *array, void *p);
++
++/* Returns the element at index i, or NULL if i is out of bounds. */
+ void *pa_dynarray_get(pa_dynarray *array, unsigned i);
+
+ /* Returns the removed item, or NULL if the array is empty. */
+@@ -53,4 +55,7 @@
+
+ unsigned pa_dynarray_size(pa_dynarray *array);
+
++#define PA_DYNARRAY_FOREACH(elem, array, idx) \
++ for ((idx) = 0; ((elem) = pa_dynarray_get(array, idx)); (idx)++)
++
+ #endif
+Index: pulseaudio/src/pulsecore/tokenizer.c
+===================================================================
+--- pulseaudio.orig/src/pulsecore/tokenizer.c 2015-08-27 17:22:56.068175130 +0200
++++ pulseaudio/src/pulsecore/tokenizer.c 2015-08-27 17:22:56.060175027 +0200
+@@ -78,8 +78,5 @@
+
+ pa_assert(a);
+
+- if (i >= pa_dynarray_size(a))
+- return NULL;
+-
+ return pa_dynarray_get(a, i);
+ }
diff --git a/debian/patches/0417-increase-timeout-check-apparmor.patch b/debian/patches/0417-increase-timeout-check-apparmor.patch
new file mode 100644
index 0000000..5dd2c8a
--- /dev/null
+++ b/debian/patches/0417-increase-timeout-check-apparmor.patch
@@ -0,0 +1,92 @@
+--- a/src/modules/trust-store/module-trust-store.c
++++ b/src/modules/trust-store/module-trust-store.c
+@@ -31,6 +31,8 @@
+ #include <pulsecore/dynarray.h>
+ #include <pulse/mainloop-api.h>
+
++#include <sys/apparmor.h>
++
+ #include "module-trust-store-symdef.h"
+
+ PA_MODULE_AUTHOR("David Henningsson");
+@@ -76,9 +78,37 @@
+ }
+
+ pc = pa_xnew0(struct per_client, 1);
+- // TODO: Do we need something else than the application name here -
+- // the application can probably spoof it
+- pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
++
++ pa_log_info("Client application name is: '%s'", pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
++
++ // ask apparmor about the context of the client, later this will be used to decide if the
++ // app should be or not using the trust store
++
++ if (aa_is_enabled()) {
++ char *context = NULL;
++ char *mode = NULL;
++
++ /* XXX: The mode string is *NOT* be freed since it forms
++ * part of the allocation returned in context.
++ *
++ * See aa_gettaskcon(2) for details.
++ */
++ if (aa_gettaskcon (client->creds.pid, &context, &mode) >= 0) {
++ pc->appname = pa_xstrdup(context);
++ pa_log_info("Client apparmor profile is: '%s'", context);
++ } else {
++ pa_log_error("AppArmo profile could not be retrieved.");
++ }
++
++ if (context)
++ free(context);
++
++ } else {
++ // while we do leave the appname as empty if we fail, if apparmor is not present we should
++ // assume that the app is not confined
++ pc->appname = pa_xstrdup("unconfined");
++ }
++
+ pc->index = client_index;
+ pc->uid = client->creds.uid;
+ pc->pid = client->creds.pid;
+@@ -102,10 +132,25 @@
+ static void thread_func(void *data) {
+ struct per_client *pc = data;
+
+- bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
+- _("%1% wants to record audio."));
++ // there are 3 possible values for the app name that we will consider at this point
++ // * empty string: there was an error when retrieving the value and therefore we will
++ // automatically deny access
++ // * uncofined: the app is unconfined and therefore we will automatically grant access
++ // * appname: we need the user to decide what to do.
++
++ if (pc->appname == NULL) {
++ pa_log_info("Client apparmor could not retrieved.");
++ pa_atomic_store(&pc->result, REQUEST_DENIED);
++ } else if (pa_streq(pc->appname, "unconfined")) {
++ pa_log_info("Conected client is unconfined.");
++ pa_atomic_store(&pc->result, REQUEST_GRANTED);
++ } else {
++ pa_log_info("User needs to authorize the application..");
++ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
++ _("%1% wants to record audio."));
++ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
++ }
+
+- pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
+ pa_fdsem_post(pc->userdata->fdsem);
+ }
+
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -2122,7 +2122,7 @@
+ libtruststore_util_la_LDFLAGS = -avoid-version
+
+ module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
+-module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
++module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor
+ module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
+ module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
+ endif
diff --git a/debian/patches/series b/debian/patches/series
index 373b53c..f14c4ca 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -30,3 +30,13 @@
0309-resampler-Allow-disabling-the-LFE-filter-by-setting-.patch
0310-resampler-Rename-lfe_filter_required-to-lfe_remixed.patch
0311-tests-add-tolerant-variation-for-comparing-the-rewin.patch
+
+# Ubuntu touch: support for trust-store
+0406-tagstruct-add-copy-method.patch
+0407-access-Add-access-control-hooks.patch
+0408-protocol-native-add-access-checks.patch
+0409-Trust-store-patch.patch
+0410-Add-thread-to-activate-trust-store-interface.patch
+0415-dynarray-Add-PA_DYNARRAY_FOREACH.patch
+0417-increase-timeout-check-apparmor.patch
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-pulseaudio/pulseaudio.git
More information about the pkg-pulseaudio-devel
mailing list