Exemple #1
0
static int
retrieve_acl(
	const char *path_p,
	acl_type_t type,
	const struct stat *st,
	acl_t *old_acl,
	acl_t *acl)
{
	if (*acl)
		return 0;
	*acl = NULL;
	if (type == ACL_TYPE_ACCESS || S_ISDIR(st->st_mode)) {
		*old_acl = acl_get_file(path_p, type);
		if (*old_acl == NULL && (errno == ENOSYS || errno == ENOTSUP)) {
			if (type == ACL_TYPE_DEFAULT)
				*old_acl = acl_init(0);
			else
				*old_acl = acl_from_mode(st->st_mode);
		}
	} else
		*old_acl = acl_init(0);
	if (*old_acl == NULL)
		return -1;
	*acl = acl_dup(*old_acl);
	if (*acl == NULL)
		return -1;
	return 0;
}
/* 23.4.15 */
acl_t
acl_get_fd(int fd)
{
	const size_t size_guess = acl_ea_size(16);
	char *ext_acl_p = alloca(size_guess);
	int retval;

	if (!ext_acl_p)
		return NULL;
	retval = fgetxattr(fd, ACL_EA_ACCESS, ext_acl_p, size_guess);
	if (retval == -1 && errno == ERANGE) {
		retval = fgetxattr(fd, ACL_EA_ACCESS, NULL, 0);
		if (retval > 0) {
			ext_acl_p = alloca(retval);
			if (!ext_acl_p)
				return NULL;
			retval = fgetxattr(fd, ACL_EA_ACCESS, ext_acl_p,retval);
		}
	}
	if (retval > 0) {
		acl_t acl = __acl_from_xattr(ext_acl_p, retval);
		return acl;
	} else if (retval == 0 || errno == ENOATTR || errno == ENODATA) {
		struct stat st;

		if (fstat(fd, &st) == 0)
			return acl_from_mode(st.st_mode);
		else
			return NULL;
	} else
		return NULL;
}
Exemple #3
0
/*
 * Create an ACL from the file permission bits
 * of the file PATH_P.
 */
static acl_t
acl_get_file_mode(const char *path_p)
{
	struct stat st;

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

	if (acl_set_file (path, ACL_TYPE_ACCESS, 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);
	if (ret == 0 && S_ISDIR (mode)) {
# if defined(HAVE_ACL_DELETE_DEF_FILE)
		ret = acl_delete_def_file (path);
# else
		acl = acl_init (0);
		ret = acl_set_file (path, ACL_TYPE_DEFAULT, acl);
		(void) acl_free (acl);
# endif
		if (ret != 0) {
			const char *qpath = quote (ctx, path);
			error (ctx, _( "setting permissions for %s"), qpath);
			quote_free (ctx, qpath);
		}
	}
	return ret;
#endif

chmod_only:
	ret = chmod (path, mode);
	if (ret != 0) {
		const char *qpath = quote (ctx, path);
		error (ctx, _("setting permissions for %s"), qpath);
		quote_free (ctx, qpath);
	}
	return ret;
}
Exemple #5
0
int getacl(const char *pathp, aclent_t *aclpbuf)
{
	acl_t acl = NULL, default_acl = NULL;	
	struct stat st;
	
	if (stat(pathp, &st) != 0) {
		return -1;
	}
		
	acl = acl_get_file(pathp, ACL_TYPE_ACCESS);
	if(acl == NULL && (errno == ENOSYS || errno == ENOTSUP)) {
		acl = acl_from_mode(st.st_mode);
		if (acl == NULL) {
			return -1;
		}
	}	
	
	if (S_ISDIR(st.st_mode)) {
		default_acl = acl_get_file(pathp, ACL_TYPE_DEFAULT);
		if ((default_acl != NULL) && (acl_entries(default_acl) == 0)) {
			acl_free(default_acl);
			default_acl = NULL;
		} 
	}
	
	acl_entry_t acl_entry;
	int ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
	int i = 0;
	while(ret > 0) {
		aclpbuf[i++] = getentry(acl_entry, st, 0);
		ret = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
	}
	acl_free(acl);
	
	if((default_acl != NULL) && (ret != -1)) {
		ret = acl_get_entry(default_acl, ACL_FIRST_ENTRY, &acl_entry);
		while(ret > 0) {			
			aclpbuf[i++] = getentry(acl_entry, st, ACL_DEFAULT);
			ret = acl_get_entry(default_acl, ACL_NEXT_ENTRY, &acl_entry);
		}
		acl_free(default_acl);
	}
	
	return i;
}
/* 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
        {
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
}
Exemple #9
0
int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
        acl_entry_t i;
        int r;
        bool have_user_obj = false, have_group_obj = false, have_other = false;
        struct stat st;
        _cleanup_(acl_freep) acl_t basic = NULL;

        assert(acl_p);

        for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
             r > 0;
             r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
                acl_tag_t tag;

                if (acl_get_tag_type(i, &tag) < 0)
                        return -errno;

                if (tag == ACL_USER_OBJ)
                        have_user_obj = true;
                else if (tag == ACL_GROUP_OBJ)
                        have_group_obj = true;
                else if (tag == ACL_OTHER)
                        have_other = true;
                if (have_user_obj && have_group_obj && have_other)
                        return 0;
        }
        if (r < 0)
                return -errno;

        r = stat(path, &st);
        if (r < 0)
                return -errno;

        basic = acl_from_mode(st.st_mode);
        if (!basic)
                return -errno;

        for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i);
             r > 0;
             r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) {
                acl_tag_t tag;
                acl_entry_t dst;

                if (acl_get_tag_type(i, &tag) < 0)
                        return -errno;

                if ((tag == ACL_USER_OBJ && have_user_obj) ||
                    (tag == ACL_GROUP_OBJ && have_group_obj) ||
                    (tag == ACL_OTHER && have_other))
                        continue;

                r = acl_create_entry(acl_p, &dst);
                if (r < 0)
                        return -errno;

                r = acl_copy_entry(dst, i);
                if (r < 0)
                        return -errno;
        }
        if (r < 0)
                return -errno;
        return 0;
}