/* * Change the mode on a file. * Inode must be locked before calling. */ static int ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l) { struct ptyfsnode *ptyfs = VTOPTYFS(vp); int error; error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp->v_type, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid, mode)); if (error) return (error); ptyfs->ptyfs_mode &= ~ALLPERMS; ptyfs->ptyfs_mode |= (mode & ALLPERMS); return 0; }
/* * Change the mode on a file. * Inode must be locked before calling. */ static int ext2fs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) { struct inode *ip = VTOI(vp); int error; error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode)); if (error) return (error); ip->i_e2fs_mode &= ~ALLPERMS; ip->i_e2fs_mode |= (mode & ALLPERMS); ip->i_flag |= IN_CHANGE; return (0); }
/* * Change the mode on a file. * Inode must be locked before calling. */ static int ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l) { struct inode *ip; int error; ip = VTOI(vp); error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode)); if (error) return (error); fstrans_start(vp->v_mount, FSTRANS_SHARED); ip->i_mode &= ~ALLPERMS; ip->i_mode |= (mode & ALLPERMS); ip->i_flag |= IN_CHANGE; DIP_ASSIGN(ip, mode, ip->i_mode); fstrans_done(vp->v_mount); return (0); }
/* * Allocate a new inode. */ int ufs_makeinode(int mode, struct vnode *dvp, const struct ufs_lookup_results *ulr, struct vnode **vpp, struct componentname *cnp) { struct inode *ip, *pdir; struct direct *newdir; struct vnode *tvp; int error; UFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount); pdir = VTOI(dvp); if ((mode & IFMT) == 0) mode |= IFREG; if ((error = UFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) { return (error); } tvp = *vpp; ip = VTOI(tvp); ip->i_gid = pdir->i_gid; DIP_ASSIGN(ip, gid, ip->i_gid); ip->i_uid = kauth_cred_geteuid(cnp->cn_cred); DIP_ASSIGN(ip, uid, ip->i_uid); error = UFS_WAPBL_BEGIN1(dvp->v_mount, dvp); if (error) { /* * Note, we can't VOP_VFREE(tvp) here like we should * because we can't write to the disk. Instead, we leave * the vnode dangling from the journal. */ vput(tvp); return (error); } #if defined(QUOTA) || defined(QUOTA2) if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) { UFS_VFREE(tvp, ip->i_number, mode); UFS_WAPBL_END1(dvp->v_mount, dvp); vput(tvp); return (error); } #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; DIP_ASSIGN(ip, mode, mode); tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_nlink = 1; DIP_ASSIGN(ip, nlink, 1); /* Authorize setting SGID if needed. */ if (ip->i_mode & ISGID) { error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid, ip->i_gid, mode)); if (error) { ip->i_mode &= ~ISGID; DIP_ASSIGN(ip, mode, ip->i_mode); } } if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; DIP_ASSIGN(ip, flags, ip->i_flags); } /* * Make sure inode goes to disk before directory entry. */ if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) goto bad; newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); ufs_makedirentry(ip, cnp, newdir); error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, NULL); pool_cache_put(ufs_direct_cache, newdir); if (error) goto bad; *vpp = tvp; return (0); bad: /* * Write error occurred trying to update the inode * or the directory so must deallocate the inode. */ ip->i_nlink = 0; DIP_ASSIGN(ip, nlink, 0); ip->i_flag |= IN_CHANGE; UFS_WAPBL_UPDATE(tvp, NULL, NULL, 0); tvp->v_type = VNON; /* explodes later if VBLK */ UFS_WAPBL_END1(dvp->v_mount, dvp); vput(tvp); return (error); }
/* * Allocate a new inode. */ int ulfs_makeinode(int mode, struct vnode *dvp, const struct ulfs_lookup_results *ulr, struct vnode **vpp, struct componentname *cnp) { struct inode *ip, *pdir; struct lfs_direct *newdir; struct vnode *tvp; int error; pdir = VTOI(dvp); if ((mode & LFS_IFMT) == 0) mode |= LFS_IFREG; if ((error = lfs_valloc(dvp, mode, cnp->cn_cred, vpp)) != 0) { return (error); } tvp = *vpp; ip = VTOI(tvp); ip->i_gid = pdir->i_gid; DIP_ASSIGN(ip, gid, ip->i_gid); ip->i_uid = kauth_cred_geteuid(cnp->cn_cred); DIP_ASSIGN(ip, uid, ip->i_uid); #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) { lfs_vfree(tvp, ip->i_number, mode); vput(tvp); return (error); } #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; DIP_ASSIGN(ip, mode, mode); tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_nlink = 1; DIP_ASSIGN(ip, nlink, 1); /* Authorize setting SGID if needed. */ if (ip->i_mode & ISGID) { error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid, ip->i_gid, mode)); if (error) { ip->i_mode &= ~ISGID; DIP_ASSIGN(ip, mode, ip->i_mode); } } if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; DIP_ASSIGN(ip, flags, ip->i_flags); } /* * Make sure inode goes to disk before directory entry. */ if ((error = lfs_update(tvp, NULL, NULL, UPDATE_DIROP)) != 0) goto bad; newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); ulfs_makedirentry(ip, cnp, newdir); error = ulfs_direnter(dvp, ulr, tvp, newdir, cnp, NULL); pool_cache_put(ulfs_direct_cache, newdir); if (error) goto bad; *vpp = tvp; return (0); bad: /* * Write error occurred trying to update the inode * or the directory so must deallocate the inode. */ ip->i_nlink = 0; DIP_ASSIGN(ip, nlink, 0); ip->i_flag |= IN_CHANGE; /* If IN_ADIROP, account for it */ lfs_unmark_vnode(tvp); tvp->v_type = VNON; /* explodes later if VBLK */ vput(tvp); return (error); }
int sysvbfs_setattr(void *arg) { struct vop_setattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; struct proc *p; } */ *ap = arg; struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct sysvbfs_node *bnode = vp->v_data; struct bfs_inode *inode = bnode->inode; struct bfs_fileattr *attr = &inode->attr; struct bfs *bfs = bnode->bmp->bfs; kauth_cred_t cred = ap->a_cred; int error; DPRINTF("%s:\n", __func__); if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) return EINVAL; if (vap->va_flags != VNOVAL) return EOPNOTSUPP; if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { uid_t uid = (vap->va_uid != (uid_t)VNOVAL) ? vap->va_uid : attr->uid; gid_t gid = (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->gid; error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, genfs_can_chown(cred, attr->uid, attr->gid, uid, gid)); if (error) return error; attr->uid = uid; attr->gid = gid; } if (vap->va_size != VNOVAL) switch (vp->v_type) { case VDIR: return EISDIR; case VCHR: case VBLK: case VFIFO: break; case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; sysvbfs_file_setsize(vp, vap->va_size); break; default: return EOPNOTSUPP; } if (vap->va_mode != (mode_t)VNOVAL) { mode_t mode = vap->va_mode; error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp->v_type, cred, attr->uid, attr->gid, mode)); if (error) return error; attr->mode = mode; } if ((vap->va_atime.tv_sec != VNOVAL) || (vap->va_mtime.tv_sec != VNOVAL) || (vap->va_ctime.tv_sec != VNOVAL)) { error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, NULL, genfs_can_chtimes(vp, vap->va_vaflags, attr->uid, cred)); if (error) return error; if (vap->va_atime.tv_sec != VNOVAL) attr->atime = vap->va_atime.tv_sec; if (vap->va_mtime.tv_sec != VNOVAL) attr->mtime = vap->va_mtime.tv_sec; if (vap->va_ctime.tv_sec != VNOVAL) attr->ctime = vap->va_ctime.tv_sec; } bfs_inode_set_attr(bfs, inode, attr); return 0; }
int v7fs_setattr(void *v) { struct vop_setattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; struct proc *p; } */ *ap = v; struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct v7fs_node *v7node = vp->v_data; struct v7fs_self *fs = v7node->v7fsmount->core; struct v7fs_inode *inode = &v7node->inode; kauth_cred_t cred = ap->a_cred; struct timespec *acc, *mod; int error = 0; acc = mod = NULL; DPRINTF("\n"); if (vp->v_mount->mnt_flag & MNT_RDONLY) { switch (vp->v_type) { default: /* special file is always writable. */ break; case VDIR: case VLNK: case VREG: DPRINTF("read-only mount\n"); return EROFS; } } if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { DPRINTF("invalid request\n"); return EINVAL; } /* File pointer mode. */ if (vap->va_flags != VNOVAL) { error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, vp, NULL, genfs_can_chflags(cred, vp->v_type, inode->uid, false)); if (error) return error; inode->append_mode = vap->va_flags & SF_APPEND; } /* File size change. */ if ((vap->va_size != VNOVAL) && (vp->v_type == VREG)) { error = v7fs_datablock_size_change(fs, vap->va_size, inode); if (error == 0) uvm_vnp_setsize(vp, vap->va_size); } uid_t uid = inode->uid; gid_t gid = inode->gid; if (vap->va_uid != (uid_t)VNOVAL) { uid = vap->va_uid; error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, genfs_can_chown(cred, inode->uid, inode->gid, uid, gid)); if (error) return error; inode->uid = uid; } if (vap->va_gid != (uid_t)VNOVAL) { gid = vap->va_gid; error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, genfs_can_chown(cred, inode->uid, inode->gid, uid, gid)); if (error) return error; inode->gid = gid; } if (vap->va_mode != (mode_t)VNOVAL) { mode_t mode = vap->va_mode; error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, NULL, genfs_can_chmod(vp->v_type, cred, inode->uid, inode->gid, mode)); if (error) { return error; } v7fs_inode_chmod(inode, mode); } if ((vap->va_atime.tv_sec != VNOVAL) || (vap->va_mtime.tv_sec != VNOVAL) || (vap->va_ctime.tv_sec != VNOVAL)) { error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, NULL, genfs_can_chtimes(vp, vap->va_vaflags, inode->uid, cred)); if (error) return error; if (vap->va_atime.tv_sec != VNOVAL) { acc = &vap->va_atime; } if (vap->va_mtime.tv_sec != VNOVAL) { mod = &vap->va_mtime; v7node->update_mtime = true; } if (vap->va_ctime.tv_sec != VNOVAL) { v7node->update_ctime = true; } } v7node->update_atime = true; v7fs_update(vp, acc, mod, 0); return error; }
/* * Allocate a new inode. */ int ulfs_makeinode(struct vattr *vap, struct vnode *dvp, const struct ulfs_lookup_results *ulr, struct vnode **vpp, struct componentname *cnp) { struct inode *ip; struct vnode *tvp; int error; error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, &tvp); if (error) return error; error = vn_lock(tvp, LK_EXCLUSIVE); if (error) { vrele(tvp); return error; } lfs_mark_vnode(tvp); *vpp = tvp; ip = VTOI(tvp); ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_nlink = 1; DIP_ASSIGN(ip, nlink, 1); /* Authorize setting SGID if needed. */ if (ip->i_mode & ISGID) { error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY, tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid, ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode))); if (error) { ip->i_mode &= ~ISGID; DIP_ASSIGN(ip, mode, ip->i_mode); } } if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; DIP_ASSIGN(ip, flags, ip->i_flags); } /* * Make sure inode goes to disk before directory entry. */ if ((error = lfs_update(tvp, NULL, NULL, UPDATE_DIROP)) != 0) goto bad; error = ulfs_direnter(dvp, ulr, tvp, cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL); if (error) goto bad; *vpp = tvp; return (0); bad: /* * Write error occurred trying to update the inode * or the directory so must deallocate the inode. */ ip->i_nlink = 0; DIP_ASSIGN(ip, nlink, 0); ip->i_flag |= IN_CHANGE; /* If IN_ADIROP, account for it */ lfs_unmark_vnode(tvp); vput(tvp); return (error); }