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

Cache object: 0fde77e777de6e174ca54fee2b710175


[ 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.