/* Copy the permissions of src_path to dst_path. This includes the
   file mode permission bits and ACLs. File ownership is not copied.
 */
int
perm_copy_fd (const char *src_path, int src_fd,
	       const char *dst_path, int dst_fd,
	       struct error_context *ctx)
{
#if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
	acl_t acl;
#endif
	struct stat st;
	int ret = 0;

	ret = fstat(src_fd, &st);
	if (ret != 0) {
		const char *qpath = quote (ctx, src_path);
		error (ctx, "%s", qpath);
		quote_free (ctx, qpath);
		return -1;
	}
#if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
	/* POSIX 1003.1e draft 17 (abandoned) specific version.  */
	acl = acl_get_fd (src_fd);
	if (acl == NULL) {
		ret = -1;
		if (errno == ENOSYS || errno == ENOTSUP)
			ret = set_acl_fd (dst_path, dst_fd, st.st_mode, ctx);
		else {
			const char *qpath = quote (ctx, src_path);
			error (ctx, "%s", qpath);
			quote_free (ctx, qpath);
		}
		return ret;
	}

	if (acl_set_fd (dst_fd, acl) != 0) {
		int saved_errno = errno;
		__apply_mask_to_mode(&st.st_mode, acl);
		ret = fchmod (dst_fd, st.st_mode);
		if ((errno != ENOSYS && errno != ENOTSUP) ||
		    acl_entries (acl) != 3) {
			const char *qpath = quote (ctx, dst_path);
			errno = saved_errno;
			error (ctx, _("preserving permissions for %s"), qpath);
			quote_free (ctx, qpath);
			ret = -1;
		}
	}
	(void) acl_free (acl);
	return ret;
#else
	/* POSIX.1 version. */
	ret = fchmod (dst_fd, st.st_mode);
	if (ret != 0) {
		const char *qpath = quote (ctx, dst_path);
		error (ctx, _("setting permissions for %s"), qpath);
		quote_free (ctx, qpath);
	}
	return ret;
#endif
}
示例#2
0
文件: tape.c 项目: Alkzndr/freebsd
/*
 * Set attributes on a file descriptor.
 */
