summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2023-05-15 17:33:01 +0100
committerSimon McVittie <smcv@collabora.com>2023-05-15 19:54:51 +0100
commitdb7a8bb598d34b65cecc32d7af9056f9e75ac611 (patch)
treee02ee06705695dd377d74cd39a9b229e84a6d5c6
parent1cbff35386f4e6584646199a26fdfe82e72d732b (diff)
downloadflatpak-db7a8bb598d34b65cecc32d7af9056f9e75ac611.tar.gz
common: Split up socket setup from flatpak-run into multiple files
flatpak-run is large enough to be getting unwieldy, so separate it out into various smaller modules. A side benefit of these is that they'll be easier to reuse in other projects, like Steam's pressure-vessel tool. Signed-off-by: Simon McVittie <smcv@collabora.com>
-rw-r--r--common/Makefile.am.inc10
-rw-r--r--common/flatpak-run-cups-private.h32
-rw-r--r--common/flatpak-run-cups.c127
-rw-r--r--common/flatpak-run-dbus-private.h52
-rw-r--r--common/flatpak-run-dbus.c449
-rw-r--r--common/flatpak-run-private.h7
-rw-r--r--common/flatpak-run-pulseaudio-private.h34
-rw-r--r--common/flatpak-run-pulseaudio.c338
-rw-r--r--common/flatpak-run-sockets-private.h37
-rw-r--r--common/flatpak-run-sockets.c278
-rw-r--r--common/flatpak-run-x11-private.h42
-rw-r--r--common/flatpak-run-x11.c333
-rw-r--r--common/flatpak-run.c1371
-rw-r--r--common/meson.build5
-rw-r--r--tests/testcommon.c1
15 files changed, 1744 insertions, 1372 deletions
diff --git a/common/Makefile.am.inc b/common/Makefile.am.inc
index aa4dc6e2..a6050289 100644
--- a/common/Makefile.am.inc
+++ b/common/Makefile.am.inc
@@ -161,6 +161,16 @@ libflatpak_common_la_SOURCES = \
common/flatpak-remote.c \
common/flatpak-run-private.h \
common/flatpak-run.c \
+ common/flatpak-run-cups-private.h \
+ common/flatpak-run-cups.c \
+ common/flatpak-run-dbus-private.h \
+ common/flatpak-run-dbus.c \
+ common/flatpak-run-pulseaudio-private.h \
+ common/flatpak-run-pulseaudio.c \
+ common/flatpak-run-sockets-private.h \
+ common/flatpak-run-sockets.c \
+ common/flatpak-run-x11-private.h \
+ common/flatpak-run-x11.c \
common/flatpak-syscalls-private.h \
common/flatpak-transaction-private.h \
common/flatpak-transaction.c \
diff --git a/common/flatpak-run-cups-private.h b/common/flatpak-run-cups-private.h
new file mode 100644
index 00000000..13c0b6d8
--- /dev/null
+++ b/common/flatpak-run-cups-private.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include "libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-common-types-private.h"
+
+G_BEGIN_DECLS
+
+void flatpak_run_add_cups_args (FlatpakBwrap *bwrap);
+
+G_END_DECLS
diff --git a/common/flatpak-run-cups.c b/common/flatpak-run-cups.c
new file mode 100644
index 00000000..c355e0f8
--- /dev/null
+++ b/common/flatpak-run-cups.c
@@ -0,0 +1,127 @@
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
+ * Copyright © 2014-2019 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#include "config.h"
+#include "flatpak-run-cups-private.h"
+
+#include "flatpak-utils-private.h"
+
+static gboolean
+flatpak_run_cups_check_server_is_socket (const char *server)
+{
+ if (g_str_has_prefix (server, "/") && strstr (server, ":") == NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Try to find a default server from a cups confguration file */
+static char *
+flatpak_run_get_cups_server_name_config (const char *path)
+{
+ g_autoptr(GFile) file = g_file_new_for_path (path);
+ g_autoptr(GError) my_error = NULL;
+ g_autoptr(GFileInputStream) input_stream = NULL;
+ g_autoptr(GDataInputStream) data_stream = NULL;
+ size_t len;
+
+ input_stream = g_file_read (file, NULL, &my_error);
+ if (my_error)
+ {
+ g_info ("CUPS configuration file '%s': %s", path, my_error->message);
+ return NULL;
+ }
+
+ data_stream = g_data_input_stream_new (G_INPUT_STREAM (input_stream));
+
+ while (TRUE)
+ {
+ g_autofree char *line = g_data_input_stream_read_line (data_stream, &len, NULL, NULL);
+ if (line == NULL)
+ break;
+
+ g_strchug (line);
+
+ if ((*line == '\0') || (*line == '#'))
+ continue;
+
+ g_auto(GStrv) tokens = g_strsplit (line, " ", 2);
+
+ if ((tokens[0] != NULL) && (tokens[1] != NULL))
+ {
+ if (strcmp ("ServerName", tokens[0]) == 0)
+ {
+ g_strchug (tokens[1]);
+
+ if (flatpak_run_cups_check_server_is_socket (tokens[1]))
+ return g_strdup (tokens[1]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static char *
+flatpak_run_get_cups_server_name (void)
+{
+ g_autofree char * cups_server = NULL;
+ g_autofree char * cups_config_path = NULL;
+
+ /* TODO
+ * we don't currently support cups servers located on the network, if such
+ * server is detected, we simply ignore it and in the worst case we fallback
+ * to the default socket
+ */
+ cups_server = g_strdup (g_getenv ("CUPS_SERVER"));
+ if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
+ return g_steal_pointer (&cups_server);
+ g_clear_pointer (&cups_server, g_free);
+
+ cups_config_path = g_build_filename (g_get_home_dir (), ".cups/client.conf", NULL);
+ cups_server = flatpak_run_get_cups_server_name_config (cups_config_path);
+ if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
+ return g_steal_pointer (&cups_server);
+ g_clear_pointer (&cups_server, g_free);
+
+ cups_server = flatpak_run_get_cups_server_name_config ("/etc/cups/client.conf");
+ if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
+ return g_steal_pointer (&cups_server);
+
+ // Fallback to default socket
+ return g_strdup ("/var/run/cups/cups.sock");
+}
+
+void
+flatpak_run_add_cups_args (FlatpakBwrap *bwrap)
+{
+ g_autofree char * sandbox_server_name = g_strdup ("/var/run/cups/cups.sock");
+ g_autofree char * cups_server_name = flatpak_run_get_cups_server_name ();
+
+ if (!g_file_test (cups_server_name, G_FILE_TEST_EXISTS))
+ {
+ g_info ("Could not find CUPS server");
+ return;
+ }
+
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", cups_server_name, sandbox_server_name,
+ NULL);
+}
diff --git a/common/flatpak-run-dbus-private.h b/common/flatpak-run-dbus-private.h
new file mode 100644
index 00000000..3b56264f
--- /dev/null
+++ b/common/flatpak-run-dbus-private.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include "libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-common-types-private.h"
+#include "flatpak-context-private.h"
+
+G_BEGIN_DECLS
+
+gboolean flatpak_run_add_session_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags,
+ const char *app_id);
+
+gboolean flatpak_run_add_system_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags);
+
+gboolean flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags);
+
+gboolean flatpak_run_maybe_start_dbus_proxy (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ const char *app_info_path,
+ GError **error);
+
+G_END_DECLS
diff --git a/common/flatpak-run-dbus.c b/common/flatpak-run-dbus.c
new file mode 100644
index 00000000..1706067b
--- /dev/null
+++ b/common/flatpak-run-dbus.c
@@ -0,0 +1,449 @@
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
+ * Copyright © 2014-2019 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#include "config.h"
+#include "flatpak-run-dbus-private.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <sys/vfs.h>
+
+#include "flatpak-utils-private.h"
+
+/* This wraps the argv in a bwrap call, primary to allow the
+ command to be run with a proper /.flatpak-info with data
+ taken from app_info_path */
+static gboolean
+add_bwrap_wrapper (FlatpakBwrap *bwrap,
+ const char *app_info_path,
+ GError **error)
+{
+ glnx_autofd int app_info_fd = -1;
+ g_auto(GLnxDirFdIterator) dir_iter = { 0 };
+ struct dirent *dent;
+ g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+ g_autofree char *proxy_socket_dir = g_build_filename (user_runtime_dir, ".dbus-proxy/", NULL);
+
+ app_info_fd = open (app_info_path, O_RDONLY | O_CLOEXEC);
+ if (app_info_fd == -1)
+ return glnx_throw_errno_prefix (error, _("Failed to open app info file"));
+
+ if (!glnx_dirfd_iterator_init_at (AT_FDCWD, "/", FALSE, &dir_iter, error))
+ return FALSE;
+
+ flatpak_bwrap_add_arg (bwrap, flatpak_get_bwrap ());
+
+ while (TRUE)
+ {
+ glnx_autofd int o_path_fd = -1;
+ struct statfs stfs;
+
+ if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dir_iter, &dent, NULL, error))
+ return FALSE;
+
+ if (dent == NULL)
+ break;
+
+ if (strcmp (dent->d_name, ".flatpak-info") == 0)
+ continue;
+
+ /* O_PATH + fstatfs is the magic that we need to statfs without automounting the target */
+ o_path_fd = openat (dir_iter.fd, dent->d_name, O_PATH | O_NOFOLLOW | O_CLOEXEC);
+ if (o_path_fd == -1 || fstatfs (o_path_fd, &stfs) != 0 || stfs.f_type == AUTOFS_SUPER_MAGIC)
+ continue; /* AUTOFS mounts are risky and can cause us to block (see issue #1633), so ignore it. Its unlikely the proxy needs such a directory. */
+
+ if (dent->d_type == DT_DIR)
+ {
+ if (strcmp (dent->d_name, "tmp") == 0 ||
+ strcmp (dent->d_name, "var") == 0 ||
+ strcmp (dent->d_name, "run") == 0)
+ flatpak_bwrap_add_arg (bwrap, "--bind");
+ else
+ flatpak_bwrap_add_arg (bwrap, "--ro-bind");
+
+ flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
+ flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
+ }
+ else if (dent->d_type == DT_LNK)
+ {
+ g_autofree gchar *target = NULL;
+
+ target = glnx_readlinkat_malloc (dir_iter.fd, dent->d_name,
+ NULL, error);
+ if (target == NULL)
+ return FALSE;
+ flatpak_bwrap_add_args (bwrap, "--symlink", target, NULL);
+ flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
+ }
+ }
+
+ flatpak_bwrap_add_args (bwrap, "--bind", proxy_socket_dir, proxy_socket_dir, NULL);
+
+ /* This is a file rather than a bind mount, because it will then
+ not be unmounted from the namespace when the namespace dies. */
+ flatpak_bwrap_add_args (bwrap, "--perms", "0600", NULL);
+ flatpak_bwrap_add_args_data_fd (bwrap, "--file", glnx_steal_fd (&app_info_fd), "/.flatpak-info");
+
+ if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+flatpak_run_maybe_start_dbus_proxy (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ const char *app_info_path,
+ GError **error)
+{
+ char x = 'x';
+ const char *proxy;
+ g_autofree char *commandline = NULL;
+ g_autoptr(FlatpakBwrap) proxy_bwrap = NULL;
+ int sync_fds[2] = {-1, -1};
+ int proxy_start_index;
+
+ if (flatpak_bwrap_is_empty (proxy_arg_bwrap))
+ {
+ g_debug ("D-Bus proxy not needed");
+ return TRUE;
+ }
+
+ proxy_bwrap = flatpak_bwrap_new (NULL);
+
+ if (!add_bwrap_wrapper (proxy_bwrap, app_info_path, error))
+ return FALSE;
+
+ proxy = g_getenv ("FLATPAK_DBUSPROXY");
+ if (proxy == NULL)
+ proxy = DBUSPROXY;
+
+ flatpak_bwrap_add_arg (proxy_bwrap, proxy);
+
+ proxy_start_index = proxy_bwrap->argv->len;
+
+ if (pipe2 (sync_fds, O_CLOEXEC) < 0)
+ {
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ _("Unable to create sync pipe"));
+ return FALSE;
+ }
+
+ /* read end goes to app */
+ flatpak_bwrap_add_args_data_fd (app_bwrap, "--sync-fd", sync_fds[0], NULL);
+
+ /* write end goes to proxy */
+ flatpak_bwrap_add_fd (proxy_bwrap, sync_fds[1]);
+ flatpak_bwrap_add_arg_printf (proxy_bwrap, "--fd=%d", sync_fds[1]);
+
+ /* Note: This steals the fds from proxy_arg_bwrap */
+ flatpak_bwrap_append_bwrap (proxy_bwrap, proxy_arg_bwrap);
+
+ if (!flatpak_bwrap_bundle_args (proxy_bwrap, proxy_start_index, -1, TRUE, error))
+ return FALSE;
+
+ flatpak_bwrap_finish (proxy_bwrap);
+
+ commandline = flatpak_quote_argv ((const char **) proxy_bwrap->argv->pdata, -1);
+ g_info ("Running '%s'", commandline);
+
+ /* We use LEAVE_DESCRIPTORS_OPEN to work around dead-lock, see flatpak_close_fds_workaround */
+ if (!g_spawn_async (NULL,
+ (char **) proxy_bwrap->argv->pdata,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
+ flatpak_bwrap_child_setup_cb, proxy_bwrap->fds,
+ NULL, error))
+ return FALSE;
+
+ /* The write end can be closed now, otherwise the read below will hang of xdg-dbus-proxy
+ fails to start. */
+ g_clear_pointer (&proxy_bwrap, flatpak_bwrap_free);
+
+ /* Sync with proxy, i.e. wait until its listening on the sockets */
+ if (read (sync_fds[0], &x, 1) != 1)
+ {
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ _("Failed to sync with dbus proxy"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static char *
+extract_unix_path_from_dbus_address (const char *address)
+{
+ const char *path, *path_end;
+
+ if (address == NULL)
+ return NULL;
+
+ if (!g_str_has_prefix (address, "unix:"))
+ return NULL;
+
+ path = strstr (address, "path=");
+ if (path == NULL)
+ return NULL;
+ path += strlen ("path=");
+ path_end = path;
+ while (*path_end != 0 && *path_end != ',')
+ path_end++;
+
+ return g_strndup (path, path_end - path);
+}
+
+static char *
+create_proxy_socket (char *template)
+{
+ g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+ g_autofree char *proxy_socket_dir = g_build_filename (user_runtime_dir, ".dbus-proxy", NULL);
+ g_autofree char *proxy_socket = g_build_filename (proxy_socket_dir, template, NULL);
+ int fd;
+
+ if (!glnx_shutil_mkdir_p_at (AT_FDCWD, proxy_socket_dir, 0755, NULL, NULL))
+ return NULL;
+
+ fd = g_mkstemp (proxy_socket);
+ if (fd == -1)
+ return NULL;
+
+ close (fd);
+
+ return g_steal_pointer (&proxy_socket);
+}
+
+gboolean
+flatpak_run_add_session_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags,
+ const char *app_id)
+{
+ static const char sandbox_socket_path[] = "/run/flatpak/bus";
+ static const char sandbox_dbus_address[] = "unix:path=/run/flatpak/bus";
+ gboolean unrestricted, no_proxy;
+ const char *dbus_address = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
+ g_autofree char *dbus_session_socket = NULL;
+
+ unrestricted = (context->sockets & FLATPAK_CONTEXT_SOCKET_SESSION_BUS) != 0;
+
+ if (dbus_address != NULL)
+ {
+ dbus_session_socket = extract_unix_path_from_dbus_address (dbus_address);
+ }
+ else
+ {
+ g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+ struct stat statbuf;
+
+ dbus_session_socket = g_build_filename (user_runtime_dir, "bus", NULL);
+
+ if (stat (dbus_session_socket, &statbuf) < 0
+ || (statbuf.st_mode & S_IFMT) != S_IFSOCK
+ || statbuf.st_uid != getuid ())
+ return FALSE;
+ }
+
+ if (unrestricted)
+ g_info ("Allowing session-dbus access");
+
+ no_proxy = (flags & FLATPAK_RUN_FLAG_NO_SESSION_BUS_PROXY) != 0;
+
+ if (dbus_session_socket != NULL && unrestricted)
+ {
+ flatpak_bwrap_add_args (app_bwrap,
+ "--ro-bind", dbus_session_socket, sandbox_socket_path,
+ NULL);
+ flatpak_bwrap_set_env (app_bwrap, "DBUS_SESSION_BUS_ADDRESS", sandbox_dbus_address, TRUE);
+ flatpak_bwrap_add_runtime_dir_member (app_bwrap, "bus");
+
+ return TRUE;
+ }
+ else if (!no_proxy && dbus_address != NULL)
+ {
+ g_autofree char *proxy_socket = create_proxy_socket ("session-bus-proxy-XXXXXX");
+
+ if (proxy_socket == NULL)
+ return FALSE;
+
+ flatpak_bwrap_add_args (proxy_arg_bwrap, dbus_address, proxy_socket, NULL);
+
+ if (!unrestricted)
+ {
+ flatpak_context_add_bus_filters (context, app_id, TRUE, flags & FLATPAK_RUN_FLAG_SANDBOX, proxy_arg_bwrap);
+
+ /* Allow calling any interface+method on all portals, but only receive broadcasts under /org/desktop/portal */
+ flatpak_bwrap_add_arg (proxy_arg_bwrap,
+ "--call=org.freedesktop.portal.*=*");
+ flatpak_bwrap_add_arg (proxy_arg_bwrap,
+ "--broadcast=org.freedesktop.portal.*=@/org/freedesktop/portal/*");
+ }
+
+ if ((flags & FLATPAK_RUN_FLAG_LOG_SESSION_BUS) != 0)
+ flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
+
+ flatpak_bwrap_add_args (app_bwrap,
+ "--ro-bind", proxy_socket, sandbox_socket_path,
+ NULL);
+ flatpak_bwrap_set_env (app_bwrap, "DBUS_SESSION_BUS_ADDRESS", sandbox_dbus_address, TRUE);
+ flatpak_bwrap_add_runtime_dir_member (app_bwrap, "bus");
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+flatpak_run_add_system_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags)
+{
+ gboolean unrestricted, no_proxy;
+ const char *dbus_address = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS");
+ g_autofree char *real_dbus_address = NULL;
+ g_autofree char *dbus_system_socket = NULL;
+
+ unrestricted = (context->sockets & FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS) != 0;
+ if (unrestricted)
+ g_info ("Allowing system-dbus access");
+
+ no_proxy = (flags & FLATPAK_RUN_FLAG_NO_SYSTEM_BUS_PROXY) != 0;
+
+ if (dbus_address != NULL)
+ dbus_system_socket = extract_unix_path_from_dbus_address (dbus_address);
+ else if (g_file_test ("/var/run/dbus/system_bus_socket", G_FILE_TEST_EXISTS))
+ dbus_system_socket = g_strdup ("/var/run/dbus/system_bus_socket");
+
+ if (dbus_system_socket != NULL && unrestricted)
+ {
+ flatpak_bwrap_add_args (app_bwrap,
+ "--ro-bind", dbus_system_socket, "/run/dbus/system_bus_socket",
+ NULL);
+ flatpak_bwrap_set_env (app_bwrap, "DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/run/dbus/system_bus_socket", TRUE);
+
+ return TRUE;
+ }
+ else if (!no_proxy && flatpak_context_get_needs_system_bus_proxy (context))
+ {
+ g_autofree char *proxy_socket = create_proxy_socket ("system-bus-proxy-XXXXXX");
+
+ if (proxy_socket == NULL)
+ return FALSE;
+
+ if (dbus_address)
+ real_dbus_address = g_strdup (dbus_address);
+ else
+ real_dbus_address = g_strdup_printf ("unix:path=%s", dbus_system_socket);
+
+ flatpak_bwrap_add_args (proxy_arg_bwrap, real_dbus_address, proxy_socket, NULL);
+
+ if (!unrestricted)
+ flatpak_context_add_bus_filters (context, NULL, FALSE, flags & FLATPAK_RUN_FLAG_SANDBOX, proxy_arg_bwrap);
+
+ if ((flags & FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS) != 0)
+ flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
+
+ flatpak_bwrap_add_args (app_bwrap,
+ "--ro-bind", proxy_socket, "/run/dbus/system_bus_socket",
+ NULL);
+ flatpak_bwrap_set_env (app_bwrap, "DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/run/dbus/system_bus_socket", TRUE);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap,
+ FlatpakBwrap *proxy_arg_bwrap,
+ FlatpakContext *context,
+ FlatpakRunFlags flags)
+{
+ static const char sandbox_socket_path[] = "/run/flatpak/at-spi-bus";
+ static const char sandbox_dbus_address[] = "unix:path=/run/flatpak/at-spi-bus";
+ g_autoptr(GDBusConnection) session_bus = NULL;
+ g_autofree char *a11y_address = NULL;
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GDBusMessage) reply = NULL;
+ g_autoptr(GDBusMessage) msg = NULL;
+ g_autofree char *proxy_socket = NULL;
+
+ if ((flags & FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY) != 0)
+ return FALSE;
+
+ session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ if (session_bus == NULL)
+ return FALSE;
+
+ msg = g_dbus_message_new_method_call ("org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus", "GetAddress");
+ g_dbus_message_set_body (msg, g_variant_new ("()"));
+ reply =
+ g_dbus_connection_send_message_with_reply_sync (session_bus, msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ 30000,
+ NULL,
+ NULL,
+ NULL);
+ if (reply)
+ {
+ if (g_dbus_message_to_gerror (reply, &local_error))
+ {
+ if (!g_error_matches (local_error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+ g_message ("Can't find a11y bus: %s", local_error->message);
+ }
+ else
+ {
+ g_variant_get (g_dbus_message_get_body (reply),
+ "(s)", &a11y_address);
+ }
+ }
+
+ if (!a11y_address)
+ return FALSE;
+
+ proxy_socket = create_proxy_socket ("a11y-bus-proxy-XXXXXX");
+ if (proxy_socket == NULL)
+ return FALSE;
+
+ flatpak_bwrap_add_args (proxy_arg_bwrap,
+ a11y_address,
+ proxy_socket, "--filter", "--sloppy-names",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
+ "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
+ NULL);
+
+ if ((flags & FLATPAK_RUN_FLAG_LOG_A11Y_BUS) != 0)
+ flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
+
+ flatpak_bwrap_add_args (app_bwrap,
+ "--ro-bind", proxy_socket, sandbox_socket_path,
+ NULL);
+ flatpak_bwrap_set_env (app_bwrap, "AT_SPI_BUS_ADDRESS", sandbox_dbus_address, TRUE);
+
+ return TRUE;
+}
diff --git a/common/flatpak-run-private.h b/common/flatpak-run-private.h
index 72b45c8d..f0f2dce1 100644
--- a/common/flatpak-run-private.h
+++ b/common/flatpak-run-private.h
@@ -200,11 +200,4 @@ gboolean flatpak_run_app (FlatpakDecomposed *app_ref,
extern const char * const *flatpak_abs_usrmerged_dirs;
-gboolean flatpak_run_parse_x11_display (const char *display,
- int *family,
- char **x11_socket,
- char **remote_host,
- char **original_display_nr,
- GError **error);
-
#endif /* __FLATPAK_RUN_H__ */
diff --git a/common/flatpak-run-pulseaudio-private.h b/common/flatpak-run-pulseaudio-private.h
new file mode 100644
index 00000000..8fa4eb5a
--- /dev/null
+++ b/common/flatpak-run-pulseaudio-private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include "libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-common-types-private.h"
+#include "flatpak-context-private.h"
+
+G_BEGIN_DECLS
+
+void flatpak_run_add_pulseaudio_args (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares);
+
+G_END_DECLS
diff --git a/common/flatpak-run-pulseaudio.c b/common/flatpak-run-pulseaudio.c
new file mode 100644
index 00000000..9495f8a2
--- /dev/null
+++ b/common/flatpak-run-pulseaudio.c
@@ -0,0 +1,338 @@
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
+ * Copyright © 2014-2019 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#include "config.h"
+#include "flatpak-run-pulseaudio-private.h"
+
+#include "flatpak-utils-private.h"
+
+/* Try to find a default server from a pulseaudio confguration file */
+static char *
+flatpak_run_get_pulseaudio_server_user_config (const char *path)
+{
+ g_autoptr(GFile) file = g_file_new_for_path (path);
+ g_autoptr(GError) my_error = NULL;
+ g_autoptr(GFileInputStream) input_stream = NULL;
+ g_autoptr(GDataInputStream) data_stream = NULL;
+ size_t len;
+
+ input_stream = g_file_read (file, NULL, &my_error);
+ if (my_error)
+ {
+ g_info ("Pulseaudio user configuration file '%s': %s", path, my_error->message);
+ return NULL;
+ }
+
+ data_stream = g_data_input_stream_new (G_INPUT_STREAM (input_stream));
+
+ while (TRUE)
+ {
+ g_autofree char *line = g_data_input_stream_read_line (data_stream, &len, NULL, NULL);
+ if (line == NULL)
+ break;
+
+ g_strchug (line);
+
+ if ((*line == '\0') || (*line == ';') || (*line == '#'))
+ continue;
+
+ if (g_str_has_prefix (line, ".include "))
+ {
+ g_autofree char *rec_path = g_strdup (line + 9);
+ g_strstrip (rec_path);
+ char *found = flatpak_run_get_pulseaudio_server_user_config (rec_path);
+ if (found)
+ return found;
+ }
+ else if (g_str_has_prefix (line, "["))
+ {
+ return NULL;
+ }
+ else
+ {
+ g_auto(GStrv) tokens = g_strsplit (line, "=", 2);
+
+ if ((tokens[0] != NULL) && (tokens[1] != NULL))
+ {
+ g_strchomp (tokens[0]);
+ if (strcmp ("default-server", tokens[0]) == 0)
+ {
+ g_strstrip (tokens[1]);
+ g_info ("Found pulseaudio socket from configuration file '%s': %s", path, tokens[1]);
+ return g_strdup (tokens[1]);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static char *
+flatpak_run_get_pulseaudio_server (void)
+{
+ const char * pulse_clientconfig;
+ char *pulse_server;
+ g_autofree char *pulse_user_config = NULL;
+
+ pulse_server = g_strdup (g_getenv ("PULSE_SERVER"));
+ if (pulse_server)
+ return pulse_server;
+
+ pulse_clientconfig = g_getenv ("PULSE_CLIENTCONFIG");
+ if (pulse_clientconfig)
+ return flatpak_run_get_pulseaudio_server_user_config (pulse_clientconfig);
+
+ pulse_user_config = g_build_filename (g_get_user_config_dir (), "pulse/client.conf", NULL);
+ pulse_server = flatpak_run_get_pulseaudio_server_user_config (pulse_user_config);
+ if (pulse_server)
+ return pulse_server;
+
+ pulse_server = flatpak_run_get_pulseaudio_server_user_config ("/etc/pulse/client.conf");
+ if (pulse_server)
+ return pulse_server;
+
+ return NULL;
+}
+
+/*
+ * Parse a PulseAudio server string, as documented on
+ * https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/ServerStrings/.
+ * Returns the first supported server address, or NULL if none are supported,
+ * or NULL with @remote set if @value points to a remote server.
+ */
+static char *
+flatpak_run_parse_pulse_server (const char *value,
+ gboolean *remote)
+{
+ g_auto(GStrv) servers = g_strsplit (value, " ", 0);
+ gsize i;
+
+ for (i = 0; servers[i] != NULL; i++)
+ {
+ const char *server = servers[i];
+ if (g_str_has_prefix (server, "{"))
+ {
+ /*
+ * TODO: compare the value within {} to the local hostname and D-Bus machine ID,
+ * and skip if it matches neither.
+ */
+ const char * closing = strstr (server, "}");
+ if (closing == NULL)
+ continue;
+ server = closing + 1;
+ }
+
+ if (g_str_has_prefix (server, "unix:"))
+ return g_strdup (server + 5);
+ if (server[0] == '/')
+ return g_strdup (server);
+
+ if (g_str_has_prefix (server, "tcp:"))
+ {
+ *remote = TRUE;
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Get the machine ID as used by PulseAudio. This is the systemd/D-Bus
+ * machine ID, or failing that, the hostname.
+ */
+static char *
+flatpak_run_get_pulse_machine_id (void)
+{
+ static const char * const machine_ids[] =
+ {
+ "/etc/machine-id",
+ "/var/lib/dbus/machine-id",
+ };
+ gsize i;
+
+ for (i = 0; i < G_N_ELEMENTS (machine_ids); i++)
+ {
+ g_autofree char *ret = NULL;
+
+ if (g_file_get_contents (machine_ids[i], &ret, NULL, NULL))
+ {
+ gsize j;
+
+ g_strstrip (ret);
+
+ for (j = 0; ret[j] != '\0'; j++)
+ {
+ if (!g_ascii_isxdigit (ret[j]))
+ break;
+ }
+
+ if (ret[0] != '\0' && ret[j] == '\0')
+ return g_steal_pointer (&ret);
+ }
+ }
+
+ return g_strdup (g_get_host_name ());
+}
+
+/*
+ * Get the directory used by PulseAudio for its configuration.
+ */
+static char *
+flatpak_run_get_pulse_home (void)
+{
+ /* Legacy path ~/.pulse is tried first, for compatibility */
+ {
+ const char *parent = g_get_home_dir ();
+ g_autofree char *ret = g_build_filename (parent, ".pulse", NULL);
+
+ if (g_file_test (ret, G_FILE_TEST_IS_DIR))
+ return g_steal_pointer (&ret);
+ }
+
+ /* The more modern path, usually ~/.config/pulse */
+ {
+ const char *parent = g_get_user_config_dir ();
+ /* Usually ~/.config/pulse */
+ g_autofree char *ret = g_build_filename (parent, "pulse", NULL);
+
+ if (g_file_test (ret, G_FILE_TEST_IS_DIR))
+ return g_steal_pointer (&ret);
+ }
+
+ return NULL;
+}
+
+/*
+ * Get the runtime directory used by PulseAudio for its socket.
+ */
+static char *
+flatpak_run_get_pulse_runtime_dir (void)
+{
+ const char *val = NULL;
+
+ val = g_getenv ("PULSE_RUNTIME_PATH");
+
+ if (val != NULL)
+ return realpath (val, NULL);
+
+ {
+ const char *user_runtime_dir = g_get_user_runtime_dir ();
+
+ if (user_runtime_dir != NULL)
+ {
+ g_autofree char *dir = g_build_filename (user_runtime_dir, "pulse", NULL);
+
+ if (g_file_test (dir, G_FILE_TEST_IS_DIR))
+ return realpath (dir, NULL);
+ }
+ }
+
+ {
+ g_autofree char *pulse_home = flatpak_run_get_pulse_home ();
+ g_autofree char *machine_id = flatpak_run_get_pulse_machine_id ();
+
+ if (pulse_home != NULL && machine_id != NULL)
+ {
+ /* This is usually a symlink, but we take its realpath() anyway */
+ g_autofree char *dir = g_strdup_printf ("%s/%s-runtime", pulse_home, machine_id);
+
+ if (g_file_test (dir, G_FILE_TEST_IS_DIR))
+ return realpath (dir, NULL);
+ }
+ }
+
+ return NULL;
+}
+
+void
+flatpak_run_add_pulseaudio_args (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares)
+{
+ g_autofree char *pulseaudio_server = flatpak_run_get_pulseaudio_server ();
+ g_autofree char *pulseaudio_socket = NULL;
+ g_autofree char *pulse_runtime_dir = flatpak_run_get_pulse_runtime_dir ();
+ gboolean remote = FALSE;
+
+ if (pulseaudio_server)
+ pulseaudio_socket = flatpak_run_parse_pulse_server (pulseaudio_server,
+ &remote);
+
+ if (pulseaudio_socket == NULL && !remote)
+ {
+ pulseaudio_socket = g_build_filename (pulse_runtime_dir, "native", NULL);
+
+ if (!g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
+ g_clear_pointer (&pulseaudio_socket, g_free);
+ }
+
+ if (pulseaudio_socket == NULL && !remote)
+ {
+ pulseaudio_socket = realpath ("/var/run/pulse/native", NULL);
+
+ if (pulseaudio_socket && !g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
+ g_clear_pointer (&pulseaudio_socket, g_free);
+ }
+
+ flatpak_bwrap_unset_env (bwrap, "PULSE_SERVER");
+
+ if (remote)
+ {
+ if ((shares & FLATPAK_CONTEXT_SHARED_NETWORK) == 0)
+ {
+ g_warning ("Remote PulseAudio server configured.");
+ g_warning ("PulseAudio access will require --share=network permission.");
+ }
+
+ g_info ("Using remote PulseAudio server \"%s\"", pulseaudio_server);
+ flatpak_bwrap_set_env (bwrap, "PULSE_SERVER", pulseaudio_server, TRUE);
+ }
+ else if (pulseaudio_socket && g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
+ {
+ static const char sandbox_socket_path[] = "/run/flatpak/pulse/native";
+ static const char pulse_server[] = "unix:/run/flatpak/pulse/native";
+ static const char config_path[] = "/run/flatpak/pulse/config";
+ gboolean share_shm = FALSE; /* TODO: When do we add this? */
+ g_autofree char *client_config = g_strdup_printf ("enable-shm=%s\n", share_shm ? "yes" : "no");
+
+ /* FIXME - error handling */
+ if (!flatpak_bwrap_add_args_data (bwrap, "pulseaudio", client_config, -1, config_path, NULL))
+ return;
+
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", pulseaudio_socket, sandbox_socket_path,
+ NULL);
+
+ flatpak_bwrap_set_env (bwrap, "PULSE_SERVER", pulse_server, TRUE);
+ flatpak_bwrap_set_env (bwrap, "PULSE_CLIENTCONFIG", config_path, TRUE);
+ flatpak_bwrap_add_runtime_dir_member (bwrap, "pulse");
+ }
+ else
+ g_info ("Could not find pulseaudio socket");
+
+ /* Also allow ALSA access. This was added in 1.8, and is not ideally named. However,
+ * since the practical permission of ALSA and PulseAudio are essentially the same, and
+ * since we don't want to add more permissions for something we plan to replace with
+ * portals/pipewire going forward we reinterpret pulseaudio to also mean ALSA.
+ */
+ if (!remote && g_file_test ("/dev/snd", G_FILE_TEST_IS_DIR))
+ flatpak_bwrap_add_args (bwrap, "--dev-bind", "/dev/snd", "/dev/snd", NULL);
+}
diff --git a/common/flatpak-run-sockets-private.h b/common/flatpak-run-sockets-private.h
new file mode 100644
index 00000000..cd4a60e2
--- /dev/null
+++ b/common/flatpak-run-sockets-private.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include "libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-common-types-private.h"
+#include "flatpak-context-private.h"
+
+G_BEGIN_DECLS
+
+void flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares,
+ FlatpakContextSockets sockets);
+void flatpak_run_add_socket_args_late (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares);
+
+G_END_DECLS
diff --git a/common/flatpak-run-sockets.c b/common/flatpak-run-sockets.c
new file mode 100644
index 00000000..e7767d26
--- /dev/null
+++ b/common/flatpak-run-sockets.c
@@ -0,0 +1,278 @@
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
+ * Copyright © 2014-2019 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#include "config.h"
+#include "flatpak-run-sockets-private.h"
+
+/* Setup for simple sockets that only need one function goes in this file.
+ * Setup for more complicated sockets should go in its own file. */
+
+#include "flatpak-run-cups-private.h"
+#include "flatpak-run-pulseaudio-private.h"
+#include "flatpak-run-x11-private.h"
+#include "flatpak-utils-private.h"
+
+/**
+ * flatpak_run_add_wayland_args:
+ *
+ * Returns: %TRUE if a Wayland socket was found.
+ */
+static gboolean
+flatpak_run_add_wayland_args (FlatpakBwrap *bwrap)
+{
+ const char *wayland_display;
+ g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
+ g_autofree char *wayland_socket = NULL;
+ g_autofree char *sandbox_wayland_socket = NULL;
+ gboolean res = FALSE;
+ struct stat statbuf;
+
+ wayland_display = g_getenv ("WAYLAND_DISPLAY");
+ if (!wayland_display)
+ wayland_display = "wayland-0";
+
+ if (wayland_display[0] == '/')
+ wayland_socket = g_strdup (wayland_display);
+ else
+ wayland_socket = g_build_filename (user_runtime_dir, wayland_display, NULL);
+
+ if (!g_str_has_prefix (wayland_display, "wayland-") ||
+ strchr (wayland_display, '/') != NULL)
+ {
+ wayland_display = "wayland-0";
+ flatpak_bwrap_set_env (bwrap, "WAYLAND_DISPLAY", wayland_display, TRUE);
+ }
+
+ sandbox_wayland_socket = g_strdup_printf ("/run/flatpak/%s", wayland_display);
+
+ if (stat (wayland_socket, &statbuf) == 0 &&
+ (statbuf.st_mode & S_IFMT) == S_IFSOCK)
+ {
+ res = TRUE;
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", wayland_socket, sandbox_wayland_socket,
+ NULL);
+ flatpak_bwrap_add_runtime_dir_member (bwrap, wayland_display);
+ }
+ return res;
+}
+
+static void
+flatpak_run_add_gssproxy_args (FlatpakBwrap *bwrap)
+{
+ /* We only expose the gssproxy user service. The gssproxy system service is
+ * not intended to be exposed to sandboxed environments.
+ */
+ g_autofree char *gssproxy_host_dir = g_build_filename (g_get_user_runtime_dir (), "gssproxy", NULL);
+ const char *gssproxy_sandboxed_dir = "/run/flatpak/gssproxy/";
+
+ if (g_file_test (gssproxy_host_dir, G_FILE_TEST_EXISTS))
+ flatpak_bwrap_add_args (bwrap, "--ro-bind", gssproxy_host_dir, gssproxy_sandboxed_dir, NULL);
+}
+
+static void
+flatpak_run_add_resolved_args (FlatpakBwrap *bwrap)
+{
+ const char *resolved_socket = "/run/systemd/resolve/io.systemd.Resolve";
+
+ if (g_file_test (resolved_socket, G_FILE_TEST_EXISTS))
+ flatpak_bwrap_add_args (bwrap, "--bind", resolved_socket, resolved_socket, NULL);
+}
+
+static void
+flatpak_run_add_journal_args (FlatpakBwrap *bwrap)
+{
+ g_autofree char *journal_socket_socket = g_strdup ("/run/systemd/journal/socket");
+ g_autofree char *journal_stdout_socket = g_strdup ("/run/systemd/journal/stdout");
+
+ if (g_file_test (journal_socket_socket, G_FILE_TEST_EXISTS))
+ {
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", journal_socket_socket, journal_socket_socket,
+ NULL);
+ }
+ if (g_file_test (journal_stdout_socket, G_FILE_TEST_EXISTS))
+ {
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", journal_stdout_socket, journal_stdout_socket,
+ NULL);
+ }
+}
+
+static void
+flatpak_run_add_pcsc_args (FlatpakBwrap *bwrap)
+{
+ const char * pcsc_socket;
+ const char * sandbox_pcsc_socket = "/run/pcscd/pcscd.comm";
+
+ pcsc_socket = g_getenv ("PCSCLITE_CSOCK_NAME");
+ if (pcsc_socket)
+ {
+ if (!g_file_test (pcsc_socket, G_FILE_TEST_EXISTS))
+ {
+ flatpak_bwrap_unset_env (bwrap, "PCSCLITE_CSOCK_NAME");
+ return;
+ }
+ }
+ else
+ {
+ pcsc_socket = "/run/pcscd/pcscd.comm";
+ if (!g_file_test (pcsc_socket, G_FILE_TEST_EXISTS))
+ return;
+ }
+
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", pcsc_socket, sandbox_pcsc_socket,
+ NULL);
+ flatpak_bwrap_set_env (bwrap, "PCSCLITE_CSOCK_NAME", sandbox_pcsc_socket, TRUE);
+}
+
+static void
+flatpak_run_add_gpg_agent_args (FlatpakBwrap *bwrap)
+{
+ const char * agent_socket;
+ g_autofree char * sandbox_agent_socket = NULL;
+ g_autoptr(GError) gpgconf_error = NULL;
+ g_autoptr(GSubprocess) process = NULL;
+ GInputStream *base_stream = NULL;
+ g_autoptr(GDataInputStream) data_stream = NULL;
+
+ process = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE,
+ &gpgconf_error,
+ "gpgconf", "--list-dir", "agent-socket", NULL);
+
+ if (gpgconf_error)
+ {
+ g_info ("GPG-Agent directories: %s", gpgconf_error->message);
+ return;
+ }
+
+ base_stream = g_subprocess_get_stdout_pipe (process);
+ data_stream = g_data_input_stream_new (base_stream);
+
+ agent_socket = g_data_input_stream_read_line (data_stream,
+ NULL, NULL,
+ &gpgconf_error);
+
+ if (!agent_socket || gpgconf_error)
+ {
+ g_info ("GPG-Agent directories: %s", gpgconf_error->message);
+ return;
+ }
+
+ sandbox_agent_socket = g_strdup_printf ("/run/user/%d/gnupg/S.gpg-agent", getuid ());
+
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind-try", agent_socket, sandbox_agent_socket,
+ NULL);
+}
+
+static void
+flatpak_run_add_ssh_args (FlatpakBwrap *bwrap)
+{
+ static const char sandbox_auth_socket[] = "/run/flatpak/ssh-auth";
+ const char * auth_socket;
+
+ auth_socket = g_getenv ("SSH_AUTH_SOCK");
+
+ if (!auth_socket)
+ return; /* ssh agent not present */
+
+ if (!g_file_test (auth_socket, G_FILE_TEST_EXISTS))
+ {
+ /* Let's clean it up, so that the application will not try to connect */
+ flatpak_bwrap_unset_env (bwrap, "SSH_AUTH_SOCK");
+ return;
+ }
+
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", auth_socket, sandbox_auth_socket,
+ NULL);
+ flatpak_bwrap_set_env (bwrap, "SSH_AUTH_SOCK", sandbox_auth_socket, TRUE);
+}
+
+/*
+ * Expose sockets that are available for `flatpak build`, apply_extra, and
+ * `flatpak run`, except for D-Bus which is handled separately due to its
+ * use of a proxy.
+ */
+void
+flatpak_run_add_socket_args_environment (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares,
+ FlatpakContextSockets sockets)
+{
+ gboolean has_wayland;
+ gboolean allow_x11;
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_WAYLAND)
+ {
+ g_info ("Allowing wayland access");
+ has_wayland = flatpak_run_add_wayland_args (bwrap);
+ }
+
+ if ((sockets & FLATPAK_CONTEXT_SOCKET_FALLBACK_X11) != 0)
+ allow_x11 = !has_wayland;
+ else
+ allow_x11 = (sockets & FLATPAK_CONTEXT_SOCKET_X11) != 0;
+
+ flatpak_run_add_x11_args (bwrap, allow_x11, shares);
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_SSH_AUTH)
+ {
+ flatpak_run_add_ssh_args (bwrap);
+ }
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_PULSEAUDIO)
+ {
+ g_info ("Allowing pulseaudio access");
+ flatpak_run_add_pulseaudio_args (bwrap, shares);
+ }
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_PCSC)
+ {
+ flatpak_run_add_pcsc_args (bwrap);
+ }
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_CUPS)
+ {
+ flatpak_run_add_cups_args (bwrap);
+ }
+
+ if (sockets & FLATPAK_CONTEXT_SOCKET_GPG_AGENT)
+ {
+ flatpak_run_add_gpg_agent_args (bwrap);
+ }
+}
+
+/*
+ * Expose sockets that are available for `flatpak run` only.
+ */
+void
+flatpak_run_add_socket_args_late (FlatpakBwrap *bwrap,
+ FlatpakContextShares shares)
+{
+ if ((shares & FLATPAK_CONTEXT_SHARED_NETWORK) != 0)
+ {
+ flatpak_run_add_gssproxy_args (bwrap);
+ flatpak_run_add_resolved_args (bwrap);
+ }
+
+ flatpak_run_add_journal_args (bwrap);
+}
diff --git a/common/flatpak-run-x11-private.h b/common/flatpak-run-x11-private.h
new file mode 100644
index 00000000..96da2e6b
--- /dev/null
+++ b/common/flatpak-run-x11-private.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#pragma once
+
+#include "libglnx.h"
+
+#include "flatpak-bwrap-private.h"
+#include "flatpak-common-types-private.h"
+#include "flatpak-context-private.h"
+
+G_BEGIN_DECLS
+
+void flatpak_run_add_x11_args (FlatpakBwrap *bwrap,
+ gboolean allowed,
+ FlatpakContextShares shares);
+
+gboolean flatpak_run_parse_x11_display (const char *display,
+ int *family,
+ char **x11_socket,
+ char **remote_host,
+ char **original_display_nr,
+ GError **error);
+
+G_END_DECLS
diff --git a/common/flatpak-run-x11.c b/common/flatpak-run-x11.c
new file mode 100644
index 00000000..af8f0fa5
--- /dev/null
+++ b/common/flatpak-run-x11.c
@@ -0,0 +1,333 @@
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
+ * Copyright © 2014-2019 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ */
+
+#include "config.h"
+#include "flatpak-run-x11-private.h"
+
+#include <sys/utsname.h>
+
+#ifdef ENABLE_XAUTH
+#include <X11/Xauth.h>
+#endif
+
+/* This is part of the X11 protocol, so we can safely hard-code it here */
+#define FamilyInternet6 (6)
+
+#ifdef ENABLE_XAUTH
+static gboolean
+auth_streq (const char *str,
+ const char *au_str,
+ size_t au_len)
+{
+ return au_len == strlen (str) && memcmp (str, au_str, au_len) == 0;
+}
+
+static gboolean
+xauth_entry_should_propagate (const Xauth *xa,
+ int family,
+ const char *remote_hostname,
+ const char *local_hostname,
+ const char *number)
+{
+ /* ensure entry isn't for a different type of access */
+ if (family != FamilyWild && xa->family != family && xa->family != FamilyWild)
+ return FALSE;
+
+ /* ensure entry isn't for remote access, except that if remote_hostname
+ * is specified, then remote access to that hostname is OK */
+ if (xa->family != FamilyWild && xa->family != FamilyLocal &&
+ (remote_hostname == NULL ||
+ !auth_streq (remote_hostname, xa->address, xa->address_length)))
+ return FALSE;
+
+ /* ensure entry is for this machine */
+ if (xa->family == FamilyLocal && !auth_streq (local_hostname, xa->address, xa->address_length))
+ {
+ /* OpenSUSE inherits the hostname value from DHCP without updating
+ * its X11 authentication cookie. The old hostname value can still
+ * be found in the environment variable XAUTHLOCALHOSTNAME.
+ * For reference:
+ * https://bugzilla.opensuse.org/show_bug.cgi?id=262309
+ * For this reason if we have a cookie whose address is equal to the
+ * variable XAUTHLOCALHOSTNAME, we still need to propagate it, but
+ * we also need to change its address to `unames.nodename`.
+ */
+ const char *xauth_local_hostname;
+ xauth_local_hostname = g_getenv ("XAUTHLOCALHOSTNAME");
+ if (xauth_local_hostname == NULL)
+ return FALSE;
+
+ if (!auth_streq ((char *) xauth_local_hostname, xa->address, xa->address_length))
+ return FALSE;
+ }
+
+ /* ensure entry is for this session */
+ if (xa->number != NULL && !auth_streq (number, xa->number, xa->number_length))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+write_xauth (int family,
+ const char *remote_host,
+ const char *number,
+ FILE *output)
+{
+ Xauth *xa, local_xa;
+ char *filename;
+ FILE *f;
+ struct utsname unames;
+
+ if (uname (&unames))
+ {
+ g_warning ("uname failed");
+ return;
+ }
+
+ filename = XauFileName ();
+ f = fopen (filename, "rb");
+ if (f == NULL)
+ return;
+
+ while (TRUE)
+ {
+ xa = XauReadAuth (f);
+ if (xa == NULL)
+ break;
+ if (xauth_entry_should_propagate (xa, family, remote_host,
+ unames.nodename, number))
+ {
+ local_xa = *xa;
+
+ if (local_xa.family == FamilyLocal &&
+ !auth_streq (unames.nodename, local_xa.address, local_xa.address_length))
+ {
+ /* If we decided to propagate this cookie, but its address
+ * doesn't match `unames.nodename`, we need to change it or
+ * inside the container it will not work.
+ */
+ local_xa.address = unames.nodename;
+ local_xa.address_length = strlen (local_xa.address);
+ }
+
+ if (!XauWriteAuth (output, &local_xa))
+ g_warning ("xauth write error");
+ }
+
+ XauDisposeAuth (xa);
+ }
+
+ fclose (f);
+}
+#else /* !ENABLE_XAUTH */
+
+/* When not doing Xauth, any distinct values will do, but use the same
+ * ones Xauth does so that we can refer to them in our unit test. */
+#define FamilyLocal (256)
+#define FamilyWild (65535)
+
+#endif /* !ENABLE_XAUTH */
+
+/*
+ * @family: (out) (not optional):
+ * @x11_socket: (out) (not optional):
+ * @display_nr_out: (out) (not optional):
+ */
+gboolean
+flatpak_run_parse_x11_display (const char *display,
+ int *family,
+ char **x11_socket,
+ char **remote_host,
+ char **display_nr_out,
+ GError **error)
+{
+ const char *colon;
+ const char *display_nr;
+ const char *display_nr_end;
+
+ /* Use the last ':', not the first, to cope with [::1]:0 */
+ colon = strrchr (display, ':');
+
+ if (colon == NULL)
+ return glnx_throw (error, "No colon found in DISPLAY=%s", display);
+
+ if (!g_ascii_isdigit (colon[1]))
+ return glnx_throw (error, "Colon not followed by a digit in DISPLAY=%s", display);
+
+ display_nr = &colon[1];
+ display_nr_end = display_nr;
+
+ while (g_ascii_isdigit (*display_nr_end))
+ display_nr_end++;
+
+ *display_nr_out = g_strndup (display_nr, display_nr_end - display_nr);
+
+ if (display == colon || g_str_has_prefix (display, "unix:"))
+ {
+ *family = FamilyLocal;
+ *x11_socket = g_strdup_printf ("/tmp/.X11-unix/X%s", *display_nr_out);
+ }
+ else if (display[0] == '[' && display[colon - display - 1] == ']')
+ {
+ *family = FamilyInternet6;
+ *remote_host = g_strndup (display + 1, colon - display - 2);
+ }
+ else
+ {
+ *family = FamilyWild;
+ *remote_host = g_strndup (display, colon - display);
+ }
+
+ return TRUE;
+}
+
+void
+flatpak_run_add_x11_args (FlatpakBwrap *bwrap,
+ gboolean allowed,
+ FlatpakContextShares shares)
+{
+ g_autofree char *x11_socket = NULL;
+ const char *display;
+ g_autoptr(GError) local_error = NULL;
+
+ /* Always cover /tmp/.X11-unix, that way we never see the host one in case
+ * we have access to the host /tmp. If you request X access we'll put the right
+ * thing in this anyway.
+ *
+ * We need to be a bit careful here, because there are two situations in
+ * which potentially hostile processes have access to /tmp and could
+ * create symlinks, which in principle could cause us to create the
+ * directory and mount the tmpfs at the target of the symlink instead
+ * of in the intended place:
+ *
+ * - With --filesystem=/tmp, it's the host /tmp - but because of the
+ * special historical status of /tmp/.X11-unix, we can assume that
+ * it is pre-created by the host system before user code gets to run.
+ *
+ * - When /tmp is shared between all instances of the same app ID,
+ * in principle the app has control over what's in /tmp, but in
+ * practice it can't interfere with /tmp/.X11-unix, because we do
+ * this unconditionally - therefore by the time app code runs,
+ * /tmp/.X11-unix is already a mount point, meaning the app cannot
+ * rename or delete it.
+ */
+ flatpak_bwrap_add_args (bwrap,
+ "--tmpfs", "/tmp/.X11-unix",
+ NULL);
+
+ if (!allowed)
+ {
+ flatpak_bwrap_unset_env (bwrap, "DISPLAY");
+ return;
+ }
+
+ g_info ("Allowing x11 access");
+
+ display = g_getenv ("DISPLAY");
+
+ if (display != NULL)
+ {
+ g_autofree char *remote_host = NULL;
+ g_autofree char *display_nr = NULL;
+ int family = -1;
+
+ if (!flatpak_run_parse_x11_display (display, &family, &x11_socket,
+ &remote_host, &display_nr,
+ &local_error))
+ {
+ g_warning ("%s", local_error->message);
+ flatpak_bwrap_unset_env (bwrap, "DISPLAY");
+ return;
+ }
+
+ g_assert (display_nr != NULL);
+
+ if (x11_socket != NULL
+ && g_file_test (x11_socket, G_FILE_TEST_EXISTS))
+ {
+ g_assert (g_str_has_prefix (x11_socket, "/tmp/.X11-unix/X"));
+ flatpak_bwrap_add_args (bwrap,
+ "--ro-bind", x11_socket, x11_socket,
+ NULL);
+ flatpak_bwrap_set_env (bwrap, "DISPLAY", display, TRUE);
+ }
+ else if ((shares & FLATPAK_CONTEXT_SHARED_NETWORK) == 0)
+ {
+ /* If DISPLAY is for example :42 but /tmp/.X11-unix/X42
+ * doesn't exist, then the only way this is going to work
+ * is if the app can connect to abstract socket
+ * @/tmp/.X11-unix/X42 or to TCP port localhost:6042,
+ * either of which requires a shared network namespace.
+ *
+ * Alternatively, if DISPLAY is othermachine:23, then we
+ * definitely need access to TCP port othermachine:6023. */
+ if (x11_socket != NULL)
+ g_warning ("X11 socket %s does not exist in filesystem.",
+ x11_socket);
+ else
+ g_warning ("Remote X11 display detected.");
+
+ g_warning ("X11 access will require --share=network permission.");
+ }
+ else if (x11_socket != NULL)
+ {
+ g_warning ("X11 socket %s does not exist in filesystem, "
+ "trying to use abstract socket instead.",
+ x11_socket);
+ }
+ else
+ {
+ g_debug ("Assuming --share=network gives access to remote X11");
+ }
+
+#ifdef ENABLE_XAUTH
+ g_auto(GLnxTmpfile) xauth_tmpf = { 0, };
+
+ if (glnx_open_anonymous_tmpfile_full (O_RDWR | O_CLOEXEC, "/tmp", &xauth_tmpf, NULL))
+ {
+ FILE *output = fdopen (xauth_tmpf.fd, "wb");
+ if (output != NULL)
+ {
+ /* fd is now owned by output, steal it from the tmpfile */
+ int tmp_fd = dup (glnx_steal_fd (&xauth_tmpf.fd));
+ if (tmp_fd != -1)
+ {
+ static const char dest[] = "/run/flatpak/Xauthority";
+
+ write_xauth (family, remote_host, display_nr, output);
+ flatpak_bwrap_add_args_data_fd (bwrap, "--ro-bind-data", tmp_fd, dest);
+
+ flatpak_bwrap_set_env (bwrap, "XAUTHORITY", dest, TRUE);
+ }
+
+ fclose (output);
+
+ if (tmp_fd != -1)
+ lseek (tmp_fd, 0, SEEK_SET);
+ }
+ }
+#endif
+ }
+ else
+ {
+ flatpak_bwrap_unset_env (bwrap, "DISPLAY");
+ }
+}
diff --git a/common/flatpak-run.c b/common/flatpak-run.c
index fa549c19..3f970bbb 100644
--- a/common/flatpak-run.c
+++ b/common/flatpak-run.c
@@ -48,16 +48,14 @@
#include <seccomp.h>
#endif
-#ifdef ENABLE_XAUTH
-#include <X11/Xauth.h>
-#endif
-
#include <glib/gi18n-lib.h>
#include <gio/gio.h>
#include "libglnx.h"
+#include "flatpak-run-dbus-private.h"
#include "flatpak-run-private.h"
+#include "flatpak-run-sockets-private.h"
#include "flatpak-utils-base-private.h"
#include "flatpak-dir-private.h"
#include "flatpak-instance-private.h"
@@ -79,1317 +77,6 @@ const char * const abs_usrmerged_dirs[] =
};
const char * const *flatpak_abs_usrmerged_dirs = abs_usrmerged_dirs;
-static char *
-extract_unix_path_from_dbus_address (const char *address)
-{
- const char *path, *path_end;
-
- if (address == NULL)
- return NULL;
-
- if (!g_str_has_prefix (address, "unix:"))
- return NULL;
-
- path = strstr (address, "path=");
- if (path == NULL)
- return NULL;
- path += strlen ("path=");
- path_end = path;
- while (*path_end != 0 && *path_end != ',')
- path_end++;
-
- return g_strndup (path, path_end - path);
-}
-
-/* This is part of the X11 protocol, so we can safely hard-code it here */
-#define FamilyInternet6 (6)
-
-#ifdef ENABLE_XAUTH
-static gboolean
-auth_streq (const char *str,
- const char *au_str,
- size_t au_len)
-{
- return au_len == strlen (str) && memcmp (str, au_str, au_len) == 0;
-}
-
-static gboolean
-xauth_entry_should_propagate (const Xauth *xa,
- int family,
- const char *remote_hostname,
- const char *local_hostname,
- const char *number)
-{
- /* ensure entry isn't for a different type of access */
- if (family != FamilyWild && xa->family != family && xa->family != FamilyWild)
- return FALSE;
-
- /* ensure entry isn't for remote access, except that if remote_hostname
- * is specified, then remote access to that hostname is OK */
- if (xa->family != FamilyWild && xa->family != FamilyLocal &&
- (remote_hostname == NULL ||
- !auth_streq (remote_hostname, xa->address, xa->address_length)))
- return FALSE;
-
- /* ensure entry is for this machine */
- if (xa->family == FamilyLocal && !auth_streq (local_hostname, xa->address, xa->address_length))
- {
- /* OpenSUSE inherits the hostname value from DHCP without updating
- * its X11 authentication cookie. The old hostname value can still
- * be found in the environment variable XAUTHLOCALHOSTNAME.
- * For reference:
- * https://bugzilla.opensuse.org/show_bug.cgi?id=262309
- * For this reason if we have a cookie whose address is equal to the
- * variable XAUTHLOCALHOSTNAME, we still need to propagate it, but
- * we also need to change its address to `unames.nodename`.
- */
- const char *xauth_local_hostname;
- xauth_local_hostname = g_getenv ("XAUTHLOCALHOSTNAME");
- if (xauth_local_hostname == NULL)
- return FALSE;
-
- if (!auth_streq ((char *) xauth_local_hostname, xa->address, xa->address_length))
- return FALSE;
- }
-
- /* ensure entry is for this session */
- if (xa->number != NULL && !auth_streq (number, xa->number, xa->number_length))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-write_xauth (int family,
- const char *remote_host,
- const char *number,
- FILE *output)
-{
- Xauth *xa, local_xa;
- char *filename;
- FILE *f;
- struct utsname unames;
-
- if (uname (&unames))
- {
- g_warning ("uname failed");
- return;
- }
-
- filename = XauFileName ();
- f = fopen (filename, "rb");
- if (f == NULL)
- return;
-
- while (TRUE)
- {
- xa = XauReadAuth (f);
- if (xa == NULL)
- break;
- if (xauth_entry_should_propagate (xa, family, remote_host,
- unames.nodename, number))
- {
- local_xa = *xa;
-
- if (local_xa.family == FamilyLocal &&
- !auth_streq (unames.nodename, local_xa.address, local_xa.address_length))
- {
- /* If we decided to propagate this cookie, but its address
- * doesn't match `unames.nodename`, we need to change it or
- * inside the container it will not work.
- */
- local_xa.address = unames.nodename;
- local_xa.address_length = strlen (local_xa.address);
- }
-
- if (!XauWriteAuth (output, &local_xa))
- g_warning ("xauth write error");
- }
-
- XauDisposeAuth (xa);
- }
-
- fclose (f);
-}
-#else /* !ENABLE_XAUTH */
-
-/* When not doing Xauth, any distinct values will do, but use the same
- * ones Xauth does so that we can refer to them in our unit test. */
-#define FamilyLocal (256)
-#define FamilyWild (65535)
-
-#endif /* !ENABLE_XAUTH */
-
-/*
- * @family: (out) (not optional):
- * @x11_socket: (out) (not optional):
- * @display_nr_out: (out) (not optional):
- */
-gboolean
-flatpak_run_parse_x11_display (const char *display,
- int *family,
- char **x11_socket,
- char **remote_host,
- char **display_nr_out,
- GError **error)
-{
- const char *colon;
- const char *display_nr;
- const char *display_nr_end;
-
- /* Use the last ':', not the first, to cope with [::1]:0 */
- colon = strrchr (display, ':');
-
- if (colon == NULL)
- return glnx_throw (error, "No colon found in DISPLAY=%s", display);
-
- if (!g_ascii_isdigit (colon[1]))
- return glnx_throw (error, "Colon not followed by a digit in DISPLAY=%s", display);
-
- display_nr = &colon[1];
- display_nr_end = display_nr;
-
- while (g_ascii_isdigit (*display_nr_end))
- display_nr_end++;
-
- *display_nr_out = g_strndup (display_nr, display_nr_end - display_nr);
-
- if (display == colon || g_str_has_prefix (display, "unix:"))
- {
- *family = FamilyLocal;
- *x11_socket = g_strdup_printf ("/tmp/.X11-unix/X%s", *display_nr_out);
- }
- else if (display[0] == '[' && display[colon - display - 1] == ']')
- {
- *family = FamilyInternet6;
- *remote_host = g_strndup (display + 1, colon - display - 2);
- }
- else
- {
- *family = FamilyWild;
- *remote_host = g_strndup (display, colon - display);
- }
-
- return TRUE;
-}
-
-static void
-flatpak_run_add_x11_args (FlatpakBwrap *bwrap,
- gboolean allowed,
- FlatpakContextShares shares)
-{
- g_autofree char *x11_socket = NULL;
- const char *display;
- g_autoptr(GError) local_error = NULL;
-
- /* Always cover /tmp/.X11-unix, that way we never see the host one in case
- * we have access to the host /tmp. If you request X access we'll put the right
- * thing in this anyway.
- *
- * We need to be a bit careful here, because there are two situations in
- * which potentially hostile processes have access to /tmp and could
- * create symlinks, which in principle could cause us to create the
- * directory and mount the tmpfs at the target of the symlink instead
- * of in the intended place:
- *
- * - With --filesystem=/tmp, it's the host /tmp - but because of the
- * special historical status of /tmp/.X11-unix, we can assume that
- * it is pre-created by the host system before user code gets to run.
- *
- * - When /tmp is shared between all instances of the same app ID,
- * in principle the app has control over what's in /tmp, but in
- * practice it can't interfere with /tmp/.X11-unix, because we do
- * this unconditionally - therefore by the time app code runs,
- * /tmp/.X11-unix is already a mount point, meaning the app cannot
- * rename or delete it.
- */
- flatpak_bwrap_add_args (bwrap,
- "--tmpfs", "/tmp/.X11-unix",
- NULL);
-
- if (!allowed)
- {
- flatpak_bwrap_unset_env (bwrap, "DISPLAY");
- return;
- }
-
- g_info ("Allowing x11 access");
-
- display = g_getenv ("DISPLAY");
-
- if (display != NULL)
- {
- g_autofree char *remote_host = NULL;
- g_autofree char *display_nr = NULL;
- int family = -1;
-
- if (!flatpak_run_parse_x11_display (display, &family, &x11_socket,
- &remote_host, &display_nr,
- &local_error))
- {
- g_warning ("%s", local_error->message);
- flatpak_bwrap_unset_env (bwrap, "DISPLAY");
- return;
- }
-
- g_assert (display_nr != NULL);
-
- if (x11_socket != NULL
- && g_file_test (x11_socket, G_FILE_TEST_EXISTS))
- {
- g_assert (g_str_has_prefix (x11_socket, "/tmp/.X11-unix/X"));
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", x11_socket, x11_socket,
- NULL);
- flatpak_bwrap_set_env (bwrap, "DISPLAY", display, TRUE);
- }
- else if ((shares & FLATPAK_CONTEXT_SHARED_NETWORK) == 0)
- {
- /* If DISPLAY is for example :42 but /tmp/.X11-unix/X42
- * doesn't exist, then the only way this is going to work
- * is if the app can connect to abstract socket
- * @/tmp/.X11-unix/X42 or to TCP port localhost:6042,
- * either of which requires a shared network namespace.
- *
- * Alternatively, if DISPLAY is othermachine:23, then we
- * definitely need access to TCP port othermachine:6023. */
- if (x11_socket != NULL)
- g_warning ("X11 socket %s does not exist in filesystem.",
- x11_socket);
- else
- g_warning ("Remote X11 display detected.");
-
- g_warning ("X11 access will require --share=network permission.");
- }
- else if (x11_socket != NULL)
- {
- g_warning ("X11 socket %s does not exist in filesystem, "
- "trying to use abstract socket instead.",
- x11_socket);
- }
- else
- {
- g_debug ("Assuming --share=network gives access to remote X11");
- }
-
-#ifdef ENABLE_XAUTH
- g_auto(GLnxTmpfile) xauth_tmpf = { 0, };
-
- if (glnx_open_anonymous_tmpfile_full (O_RDWR | O_CLOEXEC, "/tmp", &xauth_tmpf, NULL))
- {
- FILE *output = fdopen (xauth_tmpf.fd, "wb");
- if (output != NULL)
- {
- /* fd is now owned by output, steal it from the tmpfile */
- int tmp_fd = dup (glnx_steal_fd (&xauth_tmpf.fd));
- if (tmp_fd != -1)
- {
- static const char dest[] = "/run/flatpak/Xauthority";
-
- write_xauth (family, remote_host, display_nr, output);
- flatpak_bwrap_add_args_data_fd (bwrap, "--ro-bind-data", tmp_fd, dest);
-
- flatpak_bwrap_set_env (bwrap, "XAUTHORITY", dest, TRUE);
- }
-
- fclose (output);
-
- if (tmp_fd != -1)
- lseek (tmp_fd, 0, SEEK_SET);
- }
- }
-#endif
- }
- else
- {
- flatpak_bwrap_unset_env (bwrap, "DISPLAY");
- }
-}
-
-static gboolean
-flatpak_run_add_wayland_args (FlatpakBwrap *bwrap)
-{
- const char *wayland_display;
- g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
- g_autofree char *wayland_socket = NULL;
- g_autofree char *sandbox_wayland_socket = NULL;
- gboolean res = FALSE;
- struct stat statbuf;
-
- wayland_display = g_getenv ("WAYLAND_DISPLAY");
- if (!wayland_display)
- wayland_display = "wayland-0";
-
- if (wayland_display[0] == '/')
- wayland_socket = g_strdup (wayland_display);
- else
- wayland_socket = g_build_filename (user_runtime_dir, wayland_display, NULL);
-
- if (!g_str_has_prefix (wayland_display, "wayland-") ||
- strchr (wayland_display, '/') != NULL)
- {
- wayland_display = "wayland-0";
- flatpak_bwrap_set_env (bwrap, "WAYLAND_DISPLAY", wayland_display, TRUE);
- }
-
- sandbox_wayland_socket = g_strdup_printf ("/run/flatpak/%s", wayland_display);
-
- if (stat (wayland_socket, &statbuf) == 0 &&
- (statbuf.st_mode & S_IFMT) == S_IFSOCK)
- {
- res = TRUE;
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", wayland_socket, sandbox_wayland_socket,
- NULL);
- flatpak_bwrap_add_runtime_dir_member (bwrap, wayland_display);
- }
- return res;
-}
-
-static void
-flatpak_run_add_ssh_args (FlatpakBwrap *bwrap)
-{
- static const char sandbox_auth_socket[] = "/run/flatpak/ssh-auth";
- const char * auth_socket;
-
- auth_socket = g_getenv ("SSH_AUTH_SOCK");
-
- if (!auth_socket)
- return; /* ssh agent not present */
-
- if (!g_file_test (auth_socket, G_FILE_TEST_EXISTS))
- {
- /* Let's clean it up, so that the application will not try to connect */
- flatpak_bwrap_unset_env (bwrap, "SSH_AUTH_SOCK");
- return;
- }
-
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", auth_socket, sandbox_auth_socket,
- NULL);
- flatpak_bwrap_set_env (bwrap, "SSH_AUTH_SOCK", sandbox_auth_socket, TRUE);
-}
-
-static void
-flatpak_run_add_pcsc_args (FlatpakBwrap *bwrap)
-{
- const char * pcsc_socket;
- const char * sandbox_pcsc_socket = "/run/pcscd/pcscd.comm";
-
- pcsc_socket = g_getenv ("PCSCLITE_CSOCK_NAME");
- if (pcsc_socket)
- {
- if (!g_file_test (pcsc_socket, G_FILE_TEST_EXISTS))
- {
- flatpak_bwrap_unset_env (bwrap, "PCSCLITE_CSOCK_NAME");
- return;
- }
- }
- else
- {
- pcsc_socket = "/run/pcscd/pcscd.comm";
- if (!g_file_test (pcsc_socket, G_FILE_TEST_EXISTS))
- return;
- }
-
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", pcsc_socket, sandbox_pcsc_socket,
- NULL);
- flatpak_bwrap_set_env (bwrap, "PCSCLITE_CSOCK_NAME", sandbox_pcsc_socket, TRUE);
-}
-
-static gboolean
-flatpak_run_cups_check_server_is_socket (const char *server)
-{
- if (g_str_has_prefix (server, "/") && strstr (server, ":") == NULL)
- return TRUE;
-
- return FALSE;
-}
-
-/* Try to find a default server from a cups confguration file */
-static char *
-flatpak_run_get_cups_server_name_config (const char *path)
-{
- g_autoptr(GFile) file = g_file_new_for_path (path);
- g_autoptr(GError) my_error = NULL;
- g_autoptr(GFileInputStream) input_stream = NULL;
- g_autoptr(GDataInputStream) data_stream = NULL;
- size_t len;
-
- input_stream = g_file_read (file, NULL, &my_error);
- if (my_error)
- {
- g_info ("CUPS configuration file '%s': %s", path, my_error->message);
- return NULL;
- }
-
- data_stream = g_data_input_stream_new (G_INPUT_STREAM (input_stream));
-
- while (TRUE)
- {
- g_autofree char *line = g_data_input_stream_read_line (data_stream, &len, NULL, NULL);
- if (line == NULL)
- break;
-
- g_strchug (line);
-
- if ((*line == '\0') || (*line == '#'))
- continue;
-
- g_auto(GStrv) tokens = g_strsplit (line, " ", 2);
-
- if ((tokens[0] != NULL) && (tokens[1] != NULL))
- {
- if (strcmp ("ServerName", tokens[0]) == 0)
- {
- g_strchug (tokens[1]);
-
- if (flatpak_run_cups_check_server_is_socket (tokens[1]))
- return g_strdup (tokens[1]);
- }
- }
- }
-
- return NULL;
-}
-
-static char *
-flatpak_run_get_cups_server_name (void)
-{
- g_autofree char * cups_server = NULL;
- g_autofree char * cups_config_path = NULL;
-
- /* TODO
- * we don't currently support cups servers located on the network, if such
- * server is detected, we simply ignore it and in the worst case we fallback
- * to the default socket
- */
- cups_server = g_strdup (g_getenv ("CUPS_SERVER"));
- if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
- return g_steal_pointer (&cups_server);
- g_clear_pointer (&cups_server, g_free);
-
- cups_config_path = g_build_filename (g_get_home_dir (), ".cups/client.conf", NULL);
- cups_server = flatpak_run_get_cups_server_name_config (cups_config_path);
- if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
- return g_steal_pointer (&cups_server);
- g_clear_pointer (&cups_server, g_free);
-
- cups_server = flatpak_run_get_cups_server_name_config ("/etc/cups/client.conf");
- if (cups_server && flatpak_run_cups_check_server_is_socket (cups_server))
- return g_steal_pointer (&cups_server);
-
- // Fallback to default socket
- return g_strdup ("/var/run/cups/cups.sock");
-}
-
-static void
-flatpak_run_add_cups_args (FlatpakBwrap *bwrap)
-{
- g_autofree char * sandbox_server_name = g_strdup ("/var/run/cups/cups.sock");
- g_autofree char * cups_server_name = flatpak_run_get_cups_server_name ();
-
- if (!g_file_test (cups_server_name, G_FILE_TEST_EXISTS))
- {
- g_info ("Could not find CUPS server");
- return;
- }
-
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", cups_server_name, sandbox_server_name,
- NULL);
-}
-
-static void
-flatpak_run_add_gpg_agent_args (FlatpakBwrap *bwrap)
-{
- const char * agent_socket;
- g_autofree char * sandbox_agent_socket = NULL;
- g_autoptr(GError) gpgconf_error = NULL;
- g_autoptr(GSubprocess) process = NULL;
- GInputStream *base_stream = NULL;
- g_autoptr(GDataInputStream) data_stream = NULL;
-
- process = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE,
- &gpgconf_error,
- "gpgconf", "--list-dir", "agent-socket", NULL);
-
- if (gpgconf_error)
- {
- g_info ("GPG-Agent directories: %s", gpgconf_error->message);
- return;
- }
-
- base_stream = g_subprocess_get_stdout_pipe (process);
- data_stream = g_data_input_stream_new (base_stream);
-
- agent_socket = g_data_input_stream_read_line (data_stream,
- NULL, NULL,
- &gpgconf_error);
-
- if (!agent_socket || gpgconf_error)
- {
- g_info ("GPG-Agent directories: %s", gpgconf_error->message);
- return;
- }
-
- sandbox_agent_socket = g_strdup_printf ("/run/user/%d/gnupg/S.gpg-agent", getuid ());
-
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind-try", agent_socket, sandbox_agent_socket,
- NULL);
-}
-
-/* Try to find a default server from a pulseaudio confguration file */
-static char *
-flatpak_run_get_pulseaudio_server_user_config (const char *path)
-{
- g_autoptr(GFile) file = g_file_new_for_path (path);
- g_autoptr(GError) my_error = NULL;
- g_autoptr(GFileInputStream) input_stream = NULL;
- g_autoptr(GDataInputStream) data_stream = NULL;
- size_t len;
-
- input_stream = g_file_read (file, NULL, &my_error);
- if (my_error)
- {
- g_info ("Pulseaudio user configuration file '%s': %s", path, my_error->message);
- return NULL;
- }
-
- data_stream = g_data_input_stream_new (G_INPUT_STREAM (input_stream));
-
- while (TRUE)
- {
- g_autofree char *line = g_data_input_stream_read_line (data_stream, &len, NULL, NULL);
- if (line == NULL)
- break;
-
- g_strchug (line);
-
- if ((*line == '\0') || (*line == ';') || (*line == '#'))
- continue;
-
- if (g_str_has_prefix (line, ".include "))
- {
- g_autofree char *rec_path = g_strdup (line + 9);
- g_strstrip (rec_path);
- char *found = flatpak_run_get_pulseaudio_server_user_config (rec_path);
- if (found)
- return found;
- }
- else if (g_str_has_prefix (line, "["))
- {
- return NULL;
- }
- else
- {
- g_auto(GStrv) tokens = g_strsplit (line, "=", 2);
-
- if ((tokens[0] != NULL) && (tokens[1] != NULL))
- {
- g_strchomp (tokens[0]);
- if (strcmp ("default-server", tokens[0]) == 0)
- {
- g_strstrip (tokens[1]);
- g_info ("Found pulseaudio socket from configuration file '%s': %s", path, tokens[1]);
- return g_strdup (tokens[1]);
- }
- }
- }
- }
-
- return NULL;
-}
-
-static char *
-flatpak_run_get_pulseaudio_server (void)
-{
- const char * pulse_clientconfig;
- char *pulse_server;
- g_autofree char *pulse_user_config = NULL;
-
- pulse_server = g_strdup (g_getenv ("PULSE_SERVER"));
- if (pulse_server)
- return pulse_server;
-
- pulse_clientconfig = g_getenv ("PULSE_CLIENTCONFIG");
- if (pulse_clientconfig)
- return flatpak_run_get_pulseaudio_server_user_config (pulse_clientconfig);
-
- pulse_user_config = g_build_filename (g_get_user_config_dir (), "pulse/client.conf", NULL);
- pulse_server = flatpak_run_get_pulseaudio_server_user_config (pulse_user_config);
- if (pulse_server)
- return pulse_server;
-
- pulse_server = flatpak_run_get_pulseaudio_server_user_config ("/etc/pulse/client.conf");
- if (pulse_server)
- return pulse_server;
-
- return NULL;
-}
-
-/*
- * Parse a PulseAudio server string, as documented on
- * https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/ServerStrings/.
- * Returns the first supported server address, or NULL if none are supported,
- * or NULL with @remote set if @value points to a remote server.
- */
-static char *
-flatpak_run_parse_pulse_server (const char *value,
- gboolean *remote)
-{
- g_auto(GStrv) servers = g_strsplit (value, " ", 0);
- gsize i;
-
- for (i = 0; servers[i] != NULL; i++)
- {
- const char *server = servers[i];
- if (g_str_has_prefix (server, "{"))
- {
- /*
- * TODO: compare the value within {} to the local hostname and D-Bus machine ID,
- * and skip if it matches neither.
- */
- const char * closing = strstr (server, "}");
- if (closing == NULL)
- continue;
- server = closing + 1;
- }
-
- if (g_str_has_prefix (server, "unix:"))
- return g_strdup (server + 5);
- if (server[0] == '/')
- return g_strdup (server);
-
- if (g_str_has_prefix (server, "tcp:"))
- {
- *remote = TRUE;
- return NULL;
- }
- }
-
- return NULL;
-}
-
-/*
- * Get the machine ID as used by PulseAudio. This is the systemd/D-Bus
- * machine ID, or failing that, the hostname.
- */
-static char *
-flatpak_run_get_pulse_machine_id (void)
-{
- static const char * const machine_ids[] =
- {
- "/etc/machine-id",
- "/var/lib/dbus/machine-id",
- };
- gsize i;
-
- for (i = 0; i < G_N_ELEMENTS (machine_ids); i++)
- {
- g_autofree char *ret = NULL;
-
- if (g_file_get_contents (machine_ids[i], &ret, NULL, NULL))
- {
- gsize j;
-
- g_strstrip (ret);
-
- for (j = 0; ret[j] != '\0'; j++)
- {
- if (!g_ascii_isxdigit (ret[j]))
- break;
- }
-
- if (ret[0] != '\0' && ret[j] == '\0')
- return g_steal_pointer (&ret);
- }
- }
-
- return g_strdup (g_get_host_name ());
-}
-
-/*
- * Get the directory used by PulseAudio for its configuration.
- */
-static char *
-flatpak_run_get_pulse_home (void)
-{
- /* Legacy path ~/.pulse is tried first, for compatibility */
- {
- const char *parent = g_get_home_dir ();
- g_autofree char *ret = g_build_filename (parent, ".pulse", NULL);
-
- if (g_file_test (ret, G_FILE_TEST_IS_DIR))
- return g_steal_pointer (&ret);
- }
-
- /* The more modern path, usually ~/.config/pulse */
- {
- const char *parent = g_get_user_config_dir ();
- /* Usually ~/.config/pulse */
- g_autofree char *ret = g_build_filename (parent, "pulse", NULL);
-
- if (g_file_test (ret, G_FILE_TEST_IS_DIR))
- return g_steal_pointer (&ret);
- }
-
- return NULL;
-}
-
-/*
- * Get the runtime directory used by PulseAudio for its socket.
- */
-static char *
-flatpak_run_get_pulse_runtime_dir (void)
-{
- const char *val = NULL;
-
- val = g_getenv ("PULSE_RUNTIME_PATH");
-
- if (val != NULL)
- return realpath (val, NULL);
-
- {
- const char *user_runtime_dir = g_get_user_runtime_dir ();
-
- if (user_runtime_dir != NULL)
- {
- g_autofree char *dir = g_build_filename (user_runtime_dir, "pulse", NULL);
-
- if (g_file_test (dir, G_FILE_TEST_IS_DIR))
- return realpath (dir, NULL);
- }
- }
-
- {
- g_autofree char *pulse_home = flatpak_run_get_pulse_home ();
- g_autofree char *machine_id = flatpak_run_get_pulse_machine_id ();
-
- if (pulse_home != NULL && machine_id != NULL)
- {
- /* This is usually a symlink, but we take its realpath() anyway */
- g_autofree char *dir = g_strdup_printf ("%s/%s-runtime", pulse_home, machine_id);
-
- if (g_file_test (dir, G_FILE_TEST_IS_DIR))
- return realpath (dir, NULL);
- }
- }
-
- return NULL;
-}
-
-static void
-flatpak_run_add_pulseaudio_args (FlatpakBwrap *bwrap,
- FlatpakContextShares shares)
-{
- g_autofree char *pulseaudio_server = flatpak_run_get_pulseaudio_server ();
- g_autofree char *pulseaudio_socket = NULL;
- g_autofree char *pulse_runtime_dir = flatpak_run_get_pulse_runtime_dir ();
- gboolean remote = FALSE;
-
- if (pulseaudio_server)
- pulseaudio_socket = flatpak_run_parse_pulse_server (pulseaudio_server,
- &remote);
-
- if (pulseaudio_socket == NULL && !remote)
- {
- pulseaudio_socket = g_build_filename (pulse_runtime_dir, "native", NULL);
-
- if (!g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
- g_clear_pointer (&pulseaudio_socket, g_free);
- }
-
- if (pulseaudio_socket == NULL && !remote)
- {
- pulseaudio_socket = realpath ("/var/run/pulse/native", NULL);
-
- if (pulseaudio_socket && !g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
- g_clear_pointer (&pulseaudio_socket, g_free);
- }
-
- flatpak_bwrap_unset_env (bwrap, "PULSE_SERVER");
-
- if (remote)
- {
- if ((shares & FLATPAK_CONTEXT_SHARED_NETWORK) == 0)
- {
- g_warning ("Remote PulseAudio server configured.");
- g_warning ("PulseAudio access will require --share=network permission.");
- }
-
- g_info ("Using remote PulseAudio server \"%s\"", pulseaudio_server);
- flatpak_bwrap_set_env (bwrap, "PULSE_SERVER", pulseaudio_server, TRUE);
- }
- else if (pulseaudio_socket && g_file_test (pulseaudio_socket, G_FILE_TEST_EXISTS))
- {
- static const char sandbox_socket_path[] = "/run/flatpak/pulse/native";
- static const char pulse_server[] = "unix:/run/flatpak/pulse/native";
- static const char config_path[] = "/run/flatpak/pulse/config";
- gboolean share_shm = FALSE; /* TODO: When do we add this? */
- g_autofree char *client_config = g_strdup_printf ("enable-shm=%s\n", share_shm ? "yes" : "no");
-
- /* FIXME - error handling */
- if (!flatpak_bwrap_add_args_data (bwrap, "pulseaudio", client_config, -1, config_path, NULL))
- return;
-
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", pulseaudio_socket, sandbox_socket_path,
- NULL);
-
- flatpak_bwrap_set_env (bwrap, "PULSE_SERVER", pulse_server, TRUE);
- flatpak_bwrap_set_env (bwrap, "PULSE_CLIENTCONFIG", config_path, TRUE);
- flatpak_bwrap_add_runtime_dir_member (bwrap, "pulse");
- }
- else
- g_info ("Could not find pulseaudio socket");
-
- /* Also allow ALSA access. This was added in 1.8, and is not ideally named. However,
- * since the practical permission of ALSA and PulseAudio are essentially the same, and
- * since we don't want to add more permissions for something we plan to replace with
- * portals/pipewire going forward we reinterpret pulseaudio to also mean ALSA.
- */
- if (!remote && g_file_test ("/dev/snd", G_FILE_TEST_IS_DIR))
- flatpak_bwrap_add_args (bwrap, "--dev-bind", "/dev/snd", "/dev/snd", NULL);
-}
-
-static void
-flatpak_run_add_gssproxy_args (FlatpakBwrap *bwrap)
-{
- /* We only expose the gssproxy user service. The gssproxy system service is
- * not intended to be exposed to sandboxed environments.
- */
- g_autofree char *gssproxy_host_dir = g_build_filename (g_get_user_runtime_dir (), "gssproxy", NULL);
- const char *gssproxy_sandboxed_dir = "/run/flatpak/gssproxy/";
-
- if (g_file_test (gssproxy_host_dir, G_FILE_TEST_EXISTS))
- flatpak_bwrap_add_args (bwrap, "--ro-bind", gssproxy_host_dir, gssproxy_sandboxed_dir, NULL);
-}
-
-static void
-flatpak_run_add_resolved_args (FlatpakBwrap *bwrap)
-{
- const char *resolved_socket = "/run/systemd/resolve/io.systemd.Resolve";
-
- if (g_file_test (resolved_socket, G_FILE_TEST_EXISTS))
- flatpak_bwrap_add_args (bwrap, "--bind", resolved_socket, resolved_socket, NULL);
-}
-
-static void
-flatpak_run_add_journal_args (FlatpakBwrap *bwrap)
-{
- g_autofree char *journal_socket_socket = g_strdup ("/run/systemd/journal/socket");
- g_autofree char *journal_stdout_socket = g_strdup ("/run/systemd/journal/stdout");
-
- if (g_file_test (journal_socket_socket, G_FILE_TEST_EXISTS))
- {
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", journal_socket_socket, journal_socket_socket,
- NULL);
- }
- if (g_file_test (journal_stdout_socket, G_FILE_TEST_EXISTS))
- {
- flatpak_bwrap_add_args (bwrap,
- "--ro-bind", journal_stdout_socket, journal_stdout_socket,
- NULL);
- }
-}
-
-static char *
-create_proxy_socket (char *template)
-{
- g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
- g_autofree char *proxy_socket_dir = g_build_filename (user_runtime_dir, ".dbus-proxy", NULL);
- g_autofree char *proxy_socket = g_build_filename (proxy_socket_dir, template, NULL);
- int fd;
-
- if (!glnx_shutil_mkdir_p_at (AT_FDCWD, proxy_socket_dir, 0755, NULL, NULL))
- return NULL;
-
- fd = g_mkstemp (proxy_socket);
- if (fd == -1)
- return NULL;
-
- close (fd);
-
- return g_steal_pointer (&proxy_socket);
-}
-
-static gboolean
-flatpak_run_add_system_dbus_args (FlatpakBwrap *app_bwrap,
- FlatpakBwrap *proxy_arg_bwrap,
- FlatpakContext *context,
- FlatpakRunFlags flags)
-{
- gboolean unrestricted, no_proxy;
- const char *dbus_address = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS");
- g_autofree char *real_dbus_address = NULL;
- g_autofree char *dbus_system_socket = NULL;
-
- unrestricted = (context->sockets & FLATPAK_CONTEXT_SOCKET_SYSTEM_BUS) != 0;
- if (unrestricted)
- g_info ("Allowing system-dbus access");
-
- no_proxy = (flags & FLATPAK_RUN_FLAG_NO_SYSTEM_BUS_PROXY) != 0;
-
- if (dbus_address != NULL)
- dbus_system_socket = extract_unix_path_from_dbus_address (dbus_address);
- else if (g_file_test ("/var/run/dbus/system_bus_socket", G_FILE_TEST_EXISTS))
- dbus_system_socket = g_strdup ("/var/run/dbus/system_bus_socket");
-
- if (dbus_system_socket != NULL && unrestricted)
- {
- flatpak_bwrap_add_args (app_bwrap,
- "--ro-bind", dbus_system_socket, "/run/dbus/system_bus_socket",
- NULL);
- flatpak_bwrap_set_env (app_bwrap, "DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/run/dbus/system_bus_socket", TRUE);
-
- return TRUE;
- }
- else if (!no_proxy && flatpak_context_get_needs_system_bus_proxy (context))
- {
- g_autofree char *proxy_socket = create_proxy_socket ("system-bus-proxy-XXXXXX");
-
- if (proxy_socket == NULL)
- return FALSE;
-
- if (dbus_address)
- real_dbus_address = g_strdup (dbus_address);
- else
- real_dbus_address = g_strdup_printf ("unix:path=%s", dbus_system_socket);
-
- flatpak_bwrap_add_args (proxy_arg_bwrap, real_dbus_address, proxy_socket, NULL);
-
- if (!unrestricted)
- flatpak_context_add_bus_filters (context, NULL, FALSE, flags & FLATPAK_RUN_FLAG_SANDBOX, proxy_arg_bwrap);
-
- if ((flags & FLATPAK_RUN_FLAG_LOG_SYSTEM_BUS) != 0)
- flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
-
- flatpak_bwrap_add_args (app_bwrap,
- "--ro-bind", proxy_socket, "/run/dbus/system_bus_socket",
- NULL);
- flatpak_bwrap_set_env (app_bwrap, "DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/run/dbus/system_bus_socket", TRUE);
-
- return TRUE;
- }
- return FALSE;
-}
-
-static gboolean
-flatpak_run_add_session_dbus_args (FlatpakBwrap *app_bwrap,
- FlatpakBwrap *proxy_arg_bwrap,
- FlatpakContext *context,
- FlatpakRunFlags flags,
- const char *app_id)
-{
- static const char sandbox_socket_path[] = "/run/flatpak/bus";
- static const char sandbox_dbus_address[] = "unix:path=/run/flatpak/bus";
- gboolean unrestricted, no_proxy;
- const char *dbus_address = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
- g_autofree char *dbus_session_socket = NULL;
-
- unrestricted = (context->sockets & FLATPAK_CONTEXT_SOCKET_SESSION_BUS) != 0;
-
- if (dbus_address != NULL)
- {
- dbus_session_socket = extract_unix_path_from_dbus_address (dbus_address);
- }
- else
- {
- g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
- struct stat statbuf;
-
- dbus_session_socket = g_build_filename (user_runtime_dir, "bus", NULL);
-
- if (stat (dbus_session_socket, &statbuf) < 0
- || (statbuf.st_mode & S_IFMT) != S_IFSOCK
- || statbuf.st_uid != getuid ())
- return FALSE;
- }
-
- if (unrestricted)
- g_info ("Allowing session-dbus access");
-
- no_proxy = (flags & FLATPAK_RUN_FLAG_NO_SESSION_BUS_PROXY) != 0;
-
- if (dbus_session_socket != NULL && unrestricted)
- {
- flatpak_bwrap_add_args (app_bwrap,
- "--ro-bind", dbus_session_socket, sandbox_socket_path,
- NULL);
- flatpak_bwrap_set_env (app_bwrap, "DBUS_SESSION_BUS_ADDRESS", sandbox_dbus_address, TRUE);
- flatpak_bwrap_add_runtime_dir_member (app_bwrap, "bus");
-
- return TRUE;
- }
- else if (!no_proxy && dbus_address != NULL)
- {
- g_autofree char *proxy_socket = create_proxy_socket ("session-bus-proxy-XXXXXX");
-
- if (proxy_socket == NULL)
- return FALSE;
-
- flatpak_bwrap_add_args (proxy_arg_bwrap, dbus_address, proxy_socket, NULL);
-
- if (!unrestricted)
- {
- flatpak_context_add_bus_filters (context, app_id, TRUE, flags & FLATPAK_RUN_FLAG_SANDBOX, proxy_arg_bwrap);
-
- /* Allow calling any interface+method on all portals, but only receive broadcasts under /org/desktop/portal */
- flatpak_bwrap_add_arg (proxy_arg_bwrap,
- "--call=org.freedesktop.portal.*=*");
- flatpak_bwrap_add_arg (proxy_arg_bwrap,
- "--broadcast=org.freedesktop.portal.*=@/org/freedesktop/portal/*");
- }
-
- if ((flags & FLATPAK_RUN_FLAG_LOG_SESSION_BUS) != 0)
- flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
-
- flatpak_bwrap_add_args (app_bwrap,
- "--ro-bind", proxy_socket, sandbox_socket_path,
- NULL);
- flatpak_bwrap_set_env (app_bwrap, "DBUS_SESSION_BUS_ADDRESS", sandbox_dbus_address, TRUE);
- flatpak_bwrap_add_runtime_dir_member (app_bwrap, "bus");
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-flatpak_run_add_a11y_dbus_args (FlatpakBwrap *app_bwrap,
- FlatpakBwrap *proxy_arg_bwrap,
- FlatpakContext *context,
- FlatpakRunFlags flags)
-{
- static const char sandbox_socket_path[] = "/run/flatpak/at-spi-bus";
- static const char sandbox_dbus_address[] = "unix:path=/run/flatpak/at-spi-bus";
- g_autoptr(GDBusConnection) session_bus = NULL;
- g_autofree char *a11y_address = NULL;
- g_autoptr(GError) local_error = NULL;
- g_autoptr(GDBusMessage) reply = NULL;
- g_autoptr(GDBusMessage) msg = NULL;
- g_autofree char *proxy_socket = NULL;
-
- if ((flags & FLATPAK_RUN_FLAG_NO_A11Y_BUS_PROXY) != 0)
- return FALSE;
-
- session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
- if (session_bus == NULL)
- return FALSE;
-
- msg = g_dbus_message_new_method_call ("org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus", "GetAddress");
- g_dbus_message_set_body (msg, g_variant_new ("()"));
- reply =
- g_dbus_connection_send_message_with_reply_sync (session_bus, msg,
- G_DBUS_SEND_MESSAGE_FLAGS_NONE,
- 30000,
- NULL,
- NULL,
- NULL);
- if (reply)
- {
- if (g_dbus_message_to_gerror (reply, &local_error))
- {
- if (!g_error_matches (local_error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
- g_message ("Can't find a11y bus: %s", local_error->message);
- }
- else
- {
- g_variant_get (g_dbus_message_get_body (reply),
- "(s)", &a11y_address);
- }
- }
-
- if (!a11y_address)
- return FALSE;
-
- proxy_socket = create_proxy_socket ("a11y-bus-proxy-XXXXXX");
- if (proxy_socket == NULL)
- return FALSE;
-
- flatpak_bwrap_add_args (proxy_arg_bwrap,
- a11y_address,
- proxy_socket, "--filter", "--sloppy-names",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Embed@/org/a11y/atspi/accessible/root",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.Socket.Unembed@/org/a11y/atspi/accessible/root",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.Registry.GetRegisteredEvents@/org/a11y/atspi/registry",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetKeystrokeListeners@/org/a11y/atspi/registry/deviceeventcontroller",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.GetDeviceEventListeners@/org/a11y/atspi/registry/deviceeventcontroller",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersSync@/org/a11y/atspi/registry/deviceeventcontroller",
- "--call=org.a11y.atspi.Registry=org.a11y.atspi.DeviceEventController.NotifyListenersAsync@/org/a11y/atspi/registry/deviceeventcontroller",
- NULL);
-
- if ((flags & FLATPAK_RUN_FLAG_LOG_A11Y_BUS) != 0)
- flatpak_bwrap_add_args (proxy_arg_bwrap, "--log", NULL);
-
- flatpak_bwrap_add_args (app_bwrap,
- "--ro-bind", proxy_socket, sandbox_socket_path,
- NULL);
- flatpak_bwrap_set_env (app_bwrap, "AT_SPI_BUS_ADDRESS", sandbox_dbus_address, TRUE);
-
- return TRUE;
-}
-
-/* This wraps the argv in a bwrap call, primary to allow the
- command to be run with a proper /.flatpak-info with data
- taken from app_info_path */
-static gboolean
-add_bwrap_wrapper (FlatpakBwrap *bwrap,
- const char *app_info_path,
- GError **error)
-{
- glnx_autofd int app_info_fd = -1;
- g_auto(GLnxDirFdIterator) dir_iter = { 0 };
- struct dirent *dent;
- g_autofree char *user_runtime_dir = flatpak_get_real_xdg_runtime_dir ();
- g_autofree char *proxy_socket_dir = g_build_filename (user_runtime_dir, ".dbus-proxy/", NULL);
-
- app_info_fd = open (app_info_path, O_RDONLY | O_CLOEXEC);
- if (app_info_fd == -1)
- return glnx_throw_errno_prefix (error, _("Failed to open app info file"));
-
- if (!glnx_dirfd_iterator_init_at (AT_FDCWD, "/", FALSE, &dir_iter, error))
- return FALSE;
-
- flatpak_bwrap_add_arg (bwrap, flatpak_get_bwrap ());
-
- while (TRUE)
- {
- glnx_autofd int o_path_fd = -1;
- struct statfs stfs;
-
- if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dir_iter, &dent, NULL, error))
- return FALSE;
-
- if (dent == NULL)
- break;
-
- if (strcmp (dent->d_name, ".flatpak-info") == 0)
- continue;
-
- /* O_PATH + fstatfs is the magic that we need to statfs without automounting the target */
- o_path_fd = openat (dir_iter.fd, dent->d_name, O_PATH | O_NOFOLLOW | O_CLOEXEC);
- if (o_path_fd == -1 || fstatfs (o_path_fd, &stfs) != 0 || stfs.f_type == AUTOFS_SUPER_MAGIC)
- continue; /* AUTOFS mounts are risky and can cause us to block (see issue #1633), so ignore it. Its unlikely the proxy needs such a directory. */
-
- if (dent->d_type == DT_DIR)
- {
- if (strcmp (dent->d_name, "tmp") == 0 ||
- strcmp (dent->d_name, "var") == 0 ||
- strcmp (dent->d_name, "run") == 0)
- flatpak_bwrap_add_arg (bwrap, "--bind");
- else
- flatpak_bwrap_add_arg (bwrap, "--ro-bind");
-
- flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
- flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
- }
- else if (dent->d_type == DT_LNK)
- {
- g_autofree gchar *target = NULL;
-
- target = glnx_readlinkat_malloc (dir_iter.fd, dent->d_name,
- NULL, error);
- if (target == NULL)
- return FALSE;
- flatpak_bwrap_add_args (bwrap, "--symlink", target, NULL);
- flatpak_bwrap_add_arg_printf (bwrap, "/%s", dent->d_name);
- }
- }
-
- flatpak_bwrap_add_args (bwrap, "--bind", proxy_socket_dir, proxy_socket_dir, NULL);
-
- /* This is a file rather than a bind mount, because it will then
- not be unmounted from the namespace when the namespace dies. */
- flatpak_bwrap_add_args (bwrap, "--perms", "0600", NULL);
- flatpak_bwrap_add_args_data_fd (bwrap, "--file", glnx_steal_fd (&app_info_fd), "/.flatpak-info");
-
- if (!flatpak_bwrap_bundle_args (bwrap, 1, -1, FALSE, error))
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-start_dbus_proxy (FlatpakBwrap *app_bwrap,
- FlatpakBwrap *proxy_arg_bwrap,
- const char *app_info_path,
- GError **error)
-{
- char x = 'x';
- const char *proxy;
- g_autofree char *commandline = NULL;
- g_autoptr(FlatpakBwrap) proxy_bwrap = NULL;
- int sync_fds[2] = {-1, -1};
- int proxy_start_index;
-
- proxy_bwrap = flatpak_bwrap_new (NULL);
-
- if (!add_bwrap_wrapper (proxy_bwrap, app_info_path, error))
- return FALSE;
-
- proxy = g_getenv ("FLATPAK_DBUSPROXY");
- if (proxy == NULL)
- proxy = DBUSPROXY;
-
- flatpak_bwrap_add_arg (proxy_bwrap, proxy);
-
- proxy_start_index = proxy_bwrap->argv->len;
-
- if (pipe2 (sync_fds, O_CLOEXEC) < 0)
- {
- g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
- _("Unable to create sync pipe"));
- return FALSE;
- }
-
- /* read end goes to app */
- flatpak_bwrap_add_args_data_fd (app_bwrap, "--sync-fd", sync_fds[0], NULL);
-
- /* write end goes to proxy */
- flatpak_bwrap_add_fd (proxy_bwrap, sync_fds[1]);
- flatpak_bwrap_add_arg_printf (proxy_bwrap, "--fd=%d", sync_fds[1]);
-
- /* Note: This steals the fds from proxy_arg_bwrap */
- flatpak_bwrap_append_bwrap (proxy_bwrap, proxy_arg_bwrap);
-
- if (!flatpak_bwrap_bundle_args (proxy_bwrap, proxy_start_index, -1, TRUE, error))
- return FALSE;
-
- flatpak_bwrap_finish (proxy_bwrap);
-
- commandline = flatpak_quote_argv ((const char **) proxy_bwrap->argv->pdata, -1);
- g_info ("Running '%s'", commandline);
-
- /* We use LEAVE_DESCRIPTORS_OPEN to work around dead-lock, see flatpak_close_fds_workaround */
- if (!g_spawn_async (NULL,
- (char **) proxy_bwrap->argv->pdata,
- NULL,
- G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
- flatpak_bwrap_child_setup_cb, proxy_bwrap->fds,
- NULL, error))
- return FALSE;
-
- /* The write end can be closed now, otherwise the read below will hang of xdg-dbus-proxy
- fails to start. */
- g_clear_pointer (&proxy_bwrap, flatpak_bwrap_free);
-
- /* Sync with proxy, i.e. wait until its listening on the sockets */
- if (read (sync_fds[0], &x, 1) != 1)
- {
- g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
- _("Failed to sync with dbus proxy"));
- return FALSE;
- }
-
- return TRUE;
-}
-
static int
flatpak_extension_compare_by_path (gconstpointer _a,
gconstpointer _b)
@@ -1590,8 +277,6 @@ flatpak_run_add_environment_args (FlatpakBwrap *bwrap,
g_autoptr(FlatpakExports) exports = NULL;
g_autoptr(FlatpakBwrap) proxy_arg_bwrap = flatpak_bwrap_new (flatpak_bwrap_empty_env);
g_autofree char *xdg_dirs_conf = NULL;
- gboolean has_wayland = FALSE;
- gboolean allow_x11 = FALSE;
gboolean home_access = FALSE;
gboolean sandboxed = (flags & FLATPAK_RUN_FLAG_SANDBOX) != 0;
@@ -1802,45 +487,7 @@ flatpak_run_add_environment_args (FlatpakBwrap *bwrap,
flatpak_context_append_bwrap_filesystem (context, bwrap, app_id, app_id_dir,
exports, xdg_dirs_conf, home_access);
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_WAYLAND)
- {
- g_info ("Allowing wayland access");
- has_wayland = flatpak_run_add_wayland_args (bwrap);
- }
-
- if ((context->sockets & FLATPAK_CONTEXT_SOCKET_FALLBACK_X11) != 0)
- allow_x11 = !has_wayland;
- else
- allow_x11 = (context->sockets & FLATPAK_CONTEXT_SOCKET_X11) != 0;
-
- flatpak_run_add_x11_args (bwrap, allow_x11, context->shares);
-
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_SSH_AUTH)
- {
- flatpak_run_add_ssh_args (bwrap);
- }
-
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_PULSEAUDIO)
- {
- g_info ("Allowing pulseaudio access");
- flatpak_run_add_pulseaudio_args (bwrap, context->shares);
- }
-
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_PCSC)
- {
- flatpak_run_add_pcsc_args (bwrap);
- }
-
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_CUPS)
- {
- flatpak_run_add_cups_args (bwrap);
- }
-
- if (context->sockets & FLATPAK_CONTEXT_SOCKET_GPG_AGENT)
- {
- flatpak_run_add_gpg_agent_args (bwrap);
- }
-
+ flatpak_run_add_socket_args_environment (bwrap, context->shares, context->sockets);
flatpak_run_add_session_dbus_args (bwrap, proxy_arg_bwrap, context, flags, app_id);
flatpak_run_add_system_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
flatpak_run_add_a11y_dbus_args (bwrap, proxy_arg_bwrap, context, flags);
@@ -1855,8 +502,8 @@ flatpak_run_add_environment_args (FlatpakBwrap *bwrap,
g_clear_error (&my_error);
}
- if (!flatpak_bwrap_is_empty (proxy_arg_bwrap) &&
- !start_dbus_proxy (bwrap, proxy_arg_bwrap, app_info_path, error))
+ if (!flatpak_run_maybe_start_dbus_proxy (bwrap, proxy_arg_bwrap,
+ app_info_path, error))
return FALSE;
if (exports_out)
@@ -4668,13 +3315,7 @@ flatpak_run_app (FlatpakDecomposed *app_ref,
NULL);
}
- if ((app_context->shares & FLATPAK_CONTEXT_SHARED_NETWORK) != 0)
- {
- flatpak_run_add_gssproxy_args (bwrap);
- flatpak_run_add_resolved_args (bwrap);
- }
-
- flatpak_run_add_journal_args (bwrap);
+ flatpak_run_add_socket_args_late (bwrap, app_context->shares);
add_font_path_args (bwrap);
add_icon_path_args (bwrap);
diff --git a/common/meson.build b/common/meson.build
index b87f22ac..86d0573c 100644
--- a/common/meson.build
+++ b/common/meson.build
@@ -154,6 +154,11 @@ sources = [
'flatpak-remote-ref.c',
'flatpak-remote.c',
'flatpak-run.c',
+ 'flatpak-run-cups.c',
+ 'flatpak-run-dbus.c',
+ 'flatpak-run-pulseaudio.c',
+ 'flatpak-run-sockets.c',
+ 'flatpak-run-x11.c',
'flatpak-transaction.c',
'flatpak-utils-http.c',
'flatpak-utils.c',
diff --git a/tests/testcommon.c b/tests/testcommon.c
index 8ba3770d..7c96d8ed 100644
--- a/tests/testcommon.c
+++ b/tests/testcommon.c
@@ -10,6 +10,7 @@
#include "flatpak-appdata-private.h"
#include "flatpak-builtins-utils.h"
#include "flatpak-run-private.h"
+#include "flatpak-run-x11-private.h"
#include "flatpak-table-printer.h"
#include "parse-datetime.h"