1 /* Test whether a file has a nontrivial access control list.
2
3 Copyright (C) 2002-2003, 2005-2009 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
19
20 #include <config.h>
21
22 #include "acl.h"
23
24 #include "acl-internal.h"
25
26
27 #if USE_ACL && HAVE_ACL_GET_FILE
28
29 # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
30
31 /* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
32 Return 1 if the given ACL is non-trivial.
33 Return 0 if it is trivial. */
34 int
acl_extended_nontrivial(acl_t acl)35 acl_extended_nontrivial (acl_t acl)
36 {
37 /* acl is non-trivial if it is non-empty. */
38 return (acl_entries (acl) > 0);
39 }
40
41 # else /* Linux, FreeBSD, IRIX, Tru64 */
42
43 /* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
44 Return 1 if the given ACL is non-trivial.
45 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
46 Return -1 and set errno upon failure to determine it. */
47 int
acl_access_nontrivial(acl_t acl)48 acl_access_nontrivial (acl_t acl)
49 {
50 /* acl is non-trivial if it has some entries other than for "user::",
51 "group::", and "other::". Normally these three should be present
52 at least, allowing us to write
53 return (3 < acl_entries (acl));
54 but the following code is more robust. */
55 # if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
56
57 acl_entry_t ace;
58 int got_one;
59
60 for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
61 got_one > 0;
62 got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
63 {
64 acl_tag_t tag;
65 if (acl_get_tag_type (ace, &tag) < 0)
66 return -1;
67 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
68 return 1;
69 }
70 return got_one;
71
72 # else /* IRIX, Tru64 */
73 # if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
74 /* Don't use acl_get_entry: it is undocumented. */
75
76 int count = acl->acl_cnt;
77 int i;
78
79 for (i = 0; i < count; i++)
80 {
81 acl_entry_t ace = &acl->acl_entry[i];
82 acl_tag_t tag = ace->ae_tag;
83
84 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
85 || tag == ACL_OTHER_OBJ))
86 return 1;
87 }
88 return 0;
89
90 # endif
91 # if HAVE_ACL_FREE_TEXT /* Tru64 */
92 /* Don't use acl_get_entry: it takes only one argument and does not work. */
93
94 int count = acl->acl_num;
95 acl_entry_t ace;
96
97 for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
98 {
99 acl_tag_t tag;
100 acl_perm_t perm;
101
102 tag = ace->entry->acl_type;
103 if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
104 return 1;
105
106 perm = ace->entry->acl_perm;
107 /* On Tru64, perm can also contain non-standard bits such as
108 PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
109 if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
110 return 1;
111 }
112 return 0;
113
114 # endif
115 # endif
116 }
117
118 # endif
119
120
121 #elif USE_ACL && HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
122
123 # if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */
124
125 /* Test an ACL retrieved with GETACL.
126 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
127 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
128 int
acl_nontrivial(int count,aclent_t * entries)129 acl_nontrivial (int count, aclent_t *entries)
130 {
131 int i;
132
133 for (i = 0; i < count; i++)
134 {
135 aclent_t *ace = &entries[i];
136
137 /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
138 If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
139 We don't need to check ace->a_id in these cases. */
140 if (!(ace->a_type == USER_OBJ
141 || ace->a_type == GROUP_OBJ
142 || ace->a_type == OTHER_OBJ
143 /* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
144 sometimes. */
145 || ace->a_type == CLASS_OBJ))
146 return 1;
147 }
148 return 0;
149 }
150
151 # ifdef ACE_GETACL
152
153 /* Test an ACL retrieved with ACE_GETACL.
154 Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
155 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
156 int
acl_ace_nontrivial(int count,ace_t * entries)157 acl_ace_nontrivial (int count, ace_t *entries)
158 {
159 int i;
160
161 /* The flags in the ace_t structure changed in a binary incompatible way
162 when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
163 How to distinguish the two conventions at runtime?
164 In the old convention, usually three ACEs have a_flags = ACE_OWNER /
165 ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new
166 convention, these values are not used. */
167 int old_convention = 0;
168
169 for (i = 0; i < count; i++)
170 if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER))
171 {
172 old_convention = 1;
173 break;
174 }
175
176 if (old_convention)
177 /* Running on Solaris 10. */
178 for (i = 0; i < count; i++)
179 {
180 ace_t *ace = &entries[i];
181
182 /* Note:
183 If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat().
184 If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat().
185 We don't need to check ace->a_who in these cases. */
186 if (!(ace->a_type == ALLOW
187 && (ace->a_flags == ACE_OWNER
188 || ace->a_flags == ACE_GROUP
189 || ace->a_flags == ACE_OTHER)))
190 return 1;
191 }
192 else
193 /* Running on Solaris 10 (newer version) or Solaris 11. */
194 for (i = 0; i < count; i++)
195 {
196 ace_t *ace = &entries[i];
197
198 if (!(ace->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE
199 && (ace->a_flags == NEW_ACE_OWNER
200 || ace->a_flags
201 == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP)
202 || ace->a_flags == ACE_EVERYONE)
203 && (ace->a_access_mask
204 & ~(NEW_ACE_READ_DATA | NEW_ACE_WRITE_DATA | NEW_ACE_EXECUTE))
205 == 0))
206 return 1;
207 }
208
209 return 0;
210 }
211
212 # endif
213
214 # endif
215
216 #elif USE_ACL && HAVE_GETACL /* HP-UX */
217
218 /* Return 1 if the given ACL is non-trivial.
219 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
220 int
acl_nontrivial(int count,struct acl_entry * entries,struct stat * sb)221 acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb)
222 {
223 int i;
224
225 for (i = 0; i < count; i++)
226 {
227 struct acl_entry *ace = &entries[i];
228
229 if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP)
230 || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid)
231 || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP)))
232 return 1;
233 }
234 return 0;
235 }
236
237 #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
238
239 /* TODO */
240
241 #elif USE_ACL && HAVE_STATACL /* older AIX */
242
243 /* Return 1 if the given ACL is non-trivial.
244 Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
245 int
acl_nontrivial(struct acl * a)246 acl_nontrivial (struct acl *a)
247 {
248 /* The normal way to iterate through an ACL is like this:
249 struct acl_entry *ace;
250 for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
251 {
252 struct ace_id *aei;
253 switch (ace->ace_type)
254 {
255 case ACC_PERMIT:
256 case ACC_DENY:
257 case ACC_SPECIFY:
258 ...;
259 }
260 for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
261 ...
262 }
263 */
264 return (acl_last (a) != a->acl_ext ? 1 : 0);
265 }
266
267 #endif
268
269
270 /* Return 1 if NAME has a nontrivial access control list, 0 if NAME
271 only has no or a base access control list, and -1 (setting errno)
272 on error. SB must be set to the stat buffer of FILE. */
273
274 int
file_has_acl(char const * name,struct stat const * sb)275 file_has_acl (char const *name, struct stat const *sb)
276 {
277 #if USE_ACL
278 if (! S_ISLNK (sb->st_mode))
279 {
280 # if HAVE_ACL_GET_FILE
281
282 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
283 /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
284 int ret;
285
286 if (HAVE_ACL_EXTENDED_FILE) /* Linux */
287 {
288 /* On Linux, acl_extended_file is an optimized function: It only
289 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
290 ACL_TYPE_DEFAULT. */
291 ret = acl_extended_file (name);
292 }
293 else /* FreeBSD, MacOS X, IRIX, Tru64 */
294 {
295 # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
296 /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
297 and acl_get_file (name, ACL_TYPE_DEFAULT)
298 always return NULL / EINVAL. There is no point in making
299 these two useless calls. The real ACL is retrieved through
300 acl_get_file (name, ACL_TYPE_EXTENDED). */
301 acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
302 if (acl)
303 {
304 ret = acl_extended_nontrivial (acl);
305 acl_free (acl);
306 }
307 else
308 ret = -1;
309 # else /* FreeBSD, IRIX, Tru64 */
310 acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
311 if (acl)
312 {
313 int saved_errno;
314
315 ret = acl_access_nontrivial (acl);
316 saved_errno = errno;
317 acl_free (acl);
318 errno = saved_errno;
319 # if HAVE_ACL_FREE_TEXT /* Tru64 */
320 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
321 returns NULL with errno not set. There is no point in
322 making this call. */
323 # else /* FreeBSD, IRIX */
324 /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
325 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
326 either both succeed or both fail; it depends on the
327 filesystem. Therefore there is no point in making the second
328 call if the first one already failed. */
329 if (ret == 0 && S_ISDIR (sb->st_mode))
330 {
331 acl = acl_get_file (name, ACL_TYPE_DEFAULT);
332 if (acl)
333 {
334 ret = (0 < acl_entries (acl));
335 acl_free (acl);
336 }
337 else
338 ret = -1;
339 }
340 # endif
341 }
342 else
343 ret = -1;
344 # endif
345 }
346 if (ret < 0)
347 return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
348 return ret;
349
350 # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
351
352 # if defined ACL_NO_TRIVIAL
353
354 /* Solaris 10 (newer version), which has additional API declared in
355 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
356 acl_fromtext, ...). */
357 return acl_trivial (name);
358
359 # else /* Solaris, Cygwin, general case */
360
361 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
362 of Unixware. The acl() call returns the access and default ACL both
363 at once. */
364 int count;
365 {
366 aclent_t *entries;
367
368 for (;;)
369 {
370 count = acl (name, GETACLCNT, 0, NULL);
371
372 if (count < 0)
373 {
374 if (errno == ENOSYS || errno == ENOTSUP)
375 break;
376 else
377 return -1;
378 }
379
380 if (count == 0)
381 break;
382
383 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
384 returns only 3 entries for files with no ACL. But this is safe:
385 If there are more than 4 entries, there cannot be only the
386 "user::", "group::", "other:", and "mask:" entries. */
387 if (count > 4)
388 return 1;
389
390 entries = (aclent_t *) malloc (count * sizeof (aclent_t));
391 if (entries == NULL)
392 {
393 errno = ENOMEM;
394 return -1;
395 }
396 if (acl (name, GETACL, count, entries) == count)
397 {
398 if (acl_nontrivial (count, entries))
399 {
400 free (entries);
401 return 1;
402 }
403 free (entries);
404 break;
405 }
406 /* Huh? The number of ACL entries changed since the last call.
407 Repeat. */
408 free (entries);
409 }
410 }
411
412 # ifdef ACE_GETACL
413 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
414 file systems (whereas the other ones are used in UFS file systems). */
415 {
416 ace_t *entries;
417
418 for (;;)
419 {
420 count = acl (name, ACE_GETACLCNT, 0, NULL);
421
422 if (count < 0)
423 {
424 if (errno == ENOSYS || errno == EINVAL)
425 break;
426 else
427 return -1;
428 }
429
430 if (count == 0)
431 break;
432
433 /* If there are more than 3 entries, there cannot be only the
434 ACE_OWNER, ACE_GROUP, ACE_OTHER entries. */
435 if (count > 3)
436 return 1;
437
438 entries = (ace_t *) malloc (count * sizeof (ace_t));
439 if (entries == NULL)
440 {
441 errno = ENOMEM;
442 return -1;
443 }
444 if (acl (name, ACE_GETACL, count, entries) == count)
445 {
446 if (acl_ace_nontrivial (count, entries))
447 {
448 free (entries);
449 return 1;
450 }
451 free (entries);
452 break;
453 }
454 /* Huh? The number of ACL entries changed since the last call.
455 Repeat. */
456 free (entries);
457 }
458 }
459 # endif
460
461 return 0;
462 # endif
463
464 # elif HAVE_GETACL /* HP-UX */
465
466 int count;
467 struct acl_entry entries[NACLENTRIES];
468
469 for (;;)
470 {
471 count = getacl (name, 0, NULL);
472
473 if (count < 0)
474 return (errno == ENOSYS || errno == EOPNOTSUPP ? 0 : -1);
475
476 if (count == 0)
477 return 0;
478
479 if (count > NACLENTRIES)
480 /* If NACLENTRIES cannot be trusted, use dynamic memory
481 allocation. */
482 abort ();
483
484 /* If there are more than 3 entries, there cannot be only the
485 (uid,%), (%,gid), (%,%) entries. */
486 if (count > 3)
487 return 1;
488
489 if (getacl (name, count, entries) == count)
490 {
491 struct stat statbuf;
492
493 if (stat (name, &statbuf) < 0)
494 return -1;
495
496 return acl_nontrivial (count, entries, &statbuf);
497 }
498 /* Huh? The number of ACL entries changed since the last call.
499 Repeat. */
500 }
501
502 # elif HAVE_ACLX_GET && 0 /* AIX */
503
504 /* TODO: use aclx_get(), and then? */
505
506 # elif HAVE_STATACL /* older AIX */
507
508 union { struct acl a; char room[4096]; } u;
509
510 if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
511 return -1;
512
513 return acl_nontrivial (&u.a);
514
515 # endif
516 }
517 #endif
518
519 return 0;
520 }
521