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