1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "device-enumerator-private.h"
11 #include "dirent-util.h"
14 #include "format-util.h"
15 #include "logind-acl.h"
17 #include "string-util.h"
20 static int flush_acl(acl_t acl
) {
27 for (found
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
29 found
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
33 if (acl_get_tag_type(i
, &tag
) < 0)
39 if (acl_delete_entry(acl
, i
) < 0)
51 int devnode_acl(const char *path
,
53 bool del
, uid_t old_uid
,
54 bool add
, uid_t new_uid
) {
62 acl
= acl_get_file(path
, ACL_TYPE_ACCESS
);
74 } else if (del
&& old_uid
> 0) {
77 r
= acl_find_uid(acl
, old_uid
, &entry
);
82 if (acl_delete_entry(acl
, entry
) < 0) {
91 if (add
&& new_uid
> 0) {
93 acl_permset_t permset
;
96 r
= acl_find_uid(acl
, new_uid
, &entry
);
101 if (acl_create_entry(&acl
, &entry
) < 0) {
106 if (acl_set_tag_type(entry
, ACL_USER
) < 0 ||
107 acl_set_qualifier(entry
, &new_uid
) < 0) {
113 if (acl_get_permset(entry
, &permset
) < 0) {
118 rd
= acl_get_perm(permset
, ACL_READ
);
124 wt
= acl_get_perm(permset
, ACL_WRITE
);
132 if (acl_add_perm(permset
, ACL_READ
|ACL_WRITE
) < 0) {
144 if (acl_calc_mask(&acl
) < 0) {
149 if (acl_set_file(path
, ACL_TYPE_ACCESS
, acl
) < 0) {
162 int devnode_acl_all(const char *seat
,
164 bool del
, uid_t old_uid
,
165 bool add
, uid_t new_uid
) {
167 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
168 _cleanup_set_free_free_ Set
*nodes
= NULL
;
169 _cleanup_closedir_
DIR *dir
= NULL
;
176 nodes
= set_new(&path_hash_ops
);
180 r
= sd_device_enumerator_new(&e
);
187 /* We can only match by one tag in libudev. We choose
188 * "uaccess" for that. If we could match for two tags here we
189 * could add the seat name as second match tag, but this would
190 * be hardly optimizable in libudev, and hence checking the
191 * second tag manually in our loop is a good solution. */
192 r
= sd_device_enumerator_add_match_tag(e
, "uaccess");
196 r
= device_enumerator_scan_devices(e
);
200 FOREACH_DEVICE_AND_SUBSYSTEM(e
, d
) {
201 const char *node
, *sn
;
203 if (sd_device_get_property_value(d
, "ID_SEAT", &sn
) < 0 || isempty(sn
))
206 if (!streq(seat
, sn
))
209 /* In case people mistag devices with nodes, we need to ignore this */
210 if (sd_device_get_devname(d
, &node
) < 0)
217 log_debug("Found udev node %s for seat %s", n
, seat
);
218 r
= set_consume(nodes
, n
);
223 /* udev exports "dead" device nodes to allow module on-demand loading,
224 * these devices are not known to the kernel at this moment */
225 dir
= opendir("/run/udev/static_node-tags/uaccess");
227 FOREACH_DIRENT(dent
, dir
, return -errno
) {
228 _cleanup_free_
char *unescaped_devname
= NULL
;
230 if (cunescape(dent
->d_name
, UNESCAPE_RELAX
, &unescaped_devname
) < 0)
233 n
= strappend("/dev/", unescaped_devname
);
237 log_debug("Found static node %s for seat %s", n
, seat
);
238 r
= set_consume(nodes
, n
);
247 SET_FOREACH(n
, nodes
, i
) {
250 log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT
"→"UID_FMT
"%s%s)",
251 n
, seat
, old_uid
, new_uid
,
252 del
? " del" : "", add
? " add" : "");
254 k
= devnode_acl(n
, flush
, del
, old_uid
, add
, new_uid
);
256 log_debug("Device %s disappeared while setting ACLs", n
);
257 else if (k
< 0 && r
== 0)