static void
set_extattr_fd(int fd, char *name, void *buf, int size)
{
	struct extattr *eap, *eaend;

	vprintf(stdout, "Set attributes for %s:", name);
	eaend = buf + size;
	for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
		/*
		 * Make sure this entry is complete.
		 */
		if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
			dprintf(stdout, "\n\t%scorrupted",
				eap == buf ? "" : "remainder ");
			break;
		}
		if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
			continue;
		vprintf(stdout, "\n\t%s, (%d bytes), %*s",
			namespace_names[eap->ea_namespace], eap->ea_length,
			eap->ea_namelength, eap->ea_name);
		/*
		 * First we try the general attribute setting interface.
		 * However, some attributes can only be set by root or
		 * by using special interfaces (for example, ACLs).
		 */
		if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name,
		    EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
			dprintf(stdout, " (set using extattr_set_fd)");
			continue;
		}
		/*
		 * If the general interface refuses to set the attribute,
		 * then we try all the specialized interfaces that we
		 * know about.
		 */
		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
		    !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
			if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) {
				dprintf(stdout, " (set using acl_set_fd)");
				continue;
			}
		}
		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
		    !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
			if (acl_set_file(name, ACL_TYPE_DEFAULT,
			    EXTATTR_CONTENT(eap)) != -1) {
				dprintf(stdout, " (set using acl_set_file)");
				continue;
			}
		}
		vprintf(stdout, " (unable to set)");
	}
	vprintf(stdout, "\n");
}
示例#3
0
int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
			    files_struct *fsp,
			    SMB_ACL_T theacl)
{
	int res;
	acl_t acl = smb_acl_to_posix(theacl);
	if (acl == NULL) {
		return -1;
	}
	res =  acl_set_fd(fsp->fh->fd, acl);
	acl_free(acl);
	return res;
}
示例#4
0
static int fix_acl(int fd, uid_t uid) {

#ifdef HAVE_ACL
        _cleanup_(acl_freep) acl_t acl = NULL;
        acl_entry_t entry;
        acl_permset_t permset;

        assert(fd >= 0);

        if (uid <= SYSTEM_UID_MAX)
                return 0;

        /* Make sure normal users can read (but not write or delete)
         * their own coredumps */

        acl = acl_get_fd(fd);
        if (!acl) {
                log_error("Failed to get ACL: %m");
                return -errno;
        }

        if (acl_create_entry(&acl, &entry) < 0 ||
            acl_set_tag_type(entry, ACL_USER) < 0 ||
            acl_set_qualifier(entry, &uid) < 0) {
                log_error("Failed to patch ACL: %m");
                return -errno;
        }

        if (acl_get_permset(entry, &permset) < 0 ||
            acl_add_perm(permset, ACL_READ) < 0 ||
            calc_acl_mask_if_needed(&acl) < 0) {
                log_warning("Failed to patch ACL: %m");
                return -errno;
        }

        if (acl_set_fd(fd, acl) < 0) {
                log_error("Failed to apply ACL: %m");
                return -errno;
        }
#endif

        return 0;
}
示例#5
0
static int fix_acl(int fd, uid_t uid) {

#if HAVE_ACL
        _cleanup_(acl_freep) acl_t acl = NULL;
        acl_entry_t entry;
        acl_permset_t permset;
        int r;

        assert(fd >= 0);

        if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
                return 0;

        /* Make sure normal users can read (but not write or delete)
         * their own coredumps */

        acl = acl_get_fd(fd);
        if (!acl)
                return log_error_errno(errno, "Failed to get ACL: %m");

        if (acl_create_entry(&acl, &entry) < 0 ||
            acl_set_tag_type(entry, ACL_USER) < 0 ||
            acl_set_qualifier(entry, &uid) < 0)
                return log_error_errno(errno, "Failed to patch ACL: %m");

        if (acl_get_permset(entry, &permset) < 0 ||
            acl_add_perm(permset, ACL_READ) < 0)
                return log_warning_errno(errno, "Failed to patch ACL: %m");

        r = calc_acl_mask_if_needed(&acl);
        if (r < 0)
                return log_warning_errno(r, "Failed to patch ACL: %m");

        if (acl_set_fd(fd, acl) < 0)
                return log_error_errno(errno, "Failed to apply ACL: %m");
#endif

        return 0;
}
/* Set the access control list of path to the permissions defined by mode.  */
static int
set_acl_fd (char const *path, int fd, mode_t mode, struct error_context *ctx)
{
	int ret = 0;
#if defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_SET_FD)
	/* POSIX 1003.1e draft 17 (abandoned) specific version.  */
	acl_t acl = acl_from_mode (mode);
	if (!acl) {
		error (ctx, "");
		return -1;
	}

	if (acl_set_fd (fd, acl) != 0) {
		ret = -1;
		if (errno == ENOTSUP || errno == ENOSYS) {
			(void) acl_free (acl);
			goto chmod_only;
		} else {
			const char *qpath = quote (ctx, path);
			error (ctx, _("setting permissions for %s"), qpath);
			quote_free (ctx, qpath);
		}
	}
	(void) acl_free (acl);
	return ret;
#endif

chmod_only:
	ret = fchmod (fd, mode);
	if (ret != 0) {
		const char *qpath = quote (ctx, path);
		error (ctx, _("setting permissions for %s"), qpath);
		quote_free (ctx, qpath);
	}
	return ret;
}
int
qset_acl (char const *name, int desc, mode_t mode)
{
#if USE_ACL
# if HAVE_ACL_GET_FILE
  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
  /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
#  if !HAVE_ACL_TYPE_EXTENDED
  /* Linux, FreeBSD, IRIX, Tru64 */

  /* We must also have acl_from_text and acl_delete_def_file.
     (acl_delete_def_file could be emulated with acl_init followed
      by acl_set_file, but acl_set_file with an empty acl is
      unspecified.)  */

#   ifndef HAVE_ACL_FROM_TEXT
#    error Must have acl_from_text (see POSIX 1003.1e draft 17).
#   endif
#   ifndef HAVE_ACL_DELETE_DEF_FILE
#    error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
#   endif

  acl_t acl;
  int ret;

  if (HAVE_ACL_FROM_MODE) /* Linux */
    {
      acl = acl_from_mode (mode);
      if (!acl)
        return -1;
    }
  else /* FreeBSD, IRIX, Tru64 */
    {
      /* If we were to create the ACL using the functions acl_init(),
         acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
         acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
         would need to create a qualifier.  I don't know how to do this.
         So create it using acl_from_text().  */

#   if HAVE_ACL_FREE_TEXT /* Tru64 */
      char acl_text[] = "u::---,g::---,o::---,";
#   else /* FreeBSD, IRIX */
      char acl_text[] = "u::---,g::---,o::---";
#   endif

      if (mode & S_IRUSR) acl_text[ 3] = 'r';
      if (mode & S_IWUSR) acl_text[ 4] = 'w';
      if (mode & S_IXUSR) acl_text[ 5] = 'x';
      if (mode & S_IRGRP) acl_text[10] = 'r';
      if (mode & S_IWGRP) acl_text[11] = 'w';
      if (mode & S_IXGRP) acl_text[12] = 'x';
      if (mode & S_IROTH) acl_text[17] = 'r';
      if (mode & S_IWOTH) acl_text[18] = 'w';
      if (mode & S_IXOTH) acl_text[19] = 'x';

      acl = acl_from_text (acl_text);
      if (!acl)
        return -1;
    }
  if (HAVE_ACL_SET_FD && desc != -1)
    ret = acl_set_fd (desc, acl);
  else
    ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
  if (ret != 0)
    {
      int saved_errno = errno;
      acl_free (acl);

      if (ACL_NOT_WELL_SUPPORTED (errno))
        return chmod_or_fchmod (name, desc, mode);
      else
        {
          errno = saved_errno;
          return -1;
        }
    }
  else
    acl_free (acl);

  if (S_ISDIR (mode) && acl_delete_def_file (name))
    return -1;

  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.  */
      return chmod_or_fchmod (name, desc, mode);
    }
  return 0;

