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