Пример #1
0
static int
zfs_replay_acl_v0(zfsvfs_t *zfsvfs, lr_acl_v0_t *lr, boolean_t byteswap)
{
	ace_t *ace = (ace_t *)(lr + 1);	/* ace array follows lr_acl_t */
	vsecattr_t vsa;
	znode_t *zp;
	int error;

	if (byteswap) {
		byteswap_uint64_array(lr, sizeof (*lr));
		zfs_oldace_byteswap(ace, lr->lr_aclcnt);
	}

	if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
		return (error);

	bzero(&vsa, sizeof (vsa));
	vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
	vsa.vsa_aclcnt = lr->lr_aclcnt;
	vsa.vsa_aclentsz = sizeof (ace_t) * vsa.vsa_aclcnt;
	vsa.vsa_aclflags = 0;
	vsa.vsa_aclentp = ace;

#ifdef TODO
	error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);
#else
	panic("%s:%u: unsupported condition", __func__, __LINE__);
#endif

	VN_RELE(ZTOV(zp));

	return (error);
}
Пример #2
0
static int
zfs_replay_acl_v0(zfsvfs_t *zfsvfs, lr_acl_v0_t *lr, boolean_t byteswap)
{
	ace_t *ace = (ace_t *)(lr + 1);	/* ace array follows lr_acl_t */
	vsecattr_t vsa;
	znode_t *zp;
	int error;

	if (byteswap) {
		byteswap_uint64_array(lr, sizeof (*lr));
		zfs_oldace_byteswap(ace, lr->lr_aclcnt);
	}

	if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
		/*
		 * As we can log acls out of order, it's possible the
		 * file has been removed. In this case just drop the acl
		 * and return success.
		 */
		if (error == ENOENT)
			error = 0;
		return (error);
	}

	bzero(&vsa, sizeof (vsa));
	vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
	vsa.vsa_aclcnt = lr->lr_aclcnt;
	vsa.vsa_aclentp = ace;

	error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);

	VN_RELE(ZTOV(zp));

	return (error);
}
Пример #3
0
/*
 * Replaying ACLs is complicated by FUID support.
 * The log record may contain some optional data
 * to be used for replaying FUID's.  These pieces
 * are the actual FUIDs that were created initially.
 * The FUID table index may no longer be valid and
 * during zfs_create() a new index may be assigned.
 * Because of this the log will contain the original
 * doman+rid in order to create a new FUID.
 *
 * The individual ACEs may contain an ephemeral uid/gid which is no
 * longer valid and will need to be replaced with an actual FUID.
 *
 */
static int
zfs_replay_acl(zfsvfs_t *zfsvfs, void *data, boolean_t byteswap)
{
#ifdef __OSV__
	kprintf("TX_ACL_V0 not supported on OSv\n");
	return EOPNOTSUPP;
#else
	lr_acl_t *lr = data;
	ace_t *ace = (ace_t *)(lr + 1);
	vsecattr_t vsa;
	znode_t *zp;
	int error;

	if (byteswap) {
		byteswap_uint64_array(lr, sizeof (*lr));
		zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
		if (lr->lr_fuidcnt) {
			byteswap_uint64_array((caddr_t)ace +
			    ZIL_ACE_LENGTH(lr->lr_acl_bytes),
			    lr->lr_fuidcnt * sizeof (uint64_t));
		}
	}

	if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
		return (error);

#ifdef TODO
	bzero(&vsa, sizeof (vsa));
	vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
	vsa.vsa_aclcnt = lr->lr_aclcnt;
	vsa.vsa_aclentp = ace;
	vsa.vsa_aclentsz = lr->lr_acl_bytes;
	vsa.vsa_aclflags = lr->lr_acl_flags;

	if (lr->lr_fuidcnt) {
		void *fuidstart = (caddr_t)ace +
		    ZIL_ACE_LENGTH(lr->lr_acl_bytes);

		zfsvfs->z_fuid_replay =
		    zfs_replay_fuids(fuidstart, &fuidstart,
		    lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
	}

	error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);

	if (zfsvfs->z_fuid_replay)
		zfs_fuid_info_free(zfsvfs->z_fuid_replay);
#else
	error = EOPNOTSUPP;
#endif

	zfsvfs->z_fuid_replay = NULL;
	VN_RELE(ZTOV(zp));

	return (error);
#endif
}
Пример #4
0
/* ARGSUSED */
void
acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi,
    struct svc_req *req, cred_t *cr, bool_t ro)
{
	int error;
	vnode_t *vp;
	vattr_t *vap;
	vattr_t va;

	vap = NULL;

	vp = nfs3_fhtovp(&args->fh, exi);
	if (vp == NULL) {
		error = ESTALE;
		goto out1;
	}

	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);

	va.va_mask = AT_ALL;
	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;

	if (rdonly(ro, vp)) {
		resp->status = NFS3ERR_ROFS;
		goto out1;
	}

	error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);

	va.va_mask = AT_ALL;
	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;

	if (error)
		goto out;

	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
	VN_RELE(vp);

	resp->status = NFS3_OK;
	vattr_to_post_op_attr(vap, &resp->resok.attr);
	return;

out:
	if (curthread->t_flag & T_WOULDBLOCK) {
		curthread->t_flag &= ~T_WOULDBLOCK;
		resp->status = NFS3ERR_JUKEBOX;
	} else
		resp->status = puterrno3(error);
out1:
	if (vp != NULL) {
		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
		VN_RELE(vp);
	}
	vattr_to_post_op_attr(vap, &resp->resfail.attr);
}
Пример #5
0
/*
 * Replaying ACLs is complicated by FUID support.
 * The log record may contain some optional data
 * to be used for replaying FUID's.  These pieces
 * are the actual FUIDs that were created initially.
 * The FUID table index may no longer be valid and
 * during zfs_create() a new index may be assigned.
 * Because of this the log will contain the original
 * doman+rid in order to create a new FUID.
 *
 * The individual ACEs may contain an ephemeral uid/gid which is no
 * longer valid and will need to be replaced with an actual FUID.
 *
 */
