Ejemplo n.º 1
0
int
acl_set_fd(int fd, acl_t acl)
{

	if (fpathconf(fd, _PC_ACL_NFS4) == 1)
		return (acl_set_fd_np(fd, acl, ACL_TYPE_NFS4));

	return (acl_set_fd_np(fd, acl, ACL_TYPE_ACCESS));
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
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;
}