]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/fs/nfs/nfs_commonsubs.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.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  * Get a reference as above, but return failure instead of sleeping if
1839  * an exclusive lock is held.
1840  */
1841 APPLESTATIC int
1842 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1843 {
1844
1845         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1846                 return (0);
1847
1848         lp->nfslock_usecnt++;
1849         return (1);
1850 }
1851
1852 /*
1853  * Test for a lock. Return 1 if locked, 0 otherwise.
1854  */
1855 APPLESTATIC int
1856 nfsv4_testlock(struct nfsv4lock *lp)
1857 {
1858
1859         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1860             lp->nfslock_usecnt == 0)
1861                 return (0);
1862         return (1);
1863 }
1864
1865 /*
1866  * Wake up anyone sleeping, waiting for this lock.
1867  */
1868 static void
1869 nfsv4_wanted(struct nfsv4lock *lp)
1870 {
1871
1872         if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1873                 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1874                 wakeup((caddr_t)&lp->nfslock_lock);
1875         }
1876 }
1877
1878 /*
1879  * Copy a string from an mbuf list into a character array.
1880  * Return EBADRPC if there is an mbuf error,
1881  * 0 otherwise.
1882  */
1883 APPLESTATIC int
1884 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1885 {
1886         char *cp;
1887         int xfer, len;
1888         mbuf_t mp;
1889         int rem, error = 0;
1890
1891         mp = nd->nd_md;
1892         cp = nd->nd_dpos;
1893         len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1894         rem = NFSM_RNDUP(siz) - siz;
1895         while (siz > 0) {
1896                 if (len > siz)
1897                         xfer = siz;
1898                 else
1899                         xfer = len;
1900                 NFSBCOPY(cp, str, xfer);
1901                 str += xfer;
1902                 siz -= xfer;
1903                 if (siz > 0) {
1904                         mp = mbuf_next(mp);
1905                         if (mp == NULL)
1906                                 return (EBADRPC);
1907                         cp = NFSMTOD(mp, caddr_t);
1908                         len = mbuf_len(mp);
1909                 } else {
1910                         cp += xfer;
1911                         len -= xfer;
1912                 }
1913         }
1914         *str = '\0';
1915         nd->nd_dpos = cp;
1916         nd->nd_md = mp;
1917         if (rem > 0) {
1918                 if (len < rem)
1919                         error = nfsm_advance(nd, rem, len);
1920                 else
1921                         nd->nd_dpos += rem;
1922         }
1923         return (error);
1924 }
1925
1926 /*
1927  * Fill in the attributes as marked by the bitmap (V4).
1928  */
1929 APPLESTATIC int
1930 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
1931     struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1932     struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
1933 {
1934         int bitpos, retnum = 0;
1935         u_int32_t *tl;
1936         int siz, prefixnum, error;
1937         u_char *cp, namestr[NFSV4_SMALLSTR];
1938         nfsattrbit_t attrbits, retbits;
1939         nfsattrbit_t *retbitp = &retbits;
1940         u_int32_t freenum, *retnump;
1941         u_int64_t uquad;
1942         long fid;
1943         struct statfs fs;
1944         struct nfsfsinfo fsinf;
1945         struct timespec temptime;
1946         struct timeval curtime;
1947         NFSACL_T *aclp, *naclp = NULL;
1948 #ifdef QUOTA
1949         struct dqblk dqb;
1950         uid_t savuid;
1951 #endif
1952
1953         /*
1954          * First, set the bits that can be filled and get fsinfo.
1955          */
1956         NFSSET_ATTRBIT(retbitp, attrbitp);
1957         /* If p and cred are NULL, it is a client side call */
1958         if (p == NULL && cred == NULL) {
1959                 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1960                 aclp = saclp;
1961         } else {
1962                 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1963 #ifdef NFS4_ACL_EXTATTR_NAME
1964                 naclp = acl_alloc(M_WAITOK);
1965 #endif
1966                 aclp = naclp;
1967         }
1968         nfsvno_getfs(&fsinf, isdgram);
1969 #ifndef APPLE
1970         /*
1971          * Get the VFS_STATFS(), since some attributes need them.
1972          */
1973         if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
1974                 error = VFS_STATFS(vnode_mount(vp), &fs);
1975                 if (error != 0) {
1976                         if (reterr) {
1977                                 nd->nd_repstat = NFSERR_ACCES;
1978                                 return (0);
1979                         }
1980                         NFSCLRSTATFS_ATTRBIT(retbitp);
1981                 }
1982         }
1983 #endif
1984
1985         /*
1986          * And the NFSv4 ACL...
1987          */
1988         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT)
1989 #ifdef NFS4_ACL_EXTATTR_NAME
1990             && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1991                 !NFSHASNFS4ACL(vnode_mount(vp))))
1992 #endif
1993             ) {
1994                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1995         }
1996         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1997 #ifdef NFS4_ACL_EXTATTR_NAME
1998                 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1999                     !NFSHASNFS4ACL(vnode_mount(vp)))) {
2000 #endif
2001                         NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2002 #ifdef NFS4_ACL_EXTATTR_NAME
2003                 } else if (naclp != NULL) {
2004                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2005                         error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
2006                         if (error == 0)
2007                                 error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
2008                                     cred, p);
2009                         NFSVOPUNLOCK(vp, 0, p);
2010                         if (error != 0) {
2011                                 if (reterr) {
2012                                         nd->nd_repstat = NFSERR_ACCES;
2013                                         return (0);
2014                                 }
2015                                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2016                         }
2017                 }
2018 #endif
2019         }
2020         /*
2021          * Put out the attribute bitmap for the ones being filled in
2022          * and get the field for the number of attributes returned.
2023          */
2024         prefixnum = nfsrv_putattrbit(nd, retbitp);
2025         NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2026         prefixnum += NFSX_UNSIGNED;
2027
2028         /*
2029          * Now, loop around filling in the attributes for each bit set.
2030          */
2031         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2032             if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2033                 switch (bitpos) {
2034                 case NFSATTRBIT_SUPPORTEDATTRS:
2035                         NFSSETSUPP_ATTRBIT(&attrbits);
2036 #ifdef NFS4_ACL_EXTATTR_NAME
2037                         if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2038                             && !NFSHASNFS4ACL(vnode_mount(vp))))
2039 #endif
2040                         {
2041                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2042                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2043                         }
2044                         retnum += nfsrv_putattrbit(nd, &attrbits);
2045                         break;
2046                 case NFSATTRBIT_TYPE:
2047                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2048                         *tl = vtonfsv34_type(vap->va_type);
2049                         retnum += NFSX_UNSIGNED;
2050                         break;
2051                 case NFSATTRBIT_FHEXPIRETYPE:
2052                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2053                         *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2054                         retnum += NFSX_UNSIGNED;
2055                         break;
2056                 case NFSATTRBIT_CHANGE:
2057                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2058                         txdr_hyper(vap->va_filerev, tl);
2059                         retnum += NFSX_HYPER;
2060                         break;
2061                 case NFSATTRBIT_SIZE:
2062                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2063                         txdr_hyper(vap->va_size, tl);
2064                         retnum += NFSX_HYPER;
2065                         break;
2066                 case NFSATTRBIT_LINKSUPPORT:
2067                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2068                         if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2069                                 *tl = newnfs_true;
2070                         else
2071                                 *tl = newnfs_false;
2072                         retnum += NFSX_UNSIGNED;
2073                         break;
2074                 case NFSATTRBIT_SYMLINKSUPPORT:
2075                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2076                         if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2077                                 *tl = newnfs_true;
2078                         else
2079                                 *tl = newnfs_false;
2080                         retnum += NFSX_UNSIGNED;
2081                         break;
2082                 case NFSATTRBIT_NAMEDATTR:
2083                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2084                         *tl = newnfs_false;
2085                         retnum += NFSX_UNSIGNED;
2086                         break;
2087                 case NFSATTRBIT_FSID:
2088                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2089                         *tl++ = 0;
2090                         *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
2091                         *tl++ = 0;
2092                         *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
2093                         retnum += NFSX_V4FSID;
2094                         break;
2095                 case NFSATTRBIT_UNIQUEHANDLES:
2096                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2097                         *tl = newnfs_true;
2098                         retnum += NFSX_UNSIGNED;
2099                         break;
2100                 case NFSATTRBIT_LEASETIME:
2101                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2102                         *tl = txdr_unsigned(nfsrv_lease);
2103                         retnum += NFSX_UNSIGNED;
2104                         break;
2105                 case NFSATTRBIT_RDATTRERROR:
2106                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2107                         *tl = txdr_unsigned(rderror);
2108                         retnum += NFSX_UNSIGNED;
2109                         break;
2110                 /*
2111                  * Recommended Attributes. (Only the supported ones.)
2112                  */
2113 #ifdef NFS4_ACL_EXTATTR_NAME
2114                 case NFSATTRBIT_ACL:
2115                         retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2116                         break;
2117                 case NFSATTRBIT_ACLSUPPORT:
2118                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2119                         *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2120                         retnum += NFSX_UNSIGNED;
2121                         break;
2122 #endif
2123                 case NFSATTRBIT_CANSETTIME:
2124                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2125                         if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2126                                 *tl = newnfs_true;
2127                         else
2128                                 *tl = newnfs_false;
2129                         retnum += NFSX_UNSIGNED;
2130                         break;
2131                 case NFSATTRBIT_CASEINSENSITIVE:
2132                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2133                         *tl = newnfs_false;
2134                         retnum += NFSX_UNSIGNED;
2135                         break;
2136                 case NFSATTRBIT_CASEPRESERVING:
2137                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2138                         *tl = newnfs_true;
2139                         retnum += NFSX_UNSIGNED;
2140                         break;
2141                 case NFSATTRBIT_CHOWNRESTRICTED:
2142                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2143                         *tl = newnfs_true;
2144                         retnum += NFSX_UNSIGNED;
2145                         break;
2146                 case NFSATTRBIT_FILEHANDLE:
2147                         retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2148                         break;
2149                 case NFSATTRBIT_FILEID:
2150                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2151                         *tl++ = 0;
2152                         *tl = txdr_unsigned(vap->va_fileid);
2153                         retnum += NFSX_HYPER;
2154                         break;
2155                 case NFSATTRBIT_FILESAVAIL:
2156                         /*
2157                          * Check quota and use min(quota, f_ffree).
2158                          */
2159                         freenum = fs.f_ffree;
2160 #ifdef QUOTA
2161                         /*
2162                          * ufs_quotactl() insists that the uid argument
2163                          * equal p_ruid for non-root quota access, so
2164                          * we'll just make sure that's the case.
2165                          */
2166                         savuid = p->p_cred->p_ruid;
2167                         p->p_cred->p_ruid = cred->cr_uid;
2168                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2169                             cred->cr_uid, (caddr_t)&dqb))
2170                             freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2171                                 freenum);
2172                         p->p_cred->p_ruid = savuid;
2173 #endif  /* QUOTA */
2174                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2175                         *tl++ = 0;
2176                         *tl = txdr_unsigned(freenum);
2177                         retnum += NFSX_HYPER;
2178                         break;
2179                 case NFSATTRBIT_FILESFREE:
2180                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2181                         *tl++ = 0;
2182                         *tl = txdr_unsigned(fs.f_ffree);
2183                         retnum += NFSX_HYPER;
2184                         break;
2185                 case NFSATTRBIT_FILESTOTAL:
2186                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2187                         *tl++ = 0;
2188                         *tl = txdr_unsigned(fs.f_files);
2189                         retnum += NFSX_HYPER;
2190                         break;
2191                 case NFSATTRBIT_FSLOCATIONS:
2192                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2193                         *tl++ = 0;
2194                         *tl = 0;
2195                         retnum += 2 * NFSX_UNSIGNED;
2196                         break;
2197                 case NFSATTRBIT_HOMOGENEOUS:
2198                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2199                         if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2200                                 *tl = newnfs_true;
2201                         else
2202                                 *tl = newnfs_false;
2203                         retnum += NFSX_UNSIGNED;
2204                         break;
2205                 case NFSATTRBIT_MAXFILESIZE:
2206                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2207                         uquad = NFSRV_MAXFILESIZE;
2208                         txdr_hyper(uquad, tl);
2209                         retnum += NFSX_HYPER;
2210                         break;
2211                 case NFSATTRBIT_MAXLINK:
2212                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2213                         *tl = txdr_unsigned(LINK_MAX);
2214                         retnum += NFSX_UNSIGNED;
2215                         break;
2216                 case NFSATTRBIT_MAXNAME:
2217                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2218                         *tl = txdr_unsigned(NFS_MAXNAMLEN);
2219                         retnum += NFSX_UNSIGNED;
2220                         break;
2221                 case NFSATTRBIT_MAXREAD:
2222                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2223                         *tl++ = 0;
2224                         *tl = txdr_unsigned(fsinf.fs_rtmax);
2225                         retnum += NFSX_HYPER;
2226                         break;
2227                 case NFSATTRBIT_MAXWRITE:
2228                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2229                         *tl++ = 0;
2230                         *tl = txdr_unsigned(fsinf.fs_wtmax);
2231                         retnum += NFSX_HYPER;
2232                         break;
2233                 case NFSATTRBIT_MODE:
2234                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2235                         *tl = vtonfsv34_mode(vap->va_mode);
2236                         retnum += NFSX_UNSIGNED;
2237                         break;
2238                 case NFSATTRBIT_NOTRUNC:
2239                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2240                         *tl = newnfs_true;
2241                         retnum += NFSX_UNSIGNED;
2242                         break;
2243                 case NFSATTRBIT_NUMLINKS:
2244                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2245                         *tl = txdr_unsigned(vap->va_nlink);
2246                         retnum += NFSX_UNSIGNED;
2247                         break;
2248                 case NFSATTRBIT_OWNER:
2249                         cp = namestr;
2250                         nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2251                         retnum += nfsm_strtom(nd, cp, siz);
2252                         if (cp != namestr)
2253                                 free(cp, M_NFSSTRING);
2254                         break;
2255                 case NFSATTRBIT_OWNERGROUP:
2256                         cp = namestr;
2257                         nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2258                         retnum += nfsm_strtom(nd, cp, siz);
2259                         if (cp != namestr)
2260                                 free(cp, M_NFSSTRING);
2261                         break;
2262                 case NFSATTRBIT_QUOTAHARD:
2263                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2264                                 freenum = fs.f_bfree;
2265                         else
2266                                 freenum = fs.f_bavail;
2267 #ifdef QUOTA
2268                         /*
2269                          * ufs_quotactl() insists that the uid argument
2270                          * equal p_ruid for non-root quota access, so
2271                          * we'll just make sure that's the case.
2272                          */
2273                         savuid = p->p_cred->p_ruid;
2274                         p->p_cred->p_ruid = cred->cr_uid;
2275                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2276                             cred->cr_uid, (caddr_t)&dqb))
2277                             freenum = min(dqb.dqb_bhardlimit, freenum);
2278                         p->p_cred->p_ruid = savuid;
2279 #endif  /* QUOTA */
2280                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2281                         uquad = (u_int64_t)freenum;
2282                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2283                         txdr_hyper(uquad, tl);
2284                         retnum += NFSX_HYPER;
2285                         break;
2286                 case NFSATTRBIT_QUOTASOFT:
2287                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2288                                 freenum = fs.f_bfree;
2289                         else
2290                                 freenum = fs.f_bavail;
2291 #ifdef QUOTA
2292                         /*
2293                          * ufs_quotactl() insists that the uid argument
2294                          * equal p_ruid for non-root quota access, so
2295                          * we'll just make sure that's the case.
2296                          */
2297                         savuid = p->p_cred->p_ruid;
2298                         p->p_cred->p_ruid = cred->cr_uid;
2299                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2300                             cred->cr_uid, (caddr_t)&dqb))
2301                             freenum = min(dqb.dqb_bsoftlimit, freenum);
2302                         p->p_cred->p_ruid = savuid;
2303 #endif  /* QUOTA */
2304                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2305                         uquad = (u_int64_t)freenum;
2306                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2307                         txdr_hyper(uquad, tl);
2308                         retnum += NFSX_HYPER;
2309                         break;
2310                 case NFSATTRBIT_QUOTAUSED:
2311                         freenum = 0;
2312 #ifdef QUOTA
2313                         /*
2314                          * ufs_quotactl() insists that the uid argument
2315                          * equal p_ruid for non-root quota access, so
2316                          * we'll just make sure that's the case.
2317                          */
2318                         savuid = p->p_cred->p_ruid;
2319                         p->p_cred->p_ruid = cred->cr_uid;
2320                         if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2321                             cred->cr_uid, (caddr_t)&dqb))
2322                             freenum = dqb.dqb_curblocks;
2323                         p->p_cred->p_ruid = savuid;
2324 #endif  /* QUOTA */
2325                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2326                         uquad = (u_int64_t)freenum;
2327                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2328                         txdr_hyper(uquad, tl);
2329                         retnum += NFSX_HYPER;
2330                         break;
2331                 case NFSATTRBIT_RAWDEV:
2332                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2333                         *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2334                         *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2335                         retnum += NFSX_V4SPECDATA;
2336                         break;
2337                 case NFSATTRBIT_SPACEAVAIL:
2338                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2339                         if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2340                                 uquad = (u_int64_t)fs.f_bfree;
2341                         else
2342                                 uquad = (u_int64_t)fs.f_bavail;
2343                         uquad *= fs.f_bsize;
2344                         txdr_hyper(uquad, tl);
2345                         retnum += NFSX_HYPER;
2346                         break;
2347                 case NFSATTRBIT_SPACEFREE:
2348                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2349                         uquad = (u_int64_t)fs.f_bfree;
2350                         uquad *= fs.f_bsize;
2351                         txdr_hyper(uquad, tl);
2352                         retnum += NFSX_HYPER;
2353                         break;
2354                 case NFSATTRBIT_SPACETOTAL:
2355                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2356                         uquad = (u_int64_t)fs.f_blocks;
2357                         uquad *= fs.f_bsize;
2358                         txdr_hyper(uquad, tl);
2359                         retnum += NFSX_HYPER;
2360                         break;
2361                 case NFSATTRBIT_SPACEUSED:
2362                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2363                         txdr_hyper(vap->va_bytes, tl);
2364                         retnum += NFSX_HYPER;
2365                         break;
2366                 case NFSATTRBIT_TIMEACCESS:
2367                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2368                         txdr_nfsv4time(&vap->va_atime, tl);
2369                         retnum += NFSX_V4TIME;
2370                         break;
2371                 case NFSATTRBIT_TIMEACCESSSET:
2372                         NFSGETTIME(&curtime);
2373                         if (vap->va_atime.tv_sec != curtime.tv_sec) {
2374                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2375                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2376                                 txdr_nfsv4time(&vap->va_atime, tl);
2377                                 retnum += NFSX_V4SETTIME;
2378                         } else {
2379                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2380                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2381                                 retnum += NFSX_UNSIGNED;
2382                         }
2383                         break;
2384                 case NFSATTRBIT_TIMEDELTA:
2385                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2386                         temptime.tv_sec = 0;
2387                         temptime.tv_nsec = 1000000000 / hz;
2388                         txdr_nfsv4time(&temptime, tl);
2389                         retnum += NFSX_V4TIME;
2390                         break;
2391                 case NFSATTRBIT_TIMEMETADATA:
2392                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2393                         txdr_nfsv4time(&vap->va_ctime, tl);
2394                         retnum += NFSX_V4TIME;
2395                         break;
2396                 case NFSATTRBIT_TIMEMODIFY:
2397                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2398                         txdr_nfsv4time(&vap->va_mtime, tl);
2399                         retnum += NFSX_V4TIME;
2400                         break;
2401                 case NFSATTRBIT_TIMEMODIFYSET:
2402                         NFSGETTIME(&curtime);
2403                         if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2404                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2405                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2406                                 txdr_nfsv4time(&vap->va_mtime, tl);
2407                                 retnum += NFSX_V4SETTIME;
2408                         } else {
2409                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2410                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2411                                 retnum += NFSX_UNSIGNED;
2412                         }
2413                         break;
2414                 case NFSATTRBIT_MOUNTEDONFILEID:
2415                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2416                         *tl++ = 0;
2417                         if (nfsrv_atroot(vp, &fid))
2418                                 *tl = txdr_unsigned(fid);
2419                         else
2420                                 *tl = txdr_unsigned(vap->va_fileid);
2421                         retnum += NFSX_HYPER;
2422                         break;
2423                 default:
2424                         printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2425                 };
2426             }
2427         }
2428 #ifdef NFS4_ACL_EXTATTR_NAME
2429         if (naclp != NULL)
2430                 acl_free(naclp);
2431 #endif
2432         *retnump = txdr_unsigned(retnum);
2433         return (retnum + prefixnum);
2434 }
2435
2436 /*
2437  * Put the attribute bits onto an mbuf list.
2438  * Return the number of bytes of output generated.
2439  */
2440 APPLESTATIC int
2441 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2442 {
2443         u_int32_t *tl;
2444         int cnt, i, bytesize;
2445
2446         for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2447                 if (attrbitp->bits[cnt - 1])
2448                         break;
2449         bytesize = (cnt + 1) * NFSX_UNSIGNED;
2450         NFSM_BUILD(tl, u_int32_t *, bytesize);
2451         *tl++ = txdr_unsigned(cnt);
2452         for (i = 0; i < cnt; i++)
2453                 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2454         return (bytesize);
2455 }
2456
2457 /*
2458  * Convert a uid to a string.
2459  * If the lookup fails, just output the digits.
2460  * uid - the user id
2461  * cpp - points to a buffer of size NFSV4_SMALLSTR
2462  *       (malloc a larger one, as required)
2463  * retlenp - pointer to length to be returned
2464  */
2465 APPLESTATIC void
2466 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2467 {
2468         int i;
2469         struct nfsusrgrp *usrp;
2470         u_char *cp = *cpp;
2471         uid_t tmp;
2472         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2473
2474         cnt = 0;
2475 tryagain:
2476         NFSLOCKNAMEID();
2477         if (nfsrv_dnsname) {
2478                 /*
2479                  * Always map nfsrv_defaultuid to "nobody".
2480                  */
2481                 if (uid == nfsrv_defaultuid) {
2482                         i = nfsrv_dnsnamelen + 7;
2483                         if (i > len) {
2484                                 NFSUNLOCKNAMEID();
2485                                 if (len > NFSV4_SMALLSTR)
2486                                         free(cp, M_NFSSTRING);
2487                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2488                                 *cpp = cp;
2489                                 len = i;
2490                                 goto tryagain;
2491                         }
2492                         *retlenp = i;
2493                         NFSBCOPY("nobody@", cp, 7);
2494                         cp += 7;
2495                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2496                         NFSUNLOCKNAMEID();
2497                         return;
2498                 }
2499                 hasampersand = 0;
2500                 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2501                         if (usrp->lug_uid == uid) {
2502                                 if (usrp->lug_expiry < NFSD_MONOSEC)
2503                                         break;
2504                                 /*
2505                                  * If the name doesn't already have an '@'
2506                                  * in it, append @domainname to it.
2507                                  */
2508                                 for (i = 0; i < usrp->lug_namelen; i++) {
2509                                         if (usrp->lug_name[i] == '@') {
2510                                                 hasampersand = 1;
2511                                                 break;
2512                                         }
2513                                 }
2514                                 if (hasampersand)
2515                                         i = usrp->lug_namelen;
2516                                 else
2517                                         i = usrp->lug_namelen +
2518                                             nfsrv_dnsnamelen + 1;
2519                                 if (i > len) {
2520                                         NFSUNLOCKNAMEID();
2521                                         if (len > NFSV4_SMALLSTR)
2522                                                 free(cp, M_NFSSTRING);
2523                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
2524                                         *cpp = cp;
2525                                         len = i;
2526                                         goto tryagain;
2527                                 }
2528                                 *retlenp = i;
2529                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2530                                 if (!hasampersand) {
2531                                         cp += usrp->lug_namelen;
2532                                         *cp++ = '@';
2533                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2534                                 }
2535                                 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2536                                 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2537                                 NFSUNLOCKNAMEID();
2538                                 return;
2539                         }
2540                 }
2541                 NFSUNLOCKNAMEID();
2542                 cnt++;
2543                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2544                     NULL, p);
2545                 if (ret == 0 && cnt < 2)
2546                         goto tryagain;
2547         } else {
2548                 NFSUNLOCKNAMEID();
2549         }
2550
2551         /*
2552          * No match, just return a string of digits.
2553          */
2554         tmp = uid;
2555         i = 0;
2556         while (tmp || i == 0) {
2557                 tmp /= 10;
2558                 i++;
2559         }
2560         len = (i > len) ? len : i;
2561         *retlenp = len;
2562         cp += (len - 1);
2563         tmp = uid;
2564         for (i = 0; i < len; i++) {
2565                 *cp-- = '0' + (tmp % 10);
2566                 tmp /= 10;
2567         }
2568         return;
2569 }
2570
2571 /*
2572  * Convert a string to a uid.
2573  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2574  * return 0.
2575  */
2576 APPLESTATIC int
2577 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2578 {
2579         int i;
2580         u_char *cp;
2581         struct nfsusrgrp *usrp;
2582         int cnt, ret;
2583
2584         if (len == 0)
2585                 return (NFSERR_BADOWNER);
2586         /*
2587          * Look for an '@'.
2588          */
2589         cp = str;
2590         for (i = 0; i < len; i++)
2591                 if (*cp++ == '@')
2592                         break;
2593
2594         cnt = 0;
2595 tryagain:
2596         NFSLOCKNAMEID();
2597         /*
2598          * If an '@' is found and the domain name matches, search for the name
2599          * with dns stripped off.
2600          * Mixed case alpahbetics will match for the domain name, but all
2601          * upper case will not.
2602          */
2603         if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2604             (len - 1 - i) == nfsrv_dnsnamelen &&
2605             !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2606                 len -= (nfsrv_dnsnamelen + 1);
2607                 *(cp - 1) = '\0';
2608         }
2609
2610         /*
2611          * Check for the special case of "nobody".
2612          */
2613         if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2614                 *uidp = nfsrv_defaultuid;
2615                 NFSUNLOCKNAMEID();
2616                 return (0);
2617         }
2618
2619         LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2620                 if (usrp->lug_namelen == len &&
2621                     !NFSBCMP(usrp->lug_name, str, len)) {
2622                         if (usrp->lug_expiry < NFSD_MONOSEC)
2623                                 break;
2624                         *uidp = usrp->lug_uid;
2625                         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2626                         TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2627                         NFSUNLOCKNAMEID();
2628                         return (0);
2629                 }
2630         }
2631         NFSUNLOCKNAMEID();
2632         cnt++;
2633         ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2634             str, p);
2635         if (ret == 0 && cnt < 2)
2636                 goto tryagain;
2637         return (NFSERR_BADOWNER);
2638 }
2639
2640 /*
2641  * Convert a gid to a string.
2642  * gid - the group id
2643  * cpp - points to a buffer of size NFSV4_SMALLSTR
2644  *       (malloc a larger one, as required)
2645  * retlenp - pointer to length to be returned
2646  */
2647 APPLESTATIC void
2648 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2649 {
2650         int i;
2651         struct nfsusrgrp *usrp;
2652         u_char *cp = *cpp;
2653         gid_t tmp;
2654         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2655
2656         cnt = 0;
2657 tryagain:
2658         NFSLOCKNAMEID();
2659         if (nfsrv_dnsname) {
2660                 /*
2661                  * Always map nfsrv_defaultgid to "nogroup".
2662                  */
2663                 if (gid == nfsrv_defaultgid) {
2664                         i = nfsrv_dnsnamelen + 8;
2665                         if (i > len) {
2666                                 NFSUNLOCKNAMEID();
2667                                 if (len > NFSV4_SMALLSTR)
2668                                         free(cp, M_NFSSTRING);
2669                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2670                                 *cpp = cp;
2671                                 len = i;
2672                                 goto tryagain;
2673                         }
2674                         *retlenp = i;
2675                         NFSBCOPY("nogroup@", cp, 8);
2676                         cp += 8;
2677                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2678                         NFSUNLOCKNAMEID();
2679                         return;
2680                 }
2681                 hasampersand = 0;
2682                 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2683                         if (usrp->lug_gid == gid) {
2684                                 if (usrp->lug_expiry < NFSD_MONOSEC)
2685                                         break;
2686                                 /*
2687                                  * If the name doesn't already have an '@'
2688                                  * in it, append @domainname to it.
2689                                  */
2690                                 for (i = 0; i < usrp->lug_namelen; i++) {
2691                                         if (usrp->lug_name[i] == '@') {
2692                                                 hasampersand = 1;
2693                                                 break;
2694                                         }
2695                                 }
2696                                 if (hasampersand)
2697                                         i = usrp->lug_namelen;
2698                                 else
2699                                         i = usrp->lug_namelen +
2700                                             nfsrv_dnsnamelen + 1;
2701                                 if (i > len) {
2702                                         NFSUNLOCKNAMEID();
2703                                         if (len > NFSV4_SMALLSTR)
2704                                                 free(cp, M_NFSSTRING);
2705                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
2706                                         *cpp = cp;
2707                                         len = i;
2708                                         goto tryagain;
2709                                 }
2710                                 *retlenp = i;
2711                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2712                                 if (!hasampersand) {
2713                                         cp += usrp->lug_namelen;
2714                                         *cp++ = '@';
2715                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2716                                 }
2717                                 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2718                                 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2719                                 NFSUNLOCKNAMEID();
2720                                 return;
2721                         }
2722                 }
2723                 NFSUNLOCKNAMEID();
2724                 cnt++;
2725                 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2726                     NULL, p);
2727                 if (ret == 0 && cnt < 2)
2728                         goto tryagain;
2729         } else {
2730                 NFSUNLOCKNAMEID();
2731         }
2732
2733         /*
2734          * No match, just return a string of digits.
2735          */
2736         tmp = gid;
2737         i = 0;
2738         while (tmp || i == 0) {
2739                 tmp /= 10;
2740                 i++;
2741         }
2742         len = (i > len) ? len : i;
2743         *retlenp = len;
2744         cp += (len - 1);
2745         tmp = gid;
2746         for (i = 0; i < len; i++) {
2747                 *cp-- = '0' + (tmp % 10);
2748                 tmp /= 10;
2749         }
2750         return;
2751 }
2752
2753 /*
2754  * Convert a string to a gid.
2755  */
2756 APPLESTATIC int
2757 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2758 {
2759         int i;
2760         u_char *cp;
2761         struct nfsusrgrp *usrp;
2762         int cnt, ret;
2763
2764         if (len == 0)
2765                 return (NFSERR_BADOWNER);
2766         /*
2767          * Look for an '@'.
2768          */
2769         cp = str;
2770         for (i = 0; i < len; i++)
2771                 if (*cp++ == '@')
2772                         break;
2773
2774         cnt = 0;
2775 tryagain:
2776         NFSLOCKNAMEID();
2777         /*
2778          * If an '@' is found and the dns name matches, search for the name
2779          * with the dns stripped off.
2780          */
2781         if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2782             (len - 1 - i) == nfsrv_dnsnamelen &&
2783             !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2784                 len -= (nfsrv_dnsnamelen + 1);
2785                 *(cp - 1) = '\0';
2786         }
2787
2788         /*
2789          * Check for the special case of "nogroup".
2790          */
2791         if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2792                 *gidp = nfsrv_defaultgid;
2793                 NFSUNLOCKNAMEID();
2794                 return (0);
2795         }
2796
2797         LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2798                 if (usrp->lug_namelen == len &&
2799                     !NFSBCMP(usrp->lug_name, str, len)) {
2800                         if (usrp->lug_expiry < NFSD_MONOSEC)
2801                                 break;
2802                         *gidp = usrp->lug_gid;
2803                         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2804                         TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2805                         NFSUNLOCKNAMEID();
2806                         return (0);
2807                 }
2808         }
2809         NFSUNLOCKNAMEID();
2810         cnt++;
2811         ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2812             str, p);
2813         if (ret == 0 && cnt < 2)
2814                 goto tryagain;
2815         return (NFSERR_BADOWNER);
2816 }
2817
2818 /*
2819  * Cmp len chars, allowing mixed case in the first argument to match lower
2820  * case in the second, but not if the first argument is all upper case.
2821  * Return 0 for a match, 1 otherwise.
2822  */
2823 static int
2824 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2825 {
2826         int i;
2827         u_char tmp;
2828         int fndlower = 0;
2829
2830         for (i = 0; i < len; i++) {
2831                 if (*cp >= 'A' && *cp <= 'Z') {
2832                         tmp = *cp++ + ('a' - 'A');
2833                 } else {
2834                         tmp = *cp++;
2835                         if (tmp >= 'a' && tmp <= 'z')
2836                                 fndlower = 1;
2837                 }
2838                 if (tmp != *cp2++)
2839                         return (1);
2840         }
2841         if (fndlower)
2842                 return (0);
2843         else
2844                 return (1);
2845 }
2846
2847 /*
2848  * Set the port for the nfsuserd.
2849  */
2850 APPLESTATIC int
2851 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2852 {
2853         struct nfssockreq *rp;
2854         struct sockaddr_in *ad;
2855         int error;
2856
2857         NFSLOCKNAMEID();
2858         if (nfsrv_nfsuserd) {
2859                 NFSUNLOCKNAMEID();
2860                 return (EPERM);
2861         }
2862         nfsrv_nfsuserd = 1;
2863         NFSUNLOCKNAMEID();
2864         /*
2865          * Set up the socket record and connect.
2866          */
2867         rp = &nfsrv_nfsuserdsock;
2868         rp->nr_client = NULL;
2869         rp->nr_sotype = SOCK_DGRAM;
2870         rp->nr_soproto = IPPROTO_UDP;
2871         rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2872         rp->nr_cred = NULL;
2873         NFSSOCKADDRALLOC(rp->nr_nam);
2874         NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2875         ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2876         ad->sin_family = AF_INET;
2877         ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);     /* 127.0.0.1 */
2878         ad->sin_port = port;
2879         rp->nr_prog = RPCPROG_NFSUSERD;
2880         rp->nr_vers = RPCNFSUSERD_VERS;
2881         error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2882         if (error) {
2883                 NFSSOCKADDRFREE(rp->nr_nam);
2884                 nfsrv_nfsuserd = 0;
2885         }
2886         return (error);
2887 }
2888
2889 /*
2890  * Delete the nfsuserd port.
2891  */
2892 APPLESTATIC void
2893 nfsrv_nfsuserddelport(void)
2894 {
2895
2896         NFSLOCKNAMEID();
2897         if (nfsrv_nfsuserd == 0) {
2898                 NFSUNLOCKNAMEID();
2899                 return;
2900         }
2901         nfsrv_nfsuserd = 0;
2902         NFSUNLOCKNAMEID();
2903         newnfs_disconnect(&nfsrv_nfsuserdsock);
2904         NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2905 }
2906
2907 /*
2908  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2909  * name<-->id cache.
2910  * Returns 0 upon success, non-zero otherwise.
2911  */
2912 static int
2913 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2914 {
2915         u_int32_t *tl;
2916         struct nfsrv_descript *nd;
2917         int len;
2918         struct nfsrv_descript nfsd;
2919         struct ucred *cred;
2920         int error;
2921
2922         NFSLOCKNAMEID();
2923         if (nfsrv_nfsuserd == 0) {
2924                 NFSUNLOCKNAMEID();
2925                 return (EPERM);
2926         }
2927         NFSUNLOCKNAMEID();
2928         nd = &nfsd;
2929         cred = newnfs_getcred();
2930         nd->nd_flag = ND_GSSINITREPLY;
2931         nfsrvd_rephead(nd);
2932
2933         nd->nd_procnum = procnum;
2934         if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2935                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2936                 if (procnum == RPCNFSUSERD_GETUID)
2937                         *tl = txdr_unsigned(uid);
2938                 else
2939                         *tl = txdr_unsigned(gid);
2940         } else {
2941                 len = strlen(name);
2942                 (void) nfsm_strtom(nd, name, len);
2943         }
2944         error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2945                 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2946         NFSFREECRED(cred);
2947         if (!error) {
2948                 mbuf_freem(nd->nd_mrep);
2949                 error = nd->nd_repstat;
2950         }
2951         return (error);
2952 }
2953
2954 /*
2955  * This function is called from the nfssvc(2) system call, to update the
2956  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2957  */
2958 APPLESTATIC int
2959 nfssvc_idname(struct nfsd_idargs *nidp)
2960 {
2961         struct nfsusrgrp *nusrp, *usrp, *newusrp;
2962         struct nfsuserhashhead *hp;
2963         int i;
2964         int error = 0;
2965         u_char *cp;
2966
2967         if (nidp->nid_flag & NFSID_INITIALIZE) {
2968             cp = (u_char *)malloc(nidp->nid_namelen + 1,
2969                 M_NFSSTRING, M_WAITOK);
2970             error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2971                 nidp->nid_namelen);
2972             NFSLOCKNAMEID();
2973             if (nfsrv_dnsname) {
2974                 /*
2975                  * Free up all the old stuff and reinitialize hash lists.
2976                  */
2977                 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2978                         nfsrv_removeuser(usrp);
2979                 }
2980                 free(nfsrv_dnsname, M_NFSSTRING);
2981                 nfsrv_dnsname = NULL;
2982             }
2983             TAILQ_INIT(&nfsuserlruhead);
2984             for (i = 0; i < NFSUSERHASHSIZE; i++)
2985                 LIST_INIT(&nfsuserhash[i]);
2986             for (i = 0; i < NFSGROUPHASHSIZE; i++)
2987                 LIST_INIT(&nfsgrouphash[i]);
2988             for (i = 0; i < NFSUSERHASHSIZE; i++)
2989                 LIST_INIT(&nfsusernamehash[i]);
2990             for (i = 0; i < NFSGROUPHASHSIZE; i++)
2991                 LIST_INIT(&nfsgroupnamehash[i]);
2992
2993             /*
2994              * Put name in "DNS" string.
2995              */
2996             if (!error) {
2997                 nfsrv_dnsname = cp;
2998                 nfsrv_dnsnamelen = nidp->nid_namelen;
2999                 nfsrv_defaultuid = nidp->nid_uid;
3000                 nfsrv_defaultgid = nidp->nid_gid;
3001                 nfsrv_usercnt = 0;
3002                 nfsrv_usermax = nidp->nid_usermax;
3003             }
3004             NFSUNLOCKNAMEID();
3005             if (error)
3006                 free(cp, M_NFSSTRING);
3007             return (error);
3008         }
3009
3010         /*
3011          * malloc the new one now, so any potential sleep occurs before
3012          * manipulation of the lists.
3013          */
3014         MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3015             nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3016         error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3017             nidp->nid_namelen);
3018         if (error) {
3019                 free((caddr_t)newusrp, M_NFSUSERGROUP);
3020                 return (error);
3021         }
3022         newusrp->lug_namelen = nidp->nid_namelen;
3023
3024         NFSLOCKNAMEID();
3025         /*
3026          * Delete old entries, as required.
3027          */
3028         if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3029                 hp = NFSUSERHASH(nidp->nid_uid);
3030                 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3031                         if (usrp->lug_uid == nidp->nid_uid)
3032                                 nfsrv_removeuser(usrp);
3033                 }
3034         }
3035         if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3036                 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3037                 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3038                         if (usrp->lug_namelen == newusrp->lug_namelen &&
3039                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3040                             usrp->lug_namelen))
3041                                 nfsrv_removeuser(usrp);
3042                 }
3043         }
3044         if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3045                 hp = NFSGROUPHASH(nidp->nid_gid);
3046                 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3047                         if (usrp->lug_gid == nidp->nid_gid)
3048                                 nfsrv_removeuser(usrp);
3049                 }
3050         }
3051         if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3052                 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3053                 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3054                         if (usrp->lug_namelen == newusrp->lug_namelen &&
3055                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3056                             usrp->lug_namelen))
3057                                 nfsrv_removeuser(usrp);
3058                 }
3059         }
3060         TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3061                 if (usrp->lug_expiry < NFSD_MONOSEC)
3062                         nfsrv_removeuser(usrp);
3063         }
3064         while (nfsrv_usercnt >= nfsrv_usermax) {
3065                 usrp = TAILQ_FIRST(&nfsuserlruhead);
3066                 nfsrv_removeuser(usrp);
3067         }
3068
3069         /*
3070          * Now, we can add the new one.
3071          */
3072         if (nidp->nid_usertimeout)
3073                 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3074         else
3075                 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3076         if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3077                 newusrp->lug_uid = nidp->nid_uid;
3078                 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3079                     lug_numhash);
3080                 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3081                     newusrp->lug_namelen), newusrp, lug_namehash);
3082                 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3083                 nfsrv_usercnt++;
3084         } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3085                 newusrp->lug_gid = nidp->nid_gid;
3086                 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3087                     lug_numhash);
3088                 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3089                     newusrp->lug_namelen), newusrp, lug_namehash);
3090                 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3091                 nfsrv_usercnt++;
3092         } else
3093                 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3094         NFSUNLOCKNAMEID();
3095         return (error);
3096 }
3097
3098 /*
3099  * Remove a user/group name element.
3100  */
3101 static void
3102 nfsrv_removeuser(struct nfsusrgrp *usrp)
3103 {
3104
3105         NFSNAMEIDREQUIRED();
3106         LIST_REMOVE(usrp, lug_numhash);
3107         LIST_REMOVE(usrp, lug_namehash);
3108         TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3109         nfsrv_usercnt--;
3110         FREE((caddr_t)usrp, M_NFSUSERGROUP);
3111 }
3112
3113 /*
3114  * This function scans a byte string and checks for UTF-8 compliance.
3115  * It returns 0 if it conforms and NFSERR_INVAL if not.
3116  */
3117 APPLESTATIC int
3118 nfsrv_checkutf8(u_int8_t *cp, int len)
3119 {
3120         u_int32_t val = 0x0;
3121         int cnt = 0, gotd = 0, shift = 0;
3122         u_int8_t byte;
3123         static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3124
3125         /*
3126          * Here are what the variables are used for:
3127          * val - the calculated value of a multibyte char, used to check
3128          *       that it was coded with the correct range
3129          * cnt - the number of 10xxxxxx bytes to follow
3130          * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3131          * shift - lower order bits of range (ie. "val >> shift" should
3132          *       not be 0, in other words, dividing by the lower bound
3133          *       of the range should get a non-zero value)
3134          * byte - used to calculate cnt
3135          */
3136         while (len > 0) {
3137                 if (cnt > 0) {
3138                         /* This handles the 10xxxxxx bytes */
3139                         if ((*cp & 0xc0) != 0x80 ||
3140                             (gotd && (*cp & 0x20)))
3141                                 return (NFSERR_INVAL);
3142                         gotd = 0;
3143                         val <<= 6;
3144                         val |= (*cp & 0x3f);
3145                         cnt--;
3146                         if (cnt == 0 && (val >> shift) == 0x0)
3147                                 return (NFSERR_INVAL);
3148                 } else if (*cp & 0x80) {
3149                         /* first byte of multi byte char */
3150                         byte = *cp;
3151                         while ((byte & 0x40) && cnt < 6) {
3152                                 cnt++;
3153                                 byte <<= 1;
3154                         }
3155                         if (cnt == 0 || cnt == 6)
3156                                 return (NFSERR_INVAL);
3157                         val = (*cp & (0x3f >> cnt));
3158                         shift = utf8_shift[cnt - 1];
3159                         if (cnt == 2 && val == 0xd)
3160                                 /* Check for the 0xd800-0xdfff case */
3161                                 gotd = 1;
3162                 }
3163                 cp++;
3164                 len--;
3165         }
3166         if (cnt > 0)
3167                 return (NFSERR_INVAL);
3168         return (0);
3169 }
3170
3171 /*
3172  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3173  * strings, one with the root path in it and the other with the list of
3174  * locations. The list is in the same format as is found in nfr_refs.
3175  * It is a "," separated list of entries, where each of them is of the
3176  * form <server>:<rootpath>. For example
3177  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3178  * The nilp argument is set to 1 for the special case of a null fs_root
3179  * and an empty server list.
3180  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3181  * number of xdr bytes parsed in sump.
3182  */
3183 static int
3184 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3185     int *sump, int *nilp)
3186 {
3187         u_int32_t *tl;
3188         u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3189         int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3190         struct list {
3191                 SLIST_ENTRY(list) next;
3192                 int len;
3193                 u_char host[1];
3194         } *lsp, *nlsp;
3195         SLIST_HEAD(, list) head;
3196
3197         *fsrootp = NULL;
3198         *srvp = NULL;
3199         *nilp = 0;
3200
3201         /*
3202          * Get the fs_root path and check for the special case of null path
3203          * and 0 length server list.
3204          */
3205         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3206         len = fxdr_unsigned(int, *tl);
3207         if (len < 0 || len > 10240)
3208                 return (NFSERR_BADXDR);
3209         if (len == 0) {
3210                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3211                 if (*tl != 0)
3212                         return (NFSERR_BADXDR);
3213                 *nilp = 1;
3214                 *sump = 2 * NFSX_UNSIGNED;
3215                 return (0);
3216         }
3217         cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3218         error = nfsrv_mtostr(nd, cp, len);
3219         if (!error) {
3220                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3221                 cnt = fxdr_unsigned(int, *tl);
3222                 if (cnt <= 0)
3223                         error = NFSERR_BADXDR;
3224         }
3225         if (error) {
3226                 free(cp, M_NFSSTRING);
3227                 return (error);
3228         }
3229
3230         /*
3231          * Now, loop through the location list and make up the srvlist.
3232          */
3233         xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3234         cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3235         slen = 1024;
3236         siz = 0;
3237         for (i = 0; i < cnt; i++) {
3238                 SLIST_INIT(&head);
3239                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3240                 nsrv = fxdr_unsigned(int, *tl);
3241                 if (nsrv <= 0) {
3242                         free(cp, M_NFSSTRING);
3243                         free(cp2, M_NFSSTRING);
3244                         return (NFSERR_BADXDR);
3245                 }
3246
3247                 /*
3248                  * Handle the first server by putting it in the srvstr.
3249                  */
3250                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3251                 len = fxdr_unsigned(int, *tl);
3252                 if (len <= 0 || len > 1024) {
3253                         free(cp, M_NFSSTRING);
3254                         free(cp2, M_NFSSTRING);
3255                         return (NFSERR_BADXDR);
3256                 }
3257                 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3258                 if (cp3 != cp2) {
3259                         *cp3++ = ',';
3260                         siz++;
3261                 }
3262                 error = nfsrv_mtostr(nd, cp3, len);
3263                 if (error) {
3264                         free(cp, M_NFSSTRING);
3265                         free(cp2, M_NFSSTRING);
3266                         return (error);
3267                 }
3268                 cp3 += len;
3269                 *cp3++ = ':';
3270                 siz += (len + 1);
3271                 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3272                 for (j = 1; j < nsrv; j++) {
3273                         /*
3274                          * Yuck, put them in an slist and process them later.
3275                          */
3276                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3277                         len = fxdr_unsigned(int, *tl);
3278                         if (len <= 0 || len > 1024) {
3279                                 free(cp, M_NFSSTRING);
3280                                 free(cp2, M_NFSSTRING);
3281                                 return (NFSERR_BADXDR);
3282                         }
3283                         lsp = (struct list *)malloc(sizeof (struct list)
3284                             + len, M_TEMP, M_WAITOK);
3285                         error = nfsrv_mtostr(nd, lsp->host, len);
3286                         if (error) {
3287                                 free(cp, M_NFSSTRING);
3288                                 free(cp2, M_NFSSTRING);
3289                                 return (error);
3290                         }
3291                         xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3292                         lsp->len = len;
3293                         SLIST_INSERT_HEAD(&head, lsp, next);
3294                 }
3295
3296                 /*
3297                  * Finally, we can get the path.
3298                  */
3299                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3300                 len = fxdr_unsigned(int, *tl);
3301                 if (len <= 0 || len > 1024) {
3302                         free(cp, M_NFSSTRING);
3303                         free(cp2, M_NFSSTRING);
3304                         return (NFSERR_BADXDR);
3305                 }
3306                 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3307                 error = nfsrv_mtostr(nd, cp3, len);
3308                 if (error) {
3309                         free(cp, M_NFSSTRING);
3310                         free(cp2, M_NFSSTRING);
3311                         return (error);
3312                 }
3313                 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3314                 str = cp3;
3315                 stringlen = len;
3316                 cp3 += len;
3317                 siz += len;
3318                 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3319                         nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3320                             &cp2, &cp3, &slen);
3321                         *cp3++ = ',';
3322                         NFSBCOPY(lsp->host, cp3, lsp->len);
3323                         cp3 += lsp->len;
3324                         *cp3++ = ':';
3325                         NFSBCOPY(str, cp3, stringlen);
3326                         cp3 += stringlen;
3327                         *cp3 = '\0';
3328                         siz += (lsp->len + stringlen + 2);
3329                         free((caddr_t)lsp, M_TEMP);
3330                 }
3331         }
3332         *fsrootp = cp;
3333         *srvp = cp2;
3334         *sump = xdrsum;
3335         return (0);
3336 nfsmout:
3337         if (cp != NULL)
3338                 free(cp, M_NFSSTRING);
3339         if (cp2 != NULL)
3340                 free(cp2, M_NFSSTRING);
3341         return (error);
3342 }
3343
3344 /*
3345  * Make the malloc'd space large enough. This is a pain, but the xdr
3346  * doesn't set an upper bound on the side, so...
3347  */
3348 static void
3349 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3350 {
3351         u_char *cp;
3352         int i;
3353
3354         if (siz <= *slenp)
3355                 return;
3356         cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3357         NFSBCOPY(*cpp, cp, *slenp);
3358         free(*cpp, M_NFSSTRING);
3359         i = *cpp2 - *cpp;
3360         *cpp = cp;
3361         *cpp2 = cp + i;
3362         *slenp = siz + 1024;
3363 }
3364
3365 /*
3366  * Initialize the reply header data structures.
3367  */
3368 APPLESTATIC void
3369 nfsrvd_rephead(struct nfsrv_descript *nd)
3370 {
3371         mbuf_t mreq;
3372
3373         /*
3374          * If this is a big reply, use a cluster.
3375          */
3376         if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3377             nfs_bigreply[nd->nd_procnum]) {
3378                 NFSMCLGET(mreq, M_WAIT);
3379                 nd->nd_mreq = mreq;
3380                 nd->nd_mb = mreq;
3381         } else {
3382                 NFSMGET(mreq);
3383                 nd->nd_mreq = mreq;
3384                 nd->nd_mb = mreq;
3385         }
3386         nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3387         mbuf_setlen(mreq, 0);
3388
3389         if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3390                 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3391 }
3392
3393 /*
3394  * Lock a socket against others.
3395  * Currently used to serialize connect/disconnect attempts.
3396  */
3397 int
3398 newnfs_sndlock(int *flagp)
3399 {
3400         struct timespec ts;
3401
3402         NFSLOCKSOCK();
3403         while (*flagp & NFSR_SNDLOCK) {
3404                 *flagp |= NFSR_WANTSND;
3405                 ts.tv_sec = 0;
3406                 ts.tv_nsec = 0;
3407                 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3408                     PZERO - 1, "nfsndlck", &ts);
3409         }
3410         *flagp |= NFSR_SNDLOCK;
3411         NFSUNLOCKSOCK();
3412         return (0);
3413 }
3414
3415 /*
3416  * Unlock the stream socket for others.
3417  */
3418 void
3419 newnfs_sndunlock(int *flagp)
3420 {
3421
3422         NFSLOCKSOCK();
3423         if ((*flagp & NFSR_SNDLOCK) == 0)
3424                 panic("nfs sndunlock");
3425         *flagp &= ~NFSR_SNDLOCK;
3426         if (*flagp & NFSR_WANTSND) {
3427                 *flagp &= ~NFSR_WANTSND;
3428                 wakeup((caddr_t)flagp);
3429         }
3430         NFSUNLOCKSOCK();
3431 }
3432