2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "dirent-util.h"
28 #include "format-util.h"
29 #include "logind-acl.h"
31 #include "string-util.h"
32 #include "udev-util.h"
35 static int flush_acl(acl_t acl
) {
42 for (found
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
44 found
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
48 if (acl_get_tag_type(i
, &tag
) < 0)
54 if (acl_delete_entry(acl
, i
) < 0)
66 int devnode_acl(const char *path
,
68 bool del
, uid_t old_uid
,
69 bool add
, uid_t new_uid
) {
77 acl
= acl_get_file(path
, ACL_TYPE_ACCESS
);
89 } else if (del
&& old_uid
> 0) {
92 r
= acl_find_uid(acl
, old_uid
, &entry
);
97 if (acl_delete_entry(acl
, entry
) < 0) {
106 if (add
&& new_uid
> 0) {
108 acl_permset_t permset
;
111 r
= acl_find_uid(acl
, new_uid
, &entry
);
116 if (acl_create_entry(&acl
, &entry
) < 0) {
121 if (acl_set_tag_type(entry
, ACL_USER
) < 0 ||
122 acl_set_qualifier(entry
, &new_uid
) < 0) {
128 if (acl_get_permset(entry
, &permset
) < 0) {
133 rd
= acl_get_perm(permset
, ACL_READ
);
139 wt
= acl_get_perm(permset
, ACL_WRITE
);
147 if (acl_add_perm(permset
, ACL_READ
|ACL_WRITE
) < 0) {
159 if (acl_calc_mask(&acl
) < 0) {
164 if (acl_set_file(path
, ACL_TYPE_ACCESS
, acl
) < 0) {
177 int devnode_acl_all(struct udev
*udev
,
180 bool del
, uid_t old_uid
,
181 bool add
, uid_t new_uid
) {
183 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
184 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
185 _cleanup_set_free_free_ Set
*nodes
= NULL
;
186 _cleanup_closedir_
DIR *dir
= NULL
;
194 nodes
= set_new(&string_hash_ops
);
198 e
= udev_enumerate_new(udev
);
205 /* We can only match by one tag in libudev. We choose
206 * "uaccess" for that. If we could match for two tags here we
207 * could add the seat name as second match tag, but this would
208 * be hardly optimizable in libudev, and hence checking the
209 * second tag manually in our loop is a good solution. */
210 r
= udev_enumerate_add_match_tag(e
, "uaccess");
214 r
= udev_enumerate_add_match_is_initialized(e
);
218 r
= udev_enumerate_scan_devices(e
);
222 first
= udev_enumerate_get_list_entry(e
);
223 udev_list_entry_foreach(item
, first
) {
224 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
225 const char *node
, *sn
;
227 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
231 sn
= udev_device_get_property_value(d
, "ID_SEAT");
235 if (!streq(seat
, sn
))
238 node
= udev_device_get_devnode(d
);
239 /* In case people mistag devices with nodes, we need to ignore this */
247 log_debug("Found udev node %s for seat %s", n
, seat
);
248 r
= set_consume(nodes
, n
);
253 /* udev exports "dead" device nodes to allow module on-demand loading,
254 * these devices are not known to the kernel at this moment */
255 dir
= opendir("/run/udev/static_node-tags/uaccess");
257 FOREACH_DIRENT(dent
, dir
, return -errno
) {
258 _cleanup_free_
char *unescaped_devname
= NULL
;
260 if (cunescape(dent
->d_name
, UNESCAPE_RELAX
, &unescaped_devname
) < 0)
263 n
= strappend("/dev/", unescaped_devname
);
267 log_debug("Found static node %s for seat %s", n
, seat
);
268 r
= set_consume(nodes
, n
);
277 SET_FOREACH(n
, nodes
, i
) {
280 log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT
"→"UID_FMT
"%s%s)",
281 n
, seat
, old_uid
, new_uid
,
282 del
? " del" : "", add
? " add" : "");
284 k
= devnode_acl(n
, flush
, del
, old_uid
, add
, new_uid
);
286 log_debug("Device %s disappeared while setting ACLs", n
);
287 else if (k
< 0 && r
== 0)