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