Example #1
0
File: uacl.c Project: nshrine/jfacl
int _acl(const char* pathp, int op, int size, aclent_t* aclpbuf)
{
	if (op == GETACL) {
		return getacl(pathp, aclpbuf);
	} else if (op == SETACL) {
		return setacl(pathp, size, aclpbuf);
	}
}
Example #2
0
int
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
           int dest_desc, mode_t mode)
{
#if USE_ACL && HAVE_ACL_GET_FILE
  /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
  /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
# if !HAVE_ACL_TYPE_EXTENDED
  /* Linux, FreeBSD, IRIX, Tru64 */

  acl_t acl;
  int ret;

  if (HAVE_ACL_GET_FD && source_desc != -1)
    acl = acl_get_fd (source_desc);
  else
    acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
  if (acl == NULL)
    {
      if (! acl_errno_valid (errno))
        return qset_acl (dst_name, dest_desc, mode);
      else
        return -2;
    }

  if (HAVE_ACL_SET_FD && dest_desc != -1)
    ret = acl_set_fd (dest_desc, acl);
  else
    ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
  if (ret != 0)
    {
      int saved_errno = errno;

      if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl))
        {
          acl_free (acl);
          return chmod_or_fchmod (dst_name, dest_desc, mode);
        }
      else
        {
          acl_free (acl);
          chmod_or_fchmod (dst_name, dest_desc, mode);
          errno = saved_errno;
          return -1;
        }
    }
  else
    acl_free (acl);

  if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
    {
      /* We did not call chmod so far, and either the mode and the ACL are
         separate or special bits are to be set which don't fit into ACLs.  */

      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
        return -1;
    }

  if (S_ISDIR (mode))
    {
      acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
      if (acl == NULL)
        return -2;

      if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
        {
          int saved_errno = errno;

          acl_free (acl);
          errno = saved_errno;
          return -1;
        }
      else
        acl_free (acl);
    }
  return 0;

# else /* HAVE_ACL_TYPE_EXTENDED */
  /* Mac OS X */

  /* On Mac OS X,  acl_get_file (name, ACL_TYPE_ACCESS)
     and           acl_get_file (name, ACL_TYPE_DEFAULT)
     always return NULL / EINVAL.  You have to use
                   acl_get_file (name, ACL_TYPE_EXTENDED)
     or            acl_get_fd (open (name, ...))
     to retrieve an ACL.
     On the other hand,
                   acl_set_file (name, ACL_TYPE_ACCESS, acl)
     and           acl_set_file (name, ACL_TYPE_DEFAULT, acl)
     have the same effect as
                   acl_set_file (name, ACL_TYPE_EXTENDED, acl):
     Each of these calls sets the file's ACL.  */

  acl_t acl;
  int ret;

  if (HAVE_ACL_GET_FD && source_desc != -1)
    acl = acl_get_fd (source_desc);
  else
    acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
  if (acl == NULL)
    {
      if (!acl_errno_valid (errno))
        return qset_acl (dst_name, dest_desc, mode);
      else
        return -2;
    }

  if (HAVE_ACL_SET_FD && dest_desc != -1)
    ret = acl_set_fd (dest_desc, acl);
  else
    ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
  if (ret != 0)
    {
      int saved_errno = errno;

      if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl))
        {
          acl_free (acl);
          return chmod_or_fchmod (dst_name, dest_desc, mode);
        }
      else
        {
          acl_free (acl);
          chmod_or_fchmod (dst_name, dest_desc, mode);
          errno = saved_errno;
          return -1;
        }
    }
  else
    acl_free (acl);

  /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
  return chmod_or_fchmod (dst_name, dest_desc, mode);

# endif

#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */

  /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
     of Unixware.  The acl() call returns the access and default ACL both
     at once.  */
# ifdef ACE_GETACL
  int ace_count;
  ace_t *ace_entries;
# endif
  int count;
  aclent_t *entries;
  int did_chmod;
  int saved_errno;
  int ret;

