/*ARGSUSED*/ int ptyfs_setattr(void *v) { struct vop_setattr_args /* { struct vnodeop_desc *a_desc; struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct ptyfsnode *ptyfs = VTOPTYFS(vp); struct vattr *vap = ap->a_vap; kauth_cred_t cred = ap->a_cred; struct lwp *l = curlwp; int error; if (vap->va_size != VNOVAL) { switch (ptyfs->ptyfs_type) { case PTYFSroot: return EISDIR; case PTYFSpts: case PTYFSptc: break; default: return EINVAL; } } if (vap->va_flags != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid && (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) != 0) return error; /* Immutable and append-only flags are not supported on ptyfs. */ if (vap->va_flags & (IMMUTABLE | APPEND)) return EINVAL; if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) { /* Snapshot flag cannot be set or cleared */ if ((vap->va_flags & SF_SNAPSHOT) != (ptyfs->ptyfs_flags & SF_SNAPSHOT)) return EPERM; ptyfs->ptyfs_flags = vap->va_flags; } else { if ((ptyfs->ptyfs_flags & SF_SETTABLE) != (vap->va_flags & SF_SETTABLE)) return EPERM; ptyfs->ptyfs_flags &= SF_SETTABLE; ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE); } ptyfs->ptyfs_flag |= PTYFS_CHANGE; } /* * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if (ptyfs->ptyfs_type == PTYFSroot) return EPERM; error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); if (error) return error; } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0) return EPERM; if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid && (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || (error = VOP_ACCESS(vp, VWRITE, cred)) != 0)) return (error); if (vap->va_atime.tv_sec != VNOVAL) if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) ptyfs->ptyfs_flag |= PTYFS_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY; if (vap->va_birthtime.tv_sec != VNOVAL) ptyfs->ptyfs_birthtime = vap->va_birthtime; ptyfs->ptyfs_flag |= PTYFS_CHANGE; error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0); if (error) return error; } if (vap->va_mode != (mode_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if (ptyfs->ptyfs_type == PTYFSroot) return EPERM; if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 && (vap->va_mode & (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH))) return EPERM; error = ptyfs_chmod(vp, vap->va_mode, cred, l); if (error) return error; } VN_KNOTE(vp, NOTE_ATTRIB); return 0; }
/*ARGSUSED*/ int ptyfs_setattr(void *v) { struct vop_setattr_args /* { struct vnodeop_desc *a_desc; struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct ptyfsnode *ptyfs = VTOPTYFS(vp); struct vattr *vap = ap->a_vap; kauth_cred_t cred = ap->a_cred; struct lwp *l = curlwp; int error; kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS; bool changing_sysflags = false; if (vap->va_size != VNOVAL) { switch (ptyfs->ptyfs_type) { case PTYFSroot: return EISDIR; case PTYFSpts: case PTYFSptc: break; default: return EINVAL; } } if (vap->va_flags != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; /* Immutable and append-only flags are not supported on ptyfs. */ if (vap->va_flags & (IMMUTABLE | APPEND)) return EINVAL; /* Snapshot flag cannot be set or cleared */ if ((vap->va_flags & SF_SNAPSHOT) != (ptyfs->ptyfs_flags & SF_SNAPSHOT)) return EPERM; if ((ptyfs->ptyfs_flags & SF_SETTABLE) != (vap->va_flags & SF_SETTABLE)) { changing_sysflags = true; action |= KAUTH_VNODE_WRITE_SYSFLAGS; } error = kauth_authorize_vnode(cred, action, vp, NULL, genfs_can_chflags(cred, vp->v_type, ptyfs->ptyfs_uid, changing_sysflags)); if (error) return error; if (changing_sysflags) { ptyfs->ptyfs_flags = vap->va_flags; } else { ptyfs->ptyfs_flags &= SF_SETTABLE; ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE); } ptyfs->ptyfs_status |= PTYFS_CHANGE; } /* * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if (ptyfs->ptyfs_type == PTYFSroot) return EPERM; error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); if (error) return error; } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_birthtime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0) return EPERM; error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, NULL, genfs_can_chtimes(vp, vap->va_vaflags, ptyfs->ptyfs_uid, cred)); if (error) return (error); if (vap->va_atime.tv_sec != VNOVAL) if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) ptyfs->ptyfs_status |= PTYFS_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) { ptyfs->ptyfs_status |= PTYFS_CHANGE | PTYFS_MODIFY; if (vp->v_mount->mnt_flag & MNT_RELATIME) ptyfs->ptyfs_status |= PTYFS_ACCESS; } if (vap->va_birthtime.tv_sec != VNOVAL) ptyfs->ptyfs_birthtime = vap->va_birthtime; ptyfs->ptyfs_status |= PTYFS_CHANGE; error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0); if (error) return error; } if (vap->va_mode != (mode_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; if (ptyfs->ptyfs_type == PTYFSroot) return EPERM; if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 && (vap->va_mode & (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH))) return EPERM; error = ptyfs_chmod(vp, vap->va_mode, cred, l); if (error) return error; } VN_KNOTE(vp, NOTE_ATTRIB); return 0; }