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