# ifdef ACE_GETACL
  /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
     file systems (whereas the other ones are used in UFS file systems).
     There is an API
       pathconf (name, _PC_ACL_ENABLED)
       fpathconf (desc, _PC_ACL_ENABLED)
     that allows to determine which of the two kinds of ACLs is supported
     for the given file.  But some file systems may implement this call
     incorrectly, so better not use it.
     When fetching the source ACL, we simply fetch both ACL types.
     When setting the destination ACL, we try either ACL types, assuming
     that the kernel will translate the ACL from one form to the other.
     (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
     the description of ENOTSUP.)  */
  for (;;)
    {
      ace_count = (source_desc != -1
                   ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
                   : acl (src_name, ACE_GETACLCNT, 0, NULL));

      if (ace_count < 0)
        {
          if (errno == ENOSYS || errno == EINVAL)
            {
              ace_count = 0;
              ace_entries = NULL;
              break;
            }
          else
            return -2;
        }

      if (ace_count == 0)
        {
          ace_entries = NULL;
          break;
        }

      ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
      if (ace_entries == NULL)
        {
          errno = ENOMEM;
          return -2;
        }

      ret = (source_desc != -1
             ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
             : acl (src_name, ACE_GETACL, ace_count, ace_entries));
      if (ret < 0)
        {
          free (ace_entries);
          if (errno == ENOSYS || errno == EINVAL)
            {
              ace_count = 0;
              ace_entries = NULL;
              break;
            }
          else
            return -2;
        }
      if (ret == ace_count)
        break;
      /* Huh? The number of ACL entries changed since the last call.
         Repeat.  */
    }
# endif

  for (;;)
    {
      count = (source_desc != -1
               ? facl (source_desc, GETACLCNT, 0, NULL)
               : acl (src_name, GETACLCNT, 0, NULL));

      if (count < 0)
        {
          if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
            {
              count = 0;
              entries = NULL;
              break;
            }
          else
            return -2;
        }

      if (count == 0)
        {
          entries = NULL;
          break;
        }

      entries = (aclent_t *) malloc (count * sizeof (aclent_t));
      if (entries == NULL)
        {
          errno = ENOMEM;
          return -2;
        }

      if ((source_desc != -1
           ? facl (source_desc, GETACL, count, entries)
           : acl (src_name, GETACL, count, entries))
          == count)
        break;
      /* Huh? The number of ACL entries changed since the last call.
         Repeat.  */
    }

  /* Is there an ACL of either kind?  */
# ifdef ACE_GETACL
  if (ace_count == 0)
# endif
    if (count == 0)
      return qset_acl (dst_name, dest_desc, mode);

  did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
  saved_errno = 0; /* the first non-ignorable error code */

  if (!MODE_INSIDE_ACL)
    {
      /* On Cygwin, it is necessary to call chmod before acl, because
         chmod can change the contents of the ACL (in ways that don't
         change the allowed accesses, but still visible).  */
      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
        saved_errno = errno;
      did_chmod = 1;
    }

  /* If both ace_entries and entries are available, try SETACL before
     ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
     can.  */

  if (count > 0)
    {
      ret = (dest_desc != -1
             ? facl (dest_desc, SETACL, count, entries)
             : acl (dst_name, SETACL, count, entries));
      if (ret < 0 && saved_errno == 0)
        {
          saved_errno = errno;
          if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
              && !acl_nontrivial (count, entries))
            saved_errno = 0;
        }
      else
        did_chmod = 1;
    }
  free (entries);

# ifdef ACE_GETACL
  if (ace_count > 0)
    {
      ret = (dest_desc != -1
             ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
             : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
      if (ret < 0 && saved_errno == 0)
        {
          saved_errno = errno;
          if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
              && !acl_ace_nontrivial (ace_count, ace_entries))
            saved_errno = 0;
        }
    }
  free (ace_entries);
# endif

  if (MODE_INSIDE_ACL
      && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
    {
      /* We did not call chmod so far, and either the mode and the ACL are
         separate or special bits are to be set which don't fit into ACLs.  */

      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
        {
          if (saved_errno == 0)
            saved_errno = errno;
        }
    }

  if (saved_errno)
    {
      errno = saved_errno;
      return -1;
    }
  return 0;

#elif USE_ACL && HAVE_GETACL /* HP-UX */

  struct acl_entry entries[NACLENTRIES];
  int count;
# if HAVE_ACLV_H
  struct acl aclv_entries[NACLVENTRIES];
  int aclv_count;
# endif
  int did_chmod;
  int saved_errno;
  int ret;

  count = (source_desc != -1
           ? fgetacl (source_desc, NACLENTRIES, entries)
           : getacl (src_name, NACLENTRIES, entries));

  if (count < 0)
    {
      if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
        count = 0;
      else
        return -2;
    }
  else if (count > 0)
    {
      if (count > NACLENTRIES)
        /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
        abort ();
    }

# if HAVE_ACLV_H
  aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);

  if (aclv_count < 0)
    {
      if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
        count = 0;
      else
        return -2;
    }
  else if (aclv_count > 0)
    {
      if (aclv_count > NACLVENTRIES)
        /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation.  */
        abort ();
    }