#  else /* 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.  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;

  /* Remove the ACL if the file has ACLs.  */
  if (HAVE_ACL_GET_FD && desc != -1)
    acl = acl_get_fd (desc);
  else
    acl = acl_get_file (name, ACL_TYPE_EXTENDED);
  if (acl)
    {
      acl_free (acl);

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

              acl_free (acl);

              if (ACL_NOT_WELL_SUPPORTED (saved_errno))
                return chmod_or_fchmod (name, desc, mode);
              else
                {
                  errno = saved_errno;
                  return -1;
                }
            }
          acl_free (acl);
        }
    }

  /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly.  */
  return chmod_or_fchmod (name, desc, mode);
#  endif

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

  int done_setacl = 0;

#  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).  */

  /* The flags in the ace_t structure changed in a binary incompatible way
     when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
     How to distinguish the two conventions at runtime?
     We fetch the existing ACL.  In the old convention, usually three ACEs have
     a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400.
     In the new convention, these values are not used.  */
  int convention;

  {
    int count;
    ace_t *entries;

    for (;;)
      {
        if (desc != -1)
          count = facl (desc, ACE_GETACLCNT, 0, NULL);
        else
          count = acl (name, ACE_GETACLCNT, 0, NULL);
        if (count <= 0)
          {
            convention = -1;
            break;
          }
        entries = (ace_t *) malloc (count * sizeof (ace_t));
        if (entries == NULL)
          {
            errno = ENOMEM;
            return -1;
          }
        if ((desc != -1
             ? facl (desc, ACE_GETACL, count, entries)
             : acl (name, ACE_GETACL, count, entries))
            == count)
          {
            int i;

            convention = 0;
            for (i = 0; i < count; i++)
              if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
                {
                  convention = 1;
                  break;
                }
            free (entries);
            break;
          }
        /* Huh? The number of ACL entries changed since the last call.
           Repeat.  */
        free (entries);
      }
  }

  if (convention >= 0)
    {
      ace_t entries[6];
      int count;
      int ret;

      if (convention)
        {
          /* Running on Solaris 10.  */
          entries[0].a_type = OLD_ALLOW;
          entries[0].a_flags = OLD_ACE_OWNER;
          entries[0].a_who = 0; /* irrelevant */
          entries[0].a_access_mask = (mode >> 6) & 7;
          entries[1].a_type = OLD_ALLOW;
          entries[1].a_flags = OLD_ACE_GROUP;
          entries[1].a_who = 0; /* irrelevant */
          entries[1].a_access_mask = (mode >> 3) & 7;
          entries[2].a_type = OLD_ALLOW;
          entries[2].a_flags = OLD_ACE_OTHER;
          entries[2].a_who = 0;
          entries[2].a_access_mask = mode & 7;
          count = 3;
        }
      else
        {
示例#8
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
}
示例#9
0
int
copy_acl (const char *src_name, int source_desc, const char *dst_name,
	  int dest_desc, mode_t mode)
{
  int ret;

#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
  /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */

  acl_t acl;
  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_NOT_WELL_SUPPORTED (errno))
	return set_acl (dst_name, dest_desc, mode);
      else
        {
	  error (0, errno, "%s", quote (src_name));
	  return -1;
	}
    }

  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_NOT_WELL_SUPPORTED (errno))
        {
	  int n = acl_entries (acl);

	  acl_free (acl);
	  if (n == 3)
	    {
	      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
		saved_errno = errno;
	      else
		return 0;
	    }
	  else
	    chmod_or_fchmod (dst_name, dest_desc, mode);
	}
      else
	{
	  acl_free (acl);
	  chmod_or_fchmod (dst_name, dest_desc, mode);
	}
      error (0, saved_errno, _("preserving permissions for %s"),
	     quote (dst_name));
      return -1;
    }
  else
    acl_free (acl);

  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
    {
      /* We did not call chmod so far, so the special bits have not yet
         been set.  */

      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
	{
	  error (0, errno, _("preserving permissions for %s"),
		 quote (dst_name));
	  return -1;
	}
    }

  if (S_ISDIR (mode))
    {
      acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
      if (acl == NULL)
	{
	  error (0, errno, "%s", quote (src_name));
	  return -1;
	}

      if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
	{
	  error (0, errno, _("preserving permissions for %s"),
		 quote (dst_name));
	  acl_free (acl);
	  return -1;
	}
      else
        acl_free (acl);
    }
  return 0;
#else
  ret = chmod_or_fchmod (dst_name, dest_desc, mode);
  if (ret != 0)
    error (0, errno, _("preserving permissions for %s"), quote (dst_name));
  return ret;
