Home | History | Annotate | Line # | Download | only in server
nfs_nfsdserv.c revision 1.2.16.1
      1  1.2.16.1  pgoyette /*	$NetBSD: nfs_nfsdserv.c,v 1.2.16.1 2017/01/07 08:56:48 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.2.16.1  pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdserv.c 299514 2016-05-12 05:03:12Z cem "); */
     37  1.2.16.1  pgoyette __RCSID("$NetBSD: nfs_nfsdserv.c,v 1.2.16.1 2017/01/07 08:56:48 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.2.16.1  pgoyette #include <fs/nfs/common/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.2.16.1  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.2.16.1  pgoyette 
    217  1.2.16.1  pgoyette 			/*
    218  1.2.16.1  pgoyette 			 * GETATTR with write-only attr time_access_set and time_modify_set
    219  1.2.16.1  pgoyette 			 * should return NFS4ERR_INVAL.
    220  1.2.16.1  pgoyette 			 */
    221  1.2.16.1  pgoyette 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
    222  1.2.16.1  pgoyette 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
    223  1.2.16.1  pgoyette 				error = NFSERR_INVAL;
    224  1.2.16.1  pgoyette 				vput(vp);
    225  1.2.16.1  pgoyette 				goto out;
    226  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
    684  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    685  1.2.16.1  pgoyette 				clientid.qval = nd->nd_clientid.qval;
    686  1.2.16.1  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
    687  1.2.16.1  pgoyette 				printf("EEK1 multiple clids\n");
    688       1.1  dholland 		} else {
    689  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    690  1.2.16.1  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.2.16.1  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
    840  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    841  1.2.16.1  pgoyette 				clientid.qval = nd->nd_clientid.qval;
    842  1.2.16.1  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
    843  1.2.16.1  pgoyette 				printf("EEK2 multiple clids\n");
    844       1.1  dholland 		} else {
    845  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
    846  1.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	/*
   1483  1.2.16.1  pgoyette 	 * Unlock dp in this code section, so it is unlocked before
   1484  1.2.16.1  pgoyette 	 * tdp gets locked. This avoids a potential LOR if tdp is the
   1485  1.2.16.1  pgoyette 	 * parent directory of dp.
   1486  1.2.16.1  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.2.16.1  pgoyette 		if (dp != tdp) {
   1491  1.2.16.1  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1492  1.2.16.1  pgoyette 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1493  1.2.16.1  pgoyette 			    p, 0);	/* Might lock tdp. */
   1494  1.2.16.1  pgoyette 		} else {
   1495  1.2.16.1  pgoyette 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
   1496  1.2.16.1  pgoyette 			    p, 1);
   1497  1.2.16.1  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1498  1.2.16.1  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.2.16.1  pgoyette 			NFSVOPUNLOCK(dp, 0);
   1520       1.1  dholland 		} else {
   1521  1.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  pgoyette 
   1989  1.2.16.1  pgoyette 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
   1990  1.2.16.1  pgoyette 	if (vp->v_type != VREG) {
   1991  1.2.16.1  pgoyette 		if (nd->nd_flag & ND_NFSV3)
   1992  1.2.16.1  pgoyette 			error = NFSERR_NOTSUPP;
   1993  1.2.16.1  pgoyette 		else
   1994  1.2.16.1  pgoyette 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
   1995  1.2.16.1  pgoyette 		goto nfsmout;
   1996  1.2.16.1  pgoyette 	}
   1997       1.1  dholland 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
   1998  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2240  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2241  1.2.16.1  pgoyette 				clientid.qval = nd->nd_clientid.qval;
   2242  1.2.16.1  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
   2243  1.2.16.1  pgoyette 				printf("EEK3 multiple clids\n");
   2244       1.1  dholland 		} else {
   2245  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2246  1.2.16.1  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.2.16.1  pgoyette 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2267  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2268  1.2.16.1  pgoyette 				clientid.qval = nd->nd_clientid.qval;
   2269  1.2.16.1  pgoyette 			else if (nd->nd_clientid.qval != clientid.qval)
   2270  1.2.16.1  pgoyette 				printf("EEK4 multiple clids\n");
   2271       1.1  dholland 		} else {
   2272  1.2.16.1  pgoyette 			if ((nd->nd_flag & ND_NFSV41) != 0)
   2273  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2420  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2421  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2422  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2423  1.2.16.1  pgoyette 			printf("EEK5 multiple clids\n");
   2424       1.1  dholland 	} else {
   2425  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2426  1.2.16.1  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.2.16.1  pgoyette 	if (stp)
   2464  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2535  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2536  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2537  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2538  1.2.16.1  pgoyette 			printf("EEK6 multiple clids\n");
   2539       1.1  dholland 	} else {
   2540  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2541  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	retext = 0;
   2620  1.2.16.1  pgoyette 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
   2621  1.2.16.1  pgoyette 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
   2622  1.2.16.1  pgoyette 		retext = 1;
   2623  1.2.16.1  pgoyette 		/* For now, ignore these. */
   2624  1.2.16.1  pgoyette 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
   2625  1.2.16.1  pgoyette 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
   2626  1.2.16.1  pgoyette 		case NFSV4OPEN_WANTANYDELEG:
   2627  1.2.16.1  pgoyette 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
   2628  1.2.16.1  pgoyette 			    NFSLCK_WANTWDELEG);
   2629  1.2.16.1  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2630  1.2.16.1  pgoyette 			break;
   2631  1.2.16.1  pgoyette 		case NFSV4OPEN_WANTREADDELEG:
   2632  1.2.16.1  pgoyette 			stp->ls_flags |= NFSLCK_WANTRDELEG;
   2633  1.2.16.1  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2634  1.2.16.1  pgoyette 			break;
   2635  1.2.16.1  pgoyette 		case NFSV4OPEN_WANTWRITEDELEG:
   2636  1.2.16.1  pgoyette 			stp->ls_flags |= NFSLCK_WANTWDELEG;
   2637  1.2.16.1  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2638  1.2.16.1  pgoyette 			break;
   2639  1.2.16.1  pgoyette 		case NFSV4OPEN_WANTNODELEG:
   2640  1.2.16.1  pgoyette 			stp->ls_flags |= NFSLCK_WANTNODELEG;
   2641  1.2.16.1  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2642  1.2.16.1  pgoyette 			break;
   2643  1.2.16.1  pgoyette 		case NFSV4OPEN_WANTCANCEL:
   2644  1.2.16.1  pgoyette 			printf("NFSv4: ignore Open WantCancel\n");
   2645  1.2.16.1  pgoyette 			i &= ~NFSV4OPEN_WANTDELEGMASK;
   2646  1.2.16.1  pgoyette 			break;
   2647  1.2.16.1  pgoyette 		default:
   2648  1.2.16.1  pgoyette 			/* nd_repstat will be set to NFSERR_INVAL below. */
   2649  1.2.16.1  pgoyette 			break;
   2650  1.2.16.1  pgoyette 		}
   2651  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	}
   2681       1.1  dholland 	clientid.lval[0] = *tl++;
   2682       1.1  dholland 	clientid.lval[1] = *tl;
   2683  1.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   2684  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2685  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   2686  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   2687  1.2.16.1  pgoyette 			printf("EEK7 multiple clids\n");
   2688       1.1  dholland 	} else {
   2689  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   2690  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 		case NFSCREATE_EXCLUSIVE41:
   2731  1.2.16.1  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
   2732  1.2.16.1  pgoyette 			cverf[0] = *tl++;
   2733  1.2.16.1  pgoyette 			cverf[1] = *tl;
   2734  1.2.16.1  pgoyette 			error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
   2735  1.2.16.1  pgoyette 			if (error != 0)
   2736  1.2.16.1  pgoyette 				goto nfsmout;
   2737  1.2.16.1  pgoyette 			if (NFSISSET_ATTRBIT(&attrbits,
   2738  1.2.16.1  pgoyette 			    NFSATTRBIT_TIMEACCESSSET))
   2739  1.2.16.1  pgoyette 				nd->nd_repstat = NFSERR_INVAL;
   2740  1.2.16.1  pgoyette 			/*
   2741  1.2.16.1  pgoyette 			 * If the na_gid being set is the same as that of
   2742  1.2.16.1  pgoyette 			 * the directory it is going in, clear it, since
   2743  1.2.16.1  pgoyette 			 * that is what will be set by default. This allows
   2744  1.2.16.1  pgoyette 			 * a user that isn't in that group to do the create.
   2745  1.2.16.1  pgoyette 			 */
   2746  1.2.16.1  pgoyette 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
   2747  1.2.16.1  pgoyette 			    nva.na_gid == dirfor.na_gid)
   2748  1.2.16.1  pgoyette 				NFSVNO_UNSET(&nva, gid);
   2749  1.2.16.1  pgoyette 			if (nd->nd_repstat == 0)
   2750  1.2.16.1  pgoyette 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
   2751  1.2.16.1  pgoyette 			break;
   2752       1.1  dholland 		default:
   2753       1.1  dholland 			nd->nd_repstat = NFSERR_BADXDR;
   2754       1.1  dholland 			goto nfsmout;
   2755  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 			break;
   2834  1.2.16.1  pgoyette 		    case NFSCREATE_EXCLUSIVE41:
   2835  1.2.16.1  pgoyette 			exclusive_flag = 1;
   2836  1.2.16.1  pgoyette 			break;
   2837  1.2.16.1  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.2.16.1  pgoyette 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
   2843  1.2.16.1  pgoyette 	    NFSV4OPEN_CLAIMFH) {
   2844  1.2.16.1  pgoyette 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
   2845  1.2.16.1  pgoyette 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
   2846  1.2.16.1  pgoyette 			i = fxdr_unsigned(int, *tl);
   2847  1.2.16.1  pgoyette 			switch (i) {
   2848  1.2.16.1  pgoyette 			case NFSV4OPEN_DELEGATEREAD:
   2849  1.2.16.1  pgoyette 				stp->ls_flags |= NFSLCK_DELEGREAD;
   2850  1.2.16.1  pgoyette 				break;
   2851  1.2.16.1  pgoyette 			case NFSV4OPEN_DELEGATEWRITE:
   2852  1.2.16.1  pgoyette 				stp->ls_flags |= NFSLCK_DELEGWRITE;
   2853  1.2.16.1  pgoyette 			case NFSV4OPEN_DELEGATENONE:
   2854  1.2.16.1  pgoyette 				break;
   2855  1.2.16.1  pgoyette 			default:
   2856  1.2.16.1  pgoyette 				nd->nd_repstat = NFSERR_BADXDR;
   2857  1.2.16.1  pgoyette 				goto nfsmout;
   2858  1.2.16.1  pgoyette 			}
   2859  1.2.16.1  pgoyette 			stp->ls_flags |= NFSLCK_RECLAIM;
   2860  1.2.16.1  pgoyette 		} else {
   2861  1.2.16.1  pgoyette 			/* CLAIM_NULL_FH */
   2862  1.2.16.1  pgoyette 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
   2863  1.2.16.1  pgoyette 				nd->nd_repstat = NFSERR_INVAL;
   2864  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 		else if (retext != 0) {
   2954  1.2.16.1  pgoyette 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
   2955  1.2.16.1  pgoyette 			if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
   2956  1.2.16.1  pgoyette 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2957  1.2.16.1  pgoyette 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
   2958  1.2.16.1  pgoyette 				*tl = newnfs_false;
   2959  1.2.16.1  pgoyette 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
   2960  1.2.16.1  pgoyette 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   2961  1.2.16.1  pgoyette 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
   2962  1.2.16.1  pgoyette 				*tl = newnfs_false;
   2963  1.2.16.1  pgoyette 			} else {
   2964  1.2.16.1  pgoyette 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
   2965  1.2.16.1  pgoyette 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
   2966  1.2.16.1  pgoyette 			}
   2967  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3044  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3045  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3046  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3047  1.2.16.1  pgoyette 			printf("EEK8 multiple clids\n");
   3048       1.1  dholland 	} else {
   3049  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3050  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3088  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3089  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3090  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3091  1.2.16.1  pgoyette 			printf("EEK9 multiple clids\n");
   3092       1.1  dholland 	} else {
   3093  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3094  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3123  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3124  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3125  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3126  1.2.16.1  pgoyette 			printf("EEK10 multiple clids\n");
   3127       1.1  dholland 	} else {
   3128  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3129  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3172  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3173  1.2.16.1  pgoyette 		goto nfsmout;
   3174  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3188  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3189  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3190  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3191  1.2.16.1  pgoyette 			printf("EEK11 multiple clids\n");
   3192       1.1  dholland 	} else {
   3193  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3194  1.2.16.1  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.2.16.1  pgoyette 	/* opendowngrade can only work on a file object.*/
   3225  1.2.16.1  pgoyette 	if (vp->v_type != VREG) {
   3226  1.2.16.1  pgoyette 		error = NFSERR_INVAL;
   3227  1.2.16.1  pgoyette 		goto nfsmout;
   3228  1.2.16.1  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.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3273  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3274  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3275  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3276  1.2.16.1  pgoyette 			printf("EEK12 multiple clids\n");
   3277       1.1  dholland 	} else {
   3278  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3279  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3309  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3310  1.2.16.1  pgoyette 		goto nfsmout;
   3311  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3320  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3321  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3322  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3323  1.2.16.1  pgoyette 			printf("EEK13 multiple clids\n");
   3324       1.1  dholland 	} else {
   3325  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3326  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3456  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3457  1.2.16.1  pgoyette 		goto nfsmout;
   3458  1.2.16.1  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.2.16.1  pgoyette 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
   3475  1.2.16.1  pgoyette 	    M_ZERO);
   3476  1.2.16.1  pgoyette 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
   3477  1.2.16.1  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.2  christos 		snprintf(addrbuf, sizeof(addrbuf), "%d.%d.%d.%d.%d.%d",
   3530       1.2  christos 		    ucp[0] & 0xff, 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.2.16.1  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3538  1.2.16.1  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.2.16.1  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3556  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3575  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3576  1.2.16.1  pgoyette 		goto nfsmout;
   3577  1.2.16.1  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.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_NFSV41) != 0) {
   3669  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3670  1.2.16.1  pgoyette 		goto nfsmout;
   3671  1.2.16.1  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.2.16.1  pgoyette 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
   3691  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3692  1.2.16.1  pgoyette 			clientid.qval = nd->nd_clientid.qval;
   3693  1.2.16.1  pgoyette 		else if (nd->nd_clientid.qval != clientid.qval)
   3694  1.2.16.1  pgoyette 			printf("EEK14 multiple clids\n");
   3695       1.1  dholland 	} else {
   3696  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_NFSV41) != 0)
   3697  1.2.16.1  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.2.16.1  pgoyette 
   3716  1.2.16.1  pgoyette /*
   3717  1.2.16.1  pgoyette  * nfsv4 exchange_id service
   3718  1.2.16.1  pgoyette  */
   3719  1.2.16.1  pgoyette APPLESTATIC int
   3720  1.2.16.1  pgoyette nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
   3721  1.2.16.1  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3722  1.2.16.1  pgoyette {
   3723  1.2.16.1  pgoyette 	uint32_t *tl;
   3724  1.2.16.1  pgoyette 	int error = 0, i, idlen;
   3725  1.2.16.1  pgoyette 	struct nfsclient *clp = NULL;
   3726  1.2.16.1  pgoyette 	nfsquad_t clientid, confirm;
   3727  1.2.16.1  pgoyette 	uint8_t *verf;
   3728  1.2.16.1  pgoyette 	uint32_t sp4type, v41flags;
   3729  1.2.16.1  pgoyette 	uint64_t owner_minor;
   3730  1.2.16.1  pgoyette 	struct timespec verstime;
   3731  1.2.16.1  pgoyette 
   3732  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3733  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3734  1.2.16.1  pgoyette 		goto nfsmout;
   3735  1.2.16.1  pgoyette 	}
   3736  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
   3737  1.2.16.1  pgoyette 	verf = (uint8_t *)tl;
   3738  1.2.16.1  pgoyette 	tl += (NFSX_VERF / NFSX_UNSIGNED);
   3739  1.2.16.1  pgoyette 	i = fxdr_unsigned(int, *tl);
   3740  1.2.16.1  pgoyette 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
   3741  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3742  1.2.16.1  pgoyette 		goto nfsmout;
   3743  1.2.16.1  pgoyette 	}
   3744  1.2.16.1  pgoyette 	idlen = i;
   3745  1.2.16.1  pgoyette 	if (nd->nd_flag & ND_GSS)
   3746  1.2.16.1  pgoyette 		i += nd->nd_princlen;
   3747  1.2.16.1  pgoyette 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
   3748  1.2.16.1  pgoyette 	    M_ZERO);
   3749  1.2.16.1  pgoyette 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
   3750  1.2.16.1  pgoyette 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
   3751  1.2.16.1  pgoyette 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
   3752  1.2.16.1  pgoyette 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
   3753  1.2.16.1  pgoyette 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
   3754  1.2.16.1  pgoyette 	clp->lc_req.nr_cred = NULL;
   3755  1.2.16.1  pgoyette 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
   3756  1.2.16.1  pgoyette 	clp->lc_idlen = idlen;
   3757  1.2.16.1  pgoyette 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
   3758  1.2.16.1  pgoyette 	if (error != 0)
   3759  1.2.16.1  pgoyette 		goto nfsmout;
   3760  1.2.16.1  pgoyette 	if ((nd->nd_flag & ND_GSS) != 0) {
   3761  1.2.16.1  pgoyette 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
   3762  1.2.16.1  pgoyette 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
   3763  1.2.16.1  pgoyette 			clp->lc_flags |= LCL_GSSINTEGRITY;
   3764  1.2.16.1  pgoyette 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
   3765  1.2.16.1  pgoyette 			clp->lc_flags |= LCL_GSSPRIVACY;
   3766  1.2.16.1  pgoyette 	} else
   3767  1.2.16.1  pgoyette 		clp->lc_flags = LCL_NFSV41;
   3768  1.2.16.1  pgoyette 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
   3769  1.2.16.1  pgoyette 		clp->lc_flags |= LCL_NAME;
   3770  1.2.16.1  pgoyette 		clp->lc_namelen = nd->nd_princlen;
   3771  1.2.16.1  pgoyette 		clp->lc_name = &clp->lc_id[idlen];
   3772  1.2.16.1  pgoyette 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
   3773  1.2.16.1  pgoyette 	} else {
   3774  1.2.16.1  pgoyette 		clp->lc_uid = nd->nd_cred->cr_uid;
   3775  1.2.16.1  pgoyette 		clp->lc_gid = nd->nd_cred->cr_gid;
   3776  1.2.16.1  pgoyette 	}
   3777  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
   3778  1.2.16.1  pgoyette 	v41flags = fxdr_unsigned(uint32_t, *tl++);
   3779  1.2.16.1  pgoyette 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
   3780  1.2.16.1  pgoyette 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
   3781  1.2.16.1  pgoyette 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
   3782  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_INVAL;
   3783  1.2.16.1  pgoyette 		goto nfsmout;
   3784  1.2.16.1  pgoyette 	}
   3785  1.2.16.1  pgoyette 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
   3786  1.2.16.1  pgoyette 		confirm.lval[1] = 1;
   3787  1.2.16.1  pgoyette 	else
   3788  1.2.16.1  pgoyette 		confirm.lval[1] = 0;
   3789  1.2.16.1  pgoyette 	v41flags = NFSV4EXCH_USENONPNFS;
   3790  1.2.16.1  pgoyette 	sp4type = fxdr_unsigned(uint32_t, *tl);
   3791  1.2.16.1  pgoyette 	if (sp4type != NFSV4EXCH_SP4NONE) {
   3792  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   3793  1.2.16.1  pgoyette 		goto nfsmout;
   3794  1.2.16.1  pgoyette 	}
   3795  1.2.16.1  pgoyette 
   3796  1.2.16.1  pgoyette 	/*
   3797  1.2.16.1  pgoyette 	 * nfsrv_setclient() does the actual work of adding it to the
   3798  1.2.16.1  pgoyette 	 * client list. If there is no error, the structure has been
   3799  1.2.16.1  pgoyette 	 * linked into the client list and clp should no longer be used
   3800  1.2.16.1  pgoyette 	 * here. When an error is returned, it has not been linked in,
   3801  1.2.16.1  pgoyette 	 * so it should be free'd.
   3802  1.2.16.1  pgoyette 	 */
   3803  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
   3804  1.2.16.1  pgoyette 	if (clp != NULL) {
   3805  1.2.16.1  pgoyette 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3806  1.2.16.1  pgoyette 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3807  1.2.16.1  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3808  1.2.16.1  pgoyette 		free(clp, M_NFSDCLIENT);
   3809  1.2.16.1  pgoyette 	}
   3810  1.2.16.1  pgoyette 	if (nd->nd_repstat == 0) {
   3811  1.2.16.1  pgoyette 		if (confirm.lval[1] != 0)
   3812  1.2.16.1  pgoyette 			v41flags |= NFSV4EXCH_CONFIRMEDR;
   3813  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
   3814  1.2.16.1  pgoyette 		*tl++ = clientid.lval[0];			/* ClientID */
   3815  1.2.16.1  pgoyette 		*tl++ = clientid.lval[1];
   3816  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
   3817  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
   3818  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
   3819  1.2.16.1  pgoyette 		owner_minor = 0;				/* Owner */
   3820  1.2.16.1  pgoyette 		txdr_hyper(owner_minor, tl);			/* Minor */
   3821  1.2.16.1  pgoyette 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
   3822  1.2.16.1  pgoyette 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
   3823  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
   3824  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(NFSX_UNSIGNED);
   3825  1.2.16.1  pgoyette 		*tl++ = time_uptime;		/* Make scope a unique value. */
   3826  1.2.16.1  pgoyette 		*tl = txdr_unsigned(1);
   3827  1.2.16.1  pgoyette 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
   3828  1.2.16.1  pgoyette 		(void)nfsm_strtom(nd, version, strlen(version));
   3829  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
   3830  1.2.16.1  pgoyette 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
   3831  1.2.16.1  pgoyette 		verstime.tv_nsec = 0;
   3832  1.2.16.1  pgoyette 		txdr_nfsv4time(&verstime, tl);
   3833  1.2.16.1  pgoyette 	}
   3834  1.2.16.1  pgoyette 	NFSEXITCODE2(0, nd);
   3835  1.2.16.1  pgoyette 	return (0);
   3836  1.2.16.1  pgoyette nfsmout:
   3837  1.2.16.1  pgoyette 	if (clp != NULL) {
   3838  1.2.16.1  pgoyette 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
   3839  1.2.16.1  pgoyette 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
   3840  1.2.16.1  pgoyette 		free(clp->lc_stateid, M_NFSDCLIENT);
   3841  1.2.16.1  pgoyette 		free(clp, M_NFSDCLIENT);
   3842  1.2.16.1  pgoyette 	}
   3843  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   3844  1.2.16.1  pgoyette 	return (error);
   3845  1.2.16.1  pgoyette }
   3846  1.2.16.1  pgoyette 
   3847  1.2.16.1  pgoyette /*
   3848  1.2.16.1  pgoyette  * nfsv4 create session service
   3849  1.2.16.1  pgoyette  */
   3850  1.2.16.1  pgoyette APPLESTATIC int
   3851  1.2.16.1  pgoyette nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
   3852  1.2.16.1  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3853  1.2.16.1  pgoyette {
   3854  1.2.16.1  pgoyette 	uint32_t *tl;
   3855  1.2.16.1  pgoyette 	int error = 0;
   3856  1.2.16.1  pgoyette 	nfsquad_t clientid, confirm;
   3857  1.2.16.1  pgoyette 	struct nfsdsession *sep = NULL;
   3858  1.2.16.1  pgoyette 	uint32_t rdmacnt;
   3859  1.2.16.1  pgoyette 
   3860  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3861  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3862  1.2.16.1  pgoyette 		goto nfsmout;
   3863  1.2.16.1  pgoyette 	}
   3864  1.2.16.1  pgoyette 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
   3865  1.2.16.1  pgoyette 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
   3866  1.2.16.1  pgoyette 	sep->sess_refcnt = 1;
   3867  1.2.16.1  pgoyette 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
   3868  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
   3869  1.2.16.1  pgoyette 	clientid.lval[0] = *tl++;
   3870  1.2.16.1  pgoyette 	clientid.lval[1] = *tl++;
   3871  1.2.16.1  pgoyette 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
   3872  1.2.16.1  pgoyette 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
   3873  1.2.16.1  pgoyette 	/* Persistent sessions and RDMA are not supported. */
   3874  1.2.16.1  pgoyette 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
   3875  1.2.16.1  pgoyette 
   3876  1.2.16.1  pgoyette 	/* Fore channel attributes. */
   3877  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   3878  1.2.16.1  pgoyette 	tl++;					/* Header pad always 0. */
   3879  1.2.16.1  pgoyette 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
   3880  1.2.16.1  pgoyette 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
   3881  1.2.16.1  pgoyette 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
   3882  1.2.16.1  pgoyette 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
   3883  1.2.16.1  pgoyette 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
   3884  1.2.16.1  pgoyette 	if (sep->sess_maxslots > NFSV4_SLOTS)
   3885  1.2.16.1  pgoyette 		sep->sess_maxslots = NFSV4_SLOTS;
   3886  1.2.16.1  pgoyette 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
   3887  1.2.16.1  pgoyette 	if (rdmacnt > 1) {
   3888  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3889  1.2.16.1  pgoyette 		goto nfsmout;
   3890  1.2.16.1  pgoyette 	} else if (rdmacnt == 1)
   3891  1.2.16.1  pgoyette 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3892  1.2.16.1  pgoyette 
   3893  1.2.16.1  pgoyette 	/* Back channel attributes. */
   3894  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
   3895  1.2.16.1  pgoyette 	tl++;					/* Header pad always 0. */
   3896  1.2.16.1  pgoyette 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
   3897  1.2.16.1  pgoyette 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
   3898  1.2.16.1  pgoyette 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
   3899  1.2.16.1  pgoyette 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
   3900  1.2.16.1  pgoyette 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
   3901  1.2.16.1  pgoyette 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
   3902  1.2.16.1  pgoyette 	if (rdmacnt > 1) {
   3903  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_BADXDR;
   3904  1.2.16.1  pgoyette 		goto nfsmout;
   3905  1.2.16.1  pgoyette 	} else if (rdmacnt == 1)
   3906  1.2.16.1  pgoyette 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3907  1.2.16.1  pgoyette 
   3908  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   3909  1.2.16.1  pgoyette 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
   3910  1.2.16.1  pgoyette 
   3911  1.2.16.1  pgoyette 	/*
   3912  1.2.16.1  pgoyette 	 * nfsrv_getclient() searches the client list for a match and
   3913  1.2.16.1  pgoyette 	 * returns the appropriate NFSERR status.
   3914  1.2.16.1  pgoyette 	 */
   3915  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
   3916  1.2.16.1  pgoyette 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
   3917  1.2.16.1  pgoyette 	if (nd->nd_repstat == 0) {
   3918  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
   3919  1.2.16.1  pgoyette 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
   3920  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
   3921  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
   3922  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_crflags);
   3923  1.2.16.1  pgoyette 
   3924  1.2.16.1  pgoyette 		/* Fore channel attributes. */
   3925  1.2.16.1  pgoyette 		*tl++ = 0;
   3926  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxreq);
   3927  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxresp);
   3928  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
   3929  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxops);
   3930  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_maxslots);
   3931  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(1);
   3932  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
   3933  1.2.16.1  pgoyette 
   3934  1.2.16.1  pgoyette 		/* Back channel attributes. */
   3935  1.2.16.1  pgoyette 		*tl++ = 0;
   3936  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
   3937  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
   3938  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
   3939  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
   3940  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
   3941  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(1);
   3942  1.2.16.1  pgoyette 		*tl = txdr_unsigned(0);			/* No RDMA. */
   3943  1.2.16.1  pgoyette 	}
   3944  1.2.16.1  pgoyette nfsmout:
   3945  1.2.16.1  pgoyette 	if (nd->nd_repstat != 0 && sep != NULL)
   3946  1.2.16.1  pgoyette 		free(sep, M_NFSDSESSION);
   3947  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   3948  1.2.16.1  pgoyette 	return (error);
   3949  1.2.16.1  pgoyette }
   3950  1.2.16.1  pgoyette 
   3951  1.2.16.1  pgoyette /*
   3952  1.2.16.1  pgoyette  * nfsv4 sequence service
   3953  1.2.16.1  pgoyette  */
   3954  1.2.16.1  pgoyette APPLESTATIC int
   3955  1.2.16.1  pgoyette nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
   3956  1.2.16.1  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   3957  1.2.16.1  pgoyette {
   3958  1.2.16.1  pgoyette 	uint32_t *tl;
   3959  1.2.16.1  pgoyette 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
   3960  1.2.16.1  pgoyette 	int cache_this, error = 0;
   3961  1.2.16.1  pgoyette 
   3962  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   3963  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   3964  1.2.16.1  pgoyette 		goto nfsmout;
   3965  1.2.16.1  pgoyette 	}
   3966  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
   3967  1.2.16.1  pgoyette 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
   3968  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
   3969  1.2.16.1  pgoyette 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
   3970  1.2.16.1  pgoyette 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
   3971  1.2.16.1  pgoyette 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
   3972  1.2.16.1  pgoyette 	if (*tl == newnfs_true)
   3973  1.2.16.1  pgoyette 		cache_this = 1;
   3974  1.2.16.1  pgoyette 	else
   3975  1.2.16.1  pgoyette 		cache_this = 0;
   3976  1.2.16.1  pgoyette 	nd->nd_flag |= ND_HASSEQUENCE;
   3977  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
   3978  1.2.16.1  pgoyette 	    &target_highest_slotid, cache_this, &sflags, p);
   3979  1.2.16.1  pgoyette 	if (nd->nd_repstat == 0) {
   3980  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
   3981  1.2.16.1  pgoyette 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
   3982  1.2.16.1  pgoyette 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
   3983  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(sequenceid);
   3984  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(nd->nd_slotid);
   3985  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(highest_slotid);
   3986  1.2.16.1  pgoyette 		*tl++ = txdr_unsigned(target_highest_slotid);
   3987  1.2.16.1  pgoyette 		*tl = txdr_unsigned(sflags);
   3988  1.2.16.1  pgoyette 	}
   3989  1.2.16.1  pgoyette nfsmout:
   3990  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   3991  1.2.16.1  pgoyette 	return (error);
   3992  1.2.16.1  pgoyette }
   3993  1.2.16.1  pgoyette 
   3994  1.2.16.1  pgoyette /*
   3995  1.2.16.1  pgoyette  * nfsv4 reclaim complete service
   3996  1.2.16.1  pgoyette  */
   3997  1.2.16.1  pgoyette APPLESTATIC int
   3998  1.2.16.1  pgoyette nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
   3999  1.2.16.1  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4000  1.2.16.1  pgoyette {
   4001  1.2.16.1  pgoyette 	uint32_t *tl;
   4002  1.2.16.1  pgoyette 	int error = 0;
   4003  1.2.16.1  pgoyette 
   4004  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4005  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4006  1.2.16.1  pgoyette 		goto nfsmout;
   4007  1.2.16.1  pgoyette 	}
   4008  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
   4009  1.2.16.1  pgoyette 	if (*tl == newnfs_true)
   4010  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_NOTSUPP;
   4011  1.2.16.1  pgoyette 	else
   4012  1.2.16.1  pgoyette 		nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
   4013  1.2.16.1  pgoyette nfsmout:
   4014  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   4015  1.2.16.1  pgoyette 	return (error);
   4016  1.2.16.1  pgoyette }
   4017  1.2.16.1  pgoyette 
   4018  1.2.16.1  pgoyette /*
   4019  1.2.16.1  pgoyette  * nfsv4 destroy clientid service
   4020  1.2.16.1  pgoyette  */
   4021  1.2.16.1  pgoyette APPLESTATIC int
   4022  1.2.16.1  pgoyette nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
   4023  1.2.16.1  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4024  1.2.16.1  pgoyette {
   4025  1.2.16.1  pgoyette 	uint32_t *tl;
   4026  1.2.16.1  pgoyette 	nfsquad_t clientid;
   4027  1.2.16.1  pgoyette 	int error = 0;
   4028  1.2.16.1  pgoyette 
   4029  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4030  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4031  1.2.16.1  pgoyette 		goto nfsmout;
   4032  1.2.16.1  pgoyette 	}
   4033  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
   4034  1.2.16.1  pgoyette 	clientid.lval[0] = *tl++;
   4035  1.2.16.1  pgoyette 	clientid.lval[1] = *tl;
   4036  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
   4037  1.2.16.1  pgoyette nfsmout:
   4038  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   4039  1.2.16.1  pgoyette 	return (error);
   4040  1.2.16.1  pgoyette }
   4041  1.2.16.1  pgoyette 
   4042  1.2.16.1  pgoyette /*
   4043  1.2.16.1  pgoyette  * nfsv4 destroy session service
   4044  1.2.16.1  pgoyette  */
   4045  1.2.16.1  pgoyette APPLESTATIC int
   4046  1.2.16.1  pgoyette nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
   4047  1.2.16.1  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4048  1.2.16.1  pgoyette {
   4049  1.2.16.1  pgoyette 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
   4050  1.2.16.1  pgoyette 	int error = 0;
   4051  1.2.16.1  pgoyette 
   4052  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4053  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4054  1.2.16.1  pgoyette 		goto nfsmout;
   4055  1.2.16.1  pgoyette 	}
   4056  1.2.16.1  pgoyette 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
   4057  1.2.16.1  pgoyette 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
   4058  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
   4059  1.2.16.1  pgoyette nfsmout:
   4060  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   4061  1.2.16.1  pgoyette 	return (error);
   4062  1.2.16.1  pgoyette }
   4063  1.2.16.1  pgoyette 
   4064  1.2.16.1  pgoyette /*
   4065  1.2.16.1  pgoyette  * nfsv4 free stateid service
   4066  1.2.16.1  pgoyette  */
   4067  1.2.16.1  pgoyette APPLESTATIC int
   4068  1.2.16.1  pgoyette nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
   4069  1.2.16.1  pgoyette     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4070  1.2.16.1  pgoyette {
   4071  1.2.16.1  pgoyette 	uint32_t *tl;
   4072  1.2.16.1  pgoyette 	nfsv4stateid_t stateid;
   4073  1.2.16.1  pgoyette 	int error = 0;
   4074  1.2.16.1  pgoyette 
   4075  1.2.16.1  pgoyette 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
   4076  1.2.16.1  pgoyette 		nd->nd_repstat = NFSERR_WRONGSEC;
   4077  1.2.16.1  pgoyette 		goto nfsmout;
   4078  1.2.16.1  pgoyette 	}
   4079  1.2.16.1  pgoyette 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
   4080  1.2.16.1  pgoyette 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
   4081  1.2.16.1  pgoyette 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
   4082  1.2.16.1  pgoyette 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
   4083  1.2.16.1  pgoyette nfsmout:
   4084  1.2.16.1  pgoyette 	NFSEXITCODE2(error, nd);
   4085  1.2.16.1  pgoyette 	return (error);
   4086  1.2.16.1  pgoyette }
   4087  1.2.16.1  pgoyette 
   4088  1.2.16.1  pgoyette /*
   4089  1.2.16.1  pgoyette  * nfsv4 service not supported
   4090  1.2.16.1  pgoyette  */
   4091  1.2.16.1  pgoyette APPLESTATIC int
   4092  1.2.16.1  pgoyette nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
   4093  1.2.16.1  pgoyette     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
   4094  1.2.16.1  pgoyette {
   4095  1.2.16.1  pgoyette 
   4096  1.2.16.1  pgoyette 	nd->nd_repstat = NFSERR_NOTSUPP;
   4097  1.2.16.1  pgoyette 	NFSEXITCODE2(0, nd);
   4098  1.2.16.1  pgoyette 	return (0);
   4099  1.2.16.1  pgoyette }
   4100  1.2.16.1  pgoyette 
   4101