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