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

Cache object: b3194b9ca9b3177dcf4dc98961867826


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