]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
CommitLineData
f4b47811
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
478c8269 6 Copyright 2011,2013 Lennart Poettering
f4b47811
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
f4b47811
LP
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
5430f7f2 16 Lesser General Public License for more details.
f4b47811 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
f4b47811
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <assert.h>
f4b47811
LP
23#include <errno.h>
24#include <stdbool.h>
25
79c07722 26#include "acl-util.h"
478c8269
ZJS
27#include "util.h"
28#include "strv.h"
f4b47811
LP
29
30int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
31 acl_entry_t i;
dd4105b0 32 int r;
f4b47811
LP
33
34 assert(acl);
35 assert(entry);
36
dd4105b0
ZJS
37 for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
38 r > 0;
39 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
f4b47811
LP
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 }
dd4105b0 63 if (r < 0)
f4b47811
LP
64 return -errno;
65
66 return 0;
67}
478c8269 68
23ad4dd8
JAS
69int calc_acl_mask_if_needed(acl_t *acl_p) {
70 acl_entry_t i;
dd4105b0 71 int r;
23ad4dd8
JAS
72
73 assert(acl_p);
74
dd4105b0
ZJS
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)) {
23ad4dd8
JAS
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;
dd4105b0
ZJS
85 if (IN_SET(tag, ACL_USER, ACL_GROUP))
86 goto calc;
23ad4dd8 87 }
dd4105b0 88 if (r < 0)
23ad4dd8 89 return -errno;
dd4105b0 90 return 0;
23ad4dd8 91
dd4105b0 92calc:
23ad4dd8
JAS
93 if (acl_calc_mask(acl_p) < 0)
94 return -errno;
dd4105b0
ZJS
95 return 1;
96}
97
98int 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;
23ad4dd8 126
dd4105b0
ZJS
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;
23ad4dd8
JAS
159 return 0;
160}
161
478c8269
ZJS
162int 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
6e18964d 201 r = strv_consume(dst, name);
478c8269 202 if (r < 0) {
478c8269
ZJS
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}
f8eeeaf9 216
50d9e46d 217int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
f8eeeaf9
ZJS
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
50d9e46d
ZJS
254 if (want_mask) {
255 r = calc_acl_mask_if_needed(&a_acl);
256 if (r < 0)
257 return r;
258 }
f8eeeaf9
ZJS
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
50d9e46d
ZJS
272 if (want_mask) {
273 r = calc_acl_mask_if_needed(&d_acl);
274 if (r < 0)
275 return r;
276 }
f8eeeaf9
ZJS
277 }
278
279 *acl_access = a_acl;
280 *acl_default = d_acl;
281 a_acl = d_acl = NULL;
282 return 0;
283}
50d9e46d
ZJS
284
285int 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;
dd4105b0 288 int r;
50d9e46d
ZJS
289
290 old = acl_get_file(path, type);
291 if (!old)
292 return -errno;
293
dd4105b0
ZJS
294 for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
295 r > 0;
296 r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
50d9e46d
ZJS
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 }
50d9e46d 306 if (r < 0)
dd4105b0 307 return -errno;
50d9e46d
ZJS
308
309 *acl = old;
310 old = NULL;
311 return 0;
312}