2024-02-08 10:04:21 +01:00
|
|
|
/* PipeWire */
|
|
|
|
|
/* SPDX-FileCopyrightText: Copyright © 2024 Wim Taymans */
|
|
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
#include <pipewire/pipewire.h>
|
|
|
|
|
#include <pipewire/main-loop.h>
|
|
|
|
|
#include <pipewire/extensions/security-context.h>
|
|
|
|
|
|
|
|
|
|
#include <spa/utils/string.h>
|
|
|
|
|
|
|
|
|
|
#define TEST_FUNC(a,b,func) \
|
|
|
|
|
do { \
|
|
|
|
|
a.func = b.func; \
|
|
|
|
|
spa_assert_se(SPA_PTRDIFF(&a.func, &a) == SPA_PTRDIFF(&b.func, &b)); \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
static void test_abi(void)
|
|
|
|
|
{
|
|
|
|
|
static const struct {
|
|
|
|
|
uint32_t version;
|
|
|
|
|
} test = { PW_VERSION_SECURITY_CONTEXT_EVENTS, };
|
|
|
|
|
struct pw_security_context_events ev;
|
|
|
|
|
|
|
|
|
|
spa_assert_se(PW_VERSION_SECURITY_CONTEXT_EVENTS == 0);
|
|
|
|
|
spa_assert_se(sizeof(ev) == sizeof(test));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct roundtrip_data
|
|
|
|
|
{
|
|
|
|
|
struct pw_main_loop *loop;
|
|
|
|
|
int pending;
|
|
|
|
|
int done;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void core_event_done(void *object, uint32_t id, int seq)
|
|
|
|
|
{
|
|
|
|
|
struct roundtrip_data *data = object;
|
|
|
|
|
if (id == PW_ID_CORE && seq == data->pending) {
|
|
|
|
|
data->done = 1;
|
|
|
|
|
pw_main_loop_quit(data->loop);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int roundtrip(struct pw_core *core, struct pw_main_loop *loop)
|
|
|
|
|
{
|
|
|
|
|
struct spa_hook core_listener;
|
|
|
|
|
struct roundtrip_data data = { .loop = loop };
|
|
|
|
|
const struct pw_core_events core_events = {
|
|
|
|
|
PW_VERSION_CORE_EVENTS,
|
|
|
|
|
.done = core_event_done,
|
|
|
|
|
};
|
|
|
|
|
spa_zero(core_listener);
|
|
|
|
|
pw_core_add_listener(core, &core_listener,
|
|
|
|
|
&core_events, &data);
|
|
|
|
|
|
|
|
|
|
data.pending = pw_core_sync(core, PW_ID_CORE, 0);
|
|
|
|
|
|
|
|
|
|
while (!data.done)
|
|
|
|
|
pw_main_loop_run(loop);
|
|
|
|
|
|
|
|
|
|
spa_hook_remove(&core_listener);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct registry_info {
|
|
|
|
|
struct pw_registry *registry;
|
|
|
|
|
struct pw_security_context *sec;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void registry_global(void *data, uint32_t id,
|
|
|
|
|
uint32_t permissions, const char *type, uint32_t version,
|
|
|
|
|
const struct spa_dict *props)
|
|
|
|
|
{
|
|
|
|
|
struct registry_info *info = data;
|
|
|
|
|
|
|
|
|
|
if (spa_streq(type, PW_TYPE_INTERFACE_SecurityContext)) {
|
|
|
|
|
info->sec = pw_registry_bind(info->registry, id, type, version, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct pw_registry_events registry_events = {
|
|
|
|
|
PW_VERSION_REGISTRY_EVENTS,
|
|
|
|
|
.global = registry_global
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void test_create(void)
|
|
|
|
|
{
|
|
|
|
|
struct pw_main_loop *loop;
|
|
|
|
|
struct pw_context *context;
|
|
|
|
|
struct pw_core *core;
|
|
|
|
|
struct registry_info info;
|
|
|
|
|
struct spa_hook listener;
|
|
|
|
|
int res, listen_fd, close_fd[2];
|
|
|
|
|
char temp[PATH_MAX] = "/tmp/pipewire-XXXXXX";
|
|
|
|
|
struct sockaddr_un sockaddr = {0};
|
|
|
|
|
|
|
|
|
|
loop = pw_main_loop_new(NULL);
|
|
|
|
|
context = pw_context_new(pw_main_loop_get_loop(loop), NULL, 12);
|
|
|
|
|
spa_assert_se(context != NULL);
|
|
|
|
|
core = pw_context_connect(context, NULL, 0);
|
2024-03-15 12:25:30 +01:00
|
|
|
if (core == NULL && errno == EHOSTDOWN)
|
|
|
|
|
return;
|
2024-02-08 10:04:21 +01:00
|
|
|
spa_assert_se(core != NULL);
|
|
|
|
|
|
|
|
|
|
spa_zero(info);
|
|
|
|
|
info.registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, 0);
|
|
|
|
|
spa_assert_se(info.registry != NULL);
|
|
|
|
|
|
|
|
|
|
pw_registry_add_listener(info.registry, &listener, ®istry_events, &info);
|
|
|
|
|
|
|
|
|
|
roundtrip(core, loop);
|
|
|
|
|
|
|
|
|
|
spa_assert_se(info.sec != NULL);
|
|
|
|
|
|
|
|
|
|
res = mkstemp(temp);
|
|
|
|
|
spa_assert_se(res >= 0);
|
|
|
|
|
close(res);
|
|
|
|
|
|
|
|
|
|
unlink(temp);
|
|
|
|
|
|
|
|
|
|
listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
spa_assert_se(listen_fd >= 0);
|
|
|
|
|
|
|
|
|
|
sockaddr.sun_family = AF_UNIX;
|
|
|
|
|
snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", temp);
|
|
|
|
|
if (bind(listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) != 0)
|
|
|
|
|
spa_assert_not_reached();
|
|
|
|
|
|
|
|
|
|
if (listen(listen_fd, 0) != 0)
|
|
|
|
|
spa_assert_not_reached();
|
|
|
|
|
|
|
|
|
|
res = pipe2(close_fd, O_CLOEXEC);
|
|
|
|
|
spa_assert_se(res >= 0);
|
|
|
|
|
|
|
|
|
|
static const struct spa_dict_item items[] = {
|
|
|
|
|
{ "pipewire.foo.bar", "baz" },
|
2024-02-08 13:24:41 +01:00
|
|
|
{ PW_KEY_SEC_ENGINE, "org.flatpak" },
|
|
|
|
|
{ PW_KEY_ACCESS, "restricted" },
|
2024-02-08 10:04:21 +01:00
|
|
|
};
|
|
|
|
|
|
2024-02-08 13:24:41 +01:00
|
|
|
pw_security_context_create(info.sec,
|
2024-02-08 10:04:21 +01:00
|
|
|
listen_fd, close_fd[1],
|
|
|
|
|
&SPA_DICT_INIT_ARRAY(items));
|
|
|
|
|
|
|
|
|
|
roundtrip(core, loop);
|
|
|
|
|
|
2024-02-08 18:07:21 +01:00
|
|
|
unlink(temp);
|
2024-02-08 10:04:21 +01:00
|
|
|
|
|
|
|
|
pw_proxy_destroy((struct pw_proxy*)info.sec);
|
|
|
|
|
pw_proxy_destroy((struct pw_proxy*)info.registry);
|
|
|
|
|
|
|
|
|
|
pw_context_destroy(context);
|
|
|
|
|
pw_main_loop_destroy(loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
pw_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
test_abi();
|
|
|
|
|
test_create();
|
|
|
|
|
|
|
|
|
|
pw_deinit();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|