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