errno-h: document Haiku errors can’t be -1
[gnulib.git] / lib / file-has-acl.c
blobc02cfee842bf5f7f847d641d28a4081b4e0f1aa3
1 /* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
3 Copyright (C) 2002-2003, 2005-2025 Free Software Foundation, Inc.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
18 Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
20 #include <config.h>
22 /* Without this pragma, gcc 4.7.0 20120126 may suggest that the
23 file_has_acl function might be candidate for attribute 'const' */
24 #if _GL_GNUC_PREREQ (4, 6)
25 # pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
26 #endif
28 #include "acl.h"
30 #include <dirent.h>
31 #include <limits.h>
33 #include "acl-internal.h"
34 #include "attribute.h"
35 #include "minmax.h"
37 /* Check the assumption that UCHAR_MAX < INT_MAX. */
38 static_assert (ACL_SYMLINK_FOLLOW & ~ (unsigned char) -1);
40 static char const UNKNOWN_SECURITY_CONTEXT[] = "?";
42 #if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
43 # define USE_LINUX_XATTR true
44 #else
45 # define USE_LINUX_XATTR false
46 #endif
48 #if USE_LINUX_XATTR
49 # if USE_SELINUX_SELINUX_H
50 # include <selinux/selinux.h>
51 # endif
52 # include <stdckdint.h>
53 # include <stdint.h>
54 # include <string.h>
55 # include <arpa/inet.h>
56 # include <sys/xattr.h>
57 # include <linux/xattr.h>
58 # ifndef XATTR_NAME_SMACK
59 # define XATTR_NAME_SMACK "security.SMACK64"
60 # endif
61 # ifndef XATTR_NAME_SELINUX
62 # define XATTR_NAME_SELINUX "security.selinux"
63 # endif
64 # ifndef XATTR_NAME_NFSV4_ACL
65 # define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
66 # endif
67 # ifndef XATTR_NAME_POSIX_ACL_ACCESS
68 # define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access"
69 # endif
70 # ifndef XATTR_NAME_POSIX_ACL_DEFAULT
71 # define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
72 # endif
74 # ifdef HAVE_SMACK
75 # include <sys/smack.h>
76 # else
77 static char const *
78 smack_smackfs_path (void)
80 return NULL;
82 static ssize_t
83 smack_new_label_from_path (MAYBE_UNUSED const char *path,
84 MAYBE_UNUSED const char *xattr,
85 MAYBE_UNUSED int follow, MAYBE_UNUSED char **label)
87 return -1;
89 # endif
90 static bool
91 is_smack_enabled (void)
93 return !!smack_smackfs_path ();
96 enum {
97 /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */
98 ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001,
99 ACE4_IDENTIFIER_GROUP = 0x00000040
102 /* AI indicates XATTR may be present but wasn't accessible.
103 This is the case when [l]listxattr failed with E2BIG,
104 or is not supported (!acl_errno_valid()), or failed with EACCES
105 which in Linux kernel 6.12 NFS can mean merely that we lack read access.
108 static bool
109 aclinfo_may_indicate_xattr (struct aclinfo const *ai)
111 return ai->size < 0 && (!acl_errno_valid (ai->u.err)
112 || ai->u.err == EACCES || ai->u.err == E2BIG);
115 /* Does NAME have XATTR? */
117 static bool
118 has_xattr (char const *xattr, struct aclinfo const *ai,
119 MAYBE_UNUSED char const *restrict name, MAYBE_UNUSED int flags)
121 if (ai && aclinfo_has_xattr (ai, xattr))
122 return true;
123 else if (!ai || aclinfo_may_indicate_xattr (ai))
125 int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
126 (name, xattr, NULL, 0));
127 if (0 <= ret || (errno == ERANGE || errno == E2BIG))
128 return true;
130 return false;
133 /* Does AI's xattr set contain XATTR? */
135 bool
136 aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr)
138 if (0 < ai->size)
140 char const *blim = ai->buf + ai->size;
141 for (char const *b = ai->buf; b < blim; b += strlen (b) + 1)
142 for (char const *a = xattr; *a == *b; a++, b++)
143 if (!*a)
144 return true;
146 return false;
149 /* Get attributes of the file NAME into AI, if USE_ACL.
150 If FLAGS & ACL_GET_SCONTEXT, also get security context.
151 If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */
152 static void
153 get_aclinfo (char const *name, struct aclinfo *ai, int flags)
155 int scontext_err = ENOTSUP;
156 ai->buf = ai->u.__gl_acl_ch;
157 ssize_t acl_alloc = sizeof ai->u.__gl_acl_ch;
159 if (! (USE_ACL || flags & ACL_GET_SCONTEXT))
160 ai->size = 0;
161 else
163 ssize_t (*lsxattr) (char const *, char *, size_t)
164 = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr);
165 while (true)
167 ai->size = lsxattr (name, ai->buf, acl_alloc);
168 if (0 < ai->size)
169 break;
170 ai->u.err = ai->size < 0 ? errno : 0;
171 if (! (ai->size < 0 && ai->u.err == ERANGE && acl_alloc < SSIZE_MAX))
172 break;
174 /* The buffer was too small. Find how large it should have been. */
175 ssize_t size = lsxattr (name, NULL, 0);
176 if (size <= 0)
178 ai->size = size;
179 ai->u.err = size < 0 ? errno : 0;
180 break;
183 /* Grow allocation to at least 'size'. Grow it by a nontrivial
184 amount, to defend against denial of service by an adversary
185 that fiddles with ACLs. */
186 if (ai->buf != ai->u.__gl_acl_ch)
188 free (ai->buf);
189 ai->buf = ai->u.__gl_acl_ch;
191 if (ckd_add (&acl_alloc, acl_alloc, acl_alloc >> 1))
192 acl_alloc = SSIZE_MAX;
193 if (acl_alloc < size)
194 acl_alloc = size;
195 if (SIZE_MAX < acl_alloc)
197 ai->u.err = ENOMEM;
198 break;
200 char *newbuf = malloc (acl_alloc);
201 if (!newbuf)
203 ai->u.err = errno;
204 break;
206 ai->buf = newbuf;
210 /* A security context can exist only if extended attributes do. */
211 if (flags & ACL_GET_SCONTEXT
212 && (0 < ai->size || aclinfo_may_indicate_xattr (ai)))
214 if (is_smack_enabled ())
216 if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SMACK))
218 ssize_t r = smack_new_label_from_path (name, "security.SMACK64",
219 flags & ACL_SYMLINK_FOLLOW,
220 &ai->scontext);
221 scontext_err = r < 0 ? errno : 0;
224 else
226 # if USE_SELINUX_SELINUX_H
227 if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SELINUX))
229 ssize_t r =
230 ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon)
231 (name, &ai->scontext));
232 scontext_err = r < 0 ? errno : 0;
233 # ifndef SE_SELINUX_INLINE
234 /* Gnulib's selinux-h module is not in use, so getfilecon and
235 lgetfilecon can misbehave, be it via an old version of
236 libselinux where these would return 0 and set the result
237 context to NULL, or via a modern kernel+lib operating on a
238 file from a disk whose attributes were set by a kernel from
239 around 2006. In that latter case, the functions return a
240 length of 10 for the "unlabeled" context. Map both failures
241 to a return value of -1, and set errno to ENOTSUP in the
242 first case, and ENODATA in the latter. */
243 if (r == 0)
244 scontext_err = ENOTSUP;
245 if (r == 10 && memcmp (ai->scontext, "unlabeled", 10) == 0)
247 freecon (ai->scontext);
248 scontext_err = ENODATA;
250 # endif
252 # endif
255 ai->scontext_err = scontext_err;
256 if (scontext_err)
257 ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT;
260 # ifndef aclinfo_scontext_free
261 /* Free the pointer that file_has_aclinfo put into scontext.
262 However, do nothing if the argument is a null pointer;
263 This lets the caller replace the scontext member with a null pointer if it
264 is willing to own the member and call this function later. */
265 void
266 aclinfo_scontext_free (char *scontext)
268 if (scontext != UNKNOWN_SECURITY_CONTEXT)
270 if (is_smack_enabled ())
271 free (scontext);
272 else if (scontext)
273 freecon (scontext);
276 # endif
278 /* Free AI's heap storage. */
279 void
280 aclinfo_free (struct aclinfo *ai)
282 if (ai->buf != ai->u.__gl_acl_ch)
283 free (ai->buf);
284 aclinfo_scontext_free (ai->scontext);
287 /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial.
288 -1 upon failure to determine it. Possibly change errno. Assume that
289 the ACL is valid, except avoid undefined behavior even if invalid.
291 See <https://linux.die.net/man/5/nfs4_acl>. The NFSv4 acls are
292 defined in Internet RFC 7530 and as such, every NFSv4 server
293 supporting ACLs should support NFSv4 ACLs (they differ from from
294 POSIX draft ACLs). The ACLs can be obtained via the
295 nfsv4-acl-tools, e.g., the nfs4_getfacl command. Gnulib provides
296 only basic support of NFSv4 ACLs, i.e., recognize trivial vs
297 nontrivial ACLs. */
299 static int
300 acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
302 enum { BYTES_PER_NETWORK_UINT = 4};
304 /* Grab the number of aces in the acl. */
305 nbytes -= BYTES_PER_NETWORK_UINT;
306 if (nbytes < 0)
307 return -1;
308 uint32_t num_aces = ntohl (*xattr++);
309 if (6 < num_aces)
310 return 1;
311 int ace_found = 0;
313 for (int ace_n = 0; ace_n < num_aces; ace_n++)
315 /* Get the acl type and flag. Skip the mask; it's too risky to
316 test it and it does not seem to be needed. Get the wholen. */
317 nbytes -= 4 * BYTES_PER_NETWORK_UINT;
318 if (nbytes < 0)
319 return -1;
320 uint32_t type = ntohl (xattr[0]);
321 uint32_t flag = ntohl (xattr[1]);
322 uint32_t wholen = ntohl (xattr[3]);
323 xattr += 4;
324 int whowords = (wholen / BYTES_PER_NETWORK_UINT
325 + (wholen % BYTES_PER_NETWORK_UINT != 0));
326 int64_t wholen4 = whowords;
327 wholen4 *= BYTES_PER_NETWORK_UINT;
329 /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
330 ACE4_ACCESS_DENIED_ACE_TYPE. */
331 if (ACE4_ACCESS_DENIED_ACE_TYPE < type)
332 return 1;
334 /* RFC 7530 says FLAG should be 0, but be generous to NetApp and
335 also accept the group flag. */
336 if (flag & ~ACE4_IDENTIFIER_GROUP)
337 return 1;
339 /* Get the who string. Check NBYTES - WHOLEN4 before storing
340 into NBYTES, to avoid truncation on conversion. */
341 if (nbytes - wholen4 < 0)
342 return -1;
343 nbytes -= wholen4;
345 /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny.
346 Check that there is at most one ACE of each TYPE and WHO. */
347 int who2
348 = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0
349 : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2
350 : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4
351 : -1);
352 if (who2 < 0)
353 return 1;
354 int ace_found_bit = 1 << (who2 | type);
355 if (ace_found & ace_found_bit)
356 return 1;
357 ace_found |= ace_found_bit;
359 xattr += whowords;
362 return 0;
364 #endif
366 /* Return 1 if NAME has a nontrivial access control list,
367 0 if ACLs are not supported, or if NAME has no or only a base ACL,
368 and -1 (setting errno) on error. Note callers can determine
369 if ACLs are not supported as errno is set in that case also.
370 Set *AI to ACL info regardless of return value.
371 FLAGS should be a <dirent.h> d_type value, optionally ORed with
372 - _GL_DT_NOTDIR if it is known that NAME is not a directory,
373 - ACL_GET_SCONTEXT to retrieve security context and return 1 if present,
374 - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link;
375 otherwise do not follow them if possible.
376 If the d_type value is not known, use DT_UNKNOWN though this may be less
377 efficient. */
379 file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
380 struct aclinfo *restrict ai, int flags)
382 MAYBE_UNUSED unsigned char d_type = flags & UCHAR_MAX;
384 #if USE_LINUX_XATTR
385 int initial_errno = errno;
386 get_aclinfo (name, ai, flags);
388 if (!aclinfo_may_indicate_xattr (ai) && ai->size <= 0)
390 errno = ai->size < 0 ? ai->u.err : initial_errno;
391 return ai->size;
394 /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs,
395 but if it has an NFSv4 ACL that's the one that matters.
396 In earlier Fedora the two types of ACLs were mutually exclusive.
397 Attempt to work correctly on both kinds of systems. */
399 if (!has_xattr (XATTR_NAME_NFSV4_ACL, ai, name, flags))
400 return
401 (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS, ai, name, flags)
402 || ((d_type == DT_DIR || d_type == DT_UNKNOWN)
403 && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ai, name, flags)));
405 /* A buffer large enough to hold any trivial NFSv4 ACL.
406 The max length of a trivial NFSv4 ACL is 6 words for owner,
407 6 for group, 7 for everyone, all times 2 because there are both
408 allow and deny ACEs. There are 6 words for owner because of
409 type, flag, mask, wholen, "OWNER@"+pad and similarly for group;
410 everyone is another word to hold "EVERYONE@". */
411 uint32_t buf[2 * (6 + 6 + 7)];
413 int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
414 (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf));
415 if (ret < 0)
416 switch (errno)
418 case ENODATA: return 0;
419 case ERANGE : return 1; /* ACL must be nontrivial. */
420 default: return - acl_errno_valid (errno);
423 /* It looks like a trivial ACL, but investigate further. */
424 ret = acl_nfs4_nontrivial (buf, ret);
425 errno = ret < 0 ? EINVAL : initial_errno;
426 return ret;
428 #else /* !USE_LINUX_XATTR */
430 ai->buf = ai->u.__gl_acl_ch;
431 ai->size = -1;
432 ai->u.err = ENOTSUP;
433 ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT;
434 ai->scontext_err = ENOTSUP;
436 # if USE_ACL
437 # if HAVE_ACL_GET_FILE
440 /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
441 /* Linux, FreeBSD, NetBSD >= 10, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
442 int ret;
444 # if HAVE_ACL_EXTENDED_FILE /* Linux */
445 /* On Linux, acl_extended_file is an optimized function: It only
446 makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
447 ACL_TYPE_DEFAULT. */
448 ret = ((flags & ACL_SYMLINK_FOLLOW
449 ? acl_extended_file
450 : acl_extended_file_nofollow)
451 (name));
452 # elif HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
453 /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
454 and acl_get_file (name, ACL_TYPE_DEFAULT)
455 always return NULL / EINVAL. There is no point in making
456 these two useless calls. The real ACL is retrieved through
457 acl_get_file (name, ACL_TYPE_EXTENDED). */
458 acl_t acl = ((flags & ACL_SYMLINK_FOLLOW
459 ? acl_get_file
460 : acl_get_link_np)
461 (name, ACL_TYPE_EXTENDED));
462 if (acl)
464 ret = acl_extended_nontrivial (acl);
465 acl_free (acl);
467 else
468 ret = -1;
469 # else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */
470 acl_t (*acl_get_file_or_link) (char const *, acl_type_t) = acl_get_file;
471 # if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10 */
472 if (! (flags & ACL_SYMLINK_FOLLOW))
473 acl_get_file_or_link = acl_get_link_np;
474 # endif
476 acl_t acl = acl_get_file_or_link (name, ACL_TYPE_ACCESS);
477 if (acl)
479 ret = acl_access_nontrivial (acl);
480 int saved_errno = errno;
481 acl_free (acl);
482 errno = saved_errno;
483 # if HAVE_ACL_FREE_TEXT /* Tru64 */
484 /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
485 returns NULL with errno not set. There is no point in
486 making this call. */
487 # else /* FreeBSD, NetBSD >= 10, IRIX, Cygwin >= 2.5 */
488 /* On Linux, FreeBSD, NetBSD, IRIX,
489 acl_get_file (name, ACL_TYPE_ACCESS)
490 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
491 either both succeed or both fail; it depends on the
492 file system. Therefore there is no point in making the second
493 call if the first one already failed. */
494 if (ret == 0
495 && (d_type == DT_DIR
496 || (d_type == DT_UNKNOWN && !(flags & _GL_DT_NOTDIR))))
498 acl = acl_get_file_or_link (name, ACL_TYPE_DEFAULT);
499 if (acl)
501 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
502 ret = acl_access_nontrivial (acl);
503 saved_errno = errno;
504 acl_free (acl);
505 errno = saved_errno;
506 # else
507 ret = (0 < acl_entries (acl));
508 acl_free (acl);
509 # endif
511 else
513 ret = -1;
514 # ifdef __CYGWIN__ /* Cygwin >= 2.5 */
515 if (d_type == DT_UNKNOWN)
516 ret = 0;
517 # endif
520 # endif
522 else
523 ret = -1;
524 # endif
526 return ret < 0 ? - acl_errno_valid (errno) : ret;
529 # else /* !HAVE_ACL_GET_FILE */
531 /* The remaining APIs always follow symlinks and operate on
532 platforms where symlinks do not have ACLs, so skip the APIs if
533 NAME is known to be a symlink. */
534 if (d_type != DT_LNK)
537 # if HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
539 # ifdef ACL_NO_TRIVIAL
541 /* Solaris 10 (newer version), which has additional API declared in
542 <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
543 acl_fromtext, ...). */
544 return acl_trivial (name);
546 # else /* Solaris, Cygwin, general case */
548 /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
549 of Unixware. The acl() call returns the access and default ACL both
550 at once. */
552 /* Initially, try to read the entries into a stack-allocated buffer.
553 Use malloc if it does not fit. */
554 enum
556 alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
557 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
559 aclent_t buf[alloc_init];
560 size_t alloc = alloc_init;
561 aclent_t *entries = buf;
562 aclent_t *malloced = NULL;
563 int count;
565 for (;;)
567 count = acl (name, GETACL, alloc, entries);
568 if (count < 0 && errno == ENOSPC)
570 /* Increase the size of the buffer. */
571 free (malloced);
572 if (alloc > alloc_max / 2)
574 errno = ENOMEM;
575 return -1;
577 alloc = 2 * alloc; /* <= alloc_max */
578 entries = malloced =
579 (aclent_t *) malloc (alloc * sizeof (aclent_t));
580 if (entries == NULL)
581 return -1;
582 continue;
584 break;
586 if (count < 0)
588 if (errno == ENOSYS || errno == ENOTSUP)
590 else
592 free (malloced);
593 return -1;
596 else if (count == 0)
598 else
600 /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
601 returns only 3 entries for files with no ACL. But this is safe:
602 If there are more than 4 entries, there cannot be only the
603 "user::", "group::", "other:", and "mask:" entries. */
604 if (count > 4)
606 free (malloced);
607 return 1;
610 if (acl_nontrivial (count, entries))
612 free (malloced);
613 return 1;
616 free (malloced);
619 # ifdef ACE_GETACL
620 /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
621 file systems (whereas the other ones are used in UFS file systems). */
623 /* Initially, try to read the entries into a stack-allocated buffer.
624 Use malloc if it does not fit. */
625 enum
627 alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
628 alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
630 ace_t buf[alloc_init];
631 size_t alloc = alloc_init;
632 ace_t *entries = buf;
633 ace_t *malloced = NULL;
634 int count;
636 for (;;)
638 count = acl (name, ACE_GETACL, alloc, entries);
639 if (count < 0 && errno == ENOSPC)
641 /* Increase the size of the buffer. */
642 free (malloced);
643 if (alloc > alloc_max / 2)
645 errno = ENOMEM;
646 return -1;
648 alloc = 2 * alloc; /* <= alloc_max */
649 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
650 if (entries == NULL)
651 return -1;
652 continue;
654 break;
656 if (count < 0)
658 if (errno == ENOSYS || errno == EINVAL)
660 else
662 free (malloced);
663 return -1;
666 else if (count == 0)
668 else
670 /* In the old (original Solaris 10) convention:
671 If there are more than 3 entries, there cannot be only the
672 ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
673 In the newer Solaris 10 and Solaris 11 convention:
674 If there are more than 6 entries, there cannot be only the
675 ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
676 NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
677 NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
678 if (count > 6)
680 free (malloced);
681 return 1;
684 if (acl_ace_nontrivial (count, entries))
686 free (malloced);
687 return 1;
690 free (malloced);
692 # endif
694 return 0;
695 # endif
697 # elif HAVE_GETACL /* HP-UX */
700 struct acl_entry entries[NACLENTRIES];
701 int count;
703 count = getacl (name, NACLENTRIES, entries);
705 if (count < 0)
707 /* ENOSYS is seen on newer HP-UX versions.
708 EOPNOTSUPP is typically seen on NFS mounts.
709 ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
710 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
712 else
713 return -1;
715 else if (count == 0)
716 return 0;
717 else /* count > 0 */
719 if (count > NACLENTRIES)
720 /* If NACLENTRIES cannot be trusted, use dynamic memory
721 allocation. */
722 abort ();
724 /* If there are more than 3 entries, there cannot be only the
725 (uid,%), (%,gid), (%,%) entries. */
726 if (count > 3)
727 return 1;
730 struct stat statbuf;
732 if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
733 return -1;
735 return acl_nontrivial (count, entries);
740 # if HAVE_ACLV_H /* HP-UX >= 11.11 */
743 struct acl entries[NACLVENTRIES];
744 int count;
746 count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
748 if (count < 0)
750 /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
751 EINVAL is seen on NFS in HP-UX 11.31. */
752 if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
754 else
755 return -1;
757 else if (count == 0)
758 return 0;
759 else /* count > 0 */
761 if (count > NACLVENTRIES)
762 /* If NACLVENTRIES cannot be trusted, use dynamic memory
763 allocation. */
764 abort ();
766 /* If there are more than 4 entries, there cannot be only the
767 four base ACL entries. */
768 if (count > 4)
769 return 1;
771 return aclv_nontrivial (count, entries);
775 # endif
777 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
779 acl_type_t type;
780 char aclbuf[1024];
781 void *acl = aclbuf;
782 size_t aclsize = sizeof (aclbuf);
783 mode_t mode;
785 for (;;)
787 /* The docs say that type being 0 is equivalent to ACL_ANY, but it
788 is not true, in AIX 5.3. */
789 type.u64 = ACL_ANY;
790 if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
791 break;
792 if (errno == ENOSYS)
793 return 0;
794 if (errno != ENOSPC)
796 if (acl != aclbuf)
797 free (acl);
798 return -1;
800 aclsize = 2 * aclsize;
801 if (acl != aclbuf)
802 free (acl);
803 acl = malloc (aclsize);
804 if (acl == NULL)
805 return -1;
808 if (type.u64 == ACL_AIXC)
810 int result = acl_nontrivial ((struct acl *) acl);
811 if (acl != aclbuf)
812 free (acl);
813 return result;
815 else if (type.u64 == ACL_NFS4)
817 int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
818 if (acl != aclbuf)
819 free (acl);
820 return result;
822 else
824 /* A newer type of ACL has been introduced in the system.
825 We should better support it. */
826 if (acl != aclbuf)
827 free (acl);
828 errno = EINVAL;
829 return -1;
832 # elif HAVE_STATACL /* older AIX */
834 union { struct acl a; char room[4096]; } u;
836 if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
837 return -1;
839 return acl_nontrivial (&u.a);
841 # elif HAVE_ACLSORT /* NonStop Kernel */
844 struct acl entries[NACLENTRIES];
845 int count;
847 count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
849 if (count < 0)
851 if (errno == ENOSYS || errno == ENOTSUP)
853 else
854 return -1;
856 else if (count == 0)
857 return 0;
858 else /* count > 0 */
860 if (count > NACLENTRIES)
861 /* If NACLENTRIES cannot be trusted, use dynamic memory
862 allocation. */
863 abort ();
865 /* If there are more than 4 entries, there cannot be only the
866 four base ACL entries. */
867 if (count > 4)
868 return 1;
870 return acl_nontrivial (count, entries);
873 # endif
875 # endif
876 # endif
877 #endif
879 return 0;
882 /* Return 1 if NAME has a nontrivial access control list,
883 0 if ACLs are not supported, or if NAME has no or only a base ACL,
884 and -1 (setting errno) on error. Note callers can determine
885 if ACLs are not supported as errno is set in that case also.
886 SB must be set to the stat buffer of NAME,
887 obtained through stat() or lstat(). */
889 file_has_acl (char const *name, struct stat const *sb)
891 int flags = IFTODT (sb->st_mode);
892 if (!S_ISDIR (sb->st_mode))
893 flags |= _GL_DT_NOTDIR;
894 struct aclinfo ai;
895 int r = file_has_aclinfo (name, &ai, flags);
896 aclinfo_free (&ai);
897 return r;