# endif

  if (count == 0)
# if HAVE_ACLV_H
    if (aclv_count == 0)
# endif
      return qset_acl (dst_name, dest_desc, mode);

  did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
  saved_errno = 0; /* the first non-ignorable error code */

  if (count > 0)
    {
      ret = (dest_desc != -1
             ? fsetacl (dest_desc, count, entries)
             : setacl (dst_name, count, entries));
      if (ret < 0 && saved_errno == 0)
        {
          saved_errno = errno;
          if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
            {
              struct stat source_statbuf;

              if ((source_desc != -1
                   ? fstat (source_desc, &source_statbuf)
                   : stat (src_name, &source_statbuf)) == 0)
                {
                  if (!acl_nontrivial (count, entries, &source_statbuf))
                    saved_errno = 0;
                }
              else
                saved_errno = errno;
            }
        }
      else
        did_chmod = 1;
    }

# if HAVE_ACLV_H
  if (aclv_count > 0)
    {
      ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
      if (ret < 0 && saved_errno == 0)
        {
          saved_errno = errno;
          if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
            {
              if (!aclv_nontrivial (aclv_count, aclv_entries))
                saved_errno = 0;
            }
        }
      else
        did_chmod = 1;
    }
# endif

  if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
    {
      /* We did not call chmod so far, and special bits are to be set which
         don't fit into ACLs.  */

      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
        {
          if (saved_errno == 0)
            saved_errno = errno;
        }
    }

  if (saved_errno)
    {
      errno = saved_errno;
      return -1;
    }
  return 0;

#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */

  /* TODO */

#elif USE_ACL && HAVE_STATACL /* older AIX */

  union { struct acl a; char room[4096]; } u;
  int ret;

  if ((source_desc != -1
       ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
       : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
      < 0)
    return -2;

  ret = (dest_desc != -1
         ? fchacl (dest_desc, &u.a, u.a.acl_len)
         : chacl (dst_name, &u.a, u.a.acl_len));
  if (ret < 0)
    {
      int saved_errno = errno;

      chmod_or_fchmod (dst_name, dest_desc, mode);
      errno = saved_errno;
      return -1;
    }

  /* No need to call chmod_or_fchmod at this point, since the mode bits
     S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL.  */

  return 0;

#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */

  struct acl entries[NACLENTRIES];
  int count;
  int ret;

  count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);

  if (count < 0)
    {
      if (0)
        count = 0;
      else
        return -2;
    }
  else if (count > 0)
    {
      if (count > NACLENTRIES)
        /* If NACLENTRIES cannot be trusted, use dynamic memory allocation.  */
        abort ();
    }

  if (count == 0)
    return qset_acl (dst_name, dest_desc, mode);

  ret = acl ((char *) dst_name, ACL_SET, count, entries);
  if (ret < 0)
    {
      int saved_errno = errno;

      if (0)
        {
          if (!acl_nontrivial (count, entries))
            return chmod_or_fchmod (dst_name, dest_desc, mode);
        }

      chmod_or_fchmod (dst_name, dest_desc, mode);
      errno = saved_errno;
      return -1;
    }

  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
    {
      /* We did not call chmod so far, and either the mode and the ACL are
         separate or special bits are to be set which don't fit into ACLs.  */

      return chmod_or_fchmod (dst_name, dest_desc, mode);
    }
  return 0;

#else

  return qset_acl (dst_name, dest_desc, mode);

