root/lib/file-has-acl.c

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

DEFINITIONS

This source file includes following definitions.
  1. 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 
    32 #if GETXATTR_WITH_POSIX_ACLS
    33 # include <sys/xattr.h>
    34 # include <linux/xattr.h>
    35 #endif
    36 
    37 /* Return 1 if NAME has a nontrivial access control list,
    38    0 if ACLs are not supported, or if NAME has no or only a base ACL,
    39    and -1 (setting errno) on error.  Note callers can determine
    40    if ACLs are not supported as errno is set in that case also.
    41    SB must be set to the stat buffer of NAME,
    42    obtained through stat() or lstat().  */
    43 
    44 int
    45 file_has_acl (char const *name, struct stat const *sb)
    46 {
    47 #if USE_ACL
    48   if (! S_ISLNK (sb->st_mode))
    49     {
    50 
    51 # if GETXATTR_WITH_POSIX_ACLS
    52 
    53       ssize_t ret;
    54 
    55       ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0);
    56       if (ret < 0 && errno == ENODATA)
    57         ret = 0;
    58       else if (ret > 0)
    59         return 1;
    60 
    61       if (ret == 0 && S_ISDIR (sb->st_mode))
    62         {
    63           ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0);
    64           if (ret < 0 && errno == ENODATA)
    65             ret = 0;
    66           else if (ret > 0)
    67             return 1;
    68         }
    69 
    70       if (ret < 0)
    71         return - acl_errno_valid (errno);
    72       return ret;
    73 
    74 # elif HAVE_ACL_GET_FILE
    75 
    76       /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
    77       /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
    78       int ret;
    79 
    80       if (HAVE_ACL_EXTENDED_FILE) /* Linux */
    81         {
    82           /* On Linux, acl_extended_file is an optimized function: It only
    83              makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
    84              ACL_TYPE_DEFAULT.  */
    85           ret = acl_extended_file (name);
    86         }
    87       else /* FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
    88         {
    89 #  if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
    90           /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
    91              and acl_get_file (name, ACL_TYPE_DEFAULT)
    92              always return NULL / EINVAL.  There is no point in making
    93              these two useless calls.  The real ACL is retrieved through
    94              acl_get_file (name, ACL_TYPE_EXTENDED).  */
    95           acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
    96           if (acl)
    97             {
    98               ret = acl_extended_nontrivial (acl);
    99               acl_free (acl);
   100             }
   101           else
   102             ret = -1;
   103 #  else /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
   104           acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
   105           if (acl)
   106             {
   107               int saved_errno;
   108 
   109               ret = acl_access_nontrivial (acl);
   110               saved_errno = errno;
   111               acl_free (acl);
   112               errno = saved_errno;
   113 #   if HAVE_ACL_FREE_TEXT /* Tru64 */
   114               /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
   115                  returns NULL with errno not set.  There is no point in
   116                  making this call.  */
   117 #   else /* FreeBSD, IRIX, Cygwin >= 2.5 */
   118               /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
   119                  and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
   120                  either both succeed or both fail; it depends on the
   121                  file system.  Therefore there is no point in making the second
   122                  call if the first one already failed.  */
   123               if (ret == 0 && S_ISDIR (sb->st_mode))
   124                 {
   125                   acl = acl_get_file (name, ACL_TYPE_DEFAULT);
   126                   if (acl)
   127                     {
   128 #    ifdef __CYGWIN__ /* Cygwin >= 2.5 */
   129                       ret = acl_access_nontrivial (acl);
   130                       saved_errno = errno;
   131                       acl_free (acl);
   132                       errno = saved_errno;
   133 #    else
   134                       ret = (0 < acl_entries (acl));
   135                       acl_free (acl);
   136 #    endif
   137                     }
   138                   else
   139                     ret = -1;
   140                 }
   141 #   endif
   142             }
   143           else
   144             ret = -1;
   145 #  endif
   146         }
   147       if (ret < 0)
   148         return - acl_errno_valid (errno);
   149       return ret;
   150 
   151 # elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
   152 
   153 #  if defined ACL_NO_TRIVIAL
   154 
   155       /* Solaris 10 (newer version), which has additional API declared in
   156          <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
   157          acl_fromtext, ...).  */
   158       return acl_trivial (name);
   159 
   160 #  else /* Solaris, Cygwin, general case */
   161 
   162       /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
   163          of Unixware.  The acl() call returns the access and default ACL both
   164          at once.  */
   165       {
   166         /* Initially, try to read the entries into a stack-allocated buffer.
   167            Use malloc if it does not fit.  */
   168         enum
   169           {
   170             alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
   171             alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
   172           };
   173         aclent_t buf[alloc_init];
   174         size_t alloc = alloc_init;
   175         aclent_t *entries = buf;
   176         aclent_t *malloced = NULL;
   177         int count;
   178 
   179         for (;;)
   180           {
   181             count = acl (name, GETACL, alloc, entries);
   182             if (count < 0 && errno == ENOSPC)
   183               {
   184                 /* Increase the size of the buffer.  */
   185                 free (malloced);
   186                 if (alloc > alloc_max / 2)
   187                   {
   188                     errno = ENOMEM;
   189                     return -1;
   190                   }
   191                 alloc = 2 * alloc; /* <= alloc_max */
   192                 entries = malloced =
   193                   (aclent_t *) malloc (alloc * sizeof (aclent_t));
   194                 if (entries == NULL)
   195                   {
   196                     errno = ENOMEM;
   197                     return -1;
   198                   }
   199                 continue;
   200               }
   201             break;
   202           }
   203         if (count < 0)
   204           {
   205             if (errno == ENOSYS || errno == ENOTSUP)
   206               ;
   207             else
   208               {
   209                 free (malloced);
   210                 return -1;
   211               }
   212           }
   213         else if (count == 0)
   214           ;
   215         else
   216           {
   217             /* Don't use MIN_ACL_ENTRIES:  It's set to 4 on Cygwin, but Cygwin
   218                returns only 3 entries for files with no ACL.  But this is safe:
   219                If there are more than 4 entries, there cannot be only the
   220                "user::", "group::", "other:", and "mask:" entries.  */
   221             if (count > 4)
   222               {
   223                 free (malloced);
   224                 return 1;
   225               }
   226 
   227             if (acl_nontrivial (count, entries))
   228               {
   229                 free (malloced);
   230                 return 1;
   231               }
   232           }
   233         free (malloced);
   234       }
   235 
   236 #   ifdef ACE_GETACL
   237       /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
   238          file systems (whereas the other ones are used in UFS file systems).  */
   239       {
   240         /* Initially, try to read the entries into a stack-allocated buffer.
   241            Use malloc if it does not fit.  */
   242         enum
   243           {
   244             alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
   245             alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
   246           };
   247         ace_t buf[alloc_init];
   248         size_t alloc = alloc_init;
   249         ace_t *entries = buf;
   250         ace_t *malloced = NULL;
   251         int count;
   252 
   253         for (;;)
   254           {
   255             count = acl (name, ACE_GETACL, alloc, entries);
   256             if (count < 0 && errno == ENOSPC)
   257               {
   258                 /* Increase the size of the buffer.  */
   259                 free (malloced);
   260                 if (alloc > alloc_max / 2)
   261                   {
   262                     errno = ENOMEM;
   263                     return -1;
   264                   }
   265                 alloc = 2 * alloc; /* <= alloc_max */
   266                 entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
   267                 if (entries == NULL)
   268                   {
   269                     errno = ENOMEM;
   270                     return -1;
   271                   }
   272                 continue;
   273               }
   274             break;
   275           }
   276         if (count < 0)
   277           {
   278             if (errno == ENOSYS || errno == EINVAL)
   279               ;
   280             else
   281               {
   282                 free (malloced);
   283                 return -1;
   284               }
   285           }
   286         else if (count == 0)
   287           ;
   288         else
   289           {
   290             /* In the old (original Solaris 10) convention:
   291                If there are more than 3 entries, there cannot be only the
   292                ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
   293                In the newer Solaris 10 and Solaris 11 convention:
   294                If there are more than 6 entries, there cannot be only the
   295                ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
   296                NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
   297                NEW_ACE_ACCESS_DENIED_ACE_TYPE.  */
   298             if (count > 6)
   299               {
   300                 free (malloced);
   301                 return 1;
   302               }
   303 
   304             if (acl_ace_nontrivial (count, entries))
   305               {
   306                 free (malloced);
   307                 return 1;
   308               }
   309           }
   310         free (malloced);
   311       }
   312 #   endif
   313 
   314       return 0;
   315 #  endif
   316 
   317 # elif HAVE_GETACL /* HP-UX */
   318 
   319       {
   320         struct acl_entry entries[NACLENTRIES];
   321         int count;
   322 
   323         count = getacl (name, NACLENTRIES, entries);
   324 
   325         if (count < 0)
   326           {
   327             /* ENOSYS is seen on newer HP-UX versions.
   328                EOPNOTSUPP is typically seen on NFS mounts.
   329                ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
   330             if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
   331               ;
   332             else
   333               return -1;
   334           }
   335         else if (count == 0)
   336           return 0;
   337         else /* count > 0 */
   338           {
   339             if (count > NACLENTRIES)
   340               /* If NACLENTRIES cannot be trusted, use dynamic memory
   341                  allocation.  */
   342               abort ();
   343 
   344             /* If there are more than 3 entries, there cannot be only the
   345                (uid,%), (%,gid), (%,%) entries.  */
   346             if (count > 3)
   347               return 1;
   348 
   349             {
   350               struct stat statbuf;
   351 
   352               if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
   353                 return -1;
   354 
   355               return acl_nontrivial (count, entries);
   356             }
   357           }
   358       }
   359 
   360 #  if HAVE_ACLV_H /* HP-UX >= 11.11 */
   361 
   362       {
   363         struct acl entries[NACLVENTRIES];
   364         int count;
   365 
   366         count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
   367 
   368         if (count < 0)
   369           {
   370             /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
   371                EINVAL is seen on NFS in HP-UX 11.31.  */
   372             if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
   373               ;
   374             else
   375               return -1;
   376           }
   377         else if (count == 0)
   378           return 0;
   379         else /* count > 0 */
   380           {
   381             if (count > NACLVENTRIES)
   382               /* If NACLVENTRIES cannot be trusted, use dynamic memory
   383                  allocation.  */
   384               abort ();
   385 
   386             /* If there are more than 4 entries, there cannot be only the
   387                four base ACL entries.  */
   388             if (count > 4)
   389               return 1;
   390 
   391             return aclv_nontrivial (count, entries);
   392           }
   393       }
   394 
   395 #  endif
   396 
   397 # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
   398 
   399       acl_type_t type;
   400       char aclbuf[1024];
   401       void *acl = aclbuf;
   402       size_t aclsize = sizeof (aclbuf);
   403       mode_t mode;
   404 
   405       for (;;)
   406         {
   407           /* The docs say that type being 0 is equivalent to ACL_ANY, but it
   408              is not true, in AIX 5.3.  */
   409           type.u64 = ACL_ANY;
   410           if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
   411             break;
   412           if (errno == ENOSYS)
   413             return 0;
   414           if (errno != ENOSPC)
   415             {
   416               if (acl != aclbuf)
   417                 free (acl);
   418               return -1;
   419             }
   420           aclsize = 2 * aclsize;
   421           if (acl != aclbuf)
   422             free (acl);
   423           acl = malloc (aclsize);
   424           if (acl == NULL)
   425             {
   426               errno = ENOMEM;
   427               return -1;
   428             }
   429         }
   430 
   431       if (type.u64 == ACL_AIXC)
   432         {
   433           int result = acl_nontrivial ((struct acl *) acl);
   434           if (acl != aclbuf)
   435             free (acl);
   436           return result;
   437         }
   438       else if (type.u64 == ACL_NFS4)
   439         {
   440           int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
   441           if (acl != aclbuf)
   442             free (acl);
   443           return result;
   444         }
   445       else
   446         {
   447           /* A newer type of ACL has been introduced in the system.
   448              We should better support it.  */
   449           if (acl != aclbuf)
   450             free (acl);
   451           errno = EINVAL;
   452           return -1;
   453         }
   454 
   455 # elif HAVE_STATACL /* older AIX */
   456 
   457       union { struct acl a; char room[4096]; } u;
   458 
   459       if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
   460         return -1;
   461 
   462       return acl_nontrivial (&u.a);
   463 
   464 # elif HAVE_ACLSORT /* NonStop Kernel */
   465 
   466       {
   467         struct acl entries[NACLENTRIES];
   468         int count;
   469 
   470         count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
   471 
   472         if (count < 0)
   473           {
   474             if (errno == ENOSYS || errno == ENOTSUP)
   475               ;
   476             else
   477               return -1;
   478           }
   479         else if (count == 0)
   480           return 0;
   481         else /* count > 0 */
   482           {
   483             if (count > NACLENTRIES)
   484               /* If NACLENTRIES cannot be trusted, use dynamic memory
   485                  allocation.  */
   486               abort ();
   487 
   488             /* If there are more than 4 entries, there cannot be only the
   489                four base ACL entries.  */
   490             if (count > 4)
   491               return 1;
   492 
   493             return acl_nontrivial (count, entries);
   494           }
   495       }
   496 
   497 # endif
   498     }
   499 #endif
   500 
   501   return 0;
   502 }

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