root/lib/file-has-acl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. have_xattr
  2. acl_nfs4_nontrivial
  3. file_has_acl

     1 /* Test whether a file has a nontrivial ACL.  -*- coding: utf-8 -*-
     2 
     3    Copyright (C) 2002-2003, 2005-2023 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 <https://www.gnu.org/licenses/>.
    17 
    18    Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible.  */
    19 
    20 /* Without this pragma, gcc 4.7.0 20120126 may suggest that the
    21    file_has_acl function might be candidate for attribute 'const'  */
    22 #if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
    23 # pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
    24 #endif
    25 
    26 #include <config.h>
    27 
    28 #include "acl.h"
    29 
    30 #include "acl-internal.h"
    31 #include "attribute.h"
    32 #include "minmax.h"
    33 
    34 #if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
    35 # include <stdckdint.h>
    36 # include <string.h>
    37 # include <arpa/inet.h>
    38 # include <sys/xattr.h>
    39 # include <linux/xattr.h>
    40 # ifndef XATTR_NAME_NFSV4_ACL
    41 #  define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
    42 # endif
    43 # ifndef XATTR_NAME_POSIX_ACL_ACCESS
    44 #  define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access"
    45 # endif
    46 # ifndef XATTR_NAME_POSIX_ACL_DEFAULT
    47 #  define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
    48 # endif
    49 
    50 enum {
    51   /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */
    52   ACE4_ACCESS_DENIED_ACE_TYPE  = 0x00000001,
    53   ACE4_IDENTIFIER_GROUP        = 0x00000040
    54 };
    55 
    56 /* Return true if ATTR is in the set represented by the NUL-terminated
    57    strings in LISTBUF, which is of size LISTSIZE.  */
    58 
    59 ATTRIBUTE_PURE static bool
    60 have_xattr (char const *attr, char const *listbuf, ssize_t listsize)
    61 {
    62   char const *blim = listbuf + listsize;
    63   for (char const *b = listbuf; b < blim; b += strlen (b) + 1)
    64     for (char const *a = attr; *a == *b; a++, b++)
    65       if (!*a)
    66         return true;
    67   return false;
    68 }
    69 
    70 /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial.
    71    -1 upon failure to determine it.  Possibly change errno.  Assume that
    72    the ACL is valid, except avoid undefined behavior even if invalid.
    73 
    74    See <https://linux.die.net/man/5/nfs4_acl>.  The NFSv4 acls are
    75    defined in Internet RFC 7530 and as such, every NFSv4 server
    76    supporting ACLs should support NFSv4 ACLs (they differ from from
    77    POSIX draft ACLs).  The ACLs can be obtained via the
    78    nfsv4-acl-tools, e.g., the nfs4_getfacl command.  Gnulib provides
    79    only basic support of NFSv4 ACLs, i.e., recognize trivial vs
    80    nontrivial ACLs.  */
    81 
    82 static int
    83 acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
    84 {
    85   enum { BYTES_PER_NETWORK_UINT = 4};
    86 
    87   /* Grab the number of aces in the acl.  */
    88   nbytes -= BYTES_PER_NETWORK_UINT;
    89   if (nbytes < 0)
    90     return -1;
    91   uint32_t num_aces = ntohl (*xattr++);
    92   if (6 < num_aces)
    93     return 1;
    94   int ace_found = 0;
    95 
    96   for (int ace_n = 0; ace_n < num_aces; ace_n++)
    97     {
    98       /* Get the acl type and flag.  Skip the mask; it's too risky to
    99          test it and it does not seem to be needed.  Get the wholen.  */
   100       nbytes -= 4 * BYTES_PER_NETWORK_UINT;
   101       if (nbytes < 0)
   102         return -1;
   103       uint32_t type = ntohl (xattr[0]);
   104       uint32_t flag = ntohl (xattr[1]);
   105       uint32_t wholen = ntohl (xattr[3]);
   106       xattr += 4;
   107       int whowords = (wholen / BYTES_PER_NETWORK_UINT
   108                       + (wholen % BYTES_PER_NETWORK_UINT != 0));
   109       int64_t wholen4 = whowords;
   110       wholen4 *= BYTES_PER_NETWORK_UINT;
   111 
   112       /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
   113          ACE4_ACCESS_DENIED_ACE_TYPE.  */
   114       if (ACE4_ACCESS_DENIED_ACE_TYPE < type)
   115         return 1;
   116 
   117       /* RFC 7530 says FLAG should be 0, but be generous to NetApp and
   118          also accept the group flag.  */
   119       if (flag & ~ACE4_IDENTIFIER_GROUP)
   120         return 1;
   121 
   122       /* Get the who string.  Check NBYTES - WHOLEN4 before storing
   123          into NBYTES, to avoid truncation on conversion.  */
   124       if (nbytes - wholen4 < 0)
   125         return -1;
   126       nbytes -= wholen4;
   127 
   128       /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny.
   129          Check that there is at most one ACE of each TYPE and WHO.  */
   130       int who2
   131         = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0
   132            : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2
   133            : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4
   134            : -1);
   135       if (who2 < 0)
   136         return 1;
   137       int ace_found_bit = 1 << (who2 | type);
   138       if (ace_found & ace_found_bit)
   139         return 1;
   140       ace_found |= ace_found_bit;
   141 
   142       xattr += whowords;
   143     }
   144 
   145   return 0;
   146 }
   147 #endif
   148 
   149 /* Return 1 if NAME has a nontrivial access control list,
   150    0 if ACLs are not supported, or if NAME has no or only a base ACL,
   151    and -1 (setting errno) on error.  Note callers can determine
   152    if ACLs are not supported as errno is set in that case also.
   153    SB must be set to the stat buffer of NAME,
   154    obtained through stat() or lstat().  */
   155 
   156 int
   157 file_has_acl (char const *name, struct stat const *sb)
   158 {
   159 #if USE_ACL
   160   if (! S_ISLNK (sb->st_mode))
   161     {
   162 
   163 # if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
   164       int initial_errno = errno;
   165 
   166       /* The max length of a trivial NFSv4 ACL is 6 words for owner,
   167          6 for group, 7 for everyone, all times 2 because there are
   168          both allow and deny ACEs.  There are 6 words for owner
   169          because of type, flag, mask, wholen, "OWNER@"+pad and
   170          similarly for group; everyone is another word to hold
   171          "EVERYONE@".  */
   172       typedef uint32_t trivial_NFSv4_xattr_buf[2 * (6 + 6 + 7)];
   173 
   174       /* A buffer large enough to hold any trivial NFSv4 ACL,
   175          and also useful as a small array of char.  */
   176       union {
   177         trivial_NFSv4_xattr_buf xattr;
   178         char ch[sizeof (trivial_NFSv4_xattr_buf)];
   179       } stackbuf;
   180 
   181       char *listbuf = stackbuf.ch;
   182       ssize_t listbufsize = sizeof stackbuf.ch;
   183       char *heapbuf = NULL;
   184       ssize_t listsize;
   185 
   186       /* Use listxattr first, as this means just one syscall in the
   187          typical case where the file lacks an ACL.  Try stackbuf
   188          first, falling back on malloc if stackbuf is too small.  */
   189       while ((listsize = listxattr (name, listbuf, listbufsize)) < 0
   190              && errno == ERANGE)
   191         {
   192           free (heapbuf);
   193           ssize_t newsize = listxattr (name, NULL, 0);
   194           if (newsize <= 0)
   195             return newsize;
   196 
   197           /* Grow LISTBUFSIZE to at least NEWSIZE.  Grow it by a
   198              nontrivial amount too, to defend against denial of
   199              service by an adversary that fiddles with ACLs.  */
   200           bool overflow = ckd_add (&listbufsize, listbufsize, listbufsize >> 1);
   201           listbufsize = MAX (listbufsize, newsize);
   202           if (overflow || SIZE_MAX < listbufsize)
   203             {
   204               errno = ENOMEM;
   205               return -1;
   206             }
   207 
   208           listbuf = heapbuf = malloc (listbufsize);
   209           if (!listbuf)
   210             return -1;
   211         }
   212 
   213       /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs,
   214          but if it has an NFSv4 ACL that's the one that matters.
   215          In earlier Fedora the two types of ACLs were mutually exclusive.
   216          Attempt to work correctly on both kinds of systems.  */
   217       bool nfsv4_acl
   218         = 0 < listsize && have_xattr (XATTR_NAME_NFSV4_ACL, listbuf, listsize);
   219       int ret
   220         = (listsize <= 0 ? listsize
   221            : (nfsv4_acl
   222               || have_xattr (XATTR_NAME_POSIX_ACL_ACCESS, listbuf, listsize)
   223               || (S_ISDIR (sb->st_mode)
   224                   && have_xattr (XATTR_NAME_POSIX_ACL_DEFAULT,
   225                                  listbuf, listsize))));
   226       free (heapbuf);
   227 
   228       /* If there is an NFSv4 ACL, follow up with a getxattr syscall
   229          to see whether the NFSv4 ACL is nontrivial.  */
   230       if (nfsv4_acl)
   231         {
   232           ret = getxattr (name, XATTR_NAME_NFSV4_ACL,
   233                           stackbuf.xattr, sizeof stackbuf.xattr);
   234           if (ret < 0)
   235             switch (errno)
   236               {
   237               case ENODATA: return 0;
   238               case ERANGE : return 1; /* ACL must be nontrivial.  */
   239               }
   240           else
   241             {
   242               /* It looks like a trivial ACL, but investigate further.  */
   243               ret = acl_nfs4_nontrivial (stackbuf.xattr, ret);
   244               if (ret < 0)
   245                 {
   246                   errno = EINVAL;
   247                   return ret;
   248                 }
   249               errno = initial_errno;
   250             }
   251         }
   252       if (ret < 0)
   253         return - acl_errno_valid (errno);
   254       return ret;
   255 
   256 # elif HAVE_ACL_GET_FILE
   257 
   258       /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
   259       /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
   260       int ret;
   261 
   262       if (HAVE_ACL_EXTENDED_FILE) /* Linux */
   263         {
   264           /* On Linux, acl_extended_file is an optimized function: It only
   265              makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
   266              ACL_TYPE_DEFAULT.  */
   267           ret = acl_extended_file (name);
   268         }
   269       else /* FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
   270         {
   271 #  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
   272           /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
   273              and acl_get_file (name, ACL_TYPE_DEFAULT)
   274              always return NULL / EINVAL.  There is no point in making
   275              these two useless calls.  The real ACL is retrieved through
   276              acl_get_file (name, ACL_TYPE_EXTENDED).  */
   277           acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
   278           if (acl)
   279             {
   280               ret = acl_extended_nontrivial (acl);
   281               acl_free (acl);
   282             }
   283           else
   284             ret = -1;
   285 #  else /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
   286           acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
   287           if (acl)
   288             {
   289               int saved_errno;
   290 
   291               ret = acl_access_nontrivial (acl);
   292               saved_errno = errno;
   293               acl_free (acl);
   294               errno = saved_errno;
   295 #   if HAVE_ACL_FREE_TEXT /* Tru64 */
   296               /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
   297                  returns NULL with errno not set.  There is no point in
   298                  making this call.  */
   299 #   else /* FreeBSD, IRIX, Cygwin >= 2.5 */
   300               /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
   301                  and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
   302                  either both succeed or both fail; it depends on the
   303                  file system.  Therefore there is no point in making the second
   304                  call if the first one already failed.  */
   305               if (ret == 0 && S_ISDIR (sb->st_mode))
   306                 {
   307                   acl = acl_get_file (name, ACL_TYPE_DEFAULT);
   308                   if (acl)
   309                     {
   310 #    ifdef __CYGWIN__ /* Cygwin >= 2.5 */
   311                       ret = acl_access_nontrivial (acl);
   312                       saved_errno = errno;
   313                       acl_free (acl);
   314                       errno = saved_errno;
   315 #    else
   316                       ret = (0 < acl_entries (acl));
   317                       acl_free (acl);
   318 #    endif
   319                     }
   320                   else
   321                     ret = -1;
   322                 }
   323 #   endif
   324             }
   325           else
   326             ret = -1;
   327 #  endif
   328         }
   329       if (ret < 0)
   330         return - acl_errno_valid (errno);
   331       return ret;
   332 
   333 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
   334 
   335 #  if defined ACL_NO_TRIVIAL
   336 
   337       /* Solaris 10 (newer version), which has additional API declared in
   338          <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
   339          acl_fromtext, ...).  */
   340       return acl_trivial (name);
   341 
   342 #  else /* Solaris, Cygwin, general case */
   343 
   344       /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
   345          of Unixware.  The acl() call returns the access and default ACL both
   346          at once.  */
   347       {
   348         /* Initially, try to read the entries into a stack-allocated buffer.
   349            Use malloc if it does not fit.  */
   350         enum
   351           {
   352             alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
   353             alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
   354           };
   355         aclent_t buf[alloc_init];
   356         size_t alloc = alloc_init;
   357         aclent_t *entries = buf;
   358         aclent_t *malloced = NULL;
   359         int count;
   360 
   361         for (;;)
   362           {
   363             count = acl (name, GETACL, alloc, entries);
   364             if (count < 0 && errno == ENOSPC)
   365               {
   366                 /* Increase the size of the buffer.  */
   367                 free (malloced);
   368                 if (alloc > alloc_max / 2)
   369                   {
   370                     errno = ENOMEM;
   371                     return -1;
   372                   }
   373                 alloc = 2 * alloc; /* <= alloc_max */
   374                 entries = malloced =
   375                   (aclent_t *) malloc (alloc * sizeof (aclent_t));
   376                 if (entries == NULL)
   377                   {
   378                     errno = ENOMEM;
   379                     return -1;
   380                   }
   381                 continue;
   382               }
   383             break;
   384           }
   385         if (count < 0)
   386           {
   387             if (errno == ENOSYS || errno == ENOTSUP)
   388               ;
   389             else
   390               {
   391                 free (malloced);
   392                 return -1;
   393               }
   394           }
   395         else if (count == 0)
   396           ;
   397         else
   398           {
   399             /* Don't use MIN_ACL_ENTRIES:  It's set to 4 on Cygwin, but Cygwin
   400                returns only 3 entries for files with no ACL.  But this is safe:
   401                If there are more than 4 entries, there cannot be only the
   402                "user::", "group::", "other:", and "mask:" entries.  */
   403             if (count > 4)
   404               {
   405                 free (malloced);
   406                 return 1;
   407               }
   408 
   409             if (acl_nontrivial (count, entries))
   410               {
   411                 free (malloced);
   412                 return 1;
   413               }
   414           }
   415         free (malloced);
   416       }
   417 
   418 #   ifdef ACE_GETACL
   419       /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
   420          file systems (whereas the other ones are used in UFS file systems).  */
   421       {
   422         /* Initially, try to read the entries into a stack-allocated buffer.
   423            Use malloc if it does not fit.  */
   424         enum
   425           {
   426             alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
   427             alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
   428           };
   429         ace_t buf[alloc_init];
   430         size_t alloc = alloc_init;
   431         ace_t *entries = buf;
   432         ace_t *malloced = NULL;
   433         int count;
   434 
   435         for (;;)
   436           {
   437             count = acl (name, ACE_GETACL, alloc, entries);
   438             if (count < 0 && errno == ENOSPC)
   439               {
   440                 /* Increase the size of the buffer.  */
   441                 free (malloced);
   442                 if (alloc > alloc_max / 2)
   443                   {
   444                     errno = ENOMEM;
   445                     return -1;
   446                   }
   447                 alloc = 2 * alloc; /* <= alloc_max */
   448                 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
   449                 if (entries == NULL)
   450                   {
   451                     errno = ENOMEM;
   452                     return -1;
   453                   }
   454                 continue;
   455               }
   456             break;
   457           }
   458         if (count < 0)
   459           {
   460             if (errno == ENOSYS || errno == EINVAL)
   461               ;
   462             else
   463               {
   464                 free (malloced);
   465                 return -1;
   466               }
   467           }
   468         else if (count == 0)
   469           ;
   470         else
   471           {
   472             /* In the old (original Solaris 10) convention:
   473                If there are more than 3 entries, there cannot be only the
   474                ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
   475                In the newer Solaris 10 and Solaris 11 convention:
   476                If there are more than 6 entries, there cannot be only the
   477                ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
   478                NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
   479                NEW_ACE_ACCESS_DENIED_ACE_TYPE.  */
   480             if (count > 6)
   481               {
   482                 free (malloced);
   483                 return 1;
   484               }
   485 
   486             if (acl_ace_nontrivial (count, entries))
   487               {
   488                 free (malloced);
   489                 return 1;
   490               }
   491           }
   492         free (malloced);
   493       }
   494 #   endif
   495 
   496       return 0;
   497 #  endif
   498 
   499 # elif HAVE_GETACL /* HP-UX */
   500 
   501       {
   502         struct acl_entry entries[NACLENTRIES];
   503         int count;
   504 
   505         count = getacl (name, NACLENTRIES, entries);
   506 
   507         if (count < 0)
   508           {
   509             /* ENOSYS is seen on newer HP-UX versions.
   510                EOPNOTSUPP is typically seen on NFS mounts.
   511                ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
   512             if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
   513               ;
   514             else
   515               return -1;
   516           }
   517         else if (count == 0)
   518           return 0;
   519         else /* count > 0 */
   520           {
   521             if (count > NACLENTRIES)
   522               /* If NACLENTRIES cannot be trusted, use dynamic memory
   523                  allocation.  */
   524               abort ();
   525 
   526             /* If there are more than 3 entries, there cannot be only the
   527                (uid,%), (%,gid), (%,%) entries.  */
   528             if (count > 3)
   529               return 1;
   530 
   531             {
   532               struct stat statbuf;
   533 
   534               if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
   535                 return -1;
   536 
   537               return acl_nontrivial (count, entries);
   538             }
   539           }
   540       }
   541 
   542 #  if HAVE_ACLV_H /* HP-UX >= 11.11 */
   543 
   544       {
   545         struct acl entries[NACLVENTRIES];
   546         int count;
   547 
   548         count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
   549 
   550         if (count < 0)
   551           {
   552             /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
   553                EINVAL is seen on NFS in HP-UX 11.31.  */
   554             if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
   555               ;
   556             else
   557               return -1;
   558           }
   559         else if (count == 0)
   560           return 0;
   561         else /* count > 0 */
   562           {
   563             if (count > NACLVENTRIES)
   564               /* If NACLVENTRIES cannot be trusted, use dynamic memory
   565                  allocation.  */
   566               abort ();
   567 
   568             /* If there are more than 4 entries, there cannot be only the
   569                four base ACL entries.  */
   570             if (count > 4)
   571               return 1;
   572 
   573             return aclv_nontrivial (count, entries);
   574           }
   575       }
   576 
   577 #  endif
   578 
   579 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
   580 
   581       acl_type_t type;
   582       char aclbuf[1024];
   583       void *acl = aclbuf;
   584       size_t aclsize = sizeof (aclbuf);
   585       mode_t mode;
   586 
   587       for (;;)
   588         {
   589           /* The docs say that type being 0 is equivalent to ACL_ANY, but it
   590              is not true, in AIX 5.3.  */
   591           type.u64 = ACL_ANY;
   592           if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
   593             break;
   594           if (errno == ENOSYS)
   595             return 0;
   596           if (errno != ENOSPC)
   597             {
   598               if (acl != aclbuf)
   599                 free (acl);
   600               return -1;
   601             }
   602           aclsize = 2 * aclsize;
   603           if (acl != aclbuf)
   604             free (acl);
   605           acl = malloc (aclsize);
   606           if (acl == NULL)
   607             {
   608               errno = ENOMEM;
   609               return -1;
   610             }
   611         }
   612 
   613       if (type.u64 == ACL_AIXC)
   614         {
   615           int result = acl_nontrivial ((struct acl *) acl);
   616           if (acl != aclbuf)
   617             free (acl);
   618           return result;
   619         }
   620       else if (type.u64 == ACL_NFS4)
   621         {
   622           int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
   623           if (acl != aclbuf)
   624             free (acl);
   625           return result;
   626         }
   627       else
   628         {
   629           /* A newer type of ACL has been introduced in the system.
   630              We should better support it.  */
   631           if (acl != aclbuf)
   632             free (acl);
   633           errno = EINVAL;
   634           return -1;
   635         }
   636 
   637 # elif HAVE_STATACL /* older AIX */
   638 
   639       union { struct acl a; char room[4096]; } u;
   640 
   641       if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
   642         return -1;
   643 
   644       return acl_nontrivial (&u.a);
   645 
   646 # elif HAVE_ACLSORT /* NonStop Kernel */
   647 
   648       {
   649         struct acl entries[NACLENTRIES];
   650         int count;
   651 
   652         count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
   653 
   654         if (count < 0)
   655           {
   656             if (errno == ENOSYS || errno == ENOTSUP)
   657               ;
   658             else
   659               return -1;
   660           }
   661         else if (count == 0)
   662           return 0;
   663         else /* count > 0 */
   664           {
   665             if (count > NACLENTRIES)
   666               /* If NACLENTRIES cannot be trusted, use dynamic memory
   667                  allocation.  */
   668               abort ();
   669 
   670             /* If there are more than 4 entries, there cannot be only the
   671                four base ACL entries.  */
   672             if (count > 4)
   673               return 1;
   674 
   675             return acl_nontrivial (count, entries);
   676           }
   677       }
   678 
   679 # endif
   680     }
   681 #endif
   682 
   683   return 0;
   684 }

/* [<][>][^][v][top][bottom][index][help] */