chiark / gitweb /
remove unused includes
[elogind.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 <errno.h>
23 #include <stdbool.h>
24
25 #include "acl-util.h"
26 #include "util.h"
27 #include "strv.h"
28
29 int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
30         acl_entry_t i;
31         int r;
32
33         assert(acl);
34         assert(entry);
35
36         for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
37              r > 0;
38              r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
39
40                 acl_tag_t tag;
41                 uid_t *u;
42                 bool b;
43
44                 if (acl_get_tag_type(i, &tag) < 0)
45                         return -errno;
46
47                 if (tag != ACL_USER)
48                         continue;
49
50                 u = acl_get_qualifier(i);
51                 if (!u)
52                         return -errno;
53
54                 b = *u == uid;
55                 acl_free(u);
56
57                 if (b) {
58                         *entry = i;
59                         return 1;
60                 }
61         }
62         if (r < 0)
63                 return -errno;
64
65         return 0;
66 }
67
68 int calc_acl_mask_if_needed(acl_t *acl_p) {
69         acl_entry_t i;
70         int r;
71
72         assert(acl_p);
73
74         for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
75              r > 0;
76              r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
77                 acl_tag_t tag;
78
79                 if (acl_get_tag_type(i, &tag) < 0)
80                         return -errno;
81
82                 if (tag == ACL_MASK)
83                         return 0;
84                 if (IN_SET(tag, ACL_USER, ACL_GROUP))
85                         goto calc;
86         }
87         if (r < 0)
88                 return -errno;
89         return 0;
90
91 calc:
92         if (acl_calc_mask(acl_p) < 0)
93                 return -errno;
94         return 1;
95 }
96
97 int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
98         acl_entry_t i;
99         int r;
100         bool have_user_obj = false, have_group_obj = false, have_other = false;
101         struct stat st;
102         _cleanup_(acl_freep) acl_t basic = NULL;
103
104         assert(acl_p);
105
106         for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
107              r > 0;
108              r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
109                 acl_tag_t tag;
110
111                 if (acl_get_tag_type(i, &tag) < 0)
112                         return -errno;
113
114                 if (tag == ACL_USER_OBJ)
115                         have_user_obj = true;
116                 else if (tag == ACL_GROUP_OBJ)
117                         have_group_obj = true;
118                 else if (tag == ACL_OTHER)
119                         have_other = true;
120                 if (have_user_obj && have_group_obj && have_other)
121                         return 0;
122         }
123         if (r < 0)
124                 return -errno;
125
126         r = stat(path, &st);
127         if (r < 0)
128                 return -errno;
129
130         basic = acl_from_mode(st.st_mode);
131         if (!basic)
132                 return -errno;
133
134         for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i);
135              r > 0;
136              r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) {
137                 acl_tag_t tag;
138                 acl_entry_t dst;
139
140                 if (acl_get_tag_type(i, &tag) < 0)
141                         return -errno;
142
143                 if ((tag == ACL_USER_OBJ && have_user_obj) ||
144                     (tag == ACL_GROUP_OBJ && have_group_obj) ||
145                     (tag == ACL_OTHER && have_other))
146                         continue;
147
148                 r = acl_create_entry(acl_p, &dst);
149                 if (r < 0)
150                         return -errno;
151
152                 r = acl_copy_entry(dst, i);
153                 if (r < 0)
154                         return -errno;
155         }
156         if (r < 0)
157                 return -errno;
158         return 0;
159 }
160
161 int search_acl_groups(char*** dst, const char* path, bool* belong) {
162         acl_t acl;
163
164         assert(path);
165         assert(belong);
166
167         acl = acl_get_file(path, ACL_TYPE_DEFAULT);
168         if (acl) {
169                 acl_entry_t entry;
170                 int r;
171
172                 r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
173                 while (r > 0) {
174                         acl_tag_t tag;
175                         gid_t *gid;
176                         char *name;
177
178                         r = acl_get_tag_type(entry, &tag);
179                         if (r < 0)
180                                 break;
181
182                         if (tag != ACL_GROUP)
183                                 goto next;
184
185                         gid = acl_get_qualifier(entry);
186                         if (!gid)
187                                 break;
188
189                         if (in_gid(*gid) > 0) {
190                                 *belong = true;
191                                 break;
192                         }
193
194                         name = gid_to_name(*gid);
195                         if (!name) {
196                                 acl_free(acl);
197                                 return log_oom();
198                         }
199
200                         r = strv_consume(dst, name);
201                         if (r < 0) {
202                                 acl_free(acl);
203                                 return log_oom();
204                         }
205
206                 next:
207                         r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
208                 }
209
210                 acl_free(acl);
211         }
212
213         return 0;
214 }
215
216 int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
217         _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
218         _cleanup_strv_free_ char **split;
219         char **entry;
220         int r = -EINVAL;
221         _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL;
222
223         split = strv_split(text, ",");
224         if (!split)
225                 return log_oom();
226
227         STRV_FOREACH(entry, split) {
228                 char *p;
229
230                 p = startswith(*entry, "default:");
231                 if (!p)
232                         p = startswith(*entry, "d:");
233
234                 if (p)
235                         r = strv_push(&d, p);
236                 else
237                         r = strv_push(&a, *entry);
238         }
239         if (r < 0)
240                 return r;
241
242         if (!strv_isempty(a)) {
243                 _cleanup_free_ char *join;
244
245                 join = strv_join(a, ",");
246                 if (!join)
247                         return -ENOMEM;
248
249                 a_acl = acl_from_text(join);
250                 if (!a_acl)
251                         return -EINVAL;
252
253                 if (want_mask) {
254                         r = calc_acl_mask_if_needed(&a_acl);
255                         if (r < 0)
256                                 return r;
257                 }
258         }
259
260         if (!strv_isempty(d)) {
261                 _cleanup_free_ char *join;
262
263                 join = strv_join(d, ",");
264                 if (!join)
265                         return -ENOMEM;
266
267                 d_acl = acl_from_text(join);
268                 if (!d_acl)
269                         return -EINVAL;
270
271                 if (want_mask) {
272                         r = calc_acl_mask_if_needed(&d_acl);
273                         if (r < 0)
274                                 return r;
275                 }
276         }
277
278         *acl_access = a_acl;
279         *acl_default = d_acl;
280         a_acl = d_acl = NULL;
281         return 0;
282 }
283
284 int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
285         _cleanup_(acl_freep) acl_t old;
286         acl_entry_t i;
287         int r;
288
289         old = acl_get_file(path, type);
290         if (!old)
291                 return -errno;
292
293         for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
294              r > 0;
295              r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
296
297                 acl_entry_t j;
298
299                 if (acl_create_entry(&old, &j) < 0)
300                         return -errno;
301
302                 if (acl_copy_entry(j, i) < 0)
303                         return -errno;
304         }
305         if (r < 0)
306                 return -errno;
307
308         *acl = old;
309         old = NULL;
310         return 0;
311 }