The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsserver/nfs_nfsdserv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3af900fe86be644f082abe5b2875b6db


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.