mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-05 13:30:02 -05:00
protocol-native: add security context API
Add a new extension that can create a server on a user provided socket with user provided security properties. This is mainly used in flatpaks that want to create and bind a pipewire socket with specific permissions for the flatpak app. The flatpak will also provide an fd that will be closed when the server can be removed.
This commit is contained in:
parent
c5e8da7247
commit
e7846fc12a
8 changed files with 580 additions and 1 deletions
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <pipewire/impl.h>
|
||||
#include <pipewire/extensions/protocol-native.h>
|
||||
#include <pipewire/extensions/security-context.h>
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
|
|
@ -1879,6 +1880,66 @@ static int registry_marshal_destroy(void *object, uint32_t id)
|
|||
return pw_protocol_native_end_proxy(proxy, b);
|
||||
}
|
||||
|
||||
static int security_context_method_marshal_add_listener(void *object,
|
||||
struct spa_hook *listener,
|
||||
const struct pw_security_context_events *events,
|
||||
void *data)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
pw_proxy_add_object_listener(proxy, listener, events, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int security_context_marshal_create(void *object, const char *engine_name,
|
||||
int listen_fd, int close_fd, const struct spa_dict *props)
|
||||
{
|
||||
struct pw_proxy *proxy = object;
|
||||
struct spa_pod_builder *b;
|
||||
struct spa_pod_frame f;
|
||||
|
||||
b = pw_protocol_native_begin_proxy(proxy, PW_SECURITY_CONTEXT_METHOD_CREATE, NULL);
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
spa_pod_builder_add(b,
|
||||
SPA_POD_String(engine_name),
|
||||
SPA_POD_Fd(pw_protocol_native_add_proxy_fd(proxy, listen_fd)),
|
||||
SPA_POD_Fd(pw_protocol_native_add_proxy_fd(proxy, close_fd)),
|
||||
NULL);
|
||||
push_dict(b, props);
|
||||
spa_pod_builder_pop(b, &f);
|
||||
|
||||
return pw_protocol_native_end_proxy(proxy, b);
|
||||
}
|
||||
|
||||
static int security_context_demarshal_create(void *object, const struct pw_protocol_native_message *msg)
|
||||
{
|
||||
struct pw_resource *resource = object;
|
||||
struct spa_dict props = SPA_DICT_INIT(NULL, 0);
|
||||
struct spa_pod_parser prs;
|
||||
struct spa_pod_frame f[2];
|
||||
char *engine_name;
|
||||
int64_t listen_idx, close_idx;
|
||||
int listen_fd, close_fd;
|
||||
|
||||
spa_pod_parser_init(&prs, msg->data, msg->size);
|
||||
if (spa_pod_parser_push_struct(&prs, &f[0]) < 0)
|
||||
return -EINVAL;
|
||||
if (spa_pod_parser_get(&prs,
|
||||
SPA_POD_String(&engine_name),
|
||||
SPA_POD_Fd(&listen_idx),
|
||||
SPA_POD_Fd(&close_idx),
|
||||
NULL) < 0)
|
||||
return -EINVAL;
|
||||
parse_dict_struct(&prs, &f[1], &props);
|
||||
|
||||
listen_fd = pw_protocol_native_get_resource_fd(resource, listen_idx);
|
||||
close_fd = pw_protocol_native_get_resource_fd(resource, close_idx);
|
||||
|
||||
return pw_resource_notify(resource, struct pw_security_context_methods, create, 0,
|
||||
engine_name, listen_fd, close_fd, &props);
|
||||
}
|
||||
|
||||
|
||||
static const struct pw_core_methods pw_protocol_native_core_method_marshal = {
|
||||
PW_VERSION_CORE_METHODS,
|
||||
.add_listener = &core_method_marshal_add_listener,
|
||||
|
|
@ -2253,6 +2314,40 @@ static const struct pw_protocol_marshal pw_protocol_native_link_marshal = {
|
|||
.client_demarshal = pw_protocol_native_link_event_demarshal,
|
||||
};
|
||||
|
||||
|
||||
static const struct pw_security_context_methods pw_protocol_native_security_context_method_marshal = {
|
||||
PW_VERSION_LINK_METHODS,
|
||||
.add_listener = &security_context_method_marshal_add_listener,
|
||||
.create = &security_context_marshal_create,
|
||||
};
|
||||
|
||||
static const struct pw_protocol_native_demarshal
|
||||
pw_protocol_native_security_context_method_demarshal[PW_SECURITY_CONTEXT_METHOD_NUM] =
|
||||
{
|
||||
[PW_SECURITY_CONTEXT_METHOD_ADD_LISTENER] = { NULL, 0, },
|
||||
[PW_SECURITY_CONTEXT_METHOD_CREATE] = { &security_context_demarshal_create, 0, },
|
||||
};
|
||||
|
||||
static const struct pw_security_context_events pw_protocol_native_security_context_event_marshal = {
|
||||
PW_VERSION_LINK_EVENTS,
|
||||
};
|
||||
|
||||
static const struct pw_protocol_native_demarshal
|
||||
pw_protocol_native_security_context_event_demarshal[PW_SECURITY_CONTEXT_EVENT_NUM] =
|
||||
{
|
||||
};
|
||||
|
||||
static const struct pw_protocol_marshal pw_protocol_native_security_context_marshal = {
|
||||
PW_TYPE_INTERFACE_SecurityContext,
|
||||
PW_VERSION_SECURITY_CONTEXT,
|
||||
0,
|
||||
PW_SECURITY_CONTEXT_METHOD_NUM,
|
||||
PW_SECURITY_CONTEXT_EVENT_NUM,
|
||||
.client_marshal = &pw_protocol_native_security_context_method_marshal,
|
||||
.server_demarshal = pw_protocol_native_security_context_method_demarshal,
|
||||
.server_marshal = &pw_protocol_native_security_context_event_marshal,
|
||||
.client_demarshal = pw_protocol_native_security_context_event_demarshal,
|
||||
};
|
||||
void pw_protocol_native_init(struct pw_protocol *protocol)
|
||||
{
|
||||
pw_protocol_add_marshal(protocol, &pw_protocol_native_core_marshal);
|
||||
|
|
@ -2264,4 +2359,5 @@ void pw_protocol_native_init(struct pw_protocol *protocol)
|
|||
pw_protocol_add_marshal(protocol, &pw_protocol_native_factory_marshal);
|
||||
pw_protocol_add_marshal(protocol, &pw_protocol_native_client_marshal);
|
||||
pw_protocol_add_marshal(protocol, &pw_protocol_native_link_marshal);
|
||||
pw_protocol_add_marshal(protocol, &pw_protocol_native_security_context_marshal);
|
||||
}
|
||||
|
|
|
|||
132
src/modules/module-protocol-native/security-context.c
Normal file
132
src/modules/module-protocol-native/security-context.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* PipeWire */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2024 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <pipewire/impl.h>
|
||||
#include <pipewire/private.h>
|
||||
#include <pipewire/extensions/security-context.h>
|
||||
|
||||
PW_LOG_TOPIC_EXTERN(mod_topic);
|
||||
#define PW_LOG_TOPIC_DEFAULT mod_topic
|
||||
PW_LOG_TOPIC_EXTERN(mod_topic_connection);
|
||||
|
||||
struct impl {
|
||||
struct pw_context *context;
|
||||
struct pw_global *global;
|
||||
|
||||
struct pw_protocol *protocol;
|
||||
};
|
||||
|
||||
struct resource_data {
|
||||
struct impl *impl;
|
||||
|
||||
struct pw_resource *resource;
|
||||
struct spa_hook resource_listener;
|
||||
struct spa_hook object_listener;
|
||||
};
|
||||
|
||||
static int security_context_create(void *object,
|
||||
const char *engine_name,
|
||||
int listen_fd,
|
||||
int close_fd,
|
||||
const struct spa_dict *props)
|
||||
{
|
||||
struct resource_data *d = object;
|
||||
struct impl *impl = d->impl;
|
||||
pw_protocol_add_fd_server(impl->protocol, impl->context->core,
|
||||
listen_fd, close_fd, props);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pw_security_context_methods security_context_methods = {
|
||||
PW_VERSION_SECURITY_CONTEXT_METHODS,
|
||||
.create = security_context_create,
|
||||
};
|
||||
|
||||
static void global_unbind(void *data)
|
||||
{
|
||||
struct resource_data *d = data;
|
||||
if (d->resource) {
|
||||
spa_hook_remove(&d->resource_listener);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_resource_events resource_events = {
|
||||
PW_VERSION_RESOURCE_EVENTS,
|
||||
.destroy = global_unbind,
|
||||
};
|
||||
|
||||
static int
|
||||
global_bind(void *object, struct pw_impl_client *client, uint32_t permissions,
|
||||
uint32_t version, uint32_t id)
|
||||
{
|
||||
struct impl *impl = object;
|
||||
struct pw_resource *resource;
|
||||
struct resource_data *data;
|
||||
|
||||
resource = pw_resource_new(client, id, permissions,
|
||||
PW_TYPE_INTERFACE_SecurityContext,
|
||||
version, sizeof(*data));
|
||||
if (resource == NULL)
|
||||
return -errno;
|
||||
|
||||
data = pw_resource_get_user_data(resource);
|
||||
data->impl = impl;
|
||||
data->resource = resource;
|
||||
|
||||
pw_global_add_resource(impl->global, resource);
|
||||
|
||||
/* listen for when the resource goes away */
|
||||
pw_resource_add_listener(resource,
|
||||
&data->resource_listener,
|
||||
&resource_events, data);
|
||||
|
||||
/* resource methods -> implementation */
|
||||
pw_resource_add_object_listener(resource,
|
||||
&data->object_listener,
|
||||
&security_context_methods, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int protocol_native_security_context_init(struct pw_impl_module *module, struct pw_protocol *protocol)
|
||||
{
|
||||
struct pw_context *context = pw_impl_module_get_context(module);
|
||||
struct impl *impl;
|
||||
char serial_str[32];
|
||||
struct spa_dict_item items[1] = {
|
||||
SPA_DICT_ITEM_INIT(PW_KEY_OBJECT_SERIAL, serial_str),
|
||||
};
|
||||
struct spa_dict extra_props = SPA_DICT_INIT_ARRAY(items);
|
||||
static const char * const keys[] = {
|
||||
PW_KEY_OBJECT_SERIAL,
|
||||
NULL
|
||||
};
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
return -errno;
|
||||
|
||||
impl->context = context;
|
||||
impl->protocol = protocol;
|
||||
|
||||
impl->global = pw_global_new(context,
|
||||
PW_TYPE_INTERFACE_SecurityContext,
|
||||
PW_VERSION_SECURITY_CONTEXT,
|
||||
PW_SECURITY_CONTEXT_PERM_MASK,
|
||||
NULL,
|
||||
global_bind, impl);
|
||||
if (impl->global == NULL) {
|
||||
free(impl);
|
||||
return -errno;
|
||||
}
|
||||
spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
|
||||
pw_global_get_serial(impl->global));
|
||||
pw_global_update_keys(impl->global, &extra_props, keys);
|
||||
|
||||
pw_global_register(impl->global);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue