permissions: pass pw_permission struct around

Use a pw_permission struct to express permissions of object.
Improve client permissions, add/remove globals when permissions
are changed.
This commit is contained in:
Wim Taymans 2018-11-05 15:02:08 +01:00
parent f994b7eb70
commit eb0a561f8c
13 changed files with 282 additions and 320 deletions

View file

@ -509,21 +509,18 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
case PW_REMOTE_STATE_CONNECTED:
{
struct spa_dict_item items[5];
int i = 0;
struct pw_permission permissions[2];
/* set specific permissions on all existing objects without permissions */
items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_EXISTING, "r--");
/* set default permission for new objects and objects without
* specific permissions */
items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_DEFAULT, "---");
/* an example, set specific permissions on one object, this is the
* core object, we already have a binding to it that is not affected
* by the removal of X permissions, only future bindings. */
items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, "0:rw-");
* core object. */
permissions[0].id = 0;
permissions[0].permissions = PW_PERM_R | PW_PERM_X;
/* remove WX from all other objects */
permissions[1].id = SPA_ID_INVALID;
permissions[1].permissions = PW_PERM_R;
pw_core_proxy_permissions(pw_remote_get_core_proxy(data->remote),
&SPA_DICT_INIT(items, i));
2, permissions);
make_node(data);
break;

View file