#endif
}
示例#10
0
int
set_acl (char const *name, int desc, mode_t mode)
{
#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */

  /* We must also have have_acl_from_text and acl_delete_def_file.
     (acl_delete_def_file could be emulated with acl_init followed
      by acl_set_file, but acl_set_file with an empty acl is
      unspecified.)  */

# ifndef HAVE_ACL_FROM_TEXT
#  error Must have acl_from_text (see POSIX 1003.1e draft 17).
# endif
# ifndef HAVE_ACL_DELETE_DEF_FILE
#  error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
# endif

  acl_t acl;
  int ret;

  if (HAVE_ACL_FROM_MODE)
    {
      acl = acl_from_mode (mode);
      if (!acl)
	{
	  error (0, errno, "%s", quote (name));
	  return -1;
	}
    }
  else
    {
      char acl_text[] = "u::---,g::---,o::---";

      if (mode & S_IRUSR) acl_text[ 3] = 'r';
      if (mode & S_IWUSR) acl_text[ 4] = 'w';
      if (mode & S_IXUSR) acl_text[ 5] = 'x';
      if (mode & S_IRGRP) acl_text[10] = 'r';
      if (mode & S_IWGRP) acl_text[11] = 'w';
      if (mode & S_IXGRP) acl_text[12] = 'x';
      if (mode & S_IROTH) acl_text[17] = 'r';
      if (mode & S_IWOTH) acl_text[18] = 'w';
      if (mode & S_IXOTH) acl_text[19] = 'x';

      acl = acl_from_text (acl_text);
      if (!acl)
	{
	  error (0, errno, "%s", quote (name));
	  return -1;
	}
    }
  if (HAVE_ACL_SET_FD && desc != -1)
    ret = acl_set_fd (desc, acl);
  else
    ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
  if (ret != 0)
    {
      int saved_errno = errno;
      acl_free (acl);

      if (ACL_NOT_WELL_SUPPORTED (errno))
	{
	  if (chmod_or_fchmod (name, desc, mode) != 0)
	    saved_errno = errno;
	  else
	    return 0;
	}
      error (0, saved_errno, _("setting permissions for %s"), quote (name));
      return -1;
    }
  else
    acl_free (acl);

  if (S_ISDIR (mode) && acl_delete_def_file (name))
    {
      error (0, errno, _("setting permissions for %s"), quote (name));
      return -1;
    }

  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
    {
      /* We did not call chmod so far, so the special bits have not yet
         been set.  */

      if (chmod_or_fchmod (name, desc, mode))
	{
	  error (0, errno, _("preserving permissions for %s"), quote (name));
	  return -1;
	}
    }
  return 0;
#else
   int ret = chmod_or_fchmod (name, desc, mode);
   if (ret)
     error (0, errno, _("setting permissions for %s"), quote (name));
   return ret;
#endif
}
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
#endif
{
	int *marker;
	int matched;
	int i;
#if HAVE_SUN_ACL
	int e;
	aclent_t *acl_entry;
#else
	int entry_id = ACL_FIRST_ENTRY;
	acl_entry_t acl_entry;
#endif

	/* Count ACL entries in myacls array and allocate an indirect array. */
	marker = malloc(sizeof(marker[0]) * n);
	if (marker == NULL)
		return;
	for (i = 0; i < n; i++)
		marker[i] = i;

	/*
	 * Iterate over acls in system acl object, try to match each
	 * one with an item in the myacls array.
	 */
#if HAVE_SUN_ACL
	for(e = 0; e < acl->acl_cnt; e++) {
		acl_entry = &((aclent_t *)acl->acl_aclp)[e];
#else
	while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
		/* After the first time... */
		entry_id = ACL_NEXT_ENTRY;
#endif

		/* Search for a matching entry (tag and qualifier) */
		for (i = 0, matched = 0; i < n && !matched; i++) {
			if (acl_match(acl_entry, &myacls[marker[i]])) {
				/* We found a match; remove it. */
				marker[i] = marker[n - 1];
				n--;
				matched = 1;
			}
		}

		/* TODO: Print out more details in this case. */
		failure("ACL entry on file that shouldn't be there");
		assert(matched == 1);
	}

	/* Dump entries in the myacls array that weren't in the system acl. */
	for (i = 0; i < n; ++i) {
		failure(" ACL entry missing from file: "
		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
		    myacls[marker[i]].type, myacls[marker[i]].permset,
		    myacls[marker[i]].tag, myacls[marker[i]].qual,
		    myacls[marker[i]].name);
		assert(0); /* Record this as a failure. */
	}
	free(marker);
}

#endif


/*
 * Verify ACL restore-to-disk.  This test is Platform-specific.
 */

DEFINE_TEST(test_acl_platform_posix1e_restore)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
	struct stat st;
	struct archive *a;
	struct archive_entry *ae;
	int n, fd;
	char *func;
#if HAVE_SUN_ACL
	acl_t *acl, *acl2;
#else
	acl_t acl;
#endif

	/*
	 * First, do a quick manual set/read of ACL data to
	 * verify that the local filesystem does support ACLs.
	 * If it doesn't, we'll simply skip the remaining tests.
	 */
#if HAVE_SUN_ACL
	n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl != NULL);
#endif

	/* Create a test file and try ACL on it. */
	fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl);
		return;
	}

#if HAVE_SUN_ACL
	n = facl_get(fd, 0, &acl2);
	if (n != 0) {
		close(fd);
		acl_free(acl);
	}
	if (errno == ENOSYS) {
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl2->acl_type != ACLENT_T) {
		acl_free(acl2);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	acl_free(acl2);

	func = "facl_set()";
	n = facl_set(fd, acl);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl);
