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