@ -700,7 +700,7 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id,
{
struct pw_proxy *p;
struct client *client;
struct spa_dict_item items[2];
struct pw_permission perms[2];
const char *str;
p = pw_registry_proxy_bind(impl->registry_proxy,
@ -727,10 +727,9 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id,
return 0;
if (strcmp(str, "restricted") == 0) {
items[0].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT;
items[0].value = "rwx";
perms[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
pw_client_proxy_update_permissions((struct pw_client_proxy*)p,
&SPA_DICT_INIT(items, 1));
1, perms);
}
return 0;
}

View file

@ -110,6 +110,7 @@ core_check_access(void *data, struct pw_client *client)
{
struct impl *impl = data;
const struct ucred *ucred;
struct pw_permission permissions[1];
struct spa_dict_item items[2];
const char *str;
int res;
@ -128,7 +129,8 @@ core_check_access(void *data, struct pw_client *client)
if (res == 0)
goto granted;
if (res > 0)
res = EACCES;
res = -EACCES;
items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted");
goto blacklisted;
}
@ -162,7 +164,8 @@ core_check_access(void *data, struct pw_client *client)
granted:
pw_log_debug("module %p: client %p access granted", impl, client);
pw_client_set_permissions(client, PW_PERM_RWX);
permissions[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
pw_client_update_permissions(client, 1, permissions);
return;
wait_permissions:
@ -172,7 +175,6 @@ core_check_access(void *data, struct pw_client *client)
return;
blacklisted:
items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted");
pw_resource_error(pw_client_get_core_resource(client), 0, res, "blacklisted");
pw_client_update_properties(client, &SPA_DICT_INIT(items, 1));
return;

View file

@ -64,22 +64,23 @@ static void core_marshal_client_update(void *object, const struct spa_dict *prop
pw_protocol_native_end_proxy(proxy, b);
}
static void core_marshal_permissions(void *object, const struct spa_dict *props)
static void core_marshal_permissions(void *object, uint32_t n_permissions,
const struct pw_permission *permissions)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
int i, n_items;
int i;
b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_PERMISSIONS);
n_items = props ? props->n_items : 0;
spa_pod_builder_add(b, "[",
"i", n_permissions,
NULL);
spa_pod_builder_add(b, "[ i", n_items, NULL);
for (i = 0; i < n_items; i++) {
for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
"s", props->items[i].key,
"s", props->items[i].value, NULL);
"i", permissions[i].id,
"i", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@ -340,23 +341,25 @@ static int core_demarshal_client_update(void *object, void *data, size_t size)
static int core_demarshal_permissions(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
struct spa_dict props;
struct spa_pod_parser prs;
uint32_t i;
struct pw_permission *permissions;
uint32_t i, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
if (spa_pod_parser_get(&prs, "[",
"i", &n_permissions, NULL) < 0)
return -EINVAL;
props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
for (i = 0; i < props.n_items; i++) {
permissions = alloca(n_permissions * sizeof(struct pw_permission));
for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
"s", &props.items[i].key,
"s", &props.items[i].value,
"i", &permissions[i].id,
"i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0, &props);
pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0,
n_permissions, permissions);
return 0;
}
@ -1017,24 +1020,23 @@ static int client_demarshal_info(void *object, void *data, size_t size)
return 0;
}
static void client_marshal_permissions(void *object, const struct spa_dict *dict)
static void client_marshal_permissions(void *object, uint32_t index, uint32_t n_permissions,
struct pw_permission *permissions)
{
struct pw_resource *resource = object;
struct spa_pod_builder *b;
uint32_t i, n_items;
uint32_t i;
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_PROXY_EVENT_PERMISSIONS);
n_items = dict ? dict->n_items : 0;
spa_pod_builder_add(b,
"[",
"i", n_items, NULL);
"[ i", index,
"i", n_permissions, NULL);
for (i = 0; i < n_items; i++) {
for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
"s", dict->items[i].key,
"s", dict->items[i].value, NULL);
"s", permissions[i].id,
"s", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@ -1044,23 +1046,24 @@ static void client_marshal_permissions(void *object, const struct spa_dict *dict
static int client_demarshal_permissions(void *object, void *data, size_t size)
{
struct pw_proxy *proxy = object;
struct spa_dict props;
struct pw_permission *permissions;
struct spa_pod_parser prs;
uint32_t i;
uint32_t i, index, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
if (spa_pod_parser_get(&prs, "[ i", &index,
"i", &n_permissions, NULL) < 0)
return -EINVAL;
props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
for (i = 0; i < props.n_items; i++) {
permissions = alloca(n_permissions * sizeof(struct pw_permission));
for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
"s", &props.items[i].key,
"s", &props.items[i].value,
"i", &permissions[i].id,
"i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, &props);
pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, index, n_permissions, permissions);
return 0;
}
@ -1095,14 +1098,16 @@ static int client_demarshal_error(void *object, void *data, size_t size)
return 0;
}
static void client_marshal_get_permissions(void *object)
static void client_marshal_get_permissions(void *object, uint32_t index, uint32_t num)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_GET_PERMISSIONS);
spa_pod_builder_add_struct(b, "P", NULL);
spa_pod_builder_add_struct(b,
"i", index,
"i", num, NULL);
pw_protocol_native_end_proxy(proxy, b);
}
@ -1111,32 +1116,33 @@ static int client_demarshal_get_permissions(void *object, void *data, size_t siz
{
struct pw_resource *resource = object;
struct spa_pod_parser prs;
void *ptr;
uint32_t index, num;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, "[P]", &ptr, NULL) < 0)
if (spa_pod_parser_get(&prs,
"[i", &index,
"i", &num, NULL) < 0)
return -EINVAL;
pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0);
pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0, index, num);
return 0;
}
static void client_marshal_update_permissions(void *object, const struct spa_dict *props)
static void client_marshal_update_permissions(void *object, uint32_t n_permissions,
const struct pw_permission *permissions)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
int i, n_items;
int i;
b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_UPDATE_PERMISSIONS);
n_items = props ? props->n_items : 0;
spa_pod_builder_add(b, "[ i", n_permissions, NULL);
spa_pod_builder_add(b, "[ i", n_items, NULL);
for (i = 0; i < n_items; i++) {
for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
"s", props->items[i].key,
"s", props->items[i].value, NULL);
"i", permissions[i].id,
"i", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@ -1146,23 +1152,24 @@ static void client_marshal_update_permissions(void *object, const struct spa_dic
static int client_demarshal_update_permissions(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
struct spa_dict props;
struct pw_permission *permissions;
struct spa_pod_parser prs;
uint32_t i;
uint32_t i, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
if (spa_pod_parser_get(&prs, "[ i", &n_permissions, NULL) < 0)
return -EINVAL;
props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
for (i = 0; i < props.n_items; i++) {
permissions = alloca(n_permissions * sizeof(struct pw_permission));
for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
"s", &props.items[i].key,
"s", &props.items[i].value,
"i", &permissions[i].id,
"i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0, &props);
pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0,
n_permissions, permissions);
return 0;
}

View file

@ -27,11 +27,6 @@
#include "pipewire/private.h"
#include "pipewire/resource.h"
struct permission {
uint32_t id;
uint32_t permissions;
};
/** \cond */
struct impl {
struct pw_client this;
@ -46,40 +41,40 @@ struct resource_data {
};
/** find a specific permission for a global or NULL when there is none */
static struct permission *
static struct pw_permission *
find_permission(struct pw_client *client, uint32_t id)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
struct permission *p;
struct pw_permission *p;
if (!pw_array_check_index(&impl->permissions, id, struct permission))
if (!pw_array_check_index(&impl->permissions, id, struct pw_permission))
return NULL;
p = pw_array_get_unchecked(&impl->permissions, id, struct permission);
p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission);
if (p->permissions == -1)
return NULL;
else
return p;
}
static struct permission *ensure_permissions(struct pw_client *client, uint32_t id)
static struct pw_permission *ensure_permissions(struct pw_client *client, uint32_t id)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
struct permission *p;
struct pw_permission *p;
size_t len, i;
len = pw_array_get_len(&impl->permissions, struct permission);
len = pw_array_get_len(&impl->permissions, struct pw_permission);
if (len <= id) {
size_t diff = id - len + 1;
p = pw_array_add(&impl->permissions, diff * sizeof(struct permission));
p = pw_array_add(&impl->permissions, diff * sizeof(struct pw_permission));
if (p == NULL)
return NULL;
for (i = 0; i < diff; i++)
p[i].permissions = -1;
}
p = pw_array_get_unchecked(&impl->permissions, id, struct permission);
p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission);
return p;
}
@ -90,7 +85,7 @@ client_permission_func(struct pw_global *global,
struct pw_client *client, void *data)
{
struct impl *impl = data;
struct permission *p;
struct pw_permission *p;
p = find_permission(client, global->id);
if (p == NULL)
@ -99,26 +94,6 @@ client_permission_func(struct pw_global *global,
return p->permissions;
}
static uint32_t parse_mask(const char *str)
{
uint32_t mask = 0;
while (*str != '\0') {
switch (*str++) {
case 'r':
mask |= PW_PERM_R;
break;
case 'w':
mask |= PW_PERM_W;
break;
case 'x':
mask |= PW_PERM_X;
break;
}
}
return mask;
}
static void client_error(void *object, uint32_t id, int res, const char *error)
{
struct pw_resource *resource = object;
@ -127,65 +102,21 @@ static void client_error(void *object, uint32_t id, int res, const char *error)
pw_resource_error(client->core_resource, id, res, error);
}
static void client_get_permissions(void *object)
static void client_get_permissions(void *object, uint32_t index, uint32_t num)
{
struct pw_resource *resource = object;
struct resource_data *data = pw_resource_get_user_data(resource);
struct pw_client *client = data->client;
pw_log_debug("client %p", client);
}
static void client_update_permissions(void *object, const struct spa_dict *props)
static void client_update_permissions(void *object,
uint32_t n_permissions, const struct pw_permission *permissions)
{
struct pw_resource *resource = object;
struct resource_data *data = pw_resource_get_user_data(resource);
struct pw_client *client = data->client;
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
const char *str;
int i, len;
for (i = 0; i < props->n_items; i++) {
str = props->items[i].value;
pw_log_debug("client %p: %s %s", client, props->items[i].key, str);
if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) {
impl->permissions_default = parse_mask(str);
pw_log_debug("client %p: set default permissions to %08x",
client, impl->permissions_default);
}
else if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) {
struct pw_global *global;
uint32_t global_id, old_perm, new_perm;
struct permission *p;
/* permissions.update=<global-id>:[r][w][x] */
len = strcspn(str, ":");
if (len == 0)
continue;
global_id = atoi(str);
global = pw_core_find_global(client->core, global_id);
if (global == NULL) {
pw_log_warn("client %p: invalid global %d", client, global_id);
continue;
}
p = ensure_permissions(client, global_id);
old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions;
new_perm = parse_mask(str + len);
pw_log_debug("client %p: %08x %08x", client, old_perm, new_perm);
p->permissions = new_perm;
if (PW_PERM_IS_R(old_perm) && !PW_PERM_IS_R(new_perm)) {
pw_global_revoke(global, client);
}
else if (!PW_PERM_IS_R(old_perm) && PW_PERM_IS_R(new_perm)) {
pw_global_grant(global, client);
}
}
}
pw_client_update_permissions(client, n_permissions, permissions);
pw_client_set_busy(client, false);
}
@ -246,7 +177,7 @@ core_global_removed(void *data, struct pw_global *global)
{
struct impl *impl = data;
struct pw_client *client = &impl->this;
struct permission *p;
struct pw_permission *p;
p = find_permission(client, global->id);
pw_log_debug("client %p: global %d removed, %p", client, global->id, p);
@ -492,91 +423,61 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict
return changed;
}
struct permissions_update {
struct pw_client *client;
uint32_t permissions;
bool only_new;
};
static int do_permissions(void *data, struct pw_global *global)
{
struct permissions_update *update = data;
struct pw_client *client = update->client;
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
struct permission *p;
p = ensure_permissions(client, global->id);
if (p == NULL)
return -ENOMEM;
if (p->permissions == -1)
p->permissions = impl->permissions_default;
else if (update->only_new)
return 0;
p->permissions &= update->permissions;
pw_log_debug("client %p: set global %d permissions to %08x", client, global->id, p->permissions);
return 0;
}
int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict)
int pw_client_update_permissions(struct pw_client *client,
uint32_t n_permissions, const struct pw_permission *permissions)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
struct pw_core *core = client->core;
int i;
const char *str;
size_t len;
struct permissions_update update = { client, 0 };
uint32_t permissions_existing, permissions_default;
permissions_default = impl->permissions_default;
permissions_existing = -1;
for (i = 0; i < dict->n_items; i++) {
str = dict->items[i].value;
if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) {
permissions_default &= parse_mask(str);
pw_log_debug("client %p: set default permissions to %08x",
client, permissions_default);
}
else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) {
for (i = 0; i < n_permissions; i++) {
struct pw_permission *p;
uint32_t old_perm, new_perm;
struct pw_global *global;
uint32_t global_id;
/* permissions.update=<global-id>:[r][w][x] */
len = strcspn(str, ":");
if (len == 0)
if (permissions[i].id == SPA_ID_INVALID) {
old_perm = impl->permissions_default;
new_perm = permissions[i].permissions;
if (core->current_client == client)
new_perm &= old_perm;
pw_log_debug("client %p: set default permissions %08x -> %08x",
client, old_perm, new_perm);
spa_list_for_each(global, &core->global_list, link) {
p = find_permission(client, global->id);
if (p != NULL)
continue;
global_id = atoi(str);
global = pw_core_find_global(client->core, global_id);
pw_global_update_permissions(global, client, old_perm, new_perm);
}
impl->permissions_default = new_perm;
}
else {
struct pw_global *global;
global = pw_core_find_global(client->core, permissions[i].id);
if (global == NULL) {
pw_log_warn("client %p: invalid global %d", client, global_id);
pw_log_warn("client %p: invalid global %d", client, permissions[i].id);
continue;
}
p = ensure_permissions(client, global->id);
old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions;
new_perm = permissions[i].permissions;
/* apply the specific updates in order. This is ok for now, we could add
* a field to the permission struct later to accumulate the changes
* and apply them out of this loop */
update.permissions = parse_mask(str + len);
update.only_new = false;
do_permissions(&update, global);
}
else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_EXISTING) == 0) {
permissions_existing = parse_mask(str);
pw_log_debug("client %p: set existing permissions to %08x",
client, permissions_existing);
}
}
/* apply default and existing permissions after specific ones to make the
* permission update look like an atomic unordered set of changes. */
if (permissions_existing != -1) {
update.permissions = permissions_existing;
update.only_new = true;
pw_core_for_each_global(client->core, do_permissions, &update);
}
impl->permissions_default = permissions_default;
if (core->current_client == client)
new_perm &= old_perm;
pw_log_debug("client %p: set global %d permissions %08x -> %08x",
client, global->id, old_perm, new_perm);
pw_global_update_permissions(global, client, old_perm, new_perm);
p->permissions = new_perm;
}
}
if (n_permissions > 0)
pw_client_set_busy(client, false);
return 0;
}
@ -588,11 +489,3 @@ void pw_client_set_busy(struct pw_client *client, bool busy)
pw_client_events_busy_changed(client, busy);
}
}
void pw_client_set_permissions(struct pw_client *client, uint32_t permissions)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
pw_log_debug("client %p: permissions %08x", client, permissions);
impl->permissions_default = permissions;
pw_client_set_busy(client, false);
}

