Ejemplo n.º 1
0
/*
 * Set attribute vnode op. called from several syscalls
 */
int
ext2fs_setattr(void *v)
{
	struct vop_setattr_args /* {
		struct vnode *a_vp;
		struct vattr *a_vap;
		kauth_cred_t a_cred;
	} */ *ap = v;
	struct vattr *vap = ap->a_vap;
	struct vnode *vp = ap->a_vp;
	struct inode *ip = VTOI(vp);
	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;

	/*
	 * Check for unsettable attributes.
	 */
	if ((vap->va_type != VNON) || (vap->va_nlink != (nlink_t)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) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);

		/*
		 * Check if we're allowed to change the flags.
		 * If EXT2FS_SYSTEM_FLAGS is set, then the flags are treated
		 * as system flags, otherwise they're considered to be user
		 * flags.
		 */
#ifdef EXT2FS_SYSTEM_FLAGS
		/* Indicate we're changing system flags if we are. */
		if ((vap->va_flags & SF_APPEND) ||
		     (vap->va_flags & SF_IMMUTABLE)) {
			action |= KAUTH_VNODE_WRITE_SYSFLAGS;
			changing_sysflags = true;
		}

		/* Indicate the node has system flags if it does. */
		if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) {
			action |= KAUTH_VNODE_HAS_SYSFLAGS;
		}
#endif /* EXT2FS_SYSTEM_FLAGS */

		error = kauth_authorize_vnode(cred, action, vp, NULL,
		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
		    changing_sysflags));
		if (error)
			return (error);

#ifdef EXT2FS_SYSTEM_FLAGS
		ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
		ip->i_e2fs_flags |=
		    (vap->va_flags & SF_APPEND) ?  EXT2_APPEND : 0 |
		    (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
#else
		ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
		ip->i_e2fs_flags |=
		    (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
		    (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
#endif
		ip->i_flag |= IN_CHANGE;
		if (vap->va_flags & (IMMUTABLE | APPEND))
			return (0);
	}
	if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
		return (EPERM);
	/*
	 * 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);
		error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
		if (error)
			return (error);
	}
	if (vap->va_size != VNOVAL) {
		/*
		 * Disallow write attempts on read-only file systems;
		 * unless the file is a socket, fifo, or a block or
		 * character device resident on the file system.
		 */
		switch (vp->v_type) {
		case VDIR:
			return (EISDIR);
		case VLNK:
		case VREG:
			if (vp->v_mount->mnt_flag & MNT_RDONLY)
				return (EROFS);
		default:
			break;
		}
		error = ext2fs_truncate(vp, vap->va_size, 0, cred);
		if (error)
			return (error);
	}
	ip = VTOI(vp);
	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid,
		    cred));
		if (error)
			return (error);
		if (vap->va_atime.tv_sec != VNOVAL)
			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
				ip->i_flag |= IN_ACCESS;
		if (vap->va_mtime.tv_sec != VNOVAL) {
			ip->i_flag |= IN_CHANGE | IN_UPDATE;
			if (vp->v_mount->mnt_flag & MNT_RELATIME)
				ip->i_flag |= IN_ACCESS;
		}
		error = ext2fs_update(vp, &vap->va_atime, &vap->va_mtime,
			UPDATE_WAIT);
		if (error)
			return (error);
	}
	error = 0;
	if (vap->va_mode != (mode_t)VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		error = ext2fs_chmod(vp, (int)vap->va_mode, cred, l);
	}
	VN_KNOTE(vp, NOTE_ATTRIB);
	return (error);
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
/*
 * Set attribute vnode op. called from several syscalls
 */
