2024-02-08 10:04:21 +01:00
|
|
|
/* 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;
|
2024-03-15 13:00:30 +01:00
|
|
|
struct spa_hook listener;
|
2024-02-08 10:04:21 +01:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
int listen_fd,
|
|
|
|
|
int close_fd,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
struct resource_data *d = object;
|
|
|
|
|
struct impl *impl = d->impl;
|
2024-02-08 13:01:13 +01:00
|
|
|
struct pw_impl_client *client;
|
2024-02-08 13:24:41 +01:00
|
|
|
const struct pw_properties *p;
|
2024-02-08 13:01:13 +01:00
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
if ((client = impl->context->current_client) == NULL)
|
2024-02-09 10:23:03 +01:00
|
|
|
goto invalid_state;
|
2024-02-08 13:01:13 +01:00
|
|
|
if (client->protocol != impl->protocol)
|
2024-02-09 10:23:03 +01:00
|
|
|
goto invalid_state;
|
2024-02-08 13:01:13 +01:00
|
|
|
|
|
|
|
|
/* we can't make a nested security context */
|
2024-02-08 13:24:41 +01:00
|
|
|
p = pw_impl_client_get_properties(client);
|
|
|
|
|
if (pw_properties_get(p, PW_KEY_SEC_ENGINE) != NULL)
|
2024-02-08 13:01:13 +01:00
|
|
|
goto not_allowed;
|
|
|
|
|
|
|
|
|
|
if (pw_protocol_add_fd_server(impl->protocol, impl->context->core,
|
2024-02-09 10:23:03 +01:00
|
|
|
listen_fd, close_fd, props) == NULL) {
|
2024-02-08 13:01:13 +01:00
|
|
|
res = -errno;
|
2024-02-09 10:23:03 +01:00
|
|
|
pw_resource_errorf(d->resource, res, "can't add fd server: %m");
|
|
|
|
|
}
|
2024-02-08 13:01:13 +01:00
|
|
|
return res;
|
|
|
|
|
|
2024-02-09 10:23:03 +01:00
|
|
|
invalid_state:
|
|
|
|
|
pw_resource_errorf(d->resource, -EIO, "invalid client protocol");
|
|
|
|
|
return -EIO;
|
2024-02-08 13:01:13 +01:00
|
|
|
not_allowed:
|
2024-02-09 10:23:03 +01:00
|
|
|
pw_resource_errorf(d->resource, -EPERM, "Nested security context is not allowed");
|
2024-02-08 13:01:13 +01:00
|
|
|
return -EPERM;
|
2024-02-08 10:04:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-15 13:00:30 +01:00
|
|
|
|
|
|
|
|
static void global_free(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
if (impl->global) {
|
|
|
|
|
spa_hook_remove(&impl->listener);
|
|
|
|
|
impl->global = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct pw_global_events global_events = {
|
|
|
|
|
PW_VERSION_GLOBAL_EVENTS,
|
|
|
|
|
.free = global_free
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void protocol_native_security_context_free(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct impl *impl = data;
|
|
|
|
|
if (impl->global)
|
|
|
|
|
pw_global_destroy(impl->global);
|
|
|
|
|
free(impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *protocol_native_security_context_init(struct pw_impl_module *module, struct pw_protocol *protocol)
|
2024-02-08 10:04:21 +01:00
|
|
|
{
|
|
|
|
|
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)
|
2024-03-15 13:00:30 +01:00
|
|
|
return NULL;
|
2024-02-08 10:04:21 +01:00
|
|
|
|
|
|
|
|
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);
|
2024-03-15 13:00:30 +01:00
|
|
|
return NULL;
|
2024-02-08 10:04:21 +01:00
|
|
|
}
|
|
|
|
|
spa_scnprintf(serial_str, sizeof(serial_str), "%"PRIu64,
|
|
|
|
|
pw_global_get_serial(impl->global));
|
|
|
|
|
pw_global_update_keys(impl->global, &extra_props, keys);
|
|
|
|
|
|
2024-03-15 13:00:30 +01:00
|
|
|
pw_global_add_listener(impl->global, &impl->listener, &global_events, impl);
|
|
|
|
|
|
2024-02-08 10:04:21 +01:00
|
|
|
pw_global_register(impl->global);
|
|
|
|
|
|
2024-03-15 13:00:30 +01:00
|
|
|
return impl;
|
2024-02-08 10:04:21 +01:00
|
|
|
}
|