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