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); }
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); }
/* * 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 }
/* 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); }
/* * 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); }
/* * 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); }
/* 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; }
/* * 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); }