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