View file

@ -49,6 +49,7 @@ struct pw_client;
#include <pipewire/introspect.h>
#include <pipewire/properties.h>
#include <pipewire/resource.h>
#include <pipewire/permission.h>
#define PW_TYPE__Client PW_TYPE_OBJECT_BASE "Client"
#define PW_TYPE_CLIENT_BASE PW_TYPE__Client ":"
@ -146,7 +147,8 @@ const struct pw_client_info *pw_client_get_info(struct pw_client *client);
int pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict);
/** Update the client permissions */
int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict);
int pw_client_update_permissions(struct pw_client *client, uint32_t n_permissions,
const struct pw_permission *permissions);
/** Get the client properties */
const struct pw_properties *pw_client_get_properties(struct pw_client *client);
@ -177,8 +179,6 @@ void pw_client_add_listener(struct pw_client *client,
* started and no further processing is allowed to happen for the client */
void pw_client_set_busy(struct pw_client *client, bool busy);
void pw_client_set_permissions(struct pw_client *client, uint32_t permissions);
#ifdef __cplusplus
}
#endif

View file

@ -64,11 +64,11 @@ static void registry_bind(void *object, uint32_t id,
if (!PW_PERM_IS_R(permissions))
goto no_id;
if (type != global->type)
if (global->type != type)
goto wrong_interface;
pw_log_debug("global %p: bind global id %d, iface %s to %d", global, id,
spa_debug_type_find_name(pw_type_info(), type), new_id);
pw_log_debug("global %p: bind global id %d, iface %s/%d to %d", global, id,
spa_debug_type_find_name(pw_type_info(), type), version, new_id);
if (pw_global_bind(global, client, permissions, version, new_id) < 0)
goto exit;
@ -77,9 +77,13 @@ static void registry_bind(void *object, uint32_t id,
no_id:
pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id);
pw_core_resource_error(client->core_resource, id,
-ENOENT, "no such global %u", id);
goto exit;
wrong_interface:
pw_log_debug("registry %p: global with id %u has no interface %u", resource, id, type);
pw_core_resource_error(client->core_resource, id,
-ENOENT, "no such interface %u", type);
goto exit;
exit:
/* unmark the new_id the map, the client does not yet know about the failed
@ -151,10 +155,11 @@ static void core_client_update(void *object, const struct spa_dict *props)
pw_client_update_properties(resource->client, props);
}
static void core_permissions(void *object, const struct spa_dict *props)
static void core_permissions(void *object, uint32_t n_permissions,
const struct pw_permission *permissions)
{
struct pw_resource *resource = object;
pw_client_update_permissions(resource->client, props);
pw_client_update_permissions(resource->client, n_permissions, permissions);
}
static void core_sync(void *object, uint32_t seq)

View file

@ -73,16 +73,6 @@ struct pw_core;
* resources of a PipeWire instance.
*/
#define PW_PERM_R 0400 /**< object can be seen and events can be received */
#define PW_PERM_W 0200 /**< methods can be called that modify the object */
#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
* present in order to call methods that modify the object. */
#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
/** core events emited by the core object added with \ref pw_core_add_listener */
struct pw_core_events {
#define PW_VERSION_CORE_EVENTS 0

View file

@ -147,17 +147,19 @@ static int global_unregister(struct pw_global *global)
{
struct impl *impl = SPA_CONTAINER_OF(global, struct impl, this);
struct pw_core *core = global->core;
struct pw_resource *registry;
struct pw_resource *resource;
if (!impl->registered)
return 0;
spa_list_for_each(registry, &core->registry_resource_list, link) {
uint32_t permissions = pw_global_get_permissions(global, registry->client);
pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions);
spa_list_for_each(resource, &core->registry_resource_list, link) {
uint32_t permissions = pw_global_get_permissions(global, resource->client);
pw_log_debug("registry %p: global %d %08x", resource, global->id, permissions);
if (PW_PERM_IS_R(permissions))
pw_registry_resource_global_remove(registry, global->id);
pw_registry_resource_global_remove(resource, global->id);
}
spa_list_consume(resource, &global->resource_list, link)
pw_resource_destroy(resource);
spa_list_remove(&global->link);
pw_core_events_global_removed(core, global);
@ -220,11 +222,11 @@ void pw_global_add_listener(struct pw_global *global,
* \param global the global to bind to
* \param client the client that binds
* \param version the version
* \param id the id
* \param id the id of the resource
*
* Let \a client bind to \a global with the given version and id.
* After binding, the client and the global object will be able to
* exchange messages.
* exchange messages on the proxy/resource with \a id.
*
* \memberof pw_global
*/
@ -249,47 +251,39 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm
return res;
}
int pw_global_grant(struct pw_global *global, struct pw_client *client)
int pw_global_update_permissions(struct pw_global *global, struct pw_client *client,
uint32_t old_permissions, uint32_t new_permissions)
{
struct pw_resource *registry;
struct pw_core *core = global->core;
struct pw_resource *resource, *t;
spa_list_for_each(registry, &core->registry_resource_list, link) {
uint32_t permissions;
if (registry->client != client)
spa_list_for_each(resource, &core->registry_resource_list, link) {
if (resource->client != client)
continue;
permissions = pw_global_get_permissions(global, client);
pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions);
if (PW_PERM_IS_R(permissions))
pw_registry_resource_global(registry,
if (PW_PERM_IS_R(old_permissions) && !PW_PERM_IS_R(new_permissions)) {
pw_registry_resource_global_remove(resource, global->id);
}
else if (!PW_PERM_IS_R(old_permissions) && PW_PERM_IS_R(new_permissions)) {
pw_registry_resource_global(resource,
global->id,
global->parent->id,
permissions,
new_permissions,
global->type,
global->version,
global->properties ?
&global->properties->dict : NULL);
}
return 0;
}
int pw_global_revoke(struct pw_global *global, struct pw_client *client)
{
struct pw_resource *registry, *resource, *t;
struct pw_core *core = global->core;
spa_list_for_each(registry, &core->registry_resource_list, link) {
if (registry->client != client)
continue;
pw_registry_resource_global_remove(registry, global->id);
}
spa_list_for_each_safe(resource, t, &global->resource_list, link) {
if (resource->client != client)
continue;
/* don't ever destroy the core resource */
if (!PW_PERM_IS_R(new_permissions) && global->id != 0)
pw_resource_destroy(resource);
else
resource->permissions = new_permissions;
}
return 0;
}

View file

@ -128,13 +128,8 @@ int pw_global_bind(struct pw_global *global,
uint32_t version,
uint32_t id);
/** Revoke access to global for client, the global will be removed from
* the client registry and all the bound resources for the client will be
* destroyed */
int pw_global_revoke(struct pw_global *global, struct pw_client *client);
/** Grant access to a global for client. The client registry will be
* notified of a new global */
int pw_global_grant(struct pw_global *global, struct pw_client *client);
int pw_global_update_permissions(struct pw_global *global, struct pw_client *client,
uint32_t old_permissions, uint32_t new_permissions);
/** Destroy a global */
void pw_global_destroy(struct pw_global *global);

View file

@ -30,6 +30,7 @@ extern "C" {
#include <pipewire/introspect.h>
#include <pipewire/proxy.h>
#include <pipewire/permission.h>
struct pw_core_proxy;
struct pw_registry_proxy;
@ -143,18 +144,21 @@ struct pw_core_proxy_methods {
*/
void (*client_update) (void *object, const struct spa_dict *props);
/**
* Manage the permissions of the global objects
* Manage the permissions of the global objects for this
* client
*
* Update the permissions of the global objects using the
* dictionary with properties.
* provided array with permissions
*
* Globals can use the default permissions or can have specific
* permissions assigned to them.
*
* \param id the global id to change
* \param props dictionary with permission properties
* \param n_permissions number of permissions
* \param permissions array of permissions
*/
void (*permissions) (void *object, const struct spa_dict *props);
void (*permissions) (void *object,
uint32_t n_permissions,
const struct pw_permission *permissions);
/**
* Create a new object on the PipeWire server from a factory.
* Use a \a factory_name of "client-node" to create a
@ -209,9 +213,9 @@ pw_core_proxy_client_update(struct pw_core_proxy *core, const struct spa_dict *p
}
static inline void
pw_core_proxy_permissions(struct pw_core_proxy *core, const struct spa_dict *props)
pw_core_proxy_permissions(struct pw_core_proxy *core, uint32_t n_permissions, struct pw_permission *permissions)
{
pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, props);
pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, n_permissions, permissions);
}
static inline void *
@ -696,9 +700,15 @@ struct pw_client_proxy_events {
*
* Event emited as a result of the get_permissions method.
*
* \param param the parameter
* \param default_permissions the default permissions
* \param index the index of the first permission entry
* \param n_permissions the number of permissions
* \param permissions the permissions
*/
void (*permissions) (void *object, const struct spa_dict *dict);
void (*permissions) (void *object,
uint32_t index,
uint32_t n_permissions,
struct pw_permission *permissions);
};
/** Client */
@ -736,15 +746,20 @@ struct pw_client_proxy_methods {
* Get client permissions
*
* A permissions event will be emited with the permissions.
*
* \param index the first index to query, 0 for first
* \param num the maximum number of items to get
*/
void (*get_permissions) (void *object);
void (*get_permissions) (void *object, uint32_t index, uint32_t num);
/**
* Update client permissions
*
* \param dict list of permissions to update
* \param n_permissions number of permissions
* \param permissions array of new permissions
*/
void (*update_permissions) (void *object, const struct spa_dict *dict);
void (*update_permissions) (void *object, uint32_t n_permissions,
const struct pw_permission *permissions);
};
/** Client permissions */
@ -755,15 +770,17 @@ pw_client_proxy_error(struct pw_client_proxy *client, uint32_t id, int res, cons
}
static inline void
pw_client_proxy_get_permissions(struct pw_client_proxy *client)
pw_client_proxy_get_permissions(struct pw_client_proxy *client, uint32_t index, uint32_t num)
{
pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions);
pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions, index, num);
}
static inline void
pw_client_proxy_update_permissions(struct pw_client_proxy *client, const struct spa_dict *dict)
pw_client_proxy_update_permissions(struct pw_client_proxy *client, uint32_t n_permissions,
const struct pw_permission *permissions)
{
pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions, dict);
pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions,
n_permissions, permissions);
}
#define PW_VERSION_LINK 0

60
src/pipewire/permission.h Normal file
View file

@ -0,0 +1,60 @@
/* PipeWire
* Copyright (C) 2015 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.
*/
#ifndef __PIPEWIRE_PERMISSION_H__
#define __PIPEWIRE_PERMISSION_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/utils/defs.h>
/** \class pw_permission
*
* \brief a PipeWire permission
*
* Permissions are kept for a client and describe what the client is
* allowed to do with an object.
*
* See \ref page_core_api
*/
#define PW_PERM_R 0400 /**< object can be seen and events can be received */
#define PW_PERM_W 0200 /**< methods can be called that modify the object */
#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
* present in order to call methods that modify the object. */
#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
struct pw_permission {
uint32_t id; /**< id of object, SPA_ID_INVALID for default permission */
uint32_t permissions; /**< bitmask of above permissions */
};
#define PW_PERMISSION_INIT(id,p) (struct pw_permission){ (id), (p) }
#ifdef __cplusplus
}
#endif
#endif /* __PIPEWIRE_PERMISSION_H__ */

View file

@ -32,6 +32,7 @@
#include <pipewire/command.h>
#include <pipewire/interfaces.h>
#include <pipewire/type.h>
#include <pipewire/permission.h>
static const char WHITESPACE[] = " \t";
@ -1164,15 +1165,15 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
static bool do_permissions(struct data *data, const char *cmd, char *args, char **error)
{
struct remote_data *rd = data->current;
char *a[2];
char *a[3];
int n;
uint32_t id;
struct global *global;
struct spa_dict_item items[1];
struct pw_permission permissions[1];
n = pw_split_ip(args, WHITESPACE, 2, a);
if (n < 2) {
asprintf(error, "%s <client-id> <permission>", cmd);
n = pw_split_ip(args, WHITESPACE, 3, a);
if (n < 3) {
asprintf(error, "%s <client-id> <object> <permission>", cmd);
return false;
}
@ -1191,9 +1192,11 @@ static bool do_permissions(struct data *data, const char *cmd, char *args, char
return false;
}
items[0] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, a[1]);
permissions[0] = PW_PERMISSION_INIT(atoi(a[1]), atoi(a[2]));
pw_client_proxy_update_permissions((struct pw_client_proxy*)global->proxy,
&SPA_DICT_INIT(items, 1));
1, permissions);
return true;
}