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