2017-05-23 19:15:33 +02:00
|
|
|
/* PipeWire
|
2017-04-17 16:32:25 +02:00
|
|
|
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 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
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2018-02-08 10:02:17 +01:00
|
|
|
#include <dbus/dbus.h>
|
|
|
|
|
|
2017-12-18 13:16:42 +01:00
|
|
|
#include <spa/support/dbus.h>
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-07-11 15:57:20 +02:00
|
|
|
#include "pipewire/core.h"
|
2017-08-08 19:55:14 +02:00
|
|
|
#include "pipewire/interfaces.h"
|
|
|
|
|
#include "pipewire/link.h"
|
|
|
|
|
#include "pipewire/log.h"
|
2017-07-11 15:57:20 +02:00
|
|
|
#include "pipewire/module.h"
|
2017-08-08 19:55:14 +02:00
|
|
|
#include "pipewire/utils.h"
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-06-01 11:23:02 +02:00
|
|
|
static const struct spa_dict_item module_props[] = {
|
|
|
|
|
{ PW_MODULE_PROP_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
|
|
|
|
|
{ PW_MODULE_PROP_DESCRIPTION, "Perform portal queries to check permissions" },
|
|
|
|
|
{ PW_MODULE_PROP_VERSION, PACKAGE_VERSION },
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
struct impl {
|
2017-05-26 08:05:01 +02:00
|
|
|
struct pw_core *core;
|
2017-08-08 15:01:36 +02:00
|
|
|
struct pw_type *type;
|
2017-05-26 08:05:01 +02:00
|
|
|
struct pw_properties *properties;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-12-18 13:16:42 +01:00
|
|
|
struct spa_dbus_connection *conn;
|
2017-05-26 08:05:01 +02:00
|
|
|
DBusConnection *bus;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-08 16:56:29 +02:00
|
|
|
struct spa_hook core_listener;
|
2017-08-22 18:30:10 +02:00
|
|
|
struct spa_hook module_listener;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
struct spa_list client_list;
|
2017-05-23 19:15:33 +02:00
|
|
|
};
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
struct client_info {
|
2017-05-26 08:05:01 +02:00
|
|
|
struct spa_list link;
|
2017-09-15 14:52:17 +02:00
|
|
|
struct impl *impl;
|
2017-05-26 08:05:01 +02:00
|
|
|
struct pw_client *client;
|
2017-09-15 14:52:17 +02:00
|
|
|
struct spa_list resources;
|
2017-05-26 08:05:01 +02:00
|
|
|
struct spa_list async_pending;
|
2018-01-24 16:13:28 +01:00
|
|
|
bool camera_allowed;
|
2017-05-23 19:15:33 +02:00
|
|
|
};
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
struct async_pending {
|
2017-05-26 08:05:01 +02:00
|
|
|
struct spa_list link;
|
2018-01-24 16:13:28 +01:00
|
|
|
struct client_info *cinfo;
|
2017-06-12 18:20:59 +02:00
|
|
|
bool handled;
|
2017-05-26 08:05:01 +02:00
|
|
|
char *handle;
|
2017-05-23 19:15:33 +02:00
|
|
|
};
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
static struct client_info *find_client_info(struct impl *impl, struct pw_client *client)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
struct client_info *info;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
spa_list_for_each(info, &impl->client_list, link) {
|
|
|
|
|
if (info->client == client)
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
static void close_request(struct async_pending *p)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
DBusMessage *m = NULL;
|
2018-01-24 16:13:28 +01:00
|
|
|
struct impl *impl = p->cinfo->impl;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
pw_log_debug("pending %p: handle %s", p, p->handle);
|
2017-04-20 19:25:14 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!(m = dbus_message_new_method_call("org.freedesktop.portal.Request",
|
|
|
|
|
p->handle,
|
|
|
|
|
"org.freedesktop.portal.Request", "Close"))) {
|
|
|
|
|
pw_log_error("Failed to create message");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!dbus_connection_send(impl->bus, m, NULL))
|
|
|
|
|
pw_log_error("Failed to send message");
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
dbus_message_unref(m);
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
static struct async_pending *find_pending(struct client_info *cinfo, const char *handle)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
struct async_pending *p;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
spa_list_for_each(p, &cinfo->async_pending, link) {
|
|
|
|
|
if (strcmp(p->handle, handle) == 0)
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
static void free_pending(struct async_pending *p)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!p->handled)
|
|
|
|
|
close_request(p);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
pw_log_debug("pending %p: handle %s", p, p->handle);
|
|
|
|
|
spa_list_remove(&p->link);
|
|
|
|
|
free(p->handle);
|
2017-06-12 18:20:59 +02:00
|
|
|
free(p);
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
static void client_info_free(struct client_info *cinfo)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-09-15 14:52:17 +02:00
|
|
|
struct async_pending *p, *tp;
|
2017-05-26 08:05:01 +02:00
|
|
|
|
2017-09-15 14:52:17 +02:00
|
|
|
spa_list_for_each_safe(p, tp, &cinfo->async_pending, link)
|
2017-06-12 18:20:59 +02:00
|
|
|
free_pending(p);
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
spa_list_remove(&cinfo->link);
|
|
|
|
|
free(cinfo);
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
static int check_sandboxed(struct pw_client *client)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-09-18 13:25:15 +02:00
|
|
|
char root_path[2048];
|
2018-01-24 16:13:28 +01:00
|
|
|
int root_fd, info_fd, res;
|
2017-08-08 15:01:36 +02:00
|
|
|
const struct ucred *ucred;
|
2017-09-18 13:25:15 +02:00
|
|
|
struct stat stat_buf;
|
|
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
ucred = pw_client_get_ucred(client);
|
2017-08-08 15:01:36 +02:00
|
|
|
|
|
|
|
|
if (ucred) {
|
|
|
|
|
pw_log_info("client has trusted pid %d", ucred->pid);
|
2017-05-26 08:05:01 +02:00
|
|
|
} else {
|
|
|
|
|
pw_log_info("no trusted pid found, assuming not sandboxed\n");
|
2018-01-24 16:13:28 +01:00
|
|
|
return 0;
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-18 13:25:15 +02:00
|
|
|
sprintf(root_path, "/proc/%u/root", ucred->pid);
|
|
|
|
|
root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
|
|
|
|
|
if (root_fd == -1) {
|
|
|
|
|
/* Not able to open the root dir shouldn't happen. Probably the app died and
|
|
|
|
|
* we're failing due to /proc/$pid not existing. In that case fail instead
|
|
|
|
|
* of treating this as privileged. */
|
2018-01-24 16:13:28 +01:00
|
|
|
res = -errno;
|
|
|
|
|
pw_log_error("failed to open \"%s\": %m", root_path);
|
|
|
|
|
return res;
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
2017-09-18 13:25:15 +02:00
|
|
|
info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY);
|
|
|
|
|
close (root_fd);
|
|
|
|
|
if (info_fd == -1) {
|
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
|
pw_log_debug("no .flatpak-info, client on the host");
|
|
|
|
|
/* No file => on the host */
|
2018-01-24 16:13:28 +01:00
|
|
|
return 0;
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
2018-01-24 16:13:28 +01:00
|
|
|
res = -errno;
|
|
|
|
|
pw_log_error("error opening .flatpak-info: %m");
|
|
|
|
|
return res;
|
2017-09-18 13:25:15 +02:00
|
|
|
}
|
|
|
|
|
if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) {
|
2018-01-24 16:13:28 +01:00
|
|
|
/* Some weird fd => failure, assume sandboxed */
|
2017-09-18 13:25:15 +02:00
|
|
|
close(info_fd);
|
2018-01-24 16:13:28 +01:00
|
|
|
pw_log_error("error fstat .flatpak-info: %m");
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
2018-01-24 16:13:28 +01:00
|
|
|
return 1;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
2018-01-24 16:13:28 +01:00
|
|
|
check_global_owner(struct pw_client *client, struct pw_global *global)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-08-08 15:01:36 +02:00
|
|
|
struct pw_client *owner;
|
|
|
|
|
const struct ucred *owner_ucred, *client_ucred;
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (global == NULL)
|
|
|
|
|
return false;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-08 15:01:36 +02:00
|
|
|
owner = pw_global_get_owner(global);
|
|
|
|
|
if (owner == NULL)
|
2018-01-24 16:13:28 +01:00
|
|
|
return false;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-08 15:01:36 +02:00
|
|
|
owner_ucred = pw_client_get_ucred(owner);
|
|
|
|
|
client_ucred = pw_client_get_ucred(client);
|
|
|
|
|
|
|
|
|
|
if (owner_ucred == NULL || client_ucred == NULL)
|
2018-01-24 16:13:28 +01:00
|
|
|
return false;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
/* same user can see eachothers objects */
|
2017-08-08 15:01:36 +02:00
|
|
|
return owner_ucred->uid == client_ucred->uid;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
static int
|
|
|
|
|
set_global_permissions(void *data, struct pw_global *global)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2018-01-24 16:13:28 +01:00
|
|
|
struct client_info *cinfo = data;
|
|
|
|
|
struct impl *impl = cinfo->impl;
|
|
|
|
|
struct pw_client *client = cinfo->client;
|
|
|
|
|
const struct pw_properties *props;
|
|
|
|
|
const char *str;
|
|
|
|
|
struct spa_dict_item items[1];
|
|
|
|
|
int n_items = 0;
|
|
|
|
|
char perms[16];
|
|
|
|
|
bool allowed = false;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
props = pw_global_get_properties(global);
|
|
|
|
|
|
|
|
|
|
if (pw_global_get_type(global) == impl->type->core) {
|
|
|
|
|
allowed = true;
|
2017-07-13 15:21:52 +02:00
|
|
|
}
|
2018-01-24 16:13:28 +01:00
|
|
|
else if (pw_global_get_type(global) == impl->type->factory) {
|
|
|
|
|
if (props && (str = pw_properties_get(props, "factory.name"))) {
|
|
|
|
|
if (strcmp(str, "client-node") == 0)
|
|
|
|
|
allowed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (pw_global_get_type(global) == impl->type->node) {
|
|
|
|
|
if (props && (str = pw_properties_get(props, "media.class"))) {
|
|
|
|
|
if (strcmp(str, "Video/Source") == 0 && cinfo->camera_allowed)
|
|
|
|
|
allowed = true;
|
|
|
|
|
}
|
|
|
|
|
allowed |= check_global_owner(client, global);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
allowed = check_global_owner(client, global);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
snprintf(perms, sizeof(perms), "%d:%c--", pw_global_get_id(global), allowed ? 'r' : '-');
|
|
|
|
|
items[n_items++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, perms);
|
|
|
|
|
pw_client_update_permissions(client, &SPA_DICT_INIT(items, n_items));
|
|
|
|
|
|
|
|
|
|
return 0;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DBusHandlerResult
|
2017-05-26 18:19:51 +02:00
|
|
|
portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
struct client_info *cinfo = user_data;
|
2018-01-24 16:13:28 +01:00
|
|
|
struct pw_client *client = cinfo->client;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) {
|
|
|
|
|
uint32_t response = 2;
|
|
|
|
|
DBusError error;
|
|
|
|
|
struct async_pending *p;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
dbus_error_init(&error);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
dbus_connection_remove_filter(connection, portal_response, cinfo);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!dbus_message_get_args
|
|
|
|
|
(msg, &error, DBUS_TYPE_UINT32, &response, DBUS_TYPE_INVALID)) {
|
|
|
|
|
pw_log_error("failed to parse Response: %s", error.message);
|
|
|
|
|
dbus_error_free(&error);
|
|
|
|
|
}
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
p = find_pending(cinfo, dbus_message_get_path(msg));
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
p->handled = true;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
pw_log_debug("portal check result: %d", response);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
if (response == 0) {
|
2018-01-24 16:13:28 +01:00
|
|
|
/* allowed */
|
|
|
|
|
cinfo->camera_allowed = true;
|
|
|
|
|
pw_log_debug("camera access allowed");
|
2017-06-12 18:20:59 +02:00
|
|
|
} else {
|
2018-01-24 16:13:28 +01:00
|
|
|
cinfo->camera_allowed = false;
|
|
|
|
|
pw_log_debug("camera access not allowed");
|
2017-06-12 18:20:59 +02:00
|
|
|
}
|
2018-01-24 16:13:28 +01:00
|
|
|
pw_core_for_each_global(cinfo->impl->core, set_global_permissions, cinfo);
|
|
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
free_pending(p);
|
2018-01-24 16:13:28 +01:00
|
|
|
pw_client_set_busy(client, false);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
static void do_portal_check(struct client_info *cinfo)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-06-12 18:20:59 +02:00
|
|
|
struct impl *impl = cinfo->impl;
|
2017-08-08 15:01:36 +02:00
|
|
|
struct pw_client *client = cinfo->client;
|
2017-05-26 08:05:01 +02:00
|
|
|
DBusMessage *m = NULL, *r = NULL;
|
|
|
|
|
DBusError error;
|
|
|
|
|
pid_t pid;
|
|
|
|
|
DBusMessageIter msg_iter;
|
|
|
|
|
DBusMessageIter dict_iter;
|
|
|
|
|
const char *handle;
|
|
|
|
|
const char *device;
|
2017-06-12 18:20:59 +02:00
|
|
|
struct async_pending *p;
|
2017-05-26 08:05:01 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
pw_log_info("ask portal for client %p", client);
|
2017-08-08 15:01:36 +02:00
|
|
|
pw_client_set_busy(client, true);
|
2017-05-26 08:05:01 +02:00
|
|
|
|
|
|
|
|
dbus_error_init(&error);
|
|
|
|
|
|
|
|
|
|
if (!(m = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
|
|
|
|
|
"/org/freedesktop/portal/desktop",
|
|
|
|
|
"org.freedesktop.portal.Device", "AccessDevice")))
|
|
|
|
|
goto no_method_call;
|
|
|
|
|
|
|
|
|
|
device = "camera";
|
|
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
pid = pw_client_get_ucred(client)->pid;
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID))
|
|
|
|
|
goto message_failed;
|
|
|
|
|
|
|
|
|
|
dbus_message_iter_init_append(m, &msg_iter);
|
|
|
|
|
dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &dict_iter);
|
|
|
|
|
dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &device);
|
|
|
|
|
dbus_message_iter_close_container(&msg_iter, &dict_iter);
|
|
|
|
|
|
|
|
|
|
dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter);
|
|
|
|
|
dbus_message_iter_close_container(&msg_iter, &dict_iter);
|
|
|
|
|
|
|
|
|
|
if (!(r = dbus_connection_send_with_reply_and_block(impl->bus, m, -1, &error)))
|
|
|
|
|
goto send_failed;
|
|
|
|
|
|
|
|
|
|
dbus_message_unref(m);
|
|
|
|
|
|
|
|
|
|
if (!dbus_message_get_args(r, &error, DBUS_TYPE_OBJECT_PATH, &handle, DBUS_TYPE_INVALID))
|
|
|
|
|
goto parse_failed;
|
|
|
|
|
|
|
|
|
|
dbus_message_unref(r);
|
|
|
|
|
|
|
|
|
|
dbus_bus_add_match(impl->bus,
|
|
|
|
|
"type='signal',interface='org.freedesktop.portal.Request'", &error);
|
|
|
|
|
dbus_connection_flush(impl->bus);
|
|
|
|
|
if (dbus_error_is_set(&error))
|
|
|
|
|
goto subscribe_failed;
|
|
|
|
|
|
|
|
|
|
dbus_connection_add_filter(impl->bus, portal_response, cinfo, NULL);
|
|
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
p = calloc(1, sizeof(struct async_pending));
|
2018-01-24 16:13:28 +01:00
|
|
|
p->cinfo = cinfo;
|
2017-06-12 18:20:59 +02:00
|
|
|
p->handle = strdup(handle);
|
|
|
|
|
p->handled = false;
|
|
|
|
|
|
|
|
|
|
pw_log_debug("pending %p: handle %s", p, handle);
|
2017-09-15 14:52:17 +02:00
|
|
|
spa_list_append(&cinfo->async_pending, &p->link);
|
2017-05-26 08:05:01 +02:00
|
|
|
|
2017-06-12 18:20:59 +02:00
|
|
|
return;
|
2017-05-26 08:05:01 +02:00
|
|
|
|
|
|
|
|
no_method_call:
|
|
|
|
|
pw_log_error("Failed to create message");
|
2017-06-12 18:20:59 +02:00
|
|
|
goto not_allowed;
|
2017-05-26 08:05:01 +02:00
|
|
|
message_failed:
|
|
|
|
|
dbus_message_unref(m);
|
2017-06-12 18:20:59 +02:00
|
|
|
goto not_allowed;
|
2017-05-26 08:05:01 +02:00
|
|
|
send_failed:
|
|
|
|
|
pw_log_error("Failed to call portal: %s", error.message);
|
|
|
|
|
dbus_error_free(&error);
|
|
|
|
|
dbus_message_unref(m);
|
2017-06-12 18:20:59 +02:00
|
|
|
goto not_allowed;
|
2017-05-26 08:05:01 +02:00
|
|
|
parse_failed:
|
|
|
|
|
pw_log_error("Failed to parse AccessDevice result: %s", error.message);
|
|
|
|
|
dbus_error_free(&error);
|
|
|
|
|
dbus_message_unref(r);
|
2017-06-12 18:20:59 +02:00
|
|
|
goto not_allowed;
|
2017-05-26 08:05:01 +02:00
|
|
|
subscribe_failed:
|
|
|
|
|
pw_log_error("Failed to subscribe to Request signal: %s", error.message);
|
|
|
|
|
dbus_error_free(&error);
|
2017-06-12 18:20:59 +02:00
|
|
|
goto not_allowed;
|
|
|
|
|
not_allowed:
|
2018-01-24 16:13:28 +01:00
|
|
|
pw_resource_error(pw_client_get_core_resource(client), -EPERM, "not allowed");
|
2017-06-12 18:20:59 +02:00
|
|
|
return;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-08-04 10:18:54 +02:00
|
|
|
core_global_added(void *data, struct pw_global *global)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-08-04 10:18:54 +02:00
|
|
|
struct impl *impl = data;
|
2018-01-24 16:13:28 +01:00
|
|
|
struct client_info *cinfo;
|
|
|
|
|
int res;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-08 15:01:36 +02:00
|
|
|
if (pw_global_get_type(global) == impl->type->client) {
|
|
|
|
|
struct pw_client *client = pw_global_get_object(global);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
res = check_sandboxed(client);
|
|
|
|
|
if (res == 0) {
|
|
|
|
|
pw_log_debug("module %p: non sandboxed client %p", impl, client);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res < 0) {
|
|
|
|
|
pw_log_warn("module %p: client %p sandbox check failed: %s",
|
|
|
|
|
impl, client, spa_strerror(res));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
pw_log_debug("module %p: sandboxed client %p added", impl, client);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* sandboxed clients are placed in a list and we do a portal check */
|
2017-05-26 08:05:01 +02:00
|
|
|
cinfo = calloc(1, sizeof(struct client_info));
|
|
|
|
|
cinfo->impl = impl;
|
|
|
|
|
cinfo->client = client;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
spa_list_init(&cinfo->async_pending);
|
2017-06-12 18:20:59 +02:00
|
|
|
|
2017-10-24 12:58:10 +02:00
|
|
|
spa_list_append(&impl->client_list, &cinfo->link);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-01-24 16:13:28 +01:00
|
|
|
do_portal_check(cinfo);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
spa_list_for_each(cinfo, &impl->client_list, link)
|
|
|
|
|
set_global_permissions(cinfo, global);
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-08-04 10:18:54 +02:00
|
|
|
core_global_removed(void *data, struct pw_global *global)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-08-04 10:18:54 +02:00
|
|
|
struct impl *impl = data;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-08 15:01:36 +02:00
|
|
|
if (pw_global_get_type(global) == impl->type->client) {
|
|
|
|
|
struct pw_client *client = pw_global_get_object(global);
|
2017-05-26 08:05:01 +02:00
|
|
|
struct client_info *cinfo;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if ((cinfo = find_client_info(impl, client)))
|
|
|
|
|
client_info_free(cinfo);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
pw_log_debug("module %p: client %p removed", impl, client);
|
|
|
|
|
}
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-12-14 18:28:03 +01:00
|
|
|
static const struct pw_core_events core_events = {
|
2017-08-04 16:49:13 +02:00
|
|
|
PW_VERSION_CORE_EVENTS,
|
2017-08-04 10:18:54 +02:00
|
|
|
.global_added = core_global_added,
|
|
|
|
|
.global_removed = core_global_removed,
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-22 18:30:10 +02:00
|
|
|
static void module_destroy(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
struct client_info *info, *t;
|
|
|
|
|
|
|
|
|
|
spa_hook_remove(&impl->core_listener);
|
|
|
|
|
spa_hook_remove(&impl->module_listener);
|
|
|
|
|
|
2017-12-18 13:16:42 +01:00
|
|
|
spa_dbus_connection_destroy(impl->conn);
|
2017-08-22 18:30:10 +02:00
|
|
|
|
|
|
|
|
spa_list_for_each_safe(info, t, &impl->client_list, link)
|
|
|
|
|
client_info_free(info);
|
|
|
|
|
|
|
|
|
|
if (impl->properties)
|
|
|
|
|
pw_properties_free(impl->properties);
|
|
|
|
|
|
|
|
|
|
free(impl);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 18:28:03 +01:00
|
|
|
static const struct pw_module_events module_events = {
|
2017-08-22 18:30:10 +02:00
|
|
|
PW_VERSION_MODULE_EVENTS,
|
|
|
|
|
.destroy = module_destroy,
|
|
|
|
|
};
|
|
|
|
|
|
2017-12-18 11:38:30 +01:00
|
|
|
static int module_init(struct pw_module *module, struct pw_properties *properties)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-08-08 15:01:36 +02:00
|
|
|
struct pw_core *core = pw_module_get_core(module);
|
2017-05-26 08:05:01 +02:00
|
|
|
struct impl *impl;
|
2017-12-18 13:16:42 +01:00
|
|
|
struct spa_dbus *dbus;
|
|
|
|
|
const struct spa_support *support;
|
|
|
|
|
uint32_t n_support;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-12-18 13:16:42 +01:00
|
|
|
support = pw_core_get_support(core, &n_support);
|
|
|
|
|
|
|
|
|
|
dbus = spa_support_find(support, n_support, SPA_TYPE__DBus);
|
|
|
|
|
if (dbus == NULL)
|
|
|
|
|
return -ENOTSUP;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
impl = calloc(1, sizeof(struct impl));
|
2017-12-18 11:38:30 +01:00
|
|
|
if (impl == NULL)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
pw_log_debug("module %p: new", impl);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
impl->core = core;
|
2017-08-08 15:01:36 +02:00
|
|
|
impl->type = pw_core_get_type(core);
|
2017-05-26 08:05:01 +02:00
|
|
|
impl->properties = properties;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2018-02-08 10:02:17 +01:00
|
|
|
impl->conn = spa_dbus_get_connection(dbus, SPA_DBUS_TYPE_SESSION);
|
2017-12-18 13:16:42 +01:00
|
|
|
if (impl->conn == NULL)
|
|
|
|
|
goto error;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-12-18 13:16:42 +01:00
|
|
|
impl->bus = spa_dbus_connection_get(impl->conn);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
spa_list_init(&impl->client_list);
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-08-04 16:49:13 +02:00
|
|
|
pw_core_add_listener(core, &impl->core_listener, &core_events, impl);
|
2017-08-22 18:30:10 +02:00
|
|
|
pw_module_add_listener(module, &impl->module_listener, &module_events, impl);
|
2017-08-04 10:18:54 +02:00
|
|
|
|
2018-06-01 11:23:02 +02:00
|
|
|
pw_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
|
|
|
|
|
2017-12-18 11:38:30 +01:00
|
|
|
return 0;
|
2017-04-17 16:32:25 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
error:
|
2017-09-04 14:39:45 +05:30
|
|
|
free(impl);
|
2018-02-08 10:02:17 +01:00
|
|
|
pw_log_error("Failed to connect to system bus");
|
2017-12-18 11:38:30 +01:00
|
|
|
return -ENOMEM;
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-12-18 11:38:30 +01:00
|
|
|
int pipewire__module_init(struct pw_module *module, const char *args)
|
2017-04-17 16:32:25 +02:00
|
|
|
{
|
2017-08-08 15:01:36 +02:00
|
|
|
return module_init(module, NULL);
|
2017-04-17 16:32:25 +02:00
|
|
|
}
|