#endif
	acl_free(acl);
	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

#if HAVE_SUN_ACL

#endif
	close(fd);

	/* Create a write-to-disk object. */
	assert(NULL != (a = archive_write_disk_new()));
	archive_write_disk_set_options(a,
	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);

	/* Populate an archive entry with some metadata, including ACL info */
	ae = archive_entry_new();
	assert(ae != NULL);
	archive_entry_set_pathname(ae, "test0");
	archive_entry_set_mtime(ae, 123456, 7890);
	archive_entry_set_size(ae, 0);
	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
	archive_entry_free(ae);

	/* Close the archive. */
	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
	assertEqualInt(ARCHIVE_OK, archive_write_free(a));

	/* Verify the data on disk. */
	assertEqualInt(0, stat("test0", &st));
	assertEqualInt(st.st_mtime, 123456);
#if HAVE_SUN_ACL
	n = acl_get("test0", 0, &acl);
	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl = acl_get_file("test0", ACL_TYPE_ACCESS);
	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
	assert(acl != (acl_t)NULL);
#endif
	compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0]));
	acl_free(acl);
#endif	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
}

/*
 * Verify ACL read-from-disk.  This test is Platform-specific.
 */
DEFINE_TEST(test_acl_platform_posix1e_read)
{
#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
	skipping("POSIX.1e ACLs are not supported on this platform");
#else
	struct archive *a;
	struct archive_entry *ae;
	int n, fd, flags, dflags;
	char *func, *acl_text;
	const char *acl1_text, *acl2_text, *acl3_text;
#if HAVE_SUN_ACL
	acl_t *acl, *acl1, *acl2, *acl3;
#else
	acl_t acl1, acl2, acl3;
#endif

	/*
	 * Manually construct a directory and two files with
	 * different ACLs.  This also serves to verify that ACLs
	 * are supported on the local filesystem.
	 */

	/* Create a test file f1 with acl1 */
#if HAVE_SUN_ACL
	acl1_text = "user::rwx,"
	    "group::rwx,"
	    "other:rwx,"
	    "user:1:rw-,"
	    "group:15:r-x,"
	    "mask:rwx";
	n = acl_fromtext(acl1_text, &acl1);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl1_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::rwx\n"
	    "user:1:rw-\n"
	    "group:15:r-x\n"
	    "mask::rwx";
	acl1 = acl_from_text(acl1_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl1 != NULL);
#endif
	fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl1);
		return;
	}
#if HAVE_SUN_ACL
	/* Check if Solaris filesystem supports POSIX.1e ACLs */
	n = facl_get(fd, 0, &acl);
	if (n != 0)
		close(fd);
	if (n != 0 && errno == ENOSYS) {
		acl_free(acl1);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}
	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);

	if (acl->acl_type != ACLENT_T) {
		acl_free(acl);
		acl_free(acl1);
		close(fd);
		skipping("POSIX.1e ACLs are not supported on this filesystem");
		return;
	}

	func = "facl_set()";
	n = facl_set(fd, acl1);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl1);
#endif
	acl_free(acl1);

	if (n != 0) {
#if HAVE_SUN_ACL
		if (errno == ENOSYS)
#else
		if (errno == EOPNOTSUPP || errno == EINVAL)
#endif
		{
			close(fd);
			skipping("POSIX.1e ACLs are not supported on this filesystem");
			return;
		}
	}
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	close(fd);

	assertMakeDir("d", 0700);

	/*
	 * Create file d/f1 with acl2
	 *
	 * This differs from acl1 in the u:1: and g:15: permissions.
	 *
	 * This file deliberately has the same name but a different ACL.
	 * Github Issue #777 explains how libarchive's directory traversal
	 * did not always correctly enter directories before attempting
	 * to read ACLs, resulting in reading the ACL from a like-named
	 * file in the wrong directory.
	 */
#if HAVE_SUN_ACL
	acl2_text = "user::rwx,"
	    "group::rwx,"
	    "other:---,"
	    "user:1:r--,"
	    "group:15:r--,"
	    "mask:rwx";
	n = acl_fromtext(acl2_text, &acl2);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl2_text = "user::rwx\n"
	    "group::rwx\n"
	    "other::---\n"
	    "user:1:r--\n"
	    "group:15:r--\n"
	    "mask::rwx";
	acl2 = acl_from_text(acl2_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl2 != NULL);
#endif
	fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
	failure("Could not create test file?!");
	if (!assert(fd >= 0)) {
		acl_free(acl2);
		return;
	}
#if HAVE_SUN_ACL
	func = "facl_set()";
	n = facl_set(fd, acl2);
#else
	func = "acl_set_fd()";
	n = acl_set_fd(fd, acl2);
#endif
	acl_free(acl2);
	if (n != 0)
		close(fd);
	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);
	close(fd);

	/* Create nested directory d2 with default ACLs */
	assertMakeDir("d/d2", 0755);