static int
zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
{
	ace_t *ace = (ace_t *)(lr + 1);
	vsecattr_t vsa;
	znode_t *zp;
	int error;

	if (byteswap) {
		byteswap_uint64_array(lr, sizeof (*lr));
		zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
		if (lr->lr_fuidcnt) {
			byteswap_uint64_array((caddr_t)ace +
			    ZIL_ACE_LENGTH(lr->lr_acl_bytes),
			    lr->lr_fuidcnt * sizeof (uint64_t));
		}
	}

	if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
		/*
		 * As we can log acls out of order, it's possible the
		 * file has been removed. In this case just drop the acl
		 * and return success.
		 */
		if (error == ENOENT)
			error = 0;
		return (error);
	}

	bzero(&vsa, sizeof (vsa));
	vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
	vsa.vsa_aclcnt = lr->lr_aclcnt;
	vsa.vsa_aclentp = ace;
	vsa.vsa_aclentsz = lr->lr_acl_bytes;
	vsa.vsa_aclflags = lr->lr_acl_flags;

	if (lr->lr_fuidcnt) {
		void *fuidstart = (caddr_t)ace +
		    ZIL_ACE_LENGTH(lr->lr_acl_bytes);

		zfsvfs->z_fuid_replay =
		    zfs_replay_fuids(fuidstart, &fuidstart,
		    lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
	}

	error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);

	if (zfsvfs->z_fuid_replay)
		zfs_fuid_info_free(zfsvfs->z_fuid_replay);

	zfsvfs->z_fuid_replay = NULL;
	VN_RELE(ZTOV(zp));

	return (error);
}
Пример #6
0
/*
 * Set security attributes (acl's)
 *
 * Note that the dv_contents lock has already been acquired
 * by the caller's VOP_RWLOCK.
 */
static int
devfs_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
    struct cred *cr)
{
	dvnode_t *dv = VTODV(vp);
	struct vnode *avp;
	int	error;

	dcmn_err2(("devfs_setsecattr %s\n", dv->dv_name));
	ASSERT(vp->v_type == VDIR || vp->v_type == VCHR || vp->v_type == VBLK);
	ASSERT(RW_LOCK_HELD(&dv->dv_contents));

	/*
	 * Not a supported operation on drivers not providing
	 * file system based permissions.
	 */
	if (dv->dv_flags & DV_NO_FSPERM)
		return (ENOTSUP);

	/*
	 * To complete, the setsecattr requires an underlying attribute node.
	 */
	if (dv->dv_attrvp == NULL) {
		ASSERT(vp->v_type == VCHR || vp->v_type == VBLK);
		dv_shadow_node(DVTOV(dv->dv_dotdot), dv->dv_name, vp,
		    NULL, NULLVP, cr, DV_SHADOW_CREATE | DV_SHADOW_WRITE_HELD);
	}

	if ((avp = dv->dv_attrvp) == NULL) {
		dcmn_err2(("devfs_setsecattr %s: "
		    "cannot construct attribute node\n", dv->dv_name));
		return (fs_nosys());
	}

	/*
	 * The acl(2) system call issues a VOP_RWLOCK before setting an ACL.
	 * Since backing file systems expect the lock to be held before seeing
	 * a VOP_SETSECATTR ACL, we need to issue the VOP_RWLOCK to the backing
	 * store before forwarding the ACL.
	 */
	(void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL);
	error = VOP_SETSECATTR(avp, vsap, flags, cr);
	dsysdebug(error, ("vop_setsecattr %s %d\n", VTODV(vp)->dv_name, error));
	VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL);

	/*
	 * Set DV_ACL if we have a non-trivial set of ACLs.  It is not
	 * necessary to hold VOP_RWLOCK since fs_acl_nontrivial only does
	 * VOP_GETSECATTR calls.
	 */
	if (fs_acl_nontrivial(avp, cr))
		dv->dv_flags |= DV_ACL;
	return (error);
}
Пример #7
0
/* ARGSUSED */
void
acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi,
	struct svc_req *req, cred_t *cr, bool_t ro)
{
	int error;
	vnode_t *vp;
	vattr_t va;

	vp = nfs_fhtovp(&args->fh, exi);
	if (vp == NULL) {
		resp->status = NFSERR_STALE;
		return;
	}

	if (rdonly(ro, vp)) {
		VN_RELE(vp);
		resp->status = NFSERR_ROFS;
		return;
	}

	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
	error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
	if (error) {
		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
		VN_RELE(vp);
		resp->status = puterrno(error);
		return;
	}

	va.va_mask = AT_ALL;
	error = rfs4_delegated_getattr(vp, &va, 0, cr);

	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
	VN_RELE(vp);

	/* check for overflowed values */
	if (!error) {
		error = vattr_to_nattr(&va, &resp->resok.attr);
	}
	if (error) {
		resp->status = puterrno(error);
		return;
	}

	resp->status = NFS_OK;
}
Пример #8
0
/*
 * smb_vop_acl_write
 *
 * Writes the given ACL in aclp for the specified file.
 */
int
smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
{
	int error;
	vsecattr_t vsecattr;
	int aclbsize;

	ASSERT(vp);
	ASSERT(aclp);

	error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize);

	if (error == 0) {
		(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
		error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct);
		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
	}

	if (aclbsize && vsecattr.vsa_aclentp)
		kmem_free(vsecattr.vsa_aclentp, aclbsize);

	return (error);
}