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 *);
232 static int nfsm_copyfrommbuf(struct nfsrv_descript *, char *, enum uio_seg,
240 } nfsv4_opmap[NFSV42_NPROCS] = {
242 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
243 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
244 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
245 { NFSV4OP_ACCESS, 2, "Access", 6, },
246 { NFSV4OP_READLINK, 2, "Readlink", 8, },
247 { NFSV4OP_READ, 1, "Read", 4, },
248 { NFSV4OP_WRITE, 2, "Write", 5, },
249 { NFSV4OP_OPEN, 5, "Open", 4, },
250 { NFSV4OP_CREATE, 5, "Create", 6, },
251 { NFSV4OP_CREATE, 1, "Create", 6, },
252 { NFSV4OP_CREATE, 3, "Create", 6, },
253 { NFSV4OP_REMOVE, 1, "Remove", 6, },
254 { NFSV4OP_REMOVE, 1, "Remove", 6, },
255 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
256 { NFSV4OP_SAVEFH, 4, "Link", 4, },
257 { NFSV4OP_READDIR, 2, "Readdir", 7, },
258 { NFSV4OP_READDIR, 2, "Readdir", 7, },
259 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
260 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
261 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
262 { NFSV4OP_COMMIT, 2, "Commit", 6, },
263 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
264 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
265 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
266 { NFSV4OP_LOCK, 1, "Lock", 4, },
267 { NFSV4OP_LOCKU, 1, "LockU", 5, },
268 { NFSV4OP_OPEN, 2, "Open", 4, },
269 { NFSV4OP_CLOSE, 1, "Close", 5, },
270 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
271 { NFSV4OP_LOCKT, 1, "LockT", 5, },
272 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
273 { NFSV4OP_RENEW, 1, "Renew", 5, },
274 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
275 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
276 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
277 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
278 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
279 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
280 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
281 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
282 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
283 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
284 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
285 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
286 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
287 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
288 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
289 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
290 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
291 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
292 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
293 { NFSV4OP_READ, 1, "ReadDS", 6, },
294 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
295 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
296 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
297 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
298 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
299 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
300 { NFSV4OP_SEEK, 2, "Seek", 4, },
301 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
302 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
303 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
304 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
305 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
309 * NFS RPCS that have large request message size.
311 static int nfs_bigrequest[NFSV42_NPROCS] = {
312 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
318 * Start building a request. Mostly just put the first file handle in
322 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
323 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
324 int vers, int minorvers)
329 nfsattrbit_t attrbits;
332 * First, fill in some of the fields of nd.
334 nd->nd_slotseq = NULL;
335 if (vers == NFS_VER4) {
336 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
337 if (minorvers == NFSV41_MINORVERSION)
338 nd->nd_flag |= ND_NFSV41;
339 else if (minorvers == NFSV42_MINORVERSION)
340 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
341 } else if (vers == NFS_VER3)
342 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
344 if (NFSHASNFSV4(nmp)) {
345 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
346 if (nmp->nm_minorvers == 1)
347 nd->nd_flag |= ND_NFSV41;
348 else if (nmp->nm_minorvers == 2)
349 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
350 } else if (NFSHASNFSV3(nmp))
351 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
353 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
355 nd->nd_procnum = procnum;
359 * Get the first mbuf for the request.
361 if (nfs_bigrequest[procnum])
362 NFSMCLGET(mb, M_WAITOK);
366 nd->nd_mreq = nd->nd_mb = mb;
367 nd->nd_bpos = mtod(mb, caddr_t);
370 * And fill the first file handle into the request.
372 if (nd->nd_flag & ND_NFSV4) {
373 opcnt = nfsv4_opmap[procnum].opcnt +
374 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
375 if ((nd->nd_flag & ND_NFSV41) != 0) {
376 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
377 if (procnum == NFSPROC_RENEW)
379 * For the special case of Renew, just do a
383 else if (procnum == NFSPROC_WRITEDS ||
384 procnum == NFSPROC_COMMITDS)
386 * For the special case of a Writeor Commit to
387 * a DS, the opcnt == 3, for Sequence, PutFH,
393 * What should the tag really be?
395 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
396 nfsv4_opmap[procnum].taglen);
397 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
398 if ((nd->nd_flag & ND_NFSV42) != 0)
399 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
400 else if ((nd->nd_flag & ND_NFSV41) != 0)
401 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
403 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
406 *tl = txdr_unsigned(opcnt);
407 if ((nd->nd_flag & ND_NFSV41) != 0 &&
408 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
409 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
411 nd->nd_flag |= ND_LOOPBADSESS;
412 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
413 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
415 sep = nfsmnt_mdssession(nmp);
416 nfsv4_setsequence(nmp, nd, sep,
417 nfs_bigreply[procnum]);
419 nfsv4_setsequence(nmp, nd, sep,
420 nfs_bigreply[procnum]);
422 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
423 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
424 *tl = txdr_unsigned(NFSV4OP_PUTFH);
425 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
426 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
427 == 2 && procnum != NFSPROC_WRITEDS &&
428 procnum != NFSPROC_COMMITDS) {
429 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
430 *tl = txdr_unsigned(NFSV4OP_GETATTR);
432 * For Lookup Ops, we want all the directory
433 * attributes, so we can load the name cache.
435 if (procnum == NFSPROC_LOOKUP ||
436 procnum == NFSPROC_LOOKUPP)
437 NFSGETATTR_ATTRBIT(&attrbits);
439 NFSWCCATTR_ATTRBIT(&attrbits);
440 nd->nd_flag |= ND_V4WCCATTR;
442 (void) nfsrv_putattrbit(nd, &attrbits);
445 if (procnum != NFSPROC_RENEW ||
446 (nd->nd_flag & ND_NFSV41) == 0) {
447 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
448 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
451 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
453 if (procnum < NFSV42_NPROCS)
454 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
458 * Put a state Id in the mbuf list.
461 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
465 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
466 if (flag == NFSSTATEID_PUTALLZERO) {
471 } else if (flag == NFSSTATEID_PUTALLONE) {
472 st->seqid = 0xffffffff;
473 st->other[0] = 0xffffffff;
474 st->other[1] = 0xffffffff;
475 st->other[2] = 0xffffffff;
476 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
478 st->other[0] = stateidp->other[0];
479 st->other[1] = stateidp->other[1];
480 st->other[2] = stateidp->other[2];
482 st->seqid = stateidp->seqid;
483 st->other[0] = stateidp->other[0];
484 st->other[1] = stateidp->other[1];
485 st->other[2] = stateidp->other[2];
490 * Fill in the setable attributes. The full argument indicates whether
491 * to fill in them all or just mode and time.
494 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
495 struct vnode *vp, int flags, u_int32_t rdev)
498 struct nfsv2_sattr *sp;
499 nfsattrbit_t attrbits;
501 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
503 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
504 if (vap->va_mode == (mode_t)VNOVAL)
505 sp->sa_mode = newnfs_xdrneg1;
507 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
508 if (vap->va_uid == (uid_t)VNOVAL)
509 sp->sa_uid = newnfs_xdrneg1;
511 sp->sa_uid = txdr_unsigned(vap->va_uid);
512 if (vap->va_gid == (gid_t)VNOVAL)
513 sp->sa_gid = newnfs_xdrneg1;
515 sp->sa_gid = txdr_unsigned(vap->va_gid);
516 if (flags & NFSSATTR_SIZE0)
518 else if (flags & NFSSATTR_SIZENEG1)
519 sp->sa_size = newnfs_xdrneg1;
520 else if (flags & NFSSATTR_SIZERDEV)
521 sp->sa_size = txdr_unsigned(rdev);
523 sp->sa_size = txdr_unsigned(vap->va_size);
524 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
525 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
528 if (vap->va_mode != (mode_t)VNOVAL) {
529 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
531 *tl = txdr_unsigned(vap->va_mode);
533 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
536 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
537 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
539 *tl = txdr_unsigned(vap->va_uid);
541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
544 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
545 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
547 *tl = txdr_unsigned(vap->va_gid);
549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
552 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
553 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
555 txdr_hyper(vap->va_size, tl);
557 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
560 if (vap->va_atime.tv_sec != VNOVAL) {
561 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
562 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
563 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
564 txdr_nfsv3time(&vap->va_atime, tl);
566 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
567 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
570 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
571 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
573 if (vap->va_mtime.tv_sec != VNOVAL) {
574 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
575 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
576 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
577 txdr_nfsv3time(&vap->va_mtime, tl);
579 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
580 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
583 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
584 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
588 NFSZERO_ATTRBIT(&attrbits);
589 if (vap->va_mode != (mode_t)VNOVAL)
590 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
591 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
592 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
593 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
594 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
595 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
596 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
597 if (vap->va_atime.tv_sec != VNOVAL)
598 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
599 if (vap->va_mtime.tv_sec != VNOVAL)
600 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
601 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
602 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
609 * copies mbuf chain to the uio scatter/gather list
612 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
614 char *mbufcp, *uiocp;
621 mbufcp = nd->nd_dpos;
622 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
623 rem = NFSM_RNDUP(siz) - siz;
625 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
629 left = uiop->uio_iov->iov_len;
630 uiocp = uiop->uio_iov->iov_base;
641 mbufcp = mtod(mp, caddr_t);
644 ("len %d, corrupted mbuf?", len));
646 xfer = (left > len) ? len : left;
649 if (uiop->uio_iov->iov_op != NULL)
650 (*(uiop->uio_iov->iov_op))
651 (mbufcp, uiocp, xfer);
654 if (uiop->uio_segflg == UIO_SYSSPACE)
655 NFSBCOPY(mbufcp, uiocp, xfer);
657 copyout(mbufcp, uiocp, xfer);
662 uiop->uio_offset += xfer;
663 uiop->uio_resid -= xfer;
665 if (uiop->uio_iov->iov_len <= siz) {
669 uiop->uio_iov->iov_base = (void *)
670 ((char *)uiop->uio_iov->iov_base + uiosiz);
671 uiop->uio_iov->iov_len -= uiosiz;
675 nd->nd_dpos = mbufcp;
679 error = nfsm_advance(nd, rem, len);
685 NFSEXITCODE2(error, nd);
691 * Help break down an mbuf chain by setting the first siz bytes contiguous
692 * pointed to by returned val.
693 * This is used by the macro NFSM_DISSECT for tough
697 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
706 left = mtod(nd->nd_md, char *) + nd->nd_md->m_len -
709 if (!nfsm_shiftnext(nd, &left))
715 } else if (siz > ncl_mbuf_mhlen) {
716 panic("nfs S too big");
718 /* Allocate a new mbuf for the "siz" bytes of data. */
719 MGET(mp2, MT_DATA, how);
724 * Link the new mp2 mbuf into the list then copy left
725 * bytes from the mbuf before it and siz - left bytes
726 * from the mbuf(s) after it.
728 mp2->m_next = nd->nd_md->m_next;
729 nd->nd_md->m_next = mp2;
730 nd->nd_md->m_len -= left;
731 retp = p = mtod(mp2, char *);
732 memcpy(p, nd->nd_dpos, left); /* Copy what was left */
736 nd->nd_md = mp2->m_next;
737 /* Loop around copying up the siz2 bytes */
739 if (nd->nd_md == NULL)
741 nfsm_set(nd, 0, false);
742 xfer = nfsm_copyfrommbuf(nd, p,
747 nd->nd_md = nd->nd_md->m_next;
754 * Advance the position in the mbuf chain.
755 * If offs == 0, this is a no-op, but it is simpler to just return from
756 * here than check for offs > 0 for all calls to nfsm_advance.
757 * If left == -1, it should be calculated here.
760 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
767 * A negative offs might indicate a corrupted mbuf chain and,
768 * as such, a printf is logged.
771 printf("nfsrv_advance: negative offs\n");
777 * If left == -1, calculate it here.
780 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
784 * Loop around, advancing over the mbuf data.
786 while (offs > left) {
788 nd->nd_md = nd->nd_md->m_next;
789 if (nd->nd_md == NULL) {
793 left = nd->nd_md->m_len;
794 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
804 * Copy a string into mbuf(s).
805 * Return the number of bytes output, including XDR overheads.
808 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
817 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
818 *tl = txdr_unsigned(siz);
819 rem = NFSM_RNDUP(siz) - siz;
820 bytesize = NFSX_UNSIGNED + siz + rem;
823 left = M_TRAILINGSPACE(m2);
826 * Loop around copying the string to mbuf(s).
830 if (siz > ncl_mbuf_mlen)
831 NFSMCLGET(m1, M_WAITOK);
837 cp2 = mtod(m2, caddr_t);
838 left = M_TRAILINGSPACE(m2);
844 NFSBCOPY(cp, cp2, xfer);
849 if (siz == 0 && rem) {
851 panic("nfsm_strtom");
852 NFSBZERO(cp2 + xfer, rem);
857 nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
862 * Called once to initialize data structures...
867 static int nfs_inited = 0;
873 newnfs_true = txdr_unsigned(TRUE);
874 newnfs_false = txdr_unsigned(FALSE);
875 newnfs_xdrneg1 = txdr_unsigned(-1);
876 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
879 NFSSETBOOTTIME(nfsboottime);
882 * Initialize reply list and start timer
884 TAILQ_INIT(&nfsd_reqq);
889 * Put a file handle in an mbuf list.
890 * If the size argument == 0, just use the default size.
891 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
892 * Return the number of bytes output, including XDR overhead.
895 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
899 int fullsiz, rem, bytesize = 0;
903 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
905 if (size > NFSX_V2FH)
906 panic("fh size > NFSX_V2FH for NFSv2");
907 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
908 NFSBCOPY(fhp, cp, size);
909 if (size < NFSX_V2FH)
910 NFSBZERO(cp + size, NFSX_V2FH - size);
911 bytesize = NFSX_V2FH;
915 fullsiz = NFSM_RNDUP(size);
916 rem = fullsiz - size;
918 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
919 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
922 bytesize = NFSX_UNSIGNED + fullsiz;
924 (void) nfsm_strtom(nd, fhp, size);
931 * This function compares two net addresses by family and returns TRUE
932 * if they are the same host.
933 * If there is any doubt, return FALSE.
934 * The AF_INET family is handled as a special case so that address mbufs
935 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
938 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
941 struct sockaddr_in *inetaddr;
947 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
948 if (inetaddr->sin_family == AF_INET &&
949 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
956 struct sockaddr_in6 *inetaddr6;
958 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
959 /* XXX - should test sin6_scope_id ? */
960 if (inetaddr6->sin6_family == AF_INET6 &&
961 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
972 * Similar to the above, but takes to NFSSOCKADDR_T args.
975 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
977 struct sockaddr_in *addr1, *addr2;
978 struct sockaddr *inaddr;
980 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
981 switch (inaddr->sa_family) {
983 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
984 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
985 if (addr2->sin_family == AF_INET &&
986 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
992 struct sockaddr_in6 *inet6addr1, *inet6addr2;
994 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
995 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
996 /* XXX - should test sin6_scope_id ? */
997 if (inet6addr2->sin6_family == AF_INET6 &&
998 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
999 &inet6addr2->sin6_addr))
1010 * Trim the stuff already dissected off the mbuf list.
1013 newnfs_trimleading(nd)
1014 struct nfsrv_descript *nd;
1020 * First, free up leading mbufs.
1022 if (nd->nd_mrep != nd->nd_md) {
1024 while (m->m_next != nd->nd_md) {
1025 if (m->m_next == NULL)
1026 panic("nfsm trim leading");
1030 m_freem(nd->nd_mrep);
1035 * Now, adjust this mbuf, based on nd_dpos.
1037 offs = nd->nd_dpos - mtod(m, caddr_t);
1038 if (offs == m->m_len) {
1042 panic("nfsm trim leading2");
1045 } else if (offs > 0) {
1048 } else if (offs < 0)
1049 panic("nfsm trimleading offs");
1052 nd->nd_dpos = mtod(m, caddr_t);
1056 * Trim trailing data off the mbuf list being built.
1059 newnfs_trimtrailing(nd, mb, bpos)
1060 struct nfsrv_descript *nd;
1066 m_freem(mb->m_next);
1069 mb->m_len = bpos - mtod(mb, caddr_t);
1075 * Dissect a file handle on the client.
1078 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1085 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1086 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1087 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1094 nfhp = malloc(sizeof (struct nfsfh) + len,
1096 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1098 free(nfhp, M_NFSFH);
1101 nfhp->nfh_len = len;
1104 NFSEXITCODE2(error, nd);
1109 * Break down the nfsv4 acl.
1110 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1113 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1114 int *aclsizep, __unused NFSPROC_T *p)
1118 int acecnt, error = 0, aceerr = 0, acesize;
1124 * Parse out the ace entries and expect them to conform to
1125 * what can be supported by R/W/X bits.
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1128 aclsize = NFSX_UNSIGNED;
1129 acecnt = fxdr_unsigned(int, *tl);
1130 if (acecnt > ACL_MAX_ENTRIES)
1131 aceerr = NFSERR_ATTRNOTSUPP;
1132 if (nfsrv_useacl == 0)
1133 aceerr = NFSERR_ATTRNOTSUPP;
1134 for (i = 0; i < acecnt; i++) {
1135 if (aclp && !aceerr)
1136 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1137 &aceerr, &acesize, p);
1139 error = nfsrv_skipace(nd, &acesize);
1144 if (aclp && !aceerr)
1145 aclp->acl_cnt = acecnt;
1149 *aclsizep = aclsize;
1151 NFSEXITCODE2(error, nd);
1156 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1159 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1164 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1165 len = fxdr_unsigned(int, *(tl + 3));
1166 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1168 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1169 NFSEXITCODE2(error, nd);
1174 * Get attribute bits from an mbuf list.
1175 * Returns EBADRPC for a parsing error, 0 otherwise.
1176 * If the clearinvalid flag is set, clear the bits not supported.
1179 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1186 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1187 cnt = fxdr_unsigned(int, *tl);
1189 error = NFSERR_BADXDR;
1192 if (cnt > NFSATTRBIT_MAXWORDS)
1193 outcnt = NFSATTRBIT_MAXWORDS;
1196 NFSZERO_ATTRBIT(attrbitp);
1198 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1199 for (i = 0; i < outcnt; i++)
1200 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1202 for (i = 0; i < (cnt - outcnt); i++) {
1203 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1204 if (retnotsupp != NULL && *tl != 0)
1205 *retnotsupp = NFSERR_ATTRNOTSUPP;
1208 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1210 NFSEXITCODE2(error, nd);
1215 * Get the attributes for V4.
1216 * If the compare flag is true, test for any attribute changes,
1217 * otherwise return the attribute values.
1218 * These attributes cover fields in "struct vattr", "struct statfs",
1219 * "struct nfsfsinfo", the file handle and the lease duration.
1220 * The value of retcmpp is set to 1 if all attributes are the same,
1222 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1225 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1226 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1227 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1228 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1229 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1232 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1233 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1234 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1235 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1236 struct nfsfh *tnfhp;
1237 struct nfsreferral *refp;
1240 struct timespec temptime;
1243 u_int32_t freenum = 0, tuint;
1244 u_int64_t uquad = 0, thyp, thyp2;
1250 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1253 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1255 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1261 *retcmpp = retnotsup;
1264 * Just set default values to some of the important ones.
1267 nap->na_type = VREG;
1269 nap->na_rdev = (NFSDEV_T)0;
1270 nap->na_mtime.tv_sec = 0;
1271 nap->na_mtime.tv_nsec = 0;
1274 nap->na_blocksize = NFS_FABLKSIZE;
1277 sbp->f_bsize = NFS_FABLKSIZE;
1285 fsp->fs_rtmax = 8192;
1286 fsp->fs_rtpref = 8192;
1287 fsp->fs_maxname = NFS_MAXNAMLEN;
1288 fsp->fs_wtmax = 8192;
1289 fsp->fs_wtpref = 8192;
1290 fsp->fs_wtmult = NFS_FABLKSIZE;
1291 fsp->fs_dtpref = 8192;
1292 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1293 fsp->fs_timedelta.tv_sec = 0;
1294 fsp->fs_timedelta.tv_nsec = 1;
1295 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1296 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1299 pc->pc_linkmax = NFS_LINK_MAX;
1300 pc->pc_namemax = NAME_MAX;
1302 pc->pc_chownrestricted = 0;
1303 pc->pc_caseinsensitive = 0;
1304 pc->pc_casepreserving = 1;
1307 sfp->sf_ffiles = UINT64_MAX;
1308 sfp->sf_tfiles = UINT64_MAX;
1309 sfp->sf_afiles = UINT64_MAX;
1310 sfp->sf_fbytes = UINT64_MAX;
1311 sfp->sf_tbytes = UINT64_MAX;
1312 sfp->sf_abytes = UINT64_MAX;
1317 * Loop around getting the attributes.
1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1320 attrsize = fxdr_unsigned(int, *tl);
1321 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1322 if (attrsum > attrsize) {
1323 error = NFSERR_BADXDR;
1326 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1328 case NFSATTRBIT_SUPPORTEDATTRS:
1330 if (compare || nap == NULL)
1331 error = nfsrv_getattrbits(nd, &retattrbits,
1334 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1338 if (compare && !(*retcmpp)) {
1339 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1341 /* Some filesystem do not support NFSv4ACL */
1342 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1343 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1344 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1346 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1348 *retcmpp = NFSERR_NOTSAME;
1352 case NFSATTRBIT_TYPE:
1353 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1356 if (nap->na_type != nfsv34tov_type(*tl))
1357 *retcmpp = NFSERR_NOTSAME;
1359 } else if (nap != NULL) {
1360 nap->na_type = nfsv34tov_type(*tl);
1362 attrsum += NFSX_UNSIGNED;
1364 case NFSATTRBIT_FHEXPIRETYPE:
1365 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1366 if (compare && !(*retcmpp)) {
1367 if (fxdr_unsigned(int, *tl) !=
1368 NFSV4FHTYPE_PERSISTENT)
1369 *retcmpp = NFSERR_NOTSAME;
1371 attrsum += NFSX_UNSIGNED;
1373 case NFSATTRBIT_CHANGE:
1374 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1377 if (nap->na_filerev != fxdr_hyper(tl))
1378 *retcmpp = NFSERR_NOTSAME;
1380 } else if (nap != NULL) {
1381 nap->na_filerev = fxdr_hyper(tl);
1383 attrsum += NFSX_HYPER;
1385 case NFSATTRBIT_SIZE:
1386 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1389 if (nap->na_size != fxdr_hyper(tl))
1390 *retcmpp = NFSERR_NOTSAME;
1392 } else if (nap != NULL) {
1393 nap->na_size = fxdr_hyper(tl);
1395 attrsum += NFSX_HYPER;
1397 case NFSATTRBIT_LINKSUPPORT:
1398 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1401 if (fsp->fs_properties & NFSV3_FSFLINK) {
1402 if (*tl == newnfs_false)
1403 *retcmpp = NFSERR_NOTSAME;
1405 if (*tl == newnfs_true)
1406 *retcmpp = NFSERR_NOTSAME;
1409 } else if (fsp != NULL) {
1410 if (*tl == newnfs_true)
1411 fsp->fs_properties |= NFSV3_FSFLINK;
1413 fsp->fs_properties &= ~NFSV3_FSFLINK;
1415 attrsum += NFSX_UNSIGNED;
1417 case NFSATTRBIT_SYMLINKSUPPORT:
1418 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1421 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1422 if (*tl == newnfs_false)
1423 *retcmpp = NFSERR_NOTSAME;
1425 if (*tl == newnfs_true)
1426 *retcmpp = NFSERR_NOTSAME;
1429 } else if (fsp != NULL) {
1430 if (*tl == newnfs_true)
1431 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1433 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1435 attrsum += NFSX_UNSIGNED;
1437 case NFSATTRBIT_NAMEDATTR:
1438 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1439 if (compare && !(*retcmpp)) {
1440 if (*tl != newnfs_false)
1441 *retcmpp = NFSERR_NOTSAME;
1443 attrsum += NFSX_UNSIGNED;
1445 case NFSATTRBIT_FSID:
1446 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1447 thyp = fxdr_hyper(tl);
1449 thyp2 = fxdr_hyper(tl);
1451 if (*retcmpp == 0) {
1452 if (thyp != (u_int64_t)
1453 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1454 thyp2 != (u_int64_t)
1455 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1456 *retcmpp = NFSERR_NOTSAME;
1458 } else if (nap != NULL) {
1459 nap->na_filesid[0] = thyp;
1460 nap->na_filesid[1] = thyp2;
1462 attrsum += (4 * NFSX_UNSIGNED);
1464 case NFSATTRBIT_UNIQUEHANDLES:
1465 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1466 if (compare && !(*retcmpp)) {
1467 if (*tl != newnfs_true)
1468 *retcmpp = NFSERR_NOTSAME;
1470 attrsum += NFSX_UNSIGNED;
1472 case NFSATTRBIT_LEASETIME:
1473 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1475 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1477 *retcmpp = NFSERR_NOTSAME;
1478 } else if (leasep != NULL) {
1479 *leasep = fxdr_unsigned(u_int32_t, *tl);
1481 attrsum += NFSX_UNSIGNED;
1483 case NFSATTRBIT_RDATTRERROR:
1484 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1487 *retcmpp = NFSERR_INVAL;
1488 } else if (rderrp != NULL) {
1489 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1491 attrsum += NFSX_UNSIGNED;
1493 case NFSATTRBIT_ACL:
1496 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1499 naclp = acl_alloc(M_WAITOK);
1500 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1506 if (aceerr || aclp == NULL ||
1507 nfsrv_compareacl(aclp, naclp))
1508 *retcmpp = NFSERR_NOTSAME;
1511 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1513 *retcmpp = NFSERR_ATTRNOTSUPP;
1517 if (vp != NULL && aclp != NULL)
1518 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1521 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1529 case NFSATTRBIT_ACLSUPPORT:
1530 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1531 if (compare && !(*retcmpp)) {
1532 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1533 if (fxdr_unsigned(u_int32_t, *tl) !=
1535 *retcmpp = NFSERR_NOTSAME;
1537 *retcmpp = NFSERR_ATTRNOTSUPP;
1540 attrsum += NFSX_UNSIGNED;
1542 case NFSATTRBIT_ARCHIVE:
1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1544 if (compare && !(*retcmpp))
1545 *retcmpp = NFSERR_ATTRNOTSUPP;
1546 attrsum += NFSX_UNSIGNED;
1548 case NFSATTRBIT_CANSETTIME:
1549 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1552 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1553 if (*tl == newnfs_false)
1554 *retcmpp = NFSERR_NOTSAME;
1556 if (*tl == newnfs_true)
1557 *retcmpp = NFSERR_NOTSAME;
1560 } else if (fsp != NULL) {
1561 if (*tl == newnfs_true)
1562 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1564 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1566 attrsum += NFSX_UNSIGNED;
1568 case NFSATTRBIT_CASEINSENSITIVE:
1569 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1572 if (*tl != newnfs_false)
1573 *retcmpp = NFSERR_NOTSAME;
1575 } else if (pc != NULL) {
1576 pc->pc_caseinsensitive =
1577 fxdr_unsigned(u_int32_t, *tl);
1579 attrsum += NFSX_UNSIGNED;
1581 case NFSATTRBIT_CASEPRESERVING:
1582 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1585 if (*tl != newnfs_true)
1586 *retcmpp = NFSERR_NOTSAME;
1588 } else if (pc != NULL) {
1589 pc->pc_casepreserving =
1590 fxdr_unsigned(u_int32_t, *tl);
1592 attrsum += NFSX_UNSIGNED;
1594 case NFSATTRBIT_CHOWNRESTRICTED:
1595 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1598 if (*tl != newnfs_true)
1599 *retcmpp = NFSERR_NOTSAME;
1601 } else if (pc != NULL) {
1602 pc->pc_chownrestricted =
1603 fxdr_unsigned(u_int32_t, *tl);
1605 attrsum += NFSX_UNSIGNED;
1607 case NFSATTRBIT_FILEHANDLE:
1608 error = nfsm_getfh(nd, &tnfhp);
1611 tfhsize = tnfhp->nfh_len;
1614 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1616 *retcmpp = NFSERR_NOTSAME;
1617 free(tnfhp, M_NFSFH);
1618 } else if (nfhpp != NULL) {
1621 free(tnfhp, M_NFSFH);
1623 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1625 case NFSATTRBIT_FILEID:
1626 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1627 thyp = fxdr_hyper(tl);
1630 if (nap->na_fileid != thyp)
1631 *retcmpp = NFSERR_NOTSAME;
1633 } else if (nap != NULL)
1634 nap->na_fileid = thyp;
1635 attrsum += NFSX_HYPER;
1637 case NFSATTRBIT_FILESAVAIL:
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1641 sfp->sf_afiles != fxdr_hyper(tl))
1642 *retcmpp = NFSERR_NOTSAME;
1643 } else if (sfp != NULL) {
1644 sfp->sf_afiles = fxdr_hyper(tl);
1646 attrsum += NFSX_HYPER;
1648 case NFSATTRBIT_FILESFREE:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1652 sfp->sf_ffiles != fxdr_hyper(tl))
1653 *retcmpp = NFSERR_NOTSAME;
1654 } else if (sfp != NULL) {
1655 sfp->sf_ffiles = fxdr_hyper(tl);
1657 attrsum += NFSX_HYPER;
1659 case NFSATTRBIT_FILESTOTAL:
1660 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1663 sfp->sf_tfiles != fxdr_hyper(tl))
1664 *retcmpp = NFSERR_NOTSAME;
1665 } else if (sfp != NULL) {
1666 sfp->sf_tfiles = fxdr_hyper(tl);
1668 attrsum += NFSX_HYPER;
1670 case NFSATTRBIT_FSLOCATIONS:
1671 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1675 if (compare && !(*retcmpp)) {
1676 refp = nfsv4root_getreferral(vp, NULL, 0);
1678 if (cp == NULL || cp2 == NULL ||
1680 strcmp(cp2, refp->nfr_srvlist))
1681 *retcmpp = NFSERR_NOTSAME;
1682 } else if (m == 0) {
1683 *retcmpp = NFSERR_NOTSAME;
1687 free(cp, M_NFSSTRING);
1689 free(cp2, M_NFSSTRING);
1691 case NFSATTRBIT_HIDDEN:
1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1693 if (compare && !(*retcmpp))
1694 *retcmpp = NFSERR_ATTRNOTSUPP;
1695 attrsum += NFSX_UNSIGNED;
1697 case NFSATTRBIT_HOMOGENEOUS:
1698 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1701 if (fsp->fs_properties &
1702 NFSV3_FSFHOMOGENEOUS) {
1703 if (*tl == newnfs_false)
1704 *retcmpp = NFSERR_NOTSAME;
1706 if (*tl == newnfs_true)
1707 *retcmpp = NFSERR_NOTSAME;
1710 } else if (fsp != NULL) {
1711 if (*tl == newnfs_true)
1712 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1714 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1716 attrsum += NFSX_UNSIGNED;
1718 case NFSATTRBIT_MAXFILESIZE:
1719 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1720 tnfsquad.qval = fxdr_hyper(tl);
1723 tquad = NFSRV_MAXFILESIZE;
1724 if (tquad != tnfsquad.qval)
1725 *retcmpp = NFSERR_NOTSAME;
1727 } else if (fsp != NULL) {
1728 fsp->fs_maxfilesize = tnfsquad.qval;
1730 attrsum += NFSX_HYPER;
1732 case NFSATTRBIT_MAXLINK:
1733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1736 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1737 *retcmpp = NFSERR_NOTSAME;
1739 } else if (pc != NULL) {
1740 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1742 attrsum += NFSX_UNSIGNED;
1744 case NFSATTRBIT_MAXNAME:
1745 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1748 if (fsp->fs_maxname !=
1749 fxdr_unsigned(u_int32_t, *tl))
1750 *retcmpp = NFSERR_NOTSAME;
1753 tuint = fxdr_unsigned(u_int32_t, *tl);
1755 * Some Linux NFSv4 servers report this
1756 * as 0 or 4billion, so I'll set it to
1757 * NFS_MAXNAMLEN. If a server actually creates
1758 * a name longer than NFS_MAXNAMLEN, it will
1759 * get an error back.
1761 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1762 tuint = NFS_MAXNAMLEN;
1764 fsp->fs_maxname = tuint;
1766 pc->pc_namemax = tuint;
1768 attrsum += NFSX_UNSIGNED;
1770 case NFSATTRBIT_MAXREAD:
1771 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1774 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1775 *(tl + 1)) || *tl != 0)
1776 *retcmpp = NFSERR_NOTSAME;
1778 } else if (fsp != NULL) {
1779 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1780 fsp->fs_rtpref = fsp->fs_rtmax;
1781 fsp->fs_dtpref = fsp->fs_rtpref;
1783 attrsum += NFSX_HYPER;
1785 case NFSATTRBIT_MAXWRITE:
1786 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1789 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1790 *(tl + 1)) || *tl != 0)
1791 *retcmpp = NFSERR_NOTSAME;
1793 } else if (fsp != NULL) {
1794 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1795 fsp->fs_wtpref = fsp->fs_wtmax;
1797 attrsum += NFSX_HYPER;
1799 case NFSATTRBIT_MIMETYPE:
1800 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1801 i = fxdr_unsigned(int, *tl);
1802 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1803 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1806 if (compare && !(*retcmpp))
1807 *retcmpp = NFSERR_ATTRNOTSUPP;
1809 case NFSATTRBIT_MODE:
1810 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1813 if (nap->na_mode != nfstov_mode(*tl))
1814 *retcmpp = NFSERR_NOTSAME;
1816 } else if (nap != NULL) {
1817 nap->na_mode = nfstov_mode(*tl);
1819 attrsum += NFSX_UNSIGNED;
1821 case NFSATTRBIT_NOTRUNC:
1822 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1825 if (*tl != newnfs_true)
1826 *retcmpp = NFSERR_NOTSAME;
1828 } else if (pc != NULL) {
1829 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1831 attrsum += NFSX_UNSIGNED;
1833 case NFSATTRBIT_NUMLINKS:
1834 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1835 tuint = fxdr_unsigned(u_int32_t, *tl);
1838 if ((u_int32_t)nap->na_nlink != tuint)
1839 *retcmpp = NFSERR_NOTSAME;
1841 } else if (nap != NULL) {
1842 nap->na_nlink = tuint;
1844 attrsum += NFSX_UNSIGNED;
1846 case NFSATTRBIT_OWNER:
1847 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1848 j = fxdr_unsigned(int, *tl);
1850 error = NFSERR_BADXDR;
1853 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1854 if (j > NFSV4_SMALLSTR)
1855 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1858 error = nfsrv_mtostr(nd, cp, j);
1860 if (j > NFSV4_SMALLSTR)
1861 free(cp, M_NFSSTRING);
1866 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1868 *retcmpp = NFSERR_NOTSAME;
1870 } else if (nap != NULL) {
1871 if (nfsv4_strtouid(nd, cp, j, &uid))
1872 nap->na_uid = nfsrv_defaultuid;
1876 if (j > NFSV4_SMALLSTR)
1877 free(cp, M_NFSSTRING);
1879 case NFSATTRBIT_OWNERGROUP:
1880 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1881 j = fxdr_unsigned(int, *tl);
1883 error = NFSERR_BADXDR;
1886 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1887 if (j > NFSV4_SMALLSTR)
1888 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1891 error = nfsrv_mtostr(nd, cp, j);
1893 if (j > NFSV4_SMALLSTR)
1894 free(cp, M_NFSSTRING);
1899 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1901 *retcmpp = NFSERR_NOTSAME;
1903 } else if (nap != NULL) {
1904 if (nfsv4_strtogid(nd, cp, j, &gid))
1905 nap->na_gid = nfsrv_defaultgid;
1909 if (j > NFSV4_SMALLSTR)
1910 free(cp, M_NFSSTRING);
1912 case NFSATTRBIT_QUOTAHARD:
1913 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1915 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1916 freenum = sbp->f_bfree;
1918 freenum = sbp->f_bavail;
1921 * ufs_quotactl() insists that the uid argument
1922 * equal p_ruid for non-root quota access, so
1923 * we'll just make sure that's the case.
1925 savuid = p->p_cred->p_ruid;
1926 p->p_cred->p_ruid = cred->cr_uid;
1927 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1928 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1929 freenum = min(dqb.dqb_bhardlimit, freenum);
1930 p->p_cred->p_ruid = savuid;
1932 uquad = (u_int64_t)freenum;
1933 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1935 if (compare && !(*retcmpp)) {
1936 if (uquad != fxdr_hyper(tl))
1937 *retcmpp = NFSERR_NOTSAME;
1939 attrsum += NFSX_HYPER;
1941 case NFSATTRBIT_QUOTASOFT:
1942 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1944 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1945 freenum = sbp->f_bfree;
1947 freenum = sbp->f_bavail;
1950 * ufs_quotactl() insists that the uid argument
1951 * equal p_ruid for non-root quota access, so
1952 * we'll just make sure that's the case.
1954 savuid = p->p_cred->p_ruid;
1955 p->p_cred->p_ruid = cred->cr_uid;
1956 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1957 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1958 freenum = min(dqb.dqb_bsoftlimit, freenum);
1959 p->p_cred->p_ruid = savuid;
1961 uquad = (u_int64_t)freenum;
1962 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1964 if (compare && !(*retcmpp)) {
1965 if (uquad != fxdr_hyper(tl))
1966 *retcmpp = NFSERR_NOTSAME;
1968 attrsum += NFSX_HYPER;
1970 case NFSATTRBIT_QUOTAUSED:
1971 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1976 * ufs_quotactl() insists that the uid argument
1977 * equal p_ruid for non-root quota access, so
1978 * we'll just make sure that's the case.
1980 savuid = p->p_cred->p_ruid;
1981 p->p_cred->p_ruid = cred->cr_uid;
1982 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1983 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1984 freenum = dqb.dqb_curblocks;
1985 p->p_cred->p_ruid = savuid;
1987 uquad = (u_int64_t)freenum;
1988 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1990 if (compare && !(*retcmpp)) {
1991 if (uquad != fxdr_hyper(tl))
1992 *retcmpp = NFSERR_NOTSAME;
1994 attrsum += NFSX_HYPER;
1996 case NFSATTRBIT_RAWDEV:
1997 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1998 j = fxdr_unsigned(int, *tl++);
1999 k = fxdr_unsigned(int, *tl);
2002 if (nap->na_rdev != NFSMAKEDEV(j, k))
2003 *retcmpp = NFSERR_NOTSAME;
2005 } else if (nap != NULL) {
2006 nap->na_rdev = NFSMAKEDEV(j, k);
2008 attrsum += NFSX_V4SPECDATA;
2010 case NFSATTRBIT_SPACEAVAIL:
2011 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2014 sfp->sf_abytes != fxdr_hyper(tl))
2015 *retcmpp = NFSERR_NOTSAME;
2016 } else if (sfp != NULL) {
2017 sfp->sf_abytes = fxdr_hyper(tl);
2019 attrsum += NFSX_HYPER;
2021 case NFSATTRBIT_SPACEFREE:
2022 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2025 sfp->sf_fbytes != fxdr_hyper(tl))
2026 *retcmpp = NFSERR_NOTSAME;
2027 } else if (sfp != NULL) {
2028 sfp->sf_fbytes = fxdr_hyper(tl);
2030 attrsum += NFSX_HYPER;
2032 case NFSATTRBIT_SPACETOTAL:
2033 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2036 sfp->sf_tbytes != fxdr_hyper(tl))
2037 *retcmpp = NFSERR_NOTSAME;
2038 } else if (sfp != NULL) {
2039 sfp->sf_tbytes = fxdr_hyper(tl);
2041 attrsum += NFSX_HYPER;
2043 case NFSATTRBIT_SPACEUSED:
2044 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2045 thyp = fxdr_hyper(tl);
2048 if ((u_int64_t)nap->na_bytes != thyp)
2049 *retcmpp = NFSERR_NOTSAME;
2051 } else if (nap != NULL) {
2052 nap->na_bytes = thyp;
2054 attrsum += NFSX_HYPER;
2056 case NFSATTRBIT_SYSTEM:
2057 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2058 if (compare && !(*retcmpp))
2059 *retcmpp = NFSERR_ATTRNOTSUPP;
2060 attrsum += NFSX_UNSIGNED;
2062 case NFSATTRBIT_TIMEACCESS:
2063 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2064 fxdr_nfsv4time(tl, &temptime);
2067 if (!NFS_CMPTIME(temptime, nap->na_atime))
2068 *retcmpp = NFSERR_NOTSAME;
2070 } else if (nap != NULL) {
2071 nap->na_atime = temptime;
2073 attrsum += NFSX_V4TIME;
2075 case NFSATTRBIT_TIMEACCESSSET:
2076 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2077 attrsum += NFSX_UNSIGNED;
2078 i = fxdr_unsigned(int, *tl);
2079 if (i == NFSV4SATTRTIME_TOCLIENT) {
2080 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2081 attrsum += NFSX_V4TIME;
2083 if (compare && !(*retcmpp))
2084 *retcmpp = NFSERR_INVAL;
2086 case NFSATTRBIT_TIMEBACKUP:
2087 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2088 if (compare && !(*retcmpp))
2089 *retcmpp = NFSERR_ATTRNOTSUPP;
2090 attrsum += NFSX_V4TIME;
2092 case NFSATTRBIT_TIMECREATE:
2093 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2094 if (compare && !(*retcmpp))
2095 *retcmpp = NFSERR_ATTRNOTSUPP;
2096 attrsum += NFSX_V4TIME;
2098 case NFSATTRBIT_TIMEDELTA:
2099 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2103 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2104 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2105 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2106 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2109 *retcmpp = NFSERR_NOTSAME;
2112 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2115 attrsum += NFSX_V4TIME;
2117 case NFSATTRBIT_TIMEMETADATA:
2118 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2119 fxdr_nfsv4time(tl, &temptime);
2122 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2123 *retcmpp = NFSERR_NOTSAME;
2125 } else if (nap != NULL) {
2126 nap->na_ctime = temptime;
2128 attrsum += NFSX_V4TIME;
2130 case NFSATTRBIT_TIMEMODIFY:
2131 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2132 fxdr_nfsv4time(tl, &temptime);
2135 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2136 *retcmpp = NFSERR_NOTSAME;
2138 } else if (nap != NULL) {
2139 nap->na_mtime = temptime;
2141 attrsum += NFSX_V4TIME;
2143 case NFSATTRBIT_TIMEMODIFYSET:
2144 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2145 attrsum += NFSX_UNSIGNED;
2146 i = fxdr_unsigned(int, *tl);
2147 if (i == NFSV4SATTRTIME_TOCLIENT) {
2148 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2149 attrsum += NFSX_V4TIME;
2151 if (compare && !(*retcmpp))
2152 *retcmpp = NFSERR_INVAL;
2154 case NFSATTRBIT_MOUNTEDONFILEID:
2155 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2156 thyp = fxdr_hyper(tl);
2159 if (!vp || !nfsrv_atroot(vp, &thyp2))
2160 thyp2 = nap->na_fileid;
2162 *retcmpp = NFSERR_NOTSAME;
2164 } else if (nap != NULL)
2165 nap->na_mntonfileno = thyp;
2166 attrsum += NFSX_HYPER;
2168 case NFSATTRBIT_SUPPATTREXCLCREAT:
2170 error = nfsrv_getattrbits(nd, &retattrbits,
2174 if (compare && !(*retcmpp)) {
2175 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2176 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2177 NFSCLRBIT_ATTRBIT(&checkattrbits,
2178 NFSATTRBIT_TIMEACCESSSET);
2179 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2181 *retcmpp = NFSERR_NOTSAME;
2185 case NFSATTRBIT_FSLAYOUTTYPE:
2186 case NFSATTRBIT_LAYOUTTYPE:
2187 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2188 attrsum += NFSX_UNSIGNED;
2189 i = fxdr_unsigned(int, *tl);
2191 NFSM_DISSECT(tl, u_int32_t *, i *
2193 attrsum += i * NFSX_UNSIGNED;
2194 j = fxdr_unsigned(int, *tl);
2195 if (i == 1 && compare && !(*retcmpp) &&
2196 (((nfsrv_doflexfile != 0 ||
2197 nfsrv_maxpnfsmirror > 1) &&
2198 j != NFSLAYOUT_FLEXFILE) ||
2199 (nfsrv_doflexfile == 0 &&
2200 j != NFSLAYOUT_NFSV4_1_FILES)))
2201 *retcmpp = NFSERR_NOTSAME;
2203 if (nfsrv_devidcnt == 0) {
2204 if (compare && !(*retcmpp) && i > 0)
2205 *retcmpp = NFSERR_NOTSAME;
2207 if (compare && !(*retcmpp) && i != 1)
2208 *retcmpp = NFSERR_NOTSAME;
2211 case NFSATTRBIT_LAYOUTALIGNMENT:
2212 case NFSATTRBIT_LAYOUTBLKSIZE:
2213 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2214 attrsum += NFSX_UNSIGNED;
2215 i = fxdr_unsigned(int, *tl);
2216 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2217 *retcmpp = NFSERR_NOTSAME;
2220 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2222 if (compare && !(*retcmpp))
2223 *retcmpp = NFSERR_ATTRNOTSUPP;
2225 * and get out of the loop, since we can't parse
2226 * the unknown attrbute data.
2228 bitpos = NFSATTRBIT_MAX;
2234 * some clients pad the attrlist, so we need to skip over the
2237 if (attrsum > attrsize) {
2238 error = NFSERR_BADXDR;
2240 attrsize = NFSM_RNDUP(attrsize);
2241 if (attrsum < attrsize)
2242 error = nfsm_advance(nd, attrsize - attrsum, -1);
2245 NFSEXITCODE2(error, nd);
2250 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2251 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2252 * The first argument is a pointer to an nfsv4lock structure.
2253 * The second argument is 1 iff a blocking lock is wanted.
2254 * If this argument is 0, the call waits until no thread either wants nor
2255 * holds an exclusive lock.
2256 * It returns 1 if the lock was acquired, 0 otherwise.
2257 * If several processes call this function concurrently wanting the exclusive
2258 * lock, one will get the lock and the rest will return without getting the
2259 * lock. (If the caller must have the lock, it simply calls this function in a
2260 * loop until the function returns 1 to indicate the lock was acquired.)
2261 * Any usecnt must be decremented by calling nfsv4_relref() before
2262 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2263 * be called in a loop.
2264 * The isleptp argument is set to indicate if the call slept, iff not NULL
2265 * and the mp argument indicates to check for a forced dismount, iff not
2269 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2270 void *mutex, struct mount *mp)
2276 * If a lock is wanted, loop around until the lock is acquired by
2277 * someone and then released. If I want the lock, try to acquire it.
2278 * For a lock to be issued, no lock must be in force and the usecnt
2282 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2283 lp->nfslock_usecnt == 0) {
2284 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2285 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2288 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2290 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2291 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2292 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2295 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2298 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2299 PZERO - 1, "nfsv4lck", NULL);
2300 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2301 lp->nfslock_usecnt == 0) {
2302 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2303 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2311 * Release the lock acquired by nfsv4_lock().
2312 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2313 * incremented, as well.
2316 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2319 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2321 lp->nfslock_usecnt++;
2326 * Release a reference cnt.
2329 nfsv4_relref(struct nfsv4lock *lp)
2332 if (lp->nfslock_usecnt <= 0)
2333 panic("nfsv4root ref cnt");
2334 lp->nfslock_usecnt--;
2335 if (lp->nfslock_usecnt == 0)
2340 * Get a reference cnt.
2341 * This function will wait for any exclusive lock to be released, but will
2342 * not wait for threads that want the exclusive lock. If priority needs
2343 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2344 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2345 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2346 * return without getting a refcnt for that case.
2349 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2357 * Wait for a lock held.
2359 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2360 if (mp != NULL && NFSCL_FORCEDISM(mp))
2362 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2365 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2366 PZERO - 1, "nfsv4gr", NULL);
2368 if (mp != NULL && NFSCL_FORCEDISM(mp))
2371 lp->nfslock_usecnt++;
2375 * Get a reference as above, but return failure instead of sleeping if
2376 * an exclusive lock is held.
2379 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2382 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2385 lp->nfslock_usecnt++;
2390 * Test for a lock. Return 1 if locked, 0 otherwise.
2393 nfsv4_testlock(struct nfsv4lock *lp)
2396 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2397 lp->nfslock_usecnt == 0)
2403 * Wake up anyone sleeping, waiting for this lock.
2406 nfsv4_wanted(struct nfsv4lock *lp)
2409 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2410 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2411 wakeup((caddr_t)&lp->nfslock_lock);
2416 * Copy a string from an mbuf list into a character array.
2417 * Return EBADRPC if there is an mbuf error,
2421 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2430 len = mtod(mp, caddr_t) + mp->m_len - cp;
2431 rem = NFSM_RNDUP(siz) - siz;
2437 NFSBCOPY(cp, str, xfer);
2446 cp = mtod(mp, caddr_t);
2458 error = nfsm_advance(nd, rem, len);
2464 NFSEXITCODE2(error, nd);
2469 * Fill in the attributes as marked by the bitmap (V4).
2472 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2473 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2474 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2475 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2476 struct statfs *pnfssf)
2478 int bitpos, retnum = 0;
2480 int siz, prefixnum, error;
2481 u_char *cp, namestr[NFSV4_SMALLSTR];
2482 nfsattrbit_t attrbits, retbits;
2483 nfsattrbit_t *retbitp = &retbits;
2484 u_int32_t freenum, *retnump;
2487 struct nfsfsinfo fsinf;
2488 struct timespec temptime;
2489 NFSACL_T *aclp, *naclp = NULL;
2498 * First, set the bits that can be filled and get fsinfo.
2500 NFSSET_ATTRBIT(retbitp, attrbitp);
2502 * If both p and cred are NULL, it is a client side setattr call.
2503 * If both p and cred are not NULL, it is a server side reply call.
2504 * If p is not NULL and cred is NULL, it is a client side callback
2507 if (p == NULL && cred == NULL) {
2508 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2511 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2512 naclp = acl_alloc(M_WAITOK);
2515 nfsvno_getfs(&fsinf, isdgram);
2518 * Get the VFS_STATFS(), since some attributes need them.
2520 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2521 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2522 error = VFS_STATFS(mp, fs);
2525 nd->nd_repstat = NFSERR_ACCES;
2529 NFSCLRSTATFS_ATTRBIT(retbitp);
2535 * And the NFSv4 ACL...
2537 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2538 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2539 supports_nfsv4acls == 0))) {
2540 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2542 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2543 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2544 supports_nfsv4acls == 0)) {
2545 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2546 } else if (naclp != NULL) {
2547 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2548 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2550 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2554 error = NFSERR_PERM;
2557 nd->nd_repstat = NFSERR_ACCES;
2561 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2566 /* Check to see if Extended Attributes are supported. */
2568 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2569 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2570 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2571 "xxx", NULL, &atsiz, cred, p);
2573 if (error != EOPNOTSUPP)
2579 * Put out the attribute bitmap for the ones being filled in
2580 * and get the field for the number of attributes returned.
2582 prefixnum = nfsrv_putattrbit(nd, retbitp);
2583 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2584 prefixnum += NFSX_UNSIGNED;
2587 * Now, loop around filling in the attributes for each bit set.
2589 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2590 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2592 case NFSATTRBIT_SUPPORTEDATTRS:
2593 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2594 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2595 && supports_nfsv4acls == 0)) {
2596 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2597 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2599 retnum += nfsrv_putattrbit(nd, &attrbits);
2601 case NFSATTRBIT_TYPE:
2602 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2603 *tl = vtonfsv34_type(vap->va_type);
2604 retnum += NFSX_UNSIGNED;
2606 case NFSATTRBIT_FHEXPIRETYPE:
2607 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2608 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2609 retnum += NFSX_UNSIGNED;
2611 case NFSATTRBIT_CHANGE:
2612 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2613 txdr_hyper(vap->va_filerev, tl);
2614 retnum += NFSX_HYPER;
2616 case NFSATTRBIT_SIZE:
2617 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2618 txdr_hyper(vap->va_size, tl);
2619 retnum += NFSX_HYPER;
2621 case NFSATTRBIT_LINKSUPPORT:
2622 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2623 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2627 retnum += NFSX_UNSIGNED;
2629 case NFSATTRBIT_SYMLINKSUPPORT:
2630 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2631 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2635 retnum += NFSX_UNSIGNED;
2637 case NFSATTRBIT_NAMEDATTR:
2638 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2640 retnum += NFSX_UNSIGNED;
2642 case NFSATTRBIT_FSID:
2643 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2645 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2647 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2648 retnum += NFSX_V4FSID;
2650 case NFSATTRBIT_UNIQUEHANDLES:
2651 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2653 retnum += NFSX_UNSIGNED;
2655 case NFSATTRBIT_LEASETIME:
2656 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2657 *tl = txdr_unsigned(nfsrv_lease);
2658 retnum += NFSX_UNSIGNED;
2660 case NFSATTRBIT_RDATTRERROR:
2661 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2662 *tl = txdr_unsigned(rderror);
2663 retnum += NFSX_UNSIGNED;
2666 * Recommended Attributes. (Only the supported ones.)
2668 case NFSATTRBIT_ACL:
2669 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2671 case NFSATTRBIT_ACLSUPPORT:
2672 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2673 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2674 retnum += NFSX_UNSIGNED;
2676 case NFSATTRBIT_CANSETTIME:
2677 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2678 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2682 retnum += NFSX_UNSIGNED;
2684 case NFSATTRBIT_CASEINSENSITIVE:
2685 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2687 retnum += NFSX_UNSIGNED;
2689 case NFSATTRBIT_CASEPRESERVING:
2690 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2692 retnum += NFSX_UNSIGNED;
2694 case NFSATTRBIT_CHOWNRESTRICTED:
2695 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2697 retnum += NFSX_UNSIGNED;
2699 case NFSATTRBIT_FILEHANDLE:
2700 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2702 case NFSATTRBIT_FILEID:
2703 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2704 uquad = vap->va_fileid;
2705 txdr_hyper(uquad, tl);
2706 retnum += NFSX_HYPER;
2708 case NFSATTRBIT_FILESAVAIL:
2710 * Check quota and use min(quota, f_ffree).
2712 freenum = fs->f_ffree;
2715 * ufs_quotactl() insists that the uid argument
2716 * equal p_ruid for non-root quota access, so
2717 * we'll just make sure that's the case.
2719 savuid = p->p_cred->p_ruid;
2720 p->p_cred->p_ruid = cred->cr_uid;
2721 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2722 cred->cr_uid, (caddr_t)&dqb))
2723 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2725 p->p_cred->p_ruid = savuid;
2727 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2729 *tl = txdr_unsigned(freenum);
2730 retnum += NFSX_HYPER;
2732 case NFSATTRBIT_FILESFREE:
2733 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2735 *tl = txdr_unsigned(fs->f_ffree);
2736 retnum += NFSX_HYPER;
2738 case NFSATTRBIT_FILESTOTAL:
2739 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2741 *tl = txdr_unsigned(fs->f_files);
2742 retnum += NFSX_HYPER;
2744 case NFSATTRBIT_FSLOCATIONS:
2745 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2748 retnum += 2 * NFSX_UNSIGNED;
2750 case NFSATTRBIT_HOMOGENEOUS:
2751 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2752 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2756 retnum += NFSX_UNSIGNED;
2758 case NFSATTRBIT_MAXFILESIZE:
2759 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2760 uquad = NFSRV_MAXFILESIZE;
2761 txdr_hyper(uquad, tl);
2762 retnum += NFSX_HYPER;
2764 case NFSATTRBIT_MAXLINK:
2765 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2766 *tl = txdr_unsigned(NFS_LINK_MAX);
2767 retnum += NFSX_UNSIGNED;
2769 case NFSATTRBIT_MAXNAME:
2770 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2771 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2772 retnum += NFSX_UNSIGNED;
2774 case NFSATTRBIT_MAXREAD:
2775 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2777 *tl = txdr_unsigned(fsinf.fs_rtmax);
2778 retnum += NFSX_HYPER;
2780 case NFSATTRBIT_MAXWRITE:
2781 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2783 *tl = txdr_unsigned(fsinf.fs_wtmax);
2784 retnum += NFSX_HYPER;
2786 case NFSATTRBIT_MODE:
2787 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2788 *tl = vtonfsv34_mode(vap->va_mode);
2789 retnum += NFSX_UNSIGNED;
2791 case NFSATTRBIT_NOTRUNC:
2792 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2794 retnum += NFSX_UNSIGNED;
2796 case NFSATTRBIT_NUMLINKS:
2797 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2798 *tl = txdr_unsigned(vap->va_nlink);
2799 retnum += NFSX_UNSIGNED;
2801 case NFSATTRBIT_OWNER:
2803 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2804 retnum += nfsm_strtom(nd, cp, siz);
2806 free(cp, M_NFSSTRING);
2808 case NFSATTRBIT_OWNERGROUP:
2810 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2811 retnum += nfsm_strtom(nd, cp, siz);
2813 free(cp, M_NFSSTRING);
2815 case NFSATTRBIT_QUOTAHARD:
2816 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2817 freenum = fs->f_bfree;
2819 freenum = fs->f_bavail;
2822 * ufs_quotactl() insists that the uid argument
2823 * equal p_ruid for non-root quota access, so
2824 * we'll just make sure that's the case.
2826 savuid = p->p_cred->p_ruid;
2827 p->p_cred->p_ruid = cred->cr_uid;
2828 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2829 cred->cr_uid, (caddr_t)&dqb))
2830 freenum = min(dqb.dqb_bhardlimit, freenum);
2831 p->p_cred->p_ruid = savuid;
2833 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2834 uquad = (u_int64_t)freenum;
2835 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2836 txdr_hyper(uquad, tl);
2837 retnum += NFSX_HYPER;
2839 case NFSATTRBIT_QUOTASOFT:
2840 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2841 freenum = fs->f_bfree;
2843 freenum = fs->f_bavail;
2846 * ufs_quotactl() insists that the uid argument
2847 * equal p_ruid for non-root quota access, so
2848 * we'll just make sure that's the case.
2850 savuid = p->p_cred->p_ruid;
2851 p->p_cred->p_ruid = cred->cr_uid;
2852 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2853 cred->cr_uid, (caddr_t)&dqb))
2854 freenum = min(dqb.dqb_bsoftlimit, freenum);
2855 p->p_cred->p_ruid = savuid;
2857 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2858 uquad = (u_int64_t)freenum;
2859 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2860 txdr_hyper(uquad, tl);
2861 retnum += NFSX_HYPER;
2863 case NFSATTRBIT_QUOTAUSED:
2867 * ufs_quotactl() insists that the uid argument
2868 * equal p_ruid for non-root quota access, so
2869 * we'll just make sure that's the case.
2871 savuid = p->p_cred->p_ruid;
2872 p->p_cred->p_ruid = cred->cr_uid;
2873 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2874 cred->cr_uid, (caddr_t)&dqb))
2875 freenum = dqb.dqb_curblocks;
2876 p->p_cred->p_ruid = savuid;
2878 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2879 uquad = (u_int64_t)freenum;
2880 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2881 txdr_hyper(uquad, tl);
2882 retnum += NFSX_HYPER;
2884 case NFSATTRBIT_RAWDEV:
2885 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2886 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2887 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2888 retnum += NFSX_V4SPECDATA;
2890 case NFSATTRBIT_SPACEAVAIL:
2891 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2892 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2894 uquad = (u_int64_t)pnfssf->f_bfree;
2896 uquad = (u_int64_t)fs->f_bfree;
2899 uquad = (u_int64_t)pnfssf->f_bavail;
2901 uquad = (u_int64_t)fs->f_bavail;
2904 uquad *= pnfssf->f_bsize;
2906 uquad *= fs->f_bsize;
2907 txdr_hyper(uquad, tl);
2908 retnum += NFSX_HYPER;
2910 case NFSATTRBIT_SPACEFREE:
2911 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2912 if (pnfssf != NULL) {
2913 uquad = (u_int64_t)pnfssf->f_bfree;
2914 uquad *= pnfssf->f_bsize;
2916 uquad = (u_int64_t)fs->f_bfree;
2917 uquad *= fs->f_bsize;
2919 txdr_hyper(uquad, tl);
2920 retnum += NFSX_HYPER;
2922 case NFSATTRBIT_SPACETOTAL:
2923 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2924 if (pnfssf != NULL) {
2925 uquad = (u_int64_t)pnfssf->f_blocks;
2926 uquad *= pnfssf->f_bsize;
2928 uquad = (u_int64_t)fs->f_blocks;
2929 uquad *= fs->f_bsize;
2931 txdr_hyper(uquad, tl);
2932 retnum += NFSX_HYPER;
2934 case NFSATTRBIT_SPACEUSED:
2935 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2936 txdr_hyper(vap->va_bytes, tl);
2937 retnum += NFSX_HYPER;
2939 case NFSATTRBIT_TIMEACCESS:
2940 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2941 txdr_nfsv4time(&vap->va_atime, tl);
2942 retnum += NFSX_V4TIME;
2944 case NFSATTRBIT_TIMEACCESSSET:
2945 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2946 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2947 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2948 txdr_nfsv4time(&vap->va_atime, tl);
2949 retnum += NFSX_V4SETTIME;
2951 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2952 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2953 retnum += NFSX_UNSIGNED;
2956 case NFSATTRBIT_TIMEDELTA:
2957 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2958 temptime.tv_sec = 0;
2959 temptime.tv_nsec = 1000000000 / hz;
2960 txdr_nfsv4time(&temptime, tl);
2961 retnum += NFSX_V4TIME;
2963 case NFSATTRBIT_TIMEMETADATA:
2964 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2965 txdr_nfsv4time(&vap->va_ctime, tl);
2966 retnum += NFSX_V4TIME;
2968 case NFSATTRBIT_TIMEMODIFY:
2969 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2970 txdr_nfsv4time(&vap->va_mtime, tl);
2971 retnum += NFSX_V4TIME;
2973 case NFSATTRBIT_TIMEMODIFYSET:
2974 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2975 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2976 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2977 txdr_nfsv4time(&vap->va_mtime, tl);
2978 retnum += NFSX_V4SETTIME;
2980 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2981 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2982 retnum += NFSX_UNSIGNED;
2985 case NFSATTRBIT_MOUNTEDONFILEID:
2986 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2988 uquad = mounted_on_fileno;
2990 uquad = vap->va_fileid;
2991 txdr_hyper(uquad, tl);
2992 retnum += NFSX_HYPER;
2994 case NFSATTRBIT_SUPPATTREXCLCREAT:
2995 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2996 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2997 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2998 retnum += nfsrv_putattrbit(nd, &attrbits);
3000 case NFSATTRBIT_FSLAYOUTTYPE:
3001 case NFSATTRBIT_LAYOUTTYPE:
3002 if (nfsrv_devidcnt == 0)
3007 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3008 *tl++ = txdr_unsigned(1); /* One entry. */
3009 if (nfsrv_doflexfile != 0 ||
3010 nfsrv_maxpnfsmirror > 1)
3011 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3013 *tl = txdr_unsigned(
3014 NFSLAYOUT_NFSV4_1_FILES);
3016 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3019 retnum += siz * NFSX_UNSIGNED;
3021 case NFSATTRBIT_LAYOUTALIGNMENT:
3022 case NFSATTRBIT_LAYOUTBLKSIZE:
3023 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3024 *tl = txdr_unsigned(NFS_SRVMAXIO);
3025 retnum += NFSX_UNSIGNED;
3027 case NFSATTRBIT_XATTRSUPPORT:
3028 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3033 retnum += NFSX_UNSIGNED;
3036 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3043 *retnump = txdr_unsigned(retnum);
3044 return (retnum + prefixnum);
3048 * Put the attribute bits onto an mbuf list.
3049 * Return the number of bytes of output generated.
3052 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3055 int cnt, i, bytesize;
3057 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3058 if (attrbitp->bits[cnt - 1])
3060 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3061 NFSM_BUILD(tl, u_int32_t *, bytesize);
3062 *tl++ = txdr_unsigned(cnt);
3063 for (i = 0; i < cnt; i++)
3064 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3069 * Convert a uid to a string.
3070 * If the lookup fails, just output the digits.
3072 * cpp - points to a buffer of size NFSV4_SMALLSTR
3073 * (malloc a larger one, as required)
3074 * retlenp - pointer to length to be returned
3077 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3080 struct nfsusrgrp *usrp;
3083 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3084 struct nfsrv_lughash *hp;
3088 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3090 * Always map nfsrv_defaultuid to "nobody".
3092 if (uid == nfsrv_defaultuid) {
3093 i = nfsrv_dnsnamelen + 7;
3095 if (len > NFSV4_SMALLSTR)
3096 free(cp, M_NFSSTRING);
3097 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3103 NFSBCOPY("nobody@", cp, 7);
3105 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3109 hp = NFSUSERHASH(uid);
3111 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3112 if (usrp->lug_uid == uid) {
3113 if (usrp->lug_expiry < NFSD_MONOSEC)
3116 * If the name doesn't already have an '@'
3117 * in it, append @domainname to it.
3119 for (i = 0; i < usrp->lug_namelen; i++) {
3120 if (usrp->lug_name[i] == '@') {
3126 i = usrp->lug_namelen;
3128 i = usrp->lug_namelen +
3129 nfsrv_dnsnamelen + 1;
3131 mtx_unlock(&hp->mtx);
3132 if (len > NFSV4_SMALLSTR)
3133 free(cp, M_NFSSTRING);
3134 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3140 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3141 if (!hasampersand) {
3142 cp += usrp->lug_namelen;
3144 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3146 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3147 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3149 mtx_unlock(&hp->mtx);
3153 mtx_unlock(&hp->mtx);
3155 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3156 if (ret == 0 && cnt < 2)
3161 * No match, just return a string of digits.
3165 while (tmp || i == 0) {
3169 len = (i > len) ? len : i;
3173 for (i = 0; i < len; i++) {
3174 *cp-- = '0' + (tmp % 10);
3181 * Get a credential for the uid with the server's group list.
3182 * If none is found, just return the credential passed in after
3183 * logging a warning message.
3186 nfsrv_getgrpscred(struct ucred *oldcred)
3188 struct nfsusrgrp *usrp;
3189 struct ucred *newcred;
3192 struct nfsrv_lughash *hp;
3195 uid = oldcred->cr_uid;
3197 if (nfsrv_dnsnamelen > 0) {
3198 hp = NFSUSERHASH(uid);
3200 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3201 if (usrp->lug_uid == uid) {
3202 if (usrp->lug_expiry < NFSD_MONOSEC)
3204 if (usrp->lug_cred != NULL) {
3205 newcred = crhold(usrp->lug_cred);
3209 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3210 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3212 mtx_unlock(&hp->mtx);
3216 mtx_unlock(&hp->mtx);
3218 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3219 if (ret == 0 && cnt < 2)
3226 * Convert a string to a uid.
3227 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3229 * If this is called from a client side mount using AUTH_SYS and the
3230 * string is made up entirely of digits, just convert the string to
3234 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3237 char *cp, *endstr, *str0;
3238 struct nfsusrgrp *usrp;
3242 struct nfsrv_lughash *hp, *hp2;
3245 error = NFSERR_BADOWNER;
3248 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3250 tuid = (uid_t)strtoul(str0, &endstr, 10);
3251 if ((endstr - str0) == len) {
3252 /* A numeric string. */
3253 if ((nd->nd_flag & ND_KERBV) == 0 &&
3254 ((nd->nd_flag & ND_NFSCL) != 0 ||
3255 nfsd_enable_stringtouid != 0))
3258 error = NFSERR_BADOWNER;
3264 cp = strchr(str0, '@');
3266 i = (int)(cp++ - str0);
3272 if (nfsrv_dnsnamelen > 0) {
3274 * If an '@' is found and the domain name matches, search for
3275 * the name with dns stripped off.
3276 * Mixed case alpahbetics will match for the domain name, but
3277 * all upper case will not.
3279 if (cnt == 0 && i < len && i > 0 &&
3280 (len - 1 - i) == nfsrv_dnsnamelen &&
3281 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3282 len -= (nfsrv_dnsnamelen + 1);
3287 * Check for the special case of "nobody".
3289 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3290 *uidp = nfsrv_defaultuid;
3295 hp = NFSUSERNAMEHASH(str, len);
3297 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3298 if (usrp->lug_namelen == len &&
3299 !NFSBCMP(usrp->lug_name, str, len)) {
3300 if (usrp->lug_expiry < NFSD_MONOSEC)
3302 hp2 = NFSUSERHASH(usrp->lug_uid);
3303 mtx_lock(&hp2->mtx);
3304 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3305 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3307 *uidp = usrp->lug_uid;
3308 mtx_unlock(&hp2->mtx);
3309 mtx_unlock(&hp->mtx);
3314 mtx_unlock(&hp->mtx);
3316 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3318 if (ret == 0 && cnt < 2)
3321 error = NFSERR_BADOWNER;
3329 * Convert a gid to a string.
3330 * gid - the group id
3331 * cpp - points to a buffer of size NFSV4_SMALLSTR
3332 * (malloc a larger one, as required)
3333 * retlenp - pointer to length to be returned
3336 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3339 struct nfsusrgrp *usrp;
3342 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3343 struct nfsrv_lughash *hp;
3347 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3349 * Always map nfsrv_defaultgid to "nogroup".
3351 if (gid == nfsrv_defaultgid) {
3352 i = nfsrv_dnsnamelen + 8;
3354 if (len > NFSV4_SMALLSTR)
3355 free(cp, M_NFSSTRING);
3356 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3362 NFSBCOPY("nogroup@", cp, 8);
3364 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3368 hp = NFSGROUPHASH(gid);
3370 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3371 if (usrp->lug_gid == gid) {
3372 if (usrp->lug_expiry < NFSD_MONOSEC)
3375 * If the name doesn't already have an '@'
3376 * in it, append @domainname to it.
3378 for (i = 0; i < usrp->lug_namelen; i++) {
3379 if (usrp->lug_name[i] == '@') {
3385 i = usrp->lug_namelen;
3387 i = usrp->lug_namelen +
3388 nfsrv_dnsnamelen + 1;
3390 mtx_unlock(&hp->mtx);
3391 if (len > NFSV4_SMALLSTR)
3392 free(cp, M_NFSSTRING);
3393 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3399 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3400 if (!hasampersand) {
3401 cp += usrp->lug_namelen;
3403 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3405 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3406 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3408 mtx_unlock(&hp->mtx);
3412 mtx_unlock(&hp->mtx);
3414 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3415 if (ret == 0 && cnt < 2)
3420 * No match, just return a string of digits.
3424 while (tmp || i == 0) {
3428 len = (i > len) ? len : i;
3432 for (i = 0; i < len; i++) {
3433 *cp-- = '0' + (tmp % 10);
3440 * Convert a string to a gid.
3441 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3443 * If this is called from a client side mount using AUTH_SYS and the
3444 * string is made up entirely of digits, just convert the string to
3448 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3451 char *cp, *endstr, *str0;
3452 struct nfsusrgrp *usrp;
3456 struct nfsrv_lughash *hp, *hp2;
3459 error = NFSERR_BADOWNER;
3462 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3464 tgid = (gid_t)strtoul(str0, &endstr, 10);
3465 if ((endstr - str0) == len) {
3466 /* A numeric string. */
3467 if ((nd->nd_flag & ND_KERBV) == 0 &&
3468 ((nd->nd_flag & ND_NFSCL) != 0 ||
3469 nfsd_enable_stringtouid != 0))
3472 error = NFSERR_BADOWNER;
3478 cp = strchr(str0, '@');
3480 i = (int)(cp++ - str0);
3486 if (nfsrv_dnsnamelen > 0) {
3488 * If an '@' is found and the dns name matches, search for the
3489 * name with the dns stripped off.
3491 if (cnt == 0 && i < len && i > 0 &&
3492 (len - 1 - i) == nfsrv_dnsnamelen &&
3493 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3494 len -= (nfsrv_dnsnamelen + 1);
3499 * Check for the special case of "nogroup".
3501 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3502 *gidp = nfsrv_defaultgid;
3507 hp = NFSGROUPNAMEHASH(str, len);
3509 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3510 if (usrp->lug_namelen == len &&
3511 !NFSBCMP(usrp->lug_name, str, len)) {
3512 if (usrp->lug_expiry < NFSD_MONOSEC)
3514 hp2 = NFSGROUPHASH(usrp->lug_gid);
3515 mtx_lock(&hp2->mtx);
3516 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3517 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3519 *gidp = usrp->lug_gid;
3520 mtx_unlock(&hp2->mtx);
3521 mtx_unlock(&hp->mtx);
3526 mtx_unlock(&hp->mtx);
3528 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3530 if (ret == 0 && cnt < 2)
3533 error = NFSERR_BADOWNER;
3541 * Cmp len chars, allowing mixed case in the first argument to match lower
3542 * case in the second, but not if the first argument is all upper case.
3543 * Return 0 for a match, 1 otherwise.
3546 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3552 for (i = 0; i < len; i++) {
3553 if (*cp >= 'A' && *cp <= 'Z') {
3554 tmp = *cp++ + ('a' - 'A');
3557 if (tmp >= 'a' && tmp <= 'z')
3570 * Set the port for the nfsuserd.
3573 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3575 struct nfssockreq *rp;
3577 struct sockaddr_in *ad;
3580 struct sockaddr_in6 *ad6;
3581 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3586 if (nfsrv_nfsuserd != NOTRUNNING) {
3591 nfsrv_nfsuserd = STARTSTOP;
3593 * Set up the socket record and connect.
3594 * Set nr_client NULL before unlocking, just to ensure that no other
3595 * process/thread/core will use a bogus old value. This could only
3596 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3599 rp = &nfsrv_nfsuserdsock;
3600 rp->nr_client = NULL;
3602 rp->nr_sotype = SOCK_DGRAM;
3603 rp->nr_soproto = IPPROTO_UDP;
3604 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3606 rp->nr_prog = RPCPROG_NFSUSERD;
3608 switch (nargs->nuserd_family) {
3611 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3613 ad = (struct sockaddr_in *)rp->nr_nam;
3614 ad->sin_len = sizeof(struct sockaddr_in);
3615 ad->sin_family = AF_INET;
3616 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3617 ad->sin_port = nargs->nuserd_port;
3622 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3624 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3625 ad6->sin6_len = sizeof(struct sockaddr_in6);
3626 ad6->sin6_family = AF_INET6;
3627 ad6->sin6_addr = in6loopback;
3628 ad6->sin6_port = nargs->nuserd_port;
3634 rp->nr_vers = RPCNFSUSERD_VERS;
3636 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3639 nfsrv_nfsuserd = RUNNING;
3642 free(rp->nr_nam, M_SONAME);
3644 nfsrv_nfsuserd = NOTRUNNING;
3653 * Delete the nfsuserd port.
3656 nfsrv_nfsuserddelport(void)
3660 if (nfsrv_nfsuserd != RUNNING) {
3664 nfsrv_nfsuserd = STARTSTOP;
3665 /* Wait for all upcalls to complete. */
3666 while (nfsrv_userdupcalls > 0)
3667 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3670 newnfs_disconnect(&nfsrv_nfsuserdsock);
3671 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3673 nfsrv_nfsuserd = NOTRUNNING;
3678 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3680 * Returns 0 upon success, non-zero otherwise.
3683 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3686 struct nfsrv_descript *nd;
3688 struct nfsrv_descript nfsd;
3693 if (nfsrv_nfsuserd != RUNNING) {
3699 * Maintain a count of upcalls in progress, so that nfsrv_X()
3700 * can wait until no upcalls are in progress.
3702 nfsrv_userdupcalls++;
3704 KASSERT(nfsrv_userdupcalls > 0,
3705 ("nfsrv_getuser: non-positive upcalls"));
3707 cred = newnfs_getcred();
3708 nd->nd_flag = ND_GSSINITREPLY;
3711 nd->nd_procnum = procnum;
3712 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3713 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3714 if (procnum == RPCNFSUSERD_GETUID)
3715 *tl = txdr_unsigned(uid);
3717 *tl = txdr_unsigned(gid);
3720 (void) nfsm_strtom(nd, name, len);
3722 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3723 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3725 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3726 wakeup(&nfsrv_userdupcalls);
3730 m_freem(nd->nd_mrep);
3731 error = nd->nd_repstat;
3739 * This function is called from the nfssvc(2) system call, to update the
3740 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3743 nfssvc_idname(struct nfsd_idargs *nidp)
3745 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3746 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3747 int i, group_locked, groupname_locked, user_locked, username_locked;
3752 static int onethread = 0;
3753 static time_t lasttime = 0;
3755 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3759 if (nidp->nid_flag & NFSID_INITIALIZE) {
3760 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3761 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3763 free(cp, M_NFSSTRING);
3766 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3768 * Free up all the old stuff and reinitialize hash
3769 * lists. All mutexes for both lists must be locked,
3770 * with the user/group name ones before the uid/gid
3771 * ones, to avoid a LOR.
3773 for (i = 0; i < nfsrv_lughashsize; i++)
3774 mtx_lock(&nfsusernamehash[i].mtx);
3775 for (i = 0; i < nfsrv_lughashsize; i++)
3776 mtx_lock(&nfsuserhash[i].mtx);
3777 for (i = 0; i < nfsrv_lughashsize; i++)
3778 TAILQ_FOREACH_SAFE(usrp,
3779 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3780 nfsrv_removeuser(usrp, 1);
3781 for (i = 0; i < nfsrv_lughashsize; i++)
3782 mtx_unlock(&nfsuserhash[i].mtx);
3783 for (i = 0; i < nfsrv_lughashsize; i++)
3784 mtx_unlock(&nfsusernamehash[i].mtx);
3785 for (i = 0; i < nfsrv_lughashsize; i++)
3786 mtx_lock(&nfsgroupnamehash[i].mtx);
3787 for (i = 0; i < nfsrv_lughashsize; i++)
3788 mtx_lock(&nfsgrouphash[i].mtx);
3789 for (i = 0; i < nfsrv_lughashsize; i++)
3790 TAILQ_FOREACH_SAFE(usrp,
3791 &nfsgrouphash[i].lughead, lug_numhash,
3793 nfsrv_removeuser(usrp, 0);
3794 for (i = 0; i < nfsrv_lughashsize; i++)
3795 mtx_unlock(&nfsgrouphash[i].mtx);
3796 for (i = 0; i < nfsrv_lughashsize; i++)
3797 mtx_unlock(&nfsgroupnamehash[i].mtx);
3798 free(nfsrv_dnsname, M_NFSSTRING);
3799 nfsrv_dnsname = NULL;
3801 if (nfsuserhash == NULL) {
3802 /* Allocate the hash tables. */
3803 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3804 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3806 for (i = 0; i < nfsrv_lughashsize; i++)
3807 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3808 NULL, MTX_DEF | MTX_DUPOK);
3809 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3810 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3812 for (i = 0; i < nfsrv_lughashsize; i++)
3813 mtx_init(&nfsusernamehash[i].mtx,
3814 "nfsusrhash", NULL, MTX_DEF |
3816 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3817 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3819 for (i = 0; i < nfsrv_lughashsize; i++)
3820 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3821 NULL, MTX_DEF | MTX_DUPOK);
3822 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3823 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3825 for (i = 0; i < nfsrv_lughashsize; i++)
3826 mtx_init(&nfsgroupnamehash[i].mtx,
3827 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3829 /* (Re)initialize the list heads. */
3830 for (i = 0; i < nfsrv_lughashsize; i++)
3831 TAILQ_INIT(&nfsuserhash[i].lughead);
3832 for (i = 0; i < nfsrv_lughashsize; i++)
3833 TAILQ_INIT(&nfsusernamehash[i].lughead);
3834 for (i = 0; i < nfsrv_lughashsize; i++)
3835 TAILQ_INIT(&nfsgrouphash[i].lughead);
3836 for (i = 0; i < nfsrv_lughashsize; i++)
3837 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3840 * Put name in "DNS" string.
3843 nfsrv_defaultuid = nidp->nid_uid;
3844 nfsrv_defaultgid = nidp->nid_gid;
3846 nfsrv_usermax = nidp->nid_usermax;
3847 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3852 * malloc the new one now, so any potential sleep occurs before
3853 * manipulation of the lists.
3855 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3856 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3857 error = copyin(nidp->nid_name, newusrp->lug_name,
3859 if (error == 0 && nidp->nid_ngroup > 0 &&
3860 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3861 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3863 error = copyin(nidp->nid_grps, grps,
3864 sizeof(gid_t) * nidp->nid_ngroup);
3867 * Create a credential just like svc_getcred(),
3868 * but using the group list provided.
3871 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3872 crsetgroups(cr, nidp->nid_ngroup, grps);
3873 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3874 cr->cr_prison = &prison0;
3875 prison_hold(cr->cr_prison);
3877 mac_cred_associate_nfsd(cr);
3879 newusrp->lug_cred = cr;
3884 free(newusrp, M_NFSUSERGROUP);
3887 newusrp->lug_namelen = nidp->nid_namelen;
3890 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3891 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3892 * The flags user_locked, username_locked, group_locked and
3893 * groupname_locked are set to indicate all of those hash lists are
3894 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3895 * the respective one mutex is locked.
3897 user_locked = username_locked = group_locked = groupname_locked = 0;
3898 hp_name = hp_idnum = NULL;
3901 * Delete old entries, as required.
3903 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3904 /* Must lock all username hash lists first, to avoid a LOR. */
3905 for (i = 0; i < nfsrv_lughashsize; i++)
3906 mtx_lock(&nfsusernamehash[i].mtx);
3907 username_locked = 1;
3908 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3909 mtx_lock(&hp_idnum->mtx);
3910 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3912 if (usrp->lug_uid == nidp->nid_uid)
3913 nfsrv_removeuser(usrp, 1);
3915 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3916 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3917 newusrp->lug_namelen);
3918 mtx_lock(&hp_name->mtx);
3919 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3921 if (usrp->lug_namelen == newusrp->lug_namelen &&
3922 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3923 usrp->lug_namelen)) {
3924 thp = NFSUSERHASH(usrp->lug_uid);
3925 mtx_lock(&thp->mtx);
3926 nfsrv_removeuser(usrp, 1);
3927 mtx_unlock(&thp->mtx);
3930 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3931 mtx_lock(&hp_idnum->mtx);
3932 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3933 /* Must lock all groupname hash lists first, to avoid a LOR. */
3934 for (i = 0; i < nfsrv_lughashsize; i++)
3935 mtx_lock(&nfsgroupnamehash[i].mtx);
3936 groupname_locked = 1;
3937 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3938 mtx_lock(&hp_idnum->mtx);
3939 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3941 if (usrp->lug_gid == nidp->nid_gid)
3942 nfsrv_removeuser(usrp, 0);
3944 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3945 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3946 newusrp->lug_namelen);
3947 mtx_lock(&hp_name->mtx);
3948 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3950 if (usrp->lug_namelen == newusrp->lug_namelen &&
3951 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3952 usrp->lug_namelen)) {
3953 thp = NFSGROUPHASH(usrp->lug_gid);
3954 mtx_lock(&thp->mtx);
3955 nfsrv_removeuser(usrp, 0);
3956 mtx_unlock(&thp->mtx);
3959 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3960 mtx_lock(&hp_idnum->mtx);
3964 * Now, we can add the new one.
3966 if (nidp->nid_usertimeout)
3967 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3969 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3970 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3971 newusrp->lug_uid = nidp->nid_uid;
3972 thp = NFSUSERHASH(newusrp->lug_uid);
3973 mtx_assert(&thp->mtx, MA_OWNED);
3974 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3975 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3976 mtx_assert(&thp->mtx, MA_OWNED);
3977 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3978 atomic_add_int(&nfsrv_usercnt, 1);
3979 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3980 newusrp->lug_gid = nidp->nid_gid;
3981 thp = NFSGROUPHASH(newusrp->lug_gid);
3982 mtx_assert(&thp->mtx, MA_OWNED);
3983 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3984 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3985 mtx_assert(&thp->mtx, MA_OWNED);
3986 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3987 atomic_add_int(&nfsrv_usercnt, 1);
3989 if (newusrp->lug_cred != NULL)
3990 crfree(newusrp->lug_cred);
3991 free(newusrp, M_NFSUSERGROUP);
3995 * Once per second, allow one thread to trim the cache.
3997 if (lasttime < NFSD_MONOSEC &&
3998 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4000 * First, unlock the single mutexes, so that all entries
4001 * can be locked and any LOR is avoided.
4003 if (hp_name != NULL) {
4004 mtx_unlock(&hp_name->mtx);
4007 if (hp_idnum != NULL) {
4008 mtx_unlock(&hp_idnum->mtx);
4012 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4013 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4014 if (username_locked == 0) {
4015 for (i = 0; i < nfsrv_lughashsize; i++)
4016 mtx_lock(&nfsusernamehash[i].mtx);
4017 username_locked = 1;
4019 KASSERT(user_locked == 0,
4020 ("nfssvc_idname: user_locked"));
4021 for (i = 0; i < nfsrv_lughashsize; i++)
4022 mtx_lock(&nfsuserhash[i].mtx);
4024 for (i = 0; i < nfsrv_lughashsize; i++) {
4025 TAILQ_FOREACH_SAFE(usrp,
4026 &nfsuserhash[i].lughead, lug_numhash,
4028 if (usrp->lug_expiry < NFSD_MONOSEC)
4029 nfsrv_removeuser(usrp, 1);
4031 for (i = 0; i < nfsrv_lughashsize; i++) {
4033 * Trim the cache using an approximate LRU
4034 * algorithm. This code deletes the least
4035 * recently used entry on each hash list.
4037 if (nfsrv_usercnt <= nfsrv_usermax)
4039 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4041 nfsrv_removeuser(usrp, 1);
4044 if (groupname_locked == 0) {
4045 for (i = 0; i < nfsrv_lughashsize; i++)
4046 mtx_lock(&nfsgroupnamehash[i].mtx);
4047 groupname_locked = 1;
4049 KASSERT(group_locked == 0,
4050 ("nfssvc_idname: group_locked"));
4051 for (i = 0; i < nfsrv_lughashsize; i++)
4052 mtx_lock(&nfsgrouphash[i].mtx);
4054 for (i = 0; i < nfsrv_lughashsize; i++) {
4055 TAILQ_FOREACH_SAFE(usrp,
4056 &nfsgrouphash[i].lughead, lug_numhash,
4058 if (usrp->lug_expiry < NFSD_MONOSEC)
4059 nfsrv_removeuser(usrp, 0);
4061 for (i = 0; i < nfsrv_lughashsize; i++) {
4063 * Trim the cache using an approximate LRU
4064 * algorithm. This code deletes the least
4065 * recently user entry on each hash list.
4067 if (nfsrv_usercnt <= nfsrv_usermax)
4069 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4071 nfsrv_removeuser(usrp, 0);
4074 lasttime = NFSD_MONOSEC;
4075 atomic_store_rel_int(&onethread, 0);
4078 /* Now, unlock all locked mutexes. */
4079 if (hp_idnum != NULL)
4080 mtx_unlock(&hp_idnum->mtx);
4081 if (hp_name != NULL)
4082 mtx_unlock(&hp_name->mtx);
4083 if (user_locked != 0)
4084 for (i = 0; i < nfsrv_lughashsize; i++)
4085 mtx_unlock(&nfsuserhash[i].mtx);
4086 if (username_locked != 0)
4087 for (i = 0; i < nfsrv_lughashsize; i++)
4088 mtx_unlock(&nfsusernamehash[i].mtx);
4089 if (group_locked != 0)
4090 for (i = 0; i < nfsrv_lughashsize; i++)
4091 mtx_unlock(&nfsgrouphash[i].mtx);
4092 if (groupname_locked != 0)
4093 for (i = 0; i < nfsrv_lughashsize; i++)
4094 mtx_unlock(&nfsgroupnamehash[i].mtx);
4101 * Remove a user/group name element.
4104 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4106 struct nfsrv_lughash *hp;
4109 hp = NFSUSERHASH(usrp->lug_uid);
4110 mtx_assert(&hp->mtx, MA_OWNED);
4111 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4112 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4113 mtx_assert(&hp->mtx, MA_OWNED);
4114 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4116 hp = NFSGROUPHASH(usrp->lug_gid);
4117 mtx_assert(&hp->mtx, MA_OWNED);
4118 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4119 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4120 mtx_assert(&hp->mtx, MA_OWNED);
4121 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4123 atomic_add_int(&nfsrv_usercnt, -1);
4124 if (usrp->lug_cred != NULL)
4125 crfree(usrp->lug_cred);
4126 free(usrp, M_NFSUSERGROUP);
4130 * Free up all the allocations related to the name<-->id cache.
4131 * This function should only be called when the nfsuserd daemon isn't
4132 * running, since it doesn't do any locking.
4133 * This function is meant to be used when the nfscommon module is unloaded.
4136 nfsrv_cleanusergroup(void)
4138 struct nfsrv_lughash *hp, *hp2;
4139 struct nfsusrgrp *nusrp, *usrp;
4142 if (nfsuserhash == NULL)
4145 for (i = 0; i < nfsrv_lughashsize; i++) {
4146 hp = &nfsuserhash[i];
4147 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4148 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4149 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4151 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4152 if (usrp->lug_cred != NULL)
4153 crfree(usrp->lug_cred);
4154 free(usrp, M_NFSUSERGROUP);
4156 hp = &nfsgrouphash[i];
4157 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4158 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4159 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4161 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4162 if (usrp->lug_cred != NULL)
4163 crfree(usrp->lug_cred);
4164 free(usrp, M_NFSUSERGROUP);
4166 mtx_destroy(&nfsuserhash[i].mtx);
4167 mtx_destroy(&nfsusernamehash[i].mtx);
4168 mtx_destroy(&nfsgroupnamehash[i].mtx);
4169 mtx_destroy(&nfsgrouphash[i].mtx);
4171 free(nfsuserhash, M_NFSUSERGROUP);
4172 free(nfsusernamehash, M_NFSUSERGROUP);
4173 free(nfsgrouphash, M_NFSUSERGROUP);
4174 free(nfsgroupnamehash, M_NFSUSERGROUP);
4175 free(nfsrv_dnsname, M_NFSSTRING);
4179 * This function scans a byte string and checks for UTF-8 compliance.
4180 * It returns 0 if it conforms and NFSERR_INVAL if not.
4183 nfsrv_checkutf8(u_int8_t *cp, int len)
4185 u_int32_t val = 0x0;
4186 int cnt = 0, gotd = 0, shift = 0;
4188 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4192 * Here are what the variables are used for:
4193 * val - the calculated value of a multibyte char, used to check
4194 * that it was coded with the correct range
4195 * cnt - the number of 10xxxxxx bytes to follow
4196 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4197 * shift - lower order bits of range (ie. "val >> shift" should
4198 * not be 0, in other words, dividing by the lower bound
4199 * of the range should get a non-zero value)
4200 * byte - used to calculate cnt
4204 /* This handles the 10xxxxxx bytes */
4205 if ((*cp & 0xc0) != 0x80 ||
4206 (gotd && (*cp & 0x20))) {
4207 error = NFSERR_INVAL;
4212 val |= (*cp & 0x3f);
4214 if (cnt == 0 && (val >> shift) == 0x0) {
4215 error = NFSERR_INVAL;
4218 } else if (*cp & 0x80) {
4219 /* first byte of multi byte char */
4221 while ((byte & 0x40) && cnt < 6) {
4225 if (cnt == 0 || cnt == 6) {
4226 error = NFSERR_INVAL;
4229 val = (*cp & (0x3f >> cnt));
4230 shift = utf8_shift[cnt - 1];
4231 if (cnt == 2 && val == 0xd)
4232 /* Check for the 0xd800-0xdfff case */
4239 error = NFSERR_INVAL;
4247 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4248 * strings, one with the root path in it and the other with the list of
4249 * locations. The list is in the same format as is found in nfr_refs.
4250 * It is a "," separated list of entries, where each of them is of the
4251 * form <server>:<rootpath>. For example
4252 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4253 * The nilp argument is set to 1 for the special case of a null fs_root
4254 * and an empty server list.
4255 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4256 * number of xdr bytes parsed in sump.
4259 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4260 int *sump, int *nilp)
4263 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4264 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4266 SLIST_ENTRY(list) next;
4270 SLIST_HEAD(, list) head;
4277 * Get the fs_root path and check for the special case of null path
4278 * and 0 length server list.
4280 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4281 len = fxdr_unsigned(int, *tl);
4282 if (len < 0 || len > 10240) {
4283 error = NFSERR_BADXDR;
4287 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4289 error = NFSERR_BADXDR;
4293 *sump = 2 * NFSX_UNSIGNED;
4297 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4298 error = nfsrv_mtostr(nd, cp, len);
4300 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4301 cnt = fxdr_unsigned(int, *tl);
4303 error = NFSERR_BADXDR;
4309 * Now, loop through the location list and make up the srvlist.
4311 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4312 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4315 for (i = 0; i < cnt; i++) {
4317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4318 nsrv = fxdr_unsigned(int, *tl);
4320 error = NFSERR_BADXDR;
4325 * Handle the first server by putting it in the srvstr.
4327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4328 len = fxdr_unsigned(int, *tl);
4329 if (len <= 0 || len > 1024) {
4330 error = NFSERR_BADXDR;
4333 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4338 error = nfsrv_mtostr(nd, cp3, len);
4344 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4345 for (j = 1; j < nsrv; j++) {
4347 * Yuck, put them in an slist and process them later.
4349 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4350 len = fxdr_unsigned(int, *tl);
4351 if (len <= 0 || len > 1024) {
4352 error = NFSERR_BADXDR;
4355 lsp = (struct list *)malloc(sizeof (struct list)
4356 + len, M_TEMP, M_WAITOK);
4357 error = nfsrv_mtostr(nd, lsp->host, len);
4360 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4362 SLIST_INSERT_HEAD(&head, lsp, next);
4366 * Finally, we can get the path.
4368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4369 len = fxdr_unsigned(int, *tl);
4370 if (len <= 0 || len > 1024) {
4371 error = NFSERR_BADXDR;
4374 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4375 error = nfsrv_mtostr(nd, cp3, len);
4378 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4383 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4384 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4387 NFSBCOPY(lsp->host, cp3, lsp->len);
4390 NFSBCOPY(str, cp3, stringlen);
4393 siz += (lsp->len + stringlen + 2);
4400 NFSEXITCODE2(0, nd);
4404 free(cp, M_NFSSTRING);
4406 free(cp2, M_NFSSTRING);
4407 NFSEXITCODE2(error, nd);
4412 * Make the malloc'd space large enough. This is a pain, but the xdr
4413 * doesn't set an upper bound on the side, so...
4416 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4423 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4424 NFSBCOPY(*cpp, cp, *slenp);
4425 free(*cpp, M_NFSSTRING);
4429 *slenp = siz + 1024;
4433 * Initialize the reply header data structures.
4436 nfsrvd_rephead(struct nfsrv_descript *nd)
4441 * If this is a big reply, use a cluster.
4443 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4444 nfs_bigreply[nd->nd_procnum]) {
4445 NFSMCLGET(mreq, M_WAITOK);
4453 nd->nd_bpos = mtod(mreq, caddr_t);
4456 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4457 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4461 * Lock a socket against others.
4462 * Currently used to serialize connect/disconnect attempts.
4465 newnfs_sndlock(int *flagp)
4470 while (*flagp & NFSR_SNDLOCK) {
4471 *flagp |= NFSR_WANTSND;
4474 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4475 PZERO - 1, "nfsndlck", &ts);
4477 *flagp |= NFSR_SNDLOCK;
4483 * Unlock the stream socket for others.
4486 newnfs_sndunlock(int *flagp)
4490 if ((*flagp & NFSR_SNDLOCK) == 0)
4491 panic("nfs sndunlock");
4492 *flagp &= ~NFSR_SNDLOCK;
4493 if (*flagp & NFSR_WANTSND) {
4494 *flagp &= ~NFSR_WANTSND;
4495 wakeup((caddr_t)flagp);
4501 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4502 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4504 struct in_addr saddr;
4505 uint32_t portnum, *tl;
4507 sa_family_t af = AF_UNSPEC;
4508 char addr[64], protocol[5], *cp;
4509 int cantparse = 0, error = 0;
4512 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4513 i = fxdr_unsigned(int, *tl);
4514 if (i >= 3 && i <= 4) {
4515 error = nfsrv_mtostr(nd, protocol, i);
4518 if (strcmp(protocol, "tcp") == 0) {
4521 } else if (strcmp(protocol, "udp") == 0) {
4524 } else if (strcmp(protocol, "tcp6") == 0) {
4527 } else if (strcmp(protocol, "udp6") == 0) {
4535 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4540 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4541 i = fxdr_unsigned(int, *tl);
4543 error = NFSERR_BADXDR;
4545 } else if (cantparse == 0 && i >= 11 && i < 64) {
4547 * The shortest address is 11chars and the longest is < 64.
4549 error = nfsrv_mtostr(nd, addr, i);
4553 /* Find the port# at the end and extract that. */
4557 /* Count back two '.'s from end to get port# field. */
4558 for (j = 0; j < i; j++) {
4568 * The NFSv4 port# is appended as .N.N, where N is
4569 * a decimal # in the range 0-255, just like an inet4
4570 * address. Cheat and use inet_aton(), which will
4571 * return a Class A address and then shift the high
4572 * order 8bits over to convert it to the port#.
4575 if (inet_aton(cp, &saddr) == 1) {
4576 portnum = ntohl(saddr.s_addr);
4577 portv = (uint16_t)((portnum >> 16) |
4583 if (cantparse == 0) {
4584 if (af == AF_INET) {
4585 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4586 sin->sin_len = sizeof(*sin);
4587 sin->sin_family = AF_INET;
4588 sin->sin_port = htons(portv);
4593 if (inet_pton(af, addr, &sin6->sin6_addr)
4595 sin6->sin6_len = sizeof(*sin6);
4596 sin6->sin6_family = AF_INET6;
4597 sin6->sin6_port = htons(portv);
4605 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4616 * Handle an NFSv4.1 Sequence request for the session.
4617 * If reply != NULL, use it to return the cached reply, as required.
4618 * The client gets a cached reply via this call for callbacks, however the
4619 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4622 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4623 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4630 if (slotid > maxslot)
4631 return (NFSERR_BADSLOT);
4632 if (seqid == slots[slotid].nfssl_seq) {
4634 if (slots[slotid].nfssl_inprog != 0)
4635 error = NFSERR_DELAY;
4636 else if (slots[slotid].nfssl_reply != NULL) {
4637 if (reply != NULL) {
4638 *reply = slots[slotid].nfssl_reply;
4639 slots[slotid].nfssl_reply = NULL;
4641 slots[slotid].nfssl_inprog = 1;
4642 error = NFSERR_REPLYFROMCACHE;
4644 /* No reply cached, so just do it. */
4645 slots[slotid].nfssl_inprog = 1;
4646 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4647 if (slots[slotid].nfssl_reply != NULL)
4648 m_freem(slots[slotid].nfssl_reply);
4649 slots[slotid].nfssl_reply = NULL;
4650 slots[slotid].nfssl_inprog = 1;
4651 slots[slotid].nfssl_seq++;
4653 error = NFSERR_SEQMISORDERED;
4658 * Cache this reply for the slot.
4659 * Use the "rep" argument to return the cached reply if repstat is set to
4660 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4663 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4667 if (repstat == NFSERR_REPLYFROMCACHE) {
4668 *rep = slots[slotid].nfssl_reply;
4669 slots[slotid].nfssl_reply = NULL;
4671 if (slots[slotid].nfssl_reply != NULL)
4672 m_freem(slots[slotid].nfssl_reply);
4673 slots[slotid].nfssl_reply = *rep;
4675 slots[slotid].nfssl_inprog = 0;
4679 * Generate the xdr for an NFSv4.1 Sequence Operation.
4682 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4683 struct nfsclsession *sep, int dont_replycache)
4685 uint32_t *tl, slotseq = 0;
4686 int error, maxslot, slotpos;
4687 uint8_t sessionid[NFSX_V4SESSIONID];
4689 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4691 nd->nd_maxreq = sep->nfsess_maxreq;
4692 nd->nd_maxresp = sep->nfsess_maxresp;
4694 /* Build the Sequence arguments. */
4695 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4696 nd->nd_sequence = tl;
4697 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4698 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4699 nd->nd_slotseq = tl;
4701 nd->nd_flag |= ND_HASSLOTID;
4702 nd->nd_slotid = slotpos;
4703 *tl++ = txdr_unsigned(slotseq);
4704 *tl++ = txdr_unsigned(slotpos);
4705 *tl++ = txdr_unsigned(maxslot);
4706 if (dont_replycache == 0)
4712 * There are two errors and the rest of the session can
4714 * NFSERR_BADSESSION: This bad session should just generate
4715 * the same error again when the RPC is retried.
4716 * ESTALE: A forced dismount is in progress and will cause the
4717 * RPC to fail later.
4724 nd->nd_flag |= ND_HASSEQUENCE;
4728 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4729 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4731 int i, maxslot, slotpos;
4734 /* Find an unused slot. */
4737 mtx_lock(&sep->nfsess_mtx);
4739 if (nmp != NULL && sep->nfsess_defunct != 0) {
4740 /* Just return the bad session. */
4741 bcopy(sep->nfsess_sessionid, sessionid,
4743 mtx_unlock(&sep->nfsess_mtx);
4744 return (NFSERR_BADSESSION);
4747 for (i = 0; i < sep->nfsess_foreslots; i++) {
4748 if ((bitval & sep->nfsess_slots) == 0) {
4750 sep->nfsess_slots |= bitval;
4751 sep->nfsess_slotseq[i]++;
4752 *slotseqp = sep->nfsess_slotseq[i];
4757 if (slotpos == -1) {
4759 * If a forced dismount is in progress, just return.
4760 * This RPC attempt will fail when it calls
4763 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4764 mtx_unlock(&sep->nfsess_mtx);
4767 /* Wake up once/sec, to check for a forced dismount. */
4768 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4769 PZERO, "nfsclseq", hz);
4771 } while (slotpos == -1);
4772 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4774 for (i = 0; i < 64; i++) {
4775 if ((bitval & sep->nfsess_slots) != 0)
4779 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4780 mtx_unlock(&sep->nfsess_mtx);
4781 *slotposp = slotpos;
4782 *maxslotp = maxslot;
4787 * Free a session slot.
4790 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4797 mtx_lock(&sep->nfsess_mtx);
4798 if ((bitval & sep->nfsess_slots) == 0)
4799 printf("freeing free slot!!\n");
4800 sep->nfsess_slots &= ~bitval;
4801 wakeup(&sep->nfsess_slots);
4802 mtx_unlock(&sep->nfsess_mtx);
4806 * Search for a matching pnfsd DS, based on the nmp arg.
4807 * Return one if found, NULL otherwise.
4810 nfsv4_findmirror(struct nfsmount *nmp)
4812 struct nfsdevice *ds;
4814 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4816 * Search the DS server list for a match with nmp.
4818 if (nfsrv_devidcnt == 0)
4820 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4821 if (ds->nfsdev_nmp == nmp) {
4822 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4830 * Fill in the fields of "struct nfsrv_descript" for a new ext_pgs mbuf.
4831 * The build argument is true for build and false for dissect.
4834 nfsm_set(struct nfsrv_descript *nd, u_int offs, bool build)
4844 nd->nd_bpos = mtod(m, char *) + offs;
4845 rlen = m->m_len - offs;
4847 nd->nd_dpos = mtod(m, char *);
4854 * Copy up to "len" bytes from the mbuf into "cp" and adjust the
4856 * If cp == NULL, do not do the actual copy, but adjust the mbuf.
4857 * Return the number of bytes actually copied.
4858 * Adjust m_data and m_len so that a future calculation of what
4859 * is left using mtod() will work correctly.
4862 nfsm_copyfrommbuf(struct nfsrv_descript *nd, char *cp, enum uio_seg segflg,
4869 xfer = mtod(m, char *) + m->m_len - nd->nd_dpos;
4870 xfer = min(xfer, len);
4873 if (segflg == UIO_SYSSPACE)
4874 memcpy(cp, nd->nd_dpos, xfer);
4876 copyout(nd->nd_dpos, cp, xfer);
4878 nd->nd_dpos += xfer;
4886 * Shift to the next mbuf in the list list and update the nd fields.
4887 * Return true if successful, false otherwise.
4890 nfsm_shiftnext(struct nfsrv_descript *nd, int *leftp)
4893 nd->nd_md = nd->nd_md->m_next;
4894 if (nd->nd_md == NULL)
4896 *leftp = nfsm_set(nd, 0, false);