#if HAVE_SUN_ACL
	acl3_text = "user::rwx,"
	    "group::r-x,"
	    "other:r-x,"
	    "user:2:r--,"
	    "group:16:-w-,"
	    "mask:rwx,"
	    "default:user::rwx,"
	    "default:user:1:r--,"
	    "default:group::r-x,"
	    "default:group:15:r--,"
	    "default:mask:rwx,"
	    "default:other:r-x";
	n = acl_fromtext(acl3_text, &acl3);
	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
	assertEqualInt(0, n);
#else
	acl3_text = "user::rwx\n"
	    "user:1:r--\n"
	    "group::r-x\n"
	    "group:15:r--\n"
	    "mask::rwx\n"
	    "other::r-x";
	acl3 = acl_from_text(acl3_text);
	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
	assert((void *)acl3 != NULL);
#endif

#if HAVE_SUN_ACL
	func = "acl_set()";
	n = acl_set("d/d2", acl3);
#else
	func = "acl_set_file()";
	n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3);
#endif
	acl_free(acl3);

	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
	assertEqualInt(0, n);

	/* Create a read-from-disk object. */
	assert(NULL != (a = archive_read_disk_new()));
	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
	assert(NULL != (ae = archive_entry_new()));

#if HAVE_SUN_ACL
	flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E
	    | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
	    | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS;
	dflags = flags;
#else
	flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
	dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
#endif

	/* Walk the dir until we see both of the files */
	while (ARCHIVE_OK == archive_read_next_header2(a, ae)) {
		archive_read_disk_descend(a);
		if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl1_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, flags);
			assertEqualString(acl_text, acl2_text);
			free(acl_text);
		} else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) {
			acl_text = archive_entry_acl_to_text(ae, NULL, dflags);
			assertEqualString(acl_text, acl3_text);
			free(acl_text);
		}
	}

	archive_entry_free(ae);
	assertEqualInt(ARCHIVE_OK, archive_free(a));
#endif
}
示例#12
0
文件: cert.c 项目: jelmer/cups
void
cupsdAddCert(int        pid,		/* I - Process ID */
             const char *username,	/* I - Username */
             int        type)		/* I - AuthType for username */
{
  int		i;			/* Looping var */
  cupsd_cert_t	*cert;			/* Current certificate */
  int		fd;			/* Certificate file */
  char		filename[1024];		/* Certificate filename */
  static const char hex[] = "0123456789ABCDEF";
					/* Hex constants... */


  cupsdLogMessage(CUPSD_LOG_DEBUG2,
                  "cupsdAddCert: Adding certificate for PID %d", pid);

 /*
  * Allocate memory for the certificate...
  */

  if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL)
    return;

 /*
  * Fill in the certificate information...
  */

  cert->pid  = pid;
  cert->type = type;
  strlcpy(cert->username, username, sizeof(cert->username));

  for (i = 0; i < 32; i ++)
    cert->certificate[i] = hex[CUPS_RAND() & 15];

 /*
  * Save the certificate to a file readable only by the User and Group
  * (or root and SystemGroup for PID == 0)...
  */

  snprintf(filename, sizeof(filename), "%s/certs/%d", StateDir, pid);
  unlink(filename);

  if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Unable to create certificate file %s - %s",
                    filename, strerror(errno));
    free(cert);
    return;
  }

  if (pid == 0)
  {
#ifdef HAVE_ACL_INIT
    acl_t		acl;		/* ACL information */
    acl_entry_t		entry;		/* ACL entry */
    acl_permset_t	permset;	/* Permissions */
#  ifdef HAVE_MBR_UID_TO_UUID
    uuid_t		group;		/* Group ID */
#  endif /* HAVE_MBR_UID_TO_UUID */
    static int		acls_not_supported = 0;
					/* Only warn once */
#endif /* HAVE_ACL_INIT */


   /*
    * Root certificate...
    */

    fchmod(fd, 0440);
    fchown(fd, RunUser, SystemGroupIDs[0]);

    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddCert: NumSystemGroups=%d",
                    NumSystemGroups);

