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