1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "device-util.h"
10 #include "devnode-acl.h"
11 #include "dirent-util.h"
13 #include "format-util.h"
15 #include "glyph-util.h"
17 #include "string-util.h"
19 static int flush_acl(acl_t acl
) {
26 for (found
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
28 found
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
32 if (acl_get_tag_type(i
, &tag
) < 0)
38 if (acl_delete_entry(acl
, i
) < 0)
50 int devnode_acl(const char *path
,
52 bool del
, uid_t old_uid
,
53 bool add
, uid_t new_uid
) {
55 _cleanup_(acl_freep
) acl_t acl
= NULL
;
61 acl
= acl_get_file(path
, ACL_TYPE_ACCESS
);
73 } else if (del
&& old_uid
> 0) {
76 r
= acl_find_uid(acl
, old_uid
, &entry
);
81 if (acl_delete_entry(acl
, entry
) < 0)
88 if (add
&& new_uid
> 0) {
90 acl_permset_t permset
;
93 r
= acl_find_uid(acl
, new_uid
, &entry
);
98 if (acl_create_entry(&acl
, &entry
) < 0)
101 if (acl_set_tag_type(entry
, ACL_USER
) < 0 ||
102 acl_set_qualifier(entry
, &new_uid
) < 0)
106 if (acl_get_permset(entry
, &permset
) < 0)
109 rd
= acl_get_perm(permset
, ACL_READ
);
113 wt
= acl_get_perm(permset
, ACL_WRITE
);
119 if (acl_add_perm(permset
, ACL_READ
|ACL_WRITE
) < 0)
129 if (acl_calc_mask(&acl
) < 0)
132 if (acl_set_file(path
, ACL_TYPE_ACCESS
, acl
) < 0)
138 int devnode_acl_all(const char *seat
,
140 bool del
, uid_t old_uid
,
141 bool add
, uid_t new_uid
) {
143 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
144 _cleanup_set_free_ Set
*nodes
= NULL
;
145 _cleanup_closedir_
DIR *dir
= NULL
;
149 r
= sd_device_enumerator_new(&e
);
156 /* We can only match by one tag in libudev. We choose
157 * "uaccess" for that. If we could match for two tags here we
158 * could add the seat name as second match tag, but this would
159 * be hardly optimizable in libudev, and hence checking the
160 * second tag manually in our loop is a good solution. */
161 r
= sd_device_enumerator_add_match_tag(e
, "uaccess");
165 FOREACH_DEVICE(e
, d
) {
166 const char *node
, *sn
;
168 /* Make sure the tag is still in place */
169 if (sd_device_has_current_tag(d
, "uaccess") <= 0)
172 if (sd_device_get_property_value(d
, "ID_SEAT", &sn
) < 0 || isempty(sn
))
175 if (!streq(seat
, sn
))
178 /* In case people mistag devices with nodes, we need to ignore this */
179 if (sd_device_get_devname(d
, &node
) < 0)
182 log_device_debug(d
, "Found udev node %s for seat %s", node
, seat
);
183 r
= set_put_strdup_full(&nodes
, &path_hash_ops_free
, node
);
188 /* udev exports "dead" device nodes to allow module on-demand loading,
189 * these devices are not known to the kernel at this moment */
190 dir
= opendir("/run/udev/static_node-tags/uaccess");
192 FOREACH_DIRENT(de
, dir
, return -errno
) {
193 r
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &n
);
198 "Unable to read symlink '/run/udev/static_node-tags/uaccess/%s', ignoring: %m",
203 log_debug("Found static node %s for seat %s", n
, seat
);
204 r
= set_ensure_consume(&nodes
, &path_hash_ops_free
, n
);
211 SET_FOREACH(n
, nodes
) {
214 log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT
"%s"UID_FMT
"%s%s)",
215 n
, seat
, old_uid
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), new_uid
,
216 del
? " del" : "", add
? " add" : "");
218 k
= devnode_acl(n
, flush
, del
, old_uid
, add
, new_uid
);
220 log_debug("Device %s disappeared while setting ACLs", n
);