#ifdef HAVE_ACL_INIT
    if (NumSystemGroups > 1)
    {
     /*
      * Set POSIX ACLs for the root certificate so that all system
      * groups can access it...
      */

      int	j;			/* Looping var */

#  ifdef HAVE_MBR_UID_TO_UUID
     /*
      * On MacOS X, ACLs use UUIDs instead of GIDs...
      */

      acl = acl_init(NumSystemGroups - 1);

      for (i = 1; i < NumSystemGroups; i ++)
      {
       /*
        * Add each group ID to the ACL...
	*/

        for (j = 0; j < i; j ++)
	  if (SystemGroupIDs[j] == SystemGroupIDs[i])
            break;

        if (j < i)
          continue;			/* Skip duplicate groups */

        acl_create_entry(&acl, &entry);
	acl_get_permset(entry, &permset);
	acl_add_perm(permset, ACL_READ_DATA);
	acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
	mbr_gid_to_uuid((gid_t)SystemGroupIDs[i], group);
	acl_set_qualifier(entry, &group);
	acl_set_permset(entry, permset);
      }

#  else
     /*
      * POSIX ACLs need permissions for owner, group, other, and mask
      * in addition to the rest of the system groups...
      */

      acl = acl_init(NumSystemGroups + 3);

      /* Owner */
      acl_create_entry(&acl, &entry);
      acl_get_permset(entry, &permset);
      acl_add_perm(permset, ACL_READ);
      acl_set_tag_type(entry, ACL_USER_OBJ);
      acl_set_permset(entry, permset);

      /* Group */
      acl_create_entry(&acl, &entry);
      acl_get_permset(entry, &permset);
      acl_add_perm(permset, ACL_READ);
      acl_set_tag_type(entry, ACL_GROUP_OBJ);
      acl_set_permset(entry, permset);

      /* Others */
      acl_create_entry(&acl, &entry);
      acl_get_permset(entry, &permset);
      acl_add_perm(permset, 0);
      acl_set_tag_type(entry, ACL_OTHER);
      acl_set_permset(entry, permset);

      /* Mask */
      acl_create_entry(&acl, &entry);
      acl_get_permset(entry, &permset);
      acl_add_perm(permset, ACL_READ);
      acl_set_tag_type(entry, ACL_MASK);
      acl_set_permset(entry, permset);

      for (i = 1; i < NumSystemGroups; i ++)
      {
       /*
        * Add each group ID to the ACL...
	*/

        for (j = 0; j < i; j ++)
	  if (SystemGroupIDs[j] == SystemGroupIDs[i])
            break;

        if (j < i)
          continue;			/* Skip duplicate groups */

        acl_create_entry(&acl, &entry);
	acl_get_permset(entry, &permset);
	acl_add_perm(permset, ACL_READ);
	acl_set_tag_type(entry, ACL_GROUP);
	acl_set_qualifier(entry, SystemGroupIDs + i);
	acl_set_permset(entry, permset);
      }

      if (acl_valid(acl))
      {
        char *text, *textptr;		/* Temporary string */

        cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
	                strerror(errno));
        text = acl_to_text(acl, NULL);
	for (textptr = strchr(text, '\n');
	     textptr;
	     textptr = strchr(textptr + 1, '\n'))
	  *textptr = ',';

	cupsdLogMessage(CUPSD_LOG_ERROR, "ACL: %s", text);
	acl_free(text);
      }
#  endif /* HAVE_MBR_UID_TO_UUID */

      if (acl_set_fd(fd, acl))
      {
	if (errno != EOPNOTSUPP || !acls_not_supported)
	  cupsdLogMessage(CUPSD_LOG_ERROR,
			  "Unable to set ACLs on root certificate \"%s\" - %s",
			  filename, strerror(errno));

	if (errno == EOPNOTSUPP)
	  acls_not_supported = 1;
      }

      acl_free(acl);
    }
#endif /* HAVE_ACL_INIT */

    RootCertTime = time(NULL);
  }
  else
  {
   /*
    * CGI certificate...
    */

    fchmod(fd, 0400);
    fchown(fd, User, Group);
  }

  DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username,
                cert->certificate));

  write(fd, cert->certificate, strlen(cert->certificate));
  close(fd);

 /*
  * Insert the certificate at the front of the list...
  */

  cert->next = Certs;
  Certs      = cert;
}
示例#13
0
int
copy_acl (const char *src_name, int source_desc, const char *dst_name,
	  int dest_desc, mode_t mode)
{
  int ret;

#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
  /* POSIX 1003.1e (draft 17 -- abandoned) specific version.  */
  /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */

  acl_t acl;
  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_NOT_WELL_SUPPORTED (errno))
	return set_acl (dst_name, dest_desc, mode);
      else
        {
	  error (0, errno, "%s", quote (src_name));
	  return -1;
	}
    }

  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_NOT_WELL_SUPPORTED (errno))
        {
	  int n = acl_entries (acl);

	  acl_free (acl);
	  /* On most hosts with MODE_INSIDE_ACL an ACL is trivial if n == 3,
	     and it cannot be less than 3.  On IRIX 6.5 it is also trivial if
	     n == -1.
	     For simplicity and safety, assume the ACL is trivial if n <= 3.
	     Also see file-has-acl.c for some of the other possibilities;
	     it's not clear whether that complexity is needed here.  */
	  if (n <= 3 * MODE_INSIDE_ACL)
	    {
	      if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
		saved_errno = errno;
	      else
		return 0;
	    }
	  else
	    chmod_or_fchmod (dst_name, dest_desc, mode);
	}
      else
	{
	  acl_free (acl);
	  chmod_or_fchmod (dst_name, dest_desc, mode);
	}
      error (0, saved_errno, _("preserving permissions for %s"),
	     quote (dst_name));
      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)
	{
	  error (0, errno, _("preserving permissions for %s"),
		 quote (dst_name));
	  return -1;
	}
    }

  if (S_ISDIR (mode))
    {
      acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
      if (acl == NULL)
	{
	  error (0, errno, "%s", quote (src_name));
	  return -1;
	}

      if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
	{
	  error (0, errno, _("preserving permissions for %s"),
		 quote (dst_name));
	  acl_free (acl);
	  return -1;
	}
      else
        acl_free (acl);
    }
  return 0;

#else

