+/*
+ * Perform access checking for vnodes obtained from file handles that would
+ * refer to files already opened by a Unix client. You cannot just use
+ * vn_writechk() and VOP_ACCESS() for two reasons.
+ * 1 - You must check for M_EXRDONLY as well as M_RDONLY for the write case
+ * 2 - The owner is to be given access irrespective of mode bits so that
+ * processes that chmod after opening a file don't break. I don't like
+ * this because it opens a security hole, but since the nfs server opens
+ * a security hole the size of a barn door anyhow, what the heck.
+ */
+nfsrv_access(vp, flags, cred)
+ register struct vnode *vp;
+ int flags;
+ register struct ucred *cred;
+{
+ struct vattr vattr;
+ int error;
+ if (flags & VWRITE) {
+ /* Just vn_writechk() changed to check M_EXRDONLY */
+ /*
+ * Disallow write attempts on read-only file systems;
+ * unless the file is a socket or a block or character
+ * device resident on the file system.
+ */
+ if ((vp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) &&
+ vp->v_type != VCHR &&
+ vp->v_type != VBLK &&
+ vp->v_type != VSOCK)
+ return (EROFS);
+ /*
+ * If there's shared text associated with
+ * the inode, try to free it up once. If
+ * we fail, we can't allow writing.
+ */
+ if (vp->v_flag & VTEXT)
+ xrele(vp);
+ if (vp->v_flag & VTEXT)
+ return (ETXTBSY);
+ if (error = VOP_GETATTR(vp, &vattr, cred))
+ return (error);
+ if (cred->cr_uid == vattr.va_uid)
+ return (0);
+ } else {
+ if (error = VOP_GETATTR(vp, &vattr, cred))
+ return (error);
+ if (cred->cr_uid == vattr.va_uid)
+ return (0);
+ }
+ return (VOP_ACCESS(vp, flags, cred));
+}