Home | History | Annotate | Line # | Download | only in server
nfs_nfsdserv.c revision 1.1.1.2
      1      1.1  dholland /*	$NetBSD: nfs_nfsdserv.c,v 1.1.1.2 2016/11/18 07:49:14 pgoyette Exp $	*/
      2      1.1  dholland /*-
      3      1.1  dholland  * Copyright (c) 1989, 1993
      4      1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      5      1.1  dholland  *
      6      1.1  dholland  * This code is derived from software contributed to Berkeley by
      7      1.1  dholland  * Rick Macklem at The University of Guelph.
      8      1.1  dholland  *
      9      1.1  dholland  * Redistribution and use in source and binary forms, with or without
     10      1.1  dholland  * modification, are permitted provided that the following conditions
     11      1.1  dholland  * are met:
     12      1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     13      1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     14      1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     16      1.1  dholland  *    documentation and/or other materials provided with the distribution.
     17      1.1  dholland  * 4. Neither the name of the University nor the names of its contributors
     18      1.1  dholland  *    may be used to endorse or promote products derived from this software
     19      1.1  dholland  *    without specific prior written permission.
     20      1.1  dholland  *
     21      1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1  dholland  * SUCH DAMAGE.
     32      1.1  dholland  *
     33      1.1  dholland  */
     34      1.1  dholland 
     35      1.1  dholland #include <sys/cdefs.h>
     36  1.1.1.2  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdserv.c 299514 2016-05-12 05:03:12Z cem "); */
     37      1.1  dholland __RCSID("$NetBSD: nfs_nfsdserv.c,v 1.1.1.2 2016/11/18 07:49:14 pgoyette Exp $");
     38      1.1  dholland 
     39      1.1  dholland /*
     40      1.1  dholland  * nfs version 2, 3 and 4 server calls to vnode ops
     41      1.1  dholland  * - these routines generally have 3 phases
     42      1.1  dholland  *   1 - break down and validate rpc request in mbuf list
     43      1.1  dholland  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
     44      1.1  dholland  *       function in nfsd_port.c
     45      1.1  dholland  *   3 - build the rpc reply in an mbuf list
     46      1.1  dholland  * For nfsv4, these functions are called for each Op within the Compound RPC.
     47      1.1  dholland  */
     48      1.1  dholland 
     49      1.1  dholland #ifndef APPLEKEXT
     50      1.1  dholland #include <fs/nfs/nfsport.h>
     51      1.1  dholland 
     52      1.1  dholland /* Global vars */
     53      1.1  dholland extern u_int32_t newnfs_false, newnfs_true;
     54      1.1  dholland extern enum vtype nv34tov_type[8];
     55      1.1  dholland extern struct timeval nfsboottime;
     56      1.1  dholland extern int nfs_rootfhset;
     57      1.1  dholland extern int nfsrv_enable_crossmntpt;
     58  1.1.1.2  pgoyette extern int nfsrv_statehashsize;
     59      1.1  dholland #endif	/* !APPLEKEXT */
     60      1.1  dholland 
     61      1.1  dholland static int	nfs_async = 0;
     62      1.1  dholland SYSCTL_DECL(_vfs_nfsd);
     63      1.1  dholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
     64      1.1  dholland     "Tell client that writes were synced even though they were not");
     65      1.1  dholland 
     66      1.1  dholland /*
     67      1.1  dholland  * This list defines the GSS mechanisms supported.
     68      1.1  dholland  * (Don't ask me how you get these strings from the RFC stuff like
     69      1.1  dholland  *  iso(1), org(3)... but someone did it, so I don't need to know.)
     70      1.1  dholland  */
     71      1.1  dholland static struct nfsgss_mechlist nfsgss_mechlist[] = {
     72      1.1  dholland 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
     73      1.1  dholland 	{ 0, "", 0 },
     74      1.1  dholland };
     75      1.1  dholland 
     76      1.1  dholland /* local functions */
     77      1.1  dholland static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
     78      1.1  dholland     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
     79      1.1  dholland     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
     80      1.1  dholland     int *diraft_retp, nfsattrbit_t *attrbitp,
     81      1.1  dholland     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
     82      1.1  dholland     int pathlen);
     83      1.1  dholland static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
     84      1.1  dholland     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
     85      1.1  dholland     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
     86      1.1  dholland     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
     87      1.1  dholland     NFSPROC_T *p, struct nfsexstuff *exp);
     88      1.1  dholland 
     89      1.1  dholland /*
     90      1.1  dholland  * nfs access service (not a part of NFS V2)
     91      1.1  dholland  */
     92      1.1  dholland APPLESTATIC int
     93      1.1  dholland nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
     94      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
     95      1.1  dholland {
     96      1.1  dholland 	u_int32_t *tl;
     97      1.1  dholland 	int getret, error = 0;
     98      1.1  dholland 	struct nfsvattr nva;
     99      1.1  dholland 	u_int32_t testmode, nfsmode, supported = 0;
    100      1.1  dholland 	accmode_t deletebit;
    101      1.1  dholland 
    102      1.1  dholland 	if (nd->nd_repstat) {
    103      1.1  dholland 		nfsrv_postopattr(nd, 1, &nva);
    104      1.1  dholland 		goto out;
    105      1.1  dholland 	}
    106      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    107      1.1  dholland 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
    108      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) &&
    109      1.1  dholland 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
    110      1.1  dholland 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
    111      1.1  dholland 	     NFSACCESS_EXECUTE))) {
    112      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
    113      1.1  dholland 		vput(vp);
    114      1.1  dholland 		goto out;
    115      1.1  dholland 	}
    116      1.1  dholland 	if (nfsmode & NFSACCESS_READ) {
    117      1.1  dholland 		supported |= NFSACCESS_READ;
    118      1.1  dholland 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
    119      1.1  dholland 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    120      1.1  dholland 			nfsmode &= ~NFSACCESS_READ;
    121      1.1  dholland 	}
    122      1.1  dholland 	if (nfsmode & NFSACCESS_MODIFY) {
    123      1.1  dholland 		supported |= NFSACCESS_MODIFY;
    124      1.1  dholland 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
    125      1.1  dholland 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    126      1.1  dholland 			nfsmode &= ~NFSACCESS_MODIFY;
    127      1.1  dholland 	}
    128      1.1  dholland 	if (nfsmode & NFSACCESS_EXTEND) {
    129      1.1  dholland 		supported |= NFSACCESS_EXTEND;
    130      1.1  dholland 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
    131      1.1  dholland 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    132      1.1  dholland 			nfsmode &= ~NFSACCESS_EXTEND;
    133      1.1  dholland 	}
    134      1.1  dholland 	if (nfsmode & NFSACCESS_DELETE) {
    135      1.1  dholland 		supported |= NFSACCESS_DELETE;
    136      1.1  dholland 		if (vp->v_type == VDIR)
    137      1.1  dholland 			deletebit = VDELETE_CHILD;
    138      1.1  dholland 		else
    139      1.1  dholland 			deletebit = VDELETE;
    140      1.1  dholland 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
    141      1.1  dholland 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    142      1.1  dholland 			nfsmode &= ~NFSACCESS_DELETE;
    143      1.1  dholland 	}
    144      1.1  dholland 	if (vnode_vtype(vp) == VDIR)
    145      1.1  dholland 		testmode = NFSACCESS_LOOKUP;
    146      1.1  dholland 	else
    147      1.1  dholland 		testmode = NFSACCESS_EXECUTE;
    148      1.1  dholland 	if (nfsmode & testmode) {
    149      1.1  dholland 		supported |= (nfsmode & testmode);
    150      1.1  dholland 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
    151      1.1  dholland 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
    152      1.1  dholland 			nfsmode &= ~testmode;
    153      1.1  dholland 	}
    154      1.1  dholland 	nfsmode &= supported;
    155      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
    156      1.1  dholland 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    157      1.1  dholland 		nfsrv_postopattr(nd, getret, &nva);
    158      1.1  dholland 	}
    159      1.1  dholland 	vput(vp);
    160      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    161      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    162      1.1  dholland 		*tl++ = txdr_unsigned(supported);
    163      1.1  dholland 	} else
    164      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    165      1.1  dholland 	*tl = txdr_unsigned(nfsmode);
    166      1.1  dholland 
    167      1.1  dholland out:
    168      1.1  dholland 	NFSEXITCODE2(0, nd);
    169      1.1  dholland 	return (0);
    170      1.1  dholland nfsmout:
    171      1.1  dholland 	vput(vp);
    172      1.1  dholland 	NFSEXITCODE2(error, nd);
    173      1.1  dholland 	return (error);
    174      1.1  dholland }
    175      1.1  dholland 
    176      1.1  dholland /*
    177      1.1  dholland  * nfs getattr service
    178      1.1  dholland  */
    179      1.1  dholland APPLESTATIC int
    180      1.1  dholland nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
    181      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
    182      1.1  dholland {
    183      1.1  dholland 	struct nfsvattr nva;
    184      1.1  dholland 	fhandle_t fh;
    185      1.1  dholland 	int at_root = 0, error = 0, supports_nfsv4acls;
    186      1.1  dholland 	struct nfsreferral *refp;
    187      1.1  dholland 	nfsattrbit_t attrbits, tmpbits;
    188      1.1  dholland 	struct mount *mp;
    189      1.1  dholland 	struct vnode *tvp = NULL;
    190      1.1  dholland 	struct vattr va;
    191      1.1  dholland 	uint64_t mounted_on_fileno = 0;
    192      1.1  dholland 	accmode_t accmode;
    193      1.1  dholland 
    194      1.1  dholland 	if (nd->nd_repstat)
    195      1.1  dholland 		goto out;
    196      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    197      1.1  dholland 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
    198      1.1  dholland 		if (error) {
    199      1.1  dholland 			vput(vp);
    200      1.1  dholland 			goto out;
    201      1.1  dholland 		}
    202      1.1  dholland 
    203      1.1  dholland 		/*
    204      1.1  dholland 		 * Check for a referral.
    205      1.1  dholland 		 */
    206      1.1  dholland 		refp = nfsv4root_getreferral(vp, NULL, 0);
    207      1.1  dholland 		if (refp != NULL) {
    208      1.1  dholland 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
    209      1.1  dholland 			    &nd->nd_repstat);
    210      1.1  dholland 			vput(vp);
    211      1.1  dholland 			goto out;
    212      1.1  dholland 		}
    213      1.1  dholland 		if (nd->nd_repstat == 0) {
    214      1.1  dholland 			accmode = 0;
    215      1.1  dholland 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
    216  1.1.1.2  pgoyette 
    217  1.1.1.2  pgoyette 			/*
    218  1.1.1.2  pgoyette 			 * GETATTR with write-only attr time_access_set and time_modify_set
    219  1.1.1.2  pgoyette 			 * should return NFS4ERR_INVAL.
    220  1.1.1.2  pgoyette 			 */
    221  1.1.1.2  pgoyette 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
    222  1.1.1.2  pgoyette 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
    223  1.1.1.2  pgoyette 				error = NFSERR_INVAL;
    224  1.1.1.2  pgoyette 				vput(vp);
    225  1.1.1.2  pgoyette 				goto out;
    226  1.1.1.2  pgoyette 			}
    227      1.1  dholland 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
    228      1.1  dholland 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
    229      1.1  dholland 				accmode |= VREAD_ACL;
    230      1.1  dholland 			}
    231      1.1  dholland 			if (NFSNONZERO_ATTRBIT(&tmpbits))
    232      1.1  dholland 				accmode |= VREAD_ATTRIBUTES;
    233      1.1  dholland 			if (accmode != 0)
    234      1.1  dholland 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
    235      1.1  dholland 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
    236      1.1  dholland 				    NFSACCCHK_VPISLOCKED, NULL);
    237      1.1  dholland 		}
    238      1.1  dholland 	}
    239      1.1  dholland 	if (!nd->nd_repstat)
    240      1.1  dholland 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    241      1.1  dholland 	if (!nd->nd_repstat) {
    242      1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
    243      1.1  dholland 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
    244      1.1  dholland 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
    245      1.1  dholland 			if (!nd->nd_repstat)
    246      1.1  dholland 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
    247      1.1  dholland 				    &nva, &attrbits, nd->nd_cred, p);
    248      1.1  dholland 			if (nd->nd_repstat == 0) {
    249      1.1  dholland 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
    250      1.1  dholland 				mp = vp->v_mount;
    251      1.1  dholland 				if (nfsrv_enable_crossmntpt != 0 &&
    252      1.1  dholland 				    vp->v_type == VDIR &&
    253      1.1  dholland 				    (vp->v_vflag & VV_ROOT) != 0 &&
    254      1.1  dholland 				    vp != rootvnode) {
    255      1.1  dholland 					tvp = mp->mnt_vnodecovered;
    256      1.1  dholland 					VREF(tvp);
    257      1.1  dholland 					at_root = 1;
    258      1.1  dholland 				} else
    259      1.1  dholland 					at_root = 0;
    260      1.1  dholland 				vfs_ref(mp);
    261      1.1  dholland 				NFSVOPUNLOCK(vp, 0);
    262      1.1  dholland 				if (at_root != 0) {
    263      1.1  dholland 					if ((nd->nd_repstat =
    264      1.1  dholland 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
    265      1.1  dholland 						nd->nd_repstat = VOP_GETATTR(
    266      1.1  dholland 						    tvp, &va, nd->nd_cred);
    267      1.1  dholland 						vput(tvp);
    268      1.1  dholland 					} else
    269      1.1  dholland 						vrele(tvp);
    270      1.1  dholland 					if (nd->nd_repstat == 0)
    271      1.1  dholland 						mounted_on_fileno = (uint64_t)
    272      1.1  dholland 						    va.va_fileid;
    273      1.1  dholland 					else
    274      1.1  dholland 						at_root = 0;
    275      1.1  dholland 				}
    276      1.1  dholland 				if (nd->nd_repstat == 0)
    277      1.1  dholland 					nd->nd_repstat = vfs_busy(mp, 0);
    278      1.1  dholland 				vfs_rel(mp);
    279      1.1  dholland 				if (nd->nd_repstat == 0) {
    280      1.1  dholland 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
    281      1.1  dholland 					    &fh, 0, &attrbits, nd->nd_cred, p,
    282      1.1  dholland 					    isdgram, 1, supports_nfsv4acls,
    283      1.1  dholland 					    at_root, mounted_on_fileno);
    284      1.1  dholland 					vfs_unbusy(mp);
    285      1.1  dholland 				}
    286      1.1  dholland 				vrele(vp);
    287      1.1  dholland 			} else
    288      1.1  dholland 				vput(vp);
    289      1.1  dholland 		} else {
    290      1.1  dholland 			nfsrv_fillattr(nd, &nva);
    291      1.1  dholland 			vput(vp);
    292      1.1  dholland 		}
    293      1.1  dholland 	} else {
    294      1.1  dholland 		vput(vp);
    295      1.1  dholland 	}
    296      1.1  dholland 
    297      1.1  dholland out:
    298      1.1  dholland 	NFSEXITCODE2(error, nd);
    299      1.1  dholland 	return (error);
    300      1.1  dholland }
    301      1.1  dholland 
    302      1.1  dholland /*
    303      1.1  dholland  * nfs setattr service
    304      1.1  dholland  */
    305      1.1  dholland APPLESTATIC int
    306      1.1  dholland nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
    307      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    308      1.1  dholland {
    309      1.1  dholland 	struct nfsvattr nva, nva2;
    310      1.1  dholland 	u_int32_t *tl;
    311      1.1  dholland 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
    312      1.1  dholland 	struct timespec guard = { 0, 0 };
    313      1.1  dholland 	nfsattrbit_t attrbits, retbits;
    314      1.1  dholland 	nfsv4stateid_t stateid;
    315      1.1  dholland 	NFSACL_T *aclp = NULL;
    316      1.1  dholland 
    317      1.1  dholland 	if (nd->nd_repstat) {
    318      1.1  dholland 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    319      1.1  dholland 		goto out;
    320      1.1  dholland 	}
    321      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
    322      1.1  dholland 	aclp = acl_alloc(M_WAITOK);
    323      1.1  dholland 	aclp->acl_cnt = 0;
    324      1.1  dholland #endif
    325      1.1  dholland 	NFSVNO_ATTRINIT(&nva);
    326      1.1  dholland 	NFSZERO_ATTRBIT(&retbits);
    327      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    328      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
    329      1.1  dholland 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    330      1.1  dholland 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
    331      1.1  dholland 	}
    332  1.1.1.2  pgoyette 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
    333      1.1  dholland 	if (error)
    334      1.1  dholland 		goto nfsmout;
    335      1.1  dholland 	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
    336      1.1  dholland 	if (!nd->nd_repstat)
    337      1.1  dholland 		nd->nd_repstat = preat_ret;
    338      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
    339      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
    340      1.1  dholland 		gcheck = fxdr_unsigned(int, *tl);
    341      1.1  dholland 		if (gcheck) {
    342      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    343      1.1  dholland 			fxdr_nfsv3time(tl, &guard);
    344      1.1  dholland 		}
    345      1.1  dholland 		if (!nd->nd_repstat && gcheck &&
    346      1.1  dholland 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
    347      1.1  dholland 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
    348      1.1  dholland 			nd->nd_repstat = NFSERR_NOT_SYNC;
    349      1.1  dholland 		if (nd->nd_repstat) {
    350      1.1  dholland 			vput(vp);
    351      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
    352      1.1  dholland 			acl_free(aclp);
    353      1.1  dholland #endif
    354      1.1  dholland 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    355      1.1  dholland 			goto out;
    356      1.1  dholland 		}
    357      1.1  dholland 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
    358      1.1  dholland 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
    359      1.1  dholland 
    360      1.1  dholland 	/*
    361      1.1  dholland 	 * Now that we have all the fields, lets do it.
    362      1.1  dholland 	 * If the size is being changed write access is required, otherwise
    363      1.1  dholland 	 * just check for a read only file system.
    364      1.1  dholland 	 */
    365      1.1  dholland 	if (!nd->nd_repstat) {
    366      1.1  dholland 		if (NFSVNO_NOTSETSIZE(&nva)) {
    367      1.1  dholland 			if (NFSVNO_EXRDONLY(exp) ||
    368      1.1  dholland 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
    369      1.1  dholland 				nd->nd_repstat = EROFS;
    370      1.1  dholland 		} else {
    371      1.1  dholland 			if (vnode_vtype(vp) != VREG)
    372      1.1  dholland 				nd->nd_repstat = EINVAL;
    373      1.1  dholland 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
    374      1.1  dholland 			    NFSVNO_EXSTRICTACCESS(exp))
    375      1.1  dholland 				nd->nd_repstat = nfsvno_accchk(vp,
    376      1.1  dholland 				    VWRITE, nd->nd_cred, exp, p,
    377      1.1  dholland 				    NFSACCCHK_NOOVERRIDE,
    378      1.1  dholland 				    NFSACCCHK_VPISLOCKED, NULL);
    379      1.1  dholland 		}
    380      1.1  dholland 	}
    381      1.1  dholland 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
    382      1.1  dholland 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
    383      1.1  dholland 		    &nva, &attrbits, exp, p);
    384      1.1  dholland 
    385      1.1  dholland 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
    386      1.1  dholland 	    /*
    387      1.1  dholland 	     * For V4, try setting the attrbutes in sets, so that the
    388      1.1  dholland 	     * reply bitmap will be correct for an error case.
    389      1.1  dholland 	     */
    390      1.1  dholland 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
    391      1.1  dholland 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
    392      1.1  dholland 		NFSVNO_ATTRINIT(&nva2);
    393      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
    394      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
    395      1.1  dholland 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    396      1.1  dholland 		    exp);
    397      1.1  dholland 		if (!nd->nd_repstat) {
    398      1.1  dholland 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
    399      1.1  dholland 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
    400      1.1  dholland 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
    401      1.1  dholland 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
    402      1.1  dholland 		}
    403      1.1  dholland 	    }
    404      1.1  dholland 	    if (!nd->nd_repstat &&
    405      1.1  dholland 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
    406      1.1  dholland 		NFSVNO_ATTRINIT(&nva2);
    407      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
    408      1.1  dholland 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    409      1.1  dholland 		    exp);
    410      1.1  dholland 		if (!nd->nd_repstat)
    411      1.1  dholland 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
    412      1.1  dholland 	    }
    413      1.1  dholland 	    if (!nd->nd_repstat &&
    414      1.1  dholland 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
    415      1.1  dholland 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
    416      1.1  dholland 		NFSVNO_ATTRINIT(&nva2);
    417      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
    418      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
    419      1.1  dholland 		if (nva.na_vaflags & VA_UTIMES_NULL) {
    420      1.1  dholland 			nva2.na_vaflags |= VA_UTIMES_NULL;
    421      1.1  dholland 			NFSVNO_SETACTIVE(&nva2, vaflags);
    422      1.1  dholland 		}
    423      1.1  dholland 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    424      1.1  dholland 		    exp);
    425      1.1  dholland 		if (!nd->nd_repstat) {
    426      1.1  dholland 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
    427      1.1  dholland 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
    428      1.1  dholland 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
    429      1.1  dholland 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
    430      1.1  dholland 		}
    431      1.1  dholland 	    }
    432      1.1  dholland 	    if (!nd->nd_repstat &&
    433      1.1  dholland 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
    434      1.1  dholland 		NFSVNO_ATTRINIT(&nva2);
    435      1.1  dholland 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
    436      1.1  dholland 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
    437      1.1  dholland 		    exp);
    438      1.1  dholland 		if (!nd->nd_repstat)
    439      1.1  dholland 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
    440      1.1  dholland 	    }
    441      1.1  dholland 
    442      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
    443      1.1  dholland 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
    444      1.1  dholland 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
    445      1.1  dholland 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
    446      1.1  dholland 		if (!nd->nd_repstat)
    447      1.1  dholland 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
    448      1.1  dholland 	    }
    449      1.1  dholland #endif
    450      1.1  dholland 	} else if (!nd->nd_repstat) {
    451      1.1  dholland 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
    452      1.1  dholland 		    exp);
    453      1.1  dholland 	}
    454      1.1  dholland 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
    455      1.1  dholland 		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    456      1.1  dholland 		if (!nd->nd_repstat)
    457      1.1  dholland 			nd->nd_repstat = postat_ret;
    458      1.1  dholland 	}
    459      1.1  dholland 	vput(vp);
    460      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
    461      1.1  dholland 	acl_free(aclp);
    462      1.1  dholland #endif
    463      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
    464      1.1  dholland 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
    465      1.1  dholland 	else if (nd->nd_flag & ND_NFSV4)
    466      1.1  dholland 		(void) nfsrv_putattrbit(nd, &retbits);
    467      1.1  dholland 	else if (!nd->nd_repstat)
    468      1.1  dholland 		nfsrv_fillattr(nd, &nva);
    469      1.1  dholland 
    470      1.1  dholland out:
    471      1.1  dholland 	NFSEXITCODE2(0, nd);
    472      1.1  dholland 	return (0);
    473      1.1  dholland nfsmout:
    474      1.1  dholland 	vput(vp);
    475      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
    476      1.1  dholland 	acl_free(aclp);
    477      1.1  dholland #endif
    478      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    479      1.1  dholland 		/*
    480      1.1  dholland 		 * For all nd_repstat, the V4 reply includes a bitmap,
    481      1.1  dholland 		 * even NFSERR_BADXDR, which is what this will end up
    482      1.1  dholland 		 * returning.
    483      1.1  dholland 		 */
    484      1.1  dholland 		(void) nfsrv_putattrbit(nd, &retbits);
    485      1.1  dholland 	}
    486      1.1  dholland 	NFSEXITCODE2(error, nd);
    487      1.1  dholland 	return (error);
    488      1.1  dholland }
    489      1.1  dholland 
    490      1.1  dholland /*
    491      1.1  dholland  * nfs lookup rpc
    492      1.1  dholland  * (Also performs lookup parent for v4)
    493      1.1  dholland  */
    494      1.1  dholland APPLESTATIC int
    495      1.1  dholland nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
    496      1.1  dholland     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
    497      1.1  dholland     struct nfsexstuff *exp)
    498      1.1  dholland {
    499      1.1  dholland 	struct nameidata named;
    500      1.1  dholland 	vnode_t vp, dirp = NULL;
    501      1.1  dholland 	int error = 0, dattr_ret = 1;
    502      1.1  dholland 	struct nfsvattr nva, dattr;
    503      1.1  dholland 	char *bufp;
    504      1.1  dholland 	u_long *hashp;
    505      1.1  dholland 
    506      1.1  dholland 	if (nd->nd_repstat) {
    507      1.1  dholland 		nfsrv_postopattr(nd, dattr_ret, &dattr);
    508      1.1  dholland 		goto out;
    509      1.1  dholland 	}
    510      1.1  dholland 
    511      1.1  dholland 	/*
    512      1.1  dholland 	 * For some reason, if dp is a symlink, the error
    513      1.1  dholland 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
    514      1.1  dholland 	 */
    515      1.1  dholland 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
    516      1.1  dholland 		nd->nd_repstat = NFSERR_SYMLINK;
    517      1.1  dholland 		vrele(dp);
    518      1.1  dholland 		goto out;
    519      1.1  dholland 	}
    520      1.1  dholland 
    521      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
    522      1.1  dholland 	    LOCKLEAF | SAVESTART);
    523      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
    524      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
    525      1.1  dholland 	if (error) {
    526      1.1  dholland 		vrele(dp);
    527      1.1  dholland 		nfsvno_relpathbuf(&named);
    528      1.1  dholland 		goto out;
    529      1.1  dholland 	}
    530      1.1  dholland 	if (!nd->nd_repstat) {
    531      1.1  dholland 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
    532      1.1  dholland 	} else {
    533      1.1  dholland 		vrele(dp);
    534      1.1  dholland 		nfsvno_relpathbuf(&named);
    535      1.1  dholland 	}
    536      1.1  dholland 	if (nd->nd_repstat) {
    537      1.1  dholland 		if (dirp) {
    538      1.1  dholland 			if (nd->nd_flag & ND_NFSV3)
    539      1.1  dholland 				dattr_ret = nfsvno_getattr(dirp, &dattr,
    540      1.1  dholland 				    nd->nd_cred, p, 0);
    541      1.1  dholland 			vrele(dirp);
    542      1.1  dholland 		}
    543      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    544      1.1  dholland 			nfsrv_postopattr(nd, dattr_ret, &dattr);
    545      1.1  dholland 		goto out;
    546      1.1  dholland 	}
    547      1.1  dholland 	if (named.ni_startdir)
    548      1.1  dholland 		vrele(named.ni_startdir);
    549      1.1  dholland 	nfsvno_relpathbuf(&named);
    550      1.1  dholland 	vp = named.ni_vp;
    551      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
    552      1.1  dholland 	    vp->v_type != VDIR && vp->v_type != VLNK)
    553      1.1  dholland 		/*
    554      1.1  dholland 		 * Only allow lookup of VDIR and VLNK for traversal of
    555      1.1  dholland 		 * non-exported volumes during NFSv4 mounting.
    556      1.1  dholland 		 */
    557      1.1  dholland 		nd->nd_repstat = ENOENT;
    558      1.1  dholland 	if (nd->nd_repstat == 0)
    559      1.1  dholland 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
    560      1.1  dholland 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
    561      1.1  dholland 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    562      1.1  dholland 	if (vpp != NULL && nd->nd_repstat == 0)
    563      1.1  dholland 		*vpp = vp;
    564      1.1  dholland 	else
    565      1.1  dholland 		vput(vp);
    566      1.1  dholland 	if (dirp) {
    567      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    568      1.1  dholland 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
    569      1.1  dholland 			    p, 0);
    570      1.1  dholland 		vrele(dirp);
    571      1.1  dholland 	}
    572      1.1  dholland 	if (nd->nd_repstat) {
    573      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    574      1.1  dholland 			nfsrv_postopattr(nd, dattr_ret, &dattr);
    575      1.1  dholland 		goto out;
    576      1.1  dholland 	}
    577      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
    578      1.1  dholland 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
    579      1.1  dholland 		nfsrv_fillattr(nd, &nva);
    580      1.1  dholland 	} else if (nd->nd_flag & ND_NFSV3) {
    581      1.1  dholland 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
    582      1.1  dholland 		nfsrv_postopattr(nd, 0, &nva);
    583      1.1  dholland 		nfsrv_postopattr(nd, dattr_ret, &dattr);
    584      1.1  dholland 	}
    585      1.1  dholland 
    586      1.1  dholland out:
    587      1.1  dholland 	NFSEXITCODE2(error, nd);
    588      1.1  dholland 	return (error);
    589      1.1  dholland }
    590      1.1  dholland 
    591      1.1  dholland /*
    592      1.1  dholland  * nfs readlink service
    593      1.1  dholland  */
    594      1.1  dholland APPLESTATIC int
    595      1.1  dholland nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
    596      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
    597      1.1  dholland {
    598      1.1  dholland 	u_int32_t *tl;
    599      1.1  dholland 	mbuf_t mp = NULL, mpend = NULL;
    600      1.1  dholland 	int getret = 1, len;
    601      1.1  dholland 	struct nfsvattr nva;
    602      1.1  dholland 
    603      1.1  dholland 	if (nd->nd_repstat) {
    604      1.1  dholland 		nfsrv_postopattr(nd, getret, &nva);
    605      1.1  dholland 		goto out;
    606      1.1  dholland 	}
    607      1.1  dholland 	if (vnode_vtype(vp) != VLNK) {
    608      1.1  dholland 		if (nd->nd_flag & ND_NFSV2)
    609      1.1  dholland 			nd->nd_repstat = ENXIO;
    610      1.1  dholland 		else
    611      1.1  dholland 			nd->nd_repstat = EINVAL;
    612      1.1  dholland 	}
    613      1.1  dholland 	if (!nd->nd_repstat)
    614      1.1  dholland 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
    615      1.1  dholland 		    &mp, &mpend, &len);
    616      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
    617      1.1  dholland 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    618      1.1  dholland 	vput(vp);
    619      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
    620      1.1  dholland 		nfsrv_postopattr(nd, getret, &nva);
    621      1.1  dholland 	if (nd->nd_repstat)
    622      1.1  dholland 		goto out;
    623      1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    624      1.1  dholland 	*tl = txdr_unsigned(len);
    625      1.1  dholland 	mbuf_setnext(nd->nd_mb, mp);
    626      1.1  dholland 	nd->nd_mb = mpend;
    627      1.1  dholland 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
    628      1.1  dholland 
    629      1.1  dholland out:
    630      1.1  dholland 	NFSEXITCODE2(0, nd);
    631      1.1  dholland 	return (0);
    632      1.1  dholland }
    633      1.1  dholland 
    634      1.1  dholland /*
    635      1.1  dholland  * nfs read service
    636      1.1  dholland  */
    637      1.1  dholland APPLESTATIC int
    638      1.1  dholland nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
    639      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    640      1.1  dholland {
    641      1.1  dholland 	u_int32_t *tl;
    642      1.1  dholland 	int error = 0, cnt, getret = 1, reqlen, eof = 0;
    643      1.1  dholland 	mbuf_t m2, m3;
    644      1.1  dholland 	struct nfsvattr nva;
    645      1.1  dholland 	off_t off = 0x0;
    646      1.1  dholland 	struct nfsstate st, *stp = &st;
    647      1.1  dholland 	struct nfslock lo, *lop = &lo;
    648      1.1  dholland 	nfsv4stateid_t stateid;
    649      1.1  dholland 	nfsquad_t clientid;
    650      1.1  dholland 
    651      1.1  dholland 	if (nd->nd_repstat) {
    652      1.1  dholland 		nfsrv_postopattr(nd, getret, &nva);
    653      1.1  dholland 		goto out;
    654      1.1  dholland 	}
    655      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
    656      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    657      1.1  dholland 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
    658      1.1  dholland 		reqlen = fxdr_unsigned(int, *tl);
    659      1.1  dholland 	} else if (nd->nd_flag & ND_NFSV3) {
    660      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
    661      1.1  dholland 		off = fxdr_hyper(tl);
    662      1.1  dholland 		tl += 2;
    663      1.1  dholland 		reqlen = fxdr_unsigned(int, *tl);
    664      1.1  dholland 	} else {
    665      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
    666      1.1  dholland 		reqlen = fxdr_unsigned(int, *(tl + 6));
    667      1.1  dholland 	}
    668      1.1  dholland 	if (reqlen > NFS_SRVMAXDATA(nd)) {
    669      1.1  dholland 		reqlen = NFS_SRVMAXDATA(nd);
    670      1.1  dholland 	} else if (reqlen < 0) {
    671      1.1  dholland 		error = EBADRPC;
    672      1.1  dholland 		goto nfsmout;
    673      1.1  dholland 	}
    674      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
    675      1.1  dholland 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
    676      1.1  dholland 		lop->lo_flags = NFSLCK_READ;
    677      1.1  dholland 		stp->ls_ownerlen = 0;
    678      1.1  dholland 		stp->ls_op = NULL;
    679      1.1  dholland 		stp->ls_uid = nd->nd_cred->cr_uid;
    680      1.1  dholland 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    681      1.1  dholland 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
    682      1.1  dholland 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
    683  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
    684  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    685  1.1.1.2  pgoyette 				clientid.qval = nd->nd_clientid.qval;
    686  1.1.1.2  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
    687  1.1.1.2  pgoyette 				printf("EEK1 multiple clids\n");
    688      1.1  dholland 		} else {
    689  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    690  1.1.1.2  pgoyette 				printf("EEK! no clientid from session\n");
    691      1.1  dholland 			nd->nd_flag |= ND_IMPLIEDCLID;
    692      1.1  dholland 			nd->nd_clientid.qval = clientid.qval;
    693      1.1  dholland 		}
    694      1.1  dholland 		stp->ls_stateid.other[2] = *tl++;
    695      1.1  dholland 		off = fxdr_hyper(tl);
    696      1.1  dholland 		lop->lo_first = off;
    697      1.1  dholland 		tl += 2;
    698      1.1  dholland 		lop->lo_end = off + reqlen;
    699      1.1  dholland 		/*
    700      1.1  dholland 		 * Paranoia, just in case it wraps around.
    701      1.1  dholland 		 */
    702      1.1  dholland 		if (lop->lo_end < off)
    703      1.1  dholland 			lop->lo_end = NFS64BITSSET;
    704      1.1  dholland 	}
    705      1.1  dholland 	if (vnode_vtype(vp) != VREG) {
    706      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    707      1.1  dholland 			nd->nd_repstat = EINVAL;
    708      1.1  dholland 		else
    709      1.1  dholland 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
    710      1.1  dholland 			    EINVAL;
    711      1.1  dholland 	}
    712      1.1  dholland 	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    713      1.1  dholland 	if (!nd->nd_repstat)
    714      1.1  dholland 		nd->nd_repstat = getret;
    715      1.1  dholland 	if (!nd->nd_repstat &&
    716      1.1  dholland 	    (nva.na_uid != nd->nd_cred->cr_uid ||
    717      1.1  dholland 	     NFSVNO_EXSTRICTACCESS(exp))) {
    718      1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
    719      1.1  dholland 		    nd->nd_cred, exp, p,
    720      1.1  dholland 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
    721      1.1  dholland 		if (nd->nd_repstat)
    722      1.1  dholland 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
    723      1.1  dholland 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
    724      1.1  dholland 			    NFSACCCHK_VPISLOCKED, NULL);
    725      1.1  dholland 	}
    726      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
    727      1.1  dholland 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
    728      1.1  dholland 		    &stateid, exp, nd, p);
    729      1.1  dholland 	if (nd->nd_repstat) {
    730      1.1  dholland 		vput(vp);
    731      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    732      1.1  dholland 			nfsrv_postopattr(nd, getret, &nva);
    733      1.1  dholland 		goto out;
    734      1.1  dholland 	}
    735      1.1  dholland 	if (off >= nva.na_size) {
    736      1.1  dholland 		cnt = 0;
    737      1.1  dholland 		eof = 1;
    738      1.1  dholland 	} else if (reqlen == 0)
    739      1.1  dholland 		cnt = 0;
    740      1.1  dholland 	else if ((off + reqlen) >= nva.na_size) {
    741      1.1  dholland 		cnt = nva.na_size - off;
    742      1.1  dholland 		eof = 1;
    743      1.1  dholland 	} else
    744      1.1  dholland 		cnt = reqlen;
    745      1.1  dholland 	m3 = NULL;
    746      1.1  dholland 	if (cnt > 0) {
    747      1.1  dholland 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
    748      1.1  dholland 		    &m3, &m2);
    749      1.1  dholland 		if (!(nd->nd_flag & ND_NFSV4)) {
    750      1.1  dholland 			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    751      1.1  dholland 			if (!nd->nd_repstat)
    752      1.1  dholland 				nd->nd_repstat = getret;
    753      1.1  dholland 		}
    754      1.1  dholland 		if (nd->nd_repstat) {
    755      1.1  dholland 			vput(vp);
    756      1.1  dholland 			if (m3)
    757      1.1  dholland 				mbuf_freem(m3);
    758      1.1  dholland 			if (nd->nd_flag & ND_NFSV3)
    759      1.1  dholland 				nfsrv_postopattr(nd, getret, &nva);
    760      1.1  dholland 			goto out;
    761      1.1  dholland 		}
    762      1.1  dholland 	}
    763      1.1  dholland 	vput(vp);
    764      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
    765      1.1  dholland 		nfsrv_fillattr(nd, &nva);
    766      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
    767      1.1  dholland 	} else {
    768      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
    769      1.1  dholland 			nfsrv_postopattr(nd, getret, &nva);
    770      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
    771      1.1  dholland 			*tl++ = txdr_unsigned(cnt);
    772      1.1  dholland 		} else
    773      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    774      1.1  dholland 		if (eof)
    775      1.1  dholland 			*tl++ = newnfs_true;
    776      1.1  dholland 		else
    777      1.1  dholland 			*tl++ = newnfs_false;
    778      1.1  dholland 	}
    779      1.1  dholland 	*tl = txdr_unsigned(cnt);
    780      1.1  dholland 	if (m3) {
    781      1.1  dholland 		mbuf_setnext(nd->nd_mb, m3);
    782      1.1  dholland 		nd->nd_mb = m2;
    783      1.1  dholland 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
    784      1.1  dholland 	}
    785      1.1  dholland 
    786      1.1  dholland out:
    787      1.1  dholland 	NFSEXITCODE2(0, nd);
    788      1.1  dholland 	return (0);
    789      1.1  dholland nfsmout:
    790      1.1  dholland 	vput(vp);
    791      1.1  dholland 	NFSEXITCODE2(error, nd);
    792      1.1  dholland 	return (error);
    793      1.1  dholland }
    794      1.1  dholland 
    795      1.1  dholland /*
    796      1.1  dholland  * nfs write service
    797      1.1  dholland  */
    798      1.1  dholland APPLESTATIC int
    799      1.1  dholland nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
    800      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
    801      1.1  dholland {
    802      1.1  dholland 	int i, cnt;
    803      1.1  dholland 	u_int32_t *tl;
    804      1.1  dholland 	mbuf_t mp;
    805      1.1  dholland 	struct nfsvattr nva, forat;
    806      1.1  dholland 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
    807      1.1  dholland 	int stable = NFSWRITE_FILESYNC;
    808      1.1  dholland 	off_t off;
    809      1.1  dholland 	struct nfsstate st, *stp = &st;
    810      1.1  dholland 	struct nfslock lo, *lop = &lo;
    811      1.1  dholland 	nfsv4stateid_t stateid;
    812      1.1  dholland 	nfsquad_t clientid;
    813      1.1  dholland 
    814      1.1  dholland 	if (nd->nd_repstat) {
    815      1.1  dholland 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    816      1.1  dholland 		goto out;
    817      1.1  dholland 	}
    818      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
    819      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    820      1.1  dholland 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
    821      1.1  dholland 		tl += 2;
    822      1.1  dholland 		retlen = len = fxdr_unsigned(int32_t, *tl);
    823      1.1  dholland 	} else if (nd->nd_flag & ND_NFSV3) {
    824      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
    825      1.1  dholland 		off = fxdr_hyper(tl);
    826      1.1  dholland 		tl += 3;
    827      1.1  dholland 		stable = fxdr_unsigned(int, *tl++);
    828      1.1  dholland 		retlen = len = fxdr_unsigned(int32_t, *tl);
    829      1.1  dholland 	} else {
    830      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
    831      1.1  dholland 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
    832      1.1  dholland 		lop->lo_flags = NFSLCK_WRITE;
    833      1.1  dholland 		stp->ls_ownerlen = 0;
    834      1.1  dholland 		stp->ls_op = NULL;
    835      1.1  dholland 		stp->ls_uid = nd->nd_cred->cr_uid;
    836      1.1  dholland 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
    837      1.1  dholland 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
    838      1.1  dholland 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
    839  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
    840  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    841  1.1.1.2  pgoyette 				clientid.qval = nd->nd_clientid.qval;
    842  1.1.1.2  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
    843  1.1.1.2  pgoyette 				printf("EEK2 multiple clids\n");
    844      1.1  dholland 		} else {
    845  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    846  1.1.1.2  pgoyette 				printf("EEK! no clientid from session\n");
    847      1.1  dholland 			nd->nd_flag |= ND_IMPLIEDCLID;
    848      1.1  dholland 			nd->nd_clientid.qval = clientid.qval;
    849      1.1  dholland 		}
    850      1.1  dholland 		stp->ls_stateid.other[2] = *tl++;
    851      1.1  dholland 		off = fxdr_hyper(tl);
    852      1.1  dholland 		lop->lo_first = off;
    853      1.1  dholland 		tl += 2;
    854      1.1  dholland 		stable = fxdr_unsigned(int, *tl++);
    855      1.1  dholland 		retlen = len = fxdr_unsigned(int32_t, *tl);
    856      1.1  dholland 		lop->lo_end = off + len;
    857      1.1  dholland 		/*
    858      1.1  dholland 		 * Paranoia, just in case it wraps around, which shouldn't
    859      1.1  dholland 		 * ever happen anyhow.
    860      1.1  dholland 		 */
    861      1.1  dholland 		if (lop->lo_end < lop->lo_first)
    862      1.1  dholland 			lop->lo_end = NFS64BITSSET;
    863      1.1  dholland 	}
    864      1.1  dholland 
    865      1.1  dholland 	/*
    866      1.1  dholland 	 * Loop through the mbuf chain, counting how many mbufs are a
    867      1.1  dholland 	 * part of this write operation, so the iovec size is known.
    868      1.1  dholland 	 */
    869      1.1  dholland 	cnt = 0;
    870      1.1  dholland 	mp = nd->nd_md;
    871      1.1  dholland 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
    872      1.1  dholland 	while (len > 0) {
    873      1.1  dholland 		if (i > 0) {
    874      1.1  dholland 			len -= i;
    875      1.1  dholland 			cnt++;
    876      1.1  dholland 		}
    877      1.1  dholland 		mp = mbuf_next(mp);
    878      1.1  dholland 		if (!mp) {
    879      1.1  dholland 			if (len > 0) {
    880      1.1  dholland 				error = EBADRPC;
    881      1.1  dholland 				goto nfsmout;
    882      1.1  dholland 			}
    883      1.1  dholland 		} else
    884      1.1  dholland 			i = mbuf_len(mp);
    885      1.1  dholland 	}
    886      1.1  dholland 
    887  1.1.1.2  pgoyette 	if (retlen > NFS_SRVMAXIO || retlen < 0)
    888      1.1  dholland 		nd->nd_repstat = EIO;
    889      1.1  dholland 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
    890      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    891      1.1  dholland 			nd->nd_repstat = EINVAL;
    892      1.1  dholland 		else
    893      1.1  dholland 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
    894      1.1  dholland 			    EINVAL;
    895      1.1  dholland 	}
    896      1.1  dholland 	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
    897      1.1  dholland 	if (!nd->nd_repstat)
    898      1.1  dholland 		nd->nd_repstat = forat_ret;
    899      1.1  dholland 	if (!nd->nd_repstat &&
    900      1.1  dholland 	    (forat.na_uid != nd->nd_cred->cr_uid ||
    901      1.1  dholland 	     NFSVNO_EXSTRICTACCESS(exp)))
    902      1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
    903      1.1  dholland 		    nd->nd_cred, exp, p,
    904      1.1  dholland 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
    905      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
    906      1.1  dholland 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
    907      1.1  dholland 		    &stateid, exp, nd, p);
    908      1.1  dholland 	}
    909      1.1  dholland 	if (nd->nd_repstat) {
    910      1.1  dholland 		vput(vp);
    911      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    912      1.1  dholland 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    913      1.1  dholland 		goto out;
    914      1.1  dholland 	}
    915      1.1  dholland 
    916      1.1  dholland 	/*
    917      1.1  dholland 	 * For NFS Version 2, it is not obvious what a write of zero length
    918      1.1  dholland 	 * should do, but I might as well be consistent with Version 3,
    919      1.1  dholland 	 * which is to return ok so long as there are no permission problems.
    920      1.1  dholland 	 */
    921      1.1  dholland 	if (retlen > 0) {
    922      1.1  dholland 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
    923      1.1  dholland 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
    924      1.1  dholland 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
    925      1.1  dholland 		if (error)
    926      1.1  dholland 			panic("nfsrv_write mbuf");
    927      1.1  dholland 	}
    928      1.1  dholland 	if (nd->nd_flag & ND_NFSV4)
    929      1.1  dholland 		aftat_ret = 0;
    930      1.1  dholland 	else
    931      1.1  dholland 		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
    932      1.1  dholland 	vput(vp);
    933      1.1  dholland 	if (!nd->nd_repstat)
    934      1.1  dholland 		nd->nd_repstat = aftat_ret;
    935      1.1  dholland 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
    936      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
    937      1.1  dholland 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
    938      1.1  dholland 		if (nd->nd_repstat)
    939      1.1  dholland 			goto out;
    940      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
    941      1.1  dholland 		*tl++ = txdr_unsigned(retlen);
    942      1.1  dholland 		/*
    943      1.1  dholland 		 * If nfs_async is set, then pretend the write was FILESYNC.
    944      1.1  dholland 		 * Warning: Doing this violates RFC1813 and runs a risk
    945      1.1  dholland 		 * of data written by a client being lost when the server
    946      1.1  dholland 		 * crashes/reboots.
    947      1.1  dholland 		 */
    948      1.1  dholland 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
    949      1.1  dholland 			*tl++ = txdr_unsigned(stable);
    950      1.1  dholland 		else
    951      1.1  dholland 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
    952      1.1  dholland 		/*
    953      1.1  dholland 		 * Actually, there is no need to txdr these fields,
    954      1.1  dholland 		 * but it may make the values more human readable,
    955      1.1  dholland 		 * for debugging purposes.
    956      1.1  dholland 		 */
    957      1.1  dholland 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
    958      1.1  dholland 		*tl = txdr_unsigned(nfsboottime.tv_usec);
    959      1.1  dholland 	} else if (!nd->nd_repstat)
    960      1.1  dholland 		nfsrv_fillattr(nd, &nva);
    961      1.1  dholland 
    962      1.1  dholland out:
    963      1.1  dholland 	NFSEXITCODE2(0, nd);
    964      1.1  dholland 	return (0);
    965      1.1  dholland nfsmout:
    966      1.1  dholland 	vput(vp);
    967      1.1  dholland 	NFSEXITCODE2(error, nd);
    968      1.1  dholland 	return (error);
    969      1.1  dholland }
    970      1.1  dholland 
    971      1.1  dholland /*
    972      1.1  dholland  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
    973      1.1  dholland  * now does a truncate to 0 length via. setattr if it already exists
    974      1.1  dholland  * The core creation routine has been extracted out into nfsrv_creatsub(),
    975      1.1  dholland  * so it can also be used by nfsrv_open() for V4.
    976      1.1  dholland  */
    977      1.1  dholland APPLESTATIC int
    978      1.1  dholland nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
    979      1.1  dholland     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
    980      1.1  dholland {
    981      1.1  dholland 	struct nfsvattr nva, dirfor, diraft;
    982      1.1  dholland 	struct nfsv2_sattr *sp;
    983      1.1  dholland 	struct nameidata named;
    984      1.1  dholland 	u_int32_t *tl;
    985      1.1  dholland 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
    986      1.1  dholland 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
    987      1.1  dholland 	NFSDEV_T rdev = 0;
    988      1.1  dholland 	vnode_t vp = NULL, dirp = NULL;
    989      1.1  dholland 	fhandle_t fh;
    990      1.1  dholland 	char *bufp;
    991      1.1  dholland 	u_long *hashp;
    992      1.1  dholland 	enum vtype vtyp;
    993      1.1  dholland 	int32_t cverf[2], tverf[2] = { 0, 0 };
    994      1.1  dholland 
    995      1.1  dholland 	if (nd->nd_repstat) {
    996      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
    997      1.1  dholland 		goto out;
    998      1.1  dholland 	}
    999      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1000  1.1.1.2  pgoyette 	    LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
   1001      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1002      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1003      1.1  dholland 	if (error)
   1004      1.1  dholland 		goto nfsmout;
   1005      1.1  dholland 	if (!nd->nd_repstat) {
   1006      1.1  dholland 		NFSVNO_ATTRINIT(&nva);
   1007      1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   1008      1.1  dholland 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
   1009      1.1  dholland 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
   1010      1.1  dholland 			if (vtyp == VNON)
   1011      1.1  dholland 				vtyp = VREG;
   1012      1.1  dholland 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
   1013      1.1  dholland 			NFSVNO_SETATTRVAL(&nva, mode,
   1014      1.1  dholland 			    nfstov_mode(sp->sa_mode));
   1015      1.1  dholland 			switch (nva.na_type) {
   1016      1.1  dholland 			case VREG:
   1017      1.1  dholland 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
   1018      1.1  dholland 				if (tsize != -1)
   1019      1.1  dholland 					NFSVNO_SETATTRVAL(&nva, size,
   1020      1.1  dholland 					    (u_quad_t)tsize);
   1021      1.1  dholland 				break;
   1022      1.1  dholland 			case VCHR:
   1023      1.1  dholland 			case VBLK:
   1024      1.1  dholland 			case VFIFO:
   1025      1.1  dholland 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
   1026      1.1  dholland 				break;
   1027      1.1  dholland 			default:
   1028      1.1  dholland 				break;
   1029  1.1.1.2  pgoyette 			}
   1030      1.1  dholland 		} else {
   1031      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1032      1.1  dholland 			how = fxdr_unsigned(int, *tl);
   1033      1.1  dholland 			switch (how) {
   1034      1.1  dholland 			case NFSCREATE_GUARDED:
   1035      1.1  dholland 			case NFSCREATE_UNCHECKED:
   1036  1.1.1.2  pgoyette 				error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
   1037      1.1  dholland 				if (error)
   1038      1.1  dholland 					goto nfsmout;
   1039      1.1  dholland 				break;
   1040      1.1  dholland 			case NFSCREATE_EXCLUSIVE:
   1041      1.1  dholland 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   1042      1.1  dholland 				cverf[0] = *tl++;
   1043      1.1  dholland 				cverf[1] = *tl;
   1044      1.1  dholland 				exclusive_flag = 1;
   1045      1.1  dholland 				break;
   1046  1.1.1.2  pgoyette 			}
   1047      1.1  dholland 			NFSVNO_SETATTRVAL(&nva, type, VREG);
   1048      1.1  dholland 		}
   1049      1.1  dholland 	}
   1050      1.1  dholland 	if (nd->nd_repstat) {
   1051      1.1  dholland 		nfsvno_relpathbuf(&named);
   1052      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1053      1.1  dholland 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
   1054      1.1  dholland 			    p, 1);
   1055      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1056      1.1  dholland 			    &diraft);
   1057      1.1  dholland 		}
   1058      1.1  dholland 		vput(dp);
   1059      1.1  dholland 		goto out;
   1060      1.1  dholland 	}
   1061      1.1  dholland 
   1062      1.1  dholland 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   1063      1.1  dholland 	if (dirp) {
   1064      1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   1065      1.1  dholland 			vrele(dirp);
   1066      1.1  dholland 			dirp = NULL;
   1067      1.1  dholland 		} else {
   1068      1.1  dholland 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1069      1.1  dholland 			    p, 0);
   1070      1.1  dholland 		}
   1071      1.1  dholland 	}
   1072      1.1  dholland 	if (nd->nd_repstat) {
   1073      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1074      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1075      1.1  dholland 			    &diraft);
   1076      1.1  dholland 		if (dirp)
   1077      1.1  dholland 			vrele(dirp);
   1078      1.1  dholland 		goto out;
   1079      1.1  dholland 	}
   1080      1.1  dholland 
   1081      1.1  dholland 	if (!(nd->nd_flag & ND_NFSV2)) {
   1082      1.1  dholland 		switch (how) {
   1083      1.1  dholland 		case NFSCREATE_GUARDED:
   1084      1.1  dholland 			if (named.ni_vp)
   1085      1.1  dholland 				nd->nd_repstat = EEXIST;
   1086      1.1  dholland 			break;
   1087      1.1  dholland 		case NFSCREATE_UNCHECKED:
   1088      1.1  dholland 			break;
   1089      1.1  dholland 		case NFSCREATE_EXCLUSIVE:
   1090      1.1  dholland 			if (named.ni_vp == NULL)
   1091      1.1  dholland 				NFSVNO_SETATTRVAL(&nva, mode, 0);
   1092      1.1  dholland 			break;
   1093  1.1.1.2  pgoyette 		}
   1094      1.1  dholland 	}
   1095      1.1  dholland 
   1096      1.1  dholland 	/*
   1097      1.1  dholland 	 * Iff doesn't exist, create it
   1098      1.1  dholland 	 * otherwise just truncate to 0 length
   1099      1.1  dholland 	 *   should I set the mode too ?
   1100      1.1  dholland 	 */
   1101      1.1  dholland 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
   1102      1.1  dholland 	    &exclusive_flag, cverf, rdev, p, exp);
   1103      1.1  dholland 
   1104      1.1  dholland 	if (!nd->nd_repstat) {
   1105      1.1  dholland 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   1106      1.1  dholland 		if (!nd->nd_repstat)
   1107      1.1  dholland 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
   1108      1.1  dholland 			    p, 1);
   1109      1.1  dholland 		vput(vp);
   1110      1.1  dholland 		if (!nd->nd_repstat) {
   1111      1.1  dholland 			tverf[0] = nva.na_atime.tv_sec;
   1112      1.1  dholland 			tverf[1] = nva.na_atime.tv_nsec;
   1113      1.1  dholland 		}
   1114      1.1  dholland 	}
   1115      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
   1116      1.1  dholland 		if (!nd->nd_repstat) {
   1117      1.1  dholland 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
   1118      1.1  dholland 			nfsrv_fillattr(nd, &nva);
   1119      1.1  dholland 		}
   1120      1.1  dholland 	} else {
   1121      1.1  dholland 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
   1122      1.1  dholland 		    || cverf[1] != tverf[1]))
   1123      1.1  dholland 			nd->nd_repstat = EEXIST;
   1124      1.1  dholland 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1125      1.1  dholland 		vrele(dirp);
   1126      1.1  dholland 		if (!nd->nd_repstat) {
   1127      1.1  dholland 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
   1128      1.1  dholland 			nfsrv_postopattr(nd, 0, &nva);
   1129      1.1  dholland 		}
   1130      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1131      1.1  dholland 	}
   1132      1.1  dholland 
   1133      1.1  dholland out:
   1134      1.1  dholland 	NFSEXITCODE2(0, nd);
   1135      1.1  dholland 	return (0);
   1136      1.1  dholland nfsmout:
   1137      1.1  dholland 	vput(dp);
   1138      1.1  dholland 	nfsvno_relpathbuf(&named);
   1139      1.1  dholland 	NFSEXITCODE2(error, nd);
   1140      1.1  dholland 	return (error);
   1141      1.1  dholland }
   1142      1.1  dholland 
   1143      1.1  dholland /*
   1144      1.1  dholland  * nfs v3 mknod service (and v4 create)
   1145      1.1  dholland  */
   1146      1.1  dholland APPLESTATIC int
   1147      1.1  dholland nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
   1148      1.1  dholland     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1149      1.1  dholland     struct nfsexstuff *exp)
   1150      1.1  dholland {
   1151      1.1  dholland 	struct nfsvattr nva, dirfor, diraft;
   1152      1.1  dholland 	u_int32_t *tl;
   1153      1.1  dholland 	struct nameidata named;
   1154      1.1  dholland 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
   1155      1.1  dholland 	u_int32_t major, minor;
   1156      1.1  dholland 	enum vtype vtyp = VNON;
   1157      1.1  dholland 	nfstype nfs4type = NFNON;
   1158      1.1  dholland 	vnode_t vp, dirp = NULL;
   1159      1.1  dholland 	nfsattrbit_t attrbits;
   1160      1.1  dholland 	char *bufp = NULL, *pathcp = NULL;
   1161      1.1  dholland 	u_long *hashp, cnflags;
   1162      1.1  dholland 	NFSACL_T *aclp = NULL;
   1163      1.1  dholland 
   1164      1.1  dholland 	NFSVNO_ATTRINIT(&nva);
   1165      1.1  dholland 	cnflags = (LOCKPARENT | SAVESTART);
   1166      1.1  dholland 	if (nd->nd_repstat) {
   1167      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1168      1.1  dholland 		goto out;
   1169      1.1  dholland 	}
   1170      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1171      1.1  dholland 	aclp = acl_alloc(M_WAITOK);
   1172      1.1  dholland 	aclp->acl_cnt = 0;
   1173      1.1  dholland #endif
   1174      1.1  dholland 
   1175      1.1  dholland 	/*
   1176      1.1  dholland 	 * For V4, the creation stuff is here, Yuck!
   1177      1.1  dholland 	 */
   1178      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1179      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1180      1.1  dholland 		vtyp = nfsv34tov_type(*tl);
   1181      1.1  dholland 		nfs4type = fxdr_unsigned(nfstype, *tl);
   1182      1.1  dholland 		switch (nfs4type) {
   1183      1.1  dholland 		case NFLNK:
   1184      1.1  dholland 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
   1185      1.1  dholland 			    &pathlen);
   1186      1.1  dholland 			if (error)
   1187      1.1  dholland 				goto nfsmout;
   1188      1.1  dholland 			break;
   1189      1.1  dholland 		case NFCHR:
   1190      1.1  dholland 		case NFBLK:
   1191      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1192      1.1  dholland 			major = fxdr_unsigned(u_int32_t, *tl++);
   1193      1.1  dholland 			minor = fxdr_unsigned(u_int32_t, *tl);
   1194      1.1  dholland 			nva.na_rdev = NFSMAKEDEV(major, minor);
   1195      1.1  dholland 			break;
   1196      1.1  dholland 		case NFSOCK:
   1197      1.1  dholland 		case NFFIFO:
   1198      1.1  dholland 			break;
   1199      1.1  dholland 		case NFDIR:
   1200      1.1  dholland 			cnflags = (LOCKPARENT | SAVENAME);
   1201      1.1  dholland 			break;
   1202      1.1  dholland 		default:
   1203      1.1  dholland 			nd->nd_repstat = NFSERR_BADTYPE;
   1204      1.1  dholland 			vrele(dp);
   1205      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1206      1.1  dholland 			acl_free(aclp);
   1207      1.1  dholland #endif
   1208      1.1  dholland 			goto out;
   1209      1.1  dholland 		}
   1210      1.1  dholland 	}
   1211  1.1.1.2  pgoyette 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
   1212      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1213      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1214      1.1  dholland 	if (error)
   1215      1.1  dholland 		goto nfsmout;
   1216      1.1  dholland 	if (!nd->nd_repstat) {
   1217      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1218      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1219      1.1  dholland 			vtyp = nfsv34tov_type(*tl);
   1220      1.1  dholland 		}
   1221  1.1.1.2  pgoyette 		error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
   1222      1.1  dholland 		if (error)
   1223      1.1  dholland 			goto nfsmout;
   1224      1.1  dholland 		nva.na_type = vtyp;
   1225      1.1  dholland 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
   1226      1.1  dholland 		    (vtyp == VCHR || vtyp == VBLK)) {
   1227      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   1228      1.1  dholland 			major = fxdr_unsigned(u_int32_t, *tl++);
   1229      1.1  dholland 			minor = fxdr_unsigned(u_int32_t, *tl);
   1230      1.1  dholland 			nva.na_rdev = NFSMAKEDEV(major, minor);
   1231      1.1  dholland 		}
   1232      1.1  dholland 	}
   1233      1.1  dholland 
   1234      1.1  dholland 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
   1235      1.1  dholland 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
   1236      1.1  dholland 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
   1237      1.1  dholland 		    dirfor.na_gid == nva.na_gid)
   1238      1.1  dholland 			NFSVNO_UNSET(&nva, gid);
   1239      1.1  dholland 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   1240      1.1  dholland 	}
   1241      1.1  dholland 	if (nd->nd_repstat) {
   1242      1.1  dholland 		vrele(dp);
   1243      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1244      1.1  dholland 		acl_free(aclp);
   1245      1.1  dholland #endif
   1246      1.1  dholland 		nfsvno_relpathbuf(&named);
   1247      1.1  dholland 		if (pathcp)
   1248      1.1  dholland 			FREE(pathcp, M_TEMP);
   1249      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1250      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1251      1.1  dholland 			    &diraft);
   1252      1.1  dholland 		goto out;
   1253      1.1  dholland 	}
   1254      1.1  dholland 
   1255      1.1  dholland 	/*
   1256      1.1  dholland 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
   1257      1.1  dholland 	 * in va_mode, so we'll have to set a default here.
   1258      1.1  dholland 	 */
   1259      1.1  dholland 	if (NFSVNO_NOTSETMODE(&nva)) {
   1260      1.1  dholland 		if (vtyp == VLNK)
   1261      1.1  dholland 			nva.na_mode = 0755;
   1262      1.1  dholland 		else
   1263      1.1  dholland 			nva.na_mode = 0400;
   1264      1.1  dholland 	}
   1265      1.1  dholland 
   1266      1.1  dholland 	if (vtyp == VDIR)
   1267      1.1  dholland 		named.ni_cnd.cn_flags |= WILLBEDIR;
   1268      1.1  dholland 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1269      1.1  dholland 	if (nd->nd_repstat) {
   1270      1.1  dholland 		if (dirp) {
   1271      1.1  dholland 			if (nd->nd_flag & ND_NFSV3)
   1272      1.1  dholland 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1273      1.1  dholland 				    nd->nd_cred, p, 0);
   1274      1.1  dholland 			vrele(dirp);
   1275      1.1  dholland 		}
   1276      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1277      1.1  dholland 		acl_free(aclp);
   1278      1.1  dholland #endif
   1279      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1280      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1281      1.1  dholland 			    &diraft);
   1282      1.1  dholland 		goto out;
   1283      1.1  dholland 	}
   1284      1.1  dholland 	if (dirp)
   1285      1.1  dholland 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1286      1.1  dholland 
   1287      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
   1288      1.1  dholland 		if (vtyp == VDIR) {
   1289      1.1  dholland 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
   1290      1.1  dholland 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
   1291      1.1  dholland 			    exp);
   1292      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1293      1.1  dholland 			acl_free(aclp);
   1294      1.1  dholland #endif
   1295      1.1  dholland 			goto out;
   1296      1.1  dholland 		} else if (vtyp == VLNK) {
   1297      1.1  dholland 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
   1298      1.1  dholland 			    &dirfor, &diraft, &diraft_ret, &attrbits,
   1299      1.1  dholland 			    aclp, p, exp, pathcp, pathlen);
   1300      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1301      1.1  dholland 			acl_free(aclp);
   1302      1.1  dholland #endif
   1303      1.1  dholland 			FREE(pathcp, M_TEMP);
   1304      1.1  dholland 			goto out;
   1305      1.1  dholland 		}
   1306      1.1  dholland 	}
   1307      1.1  dholland 
   1308      1.1  dholland 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
   1309      1.1  dholland 	if (!nd->nd_repstat) {
   1310      1.1  dholland 		vp = named.ni_vp;
   1311      1.1  dholland 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
   1312      1.1  dholland 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
   1313      1.1  dholland 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
   1314      1.1  dholland 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
   1315      1.1  dholland 			    p, 1);
   1316      1.1  dholland 		if (vpp != NULL && nd->nd_repstat == 0) {
   1317      1.1  dholland 			NFSVOPUNLOCK(vp, 0);
   1318      1.1  dholland 			*vpp = vp;
   1319      1.1  dholland 		} else
   1320      1.1  dholland 			vput(vp);
   1321      1.1  dholland 	}
   1322      1.1  dholland 
   1323      1.1  dholland 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1324      1.1  dholland 	vrele(dirp);
   1325      1.1  dholland 	if (!nd->nd_repstat) {
   1326      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1327      1.1  dholland 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1328      1.1  dholland 			nfsrv_postopattr(nd, 0, &nva);
   1329      1.1  dholland 		} else {
   1330      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1331      1.1  dholland 			*tl++ = newnfs_false;
   1332      1.1  dholland 			txdr_hyper(dirfor.na_filerev, tl);
   1333      1.1  dholland 			tl += 2;
   1334      1.1  dholland 			txdr_hyper(diraft.na_filerev, tl);
   1335      1.1  dholland 			(void) nfsrv_putattrbit(nd, &attrbits);
   1336      1.1  dholland 		}
   1337      1.1  dholland 	}
   1338      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   1339      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1340      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1341      1.1  dholland 	acl_free(aclp);
   1342      1.1  dholland #endif
   1343      1.1  dholland 
   1344      1.1  dholland out:
   1345      1.1  dholland 	NFSEXITCODE2(0, nd);
   1346      1.1  dholland 	return (0);
   1347      1.1  dholland nfsmout:
   1348      1.1  dholland 	vrele(dp);
   1349      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   1350      1.1  dholland 	acl_free(aclp);
   1351      1.1  dholland #endif
   1352      1.1  dholland 	if (bufp)
   1353      1.1  dholland 		nfsvno_relpathbuf(&named);
   1354      1.1  dholland 	if (pathcp)
   1355      1.1  dholland 		FREE(pathcp, M_TEMP);
   1356      1.1  dholland 
   1357      1.1  dholland 	NFSEXITCODE2(error, nd);
   1358      1.1  dholland 	return (error);
   1359      1.1  dholland }
   1360      1.1  dholland 
   1361      1.1  dholland /*
   1362      1.1  dholland  * nfs remove service
   1363      1.1  dholland  */
   1364      1.1  dholland APPLESTATIC int
   1365      1.1  dholland nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
   1366      1.1  dholland     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
   1367      1.1  dholland {
   1368      1.1  dholland 	struct nameidata named;
   1369      1.1  dholland 	u_int32_t *tl;
   1370      1.1  dholland 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
   1371      1.1  dholland 	vnode_t dirp = NULL;
   1372      1.1  dholland 	struct nfsvattr dirfor, diraft;
   1373      1.1  dholland 	char *bufp;
   1374      1.1  dholland 	u_long *hashp;
   1375      1.1  dholland 
   1376      1.1  dholland 	if (nd->nd_repstat) {
   1377      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1378      1.1  dholland 		goto out;
   1379      1.1  dholland 	}
   1380      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
   1381      1.1  dholland 	    LOCKPARENT | LOCKLEAF);
   1382      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1383      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1384      1.1  dholland 	if (error) {
   1385      1.1  dholland 		vput(dp);
   1386      1.1  dholland 		nfsvno_relpathbuf(&named);
   1387      1.1  dholland 		goto out;
   1388      1.1  dholland 	}
   1389      1.1  dholland 	if (!nd->nd_repstat) {
   1390      1.1  dholland 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   1391      1.1  dholland 	} else {
   1392      1.1  dholland 		vput(dp);
   1393      1.1  dholland 		nfsvno_relpathbuf(&named);
   1394      1.1  dholland 	}
   1395      1.1  dholland 	if (dirp) {
   1396      1.1  dholland 		if (!(nd->nd_flag & ND_NFSV2)) {
   1397      1.1  dholland 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1398      1.1  dholland 			    nd->nd_cred, p, 0);
   1399      1.1  dholland 		} else {
   1400      1.1  dholland 			vrele(dirp);
   1401      1.1  dholland 			dirp = NULL;
   1402      1.1  dholland 		}
   1403      1.1  dholland 	}
   1404      1.1  dholland 	if (!nd->nd_repstat) {
   1405      1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1406      1.1  dholland 			if (vnode_vtype(named.ni_vp) == VDIR)
   1407      1.1  dholland 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
   1408      1.1  dholland 				    nd->nd_cred, p, exp);
   1409      1.1  dholland 			else
   1410      1.1  dholland 				nd->nd_repstat = nfsvno_removesub(&named, 1,
   1411      1.1  dholland 				    nd->nd_cred, p, exp);
   1412      1.1  dholland 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
   1413      1.1  dholland 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
   1414      1.1  dholland 			    nd->nd_cred, p, exp);
   1415      1.1  dholland 		} else {
   1416      1.1  dholland 			nd->nd_repstat = nfsvno_removesub(&named, 0,
   1417      1.1  dholland 			    nd->nd_cred, p, exp);
   1418      1.1  dholland 		}
   1419      1.1  dholland 	}
   1420      1.1  dholland 	if (!(nd->nd_flag & ND_NFSV2)) {
   1421      1.1  dholland 		if (dirp) {
   1422      1.1  dholland 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
   1423      1.1  dholland 			    p, 0);
   1424      1.1  dholland 			vrele(dirp);
   1425      1.1  dholland 		}
   1426      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1427      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1428      1.1  dholland 			    &diraft);
   1429      1.1  dholland 		} else if (!nd->nd_repstat) {
   1430      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1431      1.1  dholland 			*tl++ = newnfs_false;
   1432      1.1  dholland 			txdr_hyper(dirfor.na_filerev, tl);
   1433      1.1  dholland 			tl += 2;
   1434      1.1  dholland 			txdr_hyper(diraft.na_filerev, tl);
   1435      1.1  dholland 		}
   1436      1.1  dholland 	}
   1437      1.1  dholland 
   1438      1.1  dholland out:
   1439      1.1  dholland 	NFSEXITCODE2(error, nd);
   1440      1.1  dholland 	return (error);
   1441      1.1  dholland }
   1442      1.1  dholland 
   1443      1.1  dholland /*
   1444      1.1  dholland  * nfs rename service
   1445      1.1  dholland  */
   1446      1.1  dholland APPLESTATIC int
   1447      1.1  dholland nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
   1448      1.1  dholland     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
   1449      1.1  dholland     struct nfsexstuff *toexp)
   1450      1.1  dholland {
   1451      1.1  dholland 	u_int32_t *tl;
   1452      1.1  dholland 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
   1453      1.1  dholland 	int tdirfor_ret = 1, tdiraft_ret = 1;
   1454      1.1  dholland 	struct nameidata fromnd, tond;
   1455      1.1  dholland 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
   1456      1.1  dholland 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
   1457      1.1  dholland 	struct nfsexstuff tnes;
   1458      1.1  dholland 	struct nfsrvfh tfh;
   1459      1.1  dholland 	char *bufp, *tbufp = NULL;
   1460      1.1  dholland 	u_long *hashp;
   1461      1.1  dholland 	fhandle_t fh;
   1462      1.1  dholland 
   1463      1.1  dholland 	if (nd->nd_repstat) {
   1464      1.1  dholland 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
   1465      1.1  dholland 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
   1466      1.1  dholland 		goto out;
   1467      1.1  dholland 	}
   1468      1.1  dholland 	if (!(nd->nd_flag & ND_NFSV2))
   1469      1.1  dholland 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
   1470      1.1  dholland 	tond.ni_cnd.cn_nameiop = 0;
   1471      1.1  dholland 	tond.ni_startdir = NULL;
   1472      1.1  dholland 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
   1473      1.1  dholland 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
   1474      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
   1475      1.1  dholland 	if (error) {
   1476      1.1  dholland 		vput(dp);
   1477      1.1  dholland 		if (todp)
   1478      1.1  dholland 			vrele(todp);
   1479      1.1  dholland 		nfsvno_relpathbuf(&fromnd);
   1480      1.1  dholland 		goto out;
   1481      1.1  dholland 	}
   1482  1.1.1.2  pgoyette 	/*
   1483  1.1.1.2  pgoyette 	 * Unlock dp in this code section, so it is unlocked before
   1484  1.1.1.2  pgoyette 	 * tdp gets locked. This avoids a potential LOR if tdp is the
   1485  1.1.1.2  pgoyette 	 * parent directory of dp.
   1486  1.1.1.2  pgoyette 	 */
   1487      1.1  dholland 	if (nd->nd_flag & ND_NFSV4) {
   1488      1.1  dholland 		tdp = todp;
   1489      1.1  dholland 		tnes = *toexp;
   1490  1.1.1.2  pgoyette 		if (dp != tdp) {
   1491  1.1.1.2  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1492  1.1.1.2  pgoyette 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1493  1.1.1.2  pgoyette 			    p, 0);	/* Might lock tdp. */
   1494  1.1.1.2  pgoyette 		} else {
   1495  1.1.1.2  pgoyette 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1496  1.1.1.2  pgoyette 			    p, 1);
   1497  1.1.1.2  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1498  1.1.1.2  pgoyette 		}
   1499      1.1  dholland 	} else {
   1500      1.1  dholland 		tfh.nfsrvfh_len = 0;
   1501      1.1  dholland 		error = nfsrv_mtofh(nd, &tfh);
   1502      1.1  dholland 		if (error == 0)
   1503      1.1  dholland 			error = nfsvno_getfh(dp, &fh, p);
   1504      1.1  dholland 		if (error) {
   1505      1.1  dholland 			vput(dp);
   1506      1.1  dholland 			/* todp is always NULL except NFSv4 */
   1507      1.1  dholland 			nfsvno_relpathbuf(&fromnd);
   1508      1.1  dholland 			goto out;
   1509      1.1  dholland 		}
   1510      1.1  dholland 
   1511      1.1  dholland 		/* If this is the same file handle, just VREF() the vnode. */
   1512      1.1  dholland 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
   1513      1.1  dholland 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
   1514      1.1  dholland 			VREF(dp);
   1515      1.1  dholland 			tdp = dp;
   1516      1.1  dholland 			tnes = *exp;
   1517      1.1  dholland 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1518      1.1  dholland 			    p, 1);
   1519  1.1.1.2  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1520      1.1  dholland 		} else {
   1521  1.1.1.2  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1522      1.1  dholland 			nd->nd_cred->cr_uid = nd->nd_saveduid;
   1523      1.1  dholland 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
   1524  1.1.1.2  pgoyette 			    0, p);	/* Locks tdp. */
   1525      1.1  dholland 			if (tdp) {
   1526      1.1  dholland 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
   1527      1.1  dholland 				    nd->nd_cred, p, 1);
   1528      1.1  dholland 				NFSVOPUNLOCK(tdp, 0);
   1529      1.1  dholland 			}
   1530      1.1  dholland 		}
   1531      1.1  dholland 	}
   1532      1.1  dholland 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
   1533      1.1  dholland 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
   1534      1.1  dholland 	if (!nd->nd_repstat) {
   1535      1.1  dholland 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
   1536      1.1  dholland 		if (error) {
   1537      1.1  dholland 			if (tdp)
   1538      1.1  dholland 				vrele(tdp);
   1539  1.1.1.2  pgoyette 			vrele(dp);
   1540      1.1  dholland 			nfsvno_relpathbuf(&fromnd);
   1541      1.1  dholland 			nfsvno_relpathbuf(&tond);
   1542      1.1  dholland 			goto out;
   1543      1.1  dholland 		}
   1544      1.1  dholland 	}
   1545      1.1  dholland 	if (nd->nd_repstat) {
   1546      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1547      1.1  dholland 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
   1548      1.1  dholland 			    &fdiraft);
   1549      1.1  dholland 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
   1550      1.1  dholland 			    &tdiraft);
   1551      1.1  dholland 		}
   1552      1.1  dholland 		if (tdp)
   1553      1.1  dholland 			vrele(tdp);
   1554  1.1.1.2  pgoyette 		vrele(dp);
   1555      1.1  dholland 		nfsvno_relpathbuf(&fromnd);
   1556      1.1  dholland 		nfsvno_relpathbuf(&tond);
   1557      1.1  dholland 		goto out;
   1558      1.1  dholland 	}
   1559      1.1  dholland 
   1560      1.1  dholland 	/*
   1561      1.1  dholland 	 * Done parsing, now down to business.
   1562      1.1  dholland 	 */
   1563  1.1.1.2  pgoyette 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
   1564      1.1  dholland 	if (nd->nd_repstat) {
   1565      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1566      1.1  dholland 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
   1567      1.1  dholland 			    &fdiraft);
   1568      1.1  dholland 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
   1569      1.1  dholland 			    &tdiraft);
   1570      1.1  dholland 		}
   1571      1.1  dholland 		if (fdirp)
   1572      1.1  dholland 			vrele(fdirp);
   1573      1.1  dholland 		if (tdp)
   1574      1.1  dholland 			vrele(tdp);
   1575      1.1  dholland 		nfsvno_relpathbuf(&tond);
   1576      1.1  dholland 		goto out;
   1577      1.1  dholland 	}
   1578      1.1  dholland 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
   1579      1.1  dholland 		tond.ni_cnd.cn_flags |= WILLBEDIR;
   1580      1.1  dholland 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
   1581      1.1  dholland 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
   1582      1.1  dholland 	    nd->nd_flag, nd->nd_cred, p);
   1583      1.1  dholland 	if (fdirp)
   1584      1.1  dholland 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
   1585      1.1  dholland 		    0);
   1586      1.1  dholland 	if (tdirp)
   1587      1.1  dholland 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
   1588      1.1  dholland 		    0);
   1589      1.1  dholland 	if (fdirp)
   1590      1.1  dholland 		vrele(fdirp);
   1591      1.1  dholland 	if (tdirp)
   1592      1.1  dholland 		vrele(tdirp);
   1593      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1594      1.1  dholland 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
   1595      1.1  dholland 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
   1596      1.1  dholland 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1597      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
   1598      1.1  dholland 		*tl++ = newnfs_false;
   1599      1.1  dholland 		txdr_hyper(fdirfor.na_filerev, tl);
   1600      1.1  dholland 		tl += 2;
   1601      1.1  dholland 		txdr_hyper(fdiraft.na_filerev, tl);
   1602      1.1  dholland 		tl += 2;
   1603      1.1  dholland 		*tl++ = newnfs_false;
   1604      1.1  dholland 		txdr_hyper(tdirfor.na_filerev, tl);
   1605      1.1  dholland 		tl += 2;
   1606      1.1  dholland 		txdr_hyper(tdiraft.na_filerev, tl);
   1607      1.1  dholland 	}
   1608      1.1  dholland 
   1609      1.1  dholland out:
   1610      1.1  dholland 	NFSEXITCODE2(error, nd);
   1611      1.1  dholland 	return (error);
   1612      1.1  dholland }
   1613      1.1  dholland 
   1614      1.1  dholland /*
   1615      1.1  dholland  * nfs link service
   1616      1.1  dholland  */
   1617      1.1  dholland APPLESTATIC int
   1618      1.1  dholland nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
   1619      1.1  dholland     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
   1620      1.1  dholland     struct nfsexstuff *toexp)
   1621      1.1  dholland {
   1622      1.1  dholland 	struct nameidata named;
   1623      1.1  dholland 	u_int32_t *tl;
   1624      1.1  dholland 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
   1625      1.1  dholland 	vnode_t dirp = NULL, dp = NULL;
   1626      1.1  dholland 	struct nfsvattr dirfor, diraft, at;
   1627      1.1  dholland 	struct nfsexstuff tnes;
   1628      1.1  dholland 	struct nfsrvfh dfh;
   1629      1.1  dholland 	char *bufp;
   1630      1.1  dholland 	u_long *hashp;
   1631      1.1  dholland 
   1632      1.1  dholland 	if (nd->nd_repstat) {
   1633      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   1634      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1635      1.1  dholland 		goto out;
   1636      1.1  dholland 	}
   1637      1.1  dholland 	NFSVOPUNLOCK(vp, 0);
   1638      1.1  dholland 	if (vnode_vtype(vp) == VDIR) {
   1639      1.1  dholland 		if (nd->nd_flag & ND_NFSV4)
   1640      1.1  dholland 			nd->nd_repstat = NFSERR_ISDIR;
   1641      1.1  dholland 		else
   1642      1.1  dholland 			nd->nd_repstat = NFSERR_INVAL;
   1643      1.1  dholland 		if (tovp)
   1644      1.1  dholland 			vrele(tovp);
   1645      1.1  dholland 	}
   1646      1.1  dholland 	if (!nd->nd_repstat) {
   1647      1.1  dholland 		if (nd->nd_flag & ND_NFSV4) {
   1648      1.1  dholland 			dp = tovp;
   1649      1.1  dholland 			tnes = *toexp;
   1650      1.1  dholland 		} else {
   1651      1.1  dholland 			error = nfsrv_mtofh(nd, &dfh);
   1652      1.1  dholland 			if (error) {
   1653      1.1  dholland 				vrele(vp);
   1654      1.1  dholland 				/* tovp is always NULL unless NFSv4 */
   1655      1.1  dholland 				goto out;
   1656      1.1  dholland 			}
   1657      1.1  dholland 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
   1658      1.1  dholland 			    p);
   1659      1.1  dholland 			if (dp)
   1660      1.1  dholland 				NFSVOPUNLOCK(dp, 0);
   1661      1.1  dholland 		}
   1662      1.1  dholland 	}
   1663      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1664  1.1.1.2  pgoyette 	    LOCKPARENT | SAVENAME | NOCACHE);
   1665      1.1  dholland 	if (!nd->nd_repstat) {
   1666      1.1  dholland 		nfsvno_setpathbuf(&named, &bufp, &hashp);
   1667      1.1  dholland 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1668      1.1  dholland 		if (error) {
   1669      1.1  dholland 			vrele(vp);
   1670      1.1  dholland 			if (dp)
   1671      1.1  dholland 				vrele(dp);
   1672      1.1  dholland 			nfsvno_relpathbuf(&named);
   1673      1.1  dholland 			goto out;
   1674      1.1  dholland 		}
   1675      1.1  dholland 		if (!nd->nd_repstat) {
   1676      1.1  dholland 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
   1677      1.1  dholland 			    p, &dirp);
   1678      1.1  dholland 		} else {
   1679      1.1  dholland 			if (dp)
   1680      1.1  dholland 				vrele(dp);
   1681      1.1  dholland 			nfsvno_relpathbuf(&named);
   1682      1.1  dholland 		}
   1683      1.1  dholland 	}
   1684      1.1  dholland 	if (dirp) {
   1685      1.1  dholland 		if (nd->nd_flag & ND_NFSV2) {
   1686      1.1  dholland 			vrele(dirp);
   1687      1.1  dholland 			dirp = NULL;
   1688      1.1  dholland 		} else {
   1689      1.1  dholland 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
   1690      1.1  dholland 			    nd->nd_cred, p, 0);
   1691      1.1  dholland 		}
   1692      1.1  dholland 	}
   1693      1.1  dholland 	if (!nd->nd_repstat)
   1694      1.1  dholland 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
   1695      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   1696      1.1  dholland 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
   1697      1.1  dholland 	if (dirp) {
   1698      1.1  dholland 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
   1699      1.1  dholland 		vrele(dirp);
   1700      1.1  dholland 	}
   1701      1.1  dholland 	vrele(vp);
   1702      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1703      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   1704      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1705      1.1  dholland 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1706      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1707      1.1  dholland 		*tl++ = newnfs_false;
   1708      1.1  dholland 		txdr_hyper(dirfor.na_filerev, tl);
   1709      1.1  dholland 		tl += 2;
   1710      1.1  dholland 		txdr_hyper(diraft.na_filerev, tl);
   1711      1.1  dholland 	}
   1712      1.1  dholland 
   1713      1.1  dholland out:
   1714      1.1  dholland 	NFSEXITCODE2(error, nd);
   1715      1.1  dholland 	return (error);
   1716      1.1  dholland }
   1717      1.1  dholland 
   1718      1.1  dholland /*
   1719      1.1  dholland  * nfs symbolic link service
   1720      1.1  dholland  */
   1721      1.1  dholland APPLESTATIC int
   1722      1.1  dholland nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
   1723      1.1  dholland     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1724      1.1  dholland     struct nfsexstuff *exp)
   1725      1.1  dholland {
   1726      1.1  dholland 	struct nfsvattr nva, dirfor, diraft;
   1727      1.1  dholland 	struct nameidata named;
   1728      1.1  dholland 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
   1729      1.1  dholland 	vnode_t dirp = NULL;
   1730      1.1  dholland 	char *bufp, *pathcp = NULL;
   1731      1.1  dholland 	u_long *hashp;
   1732      1.1  dholland 
   1733      1.1  dholland 	if (nd->nd_repstat) {
   1734      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1735      1.1  dholland 		goto out;
   1736      1.1  dholland 	}
   1737      1.1  dholland 	if (vpp)
   1738      1.1  dholland 		*vpp = NULL;
   1739      1.1  dholland 	NFSVNO_ATTRINIT(&nva);
   1740      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1741  1.1.1.2  pgoyette 	    LOCKPARENT | SAVESTART | NOCACHE);
   1742      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1743      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1744      1.1  dholland 	if (!error && !nd->nd_repstat)
   1745      1.1  dholland 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
   1746      1.1  dholland 	if (error) {
   1747      1.1  dholland 		vrele(dp);
   1748      1.1  dholland 		nfsvno_relpathbuf(&named);
   1749      1.1  dholland 		goto out;
   1750      1.1  dholland 	}
   1751      1.1  dholland 	if (!nd->nd_repstat) {
   1752      1.1  dholland 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1753      1.1  dholland 	} else {
   1754      1.1  dholland 		vrele(dp);
   1755      1.1  dholland 		nfsvno_relpathbuf(&named);
   1756      1.1  dholland 	}
   1757      1.1  dholland 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
   1758      1.1  dholland 		vrele(dirp);
   1759      1.1  dholland 		dirp = NULL;
   1760      1.1  dholland 	}
   1761      1.1  dholland 
   1762      1.1  dholland 	/*
   1763      1.1  dholland 	 * And call nfsrvd_symlinksub() to do the common code. It will
   1764      1.1  dholland 	 * return EBADRPC upon a parsing error, 0 otherwise.
   1765      1.1  dholland 	 */
   1766      1.1  dholland 	if (!nd->nd_repstat) {
   1767      1.1  dholland 		if (dirp != NULL)
   1768      1.1  dholland 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1769      1.1  dholland 			    p, 0);
   1770      1.1  dholland 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
   1771      1.1  dholland 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
   1772      1.1  dholland 		    pathcp, pathlen);
   1773      1.1  dholland 	} else if (dirp != NULL) {
   1774      1.1  dholland 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1775      1.1  dholland 		vrele(dirp);
   1776      1.1  dholland 	}
   1777      1.1  dholland 	if (pathcp)
   1778      1.1  dholland 		FREE(pathcp, M_TEMP);
   1779      1.1  dholland 
   1780      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1781      1.1  dholland 		if (!nd->nd_repstat) {
   1782      1.1  dholland 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1783      1.1  dholland 			nfsrv_postopattr(nd, 0, &nva);
   1784      1.1  dholland 		}
   1785      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1786      1.1  dholland 	}
   1787      1.1  dholland 
   1788      1.1  dholland out:
   1789      1.1  dholland 	NFSEXITCODE2(error, nd);
   1790      1.1  dholland 	return (error);
   1791      1.1  dholland }
   1792      1.1  dholland 
   1793      1.1  dholland /*
   1794      1.1  dholland  * Common code for creating a symbolic link.
   1795      1.1  dholland  */
   1796      1.1  dholland static void
   1797      1.1  dholland nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
   1798      1.1  dholland     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   1799      1.1  dholland     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   1800      1.1  dholland     int *diraft_retp, nfsattrbit_t *attrbitp,
   1801      1.1  dholland     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
   1802      1.1  dholland     int pathlen)
   1803      1.1  dholland {
   1804      1.1  dholland 	u_int32_t *tl;
   1805      1.1  dholland 
   1806      1.1  dholland 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
   1807      1.1  dholland 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
   1808      1.1  dholland 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
   1809      1.1  dholland 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
   1810      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1811      1.1  dholland 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
   1812      1.1  dholland 			if (!nd->nd_repstat)
   1813      1.1  dholland 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
   1814      1.1  dholland 				    nvap, nd->nd_cred, p, 1);
   1815      1.1  dholland 		}
   1816      1.1  dholland 		if (vpp != NULL && nd->nd_repstat == 0) {
   1817      1.1  dholland 			NFSVOPUNLOCK(ndp->ni_vp, 0);
   1818      1.1  dholland 			*vpp = ndp->ni_vp;
   1819      1.1  dholland 		} else
   1820      1.1  dholland 			vput(ndp->ni_vp);
   1821      1.1  dholland 	}
   1822      1.1  dholland 	if (dirp) {
   1823      1.1  dholland 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
   1824      1.1  dholland 		vrele(dirp);
   1825      1.1  dholland 	}
   1826      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1827      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1828      1.1  dholland 		*tl++ = newnfs_false;
   1829      1.1  dholland 		txdr_hyper(dirforp->na_filerev, tl);
   1830      1.1  dholland 		tl += 2;
   1831      1.1  dholland 		txdr_hyper(diraftp->na_filerev, tl);
   1832      1.1  dholland 		(void) nfsrv_putattrbit(nd, attrbitp);
   1833      1.1  dholland 	}
   1834      1.1  dholland 
   1835      1.1  dholland 	NFSEXITCODE2(0, nd);
   1836      1.1  dholland }
   1837      1.1  dholland 
   1838      1.1  dholland /*
   1839      1.1  dholland  * nfs mkdir service
   1840      1.1  dholland  */
   1841      1.1  dholland APPLESTATIC int
   1842      1.1  dholland nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
   1843      1.1  dholland     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
   1844      1.1  dholland     struct nfsexstuff *exp)
   1845      1.1  dholland {
   1846      1.1  dholland 	struct nfsvattr nva, dirfor, diraft;
   1847      1.1  dholland 	struct nameidata named;
   1848      1.1  dholland 	u_int32_t *tl;
   1849      1.1  dholland 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
   1850      1.1  dholland 	vnode_t dirp = NULL;
   1851      1.1  dholland 	char *bufp;
   1852      1.1  dholland 	u_long *hashp;
   1853      1.1  dholland 
   1854      1.1  dholland 	if (nd->nd_repstat) {
   1855      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1856      1.1  dholland 		goto out;
   1857      1.1  dholland 	}
   1858      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   1859  1.1.1.2  pgoyette 	    LOCKPARENT | SAVENAME | NOCACHE);
   1860      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   1861      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   1862      1.1  dholland 	if (error)
   1863      1.1  dholland 		goto nfsmout;
   1864      1.1  dholland 	if (!nd->nd_repstat) {
   1865      1.1  dholland 		NFSVNO_ATTRINIT(&nva);
   1866      1.1  dholland 		if (nd->nd_flag & ND_NFSV3) {
   1867  1.1.1.2  pgoyette 			error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
   1868      1.1  dholland 			if (error)
   1869      1.1  dholland 				goto nfsmout;
   1870      1.1  dholland 		} else {
   1871      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   1872      1.1  dholland 			nva.na_mode = nfstov_mode(*tl++);
   1873      1.1  dholland 		}
   1874      1.1  dholland 	}
   1875      1.1  dholland 	if (!nd->nd_repstat) {
   1876      1.1  dholland 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
   1877      1.1  dholland 	} else {
   1878      1.1  dholland 		vrele(dp);
   1879      1.1  dholland 		nfsvno_relpathbuf(&named);
   1880      1.1  dholland 	}
   1881      1.1  dholland 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
   1882      1.1  dholland 		vrele(dirp);
   1883      1.1  dholland 		dirp = NULL;
   1884      1.1  dholland 	}
   1885      1.1  dholland 	if (nd->nd_repstat) {
   1886      1.1  dholland 		if (dirp != NULL) {
   1887      1.1  dholland 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
   1888      1.1  dholland 			    p, 0);
   1889      1.1  dholland 			vrele(dirp);
   1890      1.1  dholland 		}
   1891      1.1  dholland 		if (nd->nd_flag & ND_NFSV3)
   1892      1.1  dholland 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
   1893      1.1  dholland 			    &diraft);
   1894      1.1  dholland 		goto out;
   1895      1.1  dholland 	}
   1896      1.1  dholland 	if (dirp != NULL)
   1897      1.1  dholland 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
   1898      1.1  dholland 
   1899      1.1  dholland 	/*
   1900      1.1  dholland 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
   1901      1.1  dholland 	 */
   1902      1.1  dholland 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
   1903      1.1  dholland 	    &diraft_ret, NULL, NULL, p, exp);
   1904      1.1  dholland 
   1905      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   1906      1.1  dholland 		if (!nd->nd_repstat) {
   1907      1.1  dholland 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
   1908      1.1  dholland 			nfsrv_postopattr(nd, 0, &nva);
   1909      1.1  dholland 		}
   1910      1.1  dholland 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
   1911      1.1  dholland 	} else if (!nd->nd_repstat) {
   1912      1.1  dholland 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
   1913      1.1  dholland 		nfsrv_fillattr(nd, &nva);
   1914      1.1  dholland 	}
   1915      1.1  dholland 
   1916      1.1  dholland out:
   1917      1.1  dholland 	NFSEXITCODE2(0, nd);
   1918      1.1  dholland 	return (0);
   1919      1.1  dholland nfsmout:
   1920      1.1  dholland 	vrele(dp);
   1921      1.1  dholland 	nfsvno_relpathbuf(&named);
   1922      1.1  dholland 	NFSEXITCODE2(error, nd);
   1923      1.1  dholland 	return (error);
   1924      1.1  dholland }
   1925      1.1  dholland 
   1926      1.1  dholland /*
   1927      1.1  dholland  * Code common to mkdir for V2,3 and 4.
   1928      1.1  dholland  */
   1929      1.1  dholland static void
   1930      1.1  dholland nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
   1931      1.1  dholland     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
   1932      1.1  dholland     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
   1933      1.1  dholland     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
   1934      1.1  dholland     NFSPROC_T *p, struct nfsexstuff *exp)
   1935      1.1  dholland {
   1936      1.1  dholland 	vnode_t vp;
   1937      1.1  dholland 	u_int32_t *tl;
   1938      1.1  dholland 
   1939      1.1  dholland 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
   1940      1.1  dholland 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
   1941      1.1  dholland 	    nd->nd_cred, p, exp);
   1942      1.1  dholland 	if (!nd->nd_repstat) {
   1943      1.1  dholland 		vp = ndp->ni_vp;
   1944      1.1  dholland 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
   1945      1.1  dholland 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
   1946      1.1  dholland 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
   1947      1.1  dholland 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
   1948      1.1  dholland 			    p, 1);
   1949      1.1  dholland 		if (vpp && !nd->nd_repstat) {
   1950      1.1  dholland 			NFSVOPUNLOCK(vp, 0);
   1951      1.1  dholland 			*vpp = vp;
   1952      1.1  dholland 		} else {
   1953      1.1  dholland 			vput(vp);
   1954      1.1  dholland 		}
   1955      1.1  dholland 	}
   1956      1.1  dholland 	if (dirp) {
   1957      1.1  dholland 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
   1958      1.1  dholland 		vrele(dirp);
   1959      1.1  dholland 	}
   1960      1.1  dholland 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
   1961      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
   1962      1.1  dholland 		*tl++ = newnfs_false;
   1963      1.1  dholland 		txdr_hyper(dirforp->na_filerev, tl);
   1964      1.1  dholland 		tl += 2;
   1965      1.1  dholland 		txdr_hyper(diraftp->na_filerev, tl);
   1966      1.1  dholland 		(void) nfsrv_putattrbit(nd, attrbitp);
   1967      1.1  dholland 	}
   1968      1.1  dholland 
   1969      1.1  dholland 	NFSEXITCODE2(0, nd);
   1970      1.1  dholland }
   1971      1.1  dholland 
   1972      1.1  dholland /*
   1973      1.1  dholland  * nfs commit service
   1974      1.1  dholland  */
   1975      1.1  dholland APPLESTATIC int
   1976      1.1  dholland nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
   1977      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   1978      1.1  dholland {
   1979      1.1  dholland 	struct nfsvattr bfor, aft;
   1980      1.1  dholland 	u_int32_t *tl;
   1981      1.1  dholland 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
   1982      1.1  dholland 	u_int64_t off;
   1983      1.1  dholland 
   1984  1.1.1.2  pgoyette        if (nd->nd_repstat) {
   1985      1.1  dholland 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
   1986      1.1  dholland 		goto out;
   1987      1.1  dholland 	}
   1988  1.1.1.2  pgoyette 
   1989  1.1.1.2  pgoyette 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
   1990  1.1.1.2  pgoyette 	if (vp->v_type != VREG) {
   1991  1.1.1.2  pgoyette 		if (nd->nd_flag & ND_NFSV3)
   1992  1.1.1.2  pgoyette 			error = NFSERR_NOTSUPP;
   1993  1.1.1.2  pgoyette 		else
   1994  1.1.1.2  pgoyette 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
   1995  1.1.1.2  pgoyette 		goto nfsmout;
   1996  1.1.1.2  pgoyette 	}
   1997      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1998  1.1.1.2  pgoyette 
   1999      1.1  dholland 	/*
   2000      1.1  dholland 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
   2001      1.1  dholland 	 * count parameters, so these arguments are useless (someday maybe).
   2002      1.1  dholland 	 */
   2003      1.1  dholland 	off = fxdr_hyper(tl);
   2004      1.1  dholland 	tl += 2;
   2005      1.1  dholland 	cnt = fxdr_unsigned(int, *tl);
   2006      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   2007      1.1  dholland 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
   2008      1.1  dholland 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
   2009      1.1  dholland 	if (nd->nd_flag & ND_NFSV3) {
   2010      1.1  dholland 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
   2011      1.1  dholland 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
   2012      1.1  dholland 	}
   2013      1.1  dholland 	vput(vp);
   2014      1.1  dholland 	if (!nd->nd_repstat) {
   2015      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
   2016      1.1  dholland 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
   2017      1.1  dholland 		*tl = txdr_unsigned(nfsboottime.tv_usec);
   2018      1.1  dholland 	}
   2019      1.1  dholland 
   2020      1.1  dholland out:
   2021      1.1  dholland 	NFSEXITCODE2(0, nd);
   2022      1.1  dholland 	return (0);
   2023      1.1  dholland nfsmout:
   2024      1.1  dholland 	vput(vp);
   2025      1.1  dholland 	NFSEXITCODE2(error, nd);
   2026      1.1  dholland 	return (error);
   2027      1.1  dholland }
   2028      1.1  dholland 
   2029      1.1  dholland /*
   2030      1.1  dholland  * nfs statfs service
   2031      1.1  dholland  */
   2032      1.1  dholland APPLESTATIC int
   2033      1.1  dholland nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
   2034      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2035      1.1  dholland {
   2036      1.1  dholland 	struct statfs *sf;
   2037      1.1  dholland 	u_int32_t *tl;
   2038      1.1  dholland 	int getret = 1;
   2039      1.1  dholland 	struct nfsvattr at;
   2040      1.1  dholland 	struct statfs sfs;
   2041      1.1  dholland 	u_quad_t tval;
   2042      1.1  dholland 
   2043      1.1  dholland 	if (nd->nd_repstat) {
   2044      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   2045      1.1  dholland 		goto out;
   2046      1.1  dholland 	}
   2047      1.1  dholland 	sf = &sfs;
   2048      1.1  dholland 	nd->nd_repstat = nfsvno_statfs(vp, sf);
   2049      1.1  dholland 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2050      1.1  dholland 	vput(vp);
   2051      1.1  dholland 	if (nd->nd_flag & ND_NFSV3)
   2052      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   2053      1.1  dholland 	if (nd->nd_repstat)
   2054      1.1  dholland 		goto out;
   2055      1.1  dholland 	if (nd->nd_flag & ND_NFSV2) {
   2056      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
   2057      1.1  dholland 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
   2058      1.1  dholland 		*tl++ = txdr_unsigned(sf->f_bsize);
   2059      1.1  dholland 		*tl++ = txdr_unsigned(sf->f_blocks);
   2060      1.1  dholland 		*tl++ = txdr_unsigned(sf->f_bfree);
   2061      1.1  dholland 		*tl = txdr_unsigned(sf->f_bavail);
   2062      1.1  dholland 	} else {
   2063      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
   2064      1.1  dholland 		tval = (u_quad_t)sf->f_blocks;
   2065      1.1  dholland 		tval *= (u_quad_t)sf->f_bsize;
   2066      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2067      1.1  dholland 		tval = (u_quad_t)sf->f_bfree;
   2068      1.1  dholland 		tval *= (u_quad_t)sf->f_bsize;
   2069      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2070      1.1  dholland 		tval = (u_quad_t)sf->f_bavail;
   2071      1.1  dholland 		tval *= (u_quad_t)sf->f_bsize;
   2072      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2073      1.1  dholland 		tval = (u_quad_t)sf->f_files;
   2074      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2075      1.1  dholland 		tval = (u_quad_t)sf->f_ffree;
   2076      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2077      1.1  dholland 		tval = (u_quad_t)sf->f_ffree;
   2078      1.1  dholland 		txdr_hyper(tval, tl); tl += 2;
   2079      1.1  dholland 		*tl = 0;
   2080      1.1  dholland 	}
   2081      1.1  dholland 
   2082      1.1  dholland out:
   2083      1.1  dholland 	NFSEXITCODE2(0, nd);
   2084      1.1  dholland 	return (0);
   2085      1.1  dholland }
   2086      1.1  dholland 
   2087      1.1  dholland /*
   2088      1.1  dholland  * nfs fsinfo service
   2089      1.1  dholland  */
   2090      1.1  dholland APPLESTATIC int
   2091      1.1  dholland nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
   2092      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2093      1.1  dholland {
   2094      1.1  dholland 	u_int32_t *tl;
   2095      1.1  dholland 	struct nfsfsinfo fs;
   2096      1.1  dholland 	int getret = 1;
   2097      1.1  dholland 	struct nfsvattr at;
   2098      1.1  dholland 
   2099      1.1  dholland 	if (nd->nd_repstat) {
   2100      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   2101      1.1  dholland 		goto out;
   2102      1.1  dholland 	}
   2103      1.1  dholland 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2104      1.1  dholland 	nfsvno_getfs(&fs, isdgram);
   2105      1.1  dholland 	vput(vp);
   2106      1.1  dholland 	nfsrv_postopattr(nd, getret, &at);
   2107      1.1  dholland 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
   2108      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_rtmax);
   2109      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_rtpref);
   2110      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_rtmult);
   2111      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_wtmax);
   2112      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_wtpref);
   2113      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_wtmult);
   2114      1.1  dholland 	*tl++ = txdr_unsigned(fs.fs_dtpref);
   2115      1.1  dholland 	txdr_hyper(fs.fs_maxfilesize, tl);
   2116      1.1  dholland 	tl += 2;
   2117      1.1  dholland 	txdr_nfsv3time(&fs.fs_timedelta, tl);
   2118      1.1  dholland 	tl += 2;
   2119      1.1  dholland 	*tl = txdr_unsigned(fs.fs_properties);
   2120      1.1  dholland 
   2121      1.1  dholland out:
   2122      1.1  dholland 	NFSEXITCODE2(0, nd);
   2123      1.1  dholland 	return (0);
   2124      1.1  dholland }
   2125      1.1  dholland 
   2126      1.1  dholland /*
   2127      1.1  dholland  * nfs pathconf service
   2128      1.1  dholland  */
   2129      1.1  dholland APPLESTATIC int
   2130      1.1  dholland nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
   2131      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   2132      1.1  dholland {
   2133      1.1  dholland 	struct nfsv3_pathconf *pc;
   2134      1.1  dholland 	int getret = 1;
   2135      1.1  dholland 	register_t linkmax, namemax, chownres, notrunc;
   2136      1.1  dholland 	struct nfsvattr at;
   2137      1.1  dholland 
   2138      1.1  dholland 	if (nd->nd_repstat) {
   2139      1.1  dholland 		nfsrv_postopattr(nd, getret, &at);
   2140      1.1  dholland 		goto out;
   2141      1.1  dholland 	}
   2142      1.1  dholland 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
   2143      1.1  dholland 	    nd->nd_cred, p);
   2144      1.1  dholland 	if (!nd->nd_repstat)
   2145      1.1  dholland 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
   2146      1.1  dholland 		    nd->nd_cred, p);
   2147      1.1  dholland 	if (!nd->nd_repstat)
   2148      1.1  dholland 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
   2149      1.1  dholland 		    &chownres, nd->nd_cred, p);
   2150      1.1  dholland 	if (!nd->nd_repstat)
   2151      1.1  dholland 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
   2152      1.1  dholland 		    nd->nd_cred, p);
   2153      1.1  dholland 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
   2154      1.1  dholland 	vput(vp);
   2155      1.1  dholland 	nfsrv_postopattr(nd, getret, &at);
   2156      1.1  dholland 	if (!nd->nd_repstat) {
   2157      1.1  dholland 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
   2158      1.1  dholland 		pc->pc_linkmax = txdr_unsigned(linkmax);
   2159      1.1  dholland 		pc->pc_namemax = txdr_unsigned(namemax);
   2160      1.1  dholland 		pc->pc_notrunc = txdr_unsigned(notrunc);
   2161      1.1  dholland 		pc->pc_chownrestricted = txdr_unsigned(chownres);
   2162      1.1  dholland 
   2163      1.1  dholland 		/*
   2164      1.1  dholland 		 * These should probably be supported by VOP_PATHCONF(), but
   2165      1.1  dholland 		 * until msdosfs is exportable (why would you want to?), the
   2166      1.1  dholland 		 * Unix defaults should be ok.
   2167      1.1  dholland 		 */
   2168      1.1  dholland 		pc->pc_caseinsensitive = newnfs_false;
   2169      1.1  dholland 		pc->pc_casepreserving = newnfs_true;
   2170      1.1  dholland 	}
   2171      1.1  dholland 
   2172      1.1  dholland out:
   2173      1.1  dholland 	NFSEXITCODE2(0, nd);
   2174      1.1  dholland 	return (0);
   2175      1.1  dholland }
   2176      1.1  dholland 
   2177      1.1  dholland /*
   2178      1.1  dholland  * nfsv4 lock service
   2179      1.1  dholland  */
   2180      1.1  dholland APPLESTATIC int
   2181      1.1  dholland nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
   2182      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2183      1.1  dholland {
   2184      1.1  dholland 	u_int32_t *tl;
   2185      1.1  dholland 	int i;
   2186      1.1  dholland 	struct nfsstate *stp = NULL;
   2187      1.1  dholland 	struct nfslock *lop;
   2188      1.1  dholland 	struct nfslockconflict cf;
   2189      1.1  dholland 	int error = 0;
   2190      1.1  dholland 	u_short flags = NFSLCK_LOCK, lflags;
   2191      1.1  dholland 	u_int64_t offset, len;
   2192      1.1  dholland 	nfsv4stateid_t stateid;
   2193      1.1  dholland 	nfsquad_t clientid;
   2194      1.1  dholland 
   2195      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2196      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   2197      1.1  dholland 	switch (i) {
   2198      1.1  dholland 	case NFSV4LOCKT_READW:
   2199      1.1  dholland 		flags |= NFSLCK_BLOCKING;
   2200      1.1  dholland 	case NFSV4LOCKT_READ:
   2201      1.1  dholland 		lflags = NFSLCK_READ;
   2202      1.1  dholland 		break;
   2203      1.1  dholland 	case NFSV4LOCKT_WRITEW:
   2204      1.1  dholland 		flags |= NFSLCK_BLOCKING;
   2205      1.1  dholland 	case NFSV4LOCKT_WRITE:
   2206      1.1  dholland 		lflags = NFSLCK_WRITE;
   2207      1.1  dholland 		break;
   2208      1.1  dholland 	default:
   2209      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2210      1.1  dholland 		goto nfsmout;
   2211  1.1.1.2  pgoyette 	}
   2212      1.1  dholland 	if (*tl++ == newnfs_true)
   2213      1.1  dholland 		flags |= NFSLCK_RECLAIM;
   2214      1.1  dholland 	offset = fxdr_hyper(tl);
   2215      1.1  dholland 	tl += 2;
   2216      1.1  dholland 	len = fxdr_hyper(tl);
   2217      1.1  dholland 	tl += 2;
   2218      1.1  dholland 	if (*tl == newnfs_true)
   2219      1.1  dholland 		flags |= NFSLCK_OPENTOLOCK;
   2220      1.1  dholland 	if (flags & NFSLCK_OPENTOLOCK) {
   2221      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
   2222      1.1  dholland 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
   2223      1.1  dholland 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2224      1.1  dholland 			nd->nd_repstat = NFSERR_BADXDR;
   2225      1.1  dholland 			goto nfsmout;
   2226      1.1  dholland 		}
   2227      1.1  dholland 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2228      1.1  dholland 			M_NFSDSTATE, M_WAITOK);
   2229      1.1  dholland 		stp->ls_ownerlen = i;
   2230      1.1  dholland 		stp->ls_op = nd->nd_rp;
   2231      1.1  dholland 		stp->ls_seq = fxdr_unsigned(int, *tl++);
   2232      1.1  dholland 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2233      1.1  dholland 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2234      1.1  dholland 			NFSX_STATEIDOTHER);
   2235      1.1  dholland 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2236      1.1  dholland 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
   2237      1.1  dholland 		clientid.lval[0] = *tl++;
   2238      1.1  dholland 		clientid.lval[1] = *tl++;
   2239  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2240  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2241  1.1.1.2  pgoyette 				clientid.qval = nd->nd_clientid.qval;
   2242  1.1.1.2  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
   2243  1.1.1.2  pgoyette 				printf("EEK3 multiple clids\n");
   2244      1.1  dholland 		} else {
   2245  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2246  1.1.1.2  pgoyette 				printf("EEK! no clientid from session\n");
   2247      1.1  dholland 			nd->nd_flag |= ND_IMPLIEDCLID;
   2248      1.1  dholland 			nd->nd_clientid.qval = clientid.qval;
   2249      1.1  dholland 		}
   2250      1.1  dholland 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2251      1.1  dholland 		if (error)
   2252      1.1  dholland 			goto nfsmout;
   2253      1.1  dholland 	} else {
   2254      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
   2255      1.1  dholland 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
   2256      1.1  dholland 			M_NFSDSTATE, M_WAITOK);
   2257      1.1  dholland 		stp->ls_ownerlen = 0;
   2258      1.1  dholland 		stp->ls_op = nd->nd_rp;
   2259      1.1  dholland 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2260      1.1  dholland 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2261      1.1  dholland 			NFSX_STATEIDOTHER);
   2262      1.1  dholland 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2263      1.1  dholland 		stp->ls_seq = fxdr_unsigned(int, *tl);
   2264      1.1  dholland 		clientid.lval[0] = stp->ls_stateid.other[0];
   2265      1.1  dholland 		clientid.lval[1] = stp->ls_stateid.other[1];
   2266  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2267  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2268  1.1.1.2  pgoyette 				clientid.qval = nd->nd_clientid.qval;
   2269  1.1.1.2  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
   2270  1.1.1.2  pgoyette 				printf("EEK4 multiple clids\n");
   2271      1.1  dholland 		} else {
   2272  1.1.1.2  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2273  1.1.1.2  pgoyette 				printf("EEK! no clientid from session\n");
   2274      1.1  dholland 			nd->nd_flag |= ND_IMPLIEDCLID;
   2275      1.1  dholland 			nd->nd_clientid.qval = clientid.qval;
   2276      1.1  dholland 		}
   2277      1.1  dholland 	}
   2278      1.1  dholland 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
   2279      1.1  dholland 		M_NFSDLOCK, M_WAITOK);
   2280      1.1  dholland 	lop->lo_first = offset;
   2281      1.1  dholland 	if (len == NFS64BITSSET) {
   2282      1.1  dholland 		lop->lo_end = NFS64BITSSET;
   2283      1.1  dholland 	} else {
   2284      1.1  dholland 		lop->lo_end = offset + len;
   2285      1.1  dholland 		if (lop->lo_end <= lop->lo_first)
   2286      1.1  dholland 			nd->nd_repstat = NFSERR_INVAL;
   2287      1.1  dholland 	}
   2288      1.1  dholland 	lop->lo_flags = lflags;
   2289      1.1  dholland 	stp->ls_flags = flags;
   2290      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   2291      1.1  dholland 
   2292      1.1  dholland 	/*
   2293      1.1  dholland 	 * Do basic access checking.
   2294      1.1  dholland 	 */
   2295      1.1  dholland 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2296      1.1  dholland 	    if (vnode_vtype(vp) == VDIR)
   2297      1.1  dholland 		nd->nd_repstat = NFSERR_ISDIR;
   2298      1.1  dholland 	    else
   2299      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
   2300      1.1  dholland 	}
   2301      1.1  dholland 	if (!nd->nd_repstat) {
   2302      1.1  dholland 	    if (lflags & NFSLCK_WRITE) {
   2303      1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
   2304      1.1  dholland 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2305      1.1  dholland 		    NFSACCCHK_VPISLOCKED, NULL);
   2306      1.1  dholland 	    } else {
   2307      1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
   2308      1.1  dholland 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2309      1.1  dholland 		    NFSACCCHK_VPISLOCKED, NULL);
   2310      1.1  dholland 		if (nd->nd_repstat)
   2311      1.1  dholland 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   2312      1.1  dholland 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2313      1.1  dholland 			NFSACCCHK_VPISLOCKED, NULL);
   2314      1.1  dholland 	    }
   2315      1.1  dholland 	}
   2316      1.1  dholland 
   2317      1.1  dholland 	/*
   2318      1.1  dholland 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
   2319      1.1  dholland 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
   2320      1.1  dholland 	 * of nd_repstat, if it gets that far.
   2321      1.1  dholland 	 */
   2322      1.1  dholland 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
   2323      1.1  dholland 		&stateid, exp, nd, p);
   2324      1.1  dholland 	if (lop)
   2325      1.1  dholland 		FREE((caddr_t)lop, M_NFSDLOCK);
   2326      1.1  dholland 	if (stp)
   2327      1.1  dholland 		FREE((caddr_t)stp, M_NFSDSTATE);
   2328      1.1  dholland 	if (!nd->nd_repstat) {
   2329      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2330      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   2331      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2332      1.1  dholland 	} else if (nd->nd_repstat == NFSERR_DENIED) {
   2333      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2334      1.1  dholland 		txdr_hyper(cf.cl_first, tl);
   2335      1.1  dholland 		tl += 2;
   2336      1.1  dholland 		if (cf.cl_end == NFS64BITSSET)
   2337      1.1  dholland 			len = NFS64BITSSET;
   2338      1.1  dholland 		else
   2339      1.1  dholland 			len = cf.cl_end - cf.cl_first;
   2340      1.1  dholland 		txdr_hyper(len, tl);
   2341      1.1  dholland 		tl += 2;
   2342      1.1  dholland 		if (cf.cl_flags == NFSLCK_WRITE)
   2343      1.1  dholland 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   2344      1.1  dholland 		else
   2345      1.1  dholland 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   2346      1.1  dholland 		*tl++ = stateid.other[0];
   2347      1.1  dholland 		*tl = stateid.other[1];
   2348      1.1  dholland 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
   2349      1.1  dholland 	}
   2350      1.1  dholland 	vput(vp);
   2351      1.1  dholland 	NFSEXITCODE2(0, nd);
   2352      1.1  dholland 	return (0);
   2353      1.1  dholland nfsmout:
   2354      1.1  dholland 	vput(vp);
   2355      1.1  dholland 	if (stp)
   2356      1.1  dholland 		free((caddr_t)stp, M_NFSDSTATE);
   2357      1.1  dholland 	NFSEXITCODE2(error, nd);
   2358      1.1  dholland 	return (error);
   2359      1.1  dholland }
   2360      1.1  dholland 
   2361      1.1  dholland /*
   2362      1.1  dholland  * nfsv4 lock test service
   2363      1.1  dholland  */
   2364      1.1  dholland APPLESTATIC int
   2365      1.1  dholland nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
   2366      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2367      1.1  dholland {
   2368      1.1  dholland 	u_int32_t *tl;
   2369      1.1  dholland 	int i;
   2370      1.1  dholland 	struct nfsstate *stp = NULL;
   2371      1.1  dholland 	struct nfslock lo, *lop = &lo;
   2372      1.1  dholland 	struct nfslockconflict cf;
   2373      1.1  dholland 	int error = 0;
   2374      1.1  dholland 	nfsv4stateid_t stateid;
   2375      1.1  dholland 	nfsquad_t clientid;
   2376      1.1  dholland 	u_int64_t len;
   2377      1.1  dholland 
   2378      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
   2379      1.1  dholland 	i = fxdr_unsigned(int, *(tl + 7));
   2380      1.1  dholland 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2381      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2382      1.1  dholland 		goto nfsmout;
   2383      1.1  dholland 	}
   2384      1.1  dholland 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2385      1.1  dholland 	    M_NFSDSTATE, M_WAITOK);
   2386      1.1  dholland 	stp->ls_ownerlen = i;
   2387      1.1  dholland 	stp->ls_op = NULL;
   2388      1.1  dholland 	stp->ls_flags = NFSLCK_TEST;
   2389      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   2390      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   2391      1.1  dholland 	switch (i) {
   2392      1.1  dholland 	case NFSV4LOCKT_READW:
   2393      1.1  dholland 		stp->ls_flags |= NFSLCK_BLOCKING;
   2394      1.1  dholland 	case NFSV4LOCKT_READ:
   2395      1.1  dholland 		lo.lo_flags = NFSLCK_READ;
   2396      1.1  dholland 		break;
   2397      1.1  dholland 	case NFSV4LOCKT_WRITEW:
   2398      1.1  dholland 		stp->ls_flags |= NFSLCK_BLOCKING;
   2399      1.1  dholland 	case NFSV4LOCKT_WRITE:
   2400      1.1  dholland 		lo.lo_flags = NFSLCK_WRITE;
   2401      1.1  dholland 		break;
   2402      1.1  dholland 	default:
   2403      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2404      1.1  dholland 		goto nfsmout;
   2405  1.1.1.2  pgoyette 	}
   2406      1.1  dholland 	lo.lo_first = fxdr_hyper(tl);
   2407      1.1  dholland 	tl += 2;
   2408      1.1  dholland 	len = fxdr_hyper(tl);
   2409      1.1  dholland 	if (len == NFS64BITSSET) {
   2410      1.1  dholland 		lo.lo_end = NFS64BITSSET;
   2411      1.1  dholland 	} else {
   2412      1.1  dholland 		lo.lo_end = lo.lo_first + len;
   2413      1.1  dholland 		if (lo.lo_end <= lo.lo_first)
   2414      1.1  dholland 			nd->nd_repstat = NFSERR_INVAL;
   2415      1.1  dholland 	}
   2416      1.1  dholland 	tl += 2;
   2417      1.1  dholland 	clientid.lval[0] = *tl++;
   2418      1.1  dholland 	clientid.lval[1] = *tl;
   2419  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2420  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2421  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2422  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2423  1.1.1.2  pgoyette 			printf("EEK5 multiple clids\n");
   2424      1.1  dholland 	} else {
   2425  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2426  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   2427      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   2428      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   2429      1.1  dholland 	}
   2430      1.1  dholland 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2431      1.1  dholland 	if (error)
   2432      1.1  dholland 		goto nfsmout;
   2433      1.1  dholland 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2434      1.1  dholland 	    if (vnode_vtype(vp) == VDIR)
   2435      1.1  dholland 		nd->nd_repstat = NFSERR_ISDIR;
   2436      1.1  dholland 	    else
   2437      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
   2438      1.1  dholland 	}
   2439      1.1  dholland 	if (!nd->nd_repstat)
   2440      1.1  dholland 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
   2441      1.1  dholland 	    &stateid, exp, nd, p);
   2442      1.1  dholland 	if (nd->nd_repstat) {
   2443      1.1  dholland 	    if (nd->nd_repstat == NFSERR_DENIED) {
   2444      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   2445      1.1  dholland 		txdr_hyper(cf.cl_first, tl);
   2446      1.1  dholland 		tl += 2;
   2447      1.1  dholland 		if (cf.cl_end == NFS64BITSSET)
   2448      1.1  dholland 			len = NFS64BITSSET;
   2449      1.1  dholland 		else
   2450      1.1  dholland 			len = cf.cl_end - cf.cl_first;
   2451      1.1  dholland 		txdr_hyper(len, tl);
   2452      1.1  dholland 		tl += 2;
   2453      1.1  dholland 		if (cf.cl_flags == NFSLCK_WRITE)
   2454      1.1  dholland 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
   2455      1.1  dholland 		else
   2456      1.1  dholland 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
   2457      1.1  dholland 		*tl++ = stp->ls_stateid.other[0];
   2458      1.1  dholland 		*tl = stp->ls_stateid.other[1];
   2459      1.1  dholland 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
   2460      1.1  dholland 	    }
   2461      1.1  dholland 	}
   2462      1.1  dholland 	vput(vp);
   2463  1.1.1.2  pgoyette 	if (stp)
   2464  1.1.1.2  pgoyette 		FREE((caddr_t)stp, M_NFSDSTATE);
   2465      1.1  dholland 	NFSEXITCODE2(0, nd);
   2466      1.1  dholland 	return (0);
   2467      1.1  dholland nfsmout:
   2468      1.1  dholland 	vput(vp);
   2469      1.1  dholland 	if (stp)
   2470      1.1  dholland 		free((caddr_t)stp, M_NFSDSTATE);
   2471      1.1  dholland 	NFSEXITCODE2(error, nd);
   2472      1.1  dholland 	return (error);
   2473      1.1  dholland }
   2474      1.1  dholland 
   2475      1.1  dholland /*
   2476      1.1  dholland  * nfsv4 unlock service
   2477      1.1  dholland  */
   2478      1.1  dholland APPLESTATIC int
   2479      1.1  dholland nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
   2480      1.1  dholland     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
   2481      1.1  dholland {
   2482      1.1  dholland 	u_int32_t *tl;
   2483      1.1  dholland 	int i;
   2484      1.1  dholland 	struct nfsstate *stp;
   2485      1.1  dholland 	struct nfslock *lop;
   2486      1.1  dholland 	int error = 0;
   2487      1.1  dholland 	nfsv4stateid_t stateid;
   2488      1.1  dholland 	nfsquad_t clientid;
   2489      1.1  dholland 	u_int64_t len;
   2490      1.1  dholland 
   2491      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
   2492      1.1  dholland 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
   2493      1.1  dholland 	    M_NFSDSTATE, M_WAITOK);
   2494      1.1  dholland 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
   2495      1.1  dholland 	    M_NFSDLOCK, M_WAITOK);
   2496      1.1  dholland 	stp->ls_flags = NFSLCK_UNLOCK;
   2497      1.1  dholland 	lop->lo_flags = NFSLCK_UNLOCK;
   2498      1.1  dholland 	stp->ls_op = nd->nd_rp;
   2499      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   2500      1.1  dholland 	switch (i) {
   2501      1.1  dholland 	case NFSV4LOCKT_READW:
   2502      1.1  dholland 		stp->ls_flags |= NFSLCK_BLOCKING;
   2503      1.1  dholland 	case NFSV4LOCKT_READ:
   2504      1.1  dholland 		break;
   2505      1.1  dholland 	case NFSV4LOCKT_WRITEW:
   2506      1.1  dholland 		stp->ls_flags |= NFSLCK_BLOCKING;
   2507      1.1  dholland 	case NFSV4LOCKT_WRITE:
   2508      1.1  dholland 		break;
   2509      1.1  dholland 	default:
   2510      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2511      1.1  dholland 		free(stp, M_NFSDSTATE);
   2512      1.1  dholland 		free(lop, M_NFSDLOCK);
   2513      1.1  dholland 		goto nfsmout;
   2514  1.1.1.2  pgoyette 	}
   2515      1.1  dholland 	stp->ls_ownerlen = 0;
   2516      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   2517      1.1  dholland 	stp->ls_seq = fxdr_unsigned(int, *tl++);
   2518      1.1  dholland 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2519      1.1  dholland 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   2520      1.1  dholland 	    NFSX_STATEIDOTHER);
   2521      1.1  dholland 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2522      1.1  dholland 	lop->lo_first = fxdr_hyper(tl);
   2523      1.1  dholland 	tl += 2;
   2524      1.1  dholland 	len = fxdr_hyper(tl);
   2525      1.1  dholland 	if (len == NFS64BITSSET) {
   2526      1.1  dholland 		lop->lo_end = NFS64BITSSET;
   2527      1.1  dholland 	} else {
   2528      1.1  dholland 		lop->lo_end = lop->lo_first + len;
   2529      1.1  dholland 		if (lop->lo_end <= lop->lo_first)
   2530      1.1  dholland 			nd->nd_repstat = NFSERR_INVAL;
   2531      1.1  dholland 	}
   2532      1.1  dholland 	clientid.lval[0] = stp->ls_stateid.other[0];
   2533      1.1  dholland 	clientid.lval[1] = stp->ls_stateid.other[1];
   2534  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2535  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2536  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2537  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2538  1.1.1.2  pgoyette 			printf("EEK6 multiple clids\n");
   2539      1.1  dholland 	} else {
   2540  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2541  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   2542      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   2543      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   2544      1.1  dholland 	}
   2545      1.1  dholland 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2546      1.1  dholland 	    if (vnode_vtype(vp) == VDIR)
   2547      1.1  dholland 		nd->nd_repstat = NFSERR_ISDIR;
   2548      1.1  dholland 	    else
   2549      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
   2550      1.1  dholland 	}
   2551      1.1  dholland 	/*
   2552      1.1  dholland 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
   2553      1.1  dholland 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
   2554      1.1  dholland 	 * value of nd_repstat, if it gets that far.
   2555      1.1  dholland 	 */
   2556      1.1  dholland 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
   2557      1.1  dholland 	    &stateid, exp, nd, p);
   2558      1.1  dholland 	if (stp)
   2559      1.1  dholland 		FREE((caddr_t)stp, M_NFSDSTATE);
   2560      1.1  dholland 	if (lop)
   2561      1.1  dholland 		free((caddr_t)lop, M_NFSDLOCK);
   2562      1.1  dholland 	if (!nd->nd_repstat) {
   2563      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   2564      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   2565      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2566      1.1  dholland 	}
   2567      1.1  dholland nfsmout:
   2568      1.1  dholland 	vput(vp);
   2569      1.1  dholland 	NFSEXITCODE2(error, nd);
   2570      1.1  dholland 	return (error);
   2571      1.1  dholland }
   2572      1.1  dholland 
   2573      1.1  dholland /*
   2574      1.1  dholland  * nfsv4 open service
   2575      1.1  dholland  */
   2576      1.1  dholland APPLESTATIC int
   2577      1.1  dholland nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
   2578      1.1  dholland     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
   2579      1.1  dholland     struct nfsexstuff *exp)
   2580      1.1  dholland {
   2581      1.1  dholland 	u_int32_t *tl;
   2582  1.1.1.2  pgoyette 	int i, retext;
   2583      1.1  dholland 	struct nfsstate *stp = NULL;
   2584      1.1  dholland 	int error = 0, create, claim, exclusive_flag = 0;
   2585      1.1  dholland 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
   2586      1.1  dholland 	int how = NFSCREATE_UNCHECKED;
   2587      1.1  dholland 	int32_t cverf[2], tverf[2] = { 0, 0 };
   2588      1.1  dholland 	vnode_t vp = NULL, dirp = NULL;
   2589      1.1  dholland 	struct nfsvattr nva, dirfor, diraft;
   2590      1.1  dholland 	struct nameidata named;
   2591      1.1  dholland 	nfsv4stateid_t stateid, delegstateid;
   2592      1.1  dholland 	nfsattrbit_t attrbits;
   2593      1.1  dholland 	nfsquad_t clientid;
   2594      1.1  dholland 	char *bufp = NULL;
   2595      1.1  dholland 	u_long *hashp;
   2596      1.1  dholland 	NFSACL_T *aclp = NULL;
   2597      1.1  dholland 
   2598      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   2599      1.1  dholland 	aclp = acl_alloc(M_WAITOK);
   2600      1.1  dholland 	aclp->acl_cnt = 0;
   2601      1.1  dholland #endif
   2602      1.1  dholland 	NFSZERO_ATTRBIT(&attrbits);
   2603      1.1  dholland 	named.ni_startdir = NULL;
   2604      1.1  dholland 	named.ni_cnd.cn_nameiop = 0;
   2605      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
   2606      1.1  dholland 	i = fxdr_unsigned(int, *(tl + 5));
   2607      1.1  dholland 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
   2608      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2609      1.1  dholland 		goto nfsmout;
   2610      1.1  dholland 	}
   2611      1.1  dholland 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
   2612      1.1  dholland 	    M_NFSDSTATE, M_WAITOK);
   2613      1.1  dholland 	stp->ls_ownerlen = i;
   2614      1.1  dholland 	stp->ls_op = nd->nd_rp;
   2615      1.1  dholland 	stp->ls_flags = NFSLCK_OPEN;
   2616      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   2617      1.1  dholland 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   2618      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   2619  1.1.1.2  pgoyette 	retext = 0;
   2620  1.1.1.2  pgoyette 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
   2621  1.1.1.2  pgoyette 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
   2622  1.1.1.2  pgoyette 		retext = 1;
   2623  1.1.1.2  pgoyette 		/* For now, ignore these. */
   2624  1.1.1.2  pgoyette 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
   2625  1.1.1.2  pgoyette 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
   2626  1.1.1.2  pgoyette 		case NFSV4OPEN_WANTANYDELEG:
   2627  1.1.1.2  pgoyette 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
   2628  1.1.1.2  pgoyette 			    NFSLCK_WANTWDELEG);
   2629  1.1.1.2  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2630  1.1.1.2  pgoyette 			break;
   2631  1.1.1.2  pgoyette 		case NFSV4OPEN_WANTREADDELEG:
   2632  1.1.1.2  pgoyette 			stp->ls_flags |= NFSLCK_WANTRDELEG;
   2633  1.1.1.2  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2634  1.1.1.2  pgoyette 			break;
   2635  1.1.1.2  pgoyette 		case NFSV4OPEN_WANTWRITEDELEG:
   2636  1.1.1.2  pgoyette 			stp->ls_flags |= NFSLCK_WANTWDELEG;
   2637  1.1.1.2  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2638  1.1.1.2  pgoyette 			break;
   2639  1.1.1.2  pgoyette 		case NFSV4OPEN_WANTNODELEG:
   2640  1.1.1.2  pgoyette 			stp->ls_flags |= NFSLCK_WANTNODELEG;
   2641  1.1.1.2  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2642  1.1.1.2  pgoyette 			break;
   2643  1.1.1.2  pgoyette 		case NFSV4OPEN_WANTCANCEL:
   2644  1.1.1.2  pgoyette 			printf("NFSv4: ignore Open WantCancel\n");
   2645  1.1.1.2  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2646  1.1.1.2  pgoyette 			break;
   2647  1.1.1.2  pgoyette 		default:
   2648  1.1.1.2  pgoyette 			/* nd_repstat will be set to NFSERR_INVAL below. */
   2649  1.1.1.2  pgoyette 			break;
   2650  1.1.1.2  pgoyette 		}
   2651  1.1.1.2  pgoyette 	}
   2652      1.1  dholland 	switch (i) {
   2653      1.1  dholland 	case NFSV4OPEN_ACCESSREAD:
   2654      1.1  dholland 		stp->ls_flags |= NFSLCK_READACCESS;
   2655      1.1  dholland 		break;
   2656      1.1  dholland 	case NFSV4OPEN_ACCESSWRITE:
   2657      1.1  dholland 		stp->ls_flags |= NFSLCK_WRITEACCESS;
   2658      1.1  dholland 		break;
   2659      1.1  dholland 	case NFSV4OPEN_ACCESSBOTH:
   2660      1.1  dholland 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
   2661      1.1  dholland 		break;
   2662      1.1  dholland 	default:
   2663      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
   2664  1.1.1.2  pgoyette 	}
   2665      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   2666      1.1  dholland 	switch (i) {
   2667      1.1  dholland 	case NFSV4OPEN_DENYNONE:
   2668      1.1  dholland 		break;
   2669      1.1  dholland 	case NFSV4OPEN_DENYREAD:
   2670      1.1  dholland 		stp->ls_flags |= NFSLCK_READDENY;
   2671      1.1  dholland 		break;
   2672      1.1  dholland 	case NFSV4OPEN_DENYWRITE:
   2673      1.1  dholland 		stp->ls_flags |= NFSLCK_WRITEDENY;
   2674      1.1  dholland 		break;
   2675      1.1  dholland 	case NFSV4OPEN_DENYBOTH:
   2676      1.1  dholland 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
   2677      1.1  dholland 		break;
   2678      1.1  dholland 	default:
   2679      1.1  dholland 		nd->nd_repstat = NFSERR_INVAL;
   2680  1.1.1.2  pgoyette 	}
   2681      1.1  dholland 	clientid.lval[0] = *tl++;
   2682      1.1  dholland 	clientid.lval[1] = *tl;
   2683  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2684  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2685  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2686  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2687  1.1.1.2  pgoyette 			printf("EEK7 multiple clids\n");
   2688      1.1  dholland 	} else {
   2689  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2690  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   2691      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   2692      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   2693      1.1  dholland 	}
   2694      1.1  dholland 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
   2695      1.1  dholland 	if (error)
   2696      1.1  dholland 		goto nfsmout;
   2697      1.1  dholland 	NFSVNO_ATTRINIT(&nva);
   2698      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2699      1.1  dholland 	create = fxdr_unsigned(int, *tl);
   2700      1.1  dholland 	if (!nd->nd_repstat)
   2701      1.1  dholland 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
   2702      1.1  dholland 	if (create == NFSV4OPEN_CREATE) {
   2703      1.1  dholland 		nva.na_type = VREG;
   2704      1.1  dholland 		nva.na_mode = 0;
   2705      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2706      1.1  dholland 		how = fxdr_unsigned(int, *tl);
   2707      1.1  dholland 		switch (how) {
   2708      1.1  dholland 		case NFSCREATE_UNCHECKED:
   2709      1.1  dholland 		case NFSCREATE_GUARDED:
   2710  1.1.1.2  pgoyette 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
   2711      1.1  dholland 			if (error)
   2712      1.1  dholland 				goto nfsmout;
   2713      1.1  dholland 			/*
   2714      1.1  dholland 			 * If the na_gid being set is the same as that of
   2715      1.1  dholland 			 * the directory it is going in, clear it, since
   2716      1.1  dholland 			 * that is what will be set by default. This allows
   2717      1.1  dholland 			 * a user that isn't in that group to do the create.
   2718      1.1  dholland 			 */
   2719      1.1  dholland 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
   2720      1.1  dholland 			    nva.na_gid == dirfor.na_gid)
   2721      1.1  dholland 				NFSVNO_UNSET(&nva, gid);
   2722      1.1  dholland 			if (!nd->nd_repstat)
   2723      1.1  dholland 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   2724      1.1  dholland 			break;
   2725      1.1  dholland 		case NFSCREATE_EXCLUSIVE:
   2726      1.1  dholland 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   2727      1.1  dholland 			cverf[0] = *tl++;
   2728      1.1  dholland 			cverf[1] = *tl;
   2729      1.1  dholland 			break;
   2730  1.1.1.2  pgoyette 		case NFSCREATE_EXCLUSIVE41:
   2731  1.1.1.2  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   2732  1.1.1.2  pgoyette 			cverf[0] = *tl++;
   2733  1.1.1.2  pgoyette 			cverf[1] = *tl;
   2734  1.1.1.2  pgoyette 			error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
   2735  1.1.1.2  pgoyette 			if (error != 0)
   2736  1.1.1.2  pgoyette 				goto nfsmout;
   2737  1.1.1.2  pgoyette 			if (NFSISSET_ATTRBIT(&attrbits,
   2738  1.1.1.2  pgoyette 			    NFSATTRBIT_TIMEACCESSSET))
   2739  1.1.1.2  pgoyette 				nd->nd_repstat = NFSERR_INVAL;
   2740  1.1.1.2  pgoyette 			/*
   2741  1.1.1.2  pgoyette 			 * If the na_gid being set is the same as that of
   2742  1.1.1.2  pgoyette 			 * the directory it is going in, clear it, since
   2743  1.1.1.2  pgoyette 			 * that is what will be set by default. This allows
   2744  1.1.1.2  pgoyette 			 * a user that isn't in that group to do the create.
   2745  1.1.1.2  pgoyette 			 */
   2746  1.1.1.2  pgoyette 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
   2747  1.1.1.2  pgoyette 			    nva.na_gid == dirfor.na_gid)
   2748  1.1.1.2  pgoyette 				NFSVNO_UNSET(&nva, gid);
   2749  1.1.1.2  pgoyette 			if (nd->nd_repstat == 0)
   2750  1.1.1.2  pgoyette 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   2751  1.1.1.2  pgoyette 			break;
   2752      1.1  dholland 		default:
   2753      1.1  dholland 			nd->nd_repstat = NFSERR_BADXDR;
   2754      1.1  dholland 			goto nfsmout;
   2755  1.1.1.2  pgoyette 		}
   2756      1.1  dholland 	} else if (create != NFSV4OPEN_NOCREATE) {
   2757      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2758      1.1  dholland 		goto nfsmout;
   2759      1.1  dholland 	}
   2760      1.1  dholland 
   2761      1.1  dholland 	/*
   2762      1.1  dholland 	 * Now, handle the claim, which usually includes looking up a
   2763      1.1  dholland 	 * name in the directory referenced by dp. The exception is
   2764      1.1  dholland 	 * NFSV4OPEN_CLAIMPREVIOUS.
   2765      1.1  dholland 	 */
   2766      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2767      1.1  dholland 	claim = fxdr_unsigned(int, *tl);
   2768      1.1  dholland 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
   2769      1.1  dholland 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   2770      1.1  dholland 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   2771      1.1  dholland 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
   2772      1.1  dholland 		stp->ls_flags |= NFSLCK_DELEGCUR;
   2773      1.1  dholland 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
   2774      1.1  dholland 		stp->ls_flags |= NFSLCK_DELEGPREV;
   2775      1.1  dholland 	}
   2776      1.1  dholland 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
   2777      1.1  dholland 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
   2778      1.1  dholland 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
   2779      1.1  dholland 		    claim != NFSV4OPEN_CLAIMNULL)
   2780      1.1  dholland 			nd->nd_repstat = NFSERR_INVAL;
   2781      1.1  dholland 		if (nd->nd_repstat) {
   2782      1.1  dholland 			nd->nd_repstat = nfsrv_opencheck(clientid,
   2783      1.1  dholland 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
   2784      1.1  dholland 			goto nfsmout;
   2785      1.1  dholland 		}
   2786      1.1  dholland 		if (create == NFSV4OPEN_CREATE)
   2787      1.1  dholland 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
   2788  1.1.1.2  pgoyette 			LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
   2789      1.1  dholland 		else
   2790      1.1  dholland 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
   2791      1.1  dholland 			LOCKLEAF | SAVESTART);
   2792      1.1  dholland 		nfsvno_setpathbuf(&named, &bufp, &hashp);
   2793      1.1  dholland 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   2794      1.1  dholland 		if (error) {
   2795      1.1  dholland 			vrele(dp);
   2796      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   2797      1.1  dholland 			acl_free(aclp);
   2798      1.1  dholland #endif
   2799      1.1  dholland 			FREE((caddr_t)stp, M_NFSDSTATE);
   2800      1.1  dholland 			nfsvno_relpathbuf(&named);
   2801      1.1  dholland 			NFSEXITCODE2(error, nd);
   2802      1.1  dholland 			return (error);
   2803      1.1  dholland 		}
   2804      1.1  dholland 		if (!nd->nd_repstat) {
   2805      1.1  dholland 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
   2806      1.1  dholland 			    p, &dirp);
   2807      1.1  dholland 		} else {
   2808      1.1  dholland 			vrele(dp);
   2809      1.1  dholland 			nfsvno_relpathbuf(&named);
   2810      1.1  dholland 		}
   2811      1.1  dholland 		if (create == NFSV4OPEN_CREATE) {
   2812      1.1  dholland 		    switch (how) {
   2813      1.1  dholland 		    case NFSCREATE_UNCHECKED:
   2814      1.1  dholland 			if (named.ni_vp) {
   2815      1.1  dholland 				/*
   2816      1.1  dholland 				 * Clear the setable attribute bits, except
   2817      1.1  dholland 				 * for Size, if it is being truncated.
   2818      1.1  dholland 				 */
   2819      1.1  dholland 				NFSZERO_ATTRBIT(&attrbits);
   2820      1.1  dholland 				if (NFSVNO_ISSETSIZE(&nva))
   2821      1.1  dholland 					NFSSETBIT_ATTRBIT(&attrbits,
   2822      1.1  dholland 					    NFSATTRBIT_SIZE);
   2823      1.1  dholland 			}
   2824      1.1  dholland 			break;
   2825      1.1  dholland 		    case NFSCREATE_GUARDED:
   2826      1.1  dholland 			if (named.ni_vp && !nd->nd_repstat)
   2827      1.1  dholland 				nd->nd_repstat = EEXIST;
   2828      1.1  dholland 			break;
   2829      1.1  dholland 		    case NFSCREATE_EXCLUSIVE:
   2830      1.1  dholland 			exclusive_flag = 1;
   2831      1.1  dholland 			if (!named.ni_vp)
   2832      1.1  dholland 				nva.na_mode = 0;
   2833  1.1.1.2  pgoyette 			break;
   2834  1.1.1.2  pgoyette 		    case NFSCREATE_EXCLUSIVE41:
   2835  1.1.1.2  pgoyette 			exclusive_flag = 1;
   2836  1.1.1.2  pgoyette 			break;
   2837  1.1.1.2  pgoyette 		    }
   2838      1.1  dholland 		}
   2839      1.1  dholland 		nfsvno_open(nd, &named, clientid, &stateid, stp,
   2840      1.1  dholland 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
   2841      1.1  dholland 		    nd->nd_cred, p, exp, &vp);
   2842  1.1.1.2  pgoyette 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
   2843  1.1.1.2  pgoyette 	    NFSV4OPEN_CLAIMFH) {
   2844  1.1.1.2  pgoyette 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
   2845  1.1.1.2  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2846  1.1.1.2  pgoyette 			i = fxdr_unsigned(int, *tl);
   2847  1.1.1.2  pgoyette 			switch (i) {
   2848  1.1.1.2  pgoyette 			case NFSV4OPEN_DELEGATEREAD:
   2849  1.1.1.2  pgoyette 				stp->ls_flags |= NFSLCK_DELEGREAD;
   2850  1.1.1.2  pgoyette 				break;
   2851  1.1.1.2  pgoyette 			case NFSV4OPEN_DELEGATEWRITE:
   2852  1.1.1.2  pgoyette 				stp->ls_flags |= NFSLCK_DELEGWRITE;
   2853  1.1.1.2  pgoyette 			case NFSV4OPEN_DELEGATENONE:
   2854  1.1.1.2  pgoyette 				break;
   2855  1.1.1.2  pgoyette 			default:
   2856  1.1.1.2  pgoyette 				nd->nd_repstat = NFSERR_BADXDR;
   2857  1.1.1.2  pgoyette 				goto nfsmout;
   2858  1.1.1.2  pgoyette 			}
   2859  1.1.1.2  pgoyette 			stp->ls_flags |= NFSLCK_RECLAIM;
   2860  1.1.1.2  pgoyette 		} else {
   2861  1.1.1.2  pgoyette 			/* CLAIM_NULL_FH */
   2862  1.1.1.2  pgoyette 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
   2863  1.1.1.2  pgoyette 				nd->nd_repstat = NFSERR_INVAL;
   2864  1.1.1.2  pgoyette 		}
   2865      1.1  dholland 		vp = dp;
   2866      1.1  dholland 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
   2867      1.1  dholland 		if ((vp->v_iflag & VI_DOOMED) == 0)
   2868      1.1  dholland 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
   2869      1.1  dholland 			    stp, vp, nd, p, nd->nd_repstat);
   2870      1.1  dholland 		else
   2871      1.1  dholland 			nd->nd_repstat = NFSERR_PERM;
   2872      1.1  dholland 	} else {
   2873      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   2874      1.1  dholland 		goto nfsmout;
   2875      1.1  dholland 	}
   2876      1.1  dholland 
   2877      1.1  dholland 	/*
   2878      1.1  dholland 	 * Do basic access checking.
   2879      1.1  dholland 	 */
   2880      1.1  dholland 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
   2881      1.1  dholland 		/*
   2882      1.1  dholland 		 * The IETF working group decided that this is the correct
   2883      1.1  dholland 		 * error return for all non-regular files.
   2884      1.1  dholland 		 */
   2885  1.1.1.2  pgoyette 		nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
   2886      1.1  dholland 	}
   2887      1.1  dholland 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
   2888      1.1  dholland 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
   2889      1.1  dholland 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
   2890      1.1  dholland 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
   2891      1.1  dholland 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
   2892      1.1  dholland 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
   2893      1.1  dholland 	    if (nd->nd_repstat)
   2894      1.1  dholland 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
   2895      1.1  dholland 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
   2896      1.1  dholland 		    NFSACCCHK_VPISLOCKED, NULL);
   2897      1.1  dholland 	}
   2898      1.1  dholland 
   2899      1.1  dholland 	if (!nd->nd_repstat) {
   2900      1.1  dholland 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
   2901      1.1  dholland 		if (!nd->nd_repstat) {
   2902      1.1  dholland 			tverf[0] = nva.na_atime.tv_sec;
   2903      1.1  dholland 			tverf[1] = nva.na_atime.tv_nsec;
   2904      1.1  dholland 		}
   2905      1.1  dholland 	}
   2906      1.1  dholland 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
   2907      1.1  dholland 	    cverf[1] != tverf[1]))
   2908      1.1  dholland 		nd->nd_repstat = EEXIST;
   2909      1.1  dholland 	/*
   2910      1.1  dholland 	 * Do the open locking/delegation stuff.
   2911      1.1  dholland 	 */
   2912      1.1  dholland 	if (!nd->nd_repstat)
   2913      1.1  dholland 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
   2914      1.1  dholland 		&delegstateid, &rflags, exp, p, nva.na_filerev);
   2915      1.1  dholland 
   2916      1.1  dholland 	/*
   2917      1.1  dholland 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
   2918      1.1  dholland 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
   2919      1.1  dholland 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
   2920      1.1  dholland 	 */
   2921      1.1  dholland 	if (vp)
   2922      1.1  dholland 		NFSVOPUNLOCK(vp, 0);
   2923      1.1  dholland 	if (stp)
   2924      1.1  dholland 		FREE((caddr_t)stp, M_NFSDSTATE);
   2925      1.1  dholland 	if (!nd->nd_repstat && dirp)
   2926      1.1  dholland 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
   2927      1.1  dholland 		    0);
   2928      1.1  dholland 	if (!nd->nd_repstat) {
   2929      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
   2930      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   2931      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   2932      1.1  dholland 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2933      1.1  dholland 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
   2934      1.1  dholland 			*tl++ = newnfs_true;
   2935      1.1  dholland 			*tl++ = 0;
   2936      1.1  dholland 			*tl++ = 0;
   2937      1.1  dholland 			*tl++ = 0;
   2938      1.1  dholland 			*tl++ = 0;
   2939      1.1  dholland 		} else {
   2940      1.1  dholland 			*tl++ = newnfs_false;	/* Since dirp is not locked */
   2941      1.1  dholland 			txdr_hyper(dirfor.na_filerev, tl);
   2942      1.1  dholland 			tl += 2;
   2943      1.1  dholland 			txdr_hyper(diraft.na_filerev, tl);
   2944      1.1  dholland 			tl += 2;
   2945      1.1  dholland 		}
   2946      1.1  dholland 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
   2947      1.1  dholland 		(void) nfsrv_putattrbit(nd, &attrbits);
   2948      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2949      1.1  dholland 		if (rflags & NFSV4OPEN_READDELEGATE)
   2950      1.1  dholland 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
   2951      1.1  dholland 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
   2952      1.1  dholland 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
   2953  1.1.1.2  pgoyette 		else if (retext != 0) {
   2954  1.1.1.2  pgoyette 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
   2955  1.1.1.2  pgoyette 			if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
   2956  1.1.1.2  pgoyette 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2957  1.1.1.2  pgoyette 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
   2958  1.1.1.2  pgoyette 				*tl = newnfs_false;
   2959  1.1.1.2  pgoyette 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
   2960  1.1.1.2  pgoyette 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2961  1.1.1.2  pgoyette 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
   2962  1.1.1.2  pgoyette 				*tl = newnfs_false;
   2963  1.1.1.2  pgoyette 			} else {
   2964  1.1.1.2  pgoyette 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2965  1.1.1.2  pgoyette 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
   2966  1.1.1.2  pgoyette 			}
   2967  1.1.1.2  pgoyette 		} else
   2968      1.1  dholland 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
   2969      1.1  dholland 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
   2970      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
   2971      1.1  dholland 			*tl++ = txdr_unsigned(delegstateid.seqid);
   2972      1.1  dholland 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
   2973      1.1  dholland 			    NFSX_STATEIDOTHER);
   2974      1.1  dholland 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   2975      1.1  dholland 			if (rflags & NFSV4OPEN_RECALL)
   2976      1.1  dholland 				*tl = newnfs_true;
   2977      1.1  dholland 			else
   2978      1.1  dholland 				*tl = newnfs_false;
   2979      1.1  dholland 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
   2980      1.1  dholland 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2981      1.1  dholland 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
   2982      1.1  dholland 				txdr_hyper(nva.na_size, tl);
   2983      1.1  dholland 			}
   2984      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   2985      1.1  dholland 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
   2986      1.1  dholland 			*tl++ = txdr_unsigned(0x0);
   2987      1.1  dholland 			acemask = NFSV4ACE_ALLFILESMASK;
   2988      1.1  dholland 			if (nva.na_mode & S_IRUSR)
   2989      1.1  dholland 			    acemask |= NFSV4ACE_READMASK;
   2990      1.1  dholland 			if (nva.na_mode & S_IWUSR)
   2991      1.1  dholland 			    acemask |= NFSV4ACE_WRITEMASK;
   2992      1.1  dholland 			if (nva.na_mode & S_IXUSR)
   2993      1.1  dholland 			    acemask |= NFSV4ACE_EXECUTEMASK;
   2994      1.1  dholland 			*tl = txdr_unsigned(acemask);
   2995      1.1  dholland 			(void) nfsm_strtom(nd, "OWNER@", 6);
   2996      1.1  dholland 		}
   2997      1.1  dholland 		*vpp = vp;
   2998      1.1  dholland 	} else if (vp) {
   2999      1.1  dholland 		vrele(vp);
   3000      1.1  dholland 	}
   3001      1.1  dholland 	if (dirp)
   3002      1.1  dholland 		vrele(dirp);
   3003      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   3004      1.1  dholland 	acl_free(aclp);
   3005      1.1  dholland #endif
   3006      1.1  dholland 	NFSEXITCODE2(0, nd);
   3007      1.1  dholland 	return (0);
   3008      1.1  dholland nfsmout:
   3009      1.1  dholland 	vrele(dp);
   3010      1.1  dholland #ifdef NFS4_ACL_EXTATTR_NAME
   3011      1.1  dholland 	acl_free(aclp);
   3012      1.1  dholland #endif
   3013      1.1  dholland 	if (stp)
   3014      1.1  dholland 		FREE((caddr_t)stp, M_NFSDSTATE);
   3015      1.1  dholland 	NFSEXITCODE2(error, nd);
   3016      1.1  dholland 	return (error);
   3017      1.1  dholland }
   3018      1.1  dholland 
   3019      1.1  dholland /*
   3020      1.1  dholland  * nfsv4 close service
   3021      1.1  dholland  */
   3022      1.1  dholland APPLESTATIC int
   3023      1.1  dholland nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
   3024      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3025      1.1  dholland {
   3026      1.1  dholland 	u_int32_t *tl;
   3027      1.1  dholland 	struct nfsstate st, *stp = &st;
   3028      1.1  dholland 	int error = 0;
   3029      1.1  dholland 	nfsv4stateid_t stateid;
   3030      1.1  dholland 	nfsquad_t clientid;
   3031      1.1  dholland 
   3032      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
   3033      1.1  dholland 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   3034      1.1  dholland 	stp->ls_ownerlen = 0;
   3035      1.1  dholland 	stp->ls_op = nd->nd_rp;
   3036      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   3037      1.1  dholland 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3038      1.1  dholland 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   3039      1.1  dholland 	    NFSX_STATEIDOTHER);
   3040      1.1  dholland 	stp->ls_flags = NFSLCK_CLOSE;
   3041      1.1  dholland 	clientid.lval[0] = stp->ls_stateid.other[0];
   3042      1.1  dholland 	clientid.lval[1] = stp->ls_stateid.other[1];
   3043  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3044  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3045  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3046  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3047  1.1.1.2  pgoyette 			printf("EEK8 multiple clids\n");
   3048      1.1  dholland 	} else {
   3049  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3050  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3051      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3052      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3053      1.1  dholland 	}
   3054      1.1  dholland 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
   3055      1.1  dholland 	vput(vp);
   3056      1.1  dholland 	if (!nd->nd_repstat) {
   3057      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   3058      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   3059      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   3060      1.1  dholland 	}
   3061      1.1  dholland 	NFSEXITCODE2(0, nd);
   3062      1.1  dholland 	return (0);
   3063      1.1  dholland nfsmout:
   3064      1.1  dholland 	vput(vp);
   3065      1.1  dholland 	NFSEXITCODE2(error, nd);
   3066      1.1  dholland 	return (error);
   3067      1.1  dholland }
   3068      1.1  dholland 
   3069      1.1  dholland /*
   3070      1.1  dholland  * nfsv4 delegpurge service
   3071      1.1  dholland  */
   3072      1.1  dholland APPLESTATIC int
   3073      1.1  dholland nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
   3074      1.1  dholland     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3075      1.1  dholland {
   3076      1.1  dholland 	u_int32_t *tl;
   3077      1.1  dholland 	int error = 0;
   3078      1.1  dholland 	nfsquad_t clientid;
   3079      1.1  dholland 
   3080      1.1  dholland 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3081      1.1  dholland 		nd->nd_repstat = NFSERR_WRONGSEC;
   3082      1.1  dholland 		goto nfsmout;
   3083      1.1  dholland 	}
   3084      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3085      1.1  dholland 	clientid.lval[0] = *tl++;
   3086      1.1  dholland 	clientid.lval[1] = *tl;
   3087  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3088  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3089  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3090  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3091  1.1.1.2  pgoyette 			printf("EEK9 multiple clids\n");
   3092      1.1  dholland 	} else {
   3093  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3094  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3095      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3096      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3097      1.1  dholland 	}
   3098  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
   3099      1.1  dholland 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
   3100      1.1  dholland nfsmout:
   3101      1.1  dholland 	NFSEXITCODE2(error, nd);
   3102      1.1  dholland 	return (error);
   3103      1.1  dholland }
   3104      1.1  dholland 
   3105      1.1  dholland /*
   3106      1.1  dholland  * nfsv4 delegreturn service
   3107      1.1  dholland  */
   3108      1.1  dholland APPLESTATIC int
   3109      1.1  dholland nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
   3110      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3111      1.1  dholland {
   3112      1.1  dholland 	u_int32_t *tl;
   3113      1.1  dholland 	int error = 0;
   3114      1.1  dholland 	nfsv4stateid_t stateid;
   3115      1.1  dholland 	nfsquad_t clientid;
   3116      1.1  dholland 
   3117      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
   3118      1.1  dholland 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3119      1.1  dholland 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
   3120      1.1  dholland 	clientid.lval[0] = stateid.other[0];
   3121      1.1  dholland 	clientid.lval[1] = stateid.other[1];
   3122  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3123  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3124  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3125  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3126  1.1.1.2  pgoyette 			printf("EEK10 multiple clids\n");
   3127      1.1  dholland 	} else {
   3128  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3129  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3130      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3131      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3132      1.1  dholland 	}
   3133  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
   3134      1.1  dholland 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
   3135      1.1  dholland nfsmout:
   3136      1.1  dholland 	vput(vp);
   3137      1.1  dholland 	NFSEXITCODE2(error, nd);
   3138      1.1  dholland 	return (error);
   3139      1.1  dholland }
   3140      1.1  dholland 
   3141      1.1  dholland /*
   3142      1.1  dholland  * nfsv4 get file handle service
   3143      1.1  dholland  */
   3144      1.1  dholland APPLESTATIC int
   3145      1.1  dholland nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
   3146      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3147      1.1  dholland {
   3148      1.1  dholland 	fhandle_t fh;
   3149      1.1  dholland 
   3150      1.1  dholland 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   3151      1.1  dholland 	vput(vp);
   3152      1.1  dholland 	if (!nd->nd_repstat)
   3153      1.1  dholland 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
   3154      1.1  dholland 	NFSEXITCODE2(0, nd);
   3155      1.1  dholland 	return (0);
   3156      1.1  dholland }
   3157      1.1  dholland 
   3158      1.1  dholland /*
   3159      1.1  dholland  * nfsv4 open confirm service
   3160      1.1  dholland  */
   3161      1.1  dholland APPLESTATIC int
   3162      1.1  dholland nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
   3163      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3164      1.1  dholland {
   3165      1.1  dholland 	u_int32_t *tl;
   3166      1.1  dholland 	struct nfsstate st, *stp = &st;
   3167      1.1  dholland 	int error = 0;
   3168      1.1  dholland 	nfsv4stateid_t stateid;
   3169      1.1  dholland 	nfsquad_t clientid;
   3170      1.1  dholland 
   3171  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3172  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3173  1.1.1.2  pgoyette 		goto nfsmout;
   3174  1.1.1.2  pgoyette 	}
   3175      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
   3176      1.1  dholland 	stp->ls_ownerlen = 0;
   3177      1.1  dholland 	stp->ls_op = nd->nd_rp;
   3178      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   3179      1.1  dholland 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3180      1.1  dholland 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   3181      1.1  dholland 	    NFSX_STATEIDOTHER);
   3182      1.1  dholland 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   3183      1.1  dholland 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
   3184      1.1  dholland 	stp->ls_flags = NFSLCK_CONFIRM;
   3185      1.1  dholland 	clientid.lval[0] = stp->ls_stateid.other[0];
   3186      1.1  dholland 	clientid.lval[1] = stp->ls_stateid.other[1];
   3187  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3188  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3189  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3190  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3191  1.1.1.2  pgoyette 			printf("EEK11 multiple clids\n");
   3192      1.1  dholland 	} else {
   3193  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3194  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3195      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3196      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3197      1.1  dholland 	}
   3198      1.1  dholland 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
   3199      1.1  dholland 	if (!nd->nd_repstat) {
   3200      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   3201      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   3202      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   3203      1.1  dholland 	}
   3204      1.1  dholland nfsmout:
   3205      1.1  dholland 	vput(vp);
   3206      1.1  dholland 	NFSEXITCODE2(error, nd);
   3207      1.1  dholland 	return (error);
   3208      1.1  dholland }
   3209      1.1  dholland 
   3210      1.1  dholland /*
   3211      1.1  dholland  * nfsv4 open downgrade service
   3212      1.1  dholland  */
   3213      1.1  dholland APPLESTATIC int
   3214      1.1  dholland nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
   3215      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3216      1.1  dholland {
   3217      1.1  dholland 	u_int32_t *tl;
   3218      1.1  dholland 	int i;
   3219      1.1  dholland 	struct nfsstate st, *stp = &st;
   3220      1.1  dholland 	int error = 0;
   3221      1.1  dholland 	nfsv4stateid_t stateid;
   3222      1.1  dholland 	nfsquad_t clientid;
   3223      1.1  dholland 
   3224  1.1.1.2  pgoyette 	/* opendowngrade can only work on a file object.*/
   3225  1.1.1.2  pgoyette 	if (vp->v_type != VREG) {
   3226  1.1.1.2  pgoyette 		error = NFSERR_INVAL;
   3227  1.1.1.2  pgoyette 		goto nfsmout;
   3228  1.1.1.2  pgoyette 	}
   3229      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
   3230      1.1  dholland 	stp->ls_ownerlen = 0;
   3231      1.1  dholland 	stp->ls_op = nd->nd_rp;
   3232      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   3233      1.1  dholland 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
   3234      1.1  dholland 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
   3235      1.1  dholland 	    NFSX_STATEIDOTHER);
   3236      1.1  dholland 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
   3237      1.1  dholland 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
   3238      1.1  dholland 	i = fxdr_unsigned(int, *tl++);
   3239      1.1  dholland 	switch (i) {
   3240      1.1  dholland 	case NFSV4OPEN_ACCESSREAD:
   3241      1.1  dholland 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
   3242      1.1  dholland 		break;
   3243      1.1  dholland 	case NFSV4OPEN_ACCESSWRITE:
   3244      1.1  dholland 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
   3245      1.1  dholland 		break;
   3246      1.1  dholland 	case NFSV4OPEN_ACCESSBOTH:
   3247      1.1  dholland 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
   3248      1.1  dholland 		    NFSLCK_DOWNGRADE);
   3249      1.1  dholland 		break;
   3250      1.1  dholland 	default:
   3251      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   3252  1.1.1.2  pgoyette 	}
   3253      1.1  dholland 	i = fxdr_unsigned(int, *tl);
   3254      1.1  dholland 	switch (i) {
   3255      1.1  dholland 	case NFSV4OPEN_DENYNONE:
   3256      1.1  dholland 		break;
   3257      1.1  dholland 	case NFSV4OPEN_DENYREAD:
   3258      1.1  dholland 		stp->ls_flags |= NFSLCK_READDENY;
   3259      1.1  dholland 		break;
   3260      1.1  dholland 	case NFSV4OPEN_DENYWRITE:
   3261      1.1  dholland 		stp->ls_flags |= NFSLCK_WRITEDENY;
   3262      1.1  dholland 		break;
   3263      1.1  dholland 	case NFSV4OPEN_DENYBOTH:
   3264      1.1  dholland 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
   3265      1.1  dholland 		break;
   3266      1.1  dholland 	default:
   3267      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   3268  1.1.1.2  pgoyette 	}
   3269      1.1  dholland 
   3270      1.1  dholland 	clientid.lval[0] = stp->ls_stateid.other[0];
   3271      1.1  dholland 	clientid.lval[1] = stp->ls_stateid.other[1];
   3272  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3273  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3274  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3275  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3276  1.1.1.2  pgoyette 			printf("EEK12 multiple clids\n");
   3277      1.1  dholland 	} else {
   3278  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3279  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3280      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3281      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3282      1.1  dholland 	}
   3283      1.1  dholland 	if (!nd->nd_repstat)
   3284      1.1  dholland 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
   3285      1.1  dholland 		    nd, p);
   3286      1.1  dholland 	if (!nd->nd_repstat) {
   3287      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
   3288      1.1  dholland 		*tl++ = txdr_unsigned(stateid.seqid);
   3289      1.1  dholland 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
   3290      1.1  dholland 	}
   3291      1.1  dholland nfsmout:
   3292      1.1  dholland 	vput(vp);
   3293      1.1  dholland 	NFSEXITCODE2(error, nd);
   3294      1.1  dholland 	return (error);
   3295      1.1  dholland }
   3296      1.1  dholland 
   3297      1.1  dholland /*
   3298      1.1  dholland  * nfsv4 renew lease service
   3299      1.1  dholland  */
   3300      1.1  dholland APPLESTATIC int
   3301      1.1  dholland nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
   3302      1.1  dholland     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3303      1.1  dholland {
   3304      1.1  dholland 	u_int32_t *tl;
   3305      1.1  dholland 	int error = 0;
   3306      1.1  dholland 	nfsquad_t clientid;
   3307      1.1  dholland 
   3308  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3309  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3310  1.1.1.2  pgoyette 		goto nfsmout;
   3311  1.1.1.2  pgoyette 	}
   3312      1.1  dholland 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3313      1.1  dholland 		nd->nd_repstat = NFSERR_WRONGSEC;
   3314      1.1  dholland 		goto nfsmout;
   3315      1.1  dholland 	}
   3316      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
   3317      1.1  dholland 	clientid.lval[0] = *tl++;
   3318      1.1  dholland 	clientid.lval[1] = *tl;
   3319  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3320  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3321  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3322  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3323  1.1.1.2  pgoyette 			printf("EEK13 multiple clids\n");
   3324      1.1  dholland 	} else {
   3325  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3326  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3327      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3328      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3329      1.1  dholland 	}
   3330      1.1  dholland 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
   3331  1.1.1.2  pgoyette 	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
   3332      1.1  dholland nfsmout:
   3333      1.1  dholland 	NFSEXITCODE2(error, nd);
   3334      1.1  dholland 	return (error);
   3335      1.1  dholland }
   3336      1.1  dholland 
   3337      1.1  dholland /*
   3338      1.1  dholland  * nfsv4 security info service
   3339      1.1  dholland  */
   3340      1.1  dholland APPLESTATIC int
   3341      1.1  dholland nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
   3342      1.1  dholland     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
   3343      1.1  dholland {
   3344      1.1  dholland 	u_int32_t *tl;
   3345      1.1  dholland 	int len;
   3346      1.1  dholland 	struct nameidata named;
   3347      1.1  dholland 	vnode_t dirp = NULL, vp;
   3348      1.1  dholland 	struct nfsrvfh fh;
   3349      1.1  dholland 	struct nfsexstuff retnes;
   3350      1.1  dholland 	u_int32_t *sizp;
   3351      1.1  dholland 	int error = 0, savflag, i;
   3352      1.1  dholland 	char *bufp;
   3353      1.1  dholland 	u_long *hashp;
   3354      1.1  dholland 
   3355      1.1  dholland 	/*
   3356      1.1  dholland 	 * All this just to get the export flags for the name.
   3357      1.1  dholland 	 */
   3358      1.1  dholland 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
   3359      1.1  dholland 	    LOCKLEAF | SAVESTART);
   3360      1.1  dholland 	nfsvno_setpathbuf(&named, &bufp, &hashp);
   3361      1.1  dholland 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
   3362      1.1  dholland 	if (error) {
   3363      1.1  dholland 		vput(dp);
   3364      1.1  dholland 		nfsvno_relpathbuf(&named);
   3365      1.1  dholland 		goto out;
   3366      1.1  dholland 	}
   3367      1.1  dholland 	if (!nd->nd_repstat) {
   3368      1.1  dholland 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
   3369      1.1  dholland 	} else {
   3370      1.1  dholland 		vput(dp);
   3371      1.1  dholland 		nfsvno_relpathbuf(&named);
   3372      1.1  dholland 	}
   3373      1.1  dholland 	if (dirp)
   3374      1.1  dholland 		vrele(dirp);
   3375      1.1  dholland 	if (nd->nd_repstat)
   3376      1.1  dholland 		goto out;
   3377      1.1  dholland 	vrele(named.ni_startdir);
   3378      1.1  dholland 	nfsvno_relpathbuf(&named);
   3379      1.1  dholland 	fh.nfsrvfh_len = NFSX_MYFH;
   3380      1.1  dholland 	vp = named.ni_vp;
   3381      1.1  dholland 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
   3382      1.1  dholland 	vput(vp);
   3383      1.1  dholland 	savflag = nd->nd_flag;
   3384      1.1  dholland 	if (!nd->nd_repstat) {
   3385      1.1  dholland 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
   3386      1.1  dholland 		if (vp)
   3387      1.1  dholland 			vput(vp);
   3388      1.1  dholland 	}
   3389      1.1  dholland 	nd->nd_flag = savflag;
   3390      1.1  dholland 	if (nd->nd_repstat)
   3391      1.1  dholland 		goto out;
   3392      1.1  dholland 
   3393      1.1  dholland 	/*
   3394      1.1  dholland 	 * Finally have the export flags for name, so we can create
   3395      1.1  dholland 	 * the security info.
   3396      1.1  dholland 	 */
   3397      1.1  dholland 	len = 0;
   3398      1.1  dholland 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
   3399      1.1  dholland 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
   3400      1.1  dholland 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
   3401      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3402      1.1  dholland 			*tl = txdr_unsigned(RPCAUTH_UNIX);
   3403      1.1  dholland 			len++;
   3404      1.1  dholland 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
   3405      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3406      1.1  dholland 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3407      1.1  dholland 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3408      1.1  dholland 			    nfsgss_mechlist[KERBV_MECH].len);
   3409      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3410      1.1  dholland 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3411      1.1  dholland 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
   3412      1.1  dholland 			len++;
   3413      1.1  dholland 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
   3414      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3415      1.1  dholland 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3416      1.1  dholland 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3417      1.1  dholland 			    nfsgss_mechlist[KERBV_MECH].len);
   3418      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3419      1.1  dholland 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3420      1.1  dholland 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
   3421      1.1  dholland 			len++;
   3422      1.1  dholland 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
   3423      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   3424      1.1  dholland 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
   3425      1.1  dholland 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
   3426      1.1  dholland 			    nfsgss_mechlist[KERBV_MECH].len);
   3427      1.1  dholland 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3428      1.1  dholland 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
   3429      1.1  dholland 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
   3430      1.1  dholland 			len++;
   3431      1.1  dholland 		}
   3432      1.1  dholland 	}
   3433      1.1  dholland 	*sizp = txdr_unsigned(len);
   3434      1.1  dholland 
   3435      1.1  dholland out:
   3436      1.1  dholland 	NFSEXITCODE2(error, nd);
   3437      1.1  dholland 	return (error);
   3438      1.1  dholland }
   3439      1.1  dholland 
   3440      1.1  dholland /*
   3441      1.1  dholland  * nfsv4 set client id service
   3442      1.1  dholland  */
   3443      1.1  dholland APPLESTATIC int
   3444      1.1  dholland nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
   3445      1.1  dholland     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3446      1.1  dholland {
   3447      1.1  dholland 	u_int32_t *tl;
   3448      1.1  dholland 	int i;
   3449      1.1  dholland 	int error = 0, idlen;
   3450      1.1  dholland 	struct nfsclient *clp = NULL;
   3451      1.1  dholland 	struct sockaddr_in *rad;
   3452      1.1  dholland 	u_char *verf, *ucp, *ucp2, addrbuf[24];
   3453      1.1  dholland 	nfsquad_t clientid, confirm;
   3454      1.1  dholland 
   3455  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3456  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3457  1.1.1.2  pgoyette 		goto nfsmout;
   3458  1.1.1.2  pgoyette 	}
   3459      1.1  dholland 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3460      1.1  dholland 		nd->nd_repstat = NFSERR_WRONGSEC;
   3461      1.1  dholland 		goto out;
   3462      1.1  dholland 	}
   3463      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
   3464      1.1  dholland 	verf = (u_char *)tl;
   3465      1.1  dholland 	tl += (NFSX_VERF / NFSX_UNSIGNED);
   3466      1.1  dholland 	i = fxdr_unsigned(int, *tl);
   3467      1.1  dholland 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
   3468      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   3469      1.1  dholland 		goto nfsmout;
   3470      1.1  dholland 	}
   3471      1.1  dholland 	idlen = i;
   3472      1.1  dholland 	if (nd->nd_flag & ND_GSS)
   3473      1.1  dholland 		i += nd->nd_princlen;
   3474  1.1.1.2  pgoyette 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
   3475  1.1.1.2  pgoyette 	    M_ZERO);
   3476  1.1.1.2  pgoyette 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
   3477  1.1.1.2  pgoyette 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
   3478      1.1  dholland 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
   3479      1.1  dholland 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
   3480      1.1  dholland 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
   3481      1.1  dholland 	clp->lc_req.nr_cred = NULL;
   3482      1.1  dholland 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
   3483      1.1  dholland 	clp->lc_idlen = idlen;
   3484      1.1  dholland 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
   3485      1.1  dholland 	if (error)
   3486      1.1  dholland 		goto nfsmout;
   3487      1.1  dholland 	if (nd->nd_flag & ND_GSS) {
   3488      1.1  dholland 		clp->lc_flags = LCL_GSS;
   3489      1.1  dholland 		if (nd->nd_flag & ND_GSSINTEGRITY)
   3490      1.1  dholland 			clp->lc_flags |= LCL_GSSINTEGRITY;
   3491      1.1  dholland 		else if (nd->nd_flag & ND_GSSPRIVACY)
   3492      1.1  dholland 			clp->lc_flags |= LCL_GSSPRIVACY;
   3493      1.1  dholland 	} else {
   3494      1.1  dholland 		clp->lc_flags = 0;
   3495      1.1  dholland 	}
   3496      1.1  dholland 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
   3497      1.1  dholland 		clp->lc_flags |= LCL_NAME;
   3498      1.1  dholland 		clp->lc_namelen = nd->nd_princlen;
   3499      1.1  dholland 		clp->lc_name = &clp->lc_id[idlen];
   3500      1.1  dholland 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
   3501      1.1  dholland 	} else {
   3502      1.1  dholland 		clp->lc_uid = nd->nd_cred->cr_uid;
   3503      1.1  dholland 		clp->lc_gid = nd->nd_cred->cr_gid;
   3504      1.1  dholland 	}
   3505      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3506      1.1  dholland 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
   3507      1.1  dholland 	error = nfsrv_getclientipaddr(nd, clp);
   3508      1.1  dholland 	if (error)
   3509      1.1  dholland 		goto nfsmout;
   3510      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3511      1.1  dholland 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
   3512      1.1  dholland 
   3513      1.1  dholland 	/*
   3514      1.1  dholland 	 * nfsrv_setclient() does the actual work of adding it to the
   3515      1.1  dholland 	 * client list. If there is no error, the structure has been
   3516      1.1  dholland 	 * linked into the client list and clp should no longer be used
   3517      1.1  dholland 	 * here. When an error is returned, it has not been linked in,
   3518      1.1  dholland 	 * so it should be free'd.
   3519      1.1  dholland 	 */
   3520      1.1  dholland 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
   3521      1.1  dholland 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
   3522      1.1  dholland 		if (clp->lc_flags & LCL_TCPCALLBACK)
   3523      1.1  dholland 			(void) nfsm_strtom(nd, "tcp", 3);
   3524      1.1  dholland 		else
   3525      1.1  dholland 			(void) nfsm_strtom(nd, "udp", 3);
   3526      1.1  dholland 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
   3527      1.1  dholland 		ucp = (u_char *)&rad->sin_addr.s_addr;
   3528      1.1  dholland 		ucp2 = (u_char *)&rad->sin_port;
   3529      1.1  dholland 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
   3530      1.1  dholland 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
   3531      1.1  dholland 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
   3532      1.1  dholland 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
   3533      1.1  dholland 	}
   3534      1.1  dholland 	if (clp) {
   3535      1.1  dholland 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3536      1.1  dholland 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3537  1.1.1.2  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3538  1.1.1.2  pgoyette 		free(clp, M_NFSDCLIENT);
   3539      1.1  dholland 	}
   3540      1.1  dholland 	if (!nd->nd_repstat) {
   3541      1.1  dholland 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
   3542      1.1  dholland 		*tl++ = clientid.lval[0];
   3543      1.1  dholland 		*tl++ = clientid.lval[1];
   3544      1.1  dholland 		*tl++ = confirm.lval[0];
   3545      1.1  dholland 		*tl = confirm.lval[1];
   3546      1.1  dholland 	}
   3547      1.1  dholland 
   3548      1.1  dholland out:
   3549      1.1  dholland 	NFSEXITCODE2(0, nd);
   3550      1.1  dholland 	return (0);
   3551      1.1  dholland nfsmout:
   3552      1.1  dholland 	if (clp) {
   3553      1.1  dholland 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3554      1.1  dholland 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3555  1.1.1.2  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3556  1.1.1.2  pgoyette 		free(clp, M_NFSDCLIENT);
   3557      1.1  dholland 	}
   3558      1.1  dholland 	NFSEXITCODE2(error, nd);
   3559      1.1  dholland 	return (error);
   3560      1.1  dholland }
   3561      1.1  dholland 
   3562      1.1  dholland /*
   3563      1.1  dholland  * nfsv4 set client id confirm service
   3564      1.1  dholland  */
   3565      1.1  dholland APPLESTATIC int
   3566      1.1  dholland nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
   3567      1.1  dholland     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
   3568      1.1  dholland     __unused struct nfsexstuff *exp)
   3569      1.1  dholland {
   3570      1.1  dholland 	u_int32_t *tl;
   3571      1.1  dholland 	int error = 0;
   3572      1.1  dholland 	nfsquad_t clientid, confirm;
   3573      1.1  dholland 
   3574  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3575  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3576  1.1.1.2  pgoyette 		goto nfsmout;
   3577  1.1.1.2  pgoyette 	}
   3578      1.1  dholland 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3579      1.1  dholland 		nd->nd_repstat = NFSERR_WRONGSEC;
   3580      1.1  dholland 		goto nfsmout;
   3581      1.1  dholland 	}
   3582      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
   3583      1.1  dholland 	clientid.lval[0] = *tl++;
   3584      1.1  dholland 	clientid.lval[1] = *tl++;
   3585      1.1  dholland 	confirm.lval[0] = *tl++;
   3586      1.1  dholland 	confirm.lval[1] = *tl;
   3587      1.1  dholland 
   3588      1.1  dholland 	/*
   3589      1.1  dholland 	 * nfsrv_getclient() searches the client list for a match and
   3590      1.1  dholland 	 * returns the appropriate NFSERR status.
   3591      1.1  dholland 	 */
   3592      1.1  dholland 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
   3593  1.1.1.2  pgoyette 	    NULL, NULL, confirm, 0, nd, p);
   3594      1.1  dholland nfsmout:
   3595      1.1  dholland 	NFSEXITCODE2(error, nd);
   3596      1.1  dholland 	return (error);
   3597      1.1  dholland }
   3598      1.1  dholland 
   3599      1.1  dholland /*
   3600      1.1  dholland  * nfsv4 verify service
   3601      1.1  dholland  */
   3602      1.1  dholland APPLESTATIC int
   3603      1.1  dholland nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
   3604      1.1  dholland     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3605      1.1  dholland {
   3606      1.1  dholland 	int error = 0, ret, fhsize = NFSX_MYFH;
   3607      1.1  dholland 	struct nfsvattr nva;
   3608      1.1  dholland 	struct statfs sf;
   3609      1.1  dholland 	struct nfsfsinfo fs;
   3610      1.1  dholland 	fhandle_t fh;
   3611      1.1  dholland 
   3612      1.1  dholland 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
   3613      1.1  dholland 	if (!nd->nd_repstat)
   3614      1.1  dholland 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
   3615      1.1  dholland 	if (!nd->nd_repstat)
   3616      1.1  dholland 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
   3617      1.1  dholland 	if (!nd->nd_repstat) {
   3618      1.1  dholland 		nfsvno_getfs(&fs, isdgram);
   3619      1.1  dholland 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
   3620      1.1  dholland 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
   3621      1.1  dholland 		if (!error) {
   3622      1.1  dholland 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
   3623      1.1  dholland 				if (ret == 0)
   3624      1.1  dholland 					nd->nd_repstat = NFSERR_SAME;
   3625      1.1  dholland 				else if (ret != NFSERR_NOTSAME)
   3626      1.1  dholland 					nd->nd_repstat = ret;
   3627      1.1  dholland 			} else if (ret)
   3628      1.1  dholland 				nd->nd_repstat = ret;
   3629      1.1  dholland 		}
   3630      1.1  dholland 	}
   3631      1.1  dholland 	vput(vp);
   3632      1.1  dholland 	NFSEXITCODE2(error, nd);
   3633      1.1  dholland 	return (error);
   3634      1.1  dholland }
   3635      1.1  dholland 
   3636      1.1  dholland /*
   3637      1.1  dholland  * nfs openattr rpc
   3638      1.1  dholland  */
   3639      1.1  dholland APPLESTATIC int
   3640      1.1  dholland nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
   3641      1.1  dholland     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
   3642      1.1  dholland     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3643      1.1  dholland {
   3644      1.1  dholland 	u_int32_t *tl;
   3645      1.1  dholland 	int error = 0, createdir;
   3646      1.1  dholland 
   3647      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   3648      1.1  dholland 	createdir = fxdr_unsigned(int, *tl);
   3649      1.1  dholland 	nd->nd_repstat = NFSERR_NOTSUPP;
   3650      1.1  dholland nfsmout:
   3651      1.1  dholland 	vrele(dp);
   3652      1.1  dholland 	NFSEXITCODE2(error, nd);
   3653      1.1  dholland 	return (error);
   3654      1.1  dholland }
   3655      1.1  dholland 
   3656      1.1  dholland /*
   3657      1.1  dholland  * nfsv4 release lock owner service
   3658      1.1  dholland  */
   3659      1.1  dholland APPLESTATIC int
   3660      1.1  dholland nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
   3661      1.1  dholland     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3662      1.1  dholland {
   3663      1.1  dholland 	u_int32_t *tl;
   3664      1.1  dholland 	struct nfsstate *stp = NULL;
   3665      1.1  dholland 	int error = 0, len;
   3666      1.1  dholland 	nfsquad_t clientid;
   3667      1.1  dholland 
   3668  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3669  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3670  1.1.1.2  pgoyette 		goto nfsmout;
   3671  1.1.1.2  pgoyette 	}
   3672      1.1  dholland 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3673      1.1  dholland 		nd->nd_repstat = NFSERR_WRONGSEC;
   3674      1.1  dholland 		goto nfsmout;
   3675      1.1  dholland 	}
   3676      1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   3677      1.1  dholland 	len = fxdr_unsigned(int, *(tl + 2));
   3678      1.1  dholland 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
   3679      1.1  dholland 		nd->nd_repstat = NFSERR_BADXDR;
   3680      1.1  dholland 		goto nfsmout;
   3681      1.1  dholland 	}
   3682      1.1  dholland 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
   3683      1.1  dholland 	    M_NFSDSTATE, M_WAITOK);
   3684      1.1  dholland 	stp->ls_ownerlen = len;
   3685      1.1  dholland 	stp->ls_op = NULL;
   3686      1.1  dholland 	stp->ls_flags = NFSLCK_RELEASE;
   3687      1.1  dholland 	stp->ls_uid = nd->nd_cred->cr_uid;
   3688      1.1  dholland 	clientid.lval[0] = *tl++;
   3689      1.1  dholland 	clientid.lval[1] = *tl;
   3690  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3691  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3692  1.1.1.2  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3693  1.1.1.2  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3694  1.1.1.2  pgoyette 			printf("EEK14 multiple clids\n");
   3695      1.1  dholland 	} else {
   3696  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3697  1.1.1.2  pgoyette 			printf("EEK! no clientid from session\n");
   3698      1.1  dholland 		nd->nd_flag |= ND_IMPLIEDCLID;
   3699      1.1  dholland 		nd->nd_clientid.qval = clientid.qval;
   3700      1.1  dholland 	}
   3701      1.1  dholland 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
   3702      1.1  dholland 	if (error)
   3703      1.1  dholland 		goto nfsmout;
   3704      1.1  dholland 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
   3705      1.1  dholland 	FREE((caddr_t)stp, M_NFSDSTATE);
   3706      1.1  dholland 
   3707      1.1  dholland 	NFSEXITCODE2(0, nd);
   3708      1.1  dholland 	return (0);
   3709      1.1  dholland nfsmout:
   3710      1.1  dholland 	if (stp)
   3711      1.1  dholland 		free((caddr_t)stp, M_NFSDSTATE);
   3712      1.1  dholland 	NFSEXITCODE2(error, nd);
   3713      1.1  dholland 	return (error);
   3714      1.1  dholland }
   3715  1.1.1.2  pgoyette 
   3716  1.1.1.2  pgoyette /*
   3717  1.1.1.2  pgoyette  * nfsv4 exchange_id service
   3718  1.1.1.2  pgoyette  */
   3719  1.1.1.2  pgoyette APPLESTATIC int
   3720  1.1.1.2  pgoyette nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
   3721  1.1.1.2  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3722  1.1.1.2  pgoyette {
   3723  1.1.1.2  pgoyette 	uint32_t *tl;
   3724  1.1.1.2  pgoyette 	int error = 0, i, idlen;
   3725  1.1.1.2  pgoyette 	struct nfsclient *clp = NULL;
   3726  1.1.1.2  pgoyette 	nfsquad_t clientid, confirm;
   3727  1.1.1.2  pgoyette 	uint8_t *verf;
   3728  1.1.1.2  pgoyette 	uint32_t sp4type, v41flags;
   3729  1.1.1.2  pgoyette 	uint64_t owner_minor;
   3730  1.1.1.2  pgoyette 	struct timespec verstime;
   3731  1.1.1.2  pgoyette 
   3732  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3733  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3734  1.1.1.2  pgoyette 		goto nfsmout;
   3735  1.1.1.2  pgoyette 	}
   3736  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
   3737  1.1.1.2  pgoyette 	verf = (uint8_t *)tl;
   3738  1.1.1.2  pgoyette 	tl += (NFSX_VERF / NFSX_UNSIGNED);
   3739  1.1.1.2  pgoyette 	i = fxdr_unsigned(int, *tl);
   3740  1.1.1.2  pgoyette 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
   3741  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3742  1.1.1.2  pgoyette 		goto nfsmout;
   3743  1.1.1.2  pgoyette 	}
   3744  1.1.1.2  pgoyette 	idlen = i;
   3745  1.1.1.2  pgoyette 	if (nd->nd_flag & ND_GSS)
   3746  1.1.1.2  pgoyette 		i += nd->nd_princlen;
   3747  1.1.1.2  pgoyette 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
   3748  1.1.1.2  pgoyette 	    M_ZERO);
   3749  1.1.1.2  pgoyette 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
   3750  1.1.1.2  pgoyette 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
   3751  1.1.1.2  pgoyette 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
   3752  1.1.1.2  pgoyette 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
   3753  1.1.1.2  pgoyette 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
   3754  1.1.1.2  pgoyette 	clp->lc_req.nr_cred = NULL;
   3755  1.1.1.2  pgoyette 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
   3756  1.1.1.2  pgoyette 	clp->lc_idlen = idlen;
   3757  1.1.1.2  pgoyette 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
   3758  1.1.1.2  pgoyette 	if (error != 0)
   3759  1.1.1.2  pgoyette 		goto nfsmout;
   3760  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_GSS) != 0) {
   3761  1.1.1.2  pgoyette 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
   3762  1.1.1.2  pgoyette 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
   3763  1.1.1.2  pgoyette 			clp->lc_flags |= LCL_GSSINTEGRITY;
   3764  1.1.1.2  pgoyette 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
   3765  1.1.1.2  pgoyette 			clp->lc_flags |= LCL_GSSPRIVACY;
   3766  1.1.1.2  pgoyette 	} else
   3767  1.1.1.2  pgoyette 		clp->lc_flags = LCL_NFSV41;
   3768  1.1.1.2  pgoyette 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
   3769  1.1.1.2  pgoyette 		clp->lc_flags |= LCL_NAME;
   3770  1.1.1.2  pgoyette 		clp->lc_namelen = nd->nd_princlen;
   3771  1.1.1.2  pgoyette 		clp->lc_name = &clp->lc_id[idlen];
   3772  1.1.1.2  pgoyette 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
   3773  1.1.1.2  pgoyette 	} else {
   3774  1.1.1.2  pgoyette 		clp->lc_uid = nd->nd_cred->cr_uid;
   3775  1.1.1.2  pgoyette 		clp->lc_gid = nd->nd_cred->cr_gid;
   3776  1.1.1.2  pgoyette 	}
   3777  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3778  1.1.1.2  pgoyette 	v41flags = fxdr_unsigned(uint32_t, *tl++);
   3779  1.1.1.2  pgoyette 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
   3780  1.1.1.2  pgoyette 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
   3781  1.1.1.2  pgoyette 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
   3782  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_INVAL;
   3783  1.1.1.2  pgoyette 		goto nfsmout;
   3784  1.1.1.2  pgoyette 	}
   3785  1.1.1.2  pgoyette 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
   3786  1.1.1.2  pgoyette 		confirm.lval[1] = 1;
   3787  1.1.1.2  pgoyette 	else
   3788  1.1.1.2  pgoyette 		confirm.lval[1] = 0;
   3789  1.1.1.2  pgoyette 	v41flags = NFSV4EXCH_USENONPNFS;
   3790  1.1.1.2  pgoyette 	sp4type = fxdr_unsigned(uint32_t, *tl);
   3791  1.1.1.2  pgoyette 	if (sp4type != NFSV4EXCH_SP4NONE) {
   3792  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3793  1.1.1.2  pgoyette 		goto nfsmout;
   3794  1.1.1.2  pgoyette 	}
   3795  1.1.1.2  pgoyette 
   3796  1.1.1.2  pgoyette 	/*
   3797  1.1.1.2  pgoyette 	 * nfsrv_setclient() does the actual work of adding it to the
   3798  1.1.1.2  pgoyette 	 * client list. If there is no error, the structure has been
   3799  1.1.1.2  pgoyette 	 * linked into the client list and clp should no longer be used
   3800  1.1.1.2  pgoyette 	 * here. When an error is returned, it has not been linked in,
   3801  1.1.1.2  pgoyette 	 * so it should be free'd.
   3802  1.1.1.2  pgoyette 	 */
   3803  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
   3804  1.1.1.2  pgoyette 	if (clp != NULL) {
   3805  1.1.1.2  pgoyette 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3806  1.1.1.2  pgoyette 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3807  1.1.1.2  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3808  1.1.1.2  pgoyette 		free(clp, M_NFSDCLIENT);
   3809  1.1.1.2  pgoyette 	}
   3810  1.1.1.2  pgoyette 	if (nd->nd_repstat == 0) {
   3811  1.1.1.2  pgoyette 		if (confirm.lval[1] != 0)
   3812  1.1.1.2  pgoyette 			v41flags |= NFSV4EXCH_CONFIRMEDR;
   3813  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
   3814  1.1.1.2  pgoyette 		*tl++ = clientid.lval[0];			/* ClientID */
   3815  1.1.1.2  pgoyette 		*tl++ = clientid.lval[1];
   3816  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
   3817  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
   3818  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
   3819  1.1.1.2  pgoyette 		owner_minor = 0;				/* Owner */
   3820  1.1.1.2  pgoyette 		txdr_hyper(owner_minor, tl);			/* Minor */
   3821  1.1.1.2  pgoyette 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
   3822  1.1.1.2  pgoyette 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
   3823  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
   3824  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(NFSX_UNSIGNED);
   3825  1.1.1.2  pgoyette 		*tl++ = time_uptime;		/* Make scope a unique value. */
   3826  1.1.1.2  pgoyette 		*tl = txdr_unsigned(1);
   3827  1.1.1.2  pgoyette 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
   3828  1.1.1.2  pgoyette 		(void)nfsm_strtom(nd, version, strlen(version));
   3829  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
   3830  1.1.1.2  pgoyette 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
   3831  1.1.1.2  pgoyette 		verstime.tv_nsec = 0;
   3832  1.1.1.2  pgoyette 		txdr_nfsv4time(&verstime, tl);
   3833  1.1.1.2  pgoyette 	}
   3834  1.1.1.2  pgoyette 	NFSEXITCODE2(0, nd);
   3835  1.1.1.2  pgoyette 	return (0);
   3836  1.1.1.2  pgoyette nfsmout:
   3837  1.1.1.2  pgoyette 	if (clp != NULL) {
   3838  1.1.1.2  pgoyette 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3839  1.1.1.2  pgoyette 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3840  1.1.1.2  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3841  1.1.1.2  pgoyette 		free(clp, M_NFSDCLIENT);
   3842  1.1.1.2  pgoyette 	}
   3843  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   3844  1.1.1.2  pgoyette 	return (error);
   3845  1.1.1.2  pgoyette }
   3846  1.1.1.2  pgoyette 
   3847  1.1.1.2  pgoyette /*
   3848  1.1.1.2  pgoyette  * nfsv4 create session service
   3849  1.1.1.2  pgoyette  */
   3850  1.1.1.2  pgoyette APPLESTATIC int
   3851  1.1.1.2  pgoyette nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
   3852  1.1.1.2  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3853  1.1.1.2  pgoyette {
   3854  1.1.1.2  pgoyette 	uint32_t *tl;
   3855  1.1.1.2  pgoyette 	int error = 0;
   3856  1.1.1.2  pgoyette 	nfsquad_t clientid, confirm;
   3857  1.1.1.2  pgoyette 	struct nfsdsession *sep = NULL;
   3858  1.1.1.2  pgoyette 	uint32_t rdmacnt;
   3859  1.1.1.2  pgoyette 
   3860  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3861  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3862  1.1.1.2  pgoyette 		goto nfsmout;
   3863  1.1.1.2  pgoyette 	}
   3864  1.1.1.2  pgoyette 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
   3865  1.1.1.2  pgoyette 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
   3866  1.1.1.2  pgoyette 	sep->sess_refcnt = 1;
   3867  1.1.1.2  pgoyette 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
   3868  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
   3869  1.1.1.2  pgoyette 	clientid.lval[0] = *tl++;
   3870  1.1.1.2  pgoyette 	clientid.lval[1] = *tl++;
   3871  1.1.1.2  pgoyette 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
   3872  1.1.1.2  pgoyette 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
   3873  1.1.1.2  pgoyette 	/* Persistent sessions and RDMA are not supported. */
   3874  1.1.1.2  pgoyette 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
   3875  1.1.1.2  pgoyette 
   3876  1.1.1.2  pgoyette 	/* Fore channel attributes. */
   3877  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   3878  1.1.1.2  pgoyette 	tl++;					/* Header pad always 0. */
   3879  1.1.1.2  pgoyette 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
   3880  1.1.1.2  pgoyette 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
   3881  1.1.1.2  pgoyette 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
   3882  1.1.1.2  pgoyette 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
   3883  1.1.1.2  pgoyette 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
   3884  1.1.1.2  pgoyette 	if (sep->sess_maxslots > NFSV4_SLOTS)
   3885  1.1.1.2  pgoyette 		sep->sess_maxslots = NFSV4_SLOTS;
   3886  1.1.1.2  pgoyette 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
   3887  1.1.1.2  pgoyette 	if (rdmacnt > 1) {
   3888  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3889  1.1.1.2  pgoyette 		goto nfsmout;
   3890  1.1.1.2  pgoyette 	} else if (rdmacnt == 1)
   3891  1.1.1.2  pgoyette 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3892  1.1.1.2  pgoyette 
   3893  1.1.1.2  pgoyette 	/* Back channel attributes. */
   3894  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   3895  1.1.1.2  pgoyette 	tl++;					/* Header pad always 0. */
   3896  1.1.1.2  pgoyette 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
   3897  1.1.1.2  pgoyette 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
   3898  1.1.1.2  pgoyette 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
   3899  1.1.1.2  pgoyette 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
   3900  1.1.1.2  pgoyette 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
   3901  1.1.1.2  pgoyette 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
   3902  1.1.1.2  pgoyette 	if (rdmacnt > 1) {
   3903  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3904  1.1.1.2  pgoyette 		goto nfsmout;
   3905  1.1.1.2  pgoyette 	} else if (rdmacnt == 1)
   3906  1.1.1.2  pgoyette 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3907  1.1.1.2  pgoyette 
   3908  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3909  1.1.1.2  pgoyette 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
   3910  1.1.1.2  pgoyette 
   3911  1.1.1.2  pgoyette 	/*
   3912  1.1.1.2  pgoyette 	 * nfsrv_getclient() searches the client list for a match and
   3913  1.1.1.2  pgoyette 	 * returns the appropriate NFSERR status.
   3914  1.1.1.2  pgoyette 	 */
   3915  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
   3916  1.1.1.2  pgoyette 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
   3917  1.1.1.2  pgoyette 	if (nd->nd_repstat == 0) {
   3918  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
   3919  1.1.1.2  pgoyette 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
   3920  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
   3921  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
   3922  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_crflags);
   3923  1.1.1.2  pgoyette 
   3924  1.1.1.2  pgoyette 		/* Fore channel attributes. */
   3925  1.1.1.2  pgoyette 		*tl++ = 0;
   3926  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxreq);
   3927  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxresp);
   3928  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
   3929  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxops);
   3930  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxslots);
   3931  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(1);
   3932  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
   3933  1.1.1.2  pgoyette 
   3934  1.1.1.2  pgoyette 		/* Back channel attributes. */
   3935  1.1.1.2  pgoyette 		*tl++ = 0;
   3936  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
   3937  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
   3938  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
   3939  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
   3940  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
   3941  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(1);
   3942  1.1.1.2  pgoyette 		*tl = txdr_unsigned(0);			/* No RDMA. */
   3943  1.1.1.2  pgoyette 	}
   3944  1.1.1.2  pgoyette nfsmout:
   3945  1.1.1.2  pgoyette 	if (nd->nd_repstat != 0 && sep != NULL)
   3946  1.1.1.2  pgoyette 		free(sep, M_NFSDSESSION);
   3947  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   3948  1.1.1.2  pgoyette 	return (error);
   3949  1.1.1.2  pgoyette }
   3950  1.1.1.2  pgoyette 
   3951  1.1.1.2  pgoyette /*
   3952  1.1.1.2  pgoyette  * nfsv4 sequence service
   3953  1.1.1.2  pgoyette  */
   3954  1.1.1.2  pgoyette APPLESTATIC int
   3955  1.1.1.2  pgoyette nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
   3956  1.1.1.2  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3957  1.1.1.2  pgoyette {
   3958  1.1.1.2  pgoyette 	uint32_t *tl;
   3959  1.1.1.2  pgoyette 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
   3960  1.1.1.2  pgoyette 	int cache_this, error = 0;
   3961  1.1.1.2  pgoyette 
   3962  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3963  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3964  1.1.1.2  pgoyette 		goto nfsmout;
   3965  1.1.1.2  pgoyette 	}
   3966  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
   3967  1.1.1.2  pgoyette 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
   3968  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
   3969  1.1.1.2  pgoyette 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
   3970  1.1.1.2  pgoyette 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
   3971  1.1.1.2  pgoyette 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
   3972  1.1.1.2  pgoyette 	if (*tl == newnfs_true)
   3973  1.1.1.2  pgoyette 		cache_this = 1;
   3974  1.1.1.2  pgoyette 	else
   3975  1.1.1.2  pgoyette 		cache_this = 0;
   3976  1.1.1.2  pgoyette 	nd->nd_flag |= ND_HASSEQUENCE;
   3977  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
   3978  1.1.1.2  pgoyette 	    &target_highest_slotid, cache_this, &sflags, p);
   3979  1.1.1.2  pgoyette 	if (nd->nd_repstat == 0) {
   3980  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
   3981  1.1.1.2  pgoyette 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
   3982  1.1.1.2  pgoyette 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
   3983  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(sequenceid);
   3984  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(nd->nd_slotid);
   3985  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(highest_slotid);
   3986  1.1.1.2  pgoyette 		*tl++ = txdr_unsigned(target_highest_slotid);
   3987  1.1.1.2  pgoyette 		*tl = txdr_unsigned(sflags);
   3988  1.1.1.2  pgoyette 	}
   3989  1.1.1.2  pgoyette nfsmout:
   3990  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   3991  1.1.1.2  pgoyette 	return (error);
   3992  1.1.1.2  pgoyette }
   3993  1.1.1.2  pgoyette 
   3994  1.1.1.2  pgoyette /*
   3995  1.1.1.2  pgoyette  * nfsv4 reclaim complete service
   3996  1.1.1.2  pgoyette  */
   3997  1.1.1.2  pgoyette APPLESTATIC int
   3998  1.1.1.2  pgoyette nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
   3999  1.1.1.2  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4000  1.1.1.2  pgoyette {
   4001  1.1.1.2  pgoyette 	uint32_t *tl;
   4002  1.1.1.2  pgoyette 	int error = 0;
   4003  1.1.1.2  pgoyette 
   4004  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4005  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4006  1.1.1.2  pgoyette 		goto nfsmout;
   4007  1.1.1.2  pgoyette 	}
   4008  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   4009  1.1.1.2  pgoyette 	if (*tl == newnfs_true)
   4010  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   4011  1.1.1.2  pgoyette 	else
   4012  1.1.1.2  pgoyette 		nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
   4013  1.1.1.2  pgoyette nfsmout:
   4014  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   4015  1.1.1.2  pgoyette 	return (error);
   4016  1.1.1.2  pgoyette }
   4017  1.1.1.2  pgoyette 
   4018  1.1.1.2  pgoyette /*
   4019  1.1.1.2  pgoyette  * nfsv4 destroy clientid service
   4020  1.1.1.2  pgoyette  */
   4021  1.1.1.2  pgoyette APPLESTATIC int
   4022  1.1.1.2  pgoyette nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
   4023  1.1.1.2  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4024  1.1.1.2  pgoyette {
   4025  1.1.1.2  pgoyette 	uint32_t *tl;
   4026  1.1.1.2  pgoyette 	nfsquad_t clientid;
   4027  1.1.1.2  pgoyette 	int error = 0;
   4028  1.1.1.2  pgoyette 
   4029  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4030  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4031  1.1.1.2  pgoyette 		goto nfsmout;
   4032  1.1.1.2  pgoyette 	}
   4033  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
   4034  1.1.1.2  pgoyette 	clientid.lval[0] = *tl++;
   4035  1.1.1.2  pgoyette 	clientid.lval[1] = *tl;
   4036  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
   4037  1.1.1.2  pgoyette nfsmout:
   4038  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   4039  1.1.1.2  pgoyette 	return (error);
   4040  1.1.1.2  pgoyette }
   4041  1.1.1.2  pgoyette 
   4042  1.1.1.2  pgoyette /*
   4043  1.1.1.2  pgoyette  * nfsv4 destroy session service
   4044  1.1.1.2  pgoyette  */
   4045  1.1.1.2  pgoyette APPLESTATIC int
   4046  1.1.1.2  pgoyette nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
   4047  1.1.1.2  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4048  1.1.1.2  pgoyette {
   4049  1.1.1.2  pgoyette 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
   4050  1.1.1.2  pgoyette 	int error = 0;
   4051  1.1.1.2  pgoyette 
   4052  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4053  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4054  1.1.1.2  pgoyette 		goto nfsmout;
   4055  1.1.1.2  pgoyette 	}
   4056  1.1.1.2  pgoyette 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
   4057  1.1.1.2  pgoyette 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
   4058  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
   4059  1.1.1.2  pgoyette nfsmout:
   4060  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   4061  1.1.1.2  pgoyette 	return (error);
   4062  1.1.1.2  pgoyette }
   4063  1.1.1.2  pgoyette 
   4064  1.1.1.2  pgoyette /*
   4065  1.1.1.2  pgoyette  * nfsv4 free stateid service
   4066  1.1.1.2  pgoyette  */
   4067  1.1.1.2  pgoyette APPLESTATIC int
   4068  1.1.1.2  pgoyette nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
   4069  1.1.1.2  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4070  1.1.1.2  pgoyette {
   4071  1.1.1.2  pgoyette 	uint32_t *tl;
   4072  1.1.1.2  pgoyette 	nfsv4stateid_t stateid;
   4073  1.1.1.2  pgoyette 	int error = 0;
   4074  1.1.1.2  pgoyette 
   4075  1.1.1.2  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4076  1.1.1.2  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4077  1.1.1.2  pgoyette 		goto nfsmout;
   4078  1.1.1.2  pgoyette 	}
   4079  1.1.1.2  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
   4080  1.1.1.2  pgoyette 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
   4081  1.1.1.2  pgoyette 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
   4082  1.1.1.2  pgoyette 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
   4083  1.1.1.2  pgoyette nfsmout:
   4084  1.1.1.2  pgoyette 	NFSEXITCODE2(error, nd);
   4085  1.1.1.2  pgoyette 	return (error);
   4086  1.1.1.2  pgoyette }
   4087  1.1.1.2  pgoyette 
   4088  1.1.1.2  pgoyette /*
   4089  1.1.1.2  pgoyette  * nfsv4 service not supported
   4090  1.1.1.2  pgoyette  */
   4091  1.1.1.2  pgoyette APPLESTATIC int
   4092  1.1.1.2  pgoyette nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
   4093  1.1.1.2  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4094  1.1.1.2  pgoyette {
   4095  1.1.1.2  pgoyette 
   4096  1.1.1.2  pgoyette 	nd->nd_repstat = NFSERR_NOTSUPP;
   4097  1.1.1.2  pgoyette 	NFSEXITCODE2(0, nd);
   4098  1.1.1.2  pgoyette 	return (0);
   4099  1.1.1.2  pgoyette }
   4100  1.1.1.2  pgoyette 
   4101