chiark / gitweb /
tmpfiles: add 'a' type to set ACLs
[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 found;
33
34         assert(acl);
35         assert(entry);
36
37         for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
38              found > 0;
39              found = 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
64         if (found < 0)
65                 return -errno;
66
67         return 0;
68 }
69
70 int calc_acl_mask_if_needed(acl_t *acl_p) {
71         acl_entry_t i;
72         int found;
73
74         assert(acl_p);
75
76         for (found = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
77              found > 0;
78              found = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
79
80                 acl_tag_t tag;
81
82                 if (acl_get_tag_type(i, &tag) < 0)
83                         return -errno;
84
85                 if (tag == ACL_MASK)
86                         return 0;
87         }
88
89         if (found < 0)
90                 return -errno;
91
92         if (acl_calc_mask(acl_p) < 0)
93                 return -errno;
94
95         return 0;
96 }
97
98 int search_acl_groups(char*** dst, const char* path, bool* belong) {
99         acl_t acl;
100
101         assert(path);
102         assert(belong);
103
104         acl = acl_get_file(path, ACL_TYPE_DEFAULT);
105         if (acl) {
106                 acl_entry_t entry;
107                 int r;
108
109                 r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
110                 while (r > 0) {
111                         acl_tag_t tag;
112                         gid_t *gid;
113                         char *name;
114
115                         r = acl_get_tag_type(entry, &tag);
116                         if (r < 0)
117                                 break;
118
119                         if (tag != ACL_GROUP)
120                                 goto next;
121
122                         gid = acl_get_qualifier(entry);
123                         if (!gid)
124                                 break;
125
126                         if (in_gid(*gid) > 0) {
127                                 *belong = true;
128                                 break;
129                         }
130
131                         name = gid_to_name(*gid);
132                         if (!name) {
133                                 acl_free(acl);
134                                 return log_oom();
135                         }
136
137                         r = strv_consume(dst, name);
138                         if (r < 0) {
139                                 acl_free(acl);
140                                 return log_oom();
141                         }
142
143                 next:
144                         r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
145                 }
146
147                 acl_free(acl);
148         }
149
150         return 0;
151 }
152
153 int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) {
154         _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
155         _cleanup_strv_free_ char **split;
156         char **entry;
157         int r = -EINVAL;
158         _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL;
159
160         split = strv_split(text, ",");
161         if (!split)
162                 return log_oom();
163
164         STRV_FOREACH(entry, split) {
165                 char *p;
166
167                 p = startswith(*entry, "default:");
168                 if (!p)
169                         p = startswith(*entry, "d:");
170
171                 if (p)
172                         r = strv_push(&d, p);
173                 else
174                         r = strv_push(&a, *entry);
175         }
176         if (r < 0)
177                 return r;
178
179         if (!strv_isempty(a)) {
180                 _cleanup_free_ char *join;
181
182                 join = strv_join(a, ",");
183                 if (!join)
184                         return -ENOMEM;
185
186                 a_acl = acl_from_text(join);
187                 if (!a_acl)
188                         return -EINVAL;
189
190                 r = calc_acl_mask_if_needed(&a_acl);
191                 if (r < 0)
192                         return r;
193         }
194
195         if (!strv_isempty(d)) {
196                 _cleanup_free_ char *join;
197
198                 join = strv_join(d, ",");
199                 if (!join)
200                         return -ENOMEM;
201
202                 d_acl = acl_from_text(join);
203                 if (!d_acl)
204                         return -EINVAL;
205
206                 r = calc_acl_mask_if_needed(&d_acl);
207                 if (r < 0)
208                         return r;
209         }
210
211         *acl_access = a_acl;
212         *acl_default = d_acl;
213         a_acl = d_acl = NULL;
214         return 0;
215 }