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