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

Proposed by James Henstridge on 2018-08-29
Status: Needs review
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 2018-08-29 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.

Unmerged commits

dad0e3d... by James Henstridge on 2018-08-29

Backport the module-snap-policy changes from Cosmic (LP: #1781428).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 6db0099..b0058d6 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,19 @@
6+pulseaudio (1:11.1-1ubuntu7.2) bionic; urgency=medium
7+
8+ * Update snap policy to make access to audio recording conditional on
9+ plugging the "pulseaudio" or "audio-record" interfaces (LP: #1781428):
10+ - 0700-modules-add-snappy-policy-module.patch: rewrite to query
11+ snapd for the client's plugged interfaces.
12+ - 0701-enable-snap-policy-module.patch: enable the module in the
13+ default configuration.
14+ - Build depend on libsnapd-glib-dev.
15+ * Remove module-trust-store patch set:
16+ - 0409-Trust-store-patch.patch: trimmed down to pulsecore changes.
17+ - 0410-Add-thread-to-activate-trust-store-interface.patch: removed.
18+ - 0417-increase-timeout-check-apparmor.patch: removed.
19+
20+ -- James Henstridge <james.henstridge@canonical.com> Wed, 29 Aug 2018 17:42:25 +0800
21+
22 pulseaudio (1:11.1-1ubuntu7.1) bionic; urgency=medium
23
24 * 0804-bluez5-device-Rewrite-of-thread-function-reduce-send.patch,
25diff --git a/debian/control b/debian/control
26index 2d9d9a9..95694c0 100644
27--- a/debian/control
28+++ b/debian/control
29@@ -29,6 +29,7 @@ Build-Depends: debhelper (>= 10),
30 libltdl-dev (>= 2.2.6a-2),
31 liborc-0.4-dev (>= 1:0.4.11),
32 libsamplerate0-dev,
33+ libsnapd-glib-dev,
34 libsndfile1-dev (>= 1.0.20),
35 libspeexdsp-dev (>= 1.2~rc1),
36 libssl-dev,
37diff --git a/debian/patches/0409-Trust-store-patch.patch b/debian/patches/0409-Trust-store-patch.patch
38deleted file mode 100644
39index 60277af..0000000
40--- a/debian/patches/0409-Trust-store-patch.patch
41+++ /dev/null
42@@ -1,582 +0,0 @@
43-From ff36148e002232842ea0f07b148e5844c5d44ceb Mon Sep 17 00:00:00 2001
44-From: David Henningsson <david.henningsson@canonical.com>
45-Date: Wed, 22 Jul 2015 16:37:19 +0200
46-Subject: [PATCH 4/5] Trust-store patch
47-
48-...includes some fixes elsewhere as well.
49-
50-Signed-off-by: David Henningsson <david.henningsson@canonical.com>
51----
52- configure.ac | 15 ++
53- src/Makefile.am | 24 +++
54- src/modules/trust-store/module-trust-store.c | 221 +++++++++++++++++++++++++++
55- src/modules/trust-store/truststore.cc | 74 +++++++++
56- src/modules/trust-store/truststore.h | 41 +++++
57- src/pulsecore/client.h | 4 +
58- src/pulsecore/creds.h | 1 +
59- src/pulsecore/iochannel.c | 2 +
60- src/pulsecore/protocol-native.c | 13 ++
61- src/pulsecore/tagstruct.c | 1 +
62- 12 files changed, 399 insertions(+), 7 deletions(-)
63- create mode 100644 src/modules/trust-store/module-trust-store.c
64- create mode 100644 src/modules/trust-store/truststore.cc
65- create mode 100644 src/modules/trust-store/truststore.h
66-
67-Index: pulseaudio/configure.ac
68-===================================================================
69---- pulseaudio.orig/configure.ac
70-+++ pulseaudio/configure.ac
71-@@ -1413,6 +1413,19 @@ AS_IF([test "x$ax_pthread_ok" = "xyes"],
72- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
73-
74-
75-+# Ubuntu touch trust store
76-+
77-+AC_ARG_ENABLE([trust-store],
78-+ AS_HELP_STRING([--enable-trust-store], [Enable Ubuntu touch trust store]))
79-+
80-+AS_IF([test "x$enable_trust_store" != "xno"],
81-+ [PKG_CHECK_MODULES(TRUST_STORE, [ trust-store ], [HAVE_TRUST_STORE=1], [HAVE_TRUST_STORE=0])],
82-+ [HAVE_WEBRTC=0])
83-+
84-+AS_IF([test "x$enable_trust_store" = "xyes" && test "x$HAVE_TRUST_STORE" = "x0"],
85-+ [AC_MSG_ERROR([*** Ubuntu touch trust store library not found])])
86-+
87-+AM_CONDITIONAL([HAVE_TRUST_STORE], [test "x$HAVE_TRUST_STORE" = "x1"])
88-
89- ###################################
90- # Output #
91-@@ -1580,6 +1593,7 @@ AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"],
92- AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no)
93- AS_IF([test "x$HAVE_SOXR" = "x1"], ENABLE_SOXR=yes, ENABLE_SOXR=no)
94- AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no)
95-+AS_IF([test "x$HAVE_TRUST_STORE" = "x1"], ENABLE_TRUST_STORE=yes, ENABLE_TRUST_STORE=no)
96- AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no)
97- AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no)
98- AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no)
99-@@ -1643,6 +1657,7 @@ echo "
100- Enable speex (resampler, AEC): ${ENABLE_SPEEX}
101- Enable soxr (resampler): ${ENABLE_SOXR}
102- Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
103-+ Enable Ubuntu trust store: ${ENABLE_TRUST_STORE}
104- Enable gcov coverage: ${ENABLE_GCOV}
105- Enable unit tests: ${ENABLE_TESTS}
106- Database
107-Index: pulseaudio/src/Makefile.am
108-===================================================================
109---- pulseaudio.orig/src/Makefile.am
110-+++ pulseaudio/src/Makefile.am
111-@@ -1097,6 +1097,10 @@ if HAVE_WEBRTC
112- modlibexec_LTLIBRARIES += libwebrtc-util.la
113- endif
114-
115-+if HAVE_TRUST_STORE
116-+modlibexec_LTLIBRARIES += libtruststore-util.la
117-+endif
118-+
119- if HAVE_ESOUND
120- modlibexec_LTLIBRARIES += \
121- libprotocol-esound.la
122-@@ -1226,6 +1230,11 @@ modlibexec_LTLIBRARIES += \
123- module-role-ducking.la \
124- module-allow-passthrough.la
125-
126-+if HAVE_TRUST_STORE
127-+modlibexec_LTLIBRARIES += \
128-+ module-trust-store.la
129-+endif
130-+
131- if HAVE_ESOUND
132- modlibexec_LTLIBRARIES += \
133- module-esound-protocol-tcp.la \
134-@@ -1535,6 +1544,7 @@ SYMDEF_FILES = \
135- module-intended-roles-symdef.h \
136- module-suspend-on-idle-symdef.h \
137- module-echo-cancel-symdef.h \
138-+ module-trust-store-symdef.h \
139- module-hal-detect-symdef.h \
140- module-udev-detect-symdef.h \
141- module-systemd-login-symdef.h \
142-@@ -2077,6 +2087,20 @@ module_echo_cancel_la_CFLAGS += -DHAVE_W
143- module_echo_cancel_la_LIBADD += libwebrtc-util.la
144- endif
145-
146-+if HAVE_TRUST_STORE
147-+# Separate helper library to keep C and C++ code apart, like we do for webrtc
148-+libtruststore_util_la_SOURCES = modules/trust-store/truststore.cc
149-+libtruststore_util_la_CXXFLAGS = $(AM_CXXFLAGS) -std=c++11 $(SERVER_CFLAGS) $(TRUST_STORE_CFLAGS) \
150-+ $(DBUS_CFLAGS) -DHAVE_TRUST_STORE=1
151-+libtruststore_util_la_LIBADD = libpulsecore-@PA_MAJORMINOR@.la $(TRUST_STORE_LIBS) $(DBUS_LIBS)
152-+libtruststore_util_la_LDFLAGS = -avoid-version
153-+
154-+module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
155-+module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
156-+module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
157-+module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
158-+endif
159-+
160- # RTP modules
161- module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
162- module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)
163-Index: pulseaudio/src/modules/trust-store/module-trust-store.c
164-===================================================================
165---- /dev/null
166-+++ pulseaudio/src/modules/trust-store/module-trust-store.c
167-@@ -0,0 +1,228 @@
168-+/***
169-+ This file is part of PulseAudio.
170-+
171-+ Copyright 2015 Canonical Ltd.
172-+ Written by David Henningsson <david.henningsson@canonical.com>
173-+
174-+ PulseAudio is free software; you can redistribute it and/or modify
175-+ it under the terms of the GNU Lesser General Public License as published
176-+ by the Free Software Foundation; either version 2.1 of the License,
177-+ or (at your option) any later version.
178-+
179-+ PulseAudio is distributed in the hope that it will be useful, but
180-+ WITHOUT ANY WARRANTY; without even the implied warranty of
181-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
182-+ General Public License for more details.
183-+
184-+ You should have received a copy of the GNU Lesser General Public License
185-+ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
186-+***/
187-+#ifdef HAVE_CONFIG_H
188-+#include <config.h>
189-+#endif
190-+
191-+#include <pulsecore/i18n.h>
192-+#include <pulsecore/core.h>
193-+#include <pulsecore/module.h>
194-+#include <pulse/xmalloc.h>
195-+#include <pulsecore/fdsem.h>
196-+#include <pulsecore/thread.h>
197-+#include <pulsecore/core-util.h>
198-+#include <pulse/mainloop-api.h>
199-+
200-+#include "module-trust-store-symdef.h"
201-+
202-+PA_MODULE_AUTHOR("David Henningsson");
203-+PA_MODULE_DESCRIPTION("Ubuntu touch trust store integration");
204-+PA_MODULE_VERSION(PACKAGE_VERSION);
205-+PA_MODULE_LOAD_ONCE(true);
206-+
207-+#include "truststore.h"
208-+
209-+#define REQUEST_GRANTED 1
210-+#define REQUEST_DENIED -1
211-+#define REQUEST_PENDING 0
212-+
213-+struct userdata;
214-+
215-+struct per_client {
216-+ uint32_t index;
217-+ char *appname;
218-+ uid_t uid;
219-+ pid_t pid;
220-+ struct userdata *userdata;
221-+ pa_dynarray *pending_requests;
222-+ pa_atomic_t result;
223-+};
224-+
225-+struct userdata {
226-+ pa_core *core;
227-+ pa_trust_store *ts;
228-+ pa_hashmap *per_clients;
229-+ pa_thread *thread;
230-+ pa_fdsem *fdsem;
231-+ pa_io_event *io_event;
232-+ pa_hook_slot *connect_hook_slot;
233-+};
234-+
235-+static struct per_client *per_client_new(struct userdata *u, uint32_t client_index) {
236-+ struct per_client *pc;
237-+ pa_client *client = pa_idxset_get_by_index(u->core->clients, client_index);
238-+
239-+ pa_assert(client);
240-+ if (!client->creds_valid) {
241-+ pa_log_warn("Client %d has no creds, cannot authenticate", client_index);
242-+ return NULL;
243-+ }
244-+
245-+ pc = pa_xnew0(struct per_client, 1);
246-+ // TODO: Do we need something else than the application name here -
247-+ // the application can probably spoof it
248-+ pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
249-+ pc->index = client_index;
250-+ pc->uid = client->creds.uid;
251-+ pc->pid = client->creds.pid;
252-+ pc->pending_requests = pa_dynarray_new(NULL);
253-+ pc->userdata = u;
254-+
255-+ pa_hashmap_put(u->per_clients, (void *) (size_t) client_index, pc);
256-+
257-+ return pc;
258-+}
259-+
260-+static void per_client_free_from_hashmap(void *data) {
261-+ struct per_client *pc = data;
262-+ if (!pc)
263-+ return;
264-+ pa_xfree(pc->appname);
265-+ pa_dynarray_free(pc->pending_requests);
266-+ pa_xfree(pc);
267-+}
268-+
269-+static void thread_func(void *data) {
270-+ struct per_client *pc = data;
271-+
272-+ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
273-+ /// TRANSLATORS: The app icon and name appears above this string. If the phrase
274-+ /// can't be translated in this language, translate the whole sentence
275-+ /// 'This app wants to record audio.'
276-+ _("wants to record audio."));
277-+
278-+ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
279-+ pa_fdsem_post(pc->userdata->fdsem);
280-+}
281-+
282-+static void check_queue(struct userdata *u) {
283-+ struct per_client *pc;
284-+ void *dummy;
285-+
286-+ pa_log_debug("Checking queue, size: %d, thread object: %s",
287-+ pa_hashmap_size(u->per_clients), pa_yes_no(u->thread));
288-+ if (u->thread) {
289-+ pa_access_data *ad;
290-+ unsigned i;
291-+ int result;
292-+ pc = pa_thread_get_data(u->thread);
293-+ result = pa_atomic_load(&pc->result);
294-+ if (result == REQUEST_PENDING)
295-+ return; /* Still processing */
296-+ pa_thread_free(u->thread);
297-+ u->thread = NULL;
298-+
299-+ pa_log_debug("Letting client %d (%s) know the result (%s)",
300-+ pc->index, pc->appname, result == REQUEST_GRANTED ? "granted" : "rejected");
301-+ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) {
302-+ ad->async_finish_cb(ad, result == REQUEST_GRANTED);
303-+ }
304-+ pa_hashmap_remove(u->per_clients, (void*) (size_t) pc->index);
305-+ }
306-+
307-+ /* Find a client that needs asking */
308-+ PA_HASHMAP_FOREACH(pc, u->per_clients, dummy) {
309-+ if (u->thread)
310-+ return;
311-+ pa_assert(pa_atomic_load(&pc->result) == REQUEST_PENDING);
312-+ pa_log_debug("Starting thread to ask about client %d (%s)", pc->index,
313-+ pc->appname);
314-+ u->thread = pa_thread_new("trust-store", thread_func, pc);
315-+ }
316-+}
317-+
318-+static void check_fdsem(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t ee,
319-+ void *userdata) {
320-+ struct userdata *u = userdata;
321-+ pa_fdsem_after_poll(u->fdsem);
322-+ check_queue(u);
323-+ pa_fdsem_before_poll(u->fdsem);
324-+}
325-+
326-+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) {
327-+ struct per_client *pc = pa_hashmap_get(u->per_clients, (void*) (size_t) d->client_index);
328-+ int r;
329-+ if (!pc)
330-+ pc = per_client_new(u, d->client_index);
331-+
332-+ r = pa_atomic_load(&pc->result);
333-+ pa_log_debug("Checking permission to record for client %d (%s) ", d->client_index,
334-+ r == REQUEST_GRANTED ? "granted" : r != REQUEST_PENDING ? "rejected" : "unknown");
335-+ if (r == REQUEST_GRANTED) return PA_HOOK_OK;
336-+ if (r != REQUEST_PENDING) return PA_HOOK_STOP;
337-+
338-+ pa_dynarray_append(pc->pending_requests, d);
339-+ check_queue(u);
340-+ return PA_HOOK_CANCEL;
341-+}
342-+
343-+/* Test code - remove from final product */
344-+static void test(struct userdata *u) {
345-+ uint32_t dummy;
346-+ pa_client *client;
347-+
348-+ PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
349-+ if (client->creds_valid)
350-+ pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
351-+ client->creds.pid, "%1% wants to eat your laundry.");
352-+ }
353-+}
354-+
355-+int pa__init(pa_module *m) {
356-+ struct userdata *u;
357-+ pa_trust_store *ts = pa_trust_store_new();
358-+ if (ts == NULL)
359-+ return -1;
360-+ u = pa_xnew0(struct userdata, 1);
361-+ u->ts = ts;
362-+ u->core = m->core;
363-+ u->per_clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func,
364-+ NULL, per_client_free_from_hashmap);
365-+ m->userdata = u;
366-+ u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD],
367-+ PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u);
368-+
369-+ pa_assert_se(u->fdsem = pa_fdsem_new());
370-+ pa_assert_se(u->io_event = m->core->mainloop->io_new(m->core->mainloop,
371-+ pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
372-+ pa_fdsem_before_poll(u->fdsem);
373-+
374-+ test(u);
375-+ return 0;
376-+}
377-+
378-+void pa__done(pa_module *m) {
379-+ struct userdata *u = m->userdata;
380-+ if (u) {
381-+ if (u->connect_hook_slot)
382-+ pa_hook_slot_free(u->connect_hook_slot);
383-+ if (u->thread)
384-+ pa_thread_free(u->thread);
385-+ if (u->io_event)
386-+ m->core->mainloop->io_free(u->io_event);
387-+ if (u->fdsem)
388-+ pa_fdsem_free(u->fdsem);
389-+ if (u->per_clients)
390-+ pa_hashmap_free(u->per_clients);
391-+ if (u->ts)
392-+ pa_trust_store_free(u->ts);
393-+ pa_xfree(u);
394-+ }
395-+}
396-Index: pulseaudio/src/modules/trust-store/truststore.cc
397-===================================================================
398---- /dev/null
399-+++ pulseaudio/src/modules/trust-store/truststore.cc
400-@@ -0,0 +1,74 @@
401-+#ifdef HAVE_CONFIG_H
402-+#include <config.h>
403-+#endif
404-+
405-+#include <memory>
406-+#include <core/dbus/bus.h>
407-+#include <core/trust/dbus_agent.h>
408-+#include <core/trust/agent.h>
409-+
410-+#include <pulse/cdecl.h>
411-+
412-+PA_C_DECL_BEGIN
413-+#include <pulsecore/core-util.h>
414-+#include <pulse/xmalloc.h>
415-+#include <pulsecore/log.h>
416-+
417-+#include "truststore.h"
418-+PA_C_DECL_END
419-+
420-+class TrustStore {
421-+public:
422-+ std::shared_ptr<core::trust::Agent> agent;
423-+};
424-+
425-+pa_trust_store* pa_trust_store_new() {
426-+ try {
427-+ auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
428-+ auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
429-+ auto ts = new TrustStore();
430-+ ts->agent = agent;
431-+ return (pa_trust_store *) ts;
432-+ } catch(const std::exception &e) {
433-+ pa_log_error("Could not create Ubuntu touch trust store connection: %s",
434-+ e.what());
435-+ } catch(...) {
436-+ pa_log_error("Could not create Ubuntu touch trust store connection");
437-+ return NULL;
438-+ }
439-+}
440-+
441-+void pa_trust_store_free(pa_trust_store *t) {
442-+ pa_assert(t != NULL);
443-+ auto ts = (TrustStore*) t;
444-+ delete ts;
445-+}
446-+
447-+bool pa_trust_store_check(pa_trust_store *t, const char *appname,
448-+ uid_t uid, pid_t pid, const char *description) {
449-+ auto ts = (TrustStore*) t;
450-+ try {
451-+
452-+ core::trust::Agent::RequestParameters params {
453-+ core::trust::Uid{uid},
454-+ core::trust::Pid{pid},
455-+ appname,
456-+ core::trust::Feature{0},
457-+ description
458-+ };
459-+ pa_log_debug("Asking Ubuntu touch trust store for permission (app: %s)",
460-+ params.application.id.c_str());
461-+ auto answer = ts->agent->authenticate_request_with_parameters(params);
462-+ if (answer == core::trust::Request::Answer::granted) {
463-+ pa_log_debug("Request granted.");
464-+ return true;
465-+ }
466-+ pa_log_info("Request denied.");
467-+ } catch(const std::exception &e) {
468-+ pa_log_error("Could not ask Ubuntu touch trust store for permission: %s",
469-+ e.what());
470-+ } catch(...) {
471-+ pa_log_error("Could not ask Ubuntu touch trust store for permission");
472-+ }
473-+ return false;
474-+}
475-Index: pulseaudio/src/modules/trust-store/truststore.h
476-===================================================================
477---- /dev/null
478-+++ pulseaudio/src/modules/trust-store/truststore.h
479-@@ -0,0 +1,41 @@
480-+/***
481-+ This file is part of PulseAudio.
482-+
483-+ Copyright 2015 Canonical Ltd.
484-+ Written by David Henningsson <david.henningsson@canonical.com>
485-+
486-+ PulseAudio is free software; you can redistribute it and/or modify
487-+ it under the terms of the GNU Lesser General Public License as published
488-+ by the Free Software Foundation; either version 2.1 of the License,
489-+ or (at your option) any later version.
490-+
491-+ PulseAudio is distributed in the hope that it will be useful, but
492-+ WITHOUT ANY WARRANTY; without even the implied warranty of
493-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
494-+ General Public License for more details.
495-+
496-+ You should have received a copy of the GNU Lesser General Public License
497-+ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
498-+***/
499-+
500-+#ifndef footruststorehfoo
501-+#define footruststorehfoo
502-+
503-+#ifdef HAVE_CONFIG_H
504-+#include <config.h>
505-+#endif
506-+
507-+#include <pulsecore/creds.h>
508-+
509-+#ifdef HAVE_TRUST_STORE
510-+PA_C_DECL_BEGIN
511-+typedef struct pa_trust_store pa_trust_store;
512-+
513-+pa_trust_store* pa_trust_store_new();
514-+void pa_trust_store_free(pa_trust_store *ts);
515-+bool pa_trust_store_check(pa_trust_store *ts, const char *appname,
516-+ uid_t uid, pid_t pid, const char *description);
517-+PA_C_DECL_END
518-+#endif
519-+
520-+#endif
521-Index: pulseaudio/src/pulsecore/client.h
522-===================================================================
523---- pulseaudio.orig/src/pulsecore/client.h
524-+++ pulseaudio/src/pulsecore/client.h
525-@@ -26,6 +26,7 @@
526- #include <pulse/proplist.h>
527- #include <pulsecore/core.h>
528- #include <pulsecore/module.h>
529-+#include <pulsecore/creds.h>
530-
531- /* Every connection to the server should have a pa_client
532- * attached. That way the user may generate a listing of all connected
533-@@ -35,6 +36,9 @@ struct pa_client {
534- uint32_t index;
535- pa_core *core;
536-
537-+ pa_creds creds;
538-+ bool creds_valid;
539-+
540- pa_proplist *proplist;
541- pa_module *module;
542- char *driver;
543-Index: pulseaudio/src/pulsecore/creds.h
544-===================================================================
545---- pulseaudio.orig/src/pulsecore/creds.h
546-+++ pulseaudio/src/pulsecore/creds.h
547-@@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cms
548- struct pa_creds {
549- gid_t gid;
550- uid_t uid;
551-+ pid_t pid;
552- };
553-
554- /* Struct for handling ancillary data, i e, extra data that can be sent together with a message
555-Index: pulseaudio/src/pulsecore/iochannel.c
556-===================================================================
557---- pulseaudio.orig/src/pulsecore/iochannel.c
558-+++ pulseaudio/src/pulsecore/iochannel.c
559-@@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa
560-
561- u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
562-
563-+ /* FIXME: Check whether ucred->pid should be used */
564- u->pid = getpid();
565- if (ucred) {
566- u->uid = ucred->uid;
567-@@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_dat
568-
569- ancil_data->creds.gid = u.gid;
570- ancil_data->creds.uid = u.uid;
571-+ ancil_data->creds.pid = u.pid;
572- ancil_data->creds_valid = true;
573- }
574- else if (cmh->cmsg_type == SCM_RIGHTS) {
575-Index: pulseaudio/src/pulsecore/protocol-native.c
576-===================================================================
577---- pulseaudio.orig/src/pulsecore/protocol-native.c
578-+++ pulseaudio/src/pulsecore/protocol-native.c
579-@@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *p
580- do_shm = false;
581-
582- #ifdef HAVE_CREDS
583-+ {
584-+ const pa_creds *creds;
585-+ if ((creds = pa_pdispatch_creds(pd))) {
586-+ c->client->creds = *creds;
587-+ c->client->creds_valid = true;
588-+ }
589-+ }
590- if (do_shm) {
591- /* Only enable SHM if both sides are owned by the same
592- * user. This is a security measure because otherwise data
593-@@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access
594- } pa_protocol_native_access_data;
595-
596- static void check_access_finish_cb(pa_access_data *data, bool res) {
597-+ uint32_t command, tag;
598- pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
599- pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
600-
601-@@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_ac
602- goto finish;
603- }
604-
605-+ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0);
606-+ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0);
607-+ pa_assert(command == d->command);
608-+ pa_assert(tag == d->tag);
609-+
610- /* call the dispatcher again, hopefully this time, the access check will
611- * fail or succeed immediately */
612- command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
613-Index: pulseaudio/po/POTFILES.in
614-===================================================================
615---- pulseaudio.orig/po/POTFILES.in
616-+++ pulseaudio/po/POTFILES.in
617-@@ -23,6 +23,7 @@ src/modules/jack/module-jack-sink.c
618- src/modules/jack/module-jack-source.c
619- src/modules/macosx/module-coreaudio-device.c
620- src/modules/module-allow-passthrough.c
621-+src/modules/trust-store/module-trust-store.c
622- src/modules/module-always-sink.c
623- src/modules/module-cli.c
624- src/modules/module-combine.c
625diff --git a/debian/patches/0409-pa-client-peer-credentials.patch b/debian/patches/0409-pa-client-peer-credentials.patch
626new file mode 100644
627index 0000000..65ba9fd
628--- /dev/null
629+++ b/debian/patches/0409-pa-client-peer-credentials.patch
630@@ -0,0 +1,104 @@
631+From: David Henningsson <david.henningsson@canonical.com>
632+Date: Wed, 22 Jul 2015 16:37:19 +0200
633+Subject: [PATCH 4/5] Expose peer credentials on pa_client
634+
635+Signed-off-by: David Henningsson <david.henningsson@canonical.com>
636+---
637+ src/pulsecore/client.h | 4 ++++
638+ src/pulsecore/creds.h | 1 +
639+ src/pulsecore/iochannel.c | 2 ++
640+ src/pulsecore/protocol-native.c | 13 +++++++++++++
641+ 4 files changed, 20 insertions(+)
642+
643+diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h
644+index eb8173d..a038a0c 100644
645+--- a/src/pulsecore/client.h
646++++ b/src/pulsecore/client.h
647+@@ -26,6 +26,7 @@
648+ #include <pulse/proplist.h>
649+ #include <pulsecore/core.h>
650+ #include <pulsecore/module.h>
651++#include <pulsecore/creds.h>
652+
653+ /* Every connection to the server should have a pa_client
654+ * attached. That way the user may generate a listing of all connected
655+@@ -35,6 +36,9 @@ struct pa_client {
656+ uint32_t index;
657+ pa_core *core;
658+
659++ pa_creds creds;
660++ bool creds_valid;
661++
662+ pa_proplist *proplist;
663+ pa_module *module;
664+ char *driver;
665+diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h
666+index 9fdbb4f..8bcf636 100644
667+--- a/src/pulsecore/creds.h
668++++ b/src/pulsecore/creds.h
669+@@ -41,6 +41,7 @@ typedef struct pa_cmsg_ancil_data pa_cmsg_ancil_data;
670+ struct pa_creds {
671+ gid_t gid;
672+ uid_t uid;
673++ pid_t pid;
674+ };
675+
676+ /* Struct for handling ancillary data, i e, extra data that can be sent together with a message
677+diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
678+index 8973375..cd0b81d 100644
679+--- a/src/pulsecore/iochannel.c
680++++ b/src/pulsecore/iochannel.c
681+@@ -323,6 +323,7 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
682+
683+ u = (struct ucred*) CMSG_DATA(&cmsg.hdr);
684+
685++ /* FIXME: Check whether ucred->pid should be used */
686+ u->pid = getpid();
687+ if (ucred) {
688+ u->uid = ucred->uid;
689+@@ -445,6 +446,7 @@ ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l,
690+
691+ ancil_data->creds.gid = u.gid;
692+ ancil_data->creds.uid = u.uid;
693++ ancil_data->creds.pid = u.pid;
694+ ancil_data->creds_valid = true;
695+ }
696+ else if (cmh->cmsg_type == SCM_RIGHTS) {
697+diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
698+index 67b5c7a..a2f74a0 100644
699+--- a/src/pulsecore/protocol-native.c
700++++ b/src/pulsecore/protocol-native.c
701+@@ -2668,6 +2668,13 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
702+ do_shm = false;
703+
704+ #ifdef HAVE_CREDS
705++ {
706++ const pa_creds *creds;
707++ if ((creds = pa_pdispatch_creds(pd))) {
708++ c->client->creds = *creds;
709++ c->client->creds_valid = true;
710++ }
711++ }
712+ if (do_shm) {
713+ /* Only enable SHM if both sides are owned by the same
714+ * user. This is a security measure because otherwise data
715+@@ -5631,6 +5638,7 @@ typedef struct pa_protocol_native_access_data {
716+ } pa_protocol_native_access_data;
717+
718+ static void check_access_finish_cb(pa_access_data *data, bool res) {
719++ uint32_t command, tag;
720+ pa_protocol_native_access_data *d = (pa_protocol_native_access_data *) data;
721+ pa_native_connection *c = PA_NATIVE_CONNECTION(d->userdata);
722+
723+@@ -5639,6 +5647,11 @@ static void check_access_finish_cb(pa_access_data *data, bool res) {
724+ goto finish;
725+ }
726+
727++ pa_assert_se(pa_tagstruct_getu32(d->tc, &command) >= 0);
728++ pa_assert_se(pa_tagstruct_getu32(d->tc, &tag) >= 0);
729++ pa_assert(command == d->command);
730++ pa_assert(tag == d->tag);
731++
732+ /* call the dispatcher again, hopefully this time, the access check will
733+ * fail or succeed immediately */
734+ command_table[d->command](d->pd, d->command, d->tag, d->tc, d->userdata);
735diff --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
736deleted file mode 100644
737index 311a0fe..0000000
738--- a/debian/patches/0410-Add-thread-to-activate-trust-store-interface.patch
739+++ /dev/null
740@@ -1,108 +0,0 @@
741-From 90dbf1d25e12b9cfc86aecbd02f14a05fd5dca8c Mon Sep 17 00:00:00 2001
742-From: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
743-Date: Fri, 7 Aug 2015 09:08:02 +0200
744-Subject: [PATCH] Add thread to activate trust-store interface
745-
746----
747- src/modules/trust-store/module-trust-store.c | 14 +-------------
748- src/modules/trust-store/truststore.cc | 19 +++++++++++++++++++
749- 2 files changed, 20 insertions(+), 13 deletions(-)
750-
751-Index: pulseaudio/src/modules/trust-store/module-trust-store.c
752-===================================================================
753---- pulseaudio.orig/src/modules/trust-store/module-trust-store.c
754-+++ pulseaudio/src/modules/trust-store/module-trust-store.c
755-@@ -28,6 +28,7 @@
756- #include <pulsecore/fdsem.h>
757- #include <pulsecore/thread.h>
758- #include <pulsecore/core-util.h>
759-+#include <pulsecore/dynarray.h>
760- #include <pulse/mainloop-api.h>
761-
762- #include "module-trust-store-symdef.h"
763-@@ -173,18 +174,6 @@ static pa_hook_result_t connect_record_h
764- return PA_HOOK_CANCEL;
765- }
766-
767--/* Test code - remove from final product */
768--static void test(struct userdata *u) {
769-- uint32_t dummy;
770-- pa_client *client;
771--
772-- PA_IDXSET_FOREACH(client, u->core->clients, dummy) {
773-- if (client->creds_valid)
774-- pa_trust_store_check(u->ts, "The evil app", client->creds.uid,
775-- client->creds.pid, "%1% wants to eat your laundry.");
776-- }
777--}
778--
779- int pa__init(pa_module *m) {
780- struct userdata *u;
781- pa_trust_store *ts = pa_trust_store_new();
782-@@ -204,7 +193,6 @@ int pa__init(pa_module *m) {
783- pa_fdsem_get(u->fdsem), PA_IO_EVENT_INPUT, check_fdsem, u));
784- pa_fdsem_before_poll(u->fdsem);
785-
786-- test(u);
787- return 0;
788- }
789-
790-Index: pulseaudio/src/modules/trust-store/truststore.cc
791-===================================================================
792---- pulseaudio.orig/src/modules/trust-store/truststore.cc
793-+++ pulseaudio/src/modules/trust-store/truststore.cc
794-@@ -4,6 +4,7 @@
795-
796- #include <memory>
797- #include <core/dbus/bus.h>
798-+#include <core/dbus/asio/executor.h>
799- #include <core/trust/dbus_agent.h>
800- #include <core/trust/agent.h>
801-
802-@@ -13,6 +14,7 @@ PA_C_DECL_BEGIN
803- #include <pulsecore/core-util.h>
804- #include <pulse/xmalloc.h>
805- #include <pulsecore/log.h>
806-+#include <pulsecore/thread.h>
807-
808- #include "truststore.h"
809- PA_C_DECL_END
810-@@ -20,14 +22,27 @@ PA_C_DECL_END
811- class TrustStore {
812- public:
813- std::shared_ptr<core::trust::Agent> agent;
814-+ std::shared_ptr<core::dbus::Bus> bus;
815-+ pa_thread *thread;
816- };
817-
818-+static void thread_func(void *data) {
819-+ class TrustStore *ts = (class TrustStore *) data;
820-+
821-+ ts->bus->run();
822-+}
823-+
824- pa_trust_store* pa_trust_store_new() {
825- try {
826- auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
827-+ bus->install_executor(core::dbus::asio::make_executor(bus));
828-+
829- auto agent = core::trust::dbus::create_multi_user_agent_for_bus_connection(bus, "PulseAudio");
830- auto ts = new TrustStore();
831- ts->agent = agent;
832-+ ts->bus = bus;
833-+ ts->thread = pa_thread_new("trust-store-bus", thread_func, ts);
834-+
835- return (pa_trust_store *) ts;
836- } catch(const std::exception &e) {
837- pa_log_error("Could not create Ubuntu touch trust store connection: %s",
838-@@ -41,6 +56,10 @@ pa_trust_store* pa_trust_store_new() {
839- void pa_trust_store_free(pa_trust_store *t) {
840- pa_assert(t != NULL);
841- auto ts = (TrustStore*) t;
842-+ if (ts->thread) {
843-+ ts->bus->stop();
844-+ pa_thread_free(ts->thread);
845-+ }
846- delete ts;
847- }
848-
849diff --git a/debian/patches/0417-increase-timeout-check-apparmor.patch b/debian/patches/0417-increase-timeout-check-apparmor.patch
850deleted file mode 100644
851index 9571a8a..0000000
852--- a/debian/patches/0417-increase-timeout-check-apparmor.patch
853+++ /dev/null
854@@ -1,102 +0,0 @@
855-Index: pulseaudio/src/modules/trust-store/module-trust-store.c
856-===================================================================
857---- pulseaudio.orig/src/modules/trust-store/module-trust-store.c
858-+++ pulseaudio/src/modules/trust-store/module-trust-store.c
859-@@ -31,6 +31,8 @@
860- #include <pulsecore/dynarray.h>
861- #include <pulse/mainloop-api.h>
862-
863-+#include <sys/apparmor.h>
864-+
865- #include "module-trust-store-symdef.h"
866-
867- PA_MODULE_AUTHOR("David Henningsson");
868-@@ -77,9 +79,37 @@ static struct per_client *per_client_new
869- }
870-
871- pc = pa_xnew0(struct per_client, 1);
872-- // TODO: Do we need something else than the application name here -
873-- // the application can probably spoof it
874-- pc->appname = pa_xstrdup(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
875-+
876-+ pa_log_info("Client application name is: '%s'", pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME));
877-+
878-+ // ask apparmor about the context of the client, later this will be used to decide if the
879-+ // app should be or not using the trust store
880-+
881-+ if (aa_is_enabled()) {
882-+ char *context = NULL;
883-+ char *mode = NULL;
884-+
885-+ /* XXX: The mode string is *NOT* be freed since it forms
886-+ * part of the allocation returned in context.
887-+ *
888-+ * See aa_gettaskcon(2) for details.
889-+ */
890-+ if (aa_gettaskcon (client->creds.pid, &context, &mode) >= 0) {
891-+ pc->appname = pa_xstrdup(context);
892-+ pa_log_info("Client apparmor profile is: '%s'", context);
893-+ } else {
894-+ pa_log_error("AppArmo profile could not be retrieved.");
895-+ }
896-+
897-+ if (context)
898-+ free(context);
899-+
900-+ } else {
901-+ // while we do leave the appname as empty if we fail, if apparmor is not present we should
902-+ // assume that the app is not confined
903-+ pc->appname = pa_xstrdup("unconfined");
904-+ }
905-+
906- pc->index = client_index;
907- pc->uid = client->creds.uid;
908- pc->pid = client->creds.pid;
909-@@ -103,13 +133,28 @@ static void per_client_free_from_hashmap
910- static void thread_func(void *data) {
911- struct per_client *pc = data;
912-
913-- bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
914-- /// TRANSLATORS: The app icon and name appears above this string. If the phrase
915-- /// can't be translated in this language, translate the whole sentence
916-- /// 'This app wants to record audio.'
917-- _("wants to record audio."));
918-+ // there are 3 possible values for the app name that we will consider at this point
919-+ // * empty string: there was an error when retrieving the value and therefore we will
920-+ // automatically deny access
921-+ // * unconfined: the app is unconfined and therefore we will automatically grant access
922-+ // * appname: we need the user to decide what to do.
923-+
924-+ if (pc->appname == NULL) {
925-+ pa_log_info("Client apparmor could not retrieved.");
926-+ pa_atomic_store(&pc->result, REQUEST_DENIED);
927-+ } else if (pa_streq(pc->appname, "unconfined")) {
928-+ pa_log_info("Connected client is unconfined.");
929-+ pa_atomic_store(&pc->result, REQUEST_GRANTED);
930-+ } else {
931-+ pa_log_info("User needs to authorize the application..");
932-+ bool result = pa_trust_store_check(pc->userdata->ts, pc->appname, pc->uid, pc->pid,
933-+ /// TRANSLATORS: The app icon and name appears above this string. If the phrase
934-+ /// can't be translated in this language, translate the whole sentence
935-+ /// 'This app wants to record audio.'
936-+ _("wants to record audio."));
937-+ pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
938-+ }
939-
940-- pa_atomic_store(&pc->result, result ? REQUEST_GRANTED : REQUEST_DENIED);
941- pa_fdsem_post(pc->userdata->fdsem);
942- }
943-
944-Index: pulseaudio/src/Makefile.am
945-===================================================================
946---- pulseaudio.orig/src/Makefile.am
947-+++ pulseaudio/src/Makefile.am
948-@@ -2096,7 +2096,7 @@ libtruststore_util_la_LIBADD = libpulsec
949- libtruststore_util_la_LDFLAGS = -avoid-version
950-
951- module_trust_store_la_SOURCES = modules/trust-store/module-trust-store.c
952--module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS)
953-+module_trust_store_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor
954- module_trust_store_la_LIBADD = $(MODULE_LIBADD) libtruststore-util.la
955- module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
956- endif
957diff --git a/debian/patches/0700-modules-add-snappy-policy-module.patch b/debian/patches/0700-modules-add-snappy-policy-module.patch
958index 774374d..af1157f 100644
959--- a/debian/patches/0700-modules-add-snappy-policy-module.patch
960+++ b/debian/patches/0700-modules-add-snappy-policy-module.patch
961@@ -1,68 +1,107 @@
962-From a430ebc2271f5a07389ee25631a8ba5524371764 Mon Sep 17 00:00:00 2001
963-From: Simon Fels <simon.fels@canonical.com>
964-Date: Tue, 17 May 2016 17:29:31 +0200
965-Subject: [PATCH] modules: add snappy policy module
966+From: James Henstridge <james.henstridge@canonical.com>
967+Date: Tue, 7 Aug 2018 12:40:59 +0800
968+Subject: [PATCH] modules: add snap policy module
969
970+Forwarded: not-needed
971+
972+This patch allows pulseaudio to limit audio recording to snaps with
973+the audio-recording interface connected. We will not pursue upstreaming
974+this patch as the longer term solution will probably use PipeWire.
975+
976+Co-authored-by: Simon Fels <simon.fels@canonical.com>
977 ---
978- configure.ac | 18 +++++++-
979- src/Makefile.am | 18 ++++++++
980- src/modules/module-snappy-policy.c | 94 ++++++++++++++++++++++++++++++++++++++
981- 3 files changed, 129 insertions(+), 1 deletion(-)
982- create mode 100644 src/modules/module-snappy-policy.c
983+ configure.ac | 17 ++
984+ src/Makefile.am | 13 ++
985+ src/modules/module-snap-policy.c | 384 +++++++++++++++++++++++++++++++++++++++
986+ 3 files changed, 414 insertions(+)
987+ create mode 100644 src/modules/module-snap-policy.c
988
989-Index: pulseaudio/src/Makefile.am
990-===================================================================
991---- pulseaudio.orig/src/Makefile.am
992-+++ pulseaudio/src/Makefile.am
993-@@ -1241,6 +1241,11 @@ modlibexec_LTLIBRARIES += \
994+diff --git a/configure.ac b/configure.ac
995+index 77b5ff5..34b58ef 100644
996+--- a/configure.ac
997++++ b/configure.ac
998+@@ -1412,6 +1412,21 @@ AS_IF([test "x$os_is_win32" != "x1"],
999+ AS_IF([test "x$ax_pthread_ok" = "xyes"],
1000+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
1001+
1002++# Snappy support
1003++
1004++AC_ARG_ENABLE([snap],
1005++ AS_HELP_STRING([--enable-snap], [Enable snap support]))
1006++
1007++have_apparmor=0
1008++have_snapd_glib=0
1009++AS_IF([test "x$enable_snap" != "xno"],
1010++ [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [have_apparmor=1])
1011++ PKG_CHECK_MODULES(SNAPD_GLIB, [snapd-glib], [have_snapd_glib=1])])
1012++
1013++AS_IF([test "x$enable_snap" = "xyes" && test "x$have_apparmor" = "x0" -o "x$have-snapd_glib" = "x0"],
1014++ [AC_MSG_ERROR([*** Snap module dependencies missing])])
1015++
1016++AM_CONDITIONAL([BUILD_SNAP], [test "x$enable_snap" = "xyes"])
1017+
1018+
1019+ ###################################
1020+@@ -1588,6 +1603,7 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x$USE_PER_USER_ESOUND_SOCKET" = "x1"], EN
1021+ AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no)
1022+ AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no)
1023+ AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no)
1024++AS_IF([test "x$enable_snap" != "xno"], ENABLE_SNAP=yes, ENABLE_SNAP=no)
1025+
1026+ echo "
1027+ ---{ $PACKAGE_NAME $VERSION }---
1028+@@ -1643,6 +1659,7 @@ echo "
1029+ Enable speex (resampler, AEC): ${ENABLE_SPEEX}
1030+ Enable soxr (resampler): ${ENABLE_SOXR}
1031+ Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
1032++ Enable Snap support: ${ENABLE_SNAP}
1033+ Enable gcov coverage: ${ENABLE_GCOV}
1034+ Enable unit tests: ${ENABLE_TESTS}
1035+ Database
1036+diff --git a/src/Makefile.am b/src/Makefile.am
1037+index d49a6af..eb32f56 100644
1038+--- a/src/Makefile.am
1039++++ b/src/Makefile.am
1040+@@ -1232,6 +1232,11 @@ modlibexec_LTLIBRARIES += \
1041 module-esound-sink.la
1042 endif
1043
1044-+if HAVE_APPARMOR
1045++if BUILD_SNAP
1046 +modlibexec_LTLIBRARIES += \
1047-+ module-snappy-policy.la
1048++ module-snap-policy.la
1049 +endif
1050 +
1051 # See comment at librtp.la above
1052 if !OS_IS_WIN32
1053 modlibexec_LTLIBRARIES += \
1054-@@ -1582,6 +1587,11 @@ SYMDEF_FILES += \
1055- module-esound-sink-symdef.h
1056- endif
1057-
1058-+if HAVE_APPARMOR
1059-+SYMDEF_FILES += \
1060-+ module-snappy-policy-symdef.h
1061-+endif
1062-+
1063- EXTRA_DIST += $(SYMDEF_FILES)
1064- BUILT_SOURCES += $(SYMDEF_FILES) builddirs
1065-
1066-@@ -2101,6 +2111,14 @@ module_trust_store_la_LIBADD = $(MODULE_
1067- module_trust_store_la_CFLAGS = $(AM_CFLAGS) -DHAVE_TRUST_STORE=1
1068+@@ -2077,6 +2082,14 @@ module_echo_cancel_la_CFLAGS += -DHAVE_WEBRTC=1
1069+ module_echo_cancel_la_LIBADD += libwebrtc-util.la
1070 endif
1071
1072 +# Snappy
1073-+if HAVE_APPARMOR
1074-+module_snappy_policy_la_SOURCES = modules/module-snappy-policy.c
1075-+module_snappy_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -lapparmor
1076-+module_snappy_policy_la_LIBADD = $(MODULE_LIBADD)
1077-+module_snappy_policy_la_CFLAGS = $(AM_CFLAGS) -DHAVE_SNAPPY=1
1078++if BUILD_SNAP
1079++module_snap_policy_la_SOURCES = modules/module-snap-policy.c
1080++module_snap_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
1081++module_snap_policy_la_LIBADD = $(MODULE_LIBADD) $(APPARMOR_LIBS) $(SNAPD_GLIB_LIBS)
1082++module_snap_policy_la_CFLAGS = $(AM_CFLAGS) $(APPARMOR_CFLAGS) $(SNAPD_GLIB_CFLAGS) -DPA_MODULE_NAME=module_snap_policy
1083 +endif
1084 +
1085 # RTP modules
1086 module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
1087 module_rtp_send_la_LDFLAGS = $(MODULE_LDFLAGS)
1088-Index: pulseaudio/src/modules/module-snappy-policy.c
1089-===================================================================
1090+diff --git a/src/modules/module-snap-policy.c b/src/modules/module-snap-policy.c
1091+new file mode 100644
1092+index 0000000..0a1f5f4
1093 --- /dev/null
1094-+++ pulseaudio/src/modules/module-snappy-policy.c
1095-@@ -0,0 +1,98 @@
1096++++ b/src/modules/module-snap-policy.c
1097+@@ -0,0 +1,384 @@
1098 +/***
1099 + This file is part of PulseAudio.
1100 +
1101-+ Copyright 2016 Canonical Ltd.
1102-+ Written by Simon Fels <simon.fels@canonical.com>
1103++ Copyright 2018 Canonical Ltd.
1104++ Authors:
1105++ Simon Fels <simon.fels@canonical.com>
1106++ James Henstridge <james.henstridge@canonical.com>
1107 +
1108 + PulseAudio is free software; you can redistribute it and/or modify
1109 + it under the terms of the GNU Lesser General Public License as published
1110@@ -83,118 +122,360 @@ Index: pulseaudio/src/modules/module-snappy-policy.c
1111 +#endif
1112 +
1113 +#include <sys/apparmor.h>
1114-+#include <errno.h>
1115++#include <glib.h>
1116++#include <snapd-glib/snapd-glib.h>
1117 +
1118-+#include <pulsecore/i18n.h>
1119++#include <pulsecore/asyncq.h>
1120 +#include <pulsecore/core.h>
1121++#include <pulsecore/idxset.h>
1122++#include <pulsecore/hashmap.h>
1123 +#include <pulsecore/module.h>
1124-+#include <pulse/xmalloc.h>
1125-+#include <pulsecore/fdsem.h>
1126++#include <pulsecore/mutex.h>
1127 +#include <pulsecore/thread.h>
1128-+#include <pulsecore/core-util.h>
1129 +#include <pulse/mainloop-api.h>
1130-+
1131-+#include "module-snappy-policy-symdef.h"
1132++#include <pulse/xmalloc.h>
1133 +
1134 +#define SNAP_LABEL_PREFIX "snap."
1135 +#define SNAP_LABEL_PREFIX_LENGTH 5
1136 +
1137-+PA_MODULE_AUTHOR("Simon Fels");
1138-+PA_MODULE_DESCRIPTION("Ubuntu Snappy policy management");
1139++PA_MODULE_AUTHOR("Canonical Ltd");
1140++PA_MODULE_DESCRIPTION("Ubuntu Snap policy management");
1141 +PA_MODULE_VERSION(PACKAGE_VERSION);
1142 +PA_MODULE_LOAD_ONCE(true);
1143 +
1144++struct per_client {
1145++ struct userdata *userdata;
1146++ uint32_t index;
1147++ char *snap_name;
1148++ pa_dynarray *pending_requests; /* of pa_access_data */
1149++ bool completed;
1150++ bool grant_access;
1151++};
1152++
1153 +struct userdata {
1154-+ pa_core *core;
1155++ pa_io_event *io_event;
1156 + pa_hook_slot *connect_hook_slot;
1157++
1158++ pa_thread *thread;
1159++ pa_mutex *mutex;
1160++ pa_cond *cond;
1161++
1162++ pa_hashmap *clients; /* int => struct per_client */
1163++ pa_asyncq *results; /* of struct per_client */
1164++
1165++ /* Data owned by glib thread */
1166++ GMainContext *main_context;
1167++ GMainLoop *main_loop;
1168++ GCancellable *cancellable;
1169++ SnapdClient *snapd;
1170 +};
1171 +
1172-+static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d, struct userdata *u) {
1173-+ pa_client *client = pa_idxset_get_by_index(u->core->clients, d->client_index);
1174-+ if (!client)
1175-+ return PA_HOOK_OK;
1176-+
1177-+ char *label = NULL;
1178-+ char *mode = NULL;
1179-+ if (aa_gettaskcon(client->creds.pid, &label, &mode) < 0) {
1180-+ pa_log_warn("Failed to retrieve apparmor security label for pid %u: %s",
1181-+ client->creds.pid, strerror(-errno));
1182-+ return PA_HOOK_OK;
1183++/* ---- Code running in glib thread ---- */
1184++
1185++static void complete_check_access(struct per_client *pc, bool grant_access)
1186++{
1187++ struct userdata *u = pc->userdata;
1188++
1189++ pa_mutex_lock(u->mutex);
1190++ pc->grant_access = grant_access;
1191++ pc->completed = true;
1192++ pa_asyncq_push(u->results, pc, true);
1193++ pa_mutex_unlock(u->mutex);
1194++}
1195++
1196++static void get_interfaces_finished(GObject *source_object,
1197++ GAsyncResult *result,
1198++ gpointer user_data)
1199++{
1200++ struct per_client *pc = user_data;
1201++ struct userdata *u = pc->userdata;
1202++ bool grant_access = false;
1203++ g_autoptr(GError) error = NULL;
1204++ g_autoptr(GPtrArray) plugs = NULL;
1205++ unsigned i;
1206++
1207++ if (!snapd_client_get_interfaces_finish(u->snapd, result, &plugs, NULL, &error)) {
1208++ pa_log_warn("snapd_client_get_interfaces failed: %s", error->message);
1209++ goto end;
1210++ }
1211++
1212++ /* determine pc->grant_access */
1213++ for (i = 0; i < plugs->len; i++) {
1214++ SnapdPlug *plug = plugs->pdata[i];
1215++ const char *snap_name = snapd_plug_get_snap(plug);
1216++ const char *iface = snapd_plug_get_interface(plug);
1217++ const bool connected = snapd_plug_get_connections(plug)->len != 0;
1218++
1219++ /* We are only interested in connected plugs of our snap */
1220++ if (!connected || strcmp(snap_name, pc->snap_name) != 0) {
1221++ continue;
1222++ }
1223++ if (!strcmp(iface, "pulseaudio") || !strcmp(iface, "audio-record")) {
1224++ grant_access = true;
1225++ break;
1226++ }
1227++ }
1228++
1229++end:
1230++ complete_check_access(pc, grant_access);
1231++}
1232++
1233++static void get_snap_finished(GObject *source_object,
1234++ GAsyncResult *result,
1235++ gpointer user_data)
1236++{
1237++ struct per_client *pc = user_data;
1238++ struct userdata *u = pc->userdata;
1239++ g_autoptr(GError) error = NULL;
1240++ g_autoptr(SnapdSnap) snap = NULL;
1241++
1242++ snap = snapd_client_list_one_finish(u->snapd, result, &error);
1243++ if (!snap) {
1244++ pa_log_warn("snapd_client_get_snap failed: %s", error->message);
1245++ complete_check_access(pc, false);
1246++ return;
1247++ }
1248++
1249++ /* Snaps using classic confinement are granted access */
1250++ if (snapd_snap_get_confinement(snap) == SNAPD_CONFINEMENT_CLASSIC) {
1251++ complete_check_access(pc, true);
1252++ return;
1253++ }
1254++
1255++ /* We have a non-classic snap, we need to check its connected
1256++ * interfaces */
1257++ snapd_client_get_interfaces_async(u->snapd, u->cancellable,
1258++ get_interfaces_finished, pc);
1259++}
1260++
1261++
1262++static gboolean check_access(void *data)
1263++{
1264++ struct per_client *pc = data;
1265++ struct userdata *u = pc->userdata;
1266++
1267++ snapd_client_list_one_async(u->snapd, pc->snap_name, u->cancellable,
1268++ get_snap_finished, pc);
1269++ return G_SOURCE_REMOVE;
1270++}
1271++
1272++
1273++static void thread_main(void *data) {
1274++ struct userdata *u = data;
1275++
1276++ pa_mutex_lock(u->mutex);
1277++
1278++ u->main_context = g_main_context_new();
1279++ g_main_context_push_thread_default(u->main_context);
1280++ u->main_loop = g_main_loop_new(u->main_context, false);
1281++ u->cancellable = g_cancellable_new();
1282++ u->snapd = snapd_client_new();
1283++
1284++ /* Signal main thread that we've finished initialisation */
1285++ pa_cond_signal(u->cond, false);
1286++ pa_mutex_unlock(u->mutex);
1287++
1288++ pa_log_info("Starting GLib main loop");
1289++ g_main_loop_run(u->main_loop);
1290++ pa_log_info("GLib main loop exited");
1291++
1292++ g_cancellable_cancel(u->cancellable);
1293++
1294++ g_clear_object(&u->snapd);
1295++ g_clear_object(&u->cancellable);
1296++ g_main_context_pop_thread_default(u->main_context);
1297++ g_clear_pointer(&u->main_loop, g_main_loop_unref);
1298++ g_clear_pointer(&u->main_context, g_main_context_unref);
1299++}
1300++
1301++static gboolean thread_quit(void *data)
1302++{
1303++ struct userdata *u = data;
1304++
1305++ g_main_loop_quit(u->main_loop);
1306++ return G_SOURCE_REMOVE;
1307++}
1308++
1309++/* ---- Code running in main thread ---- */
1310++
1311++static struct per_client *per_client_new(struct userdata *u,
1312++ uint32_t client_index,
1313++ char *snap_name) {
1314++ struct per_client *pc = pa_xnew0(struct per_client, 1);
1315++ pc->userdata = u;
1316++ pc->index = client_index;
1317++ pc->snap_name = snap_name;
1318++ pc->pending_requests = pa_dynarray_new(NULL);
1319++ pc->completed = false;
1320++ pc->grant_access = false;
1321++ return pc;
1322++}
1323++
1324++static void per_client_free(struct per_client *pc) {
1325++ if (!pc) return;
1326++ pa_xfree(pc->snap_name);
1327++ pa_dynarray_free(pc->pending_requests);
1328++ pa_xfree(pc);
1329++}
1330++
1331++static char *client_get_snap_name(pa_core *core, uint32_t client_index) {
1332++ pa_client *client;
1333++ char *context = NULL;
1334++ char *snap_name = NULL;
1335++ char *dot;
1336++
1337++ client = pa_idxset_get_by_index(core->clients, client_index);
1338++ pa_assert(client != NULL);
1339++ if (!client->creds_valid) {
1340++ pa_log_warn("Client %u has no creds, cannot authenticate", client_index);
1341++ goto end;
1342++ }
1343++
1344++ /* If AppArmor is not enabled, then we can't identify the client */
1345++ if (!aa_is_enabled()) {
1346++ goto end;
1347 + }
1348++ if (aa_gettaskcon(client->creds.pid, &context, NULL) < 0) {
1349++ pa_log_error("AppArmor profile could not be retrieved.");
1350++ goto end;
1351++ }
1352++
1353++ /* If the AppArmor context does not begin with "snap.", then this
1354++ * is not a snap */
1355++ if (strncmp(context, SNAP_LABEL_PREFIX, SNAP_LABEL_PREFIX_LENGTH) != 0) {
1356++ goto end;
1357++ }
1358++
1359++ dot = strchr(context+SNAP_LABEL_PREFIX_LENGTH, '.');
1360++ if (dot == NULL) {
1361++ pa_log_warn("Malformed snapd AppArmor profile name: %s", context);
1362++ goto end;
1363++ }
1364++ snap_name = pa_xstrndup(context+5, dot-context-SNAP_LABEL_PREFIX_LENGTH);
1365++
1366++end:
1367++ free(context);
1368++ return snap_name;
1369++}
1370++
1371++static pa_hook_result_t connect_record_hook(pa_core *core, pa_access_data *d,
1372++ struct userdata *u) {
1373++ pa_hook_result_t result = PA_HOOK_STOP;
1374++ struct per_client *pc = NULL;
1375++ char *snap_name = NULL;
1376 +
1377-+ pa_hook_result_t decision = PA_HOOK_OK;
1378++ pa_mutex_lock(u->mutex);
1379++ pc = pa_hashmap_get(u->clients, (void *)(size_t)d->client_index);
1380++ if (pc) {
1381++ if (pc->completed) {
1382++ result = pc->grant_access ? PA_HOOK_OK : PA_HOOK_STOP;
1383++ } else {
1384++ /* A permission check for this snap is currently in progress */
1385++ pa_dynarray_append(pc->pending_requests, d);
1386++ result = PA_HOOK_CANCEL;
1387++ }
1388++ goto end;
1389++ }
1390++
1391++ snap_name = client_get_snap_name(core, d->client_index);
1392++ if (!snap_name) {
1393++ /* Not a snap, so allow access */
1394++ result = PA_HOOK_OK;
1395++ goto end;
1396++ }
1397++
1398++ /* create new per client struct, and submit to glib thread */
1399++ pc = per_client_new(u, d->client_index, snap_name);
1400++ pa_dynarray_append(pc->pending_requests, d);
1401++ pa_hashmap_put(u->clients, (void *) (size_t) d->client_index, pc);
1402++ pa_log_info("Checking access for client %d (%s)", pc->index, pc->snap_name);
1403++ g_main_context_invoke(u->main_context, check_access, pc);
1404 +
1405-+ // We only cancel the attempt of the client to start audio recording
1406-+ // when we could successfully determine that the request is coming
1407-+ // from an app which is part of a snap. Otherwise we continue to
1408-+ // work as normal.
1409-+ if (label && strncmp(SNAP_LABEL_PREFIX, label, SNAP_LABEL_PREFIX_LENGTH) == 0)
1410-+ decision = PA_HOOK_CANCEL;
1411++ result = PA_HOOK_CANCEL;
1412 +
1413-+ free(label);
1414++end:
1415++ pa_mutex_unlock(u->mutex);
1416++ return result;
1417++}
1418++
1419++static void deliver_result(struct userdata *u, struct per_client *pc) {
1420++ pa_access_data *ad;
1421++ unsigned i;
1422 +
1423-+ return decision;
1424++ pa_log_info("Access check for client %u (%s): %d",
1425++ pc->index, pc->snap_name, pc->grant_access);
1426++
1427++ /* Call the hooks without holding the mutex, since this will
1428++ * recurse into connect_record_hook. Access to pending_requests
1429++ * should be safe here, since connect_record_hook wont alter the
1430++ * array when the access check is complete. */
1431++ PA_DYNARRAY_FOREACH(ad, pc->pending_requests, i) {
1432++ ad->async_finish_cb(ad, pc->grant_access);
1433++ }
1434++ pa_mutex_lock(u->mutex);
1435++ pa_hashmap_remove_and_free(u->clients, (void *) (size_t) pc->index);
1436++ pa_mutex_unlock(u->mutex);
1437++}
1438++
1439++static void check_result(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
1440++ struct userdata *u = userdata;
1441++ struct per_client *pc;
1442++
1443++ pa_asyncq_read_after_poll(u->results);
1444++ while ((pc = pa_asyncq_pop(u->results, false)) != NULL) {
1445++ deliver_result(u, pc);
1446++ }
1447++ pa_asyncq_read_before_poll(u->results);
1448 +}
1449 +
1450 +int pa__init(pa_module *m) {
1451 + struct userdata *u;
1452-+ u = pa_xnew0(struct userdata, 1);
1453-+ u->core = m->core;
1454 +
1455++ u = pa_xnew0(struct userdata, 1);
1456 + m->userdata = u;
1457-+ u->connect_hook_slot = pa_hook_connect(&m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD],
1458-+ PA_HOOK_NORMAL, (pa_hook_cb_t) connect_record_hook, u);
1459++ u->mutex = pa_mutex_new(false, false);
1460++ u->cond = pa_cond_new();
1461++
1462++ u->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func,
1463++ pa_idxset_trivial_compare_func,
1464++ NULL, (pa_free_cb_t) per_client_free);
1465++
1466++ u->results = pa_asyncq_new(0);
1467++ u->io_event = m->core->mainloop->io_new(
1468++ m->core->mainloop, pa_asyncq_read_fd(u->results), PA_IO_EVENT_INPUT,
1469++ check_result, u);
1470++ pa_asyncq_read_before_poll(u->results);
1471++
1472++ u->connect_hook_slot = pa_hook_connect(
1473++ &m->core->access[PA_ACCESS_HOOK_CONNECT_RECORD], PA_HOOK_NORMAL,
1474++ (pa_hook_cb_t) connect_record_hook, u);
1475++
1476++ /* Start glib thread and wait for it to finish initialising. */
1477++ pa_mutex_lock(u->mutex);
1478++ u->thread = pa_thread_new("snapd-glib", thread_main, u);
1479++ pa_cond_wait(u->cond, u->mutex);
1480++ pa_mutex_unlock(u->mutex);
1481 +
1482 + return 0;
1483 +}
1484 +
1485 +void pa__done(pa_module *m) {
1486 + struct userdata *u = m->userdata;
1487-+ if (u) {
1488-+ if (u->connect_hook_slot)
1489-+ pa_hook_slot_free(u->connect_hook_slot);
1490-+ pa_xfree(u);
1491-+ }
1492-+}
1493-Index: pulseaudio/configure.ac
1494-===================================================================
1495---- pulseaudio.orig/configure.ac
1496-+++ pulseaudio/configure.ac
1497-@@ -1412,6 +1412,19 @@ AS_IF([test "x$os_is_win32" != "x1"],
1498- AS_IF([test "x$ax_pthread_ok" = "xyes"],
1499- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], 1, [Needed on Solaris]))
1500-
1501-+# Snappy support
1502++ if (!u) return;
1503 +
1504-+AC_ARG_ENABLE([snappy],
1505-+ AS_HELP_STRING([--enable-snappy], [Enable snappy support]))
1506++ pa_hook_slot_free(u->connect_hook_slot);
1507++ m->core->mainloop->io_free(u->io_event);
1508 +
1509-+AS_IF([test "x$enable_snappy" != "xno"],
1510-+ [PKG_CHECK_MODULES(APPARMOR, [libapparmor], [HAVE_APPARMOR=1], [HAVE_APPARMOR=0])],
1511-+ [HAVE_APPARMOR=0])
1512++ /* Stop the glib thread and wait for it to exit */
1513++ g_main_context_invoke(u->main_context, thread_quit, u);
1514++ pa_thread_join(u->thread);
1515++ pa_thread_free(u->thread);
1516 +
1517-+AS_IF([test "x$enable_snappy" = "xyes" && test "x$HAVE_APPARMOR" = "x0"],
1518-+ [AC_MSG_ERROR([*** Apparmor library not found])])
1519++ pa_asyncq_free(u->results, NULL); /* items in queue owned by u->clients */
1520++ g_clear_pointer(&u->clients, pa_hashmap_free);
1521 +
1522-+AM_CONDITIONAL([HAVE_APPARMOR], [test "x$HAVE_APPARMOR" = "x1"])
1523-
1524- # Ubuntu touch trust store
1525-
1526-@@ -1602,6 +1615,8 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x
1527- AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no)
1528- AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no)
1529- AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no)
1530-+AS_IF([test "x$enable_snappy" = "x1"], ENABLE_SNAPPY=yes, ENABLE_SNAPPY=no)
1531-+AS_IF([test "x$HAVE_APPARMOR" = "x1"], ENABLE_APPARMOR=yes, ENABLE_APPARMOR=no)
1532-
1533- echo "
1534- ---{ $PACKAGE_NAME $VERSION }---
1535-@@ -1658,6 +1673,8 @@ echo "
1536- Enable soxr (resampler): ${ENABLE_SOXR}
1537- Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
1538- Enable Ubuntu trust store: ${ENABLE_TRUST_STORE}
1539-+ Enable Snappy support: ${ENABLE_SNAPPY}
1540-+ Enable Apparmor: ${ENABLE_APPARMOR}
1541- Enable gcov coverage: ${ENABLE_GCOV}
1542- Enable unit tests: ${ENABLE_TESTS}
1543- Database
1544++ g_clear_pointer(&u->cond, pa_cond_free);
1545++ g_clear_pointer(&u->mutex, pa_mutex_free);
1546++
1547++ pa_xfree(u);
1548++}
1549diff --git a/debian/patches/0701-enable-snap-policy-module.patch b/debian/patches/0701-enable-snap-policy-module.patch
1550new file mode 100644
1551index 0000000..47a23ab
1552--- /dev/null
1553+++ b/debian/patches/0701-enable-snap-policy-module.patch
1554@@ -0,0 +1,30 @@
1555+From: James Henstridge <james.henstridge@canonical.com>
1556+Date: Tue, 7 Aug 2018 16:54:00 +0800
1557+Subject: daemon: enable module-snap-policy module
1558+
1559+Forwarded: not-needed
1560+
1561+This patch allows pulseaudio to limit audio recording to snaps with
1562+the audio-recording interface connected. We will not pursue upstreaming
1563+this patch as the longer term solution will probably use PipeWire.
1564+---
1565+ src/daemon/default.pa.in | 6 ++++++
1566+ 1 file changed, 6 insertions(+)
1567+
1568+diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
1569+index a9a97c0..6c5e7bc 100755
1570+--- a/src/daemon/default.pa.in
1571++++ b/src/daemon/default.pa.in
1572+@@ -158,6 +158,12 @@ load-module module-position-event-sounds
1573+ ### Cork music/video streams when a phone stream is active
1574+ load-module module-role-cork
1575+
1576++### Block audio recording for snap confined packages unless they have
1577++### the "pulseaudio" or "audio-record" interfaces plugged.
1578++.ifexists module-snap-policy@PA_SOEXT@
1579++load-module module-snap-policy
1580++.endif
1581++
1582+ ### Modules to allow autoloading of filters (such as echo cancellation)
1583+ ### on demand. module-filter-heuristics tries to determine what filters
1584+ ### make sense, and module-filter-apply does the heavy-lifting of
1585diff --git a/debian/patches/series b/debian/patches/series
1586index e92ee34..c519269 100644
1587--- a/debian/patches/series
1588+++ b/debian/patches/series
1589@@ -5,16 +5,13 @@
1590 0022-inotify-wrapper-Quit-daemon-if-pid-file-is-removed.patch
1591 0030-load-module-switch-on-connect.patch
1592
1593-# Ubuntu touch: support for trust-store
1594+# Ubuntu Snap policy support
1595 0406-tagstruct-add-copy-method.patch
1596 0407-access-Add-access-control-hooks.patch
1597 0408-protocol-native-add-access-checks.patch
1598-0409-Trust-store-patch.patch
1599-0410-Add-thread-to-activate-trust-store-interface.patch
1600-0417-increase-timeout-check-apparmor.patch
1601-
1602-# Ubuntu Snappy
1603+0409-pa-client-peer-credentials.patch
1604 0700-modules-add-snappy-policy-module.patch
1605+0701-enable-snap-policy-module.patch
1606
1607 # Bug fixes backported from PulseAudio 12
1608 0800-fix-lp1720684.patch
1609diff --git a/debian/pulseaudio.install b/debian/pulseaudio.install
1610index 513b7ad..5586bfd 100755
1611--- a/debian/pulseaudio.install
1612+++ b/debian/pulseaudio.install
1613@@ -77,7 +77,7 @@ usr/lib/pulse-*/modules/module-virtual-sink.so
1614 usr/lib/pulse-*/modules/module-virtual-source.so
1615 usr/lib/pulse-*/modules/module-switch-on-port-available.so
1616 usr/lib/pulse-*/modules/module-virtual-surround-sink.so
1617-usr/lib/pulse-*/modules/module-snappy-policy.so
1618+usr/lib/pulse-*/modules/module-snap-policy.so
1619 usr/lib/pulse-*/modules/module-x11*.so
1620 usr/lib/pulse-*/modules/module-allow-passthrough.so
1621 [linux-any] usr/lib/pulse-*/modules/module-systemd-login.so
1622diff --git a/debian/rules b/debian/rules
1623index 3737dc5..32cc45f 100755
1624--- a/debian/rules
1625+++ b/debian/rules
1626@@ -22,7 +22,7 @@ DEB_CONFIGURE_EXTRA_FLAGS = --enable-x11 --disable-hal-compat \
1627 --with-zsh-completion-dir=\$${datadir}/zsh/vendor-completions \
1628 --with-bash-completion-dir=\$${datadir}/bash-completion/completions \
1629 --with-systemduserunitdir=\$${prefix}/lib/systemd/user \
1630- --disable-bluez4 --enable-snappy
1631+ --disable-bluez4 --enable-snap
1632
1633 PA_MAJORMINOR = $(shell echo $(DEB_VERSION_UPSTREAM) | sed -r -e 's/^([0-9]+\.[0-9]+).*/\1/')
1634

Subscribers

People subscribed via source and target branches