diff --git a/src/pipewire/extensions/metadata.h b/src/pipewire/extensions/metadata.h index d53c4e657..8c0641fbb 100644 --- a/src/pipewire/extensions/metadata.h +++ b/src/pipewire/extensions/metadata.h @@ -31,6 +31,7 @@ struct pw_metadata; #define PW_METADATA_EVENT_PROPERTY 0 #define PW_METADATA_EVENT_NUM 1 + /** \ref pw_metadata events */ struct pw_metadata_events { #define PW_VERSION_METADATA_EVENTS 0 diff --git a/src/pipewire/impl-link.c b/src/pipewire/impl-link.c index 42f94f180..5271af940 100644 --- a/src/pipewire/impl-link.c +++ b/src/pipewire/impl-link.c @@ -1131,7 +1131,7 @@ static void try_unlink_controls(struct impl *impl, struct pw_impl_port *output, } static int check_owner_permissions(struct pw_context *context, - struct pw_impl_node *node, uint32_t id, uint32_t permissions) + struct pw_impl_node *node, struct pw_global *other, uint32_t permissions) { const char *str; struct pw_impl_client *client; @@ -1155,11 +1155,7 @@ static int check_owner_permissions(struct pw_context *context, /* not the right object, something wrong */ return -EIO; - if ((global = pw_context_find_global(context, id)) == NULL) - /* current client can't see node id */ - return -errno; - - perms = pw_global_get_permissions(global, client); + perms = pw_global_get_permissions(other, client); if ((perms & permissions) != permissions) /* owner client can't see other node */ return -EPERM; @@ -1174,12 +1170,37 @@ check_permission(struct pw_context *context, struct pw_properties *properties) { int res; + uint32_t in_perms, out_perms; + struct pw_global *in_global, *out_global; + + if ((in_global = input->node->global) == NULL) + return -ENOENT; + if ((out_global = output->node->global) == NULL) + return -ENOENT; + + in_perms = out_perms = PW_PERM_R | PW_PERM_L; + if (context->current_client != NULL) { + in_perms = pw_global_get_permissions(in_global, context->current_client); + out_perms = pw_global_get_permissions(out_global, context->current_client); + } + /* current client can't see input node or output node */ + if (!PW_PERM_IS_R(in_perms) || !PW_PERM_IS_R(out_perms)) + return -ENOENT; + if ((res = check_owner_permissions(context, output->node, - input->node->info.id, PW_PERM_R)) < 0) - return res; + in_global, PW_PERM_R)) < 0) { + /* output node owner can't see input node, check if the current + * client has universal link permissions for the output node */ + if (!PW_PERM_IS_L(out_perms)) + return res; + } if ((res = check_owner_permissions(context, input->node, - output->node->info.id, PW_PERM_R)) < 0) - return res; + out_global, PW_PERM_R)) < 0) { + /* input node owner can't see output node, check if the current + * client has universal link permissions for the input node */ + if (!PW_PERM_IS_L(in_perms)) + return res; + } return 0; } diff --git a/src/pipewire/node.h b/src/pipewire/node.h index b296927d7..87ba1a06e 100644 --- a/src/pipewire/node.h +++ b/src/pipewire/node.h @@ -29,7 +29,7 @@ extern "C" { */ #define PW_TYPE_INTERFACE_Node PW_TYPE_INFO_INTERFACE_BASE "Node" -#define PW_NODE_PERM_MASK PW_PERM_RWXM +#define PW_NODE_PERM_MASK PW_PERM_RWXML #define PW_VERSION_NODE 3 struct pw_node; diff --git a/src/pipewire/permission.h b/src/pipewire/permission.h index 471ea6210..22eebdb26 100644 --- a/src/pipewire/permission.h +++ b/src/pipewire/permission.h @@ -29,15 +29,19 @@ extern "C" { #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_M 0010 /**< metadata can be set on object, Since 0.3.9 */ +#define PW_PERM_L 0020 /**< a link can be made between a node that doesn't have + * permission to see the other node, Since 0.3.77 */ #define PW_PERM_RW (PW_PERM_R|PW_PERM_W) #define PW_PERM_RWX (PW_PERM_RW|PW_PERM_X) #define PW_PERM_RWXM (PW_PERM_RWX|PW_PERM_M) +#define PW_PERM_RWXML (PW_PERM_RWXM|PW_PERM_L) #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) #define PW_PERM_IS_M(p) (((p)&PW_PERM_M) == PW_PERM_M) +#define PW_PERM_IS_L(p) (((p)&PW_PERM_L) == PW_PERM_L) #define PW_PERM_ALL PW_PERM_RWXM #define PW_PERM_INVALID (uint32_t)(0xffffffff) @@ -49,12 +53,13 @@ struct pw_permission { #define PW_PERMISSION_INIT(id,p) ((struct pw_permission){ (id), (p) }) -#define PW_PERMISSION_FORMAT "%c%c%c%c" +#define PW_PERMISSION_FORMAT "%c%c%c%c%c" #define PW_PERMISSION_ARGS(permission) \ (permission) & PW_PERM_R ? 'r' : '-', \ (permission) & PW_PERM_W ? 'w' : '-', \ (permission) & PW_PERM_X ? 'x' : '-', \ - (permission) & PW_PERM_M ? 'm' : '-' + (permission) & PW_PERM_M ? 'm' : '-', \ + (permission) & PW_PERM_L ? 'l' : '-' /** * \} diff --git a/src/tools/pw-dump.c b/src/tools/pw-dump.c index 182ca1838..3adfddf09 100644 --- a/src/tools/pw-dump.c +++ b/src/tools/pw-dump.c @@ -1427,6 +1427,7 @@ static void dump_objects(struct data *d) { "w", PW_PERM_W }, { "x", PW_PERM_X }, { "m", PW_PERM_M }, + { "l", PW_PERM_L }, { NULL, }, };