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