Example #1
0
static void
preserve_fd_acls(int source_fd, int dest_fd, const char *source_path,
    const char *dest_path)
{
	acl_t acl;
	acl_type_t acl_type;
	int acl_supported = 0, ret, trivial;

	ret = fpathconf(source_fd, _PC_ACL_NFS4);
	if (ret > 0 ) {
		acl_supported = 1;
		acl_type = ACL_TYPE_NFS4;
	} else if (ret < 0 && errno != EINVAL) {
		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s",
		    source_path);
		return;
	}
	if (acl_supported == 0) {
		ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
		if (ret > 0 ) {
			acl_supported = 1;
			acl_type = ACL_TYPE_ACCESS;
		} else if (ret < 0 && errno != EINVAL) {
			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
			    source_path);
			return;
		}
	}
	if (acl_supported == 0)
		return;

	acl = acl_get_fd_np(source_fd, acl_type);
	if (acl == NULL) {
		warn("failed to get acl entries for %s", source_path);
		return;
	}
	if (acl_is_trivial_np(acl, &trivial)) {
		warn("acl_is_trivial() failed for %s", source_path);
		acl_free(acl);
		return;
	}
	if (trivial) {
		acl_free(acl);
		return;
	}
	if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
		warn("failed to set acl entries for %s", dest_path);
		acl_free(acl);
		return;
	}
	acl_free(acl);
}
Example #2
0
static int
setup_acls(struct archive_read_disk *a,
    struct archive_entry *entry, int *fd)
{
	const char	*accpath;
	acl_t		 acl;
	int		r;

	accpath = archive_entry_sourcepath(entry);
	if (accpath == NULL)
		accpath = archive_entry_pathname(entry);

	if (*fd < 0 && a->tree != NULL) {
		if (a->follow_symlinks ||
		    archive_entry_filetype(entry) != AE_IFLNK)
			*fd = a->open_on_current_dir(a->tree,
			    accpath, O_RDONLY | O_NONBLOCK);
		if (*fd < 0) {
			if (a->tree_enter_working_dir(a->tree) != 0) {
				archive_set_error(&a->archive, errno,
				    "Couldn't access %s", accpath);
				return (ARCHIVE_FAILED);
			}
		}
	}

	archive_entry_acl_clear(entry);

