]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - sys/fs/nfs/nfs_commonsubs.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / sys / fs / nfs / nfs_commonsubs.c
1 /*-
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
38  * These functions support the macros and help fiddle mbuf chains for
39  * the nfs op functions. They do things like create the rpc header and
40  * copy data between mbuf chains and uio lists.
41  */
42 #ifndef APPLEKEXT
43 #include <fs/nfs/nfsport.h>
44
45 /*
46  * Data items converted to xdr at startup, since they are constant
47  * This is kinda hokey, but may save a little time doing byte swaps
48  */
49 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
50
51 /* And other global data */
52 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
53                       NFFIFO, NFNON };
54 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
55 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
56 struct timeval nfsboottime;     /* Copy boottime once, so it never changes */
57 int nfscl_ticks;
58 int nfsrv_useacl = 1;
59 struct nfssockreq nfsrv_nfsuserdsock;
60 int nfsrv_nfsuserd = 0;
61 struct nfsreqhead nfsd_reqq;
62 uid_t nfsrv_defaultuid;
63 gid_t nfsrv_defaultgid;
64 int nfsrv_lease = NFSRV_LEASE;
65 int ncl_mbuf_mlen = MLEN;
66 NFSNAMEIDMUTEX;
67 NFSSOCKMUTEX;
68
69 /*
70  * This array of structures indicates, for V4:
71  * retfh - which of 3 types of calling args are used
72  *      0 - doesn't change cfh or use a sfh
73  *      1 - replaces cfh with a new one (unless it returns an error status)
74  *      2 - uses cfh and sfh
75  * needscfh - if the op wants a cfh and premtime
76  *      0 - doesn't use a cfh
77  *      1 - uses a cfh, but doesn't want pre-op attributes
78  *      2 - uses a cfh and wants pre-op attributes
79  * savereply - indicates a non-idempotent Op
80  *      0 - not non-idempotent
81  *      1 - non-idempotent
82  * Ops that are ordered via seqid# are handled separately from these
83  * non-idempotent Ops.
84  * Define it here, since it is used by both the client and server.
85  */
86 struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
87         { 0, 0, 0, 0 },         /* undef */
88         { 0, 0, 0, 0 },         /* undef */
89         { 0, 0, 0, 0 },         /* undef */
90         { 0, 1, 0, 0 },         /* Access */
91         { 0, 1, 0, 0 },         /* Close */
92         { 0, 2, 0, 1 },         /* Commit */
93         { 1, 2, 1, 1 },         /* Create */
94         { 0, 0, 0, 0 },         /* Delegpurge */
95         { 0, 1, 0, 0 },         /* Delegreturn */
96         { 0, 1, 0, 0 },         /* Getattr */
97         { 0, 1, 0, 0 },         /* GetFH */
98         { 2, 1, 1, 1 },         /* Link */
99         { 0, 1, 0, 0 },         /* Lock */
100         { 0, 1, 0, 0 },         /* LockT */
101         { 0, 1, 0, 0 },         /* LockU */
102         { 1, 1, 0, 0 },         /* Lookup */
103         { 1, 1, 0, 0 },         /* Lookupp */
104         { 0, 1, 0, 0 },         /* NVerify */
105         { 1, 1, 0, 1 },         /* Open */
106         { 1, 1, 0, 0 },         /* OpenAttr */
107         { 0, 1, 0, 0 },         /* OpenConfirm */
108         { 0, 1, 0, 0 },         /* OpenDowngrade */
109         { 1, 0, 0, 0 },         /* PutFH */
110         { 1, 0, 0, 0 },         /* PutPubFH */
111         { 1, 0, 0, 0 },         /* PutRootFH */
112         { 0, 1, 0, 0 },         /* Read */
113         { 0, 1, 0, 0 },         /* Readdir */
114         { 0, 1, 0, 0 },         /* ReadLink */
115         { 0, 2, 1, 1 },         /* Remove */
116         { 2, 1, 1, 1 },         /* Rename */
117         { 0, 0, 0, 0 },         /* Renew */
118         { 0, 0, 0, 0 },         /* RestoreFH */
119         { 0, 1, 0, 0 },         /* SaveFH */
120         { 0, 1, 0, 0 },         /* SecInfo */
121         { 0, 2, 1, 1 },         /* Setattr */
122         { 0, 0, 0, 0 },         /* SetClientID */
123         { 0, 0, 0, 0 },         /* SetClientIDConfirm */
124         { 0, 1, 0, 0 },         /* Verify */
125         { 0, 2, 1, 1 },         /* Write */
126         { 0, 0, 0, 0 },         /* ReleaseLockOwner */
127 };
128 #endif  /* !APPLEKEXT */
129
130 static int ncl_mbuf_mhlen = MHLEN;
131 static int nfsrv_usercnt = 0;
132 static int nfsrv_dnsnamelen;
133 static u_char *nfsrv_dnsname = NULL;
134 static int nfsrv_usermax = 999999999;
135 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
136 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
137 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
138 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
139 static struct nfsuserlruhead nfsuserlruhead;
140
141 /*
142  * This static array indicates whether or not the RPC generates a large
143  * reply. This is used by nfs_reply() to decide whether or not an mbuf
144  * cluster should be allocated. (If a cluster is required by an RPC
145  * marked 0 in this array, the code will still work, just not quite as
146  * efficiently.)
147  */
148 static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
149     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150     0, 0, 0, 0, 0 };
151
152 /* local functions */
153 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
154 static void nfsv4_wanted(struct nfsv4lock *lp);
155 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
156 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
157     NFSPROC_T *p);
158 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
159 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
160     int *, int *);
161 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
162
163
164 #ifndef APPLE
165 /*
166  * copies mbuf chain to the uio scatter/gather list
167  */
168 int
169 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
170 {
171         char *mbufcp, *uiocp;
172         int xfer, left, len;
173         mbuf_t mp;
174         long uiosiz, rem;
175         int error = 0;
176
177         mp = nd->nd_md;
178         mbufcp = nd->nd_dpos;
179         len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
180         rem = NFSM_RNDUP(siz) - siz;
181         while (siz > 0) {
182                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
183                         return (EBADRPC);
184                 left = uiop->uio_iov->iov_len;
185                 uiocp = uiop->uio_iov->iov_base;
186                 if (left > siz)
187                         left = siz;
188                 uiosiz = left;
189                 while (left > 0) {
190                         while (len == 0) {
191                                 mp = mbuf_next(mp);
192                                 if (mp == NULL)
193                                         return (EBADRPC);
194                                 mbufcp = NFSMTOD(mp, caddr_t);
195                                 len = mbuf_len(mp);
196                         }
197                         xfer = (left > len) ? len : left;
198 #ifdef notdef
199                         /* Not Yet.. */
200                         if (uiop->uio_iov->iov_op != NULL)
201                                 (*(uiop->uio_iov->iov_op))
202                                 (mbufcp, uiocp, xfer);
203                         else
204 #endif
205                         if (uiop->uio_segflg == UIO_SYSSPACE)
206                                 NFSBCOPY(mbufcp, uiocp, xfer);
207                         else
208                                 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
209                         left -= xfer;
210                         len -= xfer;
211                         mbufcp += xfer;
212                         uiocp += xfer;
213                         uiop->uio_offset += xfer;
214                         uiop->uio_resid -= xfer;
215                 }
216                 if (uiop->uio_iov->iov_len <= siz) {
217                         uiop->uio_iovcnt--;
218                         uiop->uio_iov++;
219                 } else {
220                         uiop->uio_iov->iov_base = (void *)
221                                 ((char *)uiop->uio_iov->iov_base + uiosiz);
222                         uiop->uio_iov->iov_len -= uiosiz;
223                 }
224                 siz -= uiosiz;
225         }
226         nd->nd_dpos = mbufcp;
227         nd->nd_md = mp;
228         if (rem > 0) {
229                 if (len < rem)
230                         error = nfsm_advance(nd, rem, len);
231                 else
232                         nd->nd_dpos += rem;
233         }
234         return (error);
235 }
236 #endif  /* !APPLE */
237
238 /*
239  * Help break down an mbuf chain by setting the first siz bytes contiguous
240  * pointed to by returned val.
241  * This is used by the macro NFSM_DISSECT for tough
242  * cases.
243  */
244 APPLESTATIC void *
245 nfsm_dissct(struct nfsrv_descript *nd, int siz)
246 {
247         mbuf_t mp2;
248         int siz2, xfer;
249         caddr_t p;
250         int left;
251         caddr_t retp;
252
253         retp = NULL;
254         left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
255         while (left == 0) {
256                 nd->nd_md = mbuf_next(nd->nd_md);
257                 if (nd->nd_md == NULL)
258                         return (retp);
259                 left = mbuf_len(nd->nd_md);
260                 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
261         }
262         if (left >= siz) {
263                 retp = nd->nd_dpos;
264                 nd->nd_dpos += siz;
265         } else if (mbuf_next(nd->nd_md) == NULL) {
266                 return (retp);
267         } else if (siz > ncl_mbuf_mhlen) {
268                 panic("nfs S too big");
269         } else {
270                 NFSMGET(mp2);
271                 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
272                 mbuf_setnext(nd->nd_md, mp2);
273                 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
274                 nd->nd_md = mp2;
275                 retp = p = NFSMTOD(mp2, caddr_t);
276                 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
277                 siz2 = siz - left;
278                 p += left;
279                 mp2 = mbuf_next(mp2);
280                 /* Loop around copying up the siz2 bytes */
281                 while (siz2 > 0) {
282                         if (mp2 == NULL)
283                                 return (NULL);
284                         xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
285                         if (xfer > 0) {
286                                 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
287                                 NFSM_DATAP(mp2, xfer);
288                                 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
289                                 p += xfer;
290                                 siz2 -= xfer;
291                         }
292                         if (siz2 > 0)
293                                 mp2 = mbuf_next(mp2);
294                 }
295                 mbuf_setlen(nd->nd_md, siz);
296                 nd->nd_md = mp2;
297                 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
298         }
299         return (retp);
300 }
301
302 /*
303  * Advance the position in the mbuf chain.
304  * If offs == 0, this is a no-op, but it is simpler to just return from
305  * here than check for offs > 0 for all calls to nfsm_advance.
306  * If left == -1, it should be calculated here.
307  */
308 APPLESTATIC int
309 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
310 {
311
312         if (offs == 0)
313                 return (0);
314         /*
315          * A negative offs should be considered a serious problem.
316          */
317         if (offs < 0)
318                 panic("nfsrv_advance");
319
320         /*
321          * If left == -1, calculate it here.
322          */
323         if (left == -1)
324                 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
325                     nd->nd_dpos;
326
327         /*
328          * Loop around, advancing over the mbuf data.
329          */
330         while (offs > left) {
331                 offs -= left;
332                 nd->nd_md = mbuf_next(nd->nd_md);
333                 if (nd->nd_md == NULL)
334                         return (EBADRPC);
335                 left = mbuf_len(nd->nd_md);
336                 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
337         }
338         nd->nd_dpos += offs;
339         return (0);
340 }
341
342 /*
343  * Copy a string into mbuf(s).
344  * Return the number of bytes output, including XDR overheads.
345  */
346 APPLESTATIC int
347 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
348 {
349         mbuf_t m2;
350         int xfer, left;
351         mbuf_t m1;
352         int rem, bytesize;
353         u_int32_t *tl;
354         char *cp2;
355
356         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
357         *tl = txdr_unsigned(siz);
358         rem = NFSM_RNDUP(siz) - siz;
359         bytesize = NFSX_UNSIGNED + siz + rem;
360         m2 = nd->nd_mb;
361         cp2 = nd->nd_bpos;
362         left = M_TRAILINGSPACE(m2);
363
364         /*
365          * Loop around copying the string to mbuf(s).
366          */
367         while (siz > 0) {
368                 if (left == 0) {
369                         if (siz > ncl_mbuf_mlen)
370                                 NFSMCLGET(m1, M_WAIT);
371                         else
372                                 NFSMGET(m1);
373                         mbuf_setlen(m1, 0);
374                         mbuf_setnext(m2, m1);
375                         m2 = m1;
376                         cp2 = NFSMTOD(m2, caddr_t);
377                         left = M_TRAILINGSPACE(m2);
378                 }
379                 if (left >= siz)
380                         xfer = siz;
381                 else
382                         xfer = left;
383                 NFSBCOPY(cp, cp2, xfer);
384                 cp += xfer;
385                 mbuf_setlen(m2, mbuf_len(m2) + xfer);
386                 siz -= xfer;
387                 left -= xfer;
388                 if (siz == 0 && rem) {
389                         if (left < rem)
390                                 panic("nfsm_strtom");
391                         NFSBZERO(cp2 + xfer, rem);
392                         mbuf_setlen(m2, mbuf_len(m2) + rem);
393                 }
394         }
395         nd->nd_mb = m2;
396         nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
397         return (bytesize);
398 }
399
400 /*
401  * Called once to initialize data structures...
402  */
403 APPLESTATIC void
404 newnfs_init(void)
405 {
406         static int nfs_inited = 0;
407
408         if (nfs_inited)
409                 return;
410         nfs_inited = 1;
411
412         newnfs_true = txdr_unsigned(TRUE);
413         newnfs_false = txdr_unsigned(FALSE);
414         newnfs_xdrneg1 = txdr_unsigned(-1);
415         nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
416         if (nfscl_ticks < 1)
417                 nfscl_ticks = 1;
418         NFSSETBOOTTIME(nfsboottime);
419
420         /*
421          * Initialize reply list and start timer
422          */
423         TAILQ_INIT(&nfsd_reqq);
424         NFS_TIMERINIT;
425 }
426
427 /*
428  * Put a file handle in an mbuf list.
429  * If the size argument == 0, just use the default size.
430  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
431  * Return the number of bytes output, including XDR overhead.
432  */
433 APPLESTATIC int
434 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
435 {
436         u_int32_t *tl;
437         u_int8_t *cp;
438         int fullsiz, rem, bytesize = 0;
439
440         if (size == 0)
441                 size = NFSX_MYFH;
442         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
443         case ND_NFSV2:
444                 if (size > NFSX_V2FH)
445                         panic("fh size > NFSX_V2FH for NFSv2");
446                 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
447                 NFSBCOPY(fhp, cp, size);
448                 if (size < NFSX_V2FH)
449                         NFSBZERO(cp + size, NFSX_V2FH - size);
450                 bytesize = NFSX_V2FH;
451                 break;
452         case ND_NFSV3:
453         case ND_NFSV4:
454                 fullsiz = NFSM_RNDUP(size);
455                 rem = fullsiz - size;
456                 if (set_true) {
457                     bytesize = 2 * NFSX_UNSIGNED + fullsiz;
458                     NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
459                     *tl = newnfs_true;
460                 } else {
461                     bytesize = NFSX_UNSIGNED + fullsiz;
462                 }
463                 (void) nfsm_strtom(nd, fhp, size);
464                 break;
465         };
466         return (bytesize);
467 }
468
469 /*
470  * This function compares two net addresses by family and returns TRUE
471  * if they are the same host.
472  * If there is any doubt, return FALSE.
473  * The AF_INET family is handled as a special case so that address mbufs
474  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
475  */
476 APPLESTATIC int
477 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
478 {
479         struct sockaddr_in *inetaddr;
480
481         switch (family) {
482         case AF_INET:
483                 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
484                 if (inetaddr->sin_family == AF_INET &&
485                     inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
486                         return (1);
487                 break;
488 #ifdef INET6
489         case AF_INET6:
490                 {
491                 struct sockaddr_in6 *inetaddr6;
492
493                 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
494                 /* XXX - should test sin6_scope_id ? */
495                 if (inetaddr6->sin6_family == AF_INET6 &&
496                     IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
497                           &haddr->had_inet6))
498                         return (1);
499                 }
500                 break;
501 #endif
502         };
503         return (0);
504 }
505
506 /*
507  * Similar to the above, but takes to NFSSOCKADDR_T args.
508  */
509 APPLESTATIC int
510 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
511 {
512         struct sockaddr_in *addr1, *addr2;
513         struct sockaddr *inaddr;
514
515         inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
516         switch (inaddr->sa_family) {
517         case AF_INET:
518                 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
519                 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
520                 if (addr2->sin_family == AF_INET &&
521                     addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
522                         return (1);
523                 break;
524 #ifdef INET6
525         case AF_INET6:
526                 {
527                 struct sockaddr_in6 *inet6addr1, *inet6addr2;
528
529                 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
530                 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
531                 /* XXX - should test sin6_scope_id ? */
532                 if (inet6addr2->sin6_family == AF_INET6 &&
533                     IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
534                           &inet6addr2->sin6_addr))
535                         return (1);
536                 }
537                 break;
538 #endif
539         };
540         return (0);
541 }
542
543
544 /*
545  * Trim the stuff already dissected off the mbuf list.
546  */
547 APPLESTATIC void
548 newnfs_trimleading(nd)
549         struct nfsrv_descript *nd;
550 {
551         mbuf_t m, n;
552         int offs;
553
554         /*
555          * First, free up leading mbufs.
556          */
557         if (nd->nd_mrep != nd->nd_md) {
558                 m = nd->nd_mrep;
559                 while (mbuf_next(m) != nd->nd_md) {
560                         if (mbuf_next(m) == NULL)
561                                 panic("nfsm trim leading");
562                         m = mbuf_next(m);
563                 }
564                 mbuf_setnext(m, NULL);
565                 mbuf_freem(nd->nd_mrep);
566         }
567         m = nd->nd_md;
568
569         /*
570          * Now, adjust this mbuf, based on nd_dpos.
571          */
572         offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
573         if (offs == mbuf_len(m)) {
574                 n = m;
575                 m = mbuf_next(m);
576                 if (m == NULL)
577                         panic("nfsm trim leading2");
578                 mbuf_setnext(n, NULL);
579                 mbuf_freem(n);
580         } else if (offs > 0) {
581                 mbuf_setlen(m, mbuf_len(m) - offs);
582                 NFSM_DATAP(m, offs);
583         } else if (offs < 0)
584                 panic("nfsm trimleading offs");
585         nd->nd_mrep = m;
586         nd->nd_md = m;
587         nd->nd_dpos = NFSMTOD(m, caddr_t);
588 }
589
590 /*
591  * Trim trailing data off the mbuf list being built.
592  */
593 APPLESTATIC void
594 newnfs_trimtrailing(nd, mb, bpos)
595         struct nfsrv_descript *nd;
596         mbuf_t mb;
597         caddr_t bpos;
598 {
599
600         if (mbuf_next(mb)) {
601                 mbuf_freem(mbuf_next(mb));
602                 mbuf_setnext(mb, NULL);
603         }
604         mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
605         nd->nd_mb = mb;
606         nd->nd_bpos = bpos;
607 }
608
609 /*
610  * Dissect a file handle on the client.
611  */
612 APPLESTATIC int
613 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
614 {
615         u_int32_t *tl;
616         struct nfsfh *nfhp;
617         int error, len;
618
619         *nfhpp = NULL;
620         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
621                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
622                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
623                         len > NFSX_FHMAX)
624                         return (EBADRPC);
625         } else
626                 len = NFSX_V2FH;
627         MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
628             M_NFSFH, M_WAITOK);
629         error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
630         if (error) {
631                 FREE((caddr_t)nfhp, M_NFSFH);
632                 return (error);
633         }
634         nfhp->nfh_len = len;
635         *nfhpp = nfhp;
636 nfsmout:
637         return (error);
638 }
639
640 /*
641  * Break down the nfsv4 acl.
642  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
643  */
644 APPLESTATIC int
645 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
646     int *aclsizep, __unused NFSPROC_T *p)
647 {
648         u_int32_t *tl;
649         int i, aclsize;
650         int acecnt, error = 0, aceerr = 0, acesize;
651
652         *aclerrp = 0;
653 #ifdef NFS4_ACL_EXTATTR_NAME
654         if (aclp)
655                 aclp->acl_cnt = 0;
656 #endif
657         /*
658          * Parse out the ace entries and expect them to conform to
659          * what can be supported by R/W/X bits.
660          */
661         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
662         aclsize = NFSX_UNSIGNED;
663         acecnt = fxdr_unsigned(int, *tl);
664 #ifdef NFS4_ACL_EXTATTR_NAME
665         if (acecnt > ACL_MAX_ENTRIES)
666                 aceerr = 1;
667 #endif
668         if (nfsrv_useacl == 0)
669                 aceerr = 1;
670         for (i = 0; i < acecnt; i++) {
671 #ifdef NFS4_ACL_EXTATTR_NAME
672                 if (aclp && !aceerr)
673                         error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
674                             &aceerr, &acesize, p);
675                 else
676 #endif
677                         error = nfsrv_skipace(nd, &acesize);
678                 if (error)
679                         return (error);
680                 aclsize += acesize;
681         }
682 #ifdef NFS4_ACL_EXTATTR_NAME
683         if (aclp && !aceerr)
684                 aclp->acl_cnt = acecnt;
685 #endif
686         if (aceerr)
687                 *aclerrp = aceerr;
688         if (aclsizep)
689                 *aclsizep = aclsize;
690 nfsmout:
691         return (error);
692 }
693
694 /*
695  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
696  */
697 static int
698 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
699 {
700         u_int32_t *tl;
701         int error, len = 0;
702
703         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
704         len = fxdr_unsigned(int, *(tl + 3));
705         error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
706 nfsmout:
707         *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
708         return (error);
709 }
710
711 /*
712  * Get attribute bits from an mbuf list.
713  * Returns EBADRPC for a parsing error, 0 otherwise.
714  * If the clearinvalid flag is set, clear the bits not supported.
715  */
716 APPLESTATIC int
717 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
718     int *retnotsupp)
719 {
720         u_int32_t *tl;
721         int cnt, i, outcnt;
722         int error = 0;
723
724         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
725         cnt = fxdr_unsigned(int, *tl);
726         if (cnt < 0)
727                 return (NFSERR_BADXDR);
728         if (cnt > NFSATTRBIT_MAXWORDS) {
729                 outcnt = NFSATTRBIT_MAXWORDS;
730                 if (retnotsupp)
731                         *retnotsupp = NFSERR_ATTRNOTSUPP;
732         } else {
733                 outcnt = cnt;
734         }
735         NFSZERO_ATTRBIT(attrbitp);
736         if (outcnt > 0) {
737                 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
738                 for (i = 0; i < outcnt; i++)
739                         attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
740         }
741         if (cnt > outcnt)
742                 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
743         if (cntp)
744                 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
745 nfsmout:
746         return (error);
747 }
748
749 /*
750  * Get the attributes for V4.
751  * If the compare flag is true, test for any attribute changes,
752  * otherwise return the attribute values.
753  * These attributes cover fields in "struct vattr", "struct statfs",
754  * "struct nfsfsinfo", the file handle and the lease duration.
755  * The value of retcmpp is set to 1 if all attributes are the same,
756  * and 0 otherwise.
757  * Returns EBADRPC if it can't be parsed, 0 otherwise.
758  */
759 APPLESTATIC int
760 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
761     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
762     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
763     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
764     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
765 {
766         u_int32_t *tl;
767         int i = 0, j, k, l, m, bitpos, attrsum = 0;
768         int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
769         u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
770         nfsattrbit_t attrbits, retattrbits, checkattrbits;
771         struct nfsfh *tnfhp;
772         struct nfsreferral *refp;
773         u_quad_t tquad;
774         nfsquad_t tnfsquad;
775         struct timespec temptime;
776         uid_t uid;
777         gid_t gid;
778         long fid;
779         u_int32_t freenum = 0, tuint;
780         u_int64_t uquad = 0, thyp, thyp2;
781 #ifdef QUOTA
782         struct dqblk dqb;
783         uid_t savuid;
784 #endif
785
786         if (compare) {
787                 retnotsup = 0;
788                 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
789         } else {
790                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
791         }
792         if (error)
793                 return (error);
794
795         if (compare) {
796                 *retcmpp = retnotsup;
797         } else {
798                 /*
799                  * Just set default values to some of the important ones.
800                  */
801                 if (nap != NULL) {
802                         nap->na_type = VREG;
803                         nap->na_mode = 0;
804                         nap->na_rdev = (NFSDEV_T)0;
805                         nap->na_mtime.tv_sec = 0;
806                         nap->na_mtime.tv_nsec = 0;
807                         nap->na_gen = 0;
808                         nap->na_flags = 0;
809                         nap->na_blocksize = NFS_FABLKSIZE;
810                 }
811                 if (sbp != NULL) {
812                         sbp->f_bsize = NFS_FABLKSIZE;
813                         sbp->f_blocks = 0;
814                         sbp->f_bfree = 0;
815                         sbp->f_bavail = 0;
816                         sbp->f_files = 0;
817                         sbp->f_ffree = 0;
818                 }
819                 if (fsp != NULL) {
820                         fsp->fs_rtmax = 8192;
821                         fsp->fs_rtpref = 8192;
822                         fsp->fs_maxname = NFS_MAXNAMLEN;
823                         fsp->fs_wtmax = 8192;
824                         fsp->fs_wtpref = 8192;
825                         fsp->fs_wtmult = NFS_FABLKSIZE;
826                         fsp->fs_dtpref = 8192;
827                         fsp->fs_maxfilesize = 0xffffffffffffffffull;
828                         fsp->fs_timedelta.tv_sec = 0;
829                         fsp->fs_timedelta.tv_nsec = 1;
830                         fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
831                                 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
832                 }
833                 if (pc != NULL) {
834                         pc->pc_linkmax = LINK_MAX;
835                         pc->pc_namemax = NAME_MAX;
836                         pc->pc_notrunc = 0;
837                         pc->pc_chownrestricted = 0;
838                         pc->pc_caseinsensitive = 0;
839                         pc->pc_casepreserving = 1;
840                 }
841         }
842
843         /*
844          * Loop around getting the attributes.
845          */
846         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
847         attrsize = fxdr_unsigned(int, *tl);
848         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
849             if (attrsum > attrsize) {
850                 error = NFSERR_BADXDR;
851                 goto nfsmout;
852             }
853             if (NFSISSET_ATTRBIT(&attrbits, bitpos))
854                 switch (bitpos) {
855                 case NFSATTRBIT_SUPPORTEDATTRS:
856                         retnotsup = 0;
857                         if (compare || nap == NULL)
858                             error = nfsrv_getattrbits(nd, &retattrbits,
859                                 &cnt, &retnotsup);
860                         else
861                             error = nfsrv_getattrbits(nd, &nap->na_suppattr,
862                                 &cnt, &retnotsup);
863                         if (error)
864                             return (error);
865                         if (compare && !(*retcmpp)) {
866                            NFSSETSUPP_ATTRBIT(&checkattrbits);
867                            if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
868                                || retnotsup)
869                                 *retcmpp = NFSERR_NOTSAME;
870                         }
871                         attrsum += cnt;
872                         break;
873                 case NFSATTRBIT_TYPE:
874                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
875                         if (compare) {
876                                 if (!(*retcmpp)) {
877                                     if (nap->na_type != nfsv34tov_type(*tl))
878                                         *retcmpp = NFSERR_NOTSAME;
879                                 }
880                         } else if (nap != NULL) {
881                                 nap->na_type = nfsv34tov_type(*tl);
882                         }
883                         attrsum += NFSX_UNSIGNED;
884                         break;
885                 case NFSATTRBIT_FHEXPIRETYPE:
886                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
887                         if (compare && !(*retcmpp)) {
888                                 if (fxdr_unsigned(int, *tl) !=
889                                         NFSV4FHTYPE_PERSISTENT)
890                                         *retcmpp = NFSERR_NOTSAME;
891                         }
892                         attrsum += NFSX_UNSIGNED;
893                         break;
894                 case NFSATTRBIT_CHANGE:
895                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
896                         if (compare) {
897                                 if (!(*retcmpp)) {
898                                     if (nap->na_filerev != fxdr_hyper(tl))
899                                         *retcmpp = NFSERR_NOTSAME;
900                                 }
901                         } else if (nap != NULL) {
902                                 nap->na_filerev = fxdr_hyper(tl);
903                         }
904                         attrsum += NFSX_HYPER;
905                         break;
906                 case NFSATTRBIT_SIZE:
907                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
908                         if (compare) {
909                                 if (!(*retcmpp)) {
910                                     if (nap->na_size != fxdr_hyper(tl))
911                                         *retcmpp = NFSERR_NOTSAME;
912                                 }
913                         } else if (nap != NULL) {
914                                 nap->na_size = fxdr_hyper(tl);
915                         }
916                         attrsum += NFSX_HYPER;
917                         break;
918                 case NFSATTRBIT_LINKSUPPORT:
919                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
920                         if (compare) {
921                                 if (!(*retcmpp)) {
922                                     if (fsp->fs_properties & NFSV3_FSFLINK) {
923                                         if (*tl == newnfs_false)
924                                                 *retcmpp = NFSERR_NOTSAME;
925                                     } else {
926                                         if (*tl == newnfs_true)
927                                                 *retcmpp = NFSERR_NOTSAME;
928                                     }
929                                 }
930                         } else if (fsp != NULL) {
931                                 if (*tl == newnfs_true)
932                                         fsp->fs_properties |= NFSV3_FSFLINK;
933                                 else
934                                         fsp->fs_properties &= ~NFSV3_FSFLINK;
935                         }
936                         attrsum += NFSX_UNSIGNED;
937                         break;
938                 case NFSATTRBIT_SYMLINKSUPPORT:
939                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
940                         if (compare) {
941                                 if (!(*retcmpp)) {
942                                     if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
943                                         if (*tl == newnfs_false)
944                                                 *retcmpp = NFSERR_NOTSAME;
945                                     } else {
946                                         if (*tl == newnfs_true)
947                                                 *retcmpp = NFSERR_NOTSAME;
948                                     }
949                                 }
950                         } else if (fsp != NULL) {
951                                 if (*tl == newnfs_true)
952                                         fsp->fs_properties |= NFSV3_FSFSYMLINK;
953                                 else
954                                         fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
955                         }
956                         attrsum += NFSX_UNSIGNED;
957                         break;
958                 case NFSATTRBIT_NAMEDATTR:
959                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960                         if (compare && !(*retcmpp)) {
961                                 if (*tl != newnfs_false)
962                                         *retcmpp = NFSERR_NOTSAME;
963                         }
964                         attrsum += NFSX_UNSIGNED;
965                         break;
966                 case NFSATTRBIT_FSID:
967                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
968                         thyp = fxdr_hyper(tl);
969                         tl += 2;
970                         thyp2 = fxdr_hyper(tl);
971                         if (compare) {
972                             if (*retcmpp == 0) {
973                                 if (thyp != (u_int64_t)
974                                     vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
975                                     thyp2 != (u_int64_t)
976                                     vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
977                                         *retcmpp = NFSERR_NOTSAME;
978                             }
979                         } else if (nap != NULL) {
980                                 nap->na_filesid[0] = thyp;
981                                 nap->na_filesid[1] = thyp2;
982                         }
983                         attrsum += (4 * NFSX_UNSIGNED);
984                         break;
985                 case NFSATTRBIT_UNIQUEHANDLES:
986                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987                         if (compare && !(*retcmpp)) {
988                                 if (*tl != newnfs_true)
989                                         *retcmpp = NFSERR_NOTSAME;
990                         }
991                         attrsum += NFSX_UNSIGNED;
992                         break;
993                 case NFSATTRBIT_LEASETIME:
994                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
995                         if (compare) {
996                                 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
997                                     !(*retcmpp))
998                                         *retcmpp = NFSERR_NOTSAME;
999                         } else if (leasep != NULL) {
1000                                 *leasep = fxdr_unsigned(u_int32_t, *tl);
1001                         }
1002                         attrsum += NFSX_UNSIGNED;
1003                         break;
1004                 case NFSATTRBIT_RDATTRERROR:
1005                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1006                         if (compare) {
1007                                  if (!(*retcmpp))
1008                                         *retcmpp = NFSERR_INVAL;
1009                         } else if (rderrp != NULL) {
1010                                 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1011                         }
1012                         attrsum += NFSX_UNSIGNED;
1013                         break;
1014                 case NFSATTRBIT_ACL:
1015                         if (compare) {
1016                           if (!(*retcmpp)) {
1017 #ifdef NFS4_ACL_EXTATTR_NAME
1018                             if (nfsrv_useacl) {
1019                                 NFSACL_T *naclp;
1020
1021                                 naclp = acl_alloc(M_WAITOK);
1022                                 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1023                                     &cnt, p);
1024                                 if (error) {
1025                                     acl_free(naclp);
1026                                     return (error);
1027                                 }
1028                                 if (aceerr || nfsrv_compareacl(aclp, naclp))
1029                                     *retcmpp = NFSERR_NOTSAME;
1030                                 acl_free(naclp);
1031                             } else
1032 #endif
1033                             {
1034                                 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1035                                     &cnt, p);
1036                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1037                             }
1038                           }
1039                         } else {
1040                             if (vp != NULL && aclp != NULL)
1041                                 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1042                                     &cnt, p);
1043                             else
1044                                 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1045                                     &cnt, p);
1046                             if (error)
1047                                 return (error);
1048                         }
1049                         attrsum += cnt;
1050                         break;
1051                 case NFSATTRBIT_ACLSUPPORT:
1052                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053                         if (compare && !(*retcmpp)) {
1054                                 if (nfsrv_useacl) {
1055                                         if (fxdr_unsigned(u_int32_t, *tl) !=
1056                                             NFSV4ACE_SUPTYPES)
1057                                                 *retcmpp = NFSERR_NOTSAME;
1058                                 } else {
1059                                         *retcmpp = NFSERR_ATTRNOTSUPP;
1060                                 }
1061                         }
1062                         attrsum += NFSX_UNSIGNED;
1063                         break;
1064                 case NFSATTRBIT_ARCHIVE:
1065                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1066                         if (compare && !(*retcmpp))
1067                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1068                         attrsum += NFSX_UNSIGNED;
1069                         break;
1070                 case NFSATTRBIT_CANSETTIME:
1071                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1072                         if (compare) {
1073                                 if (!(*retcmpp)) {
1074                                     if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1075                                         if (*tl == newnfs_false)
1076                                                 *retcmpp = NFSERR_NOTSAME;
1077                                     } else {
1078                                         if (*tl == newnfs_true)
1079                                                 *retcmpp = NFSERR_NOTSAME;
1080                                     }
1081                                 }
1082                         } else if (fsp != NULL) {
1083                                 if (*tl == newnfs_true)
1084                                         fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1085                                 else
1086                                         fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1087                         }
1088                         attrsum += NFSX_UNSIGNED;
1089                         break;
1090                 case NFSATTRBIT_CASEINSENSITIVE:
1091                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1092                         if (compare) {
1093                                 if (!(*retcmpp)) {
1094                                     if (*tl != newnfs_false)
1095                                         *retcmpp = NFSERR_NOTSAME;
1096                                 }
1097                         } else if (pc != NULL) {
1098                                 pc->pc_caseinsensitive =
1099                                     fxdr_unsigned(u_int32_t, *tl);
1100                         }
1101                         attrsum += NFSX_UNSIGNED;
1102                         break;
1103                 case NFSATTRBIT_CASEPRESERVING:
1104                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1105                         if (compare) {
1106                                 if (!(*retcmpp)) {
1107                                     if (*tl != newnfs_true)
1108                                         *retcmpp = NFSERR_NOTSAME;
1109                                 }
1110                         } else if (pc != NULL) {
1111                                 pc->pc_casepreserving =
1112                                     fxdr_unsigned(u_int32_t, *tl);
1113                         }
1114                         attrsum += NFSX_UNSIGNED;
1115                         break;
1116                 case NFSATTRBIT_CHOWNRESTRICTED:
1117                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118                         if (compare) {
1119                                 if (!(*retcmpp)) {
1120                                     if (*tl != newnfs_true)
1121                                         *retcmpp = NFSERR_NOTSAME;
1122                                 }
1123                         } else if (pc != NULL) {
1124                                 pc->pc_chownrestricted =
1125                                     fxdr_unsigned(u_int32_t, *tl);
1126                         }
1127                         attrsum += NFSX_UNSIGNED;
1128                         break;
1129                 case NFSATTRBIT_FILEHANDLE:
1130                         error = nfsm_getfh(nd, &tnfhp);
1131                         if (error)
1132                                 return (error);
1133                         tfhsize = tnfhp->nfh_len;
1134                         if (compare) {
1135                                 if (!(*retcmpp) &&
1136                                     !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1137                                      fhp, fhsize))
1138                                         *retcmpp = NFSERR_NOTSAME;
1139                                 FREE((caddr_t)tnfhp, M_NFSFH);
1140                         } else if (nfhpp != NULL) {
1141                                 *nfhpp = tnfhp;
1142                         } else {
1143                                 FREE((caddr_t)tnfhp, M_NFSFH);
1144                         }
1145                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1146                         break;
1147                 case NFSATTRBIT_FILEID:
1148                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1149                         thyp = fxdr_hyper(tl);
1150                         if (compare) {
1151                                 if (!(*retcmpp)) {
1152                                     if ((u_int64_t)nap->na_fileid != thyp)
1153                                         *retcmpp = NFSERR_NOTSAME;
1154                                 }
1155                         } else if (nap != NULL) {
1156                                 if (*tl++)
1157                                         printf("NFSv4 fileid > 32bits\n");
1158                                 nap->na_fileid = thyp;
1159                         }
1160                         attrsum += NFSX_HYPER;
1161                         break;
1162                 case NFSATTRBIT_FILESAVAIL:
1163                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1164                         if (compare) {
1165                                 if (!(*retcmpp) &&
1166                                     sfp->sf_afiles != fxdr_hyper(tl))
1167                                         *retcmpp = NFSERR_NOTSAME;
1168                         } else if (sfp != NULL) {
1169                                 sfp->sf_afiles = fxdr_hyper(tl);
1170                         }
1171                         attrsum += NFSX_HYPER;
1172                         break;
1173                 case NFSATTRBIT_FILESFREE:
1174                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1175                         if (compare) {
1176                                 if (!(*retcmpp) &&
1177                                     sfp->sf_ffiles != fxdr_hyper(tl))
1178                                         *retcmpp = NFSERR_NOTSAME;
1179                         } else if (sfp != NULL) {
1180                                 sfp->sf_ffiles = fxdr_hyper(tl);
1181                         }
1182                         attrsum += NFSX_HYPER;
1183                         break;
1184                 case NFSATTRBIT_FILESTOTAL:
1185                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1186                         if (compare) {
1187                                 if (!(*retcmpp) &&
1188                                     sfp->sf_tfiles != fxdr_hyper(tl))
1189                                         *retcmpp = NFSERR_NOTSAME;
1190                         } else if (sfp != NULL) {
1191                                 sfp->sf_tfiles = fxdr_hyper(tl);
1192                         }
1193                         attrsum += NFSX_HYPER;
1194                         break;
1195                 case NFSATTRBIT_FSLOCATIONS:
1196                         error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1197                         if (error)
1198                                 return (error);
1199                         attrsum += l;
1200                         if (compare && !(*retcmpp)) {
1201                                 refp = nfsv4root_getreferral(vp, NULL, 0);
1202                                 if (refp != NULL) {
1203                                         if (cp == NULL || cp2 == NULL ||
1204                                             strcmp(cp, "/") ||
1205                                             strcmp(cp2, refp->nfr_srvlist))
1206                                                 *retcmpp = NFSERR_NOTSAME;
1207                                 } else if (m == 0) {
1208                                         *retcmpp = NFSERR_NOTSAME;
1209                                 }
1210                         }
1211                         if (cp != NULL)
1212                                 free(cp, M_NFSSTRING);
1213                         if (cp2 != NULL)
1214                                 free(cp2, M_NFSSTRING);
1215                         break;
1216                 case NFSATTRBIT_HIDDEN:
1217                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1218                         if (compare && !(*retcmpp))
1219                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1220                         attrsum += NFSX_UNSIGNED;
1221                         break;
1222                 case NFSATTRBIT_HOMOGENEOUS:
1223                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1224                         if (compare) {
1225                                 if (!(*retcmpp)) {
1226                                     if (fsp->fs_properties &
1227                                         NFSV3_FSFHOMOGENEOUS) {
1228                                         if (*tl == newnfs_false)
1229                                                 *retcmpp = NFSERR_NOTSAME;
1230                                     } else {
1231                                         if (*tl == newnfs_true)
1232                                                 *retcmpp = NFSERR_NOTSAME;
1233                                     }
1234                                 }
1235                         } else if (fsp != NULL) {
1236                                 if (*tl == newnfs_true)
1237                                     fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1238                                 else
1239                                     fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1240                         }
1241                         attrsum += NFSX_UNSIGNED;
1242                         break;
1243                 case NFSATTRBIT_MAXFILESIZE:
1244                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1245                         tnfsquad.qval = fxdr_hyper(tl);
1246                         if (compare) {
1247                                 if (!(*retcmpp)) {
1248                                         tquad = NFSRV_MAXFILESIZE;
1249                                         if (tquad != tnfsquad.qval)
1250                                                 *retcmpp = NFSERR_NOTSAME;
1251                                 }
1252                         } else if (fsp != NULL) {
1253                                 fsp->fs_maxfilesize = tnfsquad.qval;
1254                         }
1255                         attrsum += NFSX_HYPER;
1256                         break;
1257                 case NFSATTRBIT_MAXLINK:
1258                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1259                         if (compare) {
1260                                 if (!(*retcmpp)) {
1261                                     if (fxdr_unsigned(int, *tl) != LINK_MAX)
1262                                         *retcmpp = NFSERR_NOTSAME;
1263                                 }
1264                         } else if (pc != NULL) {
1265                                 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1266                         }
1267                         attrsum += NFSX_UNSIGNED;
1268                         break;
1269                 case NFSATTRBIT_MAXNAME:
1270                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1271                         if (compare) {
1272                                 if (!(*retcmpp)) {
1273                                     if (fsp->fs_maxname !=
1274                                         fxdr_unsigned(u_int32_t, *tl))
1275                                                 *retcmpp = NFSERR_NOTSAME;
1276                                 }
1277                         } else {
1278                                 tuint = fxdr_unsigned(u_int32_t, *tl);
1279                                 /*
1280                                  * Some Linux NFSv4 servers report this
1281                                  * as 0 or 4billion, so I'll set it to
1282                                  * NFS_MAXNAMLEN. If a server actually creates
1283                                  * a name longer than NFS_MAXNAMLEN, it will
1284                                  * get an error back.
1285                                  */
1286                                 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1287                                         tuint = NFS_MAXNAMLEN;
1288                                 if (fsp != NULL)
1289                                         fsp->fs_maxname = tuint;
1290                                 if (pc != NULL)
1291                                         pc->pc_namemax = tuint;
1292                         }
1293                         attrsum += NFSX_UNSIGNED;
1294                         break;
1295                 case NFSATTRBIT_MAXREAD:
1296                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1297                         if (compare) {
1298                                 if (!(*retcmpp)) {
1299                                     if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1300                                         *(tl + 1)) || *tl != 0)
1301                                         *retcmpp = NFSERR_NOTSAME;
1302                                 }
1303                         } else if (fsp != NULL) {
1304                                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1305                                 fsp->fs_rtpref = fsp->fs_rtmax;
1306                                 fsp->fs_dtpref = fsp->fs_rtpref;
1307                         }
1308                         attrsum += NFSX_HYPER;
1309                         break;
1310                 case NFSATTRBIT_MAXWRITE:
1311                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1312                         if (compare) {
1313                                 if (!(*retcmpp)) {
1314                                     if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1315                                         *(tl + 1)) || *tl != 0)
1316                                         *retcmpp = NFSERR_NOTSAME;
1317                                 }
1318                         } else if (fsp != NULL) {
1319                                 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1320                                 fsp->fs_wtpref = fsp->fs_wtmax;
1321                         }
1322                         attrsum += NFSX_HYPER;
1323                         break;
1324                 case NFSATTRBIT_MIMETYPE:
1325                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1326                         i = fxdr_unsigned(int, *tl);
1327                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1328                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1329                         if (error)
1330                                 goto nfsmout;
1331                         if (compare && !(*retcmpp))
1332                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1333                         break;
1334                 case NFSATTRBIT_MODE:
1335                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1336                         if (compare) {
1337                                 if (!(*retcmpp)) {
1338                                     if (nap->na_mode != nfstov_mode(*tl))
1339                                         *retcmpp = NFSERR_NOTSAME;
1340                                 }
1341                         } else if (nap != NULL) {
1342                                 nap->na_mode = nfstov_mode(*tl);
1343                         }
1344                         attrsum += NFSX_UNSIGNED;
1345                         break;
1346                 case NFSATTRBIT_NOTRUNC:
1347                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1348                         if (compare) {
1349                                 if (!(*retcmpp)) {
1350                                     if (*tl != newnfs_true)
1351                                         *retcmpp = NFSERR_NOTSAME;
1352                                 }
1353                         } else if (pc != NULL) {
1354                                 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1355                         }
1356                         attrsum += NFSX_UNSIGNED;
1357                         break;
1358                 case NFSATTRBIT_NUMLINKS:
1359                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1360                         tuint = fxdr_unsigned(u_int32_t, *tl);
1361                         if (compare) {
1362                             if (!(*retcmpp)) {
1363                                 if ((u_int32_t)nap->na_nlink != tuint)
1364                                         *retcmpp = NFSERR_NOTSAME;
1365                             }
1366                         } else if (nap != NULL) {
1367                                 nap->na_nlink = tuint;
1368                         }
1369                         attrsum += NFSX_UNSIGNED;
1370                         break;
1371                 case NFSATTRBIT_OWNER:
1372                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373                         j = fxdr_unsigned(int, *tl);
1374                         if (j < 0)
1375                                 return (NFSERR_BADXDR);
1376                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1377                         if (j > NFSV4_SMALLSTR)
1378                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1379                         else
1380                                 cp = namestr;
1381                         error = nfsrv_mtostr(nd, cp, j);
1382                         if (error) {
1383                                 if (j > NFSV4_SMALLSTR)
1384                                         free(cp, M_NFSSTRING);
1385                                 return (error);
1386                         }
1387                         if (compare) {
1388                             if (!(*retcmpp)) {
1389                                 if (nfsv4_strtouid(cp, j, &uid, p) ||
1390                                     nap->na_uid != uid)
1391                                     *retcmpp = NFSERR_NOTSAME;
1392                             }
1393                         } else if (nap != NULL) {
1394                                 if (nfsv4_strtouid(cp, j, &uid, p))
1395                                         nap->na_uid = nfsrv_defaultuid;
1396                                 else
1397                                         nap->na_uid = uid;
1398                         }
1399                         if (j > NFSV4_SMALLSTR)
1400                                 free(cp, M_NFSSTRING);
1401                         break;
1402                 case NFSATTRBIT_OWNERGROUP:
1403                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404                         j = fxdr_unsigned(int, *tl);
1405                         if (j < 0)
1406                                 return (NFSERR_BADXDR);
1407                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1408                         if (j > NFSV4_SMALLSTR)
1409                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1410                         else
1411                                 cp = namestr;
1412                         error = nfsrv_mtostr(nd, cp, j);
1413                         if (error) {
1414                                 if (j > NFSV4_SMALLSTR)
1415                                         free(cp, M_NFSSTRING);
1416                                 return (error);
1417                         }
1418                         if (compare) {
1419                             if (!(*retcmpp)) {
1420                                 if (nfsv4_strtogid(cp, j, &gid, p) ||
1421                                     nap->na_gid != gid)
1422                                     *retcmpp = NFSERR_NOTSAME;
1423                             }
1424                         } else if (nap != NULL) {
1425                                 if (nfsv4_strtogid(cp, j, &gid, p))
1426                                         nap->na_gid = nfsrv_defaultgid;
1427                                 else
1428                                         nap->na_gid = gid;
1429                         }
1430                         if (j > NFSV4_SMALLSTR)
1431                                 free(cp, M_NFSSTRING);
1432                         break;
1433                 case NFSATTRBIT_QUOTAHARD:
1434                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1435                         if (sbp != NULL) {
1436                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1437                                 freenum = sbp->f_bfree;
1438                             else
1439                                 freenum = sbp->f_bavail;
1440 #ifdef QUOTA
1441                             /*
1442                              * ufs_quotactl() insists that the uid argument
1443                              * equal p_ruid for non-root quota access, so
1444                              * we'll just make sure that's the case.
1445                              */
1446                             savuid = p->p_cred->p_ruid;
1447                             p->p_cred->p_ruid = cred->cr_uid;
1448                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1449                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1450                                 freenum = min(dqb.dqb_bhardlimit, freenum);
1451                             p->p_cred->p_ruid = savuid;
1452 #endif  /* QUOTA */
1453                             uquad = (u_int64_t)freenum;
1454                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1455                         }
1456                         if (compare && !(*retcmpp)) {
1457                                 if (uquad != fxdr_hyper(tl))
1458                                         *retcmpp = NFSERR_NOTSAME;
1459                         }
1460                         attrsum += NFSX_HYPER;
1461                         break;
1462                 case NFSATTRBIT_QUOTASOFT:
1463                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1464                         if (sbp != NULL) {
1465                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1466                                 freenum = sbp->f_bfree;
1467                             else
1468                                 freenum = sbp->f_bavail;
1469 #ifdef QUOTA
1470                             /*
1471                              * ufs_quotactl() insists that the uid argument
1472                              * equal p_ruid for non-root quota access, so
1473                              * we'll just make sure that's the case.
1474                              */
1475                             savuid = p->p_cred->p_ruid;
1476                             p->p_cred->p_ruid = cred->cr_uid;
1477                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1478                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1479                                 freenum = min(dqb.dqb_bsoftlimit, freenum);
1480                             p->p_cred->p_ruid = savuid;
1481 #endif  /* QUOTA */
1482                             uquad = (u_int64_t)freenum;
1483                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1484                         }
1485                         if (compare && !(*retcmpp)) {
1486                                 if (uquad != fxdr_hyper(tl))
1487                                         *retcmpp = NFSERR_NOTSAME;
1488                         }
1489                         attrsum += NFSX_HYPER;
1490                         break;
1491                 case NFSATTRBIT_QUOTAUSED:
1492                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1493                         if (sbp != NULL) {
1494                             freenum = 0;
1495 #ifdef QUOTA
1496                             /*
1497                              * ufs_quotactl() insists that the uid argument
1498                              * equal p_ruid for non-root quota access, so
1499                              * we'll just make sure that's the case.
1500                              */
1501                             savuid = p->p_cred->p_ruid;
1502                             p->p_cred->p_ruid = cred->cr_uid;
1503                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1504                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1505                                 freenum = dqb.dqb_curblocks;
1506                             p->p_cred->p_ruid = savuid;
1507 #endif  /* QUOTA */
1508                             uquad = (u_int64_t)freenum;
1509                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1510                         }
1511                         if (compare && !(*retcmpp)) {
1512                                 if (uquad != fxdr_hyper(tl))
1513                                         *retcmpp = NFSERR_NOTSAME;
1514                         }
1515                         attrsum += NFSX_HYPER;
1516                         break;
1517                 case NFSATTRBIT_RAWDEV:
1518                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1519                         j = fxdr_unsigned(int, *tl++);
1520                         k = fxdr_unsigned(int, *tl);
1521                         if (compare) {
1522                             if (!(*retcmpp)) {
1523                                 if (nap->na_rdev != NFSMAKEDEV(j, k))
1524                                         *retcmpp = NFSERR_NOTSAME;
1525                             }
1526                         } else if (nap != NULL) {
1527                                 nap->na_rdev = NFSMAKEDEV(j, k);
1528                         }
1529                         attrsum += NFSX_V4SPECDATA;
1530                         break;
1531                 case NFSATTRBIT_SPACEAVAIL:
1532                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1533                         if (compare) {
1534                                 if (!(*retcmpp) &&
1535                                     sfp->sf_abytes != fxdr_hyper(tl))
1536                                         *retcmpp = NFSERR_NOTSAME;
1537                         } else if (sfp != NULL) {
1538                                 sfp->sf_abytes = fxdr_hyper(tl);
1539                         }
1540                         attrsum += NFSX_HYPER;
1541                         break;
1542                 case NFSATTRBIT_SPACEFREE:
1543                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1544                         if (compare) {
1545                                 if (!(*retcmpp) &&
1546                                     sfp->sf_fbytes != fxdr_hyper(tl))
1547                                         *retcmpp = NFSERR_NOTSAME;
1548                         } else if (sfp != NULL) {
1549                                 sfp->sf_fbytes = fxdr_hyper(tl);
1550                         }
1551                         attrsum += NFSX_HYPER;
1552                         break;
1553                 case NFSATTRBIT_SPACETOTAL:
1554                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1555                         if (compare) {
1556                                 if (!(*retcmpp) &&
1557                                     sfp->sf_tbytes != fxdr_hyper(tl))
1558                                         *retcmpp = NFSERR_NOTSAME;
1559                         } else if (sfp != NULL) {
1560                                 sfp->sf_tbytes = fxdr_hyper(tl);
1561                         }
1562                         attrsum += NFSX_HYPER;
1563                         break;
1564                 case NFSATTRBIT_SPACEUSED:
1565                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1566                         thyp = fxdr_hyper(tl);
1567                         if (compare) {
1568                             if (!(*retcmpp)) {
1569                                 if ((u_int64_t)nap->na_bytes != thyp)
1570                                         *retcmpp = NFSERR_NOTSAME;
1571                             }
1572                         } else if (nap != NULL) {
1573                                 nap->na_bytes = thyp;
1574                         }
1575                         attrsum += NFSX_HYPER;
1576                         break;
1577                 case NFSATTRBIT_SYSTEM:
1578                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1579                         if (compare && !(*retcmpp))
1580                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1581                         attrsum += NFSX_UNSIGNED;
1582                         break;
1583                 case NFSATTRBIT_TIMEACCESS:
1584                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1585                         fxdr_nfsv4time(tl, &temptime);
1586                         if (compare) {
1587                             if (!(*retcmpp)) {
1588                                 if (!NFS_CMPTIME(temptime, nap->na_atime))
1589                                         *retcmpp = NFSERR_NOTSAME;
1590                             }
1591                         } else if (nap != NULL) {
1592                                 nap->na_atime = temptime;
1593                         }
1594                         attrsum += NFSX_V4TIME;
1595                         break;
1596                 case NFSATTRBIT_TIMEACCESSSET:
1597                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1598                         attrsum += NFSX_UNSIGNED;
1599                         i = fxdr_unsigned(int, *tl);
1600                         if (i == NFSV4SATTRTIME_TOCLIENT) {
1601                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1602                                 attrsum += NFSX_V4TIME;
1603                         }
1604                         if (compare && !(*retcmpp))
1605                                 *retcmpp = NFSERR_INVAL;
1606                         break;
1607                 case NFSATTRBIT_TIMEBACKUP:
1608                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1609                         if (compare && !(*retcmpp))
1610                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1611                         attrsum += NFSX_V4TIME;
1612                         break;
1613                 case NFSATTRBIT_TIMECREATE:
1614                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1615                         if (compare && !(*retcmpp))
1616                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1617                         attrsum += NFSX_V4TIME;
1618                         break;
1619                 case NFSATTRBIT_TIMEDELTA:
1620                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1621                         if (fsp != NULL) {
1622                             if (compare) {
1623                                 if (!(*retcmpp)) {
1624                                     if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1625                                         fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1626                                         (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1627                                         (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1628                                          1000000000) ||
1629                                         *tl != 0)
1630                                             *retcmpp = NFSERR_NOTSAME;
1631                                 }
1632                             } else {
1633                                 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1634                             }
1635                         }
1636                         attrsum += NFSX_V4TIME;
1637                         break;
1638                 case NFSATTRBIT_TIMEMETADATA:
1639                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1640                         fxdr_nfsv4time(tl, &temptime);
1641                         if (compare) {
1642                             if (!(*retcmpp)) {
1643                                 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1644                                         *retcmpp = NFSERR_NOTSAME;
1645                             }
1646                         } else if (nap != NULL) {
1647                                 nap->na_ctime = temptime;
1648                         }
1649                         attrsum += NFSX_V4TIME;
1650                         break;
1651                 case NFSATTRBIT_TIMEMODIFY:
1652                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1653                         fxdr_nfsv4time(tl, &temptime);
1654                         if (compare) {
1655                             if (!(*retcmpp)) {
1656                                 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1657                                         *retcmpp = NFSERR_NOTSAME;
1658                             }
1659                         } else if (nap != NULL) {
1660                                 nap->na_mtime = temptime;
1661                         }
1662                         attrsum += NFSX_V4TIME;
1663                         break;
1664                 case NFSATTRBIT_TIMEMODIFYSET:
1665                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1666                         attrsum += NFSX_UNSIGNED;
1667                         i = fxdr_unsigned(int, *tl);
1668                         if (i == NFSV4SATTRTIME_TOCLIENT) {
1669                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1670                                 attrsum += NFSX_V4TIME;
1671                         }
1672                         if (compare && !(*retcmpp))
1673                                 *retcmpp = NFSERR_INVAL;
1674                         break;
1675                 case NFSATTRBIT_MOUNTEDONFILEID:
1676                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1677                         thyp = fxdr_hyper(tl);
1678                         if (compare) {
1679                             if (!(*retcmpp)) {
1680                                 if (*tl++) {
1681                                         *retcmpp = NFSERR_NOTSAME;
1682                                 } else {
1683                                         if (!vp || !nfsrv_atroot(vp, &fid))
1684                                                 fid = nap->na_fileid;
1685                                         if ((u_int64_t)fid != thyp)
1686                                                 *retcmpp = NFSERR_NOTSAME;
1687                                 }
1688                             }
1689                         } else if (nap != NULL) {
1690                             if (*tl++)
1691                                 printf("NFSv4 mounted on fileid > 32bits\n");
1692                             nap->na_mntonfileno = thyp;
1693                         }
1694                         attrsum += NFSX_HYPER;
1695                         break;
1696                 default:
1697                         printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1698                                 bitpos);
1699                         if (compare && !(*retcmpp))
1700                                 *retcmpp = NFSERR_ATTRNOTSUPP;
1701                         /*
1702                          * and get out of the loop, since we can't parse
1703                          * the unknown attrbute data.
1704                          */
1705                         bitpos = NFSATTRBIT_MAX;
1706                         break;
1707                 };
1708         }
1709
1710         /*
1711          * some clients pad the attrlist, so we need to skip over the
1712          * padding.
1713          */
1714         if (attrsum > attrsize) {
1715                 error = NFSERR_BADXDR;
1716         } else {
1717                 attrsize = NFSM_RNDUP(attrsize);
1718                 if (attrsum < attrsize)
1719                         error = nfsm_advance(nd, attrsize - attrsum, -1);
1720         }
1721 nfsmout:
1722         return (error);
1723 }
1724
1725 /*
1726  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1727  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1728  * The first argument is a pointer to an nfsv4lock structure.
1729  * The second argument is 1 iff a blocking lock is wanted.
1730  * If this argument is 0, the call waits until no thread either wants nor
1731  * holds an exclusive lock.
1732  * It returns 1 if the lock was acquired, 0 otherwise.
1733  * If several processes call this function concurrently wanting the exclusive
1734  * lock, one will get the lock and the rest will return without getting the
1735  * lock. (If the caller must have the lock, it simply calls this function in a
1736  *  loop until the function returns 1 to indicate the lock was acquired.)
1737  * Any usecnt must be decremented by calling nfsv4_relref() before
1738  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1739  * be called in a loop.
1740  * The last argument is set to indicate if the call slept, iff not NULL.
1741  */
1742 APPLESTATIC int
1743 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1744     void *mutex)
1745 {
1746
1747         if (isleptp)
1748                 *isleptp = 0;
1749         /*
1750          * If a lock is wanted, loop around until the lock is acquired by
1751          * someone and then released. If I want the lock, try to acquire it.
1752          * For a lock to be issued, no lock must be in force and the usecnt
1753          * must be zero.
1754          */
1755         if (iwantlock) {
1756             if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1757                 lp->nfslock_usecnt == 0) {
1758                 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1759                 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1760                 return (1);
1761             }
1762             lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1763         }
1764         while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1765                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1766                 if (isleptp)
1767                         *isleptp = 1;
1768                 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1769                     PZERO - 1, "nfsv4lck", NULL);
1770                 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1771                     lp->nfslock_usecnt == 0) {
1772                         lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1773                         lp->nfslock_lock |= NFSV4LOCK_LOCK;
1774                         return (1);
1775                 }
1776         }
1777         return (0);
1778 }
1779
1780 /*
1781  * Release the lock acquired by nfsv4_lock().
1782  * The second argument is set to 1 to indicate the nfslock_usecnt should be
1783  * incremented, as well.
1784  */
1785 APPLESTATIC void
1786 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1787 {
1788
1789         lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1790         if (incref)
1791                 lp->nfslock_usecnt++;
1792         nfsv4_wanted(lp);
1793 }
1794
1795 /*
1796  * Release a reference cnt.
1797  */
1798 APPLESTATIC void
1799 nfsv4_relref(struct nfsv4lock *lp)
1800 {
1801
1802         if (lp->nfslock_usecnt <= 0)
1803                 panic("nfsv4root ref cnt");
1804         lp->nfslock_usecnt--;
1805         if (lp->nfslock_usecnt == 0)
1806                 nfsv4_wanted(lp);
1807 }
1808
1809 /*
1810  * Get a reference cnt.
1811  * This function will wait for any exclusive lock to be released, but will
1812  * not wait for threads that want the exclusive lock. If priority needs
1813  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1814  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1815  */
1816 APPLESTATIC void
1817 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
1818 {
1819
1820         if (isleptp)
1821                 *isleptp = 0;
1822
1823         /*
1824          * Wait for a lock held.
1825          */
1826         while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1827                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1828                 if (isleptp)
1829                         *isleptp = 1;
1830                 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1831                     PZERO - 1, "nfsv4lck", NULL);
1832         }
1833
1834         lp->nfslock_usecnt++;
1835 }
1836
1837 /*
1838  * Wake up anyone sleeping, waiting for this lock.
1839  */
1840 static void
1841 nfsv4_wanted(struct nfsv4lock *lp)
1842 {
1843
1844         if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1845                 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1846                 wakeup((caddr_t)&lp->nfslock_lock);
1847         }
1848 }
1849
1850 /*
1851  * Copy a string from an mbuf list into a character array.
1852  * Return EBADRPC if there is an mbuf error,
1853  * 0 otherwise.
1854  */
1855 APPLESTATIC int
1856 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1857 {
1858         char *cp;
1859         int xfer, len;
1860         mbuf_t mp;
1861         int rem, error = 0;
1862
1863         mp = nd->nd_md;
1864         cp = nd->nd_dpos;
1865         len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1866         rem = NFSM_RNDUP(siz) - siz;
1867         while (siz > 0) {
1868                 if (len > siz)
1869                         xfer = siz;
1870                 else
1871                         xfer = len;
1872                 NFSBCOPY(cp, str, xfer);
1873                 str += xfer;
1874                 siz -= xfer;
1875                 if (siz > 0) {
1876                         mp = mbuf_next(mp);
1877                         if (mp == NULL)
1878                                 return (EBADRPC);
1879                         cp = NFSMTOD(mp, caddr_t);
1880                         len = mbuf_len(mp);
1881                 } else {
1882                         cp += xfer;
1883                         len -= xfer;
1884                 }
1885         }
1886         *str = '\0';
1887         nd->nd_dpos = cp;
1888         nd->nd_md = mp;
1889         if (rem > 0) {
1890                 if (len < rem)
1891                         error = nfsm_advance(nd, rem, len);
1892                 else
1893                         nd->nd_dpos += rem;
1894         }
1895         return (error);
1896 }
1897
1898 /*
1899  * Fill in the attributes as marked by the bitmap (V4).
1900  */
1901 APPLESTATIC int
1902 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
1903     struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1904     struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
1905 {
1906         int bitpos, retnum = 0;
1907         u_int32_t *tl;
1908         int siz, prefixnum, error;
1909         u_char *cp, namestr[NFSV4_SMALLSTR];
1910         nfsattrbit_t attrbits, retbits;
1911         nfsattrbit_t *retbitp = &retbits;
1912         u_int32_t freenum, *retnump;
1913         u_int64_t uquad;
1914         long fid;
1915         struct statfs fs;
1916         struct nfsfsinfo fsinf;
1917         struct timespec temptime;
1918         struct timeval curtime;
1919         NFSACL_T *aclp, *naclp = NULL;
1920 #ifdef QUOTA
1921         struct dqblk dqb;
1922         uid_t savuid;
1923 #endif
1924
1925         /*
1926          * First, set the bits that can be filled and get fsinfo.
1927          */
1928         NFSSET_ATTRBIT(retbitp, attrbitp);
1929         /* If p and cred are NULL, it is a client side call */
1930         if (p == NULL && cred == NULL) {
1931                 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1932                 aclp = saclp;
1933         } else {
1934                 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1935 #ifdef NFS4_ACL_EXTATTR_NAME
1936                 naclp = acl_alloc(M_WAITOK);
1937 #endif
1938                 aclp = naclp;
1939         }
1940         nfsvno_getfs(&fsinf, isdgram);
1941 #ifndef APPLE
1942         /*
1943          * Get the VFS_STATFS(), since some attributes need them.
1944          */
1945         if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
1946                 error = VFS_STATFS(vnode_mount(vp), &fs);
1947                 if (error != 0) {
1948                         if (reterr) {
1949                                 nd->nd_repstat = NFSERR_ACCES;
1950                                 return (0);
1951                         }
1952                         NFSCLRSTATFS_ATTRBIT(retbitp);
1953                 }
1954         }
1955 #endif
1956
1957         /*
1958          * And the NFSv4 ACL...
1959          */
1960         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT)
1961 #ifdef NFS4_ACL_EXTATTR_NAME
1962             && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1963                 !NFSHASNFS4ACL(vnode_mount(vp))))
1964 #endif
1965             ) {
1966                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1967         }
1968         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1969 #ifdef NFS4_ACL_EXTATTR_NAME
1970                 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1971                     !NFSHASNFS4ACL(vnode_mount(vp)))) {
1972 #endif
1973                         NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1974 #ifdef NFS4_ACL_EXTATTR_NAME
1975                 } else if (naclp != NULL) {
1976                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
1977                         error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
1978                         if (error == 0)
1979                                 error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
1980                                     cred, p);
1981                         NFSVOPUNLOCK(vp, 0, p);
1982                         if (error != 0) {
1983                                 if (reterr) {
1984                                         nd->nd_repstat = NFSERR_ACCES;
1985                                         return (0);
1986                                 }
1987                                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1988                         }
1989                 }
1990 #endif
1991         }
1992         /*
1993          * Put out the attribute bitmap for the ones being filled in
1994          * and get the field for the number of attributes returned.
1995          */
1996         prefixnum = nfsrv_putattrbit(nd, retbitp);
1997         NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1998         prefixnum += NFSX_UNSIGNED;
1999
2000         /*
2001          * Now, loop around filling in the attributes for each bit set.
2002          */
2003         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2004             if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2005                 switch (bitpos) {
2006                 case NFSATTRBIT_SUPPORTEDATTRS:
2007                         NFSSETSUPP_ATTRBIT(&attrbits);
2008 #ifdef NFS4_ACL_EXTATTR_NAME
2009                         if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2010                             && !NFSHASNFS4ACL(vnode_mount(vp))))
2011 #endif
2012                         {
2013                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2014                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2015                         }
2016                         retnum += nfsrv_putattrbit(nd, &attrbits);
2017                         break;
2018                 case NFSATTRBIT_TYPE:
2019                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2020                         *tl = vtonfsv34_type(vap->va_type);
2021                         retnum += NFSX_UNSIGNED;
2022                         break;
2023                 case NFSATTRBIT_FHEXPIRETYPE:
2024                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2025                         *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2026                         retnum += NFSX_UNSIGNED;
2027                         break;
2028                 case NFSATTRBIT_CHANGE:
2029                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2030                         txdr_hyper(vap->va_filerev, tl);
2031                         retnum += NFSX_HYPER;
2032                         break;
2033                 case NFSATTRBIT_SIZE:
2034                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2035                         txdr_hyper(vap->va_size, tl);
2036                         retnum += NFSX_HYPER;
2037                         break;
2038                 case NFSATTRBIT_LINKSUPPORT:
2039                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2040                         if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2041                                 *tl = newnfs_true;
2042                         else
2043                                 *tl = newnfs_false;
2044                         retnum += NFSX_UNSIGNED;
2045                         break;
2046                 case NFSATTRBIT_SYMLINKSUPPORT:
2047                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2048                         if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2049                                 *tl = newnfs_true;
2050                         else
2051                                 *tl = newnfs_false;
2052                         retnum += NFSX_UNSIGNED;
2053                         break;
2054                 case NFSATTRBIT_NAMEDATTR:
2055                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2056                         *tl = newnfs_false;
2057                         retnum += NFSX_UNSIGNED;
2058                         break;
2059                 case NFSATTRBIT_FSID:
2060                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2061                         *tl++ = 0;
2062                         *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
2063                         *tl++ = 0;
2064                         *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
2065                         retnum += NFSX_V4FSID;
2066                         break;
2067                 case NFSATTRBIT_UNIQUEHANDLES:
2068                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2069                         *tl = newnfs_true;
2070                         retnum += NFSX_UNSIGNED;
2071                         break;
2072                 case NFSATTRBIT_LEASETIME:
2073                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2074                         *tl = txdr_unsigned(nfsrv_lease);
2075                         retnum += NFSX_UNSIGNED;
2076                         break;
2077                 case NFSATTRBIT_RDATTRERROR:
2078                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2079                         *tl = txdr_unsigned(rderror);
2080                         retnum += NFSX_UNSIGNED;
2081                         break;
2082                 /*
2083                  * Recommended Attributes. (Only the supported ones.)
2084                  */
2085 #ifdef NFS4_ACL_EXTATTR_NAME
2086                 case NFSATTRBIT_ACL:
2087                         retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2088                         break;
2089                 case NFSATTRBIT_ACLSUPPORT:
2090                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2091                         *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2092                         retnum += NFSX_UNSIGNED;
2093                         break;
2094 #endif
2095                 case NFSATTRBIT_CANSETTIME:
2096                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2097                         if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2098                                 *tl = newnfs_true;
2099                         else
2100                                 *tl = newnfs_false;
2101                         retnum += NFSX_UNSIGNED;
2102                         break;
2103                 case NFSATTRBIT_CASEINSENSITIVE:
2104                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2105                         *tl = newnfs_false;
2106                         retnum += NFSX_UNSIGNED;
2107                         break;
2108                 case NFSATTRBIT_CASEPRESERVING:
2109                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110                         *tl = newnfs_true;
2111                         retnum += NFSX_UNSIGNED;
2112                         break;
2113                 case NFSATTRBIT_CHOWNRESTRICTED:
2114                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2115                         *tl = newnfs_true;
2116                         retnum += NFSX_UNSIGNED;
2117                         break;
2118                 case NFSATTRBIT_FILEHANDLE:
2119                         retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2120                         break;
2121                 case NFSATTRBIT_FILEID:
2122                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2123                         *tl++ = 0;
2124                         *tl = txdr_unsigned(vap->va_fileid);
2125                         retnum += NFSX_HYPER;
2126                         break;
2127                 case NFSATTRBIT_FILESAVAIL:
2128                         /*
2129                          * Check quota and use min(quota, f_ffree).
2130                          */
2131                         freenum = fs.f_ffree;
2132 #ifdef QUOTA
2133                         /*
2134                          * ufs_quotactl() insists that the uid argument
2135                          * equal p_ruid for non-root quota access, so
2136                          * we'll just make sure that's the case.
2137                          */
2138                         savuid = p->p_cred->p_ruid;
2139                         p->p_cred->p_ruid = cred->cr_uid;
2140                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2141                             cred->cr_uid, (caddr_t)&dqb))
2142                             freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2143                                 freenum);
2144                         p->p_cred->p_ruid = savuid;
2145 #endif  /* QUOTA */
2146                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2147                         *tl++ = 0;
2148                         *tl = txdr_unsigned(freenum);
2149                         retnum += NFSX_HYPER;
2150                         break;
2151                 case NFSATTRBIT_FILESFREE:
2152                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2153                         *tl++ = 0;
2154                         *tl = txdr_unsigned(fs.f_ffree);
2155                         retnum += NFSX_HYPER;
2156                         break;
2157                 case NFSATTRBIT_FILESTOTAL:
2158                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2159                         *tl++ = 0;
2160                         *tl = txdr_unsigned(fs.f_files);
2161                         retnum += NFSX_HYPER;
2162                         break;
2163                 case NFSATTRBIT_FSLOCATIONS:
2164                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2165                         *tl++ = 0;
2166                         *tl = 0;
2167                         retnum += 2 * NFSX_UNSIGNED;
2168                         break;
2169                 case NFSATTRBIT_HOMOGENEOUS:
2170                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2171                         if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2172                                 *tl = newnfs_true;
2173                         else
2174                                 *tl = newnfs_false;
2175                         retnum += NFSX_UNSIGNED;
2176                         break;
2177                 case NFSATTRBIT_MAXFILESIZE:
2178                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2179                         uquad = NFSRV_MAXFILESIZE;
2180                         txdr_hyper(uquad, tl);
2181                         retnum += NFSX_HYPER;
2182                         break;
2183                 case NFSATTRBIT_MAXLINK:
2184                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185                         *tl = txdr_unsigned(LINK_MAX);
2186                         retnum += NFSX_UNSIGNED;
2187                         break;
2188                 case NFSATTRBIT_MAXNAME:
2189                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190                         *tl = txdr_unsigned(NFS_MAXNAMLEN);
2191                         retnum += NFSX_UNSIGNED;
2192                         break;
2193                 case NFSATTRBIT_MAXREAD:
2194                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2195                         *tl++ = 0;
2196                         *tl = txdr_unsigned(fsinf.fs_rtmax);
2197                         retnum += NFSX_HYPER;
2198                         break;
2199                 case NFSATTRBIT_MAXWRITE:
2200                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2201                         *tl++ = 0;
2202                         *tl = txdr_unsigned(fsinf.fs_wtmax);
2203                         retnum += NFSX_HYPER;
2204                         break;
2205                 case NFSATTRBIT_MODE:
2206                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2207                         *tl = vtonfsv34_mode(vap->va_mode);
2208                         retnum += NFSX_UNSIGNED;
2209                         break;
2210                 case NFSATTRBIT_NOTRUNC:
2211                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2212                         *tl = newnfs_true;
2213                         retnum += NFSX_UNSIGNED;
2214                         break;
2215                 case NFSATTRBIT_NUMLINKS:
2216                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2217                         *tl = txdr_unsigned(vap->va_nlink);
2218                         retnum += NFSX_UNSIGNED;
2219                         break;
2220                 case NFSATTRBIT_OWNER:
2221                         cp = namestr;
2222                         nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2223                         retnum += nfsm_strtom(nd, cp, siz);
2224                         if (cp != namestr)
2225                                 free(cp, M_NFSSTRING);
2226                         break;
2227                 case NFSATTRBIT_OWNERGROUP:
2228                         cp = namestr;
2229                         nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2230                         retnum += nfsm_strtom(nd, cp, siz);
2231                         if (cp != namestr)
2232                                 free(cp, M_NFSSTRING);
2233                         break;
2234                 case NFSATTRBIT_QUOTAHARD:
2235                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2236                                 freenum = fs.f_bfree;
2237                         else
2238                                 freenum = fs.f_bavail;
2239 #ifdef QUOTA
2240                         /*
2241                          * ufs_quotactl() insists that the uid argument
2242                          * equal p_ruid for non-root quota access, so
2243                          * we'll just make sure that's the case.
2244                          */
2245                         savuid = p->p_cred->p_ruid;
2246                         p->p_cred->p_ruid = cred->cr_uid;
2247                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2248                             cred->cr_uid, (caddr_t)&dqb))
2249                             freenum = min(dqb.dqb_bhardlimit, freenum);
2250                         p->p_cred->p_ruid = savuid;
2251 #endif  /* QUOTA */
2252                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2253                         uquad = (u_int64_t)freenum;
2254                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2255                         txdr_hyper(uquad, tl);
2256                         retnum += NFSX_HYPER;
2257                         break;
2258                 case NFSATTRBIT_QUOTASOFT:
2259                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2260                                 freenum = fs.f_bfree;
2261                         else
2262                                 freenum = fs.f_bavail;
2263 #ifdef QUOTA
2264                         /*
2265                          * ufs_quotactl() insists that the uid argument
2266                          * equal p_ruid for non-root quota access, so
2267                          * we'll just make sure that's the case.
2268                          */
2269                         savuid = p->p_cred->p_ruid;
2270                         p->p_cred->p_ruid = cred->cr_uid;
2271                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2272                             cred->cr_uid, (caddr_t)&dqb))
2273                             freenum = min(dqb.dqb_bsoftlimit, freenum);
2274                         p->p_cred->p_ruid = savuid;
2275 #endif  /* QUOTA */
2276                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2277                         uquad = (u_int64_t)freenum;
2278                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2279                         txdr_hyper(uquad, tl);
2280                         retnum += NFSX_HYPER;
2281                         break;
2282                 case NFSATTRBIT_QUOTAUSED:
2283                         freenum = 0;
2284 #ifdef QUOTA
2285                         /*
2286                          * ufs_quotactl() insists that the uid argument
2287                          * equal p_ruid for non-root quota access, so
2288                          * we'll just make sure that's the case.
2289                          */
2290                         savuid = p->p_cred->p_ruid;
2291                         p->p_cred->p_ruid = cred->cr_uid;
2292                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2293                             cred->cr_uid, (caddr_t)&dqb))
2294                             freenum = dqb.dqb_curblocks;
2295                         p->p_cred->p_ruid = savuid;
2296 #endif  /* QUOTA */
2297                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2298                         uquad = (u_int64_t)freenum;
2299                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2300                         txdr_hyper(uquad, tl);
2301                         retnum += NFSX_HYPER;
2302                         break;
2303                 case NFSATTRBIT_RAWDEV:
2304                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2305                         *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2306                         *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2307                         retnum += NFSX_V4SPECDATA;
2308                         break;
2309                 case NFSATTRBIT_SPACEAVAIL:
2310                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2311                         if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2312                                 uquad = (u_int64_t)fs.f_bfree;
2313                         else
2314                                 uquad = (u_int64_t)fs.f_bavail;
2315                         uquad *= fs.f_bsize;
2316                         txdr_hyper(uquad, tl);
2317                         retnum += NFSX_HYPER;
2318                         break;
2319                 case NFSATTRBIT_SPACEFREE:
2320                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2321                         uquad = (u_int64_t)fs.f_bfree;
2322                         uquad *= fs.f_bsize;
2323                         txdr_hyper(uquad, tl);
2324                         retnum += NFSX_HYPER;
2325                         break;
2326                 case NFSATTRBIT_SPACETOTAL:
2327                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2328                         uquad = (u_int64_t)fs.f_blocks;
2329                         uquad *= fs.f_bsize;
2330                         txdr_hyper(uquad, tl);
2331                         retnum += NFSX_HYPER;
2332                         break;
2333                 case NFSATTRBIT_SPACEUSED:
2334                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2335                         txdr_hyper(vap->va_bytes, tl);
2336                         retnum += NFSX_HYPER;
2337                         break;
2338                 case NFSATTRBIT_TIMEACCESS:
2339                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2340                         txdr_nfsv4time(&vap->va_atime, tl);
2341                         retnum += NFSX_V4TIME;
2342                         break;
2343                 case NFSATTRBIT_TIMEACCESSSET:
2344                         NFSGETTIME(&curtime);
2345                         if (vap->va_atime.tv_sec != curtime.tv_sec) {
2346                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2347                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2348                                 txdr_nfsv4time(&vap->va_atime, tl);
2349                                 retnum += NFSX_V4SETTIME;
2350                         } else {
2351                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2352                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2353                                 retnum += NFSX_UNSIGNED;
2354                         }
2355                         break;
2356                 case NFSATTRBIT_TIMEDELTA:
2357                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2358                         temptime.tv_sec = 0;
2359                         temptime.tv_nsec = 1000000000 / hz;
2360                         txdr_nfsv4time(&temptime, tl);
2361                         retnum += NFSX_V4TIME;
2362                         break;
2363                 case NFSATTRBIT_TIMEMETADATA:
2364                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2365                         txdr_nfsv4time(&vap->va_ctime, tl);
2366                         retnum += NFSX_V4TIME;
2367                         break;
2368                 case NFSATTRBIT_TIMEMODIFY:
2369                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2370                         txdr_nfsv4time(&vap->va_mtime, tl);
2371                         retnum += NFSX_V4TIME;
2372                         break;
2373                 case NFSATTRBIT_TIMEMODIFYSET:
2374                         NFSGETTIME(&curtime);
2375                         if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2376                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2377                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2378                                 txdr_nfsv4time(&vap->va_mtime, tl);
2379                                 retnum += NFSX_V4SETTIME;
2380                         } else {
2381                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2382                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2383                                 retnum += NFSX_UNSIGNED;
2384                         }
2385                         break;
2386                 case NFSATTRBIT_MOUNTEDONFILEID:
2387                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2388                         *tl++ = 0;
2389                         if (nfsrv_atroot(vp, &fid))
2390                                 *tl = txdr_unsigned(fid);
2391                         else
2392                                 *tl = txdr_unsigned(vap->va_fileid);
2393                         retnum += NFSX_HYPER;
2394                         break;
2395                 default:
2396                         printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2397                 };
2398             }
2399         }
2400 #ifdef NFS4_ACL_EXTATTR_NAME
2401         if (naclp != NULL)
2402                 acl_free(naclp);
2403 #endif
2404         *retnump = txdr_unsigned(retnum);
2405         return (retnum + prefixnum);
2406 }
2407
2408 /*
2409  * Put the attribute bits onto an mbuf list.
2410  * Return the number of bytes of output generated.
2411  */
2412 APPLESTATIC int
2413 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2414 {
2415         u_int32_t *tl;
2416         int cnt, i, bytesize;
2417
2418         for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2419                 if (attrbitp->bits[cnt - 1])
2420                         break;
2421         bytesize = (cnt + 1) * NFSX_UNSIGNED;
2422         NFSM_BUILD(tl, u_int32_t *, bytesize);
2423         *tl++ = txdr_unsigned(cnt);
2424         for (i = 0; i < cnt; i++)
2425                 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2426         return (bytesize);
2427 }
2428
2429 /*
2430  * Convert a uid to a string.
2431  * If the lookup fails, just output the digits.
2432  * uid - the user id
2433  * cpp - points to a buffer of size NFSV4_SMALLSTR
2434  *       (malloc a larger one, as required)
2435  * retlenp - pointer to length to be returned
2436  */
2437 APPLESTATIC void
2438 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2439 {
2440         int i;
2441         struct nfsusrgrp *usrp;
2442         u_char *cp = *cpp;
2443         uid_t tmp;
2444         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2445
2446         cnt = 0;
2447 tryagain:
2448         NFSLOCKNAMEID();
2449         if (nfsrv_dnsname) {
2450                 /*
2451                  * Always map nfsrv_defaultuid to "nobody".
2452                  */
2453                 if (uid == nfsrv_defaultuid) {
2454                         i = nfsrv_dnsnamelen + 7;
2455                         if (i > len) {
2456                                 NFSUNLOCKNAMEID();
2457                                 if (len > NFSV4_SMALLSTR)
2458                                         free(cp, M_NFSSTRING);
2459                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2460                                 *cpp = cp;
2461                                 len = i;
2462                                 goto tryagain;
2463                         }
2464                         *retlenp = i;
2465                         NFSBCOPY("nobody@", cp, 7);
2466                         cp += 7;
2467                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2468                         NFSUNLOCKNAMEID();
2469                         return;
2470                 }
2471                 hasampersand = 0;
2472                 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2473                         if (usrp->lug_uid == uid) {
2474                                 if (usrp->lug_expiry < NFSD_MONOSEC)
2475                                         break;
2476                                 /*
2477                                  * If the name doesn't already have an '@'
2478                                  * in it, append @domainname to it.
2479                                  */
2480                                 for (i = 0; i < usrp->lug_namelen; i++) {
2481                                         if (usrp->lug_name[i] == '@') {
2482                                                 hasampersand = 1;
2483                                                 break;
2484                                         }
2485                                 }
2486                                 if (hasampersand)
2487                                         i = usrp->lug_namelen;
2488                                 else
2489                                         i = usrp->lug_namelen +
2490                                             nfsrv_dnsnamelen + 1;
2491                                 if (i > len) {
2492                                         NFSUNLOCKNAMEID();
2493                                         if (len > NFSV4_SMALLSTR)
2494                                                 free(cp, M_NFSSTRING);
2495                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
2496                                         *cpp = cp;
2497                                         len = i;
2498                                         goto tryagain;
2499                                 }
2500                                 *retlenp = i;
2501                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2502                                 if (!hasampersand) {
2503                                         cp += usrp->lug_namelen;
2504                                         *cp++ = '@';
2505                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2506                                 }
2507                                 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2508                                 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2509                                 NFSUNLOCKNAMEID();
2510                                 return;
2511                         }
2512                 }
2513                 NFSUNLOCKNAMEID();
2514                 cnt++;
2515                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2516                     NULL, p);
2517                 if (ret == 0 && cnt < 2)
2518                         goto tryagain;
2519         } else {
2520                 NFSUNLOCKNAMEID();
2521         }
2522
2523         /*
2524          * No match, just return a string of digits.
2525          */
2526         tmp = uid;
2527         i = 0;
2528         while (tmp || i == 0) {
2529                 tmp /= 10;
2530                 i++;
2531         }
2532         len = (i > len) ? len : i;
2533         *retlenp = len;
2534         cp += (len - 1);
2535         tmp = uid;
2536         for (i = 0; i < len; i++) {
2537                 *cp-- = '0' + (tmp % 10);
2538                 tmp /= 10;
2539         }
2540         return;
2541 }
2542
2543 /*
2544  * Convert a string to a uid.
2545  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2546  * return 0.
2547  */
2548 APPLESTATIC int
2549 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2550 {
2551         int i;
2552         u_char *cp;
2553         struct nfsusrgrp *usrp;
2554         int cnt, ret;
2555
2556         if (len == 0)
2557                 return (NFSERR_BADOWNER);
2558         /*
2559          * Look for an '@'.
2560          */
2561         cp = str;
2562         for (i = 0; i < len; i++)
2563                 if (*cp++ == '@')
2564                         break;
2565
2566         cnt = 0;
2567 tryagain:
2568         NFSLOCKNAMEID();
2569         /*
2570          * If an '@' is found and the domain name matches, search for the name
2571          * with dns stripped off.
2572          * Mixed case alpahbetics will match for the domain name, but all
2573          * upper case will not.
2574          */
2575         if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2576             (len - 1 - i) == nfsrv_dnsnamelen &&
2577             !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2578                 len -= (nfsrv_dnsnamelen + 1);
2579                 *(cp - 1) = '\0';
2580         }
2581
2582         /*
2583          * Check for the special case of "nobody".
2584          */
2585         if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2586                 *uidp = nfsrv_defaultuid;
2587                 NFSUNLOCKNAMEID();
2588                 return (0);
2589         }
2590
2591         LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2592                 if (usrp->lug_namelen == len &&
2593                     !NFSBCMP(usrp->lug_name, str, len)) {
2594                         if (usrp->lug_expiry < NFSD_MONOSEC)
2595                                 break;
2596                         *uidp = usrp->lug_uid;
2597                         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2598                         TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2599                         NFSUNLOCKNAMEID();
2600                         return (0);
2601                 }
2602         }
2603         NFSUNLOCKNAMEID();
2604         cnt++;
2605         ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2606             str, p);
2607         if (ret == 0 && cnt < 2)
2608                 goto tryagain;
2609         return (NFSERR_BADOWNER);
2610 }
2611
2612 /*
2613  * Convert a gid to a string.
2614  * gid - the group id
2615  * cpp - points to a buffer of size NFSV4_SMALLSTR
2616  *       (malloc a larger one, as required)
2617  * retlenp - pointer to length to be returned
2618  */
2619 APPLESTATIC void
2620 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2621 {
2622         int i;
2623         struct nfsusrgrp *usrp;
2624         u_char *cp = *cpp;
2625         gid_t tmp;
2626         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2627
2628         cnt = 0;
2629 tryagain:
2630         NFSLOCKNAMEID();
2631         if (nfsrv_dnsname) {
2632                 /*
2633                  * Always map nfsrv_defaultgid to "nogroup".
2634                  */
2635                 if (gid == nfsrv_defaultgid) {
2636                         i = nfsrv_dnsnamelen + 8;
2637                         if (i > len) {
2638                                 NFSUNLOCKNAMEID();
2639                                 if (len > NFSV4_SMALLSTR)
2640                                         free(cp, M_NFSSTRING);
2641                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2642                                 *cpp = cp;
2643                                 len = i;
2644                                 goto tryagain;
2645                         }
2646                         *retlenp = i;
2647                         NFSBCOPY("nogroup@", cp, 8);
2648                         cp += 8;
2649                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2650                         NFSUNLOCKNAMEID();
2651                         return;
2652                 }
2653                 hasampersand = 0;
2654                 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2655                         if (usrp->lug_gid == gid) {
2656                                 if (usrp->lug_expiry < NFSD_MONOSEC)
2657                                         break;
2658                                 /*
2659                                  * If the name doesn't already have an '@'
2660                                  * in it, append @domainname to it.
2661                                  */
2662                                 for (i = 0; i < usrp->lug_namelen; i++) {
2663                                         if (usrp->lug_name[i] == '@') {
2664                                                 hasampersand = 1;
2665                                                 break;
2666                                         }
2667                                 }
2668                                 if (hasampersand)
2669                                         i = usrp->lug_namelen;
2670                                 else
2671                                         i = usrp->lug_namelen +
2672                                             nfsrv_dnsnamelen + 1;
2673                                 if (i > len) {
2674                                         NFSUNLOCKNAMEID();
2675                                         if (len > NFSV4_SMALLSTR)
2676                                                 free(cp, M_NFSSTRING);
2677                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
2678                                         *cpp = cp;
2679                                         len = i;
2680                                         goto tryagain;
2681                                 }
2682                                 *retlenp = i;
2683                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2684                                 if (!hasampersand) {
2685                                         cp += usrp->lug_namelen;
2686                                         *cp++ = '@';
2687                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2688                                 }
2689                                 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2690                                 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2691                                 NFSUNLOCKNAMEID();
2692                                 return;
2693                         }
2694                 }
2695                 NFSUNLOCKNAMEID();
2696                 cnt++;
2697                 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2698                     NULL, p);
2699                 if (ret == 0 && cnt < 2)
2700                         goto tryagain;
2701         } else {
2702                 NFSUNLOCKNAMEID();
2703         }
2704
2705         /*
2706          * No match, just return a string of digits.
2707          */
2708         tmp = gid;
2709         i = 0;
2710         while (tmp || i == 0) {
2711                 tmp /= 10;
2712                 i++;
2713         }
2714         len = (i > len) ? len : i;
2715         *retlenp = len;
2716         cp += (len - 1);
2717         tmp = gid;
2718         for (i = 0; i < len; i++) {
2719                 *cp-- = '0' + (tmp % 10);
2720                 tmp /= 10;
2721         }
2722         return;
2723 }
2724
2725 /*
2726  * Convert a string to a gid.
2727  */
2728 APPLESTATIC int
2729 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2730 {
2731         int i;
2732         u_char *cp;
2733         struct nfsusrgrp *usrp;
2734         int cnt, ret;
2735
2736         if (len == 0)
2737                 return (NFSERR_BADOWNER);
2738         /*
2739          * Look for an '@'.
2740          */
2741         cp = str;
2742         for (i = 0; i < len; i++)
2743                 if (*cp++ == '@')
2744                         break;
2745
2746         cnt = 0;
2747 tryagain:
2748         NFSLOCKNAMEID();
2749         /*
2750          * If an '@' is found and the dns name matches, search for the name
2751          * with the dns stripped off.
2752          */
2753         if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2754             (len - 1 - i) == nfsrv_dnsnamelen &&
2755             !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2756                 len -= (nfsrv_dnsnamelen + 1);
2757                 *(cp - 1) = '\0';
2758         }
2759
2760         /*
2761          * Check for the special case of "nogroup".
2762          */
2763         if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2764                 *gidp = nfsrv_defaultgid;
2765                 NFSUNLOCKNAMEID();
2766                 return (0);
2767         }
2768
2769         LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2770                 if (usrp->lug_namelen == len &&
2771                     !NFSBCMP(usrp->lug_name, str, len)) {
2772                         if (usrp->lug_expiry < NFSD_MONOSEC)
2773                                 break;
2774                         *gidp = usrp->lug_gid;
2775                         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2776                         TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2777                         NFSUNLOCKNAMEID();
2778                         return (0);
2779                 }
2780         }
2781         NFSUNLOCKNAMEID();
2782         cnt++;
2783         ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2784             str, p);
2785         if (ret == 0 && cnt < 2)
2786                 goto tryagain;
2787         return (NFSERR_BADOWNER);
2788 }
2789
2790 /*
2791  * Cmp len chars, allowing mixed case in the first argument to match lower
2792  * case in the second, but not if the first argument is all upper case.
2793  * Return 0 for a match, 1 otherwise.
2794  */
2795 static int
2796 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2797 {
2798         int i;
2799         u_char tmp;
2800         int fndlower = 0;
2801
2802         for (i = 0; i < len; i++) {
2803                 if (*cp >= 'A' && *cp <= 'Z') {
2804                         tmp = *cp++ + ('a' - 'A');
2805                 } else {
2806                         tmp = *cp++;
2807                         if (tmp >= 'a' && tmp <= 'z')
2808                                 fndlower = 1;
2809                 }
2810                 if (tmp != *cp2++)
2811                         return (1);
2812         }
2813         if (fndlower)
2814                 return (0);
2815         else
2816                 return (1);
2817 }
2818
2819 /*
2820  * Set the port for the nfsuserd.
2821  */
2822 APPLESTATIC int
2823 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2824 {
2825         struct nfssockreq *rp;
2826         struct sockaddr_in *ad;
2827         int error;
2828
2829         NFSLOCKNAMEID();
2830         if (nfsrv_nfsuserd) {
2831                 NFSUNLOCKNAMEID();
2832                 return (EPERM);
2833         }
2834         nfsrv_nfsuserd = 1;
2835         NFSUNLOCKNAMEID();
2836         /*
2837          * Set up the socket record and connect.
2838          */
2839         rp = &nfsrv_nfsuserdsock;
2840         rp->nr_client = NULL;
2841         rp->nr_sotype = SOCK_DGRAM;
2842         rp->nr_soproto = IPPROTO_UDP;
2843         rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2844         rp->nr_cred = NULL;
2845         NFSSOCKADDRALLOC(rp->nr_nam);
2846         NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2847         ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2848         ad->sin_family = AF_INET;
2849         ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);     /* 127.0.0.1 */
2850         ad->sin_port = port;
2851         rp->nr_prog = RPCPROG_NFSUSERD;
2852         rp->nr_vers = RPCNFSUSERD_VERS;
2853         error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2854         if (error) {
2855                 NFSSOCKADDRFREE(rp->nr_nam);
2856                 nfsrv_nfsuserd = 0;
2857         }
2858         return (error);
2859 }
2860
2861 /*
2862  * Delete the nfsuserd port.
2863  */
2864 APPLESTATIC void
2865 nfsrv_nfsuserddelport(void)
2866 {
2867
2868         NFSLOCKNAMEID();
2869         if (nfsrv_nfsuserd == 0) {
2870                 NFSUNLOCKNAMEID();
2871                 return;
2872         }
2873         nfsrv_nfsuserd = 0;
2874         NFSUNLOCKNAMEID();
2875         newnfs_disconnect(&nfsrv_nfsuserdsock);
2876         NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2877 }
2878
2879 /*
2880  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2881  * name<-->id cache.
2882  * Returns 0 upon success, non-zero otherwise.
2883  */
2884 static int
2885 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2886 {
2887         u_int32_t *tl;
2888         struct nfsrv_descript *nd;
2889         int len;
2890         struct nfsrv_descript nfsd;
2891         struct ucred *cred;
2892         int error;
2893
2894         NFSLOCKNAMEID();
2895         if (nfsrv_nfsuserd == 0) {
2896                 NFSUNLOCKNAMEID();
2897                 return (EPERM);
2898         }
2899         NFSUNLOCKNAMEID();
2900         nd = &nfsd;
2901         cred = newnfs_getcred();
2902         nd->nd_flag = ND_GSSINITREPLY;
2903         nfsrvd_rephead(nd);
2904
2905         nd->nd_procnum = procnum;
2906         if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2907                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2908                 if (procnum == RPCNFSUSERD_GETUID)
2909                         *tl = txdr_unsigned(uid);
2910                 else
2911                         *tl = txdr_unsigned(gid);
2912         } else {
2913                 len = strlen(name);
2914                 (void) nfsm_strtom(nd, name, len);
2915         }
2916         error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2917                 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2918         NFSFREECRED(cred);
2919         if (!error) {
2920                 mbuf_freem(nd->nd_mrep);
2921                 error = nd->nd_repstat;
2922         }
2923         return (error);
2924 }
2925
2926 /*
2927  * This function is called from the nfssvc(2) system call, to update the
2928  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2929  */
2930 APPLESTATIC int
2931 nfssvc_idname(struct nfsd_idargs *nidp)
2932 {
2933         struct nfsusrgrp *nusrp, *usrp, *newusrp;
2934         struct nfsuserhashhead *hp;
2935         int i;
2936         int error = 0;
2937         u_char *cp;
2938
2939         if (nidp->nid_flag & NFSID_INITIALIZE) {
2940             cp = (u_char *)malloc(nidp->nid_namelen + 1,
2941                 M_NFSSTRING, M_WAITOK);
2942             error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2943                 nidp->nid_namelen);
2944             NFSLOCKNAMEID();
2945             if (nfsrv_dnsname) {
2946                 /*
2947                  * Free up all the old stuff and reinitialize hash lists.
2948                  */
2949                 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2950                         nfsrv_removeuser(usrp);
2951                 }
2952                 free(nfsrv_dnsname, M_NFSSTRING);
2953                 nfsrv_dnsname = NULL;
2954             }
2955             TAILQ_INIT(&nfsuserlruhead);
2956             for (i = 0; i < NFSUSERHASHSIZE; i++)
2957                 LIST_INIT(&nfsuserhash[i]);
2958             for (i = 0; i < NFSGROUPHASHSIZE; i++)
2959                 LIST_INIT(&nfsgrouphash[i]);
2960             for (i = 0; i < NFSUSERHASHSIZE; i++)
2961                 LIST_INIT(&nfsusernamehash[i]);
2962             for (i = 0; i < NFSGROUPHASHSIZE; i++)
2963                 LIST_INIT(&nfsgroupnamehash[i]);
2964
2965             /*
2966              * Put name in "DNS" string.
2967              */
2968             if (!error) {
2969                 nfsrv_dnsname = cp;
2970                 nfsrv_dnsnamelen = nidp->nid_namelen;
2971                 nfsrv_defaultuid = nidp->nid_uid;
2972                 nfsrv_defaultgid = nidp->nid_gid;
2973                 nfsrv_usercnt = 0;
2974                 nfsrv_usermax = nidp->nid_usermax;
2975             }
2976             NFSUNLOCKNAMEID();
2977             if (error)
2978                 free(cp, M_NFSSTRING);
2979             return (error);
2980         }
2981
2982         /*
2983          * malloc the new one now, so any potential sleep occurs before
2984          * manipulation of the lists.
2985          */
2986         MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
2987             nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
2988         error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
2989             nidp->nid_namelen);
2990         if (error) {
2991                 free((caddr_t)newusrp, M_NFSUSERGROUP);
2992                 return (error);
2993         }
2994         newusrp->lug_namelen = nidp->nid_namelen;
2995
2996         NFSLOCKNAMEID();
2997         /*
2998          * Delete old entries, as required.
2999          */
3000         if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3001                 hp = NFSUSERHASH(nidp->nid_uid);
3002                 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3003                         if (usrp->lug_uid == nidp->nid_uid)
3004                                 nfsrv_removeuser(usrp);
3005                 }
3006         }
3007         if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3008                 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3009                 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3010                         if (usrp->lug_namelen == newusrp->lug_namelen &&
3011                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3012                             usrp->lug_namelen))
3013                                 nfsrv_removeuser(usrp);
3014                 }
3015         }
3016         if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3017                 hp = NFSGROUPHASH(nidp->nid_gid);
3018                 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3019                         if (usrp->lug_gid == nidp->nid_gid)
3020                                 nfsrv_removeuser(usrp);
3021                 }
3022         }
3023         if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3024                 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3025                 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3026                         if (usrp->lug_namelen == newusrp->lug_namelen &&
3027                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3028                             usrp->lug_namelen))
3029                                 nfsrv_removeuser(usrp);
3030                 }
3031         }
3032         TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3033                 if (usrp->lug_expiry < NFSD_MONOSEC)
3034                         nfsrv_removeuser(usrp);
3035         }
3036         while (nfsrv_usercnt >= nfsrv_usermax) {
3037                 usrp = TAILQ_FIRST(&nfsuserlruhead);
3038                 nfsrv_removeuser(usrp);
3039         }
3040
3041         /*
3042          * Now, we can add the new one.
3043          */
3044         if (nidp->nid_usertimeout)
3045                 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3046         else
3047                 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3048         if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3049                 newusrp->lug_uid = nidp->nid_uid;
3050                 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3051                     lug_numhash);
3052                 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3053                     newusrp->lug_namelen), newusrp, lug_namehash);
3054                 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3055                 nfsrv_usercnt++;
3056         } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3057                 newusrp->lug_gid = nidp->nid_gid;
3058                 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3059                     lug_numhash);
3060                 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3061                     newusrp->lug_namelen), newusrp, lug_namehash);
3062                 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3063                 nfsrv_usercnt++;
3064         } else
3065                 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3066         NFSUNLOCKNAMEID();
3067         return (error);
3068 }
3069
3070 /*
3071  * Remove a user/group name element.
3072  */
3073 static void
3074 nfsrv_removeuser(struct nfsusrgrp *usrp)
3075 {
3076
3077         NFSNAMEIDREQUIRED();
3078         LIST_REMOVE(usrp, lug_numhash);
3079         LIST_REMOVE(usrp, lug_namehash);
3080         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3081         nfsrv_usercnt--;
3082         FREE((caddr_t)usrp, M_NFSUSERGROUP);
3083 }
3084
3085 /*
3086  * This function scans a byte string and checks for UTF-8 compliance.
3087  * It returns 0 if it conforms and NFSERR_INVAL if not.
3088  */
3089 APPLESTATIC int
3090 nfsrv_checkutf8(u_int8_t *cp, int len)
3091 {
3092         u_int32_t val = 0x0;
3093         int cnt = 0, gotd = 0, shift = 0;
3094         u_int8_t byte;
3095         static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3096
3097         /*
3098          * Here are what the variables are used for:
3099          * val - the calculated value of a multibyte char, used to check
3100          *       that it was coded with the correct range
3101          * cnt - the number of 10xxxxxx bytes to follow
3102          * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3103          * shift - lower order bits of range (ie. "val >> shift" should
3104          *       not be 0, in other words, dividing by the lower bound
3105          *       of the range should get a non-zero value)
3106          * byte - used to calculate cnt
3107          */
3108         while (len > 0) {
3109                 if (cnt > 0) {
3110                         /* This handles the 10xxxxxx bytes */
3111                         if ((*cp & 0xc0) != 0x80 ||
3112                             (gotd && (*cp & 0x20)))
3113                                 return (NFSERR_INVAL);
3114                         gotd = 0;
3115                         val <<= 6;
3116                         val |= (*cp & 0x3f);
3117                         cnt--;
3118                         if (cnt == 0 && (val >> shift) == 0x0)
3119                                 return (NFSERR_INVAL);
3120                 } else if (*cp & 0x80) {
3121                         /* first byte of multi byte char */
3122                         byte = *cp;
3123                         while ((byte & 0x40) && cnt < 6) {
3124                                 cnt++;
3125                                 byte <<= 1;
3126                         }
3127                         if (cnt == 0 || cnt == 6)
3128                                 return (NFSERR_INVAL);
3129                         val = (*cp & (0x3f >> cnt));
3130                         shift = utf8_shift[cnt - 1];
3131                         if (cnt == 2 && val == 0xd)
3132                                 /* Check for the 0xd800-0xdfff case */
3133                                 gotd = 1;
3134                 }
3135                 cp++;
3136                 len--;
3137         }
3138         if (cnt > 0)
3139                 return (NFSERR_INVAL);
3140         return (0);
3141 }
3142
3143 /*
3144  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3145  * strings, one with the root path in it and the other with the list of
3146  * locations. The list is in the same format as is found in nfr_refs.
3147  * It is a "," separated list of entries, where each of them is of the
3148  * form <server>:<rootpath>. For example
3149  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3150  * The nilp argument is set to 1 for the special case of a null fs_root
3151  * and an empty server list.
3152  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3153  * number of xdr bytes parsed in sump.
3154  */
3155 static int
3156 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3157     int *sump, int *nilp)
3158 {
3159         u_int32_t *tl;
3160         u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3161         int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3162         struct list {
3163                 SLIST_ENTRY(list) next;
3164                 int len;
3165                 u_char host[1];
3166         } *lsp, *nlsp;
3167         SLIST_HEAD(, list) head;
3168
3169         *fsrootp = NULL;
3170         *srvp = NULL;
3171         *nilp = 0;
3172
3173         /*
3174          * Get the fs_root path and check for the special case of null path
3175          * and 0 length server list.
3176          */
3177         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3178         len = fxdr_unsigned(int, *tl);
3179         if (len < 0 || len > 10240)
3180                 return (NFSERR_BADXDR);
3181         if (len == 0) {
3182                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3183                 if (*tl != 0)
3184                         return (NFSERR_BADXDR);
3185                 *nilp = 1;
3186                 *sump = 2 * NFSX_UNSIGNED;
3187                 return (0);
3188         }
3189         cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3190         error = nfsrv_mtostr(nd, cp, len);
3191         if (!error) {
3192                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3193                 cnt = fxdr_unsigned(int, *tl);
3194                 if (cnt <= 0)
3195                         error = NFSERR_BADXDR;
3196         }
3197         if (error) {
3198                 free(cp, M_NFSSTRING);
3199                 return (error);
3200         }
3201
3202         /*
3203          * Now, loop through the location list and make up the srvlist.
3204          */
3205         xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3206         cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3207         slen = 1024;
3208         siz = 0;
3209         for (i = 0; i < cnt; i++) {
3210                 SLIST_INIT(&head);
3211                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3212                 nsrv = fxdr_unsigned(int, *tl);
3213                 if (nsrv <= 0) {
3214                         free(cp, M_NFSSTRING);
3215                         free(cp2, M_NFSSTRING);
3216                         return (NFSERR_BADXDR);
3217                 }
3218
3219                 /*
3220                  * Handle the first server by putting it in the srvstr.
3221                  */
3222                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3223                 len = fxdr_unsigned(int, *tl);
3224                 if (len <= 0 || len > 1024) {
3225                         free(cp, M_NFSSTRING);
3226                         free(cp2, M_NFSSTRING);
3227                         return (NFSERR_BADXDR);
3228                 }
3229                 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3230                 if (cp3 != cp2) {
3231                         *cp3++ = ',';
3232                         siz++;
3233                 }
3234                 error = nfsrv_mtostr(nd, cp3, len);
3235                 if (error) {
3236                         free(cp, M_NFSSTRING);
3237                         free(cp2, M_NFSSTRING);
3238                         return (error);
3239                 }
3240                 cp3 += len;
3241                 *cp3++ = ':';
3242                 siz += (len + 1);
3243                 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3244                 for (j = 1; j < nsrv; j++) {
3245                         /*
3246                          * Yuck, put them in an slist and process them later.
3247                          */
3248                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3249                         len = fxdr_unsigned(int, *tl);
3250                         if (len <= 0 || len > 1024) {
3251                                 free(cp, M_NFSSTRING);
3252                                 free(cp2, M_NFSSTRING);
3253                                 return (NFSERR_BADXDR);
3254                         }
3255                         lsp = (struct list *)malloc(sizeof (struct list)
3256                             + len, M_TEMP, M_WAITOK);
3257                         error = nfsrv_mtostr(nd, lsp->host, len);
3258                         if (error) {
3259                                 free(cp, M_NFSSTRING);
3260                                 free(cp2, M_NFSSTRING);
3261                                 return (error);
3262                         }
3263                         xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3264                         lsp->len = len;
3265                         SLIST_INSERT_HEAD(&head, lsp, next);
3266                 }
3267
3268                 /*
3269                  * Finally, we can get the path.
3270                  */
3271                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3272                 len = fxdr_unsigned(int, *tl);
3273                 if (len <= 0 || len > 1024) {
3274                         free(cp, M_NFSSTRING);
3275                         free(cp2, M_NFSSTRING);
3276                         return (NFSERR_BADXDR);
3277                 }
3278                 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3279                 error = nfsrv_mtostr(nd, cp3, len);
3280                 if (error) {
3281                         free(cp, M_NFSSTRING);
3282                         free(cp2, M_NFSSTRING);
3283                         return (error);
3284                 }
3285                 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3286                 str = cp3;
3287                 stringlen = len;
3288                 cp3 += len;
3289                 siz += len;
3290                 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3291                         nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3292                             &cp2, &cp3, &slen);
3293                         *cp3++ = ',';
3294                         NFSBCOPY(lsp->host, cp3, lsp->len);
3295                         cp3 += lsp->len;
3296                         *cp3++ = ':';
3297                         NFSBCOPY(str, cp3, stringlen);
3298                         cp3 += stringlen;
3299                         *cp3 = '\0';
3300                         siz += (lsp->len + stringlen + 2);
3301                         free((caddr_t)lsp, M_TEMP);
3302                 }
3303         }
3304         *fsrootp = cp;
3305         *srvp = cp2;
3306         *sump = xdrsum;
3307         return (0);
3308 nfsmout:
3309         if (cp != NULL)
3310                 free(cp, M_NFSSTRING);
3311         if (cp2 != NULL)
3312                 free(cp2, M_NFSSTRING);
3313         return (error);
3314 }
3315
3316 /*
3317  * Make the malloc'd space large enough. This is a pain, but the xdr
3318  * doesn't set an upper bound on the side, so...
3319  */
3320 static void
3321 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3322 {
3323         u_char *cp;
3324         int i;
3325
3326         if (siz <= *slenp)
3327                 return;
3328         cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3329         NFSBCOPY(*cpp, cp, *slenp);
3330         free(*cpp, M_NFSSTRING);
3331         i = *cpp2 - *cpp;
3332         *cpp = cp;
3333         *cpp2 = cp + i;
3334         *slenp = siz + 1024;
3335 }
3336
3337 /*
3338  * Initialize the reply header data structures.
3339  */
3340 APPLESTATIC void
3341 nfsrvd_rephead(struct nfsrv_descript *nd)
3342 {
3343         mbuf_t mreq;
3344
3345         /*
3346          * If this is a big reply, use a cluster.
3347          */
3348         if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3349             nfs_bigreply[nd->nd_procnum]) {
3350                 NFSMCLGET(mreq, M_WAIT);
3351                 nd->nd_mreq = mreq;
3352                 nd->nd_mb = mreq;
3353         } else {
3354                 NFSMGET(mreq);
3355                 nd->nd_mreq = mreq;
3356                 nd->nd_mb = mreq;
3357         }
3358         nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3359         mbuf_setlen(mreq, 0);
3360
3361         if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3362                 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3363 }
3364
3365 /*
3366  * Lock a socket against others.
3367  * Currently used to serialize connect/disconnect attempts.
3368  */
3369 int
3370 newnfs_sndlock(int *flagp)
3371 {
3372         struct timespec ts;
3373
3374         NFSLOCKSOCK();
3375         while (*flagp & NFSR_SNDLOCK) {
3376                 *flagp |= NFSR_WANTSND;
3377                 ts.tv_sec = 0;
3378                 ts.tv_nsec = 0;
3379                 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3380                     PZERO - 1, "nfsndlck", &ts);
3381         }
3382         *flagp |= NFSR_SNDLOCK;
3383         NFSUNLOCKSOCK();
3384         return (0);
3385 }
3386
3387 /*
3388  * Unlock the stream socket for others.
3389  */
3390 void
3391 newnfs_sndunlock(int *flagp)
3392 {
3393
3394         NFSLOCKSOCK();
3395         if ((*flagp & NFSR_SNDLOCK) == 0)
3396                 panic("nfs sndunlock");
3397         *flagp &= ~NFSR_SNDLOCK;
3398         if (*flagp & NFSR_WANTSND) {
3399                 *flagp &= ~NFSR_WANTSND;
3400                 wakeup((caddr_t)flagp);
3401         }
3402         NFSUNLOCKSOCK();
3403 }
3404