Merge ~ubuntu-audio-dev/pulseaudio:snap-policy-bionic into ~ubuntu-audio-dev/pulseaudio:ubuntu-bionic

Proposed by James Henstridge
Status: Merged
Merged at revision: 635d02e2aabf13996cebf97de46ffce87d99ee5c
Proposed branch: ~ubuntu-audio-dev/pulseaudio:snap-policy-bionic
Merge into: ~ubuntu-audio-dev/pulseaudio:ubuntu-bionic
Diff against target: 1633 lines (+556/-229)
9 files modified
debian/changelog (+16/-0)
debian/control (+1/-0)
debian/patches/0409-pa-client-peer-credentials.patch (+104/-0)
debian/patches/0700-modules-add-snappy-policy-module.patch (+400/-119)
debian/patches/0701-enable-snap-policy-module.patch (+30/-0)
debian/patches/series (+3/-6)
debian/pulseaudio.install (+1/-1)
debian/rules (+1/-1)
dev/null (+0/-102)
Reviewer Review Type Date Requested Status
Ubuntu Audio Development Team Pending
Review via email: mp+353962@code.launchpad.net

Commit message

Backport the snap policy module changes to Bionic.

Description of the change

This is a backport of the changes in Cosmic's pulseaudio 1:12.2-0ubuntu2 and 1:12.2-0ubuntu3.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/debian/changelog b/debian/changelog
index d7ba18f..56cbc22 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,19 @@
1pulseaudio (1:11.1-1ubuntu7.5) bionic; urgency=medium
2
3 * Update snap policy to make access to audio recording conditional on
4 plugging the "pulseaudio" or "audio-record" interfaces (LP: #1781428):
5 - 0700-modules-add-snappy-policy-module.patch: rewrite to query
6 snapd for the client's plugged interfaces.
7 - 0701-enable-snap-policy-module.patch: enable the module in the
8 default configuration.
9 - Build depend on libsnapd-glib-dev.
10 * Remove module-trust-store patch set:
11 - 0409-Trust-store-patch.patch: trimmed down to pulsecore changes.
12 - 0410-Add-thread-to-activate-trust-store-interface.patch: removed.
13 - 0417-increase-timeout-check-apparmor.patch: removed.
14
15 -- James Henstridge <james.henstridge@canonical.com> Wed, 05 Nov 2019 17:16:25 +0800
16
1pulseaudio (1:11.1-1ubuntu7.4) bionic; urgency=medium17pulseaudio (1:11.1-1ubuntu7.4) bionic; urgency=medium
218
3 [Hui Wang]19 [Hui Wang]
diff --git a/debian/control b/debian/control
index 2d9d9a9..a226566 100644
--- a/debian/control
+++ b/debian/control
@@ -29,6 +29,7 @@ Build-Depends: debhelper (>= 10),
29 libltdl-dev (>= 2.2.6a-2),29 libltdl-dev (>= 2.2.6a-2),
30 liborc-0.4-dev (>= 1:0.4.11),30 liborc-0.4-dev (>= 1:0.4.11),
31 libsamplerate0-dev,31 libsamplerate0-dev,
32 libsnapd-glib-dev (>= 1.44),
32 libsndfile1-dev (>= 1.0.20),33 libsndfile1-dev (>= 1.0.20),
33 libspeexdsp-dev (>= 1.2~rc1),34 libspeexdsp-dev (>= 1.2~rc1),
34 libssl-dev,35 libssl-dev,
diff --git a/debian/patches/0409-Trust-store-patch.patch b/debian/patches/0409-Trust-store-patch.patch
35deleted file mode 10064436deleted file mode 100644
index 60277af..0000000
--- a/debian/patches/0409-Trust-store-patch.patch
+++ /dev/null
@@ -1,582 +0,0 @@
1From ff36148e002232842ea0f07b148e5844c5d44ceb Mon Sep 17 00:00:00 2001
2From: David Henningsson <david.henningsson@canonical.com>
3Date: Wed, 22 Jul 2015 16:37:19 +0200
4Subject: [PATCH 4/5] Trust-store patch
5
6...includes some fixes elsewhere as well.
7
8Signed-off-by: David Henningsson <david.henningsson@canonical.com>
9---
10 configure.ac | 15 ++
11 src/Makefile.am | 24 +++
12 src/modules/trust-store/module-trust-store.c | 221 +++++++++++++++++++++++++++
13 src/modules/trust-store/truststore.cc | 74 +++++++++
14 src/modules/trust-store/truststore.h | 41 +++++
15 src/pulsecore/client.h | 4 +
16 src/pulsecore/creds.h | 1 +
17 src/pulsecore/iochannel.c | 2 +
18 src/pulsecore/protocol-native.c | 13 ++
19 src/pulsecore/tagstruct.c | 1 +
20 12 files changed, 399 insertions(+), 7 deletions(-)
21 create mode 100644 src/modules/trust-store/module-trust-store.c
22 create mode 100644 src/modules/trust-store/truststore.cc
23 create mode 100644 src/modules/trust-store/truststore.h
24
25Index: pulseaudio/configure.ac
26===================================================================
27--- pulseaudio.orig/configure.ac
28+++ pulseaudio/configure.ac
29@@ -1413,6 +1413,19 @@ AS_IF([test "x$ax_pthread_ok" = "xyes"],
30 AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
31
32
33+# Ubuntu touch trust store
34+
35+AC_ARG_ENABLE([trust-store],
36+ AS_HELP_STRING([--enable-trust-store], [Enable Ubuntu touch trust store]))
37+
38+AS_IF([test "x$enable_trust_store" != "xno"],
39+ [PKG_CHECK_MODULES(TRUST_STORE, [ trust-store ], [HAVE_TRUST_STORE=1], [HAVE_TRUST_STORE=0])],
40+ [HAVE_WEBRTC=0])
41+
42+AS_IF([test "x$enable_trust_store" = "xyes" && test "x$HAVE_TRUST_STORE" = "x0"],
43+ [AC_MSG_ERROR([*** Ubuntu touch trust store library not found])])
44+
45+AM_CONDITIONAL([HAVE_TRUST_STORE], [test "x$HAVE_TRUST_STORE" = "x1"])
46
47 ###################################
48 # Output #
49@@ -1580,6 +1593,7 @@ AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"],
50 AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no)
51 AS_IF([test "x$HAVE_SOXR" = "x1"], ENABLE_SOXR=yes, ENABLE_SOXR=no)
52 AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no)
53+AS_IF([test "x$HAVE_TRUST_STORE" = "x1"], ENABLE_TRUST_STORE=yes, ENABLE_TRUST_STORE=no)
54 AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no)
55 AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no)
56 AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no)
57@@ -1643,6 +1657,7 @@ echo "
58 Enable speex (resampler, AEC): ${ENABLE_SPEEX}
59 Enable soxr (resampler): ${ENABLE_SOXR}
60 Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
61+ Enable Ubuntu trust store: ${ENABLE_TRUST_STORE}
62 Enable gcov coverage: ${ENABLE_GCOV}
63 Enable unit tests: ${ENABLE_TESTS}
64 Database
65Index: pulseaudio/src/Makefile.am
66===================================================================
67--- pulseaudio.orig/src/Makefile.am
68+++ pulseaudio/src/Makefile.am
69@@ -1097,6 +1097,10 @@ if HAVE_WEBRTC
70 modlibexec_LTLIBRARIES += libwebrtc-util.la
71 endif
72
73+if HAVE_TRUST_STORE
74+modlibexec_LTLIBRARIES += libtruststore-util.la
75+endif
76+
77 if HAVE_ESOUND
78 modlibexec_LTLIBRARIES += \
79 libprotocol-esound.la
80@@ -1226,6 +1230,11 @@ modlibexec_LTLIBRARIES += \
81 module-role-ducking.la \
82 module-allow-passthrough.la
83
84+if HAVE_TRUST_STORE
85+modlibexec_LTLIBRARIES += \
86+ module-trust-store.la
87+endif
88+
89 if HAVE_ESOUND
90 modlibexec_LTLIBRARIES += \
91 module-esound-protocol-tcp.la \
92@@ -1535,6 +1544,7 @@ SYMDEF_FILES = \
93 module-intended-roles-symdef.h \
94 module-suspend-on-idle-symdef.h \
95 module-echo-cancel-symdef.h \
96+ module-trust-store-symdef.h \
97 module-hal-detect-symdef.h \
98 module-udev-detect-symdef.h \
99 module-systemd-login-symdef.h \
100@@ -2077,6 +2087,20 @@ module_echo_cancel_la_CFLAGS += -DHAVE_W
101 module_echo_cancel_la_LIBADD += libwebrtc-util.la
102 endif
103
104+if HAVE_TRUST_STORE
105+# Separate helper library to keep C and C++ code apart, like we do for webrtc
106+libtruststore_util_la_SOURCES = modules/trust-store/truststore.cc
107+libtruststore_util_la_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 $(SERVER_CFLAGS) $(TRUST_STORE_CFLAGS) \
108+ $(DBUS_CFLAGS) -DHAVE_TRUST_STORE=1
109+libtruststore_util_la_LIBADD = libpulsecore-@PA_MAJORMINOR@.la $(TRUST_STORE_LIBS) $(DBUS_LIBS)
110+libtruststore_util_la_LDFLAGS = -avoid-version
111+
112+module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
113+module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
114+module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
115+module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
116+endif
117+
118 # RTP modules
119 module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
120 module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)
121Index: pulseaudio/src/modules/trust-store/module-trust-store.c
122===================================================================
123--- /dev/null
124+++ pulseaudio/src/modules/trust-store/module-trust-store.c
125@@ -0,0 +1,228 @@
126+/***
127+ This file is part of PulseAudio.
128+
129+ Copyright 2015 Canonical Ltd.
130+ Written by David Henningsson <david.henningsson@canonical.com>
131+
132+ PulseAudio is free software; you can redistribute it and/or modify
133+ it under the terms of the GNU Lesser General Public License as published
134+ by the Free Software Foundation; either version 2.1 of the License,
135+ or (at your option) any later version.
136+
137+ PulseAudio is distributed in the hope that it will be useful, but
138+ WITHOUT ANY WARRANTY; without even the implied warranty of
139+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
140+ General Public License for more details.
141+
142+ You should have received a copy of the GNU Lesser General Public License
143+ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
144+***/
145+#ifdef HAVE_CONFIG_H
146+#include <config.h>
147+#endif
148+
149+#include <pulsecore/i18n.h>
150+#include <pulsecore/core.h>
151+#include <pulsecore/module.h>
152+#include <pulse/xmalloc.h>
153+#include <pulsecore/fdsem.h>
154+#include <pulsecore/thread.h>
155+#include <pulsecore/core-util.h>
156+#include <pulse/mainloop-api.h>
157+
158+#include "module-trust-store-symdef.h"
159+
160+PA_MODULE_AUTHOR("David Henningsson");
161+PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration");
162+PA_MODULE_VERSION(PACKAGE_VERSION);
163+PA_MODULE_LOAD_ONCE(true);
164+
165+#include "truststore.h"
166+
167+#define REQUEST_GRANTED 1
168+#define REQUEST_DENIED -1
169+#define REQUEST_PENDING 0
170+
171+struct userdata;
172+
173+struct per_client {
174+ uint32_t index;
175+ char *appname;
176+ uid_t uid;
177+ pid_t pid;
178+ struct userdata *userdata;
179+ pa_dynarray *pending_requests;
180+ pa_atomic_t result;
181+};
182+
183+struct userdata {
184+ pa_core *core;
185+ pa_trust_store *ts;
186+ pa_hashmap *per_clients;
187+ pa_thread *thread;
188+ pa_fdsem *fdsem;
189+ pa_io_event *io_event;
190+ pa_hook_slot *connect_hook_slot;
191+};
192+
193+static struct per_client *per_client_new(struct userdata *u, uint32_t client_index) {
194+ struct per_client *pc;
195+ pa_client *client = pa_idxset_get_by_index(u->core->clients, client_index);
196+
197+ pa_assert(client);
198+ if (!client->creds_valid) {
199+ pa_log_warn("Client %d has no creds, cannot authenticate", client_index);
200+ return NULL;
201+ }
202+
203+ pc = pa_xnew0(struct per_client, 1);
204+ // TODO: Do we need something else than the application name here -
205+ // the application can probably spoof it
206+ pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
207+ pc->index = client_index;
208+ pc->uid = client->creds.uid;
209+ pc->pid = client->creds.pid;
210+ pc->pending_requests = pa_dynarray_new(NULL);
211+ pc->userdata = u;
212+
213+ pa_hashmap_put(u->per_clients, (void *) (size_t) client_index, pc);
214+
215+ return pc;
216+}
217+
218+static void per_client_free_from_hashmap(void *data) {
219+ struct per_client *pc = data;
220+ if (!pc)
221+ return;
222+ pa_xfree(pc->appname);
223+ pa_dynarray_free(pc->pending_requests);
224+ pa_xfree(pc);
225+}
226+
227+static void thread_func(void *data) {
228+ struct per_client *pc = data;
229+
230+ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
231+ /// TRANSLATORS: The app icon and name appears above this string. If the phrase
232+ /// can't be translated in this language, translate the whole sentence
233+ /// 'This app wants to record audio.'
234+ _("wants to record audio."));
235+
236+ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
237+ pa_fdsem_post(pc->userdata->fdsem);
238+}
239+
240+static void check_queue(struct userdata *u) {
241+ struct per_client *pc;
242+ void *dummy;
243+
244+ pa_log_debug("Checking queue, size: %d, thread object: %s",
245+ pa_hashmap_size(u->per_clients), pa_yes_no(u->thread));
246+ if (u->thread) {
247+ pa_access_data *ad;
248+ unsigned i;
249+ int result;
250+ pc = pa_thread_get_data(u->thread);
251+ result = pa_atomic_load(&pc->result);
252+ if (result == REQUEST_PENDING)
253+ return; /* Still processing */
254+ pa_thread_free(u->thread);
255+ u->thread = NULL;
256+
257+ pa_log_debug("Letting client %d (%s) know the result (%s)",
258+ pc->index, pc->appname, result == REQUEST_GRANTED ? "granted" : "rejected");
259+ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) {
260+ ad->async_finish_cb(ad, result == REQUEST_GRANTED);
261+ }
262+ pa_hashmap_remove(u->per_clients, (void*) (size_t) pc->index);
263+ }
264+
265+ /* Find a client that needs asking */
266+ PA_HASHMAP_FOREACH(pc, u->per_clients, dummy) {
267+ if (u->thread)
268+ return;
269+ pa_assert(pa_atomic_load(&pc->result) == REQUEST_PENDING);
270+ pa_log_debug("Starting thread to ask about client %d (%s)", pc->index,
271+ pc->appname);
272+ u->thread = pa_thread_new("trust-store", thread_func, pc);
273+ }
274+}
275+
276+static void check_fdsem(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t ee,
277+ void *userdata) {
278+ struct userdata *u = userdata;
279+ pa_fdsem_after_poll(u->fdsem);
280+ check_queue(u);
281+ pa_fdsem_before_poll(u->fdsem);
282+}
283+
284+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) {
285+ struct per_client *pc = pa_hashmap_get(u->per_clients, (void*) (size_t) d->client_index);
286+ int r;
287+ if (!pc)
288+ pc = per_client_new(u, d->client_index);
289+
290+ r = pa_atomic_load(&pc->result);
291+ pa_log_debug("Checking permission to record for client %d (%s) ", d->client_index,
292+ r == REQUEST_GRANTED ? "granted" : r != REQUEST_PENDING ? "rejected" : "unknown");
293+ if (r == REQUEST_GRANTED) return PA_HOOK_OK;
294+ if (r != REQUEST_PENDING) return PA_HOOK_STOP;
295+
296+ pa_dynarray_append(pc->pending_requests, d);
297+ check_queue(u);
298+ return PA_HOOK_CANCEL;
299+}
300+
301+/* Test code - remove from final product */
302+static void test(struct userdata *u) {
303+ uint32_t dummy;
304+ pa_client *client;
305+
306+ PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
307+ if (client->creds_valid)
308+ pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
309+ client->creds.pid, "%1% wants to eat your laundry.");
310+ }
311+}
312+
313+int pa__init(pa_module *m) {
314+ struct userdata *u;
315+ pa_trust_store *ts = pa_trust_store_new();
316+ if (ts == NULL)
317+ return -1;
318+ u = pa_xnew0(struct userdata, 1);
319+ u->ts = ts;
320+ u->core = m->core;
321+ u->per_clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func,
322+ NULL, per_client_free_from_hashmap);
323+ m->userdata = u;
324+ u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD],
325+ PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u);
326+
327+ pa_assert_se(u->fdsem = pa_fdsem_new());
328+ pa_assert_se(u->io_event = m->core->mainloop->io_new(m->core->mainloop,
329+ pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
330+ pa_fdsem_before_poll(u->fdsem);
331+
332+ test(u);
333+ return 0;
334+}
335+
336+void pa__done(pa_module *m) {
337+ struct userdata *u = m->userdata;
338+ if (u) {
339+ if (u->connect_hook_slot)
340+ pa_hook_slot_free(u->connect_hook_slot);
341+ if (u->thread)
342+ pa_thread_free(u->thread);
343+ if (u->io_event)
344+ m->core->mainloop->io_free(u->io_event);
345+ if (u->fdsem)
346+ pa_fdsem_free(u->fdsem);
347+ if (u->per_clients)
348+ pa_hashmap_free(u->per_clients);
349+ if (u->ts)
350+ pa_trust_store_free(u->ts);
351+ pa_xfree(u);
352+ }
353+}
354Index: pulseaudio/src/modules/trust-store/truststore.cc
355===================================================================
356--- /dev/null
357+++ pulseaudio/src/modules/trust-store/truststore.cc
358@@ -0,0 +1,74 @@
359+#ifdef HAVE_CONFIG_H
360+#include <config.h>
361+#endif
362+
363+#include <memory>
364+#include <core/dbus/bus.h>
365+#include <core/trust/dbus_agent.h>
366+#include <core/trust/agent.h>
367+
368+#include <pulse/cdecl.h>
369+
370+PA_C_DECL_BEGIN
371+#include <pulsecore/core-util.h>
372+#include <pulse/xmalloc.h>
373+#include <pulsecore/log.h>
374+
375+#include "truststore.h"
376+PA_C_DECL_END
377+
378+class TrustStore {
379+public:
380+ std::shared_ptr<core::trust::Agent> agent;
381+};
382+
383+pa_trust_store* pa_trust_store_new() {
384+ try {
385+ auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
386+ auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
387+ auto ts = new TrustStore();
388+ ts->agent = agent;
389+ return (pa_trust_store *) ts;
390+ } catch(const std::exception &e) {
391+ pa_log_error("Could not create Ubuntu touch trust store connection: %s",
392+ e.what());
393+ } catch(...) {
394+ pa_log_error("Could not create Ubuntu touch trust store connection");
395+ return NULL;
396+ }
397+}
398+
399+void pa_trust_store_free(pa_trust_store *t) {
400+ pa_assert(t != NULL);
401+ auto ts = (TrustStore*) t;
402+ delete ts;
403+}
404+
405+bool pa_trust_store_check(pa_trust_store *t, const char *appname,
406+ uid_t uid, pid_t pid, const char *description) {
407+ auto ts = (TrustStore*) t;
408+ try {
409+
410+ core::trust::Agent::RequestParameters params {
411+ core::trust::Uid{uid},
412+ core::trust::Pid{pid},
413+ appname,
414+ core::trust::Feature{0},
415+ description
416+ };
417+ pa_log_debug("Asking Ubuntu touch trust store for permission (app: %s)",
418+ params.application.id.c_str());
419+ auto answer = ts->agent->authenticate_request_with_parameters(params);
420+ if (answer == core::trust::Request::Answer::granted) {
421+ pa_log_debug("Request granted.");
422+ return true;
423+ }
424+ pa_log_info("Request denied.");
425+ } catch(const std::exception &e) {
426+ pa_log_error("Could not ask Ubuntu touch trust store for permission: %s",
427+ e.what());
428+ } catch(...) {
429+ pa_log_error("Could not ask Ubuntu touch trust store for permission");
430+ }
431+ return false;
432+}
433Index: pulseaudio/src/modules/trust-store/truststore.h
434===================================================================
435--- /dev/null
436+++ pulseaudio/src/modules/trust-store/truststore.h
437@@ -0,0 +1,41 @@
438+/***
439+ This file is part of PulseAudio.
440+
441+ Copyright 2015 Canonical Ltd.
442+ Written by David Henningsson <david.henningsson@canonical.com>
443+
444+ PulseAudio is free software; you can redistribute it and/or modify
445+ it under the terms of the GNU Lesser General Public License as published
446+ by the Free Software Foundation; either version 2.1 of the License,
447+ or (at your option) any later version.
448+
449+ PulseAudio is distributed in the hope that it will be useful, but
450+ WITHOUT ANY WARRANTY; without even the implied warranty of
451+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
452+ General Public License for more details.
453+
454+ You should have received a copy of the GNU Lesser General Public License
455+ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
456+***/
457+
458+#ifndef footruststorehfoo
459+#define footruststorehfoo
460+
461+#ifdef HAVE_CONFIG_H
462+#include <config.h>
463+#endif
464+
465+#include <pulsecore/creds.h>
466+
467+#ifdef HAVE_TRUST_STORE
468+PA_C_DECL_BEGIN
469+typedef struct pa_trust_store pa_trust_store;
470+
471+pa_trust_store* pa_trust_store_new();
472+void pa_trust_store_free(pa_trust_store *ts);
473+bool pa_trust_store_check(pa_trust_store *ts, const char *appname,
474+ uid_t uid, pid_t pid, const char *description);
475+PA_C_DECL_END
476+#endif
477+
478+#endif
479Index: pulseaudio/src/pulsecore/client.h
480===================================================================
481--- pulseaudio.orig/src/pulsecore/client.h
482+++ pulseaudio/src/pulsecore/client.h
483@@ -26,6 +26,7 @@
484 #include <pulse/proplist.h>
485 #include <pulsecore/core.h>
486 #include <pulsecore/module.h>
487+#include <pulsecore/creds.h>
488
489 /* Every connection to the server should have a pa_client
490 * attached. That way the user may generate a listing of all connected
491@@ -35,6 +36,9 @@ struct pa_client {
492 uint32_t index;
493 pa_core *core;
494
495+ pa_creds creds;
496+ bool creds_valid;
497+
498 pa_proplist *proplist;
499 pa_module *module;
500 char *driver;
501Index: pulseaudio/src/pulsecore/creds.h
502===================================================================
503--- pulseaudio.orig/src/pulsecore/creds.h
504+++ pulseaudio/src/pulsecore/creds.h
505@@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cms
506 struct pa_creds {
507 gid_t gid;
508 uid_t uid;
509+ pid_t pid;
510 };
511
512 /* Struct for handling ancillary data, i e, extra data that can be sent together with a message
513Index: pulseaudio/src/pulsecore/iochannel.c
514===================================================================
515--- pulseaudio.orig/src/pulsecore/iochannel.c
516+++ pulseaudio/src/pulsecore/iochannel.c
517@@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa
518
519 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
520
521+ /* FIXME: Check whether ucred->pid should be used */
522 u->pid = getpid();
523 if (ucred) {
524 u->uid = ucred->uid;
525@@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_dat
526
527 ancil_data->creds.gid = u.gid;
528 ancil_data->creds.uid = u.uid;
529+ ancil_data->creds.pid = u.pid;
530 ancil_data->creds_valid = true;
531 }
532 else if (cmh->cmsg_type == SCM_RIGHTS) {
533Index: pulseaudio/src/pulsecore/protocol-native.c
534===================================================================
535--- pulseaudio.orig/src/pulsecore/protocol-native.c
536+++ pulseaudio/src/pulsecore/protocol-native.c
537@@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *p
538 do_shm = false;
539
540 #ifdef HAVE_CREDS
541+ {
542+ const pa_creds *creds;
543+ if ((creds = pa_pdispatch_creds(pd))) {
544+ c->client->creds = *creds;
545+ c->client->creds_valid = true;
546+ }
547+ }
548 if (do_shm) {
549 /* Only enable SHM if both sides are owned by the same
550 * user. This is a security measure because otherwise data
551@@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access
552 } pa_protocol_native_access_data;
553
554 static void check_access_finish_cb(pa_access_data *data, bool res) {
555+ uint32_t command, tag;
556 pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
557 pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
558
559@@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_ac
560 goto finish;
561 }
562
563+ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0);
564+ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0);
565+ pa_assert(command == d->command);
566+ pa_assert(tag == d->tag);
567+
568 /* call the dispatcher again, hopefully this time, the access check will
569 * fail or succeed immediately */
570 command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
571Index: pulseaudio/po/POTFILES.in
572===================================================================
573--- pulseaudio.orig/po/POTFILES.in
574+++ pulseaudio/po/POTFILES.in
575@@ -23,6 +23,7 @@ src/modules/jack/module-jack-sink.c
576 src/modules/jack/module-jack-source.c
577 src/modules/macosx/module-coreaudio-device.c
578 src/modules/module-allow-passthrough.c
579+src/modules/trust-store/module-trust-store.c
580 src/modules/module-always-sink.c
581 src/modules/module-cli.c
582 src/modules/module-combine.c
diff --git a/debian/patches/0409-pa-client-peer-credentials.patch b/debian/patches/0409-pa-client-peer-credentials.patch
583new file mode 1006440new file mode 100644
index 0000000..65ba9fd
--- /dev/null
+++ b/debian/patches/0409-pa-client-peer-credentials.patch
@@ -0,0 +1,104 @@
1From: David Henningsson <david.henningsson@canonical.com>
2Date: Wed, 22 Jul 2015 16:37:19 +0200
3Subject: [PATCH 4/5] Expose peer credentials on pa_client
4
5Signed-off-by: David Henningsson <david.henningsson@canonical.com>
6---
7 src/pulsecore/client.h | 4 ++++
8 src/pulsecore/creds.h | 1 +
9 src/pulsecore/iochannel.c | 2 ++
10 src/pulsecore/protocol-native.c | 13 +++++++++++++
11 4 files changed, 20 insertions(+)
12
13diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h
14index eb8173d..a038a0c 100644
15--- a/src/pulsecore/client.h
16+++ b/src/pulsecore/client.h
17@@ -26,6 +26,7 @@
18 #include <pulse/proplist.h>
19 #include <pulsecore/core.h>
20 #include <pulsecore/module.h>
21+#include <pulsecore/creds.h>
22
23 /* Every connection to the server should have a pa_client
24 * attached. That way the user may generate a listing of all connected
25@@ -35,6 +36,9 @@ struct pa_client {
26 uint32_t index;
27 pa_core *core;
28
29+ pa_creds creds;
30+ bool creds_valid;
31+
32 pa_proplist *proplist;
33 pa_module *module;
34 char *driver;
35diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h
36index 9fdbb4f..8bcf636 100644
37--- a/src/pulsecore/creds.h
38+++ b/src/pulsecore/creds.h
39@@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cmsg_ancil_data;
40 struct pa_creds {
41 gid_t gid;
42 uid_t uid;
43+ pid_t pid;
44 };
45
46 /* Struct for handling ancillary data, i e, extra data that can be sent together with a message
47diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
48index 8973375..cd0b81d 100644
49--- a/src/pulsecore/iochannel.c
50+++ b/src/pulsecore/iochannel.c
51@@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
52
53 u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
54
55+ /* FIXME: Check whether ucred->pid should be used */
56 u->pid = getpid();
57 if (ucred) {
58 u->uid = ucred->uid;
59@@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l,
60
61 ancil_data->creds.gid = u.gid;
62 ancil_data->creds.uid = u.uid;
63+ ancil_data->creds.pid = u.pid;
64 ancil_data->creds_valid = true;
65 }
66 else if (cmh->cmsg_type == SCM_RIGHTS) {
67diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
68index 67b5c7a..a2f74a0 100644
69--- a/src/pulsecore/protocol-native.c
70+++ b/src/pulsecore/protocol-native.c
71@@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
72 do_shm = false;
73
74 #ifdef HAVE_CREDS
75+ {
76+ const pa_creds *creds;
77+ if ((creds = pa_pdispatch_creds(pd))) {
78+ c->client->creds = *creds;
79+ c->client->creds_valid = true;
80+ }
81+ }
82 if (do_shm) {
83 /* Only enable SHM if both sides are owned by the same
84 * user. This is a security measure because otherwise data
85@@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access_data {
86 } pa_protocol_native_access_data;
87
88 static void check_access_finish_cb(pa_access_data *data, bool res) {
89+ uint32_t command, tag;
90 pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
91 pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
92
93@@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_access_data *data, bool res) {
94 goto finish;
95 }
96
97+ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0);
98+ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0);
99+ pa_assert(command == d->command);
100+ pa_assert(tag == d->tag);
101+
102 /* call the dispatcher again, hopefully this time, the access check will
103 * fail or succeed immediately */
104 command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
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
0deleted file mode 100644105deleted file mode 100644
index 311a0fe..0000000
--- a/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch
+++ /dev/null
@@ -1,108 +0,0 @@
1From 90dbf1d25e12b9cfc86aecbd02f14a05fd5dca8c Mon Sep 17 00:00:00 2001
2From: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
3Date: Fri, 7 Aug 2015 09:08:02 +0200
4Subject: [PATCH] Add thread to activate trust-store interface
5
6---
7 src/modules/trust-store/module-trust-store.c | 14 +-------------
8 src/modules/trust-store/truststore.cc | 19 +++++++++++++++++++
9 2 files changed, 20 insertions(+), 13 deletions(-)
10
11Index: pulseaudio/src/modules/trust-store/module-trust-store.c
12===================================================================
13--- pulseaudio.orig/src/modules/trust-store/module-trust-store.c
14+++ pulseaudio/src/modules/trust-store/module-trust-store.c
15@@ -28,6 +28,7 @@
16 #include <pulsecore/fdsem.h>
17 #include <pulsecore/thread.h>
18 #include <pulsecore/core-util.h>
19+#include <pulsecore/dynarray.h>
20 #include <pulse/mainloop-api.h>
21
22 #include "module-trust-store-symdef.h"
23@@ -173,18 +174,6 @@ static pa_hook_result_t connect_record_h
24 return PA_HOOK_CANCEL;
25 }
26
27-/* Test code - remove from final product */
28-static void test(struct userdata *u) {
29- uint32_t dummy;
30- pa_client *client;
31-
32- PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
33- if (client->creds_valid)
34- pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
35- client->creds.pid, "%1% wants to eat your laundry.");
36- }
37-}
38-
39 int pa__init(pa_module *m) {
40 struct userdata *u;
41 pa_trust_store *ts = pa_trust_store_new();
42@@ -204,7 +193,6 @@ int pa__init(pa_module *m) {
43 pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
44 pa_fdsem_before_poll(u->fdsem);
45
46- test(u);
47 return 0;
48 }
49
50Index: pulseaudio/src/modules/trust-store/truststore.cc
51===================================================================
52--- pulseaudio.orig/src/modules/trust-store/truststore.cc
53+++ pulseaudio/src/modules/trust-store/truststore.cc
54@@ -4,6 +4,7 @@
55
56 #include <memory>
57 #include <core/dbus/bus.h>
58+#include <core/dbus/asio/executor.h>
59 #include <core/trust/dbus_agent.h>
60 #include <core/trust/agent.h>
61
62@@ -13,6 +14,7 @@ PA_C_DECL_BEGIN
63 #include <pulsecore/core-util.h>
64 #include <pulse/xmalloc.h>
65 #include <pulsecore/log.h>
66+#include <pulsecore/thread.h>
67
68 #include "truststore.h"
69 PA_C_DECL_END
70@@ -20,14 +22,27 @@ PA_C_DECL_END
71 class TrustStore {
72 public:
73 std::shared_ptr<core::trust::Agent> agent;
74+ std::shared_ptr<core::dbus::Bus> bus;
75+ pa_thread *thread;
76 };
77
78+static void thread_func(void *data) {
79+ class TrustStore *ts = (class TrustStore *) data;
80+
81+ ts->bus->run();
82+}
83+
84 pa_trust_store* pa_trust_store_new() {
85 try {
86 auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
87+ bus->install_executor(core::dbus::asio::make_executor(bus));
88+
89 auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
90 auto ts = new TrustStore();
91 ts->agent = agent;
92+ ts->bus = bus;
93+ ts->thread = pa_thread_new("trust-store-bus", thread_func, ts);
94+
95 return (pa_trust_store *) ts;
96 } catch(const std::exception &e) {
97 pa_log_error("Could not create Ubuntu touch trust store connection: %s",
98@@ -41,6 +56,10 @@ pa_trust_store* pa_trust_store_new() {
99 void pa_trust_store_free(pa_trust_store *t) {
100 pa_assert(t != NULL);
101 auto ts = (TrustStore*) t;
102+ if (ts->thread) {
103+ ts->bus->stop();
104+ pa_thread_free(ts->thread);
105+ }
106 delete ts;
107 }
108
diff --git a/debian/patches/0417-increase-timeout-check-apparmor.patch b/debian/patches/0417-increase-timeout-check-apparmor.patch
109deleted file mode 1006440deleted file mode 100644
index 9571a8a..0000000
--- a/debian/patches/0417-increase-timeout-check-apparmor.patch
+++ /dev/null
@@ -1,102 +0,0 @@
1Index: pulseaudio/src/modules/trust-store/module-trust-store.c
2===================================================================
3--- pulseaudio.orig/src/modules/trust-store/module-trust-store.c
4+++ pulseaudio/src/modules/trust-store/module-trust-store.c
5@@ -31,6 +31,8 @@
6 #include <pulsecore/dynarray.h>
7 #include <pulse/mainloop-api.h>
8
9+#include <sys/apparmor.h>
10+
11 #include "module-trust-store-symdef.h"
12
13 PA_MODULE_AUTHOR("David Henningsson");
14@@ -77,9 +79,37 @@ static struct per_client *per_client_new
15 }
16
17 pc = pa_xnew0(struct per_client, 1);
18- // TODO: Do we need something else than the application name here -
19- // the application can probably spoof it
20- pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
21+
22+ pa_log_info("Client application name is: '%s'", pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
23+
24+ // ask apparmor about the context of the client, later this will be used to decide if the
25+ // app should be or not using the trust store
26+
27+ if (aa_is_enabled()) {
28+ char *context = NULL;
29+ char *mode = NULL;
30+
31+ /* XXX: The mode string is *NOT* be freed since it forms
32+ * part of the allocation returned in context.
33+ *
34+ * See aa_gettaskcon(2) for details.
35+ */
36+ if (aa_gettaskcon (client->creds.pid, &context, &mode) >= 0) {
37+ pc->appname = pa_xstrdup(context);
38+ pa_log_info("Client apparmor profile is: '%s'", context);
39+ } else {
40+ pa_log_error("AppArmo profile could not be retrieved.");
41+ }
42+
43+ if (context)
44+ free(context);
45+
46+ } else {
47+ // while we do leave the appname as empty if we fail, if apparmor is not present we should
48+ // assume that the app is not confined
49+ pc->appname = pa_xstrdup("unconfined");
50+ }
51+
52 pc->index = client_index;
53 pc->uid = client->creds.uid;
54 pc->pid = client->creds.pid;
55@@ -103,13 +133,28 @@ static void per_client_free_from_hashmap
56 static void thread_func(void *data) {
57 struct per_client *pc = data;
58
59- bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
60- /// TRANSLATORS: The app icon and name appears above this string. If the phrase
61- /// can't be translated in this language, translate the whole sentence
62- /// 'This app wants to record audio.'
63- _("wants to record audio."));
64+ // there are 3 possible values for the app name that we will consider at this point
65+ // * empty string: there was an error when retrieving the value and therefore we will
66+ // automatically deny access
67+ // * unconfined: the app is unconfined and therefore we will automatically grant access
68+ // * appname: we need the user to decide what to do.
69+
70+ if (pc->appname == NULL) {
71+ pa_log_info("Client apparmor could not retrieved.");
72+ pa_atomic_store(&pc->result, REQUEST_DENIED);
73+ } else if (pa_streq(pc->appname, "unconfined")) {
74+ pa_log_info("Connected client is unconfined.");
75+ pa_atomic_store(&pc->result, REQUEST_GRANTED);
76+ } else {
77+ pa_log_info("User needs to authorize the application..");
78+ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
79+ /// TRANSLATORS: The app icon and name appears above this string. If the phrase
80+ /// can't be translated in this language, translate the whole sentence
81+ /// 'This app wants to record audio.'
82+ _("wants to record audio."));
83+ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
84+ }
85
86- pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
87 pa_fdsem_post(pc->userdata->fdsem);
88 }
89
90Index: pulseaudio/src/Makefile.am
91===================================================================
92--- pulseaudio.orig/src/Makefile.am
93+++ pulseaudio/src/Makefile.am
94@@ -2096,7 +2096,7 @@ libtruststore_util_la_LIBADD = libpulsec
95 libtruststore_util_la_LDFLAGS = -avoid-version
96
97 module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
98-module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
99+module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor
100 module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
101 module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
102 endif
diff --git a/debian/patches/0700-modules-add-snappy-policy-module.patch b/debian/patches/0700-modules-add-snappy-policy-module.patch
index 774374d..03d61b6 100644
--- a/debian/patches/0700-modules-add-snappy-policy-module.patch
+++ b/debian/patches/0700-modules-add-snappy-policy-module.patch
@@ -1,68 +1,107 @@
1From a430ebc2271f5a07389ee25631a8ba5524371764 Mon Sep 17 00:00:00 20011From: James Henstridge <james.henstridge@canonical.com>
2From: Simon Fels <simon.fels@canonical.com>2Date: Tue, 7 Aug 2018 12:40:59 +0800
3Date: Tue, 17 May 2016 17:29:31 +02003Subject: [PATCH] modules: add snap policy module
4Subject: [PATCH] modules: add snappy policy module
54
5Forwarded: not-needed
6
7This patch allows pulseaudio to limit audio recording to snaps with
8the audio-recording interface connected. We will not pursue upstreaming
9this patch as the longer term solution will probably use PipeWire.
10
11Co-authored-by: Simon Fels <simon.fels@canonical.com>
6---12---
7 configure.ac | 18 +++++++-13 configure.ac | 17 ++
8 src/Makefile.am | 18 ++++++++14 src/Makefile.am | 13 ++
9 src/modules/module-snappy-policy.c | 94 ++++++++++++++++++++++++++++++++++++++15 src/modules/module-snap-policy.c | 384 +++++++++++++++++++++++++++++++++++++++
10 3 files changed, 129 insertions(+), 1 deletion(-)16 3 files changed, 414 insertions(+)
11 create mode 100644 src/modules/module-snappy-policy.c17 create mode 100644 src/modules/module-snap-policy.c
1218
13Index: pulseaudio/src/Makefile.am19diff --git a/configure.ac b/configure.ac
14===================================================================20index 77b5ff5..34b58ef 100644
15--- pulseaudio.orig/src/Makefile.am21--- a/configure.ac
16+++ pulseaudio/src/Makefile.am22+++ b/configure.ac
17@@ -1241,6 +1241,11 @@ modlibexec_LTLIBRARIES += \23@@ -1412,6 +1412,21 @@ AS_IF([test "x$os_is_win32" != "x1"],
24 AS_IF([test "x$ax_pthread_ok" = "xyes"],
25 AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
26
27+# Snappy support
28+
29+AC_ARG_ENABLE([snap],
30+ AS_HELP_STRING([--enable-snap], [Enable snap support]))
31+
32+have_apparmor=0
33+have_snapd_glib=0
34+AS_IF([test "x$enable_snap" != "xno"],
35+ [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [have_apparmor=1])
36+ PKG_CHECK_MODULES(SNAPD_GLIB, [snapd-glib], [have_snapd_glib=1])])
37+
38+AS_IF([test "x$enable_snap" = "xyes" && test "x$have_apparmor" = "x0" -o "x$have-snapd_glib" = "x0"],
39+ [AC_MSG_ERROR([*** Snap module dependencies missing])])
40+
41+AM_CONDITIONAL([BUILD_SNAP], [test "x$enable_snap" = "xyes"])
42
43
44 ###################################
45@@ -1588,6 +1603,7 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x$USE_PER_USER_ESOUND_SOCKET" = "x1"], EN
46 AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no)
47 AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no)
48 AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no)
49+AS_IF([test "x$enable_snap" != "xno"], ENABLE_SNAP=yes, ENABLE_SNAP=no)
50
51 echo "
52 ---{ $PACKAGE_NAME $VERSION }---
53@@ -1643,6 +1659,7 @@ echo "
54 Enable speex (resampler, AEC): ${ENABLE_SPEEX}
55 Enable soxr (resampler): ${ENABLE_SOXR}
56 Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
57+ Enable Snap support: ${ENABLE_SNAP}
58 Enable gcov coverage: ${ENABLE_GCOV}
59 Enable unit tests: ${ENABLE_TESTS}
60 Database
61diff --git a/src/Makefile.am b/src/Makefile.am
62index d49a6af..eb32f56 100644
63--- a/src/Makefile.am
64+++ b/src/Makefile.am
65@@ -1232,6 +1232,11 @@ modlibexec_LTLIBRARIES += \
18 module-esound-sink.la66 module-esound-sink.la
19 endif67 endif
20 68
21+if HAVE_APPARMOR69+if BUILD_SNAP
22+modlibexec_LTLIBRARIES += \70+modlibexec_LTLIBRARIES += \
23+ module-snappy-policy.la71+ module-snap-policy.la
24+endif72+endif
25+73+
26 # See comment at librtp.la above74 # See comment at librtp.la above
27 if !OS_IS_WIN3275 if !OS_IS_WIN32
28 modlibexec_LTLIBRARIES += \76 modlibexec_LTLIBRARIES += \
29@@ -1582,6 +1587,11 @@ SYMDEF_FILES += \77@@ -2077,6 +2082,14 @@ module_echo_cancel_la_CFLAGS += -DHAVE_WEBRTC=1
30 module-esound-sink-symdef.h78 module_echo_cancel_la_LIBADD += libwebrtc-util.la
31 endif
32
33+if HAVE_APPARMOR
34+SYMDEF_FILES += \
35+ module-snappy-policy-symdef.h
36+endif
37+
38 EXTRA_DIST += $(SYMDEF_FILES)
39 BUILT_SOURCES += $(SYMDEF_FILES) builddirs
40
41@@ -2101,6 +2111,14 @@ module_trust_store_la_LIBADD = $(MODULE_
42 module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
43 endif79 endif
44 80
45+# Snappy81+# Snappy
46+if HAVE_APPARMOR82+if BUILD_SNAP
47+module_snappy_policy_la_SOURCES = modules/module-snappy-policy.c83+module_snap_policy_la_SOURCES = modules/module-snap-policy.c
48+module_snappy_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor84+module_snap_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
49+module_snappy_policy_la_LIBADD = $(MODULE_LIBADD)85+module_snap_policy_la_LIBADD = $(MODULE_LIBADD) $(APPARMOR_LIBS) $(SNAPD_GLIB_LIBS)
50+module_snappy_policy_la_CFLAGS = $(AM_CFLAGS) -DHAVE_SNAPPY=186+module_snap_policy_la_CFLAGS = $(AM_CFLAGS) $(APPARMOR_CFLAGS) $(SNAPD_GLIB_CFLAGS) -DPA_MODULE_NAME=module_snap_policy
51+endif87+endif
52+88+
53 # RTP modules89 # RTP modules
54 module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c90 module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
55 module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)91 module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)
56Index: pulseaudio/src/modules/module-snappy-policy.c92diff --git a/src/modules/module-snap-policy.c b/src/modules/module-snap-policy.c
57===================================================================93new file mode 100644
94index 0000000..0a1f5f4
58--- /dev/null95--- /dev/null
59+++ pulseaudio/src/modules/module-snappy-policy.c96+++ b/src/modules/module-snap-policy.c
60@@ -0,0 +1,98 @@97@@ -0,0 +1,384 @@
61+/***98+/***
62+ This file is part of PulseAudio.99+ This file is part of PulseAudio.
63+100+
64+ Copyright 2016 Canonical Ltd.101+ Copyright 2018 Canonical Ltd.
65+ Written by Simon Fels <simon.fels@canonical.com>102+ Authors:
103+ Simon Fels <simon.fels@canonical.com>
104+ James Henstridge <james.henstridge@canonical.com>
66+105+
67+ PulseAudio is free software; you can redistribute it and/or modify106+ PulseAudio is free software; you can redistribute it and/or modify
68+ it under the terms of the GNU Lesser General Public License as published107+ it under the terms of the GNU Lesser General Public License as published
@@ -83,118 +122,360 @@ Index: pulseaudio/src/modules/module-snappy-policy.c
83+#endif122+#endif
84+123+
85+#include <sys/apparmor.h>124+#include <sys/apparmor.h>
86+#include <errno.h>125+#include <glib.h>
126+#include <snapd-glib/snapd-glib.h>
87+127+
88+#include <pulsecore/i18n.h>128+#include <pulsecore/asyncq.h>
89+#include <pulsecore/core.h>129+#include <pulsecore/core.h>
130+#include <pulsecore/idxset.h>
131+#include <pulsecore/hashmap.h>
90+#include <pulsecore/module.h>132+#include <pulsecore/module.h>
91+#include <pulse/xmalloc.h>133+#include <pulsecore/mutex.h>
92+#include <pulsecore/fdsem.h>
93+#include <pulsecore/thread.h>134+#include <pulsecore/thread.h>
94+#include <pulsecore/core-util.h>
95+#include <pulse/mainloop-api.h>135+#include <pulse/mainloop-api.h>
96+136+#include <pulse/xmalloc.h>
97+#include "module-snappy-policy-symdef.h"
98+137+
99+#define SNAP_LABEL_PREFIX "snap."138+#define SNAP_LABEL_PREFIX "snap."
100+#define SNAP_LABEL_PREFIX_LENGTH 5139+#define SNAP_LABEL_PREFIX_LENGTH 5
101+140+
102+PA_MODULE_AUTHOR("Simon Fels");141+PA_MODULE_AUTHOR("Canonical Ltd");
103+PA_MODULE_DESCRIPTION("Ubuntu Snappy policy management");142+PA_MODULE_DESCRIPTION("Ubuntu Snap policy management");
104+PA_MODULE_VERSION(PACKAGE_VERSION);143+PA_MODULE_VERSION(PACKAGE_VERSION);
105+PA_MODULE_LOAD_ONCE(true);144+PA_MODULE_LOAD_ONCE(true);
106+145+
146+struct per_client {
147+ struct userdata *userdata;
148+ uint32_t index;
149+ char *snap_name;
150+ pa_dynarray *pending_requests; /* of pa_access_data */
151+ bool completed;
152+ bool grant_access;
153+};
154+
107+struct userdata {155+struct userdata {
108+ pa_core *core;156+ pa_io_event *io_event;
109+ pa_hook_slot *connect_hook_slot;157+ pa_hook_slot *connect_hook_slot;
158+
159+ pa_thread *thread;
160+ pa_mutex *mutex;
161+ pa_cond *cond;
162+
163+ pa_hashmap *clients; /* int => struct per_client */
164+ pa_asyncq *results; /* of struct per_client */
165+
166+ /* Data owned by glib thread */
167+ GMainContext *main_context;
168+ GMainLoop *main_loop;
169+ GCancellable *cancellable;
170+ SnapdClient *snapd;
110+};171+};
111+172+
112+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) {173+/* ---- Code running in glib thread ---- */
113+ pa_client *client = pa_idxset_get_by_index(u->core->clients, d->client_index);174+
114+ if (!client)175+static void complete_check_access(struct per_client *pc, bool grant_access)
115+ return PA_HOOK_OK;176+{
116+177+ struct userdata *u = pc->userdata;
117+ char *label = NULL;178+
118+ char *mode = NULL;179+ pa_mutex_lock(u->mutex);
119+ if (aa_gettaskcon(client->creds.pid, &label, &mode) < 0) {180+ pc->grant_access = grant_access;
120+ pa_log_warn("Failed to retrieve apparmor security label for pid %u: %s",181+ pc->completed = true;
121+ client->creds.pid, strerror(-errno));182+ pa_asyncq_push(u->results, pc, true);
122+ return PA_HOOK_OK;183+ pa_mutex_unlock(u->mutex);
184+}
185+
186+static void get_interfaces_finished(GObject *source_object,
187+ GAsyncResult *result,
188+ gpointer user_data)
189+{
190+ struct per_client *pc = user_data;
191+ struct userdata *u = pc->userdata;
192+ bool grant_access = false;
193+ g_autoptr(GError) error = NULL;
194+ g_autoptr(GPtrArray) plugs = NULL;
195+ unsigned i;
196+
197+ if (!snapd_client_get_interfaces_finish(u->snapd, result, &plugs, NULL, &error)) {
198+ pa_log_warn("snapd_client_get_interfaces failed: %s", error->message);
199+ goto end;
200+ }
201+
202+ /* determine pc->grant_access */
203+ for (i = 0; i < plugs->len; i++) {
204+ SnapdPlug *plug = plugs->pdata[i];
205+ const char *snap_name = snapd_plug_get_snap(plug);
206+ const char *iface = snapd_plug_get_interface(plug);
207+ const bool connected = snapd_plug_get_connections(plug)->len != 0;
208+
209+ /* We are only interested in connected plugs of our snap */
210+ if (!connected || strcmp(snap_name, pc->snap_name) != 0) {
211+ continue;
212+ }
213+ if (!strcmp(iface, "pulseaudio") || !strcmp(iface, "audio-record")) {
214+ grant_access = true;
215+ break;
216+ }
217+ }
218+
219+end:
220+ complete_check_access(pc, grant_access);
221+}
222+
223+static void get_snap_finished(GObject *source_object,
224+ GAsyncResult *result,
225+ gpointer user_data)
226+{
227+ struct per_client *pc = user_data;
228+ struct userdata *u = pc->userdata;
229+ g_autoptr(GError) error = NULL;
230+ g_autoptr(SnapdSnap) snap = NULL;
231+
232+ snap = snapd_client_get_snap_finish(u->snapd, result, &error);
233+ if (!snap) {
234+ pa_log_warn("snapd_client_get_snap failed: %s", error->message);
235+ complete_check_access(pc, false);
236+ return;
237+ }
238+
239+ /* Snaps using classic confinement are granted access */
240+ if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC) {
241+ complete_check_access(pc, true);
242+ return;
243+ }
244+
245+ /* We have a non-classic snap, we need to check its connected
246+ * interfaces */
247+ snapd_client_get_interfaces_async(u->snapd, u->cancellable,
248+ get_interfaces_finished, pc);
249+}
250+
251+
252+static gboolean check_access(void *data)
253+{
254+ struct per_client *pc = data;
255+ struct userdata *u = pc->userdata;
256+
257+ snapd_client_get_snap_async(u->snapd, pc->snap_name, u->cancellable,
258+ get_snap_finished, pc);
259+ return G_SOURCE_REMOVE;
260+}
261+
262+
263+static void thread_main(void *data) {
264+ struct userdata *u = data;
265+
266+ pa_mutex_lock(u->mutex);
267+
268+ u->main_context = g_main_context_new();
269+ g_main_context_push_thread_default(u->main_context);
270+ u->main_loop = g_main_loop_new(u->main_context, false);
271+ u->cancellable = g_cancellable_new();
272+ u->snapd = snapd_client_new();
273+
274+ /* Signal main thread that we've finished initialisation */
275+ pa_cond_signal(u->cond, false);
276+ pa_mutex_unlock(u->mutex);
277+
278+ pa_log_info("Starting GLib main loop");
279+ g_main_loop_run(u->main_loop);
280+ pa_log_info("GLib main loop exited");
281+
282+ g_cancellable_cancel(u->cancellable);
283+
284+ g_clear_object(&u->snapd);
285+ g_clear_object(&u->cancellable);
286+ g_main_context_pop_thread_default(u->main_context);
287+ g_clear_pointer(&u->main_loop, g_main_loop_unref);
288+ g_clear_pointer(&u->main_context, g_main_context_unref);
289+}
290+
291+static gboolean thread_quit(void *data)
292+{
293+ struct userdata *u = data;
294+
295+ g_main_loop_quit(u->main_loop);
296+ return G_SOURCE_REMOVE;
297+}
298+
299+/* ---- Code running in main thread ---- */
300+
301+static struct per_client *per_client_new(struct userdata *u,
302+ uint32_t client_index,
303+ char *snap_name) {
304+ struct per_client *pc = pa_xnew0(struct per_client, 1);
305+ pc->userdata = u;
306+ pc->index = client_index;
307+ pc->snap_name = snap_name;
308+ pc->pending_requests = pa_dynarray_new(NULL);
309+ pc->completed = false;
310+ pc->grant_access = false;
311+ return pc;
312+}
313+
314+static void per_client_free(struct per_client *pc) {
315+ if (!pc) return;
316+ pa_xfree(pc->snap_name);
317+ pa_dynarray_free(pc->pending_requests);
318+ pa_xfree(pc);
319+}
320+
321+static char *client_get_snap_name(pa_core *core, uint32_t client_index) {
322+ pa_client *client;
323+ char *context = NULL;
324+ char *snap_name = NULL;
325+ char *dot;
326+
327+ client = pa_idxset_get_by_index(core->clients, client_index);
328+ pa_assert(client != NULL);
329+ if (!client->creds_valid) {
330+ pa_log_warn("Client %u has no creds, cannot authenticate", client_index);
331+ goto end;
332+ }
333+
334+ /* If AppArmor is not enabled, then we can't identify the client */
335+ if (!aa_is_enabled()) {
336+ goto end;
123+ }337+ }
338+ if (aa_gettaskcon(client->creds.pid, &context, NULL) < 0) {
339+ pa_log_error("AppArmor profile could not be retrieved.");
340+ goto end;
341+ }
342+
343+ /* If the AppArmor context does not begin with "snap.", then this
344+ * is not a snap */
345+ if (strncmp(context, SNAP_LABEL_PREFIX, SNAP_LABEL_PREFIX_LENGTH) != 0) {
346+ goto end;
347+ }
348+
349+ dot = strchr(context+SNAP_LABEL_PREFIX_LENGTH, '.');
350+ if (dot == NULL) {
351+ pa_log_warn("Malformed snapd AppArmor profile name: %s", context);
352+ goto end;
353+ }
354+ snap_name = pa_xstrndup(context+5, dot-context-SNAP_LABEL_PREFIX_LENGTH);
355+
356+end:
357+ free(context);
358+ return snap_name;
359+}
360+
361+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d,
362+ struct userdata *u) {
363+ pa_hook_result_t result = PA_HOOK_STOP;
364+ struct per_client *pc = NULL;
365+ char *snap_name = NULL;
124+366+
125+ pa_hook_result_t decision = PA_HOOK_OK;367+ pa_mutex_lock(u->mutex);
368+ pc = pa_hashmap_get(u->clients, (void *)(size_t)d->client_index);
369+ if (pc) {
370+ if (pc->completed) {
371+ result = pc->grant_access ? PA_HOOK_OK : PA_HOOK_STOP;
372+ } else {
373+ /* A permission check for this snap is currently in progress */
374+ pa_dynarray_append(pc->pending_requests, d);
375+ result = PA_HOOK_CANCEL;
376+ }
377+ goto end;
378+ }
379+
380+ snap_name = client_get_snap_name(core, d->client_index);
381+ if (!snap_name) {
382+ /* Not a snap, so allow access */
383+ result = PA_HOOK_OK;
384+ goto end;
385+ }
386+
387+ /* create new per client struct, and submit to glib thread */
388+ pc = per_client_new(u, d->client_index, snap_name);
389+ pa_dynarray_append(pc->pending_requests, d);
390+ pa_hashmap_put(u->clients, (void *) (size_t) d->client_index, pc);
391+ pa_log_info("Checking access for client %d (%s)", pc->index, pc->snap_name);
392+ g_main_context_invoke(u->main_context, check_access, pc);
126+393+
127+ // We only cancel the attempt of the client to start audio recording394+ result = PA_HOOK_CANCEL;
128+ // when we could successfully determine that the request is coming
129+ // from an app which is part of a snap. Otherwise we continue to
130+ // work as normal.
131+ if (label && strncmp(SNAP_LABEL_PREFIX, label, SNAP_LABEL_PREFIX_LENGTH) == 0)
132+ decision = PA_HOOK_CANCEL;
133+395+
134+ free(label);396+end:
397+ pa_mutex_unlock(u->mutex);
398+ return result;
399+}
400+
401+static void deliver_result(struct userdata *u, struct per_client *pc) {
402+ pa_access_data *ad;
403+ unsigned i;
135+404+
136+ return decision;405+ pa_log_info("Access check for client %u (%s): %d",
406+ pc->index, pc->snap_name, pc->grant_access);
407+
408+ /* Call the hooks without holding the mutex, since this will
409+ * recurse into connect_record_hook. Access to pending_requests
410+ * should be safe here, since connect_record_hook wont alter the
411+ * array when the access check is complete. */
412+ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) {
413+ ad->async_finish_cb(ad, pc->grant_access);
414+ }
415+ pa_mutex_lock(u->mutex);
416+ pa_hashmap_remove_and_free(u->clients, (void *) (size_t) pc->index);
417+ pa_mutex_unlock(u->mutex);
418+}
419+
420+static void check_result(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
421+ struct userdata *u = userdata;
422+ struct per_client *pc;
423+
424+ pa_asyncq_read_after_poll(u->results);
425+ while ((pc = pa_asyncq_pop(u->results, false)) != NULL) {
426+ deliver_result(u, pc);
427+ }
428+ pa_asyncq_read_before_poll(u->results);
137+}429+}
138+430+
139+int pa__init(pa_module *m) {431+int pa__init(pa_module *m) {
140+ struct userdata *u;432+ struct userdata *u;
141+ u = pa_xnew0(struct userdata, 1);
142+ u->core = m->core;
143+433+
434+ u = pa_xnew0(struct userdata, 1);
144+ m->userdata = u;435+ m->userdata = u;
145+ u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD],436+ u->mutex = pa_mutex_new(false, false);
146+ PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u);437+ u->cond = pa_cond_new();
438+
439+ u->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func,
440+ pa_idxset_trivial_compare_func,
441+ NULL, (pa_free_cb_t) per_client_free);
442+
443+ u->results = pa_asyncq_new(0);
444+ u->io_event = m->core->mainloop->io_new(
445+ m->core->mainloop, pa_asyncq_read_fd(u->results), PA_IO_EVENT_INPUT,
446+ check_result, u);
447+ pa_asyncq_read_before_poll(u->results);
448+
449+ u->connect_hook_slot = pa_hook_connect(
450+ &m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], PA_HOOK_NORMAL,
451+ (pa_hook_cb_t) connect_record_hook, u);
452+
453+ /* Start glib thread and wait for it to finish initialising. */
454+ pa_mutex_lock(u->mutex);
455+ u->thread = pa_thread_new("snapd-glib", thread_main, u);
456+ pa_cond_wait(u->cond, u->mutex);
457+ pa_mutex_unlock(u->mutex);
147+458+
148+ return 0;459+ return 0;
149+}460+}
150+461+
151+void pa__done(pa_module *m) {462+void pa__done(pa_module *m) {
152+ struct userdata *u = m->userdata;463+ struct userdata *u = m->userdata;
153+ if (u) {464+ if (!u) return;
154+ if (u->connect_hook_slot)
155+ pa_hook_slot_free(u->connect_hook_slot);
156+ pa_xfree(u);
157+ }
158+}
159Index: pulseaudio/configure.ac
160===================================================================
161--- pulseaudio.orig/configure.ac
162+++ pulseaudio/configure.ac
163@@ -1412,6 +1412,19 @@ AS_IF([test "x$os_is_win32" != "x1"],
164 AS_IF([test "x$ax_pthread_ok" = "xyes"],
165 AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
166
167+# Snappy support
168+465+
169+AC_ARG_ENABLE([snappy],466+ pa_hook_slot_free(u->connect_hook_slot);
170+ AS_HELP_STRING([--enable-snappy], [Enable snappy support]))467+ m->core->mainloop->io_free(u->io_event);
171+468+
172+AS_IF([test "x$enable_snappy" != "xno"],469+ /* Stop the glib thread and wait for it to exit */
173+ [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [HAVE_APPARMOR=1], [HAVE_APPARMOR=0])],470+ g_main_context_invoke(u->main_context, thread_quit, u);
174+ [HAVE_APPARMOR=0])471+ pa_thread_join(u->thread);
472+ pa_thread_free(u->thread);
175+473+
176+AS_IF([test "x$enable_snappy" = "xyes" && test "x$HAVE_APPARMOR" = "x0"],474+ pa_asyncq_free(u->results, NULL); /* items in queue owned by u->clients */
177+ [AC_MSG_ERROR([*** Apparmor library not found])])475+ g_clear_pointer(&u->clients, pa_hashmap_free);
178+476+
179+AM_CONDITIONAL([HAVE_APPARMOR], [test "x$HAVE_APPARMOR" = "x1"])477+ g_clear_pointer(&u->cond, pa_cond_free);
180 478+ g_clear_pointer(&u->mutex, pa_mutex_free);
181 # Ubuntu touch trust store479+
182 480+ pa_xfree(u);
183@@ -1602,6 +1615,8 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x481+}
184 AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no)
185 AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no)
186 AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no)
187+AS_IF([test "x$enable_snappy" = "x1"], ENABLE_SNAPPY=yes, ENABLE_SNAPPY=no)
188+AS_IF([test "x$HAVE_APPARMOR" = "x1"], ENABLE_APPARMOR=yes, ENABLE_APPARMOR=no)
189
190 echo "
191 ---{ $PACKAGE_NAME $VERSION }---
192@@ -1658,6 +1673,8 @@ echo "
193 Enable soxr (resampler): ${ENABLE_SOXR}
194 Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
195 Enable Ubuntu trust store: ${ENABLE_TRUST_STORE}
196+ Enable Snappy support: ${ENABLE_SNAPPY}
197+ Enable Apparmor: ${ENABLE_APPARMOR}
198 Enable gcov coverage: ${ENABLE_GCOV}
199 Enable unit tests: ${ENABLE_TESTS}
200 Database
diff --git a/debian/patches/0701-enable-snap-policy-module.patch b/debian/patches/0701-enable-snap-policy-module.patch
201new file mode 100644482new file mode 100644
index 0000000..47a23ab
--- /dev/null
+++ b/debian/patches/0701-enable-snap-policy-module.patch
@@ -0,0 +1,30 @@
1From: James Henstridge <james.henstridge@canonical.com>
2Date: Tue, 7 Aug 2018 16:54:00 +0800
3Subject: daemon: enable module-snap-policy module
4
5Forwarded: not-needed
6
7This patch allows pulseaudio to limit audio recording to snaps with
8the audio-recording interface connected. We will not pursue upstreaming
9this patch as the longer term solution will probably use PipeWire.
10---
11 src/daemon/default.pa.in | 6 ++++++
12 1 file changed, 6 insertions(+)
13
14diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
15index a9a97c0..6c5e7bc 100755
16--- a/src/daemon/default.pa.in
17+++ b/src/daemon/default.pa.in
18@@ -158,6 +158,12 @@ load-module module-position-event-sounds
19 ### Cork music/video streams when a phone stream is active
20 load-module module-role-cork
21
22+### Block audio recording for snap confined packages unless they have
23+### the "pulseaudio" or "audio-record" interfaces plugged.
24+.ifexists module-snap-policy@PA_SOEXT@
25+load-module module-snap-policy
26+.endif
27+
28 ### Modules to allow autoloading of filters (such as echo cancellation)
29 ### on demand. module-filter-heuristics tries to determine what filters
30 ### make sense, and module-filter-apply does the heavy-lifting of
diff --git a/debian/patches/series b/debian/patches/series
index 6d07b3b..34b66de 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -5,16 +5,13 @@
50022-inotify-wrapper-Quit-daemon-if-pid-file-is-removed.patch50022-inotify-wrapper-Quit-daemon-if-pid-file-is-removed.patch
60030-load-module-switch-on-connect.patch60030-load-module-switch-on-connect.patch
77
8# Ubuntu touch: support for trust-store8# Ubuntu Snap policy support
90406-tagstruct-add-copy-method.patch90406-tagstruct-add-copy-method.patch
100407-access-Add-access-control-hooks.patch100407-access-Add-access-control-hooks.patch
110408-protocol-native-add-access-checks.patch110408-protocol-native-add-access-checks.patch
120409-Trust-store-patch.patch120409-pa-client-peer-credentials.patch
130410-Add-thread-to-activate-trust-store-interface.patch
140417-increase-timeout-check-apparmor.patch
15
16# Ubuntu Snappy
170700-modules-add-snappy-policy-module.patch130700-modules-add-snappy-policy-module.patch
140701-enable-snap-policy-module.patch
1815
19# Bug fixes backported from PulseAudio 1216# Bug fixes backported from PulseAudio 12
200800-fix-lp1720684.patch170800-fix-lp1720684.patch
diff --git a/debian/pulseaudio.install b/debian/pulseaudio.install
index 513b7ad..5586bfd 100755
--- a/debian/pulseaudio.install
+++ b/debian/pulseaudio.install
@@ -77,7 +77,7 @@ usr/lib/pulse-*/modules/module-virtual-sink.so
77usr/lib/pulse-*/modules/module-virtual-source.so77usr/lib/pulse-*/modules/module-virtual-source.so
78usr/lib/pulse-*/modules/module-switch-on-port-available.so78usr/lib/pulse-*/modules/module-switch-on-port-available.so
79usr/lib/pulse-*/modules/module-virtual-surround-sink.so79usr/lib/pulse-*/modules/module-virtual-surround-sink.so
80usr/lib/pulse-*/modules/module-snappy-policy.so80usr/lib/pulse-*/modules/module-snap-policy.so
81usr/lib/pulse-*/modules/module-x11*.so81usr/lib/pulse-*/modules/module-x11*.so
82usr/lib/pulse-*/modules/module-allow-passthrough.so82usr/lib/pulse-*/modules/module-allow-passthrough.so
83[linux-any] usr/lib/pulse-*/modules/module-systemd-login.so83[linux-any] usr/lib/pulse-*/modules/module-systemd-login.so
diff --git a/debian/rules b/debian/rules
index 3737dc5..32cc45f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -22,7 +22,7 @@ DEB_CONFIGURE_EXTRA_FLAGS = --enable-x11 --disable-hal-compat \
22 --with-zsh-completion-dir=\$${datadir}/zsh/vendor-completions \22 --with-zsh-completion-dir=\$${datadir}/zsh/vendor-completions \
23 --with-bash-completion-dir=\$${datadir}/bash-completion/completions \23 --with-bash-completion-dir=\$${datadir}/bash-completion/completions \
24 --with-systemduserunitdir=\$${prefix}/lib/systemd/user \24 --with-systemduserunitdir=\$${prefix}/lib/systemd/user \
25 --disable-bluez4 --enable-snappy25 --disable-bluez4 --enable-snap
2626
27PA_MAJORMINOR = $(shell echo $(DEB_VERSION_UPSTREAM) | sed -r -e 's/^([0-9]+\.[0-9]+).*/\1/')27PA_MAJORMINOR = $(shell echo $(DEB_VERSION_UPSTREAM) | sed -r -e 's/^([0-9]+\.[0-9]+).*/\1/')
2828

Subscribers

People subscribed via source and target branches