chiark / gitweb /
shared/log: read /proc/cmdline only in daemons
[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 <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 }