[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