Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <string.h>
5 : :
6 : : #include "sd-device.h"
7 : :
8 : : #include "acl-util.h"
9 : : #include "alloc-util.h"
10 : : #include "device-util.h"
11 : : #include "dirent-util.h"
12 : : #include "escape.h"
13 : : #include "fd-util.h"
14 : : #include "format-util.h"
15 : : #include "logind-acl.h"
16 : : #include "set.h"
17 : : #include "string-util.h"
18 : : #include "util.h"
19 : :
20 : 0 : static int flush_acl(acl_t acl) {
21 : : acl_entry_t i;
22 : : int found;
23 : 0 : bool changed = false;
24 : :
25 [ # # ]: 0 : assert(acl);
26 : :
27 [ # # ]: 0 : for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
28 : : found > 0;
29 : 0 : found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
30 : :
31 : : acl_tag_t tag;
32 : :
33 [ # # ]: 0 : if (acl_get_tag_type(i, &tag) < 0)
34 : 0 : return -errno;
35 : :
36 [ # # ]: 0 : if (tag != ACL_USER)
37 : 0 : continue;
38 : :
39 [ # # ]: 0 : if (acl_delete_entry(acl, i) < 0)
40 : 0 : return -errno;
41 : :
42 : 0 : changed = true;
43 : : }
44 : :
45 [ # # ]: 0 : if (found < 0)
46 : 0 : return -errno;
47 : :
48 : 0 : return changed;
49 : : }
50 : :
51 : 0 : int devnode_acl(const char *path,
52 : : bool flush,
53 : : bool del, uid_t old_uid,
54 : : bool add, uid_t new_uid) {
55 : :
56 : : acl_t acl;
57 : 0 : int r = 0;
58 : 0 : bool changed = false;
59 : :
60 [ # # ]: 0 : assert(path);
61 : :
62 : 0 : acl = acl_get_file(path, ACL_TYPE_ACCESS);
63 [ # # ]: 0 : if (!acl)
64 : 0 : return -errno;
65 : :
66 [ # # ]: 0 : if (flush) {
67 : :
68 : 0 : r = flush_acl(acl);
69 [ # # ]: 0 : if (r < 0)
70 : 0 : goto finish;
71 [ # # ]: 0 : if (r > 0)
72 : 0 : changed = true;
73 : :
74 [ # # # # ]: 0 : } else if (del && old_uid > 0) {
75 : : acl_entry_t entry;
76 : :
77 : 0 : r = acl_find_uid(acl, old_uid, &entry);
78 [ # # ]: 0 : if (r < 0)
79 : 0 : goto finish;
80 : :
81 [ # # ]: 0 : if (r > 0) {
82 [ # # ]: 0 : if (acl_delete_entry(acl, entry) < 0) {
83 : 0 : r = -errno;
84 : 0 : goto finish;
85 : : }
86 : :
87 : 0 : changed = true;
88 : : }
89 : : }
90 : :
91 [ # # # # ]: 0 : if (add && new_uid > 0) {
92 : : acl_entry_t entry;
93 : : acl_permset_t permset;
94 : : int rd, wt;
95 : :
96 : 0 : r = acl_find_uid(acl, new_uid, &entry);
97 [ # # ]: 0 : if (r < 0)
98 : 0 : goto finish;
99 : :
100 [ # # ]: 0 : if (r == 0) {
101 [ # # ]: 0 : if (acl_create_entry(&acl, &entry) < 0) {
102 : 0 : r = -errno;
103 : 0 : goto finish;
104 : : }
105 : :
106 [ # # # # ]: 0 : if (acl_set_tag_type(entry, ACL_USER) < 0 ||
107 : 0 : acl_set_qualifier(entry, &new_uid) < 0) {
108 : 0 : r = -errno;
109 : 0 : goto finish;
110 : : }
111 : : }
112 : :
113 [ # # ]: 0 : if (acl_get_permset(entry, &permset) < 0) {
114 : 0 : r = -errno;
115 : 0 : goto finish;
116 : : }
117 : :
118 : 0 : rd = acl_get_perm(permset, ACL_READ);
119 [ # # ]: 0 : if (rd < 0) {
120 : 0 : r = -errno;
121 : 0 : goto finish;
122 : : }
123 : :
124 : 0 : wt = acl_get_perm(permset, ACL_WRITE);
125 [ # # ]: 0 : if (wt < 0) {
126 : 0 : r = -errno;
127 : 0 : goto finish;
128 : : }
129 : :
130 [ # # # # ]: 0 : if (!rd || !wt) {
131 : :
132 [ # # ]: 0 : if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) {
133 : 0 : r = -errno;
134 : 0 : goto finish;
135 : : }
136 : :
137 : 0 : changed = true;
138 : : }
139 : : }
140 : :
141 [ # # ]: 0 : if (!changed)
142 : 0 : goto finish;
143 : :
144 [ # # ]: 0 : if (acl_calc_mask(&acl) < 0) {
145 : 0 : r = -errno;
146 : 0 : goto finish;
147 : : }
148 : :
149 [ # # ]: 0 : if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
150 : 0 : r = -errno;
151 : 0 : goto finish;
152 : : }
153 : :
154 : 0 : r = 0;
155 : :
156 : 0 : finish:
157 : 0 : acl_free(acl);
158 : :
159 : 0 : return r;
160 : : }
161 : :
162 : 0 : int devnode_acl_all(const char *seat,
163 : : bool flush,
164 : : bool del, uid_t old_uid,
165 : : bool add, uid_t new_uid) {
166 : :
167 : 0 : _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
168 : 0 : _cleanup_set_free_free_ Set *nodes = NULL;
169 : 0 : _cleanup_closedir_ DIR *dir = NULL;
170 : : struct dirent *dent;
171 : : sd_device *d;
172 : : Iterator i;
173 : : char *n;
174 : : int r;
175 : :
176 : 0 : nodes = set_new(&path_hash_ops);
177 [ # # ]: 0 : if (!nodes)
178 : 0 : return -ENOMEM;
179 : :
180 : 0 : r = sd_device_enumerator_new(&e);
181 [ # # ]: 0 : if (r < 0)
182 : 0 : return r;
183 : :
184 [ # # ]: 0 : if (isempty(seat))
185 : 0 : seat = "seat0";
186 : :
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 : 0 : r = sd_device_enumerator_add_match_tag(e, "uaccess");
193 [ # # ]: 0 : if (r < 0)
194 : 0 : return r;
195 : :
196 [ # # ]: 0 : FOREACH_DEVICE(e, d) {
197 : : const char *node, *sn;
198 : :
199 [ # # # # ]: 0 : if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
200 : 0 : sn = "seat0";
201 : :
202 [ # # ]: 0 : if (!streq(seat, sn))
203 : 0 : continue;
204 : :
205 : : /* In case people mistag devices with nodes, we need to ignore this */
206 [ # # ]: 0 : if (sd_device_get_devname(d, &node) < 0)
207 : 0 : continue;
208 : :
209 [ # # # # : 0 : log_device_debug(d, "Found udev node %s for seat %s", node, seat);
# # ]
210 : 0 : r = set_put_strdup(nodes, node);
211 [ # # ]: 0 : if (r < 0)
212 : 0 : return r;
213 : : }
214 : :
215 : : /* udev exports "dead" device nodes to allow module on-demand loading,
216 : : * these devices are not known to the kernel at this moment */
217 : 0 : dir = opendir("/run/udev/static_node-tags/uaccess");
218 [ # # ]: 0 : if (dir) {
219 [ # # # # : 0 : FOREACH_DIRENT(dent, dir, return -errno) {
# # ]
220 [ # # # ]: 0 : _cleanup_free_ char *unescaped_devname = NULL;
221 : :
222 [ # # ]: 0 : if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0)
223 : 0 : return -ENOMEM;
224 : :
225 : 0 : n = path_join("/dev", unescaped_devname);
226 [ # # ]: 0 : if (!n)
227 : 0 : return -ENOMEM;
228 : :
229 [ # # ]: 0 : log_debug("Found static node %s for seat %s", n, seat);
230 : 0 : r = set_consume(nodes, n);
231 [ # # ]: 0 : if (r == -EEXIST)
232 : 0 : continue;
233 [ # # ]: 0 : if (r < 0)
234 : 0 : return r;
235 : : }
236 : : }
237 : :
238 : 0 : r = 0;
239 [ # # ]: 0 : SET_FOREACH(n, nodes, i) {
240 : : int k;
241 : :
242 [ # # # # : 0 : log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT"→"UID_FMT"%s%s)",
# # ]
243 : : n, seat, old_uid, new_uid,
244 : : del ? " del" : "", add ? " add" : "");
245 : :
246 : 0 : k = devnode_acl(n, flush, del, old_uid, add, new_uid);
247 [ # # ]: 0 : if (k == -ENOENT)
248 [ # # ]: 0 : log_debug("Device %s disappeared while setting ACLs", n);
249 [ # # # # ]: 0 : else if (k < 0 && r == 0)
250 : 0 : r = k;
251 : : }
252 : :
253 : 0 : return r;
254 : : }
|