1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2011 Lennart Poettering
10 #include "alloc-util.h"
11 #include "dirent-util.h"
14 #include "format-util.h"
15 #include "logind-acl.h"
17 #include "string-util.h"
18 #include "udev-util.h"
21 static int flush_acl(acl_t acl
) {
28 for (found
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
30 found
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
34 if (acl_get_tag_type(i
, &tag
) < 0)
40 if (acl_delete_entry(acl
, i
) < 0)
52 int devnode_acl(const char *path
,
54 bool del
, uid_t old_uid
,
55 bool add
, uid_t new_uid
) {
63 acl
= acl_get_file(path
, ACL_TYPE_ACCESS
);
75 } else if (del
&& old_uid
> 0) {
78 r
= acl_find_uid(acl
, old_uid
, &entry
);
83 if (acl_delete_entry(acl
, entry
) < 0) {
92 if (add
&& new_uid
> 0) {
94 acl_permset_t permset
;
97 r
= acl_find_uid(acl
, new_uid
, &entry
);
102 if (acl_create_entry(&acl
, &entry
) < 0) {
107 if (acl_set_tag_type(entry
, ACL_USER
) < 0 ||
108 acl_set_qualifier(entry
, &new_uid
) < 0) {
114 if (acl_get_permset(entry
, &permset
) < 0) {
119 rd
= acl_get_perm(permset
, ACL_READ
);
125 wt
= acl_get_perm(permset
, ACL_WRITE
);
133 if (acl_add_perm(permset
, ACL_READ
|ACL_WRITE
) < 0) {
145 if (acl_calc_mask(&acl
) < 0) {
150 if (acl_set_file(path
, ACL_TYPE_ACCESS
, acl
) < 0) {
163 int devnode_acl_all(struct udev
*udev
,
166 bool del
, uid_t old_uid
,
167 bool add
, uid_t new_uid
) {
169 _cleanup_(udev_enumerate_unrefp
) struct udev_enumerate
*e
= NULL
;
170 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
171 _cleanup_set_free_free_ Set
*nodes
= NULL
;
172 _cleanup_closedir_
DIR *dir
= NULL
;
180 nodes
= set_new(&path_hash_ops
);
184 e
= udev_enumerate_new(udev
);
191 /* We can only match by one tag in libudev. We choose
192 * "uaccess" for that. If we could match for two tags here we
193 * could add the seat name as second match tag, but this would
194 * be hardly optimizable in libudev, and hence checking the
195 * second tag manually in our loop is a good solution. */
196 r
= udev_enumerate_add_match_tag(e
, "uaccess");
200 r
= udev_enumerate_add_match_is_initialized(e
);
204 r
= udev_enumerate_scan_devices(e
);
208 first
= udev_enumerate_get_list_entry(e
);
209 udev_list_entry_foreach(item
, first
) {
210 _cleanup_(udev_device_unrefp
) struct udev_device
*d
= NULL
;
211 const char *node
, *sn
;
213 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
217 sn
= udev_device_get_property_value(d
, "ID_SEAT");
221 if (!streq(seat
, sn
))
224 node
= udev_device_get_devnode(d
);
225 /* In case people mistag devices with nodes, we need to ignore this */
233 log_debug("Found udev node %s for seat %s", n
, seat
);
234 r
= set_consume(nodes
, n
);
239 /* udev exports "dead" device nodes to allow module on-demand loading,
240 * these devices are not known to the kernel at this moment */
241 dir
= opendir("/run/udev/static_node-tags/uaccess");
243 FOREACH_DIRENT(dent
, dir
, return -errno
) {
244 _cleanup_free_
char *unescaped_devname
= NULL
;
246 if (cunescape(dent
->d_name
, UNESCAPE_RELAX
, &unescaped_devname
) < 0)
249 n
= strappend("/dev/", unescaped_devname
);
253 log_debug("Found static node %s for seat %s", n
, seat
);
254 r
= set_consume(nodes
, n
);
263 SET_FOREACH(n
, nodes
, i
) {
266 log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT
"→"UID_FMT
"%s%s)",
267 n
, seat
, old_uid
, new_uid
,
268 del
? " del" : "", add
? " add" : "");
270 k
= devnode_acl(n
, flush
, del
, old_uid
, add
, new_uid
);
272 log_debug("Device %s disappeared while setting ACLs", n
);
273 else if (k
< 0 && r
== 0)