	acl = NULL;

#ifdef ACL_TYPE_NFS4
	/* Try NFS4 ACL first. */
	if (*fd >= 0)
#if HAVE_ACL_GET_FD_NP
		acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
#else
		acl = acl_get_fd(*fd);
#endif
#if HAVE_ACL_GET_LINK_NP
	else if (!a->follow_symlinks)
Example #3
0
int
modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow) {
	
	acl_t oacl = NULL;
	unsigned aindex  = 0, flag_new_acl = 0;
	acl_entry_t newent = NULL;
	acl_entry_t entry = NULL;
	unsigned retval = 0;

	extern int chmod_fflag;

/* XXX acl_get_file() returns a zero entry ACL if an ACL was previously
 * associated with the file, and has had its entries removed.
 * However, POSIX 1003.1e states that a zero entry ACL should be 
 * returned if the caller asks for ACL_TYPE_DEFAULT, and no ACL is 
 * associated with the path; it
 * does not specifically state that a request for ACL_TYPE_EXTENDED
 * should not return a zero entry ACL, however.
 */

/* Determine if we've been given a zero entry ACL, or create an ACL if 
 * none exists. There are some issues to consider here: Should we create
 * a zero-entry ACL for a delete or check canonicity operation?
 */

	if (path == NULL)
		chmod_usage();

	if (optflags & ACL_CLEAR_FLAG) {
		filesec_t fsec = filesec_init();
		if (fsec == NULL) {
			// err(1, "filesec_init() failed");
            fprintf(stderr, "chmod: filesec_init() failed: %s\n", strerror(errno));
            pthread_exit(NULL);
		}
		if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) {
            // err(1, "filesec_set_property() failed");
            fprintf(stderr, "chmod: filesec_set_property() failed: %s\n", strerror(errno));
            pthread_exit(NULL);
                }
		if (follow) {
			if (chmodx_np(path, fsec) != 0) {
                if (!chmod_fflag) {
					// warn("Failed to clear ACL on file %s", path);
                    fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno));
				}
				retval = 1;
			}
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				if (fchmodx_np(fd, fsec) != 0) {
					if (!chmod_fflag) {
                        fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno));
                        // warn("Failed to clear ACL on file %s", path);
					}
					retval = 1;
				}
				close(fd);
			} else {
				if (!chmod_fflag) {
					// warn("Failed to open file %s", path);
                    fprintf(stderr, "chmod: Failed to open file %s: %s\n", path, strerror(errno));
				}
				retval = 1;
			}
		}
		filesec_free(fsec);
		return (retval);
	}

	if (optflags & ACL_FROM_STDIN) {
		oacl = acl_dup(modifier);
	} else {
		if (follow) {
			oacl = acl_get_file(path, ACL_TYPE_EXTENDED);
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				oacl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED);
				close(fd);
			}
		}
		if ((oacl == NULL) ||
		    (acl_get_entry(oacl,ACL_FIRST_ENTRY, &newent) != 0)) {
            if ((oacl = acl_init(1)) == NULL) {
				// err(1, "acl_init() failed");
                fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno));
                pthread_exit(NULL);
            }
			flag_new_acl = 1;
			position = 0;
		}
	
		if ((0 == flag_new_acl) && (optflags & (ACL_REMOVE_INHERIT_FLAG | 
							ACL_REMOVE_INHERITED_ENTRIES))) {
			acl_t facl = NULL;
            if ((facl = acl_init(1)) == NULL) {
				//err(1, "acl_init() failed");
                fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno));
                pthread_exit(NULL);
            }
			for (aindex = 0; 
			     acl_get_entry(oacl, 
					   (entry == NULL ? ACL_FIRST_ENTRY : 
					    ACL_NEXT_ENTRY), &entry) == 0; 
			     aindex++) {
				acl_flagset_t eflags;
				acl_entry_t fent = NULL;
				if (acl_get_flagset_np(entry, &eflags) != 0) {
                    fprintf(stderr,  "chmod: Unable to obtain flagset: %s\n", strerror(errno));
                    pthread_exit(NULL);
                    // err(1, "Unable to obtain flagset");
				}
				
				if (acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) {
					if (optflags & ACL_REMOVE_INHERIT_FLAG) {
						acl_delete_flag_np(eflags, ACL_ENTRY_INHERITED);
						acl_set_flagset_np(entry, eflags);
						acl_create_entry(&facl, &fent);
						acl_copy_entry(fent, entry);
					}
				}
				else {
					acl_create_entry(&facl, &fent);
					acl_copy_entry(fent, entry);
				}
			}
			if (oacl)
				acl_free(oacl);
			oacl = facl;
		} else if (optflags & ACL_TO_STDOUT) {
			ssize_t len; /* need to get printacl() from ls(1) */
			char *text = acl_to_text(oacl, &len);
			puts(text);
			acl_free(text);
		} else if (optflags & ACL_CHECK_CANONICITY) {
			if (flag_new_acl) {
				// warnx("No ACL currently associated with file '%s'", path);
                fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path);
			}
			retval = is_canonical(oacl);
		} else if ((optflags & ACL_SET_FLAG) && (position == -1) && 
		    (!is_canonical(oacl))) {
			// warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path);
            fprintf(stderr, "chmod: The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# \n", path);
			retval = 1;
		} else if (((optflags & ACL_DELETE_FLAG) && (position != -1))
		    || (optflags & ACL_CHECK_CANONICITY)) {
			retval = modify_acl(&oacl, NULL, optflags, position, 
					    inheritance_level, flag_new_acl, path);
		} else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) {
			// warnx("No ACL currently associated with file '%s'", path);
            fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path);
			retval = 1;
		} else {
			if (!modifier) { /* avoid bus error in acl_get_entry */
				// errx(1, "Internal error: modifier should not be NULL");
                fprintf(stderr, "Internal error: modifier should not be NULL\n");
                pthread_exit(NULL);
			}
			for (aindex = 0; 
			     acl_get_entry(modifier, 
					   (entry == NULL ? ACL_FIRST_ENTRY : 
					    ACL_NEXT_ENTRY), &entry) == 0; 
			     aindex++) {

				retval += modify_acl(&oacl, entry, optflags, 
						     position, inheritance_level, 
						     flag_new_acl, path);
			}
		}
	}

/* XXX Potential race here, since someone else could've modified or
 * read the ACL on this file (with the intention of modifying it) in
 * the interval from acl_get_file() to acl_set_file(); we can
 * minimize one aspect of this  window by comparing the original acl
 * to a fresh one from acl_get_file() but we could consider a
 * "changeset" mechanism, common locking  strategy, or kernel
 * supplied reservation mechanism to prevent this race.
 */
	if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY))) {
		int status = -1;
		if (follow) {
	    		status = acl_set_file(path, ACL_TYPE_EXTENDED, oacl);
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				status = acl_set_fd_np(fd, oacl,
							ACL_TYPE_EXTENDED);
				close(fd);
			}
		}
		if (status != 0) {
			if (!chmod_fflag)
                fprintf(stderr, "chmod: Failed to set ACL on file '%s': %s\n", path, strerror(errno));
            // warn("Failed to set ACL on file '%s'", path);
			retval = 1;
		}
	}
	
	if (oacl)
		acl_free(oacl);
	
	return retval;
}