#endif
}
Example #3
0
int
main (int argc, char *argv[])
{
  const char *file1;
  const char *file2;

  set_program_name (argv[0]);

  ASSERT (argc == 3);

  file1 = argv[1];
  file2 = argv[2];

  /* Compare the contents of the two files.  */
  {
    size_t size1;
    char *contents1;
    size_t size2;
    char *contents2;

    contents1 = read_file (file1, &size1);
    if (contents1 == NULL)
      {
        fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
        fflush (stderr);
        abort ();
      }
    contents2 = read_file (file2, &size2);
    if (contents2 == NULL)
      {
        fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
        fflush (stderr);
        abort ();
      }

    if (size2 != size1)
      {
        fprintf (stderr, "files %s and %s have different sizes\n",
                 file1, file2);
        fflush (stderr);
        abort ();
      }
    if (memcmp (contents1, contents2, size1) != 0)
      {
        fprintf (stderr, "files %s and %s have different contents\n",
                 file1, file2);
        fflush (stderr);
        abort ();
      }
  }

  /* Compare the access permissions of the two files, including ACLs.  */
  {
    struct stat statbuf1;
    struct stat statbuf2;

    if (stat (file1, &statbuf1) < 0)
      {
        fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
        fflush (stderr);
        abort ();
      }
    if (stat (file2, &statbuf2) < 0)
      {
        fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
        fflush (stderr);
        abort ();
      }
    if (statbuf1.st_mode != statbuf2.st_mode)
      {
        fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
                 file1, file2,
                (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
        return 1;
      }
  }
  {
#if HAVE_ACL_GET_FILE /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
    static const int types[] =
      {
        ACL_TYPE_ACCESS
# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
        , ACL_TYPE_EXTENDED
# endif
      };
    int t;

    for (t = 0; t < sizeof (types) / sizeof (types[0]); t++)
      {
        int type = types[t];
        acl_t acl1;
        char *text1;
        int errno1;
        acl_t acl2;
        char *text2;
        int errno2;

        acl1 = acl_get_file (file1, type);
        if (acl1 == (acl_t)NULL)
          {
            text1 = NULL;
            errno1 = errno;
          }
        else
          {
            text1 = acl_to_text (acl1, NULL);
            if (text1 == NULL)
              errno1 = errno;
            else
              errno1 = 0;
          }
        acl2 = acl_get_file (file2, type);
        if (acl2 == (acl_t)NULL)
          {
            text2 = NULL;
            errno2 = errno;
          }
        else
          {
            text2 = acl_to_text (acl2, NULL);
            if (text2 == NULL)
              errno2 = errno;
            else
              errno2 = 0;
          }

        if (acl1 != (acl_t)NULL)
          {
            if (acl2 != (acl_t)NULL)
              {
                if (text1 != NULL)
                  {
                    if (text2 != NULL)
                      {
                        if (strcmp (text1, text2) != 0)
                          {
                            fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
                                     file1, file2, text1, text2);
                            return 1;
                          }
                      }
                    else
                      {
                        fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
                                 file1, file2);
                        return 1;
                      }
                  }
                else
                  {
                    if (text2 != NULL)
                      {
                        fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
                                 file1, file2);
                        return 1;
                      }
                    else
                      {
                        if (errno1 != errno2)
                          {
                            fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
                                     file1, file2, errno1, errno2);
                            return 1;
                          }
                      }
                  }
              }
            else
              {
                fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
                         file1, file2);
                return 1;
              }
          }
        else
          {
            if (acl2 != (acl_t)NULL)
              {
                fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
                         file1, file2);
                return 1;
              }
          }
      }
#elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
  int count1;
  int count2;

  count1 = acl (file1, GETACLCNT, 0, NULL);
  if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
    count1 = 0;
  count2 = acl (file2, GETACLCNT, 0, NULL);
  if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */
    count2 = 0;

  if (count1 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (count2 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }
  if (count1 != count2)
    {
      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
               file1, file2, count1, count2);
      return 1;
    }
  else
    {
      aclent_t *entries1 = XNMALLOC (count1, aclent_t);
      aclent_t *entries2 = XNMALLOC (count2, aclent_t);
      int i;

      if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
      if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
      for (i = 0; i < count1; i++)
        {
          if (entries1[i].a_type != entries2[i].a_type)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
                       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
              return 1;
            }
          if (entries1[i].a_id != entries2[i].a_id)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
                       file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
              return 1;
            }
          if (entries1[i].a_perm != entries2[i].a_perm)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
                       file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
              return 1;
            }
        }
    }
