nfs_nfsdserv.c revision 300778
197403Sobrien/*- 297403Sobrien * Copyright (c) 1989, 1993 3169691Skan * The Regents of the University of California. All rights reserved. 4169691Skan * 597403Sobrien * This code is derived from software contributed to Berkeley by 697403Sobrien * Rick Macklem at The University of Guelph. 797403Sobrien * 897403Sobrien * Redistribution and use in source and binary forms, with or without 997403Sobrien * modification, are permitted provided that the following conditions 1097403Sobrien * are met: 1197403Sobrien * 1. Redistributions of source code must retain the above copyright 1297403Sobrien * notice, this list of conditions and the following disclaimer. 1397403Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1497403Sobrien * notice, this list of conditions and the following disclaimer in the 1597403Sobrien * documentation and/or other materials provided with the distribution. 1697403Sobrien * 4. Neither the name of the University nor the names of its contributors 1797403Sobrien * may be used to endorse or promote products derived from this software 1897403Sobrien * without specific prior written permission. 1997403Sobrien * 20169691Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2197403Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2297403Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2397403Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2497403Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2597403Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2697403Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2797403Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2897403Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2997403Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3097403Sobrien * SUCH DAMAGE. 3197403Sobrien * 3297403Sobrien */ 3397403Sobrien 3497403Sobrien#include <sys/cdefs.h> 3597403Sobrien__FBSDID("$FreeBSD: stable/10/sys/fs/nfsserver/nfs_nfsdserv.c 300778 2016-05-26 21:32:16Z rmacklem $"); 3697403Sobrien 37169691Skan/* 38169691Skan * nfs version 2, 3 and 4 server calls to vnode ops 39169691Skan * - these routines generally have 3 phases 40169691Skan * 1 - break down and validate rpc request in mbuf list 41132720Skan * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 42132720Skan * function in nfsd_port.c 4397403Sobrien * 3 - build the rpc reply in an mbuf list 4497403Sobrien * For nfsv4, these functions are called for each Op within the Compound RPC. 4597403Sobrien */ 46169691Skan 47132720Skan#ifndef APPLEKEXT 4897403Sobrien#include <fs/nfs/nfsport.h> 49169691Skan 50169691Skan/* Global vars */ 51117397Skanextern u_int32_t newnfs_false, newnfs_true; 52117397Skanextern enum vtype nv34tov_type[8]; 53117397Skanextern struct timeval nfsboottime; 54117397Skanextern int nfs_rootfhset; 55117397Skanextern int nfsrv_enable_crossmntpt; 56117397Skanextern int nfsrv_statehashsize; 57117397Skan#endif /* !APPLEKEXT */ 58117397Skan 59117397Skanstatic int nfs_async = 0; 60117397SkanSYSCTL_DECL(_vfs_nfsd); 61117397SkanSYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 62117397Skan "Tell client that writes were synced even though they were not"); 63117397Skan 64117397Skan/* 65117397Skan * This list defines the GSS mechanisms supported. 66117397Skan * (Don't ask me how you get these strings from the RFC stuff like 67117397Skan * iso(1), org(3)... but someone did it, so I don't need to know.) 68117397Skan */ 69117397Skanstatic struct nfsgss_mechlist nfsgss_mechlist[] = { 70117397Skan { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 71117397Skan { 0, "", 0 }, 72117397Skan}; 73117397Skan 74117397Skan/* local functions */ 75117397Skanstatic void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 76117397Skan struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 77132720Skan vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 78117397Skan int *diraft_retp, nfsattrbit_t *attrbitp, 79117397Skan NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 80117397Skan int pathlen); 81117397Skanstatic void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 82117397Skan struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 83117397Skan vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 84117397Skan int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 85117397Skan NFSPROC_T *p, struct nfsexstuff *exp); 86117397Skan 87117397Skan/* 88117397Skan * nfs access service (not a part of NFS V2) 89117397Skan */ 90117397SkanAPPLESTATIC int 91117397Skannfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 92117397Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 93117397Skan{ 94117397Skan u_int32_t *tl; 95117397Skan int getret, error = 0; 96117397Skan struct nfsvattr nva; 97117397Skan u_int32_t testmode, nfsmode, supported = 0; 98117397Skan accmode_t deletebit; 99117397Skan 100117397Skan if (nd->nd_repstat) { 101117397Skan nfsrv_postopattr(nd, 1, &nva); 102117397Skan goto out; 103117397Skan } 104117397Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 105117397Skan nfsmode = fxdr_unsigned(u_int32_t, *tl); 106117397Skan if ((nd->nd_flag & ND_NFSV4) && 107117397Skan (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 108117397Skan NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 10997403Sobrien NFSACCESS_EXECUTE))) { 11097403Sobrien nd->nd_repstat = NFSERR_INVAL; 11197403Sobrien vput(vp); 11297403Sobrien goto out; 113169691Skan } 114169691Skan if (nfsmode & NFSACCESS_READ) { 11597403Sobrien supported |= NFSACCESS_READ; 11697403Sobrien if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 117132720Skan NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 118132720Skan nfsmode &= ~NFSACCESS_READ; 119132720Skan } 120169691Skan if (nfsmode & NFSACCESS_MODIFY) { 121169691Skan supported |= NFSACCESS_MODIFY; 122169691Skan if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 123169691Skan NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 124169691Skan nfsmode &= ~NFSACCESS_MODIFY; 125169691Skan } 12697403Sobrien if (nfsmode & NFSACCESS_EXTEND) { 12797403Sobrien supported |= NFSACCESS_EXTEND; 12897403Sobrien if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 129132720Skan NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 130132720Skan nfsmode &= ~NFSACCESS_EXTEND; 131117397Skan } 13297403Sobrien if (nfsmode & NFSACCESS_DELETE) { 13397403Sobrien supported |= NFSACCESS_DELETE; 13497403Sobrien if (vp->v_type == VDIR) 135132720Skan deletebit = VDELETE_CHILD; 136132720Skan else 13797403Sobrien deletebit = VDELETE; 138132720Skan if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 139132720Skan NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 14097403Sobrien nfsmode &= ~NFSACCESS_DELETE; 14197403Sobrien } 14297403Sobrien if (vnode_vtype(vp) == VDIR) 14397403Sobrien testmode = NFSACCESS_LOOKUP; 14497403Sobrien else 14597403Sobrien testmode = NFSACCESS_EXECUTE; 146132720Skan if (nfsmode & testmode) { 147132720Skan supported |= (nfsmode & testmode); 14897403Sobrien if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 149132720Skan NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 150132720Skan nfsmode &= ~testmode; 151132720Skan } 152132720Skan nfsmode &= supported; 153132720Skan if (nd->nd_flag & ND_NFSV3) { 154132720Skan getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 155132720Skan nfsrv_postopattr(nd, getret, &nva); 15697403Sobrien } 15797403Sobrien vput(vp); 15897403Sobrien if (nd->nd_flag & ND_NFSV4) { 159117397Skan NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 16097403Sobrien *tl++ = txdr_unsigned(supported); 16197403Sobrien } else 16297403Sobrien NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 16397403Sobrien *tl = txdr_unsigned(nfsmode); 16497403Sobrien 16597403Sobrienout: 16697403Sobrien NFSEXITCODE2(0, nd); 167117397Skan return (0); 16897403Sobriennfsmout: 16997403Sobrien vput(vp); 170117397Skan NFSEXITCODE2(error, nd); 171132720Skan return (error); 172132720Skan} 173132720Skan 17497403Sobrien/* 175132720Skan * nfs getattr service 176132720Skan */ 177132720SkanAPPLESTATIC int 178117397Skannfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 179132720Skan vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 180132720Skan{ 181169691Skan struct nfsvattr nva; 182169691Skan fhandle_t fh; 183169691Skan int at_root = 0, error = 0, supports_nfsv4acls; 184169691Skan struct nfsreferral *refp; 185169691Skan nfsattrbit_t attrbits, tmpbits; 186169691Skan struct mount *mp; 187169691Skan struct vnode *tvp = NULL; 188132720Skan struct vattr va; 18997403Sobrien uint64_t mounted_on_fileno = 0; 19097403Sobrien accmode_t accmode; 191132720Skan 19297403Sobrien if (nd->nd_repstat) 19397403Sobrien goto out; 19497403Sobrien if (nd->nd_flag & ND_NFSV4) { 195132720Skan error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 19697403Sobrien if (error) { 19797403Sobrien vput(vp); 198117397Skan goto out; 199132720Skan } 20097403Sobrien 20197403Sobrien /* 202117397Skan * Check for a referral. 203132720Skan */ 20497403Sobrien refp = nfsv4root_getreferral(vp, NULL, 0); 205169691Skan if (refp != NULL) { 206169691Skan (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 207169691Skan &nd->nd_repstat); 208169691Skan vput(vp); 209169691Skan goto out; 210169691Skan } 211169691Skan if (nd->nd_repstat == 0) { 212169691Skan accmode = 0; 213169691Skan NFSSET_ATTRBIT(&tmpbits, &attrbits); 214169691Skan if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 215117397Skan NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 21697403Sobrien accmode |= VREAD_ACL; 21797403Sobrien } 21897403Sobrien if (NFSNONZERO_ATTRBIT(&tmpbits)) 219117397Skan accmode |= VREAD_ATTRIBUTES; 22097403Sobrien if (accmode != 0) 221117397Skan nd->nd_repstat = nfsvno_accchk(vp, accmode, 222117397Skan nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 223117397Skan NFSACCCHK_VPISLOCKED, NULL); 22497403Sobrien } 22597403Sobrien } 22697403Sobrien if (!nd->nd_repstat) 227117397Skan nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 228132720Skan if (!nd->nd_repstat) { 22997403Sobrien if (nd->nd_flag & ND_NFSV4) { 230117397Skan if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 23197403Sobrien nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 232117397Skan if (!nd->nd_repstat) 233146897Skan nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 234132720Skan &nva, &attrbits, nd->nd_cred, p); 235146897Skan if (nd->nd_repstat == 0) { 236169691Skan supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 237169691Skan mp = vp->v_mount; 238132720Skan if (nfsrv_enable_crossmntpt != 0 && 23997403Sobrien vp->v_type == VDIR && 24097403Sobrien (vp->v_vflag & VV_ROOT) != 0 && 241117397Skan vp != rootvnode) { 24297403Sobrien tvp = mp->mnt_vnodecovered; 24397403Sobrien VREF(tvp); 244117397Skan at_root = 1; 24597403Sobrien } else 246117397Skan at_root = 0; 247146897Skan vfs_ref(mp); 248132720Skan NFSVOPUNLOCK(vp, 0); 249146897Skan if (at_root != 0) { 250169691Skan if ((nd->nd_repstat = 251117397Skan NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 25297403Sobrien nd->nd_repstat = VOP_GETATTR( 25397403Sobrien tvp, &va, nd->nd_cred); 254117397Skan vput(tvp); 25597403Sobrien } else 25697403Sobrien vrele(tvp); 25797403Sobrien if (nd->nd_repstat == 0) 25897403Sobrien mounted_on_fileno = (uint64_t) 25997403Sobrien va.va_fileid; 26097403Sobrien else 26197403Sobrien at_root = 0; 26297403Sobrien } 26397403Sobrien if (nd->nd_repstat == 0) 26497403Sobrien nd->nd_repstat = vfs_busy(mp, 0); 26597403Sobrien vfs_rel(mp); 26697403Sobrien if (nd->nd_repstat == 0) { 26797403Sobrien (void)nfsvno_fillattr(nd, mp, vp, &nva, 26897403Sobrien &fh, 0, &attrbits, nd->nd_cred, p, 26997403Sobrien isdgram, 1, supports_nfsv4acls, 27097403Sobrien at_root, mounted_on_fileno); 271169691Skan vfs_unbusy(mp); 272132720Skan } 27397403Sobrien vrele(vp); 27497403Sobrien } else 27597403Sobrien vput(vp); 276132720Skan } else { 27797403Sobrien nfsrv_fillattr(nd, &nva); 278117397Skan vput(vp); 279117397Skan } 28097403Sobrien } else { 28197403Sobrien vput(vp); 282117397Skan } 283117397Skan 28497403Sobrienout: 28597403Sobrien NFSEXITCODE2(error, nd); 286117397Skan return (error); 28797403Sobrien} 28897403Sobrien 28997403Sobrien/* 29097403Sobrien * nfs setattr service 29197403Sobrien */ 292117397SkanAPPLESTATIC int 293169691Skannfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 294169691Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 29597403Sobrien{ 296117397Skan struct nfsvattr nva, nva2; 297169691Skan u_int32_t *tl; 298169691Skan int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 29997403Sobrien struct timespec guard = { 0, 0 }; 300117397Skan nfsattrbit_t attrbits, retbits; 30197403Sobrien nfsv4stateid_t stateid; 302117397Skan NFSACL_T *aclp = NULL; 303117397Skan 304117397Skan if (nd->nd_repstat) { 30597403Sobrien nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 30697403Sobrien goto out; 307132720Skan } 308132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 309117397Skan aclp = acl_alloc(M_WAITOK); 31097403Sobrien aclp->acl_cnt = 0; 311132720Skan#endif 312132720Skan NFSVNO_ATTRINIT(&nva); 31397403Sobrien NFSZERO_ATTRBIT(&retbits); 31497403Sobrien if (nd->nd_flag & ND_NFSV4) { 315169691Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 316169691Skan stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 317169691Skan NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 318169691Skan } 319169691Skan error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 320169691Skan if (error) 321169691Skan goto nfsmout; 322132720Skan preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1); 323132720Skan if (!nd->nd_repstat) 324132720Skan nd->nd_repstat = preat_ret; 325117397Skan if (nd->nd_flag & ND_NFSV3) { 326132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 327132720Skan gcheck = fxdr_unsigned(int, *tl); 32897403Sobrien if (gcheck) { 32997403Sobrien NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 330169691Skan fxdr_nfsv3time(tl, &guard); 331169691Skan } 332169691Skan if (!nd->nd_repstat && gcheck && 333169691Skan (nva2.na_ctime.tv_sec != guard.tv_sec || 334169691Skan nva2.na_ctime.tv_nsec != guard.tv_nsec)) 335169691Skan nd->nd_repstat = NFSERR_NOT_SYNC; 336169691Skan if (nd->nd_repstat) { 337169691Skan vput(vp); 338169691Skan#ifdef NFS4_ACL_EXTATTR_NAME 339169691Skan acl_free(aclp); 340169691Skan#endif 341169691Skan nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 342169691Skan goto out; 343169691Skan } 344169691Skan } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 345169691Skan nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 346169691Skan 347169691Skan /* 348169691Skan * Now that we have all the fields, lets do it. 349169691Skan * If the size is being changed write access is required, otherwise 350169691Skan * just check for a read only file system. 351169691Skan */ 352169691Skan if (!nd->nd_repstat) { 353169691Skan if (NFSVNO_NOTSETSIZE(&nva)) { 354169691Skan if (NFSVNO_EXRDONLY(exp) || 355169691Skan (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 356169691Skan nd->nd_repstat = EROFS; 357169691Skan } else { 358169691Skan if (vnode_vtype(vp) != VREG) 359169691Skan nd->nd_repstat = EINVAL; 360169691Skan else if (nva2.na_uid != nd->nd_cred->cr_uid || 361169691Skan NFSVNO_EXSTRICTACCESS(exp)) 362169691Skan nd->nd_repstat = nfsvno_accchk(vp, 363169691Skan VWRITE, nd->nd_cred, exp, p, 364169691Skan NFSACCCHK_NOOVERRIDE, 365169691Skan NFSACCCHK_VPISLOCKED, NULL); 366169691Skan } 36797403Sobrien } 36897403Sobrien if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 36997403Sobrien nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 37097403Sobrien &nva, &attrbits, exp, p); 37197403Sobrien 372117397Skan if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 373117397Skan /* 37497403Sobrien * For V4, try setting the attrbutes in sets, so that the 37597403Sobrien * reply bitmap will be correct for an error case. 37697403Sobrien */ 37797403Sobrien if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 37897403Sobrien NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 37997403Sobrien NFSVNO_ATTRINIT(&nva2); 38097403Sobrien NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 38197403Sobrien NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 38297403Sobrien nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 38397403Sobrien exp); 384117397Skan if (!nd->nd_repstat) { 38597403Sobrien if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 38697403Sobrien NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 387169691Skan if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 38897403Sobrien NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 38997403Sobrien } 39097403Sobrien } 391169691Skan if (!nd->nd_repstat && 39297403Sobrien NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 393259705Spfg NFSVNO_ATTRINIT(&nva2); 394259705Spfg NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 395259705Spfg nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 396259705Spfg exp); 397259705Spfg if (!nd->nd_repstat) 398259705Spfg NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 399259705Spfg } 400259705Spfg if (!nd->nd_repstat && 401259705Spfg (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 402259705Spfg NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 403117397Skan NFSVNO_ATTRINIT(&nva2); 40497403Sobrien NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 40597403Sobrien NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 406117397Skan if (nva.na_vaflags & VA_UTIMES_NULL) { 40797403Sobrien nva2.na_vaflags |= VA_UTIMES_NULL; 40897403Sobrien NFSVNO_SETACTIVE(&nva2, vaflags); 409117397Skan } 41097403Sobrien nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 411132720Skan exp); 41297403Sobrien if (!nd->nd_repstat) { 41397403Sobrien if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 41497403Sobrien NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 41597403Sobrien if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 41697403Sobrien NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 41797403Sobrien } 418132720Skan } 419132720Skan if (!nd->nd_repstat && 420132720Skan NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 421117397Skan NFSVNO_ATTRINIT(&nva2); 42297403Sobrien NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 42397403Sobrien nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 424132720Skan exp); 425169691Skan if (!nd->nd_repstat) 426132720Skan NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 427117397Skan } 42897403Sobrien 42997403Sobrien#ifdef NFS4_ACL_EXTATTR_NAME 43097403Sobrien if (!nd->nd_repstat && aclp->acl_cnt > 0 && 431132720Skan NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 432132720Skan nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 433132720Skan if (!nd->nd_repstat) 434132720Skan NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 43597403Sobrien } 436132720Skan#endif 437132720Skan } else if (!nd->nd_repstat) { 438132720Skan nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 439132720Skan exp); 440132720Skan } 441132720Skan if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 44297403Sobrien postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 44397403Sobrien if (!nd->nd_repstat) 444132720Skan nd->nd_repstat = postat_ret; 445132720Skan } 446132720Skan vput(vp); 447132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 448132720Skan acl_free(aclp); 449132720Skan#endif 450132720Skan if (nd->nd_flag & ND_NFSV3) 45197403Sobrien nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 45297403Sobrien else if (nd->nd_flag & ND_NFSV4) 45397403Sobrien (void) nfsrv_putattrbit(nd, &retbits); 454132720Skan else if (!nd->nd_repstat) 455132720Skan nfsrv_fillattr(nd, &nva); 456132720Skan 457132720Skanout: 458132720Skan NFSEXITCODE2(0, nd); 459132720Skan return (0); 460169691Skannfsmout: 461132720Skan vput(vp); 462132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 46397403Sobrien acl_free(aclp); 46497403Sobrien#endif 465132720Skan if (nd->nd_flag & ND_NFSV4) { 466132720Skan /* 467132720Skan * For all nd_repstat, the V4 reply includes a bitmap, 468132720Skan * even NFSERR_BADXDR, which is what this will end up 469132720Skan * returning. 47097403Sobrien */ 471132720Skan (void) nfsrv_putattrbit(nd, &retbits); 472132720Skan } 473132720Skan NFSEXITCODE2(error, nd); 474132720Skan return (error); 475132720Skan} 476132720Skan 47797403Sobrien/* 47897403Sobrien * nfs lookup rpc 479132720Skan * (Also performs lookup parent for v4) 480132720Skan */ 481132720SkanAPPLESTATIC int 482132720Skannfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 483132720Skan vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 484132720Skan struct nfsexstuff *exp) 48597403Sobrien{ 48697403Sobrien struct nameidata named; 48797403Sobrien vnode_t vp, dirp = NULL; 48897403Sobrien int error = 0, dattr_ret = 1; 489132720Skan struct nfsvattr nva, dattr; 490132720Skan char *bufp; 491132720Skan u_long *hashp; 492117397Skan 49397403Sobrien if (nd->nd_repstat) { 49497403Sobrien nfsrv_postopattr(nd, dattr_ret, &dattr); 495132720Skan goto out; 496132720Skan } 497132720Skan 498132720Skan /* 499117397Skan * For some reason, if dp is a symlink, the error 500132720Skan * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 501169691Skan */ 50297403Sobrien if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 503132720Skan nd->nd_repstat = NFSERR_SYMLINK; 504132720Skan vrele(dp); 505132720Skan goto out; 506132720Skan } 507117397Skan 508132720Skan NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 509169691Skan LOCKLEAF | SAVESTART); 51097403Sobrien nfsvno_setpathbuf(&named, &bufp, &hashp); 511132720Skan error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 512132720Skan if (error) { 513132720Skan vrele(dp); 514132720Skan nfsvno_relpathbuf(&named); 515132720Skan goto out; 516132720Skan } 517132720Skan if (!nd->nd_repstat) { 518117397Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 519132720Skan } else { 520132720Skan vrele(dp); 521132720Skan nfsvno_relpathbuf(&named); 522132720Skan } 523132720Skan if (nd->nd_repstat) { 52497403Sobrien if (dirp) { 52597403Sobrien if (nd->nd_flag & ND_NFSV3) 526132720Skan dattr_ret = nfsvno_getattr(dirp, &dattr, 527132720Skan nd->nd_cred, p, 0); 528132720Skan vrele(dirp); 529132720Skan } 530117397Skan if (nd->nd_flag & ND_NFSV3) 531117397Skan nfsrv_postopattr(nd, dattr_ret, &dattr); 532117397Skan goto out; 533117397Skan } 53497403Sobrien if (named.ni_startdir) 53597403Sobrien vrele(named.ni_startdir); 53697403Sobrien nfsvno_relpathbuf(&named); 537132720Skan vp = named.ni_vp; 538132720Skan if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 539132720Skan vp->v_type != VDIR && vp->v_type != VLNK) 540132720Skan /* 541117397Skan * Only allow lookup of VDIR and VLNK for traversal of 542117397Skan * non-exported volumes during NFSv4 mounting. 54397403Sobrien */ 54497403Sobrien nd->nd_repstat = ENOENT; 545132720Skan if (nd->nd_repstat == 0) 546132720Skan nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 547132720Skan if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 548132720Skan nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 549117397Skan if (vpp != NULL && nd->nd_repstat == 0) 55097403Sobrien *vpp = vp; 55197403Sobrien else 552132720Skan vput(vp); 553132720Skan if (dirp) { 55497403Sobrien if (nd->nd_flag & ND_NFSV3) 55597403Sobrien dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred, 556132720Skan p, 0); 557132720Skan vrele(dirp); 558132720Skan } 559132720Skan if (nd->nd_repstat) { 560117397Skan if (nd->nd_flag & ND_NFSV3) 56197403Sobrien nfsrv_postopattr(nd, dattr_ret, &dattr); 56297403Sobrien goto out; 56397403Sobrien } 564132720Skan if (nd->nd_flag & ND_NFSV2) { 565132720Skan (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 566132720Skan nfsrv_fillattr(nd, &nva); 567132720Skan } else if (nd->nd_flag & ND_NFSV3) { 568132720Skan (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 569117397Skan nfsrv_postopattr(nd, 0, &nva); 570117397Skan nfsrv_postopattr(nd, dattr_ret, &dattr); 57197403Sobrien } 57297403Sobrien 573132720Skanout: 574132720Skan NFSEXITCODE2(error, nd); 575132720Skan return (error); 576132720Skan} 577132720Skan 578117397Skan/* 579117397Skan * nfs readlink service 58097403Sobrien */ 58197403SobrienAPPLESTATIC int 582132720Skannfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 583132720Skan vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 584132720Skan{ 585132720Skan u_int32_t *tl; 586132720Skan mbuf_t mp = NULL, mpend = NULL; 587117397Skan int getret = 1, len; 588117397Skan struct nfsvattr nva; 58997403Sobrien 59097403Sobrien if (nd->nd_repstat) { 591132720Skan nfsrv_postopattr(nd, getret, &nva); 592132720Skan goto out; 593132720Skan } 594132720Skan if (vnode_vtype(vp) != VLNK) { 595132720Skan if (nd->nd_flag & ND_NFSV2) 596117397Skan nd->nd_repstat = ENXIO; 597117397Skan else 59897403Sobrien nd->nd_repstat = EINVAL; 59997403Sobrien } 60097403Sobrien if (!nd->nd_repstat) 60197403Sobrien nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 602132720Skan &mp, &mpend, &len); 603132720Skan if (nd->nd_flag & ND_NFSV3) 604117397Skan getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 605169691Skan vput(vp); 606169691Skan if (nd->nd_flag & ND_NFSV3) 60797403Sobrien nfsrv_postopattr(nd, getret, &nva); 608132720Skan if (nd->nd_repstat) 609132720Skan goto out; 610117397Skan NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 611169691Skan *tl = txdr_unsigned(len); 612169691Skan mbuf_setnext(nd->nd_mb, mp); 61397403Sobrien nd->nd_mb = mpend; 614132720Skan nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 615117397Skan 616169691Skanout: 617169691Skan NFSEXITCODE2(0, nd); 61897403Sobrien return (0); 619132720Skan} 620132720Skan 621132720Skan/* 622132720Skan * nfs read service 623132720Skan */ 624132720SkanAPPLESTATIC int 625132720Skannfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 626132720Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 627132720Skan{ 628132720Skan u_int32_t *tl; 629117397Skan int error = 0, cnt, getret = 1, reqlen, eof = 0; 63097403Sobrien mbuf_t m2, m3; 63197403Sobrien struct nfsvattr nva; 632132720Skan off_t off = 0x0; 633132720Skan struct nfsstate st, *stp = &st; 634132720Skan struct nfslock lo, *lop = &lo; 635132720Skan nfsv4stateid_t stateid; 636132720Skan nfsquad_t clientid; 637132720Skan 638132720Skan if (nd->nd_repstat) { 639132720Skan nfsrv_postopattr(nd, getret, &nva); 640132720Skan goto out; 641132720Skan } 642117397Skan if (nd->nd_flag & ND_NFSV2) { 643169691Skan NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 644169691Skan off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 64597403Sobrien reqlen = fxdr_unsigned(int, *tl); 646132720Skan } else if (nd->nd_flag & ND_NFSV3) { 647132720Skan NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 648132720Skan off = fxdr_hyper(tl); 649132720Skan tl += 2; 650117397Skan reqlen = fxdr_unsigned(int, *tl); 651169691Skan } else { 652169691Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 65397403Sobrien reqlen = fxdr_unsigned(int, *(tl + 6)); 654132720Skan } 655132720Skan if (reqlen > NFS_SRVMAXDATA(nd)) { 656132720Skan reqlen = NFS_SRVMAXDATA(nd); 657169691Skan } else if (reqlen < 0) { 658169691Skan error = EBADRPC; 659132720Skan goto nfsmout; 660132720Skan } 661132720Skan if (nd->nd_flag & ND_NFSV4) { 662132720Skan stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 663132720Skan lop->lo_flags = NFSLCK_READ; 664132720Skan stp->ls_ownerlen = 0; 665132720Skan stp->ls_op = NULL; 666132720Skan stp->ls_uid = nd->nd_cred->cr_uid; 667132720Skan stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 668132720Skan clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 669132720Skan clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 670132720Skan if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 671117397Skan if ((nd->nd_flag & ND_NFSV41) != 0) 67297403Sobrien clientid.qval = nd->nd_clientid.qval; 67397403Sobrien else if (nd->nd_clientid.qval != clientid.qval) 674132720Skan printf("EEK1 multiple clids\n"); 675132720Skan } else { 676132720Skan if ((nd->nd_flag & ND_NFSV41) != 0) 677117397Skan printf("EEK! no clientid from session\n"); 678169691Skan nd->nd_flag |= ND_IMPLIEDCLID; 679169691Skan nd->nd_clientid.qval = clientid.qval; 68097403Sobrien } 681132720Skan stp->ls_stateid.other[2] = *tl++; 682132720Skan off = fxdr_hyper(tl); 683132720Skan lop->lo_first = off; 684117397Skan tl += 2; 685169691Skan lop->lo_end = off + reqlen; 686169691Skan /* 68797403Sobrien * Paranoia, just in case it wraps around. 68897403Sobrien */ 689132720Skan if (lop->lo_end < off) 690132720Skan lop->lo_end = NFS64BITSSET; 691169691Skan } 692132720Skan if (vnode_vtype(vp) != VREG) { 693132720Skan if (nd->nd_flag & ND_NFSV3) 694132720Skan nd->nd_repstat = EINVAL; 695132720Skan else 696132720Skan nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 697132720Skan EINVAL; 698132720Skan } 699117397Skan getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 700117397Skan if (!nd->nd_repstat) 701132720Skan nd->nd_repstat = getret; 702132720Skan if (!nd->nd_repstat && 703132720Skan (nva.na_uid != nd->nd_cred->cr_uid || 704132720Skan NFSVNO_EXSTRICTACCESS(exp))) { 70597403Sobrien nd->nd_repstat = nfsvno_accchk(vp, VREAD, 706132720Skan nd->nd_cred, exp, p, 707132720Skan NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 708169691Skan if (nd->nd_repstat) 709132720Skan nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 710132720Skan nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 711132720Skan NFSACCCHK_VPISLOCKED, NULL); 712132720Skan } 713132720Skan if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 714132720Skan nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 715132720Skan &stateid, exp, nd, p); 716117397Skan if (nd->nd_repstat) { 717117397Skan vput(vp); 718117397Skan if (nd->nd_flag & ND_NFSV3) 719169691Skan nfsrv_postopattr(nd, getret, &nva); 720169691Skan goto out; 721169691Skan } 722169691Skan if (off >= nva.na_size) { 723117397Skan cnt = 0; 724117397Skan eof = 1; 72597403Sobrien } else if (reqlen == 0) 72697403Sobrien cnt = 0; 727132720Skan else if ((off + reqlen) >= nva.na_size) { 728132720Skan cnt = nva.na_size - off; 729132720Skan eof = 1; 730132720Skan } else 731132720Skan cnt = reqlen; 732132720Skan m3 = NULL; 733132720Skan if (cnt > 0) { 734132720Skan nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 735132720Skan &m3, &m2); 736132720Skan if (!(nd->nd_flag & ND_NFSV4)) { 737117397Skan getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 73897403Sobrien if (!nd->nd_repstat) 73997403Sobrien nd->nd_repstat = getret; 74097403Sobrien } 741132720Skan if (nd->nd_repstat) { 742117397Skan vput(vp); 74397403Sobrien if (m3) 74497403Sobrien mbuf_freem(m3); 745132720Skan if (nd->nd_flag & ND_NFSV3) 746132720Skan nfsrv_postopattr(nd, getret, &nva); 747132720Skan goto out; 748132720Skan } 749132720Skan } 750132720Skan vput(vp); 751132720Skan if (nd->nd_flag & ND_NFSV2) { 752132720Skan nfsrv_fillattr(nd, &nva); 753132720Skan NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 754132720Skan } else { 755132720Skan if (nd->nd_flag & ND_NFSV3) { 756117397Skan nfsrv_postopattr(nd, getret, &nva); 75797403Sobrien NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 75897403Sobrien *tl++ = txdr_unsigned(cnt); 75997403Sobrien } else 760132720Skan NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 761117397Skan if (eof) 762117397Skan *tl++ = newnfs_true; 76397403Sobrien else 76497403Sobrien *tl++ = newnfs_false; 76597403Sobrien } 766132720Skan *tl = txdr_unsigned(cnt); 767132720Skan if (m3) { 768132720Skan mbuf_setnext(nd->nd_mb, m3); 769132720Skan nd->nd_mb = m2; 770132720Skan nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 771117397Skan } 772169691Skan 773169691Skanout: 77497403Sobrien NFSEXITCODE2(0, nd); 775132720Skan return (0); 776132720Skannfsmout: 777132720Skan vput(vp); 778132720Skan NFSEXITCODE2(error, nd); 779132720Skan return (error); 780117397Skan} 781169691Skan 782169691Skan/* 78397403Sobrien * nfs write service 784132720Skan */ 785132720SkanAPPLESTATIC int 786169691Skannfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 787132720Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 788132720Skan{ 789117397Skan int i, cnt; 790169691Skan u_int32_t *tl; 791169691Skan mbuf_t mp; 792169691Skan struct nfsvattr nva, forat; 793169691Skan int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 794169691Skan int stable = NFSWRITE_FILESYNC; 79597403Sobrien off_t off; 796132720Skan struct nfsstate st, *stp = &st; 797132720Skan struct nfslock lo, *lop = &lo; 798132720Skan nfsv4stateid_t stateid; 799132720Skan nfsquad_t clientid; 800132720Skan 801117397Skan if (nd->nd_repstat) { 80297403Sobrien nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 80397403Sobrien goto out; 804132720Skan } 805132720Skan if (nd->nd_flag & ND_NFSV2) { 806132720Skan NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 807132720Skan off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 808132720Skan tl += 2; 809132720Skan retlen = len = fxdr_unsigned(int32_t, *tl); 810132720Skan } else if (nd->nd_flag & ND_NFSV3) { 811132720Skan NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 812132720Skan off = fxdr_hyper(tl); 813132720Skan tl += 3; 814132720Skan stable = fxdr_unsigned(int, *tl++); 815132720Skan retlen = len = fxdr_unsigned(int32_t, *tl); 816117397Skan } else { 81797403Sobrien NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 81897403Sobrien stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 819132720Skan lop->lo_flags = NFSLCK_WRITE; 820132720Skan stp->ls_ownerlen = 0; 821132720Skan stp->ls_op = NULL; 822132720Skan stp->ls_uid = nd->nd_cred->cr_uid; 823132720Skan stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 824132720Skan clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 825117397Skan clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 82697403Sobrien if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 82797403Sobrien if ((nd->nd_flag & ND_NFSV41) != 0) 828132720Skan clientid.qval = nd->nd_clientid.qval; 829132720Skan else if (nd->nd_clientid.qval != clientid.qval) 830132720Skan printf("EEK2 multiple clids\n"); 831132720Skan } else { 832132720Skan if ((nd->nd_flag & ND_NFSV41) != 0) 833117397Skan printf("EEK! no clientid from session\n"); 83497403Sobrien nd->nd_flag |= ND_IMPLIEDCLID; 835132720Skan nd->nd_clientid.qval = clientid.qval; 836132720Skan } 837132720Skan stp->ls_stateid.other[2] = *tl++; 838132720Skan off = fxdr_hyper(tl); 83997403Sobrien lop->lo_first = off; 840132720Skan tl += 2; 841132720Skan stable = fxdr_unsigned(int, *tl++); 842132720Skan retlen = len = fxdr_unsigned(int32_t, *tl); 843132720Skan lop->lo_end = off + len; 844132720Skan /* 845132720Skan * Paranoia, just in case it wraps around, which shouldn't 846132720Skan * ever happen anyhow. 847132720Skan */ 848117397Skan if (lop->lo_end < lop->lo_first) 849169691Skan lop->lo_end = NFS64BITSSET; 85097403Sobrien } 851132720Skan 852132720Skan /* 853132720Skan * Loop through the mbuf chain, counting how many mbufs are a 854132720Skan * part of this write operation, so the iovec size is known. 855132720Skan */ 856132720Skan cnt = 0; 857132720Skan mp = nd->nd_md; 858132720Skan i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 85997403Sobrien while (len > 0) { 860117397Skan if (i > 0) { 86197403Sobrien len -= i; 86297403Sobrien cnt++; 86397403Sobrien } 864132720Skan mp = mbuf_next(mp); 865132720Skan if (!mp) { 866132720Skan if (len > 0) { 867132720Skan error = EBADRPC; 868117397Skan goto nfsmout; 86997403Sobrien } 870169691Skan } else 871169691Skan i = mbuf_len(mp); 872169691Skan } 873169691Skan 874169691Skan if (retlen > NFS_SRVMAXIO || retlen < 0) 875169691Skan nd->nd_repstat = EIO; 876169691Skan if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 87797403Sobrien if (nd->nd_flag & ND_NFSV3) 878132720Skan nd->nd_repstat = EINVAL; 879132720Skan else 880132720Skan nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 881132720Skan EINVAL; 882132720Skan } 883117397Skan forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1); 88497403Sobrien if (!nd->nd_repstat) 88597403Sobrien nd->nd_repstat = forat_ret; 886132720Skan if (!nd->nd_repstat && 887132720Skan (forat.na_uid != nd->nd_cred->cr_uid || 888132720Skan NFSVNO_EXSTRICTACCESS(exp))) 889132720Skan nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 890132720Skan nd->nd_cred, exp, p, 891132720Skan NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 892132720Skan if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 893132720Skan nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 894132720Skan &stateid, exp, nd, p); 895132720Skan } 896132720Skan if (nd->nd_repstat) { 897132720Skan vput(vp); 898117397Skan if (nd->nd_flag & ND_NFSV3) 899132720Skan nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 900132720Skan goto out; 901132720Skan } 902132720Skan 90397403Sobrien /* 904132720Skan * For NFS Version 2, it is not obvious what a write of zero length 905132720Skan * should do, but I might as well be consistent with Version 3, 906132720Skan * which is to return ok so long as there are no permission problems. 907132720Skan */ 908132720Skan if (retlen > 0) { 909132720Skan nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable, 910132720Skan nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 911132720Skan error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 912132720Skan if (error) 913132720Skan panic("nfsrv_write mbuf"); 914117397Skan } 915117397Skan if (nd->nd_flag & ND_NFSV4) 91697403Sobrien aftat_ret = 0; 917132720Skan else 918132720Skan aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 919132720Skan vput(vp); 920132720Skan if (!nd->nd_repstat) 921132720Skan nd->nd_repstat = aftat_ret; 922132720Skan if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 923132720Skan if (nd->nd_flag & ND_NFSV3) 924132720Skan nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 925132720Skan if (nd->nd_repstat) 926117397Skan goto out; 92797403Sobrien NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 928132720Skan *tl++ = txdr_unsigned(retlen); 929132720Skan /* 930132720Skan * If nfs_async is set, then pretend the write was FILESYNC. 931132720Skan * Warning: Doing this violates RFC1813 and runs a risk 93297403Sobrien * of data written by a client being lost when the server 933132720Skan * crashes/reboots. 934132720Skan */ 935132720Skan if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 936132720Skan *tl++ = txdr_unsigned(stable); 937132720Skan else 938132720Skan *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 939132720Skan /* 940132720Skan * Actually, there is no need to txdr these fields, 941132720Skan * but it may make the values more human readable, 942117397Skan * for debugging purposes. 94397403Sobrien */ 944132720Skan *tl++ = txdr_unsigned(nfsboottime.tv_sec); 94597403Sobrien *tl = txdr_unsigned(nfsboottime.tv_usec); 946132720Skan } else if (!nd->nd_repstat) 947132720Skan nfsrv_fillattr(nd, &nva); 948132720Skan 949132720Skanout: 950132720Skan NFSEXITCODE2(0, nd); 951132720Skan return (0); 952132720Skannfsmout: 953132720Skan vput(vp); 95497403Sobrien NFSEXITCODE2(error, nd); 955117397Skan return (error); 95697403Sobrien} 95797403Sobrien 95897403Sobrien/* 959132720Skan * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 960132720Skan * now does a truncate to 0 length via. setattr if it already exists 961132720Skan * The core creation routine has been extracted out into nfsrv_creatsub(), 962132720Skan * so it can also be used by nfsrv_open() for V4. 963132720Skan */ 964132720SkanAPPLESTATIC int 965132720Skannfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 966132720Skan vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 967132720Skan{ 968132720Skan struct nfsvattr nva, dirfor, diraft; 969132720Skan struct nfsv2_sattr *sp; 970132720Skan struct nameidata named; 971117397Skan u_int32_t *tl; 97297403Sobrien int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 97397403Sobrien int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 97497403Sobrien NFSDEV_T rdev = 0; 975132720Skan vnode_t vp = NULL, dirp = NULL; 976132720Skan fhandle_t fh; 977132720Skan char *bufp; 978132720Skan u_long *hashp; 979132720Skan enum vtype vtyp; 980132720Skan int32_t cverf[2], tverf[2] = { 0, 0 }; 981132720Skan 982132720Skan if (nd->nd_repstat) { 983132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 984132720Skan goto out; 985132720Skan } 98697403Sobrien NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 987169691Skan LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 988169691Skan nfsvno_setpathbuf(&named, &bufp, &hashp); 98997403Sobrien error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 99097403Sobrien if (error) 991132720Skan goto nfsmout; 992132720Skan if (!nd->nd_repstat) { 993132720Skan NFSVNO_ATTRINIT(&nva); 994132720Skan if (nd->nd_flag & ND_NFSV2) { 995132720Skan NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 996132720Skan vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 997132720Skan if (vtyp == VNON) 998132720Skan vtyp = VREG; 999132720Skan NFSVNO_SETATTRVAL(&nva, type, vtyp); 1000132720Skan NFSVNO_SETATTRVAL(&nva, mode, 1001132720Skan nfstov_mode(sp->sa_mode)); 1002117397Skan switch (nva.na_type) { 100397403Sobrien case VREG: 1004132720Skan tsize = fxdr_unsigned(int32_t, sp->sa_size); 100597403Sobrien if (tsize != -1) 1006132720Skan NFSVNO_SETATTRVAL(&nva, size, 1007132720Skan (u_quad_t)tsize); 1008132720Skan break; 1009132720Skan case VCHR: 1010132720Skan case VBLK: 1011132720Skan case VFIFO: 1012132720Skan rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 1013132720Skan break; 1014132720Skan default: 1015132720Skan break; 1016132720Skan }; 1017132720Skan } else { 1018132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1019132720Skan how = fxdr_unsigned(int, *tl); 1020132720Skan switch (how) { 1021132720Skan case NFSCREATE_GUARDED: 1022132720Skan case NFSCREATE_UNCHECKED: 1023132720Skan error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1024117397Skan if (error) 102597403Sobrien goto nfsmout; 1026132720Skan break; 1027132720Skan case NFSCREATE_EXCLUSIVE: 1028132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1029132720Skan cverf[0] = *tl++; 103097403Sobrien cverf[1] = *tl; 1031132720Skan exclusive_flag = 1; 1032132720Skan break; 1033132720Skan }; 1034132720Skan NFSVNO_SETATTRVAL(&nva, type, VREG); 1035132720Skan } 1036132720Skan } 1037132720Skan if (nd->nd_repstat) { 1038132720Skan nfsvno_relpathbuf(&named); 1039132720Skan if (nd->nd_flag & ND_NFSV3) { 1040132720Skan dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 1041132720Skan p, 1); 1042132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1043132720Skan &diraft); 1044132720Skan } 1045132720Skan vput(dp); 1046132720Skan goto out; 1047117397Skan } 1048117397Skan 104997403Sobrien nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1050132720Skan if (dirp) { 1051132720Skan if (nd->nd_flag & ND_NFSV2) { 1052132720Skan vrele(dirp); 1053132720Skan dirp = NULL; 1054132720Skan } else { 1055132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1056132720Skan p, 0); 1057132720Skan } 1058132720Skan } 1059132720Skan if (nd->nd_repstat) { 1060132720Skan if (nd->nd_flag & ND_NFSV3) 1061132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1062132720Skan &diraft); 1063132720Skan if (dirp) 1064132720Skan vrele(dirp); 1065117397Skan goto out; 106697403Sobrien } 1067132720Skan 1068132720Skan if (!(nd->nd_flag & ND_NFSV2)) { 1069132720Skan switch (how) { 1070132720Skan case NFSCREATE_GUARDED: 107197403Sobrien if (named.ni_vp) 1072132720Skan nd->nd_repstat = EEXIST; 1073132720Skan break; 1074132720Skan case NFSCREATE_UNCHECKED: 1075132720Skan break; 1076132720Skan case NFSCREATE_EXCLUSIVE: 1077132720Skan if (named.ni_vp == NULL) 1078132720Skan NFSVNO_SETATTRVAL(&nva, mode, 0); 1079132720Skan break; 1080132720Skan }; 1081132720Skan } 1082132720Skan 1083132720Skan /* 1084132720Skan * Iff doesn't exist, create it 1085132720Skan * otherwise just truncate to 0 length 1086132720Skan * should I set the mode too ? 1087132720Skan */ 1088117397Skan nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 108997403Sobrien &exclusive_flag, cverf, rdev, p, exp); 1090132720Skan 1091132720Skan if (!nd->nd_repstat) { 109297403Sobrien nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 1093132720Skan if (!nd->nd_repstat) 1094132720Skan nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1095132720Skan p, 1); 1096132720Skan vput(vp); 1097132720Skan if (!nd->nd_repstat) { 1098132720Skan tverf[0] = nva.na_atime.tv_sec; 1099132720Skan tverf[1] = nva.na_atime.tv_nsec; 1100132720Skan } 1101132720Skan } 1102132720Skan if (nd->nd_flag & ND_NFSV2) { 1103132720Skan if (!nd->nd_repstat) { 1104132720Skan (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 1105117397Skan nfsrv_fillattr(nd, &nva); 1106132720Skan } 110797403Sobrien } else { 1108132720Skan if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1109132720Skan || cverf[1] != tverf[1])) 1110132720Skan nd->nd_repstat = EEXIST; 1111117397Skan diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1112169691Skan vrele(dirp); 111397403Sobrien if (!nd->nd_repstat) { 111497403Sobrien (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 1115132720Skan nfsrv_postopattr(nd, 0, &nva); 1116132720Skan } 1117132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1118132720Skan } 1119132720Skan 1120132720Skanout: 1121132720Skan NFSEXITCODE2(0, nd); 1122132720Skan return (0); 1123132720Skannfsmout: 1124132720Skan vput(dp); 1125132720Skan nfsvno_relpathbuf(&named); 1126132720Skan NFSEXITCODE2(error, nd); 1127132720Skan return (error); 1128132720Skan} 1129117397Skan 113097403Sobrien/* 1131169691Skan * nfs v3 mknod service (and v4 create) 1132169691Skan */ 1133169691SkanAPPLESTATIC int 1134169691Skannfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1135169691Skan vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 113697403Sobrien struct nfsexstuff *exp) 1137132720Skan{ 1138132720Skan struct nfsvattr nva, dirfor, diraft; 1139132720Skan u_int32_t *tl; 1140132720Skan struct nameidata named; 1141132720Skan int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1142132720Skan u_int32_t major, minor; 1143132720Skan enum vtype vtyp = VNON; 1144132720Skan nfstype nfs4type = NFNON; 1145117397Skan vnode_t vp, dirp = NULL; 114697403Sobrien nfsattrbit_t attrbits; 114797403Sobrien char *bufp = NULL, *pathcp = NULL; 1148132720Skan u_long *hashp, cnflags; 1149132720Skan NFSACL_T *aclp = NULL; 1150132720Skan 1151169691Skan NFSVNO_ATTRINIT(&nva); 1152117397Skan cnflags = (LOCKPARENT | SAVESTART); 1153169691Skan if (nd->nd_repstat) { 115497403Sobrien nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 115597403Sobrien goto out; 1156132720Skan } 1157132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1158132720Skan aclp = acl_alloc(M_WAITOK); 1159132720Skan aclp->acl_cnt = 0; 1160132720Skan#endif 1161132720Skan 1162132720Skan /* 1163132720Skan * For V4, the creation stuff is here, Yuck! 1164132720Skan */ 1165117397Skan if (nd->nd_flag & ND_NFSV4) { 116697403Sobrien NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 116797403Sobrien vtyp = nfsv34tov_type(*tl); 1168132720Skan nfs4type = fxdr_unsigned(nfstype, *tl); 1169132720Skan switch (nfs4type) { 1170132720Skan case NFLNK: 1171169691Skan error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 117297403Sobrien &pathlen); 1173169691Skan if (error) 117497403Sobrien goto nfsmout; 117597403Sobrien break; 1176132720Skan case NFCHR: 1177132720Skan case NFBLK: 1178132720Skan NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1179132720Skan major = fxdr_unsigned(u_int32_t, *tl++); 1180132720Skan minor = fxdr_unsigned(u_int32_t, *tl); 1181132720Skan nva.na_rdev = NFSMAKEDEV(major, minor); 1182132720Skan break; 1183132720Skan case NFSOCK: 1184132720Skan case NFFIFO: 1185132720Skan break; 1186132720Skan case NFDIR: 1187132720Skan cnflags = (LOCKPARENT | SAVENAME); 1188132720Skan break; 1189132720Skan default: 1190132720Skan nd->nd_repstat = NFSERR_BADTYPE; 1191132720Skan vrele(dp); 1192117397Skan#ifdef NFS4_ACL_EXTATTR_NAME 119397403Sobrien acl_free(aclp); 119497403Sobrien#endif 119597403Sobrien goto out; 1196132720Skan } 1197132720Skan } 1198132720Skan NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 1199132720Skan nfsvno_setpathbuf(&named, &bufp, &hashp); 1200132720Skan error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1201132720Skan if (error) 1202132720Skan goto nfsmout; 1203132720Skan if (!nd->nd_repstat) { 1204132720Skan if (nd->nd_flag & ND_NFSV3) { 1205132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1206132720Skan vtyp = nfsv34tov_type(*tl); 1207132720Skan } 1208132720Skan error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 1209132720Skan if (error) 1210132720Skan goto nfsmout; 1211132720Skan nva.na_type = vtyp; 1212132720Skan if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1213132720Skan (vtyp == VCHR || vtyp == VBLK)) { 1214117397Skan NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 121597403Sobrien major = fxdr_unsigned(u_int32_t, *tl++); 1216132720Skan minor = fxdr_unsigned(u_int32_t, *tl); 1217132720Skan nva.na_rdev = NFSMAKEDEV(major, minor); 1218132720Skan } 1219132720Skan } 122097403Sobrien 1221132720Skan dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 1222132720Skan if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 1223132720Skan if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 1224132720Skan dirfor.na_gid == nva.na_gid) 1225169691Skan NFSVNO_UNSET(&nva, gid); 1226169691Skan nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 1227132720Skan } 1228132720Skan if (nd->nd_repstat) { 1229132720Skan vrele(dp); 1230132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1231132720Skan acl_free(aclp); 1232169691Skan#endif 1233169691Skan nfsvno_relpathbuf(&named); 1234132720Skan if (pathcp) 1235132720Skan FREE(pathcp, M_TEMP); 1236132720Skan if (nd->nd_flag & ND_NFSV3) 1237132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1238117397Skan &diraft); 123997403Sobrien goto out; 1240117397Skan } 124197403Sobrien 1242132720Skan /* 1243132720Skan * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 1244132720Skan * in va_mode, so we'll have to set a default here. 1245132720Skan */ 1246169691Skan if (NFSVNO_NOTSETMODE(&nva)) { 1247132720Skan if (vtyp == VLNK) 1248132720Skan nva.na_mode = 0755; 1249132720Skan else 1250132720Skan nva.na_mode = 0400; 1251132720Skan } 1252169691Skan 1253132720Skan if (vtyp == VDIR) 1254132720Skan named.ni_cnd.cn_flags |= WILLBEDIR; 1255132720Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1256132720Skan if (nd->nd_repstat) { 1257117397Skan if (dirp) { 125897403Sobrien if (nd->nd_flag & ND_NFSV3) 1259132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1260132720Skan nd->nd_cred, p, 0); 1261132720Skan vrele(dirp); 1262132720Skan } 126397403Sobrien#ifdef NFS4_ACL_EXTATTR_NAME 1264132720Skan acl_free(aclp); 1265132720Skan#endif 1266132720Skan if (nd->nd_flag & ND_NFSV3) 1267132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1268132720Skan &diraft); 1269132720Skan goto out; 1270132720Skan } 1271132720Skan if (dirp) 1272132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1273132720Skan 1274132720Skan if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 1275132720Skan if (vtyp == VDIR) { 1276132720Skan nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 1277132720Skan &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 1278132720Skan exp); 1279132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1280117397Skan acl_free(aclp); 128197403Sobrien#endif 1282132720Skan goto out; 1283132720Skan } else if (vtyp == VLNK) { 128497403Sobrien nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1285132720Skan &dirfor, &diraft, &diraft_ret, &attrbits, 1286132720Skan aclp, p, exp, pathcp, pathlen); 1287132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1288132720Skan acl_free(aclp); 1289132720Skan#endif 1290132720Skan FREE(pathcp, M_TEMP); 1291132720Skan goto out; 1292132720Skan } 1293132720Skan } 1294132720Skan 1295132720Skan nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 1296132720Skan if (!nd->nd_repstat) { 1297132720Skan vp = named.ni_vp; 1298117397Skan nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 129997403Sobrien nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 130097403Sobrien if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 130197403Sobrien nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1302132720Skan p, 1); 1303132720Skan if (vpp != NULL && nd->nd_repstat == 0) { 1304132720Skan NFSVOPUNLOCK(vp, 0); 1305132720Skan *vpp = vp; 1306132720Skan } else 1307132720Skan vput(vp); 1308132720Skan } 1309132720Skan 1310132720Skan diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1311132720Skan vrele(dirp); 1312132720Skan if (!nd->nd_repstat) { 1313132720Skan if (nd->nd_flag & ND_NFSV3) { 1314132720Skan (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1315132720Skan nfsrv_postopattr(nd, 0, &nva); 1316117397Skan } else { 1317132720Skan NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1318132720Skan *tl++ = newnfs_false; 1319132720Skan txdr_hyper(dirfor.na_filerev, tl); 1320132720Skan tl += 2; 1321132720Skan txdr_hyper(diraft.na_filerev, tl); 1322132720Skan (void) nfsrv_putattrbit(nd, &attrbits); 132397403Sobrien } 1324132720Skan } 1325132720Skan if (nd->nd_flag & ND_NFSV3) 1326132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1327132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1328132720Skan acl_free(aclp); 1329132720Skan#endif 1330132720Skan 1331132720Skanout: 1332132720Skan NFSEXITCODE2(0, nd); 1333132720Skan return (0); 1334132720Skannfsmout: 1335132720Skan vrele(dp); 1336132720Skan#ifdef NFS4_ACL_EXTATTR_NAME 1337117397Skan acl_free(aclp); 133897403Sobrien#endif 1339132720Skan if (bufp) 1340132720Skan nfsvno_relpathbuf(&named); 1341132720Skan if (pathcp) 1342132720Skan FREE(pathcp, M_TEMP); 134397403Sobrien 1344132720Skan NFSEXITCODE2(error, nd); 1345132720Skan return (error); 1346132720Skan} 1347132720Skan 1348132720Skan/* 1349132720Skan * nfs remove service 1350132720Skan */ 1351132720SkanAPPLESTATIC int 1352132720Skannfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1353132720Skan vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 1354132720Skan{ 1355132720Skan struct nameidata named; 1356132720Skan u_int32_t *tl; 1357132720Skan int error = 0, dirfor_ret = 1, diraft_ret = 1; 1358117397Skan vnode_t dirp = NULL; 1359132720Skan struct nfsvattr dirfor, diraft; 1360132720Skan char *bufp; 1361132720Skan u_long *hashp; 1362132720Skan 1363132720Skan if (nd->nd_repstat) { 1364132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 136597403Sobrien goto out; 1366132720Skan } 1367132720Skan NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 1368132720Skan LOCKPARENT | LOCKLEAF); 1369132720Skan nfsvno_setpathbuf(&named, &bufp, &hashp); 1370132720Skan error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1371132720Skan if (error) { 1372132720Skan vput(dp); 1373132720Skan nfsvno_relpathbuf(&named); 1374132720Skan goto out; 1375132720Skan } 1376132720Skan if (!nd->nd_repstat) { 1377132720Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1378132720Skan } else { 1379132720Skan vput(dp); 138097403Sobrien nfsvno_relpathbuf(&named); 1381117397Skan } 138297403Sobrien if (dirp) { 138397403Sobrien if (!(nd->nd_flag & ND_NFSV2)) { 1384132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1385132720Skan nd->nd_cred, p, 0); 1386132720Skan } else { 1387132720Skan vrele(dirp); 1388169691Skan dirp = NULL; 1389132720Skan } 1390132720Skan } 139197403Sobrien if (!nd->nd_repstat) { 1392102782Skan if (nd->nd_flag & ND_NFSV4) { 1393102782Skan if (vnode_vtype(named.ni_vp) == VDIR) 1394117397Skan nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 1395169691Skan nd->nd_cred, p, exp); 1396169691Skan else 1397169691Skan nd->nd_repstat = nfsvno_removesub(&named, 1, 1398169691Skan nd->nd_cred, p, exp); 1399169691Skan } else if (nd->nd_procnum == NFSPROC_RMDIR) { 1400169691Skan nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 1401169691Skan nd->nd_cred, p, exp); 1402169691Skan } else { 1403102782Skan nd->nd_repstat = nfsvno_removesub(&named, 0, 1404117397Skan nd->nd_cred, p, exp); 1405169691Skan } 1406169691Skan } 1407169691Skan if (!(nd->nd_flag & ND_NFSV2)) { 1408169691Skan if (dirp) { 1409169691Skan diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 1410169691Skan p, 0); 1411169691Skan vrele(dirp); 1412169691Skan } 1413169691Skan if (nd->nd_flag & ND_NFSV3) { 1414102782Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1415117397Skan &diraft); 1416169691Skan } else if (!nd->nd_repstat) { 1417169691Skan NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1418169691Skan *tl++ = newnfs_false; 1419169691Skan txdr_hyper(dirfor.na_filerev, tl); 1420169691Skan tl += 2; 1421169691Skan txdr_hyper(diraft.na_filerev, tl); 1422169691Skan } 1423169691Skan } 1424102782Skan 1425117397Skanout: 1426169691Skan NFSEXITCODE2(error, nd); 1427169691Skan return (error); 1428169691Skan} 1429169691Skan 1430169691Skan/* 1431169691Skan * nfs rename service 1432169691Skan */ 1433169691SkanAPPLESTATIC int 1434169691Skannfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1435169691Skan vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 143697403Sobrien struct nfsexstuff *toexp) 1437132720Skan{ 1438132720Skan u_int32_t *tl; 1439132720Skan int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 1440132720Skan int tdirfor_ret = 1, tdiraft_ret = 1; 1441132720Skan struct nameidata fromnd, tond; 1442132720Skan vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 144397403Sobrien struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 1444132720Skan struct nfsexstuff tnes; 1445132720Skan struct nfsrvfh tfh; 1446132720Skan char *bufp, *tbufp = NULL; 144797403Sobrien u_long *hashp; 1448132720Skan fhandle_t fh; 1449132720Skan 1450169691Skan if (nd->nd_repstat) { 145197403Sobrien nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1452132720Skan nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1453132720Skan goto out; 1454169691Skan } 1455132720Skan if (!(nd->nd_flag & ND_NFSV2)) 145697403Sobrien fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1); 145797403Sobrien tond.ni_cnd.cn_nameiop = 0; 1458132720Skan tond.ni_startdir = NULL; 145997403Sobrien NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 1460132720Skan nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 1461132720Skan error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 146297403Sobrien if (error) { 1463132720Skan vput(dp); 146497403Sobrien if (todp) 146597403Sobrien vrele(todp); 1466117397Skan nfsvno_relpathbuf(&fromnd); 1467132720Skan goto out; 146897403Sobrien } 1469132720Skan /* 1470132720Skan * Unlock dp in this code section, so it is unlocked before 1471132720Skan * tdp gets locked. This avoids a potential LOR if tdp is the 1472132720Skan * parent directory of dp. 1473117397Skan */ 1474132720Skan if (nd->nd_flag & ND_NFSV4) { 147597403Sobrien tdp = todp; 1476132720Skan tnes = *toexp; 147797403Sobrien if (dp != tdp) { 1478169691Skan NFSVOPUNLOCK(dp, 0); 147997403Sobrien tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 148097403Sobrien p, 0); /* Might lock tdp. */ 148197403Sobrien } else { 148297403Sobrien tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1483132720Skan p, 1); 148497403Sobrien NFSVOPUNLOCK(dp, 0); 1485132720Skan } 148697403Sobrien } else { 1487117397Skan tfh.nfsrvfh_len = 0; 148897403Sobrien error = nfsrv_mtofh(nd, &tfh); 148997403Sobrien if (error == 0) 1490132720Skan error = nfsvno_getfh(dp, &fh, p); 149197403Sobrien if (error) { 1492132720Skan vput(dp); 149397403Sobrien /* todp is always NULL except NFSv4 */ 149497403Sobrien nfsvno_relpathbuf(&fromnd); 1495117397Skan goto out; 149697403Sobrien } 149797403Sobrien 149897403Sobrien /* If this is the same file handle, just VREF() the vnode. */ 149997403Sobrien if (tfh.nfsrvfh_len == NFSX_MYFH && 1500132720Skan !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 1501132720Skan VREF(dp); 1502132720Skan tdp = dp; 1503132720Skan tnes = *exp; 1504132720Skan tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1505132720Skan p, 1); 1506132720Skan NFSVOPUNLOCK(dp, 0); 1507132720Skan } else { 1508132720Skan NFSVOPUNLOCK(dp, 0); 1509132720Skan nd->nd_cred->cr_uid = nd->nd_saveduid; 1510132720Skan nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 1511117397Skan 0, p); /* Locks tdp. */ 151297403Sobrien if (tdp) { 151397403Sobrien tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, 1514132720Skan nd->nd_cred, p, 1); 1515132720Skan NFSVOPUNLOCK(tdp, 0); 1516132720Skan } 1517132720Skan } 1518132720Skan } 1519132720Skan NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 1520132720Skan nfsvno_setpathbuf(&tond, &tbufp, &hashp); 1521117397Skan if (!nd->nd_repstat) { 1522132720Skan error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 152397403Sobrien if (error) { 152497403Sobrien if (tdp) 1525132720Skan vrele(tdp); 1526132720Skan vrele(dp); 1527132720Skan nfsvno_relpathbuf(&fromnd); 1528132720Skan nfsvno_relpathbuf(&tond); 1529132720Skan goto out; 1530132720Skan } 1531117397Skan } 1532169691Skan if (nd->nd_repstat) { 1533169691Skan if (nd->nd_flag & ND_NFSV3) { 153497403Sobrien nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1535132720Skan &fdiraft); 1536132720Skan nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1537132720Skan &tdiraft); 1538132720Skan } 1539132720Skan if (tdp) 1540132720Skan vrele(tdp); 1541117397Skan vrele(dp); 1542169691Skan nfsvno_relpathbuf(&fromnd); 1543169691Skan nfsvno_relpathbuf(&tond); 154497403Sobrien goto out; 1545132720Skan } 1546132720Skan 1547132720Skan /* 1548117397Skan * Done parsing, now down to business. 1549169691Skan */ 1550169691Skan nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 155197403Sobrien if (nd->nd_repstat) { 1552132720Skan if (nd->nd_flag & ND_NFSV3) { 1553132720Skan nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1554132720Skan &fdiraft); 1555132720Skan nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1556132720Skan &tdiraft); 1557132720Skan } 1558132720Skan if (fdirp) 1559132720Skan vrele(fdirp); 1560132720Skan if (tdp) 1561132720Skan vrele(tdp); 1562132720Skan nfsvno_relpathbuf(&tond); 1563117397Skan goto out; 156497403Sobrien } 156597403Sobrien if (vnode_vtype(fromnd.ni_vp) == VDIR) 1566132720Skan tond.ni_cnd.cn_flags |= WILLBEDIR; 1567132720Skan nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 1568132720Skan nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 1569132720Skan nd->nd_flag, nd->nd_cred, p); 1570132720Skan if (fdirp) 1571132720Skan fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p, 1572132720Skan 0); 1573132720Skan if (tdirp) 1574132720Skan tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p, 1575132720Skan 0); 1576117397Skan if (fdirp) 157797403Sobrien vrele(fdirp); 157897403Sobrien if (tdirp) 157997403Sobrien vrele(tdirp); 1580132720Skan if (nd->nd_flag & ND_NFSV3) { 1581132720Skan nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1582132720Skan nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1583132720Skan } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1584132720Skan NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1585132720Skan *tl++ = newnfs_false; 1586132720Skan txdr_hyper(fdirfor.na_filerev, tl); 1587132720Skan tl += 2; 1588132720Skan txdr_hyper(fdiraft.na_filerev, tl); 1589132720Skan tl += 2; 1590117397Skan *tl++ = newnfs_false; 159197403Sobrien txdr_hyper(tdirfor.na_filerev, tl); 1592132720Skan tl += 2; 1593132720Skan txdr_hyper(tdiraft.na_filerev, tl); 1594132720Skan } 1595132720Skan 159697403Sobrienout: 1597132720Skan NFSEXITCODE2(error, nd); 1598132720Skan return (error); 1599132720Skan} 1600132720Skan 1601132720Skan/* 1602132720Skan * nfs link service 1603132720Skan */ 1604132720SkanAPPLESTATIC int 1605132720Skannfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1606132720Skan vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 1607117397Skan struct nfsexstuff *toexp) 160897403Sobrien{ 160997403Sobrien struct nameidata named; 1610132720Skan u_int32_t *tl; 1611132720Skan int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 1612132720Skan vnode_t dirp = NULL, dp = NULL; 1613132720Skan struct nfsvattr dirfor, diraft, at; 1614132720Skan struct nfsexstuff tnes; 1615132720Skan struct nfsrvfh dfh; 1616132720Skan char *bufp; 1617132720Skan u_long *hashp; 1618132720Skan 1619132720Skan if (nd->nd_repstat) { 1620117397Skan nfsrv_postopattr(nd, getret, &at); 162197403Sobrien nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 162297403Sobrien goto out; 162397403Sobrien } 1624132720Skan NFSVOPUNLOCK(vp, 0); 1625132720Skan if (vnode_vtype(vp) == VDIR) { 1626132720Skan if (nd->nd_flag & ND_NFSV4) 1627132720Skan nd->nd_repstat = NFSERR_ISDIR; 1628132720Skan else 1629132720Skan nd->nd_repstat = NFSERR_INVAL; 1630132720Skan if (tovp) 1631132720Skan vrele(tovp); 1632132720Skan } 1633132720Skan if (!nd->nd_repstat) { 1634132720Skan if (nd->nd_flag & ND_NFSV4) { 1635117397Skan dp = tovp; 163697403Sobrien tnes = *toexp; 163797403Sobrien } else { 1638132720Skan error = nfsrv_mtofh(nd, &dfh); 1639132720Skan if (error) { 1640132720Skan vrele(vp); 1641169691Skan /* tovp is always NULL unless NFSv4 */ 1642132720Skan goto out; 1643132720Skan } 1644132720Skan nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 1645132720Skan p); 1646132720Skan if (dp) 1647132720Skan NFSVOPUNLOCK(dp, 0); 1648117397Skan } 164997403Sobrien } 1650132720Skan NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1651132720Skan LOCKPARENT | SAVENAME | NOCACHE); 1652132720Skan if (!nd->nd_repstat) { 1653132720Skan nfsvno_setpathbuf(&named, &bufp, &hashp); 165497403Sobrien error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1655132720Skan if (error) { 1656132720Skan vrele(vp); 1657132720Skan if (dp) 1658169691Skan vrele(dp); 1659132720Skan nfsvno_relpathbuf(&named); 1660132720Skan goto out; 1661132720Skan } 1662132720Skan if (!nd->nd_repstat) { 1663132720Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1664132720Skan p, &dirp); 1665117397Skan } else { 166697403Sobrien if (dp) 166797403Sobrien vrele(dp); 1668132720Skan nfsvno_relpathbuf(&named); 1669132720Skan } 1670132720Skan } 1671132720Skan if (dirp) { 1672132720Skan if (nd->nd_flag & ND_NFSV2) { 1673132720Skan vrele(dirp); 1674132720Skan dirp = NULL; 1675132720Skan } else { 1676132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1677132720Skan nd->nd_cred, p, 0); 1678117397Skan } 167997403Sobrien } 168097403Sobrien if (!nd->nd_repstat) 168197403Sobrien nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1682132720Skan if (nd->nd_flag & ND_NFSV3) 1683132720Skan getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 1684132720Skan if (dirp) { 1685229551Spfg diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1686132720Skan vrele(dirp); 1687132720Skan } 1688132720Skan vrele(vp); 1689132720Skan if (nd->nd_flag & ND_NFSV3) { 1690132720Skan nfsrv_postopattr(nd, getret, &at); 1691132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1692132720Skan } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1693117397Skan NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 169497403Sobrien *tl++ = newnfs_false; 169597403Sobrien txdr_hyper(dirfor.na_filerev, tl); 1696132720Skan tl += 2; 1697132720Skan txdr_hyper(diraft.na_filerev, tl); 1698132720Skan } 1699132720Skan 1700132720Skanout: 1701132720Skan NFSEXITCODE2(error, nd); 1702132720Skan return (error); 1703132720Skan} 1704132720Skan 1705132720Skan/* 1706117397Skan * nfs symbolic link service 170797403Sobrien */ 1708132720SkanAPPLESTATIC int 1709132720Skannfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1710132720Skan vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1711132720Skan struct nfsexstuff *exp) 171297403Sobrien{ 1713132720Skan struct nfsvattr nva, dirfor, diraft; 1714132720Skan struct nameidata named; 1715132720Skan int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1716132720Skan vnode_t dirp = NULL; 1717132720Skan char *bufp, *pathcp = NULL; 1718132720Skan u_long *hashp; 1719132720Skan 1720132720Skan if (nd->nd_repstat) { 1721132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1722132720Skan goto out; 1723132720Skan } 1724132720Skan if (vpp) 1725117397Skan *vpp = NULL; 172697403Sobrien NFSVNO_ATTRINIT(&nva); 172797403Sobrien NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 172897403Sobrien LOCKPARENT | SAVESTART | NOCACHE); 1729132720Skan nfsvno_setpathbuf(&named, &bufp, &hashp); 1730132720Skan error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1731132720Skan if (!error && !nd->nd_repstat) 1732132720Skan error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1733132720Skan if (error) { 1734132720Skan vrele(dp); 1735132720Skan nfsvno_relpathbuf(&named); 1736132720Skan goto out; 1737132720Skan } 1738132720Skan if (!nd->nd_repstat) { 1739117397Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 174097403Sobrien } else { 174197403Sobrien vrele(dp); 174297403Sobrien nfsvno_relpathbuf(&named); 1743132720Skan } 1744132720Skan if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1745132720Skan vrele(dirp); 1746229551Spfg dirp = NULL; 1747132720Skan } 1748132720Skan 1749132720Skan /* 1750132720Skan * And call nfsrvd_symlinksub() to do the common code. It will 1751132720Skan * return EBADRPC upon a parsing error, 0 otherwise. 1752132720Skan */ 1753132720Skan if (!nd->nd_repstat) { 1754117397Skan if (dirp != NULL) 175597403Sobrien dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 175697403Sobrien p, 0); 1757132720Skan nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1758132720Skan &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1759132720Skan pathcp, pathlen); 1760132720Skan } else if (dirp != NULL) { 1761132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1762132720Skan vrele(dirp); 1763132720Skan } 1764132720Skan if (pathcp) 1765132720Skan FREE(pathcp, M_TEMP); 1766132720Skan 1767117397Skan if (nd->nd_flag & ND_NFSV3) { 176897403Sobrien if (!nd->nd_repstat) { 1769132720Skan (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1770132720Skan nfsrv_postopattr(nd, 0, &nva); 1771132720Skan } 1772132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 177397403Sobrien } 1774132720Skan 1775132720Skanout: 1776132720Skan NFSEXITCODE2(error, nd); 1777229551Spfg return (error); 1778132720Skan} 1779132720Skan 1780132720Skan/* 1781132720Skan * Common code for creating a symbolic link. 1782132720Skan */ 1783132720Skanstatic void 1784132720Skannfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1785132720Skan struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1786117397Skan vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 178797403Sobrien int *diraft_retp, nfsattrbit_t *attrbitp, 178897403Sobrien NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 178997403Sobrien int pathlen) 1790132720Skan{ 1791132720Skan u_int32_t *tl; 1792132720Skan 1793132720Skan nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1794132720Skan !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1795132720Skan if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1796132720Skan nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1797132720Skan if (nd->nd_flag & ND_NFSV3) { 1798132720Skan nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1799132720Skan if (!nd->nd_repstat) 1800117397Skan nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 180197403Sobrien nvap, nd->nd_cred, p, 1); 180297403Sobrien } 180397403Sobrien if (vpp != NULL && nd->nd_repstat == 0) { 1804132720Skan NFSVOPUNLOCK(ndp->ni_vp, 0); 1805132720Skan *vpp = ndp->ni_vp; 1806132720Skan } else 1807229551Spfg vput(ndp->ni_vp); 1808132720Skan } 1809132720Skan if (dirp) { 1810132720Skan *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1811132720Skan vrele(dirp); 1812132720Skan } 1813132720Skan if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1814132720Skan NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1815117397Skan *tl++ = newnfs_false; 1816117397Skan txdr_hyper(dirforp->na_filerev, tl); 181797403Sobrien tl += 2; 181897403Sobrien txdr_hyper(diraftp->na_filerev, tl); 1819132720Skan (void) nfsrv_putattrbit(nd, attrbitp); 1820132720Skan } 1821132720Skan 1822132720Skan NFSEXITCODE2(0, nd); 1823132720Skan} 1824132720Skan 1825132720Skan/* 1826132720Skan * nfs mkdir service 1827132720Skan */ 1828132720SkanAPPLESTATIC int 1829117397Skannfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 183097403Sobrien vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1831132720Skan struct nfsexstuff *exp) 1832132720Skan{ 1833132720Skan struct nfsvattr nva, dirfor, diraft; 1834132720Skan struct nameidata named; 183597403Sobrien u_int32_t *tl; 1836132720Skan int error = 0, dirfor_ret = 1, diraft_ret = 1; 1837132720Skan vnode_t dirp = NULL; 1838132720Skan char *bufp; 1839132720Skan u_long *hashp; 1840132720Skan 1841132720Skan if (nd->nd_repstat) { 1842132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1843132720Skan goto out; 1844132720Skan } 1845132720Skan NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1846117397Skan LOCKPARENT | SAVENAME | NOCACHE); 184797403Sobrien nfsvno_setpathbuf(&named, &bufp, &hashp); 184897403Sobrien error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1849132720Skan if (error) 1850132720Skan goto nfsmout; 1851132720Skan if (!nd->nd_repstat) { 1852229551Spfg NFSVNO_ATTRINIT(&nva); 1853229551Spfg if (nd->nd_flag & ND_NFSV3) { 1854132720Skan error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1855132720Skan if (error) 1856132720Skan goto nfsmout; 1857132720Skan } else { 1858132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1859117397Skan nva.na_mode = nfstov_mode(*tl++); 186097403Sobrien } 186197403Sobrien } 186297403Sobrien if (!nd->nd_repstat) { 1863132720Skan nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1864132720Skan } else { 1865132720Skan vrele(dp); 1866229551Spfg nfsvno_relpathbuf(&named); 1867132720Skan } 1868229551Spfg if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1869132720Skan vrele(dirp); 1870132720Skan dirp = NULL; 1871132720Skan } 1872132720Skan if (nd->nd_repstat) { 1873132720Skan if (dirp != NULL) { 1874132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1875117397Skan p, 0); 1876117397Skan vrele(dirp); 187797403Sobrien } 1878132720Skan if (nd->nd_flag & ND_NFSV3) 1879229551Spfg nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1880132720Skan &diraft); 1881229551Spfg goto out; 1882229551Spfg } 1883132720Skan if (dirp != NULL) 1884132720Skan dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1885132720Skan 1886132720Skan /* 1887132720Skan * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1888117397Skan */ 188997403Sobrien nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1890132720Skan &diraft_ret, NULL, NULL, p, exp); 1891132720Skan 1892132720Skan if (nd->nd_flag & ND_NFSV3) { 1893132720Skan if (!nd->nd_repstat) { 189497403Sobrien (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1895132720Skan nfsrv_postopattr(nd, 0, &nva); 1896132720Skan } 1897132720Skan nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1898229551Spfg } else if (!nd->nd_repstat) { 1899229551Spfg (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1900132720Skan nfsrv_fillattr(nd, &nva); 1901132720Skan } 1902132720Skan 1903132720Skanout: 1904132720Skan NFSEXITCODE2(0, nd); 1905117397Skan return (0); 190697403Sobriennfsmout: 190797403Sobrien vrele(dp); 1908132720Skan nfsvno_relpathbuf(&named); 1909132720Skan NFSEXITCODE2(error, nd); 1910132720Skan return (error); 1911132720Skan} 1912132720Skan 1913132720Skan/* 1914132720Skan * Code common to mkdir for V2,3 and 4. 1915132720Skan */ 1916132720Skanstatic void 1917132720Skannfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1918132720Skan struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1919132720Skan vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1920117397Skan int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 192197403Sobrien NFSPROC_T *p, struct nfsexstuff *exp) 1922132720Skan{ 1923132720Skan vnode_t vp; 192497403Sobrien u_int32_t *tl; 1925132720Skan 1926132720Skan NFSVNO_SETATTRVAL(nvap, type, VDIR); 1927132720Skan nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1928132720Skan nd->nd_cred, p, exp); 1929132720Skan if (!nd->nd_repstat) { 1930132720Skan vp = ndp->ni_vp; 1931132720Skan nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1932146897Skan nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1933146897Skan if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1934146897Skan nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1935146897Skan p, 1); 1936146897Skan if (vpp && !nd->nd_repstat) { 1937132720Skan NFSVOPUNLOCK(vp, 0); 1938117397Skan *vpp = vp; 193997403Sobrien } else { 194097403Sobrien vput(vp); 1941132720Skan } 1942132720Skan } 1943132720Skan if (dirp) { 1944117397Skan *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 194597403Sobrien vrele(dirp); 194697403Sobrien } 1947259705Spfg if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 194897403Sobrien NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 194997403Sobrien *tl++ = newnfs_false; 195097403Sobrien txdr_hyper(dirforp->na_filerev, tl); 1951132720Skan tl += 2; 1952132720Skan txdr_hyper(diraftp->na_filerev, tl); 1953132720Skan (void) nfsrv_putattrbit(nd, attrbitp); 1954132720Skan } 1955132720Skan 1956132720Skan NFSEXITCODE2(0, nd); 1957132720Skan} 1958132720Skan 1959132720Skan/* 1960132720Skan * nfs commit service 1961146897Skan */ 1962146897SkanAPPLESTATIC int 1963146897Skannfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1964146897Skan vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1965146897Skan{ 1966146897Skan struct nfsvattr bfor, aft; 1967132720Skan u_int32_t *tl; 1968117397Skan int error = 0, for_ret = 1, aft_ret = 1, cnt; 196997403Sobrien u_int64_t off; 197097403Sobrien 1971132720Skan if (nd->nd_repstat) { 1972132720Skan nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1973132720Skan goto out; 1974132720Skan } 1975132720Skan NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1976132720Skan /* 1977132720Skan * XXX At this time VOP_FSYNC() does not accept offset and byte 1978132720Skan * count parameters, so these arguments are useless (someday maybe). 1979132720Skan */ 1980132720Skan off = fxdr_hyper(tl); 1981132720Skan tl += 2; 1982132720Skan cnt = fxdr_unsigned(int, *tl); 1983132720Skan if (nd->nd_flag & ND_NFSV3) 1984132720Skan for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 1985146897Skan nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 1986146897Skan if (nd->nd_flag & ND_NFSV3) { 1987146897Skan aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 1988146897Skan nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1989146897Skan } 1990146897Skan vput(vp); 1991132720Skan if (!nd->nd_repstat) { 1992117397Skan NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 199397403Sobrien *tl++ = txdr_unsigned(nfsboottime.tv_sec); 199497403Sobrien *tl = txdr_unsigned(nfsboottime.tv_usec); 199597403Sobrien } 1996132720Skan 1997132720Skanout: 1998132720Skan NFSEXITCODE2(0, nd); 1999132720Skan return (0); 2000132720Skannfsmout: 2001132720Skan vput(vp); 2002132720Skan NFSEXITCODE2(error, nd); 2003146897Skan return (error); 2004146897Skan} 2005146897Skan 2006146897Skan/* 2007146897Skan * nfs statfs service 2008146897Skan */ 2009132720SkanAPPLESTATIC int 2010117397Skannfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 201197403Sobrien vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 201297403Sobrien{ 2013132720Skan struct statfs *sf; 2014117397Skan u_int32_t *tl; 2015132720Skan int getret = 1; 2016132720Skan struct nfsvattr at; 2017132720Skan struct statfs sfs; 2018132720Skan u_quad_t tval; 2019132720Skan 2020132720Skan if (nd->nd_repstat) { 2021132720Skan nfsrv_postopattr(nd, getret, &at); 2022132720Skan goto out; 2023132720Skan } 2024132720Skan sf = &sfs; 2025146897Skan nd->nd_repstat = nfsvno_statfs(vp, sf); 2026146897Skan getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2027146897Skan vput(vp); 2028146897Skan if (nd->nd_flag & ND_NFSV3) 2029146897Skan nfsrv_postopattr(nd, getret, &at); 2030146897Skan if (nd->nd_repstat) 2031146897Skan goto out; 2032132720Skan if (nd->nd_flag & ND_NFSV2) { 2033117397Skan NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 203497403Sobrien *tl++ = txdr_unsigned(NFS_V2MAXDATA); 203597403Sobrien *tl++ = txdr_unsigned(sf->f_bsize); 2036132720Skan *tl++ = txdr_unsigned(sf->f_blocks); 2037132720Skan *tl++ = txdr_unsigned(sf->f_bfree); 2038132720Skan *tl = txdr_unsigned(sf->f_bavail); 2039132720Skan } else { 2040132720Skan NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2041132720Skan tval = (u_quad_t)sf->f_blocks; 2042132720Skan tval *= (u_quad_t)sf->f_bsize; 2043132720Skan txdr_hyper(tval, tl); tl += 2; 2044132720Skan tval = (u_quad_t)sf->f_bfree; 2045132720Skan tval *= (u_quad_t)sf->f_bsize; 2046132720Skan txdr_hyper(tval, tl); tl += 2; 2047132720Skan tval = (u_quad_t)sf->f_bavail; 2048146897Skan tval *= (u_quad_t)sf->f_bsize; 2049146897Skan txdr_hyper(tval, tl); tl += 2; 2050146897Skan tval = (u_quad_t)sf->f_files; 2051146897Skan txdr_hyper(tval, tl); tl += 2; 2052146897Skan tval = (u_quad_t)sf->f_ffree; 2053146897Skan txdr_hyper(tval, tl); tl += 2; 2054132720Skan tval = (u_quad_t)sf->f_ffree; 2055132720Skan txdr_hyper(tval, tl); tl += 2; 2056132720Skan *tl = 0; 2057132720Skan } 2058117397Skan 2059117397Skanout: 206097403Sobrien NFSEXITCODE2(0, nd); 206197403Sobrien return (0); 206297403Sobrien} 206397403Sobrien 206497403Sobrien/* 206597403Sobrien * nfs fsinfo service 2066146897Skan */ 2067132720SkanAPPLESTATIC int 2068146897Skannfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2069146897Skan vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2070146897Skan{ 207197403Sobrien u_int32_t *tl; 207297403Sobrien struct nfsfsinfo fs; 2073132720Skan int getret = 1; 2074132720Skan struct nfsvattr at; 2075132720Skan 2076132720Skan if (nd->nd_repstat) { 2077132720Skan nfsrv_postopattr(nd, getret, &at); 2078132720Skan goto out; 207997403Sobrien } 208097403Sobrien getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 208197403Sobrien nfsvno_getfs(&fs, isdgram); 208297403Sobrien vput(vp); 208397403Sobrien nfsrv_postopattr(nd, getret, &at); 208497403Sobrien NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 208597403Sobrien *tl++ = txdr_unsigned(fs.fs_rtmax); 208697403Sobrien *tl++ = txdr_unsigned(fs.fs_rtpref); 208797403Sobrien *tl++ = txdr_unsigned(fs.fs_rtmult); 208897403Sobrien *tl++ = txdr_unsigned(fs.fs_wtmax); 2089132720Skan *tl++ = txdr_unsigned(fs.fs_wtpref); 2090132720Skan *tl++ = txdr_unsigned(fs.fs_wtmult); 2091132720Skan *tl++ = txdr_unsigned(fs.fs_dtpref); 2092132720Skan txdr_hyper(fs.fs_maxfilesize, tl); 2093132720Skan tl += 2; 2094132720Skan txdr_nfsv3time(&fs.fs_timedelta, tl); 209597403Sobrien tl += 2; 209697403Sobrien *tl = txdr_unsigned(fs.fs_properties); 209797403Sobrien 209897403Sobrienout: 209997403Sobrien NFSEXITCODE2(0, nd); 2100132720Skan return (0); 2101132720Skan} 2102132720Skan 2103132720Skan/* 2104132720Skan * nfs pathconf service 2105132720Skan */ 210697403SobrienAPPLESTATIC int 210797403Sobriennfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 210897403Sobrien vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 210997403Sobrien{ 2110132720Skan struct nfsv3_pathconf *pc; 2111132720Skan int getret = 1; 2112132720Skan register_t linkmax, namemax, chownres, notrunc; 2113132720Skan struct nfsvattr at; 2114132720Skan 2115132720Skan if (nd->nd_repstat) { 211697403Sobrien nfsrv_postopattr(nd, getret, &at); 211797403Sobrien goto out; 211897403Sobrien } 211997403Sobrien nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 212097403Sobrien nd->nd_cred, p); 212197403Sobrien if (!nd->nd_repstat) 212297403Sobrien nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 212397403Sobrien nd->nd_cred, p); 212497403Sobrien if (!nd->nd_repstat) 212597403Sobrien nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2126132720Skan &chownres, nd->nd_cred, p); 2127132720Skan if (!nd->nd_repstat) 2128132720Skan nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2129132720Skan nd->nd_cred, p); 2130132720Skan getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2131132720Skan vput(vp); 213297403Sobrien nfsrv_postopattr(nd, getret, &at); 213397403Sobrien if (!nd->nd_repstat) { 213497403Sobrien NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 213597403Sobrien pc->pc_linkmax = txdr_unsigned(linkmax); 2136132720Skan pc->pc_namemax = txdr_unsigned(namemax); 213797403Sobrien pc->pc_notrunc = txdr_unsigned(notrunc); 213897403Sobrien pc->pc_chownrestricted = txdr_unsigned(chownres); 213997403Sobrien 214097403Sobrien /* 214197403Sobrien * These should probably be supported by VOP_PATHCONF(), but 214297403Sobrien * until msdosfs is exportable (why would you want to?), the 214397403Sobrien * Unix defaults should be ok. 2144132720Skan */ 2145132720Skan pc->pc_caseinsensitive = newnfs_false; 2146132720Skan pc->pc_casepreserving = newnfs_true; 2147132720Skan } 2148132720Skan 2149132720Skanout: 215097403Sobrien NFSEXITCODE2(0, nd); 215197403Sobrien return (0); 215297403Sobrien} 215397403Sobrien 215497403Sobrien/* 215597403Sobrien * nfsv4 lock service 2156132720Skan */ 2157132720SkanAPPLESTATIC int 2158132720Skannfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2159132720Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2160132720Skan{ 2161132720Skan u_int32_t *tl; 216297403Sobrien int i; 216397403Sobrien struct nfsstate *stp = NULL; 216497403Sobrien struct nfslock *lop; 216597403Sobrien struct nfslockconflict cf; 216697403Sobrien int error = 0; 216797403Sobrien u_short flags = NFSLCK_LOCK, lflags; 2168132720Skan u_int64_t offset, len; 2169132720Skan nfsv4stateid_t stateid; 2170132720Skan nfsquad_t clientid; 2171132720Skan 2172132720Skan NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2173132720Skan i = fxdr_unsigned(int, *tl++); 217497403Sobrien switch (i) { 217597403Sobrien case NFSV4LOCKT_READW: 217697403Sobrien flags |= NFSLCK_BLOCKING; 217797403Sobrien case NFSV4LOCKT_READ: 217897403Sobrien lflags = NFSLCK_READ; 217997403Sobrien break; 218097403Sobrien case NFSV4LOCKT_WRITEW: 2181132720Skan flags |= NFSLCK_BLOCKING; 2182132720Skan case NFSV4LOCKT_WRITE: 2183132720Skan lflags = NFSLCK_WRITE; 2184132720Skan break; 2185132720Skan default: 2186132720Skan nd->nd_repstat = NFSERR_BADXDR; 218797403Sobrien goto nfsmout; 218897403Sobrien }; 218997403Sobrien if (*tl++ == newnfs_true) 219097403Sobrien flags |= NFSLCK_RECLAIM; 219197403Sobrien offset = fxdr_hyper(tl); 219297403Sobrien tl += 2; 2193132720Skan len = fxdr_hyper(tl); 2194132720Skan tl += 2; 2195132720Skan if (*tl == newnfs_true) 2196132720Skan flags |= NFSLCK_OPENTOLOCK; 2197132720Skan if (flags & NFSLCK_OPENTOLOCK) { 2198132720Skan NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 219997403Sobrien i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 220097403Sobrien if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 220197403Sobrien nd->nd_repstat = NFSERR_BADXDR; 220297403Sobrien goto nfsmout; 220397403Sobrien } 220497403Sobrien MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2205132720Skan M_NFSDSTATE, M_WAITOK); 2206132720Skan stp->ls_ownerlen = i; 2207132720Skan stp->ls_op = nd->nd_rp; 2208132720Skan stp->ls_seq = fxdr_unsigned(int, *tl++); 2209132720Skan stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2210132720Skan NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 221197403Sobrien NFSX_STATEIDOTHER); 221297403Sobrien tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 221397403Sobrien stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 221497403Sobrien clientid.lval[0] = *tl++; 221597403Sobrien clientid.lval[1] = *tl++; 221697403Sobrien if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 221797403Sobrien if ((nd->nd_flag & ND_NFSV41) != 0) 2218132720Skan clientid.qval = nd->nd_clientid.qval; 2219132720Skan else if (nd->nd_clientid.qval != clientid.qval) 2220132720Skan printf("EEK3 multiple clids\n"); 2221132720Skan } else { 2222132720Skan if ((nd->nd_flag & ND_NFSV41) != 0) 2223132720Skan printf("EEK! no clientid from session\n"); 222497403Sobrien nd->nd_flag |= ND_IMPLIEDCLID; 222597403Sobrien nd->nd_clientid.qval = clientid.qval; 222697403Sobrien } 222797403Sobrien error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 222897403Sobrien if (error) 222997403Sobrien goto nfsmout; 2230132720Skan } else { 2231132720Skan NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2232132720Skan MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2233132720Skan M_NFSDSTATE, M_WAITOK); 2234132720Skan stp->ls_ownerlen = 0; 2235132720Skan stp->ls_op = nd->nd_rp; 223697403Sobrien stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 223797403Sobrien NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 223897403Sobrien NFSX_STATEIDOTHER); 223997403Sobrien tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 224097403Sobrien stp->ls_seq = fxdr_unsigned(int, *tl); 224197403Sobrien clientid.lval[0] = stp->ls_stateid.other[0]; 2242132720Skan clientid.lval[1] = stp->ls_stateid.other[1]; 2243132720Skan if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2244132720Skan if ((nd->nd_flag & ND_NFSV41) != 0) 2245132720Skan clientid.qval = nd->nd_clientid.qval; 2246132720Skan else if (nd->nd_clientid.qval != clientid.qval) 2247132720Skan printf("EEK4 multiple clids\n"); 224897403Sobrien } else { 224997403Sobrien if ((nd->nd_flag & ND_NFSV41) != 0) 225097403Sobrien printf("EEK! no clientid from session\n"); 225197403Sobrien nd->nd_flag |= ND_IMPLIEDCLID; 225297403Sobrien nd->nd_clientid.qval = clientid.qval; 225397403Sobrien } 225497403Sobrien } 2255132720Skan MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2256132720Skan M_NFSDLOCK, M_WAITOK); 2257132720Skan lop->lo_first = offset; 2258132720Skan if (len == NFS64BITSSET) { 2259132720Skan lop->lo_end = NFS64BITSSET; 2260132720Skan } else { 226197403Sobrien lop->lo_end = offset + len; 226297403Sobrien if (lop->lo_end <= lop->lo_first) 226397403Sobrien nd->nd_repstat = NFSERR_INVAL; 226497403Sobrien } 226597403Sobrien lop->lo_flags = lflags; 226697403Sobrien stp->ls_flags = flags; 2267132720Skan stp->ls_uid = nd->nd_cred->cr_uid; 2268132720Skan 2269132720Skan /* 2270132720Skan * Do basic access checking. 2271132720Skan */ 2272132720Skan if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 227397403Sobrien if (vnode_vtype(vp) == VDIR) 227497403Sobrien nd->nd_repstat = NFSERR_ISDIR; 227597403Sobrien else 227697403Sobrien nd->nd_repstat = NFSERR_INVAL; 227797403Sobrien } 227897403Sobrien if (!nd->nd_repstat) { 2279132720Skan if (lflags & NFSLCK_WRITE) { 2280132720Skan nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2281132720Skan nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2282132720Skan NFSACCCHK_VPISLOCKED, NULL); 2283132720Skan } else { 2284132720Skan nd->nd_repstat = nfsvno_accchk(vp, VREAD, 228597403Sobrien nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 228697403Sobrien NFSACCCHK_VPISLOCKED, NULL); 228797403Sobrien if (nd->nd_repstat) 228897403Sobrien nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 228997403Sobrien nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 229097403Sobrien NFSACCCHK_VPISLOCKED, NULL); 229197403Sobrien } 2292132720Skan } 2293132720Skan 2294132720Skan /* 2295132720Skan * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2296132720Skan * seqid# gets updated. nfsrv_lockctrl() will return the value 2297132720Skan * of nd_repstat, if it gets that far. 229897403Sobrien */ 229997403Sobrien nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 230097403Sobrien &stateid, exp, nd, p); 230197403Sobrien if (lop) 230297403Sobrien FREE((caddr_t)lop, M_NFSDLOCK); 230397403Sobrien if (stp) 2304132720Skan FREE((caddr_t)stp, M_NFSDSTATE); 2305132720Skan if (!nd->nd_repstat) { 2306132720Skan NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2307132720Skan *tl++ = txdr_unsigned(stateid.seqid); 2308132720Skan NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2309132720Skan } else if (nd->nd_repstat == NFSERR_DENIED) { 231097403Sobrien NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 231197403Sobrien txdr_hyper(cf.cl_first, tl); 231297403Sobrien tl += 2; 231397403Sobrien if (cf.cl_end == NFS64BITSSET) 231497403Sobrien len = NFS64BITSSET; 231597403Sobrien else 2316132720Skan len = cf.cl_end - cf.cl_first; 2317132720Skan txdr_hyper(len, tl); 2318132720Skan tl += 2; 2319132720Skan if (cf.cl_flags == NFSLCK_WRITE) 2320132720Skan *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2321132720Skan else 232297403Sobrien *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 232397403Sobrien *tl++ = stateid.other[0]; 232497403Sobrien *tl = stateid.other[1]; 232597403Sobrien (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2326169691Skan } 232797403Sobrien vput(vp); 232897403Sobrien NFSEXITCODE2(0, nd); 2329132720Skan return (0); 2330132720Skannfsmout: 2331132720Skan vput(vp); 2332132720Skan if (stp) 2333132720Skan free((caddr_t)stp, M_NFSDSTATE); 2334132720Skan NFSEXITCODE2(error, nd); 233597403Sobrien return (error); 233697403Sobrien} 233797403Sobrien 233897403Sobrien/* 233997403Sobrien * nfsv4 lock test service 234097403Sobrien */ 2341132720SkanAPPLESTATIC int 2342132720Skannfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2343132720Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2344132720Skan{ 2345132720Skan u_int32_t *tl; 2346132720Skan int i; 234797403Sobrien struct nfsstate *stp = NULL; 234897403Sobrien struct nfslock lo, *lop = &lo; 234997403Sobrien struct nfslockconflict cf; 235097403Sobrien int error = 0; 235197403Sobrien nfsv4stateid_t stateid; 235297403Sobrien nfsquad_t clientid; 2353132720Skan u_int64_t len; 2354132720Skan 2355132720Skan NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2356132720Skan i = fxdr_unsigned(int, *(tl + 7)); 2357132720Skan if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2358132720Skan nd->nd_repstat = NFSERR_BADXDR; 235997403Sobrien goto nfsmout; 236097403Sobrien } 236197403Sobrien MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 236297403Sobrien M_NFSDSTATE, M_WAITOK); 236397403Sobrien stp->ls_ownerlen = i; 236497403Sobrien stp->ls_op = NULL; 2365132720Skan stp->ls_flags = NFSLCK_TEST; 2366132720Skan stp->ls_uid = nd->nd_cred->cr_uid; 2367132720Skan i = fxdr_unsigned(int, *tl++); 2368132720Skan switch (i) { 2369132720Skan case NFSV4LOCKT_READW: 2370132720Skan stp->ls_flags |= NFSLCK_BLOCKING; 2371132720Skan case NFSV4LOCKT_READ: 237297403Sobrien lo.lo_flags = NFSLCK_READ; 237397403Sobrien break; 237497403Sobrien case NFSV4LOCKT_WRITEW: 237597403Sobrien stp->ls_flags |= NFSLCK_BLOCKING; 237697403Sobrien case NFSV4LOCKT_WRITE: 237797403Sobrien lo.lo_flags = NFSLCK_WRITE; 2378132720Skan break; 2379132720Skan default: 2380132720Skan nd->nd_repstat = NFSERR_BADXDR; 2381132720Skan goto nfsmout; 2382132720Skan }; 2383132720Skan lo.lo_first = fxdr_hyper(tl); 2384132720Skan tl += 2; 2385132720Skan len = fxdr_hyper(tl); 2386132720Skan if (len == NFS64BITSSET) { 2387132720Skan lo.lo_end = NFS64BITSSET; 2388132720Skan } else { 238997403Sobrien lo.lo_end = lo.lo_first + len; 239097403Sobrien if (lo.lo_end <= lo.lo_first) 239197403Sobrien nd->nd_repstat = NFSERR_INVAL; 239297403Sobrien } 239397403Sobrien tl += 2; 2394169691Skan clientid.lval[0] = *tl++; 2395169691Skan clientid.lval[1] = *tl; 2396169691Skan if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2397169691Skan if ((nd->nd_flag & ND_NFSV41) != 0) 2398132720Skan clientid.qval = nd->nd_clientid.qval; 2399132720Skan else if (nd->nd_clientid.qval != clientid.qval) 2400132720Skan printf("EEK5 multiple clids\n"); 2401132720Skan } else { 2402132720Skan if ((nd->nd_flag & ND_NFSV41) != 0) 2403132720Skan printf("EEK! no clientid from session\n"); 2404132720Skan nd->nd_flag |= ND_IMPLIEDCLID; 2405132720Skan nd->nd_clientid.qval = clientid.qval; 2406132720Skan } 240797403Sobrien error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2408169691Skan if (error) 240997403Sobrien goto nfsmout; 2410169691Skan if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2411169691Skan if (vnode_vtype(vp) == VDIR) 2412169691Skan nd->nd_repstat = NFSERR_ISDIR; 2413169691Skan else 2414169691Skan nd->nd_repstat = NFSERR_INVAL; 2415169691Skan } 241697403Sobrien if (!nd->nd_repstat) 2417132720Skan nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2418132720Skan &stateid, exp, nd, p); 2419132720Skan if (nd->nd_repstat) { 2420132720Skan if (nd->nd_repstat == NFSERR_DENIED) { 2421132720Skan NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2422132720Skan txdr_hyper(cf.cl_first, tl); 2423132720Skan tl += 2; 2424132720Skan if (cf.cl_end == NFS64BITSSET) 2425132720Skan len = NFS64BITSSET; 2426132720Skan else 2427132720Skan len = cf.cl_end - cf.cl_first; 2428132720Skan txdr_hyper(len, tl); 2429132720Skan tl += 2; 243097403Sobrien if (cf.cl_flags == NFSLCK_WRITE) 2431169691Skan *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 243297403Sobrien else 243397403Sobrien *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 243497403Sobrien *tl++ = stp->ls_stateid.other[0]; 2435132720Skan *tl = stp->ls_stateid.other[1]; 2436132720Skan (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2437132720Skan } 2438132720Skan } 2439132720Skan vput(vp); 2440132720Skan if (stp) 2441132720Skan FREE((caddr_t)stp, M_NFSDSTATE); 2442132720Skan NFSEXITCODE2(0, nd); 2443132720Skan return (0); 2444132720Skannfsmout: 2445132720Skan vput(vp); 2446132720Skan if (stp) 244797403Sobrien free((caddr_t)stp, M_NFSDSTATE); 2448169691Skan NFSEXITCODE2(error, nd); 244997403Sobrien return (error); 2450169691Skan} 2451169691Skan 245297403Sobrien/* 2453169691Skan * nfsv4 unlock service 2454169691Skan */ 2455169691SkanAPPLESTATIC int 2456169691Skannfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2457169691Skan vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2458169691Skan{ 2459169691Skan u_int32_t *tl; 2460169691Skan int i; 2461169691Skan struct nfsstate *stp; 2462169691Skan struct nfslock *lop; 2463169691Skan int error = 0; 2464169691Skan nfsv4stateid_t stateid; 2465169691Skan nfsquad_t clientid; 2466169691Skan u_int64_t len; 2467132720Skan 2468 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2469 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2470 M_NFSDSTATE, M_WAITOK); 2471 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2472 M_NFSDLOCK, M_WAITOK); 2473 stp->ls_flags = NFSLCK_UNLOCK; 2474 lop->lo_flags = NFSLCK_UNLOCK; 2475 stp->ls_op = nd->nd_rp; 2476 i = fxdr_unsigned(int, *tl++); 2477 switch (i) { 2478 case NFSV4LOCKT_READW: 2479 stp->ls_flags |= NFSLCK_BLOCKING; 2480 case NFSV4LOCKT_READ: 2481 break; 2482 case NFSV4LOCKT_WRITEW: 2483 stp->ls_flags |= NFSLCK_BLOCKING; 2484 case NFSV4LOCKT_WRITE: 2485 break; 2486 default: 2487 nd->nd_repstat = NFSERR_BADXDR; 2488 free(stp, M_NFSDSTATE); 2489 free(lop, M_NFSDLOCK); 2490 goto nfsmout; 2491 }; 2492 stp->ls_ownerlen = 0; 2493 stp->ls_uid = nd->nd_cred->cr_uid; 2494 stp->ls_seq = fxdr_unsigned(int, *tl++); 2495 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2496 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2497 NFSX_STATEIDOTHER); 2498 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2499 lop->lo_first = fxdr_hyper(tl); 2500 tl += 2; 2501 len = fxdr_hyper(tl); 2502 if (len == NFS64BITSSET) { 2503 lop->lo_end = NFS64BITSSET; 2504 } else { 2505 lop->lo_end = lop->lo_first + len; 2506 if (lop->lo_end <= lop->lo_first) 2507 nd->nd_repstat = NFSERR_INVAL; 2508 } 2509 clientid.lval[0] = stp->ls_stateid.other[0]; 2510 clientid.lval[1] = stp->ls_stateid.other[1]; 2511 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2512 if ((nd->nd_flag & ND_NFSV41) != 0) 2513 clientid.qval = nd->nd_clientid.qval; 2514 else if (nd->nd_clientid.qval != clientid.qval) 2515 printf("EEK6 multiple clids\n"); 2516 } else { 2517 if ((nd->nd_flag & ND_NFSV41) != 0) 2518 printf("EEK! no clientid from session\n"); 2519 nd->nd_flag |= ND_IMPLIEDCLID; 2520 nd->nd_clientid.qval = clientid.qval; 2521 } 2522 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2523 if (vnode_vtype(vp) == VDIR) 2524 nd->nd_repstat = NFSERR_ISDIR; 2525 else 2526 nd->nd_repstat = NFSERR_INVAL; 2527 } 2528 /* 2529 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2530 * seqid# gets incremented. nfsrv_lockctrl() will return the 2531 * value of nd_repstat, if it gets that far. 2532 */ 2533 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2534 &stateid, exp, nd, p); 2535 if (stp) 2536 FREE((caddr_t)stp, M_NFSDSTATE); 2537 if (lop) 2538 free((caddr_t)lop, M_NFSDLOCK); 2539 if (!nd->nd_repstat) { 2540 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2541 *tl++ = txdr_unsigned(stateid.seqid); 2542 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2543 } 2544nfsmout: 2545 vput(vp); 2546 NFSEXITCODE2(error, nd); 2547 return (error); 2548} 2549 2550/* 2551 * nfsv4 open service 2552 */ 2553APPLESTATIC int 2554nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2555 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2556 struct nfsexstuff *exp) 2557{ 2558 u_int32_t *tl; 2559 int i, retext; 2560 struct nfsstate *stp = NULL; 2561 int error = 0, create, claim, exclusive_flag = 0; 2562 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2563 int how = NFSCREATE_UNCHECKED; 2564 int32_t cverf[2], tverf[2] = { 0, 0 }; 2565 vnode_t vp = NULL, dirp = NULL; 2566 struct nfsvattr nva, dirfor, diraft; 2567 struct nameidata named; 2568 nfsv4stateid_t stateid, delegstateid; 2569 nfsattrbit_t attrbits; 2570 nfsquad_t clientid; 2571 char *bufp = NULL; 2572 u_long *hashp; 2573 NFSACL_T *aclp = NULL; 2574 2575#ifdef NFS4_ACL_EXTATTR_NAME 2576 aclp = acl_alloc(M_WAITOK); 2577 aclp->acl_cnt = 0; 2578#endif 2579 NFSZERO_ATTRBIT(&attrbits); 2580 named.ni_startdir = NULL; 2581 named.ni_cnd.cn_nameiop = 0; 2582 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2583 i = fxdr_unsigned(int, *(tl + 5)); 2584 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2585 nd->nd_repstat = NFSERR_BADXDR; 2586 goto nfsmout; 2587 } 2588 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2589 M_NFSDSTATE, M_WAITOK); 2590 stp->ls_ownerlen = i; 2591 stp->ls_op = nd->nd_rp; 2592 stp->ls_flags = NFSLCK_OPEN; 2593 stp->ls_uid = nd->nd_cred->cr_uid; 2594 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2595 i = fxdr_unsigned(int, *tl++); 2596 retext = 0; 2597 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2598 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2599 retext = 1; 2600 /* For now, ignore these. */ 2601 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2602 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2603 case NFSV4OPEN_WANTANYDELEG: 2604 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2605 NFSLCK_WANTWDELEG); 2606 i &= ~NFSV4OPEN_WANTDELEGMASK; 2607 break; 2608 case NFSV4OPEN_WANTREADDELEG: 2609 stp->ls_flags |= NFSLCK_WANTRDELEG; 2610 i &= ~NFSV4OPEN_WANTDELEGMASK; 2611 break; 2612 case NFSV4OPEN_WANTWRITEDELEG: 2613 stp->ls_flags |= NFSLCK_WANTWDELEG; 2614 i &= ~NFSV4OPEN_WANTDELEGMASK; 2615 break; 2616 case NFSV4OPEN_WANTNODELEG: 2617 stp->ls_flags |= NFSLCK_WANTNODELEG; 2618 i &= ~NFSV4OPEN_WANTDELEGMASK; 2619 break; 2620 case NFSV4OPEN_WANTCANCEL: 2621 printf("NFSv4: ignore Open WantCancel\n"); 2622 i &= ~NFSV4OPEN_WANTDELEGMASK; 2623 break; 2624 default: 2625 /* nd_repstat will be set to NFSERR_INVAL below. */ 2626 break; 2627 }; 2628 } 2629 switch (i) { 2630 case NFSV4OPEN_ACCESSREAD: 2631 stp->ls_flags |= NFSLCK_READACCESS; 2632 break; 2633 case NFSV4OPEN_ACCESSWRITE: 2634 stp->ls_flags |= NFSLCK_WRITEACCESS; 2635 break; 2636 case NFSV4OPEN_ACCESSBOTH: 2637 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2638 break; 2639 default: 2640 nd->nd_repstat = NFSERR_INVAL; 2641 }; 2642 i = fxdr_unsigned(int, *tl++); 2643 switch (i) { 2644 case NFSV4OPEN_DENYNONE: 2645 break; 2646 case NFSV4OPEN_DENYREAD: 2647 stp->ls_flags |= NFSLCK_READDENY; 2648 break; 2649 case NFSV4OPEN_DENYWRITE: 2650 stp->ls_flags |= NFSLCK_WRITEDENY; 2651 break; 2652 case NFSV4OPEN_DENYBOTH: 2653 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2654 break; 2655 default: 2656 nd->nd_repstat = NFSERR_INVAL; 2657 }; 2658 clientid.lval[0] = *tl++; 2659 clientid.lval[1] = *tl; 2660 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2661 if ((nd->nd_flag & ND_NFSV41) != 0) 2662 clientid.qval = nd->nd_clientid.qval; 2663 else if (nd->nd_clientid.qval != clientid.qval) 2664 printf("EEK7 multiple clids\n"); 2665 } else { 2666 if ((nd->nd_flag & ND_NFSV41) != 0) 2667 printf("EEK! no clientid from session\n"); 2668 nd->nd_flag |= ND_IMPLIEDCLID; 2669 nd->nd_clientid.qval = clientid.qval; 2670 } 2671 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2672 if (error) 2673 goto nfsmout; 2674 NFSVNO_ATTRINIT(&nva); 2675 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2676 create = fxdr_unsigned(int, *tl); 2677 if (!nd->nd_repstat) 2678 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 2679 if (create == NFSV4OPEN_CREATE) { 2680 nva.na_type = VREG; 2681 nva.na_mode = 0; 2682 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2683 how = fxdr_unsigned(int, *tl); 2684 switch (how) { 2685 case NFSCREATE_UNCHECKED: 2686 case NFSCREATE_GUARDED: 2687 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2688 if (error) 2689 goto nfsmout; 2690 /* 2691 * If the na_gid being set is the same as that of 2692 * the directory it is going in, clear it, since 2693 * that is what will be set by default. This allows 2694 * a user that isn't in that group to do the create. 2695 */ 2696 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2697 nva.na_gid == dirfor.na_gid) 2698 NFSVNO_UNSET(&nva, gid); 2699 if (!nd->nd_repstat) 2700 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2701 break; 2702 case NFSCREATE_EXCLUSIVE: 2703 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2704 cverf[0] = *tl++; 2705 cverf[1] = *tl; 2706 break; 2707 case NFSCREATE_EXCLUSIVE41: 2708 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2709 cverf[0] = *tl++; 2710 cverf[1] = *tl; 2711 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2712 if (error != 0) 2713 goto nfsmout; 2714 if (NFSISSET_ATTRBIT(&attrbits, 2715 NFSATTRBIT_TIMEACCESSSET)) 2716 nd->nd_repstat = NFSERR_INVAL; 2717 /* 2718 * If the na_gid being set is the same as that of 2719 * the directory it is going in, clear it, since 2720 * that is what will be set by default. This allows 2721 * a user that isn't in that group to do the create. 2722 */ 2723 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2724 nva.na_gid == dirfor.na_gid) 2725 NFSVNO_UNSET(&nva, gid); 2726 if (nd->nd_repstat == 0) 2727 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2728 break; 2729 default: 2730 nd->nd_repstat = NFSERR_BADXDR; 2731 goto nfsmout; 2732 }; 2733 } else if (create != NFSV4OPEN_NOCREATE) { 2734 nd->nd_repstat = NFSERR_BADXDR; 2735 goto nfsmout; 2736 } 2737 2738 /* 2739 * Now, handle the claim, which usually includes looking up a 2740 * name in the directory referenced by dp. The exception is 2741 * NFSV4OPEN_CLAIMPREVIOUS. 2742 */ 2743 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2744 claim = fxdr_unsigned(int, *tl); 2745 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2746 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2747 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2748 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2749 stp->ls_flags |= NFSLCK_DELEGCUR; 2750 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2751 stp->ls_flags |= NFSLCK_DELEGPREV; 2752 } 2753 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2754 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2755 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2756 claim != NFSV4OPEN_CLAIMNULL) 2757 nd->nd_repstat = NFSERR_INVAL; 2758 if (nd->nd_repstat) { 2759 nd->nd_repstat = nfsrv_opencheck(clientid, 2760 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2761 goto nfsmout; 2762 } 2763 if (create == NFSV4OPEN_CREATE) 2764 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2765 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 2766 else 2767 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2768 LOCKLEAF | SAVESTART); 2769 nfsvno_setpathbuf(&named, &bufp, &hashp); 2770 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2771 if (error) { 2772 vrele(dp); 2773#ifdef NFS4_ACL_EXTATTR_NAME 2774 acl_free(aclp); 2775#endif 2776 FREE((caddr_t)stp, M_NFSDSTATE); 2777 nfsvno_relpathbuf(&named); 2778 NFSEXITCODE2(error, nd); 2779 return (error); 2780 } 2781 if (!nd->nd_repstat) { 2782 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2783 p, &dirp); 2784 } else { 2785 vrele(dp); 2786 nfsvno_relpathbuf(&named); 2787 } 2788 if (create == NFSV4OPEN_CREATE) { 2789 switch (how) { 2790 case NFSCREATE_UNCHECKED: 2791 if (named.ni_vp) { 2792 /* 2793 * Clear the setable attribute bits, except 2794 * for Size, if it is being truncated. 2795 */ 2796 NFSZERO_ATTRBIT(&attrbits); 2797 if (NFSVNO_ISSETSIZE(&nva)) 2798 NFSSETBIT_ATTRBIT(&attrbits, 2799 NFSATTRBIT_SIZE); 2800 } 2801 break; 2802 case NFSCREATE_GUARDED: 2803 if (named.ni_vp && !nd->nd_repstat) 2804 nd->nd_repstat = EEXIST; 2805 break; 2806 case NFSCREATE_EXCLUSIVE: 2807 exclusive_flag = 1; 2808 if (!named.ni_vp) 2809 nva.na_mode = 0; 2810 break; 2811 case NFSCREATE_EXCLUSIVE41: 2812 exclusive_flag = 1; 2813 break; 2814 }; 2815 } 2816 nfsvno_open(nd, &named, clientid, &stateid, stp, 2817 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2818 nd->nd_cred, p, exp, &vp); 2819 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2820 NFSV4OPEN_CLAIMFH) { 2821 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2822 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2823 i = fxdr_unsigned(int, *tl); 2824 switch (i) { 2825 case NFSV4OPEN_DELEGATEREAD: 2826 stp->ls_flags |= NFSLCK_DELEGREAD; 2827 break; 2828 case NFSV4OPEN_DELEGATEWRITE: 2829 stp->ls_flags |= NFSLCK_DELEGWRITE; 2830 case NFSV4OPEN_DELEGATENONE: 2831 break; 2832 default: 2833 nd->nd_repstat = NFSERR_BADXDR; 2834 goto nfsmout; 2835 }; 2836 stp->ls_flags |= NFSLCK_RECLAIM; 2837 } else { 2838 /* CLAIM_NULL_FH */ 2839 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 2840 nd->nd_repstat = NFSERR_INVAL; 2841 } 2842 vp = dp; 2843 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2844 if ((vp->v_iflag & VI_DOOMED) == 0) 2845 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2846 stp, vp, nd, p, nd->nd_repstat); 2847 else 2848 nd->nd_repstat = NFSERR_PERM; 2849 } else { 2850 nd->nd_repstat = NFSERR_BADXDR; 2851 goto nfsmout; 2852 } 2853 2854 /* 2855 * Do basic access checking. 2856 */ 2857 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2858 /* 2859 * The IETF working group decided that this is the correct 2860 * error return for all non-regular files. 2861 */ 2862 nd->nd_repstat = NFSERR_SYMLINK; 2863 } 2864 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2865 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2866 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2867 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2868 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2869 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2870 if (nd->nd_repstat) 2871 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2872 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2873 NFSACCCHK_VPISLOCKED, NULL); 2874 } 2875 2876 if (!nd->nd_repstat) { 2877 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2878 if (!nd->nd_repstat) { 2879 tverf[0] = nva.na_atime.tv_sec; 2880 tverf[1] = nva.na_atime.tv_nsec; 2881 } 2882 } 2883 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2884 cverf[1] != tverf[1])) 2885 nd->nd_repstat = EEXIST; 2886 /* 2887 * Do the open locking/delegation stuff. 2888 */ 2889 if (!nd->nd_repstat) 2890 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2891 &delegstateid, &rflags, exp, p, nva.na_filerev); 2892 2893 /* 2894 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2895 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2896 * (ie: Leave the NFSVOPUNLOCK() about here.) 2897 */ 2898 if (vp) 2899 NFSVOPUNLOCK(vp, 0); 2900 if (stp) 2901 FREE((caddr_t)stp, M_NFSDSTATE); 2902 if (!nd->nd_repstat && dirp) 2903 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 2904 0); 2905 if (!nd->nd_repstat) { 2906 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2907 *tl++ = txdr_unsigned(stateid.seqid); 2908 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2909 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2910 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2911 *tl++ = newnfs_true; 2912 *tl++ = 0; 2913 *tl++ = 0; 2914 *tl++ = 0; 2915 *tl++ = 0; 2916 } else { 2917 *tl++ = newnfs_false; /* Since dirp is not locked */ 2918 txdr_hyper(dirfor.na_filerev, tl); 2919 tl += 2; 2920 txdr_hyper(diraft.na_filerev, tl); 2921 tl += 2; 2922 } 2923 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2924 (void) nfsrv_putattrbit(nd, &attrbits); 2925 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2926 if (rflags & NFSV4OPEN_READDELEGATE) 2927 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2928 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2929 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2930 else if (retext != 0) { 2931 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 2932 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2933 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2934 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2935 *tl = newnfs_false; 2936 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2937 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2938 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2939 *tl = newnfs_false; 2940 } else { 2941 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2942 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2943 } 2944 } else 2945 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2946 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2947 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2948 *tl++ = txdr_unsigned(delegstateid.seqid); 2949 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2950 NFSX_STATEIDOTHER); 2951 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2952 if (rflags & NFSV4OPEN_RECALL) 2953 *tl = newnfs_true; 2954 else 2955 *tl = newnfs_false; 2956 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2957 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2958 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2959 txdr_hyper(nva.na_size, tl); 2960 } 2961 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2962 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2963 *tl++ = txdr_unsigned(0x0); 2964 acemask = NFSV4ACE_ALLFILESMASK; 2965 if (nva.na_mode & S_IRUSR) 2966 acemask |= NFSV4ACE_READMASK; 2967 if (nva.na_mode & S_IWUSR) 2968 acemask |= NFSV4ACE_WRITEMASK; 2969 if (nva.na_mode & S_IXUSR) 2970 acemask |= NFSV4ACE_EXECUTEMASK; 2971 *tl = txdr_unsigned(acemask); 2972 (void) nfsm_strtom(nd, "OWNER@", 6); 2973 } 2974 *vpp = vp; 2975 } else if (vp) { 2976 vrele(vp); 2977 } 2978 if (dirp) 2979 vrele(dirp); 2980#ifdef NFS4_ACL_EXTATTR_NAME 2981 acl_free(aclp); 2982#endif 2983 NFSEXITCODE2(0, nd); 2984 return (0); 2985nfsmout: 2986 vrele(dp); 2987#ifdef NFS4_ACL_EXTATTR_NAME 2988 acl_free(aclp); 2989#endif 2990 if (stp) 2991 FREE((caddr_t)stp, M_NFSDSTATE); 2992 NFSEXITCODE2(error, nd); 2993 return (error); 2994} 2995 2996/* 2997 * nfsv4 close service 2998 */ 2999APPLESTATIC int 3000nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3001 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3002{ 3003 u_int32_t *tl; 3004 struct nfsstate st, *stp = &st; 3005 int error = 0; 3006 nfsv4stateid_t stateid; 3007 nfsquad_t clientid; 3008 3009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3010 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3011 stp->ls_ownerlen = 0; 3012 stp->ls_op = nd->nd_rp; 3013 stp->ls_uid = nd->nd_cred->cr_uid; 3014 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3015 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3016 NFSX_STATEIDOTHER); 3017 stp->ls_flags = NFSLCK_CLOSE; 3018 clientid.lval[0] = stp->ls_stateid.other[0]; 3019 clientid.lval[1] = stp->ls_stateid.other[1]; 3020 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3021 if ((nd->nd_flag & ND_NFSV41) != 0) 3022 clientid.qval = nd->nd_clientid.qval; 3023 else if (nd->nd_clientid.qval != clientid.qval) 3024 printf("EEK8 multiple clids\n"); 3025 } else { 3026 if ((nd->nd_flag & ND_NFSV41) != 0) 3027 printf("EEK! no clientid from session\n"); 3028 nd->nd_flag |= ND_IMPLIEDCLID; 3029 nd->nd_clientid.qval = clientid.qval; 3030 } 3031 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3032 vput(vp); 3033 if (!nd->nd_repstat) { 3034 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3035 *tl++ = txdr_unsigned(stateid.seqid); 3036 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3037 } 3038 NFSEXITCODE2(0, nd); 3039 return (0); 3040nfsmout: 3041 vput(vp); 3042 NFSEXITCODE2(error, nd); 3043 return (error); 3044} 3045 3046/* 3047 * nfsv4 delegpurge service 3048 */ 3049APPLESTATIC int 3050nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3051 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3052{ 3053 u_int32_t *tl; 3054 int error = 0; 3055 nfsquad_t clientid; 3056 3057 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3058 nd->nd_repstat = NFSERR_WRONGSEC; 3059 goto nfsmout; 3060 } 3061 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3062 clientid.lval[0] = *tl++; 3063 clientid.lval[1] = *tl; 3064 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3065 if ((nd->nd_flag & ND_NFSV41) != 0) 3066 clientid.qval = nd->nd_clientid.qval; 3067 else if (nd->nd_clientid.qval != clientid.qval) 3068 printf("EEK9 multiple clids\n"); 3069 } else { 3070 if ((nd->nd_flag & ND_NFSV41) != 0) 3071 printf("EEK! no clientid from session\n"); 3072 nd->nd_flag |= ND_IMPLIEDCLID; 3073 nd->nd_clientid.qval = clientid.qval; 3074 } 3075 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3076 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 3077nfsmout: 3078 NFSEXITCODE2(error, nd); 3079 return (error); 3080} 3081 3082/* 3083 * nfsv4 delegreturn service 3084 */ 3085APPLESTATIC int 3086nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3087 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3088{ 3089 u_int32_t *tl; 3090 int error = 0; 3091 nfsv4stateid_t stateid; 3092 nfsquad_t clientid; 3093 3094 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3095 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3096 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3097 clientid.lval[0] = stateid.other[0]; 3098 clientid.lval[1] = stateid.other[1]; 3099 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3100 if ((nd->nd_flag & ND_NFSV41) != 0) 3101 clientid.qval = nd->nd_clientid.qval; 3102 else if (nd->nd_clientid.qval != clientid.qval) 3103 printf("EEK10 multiple clids\n"); 3104 } else { 3105 if ((nd->nd_flag & ND_NFSV41) != 0) 3106 printf("EEK! no clientid from session\n"); 3107 nd->nd_flag |= ND_IMPLIEDCLID; 3108 nd->nd_clientid.qval = clientid.qval; 3109 } 3110 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3111 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 3112nfsmout: 3113 vput(vp); 3114 NFSEXITCODE2(error, nd); 3115 return (error); 3116} 3117 3118/* 3119 * nfsv4 get file handle service 3120 */ 3121APPLESTATIC int 3122nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3123 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3124{ 3125 fhandle_t fh; 3126 3127 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3128 vput(vp); 3129 if (!nd->nd_repstat) 3130 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3131 NFSEXITCODE2(0, nd); 3132 return (0); 3133} 3134 3135/* 3136 * nfsv4 open confirm service 3137 */ 3138APPLESTATIC int 3139nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3140 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3141{ 3142 u_int32_t *tl; 3143 struct nfsstate st, *stp = &st; 3144 int error = 0; 3145 nfsv4stateid_t stateid; 3146 nfsquad_t clientid; 3147 3148 if ((nd->nd_flag & ND_NFSV41) != 0) { 3149 nd->nd_repstat = NFSERR_NOTSUPP; 3150 goto nfsmout; 3151 } 3152 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3153 stp->ls_ownerlen = 0; 3154 stp->ls_op = nd->nd_rp; 3155 stp->ls_uid = nd->nd_cred->cr_uid; 3156 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3157 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3158 NFSX_STATEIDOTHER); 3159 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3160 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3161 stp->ls_flags = NFSLCK_CONFIRM; 3162 clientid.lval[0] = stp->ls_stateid.other[0]; 3163 clientid.lval[1] = stp->ls_stateid.other[1]; 3164 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3165 if ((nd->nd_flag & ND_NFSV41) != 0) 3166 clientid.qval = nd->nd_clientid.qval; 3167 else if (nd->nd_clientid.qval != clientid.qval) 3168 printf("EEK11 multiple clids\n"); 3169 } else { 3170 if ((nd->nd_flag & ND_NFSV41) != 0) 3171 printf("EEK! no clientid from session\n"); 3172 nd->nd_flag |= ND_IMPLIEDCLID; 3173 nd->nd_clientid.qval = clientid.qval; 3174 } 3175 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3176 if (!nd->nd_repstat) { 3177 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3178 *tl++ = txdr_unsigned(stateid.seqid); 3179 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3180 } 3181nfsmout: 3182 vput(vp); 3183 NFSEXITCODE2(error, nd); 3184 return (error); 3185} 3186 3187/* 3188 * nfsv4 open downgrade service 3189 */ 3190APPLESTATIC int 3191nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3192 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3193{ 3194 u_int32_t *tl; 3195 int i; 3196 struct nfsstate st, *stp = &st; 3197 int error = 0; 3198 nfsv4stateid_t stateid; 3199 nfsquad_t clientid; 3200 3201 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3202 stp->ls_ownerlen = 0; 3203 stp->ls_op = nd->nd_rp; 3204 stp->ls_uid = nd->nd_cred->cr_uid; 3205 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3206 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3207 NFSX_STATEIDOTHER); 3208 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3209 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3210 i = fxdr_unsigned(int, *tl++); 3211 switch (i) { 3212 case NFSV4OPEN_ACCESSREAD: 3213 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3214 break; 3215 case NFSV4OPEN_ACCESSWRITE: 3216 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3217 break; 3218 case NFSV4OPEN_ACCESSBOTH: 3219 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3220 NFSLCK_DOWNGRADE); 3221 break; 3222 default: 3223 nd->nd_repstat = NFSERR_BADXDR; 3224 }; 3225 i = fxdr_unsigned(int, *tl); 3226 switch (i) { 3227 case NFSV4OPEN_DENYNONE: 3228 break; 3229 case NFSV4OPEN_DENYREAD: 3230 stp->ls_flags |= NFSLCK_READDENY; 3231 break; 3232 case NFSV4OPEN_DENYWRITE: 3233 stp->ls_flags |= NFSLCK_WRITEDENY; 3234 break; 3235 case NFSV4OPEN_DENYBOTH: 3236 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3237 break; 3238 default: 3239 nd->nd_repstat = NFSERR_BADXDR; 3240 }; 3241 3242 clientid.lval[0] = stp->ls_stateid.other[0]; 3243 clientid.lval[1] = stp->ls_stateid.other[1]; 3244 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3245 if ((nd->nd_flag & ND_NFSV41) != 0) 3246 clientid.qval = nd->nd_clientid.qval; 3247 else if (nd->nd_clientid.qval != clientid.qval) 3248 printf("EEK12 multiple clids\n"); 3249 } else { 3250 if ((nd->nd_flag & ND_NFSV41) != 0) 3251 printf("EEK! no clientid from session\n"); 3252 nd->nd_flag |= ND_IMPLIEDCLID; 3253 nd->nd_clientid.qval = clientid.qval; 3254 } 3255 if (!nd->nd_repstat) 3256 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3257 nd, p); 3258 if (!nd->nd_repstat) { 3259 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3260 *tl++ = txdr_unsigned(stateid.seqid); 3261 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3262 } 3263nfsmout: 3264 vput(vp); 3265 NFSEXITCODE2(error, nd); 3266 return (error); 3267} 3268 3269/* 3270 * nfsv4 renew lease service 3271 */ 3272APPLESTATIC int 3273nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3274 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3275{ 3276 u_int32_t *tl; 3277 int error = 0; 3278 nfsquad_t clientid; 3279 3280 if ((nd->nd_flag & ND_NFSV41) != 0) { 3281 nd->nd_repstat = NFSERR_NOTSUPP; 3282 goto nfsmout; 3283 } 3284 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3285 nd->nd_repstat = NFSERR_WRONGSEC; 3286 goto nfsmout; 3287 } 3288 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3289 clientid.lval[0] = *tl++; 3290 clientid.lval[1] = *tl; 3291 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3292 if ((nd->nd_flag & ND_NFSV41) != 0) 3293 clientid.qval = nd->nd_clientid.qval; 3294 else if (nd->nd_clientid.qval != clientid.qval) 3295 printf("EEK13 multiple clids\n"); 3296 } else { 3297 if ((nd->nd_flag & ND_NFSV41) != 0) 3298 printf("EEK! no clientid from session\n"); 3299 nd->nd_flag |= ND_IMPLIEDCLID; 3300 nd->nd_clientid.qval = clientid.qval; 3301 } 3302 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3303 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3304nfsmout: 3305 NFSEXITCODE2(error, nd); 3306 return (error); 3307} 3308 3309/* 3310 * nfsv4 security info service 3311 */ 3312APPLESTATIC int 3313nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3314 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3315{ 3316 u_int32_t *tl; 3317 int len; 3318 struct nameidata named; 3319 vnode_t dirp = NULL, vp; 3320 struct nfsrvfh fh; 3321 struct nfsexstuff retnes; 3322 u_int32_t *sizp; 3323 int error = 0, savflag, i; 3324 char *bufp; 3325 u_long *hashp; 3326 3327 /* 3328 * All this just to get the export flags for the name. 3329 */ 3330 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3331 LOCKLEAF | SAVESTART); 3332 nfsvno_setpathbuf(&named, &bufp, &hashp); 3333 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3334 if (error) { 3335 vput(dp); 3336 nfsvno_relpathbuf(&named); 3337 goto out; 3338 } 3339 if (!nd->nd_repstat) { 3340 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3341 } else { 3342 vput(dp); 3343 nfsvno_relpathbuf(&named); 3344 } 3345 if (dirp) 3346 vrele(dirp); 3347 if (nd->nd_repstat) 3348 goto out; 3349 vrele(named.ni_startdir); 3350 nfsvno_relpathbuf(&named); 3351 fh.nfsrvfh_len = NFSX_MYFH; 3352 vp = named.ni_vp; 3353 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3354 vput(vp); 3355 savflag = nd->nd_flag; 3356 if (!nd->nd_repstat) { 3357 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3358 if (vp) 3359 vput(vp); 3360 } 3361 nd->nd_flag = savflag; 3362 if (nd->nd_repstat) 3363 goto out; 3364 3365 /* 3366 * Finally have the export flags for name, so we can create 3367 * the security info. 3368 */ 3369 len = 0; 3370 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3371 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3372 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3373 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3374 *tl = txdr_unsigned(RPCAUTH_UNIX); 3375 len++; 3376 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3377 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3378 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3379 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3380 nfsgss_mechlist[KERBV_MECH].len); 3381 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3382 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3383 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3384 len++; 3385 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3386 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3387 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3388 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3389 nfsgss_mechlist[KERBV_MECH].len); 3390 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3391 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3392 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3393 len++; 3394 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3395 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3396 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3397 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3398 nfsgss_mechlist[KERBV_MECH].len); 3399 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3400 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3401 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3402 len++; 3403 } 3404 } 3405 *sizp = txdr_unsigned(len); 3406 3407out: 3408 NFSEXITCODE2(error, nd); 3409 return (error); 3410} 3411 3412/* 3413 * nfsv4 set client id service 3414 */ 3415APPLESTATIC int 3416nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3417 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3418{ 3419 u_int32_t *tl; 3420 int i; 3421 int error = 0, idlen; 3422 struct nfsclient *clp = NULL; 3423 struct sockaddr_in *rad; 3424 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3425 nfsquad_t clientid, confirm; 3426 3427 if ((nd->nd_flag & ND_NFSV41) != 0) { 3428 nd->nd_repstat = NFSERR_NOTSUPP; 3429 goto nfsmout; 3430 } 3431 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3432 nd->nd_repstat = NFSERR_WRONGSEC; 3433 goto out; 3434 } 3435 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3436 verf = (u_char *)tl; 3437 tl += (NFSX_VERF / NFSX_UNSIGNED); 3438 i = fxdr_unsigned(int, *tl); 3439 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3440 nd->nd_repstat = NFSERR_BADXDR; 3441 goto nfsmout; 3442 } 3443 idlen = i; 3444 if (nd->nd_flag & ND_GSS) 3445 i += nd->nd_princlen; 3446 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3447 M_ZERO); 3448 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3449 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3450 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3451 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3452 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3453 clp->lc_req.nr_cred = NULL; 3454 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3455 clp->lc_idlen = idlen; 3456 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3457 if (error) 3458 goto nfsmout; 3459 if (nd->nd_flag & ND_GSS) { 3460 clp->lc_flags = LCL_GSS; 3461 if (nd->nd_flag & ND_GSSINTEGRITY) 3462 clp->lc_flags |= LCL_GSSINTEGRITY; 3463 else if (nd->nd_flag & ND_GSSPRIVACY) 3464 clp->lc_flags |= LCL_GSSPRIVACY; 3465 } else { 3466 clp->lc_flags = 0; 3467 } 3468 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3469 clp->lc_flags |= LCL_NAME; 3470 clp->lc_namelen = nd->nd_princlen; 3471 clp->lc_name = &clp->lc_id[idlen]; 3472 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3473 } else { 3474 clp->lc_uid = nd->nd_cred->cr_uid; 3475 clp->lc_gid = nd->nd_cred->cr_gid; 3476 } 3477 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3478 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3479 error = nfsrv_getclientipaddr(nd, clp); 3480 if (error) 3481 goto nfsmout; 3482 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3483 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3484 3485 /* 3486 * nfsrv_setclient() does the actual work of adding it to the 3487 * client list. If there is no error, the structure has been 3488 * linked into the client list and clp should no longer be used 3489 * here. When an error is returned, it has not been linked in, 3490 * so it should be free'd. 3491 */ 3492 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3493 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3494 if (clp->lc_flags & LCL_TCPCALLBACK) 3495 (void) nfsm_strtom(nd, "tcp", 3); 3496 else 3497 (void) nfsm_strtom(nd, "udp", 3); 3498 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3499 ucp = (u_char *)&rad->sin_addr.s_addr; 3500 ucp2 = (u_char *)&rad->sin_port; 3501 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3502 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3503 ucp2[0] & 0xff, ucp2[1] & 0xff); 3504 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3505 } 3506 if (clp) { 3507 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3508 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3509 free(clp->lc_stateid, M_NFSDCLIENT); 3510 free(clp, M_NFSDCLIENT); 3511 } 3512 if (!nd->nd_repstat) { 3513 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3514 *tl++ = clientid.lval[0]; 3515 *tl++ = clientid.lval[1]; 3516 *tl++ = confirm.lval[0]; 3517 *tl = confirm.lval[1]; 3518 } 3519 3520out: 3521 NFSEXITCODE2(0, nd); 3522 return (0); 3523nfsmout: 3524 if (clp) { 3525 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3526 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3527 free(clp->lc_stateid, M_NFSDCLIENT); 3528 free(clp, M_NFSDCLIENT); 3529 } 3530 NFSEXITCODE2(error, nd); 3531 return (error); 3532} 3533 3534/* 3535 * nfsv4 set client id confirm service 3536 */ 3537APPLESTATIC int 3538nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3539 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3540 __unused struct nfsexstuff *exp) 3541{ 3542 u_int32_t *tl; 3543 int error = 0; 3544 nfsquad_t clientid, confirm; 3545 3546 if ((nd->nd_flag & ND_NFSV41) != 0) { 3547 nd->nd_repstat = NFSERR_NOTSUPP; 3548 goto nfsmout; 3549 } 3550 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3551 nd->nd_repstat = NFSERR_WRONGSEC; 3552 goto nfsmout; 3553 } 3554 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3555 clientid.lval[0] = *tl++; 3556 clientid.lval[1] = *tl++; 3557 confirm.lval[0] = *tl++; 3558 confirm.lval[1] = *tl; 3559 3560 /* 3561 * nfsrv_getclient() searches the client list for a match and 3562 * returns the appropriate NFSERR status. 3563 */ 3564 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3565 NULL, NULL, confirm, 0, nd, p); 3566nfsmout: 3567 NFSEXITCODE2(error, nd); 3568 return (error); 3569} 3570 3571/* 3572 * nfsv4 verify service 3573 */ 3574APPLESTATIC int 3575nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3576 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3577{ 3578 int error = 0, ret, fhsize = NFSX_MYFH; 3579 struct nfsvattr nva; 3580 struct statfs sf; 3581 struct nfsfsinfo fs; 3582 fhandle_t fh; 3583 3584 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3585 if (!nd->nd_repstat) 3586 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3587 if (!nd->nd_repstat) 3588 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3589 if (!nd->nd_repstat) { 3590 nfsvno_getfs(&fs, isdgram); 3591 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3592 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3593 if (!error) { 3594 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3595 if (ret == 0) 3596 nd->nd_repstat = NFSERR_SAME; 3597 else if (ret != NFSERR_NOTSAME) 3598 nd->nd_repstat = ret; 3599 } else if (ret) 3600 nd->nd_repstat = ret; 3601 } 3602 } 3603 vput(vp); 3604 NFSEXITCODE2(error, nd); 3605 return (error); 3606} 3607 3608/* 3609 * nfs openattr rpc 3610 */ 3611APPLESTATIC int 3612nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3613 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3614 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3615{ 3616 u_int32_t *tl; 3617 int error = 0, createdir; 3618 3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3620 createdir = fxdr_unsigned(int, *tl); 3621 nd->nd_repstat = NFSERR_NOTSUPP; 3622nfsmout: 3623 vrele(dp); 3624 NFSEXITCODE2(error, nd); 3625 return (error); 3626} 3627 3628/* 3629 * nfsv4 release lock owner service 3630 */ 3631APPLESTATIC int 3632nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3633 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3634{ 3635 u_int32_t *tl; 3636 struct nfsstate *stp = NULL; 3637 int error = 0, len; 3638 nfsquad_t clientid; 3639 3640 if ((nd->nd_flag & ND_NFSV41) != 0) { 3641 nd->nd_repstat = NFSERR_NOTSUPP; 3642 goto nfsmout; 3643 } 3644 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3645 nd->nd_repstat = NFSERR_WRONGSEC; 3646 goto nfsmout; 3647 } 3648 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3649 len = fxdr_unsigned(int, *(tl + 2)); 3650 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3651 nd->nd_repstat = NFSERR_BADXDR; 3652 goto nfsmout; 3653 } 3654 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3655 M_NFSDSTATE, M_WAITOK); 3656 stp->ls_ownerlen = len; 3657 stp->ls_op = NULL; 3658 stp->ls_flags = NFSLCK_RELEASE; 3659 stp->ls_uid = nd->nd_cred->cr_uid; 3660 clientid.lval[0] = *tl++; 3661 clientid.lval[1] = *tl; 3662 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3663 if ((nd->nd_flag & ND_NFSV41) != 0) 3664 clientid.qval = nd->nd_clientid.qval; 3665 else if (nd->nd_clientid.qval != clientid.qval) 3666 printf("EEK14 multiple clids\n"); 3667 } else { 3668 if ((nd->nd_flag & ND_NFSV41) != 0) 3669 printf("EEK! no clientid from session\n"); 3670 nd->nd_flag |= ND_IMPLIEDCLID; 3671 nd->nd_clientid.qval = clientid.qval; 3672 } 3673 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3674 if (error) 3675 goto nfsmout; 3676 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3677 FREE((caddr_t)stp, M_NFSDSTATE); 3678 3679 NFSEXITCODE2(0, nd); 3680 return (0); 3681nfsmout: 3682 if (stp) 3683 free((caddr_t)stp, M_NFSDSTATE); 3684 NFSEXITCODE2(error, nd); 3685 return (error); 3686} 3687 3688/* 3689 * nfsv4 exchange_id service 3690 */ 3691APPLESTATIC int 3692nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3693 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3694{ 3695 uint32_t *tl; 3696 int error = 0, i, idlen; 3697 struct nfsclient *clp = NULL; 3698 nfsquad_t clientid, confirm; 3699 uint8_t *verf; 3700 uint32_t sp4type, v41flags; 3701 uint64_t owner_minor; 3702 struct timespec verstime; 3703 3704 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3705 nd->nd_repstat = NFSERR_WRONGSEC; 3706 goto nfsmout; 3707 } 3708 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3709 verf = (uint8_t *)tl; 3710 tl += (NFSX_VERF / NFSX_UNSIGNED); 3711 i = fxdr_unsigned(int, *tl); 3712 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3713 nd->nd_repstat = NFSERR_BADXDR; 3714 goto nfsmout; 3715 } 3716 idlen = i; 3717 if (nd->nd_flag & ND_GSS) 3718 i += nd->nd_princlen; 3719 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3720 M_ZERO); 3721 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3722 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3723 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3724 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3725 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3726 clp->lc_req.nr_cred = NULL; 3727 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3728 clp->lc_idlen = idlen; 3729 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3730 if (error != 0) 3731 goto nfsmout; 3732 if ((nd->nd_flag & ND_GSS) != 0) { 3733 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3734 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3735 clp->lc_flags |= LCL_GSSINTEGRITY; 3736 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3737 clp->lc_flags |= LCL_GSSPRIVACY; 3738 } else 3739 clp->lc_flags = LCL_NFSV41; 3740 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3741 clp->lc_flags |= LCL_NAME; 3742 clp->lc_namelen = nd->nd_princlen; 3743 clp->lc_name = &clp->lc_id[idlen]; 3744 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3745 } else { 3746 clp->lc_uid = nd->nd_cred->cr_uid; 3747 clp->lc_gid = nd->nd_cred->cr_gid; 3748 } 3749 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3750 v41flags = fxdr_unsigned(uint32_t, *tl++); 3751 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3752 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3753 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3754 nd->nd_repstat = NFSERR_INVAL; 3755 goto nfsmout; 3756 } 3757 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3758 confirm.lval[1] = 1; 3759 else 3760 confirm.lval[1] = 0; 3761 v41flags = NFSV4EXCH_USENONPNFS; 3762 sp4type = fxdr_unsigned(uint32_t, *tl); 3763 if (sp4type != NFSV4EXCH_SP4NONE) { 3764 nd->nd_repstat = NFSERR_NOTSUPP; 3765 goto nfsmout; 3766 } 3767 3768 /* 3769 * nfsrv_setclient() does the actual work of adding it to the 3770 * client list. If there is no error, the structure has been 3771 * linked into the client list and clp should no longer be used 3772 * here. When an error is returned, it has not been linked in, 3773 * so it should be free'd. 3774 */ 3775 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3776 if (clp != NULL) { 3777 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3778 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3779 free(clp->lc_stateid, M_NFSDCLIENT); 3780 free(clp, M_NFSDCLIENT); 3781 } 3782 if (nd->nd_repstat == 0) { 3783 if (confirm.lval[1] != 0) 3784 v41flags |= NFSV4EXCH_CONFIRMEDR; 3785 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3786 *tl++ = clientid.lval[0]; /* ClientID */ 3787 *tl++ = clientid.lval[1]; 3788 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3789 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3790 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3791 owner_minor = 0; /* Owner */ 3792 txdr_hyper(owner_minor, tl); /* Minor */ 3793 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3794 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3795 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3796 *tl++ = txdr_unsigned(NFSX_UNSIGNED); 3797 *tl++ = time_uptime; /* Make scope a unique value. */ 3798 *tl = txdr_unsigned(1); 3799 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3800 (void)nfsm_strtom(nd, version, strlen(version)); 3801 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3802 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3803 verstime.tv_nsec = 0; 3804 txdr_nfsv4time(&verstime, tl); 3805 } 3806 NFSEXITCODE2(0, nd); 3807 return (0); 3808nfsmout: 3809 if (clp != NULL) { 3810 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3811 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3812 free(clp->lc_stateid, M_NFSDCLIENT); 3813 free(clp, M_NFSDCLIENT); 3814 } 3815 NFSEXITCODE2(error, nd); 3816 return (error); 3817} 3818 3819/* 3820 * nfsv4 create session service 3821 */ 3822APPLESTATIC int 3823nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3824 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3825{ 3826 uint32_t *tl; 3827 int error = 0; 3828 nfsquad_t clientid, confirm; 3829 struct nfsdsession *sep = NULL; 3830 uint32_t rdmacnt; 3831 3832 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3833 nd->nd_repstat = NFSERR_WRONGSEC; 3834 goto nfsmout; 3835 } 3836 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3837 M_NFSDSESSION, M_WAITOK | M_ZERO); 3838 sep->sess_refcnt = 1; 3839 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3840 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3841 clientid.lval[0] = *tl++; 3842 clientid.lval[1] = *tl++; 3843 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3844 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3845 /* Persistent sessions and RDMA are not supported. */ 3846 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3847 3848 /* Fore channel attributes. */ 3849 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3850 tl++; /* Header pad always 0. */ 3851 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3852 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3853 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3854 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3855 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3856 if (sep->sess_maxslots > NFSV4_SLOTS) 3857 sep->sess_maxslots = NFSV4_SLOTS; 3858 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3859 if (rdmacnt > 1) { 3860 nd->nd_repstat = NFSERR_BADXDR; 3861 goto nfsmout; 3862 } else if (rdmacnt == 1) 3863 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3864 3865 /* Back channel attributes. */ 3866 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3867 tl++; /* Header pad always 0. */ 3868 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3869 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3870 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3871 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3872 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3873 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3874 if (rdmacnt > 1) { 3875 nd->nd_repstat = NFSERR_BADXDR; 3876 goto nfsmout; 3877 } else if (rdmacnt == 1) 3878 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3879 3880 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3881 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3882 3883 /* 3884 * nfsrv_getclient() searches the client list for a match and 3885 * returns the appropriate NFSERR status. 3886 */ 3887 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3888 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3889 if (nd->nd_repstat == 0) { 3890 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3891 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3892 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3893 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3894 *tl++ = txdr_unsigned(sep->sess_crflags); 3895 3896 /* Fore channel attributes. */ 3897 *tl++ = 0; 3898 *tl++ = txdr_unsigned(sep->sess_maxreq); 3899 *tl++ = txdr_unsigned(sep->sess_maxresp); 3900 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3901 *tl++ = txdr_unsigned(sep->sess_maxops); 3902 *tl++ = txdr_unsigned(sep->sess_maxslots); 3903 *tl++ = txdr_unsigned(1); 3904 *tl++ = txdr_unsigned(0); /* No RDMA. */ 3905 3906 /* Back channel attributes. */ 3907 *tl++ = 0; 3908 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3909 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3910 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3911 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3912 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3913 *tl++ = txdr_unsigned(1); 3914 *tl = txdr_unsigned(0); /* No RDMA. */ 3915 } 3916nfsmout: 3917 if (nd->nd_repstat != 0 && sep != NULL) 3918 free(sep, M_NFSDSESSION); 3919 NFSEXITCODE2(error, nd); 3920 return (error); 3921} 3922 3923/* 3924 * nfsv4 sequence service 3925 */ 3926APPLESTATIC int 3927nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3928 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3929{ 3930 uint32_t *tl; 3931 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3932 int cache_this, error = 0; 3933 3934 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3935 nd->nd_repstat = NFSERR_WRONGSEC; 3936 goto nfsmout; 3937 } 3938 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3939 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3940 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3941 sequenceid = fxdr_unsigned(uint32_t, *tl++); 3942 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3943 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3944 if (*tl == newnfs_true) 3945 cache_this = 1; 3946 else 3947 cache_this = 0; 3948 nd->nd_flag |= ND_HASSEQUENCE; 3949 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3950 &target_highest_slotid, cache_this, &sflags, p); 3951 if (nd->nd_repstat == 0) { 3952 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3953 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3954 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3955 *tl++ = txdr_unsigned(sequenceid); 3956 *tl++ = txdr_unsigned(nd->nd_slotid); 3957 *tl++ = txdr_unsigned(highest_slotid); 3958 *tl++ = txdr_unsigned(target_highest_slotid); 3959 *tl = txdr_unsigned(sflags); 3960 } 3961nfsmout: 3962 NFSEXITCODE2(error, nd); 3963 return (error); 3964} 3965 3966/* 3967 * nfsv4 reclaim complete service 3968 */ 3969APPLESTATIC int 3970nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 3971 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3972{ 3973 uint32_t *tl; 3974 int error = 0; 3975 3976 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3977 nd->nd_repstat = NFSERR_WRONGSEC; 3978 goto nfsmout; 3979 } 3980 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3981 if (*tl == newnfs_true) 3982 nd->nd_repstat = NFSERR_NOTSUPP; 3983 else 3984 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 3985nfsmout: 3986 NFSEXITCODE2(error, nd); 3987 return (error); 3988} 3989 3990/* 3991 * nfsv4 destroy clientid service 3992 */ 3993APPLESTATIC int 3994nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 3995 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3996{ 3997 uint32_t *tl; 3998 nfsquad_t clientid; 3999 int error = 0; 4000 4001 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4002 nd->nd_repstat = NFSERR_WRONGSEC; 4003 goto nfsmout; 4004 } 4005 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4006 clientid.lval[0] = *tl++; 4007 clientid.lval[1] = *tl; 4008 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4009nfsmout: 4010 NFSEXITCODE2(error, nd); 4011 return (error); 4012} 4013 4014/* 4015 * nfsv4 destroy session service 4016 */ 4017APPLESTATIC int 4018nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4019 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4020{ 4021 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4022 int error = 0; 4023 4024 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4025 nd->nd_repstat = NFSERR_WRONGSEC; 4026 goto nfsmout; 4027 } 4028 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4029 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4030 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4031nfsmout: 4032 NFSEXITCODE2(error, nd); 4033 return (error); 4034} 4035 4036/* 4037 * nfsv4 free stateid service 4038 */ 4039APPLESTATIC int 4040nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4041 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4042{ 4043 uint32_t *tl; 4044 nfsv4stateid_t stateid; 4045 int error = 0; 4046 4047 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4048 nd->nd_repstat = NFSERR_WRONGSEC; 4049 goto nfsmout; 4050 } 4051 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4052 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4053 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4054 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4055nfsmout: 4056 NFSEXITCODE2(error, nd); 4057 return (error); 4058} 4059 4060/* 4061 * nfsv4 service not supported 4062 */ 4063APPLESTATIC int 4064nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4065 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4066{ 4067 4068 nd->nd_repstat = NFSERR_NOTSUPP; 4069 NFSEXITCODE2(0, nd); 4070 return (0); 4071} 4072 4073