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