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