# ifdef ACE_GETACL
  count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
  if (count1 < 0 && errno == EINVAL)
    count1 = 0;
  count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
  if (count2 < 0 && errno == EINVAL)
    count2 = 0;
  if (count1 < 0)
    {
      fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (count2 < 0)
    {
      fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }
  if (count1 != count2)
    {
      fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
               file1, file2, count1, count2);
      return 1;
    }
  else if (count1 > 0)
    {
      ace_t *entries1 = XNMALLOC (count1, ace_t);
      ace_t *entries2 = XNMALLOC (count2, ace_t);
      int i;

      if (acl (file1, ACE_GETACL, count1, entries1) < count1)
        {
          fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
      if (acl (file2, ACE_GETACL, count2, entries2) < count1)
        {
          fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
      for (i = 0; i < count1; i++)
        {
          if (entries1[i].a_type != entries2[i].a_type)
            {
              fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
                       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
              return 1;
            }
          if (entries1[i].a_who != entries2[i].a_who)
            {
              fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
                       file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
              return 1;
            }
          if (entries1[i].a_access_mask != entries2[i].a_access_mask)
            {
              fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
                       file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
              return 1;
            }
          if (entries1[i].a_flags != entries2[i].a_flags)
            {
              fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
                       file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
              return 1;
            }
        }
    }
# endif
#elif HAVE_GETACL /* HP-UX */
  int count1;
  int count2;

  count1 = getacl (file1, 0, NULL);
  if (count1 < 0
      && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
    count1 = 0;
  count2 = getacl (file2, 0, NULL);
  if (count2 < 0
      && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
    count2 = 0;

  if (count1 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (count2 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }
  if (count1 != count2)
    {
      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
               file1, file2, count1, count2);
      return 1;
    }
  else if (count1 > 0)
    {
      struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
      struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
      int i;

      if (getacl (file1, count1, entries1) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
      if (getacl (file2, count2, entries2) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
      for (i = 0; i < count1; i++)
        {
          if (entries1[i].uid != entries2[i].uid)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
                       file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
              return 1;
            }
          if (entries1[i].gid != entries2[i].gid)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
                       file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
              return 1;
            }
          if (entries1[i].mode != entries2[i].mode)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
                       file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
              return 1;
            }
        }
    }

# if HAVE_ACLV_H /* HP-UX >= 11.11 */
  {
    struct acl dummy_entries[NACLVENTRIES];

    count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries);
    if (count1 < 0
        && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
      count1 = 0;
    count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries);
    if (count2 < 0
        && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL))
      count2 = 0;
  }

  if (count1 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (count2 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }
  if (count1 != count2)
    {
      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
               file1, file2, count1, count2);
      return 1;
    }
  else if (count1 > 0)
    {
      struct acl *entries1 = XNMALLOC (count1, struct acl);
      struct acl *entries2 = XNMALLOC (count2, struct acl);
      int i;

      if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
      if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
      for (i = 0; i < count1; i++)
        {
          if (entries1[i].a_type != entries2[i].a_type)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
                       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
              return 1;
            }
          if (entries1[i].a_id != entries2[i].a_id)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
                       file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
              return 1;
            }
          if (entries1[i].a_perm != entries2[i].a_perm)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
                       file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
              return 1;
            }
        }
    }
# endif
#elif HAVE_ACLX_GET /* AIX */
  acl_type_t type1;
  char acl1[1000];
  size_t aclsize1 = sizeof (acl1);
  mode_t mode1;
  char text1[1000];
  size_t textsize1 = sizeof (text1);
  acl_type_t type2;
  char acl2[1000];
  size_t aclsize2 = sizeof (acl2);
  mode_t mode2;
  char text2[1000];
  size_t textsize2 = sizeof (text2);

  /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not
     true, in AIX 5.3.  */
  type1.u64 = ACL_ANY;
  if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
    {
      if (errno == ENOSYS)
        text1[0] = '\0';
      else
        {
          fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
    }
  else
    if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0)
      {
        fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
        fflush (stderr);
        abort ();
      }

  /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not
     true, in AIX 5.3.  */
  type2.u64 = ACL_ANY;
  if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
    {
      if (errno == ENOSYS)
        text2[0] = '\0';
      else
        {
          fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
    }
  else
    if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0)
      {
        fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
        fflush (stderr);
        abort ();
      }

  if (strcmp (text1, text2) != 0)
    {
      fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
               file1, file2, text1, text2);
      return 1;
    }
#elif HAVE_STATACL /* older AIX */
  union { struct acl a; char room[4096]; } acl1;
  union { struct acl a; char room[4096]; } acl2;
  unsigned int i;

  if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }

  if (acl1.a.acl_len != acl2.a.acl_len)
    {
      fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
               file1, file2, acl1.a.acl_len, acl2.a.acl_len);
      return 1;
    }
  if (acl1.a.acl_mode != acl2.a.acl_mode)
    {
      fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
               file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
      return 1;
    }
  if (acl1.a.u_access != acl2.a.u_access
      || acl1.a.g_access != acl2.a.g_access
      || acl1.a.o_access != acl2.a.o_access)
    {
      fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
               file1, file2,
               acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
               acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
      return 1;
    }
  if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
    {
      fprintf (stderr, "files %s and %s have different ACL entries\n",
               file1, file2);
      return 1;
    }
