FreeBSD/sys/fs/nfsserver/nfs_nfsdport.c
/*
 * 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_ACCESSX() for two reasons.
 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write
 *     case.
 * 2 - The owner is to be given access irrespective of mode bits for some
 *     operations, so that processes that chmod after opening a file don't
 *     break.
 */
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_ACCESSX() for two reasons.
1 - You must check for exported rdonly as well as MNT_RDONLY for the write
case.
2 - The owner is to be given access irrespective of mode bits for some
operations, so that processes that chmod after opening a file don't
break.
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_ACCESSX () for two reasons . 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case . 2 - The owner is to be given access irrespective of mode bits for some operations so that processes that chmod after opening a file don ' t break .
int
nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
    struct nfsexstuff *exp, struct thread *p, int override, int vpislocked,
    u_int32_t *supportedtypep)
{
	struct vattr vattr;
	int error = 0, getret = 0;
	if (vpislocked == 0) {
		if (NFSVOPLOCK(vp, LK_SHARED) != 0) {
			error = EPERM;
			goto out;
		}
	}
	if (accmode & VWRITE) {
		if (NFSVNO_EXRDONLY(exp) ||
		    (vp->v_mount->mnt_flag & MNT_RDONLY)) {
			switch (vp->v_type) {
			case VREG:
			case VDIR:
			case VLNK:
				error = EROFS;
			default:
				break;
			}
		}
		if (VOP_IS_TEXT(vp) && error == 0)
			error = ETXTBSY;
	}
	if (error != 0) {
		if (vpislocked == 0)
			NFSVOPUNLOCK(vp, 0);
		goto out;
	}
	error = VOP_ACCESSX(vp, accmode, cred, p);
	if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) {
		error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p);
		if (error == 0) {
			if (vp->v_type == VDIR) {
				accmode &= ~(VDELETE | VDELETE_CHILD);
				accmode |= VWRITE;
				error = VOP_ACCESSX(vp, accmode, cred, p);
			} else if (supportedtypep != NULL) {
				*supportedtypep &= ~NFSACCESS_DELETE;
			}
		}
	}
	if (override != NFSACCCHK_NOOVERRIDE &&
	    (error == EPERM || error == EACCES)) {
		if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT))
			error = 0;
		else if (override & NFSACCCHK_ALLOWOWNER) {
			getret = VOP_GETATTR(vp, &vattr, cred);
			if (getret == 0 && cred->cr_uid == vattr.va_uid)
				error = 0;
		}
	}
	if (vpislocked == 0)
		NFSVOPUNLOCK(vp, 0);
out:
	NFSEXITCODE(error);
	return (error);
}
int nfsvno_accchk ( struct vnode * vp , accmode_t accmode , struct ucred * cred , struct nfsexstuff * exp , struct thread * p , int override , int vpislocked , u_int32_t * supportedtypep ) { struct vattr vattr ; int error = 0 , getret = 0 ; if ( vpislocked == 0 ) { if ( NFSVOPLOCK ( vp , LK_SHARED ) != 0 ) { error = EPERM ; goto out ; } } if ( accmode & VWRITE ) { if ( NFSVNO_EXRDONLY ( exp ) || ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) ) { switch ( vp -> v_type ) { case VREG : case VDIR : case VLNK : error = EROFS ; default : break ; } } if ( VOP_IS_TEXT ( vp ) && error == 0 ) error = ETXTBSY ; } if ( error != 0 ) { if ( vpislocked == 0 ) NFSVOPUNLOCK ( vp , 0 ) ; goto out ; } error = VOP_ACCESSX ( vp , accmode , cred , p ) ; if ( error != 0 && ( accmode & ( VDELETE | VDELETE_CHILD ) ) ) { error = VOP_ACCESSX ( vp , accmode | VEXPLICIT_DENY , cred , p ) ; if ( error == 0 ) { if ( vp -> v_type == VDIR ) { accmode &= ~ ( VDELETE | VDELETE_CHILD ) ; accmode |= VWRITE ; error = VOP_ACCESSX ( vp , accmode , cred , p ) ; } else if ( supportedtypep != NULL ) { * supportedtypep &= ~ NFSACCESS_DELETE ; } } } if ( override != NFSACCCHK_NOOVERRIDE && ( error == EPERM || error == EACCES ) ) { if ( cred -> cr_uid == 0 && ( override & NFSACCCHK_ALLOWROOT ) ) error = 0 ; else if ( override & NFSACCCHK_ALLOWOWNER ) { getret = VOP_GETATTR ( vp , & vattr , cred ) ; if ( getret == 0 && cred -> cr_uid == vattr . va_uid ) error = 0 ; } } if ( vpislocked == 0 ) NFSVOPUNLOCK ( vp , 0 ) ; out : NFSEXITCODE ( error ) ; return ( error ) ; }
Perform access checking for vnodes obtained from file handles that would
 refer to files already opened by a Unix client.
Perform access checking for vnodes obtained from file handles that would refer to files already opened by a Unix client .
/* Just vn_writechk() changed to check rdonly */ /*
		 * 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 there's shared text associated with
		 * the inode, try to free it up once.  If
		 * we fail, we can't allow writing.
		 */ /*
	 * Should the override still be applied when ACLs are enabled?
	 */ /*
		 * Try again with VEXPLICIT_DENY, to see if the test for
		 * deletion is supported.
		 */ /*
	 * Allow certain operations for the owner (reads and writes
	 * on files that are already open).
	 */