]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/acl-util.c
shared/acl-util: add mask only when needed, always add base ACLs
[thirdparty/systemd.git] / src / shared / acl-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011,2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <stdbool.h>
25
26 #include "acl-util.h"
27 #include "util.h"
28 #include "strv.h"
29
30 int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
31 acl_entry_t i;
32 int r;
33
34 assert(acl);
35 assert(entry);
36
37 for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
38 r > 0;
39 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
40
41 acl_tag_t tag;
42 uid_t *u;
43 bool b;
44
45 if (acl_get_tag_type(i, &tag) < 0)
46 return -errno;
47
48 if (tag != ACL_USER)
49 continue;
50
51 u = acl_get_qualifier(i);
52 if (!u)
53 return -errno;
54
55 b = *u == uid;
56 acl_free(u);
57
58 if (b) {
59 *entry = i;
60 return 1;
61 }
62 }
63 if (r < 0)
64 return -errno;
65
66 return 0;
67 }
68
69 int calc_acl_mask_if_needed(acl_t *acl_p) {
70 acl_entry_t i;
71 int r;
72
73 assert(acl_p);
74
75 for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
76 r > 0;
77 r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
78 acl_tag_t tag;
79
80 if (acl_get_tag_type(i, &tag) < 0)
81 return -errno;
82
83 if (tag == ACL_MASK)
84 return 0;
85 if (IN_SET(tag, ACL_USER, ACL_GROUP))
86 goto calc;
87 }
88 if (r < 0)
89 return -errno;
90 return 0;
91
92 calc:
93 if (acl_calc_mask(acl_p) < 0)
94 return -errno;
95 return 1;
96 }
97
98 int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
99 acl_entry_t i;
100 int r;
101 bool have_user_obj = false, have_group_obj = false, have_other = false;
102 struct stat st;
103 _cleanup_(acl_freep) acl_t basic = NULL;
104
105 assert(acl_p);
106
107 for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
108 r > 0;
109 r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
110 acl_tag_t tag;
111
112 if (acl_get_tag_type(i, &tag) < 0)
113 return -errno;
114
115 if (tag == ACL_USER_OBJ)
116 have_user_obj = true;
117 else if (tag == ACL_GROUP_OBJ)
118 have_group_obj = true;
119 else if (tag == ACL_OTHER)
120 have_other = true;
121 if (have_user_obj && have_group_obj && have_other)
122 return 0;
123 }
124 if (r < 0)
125 return -errno;
126
127 r = stat(path, &st);
128 if (r < 0)
129 return -errno;
130
131 basic = acl_from_mode(st.st_mode);
132 if (!basic)
133 return -errno;
134
135 for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i);
136 r > 0;
137 r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) {
138 acl_tag_t tag;
139 acl_entry_t dst;
140
141 if (acl_get_tag_type(i, &tag) < 0)
142 return -errno;
143
144 if ((tag == ACL_USER_OBJ && have_user_obj) ||
145 (tag == ACL_GROUP_OBJ && have_group_obj) ||
146 (tag == ACL_OTHER && have_other))
147 continue;
148
149 r = acl_create_entry(acl_p, &dst);
150 if (r < 0)
151 return -errno;
152
153 r = acl_copy_entry(dst, i);
154 if (r < 0)
155 return -errno;
156 }
157 if (r < 0)
158 return -errno;
159 return 0;
160 }
161
162 int search_acl_groups(char*** dst, const char* path, bool* belong) {
163 acl_t acl;
164
165 assert(path);
166 assert(belong);
167
168 acl = acl_get_file(path, ACL_TYPE_DEFAULT);
169 if (acl) {
170 acl_entry_t entry;
171 int r;
172
173 r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
174 while (r > 0) {
175 acl_tag_t tag;
176 gid_t *gid;
177 char *name;
178
179 r = acl_get_tag_type(entry, &tag);
180 if (r < 0)
181 break;
182
183 if (tag != ACL_GROUP)
184 goto next;
185
186 gid = acl_get_qualifier(entry);
187 if (!gid)
188 break;
189
190 if (in_gid(*gid) > 0) {
191 *belong = true;
192 break;
193 }
194
195 name = gid_to_name(*gid);
196 if (!name) {
197 acl_free(acl);
198 return log_oom();
199 }
200
201 r = strv_consume(dst, name);
202 if (r < 0) {
203 acl_free(acl);
204 return log_oom();
205 }
206
207 next:
208 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
209 }
210
211 acl_free(acl);
212 }
213
214 return 0;
215 }
216
217 int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
218 _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
219 _cleanup_strv_free_ char **split;
220 char **entry;
221 int r = -EINVAL;
222 _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL;
223
224 split = strv_split(text, ",");
225 if (!split)
226 return log_oom();
227
228 STRV_FOREACH(entry, split) {
229 char *p;
230
231 p = startswith(*entry, "default:");
232 if (!p)
233 p = startswith(*entry, "d:");
234
235 if (p)
236 r = strv_push(&d, p);
237 else
238 r = strv_push(&a, *entry);
239 }
240 if (r < 0)
241 return r;
242
243 if (!strv_isempty(a)) {
244 _cleanup_free_ char *join;
245
246 join = strv_join(a, ",");
247 if (!join)
248 return -ENOMEM;
249
250 a_acl = acl_from_text(join);
251 if (!a_acl)
252 return -EINVAL;
253
254 if (want_mask) {
255 r = calc_acl_mask_if_needed(&a_acl);
256 if (r < 0)
257 return r;
258 }
259 }
260
261 if (!strv_isempty(d)) {
262 _cleanup_free_ char *join;
263
264 join = strv_join(d, ",");
265 if (!join)
266 return -ENOMEM;
267
268 d_acl = acl_from_text(join);
269 if (!d_acl)
270 return -EINVAL;
271
272 if (want_mask) {
273 r = calc_acl_mask_if_needed(&d_acl);
274 if (r < 0)
275 return r;
276 }
277 }
278
279 *acl_access = a_acl;
280 *acl_default = d_acl;
281 a_acl = d_acl = NULL;
282 return 0;
283 }
284
285 int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
286 _cleanup_(acl_freep) acl_t old;
287 acl_entry_t i;
288 int r;
289
290 old = acl_get_file(path, type);
291 if (!old)
292 return -errno;
293
294 for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
295 r > 0;
296 r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
297
298 acl_entry_t j;
299
300 if (acl_create_entry(&old, &j) < 0)
301 return -errno;
302
303 if (acl_copy_entry(j, i) < 0)
304 return -errno;
305 }
306 if (r < 0)
307 return -errno;
308
309 *acl = old;
310 old = NULL;
311 return 0;
312 }