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