# if USE_ACL && defined ACL_NO_TRIVIAL
  /* Solaris 10 NFSv4 ACLs.  */
  acl_t *aclp = NULL;
  ret = (source_desc < 0
	 ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp)
	 : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp));
  if (ret != 0 && errno != ENOSYS)
    {
      error (0, errno, "%s", quote (src_name));
      return ret;
    }
# endif

  ret = qset_acl (dst_name, dest_desc, mode);
  if (ret != 0)
    error (0, errno, _("preserving permissions for %s"), quote (dst_name));

# if USE_ACL && defined ACL_NO_TRIVIAL
  if (ret == 0 && aclp)
    {
      ret = (dest_desc < 0
	     ? acl_set (dst_name, aclp)
	     : facl_set (dest_desc, aclp));
      if (ret != 0)
	error (0, errno, _("preserving permissions for %s"), quote (dst_name));
      acl_free (aclp);
    }
# endif

  return ret;
#endif
}
示例#14
0
static int
set_acl(struct archive *a, int fd, const char *name,
        struct archive_acl *abstract_acl,
        acl_type_t acl_type, int ae_requested_type, const char *tname)
{
    acl_t		 acl;
    acl_entry_t	 acl_entry;
    acl_permset_t	 acl_permset;
#ifdef ACL_TYPE_NFS4
    acl_flagset_t	 acl_flagset;
    int		 r;
#endif
    int		 ret;
    int		 ae_type, ae_permset, ae_tag, ae_id;
    uid_t		 ae_uid;
    gid_t		 ae_gid;
    const char	*ae_name;
    int		 entries;
    int		 i;

    ret = ARCHIVE_OK;
    entries = archive_acl_reset(abstract_acl, ae_requested_type);
    if (entries == 0)
        return (ARCHIVE_OK);
    acl = acl_init(entries);
    while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
                            &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
        acl_create_entry(&acl, &acl_entry);

        switch (ae_tag) {
        case ARCHIVE_ENTRY_ACL_USER:
            acl_set_tag_type(acl_entry, ACL_USER);
            ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
            acl_set_qualifier(acl_entry, &ae_uid);
            break;
        case ARCHIVE_ENTRY_ACL_GROUP:
            acl_set_tag_type(acl_entry, ACL_GROUP);
            ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
            acl_set_qualifier(acl_entry, &ae_gid);
            break;
        case ARCHIVE_ENTRY_ACL_USER_OBJ:
            acl_set_tag_type(acl_entry, ACL_USER_OBJ);
            break;
        case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
            acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
            break;
        case ARCHIVE_ENTRY_ACL_MASK:
            acl_set_tag_type(acl_entry, ACL_MASK);
            break;
        case ARCHIVE_ENTRY_ACL_OTHER:
            acl_set_tag_type(acl_entry, ACL_OTHER);
            break;
#ifdef ACL_TYPE_NFS4
        case ARCHIVE_ENTRY_ACL_EVERYONE:
            acl_set_tag_type(acl_entry, ACL_EVERYONE);
            break;
#endif
        default:
            /* XXX */
            break;
        }

#ifdef ACL_TYPE_NFS4
        switch (ae_type) {
        case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
            acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
            break;
        case ARCHIVE_ENTRY_ACL_TYPE_DENY:
            acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
            break;
        case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
            acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
            break;
        case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
            acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
            break;
        case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
        case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
            // These don't translate directly into the system ACL.
            break;
        default:
            // XXX error handling here.
            break;
        }
#endif

        acl_get_permset(acl_entry, &acl_permset);
        acl_clear_perms(acl_permset);

        for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
            if (ae_permset & acl_perm_map[i].archive_perm)
                acl_add_perm(acl_permset,
                             acl_perm_map[i].platform_perm);
        }

#ifdef ACL_TYPE_NFS4
        // XXX acl_get_flagset_np on FreeBSD returns EINVAL for
        // non-NFSv4 ACLs
        r = acl_get_flagset_np(acl_entry, &acl_flagset);
        if (r == 0) {
            acl_clear_flags_np(acl_flagset);
            for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
                if (ae_permset & acl_inherit_map[i].archive_inherit)
                    acl_add_flag_np(acl_flagset,
                                    acl_inherit_map[i].platform_inherit);
            }
        }
#endif
    }

    /* Try restoring the ACL through 'fd' if we can. */
#if HAVE_ACL_SET_FD
    if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
        ret = ARCHIVE_OK;
    else
#else
#if HAVE_ACL_SET_FD_NP
    if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
        ret = ARCHIVE_OK;
    else
#endif
#endif
#if HAVE_ACL_SET_LINK_NP
        if (acl_set_link_np(name, acl_type, acl) != 0) {
            archive_set_error(a, errno, "Failed to set %s acl", tname);
            ret = ARCHIVE_WARN;
        }
#else
        /* TODO: Skip this if 'name' is a symlink. */
        if (acl_set_file(name, acl_type, acl) != 0) {
            archive_set_error(a, errno, "Failed to set %s acl", tname);
            ret = ARCHIVE_WARN;
        }
#endif
    acl_free(acl);
    return (ret);
}