#elif HAVE_ACLSORT /* NonStop Kernel */
  int count1;
  int count2;

  count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL);
  count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL);

  if (count1 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
      fflush (stderr);
      abort ();
    }
  if (count2 < 0)
    {
      fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
      fflush (stderr);
      abort ();
    }
  if (count1 != count2)
    {
      fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
               file1, file2, count1, count2);
      return 1;
    }
  else if (count1 > 0)
    {
      struct acl *entries1 = XNMALLOC (count1, struct acl);
      struct acl *entries2 = XNMALLOC (count2, struct acl);
      int i;

      if (acl ((char *) file1, ACL_GET, count1, entries1) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
          fflush (stderr);
          abort ();
        }
      if (acl ((char *) file2, ACL_GET, count2, entries2) < count1)
        {
          fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
          fflush (stderr);
          abort ();
        }
      for (i = 0; i < count1; i++)
        {
          if (entries1[i].a_type != entries2[i].a_type)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
                       file1, file2, i, entries1[i].a_type, entries2[i].a_type);
              return 1;
            }
          if (entries1[i].a_id != entries2[i].a_id)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
                       file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
              return 1;
            }
          if (entries1[i].a_perm != entries2[i].a_perm)
            {
              fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
                       file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
              return 1;
            }
        }
    }