int
ufs_setattr(void *v)
{
	struct vop_setattr_args /* {
		struct vnode	*a_vp;
		struct vattr	*a_vap;
		kauth_cred_t	a_cred;
	} */ *ap = v;
	struct vattr	*vap;
	struct vnode	*vp;
	struct inode	*ip;
	kauth_cred_t	cred;
	struct lwp	*l;
	int		error;
	kauth_action_t	action;
	bool		changing_sysflags;

	vap = ap->a_vap;
	vp = ap->a_vp;
	ip = VTOI(vp);
	cred = ap->a_cred;
	l = curlwp;
	action = KAUTH_VNODE_WRITE_FLAGS;
	changing_sysflags = false;

	/*
	 * Check for unsettable attributes.
	 */
	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);
	}

	fstrans_start(vp->v_mount, FSTRANS_SHARED);

	if (vap->va_flags != VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
			error = EROFS;
			goto out;
		}

		/* Snapshot flag cannot be set or cleared */
		if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
		    (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
			error = EPERM;
			goto out;
		}

		if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
			action |= KAUTH_VNODE_HAS_SYSFLAGS;
		}

		if ((vap->va_flags & SF_SETTABLE) !=
		    (ip->i_flags & SF_SETTABLE)) {
			action |= KAUTH_VNODE_WRITE_SYSFLAGS;
			changing_sysflags = true;
		}

		error = kauth_authorize_vnode(cred, action, vp, NULL,
		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
		    changing_sysflags));
		if (error)
			goto out;

		if (changing_sysflags) {
			error = UFS_WAPBL_BEGIN(vp->v_mount);
			if (error)
				goto out;
			ip->i_flags = vap->va_flags;
			DIP_ASSIGN(ip, flags, ip->i_flags);
		} else {
			error = UFS_WAPBL_BEGIN(vp->v_mount);
			if (error)
				goto out;
			ip->i_flags &= SF_SETTABLE;
			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
			DIP_ASSIGN(ip, flags, ip->i_flags);
		}
		ip->i_flag |= IN_CHANGE;
		UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
		UFS_WAPBL_END(vp->v_mount);
		if (vap->va_flags & (IMMUTABLE | APPEND)) {
			error = 0;
			goto out;
		}
	}
	if (ip->i_flags & (IMMUTABLE | APPEND)) {
		error = EPERM;
		goto out;
	}
	/*
	 * 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) {
			error = EROFS;
			goto out;
		}
		error = UFS_WAPBL_BEGIN(vp->v_mount);
		if (error)
			goto out;
		error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
		UFS_WAPBL_END(vp->v_mount);
		if (error)
			goto out;
	}
	if (vap->va_size != VNOVAL) {
		/*
		 * Disallow write attempts on read-only file systems;
		 * unless the file is a socket, fifo, or a block or
		 * character device resident on the file system.
		 */
		switch (vp->v_type) {
		case VDIR:
			error = EISDIR;
			goto out;
		case VCHR:
		case VBLK:
		case VFIFO:
			break;
		case VREG:
			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
				error = EROFS;
				goto out;
			}
			if ((ip->i_flags & SF_SNAPSHOT) != 0) {
				error = EPERM;
				goto out;
			}
			error = ufs_truncate(vp, vap->va_size, cred);
			if (error)
				goto out;
			break;
		default:
			error = EOPNOTSUPP;
			goto out;
		}
	}
	ip = VTOI(vp);
	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) {
			error = EROFS;
			goto out;
		}
		if ((ip->i_flags & SF_SNAPSHOT) != 0) {
			error = EPERM;
			goto out;
		}
		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
		if (error)
			goto out;
		error = UFS_WAPBL_BEGIN(vp->v_mount);
		if (error)
			goto out;
		if (vap->va_atime.tv_sec != VNOVAL)
			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
				ip->i_flag |= IN_ACCESS;
		if (vap->va_mtime.tv_sec != VNOVAL) {
			ip->i_flag |= IN_CHANGE | IN_UPDATE;
			if (vp->v_mount->mnt_flag & MNT_RELATIME)
				ip->i_flag |= IN_ACCESS;
		}
		if (vap->va_birthtime.tv_sec != VNOVAL &&
		    ip->i_ump->um_fstype == UFS2) {
			ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
			ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
		}
		error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
		UFS_WAPBL_END(vp->v_mount);
		if (error)
			goto out;
	}
	error = 0;
	if (vap->va_mode != (mode_t)VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
			error = EROFS;
			goto out;
		}
		if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
		    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
		     S_IXOTH | S_IWOTH))) {
			error = EPERM;
			goto out;
		}
		error = UFS_WAPBL_BEGIN(vp->v_mount);
		if (error)
			goto out;
		error = ufs_chmod(vp, (int)vap->va_mode, cred, l);
		UFS_WAPBL_END(vp->v_mount);
	}
	VN_KNOTE(vp, NOTE_ATTRIB);
out:
	fstrans_done(vp->v_mount);
	return (error);
}
Ejemplo n.º 4
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;
}