root/maint/gnulib/lib/file-has-acl.c

/* [previous][next][first][last][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-2021 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 }

/* [previous][next][first][last][top][bottom][index][help] */