#endif
  }

  return 0;
}
Example #4
0
static CLIENT *access_check (int rc, struct sockaddr_in ssin)
{
	struct stat _stat;
	ulong ipaddr;
	ACL *acl;
	CLIENT *retval;
	int curconcur;

	if (master->connections > cfg.MaxConnections) {
		write (rc, MSG_SERVERFULL, strlen (MSG_SERVERFULL));
		info ("Too many global connections, increase cfg.MaxConnections");
		return NULL;
	}

	if (stat (cfg.DisableFile, &_stat) == 0) {
		write (rc, cfg.DisableText, strlen (cfg.DisableText));
		write (rc, "\r\n", 2);
		return NULL;
	}

	errno = 0;

	ipaddr = ntohl (ssin.sin_addr.s_addr);

	if ( cfg.JSONACL ) {
		if ( (acl = gethttpacl(inet_ntoa(ssin.sin_addr), curl)) == NULL )
		{
			syslog(LOG_ERR, "Cant get JSON ACL.");
			write(rc, MSG_NOACL, strlen(MSG_NOACL));
			return NULL;
		}
	} else {
		if ( (acl = getacl(ipaddr)) == NULL )
		{
			syslog(LOG_ERR, "Cant get default ACL, define \"acl 0/0\" in access.conf");
			write(rc, MSG_NOACL, strlen(MSG_NOACL));
			return NULL;
		}
	}

	if ( ! nullstr(acl->profile->Disabled) )
	{
		write(rc, "400 ", 4);
		write(rc, acl->profile->Disabled, strlen(acl->profile->Disabled));
		return NULL;
	}

	if (acl->deny) {
		write(rc, MSG_NOPERM, strlen(MSG_NOPERM));
		info("denied connection from %s", inet_ntoa(ssin.sin_addr));
		return NULL;
	}

	if (acl->profile->connections > acl->profile->MaxConnections) {
		write(rc, MSG_TOOMANYCONNSPRF, strlen(MSG_TOOMANYCONNSPRF));
		return NULL;
	}

	semlock_lock (master->semid);
	retval = find_slot (ipaddr, &curconcur, acl->unlimit ? 0 : acl->profile->MaxHostConcurrent);
	semlock_unlock (master->semid);

	if (retval == NULL) {
		char buf[128];
		sprintf (buf, MSG_TOOMANY_CONCURRENT, acl->profile->MaxHostConcurrent);
		write (rc, buf, strlen (buf));
		syslog(LOG_DEBUG, "Too many concurrent connections from %s"
				, inet_ntoa (ssin.sin_addr));
		return NULL;
	}

	retval->acl = acl;
	memcpy (&retval->addr, &ssin, sizeof (ssin));
	retval->socket = rc;

	return retval;
}
Example #5
0
int
file_has_acl (char const *name, struct stat const *sb)
{
#if USE_ACL
  if (! S_ISLNK (sb->st_mode))
    {
# if HAVE_ACL_GET_FILE

      /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
      /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
      int ret;

      if (HAVE_ACL_EXTENDED_FILE) /* Linux */
        {
          /* On Linux, acl_extended_file is an optimized function: It only
             makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
             ACL_TYPE_DEFAULT.  */
          ret = acl_extended_file (name);
        }
      else /* FreeBSD, MacOS X, IRIX, Tru64 */
        {
#  if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
          /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
             and acl_get_file (name, ACL_TYPE_DEFAULT)
             always return NULL / EINVAL.  There is no point in making
             these two useless calls.  The real ACL is retrieved through
             acl_get_file (name, ACL_TYPE_EXTENDED).  */
          acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
          if (acl)
            {
              ret = acl_extended_nontrivial (acl);
              acl_free (acl);
            }
          else
            ret = -1;
#  else /* FreeBSD, IRIX, Tru64 */
          acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
          if (acl)
            {
              int saved_errno;

              ret = acl_access_nontrivial (acl);
              saved_errno = errno;
              acl_free (acl);
              errno = saved_errno;
#   if HAVE_ACL_FREE_TEXT /* Tru64 */
              /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
                 returns NULL with errno not set.  There is no point in
                 making this call.  */
#   else /* FreeBSD, IRIX */
              /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
                 and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
                 either both succeed or both fail; it depends on the
                 file system.  Therefore there is no point in making the second
                 call if the first one already failed.  */
              if (ret == 0 && S_ISDIR (sb->st_mode))
                {
                  acl = acl_get_file (name, ACL_TYPE_DEFAULT);
                  if (acl)
                    {
                      ret = (0 < acl_entries (acl));
                      acl_free (acl);
                    }
                  else
                    ret = -1;
                }
#   endif
            }
          else
            ret = -1;
#  endif
        }
      if (ret < 0)
        return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
      return ret;

# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */

#  if defined ACL_NO_TRIVIAL

      /* Solaris 10 (newer version), which has additional API declared in
         <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
         acl_fromtext, ...).  */
      return acl_trivial (name);

#  else /* Solaris, Cygwin, general case */

      /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
         of Unixware.  The acl() call returns the access and default ACL both
         at once.  */
      int count;
      {
        aclent_t *entries;

        for (;;)
          {
            count = acl (name, GETACLCNT, 0, NULL);

            if (count < 0)
              {
                if (errno == ENOSYS || errno == ENOTSUP)
                  break;
                else
                  return -1;
              }

            if (count == 0)
              break;

            /* Don't use MIN_ACL_ENTRIES:  It's set to 4 on Cygwin, but Cygwin
               returns only 3 entries for files with no ACL.  But this is safe:
               If there are more than 4 entries, there cannot be only the
               "user::", "group::", "other:", and "mask:" entries.  */
            if (count > 4)
              return 1;

            entries = (aclent_t *) malloc (count * sizeof (aclent_t));
            if (entries == NULL)
              {
                errno = ENOMEM;
                return -1;
              }
            if (acl (name, GETACL, count, entries) == count)
              {
                if (acl_nontrivial (count, entries))
                  {
                    free (entries);
                    return 1;
                  }
                free (entries);
                break;
              }
            /* Huh? The number of ACL entries changed since the last call.
               Repeat.  */
            free (entries);
          }
      }

#   ifdef ACE_GETACL
      /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
         file systems (whereas the other ones are used in UFS file systems).  */
      {
        ace_t *entries;

        for (;;)
          {
            count = acl (name, ACE_GETACLCNT, 0, NULL);

            if (count < 0)
              {
                if (errno == ENOSYS || errno == EINVAL)
                  break;
                else
                  return -1;
              }

            if (count == 0)
              break;

            /* In the old (original Solaris 10) convention:
               If there are more than 3 entries, there cannot be only the
               ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
               In the newer Solaris 10 and Solaris 11 convention:
               If there are more than 6 entries, there cannot be only the
               ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
               NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
               NEW_ACE_ACCESS_DENIED_ACE_TYPE.  */
            if (count > 6)
              return 1;

            entries = (ace_t *) malloc (count * sizeof (ace_t));
            if (entries == NULL)
              {
                errno = ENOMEM;
                return -1;
              }
            if (acl (name, ACE_GETACL, count, entries) == count)
              {
                if (acl_ace_nontrivial (count, entries))
                  {
                    free (entries);
                    return 1;
                  }
                free (entries);
                break;
              }
            /* Huh? The number of ACL entries changed since the last call.
               Repeat.  */
            free (entries);
          }
      }
#   endif

      return 0;
#  endif

# elif HAVE_GETACL /* HP-UX */

      for (;;)
        {
          int count;
          struct acl_entry entries[NACLENTRIES];

          count = getacl (name, 0, NULL);

          if (count < 0)
            {
              /* ENOSYS is seen on newer HP-UX versions.
                 EOPNOTSUPP is typically seen on NFS mounts.
                 ENOTSUP was seen on Quantum StorNext file systems (cvfs).  */
              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
                break;
              else
                return -1;
            }

          if (count == 0)
            return 0;

          if (count > NACLENTRIES)
            /* If NACLENTRIES cannot be trusted, use dynamic memory
               allocation.  */
            abort ();

          /* If there are more than 3 entries, there cannot be only the
             (uid,%), (%,gid), (%,%) entries.  */
          if (count > 3)
            return 1;

          if (getacl (name, count, entries) == count)
            {
              struct stat statbuf;

              if (stat (name, &statbuf) < 0)
                return -1;

              return acl_nontrivial (count, entries, &statbuf);
            }
          /* Huh? The number of ACL entries changed since the last call.
             Repeat.  */
        }

#  if HAVE_ACLV_H /* HP-UX >= 11.11 */

      for (;;)
        {
          int count;
          struct acl entries[NACLVENTRIES];

          count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries);

          if (count < 0)
            {
              /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
                 EINVAL is seen on NFS in HP-UX 11.31.  */
              if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
                break;
              else
                return -1;
            }

          if (count == 0)
            return 0;

          if (count > NACLVENTRIES)
            /* If NACLVENTRIES cannot be trusted, use dynamic memory
               allocation.  */
            abort ();

          /* If there are more than 4 entries, there cannot be only the
             four base ACL entries.  */
          if (count > 4)
            return 1;

          if (acl ((char *) name, ACL_GET, count, entries) == count)
            return aclv_nontrivial (count, entries);
          /* Huh? The number of ACL entries changed since the last call.
             Repeat.  */
        }

#  endif

# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */

      acl_type_t type;
      char aclbuf[1024];
      void *acl = aclbuf;
      size_t aclsize = sizeof (aclbuf);
      mode_t mode;

      for (;;)
        {
          /* The docs say that type being 0 is equivalent to ACL_ANY, but it
             is not true, in AIX 5.3.  */
          type.u64 = ACL_ANY;
          if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
            break;
          if (errno == ENOSYS)
            return 0;
          if (errno != ENOSPC)
            {
              if (acl != aclbuf)
                {
                  int saved_errno = errno;
                  free (acl);
                  errno = saved_errno;
                }
              return -1;
            }
          aclsize = 2 * aclsize;
          if (acl != aclbuf)
            free (acl);
          acl = malloc (aclsize);
          if (acl == NULL)
            {
              errno = ENOMEM;
              return -1;
            }
        }

      if (type.u64 == ACL_AIXC)
        {
          int result = acl_nontrivial ((struct acl *) acl);
          if (acl != aclbuf)
            free (acl);
          return result;
        }
      else if (type.u64 == ACL_NFS4)
        {
          int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl);
          if (acl != aclbuf)
            free (acl);
          return result;
        }
      else
        {
          /* A newer type of ACL has been introduced in the system.
             We should better support it.  */
          if (acl != aclbuf)
            free (acl);
          errno = EINVAL;
          return -1;
        }

# elif HAVE_STATACL /* older AIX */

      union { struct acl a; char room[4096]; } u;

      if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
        return -1;

      return acl_nontrivial (&u.a);

# elif HAVE_ACLSORT /* NonStop Kernel */

      int count;
      struct acl entries[NACLENTRIES];

      for (;;)
        {
          count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL);

          if (count < 0)
            {
              if (errno == ENOSYS || errno == ENOTSUP)
                break;
              else
                return -1;
            }

          if (count == 0)
            return 0;

          if (count > NACLENTRIES)
            /* If NACLENTRIES cannot be trusted, use dynamic memory
               allocation.  */
            abort ();

          /* If there are more than 4 entries, there cannot be only the
             four base ACL entries.  */
          if (count > 4)
            return 1;

          if (acl ((char *) name, ACL_GET, count, entries) == count)
            return acl_nontrivial (count, entries);
          /* Huh? The number of ACL entries changed since the last call.
             Repeat.  */
        }

# endif
    }
#endif

  return 0;
}