2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
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.
46 #include "opt_inet6.h"
48 #include <fs/nfs/nfsport.h>
50 #include <sys/extattr.h>
52 #include <security/mac/mac_framework.h>
55 * Data items converted to xdr at startup, since they are constant
56 * This is kinda hokey, but may save a little time doing byte swaps
58 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
60 /* And other global data */
61 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
63 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
64 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
65 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
68 struct nfssockreq nfsrv_nfsuserdsock;
69 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
70 static int nfsrv_userdupcalls = 0;
71 struct nfsreqhead nfsd_reqq;
72 uid_t nfsrv_defaultuid = UID_NOBODY;
73 gid_t nfsrv_defaultgid = GID_NOGROUP;
74 int nfsrv_lease = NFSRV_LEASE;
75 int ncl_mbuf_mlen = MLEN;
76 int nfsd_enable_stringtouid = 0;
77 int nfsrv_doflexfile = 0;
78 static int nfs_enable_uidtostring = 0;
81 extern int nfsrv_lughashsize;
82 extern struct mtx nfsrv_dslock_mtx;
83 extern volatile int nfsrv_devidcnt;
84 extern int nfscl_debuglevel;
85 extern struct nfsdevicehead nfsrv_devidhead;
86 extern struct nfsstatsv1 nfsstatsv1;
88 SYSCTL_DECL(_vfs_nfs);
89 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
90 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
92 int nfsrv_maxpnfsmirror = 1;
93 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
94 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
96 int nfs_maxcopyrange = 10 * 1024 * 1024;
97 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
98 &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
101 * This array of structures indicates, for V4:
102 * retfh - which of 3 types of calling args are used
103 * 0 - doesn't change cfh or use a sfh
104 * 1 - replaces cfh with a new one (unless it returns an error status)
105 * 2 - uses cfh and sfh
106 * needscfh - if the op wants a cfh and premtime
107 * 0 - doesn't use a cfh
108 * 1 - uses a cfh, but doesn't want pre-op attributes
109 * 2 - uses a cfh and wants pre-op attributes
110 * savereply - indicates a non-idempotent Op
111 * 0 - not non-idempotent
113 * Ops that are ordered via seqid# are handled separately from these
114 * non-idempotent Ops.
115 * Define it here, since it is used by both the client and server.
117 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
118 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
121 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
123 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
124 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
125 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
127 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
128 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
129 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
133 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
134 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
135 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
136 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
137 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
138 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
140 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
141 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
142 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
143 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
144 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
145 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
146 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
147 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
152 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
155 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
156 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
161 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
167 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
168 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
169 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
170 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
171 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
173 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
174 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
175 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
176 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
177 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
178 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
179 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
180 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
181 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
182 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
183 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
184 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
185 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
186 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
187 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
188 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
189 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
190 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
191 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
192 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
193 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
195 #endif /* !APPLEKEXT */
197 static int ncl_mbuf_mhlen = MHLEN;
198 static int nfsrv_usercnt = 0;
199 static int nfsrv_dnsnamelen;
200 static u_char *nfsrv_dnsname = NULL;
201 static int nfsrv_usermax = 999999999;
202 struct nfsrv_lughash {
204 struct nfsuserhashhead lughead;
206 static struct nfsrv_lughash *nfsuserhash;
207 static struct nfsrv_lughash *nfsusernamehash;
208 static struct nfsrv_lughash *nfsgrouphash;
209 static struct nfsrv_lughash *nfsgroupnamehash;
212 * This static array indicates whether or not the RPC generates a large
213 * reply. This is used by nfs_reply() to decide whether or not an mbuf
214 * cluster should be allocated. (If a cluster is required by an RPC
215 * marked 0 in this array, the code will still work, just not quite as
218 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
223 /* local functions */
224 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
225 static void nfsv4_wanted(struct nfsv4lock *lp);
226 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
227 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
228 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
229 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
231 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
238 } nfsv4_opmap[NFSV42_NPROCS] = {
240 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
241 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
242 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
243 { NFSV4OP_ACCESS, 2, "Access", 6, },
244 { NFSV4OP_READLINK, 2, "Readlink", 8, },
245 { NFSV4OP_READ, 1, "Read", 4, },
246 { NFSV4OP_WRITE, 2, "Write", 5, },
247 { NFSV4OP_OPEN, 5, "Open", 4, },
248 { NFSV4OP_CREATE, 5, "Create", 6, },
249 { NFSV4OP_CREATE, 1, "Create", 6, },
250 { NFSV4OP_CREATE, 3, "Create", 6, },
251 { NFSV4OP_REMOVE, 1, "Remove", 6, },
252 { NFSV4OP_REMOVE, 1, "Remove", 6, },
253 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
254 { NFSV4OP_SAVEFH, 4, "Link", 4, },
255 { NFSV4OP_READDIR, 2, "Readdir", 7, },
256 { NFSV4OP_READDIR, 2, "Readdir", 7, },
257 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
259 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
260 { NFSV4OP_COMMIT, 2, "Commit", 6, },
261 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
262 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
263 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
264 { NFSV4OP_LOCK, 1, "Lock", 4, },
265 { NFSV4OP_LOCKU, 1, "LockU", 5, },
266 { NFSV4OP_OPEN, 2, "Open", 4, },
267 { NFSV4OP_CLOSE, 1, "Close", 5, },
268 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
269 { NFSV4OP_LOCKT, 1, "LockT", 5, },
270 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
271 { NFSV4OP_RENEW, 1, "Renew", 5, },
272 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
273 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
274 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
275 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
276 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
277 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
278 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
279 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
280 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
281 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
282 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
283 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
284 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
285 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
286 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
287 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
288 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
289 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
290 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
291 { NFSV4OP_READ, 1, "ReadDS", 6, },
292 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
293 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
294 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
295 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
296 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
297 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
298 { NFSV4OP_SEEK, 2, "Seek", 4, },
299 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
300 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
301 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
302 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
303 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
307 * NFS RPCS that have large request message size.
309 static int nfs_bigrequest[NFSV42_NPROCS] = {
310 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
316 * Start building a request. Mostly just put the first file handle in
320 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
321 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
322 int vers, int minorvers)
327 nfsattrbit_t attrbits;
330 * First, fill in some of the fields of nd.
332 nd->nd_slotseq = NULL;
333 if (vers == NFS_VER4) {
334 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
335 if (minorvers == NFSV41_MINORVERSION)
336 nd->nd_flag |= ND_NFSV41;
337 else if (minorvers == NFSV42_MINORVERSION)
338 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
339 } else if (vers == NFS_VER3)
340 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
342 if (NFSHASNFSV4(nmp)) {
343 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
344 if (nmp->nm_minorvers == 1)
345 nd->nd_flag |= ND_NFSV41;
346 else if (nmp->nm_minorvers == 2)
347 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
348 } else if (NFSHASNFSV3(nmp))
349 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
351 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
353 nd->nd_procnum = procnum;
357 * Get the first mbuf for the request.
359 if (nfs_bigrequest[procnum])
360 NFSMCLGET(mb, M_WAITOK);
364 nd->nd_mreq = nd->nd_mb = mb;
365 nd->nd_bpos = NFSMTOD(mb, caddr_t);
368 * And fill the first file handle into the request.
370 if (nd->nd_flag & ND_NFSV4) {
371 opcnt = nfsv4_opmap[procnum].opcnt +
372 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
373 if ((nd->nd_flag & ND_NFSV41) != 0) {
374 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
375 if (procnum == NFSPROC_RENEW)
377 * For the special case of Renew, just do a
381 else if (procnum == NFSPROC_WRITEDS ||
382 procnum == NFSPROC_COMMITDS)
384 * For the special case of a Writeor Commit to
385 * a DS, the opcnt == 3, for Sequence, PutFH,
391 * What should the tag really be?
393 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
394 nfsv4_opmap[procnum].taglen);
395 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
396 if ((nd->nd_flag & ND_NFSV42) != 0)
397 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
398 else if ((nd->nd_flag & ND_NFSV41) != 0)
399 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
401 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
404 *tl = txdr_unsigned(opcnt);
405 if ((nd->nd_flag & ND_NFSV41) != 0 &&
406 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
407 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
409 nd->nd_flag |= ND_LOOPBADSESS;
410 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
411 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
413 sep = nfsmnt_mdssession(nmp);
414 nfsv4_setsequence(nmp, nd, sep,
415 nfs_bigreply[procnum]);
417 nfsv4_setsequence(nmp, nd, sep,
418 nfs_bigreply[procnum]);
420 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
421 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
422 *tl = txdr_unsigned(NFSV4OP_PUTFH);
423 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
424 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
425 == 2 && procnum != NFSPROC_WRITEDS &&
426 procnum != NFSPROC_COMMITDS) {
427 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
428 *tl = txdr_unsigned(NFSV4OP_GETATTR);
430 * For Lookup Ops, we want all the directory
431 * attributes, so we can load the name cache.
433 if (procnum == NFSPROC_LOOKUP ||
434 procnum == NFSPROC_LOOKUPP)
435 NFSGETATTR_ATTRBIT(&attrbits);
437 NFSWCCATTR_ATTRBIT(&attrbits);
438 nd->nd_flag |= ND_V4WCCATTR;
440 (void) nfsrv_putattrbit(nd, &attrbits);
443 if (procnum != NFSPROC_RENEW ||
444 (nd->nd_flag & ND_NFSV41) == 0) {
445 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
446 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
449 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
451 if (procnum < NFSV42_NPROCS)
452 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
456 * Put a state Id in the mbuf list.
459 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
463 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
464 if (flag == NFSSTATEID_PUTALLZERO) {
469 } else if (flag == NFSSTATEID_PUTALLONE) {
470 st->seqid = 0xffffffff;
471 st->other[0] = 0xffffffff;
472 st->other[1] = 0xffffffff;
473 st->other[2] = 0xffffffff;
474 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
476 st->other[0] = stateidp->other[0];
477 st->other[1] = stateidp->other[1];
478 st->other[2] = stateidp->other[2];
480 st->seqid = stateidp->seqid;
481 st->other[0] = stateidp->other[0];
482 st->other[1] = stateidp->other[1];
483 st->other[2] = stateidp->other[2];
488 * Fill in the setable attributes. The full argument indicates whether
489 * to fill in them all or just mode and time.
492 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
493 struct vnode *vp, int flags, u_int32_t rdev)
496 struct nfsv2_sattr *sp;
497 nfsattrbit_t attrbits;
499 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
501 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
502 if (vap->va_mode == (mode_t)VNOVAL)
503 sp->sa_mode = newnfs_xdrneg1;
505 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
506 if (vap->va_uid == (uid_t)VNOVAL)
507 sp->sa_uid = newnfs_xdrneg1;
509 sp->sa_uid = txdr_unsigned(vap->va_uid);
510 if (vap->va_gid == (gid_t)VNOVAL)
511 sp->sa_gid = newnfs_xdrneg1;
513 sp->sa_gid = txdr_unsigned(vap->va_gid);
514 if (flags & NFSSATTR_SIZE0)
516 else if (flags & NFSSATTR_SIZENEG1)
517 sp->sa_size = newnfs_xdrneg1;
518 else if (flags & NFSSATTR_SIZERDEV)
519 sp->sa_size = txdr_unsigned(rdev);
521 sp->sa_size = txdr_unsigned(vap->va_size);
522 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
523 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
526 if (vap->va_mode != (mode_t)VNOVAL) {
527 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
529 *tl = txdr_unsigned(vap->va_mode);
531 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
534 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
535 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
537 *tl = txdr_unsigned(vap->va_uid);
539 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
542 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
543 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
545 *tl = txdr_unsigned(vap->va_gid);
547 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
550 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
551 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
553 txdr_hyper(vap->va_size, tl);
555 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
558 if (vap->va_atime.tv_sec != VNOVAL) {
559 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
560 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
561 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
562 txdr_nfsv3time(&vap->va_atime, tl);
564 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
565 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
568 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
569 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
571 if (vap->va_mtime.tv_sec != VNOVAL) {
572 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
573 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
574 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
575 txdr_nfsv3time(&vap->va_mtime, tl);
577 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
578 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
581 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
582 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
586 NFSZERO_ATTRBIT(&attrbits);
587 if (vap->va_mode != (mode_t)VNOVAL)
588 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
589 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
590 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
591 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
592 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
593 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
594 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
595 if (vap->va_atime.tv_sec != VNOVAL)
596 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
597 if (vap->va_mtime.tv_sec != VNOVAL)
598 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
599 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
600 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
607 * copies mbuf chain to the uio scatter/gather list
610 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
612 char *mbufcp, *uiocp;
619 mbufcp = nd->nd_dpos;
620 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
621 rem = NFSM_RNDUP(siz) - siz;
623 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
627 left = uiop->uio_iov->iov_len;
628 uiocp = uiop->uio_iov->iov_base;
639 mbufcp = NFSMTOD(mp, caddr_t);
642 ("len %d, corrupted mbuf?", len));
644 xfer = (left > len) ? len : left;
647 if (uiop->uio_iov->iov_op != NULL)
648 (*(uiop->uio_iov->iov_op))
649 (mbufcp, uiocp, xfer);
652 if (uiop->uio_segflg == UIO_SYSSPACE)
653 NFSBCOPY(mbufcp, uiocp, xfer);
655 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
660 uiop->uio_offset += xfer;
661 uiop->uio_resid -= xfer;
663 if (uiop->uio_iov->iov_len <= siz) {
667 uiop->uio_iov->iov_base = (void *)
668 ((char *)uiop->uio_iov->iov_base + uiosiz);
669 uiop->uio_iov->iov_len -= uiosiz;
673 nd->nd_dpos = mbufcp;
677 error = nfsm_advance(nd, rem, len);
683 NFSEXITCODE2(error, nd);
689 * Help break down an mbuf chain by setting the first siz bytes contiguous
690 * pointed to by returned val.
691 * This is used by the macro NFSM_DISSECT for tough
695 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
704 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
706 nd->nd_md = mbuf_next(nd->nd_md);
707 if (nd->nd_md == NULL)
709 left = mbuf_len(nd->nd_md);
710 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
715 } else if (mbuf_next(nd->nd_md) == NULL) {
717 } else if (siz > ncl_mbuf_mhlen) {
718 panic("nfs S too big");
720 MGET(mp2, MT_DATA, how);
723 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
724 mbuf_setnext(nd->nd_md, mp2);
725 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
727 retp = p = NFSMTOD(mp2, caddr_t);
728 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
731 mp2 = mbuf_next(mp2);
732 /* Loop around copying up the siz2 bytes */
736 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
738 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
739 NFSM_DATAP(mp2, xfer);
740 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
745 mp2 = mbuf_next(mp2);
747 mbuf_setlen(nd->nd_md, siz);
749 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
755 * Advance the position in the mbuf chain.
756 * If offs == 0, this is a no-op, but it is simpler to just return from
757 * here than check for offs > 0 for all calls to nfsm_advance.
758 * If left == -1, it should be calculated here.
761 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
768 * A negative offs might indicate a corrupted mbuf chain and,
769 * as such, a printf is logged.
772 printf("nfsrv_advance: negative offs\n");
778 * If left == -1, calculate it here.
781 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
785 * Loop around, advancing over the mbuf data.
787 while (offs > left) {
789 nd->nd_md = mbuf_next(nd->nd_md);
790 if (nd->nd_md == NULL) {
794 left = mbuf_len(nd->nd_md);
795 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
805 * Copy a string into mbuf(s).
806 * Return the number of bytes output, including XDR overheads.
809 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
818 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
819 *tl = txdr_unsigned(siz);
820 rem = NFSM_RNDUP(siz) - siz;
821 bytesize = NFSX_UNSIGNED + siz + rem;
824 left = M_TRAILINGSPACE(m2);
827 * Loop around copying the string to mbuf(s).
831 if (siz > ncl_mbuf_mlen)
832 NFSMCLGET(m1, M_WAITOK);
836 mbuf_setnext(m2, m1);
838 cp2 = NFSMTOD(m2, caddr_t);
839 left = M_TRAILINGSPACE(m2);
845 NFSBCOPY(cp, cp2, xfer);
847 mbuf_setlen(m2, mbuf_len(m2) + xfer);
850 if (siz == 0 && rem) {
852 panic("nfsm_strtom");
853 NFSBZERO(cp2 + xfer, rem);
854 mbuf_setlen(m2, mbuf_len(m2) + rem);
858 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
863 * Called once to initialize data structures...
868 static int nfs_inited = 0;
874 newnfs_true = txdr_unsigned(TRUE);
875 newnfs_false = txdr_unsigned(FALSE);
876 newnfs_xdrneg1 = txdr_unsigned(-1);
877 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
880 NFSSETBOOTTIME(nfsboottime);
883 * Initialize reply list and start timer
885 TAILQ_INIT(&nfsd_reqq);
890 * Put a file handle in an mbuf list.
891 * If the size argument == 0, just use the default size.
892 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
893 * Return the number of bytes output, including XDR overhead.
896 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
900 int fullsiz, rem, bytesize = 0;
904 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
906 if (size > NFSX_V2FH)
907 panic("fh size > NFSX_V2FH for NFSv2");
908 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
909 NFSBCOPY(fhp, cp, size);
910 if (size < NFSX_V2FH)
911 NFSBZERO(cp + size, NFSX_V2FH - size);
912 bytesize = NFSX_V2FH;
916 fullsiz = NFSM_RNDUP(size);
917 rem = fullsiz - size;
919 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
920 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
923 bytesize = NFSX_UNSIGNED + fullsiz;
925 (void) nfsm_strtom(nd, fhp, size);
932 * This function compares two net addresses by family and returns TRUE
933 * if they are the same host.
934 * If there is any doubt, return FALSE.
935 * The AF_INET family is handled as a special case so that address mbufs
936 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
939 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
942 struct sockaddr_in *inetaddr;
948 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
949 if (inetaddr->sin_family == AF_INET &&
950 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
957 struct sockaddr_in6 *inetaddr6;
959 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
960 /* XXX - should test sin6_scope_id ? */
961 if (inetaddr6->sin6_family == AF_INET6 &&
962 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
973 * Similar to the above, but takes to NFSSOCKADDR_T args.
976 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
978 struct sockaddr_in *addr1, *addr2;
979 struct sockaddr *inaddr;
981 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
982 switch (inaddr->sa_family) {
984 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
985 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
986 if (addr2->sin_family == AF_INET &&
987 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
993 struct sockaddr_in6 *inet6addr1, *inet6addr2;
995 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
996 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
997 /* XXX - should test sin6_scope_id ? */
998 if (inet6addr2->sin6_family == AF_INET6 &&
999 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1000 &inet6addr2->sin6_addr))
1011 * Trim the stuff already dissected off the mbuf list.
1014 newnfs_trimleading(nd)
1015 struct nfsrv_descript *nd;
1021 * First, free up leading mbufs.
1023 if (nd->nd_mrep != nd->nd_md) {
1025 while (mbuf_next(m) != nd->nd_md) {
1026 if (mbuf_next(m) == NULL)
1027 panic("nfsm trim leading");
1030 mbuf_setnext(m, NULL);
1031 mbuf_freem(nd->nd_mrep);
1036 * Now, adjust this mbuf, based on nd_dpos.
1038 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
1039 if (offs == mbuf_len(m)) {
1043 panic("nfsm trim leading2");
1044 mbuf_setnext(n, NULL);
1046 } else if (offs > 0) {
1047 mbuf_setlen(m, mbuf_len(m) - offs);
1048 NFSM_DATAP(m, offs);
1049 } else if (offs < 0)
1050 panic("nfsm trimleading offs");
1053 nd->nd_dpos = NFSMTOD(m, caddr_t);
1057 * Trim trailing data off the mbuf list being built.
1060 newnfs_trimtrailing(nd, mb, bpos)
1061 struct nfsrv_descript *nd;
1066 if (mbuf_next(mb)) {
1067 mbuf_freem(mbuf_next(mb));
1068 mbuf_setnext(mb, NULL);
1070 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1076 * Dissect a file handle on the client.
1079 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1086 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1087 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1088 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1095 nfhp = malloc(sizeof (struct nfsfh) + len,
1097 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1099 free(nfhp, M_NFSFH);
1102 nfhp->nfh_len = len;
1105 NFSEXITCODE2(error, nd);
1110 * Break down the nfsv4 acl.
1111 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1114 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1115 int *aclsizep, __unused NFSPROC_T *p)
1119 int acecnt, error = 0, aceerr = 0, acesize;
1125 * Parse out the ace entries and expect them to conform to
1126 * what can be supported by R/W/X bits.
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 aclsize = NFSX_UNSIGNED;
1130 acecnt = fxdr_unsigned(int, *tl);
1131 if (acecnt > ACL_MAX_ENTRIES)
1132 aceerr = NFSERR_ATTRNOTSUPP;
1133 if (nfsrv_useacl == 0)
1134 aceerr = NFSERR_ATTRNOTSUPP;
1135 for (i = 0; i < acecnt; i++) {
1136 if (aclp && !aceerr)
1137 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1138 &aceerr, &acesize, p);
1140 error = nfsrv_skipace(nd, &acesize);
1145 if (aclp && !aceerr)
1146 aclp->acl_cnt = acecnt;
1150 *aclsizep = aclsize;
1152 NFSEXITCODE2(error, nd);
1157 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1160 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1165 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1166 len = fxdr_unsigned(int, *(tl + 3));
1167 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1169 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1170 NFSEXITCODE2(error, nd);
1175 * Get attribute bits from an mbuf list.
1176 * Returns EBADRPC for a parsing error, 0 otherwise.
1177 * If the clearinvalid flag is set, clear the bits not supported.
1180 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1187 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1188 cnt = fxdr_unsigned(int, *tl);
1190 error = NFSERR_BADXDR;
1193 if (cnt > NFSATTRBIT_MAXWORDS)
1194 outcnt = NFSATTRBIT_MAXWORDS;
1197 NFSZERO_ATTRBIT(attrbitp);
1199 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1200 for (i = 0; i < outcnt; i++)
1201 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1203 for (i = 0; i < (cnt - outcnt); i++) {
1204 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1205 if (retnotsupp != NULL && *tl != 0)
1206 *retnotsupp = NFSERR_ATTRNOTSUPP;
1209 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1211 NFSEXITCODE2(error, nd);
1216 * Get the attributes for V4.
1217 * If the compare flag is true, test for any attribute changes,
1218 * otherwise return the attribute values.
1219 * These attributes cover fields in "struct vattr", "struct statfs",
1220 * "struct nfsfsinfo", the file handle and the lease duration.
1221 * The value of retcmpp is set to 1 if all attributes are the same,
1223 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1226 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1227 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1228 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1229 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1230 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1233 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1234 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1235 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1236 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1237 struct nfsfh *tnfhp;
1238 struct nfsreferral *refp;
1241 struct timespec temptime;
1244 u_int32_t freenum = 0, tuint;
1245 u_int64_t uquad = 0, thyp, thyp2;
1251 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1254 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1256 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1262 *retcmpp = retnotsup;
1265 * Just set default values to some of the important ones.
1268 nap->na_type = VREG;
1270 nap->na_rdev = (NFSDEV_T)0;
1271 nap->na_mtime.tv_sec = 0;
1272 nap->na_mtime.tv_nsec = 0;
1275 nap->na_blocksize = NFS_FABLKSIZE;
1278 sbp->f_bsize = NFS_FABLKSIZE;
1286 fsp->fs_rtmax = 8192;
1287 fsp->fs_rtpref = 8192;
1288 fsp->fs_maxname = NFS_MAXNAMLEN;
1289 fsp->fs_wtmax = 8192;
1290 fsp->fs_wtpref = 8192;
1291 fsp->fs_wtmult = NFS_FABLKSIZE;
1292 fsp->fs_dtpref = 8192;
1293 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1294 fsp->fs_timedelta.tv_sec = 0;
1295 fsp->fs_timedelta.tv_nsec = 1;
1296 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1297 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1300 pc->pc_linkmax = NFS_LINK_MAX;
1301 pc->pc_namemax = NAME_MAX;
1303 pc->pc_chownrestricted = 0;
1304 pc->pc_caseinsensitive = 0;
1305 pc->pc_casepreserving = 1;
1308 sfp->sf_ffiles = UINT64_MAX;
1309 sfp->sf_tfiles = UINT64_MAX;
1310 sfp->sf_afiles = UINT64_MAX;
1311 sfp->sf_fbytes = UINT64_MAX;
1312 sfp->sf_tbytes = UINT64_MAX;
1313 sfp->sf_abytes = UINT64_MAX;
1318 * Loop around getting the attributes.
1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1321 attrsize = fxdr_unsigned(int, *tl);
1322 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1323 if (attrsum > attrsize) {
1324 error = NFSERR_BADXDR;
1327 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1329 case NFSATTRBIT_SUPPORTEDATTRS:
1331 if (compare || nap == NULL)
1332 error = nfsrv_getattrbits(nd, &retattrbits,
1335 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1339 if (compare && !(*retcmpp)) {
1340 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1342 /* Some filesystem do not support NFSv4ACL */
1343 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1344 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1345 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1347 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1349 *retcmpp = NFSERR_NOTSAME;
1353 case NFSATTRBIT_TYPE:
1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1357 if (nap->na_type != nfsv34tov_type(*tl))
1358 *retcmpp = NFSERR_NOTSAME;
1360 } else if (nap != NULL) {
1361 nap->na_type = nfsv34tov_type(*tl);
1363 attrsum += NFSX_UNSIGNED;
1365 case NFSATTRBIT_FHEXPIRETYPE:
1366 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1367 if (compare && !(*retcmpp)) {
1368 if (fxdr_unsigned(int, *tl) !=
1369 NFSV4FHTYPE_PERSISTENT)
1370 *retcmpp = NFSERR_NOTSAME;
1372 attrsum += NFSX_UNSIGNED;
1374 case NFSATTRBIT_CHANGE:
1375 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1378 if (nap->na_filerev != fxdr_hyper(tl))
1379 *retcmpp = NFSERR_NOTSAME;
1381 } else if (nap != NULL) {
1382 nap->na_filerev = fxdr_hyper(tl);
1384 attrsum += NFSX_HYPER;
1386 case NFSATTRBIT_SIZE:
1387 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1390 if (nap->na_size != fxdr_hyper(tl))
1391 *retcmpp = NFSERR_NOTSAME;
1393 } else if (nap != NULL) {
1394 nap->na_size = fxdr_hyper(tl);
1396 attrsum += NFSX_HYPER;
1398 case NFSATTRBIT_LINKSUPPORT:
1399 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1402 if (fsp->fs_properties & NFSV3_FSFLINK) {
1403 if (*tl == newnfs_false)
1404 *retcmpp = NFSERR_NOTSAME;
1406 if (*tl == newnfs_true)
1407 *retcmpp = NFSERR_NOTSAME;
1410 } else if (fsp != NULL) {
1411 if (*tl == newnfs_true)
1412 fsp->fs_properties |= NFSV3_FSFLINK;
1414 fsp->fs_properties &= ~NFSV3_FSFLINK;
1416 attrsum += NFSX_UNSIGNED;
1418 case NFSATTRBIT_SYMLINKSUPPORT:
1419 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1423 if (*tl == newnfs_false)
1424 *retcmpp = NFSERR_NOTSAME;
1426 if (*tl == newnfs_true)
1427 *retcmpp = NFSERR_NOTSAME;
1430 } else if (fsp != NULL) {
1431 if (*tl == newnfs_true)
1432 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1434 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1436 attrsum += NFSX_UNSIGNED;
1438 case NFSATTRBIT_NAMEDATTR:
1439 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1440 if (compare && !(*retcmpp)) {
1441 if (*tl != newnfs_false)
1442 *retcmpp = NFSERR_NOTSAME;
1444 attrsum += NFSX_UNSIGNED;
1446 case NFSATTRBIT_FSID:
1447 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1448 thyp = fxdr_hyper(tl);
1450 thyp2 = fxdr_hyper(tl);
1452 if (*retcmpp == 0) {
1453 if (thyp != (u_int64_t)
1454 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1455 thyp2 != (u_int64_t)
1456 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1457 *retcmpp = NFSERR_NOTSAME;
1459 } else if (nap != NULL) {
1460 nap->na_filesid[0] = thyp;
1461 nap->na_filesid[1] = thyp2;
1463 attrsum += (4 * NFSX_UNSIGNED);
1465 case NFSATTRBIT_UNIQUEHANDLES:
1466 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1467 if (compare && !(*retcmpp)) {
1468 if (*tl != newnfs_true)
1469 *retcmpp = NFSERR_NOTSAME;
1471 attrsum += NFSX_UNSIGNED;
1473 case NFSATTRBIT_LEASETIME:
1474 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1476 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1478 *retcmpp = NFSERR_NOTSAME;
1479 } else if (leasep != NULL) {
1480 *leasep = fxdr_unsigned(u_int32_t, *tl);
1482 attrsum += NFSX_UNSIGNED;
1484 case NFSATTRBIT_RDATTRERROR:
1485 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1488 *retcmpp = NFSERR_INVAL;
1489 } else if (rderrp != NULL) {
1490 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1492 attrsum += NFSX_UNSIGNED;
1494 case NFSATTRBIT_ACL:
1497 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1500 naclp = acl_alloc(M_WAITOK);
1501 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1507 if (aceerr || aclp == NULL ||
1508 nfsrv_compareacl(aclp, naclp))
1509 *retcmpp = NFSERR_NOTSAME;
1512 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1514 *retcmpp = NFSERR_ATTRNOTSUPP;
1518 if (vp != NULL && aclp != NULL)
1519 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1522 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1530 case NFSATTRBIT_ACLSUPPORT:
1531 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1532 if (compare && !(*retcmpp)) {
1533 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1534 if (fxdr_unsigned(u_int32_t, *tl) !=
1536 *retcmpp = NFSERR_NOTSAME;
1538 *retcmpp = NFSERR_ATTRNOTSUPP;
1541 attrsum += NFSX_UNSIGNED;
1543 case NFSATTRBIT_ARCHIVE:
1544 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1545 if (compare && !(*retcmpp))
1546 *retcmpp = NFSERR_ATTRNOTSUPP;
1547 attrsum += NFSX_UNSIGNED;
1549 case NFSATTRBIT_CANSETTIME:
1550 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1553 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1554 if (*tl == newnfs_false)
1555 *retcmpp = NFSERR_NOTSAME;
1557 if (*tl == newnfs_true)
1558 *retcmpp = NFSERR_NOTSAME;
1561 } else if (fsp != NULL) {
1562 if (*tl == newnfs_true)
1563 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1565 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1567 attrsum += NFSX_UNSIGNED;
1569 case NFSATTRBIT_CASEINSENSITIVE:
1570 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1573 if (*tl != newnfs_false)
1574 *retcmpp = NFSERR_NOTSAME;
1576 } else if (pc != NULL) {
1577 pc->pc_caseinsensitive =
1578 fxdr_unsigned(u_int32_t, *tl);
1580 attrsum += NFSX_UNSIGNED;
1582 case NFSATTRBIT_CASEPRESERVING:
1583 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1586 if (*tl != newnfs_true)
1587 *retcmpp = NFSERR_NOTSAME;
1589 } else if (pc != NULL) {
1590 pc->pc_casepreserving =
1591 fxdr_unsigned(u_int32_t, *tl);
1593 attrsum += NFSX_UNSIGNED;
1595 case NFSATTRBIT_CHOWNRESTRICTED:
1596 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1599 if (*tl != newnfs_true)
1600 *retcmpp = NFSERR_NOTSAME;
1602 } else if (pc != NULL) {
1603 pc->pc_chownrestricted =
1604 fxdr_unsigned(u_int32_t, *tl);
1606 attrsum += NFSX_UNSIGNED;
1608 case NFSATTRBIT_FILEHANDLE:
1609 error = nfsm_getfh(nd, &tnfhp);
1612 tfhsize = tnfhp->nfh_len;
1615 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1617 *retcmpp = NFSERR_NOTSAME;
1618 free(tnfhp, M_NFSFH);
1619 } else if (nfhpp != NULL) {
1622 free(tnfhp, M_NFSFH);
1624 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1626 case NFSATTRBIT_FILEID:
1627 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1628 thyp = fxdr_hyper(tl);
1631 if (nap->na_fileid != thyp)
1632 *retcmpp = NFSERR_NOTSAME;
1634 } else if (nap != NULL)
1635 nap->na_fileid = thyp;
1636 attrsum += NFSX_HYPER;
1638 case NFSATTRBIT_FILESAVAIL:
1639 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1642 sfp->sf_afiles != fxdr_hyper(tl))
1643 *retcmpp = NFSERR_NOTSAME;
1644 } else if (sfp != NULL) {
1645 sfp->sf_afiles = fxdr_hyper(tl);
1647 attrsum += NFSX_HYPER;
1649 case NFSATTRBIT_FILESFREE:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1653 sfp->sf_ffiles != fxdr_hyper(tl))
1654 *retcmpp = NFSERR_NOTSAME;
1655 } else if (sfp != NULL) {
1656 sfp->sf_ffiles = fxdr_hyper(tl);
1658 attrsum += NFSX_HYPER;
1660 case NFSATTRBIT_FILESTOTAL:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1664 sfp->sf_tfiles != fxdr_hyper(tl))
1665 *retcmpp = NFSERR_NOTSAME;
1666 } else if (sfp != NULL) {
1667 sfp->sf_tfiles = fxdr_hyper(tl);
1669 attrsum += NFSX_HYPER;
1671 case NFSATTRBIT_FSLOCATIONS:
1672 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1676 if (compare && !(*retcmpp)) {
1677 refp = nfsv4root_getreferral(vp, NULL, 0);
1679 if (cp == NULL || cp2 == NULL ||
1681 strcmp(cp2, refp->nfr_srvlist))
1682 *retcmpp = NFSERR_NOTSAME;
1683 } else if (m == 0) {
1684 *retcmpp = NFSERR_NOTSAME;
1688 free(cp, M_NFSSTRING);
1690 free(cp2, M_NFSSTRING);
1692 case NFSATTRBIT_HIDDEN:
1693 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1694 if (compare && !(*retcmpp))
1695 *retcmpp = NFSERR_ATTRNOTSUPP;
1696 attrsum += NFSX_UNSIGNED;
1698 case NFSATTRBIT_HOMOGENEOUS:
1699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1702 if (fsp->fs_properties &
1703 NFSV3_FSFHOMOGENEOUS) {
1704 if (*tl == newnfs_false)
1705 *retcmpp = NFSERR_NOTSAME;
1707 if (*tl == newnfs_true)
1708 *retcmpp = NFSERR_NOTSAME;
1711 } else if (fsp != NULL) {
1712 if (*tl == newnfs_true)
1713 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1715 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1717 attrsum += NFSX_UNSIGNED;
1719 case NFSATTRBIT_MAXFILESIZE:
1720 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1721 tnfsquad.qval = fxdr_hyper(tl);
1724 tquad = NFSRV_MAXFILESIZE;
1725 if (tquad != tnfsquad.qval)
1726 *retcmpp = NFSERR_NOTSAME;
1728 } else if (fsp != NULL) {
1729 fsp->fs_maxfilesize = tnfsquad.qval;
1731 attrsum += NFSX_HYPER;
1733 case NFSATTRBIT_MAXLINK:
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1737 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1738 *retcmpp = NFSERR_NOTSAME;
1740 } else if (pc != NULL) {
1741 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1743 attrsum += NFSX_UNSIGNED;
1745 case NFSATTRBIT_MAXNAME:
1746 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1749 if (fsp->fs_maxname !=
1750 fxdr_unsigned(u_int32_t, *tl))
1751 *retcmpp = NFSERR_NOTSAME;
1754 tuint = fxdr_unsigned(u_int32_t, *tl);
1756 * Some Linux NFSv4 servers report this
1757 * as 0 or 4billion, so I'll set it to
1758 * NFS_MAXNAMLEN. If a server actually creates
1759 * a name longer than NFS_MAXNAMLEN, it will
1760 * get an error back.
1762 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1763 tuint = NFS_MAXNAMLEN;
1765 fsp->fs_maxname = tuint;
1767 pc->pc_namemax = tuint;
1769 attrsum += NFSX_UNSIGNED;
1771 case NFSATTRBIT_MAXREAD:
1772 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1775 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1776 *(tl + 1)) || *tl != 0)
1777 *retcmpp = NFSERR_NOTSAME;
1779 } else if (fsp != NULL) {
1780 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1781 fsp->fs_rtpref = fsp->fs_rtmax;
1782 fsp->fs_dtpref = fsp->fs_rtpref;
1784 attrsum += NFSX_HYPER;
1786 case NFSATTRBIT_MAXWRITE:
1787 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1790 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1791 *(tl + 1)) || *tl != 0)
1792 *retcmpp = NFSERR_NOTSAME;
1794 } else if (fsp != NULL) {
1795 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1796 fsp->fs_wtpref = fsp->fs_wtmax;
1798 attrsum += NFSX_HYPER;
1800 case NFSATTRBIT_MIMETYPE:
1801 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1802 i = fxdr_unsigned(int, *tl);
1803 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1804 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1807 if (compare && !(*retcmpp))
1808 *retcmpp = NFSERR_ATTRNOTSUPP;
1810 case NFSATTRBIT_MODE:
1811 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1814 if (nap->na_mode != nfstov_mode(*tl))
1815 *retcmpp = NFSERR_NOTSAME;
1817 } else if (nap != NULL) {
1818 nap->na_mode = nfstov_mode(*tl);
1820 attrsum += NFSX_UNSIGNED;
1822 case NFSATTRBIT_NOTRUNC:
1823 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1826 if (*tl != newnfs_true)
1827 *retcmpp = NFSERR_NOTSAME;
1829 } else if (pc != NULL) {
1830 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1832 attrsum += NFSX_UNSIGNED;
1834 case NFSATTRBIT_NUMLINKS:
1835 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1836 tuint = fxdr_unsigned(u_int32_t, *tl);
1839 if ((u_int32_t)nap->na_nlink != tuint)
1840 *retcmpp = NFSERR_NOTSAME;
1842 } else if (nap != NULL) {
1843 nap->na_nlink = tuint;
1845 attrsum += NFSX_UNSIGNED;
1847 case NFSATTRBIT_OWNER:
1848 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1849 j = fxdr_unsigned(int, *tl);
1851 error = NFSERR_BADXDR;
1854 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1855 if (j > NFSV4_SMALLSTR)
1856 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1859 error = nfsrv_mtostr(nd, cp, j);
1861 if (j > NFSV4_SMALLSTR)
1862 free(cp, M_NFSSTRING);
1867 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1869 *retcmpp = NFSERR_NOTSAME;
1871 } else if (nap != NULL) {
1872 if (nfsv4_strtouid(nd, cp, j, &uid))
1873 nap->na_uid = nfsrv_defaultuid;
1877 if (j > NFSV4_SMALLSTR)
1878 free(cp, M_NFSSTRING);
1880 case NFSATTRBIT_OWNERGROUP:
1881 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1882 j = fxdr_unsigned(int, *tl);
1884 error = NFSERR_BADXDR;
1887 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1888 if (j > NFSV4_SMALLSTR)
1889 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1892 error = nfsrv_mtostr(nd, cp, j);
1894 if (j > NFSV4_SMALLSTR)
1895 free(cp, M_NFSSTRING);
1900 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1902 *retcmpp = NFSERR_NOTSAME;
1904 } else if (nap != NULL) {
1905 if (nfsv4_strtogid(nd, cp, j, &gid))
1906 nap->na_gid = nfsrv_defaultgid;
1910 if (j > NFSV4_SMALLSTR)
1911 free(cp, M_NFSSTRING);
1913 case NFSATTRBIT_QUOTAHARD:
1914 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1916 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1917 freenum = sbp->f_bfree;
1919 freenum = sbp->f_bavail;
1922 * ufs_quotactl() insists that the uid argument
1923 * equal p_ruid for non-root quota access, so
1924 * we'll just make sure that's the case.
1926 savuid = p->p_cred->p_ruid;
1927 p->p_cred->p_ruid = cred->cr_uid;
1928 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1929 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1930 freenum = min(dqb.dqb_bhardlimit, freenum);
1931 p->p_cred->p_ruid = savuid;
1933 uquad = (u_int64_t)freenum;
1934 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1936 if (compare && !(*retcmpp)) {
1937 if (uquad != fxdr_hyper(tl))
1938 *retcmpp = NFSERR_NOTSAME;
1940 attrsum += NFSX_HYPER;
1942 case NFSATTRBIT_QUOTASOFT:
1943 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1945 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1946 freenum = sbp->f_bfree;
1948 freenum = sbp->f_bavail;
1951 * ufs_quotactl() insists that the uid argument
1952 * equal p_ruid for non-root quota access, so
1953 * we'll just make sure that's the case.
1955 savuid = p->p_cred->p_ruid;
1956 p->p_cred->p_ruid = cred->cr_uid;
1957 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1958 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1959 freenum = min(dqb.dqb_bsoftlimit, freenum);
1960 p->p_cred->p_ruid = savuid;
1962 uquad = (u_int64_t)freenum;
1963 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1965 if (compare && !(*retcmpp)) {
1966 if (uquad != fxdr_hyper(tl))
1967 *retcmpp = NFSERR_NOTSAME;
1969 attrsum += NFSX_HYPER;
1971 case NFSATTRBIT_QUOTAUSED:
1972 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1977 * ufs_quotactl() insists that the uid argument
1978 * equal p_ruid for non-root quota access, so
1979 * we'll just make sure that's the case.
1981 savuid = p->p_cred->p_ruid;
1982 p->p_cred->p_ruid = cred->cr_uid;
1983 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1984 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1985 freenum = dqb.dqb_curblocks;
1986 p->p_cred->p_ruid = savuid;
1988 uquad = (u_int64_t)freenum;
1989 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1991 if (compare && !(*retcmpp)) {
1992 if (uquad != fxdr_hyper(tl))
1993 *retcmpp = NFSERR_NOTSAME;
1995 attrsum += NFSX_HYPER;
1997 case NFSATTRBIT_RAWDEV:
1998 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1999 j = fxdr_unsigned(int, *tl++);
2000 k = fxdr_unsigned(int, *tl);
2003 if (nap->na_rdev != NFSMAKEDEV(j, k))
2004 *retcmpp = NFSERR_NOTSAME;
2006 } else if (nap != NULL) {
2007 nap->na_rdev = NFSMAKEDEV(j, k);
2009 attrsum += NFSX_V4SPECDATA;
2011 case NFSATTRBIT_SPACEAVAIL:
2012 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2015 sfp->sf_abytes != fxdr_hyper(tl))
2016 *retcmpp = NFSERR_NOTSAME;
2017 } else if (sfp != NULL) {
2018 sfp->sf_abytes = fxdr_hyper(tl);
2020 attrsum += NFSX_HYPER;
2022 case NFSATTRBIT_SPACEFREE:
2023 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2026 sfp->sf_fbytes != fxdr_hyper(tl))
2027 *retcmpp = NFSERR_NOTSAME;
2028 } else if (sfp != NULL) {
2029 sfp->sf_fbytes = fxdr_hyper(tl);
2031 attrsum += NFSX_HYPER;
2033 case NFSATTRBIT_SPACETOTAL:
2034 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2037 sfp->sf_tbytes != fxdr_hyper(tl))
2038 *retcmpp = NFSERR_NOTSAME;
2039 } else if (sfp != NULL) {
2040 sfp->sf_tbytes = fxdr_hyper(tl);
2042 attrsum += NFSX_HYPER;
2044 case NFSATTRBIT_SPACEUSED:
2045 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2046 thyp = fxdr_hyper(tl);
2049 if ((u_int64_t)nap->na_bytes != thyp)
2050 *retcmpp = NFSERR_NOTSAME;
2052 } else if (nap != NULL) {
2053 nap->na_bytes = thyp;
2055 attrsum += NFSX_HYPER;
2057 case NFSATTRBIT_SYSTEM:
2058 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2059 if (compare && !(*retcmpp))
2060 *retcmpp = NFSERR_ATTRNOTSUPP;
2061 attrsum += NFSX_UNSIGNED;
2063 case NFSATTRBIT_TIMEACCESS:
2064 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2065 fxdr_nfsv4time(tl, &temptime);
2068 if (!NFS_CMPTIME(temptime, nap->na_atime))
2069 *retcmpp = NFSERR_NOTSAME;
2071 } else if (nap != NULL) {
2072 nap->na_atime = temptime;
2074 attrsum += NFSX_V4TIME;
2076 case NFSATTRBIT_TIMEACCESSSET:
2077 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2078 attrsum += NFSX_UNSIGNED;
2079 i = fxdr_unsigned(int, *tl);
2080 if (i == NFSV4SATTRTIME_TOCLIENT) {
2081 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2082 attrsum += NFSX_V4TIME;
2084 if (compare && !(*retcmpp))
2085 *retcmpp = NFSERR_INVAL;
2087 case NFSATTRBIT_TIMEBACKUP:
2088 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2089 if (compare && !(*retcmpp))
2090 *retcmpp = NFSERR_ATTRNOTSUPP;
2091 attrsum += NFSX_V4TIME;
2093 case NFSATTRBIT_TIMECREATE:
2094 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2095 if (compare && !(*retcmpp))
2096 *retcmpp = NFSERR_ATTRNOTSUPP;
2097 attrsum += NFSX_V4TIME;
2099 case NFSATTRBIT_TIMEDELTA:
2100 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2104 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2105 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2106 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2107 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2110 *retcmpp = NFSERR_NOTSAME;
2113 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2116 attrsum += NFSX_V4TIME;
2118 case NFSATTRBIT_TIMEMETADATA:
2119 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2120 fxdr_nfsv4time(tl, &temptime);
2123 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2124 *retcmpp = NFSERR_NOTSAME;
2126 } else if (nap != NULL) {
2127 nap->na_ctime = temptime;
2129 attrsum += NFSX_V4TIME;
2131 case NFSATTRBIT_TIMEMODIFY:
2132 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2133 fxdr_nfsv4time(tl, &temptime);
2136 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2137 *retcmpp = NFSERR_NOTSAME;
2139 } else if (nap != NULL) {
2140 nap->na_mtime = temptime;
2142 attrsum += NFSX_V4TIME;
2144 case NFSATTRBIT_TIMEMODIFYSET:
2145 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2146 attrsum += NFSX_UNSIGNED;
2147 i = fxdr_unsigned(int, *tl);
2148 if (i == NFSV4SATTRTIME_TOCLIENT) {
2149 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2150 attrsum += NFSX_V4TIME;
2152 if (compare && !(*retcmpp))
2153 *retcmpp = NFSERR_INVAL;
2155 case NFSATTRBIT_MOUNTEDONFILEID:
2156 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2157 thyp = fxdr_hyper(tl);
2160 if (!vp || !nfsrv_atroot(vp, &thyp2))
2161 thyp2 = nap->na_fileid;
2163 *retcmpp = NFSERR_NOTSAME;
2165 } else if (nap != NULL)
2166 nap->na_mntonfileno = thyp;
2167 attrsum += NFSX_HYPER;
2169 case NFSATTRBIT_SUPPATTREXCLCREAT:
2171 error = nfsrv_getattrbits(nd, &retattrbits,
2175 if (compare && !(*retcmpp)) {
2176 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2177 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2178 NFSCLRBIT_ATTRBIT(&checkattrbits,
2179 NFSATTRBIT_TIMEACCESSSET);
2180 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2182 *retcmpp = NFSERR_NOTSAME;
2186 case NFSATTRBIT_FSLAYOUTTYPE:
2187 case NFSATTRBIT_LAYOUTTYPE:
2188 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2189 attrsum += NFSX_UNSIGNED;
2190 i = fxdr_unsigned(int, *tl);
2192 NFSM_DISSECT(tl, u_int32_t *, i *
2194 attrsum += i * NFSX_UNSIGNED;
2195 j = fxdr_unsigned(int, *tl);
2196 if (i == 1 && compare && !(*retcmpp) &&
2197 (((nfsrv_doflexfile != 0 ||
2198 nfsrv_maxpnfsmirror > 1) &&
2199 j != NFSLAYOUT_FLEXFILE) ||
2200 (nfsrv_doflexfile == 0 &&
2201 j != NFSLAYOUT_NFSV4_1_FILES)))
2202 *retcmpp = NFSERR_NOTSAME;
2204 if (nfsrv_devidcnt == 0) {
2205 if (compare && !(*retcmpp) && i > 0)
2206 *retcmpp = NFSERR_NOTSAME;
2208 if (compare && !(*retcmpp) && i != 1)
2209 *retcmpp = NFSERR_NOTSAME;
2212 case NFSATTRBIT_LAYOUTALIGNMENT:
2213 case NFSATTRBIT_LAYOUTBLKSIZE:
2214 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2215 attrsum += NFSX_UNSIGNED;
2216 i = fxdr_unsigned(int, *tl);
2217 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2218 *retcmpp = NFSERR_NOTSAME;
2221 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2223 if (compare && !(*retcmpp))
2224 *retcmpp = NFSERR_ATTRNOTSUPP;
2226 * and get out of the loop, since we can't parse
2227 * the unknown attrbute data.
2229 bitpos = NFSATTRBIT_MAX;
2235 * some clients pad the attrlist, so we need to skip over the
2238 if (attrsum > attrsize) {
2239 error = NFSERR_BADXDR;
2241 attrsize = NFSM_RNDUP(attrsize);
2242 if (attrsum < attrsize)
2243 error = nfsm_advance(nd, attrsize - attrsum, -1);
2246 NFSEXITCODE2(error, nd);
2251 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2252 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2253 * The first argument is a pointer to an nfsv4lock structure.
2254 * The second argument is 1 iff a blocking lock is wanted.
2255 * If this argument is 0, the call waits until no thread either wants nor
2256 * holds an exclusive lock.
2257 * It returns 1 if the lock was acquired, 0 otherwise.
2258 * If several processes call this function concurrently wanting the exclusive
2259 * lock, one will get the lock and the rest will return without getting the
2260 * lock. (If the caller must have the lock, it simply calls this function in a
2261 * loop until the function returns 1 to indicate the lock was acquired.)
2262 * Any usecnt must be decremented by calling nfsv4_relref() before
2263 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2264 * be called in a loop.
2265 * The isleptp argument is set to indicate if the call slept, iff not NULL
2266 * and the mp argument indicates to check for a forced dismount, iff not
2270 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2271 void *mutex, struct mount *mp)
2277 * If a lock is wanted, loop around until the lock is acquired by
2278 * someone and then released. If I want the lock, try to acquire it.
2279 * For a lock to be issued, no lock must be in force and the usecnt
2283 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2284 lp->nfslock_usecnt == 0) {
2285 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2286 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2289 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2291 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2292 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2293 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2296 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2299 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2300 PZERO - 1, "nfsv4lck", NULL);
2301 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2302 lp->nfslock_usecnt == 0) {
2303 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2304 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2312 * Release the lock acquired by nfsv4_lock().
2313 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2314 * incremented, as well.
2317 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2320 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2322 lp->nfslock_usecnt++;
2327 * Release a reference cnt.
2330 nfsv4_relref(struct nfsv4lock *lp)
2333 if (lp->nfslock_usecnt <= 0)
2334 panic("nfsv4root ref cnt");
2335 lp->nfslock_usecnt--;
2336 if (lp->nfslock_usecnt == 0)
2341 * Get a reference cnt.
2342 * This function will wait for any exclusive lock to be released, but will
2343 * not wait for threads that want the exclusive lock. If priority needs
2344 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2345 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2346 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2347 * return without getting a refcnt for that case.
2350 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2358 * Wait for a lock held.
2360 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2361 if (mp != NULL && NFSCL_FORCEDISM(mp))
2363 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2366 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2367 PZERO - 1, "nfsv4gr", NULL);
2369 if (mp != NULL && NFSCL_FORCEDISM(mp))
2372 lp->nfslock_usecnt++;
2376 * Get a reference as above, but return failure instead of sleeping if
2377 * an exclusive lock is held.
2380 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2383 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2386 lp->nfslock_usecnt++;
2391 * Test for a lock. Return 1 if locked, 0 otherwise.
2394 nfsv4_testlock(struct nfsv4lock *lp)
2397 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2398 lp->nfslock_usecnt == 0)
2404 * Wake up anyone sleeping, waiting for this lock.
2407 nfsv4_wanted(struct nfsv4lock *lp)
2410 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2411 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2412 wakeup((caddr_t)&lp->nfslock_lock);
2417 * Copy a string from an mbuf list into a character array.
2418 * Return EBADRPC if there is an mbuf error,
2422 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2431 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2432 rem = NFSM_RNDUP(siz) - siz;
2438 NFSBCOPY(cp, str, xfer);
2447 cp = NFSMTOD(mp, caddr_t);
2459 error = nfsm_advance(nd, rem, len);
2465 NFSEXITCODE2(error, nd);
2470 * Fill in the attributes as marked by the bitmap (V4).
2473 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2474 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2475 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2476 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2477 struct statfs *pnfssf)
2479 int bitpos, retnum = 0;
2481 int siz, prefixnum, error;
2482 u_char *cp, namestr[NFSV4_SMALLSTR];
2483 nfsattrbit_t attrbits, retbits;
2484 nfsattrbit_t *retbitp = &retbits;
2485 u_int32_t freenum, *retnump;
2488 struct nfsfsinfo fsinf;
2489 struct timespec temptime;
2490 NFSACL_T *aclp, *naclp = NULL;
2499 * First, set the bits that can be filled and get fsinfo.
2501 NFSSET_ATTRBIT(retbitp, attrbitp);
2503 * If both p and cred are NULL, it is a client side setattr call.
2504 * If both p and cred are not NULL, it is a server side reply call.
2505 * If p is not NULL and cred is NULL, it is a client side callback
2508 if (p == NULL && cred == NULL) {
2509 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2512 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2513 naclp = acl_alloc(M_WAITOK);
2516 nfsvno_getfs(&fsinf, isdgram);
2519 * Get the VFS_STATFS(), since some attributes need them.
2521 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2522 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2523 error = VFS_STATFS(mp, fs);
2526 nd->nd_repstat = NFSERR_ACCES;
2530 NFSCLRSTATFS_ATTRBIT(retbitp);
2536 * And the NFSv4 ACL...
2538 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2539 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2540 supports_nfsv4acls == 0))) {
2541 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2543 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2544 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2545 supports_nfsv4acls == 0)) {
2546 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2547 } else if (naclp != NULL) {
2548 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2549 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2551 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2555 error = NFSERR_PERM;
2558 nd->nd_repstat = NFSERR_ACCES;
2562 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2567 /* Check to see if Extended Attributes are supported. */
2569 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2570 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2571 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2572 "xxx", NULL, &atsiz, cred, p);
2574 if (error != EOPNOTSUPP)
2580 * Put out the attribute bitmap for the ones being filled in
2581 * and get the field for the number of attributes returned.
2583 prefixnum = nfsrv_putattrbit(nd, retbitp);
2584 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2585 prefixnum += NFSX_UNSIGNED;
2588 * Now, loop around filling in the attributes for each bit set.
2590 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2591 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2593 case NFSATTRBIT_SUPPORTEDATTRS:
2594 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2595 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2596 && supports_nfsv4acls == 0)) {
2597 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2598 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2600 retnum += nfsrv_putattrbit(nd, &attrbits);
2602 case NFSATTRBIT_TYPE:
2603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 *tl = vtonfsv34_type(vap->va_type);
2605 retnum += NFSX_UNSIGNED;
2607 case NFSATTRBIT_FHEXPIRETYPE:
2608 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2610 retnum += NFSX_UNSIGNED;
2612 case NFSATTRBIT_CHANGE:
2613 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2614 txdr_hyper(vap->va_filerev, tl);
2615 retnum += NFSX_HYPER;
2617 case NFSATTRBIT_SIZE:
2618 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2619 txdr_hyper(vap->va_size, tl);
2620 retnum += NFSX_HYPER;
2622 case NFSATTRBIT_LINKSUPPORT:
2623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2624 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2628 retnum += NFSX_UNSIGNED;
2630 case NFSATTRBIT_SYMLINKSUPPORT:
2631 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2632 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2636 retnum += NFSX_UNSIGNED;
2638 case NFSATTRBIT_NAMEDATTR:
2639 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2641 retnum += NFSX_UNSIGNED;
2643 case NFSATTRBIT_FSID:
2644 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2646 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2648 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2649 retnum += NFSX_V4FSID;
2651 case NFSATTRBIT_UNIQUEHANDLES:
2652 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2654 retnum += NFSX_UNSIGNED;
2656 case NFSATTRBIT_LEASETIME:
2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2658 *tl = txdr_unsigned(nfsrv_lease);
2659 retnum += NFSX_UNSIGNED;
2661 case NFSATTRBIT_RDATTRERROR:
2662 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2663 *tl = txdr_unsigned(rderror);
2664 retnum += NFSX_UNSIGNED;
2667 * Recommended Attributes. (Only the supported ones.)
2669 case NFSATTRBIT_ACL:
2670 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2672 case NFSATTRBIT_ACLSUPPORT:
2673 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2674 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2675 retnum += NFSX_UNSIGNED;
2677 case NFSATTRBIT_CANSETTIME:
2678 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2679 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2683 retnum += NFSX_UNSIGNED;
2685 case NFSATTRBIT_CASEINSENSITIVE:
2686 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2688 retnum += NFSX_UNSIGNED;
2690 case NFSATTRBIT_CASEPRESERVING:
2691 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2693 retnum += NFSX_UNSIGNED;
2695 case NFSATTRBIT_CHOWNRESTRICTED:
2696 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2698 retnum += NFSX_UNSIGNED;
2700 case NFSATTRBIT_FILEHANDLE:
2701 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2703 case NFSATTRBIT_FILEID:
2704 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2705 uquad = vap->va_fileid;
2706 txdr_hyper(uquad, tl);
2707 retnum += NFSX_HYPER;
2709 case NFSATTRBIT_FILESAVAIL:
2711 * Check quota and use min(quota, f_ffree).
2713 freenum = fs->f_ffree;
2716 * ufs_quotactl() insists that the uid argument
2717 * equal p_ruid for non-root quota access, so
2718 * we'll just make sure that's the case.
2720 savuid = p->p_cred->p_ruid;
2721 p->p_cred->p_ruid = cred->cr_uid;
2722 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2723 cred->cr_uid, (caddr_t)&dqb))
2724 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2726 p->p_cred->p_ruid = savuid;
2728 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2730 *tl = txdr_unsigned(freenum);
2731 retnum += NFSX_HYPER;
2733 case NFSATTRBIT_FILESFREE:
2734 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2736 *tl = txdr_unsigned(fs->f_ffree);
2737 retnum += NFSX_HYPER;
2739 case NFSATTRBIT_FILESTOTAL:
2740 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2742 *tl = txdr_unsigned(fs->f_files);
2743 retnum += NFSX_HYPER;
2745 case NFSATTRBIT_FSLOCATIONS:
2746 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2749 retnum += 2 * NFSX_UNSIGNED;
2751 case NFSATTRBIT_HOMOGENEOUS:
2752 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2753 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2757 retnum += NFSX_UNSIGNED;
2759 case NFSATTRBIT_MAXFILESIZE:
2760 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2761 uquad = NFSRV_MAXFILESIZE;
2762 txdr_hyper(uquad, tl);
2763 retnum += NFSX_HYPER;
2765 case NFSATTRBIT_MAXLINK:
2766 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2767 *tl = txdr_unsigned(NFS_LINK_MAX);
2768 retnum += NFSX_UNSIGNED;
2770 case NFSATTRBIT_MAXNAME:
2771 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2772 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2773 retnum += NFSX_UNSIGNED;
2775 case NFSATTRBIT_MAXREAD:
2776 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2778 *tl = txdr_unsigned(fsinf.fs_rtmax);
2779 retnum += NFSX_HYPER;
2781 case NFSATTRBIT_MAXWRITE:
2782 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2784 *tl = txdr_unsigned(fsinf.fs_wtmax);
2785 retnum += NFSX_HYPER;
2787 case NFSATTRBIT_MODE:
2788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2789 *tl = vtonfsv34_mode(vap->va_mode);
2790 retnum += NFSX_UNSIGNED;
2792 case NFSATTRBIT_NOTRUNC:
2793 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2795 retnum += NFSX_UNSIGNED;
2797 case NFSATTRBIT_NUMLINKS:
2798 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2799 *tl = txdr_unsigned(vap->va_nlink);
2800 retnum += NFSX_UNSIGNED;
2802 case NFSATTRBIT_OWNER:
2804 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2805 retnum += nfsm_strtom(nd, cp, siz);
2807 free(cp, M_NFSSTRING);
2809 case NFSATTRBIT_OWNERGROUP:
2811 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2812 retnum += nfsm_strtom(nd, cp, siz);
2814 free(cp, M_NFSSTRING);
2816 case NFSATTRBIT_QUOTAHARD:
2817 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2818 freenum = fs->f_bfree;
2820 freenum = fs->f_bavail;
2823 * ufs_quotactl() insists that the uid argument
2824 * equal p_ruid for non-root quota access, so
2825 * we'll just make sure that's the case.
2827 savuid = p->p_cred->p_ruid;
2828 p->p_cred->p_ruid = cred->cr_uid;
2829 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2830 cred->cr_uid, (caddr_t)&dqb))
2831 freenum = min(dqb.dqb_bhardlimit, freenum);
2832 p->p_cred->p_ruid = savuid;
2834 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2835 uquad = (u_int64_t)freenum;
2836 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2837 txdr_hyper(uquad, tl);
2838 retnum += NFSX_HYPER;
2840 case NFSATTRBIT_QUOTASOFT:
2841 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2842 freenum = fs->f_bfree;
2844 freenum = fs->f_bavail;
2847 * ufs_quotactl() insists that the uid argument
2848 * equal p_ruid for non-root quota access, so
2849 * we'll just make sure that's the case.
2851 savuid = p->p_cred->p_ruid;
2852 p->p_cred->p_ruid = cred->cr_uid;
2853 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2854 cred->cr_uid, (caddr_t)&dqb))
2855 freenum = min(dqb.dqb_bsoftlimit, freenum);
2856 p->p_cred->p_ruid = savuid;
2858 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2859 uquad = (u_int64_t)freenum;
2860 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2861 txdr_hyper(uquad, tl);
2862 retnum += NFSX_HYPER;
2864 case NFSATTRBIT_QUOTAUSED:
2868 * ufs_quotactl() insists that the uid argument
2869 * equal p_ruid for non-root quota access, so
2870 * we'll just make sure that's the case.
2872 savuid = p->p_cred->p_ruid;
2873 p->p_cred->p_ruid = cred->cr_uid;
2874 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2875 cred->cr_uid, (caddr_t)&dqb))
2876 freenum = dqb.dqb_curblocks;
2877 p->p_cred->p_ruid = savuid;
2879 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2880 uquad = (u_int64_t)freenum;
2881 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2882 txdr_hyper(uquad, tl);
2883 retnum += NFSX_HYPER;
2885 case NFSATTRBIT_RAWDEV:
2886 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2887 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2888 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2889 retnum += NFSX_V4SPECDATA;
2891 case NFSATTRBIT_SPACEAVAIL:
2892 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2893 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2895 uquad = (u_int64_t)pnfssf->f_bfree;
2897 uquad = (u_int64_t)fs->f_bfree;
2900 uquad = (u_int64_t)pnfssf->f_bavail;
2902 uquad = (u_int64_t)fs->f_bavail;
2905 uquad *= pnfssf->f_bsize;
2907 uquad *= fs->f_bsize;
2908 txdr_hyper(uquad, tl);
2909 retnum += NFSX_HYPER;
2911 case NFSATTRBIT_SPACEFREE:
2912 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2913 if (pnfssf != NULL) {
2914 uquad = (u_int64_t)pnfssf->f_bfree;
2915 uquad *= pnfssf->f_bsize;
2917 uquad = (u_int64_t)fs->f_bfree;
2918 uquad *= fs->f_bsize;
2920 txdr_hyper(uquad, tl);
2921 retnum += NFSX_HYPER;
2923 case NFSATTRBIT_SPACETOTAL:
2924 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2925 if (pnfssf != NULL) {
2926 uquad = (u_int64_t)pnfssf->f_blocks;
2927 uquad *= pnfssf->f_bsize;
2929 uquad = (u_int64_t)fs->f_blocks;
2930 uquad *= fs->f_bsize;
2932 txdr_hyper(uquad, tl);
2933 retnum += NFSX_HYPER;
2935 case NFSATTRBIT_SPACEUSED:
2936 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2937 txdr_hyper(vap->va_bytes, tl);
2938 retnum += NFSX_HYPER;
2940 case NFSATTRBIT_TIMEACCESS:
2941 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2942 txdr_nfsv4time(&vap->va_atime, tl);
2943 retnum += NFSX_V4TIME;
2945 case NFSATTRBIT_TIMEACCESSSET:
2946 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2947 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2948 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2949 txdr_nfsv4time(&vap->va_atime, tl);
2950 retnum += NFSX_V4SETTIME;
2952 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2953 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2954 retnum += NFSX_UNSIGNED;
2957 case NFSATTRBIT_TIMEDELTA:
2958 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2959 temptime.tv_sec = 0;
2960 temptime.tv_nsec = 1000000000 / hz;
2961 txdr_nfsv4time(&temptime, tl);
2962 retnum += NFSX_V4TIME;
2964 case NFSATTRBIT_TIMEMETADATA:
2965 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2966 txdr_nfsv4time(&vap->va_ctime, tl);
2967 retnum += NFSX_V4TIME;
2969 case NFSATTRBIT_TIMEMODIFY:
2970 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2971 txdr_nfsv4time(&vap->va_mtime, tl);
2972 retnum += NFSX_V4TIME;
2974 case NFSATTRBIT_TIMEMODIFYSET:
2975 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2976 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2977 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2978 txdr_nfsv4time(&vap->va_mtime, tl);
2979 retnum += NFSX_V4SETTIME;
2981 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2982 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2983 retnum += NFSX_UNSIGNED;
2986 case NFSATTRBIT_MOUNTEDONFILEID:
2987 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2989 uquad = mounted_on_fileno;
2991 uquad = vap->va_fileid;
2992 txdr_hyper(uquad, tl);
2993 retnum += NFSX_HYPER;
2995 case NFSATTRBIT_SUPPATTREXCLCREAT:
2996 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2997 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2998 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2999 retnum += nfsrv_putattrbit(nd, &attrbits);
3001 case NFSATTRBIT_FSLAYOUTTYPE:
3002 case NFSATTRBIT_LAYOUTTYPE:
3003 if (nfsrv_devidcnt == 0)
3008 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3009 *tl++ = txdr_unsigned(1); /* One entry. */
3010 if (nfsrv_doflexfile != 0 ||
3011 nfsrv_maxpnfsmirror > 1)
3012 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3014 *tl = txdr_unsigned(
3015 NFSLAYOUT_NFSV4_1_FILES);
3017 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3020 retnum += siz * NFSX_UNSIGNED;
3022 case NFSATTRBIT_LAYOUTALIGNMENT:
3023 case NFSATTRBIT_LAYOUTBLKSIZE:
3024 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3025 *tl = txdr_unsigned(NFS_SRVMAXIO);
3026 retnum += NFSX_UNSIGNED;
3028 case NFSATTRBIT_XATTRSUPPORT:
3029 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3034 retnum += NFSX_UNSIGNED;
3037 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3044 *retnump = txdr_unsigned(retnum);
3045 return (retnum + prefixnum);
3049 * Put the attribute bits onto an mbuf list.
3050 * Return the number of bytes of output generated.
3053 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3056 int cnt, i, bytesize;
3058 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3059 if (attrbitp->bits[cnt - 1])
3061 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3062 NFSM_BUILD(tl, u_int32_t *, bytesize);
3063 *tl++ = txdr_unsigned(cnt);
3064 for (i = 0; i < cnt; i++)
3065 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3070 * Convert a uid to a string.
3071 * If the lookup fails, just output the digits.
3073 * cpp - points to a buffer of size NFSV4_SMALLSTR
3074 * (malloc a larger one, as required)
3075 * retlenp - pointer to length to be returned
3078 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3081 struct nfsusrgrp *usrp;
3084 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3085 struct nfsrv_lughash *hp;
3089 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3091 * Always map nfsrv_defaultuid to "nobody".
3093 if (uid == nfsrv_defaultuid) {
3094 i = nfsrv_dnsnamelen + 7;
3096 if (len > NFSV4_SMALLSTR)
3097 free(cp, M_NFSSTRING);
3098 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3104 NFSBCOPY("nobody@", cp, 7);
3106 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3110 hp = NFSUSERHASH(uid);
3112 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3113 if (usrp->lug_uid == uid) {
3114 if (usrp->lug_expiry < NFSD_MONOSEC)
3117 * If the name doesn't already have an '@'
3118 * in it, append @domainname to it.
3120 for (i = 0; i < usrp->lug_namelen; i++) {
3121 if (usrp->lug_name[i] == '@') {
3127 i = usrp->lug_namelen;
3129 i = usrp->lug_namelen +
3130 nfsrv_dnsnamelen + 1;
3132 mtx_unlock(&hp->mtx);
3133 if (len > NFSV4_SMALLSTR)
3134 free(cp, M_NFSSTRING);
3135 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3141 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3142 if (!hasampersand) {
3143 cp += usrp->lug_namelen;
3145 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3147 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3148 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3150 mtx_unlock(&hp->mtx);
3154 mtx_unlock(&hp->mtx);
3156 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3157 if (ret == 0 && cnt < 2)
3162 * No match, just return a string of digits.
3166 while (tmp || i == 0) {
3170 len = (i > len) ? len : i;
3174 for (i = 0; i < len; i++) {
3175 *cp-- = '0' + (tmp % 10);
3182 * Get a credential for the uid with the server's group list.
3183 * If none is found, just return the credential passed in after
3184 * logging a warning message.
3187 nfsrv_getgrpscred(struct ucred *oldcred)
3189 struct nfsusrgrp *usrp;
3190 struct ucred *newcred;
3193 struct nfsrv_lughash *hp;
3196 uid = oldcred->cr_uid;
3198 if (nfsrv_dnsnamelen > 0) {
3199 hp = NFSUSERHASH(uid);
3201 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3202 if (usrp->lug_uid == uid) {
3203 if (usrp->lug_expiry < NFSD_MONOSEC)
3205 if (usrp->lug_cred != NULL) {
3206 newcred = crhold(usrp->lug_cred);
3210 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3211 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3213 mtx_unlock(&hp->mtx);
3217 mtx_unlock(&hp->mtx);
3219 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3220 if (ret == 0 && cnt < 2)
3227 * Convert a string to a uid.
3228 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3230 * If this is called from a client side mount using AUTH_SYS and the
3231 * string is made up entirely of digits, just convert the string to
3235 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3238 char *cp, *endstr, *str0;
3239 struct nfsusrgrp *usrp;
3243 struct nfsrv_lughash *hp, *hp2;
3246 error = NFSERR_BADOWNER;
3249 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3251 tuid = (uid_t)strtoul(str0, &endstr, 10);
3252 if ((endstr - str0) == len) {
3253 /* A numeric string. */
3254 if ((nd->nd_flag & ND_KERBV) == 0 &&
3255 ((nd->nd_flag & ND_NFSCL) != 0 ||
3256 nfsd_enable_stringtouid != 0))
3259 error = NFSERR_BADOWNER;
3265 cp = strchr(str0, '@');
3267 i = (int)(cp++ - str0);
3273 if (nfsrv_dnsnamelen > 0) {
3275 * If an '@' is found and the domain name matches, search for
3276 * the name with dns stripped off.
3277 * Mixed case alpahbetics will match for the domain name, but
3278 * all upper case will not.
3280 if (cnt == 0 && i < len && i > 0 &&
3281 (len - 1 - i) == nfsrv_dnsnamelen &&
3282 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3283 len -= (nfsrv_dnsnamelen + 1);
3288 * Check for the special case of "nobody".
3290 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3291 *uidp = nfsrv_defaultuid;
3296 hp = NFSUSERNAMEHASH(str, len);
3298 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3299 if (usrp->lug_namelen == len &&
3300 !NFSBCMP(usrp->lug_name, str, len)) {
3301 if (usrp->lug_expiry < NFSD_MONOSEC)
3303 hp2 = NFSUSERHASH(usrp->lug_uid);
3304 mtx_lock(&hp2->mtx);
3305 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3306 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3308 *uidp = usrp->lug_uid;
3309 mtx_unlock(&hp2->mtx);
3310 mtx_unlock(&hp->mtx);
3315 mtx_unlock(&hp->mtx);
3317 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3319 if (ret == 0 && cnt < 2)
3322 error = NFSERR_BADOWNER;
3330 * Convert a gid to a string.
3331 * gid - the group id
3332 * cpp - points to a buffer of size NFSV4_SMALLSTR
3333 * (malloc a larger one, as required)
3334 * retlenp - pointer to length to be returned
3337 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3340 struct nfsusrgrp *usrp;
3343 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3344 struct nfsrv_lughash *hp;
3348 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3350 * Always map nfsrv_defaultgid to "nogroup".
3352 if (gid == nfsrv_defaultgid) {
3353 i = nfsrv_dnsnamelen + 8;
3355 if (len > NFSV4_SMALLSTR)
3356 free(cp, M_NFSSTRING);
3357 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3363 NFSBCOPY("nogroup@", cp, 8);
3365 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3369 hp = NFSGROUPHASH(gid);
3371 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3372 if (usrp->lug_gid == gid) {
3373 if (usrp->lug_expiry < NFSD_MONOSEC)
3376 * If the name doesn't already have an '@'
3377 * in it, append @domainname to it.
3379 for (i = 0; i < usrp->lug_namelen; i++) {
3380 if (usrp->lug_name[i] == '@') {
3386 i = usrp->lug_namelen;
3388 i = usrp->lug_namelen +
3389 nfsrv_dnsnamelen + 1;
3391 mtx_unlock(&hp->mtx);
3392 if (len > NFSV4_SMALLSTR)
3393 free(cp, M_NFSSTRING);
3394 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3400 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3401 if (!hasampersand) {
3402 cp += usrp->lug_namelen;
3404 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3406 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3407 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3409 mtx_unlock(&hp->mtx);
3413 mtx_unlock(&hp->mtx);
3415 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3416 if (ret == 0 && cnt < 2)
3421 * No match, just return a string of digits.
3425 while (tmp || i == 0) {
3429 len = (i > len) ? len : i;
3433 for (i = 0; i < len; i++) {
3434 *cp-- = '0' + (tmp % 10);
3441 * Convert a string to a gid.
3442 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3444 * If this is called from a client side mount using AUTH_SYS and the
3445 * string is made up entirely of digits, just convert the string to
3449 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3452 char *cp, *endstr, *str0;
3453 struct nfsusrgrp *usrp;
3457 struct nfsrv_lughash *hp, *hp2;
3460 error = NFSERR_BADOWNER;
3463 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3465 tgid = (gid_t)strtoul(str0, &endstr, 10);
3466 if ((endstr - str0) == len) {
3467 /* A numeric string. */
3468 if ((nd->nd_flag & ND_KERBV) == 0 &&
3469 ((nd->nd_flag & ND_NFSCL) != 0 ||
3470 nfsd_enable_stringtouid != 0))
3473 error = NFSERR_BADOWNER;
3479 cp = strchr(str0, '@');
3481 i = (int)(cp++ - str0);
3487 if (nfsrv_dnsnamelen > 0) {
3489 * If an '@' is found and the dns name matches, search for the
3490 * name with the dns stripped off.
3492 if (cnt == 0 && i < len && i > 0 &&
3493 (len - 1 - i) == nfsrv_dnsnamelen &&
3494 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3495 len -= (nfsrv_dnsnamelen + 1);
3500 * Check for the special case of "nogroup".
3502 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3503 *gidp = nfsrv_defaultgid;
3508 hp = NFSGROUPNAMEHASH(str, len);
3510 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3511 if (usrp->lug_namelen == len &&
3512 !NFSBCMP(usrp->lug_name, str, len)) {
3513 if (usrp->lug_expiry < NFSD_MONOSEC)
3515 hp2 = NFSGROUPHASH(usrp->lug_gid);
3516 mtx_lock(&hp2->mtx);
3517 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3518 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3520 *gidp = usrp->lug_gid;
3521 mtx_unlock(&hp2->mtx);
3522 mtx_unlock(&hp->mtx);
3527 mtx_unlock(&hp->mtx);
3529 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3531 if (ret == 0 && cnt < 2)
3534 error = NFSERR_BADOWNER;
3542 * Cmp len chars, allowing mixed case in the first argument to match lower
3543 * case in the second, but not if the first argument is all upper case.
3544 * Return 0 for a match, 1 otherwise.
3547 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3553 for (i = 0; i < len; i++) {
3554 if (*cp >= 'A' && *cp <= 'Z') {
3555 tmp = *cp++ + ('a' - 'A');
3558 if (tmp >= 'a' && tmp <= 'z')
3571 * Set the port for the nfsuserd.
3574 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3576 struct nfssockreq *rp;
3578 struct sockaddr_in *ad;
3581 struct sockaddr_in6 *ad6;
3582 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3587 if (nfsrv_nfsuserd != NOTRUNNING) {
3592 nfsrv_nfsuserd = STARTSTOP;
3594 * Set up the socket record and connect.
3595 * Set nr_client NULL before unlocking, just to ensure that no other
3596 * process/thread/core will use a bogus old value. This could only
3597 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3600 rp = &nfsrv_nfsuserdsock;
3601 rp->nr_client = NULL;
3603 rp->nr_sotype = SOCK_DGRAM;
3604 rp->nr_soproto = IPPROTO_UDP;
3605 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3607 rp->nr_prog = RPCPROG_NFSUSERD;
3609 switch (nargs->nuserd_family) {
3612 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3614 ad = (struct sockaddr_in *)rp->nr_nam;
3615 ad->sin_len = sizeof(struct sockaddr_in);
3616 ad->sin_family = AF_INET;
3617 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3618 ad->sin_port = nargs->nuserd_port;
3623 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3625 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3626 ad6->sin6_len = sizeof(struct sockaddr_in6);
3627 ad6->sin6_family = AF_INET6;
3628 ad6->sin6_addr = in6loopback;
3629 ad6->sin6_port = nargs->nuserd_port;
3635 rp->nr_vers = RPCNFSUSERD_VERS;
3637 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3640 nfsrv_nfsuserd = RUNNING;
3643 free(rp->nr_nam, M_SONAME);
3645 nfsrv_nfsuserd = NOTRUNNING;
3654 * Delete the nfsuserd port.
3657 nfsrv_nfsuserddelport(void)
3661 if (nfsrv_nfsuserd != RUNNING) {
3665 nfsrv_nfsuserd = STARTSTOP;
3666 /* Wait for all upcalls to complete. */
3667 while (nfsrv_userdupcalls > 0)
3668 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3671 newnfs_disconnect(&nfsrv_nfsuserdsock);
3672 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3674 nfsrv_nfsuserd = NOTRUNNING;
3679 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3681 * Returns 0 upon success, non-zero otherwise.
3684 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3687 struct nfsrv_descript *nd;
3689 struct nfsrv_descript nfsd;
3694 if (nfsrv_nfsuserd != RUNNING) {
3700 * Maintain a count of upcalls in progress, so that nfsrv_X()
3701 * can wait until no upcalls are in progress.
3703 nfsrv_userdupcalls++;
3705 KASSERT(nfsrv_userdupcalls > 0,
3706 ("nfsrv_getuser: non-positive upcalls"));
3708 cred = newnfs_getcred();
3709 nd->nd_flag = ND_GSSINITREPLY;
3712 nd->nd_procnum = procnum;
3713 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3714 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3715 if (procnum == RPCNFSUSERD_GETUID)
3716 *tl = txdr_unsigned(uid);
3718 *tl = txdr_unsigned(gid);
3721 (void) nfsm_strtom(nd, name, len);
3723 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3724 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3726 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3727 wakeup(&nfsrv_userdupcalls);
3731 mbuf_freem(nd->nd_mrep);
3732 error = nd->nd_repstat;
3740 * This function is called from the nfssvc(2) system call, to update the
3741 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3744 nfssvc_idname(struct nfsd_idargs *nidp)
3746 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3747 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3748 int i, group_locked, groupname_locked, user_locked, username_locked;
3753 static int onethread = 0;
3754 static time_t lasttime = 0;
3756 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3760 if (nidp->nid_flag & NFSID_INITIALIZE) {
3761 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3762 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3765 free(cp, M_NFSSTRING);
3768 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3770 * Free up all the old stuff and reinitialize hash
3771 * lists. All mutexes for both lists must be locked,
3772 * with the user/group name ones before the uid/gid
3773 * ones, to avoid a LOR.
3775 for (i = 0; i < nfsrv_lughashsize; i++)
3776 mtx_lock(&nfsusernamehash[i].mtx);
3777 for (i = 0; i < nfsrv_lughashsize; i++)
3778 mtx_lock(&nfsuserhash[i].mtx);
3779 for (i = 0; i < nfsrv_lughashsize; i++)
3780 TAILQ_FOREACH_SAFE(usrp,
3781 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3782 nfsrv_removeuser(usrp, 1);
3783 for (i = 0; i < nfsrv_lughashsize; i++)
3784 mtx_unlock(&nfsuserhash[i].mtx);
3785 for (i = 0; i < nfsrv_lughashsize; i++)
3786 mtx_unlock(&nfsusernamehash[i].mtx);
3787 for (i = 0; i < nfsrv_lughashsize; i++)
3788 mtx_lock(&nfsgroupnamehash[i].mtx);
3789 for (i = 0; i < nfsrv_lughashsize; i++)
3790 mtx_lock(&nfsgrouphash[i].mtx);
3791 for (i = 0; i < nfsrv_lughashsize; i++)
3792 TAILQ_FOREACH_SAFE(usrp,
3793 &nfsgrouphash[i].lughead, lug_numhash,
3795 nfsrv_removeuser(usrp, 0);
3796 for (i = 0; i < nfsrv_lughashsize; i++)
3797 mtx_unlock(&nfsgrouphash[i].mtx);
3798 for (i = 0; i < nfsrv_lughashsize; i++)
3799 mtx_unlock(&nfsgroupnamehash[i].mtx);
3800 free(nfsrv_dnsname, M_NFSSTRING);
3801 nfsrv_dnsname = NULL;
3803 if (nfsuserhash == NULL) {
3804 /* Allocate the hash tables. */
3805 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3806 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3808 for (i = 0; i < nfsrv_lughashsize; i++)
3809 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3810 NULL, MTX_DEF | MTX_DUPOK);
3811 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3812 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3814 for (i = 0; i < nfsrv_lughashsize; i++)
3815 mtx_init(&nfsusernamehash[i].mtx,
3816 "nfsusrhash", NULL, MTX_DEF |
3818 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3819 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3821 for (i = 0; i < nfsrv_lughashsize; i++)
3822 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3823 NULL, MTX_DEF | MTX_DUPOK);
3824 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3825 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3827 for (i = 0; i < nfsrv_lughashsize; i++)
3828 mtx_init(&nfsgroupnamehash[i].mtx,
3829 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3831 /* (Re)initialize the list heads. */
3832 for (i = 0; i < nfsrv_lughashsize; i++)
3833 TAILQ_INIT(&nfsuserhash[i].lughead);
3834 for (i = 0; i < nfsrv_lughashsize; i++)
3835 TAILQ_INIT(&nfsusernamehash[i].lughead);
3836 for (i = 0; i < nfsrv_lughashsize; i++)
3837 TAILQ_INIT(&nfsgrouphash[i].lughead);
3838 for (i = 0; i < nfsrv_lughashsize; i++)
3839 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3842 * Put name in "DNS" string.
3845 nfsrv_defaultuid = nidp->nid_uid;
3846 nfsrv_defaultgid = nidp->nid_gid;
3848 nfsrv_usermax = nidp->nid_usermax;
3849 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3854 * malloc the new one now, so any potential sleep occurs before
3855 * manipulation of the lists.
3857 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3858 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3859 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3861 if (error == 0 && nidp->nid_ngroup > 0 &&
3862 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3863 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3865 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3866 sizeof(gid_t) * nidp->nid_ngroup);
3869 * Create a credential just like svc_getcred(),
3870 * but using the group list provided.
3873 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3874 crsetgroups(cr, nidp->nid_ngroup, grps);
3875 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3876 cr->cr_prison = &prison0;
3877 prison_hold(cr->cr_prison);
3879 mac_cred_associate_nfsd(cr);
3881 newusrp->lug_cred = cr;
3886 free(newusrp, M_NFSUSERGROUP);
3889 newusrp->lug_namelen = nidp->nid_namelen;
3892 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3893 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3894 * The flags user_locked, username_locked, group_locked and
3895 * groupname_locked are set to indicate all of those hash lists are
3896 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3897 * the respective one mutex is locked.
3899 user_locked = username_locked = group_locked = groupname_locked = 0;
3900 hp_name = hp_idnum = NULL;
3903 * Delete old entries, as required.
3905 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3906 /* Must lock all username hash lists first, to avoid a LOR. */
3907 for (i = 0; i < nfsrv_lughashsize; i++)
3908 mtx_lock(&nfsusernamehash[i].mtx);
3909 username_locked = 1;
3910 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3911 mtx_lock(&hp_idnum->mtx);
3912 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3914 if (usrp->lug_uid == nidp->nid_uid)
3915 nfsrv_removeuser(usrp, 1);
3917 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3918 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3919 newusrp->lug_namelen);
3920 mtx_lock(&hp_name->mtx);
3921 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3923 if (usrp->lug_namelen == newusrp->lug_namelen &&
3924 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3925 usrp->lug_namelen)) {
3926 thp = NFSUSERHASH(usrp->lug_uid);
3927 mtx_lock(&thp->mtx);
3928 nfsrv_removeuser(usrp, 1);
3929 mtx_unlock(&thp->mtx);
3932 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3933 mtx_lock(&hp_idnum->mtx);
3934 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3935 /* Must lock all groupname hash lists first, to avoid a LOR. */
3936 for (i = 0; i < nfsrv_lughashsize; i++)
3937 mtx_lock(&nfsgroupnamehash[i].mtx);
3938 groupname_locked = 1;
3939 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3940 mtx_lock(&hp_idnum->mtx);
3941 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3943 if (usrp->lug_gid == nidp->nid_gid)
3944 nfsrv_removeuser(usrp, 0);
3946 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3947 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3948 newusrp->lug_namelen);
3949 mtx_lock(&hp_name->mtx);
3950 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3952 if (usrp->lug_namelen == newusrp->lug_namelen &&
3953 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3954 usrp->lug_namelen)) {
3955 thp = NFSGROUPHASH(usrp->lug_gid);
3956 mtx_lock(&thp->mtx);
3957 nfsrv_removeuser(usrp, 0);
3958 mtx_unlock(&thp->mtx);
3961 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3962 mtx_lock(&hp_idnum->mtx);
3966 * Now, we can add the new one.
3968 if (nidp->nid_usertimeout)
3969 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3971 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3972 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3973 newusrp->lug_uid = nidp->nid_uid;
3974 thp = NFSUSERHASH(newusrp->lug_uid);
3975 mtx_assert(&thp->mtx, MA_OWNED);
3976 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3977 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3978 mtx_assert(&thp->mtx, MA_OWNED);
3979 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3980 atomic_add_int(&nfsrv_usercnt, 1);
3981 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3982 newusrp->lug_gid = nidp->nid_gid;
3983 thp = NFSGROUPHASH(newusrp->lug_gid);
3984 mtx_assert(&thp->mtx, MA_OWNED);
3985 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3986 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3987 mtx_assert(&thp->mtx, MA_OWNED);
3988 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3989 atomic_add_int(&nfsrv_usercnt, 1);
3991 if (newusrp->lug_cred != NULL)
3992 crfree(newusrp->lug_cred);
3993 free(newusrp, M_NFSUSERGROUP);
3997 * Once per second, allow one thread to trim the cache.
3999 if (lasttime < NFSD_MONOSEC &&
4000 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4002 * First, unlock the single mutexes, so that all entries
4003 * can be locked and any LOR is avoided.
4005 if (hp_name != NULL) {
4006 mtx_unlock(&hp_name->mtx);
4009 if (hp_idnum != NULL) {
4010 mtx_unlock(&hp_idnum->mtx);
4014 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4015 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4016 if (username_locked == 0) {
4017 for (i = 0; i < nfsrv_lughashsize; i++)
4018 mtx_lock(&nfsusernamehash[i].mtx);
4019 username_locked = 1;
4021 KASSERT(user_locked == 0,
4022 ("nfssvc_idname: user_locked"));
4023 for (i = 0; i < nfsrv_lughashsize; i++)
4024 mtx_lock(&nfsuserhash[i].mtx);
4026 for (i = 0; i < nfsrv_lughashsize; i++) {
4027 TAILQ_FOREACH_SAFE(usrp,
4028 &nfsuserhash[i].lughead, lug_numhash,
4030 if (usrp->lug_expiry < NFSD_MONOSEC)
4031 nfsrv_removeuser(usrp, 1);
4033 for (i = 0; i < nfsrv_lughashsize; i++) {
4035 * Trim the cache using an approximate LRU
4036 * algorithm. This code deletes the least
4037 * recently used entry on each hash list.
4039 if (nfsrv_usercnt <= nfsrv_usermax)
4041 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4043 nfsrv_removeuser(usrp, 1);
4046 if (groupname_locked == 0) {
4047 for (i = 0; i < nfsrv_lughashsize; i++)
4048 mtx_lock(&nfsgroupnamehash[i].mtx);
4049 groupname_locked = 1;
4051 KASSERT(group_locked == 0,
4052 ("nfssvc_idname: group_locked"));
4053 for (i = 0; i < nfsrv_lughashsize; i++)
4054 mtx_lock(&nfsgrouphash[i].mtx);
4056 for (i = 0; i < nfsrv_lughashsize; i++) {
4057 TAILQ_FOREACH_SAFE(usrp,
4058 &nfsgrouphash[i].lughead, lug_numhash,
4060 if (usrp->lug_expiry < NFSD_MONOSEC)
4061 nfsrv_removeuser(usrp, 0);
4063 for (i = 0; i < nfsrv_lughashsize; i++) {
4065 * Trim the cache using an approximate LRU
4066 * algorithm. This code deletes the least
4067 * recently user entry on each hash list.
4069 if (nfsrv_usercnt <= nfsrv_usermax)
4071 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4073 nfsrv_removeuser(usrp, 0);
4076 lasttime = NFSD_MONOSEC;
4077 atomic_store_rel_int(&onethread, 0);
4080 /* Now, unlock all locked mutexes. */
4081 if (hp_idnum != NULL)
4082 mtx_unlock(&hp_idnum->mtx);
4083 if (hp_name != NULL)
4084 mtx_unlock(&hp_name->mtx);
4085 if (user_locked != 0)
4086 for (i = 0; i < nfsrv_lughashsize; i++)
4087 mtx_unlock(&nfsuserhash[i].mtx);
4088 if (username_locked != 0)
4089 for (i = 0; i < nfsrv_lughashsize; i++)
4090 mtx_unlock(&nfsusernamehash[i].mtx);
4091 if (group_locked != 0)
4092 for (i = 0; i < nfsrv_lughashsize; i++)
4093 mtx_unlock(&nfsgrouphash[i].mtx);
4094 if (groupname_locked != 0)
4095 for (i = 0; i < nfsrv_lughashsize; i++)
4096 mtx_unlock(&nfsgroupnamehash[i].mtx);
4103 * Remove a user/group name element.
4106 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4108 struct nfsrv_lughash *hp;
4111 hp = NFSUSERHASH(usrp->lug_uid);
4112 mtx_assert(&hp->mtx, MA_OWNED);
4113 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4114 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4115 mtx_assert(&hp->mtx, MA_OWNED);
4116 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4118 hp = NFSGROUPHASH(usrp->lug_gid);
4119 mtx_assert(&hp->mtx, MA_OWNED);
4120 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4121 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4122 mtx_assert(&hp->mtx, MA_OWNED);
4123 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4125 atomic_add_int(&nfsrv_usercnt, -1);
4126 if (usrp->lug_cred != NULL)
4127 crfree(usrp->lug_cred);
4128 free(usrp, M_NFSUSERGROUP);
4132 * Free up all the allocations related to the name<-->id cache.
4133 * This function should only be called when the nfsuserd daemon isn't
4134 * running, since it doesn't do any locking.
4135 * This function is meant to be used when the nfscommon module is unloaded.
4138 nfsrv_cleanusergroup(void)
4140 struct nfsrv_lughash *hp, *hp2;
4141 struct nfsusrgrp *nusrp, *usrp;
4144 if (nfsuserhash == NULL)
4147 for (i = 0; i < nfsrv_lughashsize; i++) {
4148 hp = &nfsuserhash[i];
4149 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4150 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4151 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4153 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4154 if (usrp->lug_cred != NULL)
4155 crfree(usrp->lug_cred);
4156 free(usrp, M_NFSUSERGROUP);
4158 hp = &nfsgrouphash[i];
4159 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4160 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4161 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4163 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4164 if (usrp->lug_cred != NULL)
4165 crfree(usrp->lug_cred);
4166 free(usrp, M_NFSUSERGROUP);
4168 mtx_destroy(&nfsuserhash[i].mtx);
4169 mtx_destroy(&nfsusernamehash[i].mtx);
4170 mtx_destroy(&nfsgroupnamehash[i].mtx);
4171 mtx_destroy(&nfsgrouphash[i].mtx);
4173 free(nfsuserhash, M_NFSUSERGROUP);
4174 free(nfsusernamehash, M_NFSUSERGROUP);
4175 free(nfsgrouphash, M_NFSUSERGROUP);
4176 free(nfsgroupnamehash, M_NFSUSERGROUP);
4177 free(nfsrv_dnsname, M_NFSSTRING);
4181 * This function scans a byte string and checks for UTF-8 compliance.
4182 * It returns 0 if it conforms and NFSERR_INVAL if not.
4185 nfsrv_checkutf8(u_int8_t *cp, int len)
4187 u_int32_t val = 0x0;
4188 int cnt = 0, gotd = 0, shift = 0;
4190 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4194 * Here are what the variables are used for:
4195 * val - the calculated value of a multibyte char, used to check
4196 * that it was coded with the correct range
4197 * cnt - the number of 10xxxxxx bytes to follow
4198 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4199 * shift - lower order bits of range (ie. "val >> shift" should
4200 * not be 0, in other words, dividing by the lower bound
4201 * of the range should get a non-zero value)
4202 * byte - used to calculate cnt
4206 /* This handles the 10xxxxxx bytes */
4207 if ((*cp & 0xc0) != 0x80 ||
4208 (gotd && (*cp & 0x20))) {
4209 error = NFSERR_INVAL;
4214 val |= (*cp & 0x3f);
4216 if (cnt == 0 && (val >> shift) == 0x0) {
4217 error = NFSERR_INVAL;
4220 } else if (*cp & 0x80) {
4221 /* first byte of multi byte char */
4223 while ((byte & 0x40) && cnt < 6) {
4227 if (cnt == 0 || cnt == 6) {
4228 error = NFSERR_INVAL;
4231 val = (*cp & (0x3f >> cnt));
4232 shift = utf8_shift[cnt - 1];
4233 if (cnt == 2 && val == 0xd)
4234 /* Check for the 0xd800-0xdfff case */
4241 error = NFSERR_INVAL;
4249 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4250 * strings, one with the root path in it and the other with the list of
4251 * locations. The list is in the same format as is found in nfr_refs.
4252 * It is a "," separated list of entries, where each of them is of the
4253 * form <server>:<rootpath>. For example
4254 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4255 * The nilp argument is set to 1 for the special case of a null fs_root
4256 * and an empty server list.
4257 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4258 * number of xdr bytes parsed in sump.
4261 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4262 int *sump, int *nilp)
4265 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4266 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4268 SLIST_ENTRY(list) next;
4272 SLIST_HEAD(, list) head;
4279 * Get the fs_root path and check for the special case of null path
4280 * and 0 length server list.
4282 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4283 len = fxdr_unsigned(int, *tl);
4284 if (len < 0 || len > 10240) {
4285 error = NFSERR_BADXDR;
4289 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4291 error = NFSERR_BADXDR;
4295 *sump = 2 * NFSX_UNSIGNED;
4299 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4300 error = nfsrv_mtostr(nd, cp, len);
4302 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4303 cnt = fxdr_unsigned(int, *tl);
4305 error = NFSERR_BADXDR;
4311 * Now, loop through the location list and make up the srvlist.
4313 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4314 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4317 for (i = 0; i < cnt; i++) {
4319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4320 nsrv = fxdr_unsigned(int, *tl);
4322 error = NFSERR_BADXDR;
4327 * Handle the first server by putting it in the srvstr.
4329 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4330 len = fxdr_unsigned(int, *tl);
4331 if (len <= 0 || len > 1024) {
4332 error = NFSERR_BADXDR;
4335 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4340 error = nfsrv_mtostr(nd, cp3, len);
4346 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4347 for (j = 1; j < nsrv; j++) {
4349 * Yuck, put them in an slist and process them later.
4351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4352 len = fxdr_unsigned(int, *tl);
4353 if (len <= 0 || len > 1024) {
4354 error = NFSERR_BADXDR;
4357 lsp = (struct list *)malloc(sizeof (struct list)
4358 + len, M_TEMP, M_WAITOK);
4359 error = nfsrv_mtostr(nd, lsp->host, len);
4362 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4364 SLIST_INSERT_HEAD(&head, lsp, next);
4368 * Finally, we can get the path.
4370 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4371 len = fxdr_unsigned(int, *tl);
4372 if (len <= 0 || len > 1024) {
4373 error = NFSERR_BADXDR;
4376 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4377 error = nfsrv_mtostr(nd, cp3, len);
4380 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4385 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4386 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4389 NFSBCOPY(lsp->host, cp3, lsp->len);
4392 NFSBCOPY(str, cp3, stringlen);
4395 siz += (lsp->len + stringlen + 2);
4402 NFSEXITCODE2(0, nd);
4406 free(cp, M_NFSSTRING);
4408 free(cp2, M_NFSSTRING);
4409 NFSEXITCODE2(error, nd);
4414 * Make the malloc'd space large enough. This is a pain, but the xdr
4415 * doesn't set an upper bound on the side, so...
4418 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4425 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4426 NFSBCOPY(*cpp, cp, *slenp);
4427 free(*cpp, M_NFSSTRING);
4431 *slenp = siz + 1024;
4435 * Initialize the reply header data structures.
4438 nfsrvd_rephead(struct nfsrv_descript *nd)
4443 * If this is a big reply, use a cluster.
4445 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4446 nfs_bigreply[nd->nd_procnum]) {
4447 NFSMCLGET(mreq, M_WAITOK);
4455 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4456 mbuf_setlen(mreq, 0);
4458 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4459 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4463 * Lock a socket against others.
4464 * Currently used to serialize connect/disconnect attempts.
4467 newnfs_sndlock(int *flagp)
4472 while (*flagp & NFSR_SNDLOCK) {
4473 *flagp |= NFSR_WANTSND;
4476 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4477 PZERO - 1, "nfsndlck", &ts);
4479 *flagp |= NFSR_SNDLOCK;
4485 * Unlock the stream socket for others.
4488 newnfs_sndunlock(int *flagp)
4492 if ((*flagp & NFSR_SNDLOCK) == 0)
4493 panic("nfs sndunlock");
4494 *flagp &= ~NFSR_SNDLOCK;
4495 if (*flagp & NFSR_WANTSND) {
4496 *flagp &= ~NFSR_WANTSND;
4497 wakeup((caddr_t)flagp);
4503 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4504 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4506 struct in_addr saddr;
4507 uint32_t portnum, *tl;
4509 sa_family_t af = AF_UNSPEC;
4510 char addr[64], protocol[5], *cp;
4511 int cantparse = 0, error = 0;
4514 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4515 i = fxdr_unsigned(int, *tl);
4516 if (i >= 3 && i <= 4) {
4517 error = nfsrv_mtostr(nd, protocol, i);
4520 if (strcmp(protocol, "tcp") == 0) {
4523 } else if (strcmp(protocol, "udp") == 0) {
4526 } else if (strcmp(protocol, "tcp6") == 0) {
4529 } else if (strcmp(protocol, "udp6") == 0) {
4537 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4542 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4543 i = fxdr_unsigned(int, *tl);
4545 error = NFSERR_BADXDR;
4547 } else if (cantparse == 0 && i >= 11 && i < 64) {
4549 * The shortest address is 11chars and the longest is < 64.
4551 error = nfsrv_mtostr(nd, addr, i);
4555 /* Find the port# at the end and extract that. */
4559 /* Count back two '.'s from end to get port# field. */
4560 for (j = 0; j < i; j++) {
4570 * The NFSv4 port# is appended as .N.N, where N is
4571 * a decimal # in the range 0-255, just like an inet4
4572 * address. Cheat and use inet_aton(), which will
4573 * return a Class A address and then shift the high
4574 * order 8bits over to convert it to the port#.
4577 if (inet_aton(cp, &saddr) == 1) {
4578 portnum = ntohl(saddr.s_addr);
4579 portv = (uint16_t)((portnum >> 16) |
4585 if (cantparse == 0) {
4586 if (af == AF_INET) {
4587 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4588 sin->sin_len = sizeof(*sin);
4589 sin->sin_family = AF_INET;
4590 sin->sin_port = htons(portv);
4595 if (inet_pton(af, addr, &sin6->sin6_addr)
4597 sin6->sin6_len = sizeof(*sin6);
4598 sin6->sin6_family = AF_INET6;
4599 sin6->sin6_port = htons(portv);
4607 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4618 * Handle an NFSv4.1 Sequence request for the session.
4619 * If reply != NULL, use it to return the cached reply, as required.
4620 * The client gets a cached reply via this call for callbacks, however the
4621 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4624 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4625 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4632 if (slotid > maxslot)
4633 return (NFSERR_BADSLOT);
4634 if (seqid == slots[slotid].nfssl_seq) {
4636 if (slots[slotid].nfssl_inprog != 0)
4637 error = NFSERR_DELAY;
4638 else if (slots[slotid].nfssl_reply != NULL) {
4639 if (reply != NULL) {
4640 *reply = slots[slotid].nfssl_reply;
4641 slots[slotid].nfssl_reply = NULL;
4643 slots[slotid].nfssl_inprog = 1;
4644 error = NFSERR_REPLYFROMCACHE;
4646 /* No reply cached, so just do it. */
4647 slots[slotid].nfssl_inprog = 1;
4648 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4649 if (slots[slotid].nfssl_reply != NULL)
4650 m_freem(slots[slotid].nfssl_reply);
4651 slots[slotid].nfssl_reply = NULL;
4652 slots[slotid].nfssl_inprog = 1;
4653 slots[slotid].nfssl_seq++;
4655 error = NFSERR_SEQMISORDERED;
4660 * Cache this reply for the slot.
4661 * Use the "rep" argument to return the cached reply if repstat is set to
4662 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4665 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4669 if (repstat == NFSERR_REPLYFROMCACHE) {
4670 *rep = slots[slotid].nfssl_reply;
4671 slots[slotid].nfssl_reply = NULL;
4673 if (slots[slotid].nfssl_reply != NULL)
4674 m_freem(slots[slotid].nfssl_reply);
4675 slots[slotid].nfssl_reply = *rep;
4677 slots[slotid].nfssl_inprog = 0;
4681 * Generate the xdr for an NFSv4.1 Sequence Operation.
4684 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4685 struct nfsclsession *sep, int dont_replycache)
4687 uint32_t *tl, slotseq = 0;
4688 int error, maxslot, slotpos;
4689 uint8_t sessionid[NFSX_V4SESSIONID];
4691 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4693 nd->nd_maxreq = sep->nfsess_maxreq;
4694 nd->nd_maxresp = sep->nfsess_maxresp;
4696 /* Build the Sequence arguments. */
4697 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4698 nd->nd_sequence = tl;
4699 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4700 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4701 nd->nd_slotseq = tl;
4703 nd->nd_flag |= ND_HASSLOTID;
4704 nd->nd_slotid = slotpos;
4705 *tl++ = txdr_unsigned(slotseq);
4706 *tl++ = txdr_unsigned(slotpos);
4707 *tl++ = txdr_unsigned(maxslot);
4708 if (dont_replycache == 0)
4714 * There are two errors and the rest of the session can
4716 * NFSERR_BADSESSION: This bad session should just generate
4717 * the same error again when the RPC is retried.
4718 * ESTALE: A forced dismount is in progress and will cause the
4719 * RPC to fail later.
4726 nd->nd_flag |= ND_HASSEQUENCE;
4730 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4731 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4733 int i, maxslot, slotpos;
4736 /* Find an unused slot. */
4739 mtx_lock(&sep->nfsess_mtx);
4741 if (nmp != NULL && sep->nfsess_defunct != 0) {
4742 /* Just return the bad session. */
4743 bcopy(sep->nfsess_sessionid, sessionid,
4745 mtx_unlock(&sep->nfsess_mtx);
4746 return (NFSERR_BADSESSION);
4749 for (i = 0; i < sep->nfsess_foreslots; i++) {
4750 if ((bitval & sep->nfsess_slots) == 0) {
4752 sep->nfsess_slots |= bitval;
4753 sep->nfsess_slotseq[i]++;
4754 *slotseqp = sep->nfsess_slotseq[i];
4759 if (slotpos == -1) {
4761 * If a forced dismount is in progress, just return.
4762 * This RPC attempt will fail when it calls
4765 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4766 mtx_unlock(&sep->nfsess_mtx);
4769 /* Wake up once/sec, to check for a forced dismount. */
4770 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4771 PZERO, "nfsclseq", hz);
4773 } while (slotpos == -1);
4774 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4776 for (i = 0; i < 64; i++) {
4777 if ((bitval & sep->nfsess_slots) != 0)
4781 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4782 mtx_unlock(&sep->nfsess_mtx);
4783 *slotposp = slotpos;
4784 *maxslotp = maxslot;
4789 * Free a session slot.
4792 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4799 mtx_lock(&sep->nfsess_mtx);
4800 if ((bitval & sep->nfsess_slots) == 0)
4801 printf("freeing free slot!!\n");
4802 sep->nfsess_slots &= ~bitval;
4803 wakeup(&sep->nfsess_slots);
4804 mtx_unlock(&sep->nfsess_mtx);
4808 * Search for a matching pnfsd DS, based on the nmp arg.
4809 * Return one if found, NULL otherwise.
4812 nfsv4_findmirror(struct nfsmount *nmp)
4814 struct nfsdevice *ds;
4816 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4818 * Search the DS server list for a match with nmp.
4820 if (nfsrv_devidcnt == 0)
4822 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4823 if (ds->nfsdev_nmp == nmp) {
4824 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");