mirror of
https://github.com/flatpak/flatpak.git
synced 2026-02-03 04:21:28 -05:00
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>
This commit is contained in:
@@ -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 \
|
||||
|
||||
32
common/flatpak-run-cups-private.h
Normal file
32
common/flatpak-run-cups-private.h
Normal file
@@ -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
|
||||
127
common/flatpak-run-cups.c
Normal file
127
common/flatpak-run-cups.c
Normal file
@@ -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);
|
||||
}
|
||||
52
common/flatpak-run-dbus-private.h
Normal file
52
common/flatpak-run-dbus-private.h
Normal file
@@ -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
|
||||
449
common/flatpak-run-dbus.c
Normal file
449
common/flatpak-run-dbus.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
|
||||
34
common/flatpak-run-pulseaudio-private.h
Normal file
34
common/flatpak-run-pulseaudio-private.h
Normal file
@@ -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
|
||||
338
common/flatpak-run-pulseaudio.c
Normal file
338
common/flatpak-run-pulseaudio.c
Normal file
@@ -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);
|
||||
}
|
||||
37
common/flatpak-run-sockets-private.h
Normal file
37
common/flatpak-run-sockets-private.h
Normal file
@@ -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
|
||||
278
common/flatpak-run-sockets.c
Normal file
278
common/flatpak-run-sockets.c
Normal file
@@ -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);
|
||||
}
|
||||
42
common/flatpak-run-x11-private.h
Normal file
42
common/flatpak-run-x11-private.h
Normal file
@@ -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
|
||||
333
common/flatpak-run-x11.c
Normal file
333
common/flatpak-run-x11.c
Normal file
@@ -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");
|
||||
}
|
||||
}
|
||||
1371
common/flatpak-run.c
1371
common/flatpak-run.c
File diff suppressed because it is too large
Load Diff
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user