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.
45 #include "opt_inet6.h"
47 #include <fs/nfs/nfsport.h>
49 #include <sys/extattr.h>
51 #include <security/mac/mac_framework.h>
54 * Data items converted to xdr at startup, since they are constant
55 * This is kinda hokey, but may save a little time doing byte swaps
57 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
59 /* And other global data */
60 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
62 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
63 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
64 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
67 struct nfssockreq nfsrv_nfsuserdsock;
68 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
69 static int nfsrv_userdupcalls = 0;
70 struct nfsreqhead nfsd_reqq;
71 uid_t nfsrv_defaultuid = UID_NOBODY;
72 gid_t nfsrv_defaultgid = GID_NOGROUP;
73 int nfsrv_lease = NFSRV_LEASE;
74 int ncl_mbuf_mlen = MLEN;
75 int nfsd_enable_stringtouid = 0;
76 int nfsrv_doflexfile = 0;
77 static int nfs_enable_uidtostring = 0;
80 extern int nfsrv_lughashsize;
81 extern struct mtx nfsrv_dslock_mtx;
82 extern volatile int nfsrv_devidcnt;
83 extern int nfscl_debuglevel;
84 extern struct nfsdevicehead nfsrv_devidhead;
85 extern struct nfsstatsv1 nfsstatsv1;
87 SYSCTL_DECL(_vfs_nfs);
88 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
89 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
91 int nfsrv_maxpnfsmirror = 1;
92 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
93 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
95 int nfs_maxcopyrange = 10 * 1024 * 1024;
96 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
97 &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
100 * This array of structures indicates, for V4:
101 * retfh - which of 3 types of calling args are used
102 * 0 - doesn't change cfh or use a sfh
103 * 1 - replaces cfh with a new one (unless it returns an error status)
104 * 2 - uses cfh and sfh
105 * needscfh - if the op wants a cfh and premtime
106 * 0 - doesn't use a cfh
107 * 1 - uses a cfh, but doesn't want pre-op attributes
108 * 2 - uses a cfh and wants pre-op attributes
109 * savereply - indicates a non-idempotent Op
110 * 0 - not non-idempotent
112 * Ops that are ordered via seqid# are handled separately from these
113 * non-idempotent Ops.
114 * Define it here, since it is used by both the client and server.
116 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
117 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
118 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
119 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
122 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
123 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
126 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
128 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
129 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
132 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
133 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
134 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
135 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
136 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
137 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
138 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
139 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
140 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
141 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
142 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
143 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
144 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
145 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
146 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
151 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
154 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
155 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
160 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
161 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
166 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
167 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
168 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
169 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
170 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
171 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
172 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
173 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
174 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
175 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
176 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
177 { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
178 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
179 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
180 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
181 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
182 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
183 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
184 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
185 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
186 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
187 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
188 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
189 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
190 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
191 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
192 { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
195 static int ncl_mbuf_mhlen = MHLEN;
196 static int nfsrv_usercnt = 0;
197 static int nfsrv_dnsnamelen;
198 static u_char *nfsrv_dnsname = NULL;
199 static int nfsrv_usermax = 999999999;
200 struct nfsrv_lughash {
202 struct nfsuserhashhead lughead;
204 static struct nfsrv_lughash *nfsuserhash;
205 static struct nfsrv_lughash *nfsusernamehash;
206 static struct nfsrv_lughash *nfsgrouphash;
207 static struct nfsrv_lughash *nfsgroupnamehash;
210 * This static array indicates whether or not the RPC generates a large
211 * reply. This is used by nfs_reply() to decide whether or not an mbuf
212 * cluster should be allocated. (If a cluster is required by an RPC
213 * marked 0 in this array, the code will still work, just not quite as
216 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
221 /* local functions */
222 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
223 static void nfsv4_wanted(struct nfsv4lock *lp);
224 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
225 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
226 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
227 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
229 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
236 } nfsv4_opmap[NFSV42_NPROCS] = {
238 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
239 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
240 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
241 { NFSV4OP_ACCESS, 2, "Access", 6, },
242 { NFSV4OP_READLINK, 2, "Readlink", 8, },
243 { NFSV4OP_READ, 1, "Read", 4, },
244 { NFSV4OP_WRITE, 2, "Write", 5, },
245 { NFSV4OP_OPEN, 5, "Open", 4, },
246 { NFSV4OP_CREATE, 5, "Create", 6, },
247 { NFSV4OP_CREATE, 1, "Create", 6, },
248 { NFSV4OP_CREATE, 3, "Create", 6, },
249 { NFSV4OP_REMOVE, 1, "Remove", 6, },
250 { NFSV4OP_REMOVE, 1, "Remove", 6, },
251 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
252 { NFSV4OP_SAVEFH, 4, "Link", 4, },
253 { NFSV4OP_READDIR, 2, "Readdir", 7, },
254 { NFSV4OP_READDIR, 2, "Readdir", 7, },
255 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
256 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
257 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
258 { NFSV4OP_COMMIT, 2, "Commit", 6, },
259 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
260 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
261 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
262 { NFSV4OP_LOCK, 1, "Lock", 4, },
263 { NFSV4OP_LOCKU, 1, "LockU", 5, },
264 { NFSV4OP_OPEN, 2, "Open", 4, },
265 { NFSV4OP_CLOSE, 1, "Close", 5, },
266 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
267 { NFSV4OP_LOCKT, 1, "LockT", 5, },
268 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
269 { NFSV4OP_RENEW, 1, "Renew", 5, },
270 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
271 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
272 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
273 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
274 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
275 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
276 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
277 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
278 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
279 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
280 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
281 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
282 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
283 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
284 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
285 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
286 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
287 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
288 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
289 { NFSV4OP_READ, 1, "ReadDS", 6, },
290 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
291 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
292 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
293 { NFSV4OP_IOADVISE, 1, "Advise", 6, },
294 { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
295 { NFSV4OP_SAVEFH, 5, "Copy", 4, },
296 { NFSV4OP_SEEK, 2, "Seek", 4, },
297 { NFSV4OP_SEEK, 1, "SeekDS", 6, },
298 { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
299 { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
300 { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
301 { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
305 * NFS RPCS that have large request message size.
307 static int nfs_bigrequest[NFSV42_NPROCS] = {
308 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
314 * Start building a request. Mostly just put the first file handle in
318 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
319 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
320 int vers, int minorvers)
325 nfsattrbit_t attrbits;
328 * First, fill in some of the fields of nd.
330 nd->nd_slotseq = NULL;
331 if (vers == NFS_VER4) {
332 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
333 if (minorvers == NFSV41_MINORVERSION)
334 nd->nd_flag |= ND_NFSV41;
335 else if (minorvers == NFSV42_MINORVERSION)
336 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
337 } else if (vers == NFS_VER3)
338 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
340 if (NFSHASNFSV4(nmp)) {
341 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
342 if (nmp->nm_minorvers == 1)
343 nd->nd_flag |= ND_NFSV41;
344 else if (nmp->nm_minorvers == 2)
345 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
346 } else if (NFSHASNFSV3(nmp))
347 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
349 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
351 nd->nd_procnum = procnum;
355 * Get the first mbuf for the request.
357 if (nfs_bigrequest[procnum])
358 NFSMCLGET(mb, M_WAITOK);
362 nd->nd_mreq = nd->nd_mb = mb;
363 nd->nd_bpos = mtod(mb, caddr_t);
366 * And fill the first file handle into the request.
368 if (nd->nd_flag & ND_NFSV4) {
369 opcnt = nfsv4_opmap[procnum].opcnt +
370 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
371 if ((nd->nd_flag & ND_NFSV41) != 0) {
372 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
373 if (procnum == NFSPROC_RENEW)
375 * For the special case of Renew, just do a
379 else if (procnum == NFSPROC_WRITEDS ||
380 procnum == NFSPROC_COMMITDS)
382 * For the special case of a Writeor Commit to
383 * a DS, the opcnt == 3, for Sequence, PutFH,
389 * What should the tag really be?
391 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
392 nfsv4_opmap[procnum].taglen);
393 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
394 if ((nd->nd_flag & ND_NFSV42) != 0)
395 *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
396 else if ((nd->nd_flag & ND_NFSV41) != 0)
397 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
399 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
402 *tl = txdr_unsigned(opcnt);
403 if ((nd->nd_flag & ND_NFSV41) != 0 &&
404 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
405 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
407 nd->nd_flag |= ND_LOOPBADSESS;
408 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
409 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
411 sep = nfsmnt_mdssession(nmp);
412 nfsv4_setsequence(nmp, nd, sep,
413 nfs_bigreply[procnum]);
415 nfsv4_setsequence(nmp, nd, sep,
416 nfs_bigreply[procnum]);
418 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
419 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
420 *tl = txdr_unsigned(NFSV4OP_PUTFH);
421 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
422 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
423 == 2 && procnum != NFSPROC_WRITEDS &&
424 procnum != NFSPROC_COMMITDS) {
425 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
426 *tl = txdr_unsigned(NFSV4OP_GETATTR);
428 * For Lookup Ops, we want all the directory
429 * attributes, so we can load the name cache.
431 if (procnum == NFSPROC_LOOKUP ||
432 procnum == NFSPROC_LOOKUPP)
433 NFSGETATTR_ATTRBIT(&attrbits);
435 NFSWCCATTR_ATTRBIT(&attrbits);
436 nd->nd_flag |= ND_V4WCCATTR;
438 (void) nfsrv_putattrbit(nd, &attrbits);
441 if (procnum != NFSPROC_RENEW ||
442 (nd->nd_flag & ND_NFSV41) == 0) {
443 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
444 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
447 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
449 if (procnum < NFSV42_NPROCS)
450 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
454 * Put a state Id in the mbuf list.
457 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
461 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
462 if (flag == NFSSTATEID_PUTALLZERO) {
467 } else if (flag == NFSSTATEID_PUTALLONE) {
468 st->seqid = 0xffffffff;
469 st->other[0] = 0xffffffff;
470 st->other[1] = 0xffffffff;
471 st->other[2] = 0xffffffff;
472 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
474 st->other[0] = stateidp->other[0];
475 st->other[1] = stateidp->other[1];
476 st->other[2] = stateidp->other[2];
478 st->seqid = stateidp->seqid;
479 st->other[0] = stateidp->other[0];
480 st->other[1] = stateidp->other[1];
481 st->other[2] = stateidp->other[2];
486 * Fill in the setable attributes. The full argument indicates whether
487 * to fill in them all or just mode and time.
490 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
491 struct vnode *vp, int flags, u_int32_t rdev)
494 struct nfsv2_sattr *sp;
495 nfsattrbit_t attrbits;
497 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
499 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
500 if (vap->va_mode == (mode_t)VNOVAL)
501 sp->sa_mode = newnfs_xdrneg1;
503 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
504 if (vap->va_uid == (uid_t)VNOVAL)
505 sp->sa_uid = newnfs_xdrneg1;
507 sp->sa_uid = txdr_unsigned(vap->va_uid);
508 if (vap->va_gid == (gid_t)VNOVAL)
509 sp->sa_gid = newnfs_xdrneg1;
511 sp->sa_gid = txdr_unsigned(vap->va_gid);
512 if (flags & NFSSATTR_SIZE0)
514 else if (flags & NFSSATTR_SIZENEG1)
515 sp->sa_size = newnfs_xdrneg1;
516 else if (flags & NFSSATTR_SIZERDEV)
517 sp->sa_size = txdr_unsigned(rdev);
519 sp->sa_size = txdr_unsigned(vap->va_size);
520 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
521 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
524 if (vap->va_mode != (mode_t)VNOVAL) {
525 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
527 *tl = txdr_unsigned(vap->va_mode);
529 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
532 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
533 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
535 *tl = txdr_unsigned(vap->va_uid);
537 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
540 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
541 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
543 *tl = txdr_unsigned(vap->va_gid);
545 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
548 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
549 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
551 txdr_hyper(vap->va_size, tl);
553 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
556 if (vap->va_atime.tv_sec != VNOVAL) {
557 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
558 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
559 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
560 txdr_nfsv3time(&vap->va_atime, tl);
562 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
563 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
566 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
567 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
569 if (vap->va_mtime.tv_sec != VNOVAL) {
570 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
571 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
572 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
573 txdr_nfsv3time(&vap->va_mtime, tl);
575 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
576 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
579 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
580 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
584 NFSZERO_ATTRBIT(&attrbits);
585 if (vap->va_mode != (mode_t)VNOVAL)
586 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
587 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
588 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
589 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
590 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
591 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
592 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
593 if (vap->va_atime.tv_sec != VNOVAL)
594 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
595 if (vap->va_mtime.tv_sec != VNOVAL)
596 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
597 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
598 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
605 * copies mbuf chain to the uio scatter/gather list
608 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
610 char *mbufcp, *uiocp;
617 mbufcp = nd->nd_dpos;
618 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
619 rem = NFSM_RNDUP(siz) - siz;
621 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
625 left = uiop->uio_iov->iov_len;
626 uiocp = uiop->uio_iov->iov_base;
637 mbufcp = mtod(mp, caddr_t);
640 ("len %d, corrupted mbuf?", len));
642 xfer = (left > len) ? len : left;
645 if (uiop->uio_iov->iov_op != NULL)
646 (*(uiop->uio_iov->iov_op))
647 (mbufcp, uiocp, xfer);
650 if (uiop->uio_segflg == UIO_SYSSPACE)
651 NFSBCOPY(mbufcp, uiocp, xfer);
653 copyout(mbufcp, uiocp, xfer);
658 uiop->uio_offset += xfer;
659 uiop->uio_resid -= xfer;
661 if (uiop->uio_iov->iov_len <= siz) {
665 uiop->uio_iov->iov_base = (void *)
666 ((char *)uiop->uio_iov->iov_base + uiosiz);
667 uiop->uio_iov->iov_len -= uiosiz;
671 nd->nd_dpos = mbufcp;
675 error = nfsm_advance(nd, rem, len);
681 NFSEXITCODE2(error, nd);
687 * Help break down an mbuf chain by setting the first siz bytes contiguous
688 * pointed to by returned val.
689 * This is used by the macro NFSM_DISSECT for tough
693 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
702 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
704 nd->nd_md = nd->nd_md->m_next;
705 if (nd->nd_md == NULL)
707 left = nd->nd_md->m_len;
708 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
713 } else if (nd->nd_md->m_next == NULL) {
715 } else if (siz > ncl_mbuf_mhlen) {
716 panic("nfs S too big");
718 MGET(mp2, MT_DATA, how);
721 mp2->m_next = nd->nd_md->m_next;
722 nd->nd_md->m_next = mp2;
723 nd->nd_md->m_len -= left;
725 retp = p = mtod(mp2, caddr_t);
726 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
730 /* Loop around copying up the siz2 bytes */
734 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
736 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
745 nd->nd_md->m_len = siz;
747 nd->nd_dpos = mtod(mp2, caddr_t);
753 * Advance the position in the mbuf chain.
754 * If offs == 0, this is a no-op, but it is simpler to just return from
755 * here than check for offs > 0 for all calls to nfsm_advance.
756 * If left == -1, it should be calculated here.
759 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
766 * A negative offs might indicate a corrupted mbuf chain and,
767 * as such, a printf is logged.
770 printf("nfsrv_advance: negative offs\n");
776 * If left == -1, calculate it here.
779 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
783 * Loop around, advancing over the mbuf data.
785 while (offs > left) {
787 nd->nd_md = nd->nd_md->m_next;
788 if (nd->nd_md == NULL) {
792 left = nd->nd_md->m_len;
793 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
803 * Copy a string into mbuf(s).
804 * Return the number of bytes output, including XDR overheads.
807 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
816 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
817 *tl = txdr_unsigned(siz);
818 rem = NFSM_RNDUP(siz) - siz;
819 bytesize = NFSX_UNSIGNED + siz + rem;
822 left = M_TRAILINGSPACE(m2);
825 * Loop around copying the string to mbuf(s).
829 if (siz > ncl_mbuf_mlen)
830 NFSMCLGET(m1, M_WAITOK);
836 cp2 = mtod(m2, caddr_t);
837 left = M_TRAILINGSPACE(m2);
843 NFSBCOPY(cp, cp2, xfer);
848 if (siz == 0 && rem) {
850 panic("nfsm_strtom");
851 NFSBZERO(cp2 + xfer, rem);
856 nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
861 * Called once to initialize data structures...
866 static int nfs_inited = 0;
872 newnfs_true = txdr_unsigned(TRUE);
873 newnfs_false = txdr_unsigned(FALSE);
874 newnfs_xdrneg1 = txdr_unsigned(-1);
875 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
878 NFSSETBOOTTIME(nfsboottime);
881 * Initialize reply list and start timer
883 TAILQ_INIT(&nfsd_reqq);
888 * Put a file handle in an mbuf list.
889 * If the size argument == 0, just use the default size.
890 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
891 * Return the number of bytes output, including XDR overhead.
894 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
898 int fullsiz, rem, bytesize = 0;
902 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
904 if (size > NFSX_V2FH)
905 panic("fh size > NFSX_V2FH for NFSv2");
906 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
907 NFSBCOPY(fhp, cp, size);
908 if (size < NFSX_V2FH)
909 NFSBZERO(cp + size, NFSX_V2FH - size);
910 bytesize = NFSX_V2FH;
914 fullsiz = NFSM_RNDUP(size);
915 rem = fullsiz - size;
917 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
918 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
921 bytesize = NFSX_UNSIGNED + fullsiz;
923 (void) nfsm_strtom(nd, fhp, size);
930 * This function compares two net addresses by family and returns TRUE
931 * if they are the same host.
932 * If there is any doubt, return FALSE.
933 * The AF_INET family is handled as a special case so that address mbufs
934 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
937 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
940 struct sockaddr_in *inetaddr;
946 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
947 if (inetaddr->sin_family == AF_INET &&
948 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
955 struct sockaddr_in6 *inetaddr6;
957 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
958 /* XXX - should test sin6_scope_id ? */
959 if (inetaddr6->sin6_family == AF_INET6 &&
960 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
971 * Similar to the above, but takes to NFSSOCKADDR_T args.
974 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
976 struct sockaddr_in *addr1, *addr2;
977 struct sockaddr *inaddr;
979 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
980 switch (inaddr->sa_family) {
982 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
983 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
984 if (addr2->sin_family == AF_INET &&
985 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
991 struct sockaddr_in6 *inet6addr1, *inet6addr2;
993 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
994 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
995 /* XXX - should test sin6_scope_id ? */
996 if (inet6addr2->sin6_family == AF_INET6 &&
997 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
998 &inet6addr2->sin6_addr))
1008 * Trim trailing data off the mbuf list being built.
1011 newnfs_trimtrailing(nd, mb, bpos)
1012 struct nfsrv_descript *nd;
1018 m_freem(mb->m_next);
1021 mb->m_len = bpos - mtod(mb, caddr_t);
1027 * Dissect a file handle on the client.
1030 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1037 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1038 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1039 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1046 nfhp = malloc(sizeof (struct nfsfh) + len,
1048 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1050 free(nfhp, M_NFSFH);
1053 nfhp->nfh_len = len;
1056 NFSEXITCODE2(error, nd);
1061 * Break down the nfsv4 acl.
1062 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1065 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1066 int *aclsizep, __unused NFSPROC_T *p)
1070 int acecnt, error = 0, aceerr = 0, acesize;
1076 * Parse out the ace entries and expect them to conform to
1077 * what can be supported by R/W/X bits.
1079 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1080 aclsize = NFSX_UNSIGNED;
1081 acecnt = fxdr_unsigned(int, *tl);
1082 if (acecnt > ACL_MAX_ENTRIES)
1083 aceerr = NFSERR_ATTRNOTSUPP;
1084 if (nfsrv_useacl == 0)
1085 aceerr = NFSERR_ATTRNOTSUPP;
1086 for (i = 0; i < acecnt; i++) {
1087 if (aclp && !aceerr)
1088 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1089 &aceerr, &acesize, p);
1091 error = nfsrv_skipace(nd, &acesize);
1096 if (aclp && !aceerr)
1097 aclp->acl_cnt = acecnt;
1101 *aclsizep = aclsize;
1103 NFSEXITCODE2(error, nd);
1108 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1111 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1116 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1117 len = fxdr_unsigned(int, *(tl + 3));
1118 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1120 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1121 NFSEXITCODE2(error, nd);
1126 * Get attribute bits from an mbuf list.
1127 * Returns EBADRPC for a parsing error, 0 otherwise.
1128 * If the clearinvalid flag is set, clear the bits not supported.
1131 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1138 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1139 cnt = fxdr_unsigned(int, *tl);
1141 error = NFSERR_BADXDR;
1144 if (cnt > NFSATTRBIT_MAXWORDS)
1145 outcnt = NFSATTRBIT_MAXWORDS;
1148 NFSZERO_ATTRBIT(attrbitp);
1150 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1151 for (i = 0; i < outcnt; i++)
1152 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1154 for (i = 0; i < (cnt - outcnt); i++) {
1155 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1156 if (retnotsupp != NULL && *tl != 0)
1157 *retnotsupp = NFSERR_ATTRNOTSUPP;
1160 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1162 NFSEXITCODE2(error, nd);
1167 * Get the attributes for V4.
1168 * If the compare flag is true, test for any attribute changes,
1169 * otherwise return the attribute values.
1170 * These attributes cover fields in "struct vattr", "struct statfs",
1171 * "struct nfsfsinfo", the file handle and the lease duration.
1172 * The value of retcmpp is set to 1 if all attributes are the same,
1174 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1177 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1178 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1179 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1180 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1181 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1184 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1185 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1186 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1187 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1188 struct nfsfh *tnfhp;
1189 struct nfsreferral *refp;
1192 struct timespec temptime;
1195 u_int32_t freenum = 0, tuint;
1196 u_int64_t uquad = 0, thyp, thyp2;
1202 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1205 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1207 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1213 *retcmpp = retnotsup;
1216 * Just set default values to some of the important ones.
1219 nap->na_type = VREG;
1221 nap->na_rdev = (NFSDEV_T)0;
1222 nap->na_mtime.tv_sec = 0;
1223 nap->na_mtime.tv_nsec = 0;
1226 nap->na_blocksize = NFS_FABLKSIZE;
1229 sbp->f_bsize = NFS_FABLKSIZE;
1237 fsp->fs_rtmax = 8192;
1238 fsp->fs_rtpref = 8192;
1239 fsp->fs_maxname = NFS_MAXNAMLEN;
1240 fsp->fs_wtmax = 8192;
1241 fsp->fs_wtpref = 8192;
1242 fsp->fs_wtmult = NFS_FABLKSIZE;
1243 fsp->fs_dtpref = 8192;
1244 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1245 fsp->fs_timedelta.tv_sec = 0;
1246 fsp->fs_timedelta.tv_nsec = 1;
1247 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1248 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1251 pc->pc_linkmax = NFS_LINK_MAX;
1252 pc->pc_namemax = NAME_MAX;
1254 pc->pc_chownrestricted = 0;
1255 pc->pc_caseinsensitive = 0;
1256 pc->pc_casepreserving = 1;
1259 sfp->sf_ffiles = UINT64_MAX;
1260 sfp->sf_tfiles = UINT64_MAX;
1261 sfp->sf_afiles = UINT64_MAX;
1262 sfp->sf_fbytes = UINT64_MAX;
1263 sfp->sf_tbytes = UINT64_MAX;
1264 sfp->sf_abytes = UINT64_MAX;
1269 * Loop around getting the attributes.
1271 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1272 attrsize = fxdr_unsigned(int, *tl);
1273 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1274 if (attrsum > attrsize) {
1275 error = NFSERR_BADXDR;
1278 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1280 case NFSATTRBIT_SUPPORTEDATTRS:
1282 if (compare || nap == NULL)
1283 error = nfsrv_getattrbits(nd, &retattrbits,
1286 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1290 if (compare && !(*retcmpp)) {
1291 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1293 /* Some filesystem do not support NFSv4ACL */
1294 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1295 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1296 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1298 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1300 *retcmpp = NFSERR_NOTSAME;
1304 case NFSATTRBIT_TYPE:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1308 if (nap->na_type != nfsv34tov_type(*tl))
1309 *retcmpp = NFSERR_NOTSAME;
1311 } else if (nap != NULL) {
1312 nap->na_type = nfsv34tov_type(*tl);
1314 attrsum += NFSX_UNSIGNED;
1316 case NFSATTRBIT_FHEXPIRETYPE:
1317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1318 if (compare && !(*retcmpp)) {
1319 if (fxdr_unsigned(int, *tl) !=
1320 NFSV4FHTYPE_PERSISTENT)
1321 *retcmpp = NFSERR_NOTSAME;
1323 attrsum += NFSX_UNSIGNED;
1325 case NFSATTRBIT_CHANGE:
1326 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1329 if (nap->na_filerev != fxdr_hyper(tl))
1330 *retcmpp = NFSERR_NOTSAME;
1332 } else if (nap != NULL) {
1333 nap->na_filerev = fxdr_hyper(tl);
1335 attrsum += NFSX_HYPER;
1337 case NFSATTRBIT_SIZE:
1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1341 if (nap->na_size != fxdr_hyper(tl))
1342 *retcmpp = NFSERR_NOTSAME;
1344 } else if (nap != NULL) {
1345 nap->na_size = fxdr_hyper(tl);
1347 attrsum += NFSX_HYPER;
1349 case NFSATTRBIT_LINKSUPPORT:
1350 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1353 if (fsp->fs_properties & NFSV3_FSFLINK) {
1354 if (*tl == newnfs_false)
1355 *retcmpp = NFSERR_NOTSAME;
1357 if (*tl == newnfs_true)
1358 *retcmpp = NFSERR_NOTSAME;
1361 } else if (fsp != NULL) {
1362 if (*tl == newnfs_true)
1363 fsp->fs_properties |= NFSV3_FSFLINK;
1365 fsp->fs_properties &= ~NFSV3_FSFLINK;
1367 attrsum += NFSX_UNSIGNED;
1369 case NFSATTRBIT_SYMLINKSUPPORT:
1370 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1374 if (*tl == newnfs_false)
1375 *retcmpp = NFSERR_NOTSAME;
1377 if (*tl == newnfs_true)
1378 *retcmpp = NFSERR_NOTSAME;
1381 } else if (fsp != NULL) {
1382 if (*tl == newnfs_true)
1383 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1385 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1387 attrsum += NFSX_UNSIGNED;
1389 case NFSATTRBIT_NAMEDATTR:
1390 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1391 if (compare && !(*retcmpp)) {
1392 if (*tl != newnfs_false)
1393 *retcmpp = NFSERR_NOTSAME;
1395 attrsum += NFSX_UNSIGNED;
1397 case NFSATTRBIT_FSID:
1398 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1399 thyp = fxdr_hyper(tl);
1401 thyp2 = fxdr_hyper(tl);
1403 if (*retcmpp == 0) {
1404 if (thyp != (u_int64_t)
1405 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1406 thyp2 != (u_int64_t)
1407 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1408 *retcmpp = NFSERR_NOTSAME;
1410 } else if (nap != NULL) {
1411 nap->na_filesid[0] = thyp;
1412 nap->na_filesid[1] = thyp2;
1414 attrsum += (4 * NFSX_UNSIGNED);
1416 case NFSATTRBIT_UNIQUEHANDLES:
1417 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1418 if (compare && !(*retcmpp)) {
1419 if (*tl != newnfs_true)
1420 *retcmpp = NFSERR_NOTSAME;
1422 attrsum += NFSX_UNSIGNED;
1424 case NFSATTRBIT_LEASETIME:
1425 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1427 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1429 *retcmpp = NFSERR_NOTSAME;
1430 } else if (leasep != NULL) {
1431 *leasep = fxdr_unsigned(u_int32_t, *tl);
1433 attrsum += NFSX_UNSIGNED;
1435 case NFSATTRBIT_RDATTRERROR:
1436 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1439 *retcmpp = NFSERR_INVAL;
1440 } else if (rderrp != NULL) {
1441 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1443 attrsum += NFSX_UNSIGNED;
1445 case NFSATTRBIT_ACL:
1448 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1451 naclp = acl_alloc(M_WAITOK);
1452 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1458 if (aceerr || aclp == NULL ||
1459 nfsrv_compareacl(aclp, naclp))
1460 *retcmpp = NFSERR_NOTSAME;
1463 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1465 *retcmpp = NFSERR_ATTRNOTSUPP;
1469 if (vp != NULL && aclp != NULL)
1470 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1473 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1481 case NFSATTRBIT_ACLSUPPORT:
1482 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1483 if (compare && !(*retcmpp)) {
1484 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1485 if (fxdr_unsigned(u_int32_t, *tl) !=
1487 *retcmpp = NFSERR_NOTSAME;
1489 *retcmpp = NFSERR_ATTRNOTSUPP;
1492 attrsum += NFSX_UNSIGNED;
1494 case NFSATTRBIT_ARCHIVE:
1495 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1496 if (compare && !(*retcmpp))
1497 *retcmpp = NFSERR_ATTRNOTSUPP;
1498 attrsum += NFSX_UNSIGNED;
1500 case NFSATTRBIT_CANSETTIME:
1501 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1504 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1505 if (*tl == newnfs_false)
1506 *retcmpp = NFSERR_NOTSAME;
1508 if (*tl == newnfs_true)
1509 *retcmpp = NFSERR_NOTSAME;
1512 } else if (fsp != NULL) {
1513 if (*tl == newnfs_true)
1514 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1516 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1518 attrsum += NFSX_UNSIGNED;
1520 case NFSATTRBIT_CASEINSENSITIVE:
1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1524 if (*tl != newnfs_false)
1525 *retcmpp = NFSERR_NOTSAME;
1527 } else if (pc != NULL) {
1528 pc->pc_caseinsensitive =
1529 fxdr_unsigned(u_int32_t, *tl);
1531 attrsum += NFSX_UNSIGNED;
1533 case NFSATTRBIT_CASEPRESERVING:
1534 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1537 if (*tl != newnfs_true)
1538 *retcmpp = NFSERR_NOTSAME;
1540 } else if (pc != NULL) {
1541 pc->pc_casepreserving =
1542 fxdr_unsigned(u_int32_t, *tl);
1544 attrsum += NFSX_UNSIGNED;
1546 case NFSATTRBIT_CHOWNRESTRICTED:
1547 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1550 if (*tl != newnfs_true)
1551 *retcmpp = NFSERR_NOTSAME;
1553 } else if (pc != NULL) {
1554 pc->pc_chownrestricted =
1555 fxdr_unsigned(u_int32_t, *tl);
1557 attrsum += NFSX_UNSIGNED;
1559 case NFSATTRBIT_FILEHANDLE:
1560 error = nfsm_getfh(nd, &tnfhp);
1563 tfhsize = tnfhp->nfh_len;
1566 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1568 *retcmpp = NFSERR_NOTSAME;
1569 free(tnfhp, M_NFSFH);
1570 } else if (nfhpp != NULL) {
1573 free(tnfhp, M_NFSFH);
1575 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1577 case NFSATTRBIT_FILEID:
1578 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1579 thyp = fxdr_hyper(tl);
1582 if (nap->na_fileid != thyp)
1583 *retcmpp = NFSERR_NOTSAME;
1585 } else if (nap != NULL)
1586 nap->na_fileid = thyp;
1587 attrsum += NFSX_HYPER;
1589 case NFSATTRBIT_FILESAVAIL:
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1593 sfp->sf_afiles != fxdr_hyper(tl))
1594 *retcmpp = NFSERR_NOTSAME;
1595 } else if (sfp != NULL) {
1596 sfp->sf_afiles = fxdr_hyper(tl);
1598 attrsum += NFSX_HYPER;
1600 case NFSATTRBIT_FILESFREE:
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1604 sfp->sf_ffiles != fxdr_hyper(tl))
1605 *retcmpp = NFSERR_NOTSAME;
1606 } else if (sfp != NULL) {
1607 sfp->sf_ffiles = fxdr_hyper(tl);
1609 attrsum += NFSX_HYPER;
1611 case NFSATTRBIT_FILESTOTAL:
1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1615 sfp->sf_tfiles != fxdr_hyper(tl))
1616 *retcmpp = NFSERR_NOTSAME;
1617 } else if (sfp != NULL) {
1618 sfp->sf_tfiles = fxdr_hyper(tl);
1620 attrsum += NFSX_HYPER;
1622 case NFSATTRBIT_FSLOCATIONS:
1623 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1627 if (compare && !(*retcmpp)) {
1628 refp = nfsv4root_getreferral(vp, NULL, 0);
1630 if (cp == NULL || cp2 == NULL ||
1632 strcmp(cp2, refp->nfr_srvlist))
1633 *retcmpp = NFSERR_NOTSAME;
1634 } else if (m == 0) {
1635 *retcmpp = NFSERR_NOTSAME;
1639 free(cp, M_NFSSTRING);
1641 free(cp2, M_NFSSTRING);
1643 case NFSATTRBIT_HIDDEN:
1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 if (compare && !(*retcmpp))
1646 *retcmpp = NFSERR_ATTRNOTSUPP;
1647 attrsum += NFSX_UNSIGNED;
1649 case NFSATTRBIT_HOMOGENEOUS:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1653 if (fsp->fs_properties &
1654 NFSV3_FSFHOMOGENEOUS) {
1655 if (*tl == newnfs_false)
1656 *retcmpp = NFSERR_NOTSAME;
1658 if (*tl == newnfs_true)
1659 *retcmpp = NFSERR_NOTSAME;
1662 } else if (fsp != NULL) {
1663 if (*tl == newnfs_true)
1664 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1666 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1668 attrsum += NFSX_UNSIGNED;
1670 case NFSATTRBIT_MAXFILESIZE:
1671 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1672 tnfsquad.qval = fxdr_hyper(tl);
1675 tquad = NFSRV_MAXFILESIZE;
1676 if (tquad != tnfsquad.qval)
1677 *retcmpp = NFSERR_NOTSAME;
1679 } else if (fsp != NULL) {
1680 fsp->fs_maxfilesize = tnfsquad.qval;
1682 attrsum += NFSX_HYPER;
1684 case NFSATTRBIT_MAXLINK:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1688 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1689 *retcmpp = NFSERR_NOTSAME;
1691 } else if (pc != NULL) {
1692 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1694 attrsum += NFSX_UNSIGNED;
1696 case NFSATTRBIT_MAXNAME:
1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1700 if (fsp->fs_maxname !=
1701 fxdr_unsigned(u_int32_t, *tl))
1702 *retcmpp = NFSERR_NOTSAME;
1705 tuint = fxdr_unsigned(u_int32_t, *tl);
1707 * Some Linux NFSv4 servers report this
1708 * as 0 or 4billion, so I'll set it to
1709 * NFS_MAXNAMLEN. If a server actually creates
1710 * a name longer than NFS_MAXNAMLEN, it will
1711 * get an error back.
1713 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1714 tuint = NFS_MAXNAMLEN;
1716 fsp->fs_maxname = tuint;
1718 pc->pc_namemax = tuint;
1720 attrsum += NFSX_UNSIGNED;
1722 case NFSATTRBIT_MAXREAD:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1726 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1727 *(tl + 1)) || *tl != 0)
1728 *retcmpp = NFSERR_NOTSAME;
1730 } else if (fsp != NULL) {
1731 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1732 fsp->fs_rtpref = fsp->fs_rtmax;
1733 fsp->fs_dtpref = fsp->fs_rtpref;
1735 attrsum += NFSX_HYPER;
1737 case NFSATTRBIT_MAXWRITE:
1738 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1741 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1742 *(tl + 1)) || *tl != 0)
1743 *retcmpp = NFSERR_NOTSAME;
1745 } else if (fsp != NULL) {
1746 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1747 fsp->fs_wtpref = fsp->fs_wtmax;
1749 attrsum += NFSX_HYPER;
1751 case NFSATTRBIT_MIMETYPE:
1752 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1753 i = fxdr_unsigned(int, *tl);
1754 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1755 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1758 if (compare && !(*retcmpp))
1759 *retcmpp = NFSERR_ATTRNOTSUPP;
1761 case NFSATTRBIT_MODE:
1762 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1765 if (nap->na_mode != nfstov_mode(*tl))
1766 *retcmpp = NFSERR_NOTSAME;
1768 } else if (nap != NULL) {
1769 nap->na_mode = nfstov_mode(*tl);
1771 attrsum += NFSX_UNSIGNED;
1773 case NFSATTRBIT_NOTRUNC:
1774 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1777 if (*tl != newnfs_true)
1778 *retcmpp = NFSERR_NOTSAME;
1780 } else if (pc != NULL) {
1781 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1783 attrsum += NFSX_UNSIGNED;
1785 case NFSATTRBIT_NUMLINKS:
1786 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1787 tuint = fxdr_unsigned(u_int32_t, *tl);
1790 if ((u_int32_t)nap->na_nlink != tuint)
1791 *retcmpp = NFSERR_NOTSAME;
1793 } else if (nap != NULL) {
1794 nap->na_nlink = tuint;
1796 attrsum += NFSX_UNSIGNED;
1798 case NFSATTRBIT_OWNER:
1799 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1800 j = fxdr_unsigned(int, *tl);
1802 error = NFSERR_BADXDR;
1805 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1806 if (j > NFSV4_SMALLSTR)
1807 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1810 error = nfsrv_mtostr(nd, cp, j);
1812 if (j > NFSV4_SMALLSTR)
1813 free(cp, M_NFSSTRING);
1818 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1820 *retcmpp = NFSERR_NOTSAME;
1822 } else if (nap != NULL) {
1823 if (nfsv4_strtouid(nd, cp, j, &uid))
1824 nap->na_uid = nfsrv_defaultuid;
1828 if (j > NFSV4_SMALLSTR)
1829 free(cp, M_NFSSTRING);
1831 case NFSATTRBIT_OWNERGROUP:
1832 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1833 j = fxdr_unsigned(int, *tl);
1835 error = NFSERR_BADXDR;
1838 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1839 if (j > NFSV4_SMALLSTR)
1840 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1843 error = nfsrv_mtostr(nd, cp, j);
1845 if (j > NFSV4_SMALLSTR)
1846 free(cp, M_NFSSTRING);
1851 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1853 *retcmpp = NFSERR_NOTSAME;
1855 } else if (nap != NULL) {
1856 if (nfsv4_strtogid(nd, cp, j, &gid))
1857 nap->na_gid = nfsrv_defaultgid;
1861 if (j > NFSV4_SMALLSTR)
1862 free(cp, M_NFSSTRING);
1864 case NFSATTRBIT_QUOTAHARD:
1865 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1867 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1868 freenum = sbp->f_bfree;
1870 freenum = sbp->f_bavail;
1873 * ufs_quotactl() insists that the uid argument
1874 * equal p_ruid for non-root quota access, so
1875 * we'll just make sure that's the case.
1877 savuid = p->p_cred->p_ruid;
1878 p->p_cred->p_ruid = cred->cr_uid;
1879 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1880 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1881 freenum = min(dqb.dqb_bhardlimit, freenum);
1882 p->p_cred->p_ruid = savuid;
1884 uquad = (u_int64_t)freenum;
1885 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1887 if (compare && !(*retcmpp)) {
1888 if (uquad != fxdr_hyper(tl))
1889 *retcmpp = NFSERR_NOTSAME;
1891 attrsum += NFSX_HYPER;
1893 case NFSATTRBIT_QUOTASOFT:
1894 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1896 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1897 freenum = sbp->f_bfree;
1899 freenum = sbp->f_bavail;
1902 * ufs_quotactl() insists that the uid argument
1903 * equal p_ruid for non-root quota access, so
1904 * we'll just make sure that's the case.
1906 savuid = p->p_cred->p_ruid;
1907 p->p_cred->p_ruid = cred->cr_uid;
1908 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1909 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1910 freenum = min(dqb.dqb_bsoftlimit, freenum);
1911 p->p_cred->p_ruid = savuid;
1913 uquad = (u_int64_t)freenum;
1914 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1916 if (compare && !(*retcmpp)) {
1917 if (uquad != fxdr_hyper(tl))
1918 *retcmpp = NFSERR_NOTSAME;
1920 attrsum += NFSX_HYPER;
1922 case NFSATTRBIT_QUOTAUSED:
1923 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1928 * ufs_quotactl() insists that the uid argument
1929 * equal p_ruid for non-root quota access, so
1930 * we'll just make sure that's the case.
1932 savuid = p->p_cred->p_ruid;
1933 p->p_cred->p_ruid = cred->cr_uid;
1934 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1935 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1936 freenum = dqb.dqb_curblocks;
1937 p->p_cred->p_ruid = savuid;
1939 uquad = (u_int64_t)freenum;
1940 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1942 if (compare && !(*retcmpp)) {
1943 if (uquad != fxdr_hyper(tl))
1944 *retcmpp = NFSERR_NOTSAME;
1946 attrsum += NFSX_HYPER;
1948 case NFSATTRBIT_RAWDEV:
1949 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1950 j = fxdr_unsigned(int, *tl++);
1951 k = fxdr_unsigned(int, *tl);
1954 if (nap->na_rdev != NFSMAKEDEV(j, k))
1955 *retcmpp = NFSERR_NOTSAME;
1957 } else if (nap != NULL) {
1958 nap->na_rdev = NFSMAKEDEV(j, k);
1960 attrsum += NFSX_V4SPECDATA;
1962 case NFSATTRBIT_SPACEAVAIL:
1963 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1966 sfp->sf_abytes != fxdr_hyper(tl))
1967 *retcmpp = NFSERR_NOTSAME;
1968 } else if (sfp != NULL) {
1969 sfp->sf_abytes = fxdr_hyper(tl);
1971 attrsum += NFSX_HYPER;
1973 case NFSATTRBIT_SPACEFREE:
1974 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1977 sfp->sf_fbytes != fxdr_hyper(tl))
1978 *retcmpp = NFSERR_NOTSAME;
1979 } else if (sfp != NULL) {
1980 sfp->sf_fbytes = fxdr_hyper(tl);
1982 attrsum += NFSX_HYPER;
1984 case NFSATTRBIT_SPACETOTAL:
1985 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1988 sfp->sf_tbytes != fxdr_hyper(tl))
1989 *retcmpp = NFSERR_NOTSAME;
1990 } else if (sfp != NULL) {
1991 sfp->sf_tbytes = fxdr_hyper(tl);
1993 attrsum += NFSX_HYPER;
1995 case NFSATTRBIT_SPACEUSED:
1996 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1997 thyp = fxdr_hyper(tl);
2000 if ((u_int64_t)nap->na_bytes != thyp)
2001 *retcmpp = NFSERR_NOTSAME;
2003 } else if (nap != NULL) {
2004 nap->na_bytes = thyp;
2006 attrsum += NFSX_HYPER;
2008 case NFSATTRBIT_SYSTEM:
2009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2010 if (compare && !(*retcmpp))
2011 *retcmpp = NFSERR_ATTRNOTSUPP;
2012 attrsum += NFSX_UNSIGNED;
2014 case NFSATTRBIT_TIMEACCESS:
2015 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2016 fxdr_nfsv4time(tl, &temptime);
2019 if (!NFS_CMPTIME(temptime, nap->na_atime))
2020 *retcmpp = NFSERR_NOTSAME;
2022 } else if (nap != NULL) {
2023 nap->na_atime = temptime;
2025 attrsum += NFSX_V4TIME;
2027 case NFSATTRBIT_TIMEACCESSSET:
2028 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2029 attrsum += NFSX_UNSIGNED;
2030 i = fxdr_unsigned(int, *tl);
2031 if (i == NFSV4SATTRTIME_TOCLIENT) {
2032 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2033 attrsum += NFSX_V4TIME;
2035 if (compare && !(*retcmpp))
2036 *retcmpp = NFSERR_INVAL;
2038 case NFSATTRBIT_TIMEBACKUP:
2039 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2040 if (compare && !(*retcmpp))
2041 *retcmpp = NFSERR_ATTRNOTSUPP;
2042 attrsum += NFSX_V4TIME;
2044 case NFSATTRBIT_TIMECREATE:
2045 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2046 if (compare && !(*retcmpp))
2047 *retcmpp = NFSERR_ATTRNOTSUPP;
2048 attrsum += NFSX_V4TIME;
2050 case NFSATTRBIT_TIMEDELTA:
2051 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2055 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2056 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2057 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2058 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2061 *retcmpp = NFSERR_NOTSAME;
2064 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2067 attrsum += NFSX_V4TIME;
2069 case NFSATTRBIT_TIMEMETADATA:
2070 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2071 fxdr_nfsv4time(tl, &temptime);
2074 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2075 *retcmpp = NFSERR_NOTSAME;
2077 } else if (nap != NULL) {
2078 nap->na_ctime = temptime;
2080 attrsum += NFSX_V4TIME;
2082 case NFSATTRBIT_TIMEMODIFY:
2083 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2084 fxdr_nfsv4time(tl, &temptime);
2087 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2088 *retcmpp = NFSERR_NOTSAME;
2090 } else if (nap != NULL) {
2091 nap->na_mtime = temptime;
2093 attrsum += NFSX_V4TIME;
2095 case NFSATTRBIT_TIMEMODIFYSET:
2096 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2097 attrsum += NFSX_UNSIGNED;
2098 i = fxdr_unsigned(int, *tl);
2099 if (i == NFSV4SATTRTIME_TOCLIENT) {
2100 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2101 attrsum += NFSX_V4TIME;
2103 if (compare && !(*retcmpp))
2104 *retcmpp = NFSERR_INVAL;
2106 case NFSATTRBIT_MOUNTEDONFILEID:
2107 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2108 thyp = fxdr_hyper(tl);
2111 if (!vp || !nfsrv_atroot(vp, &thyp2))
2112 thyp2 = nap->na_fileid;
2114 *retcmpp = NFSERR_NOTSAME;
2116 } else if (nap != NULL)
2117 nap->na_mntonfileno = thyp;
2118 attrsum += NFSX_HYPER;
2120 case NFSATTRBIT_SUPPATTREXCLCREAT:
2122 error = nfsrv_getattrbits(nd, &retattrbits,
2126 if (compare && !(*retcmpp)) {
2127 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2128 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2129 NFSCLRBIT_ATTRBIT(&checkattrbits,
2130 NFSATTRBIT_TIMEACCESSSET);
2131 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2133 *retcmpp = NFSERR_NOTSAME;
2137 case NFSATTRBIT_FSLAYOUTTYPE:
2138 case NFSATTRBIT_LAYOUTTYPE:
2139 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2140 attrsum += NFSX_UNSIGNED;
2141 i = fxdr_unsigned(int, *tl);
2143 NFSM_DISSECT(tl, u_int32_t *, i *
2145 attrsum += i * NFSX_UNSIGNED;
2146 j = fxdr_unsigned(int, *tl);
2147 if (i == 1 && compare && !(*retcmpp) &&
2148 (((nfsrv_doflexfile != 0 ||
2149 nfsrv_maxpnfsmirror > 1) &&
2150 j != NFSLAYOUT_FLEXFILE) ||
2151 (nfsrv_doflexfile == 0 &&
2152 j != NFSLAYOUT_NFSV4_1_FILES)))
2153 *retcmpp = NFSERR_NOTSAME;
2155 if (nfsrv_devidcnt == 0) {
2156 if (compare && !(*retcmpp) && i > 0)
2157 *retcmpp = NFSERR_NOTSAME;
2159 if (compare && !(*retcmpp) && i != 1)
2160 *retcmpp = NFSERR_NOTSAME;
2163 case NFSATTRBIT_LAYOUTALIGNMENT:
2164 case NFSATTRBIT_LAYOUTBLKSIZE:
2165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2166 attrsum += NFSX_UNSIGNED;
2167 i = fxdr_unsigned(int, *tl);
2168 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2169 *retcmpp = NFSERR_NOTSAME;
2172 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2174 if (compare && !(*retcmpp))
2175 *retcmpp = NFSERR_ATTRNOTSUPP;
2177 * and get out of the loop, since we can't parse
2178 * the unknown attrbute data.
2180 bitpos = NFSATTRBIT_MAX;
2186 * some clients pad the attrlist, so we need to skip over the
2189 if (attrsum > attrsize) {
2190 error = NFSERR_BADXDR;
2192 attrsize = NFSM_RNDUP(attrsize);
2193 if (attrsum < attrsize)
2194 error = nfsm_advance(nd, attrsize - attrsum, -1);
2197 NFSEXITCODE2(error, nd);
2202 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2203 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2204 * The first argument is a pointer to an nfsv4lock structure.
2205 * The second argument is 1 iff a blocking lock is wanted.
2206 * If this argument is 0, the call waits until no thread either wants nor
2207 * holds an exclusive lock.
2208 * It returns 1 if the lock was acquired, 0 otherwise.
2209 * If several processes call this function concurrently wanting the exclusive
2210 * lock, one will get the lock and the rest will return without getting the
2211 * lock. (If the caller must have the lock, it simply calls this function in a
2212 * loop until the function returns 1 to indicate the lock was acquired.)
2213 * Any usecnt must be decremented by calling nfsv4_relref() before
2214 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2215 * be called in a loop.
2216 * The isleptp argument is set to indicate if the call slept, iff not NULL
2217 * and the mp argument indicates to check for a forced dismount, iff not
2221 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2222 void *mutex, struct mount *mp)
2228 * If a lock is wanted, loop around until the lock is acquired by
2229 * someone and then released. If I want the lock, try to acquire it.
2230 * For a lock to be issued, no lock must be in force and the usecnt
2234 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2235 lp->nfslock_usecnt == 0) {
2236 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2237 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2240 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2242 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2243 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2244 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2247 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2250 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2251 PZERO - 1, "nfsv4lck", NULL);
2252 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2253 lp->nfslock_usecnt == 0) {
2254 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2255 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2263 * Release the lock acquired by nfsv4_lock().
2264 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2265 * incremented, as well.
2268 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2271 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2273 lp->nfslock_usecnt++;
2278 * Release a reference cnt.
2281 nfsv4_relref(struct nfsv4lock *lp)
2284 if (lp->nfslock_usecnt <= 0)
2285 panic("nfsv4root ref cnt");
2286 lp->nfslock_usecnt--;
2287 if (lp->nfslock_usecnt == 0)
2292 * Get a reference cnt.
2293 * This function will wait for any exclusive lock to be released, but will
2294 * not wait for threads that want the exclusive lock. If priority needs
2295 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2296 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2297 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2298 * return without getting a refcnt for that case.
2301 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2309 * Wait for a lock held.
2311 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2312 if (mp != NULL && NFSCL_FORCEDISM(mp))
2314 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2317 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2318 PZERO - 1, "nfsv4gr", NULL);
2320 if (mp != NULL && NFSCL_FORCEDISM(mp))
2323 lp->nfslock_usecnt++;
2327 * Get a reference as above, but return failure instead of sleeping if
2328 * an exclusive lock is held.
2331 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2334 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2337 lp->nfslock_usecnt++;
2342 * Test for a lock. Return 1 if locked, 0 otherwise.
2345 nfsv4_testlock(struct nfsv4lock *lp)
2348 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2349 lp->nfslock_usecnt == 0)
2355 * Wake up anyone sleeping, waiting for this lock.
2358 nfsv4_wanted(struct nfsv4lock *lp)
2361 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2362 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2363 wakeup((caddr_t)&lp->nfslock_lock);
2368 * Copy a string from an mbuf list into a character array.
2369 * Return EBADRPC if there is an mbuf error,
2373 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2382 len = mtod(mp, caddr_t) + mp->m_len - cp;
2383 rem = NFSM_RNDUP(siz) - siz;
2389 NFSBCOPY(cp, str, xfer);
2398 cp = mtod(mp, caddr_t);
2410 error = nfsm_advance(nd, rem, len);
2416 NFSEXITCODE2(error, nd);
2421 * Fill in the attributes as marked by the bitmap (V4).
2424 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2425 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2426 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2427 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2428 struct statfs *pnfssf)
2430 int bitpos, retnum = 0;
2432 int siz, prefixnum, error;
2433 u_char *cp, namestr[NFSV4_SMALLSTR];
2434 nfsattrbit_t attrbits, retbits;
2435 nfsattrbit_t *retbitp = &retbits;
2436 u_int32_t freenum, *retnump;
2439 struct nfsfsinfo fsinf;
2440 struct timespec temptime;
2441 NFSACL_T *aclp, *naclp = NULL;
2450 * First, set the bits that can be filled and get fsinfo.
2452 NFSSET_ATTRBIT(retbitp, attrbitp);
2454 * If both p and cred are NULL, it is a client side setattr call.
2455 * If both p and cred are not NULL, it is a server side reply call.
2456 * If p is not NULL and cred is NULL, it is a client side callback
2459 if (p == NULL && cred == NULL) {
2460 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2463 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2464 naclp = acl_alloc(M_WAITOK);
2467 nfsvno_getfs(&fsinf, isdgram);
2470 * Get the VFS_STATFS(), since some attributes need them.
2472 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2473 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2474 error = VFS_STATFS(mp, fs);
2477 nd->nd_repstat = NFSERR_ACCES;
2481 NFSCLRSTATFS_ATTRBIT(retbitp);
2487 * And the NFSv4 ACL...
2489 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2490 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2491 supports_nfsv4acls == 0))) {
2492 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2494 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2495 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2496 supports_nfsv4acls == 0)) {
2497 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2498 } else if (naclp != NULL) {
2499 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2500 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2502 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2506 error = NFSERR_PERM;
2509 nd->nd_repstat = NFSERR_ACCES;
2513 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2518 /* Check to see if Extended Attributes are supported. */
2520 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2521 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2522 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2523 "xxx", NULL, &atsiz, cred, p);
2525 if (error != EOPNOTSUPP)
2531 * Put out the attribute bitmap for the ones being filled in
2532 * and get the field for the number of attributes returned.
2534 prefixnum = nfsrv_putattrbit(nd, retbitp);
2535 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2536 prefixnum += NFSX_UNSIGNED;
2539 * Now, loop around filling in the attributes for each bit set.
2541 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2542 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2544 case NFSATTRBIT_SUPPORTEDATTRS:
2545 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2546 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2547 && supports_nfsv4acls == 0)) {
2548 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2549 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2551 retnum += nfsrv_putattrbit(nd, &attrbits);
2553 case NFSATTRBIT_TYPE:
2554 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2555 *tl = vtonfsv34_type(vap->va_type);
2556 retnum += NFSX_UNSIGNED;
2558 case NFSATTRBIT_FHEXPIRETYPE:
2559 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2560 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2561 retnum += NFSX_UNSIGNED;
2563 case NFSATTRBIT_CHANGE:
2564 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2565 txdr_hyper(vap->va_filerev, tl);
2566 retnum += NFSX_HYPER;
2568 case NFSATTRBIT_SIZE:
2569 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2570 txdr_hyper(vap->va_size, tl);
2571 retnum += NFSX_HYPER;
2573 case NFSATTRBIT_LINKSUPPORT:
2574 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2575 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2579 retnum += NFSX_UNSIGNED;
2581 case NFSATTRBIT_SYMLINKSUPPORT:
2582 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2583 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2587 retnum += NFSX_UNSIGNED;
2589 case NFSATTRBIT_NAMEDATTR:
2590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2592 retnum += NFSX_UNSIGNED;
2594 case NFSATTRBIT_FSID:
2595 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2597 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2599 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2600 retnum += NFSX_V4FSID;
2602 case NFSATTRBIT_UNIQUEHANDLES:
2603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2605 retnum += NFSX_UNSIGNED;
2607 case NFSATTRBIT_LEASETIME:
2608 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 *tl = txdr_unsigned(nfsrv_lease);
2610 retnum += NFSX_UNSIGNED;
2612 case NFSATTRBIT_RDATTRERROR:
2613 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2614 *tl = txdr_unsigned(rderror);
2615 retnum += NFSX_UNSIGNED;
2618 * Recommended Attributes. (Only the supported ones.)
2620 case NFSATTRBIT_ACL:
2621 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2623 case NFSATTRBIT_ACLSUPPORT:
2624 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2626 retnum += NFSX_UNSIGNED;
2628 case NFSATTRBIT_CANSETTIME:
2629 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2630 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2634 retnum += NFSX_UNSIGNED;
2636 case NFSATTRBIT_CASEINSENSITIVE:
2637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2639 retnum += NFSX_UNSIGNED;
2641 case NFSATTRBIT_CASEPRESERVING:
2642 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2644 retnum += NFSX_UNSIGNED;
2646 case NFSATTRBIT_CHOWNRESTRICTED:
2647 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2649 retnum += NFSX_UNSIGNED;
2651 case NFSATTRBIT_FILEHANDLE:
2652 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2654 case NFSATTRBIT_FILEID:
2655 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2656 uquad = vap->va_fileid;
2657 txdr_hyper(uquad, tl);
2658 retnum += NFSX_HYPER;
2660 case NFSATTRBIT_FILESAVAIL:
2662 * Check quota and use min(quota, f_ffree).
2664 freenum = fs->f_ffree;
2667 * ufs_quotactl() insists that the uid argument
2668 * equal p_ruid for non-root quota access, so
2669 * we'll just make sure that's the case.
2671 savuid = p->p_cred->p_ruid;
2672 p->p_cred->p_ruid = cred->cr_uid;
2673 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2674 cred->cr_uid, (caddr_t)&dqb))
2675 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2677 p->p_cred->p_ruid = savuid;
2679 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2681 *tl = txdr_unsigned(freenum);
2682 retnum += NFSX_HYPER;
2684 case NFSATTRBIT_FILESFREE:
2685 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2687 *tl = txdr_unsigned(fs->f_ffree);
2688 retnum += NFSX_HYPER;
2690 case NFSATTRBIT_FILESTOTAL:
2691 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2693 *tl = txdr_unsigned(fs->f_files);
2694 retnum += NFSX_HYPER;
2696 case NFSATTRBIT_FSLOCATIONS:
2697 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2700 retnum += 2 * NFSX_UNSIGNED;
2702 case NFSATTRBIT_HOMOGENEOUS:
2703 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2704 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2708 retnum += NFSX_UNSIGNED;
2710 case NFSATTRBIT_MAXFILESIZE:
2711 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2712 uquad = NFSRV_MAXFILESIZE;
2713 txdr_hyper(uquad, tl);
2714 retnum += NFSX_HYPER;
2716 case NFSATTRBIT_MAXLINK:
2717 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2718 *tl = txdr_unsigned(NFS_LINK_MAX);
2719 retnum += NFSX_UNSIGNED;
2721 case NFSATTRBIT_MAXNAME:
2722 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2723 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2724 retnum += NFSX_UNSIGNED;
2726 case NFSATTRBIT_MAXREAD:
2727 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2729 *tl = txdr_unsigned(fsinf.fs_rtmax);
2730 retnum += NFSX_HYPER;
2732 case NFSATTRBIT_MAXWRITE:
2733 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2735 *tl = txdr_unsigned(fsinf.fs_wtmax);
2736 retnum += NFSX_HYPER;
2738 case NFSATTRBIT_MODE:
2739 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2740 *tl = vtonfsv34_mode(vap->va_mode);
2741 retnum += NFSX_UNSIGNED;
2743 case NFSATTRBIT_NOTRUNC:
2744 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2746 retnum += NFSX_UNSIGNED;
2748 case NFSATTRBIT_NUMLINKS:
2749 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2750 *tl = txdr_unsigned(vap->va_nlink);
2751 retnum += NFSX_UNSIGNED;
2753 case NFSATTRBIT_OWNER:
2755 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2756 retnum += nfsm_strtom(nd, cp, siz);
2758 free(cp, M_NFSSTRING);
2760 case NFSATTRBIT_OWNERGROUP:
2762 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2763 retnum += nfsm_strtom(nd, cp, siz);
2765 free(cp, M_NFSSTRING);
2767 case NFSATTRBIT_QUOTAHARD:
2768 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2769 freenum = fs->f_bfree;
2771 freenum = fs->f_bavail;
2774 * ufs_quotactl() insists that the uid argument
2775 * equal p_ruid for non-root quota access, so
2776 * we'll just make sure that's the case.
2778 savuid = p->p_cred->p_ruid;
2779 p->p_cred->p_ruid = cred->cr_uid;
2780 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2781 cred->cr_uid, (caddr_t)&dqb))
2782 freenum = min(dqb.dqb_bhardlimit, freenum);
2783 p->p_cred->p_ruid = savuid;
2785 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2786 uquad = (u_int64_t)freenum;
2787 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2788 txdr_hyper(uquad, tl);
2789 retnum += NFSX_HYPER;
2791 case NFSATTRBIT_QUOTASOFT:
2792 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2793 freenum = fs->f_bfree;
2795 freenum = fs->f_bavail;
2798 * ufs_quotactl() insists that the uid argument
2799 * equal p_ruid for non-root quota access, so
2800 * we'll just make sure that's the case.
2802 savuid = p->p_cred->p_ruid;
2803 p->p_cred->p_ruid = cred->cr_uid;
2804 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2805 cred->cr_uid, (caddr_t)&dqb))
2806 freenum = min(dqb.dqb_bsoftlimit, freenum);
2807 p->p_cred->p_ruid = savuid;
2809 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2810 uquad = (u_int64_t)freenum;
2811 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2812 txdr_hyper(uquad, tl);
2813 retnum += NFSX_HYPER;
2815 case NFSATTRBIT_QUOTAUSED:
2819 * ufs_quotactl() insists that the uid argument
2820 * equal p_ruid for non-root quota access, so
2821 * we'll just make sure that's the case.
2823 savuid = p->p_cred->p_ruid;
2824 p->p_cred->p_ruid = cred->cr_uid;
2825 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2826 cred->cr_uid, (caddr_t)&dqb))
2827 freenum = dqb.dqb_curblocks;
2828 p->p_cred->p_ruid = savuid;
2830 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2831 uquad = (u_int64_t)freenum;
2832 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2833 txdr_hyper(uquad, tl);
2834 retnum += NFSX_HYPER;
2836 case NFSATTRBIT_RAWDEV:
2837 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2838 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2839 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2840 retnum += NFSX_V4SPECDATA;
2842 case NFSATTRBIT_SPACEAVAIL:
2843 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2844 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2846 uquad = (u_int64_t)pnfssf->f_bfree;
2848 uquad = (u_int64_t)fs->f_bfree;
2851 uquad = (u_int64_t)pnfssf->f_bavail;
2853 uquad = (u_int64_t)fs->f_bavail;
2856 uquad *= pnfssf->f_bsize;
2858 uquad *= fs->f_bsize;
2859 txdr_hyper(uquad, tl);
2860 retnum += NFSX_HYPER;
2862 case NFSATTRBIT_SPACEFREE:
2863 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2864 if (pnfssf != NULL) {
2865 uquad = (u_int64_t)pnfssf->f_bfree;
2866 uquad *= pnfssf->f_bsize;
2868 uquad = (u_int64_t)fs->f_bfree;
2869 uquad *= fs->f_bsize;
2871 txdr_hyper(uquad, tl);
2872 retnum += NFSX_HYPER;
2874 case NFSATTRBIT_SPACETOTAL:
2875 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2876 if (pnfssf != NULL) {
2877 uquad = (u_int64_t)pnfssf->f_blocks;
2878 uquad *= pnfssf->f_bsize;
2880 uquad = (u_int64_t)fs->f_blocks;
2881 uquad *= fs->f_bsize;
2883 txdr_hyper(uquad, tl);
2884 retnum += NFSX_HYPER;
2886 case NFSATTRBIT_SPACEUSED:
2887 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2888 txdr_hyper(vap->va_bytes, tl);
2889 retnum += NFSX_HYPER;
2891 case NFSATTRBIT_TIMEACCESS:
2892 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2893 txdr_nfsv4time(&vap->va_atime, tl);
2894 retnum += NFSX_V4TIME;
2896 case NFSATTRBIT_TIMEACCESSSET:
2897 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2898 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2899 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2900 txdr_nfsv4time(&vap->va_atime, tl);
2901 retnum += NFSX_V4SETTIME;
2903 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2904 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2905 retnum += NFSX_UNSIGNED;
2908 case NFSATTRBIT_TIMEDELTA:
2909 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2910 temptime.tv_sec = 0;
2911 temptime.tv_nsec = 1000000000 / hz;
2912 txdr_nfsv4time(&temptime, tl);
2913 retnum += NFSX_V4TIME;
2915 case NFSATTRBIT_TIMEMETADATA:
2916 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2917 txdr_nfsv4time(&vap->va_ctime, tl);
2918 retnum += NFSX_V4TIME;
2920 case NFSATTRBIT_TIMEMODIFY:
2921 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2922 txdr_nfsv4time(&vap->va_mtime, tl);
2923 retnum += NFSX_V4TIME;
2925 case NFSATTRBIT_TIMEMODIFYSET:
2926 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2927 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2928 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2929 txdr_nfsv4time(&vap->va_mtime, tl);
2930 retnum += NFSX_V4SETTIME;
2932 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2933 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2934 retnum += NFSX_UNSIGNED;
2937 case NFSATTRBIT_MOUNTEDONFILEID:
2938 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2940 uquad = mounted_on_fileno;
2942 uquad = vap->va_fileid;
2943 txdr_hyper(uquad, tl);
2944 retnum += NFSX_HYPER;
2946 case NFSATTRBIT_SUPPATTREXCLCREAT:
2947 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2948 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2949 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2950 retnum += nfsrv_putattrbit(nd, &attrbits);
2952 case NFSATTRBIT_FSLAYOUTTYPE:
2953 case NFSATTRBIT_LAYOUTTYPE:
2954 if (nfsrv_devidcnt == 0)
2959 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2960 *tl++ = txdr_unsigned(1); /* One entry. */
2961 if (nfsrv_doflexfile != 0 ||
2962 nfsrv_maxpnfsmirror > 1)
2963 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2965 *tl = txdr_unsigned(
2966 NFSLAYOUT_NFSV4_1_FILES);
2968 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2971 retnum += siz * NFSX_UNSIGNED;
2973 case NFSATTRBIT_LAYOUTALIGNMENT:
2974 case NFSATTRBIT_LAYOUTBLKSIZE:
2975 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2976 *tl = txdr_unsigned(NFS_SRVMAXIO);
2977 retnum += NFSX_UNSIGNED;
2979 case NFSATTRBIT_XATTRSUPPORT:
2980 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2985 retnum += NFSX_UNSIGNED;
2988 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2995 *retnump = txdr_unsigned(retnum);
2996 return (retnum + prefixnum);
3000 * Put the attribute bits onto an mbuf list.
3001 * Return the number of bytes of output generated.
3004 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3007 int cnt, i, bytesize;
3009 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3010 if (attrbitp->bits[cnt - 1])
3012 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3013 NFSM_BUILD(tl, u_int32_t *, bytesize);
3014 *tl++ = txdr_unsigned(cnt);
3015 for (i = 0; i < cnt; i++)
3016 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3021 * Convert a uid to a string.
3022 * If the lookup fails, just output the digits.
3024 * cpp - points to a buffer of size NFSV4_SMALLSTR
3025 * (malloc a larger one, as required)
3026 * retlenp - pointer to length to be returned
3029 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3032 struct nfsusrgrp *usrp;
3035 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3036 struct nfsrv_lughash *hp;
3040 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3042 * Always map nfsrv_defaultuid to "nobody".
3044 if (uid == nfsrv_defaultuid) {
3045 i = nfsrv_dnsnamelen + 7;
3047 if (len > NFSV4_SMALLSTR)
3048 free(cp, M_NFSSTRING);
3049 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3055 NFSBCOPY("nobody@", cp, 7);
3057 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3061 hp = NFSUSERHASH(uid);
3063 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3064 if (usrp->lug_uid == uid) {
3065 if (usrp->lug_expiry < NFSD_MONOSEC)
3068 * If the name doesn't already have an '@'
3069 * in it, append @domainname to it.
3071 for (i = 0; i < usrp->lug_namelen; i++) {
3072 if (usrp->lug_name[i] == '@') {
3078 i = usrp->lug_namelen;
3080 i = usrp->lug_namelen +
3081 nfsrv_dnsnamelen + 1;
3083 mtx_unlock(&hp->mtx);
3084 if (len > NFSV4_SMALLSTR)
3085 free(cp, M_NFSSTRING);
3086 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3092 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3093 if (!hasampersand) {
3094 cp += usrp->lug_namelen;
3096 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3098 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3099 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3101 mtx_unlock(&hp->mtx);
3105 mtx_unlock(&hp->mtx);
3107 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3108 if (ret == 0 && cnt < 2)
3113 * No match, just return a string of digits.
3117 while (tmp || i == 0) {
3121 len = (i > len) ? len : i;
3125 for (i = 0; i < len; i++) {
3126 *cp-- = '0' + (tmp % 10);
3133 * Get a credential for the uid with the server's group list.
3134 * If none is found, just return the credential passed in after
3135 * logging a warning message.
3138 nfsrv_getgrpscred(struct ucred *oldcred)
3140 struct nfsusrgrp *usrp;
3141 struct ucred *newcred;
3144 struct nfsrv_lughash *hp;
3147 uid = oldcred->cr_uid;
3149 if (nfsrv_dnsnamelen > 0) {
3150 hp = NFSUSERHASH(uid);
3152 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3153 if (usrp->lug_uid == uid) {
3154 if (usrp->lug_expiry < NFSD_MONOSEC)
3156 if (usrp->lug_cred != NULL) {
3157 newcred = crhold(usrp->lug_cred);
3161 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3162 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3164 mtx_unlock(&hp->mtx);
3168 mtx_unlock(&hp->mtx);
3170 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3171 if (ret == 0 && cnt < 2)
3178 * Convert a string to a uid.
3179 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3181 * If this is called from a client side mount using AUTH_SYS and the
3182 * string is made up entirely of digits, just convert the string to
3186 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3189 char *cp, *endstr, *str0;
3190 struct nfsusrgrp *usrp;
3194 struct nfsrv_lughash *hp, *hp2;
3197 error = NFSERR_BADOWNER;
3200 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3202 tuid = (uid_t)strtoul(str0, &endstr, 10);
3203 if ((endstr - str0) == len) {
3204 /* A numeric string. */
3205 if ((nd->nd_flag & ND_KERBV) == 0 &&
3206 ((nd->nd_flag & ND_NFSCL) != 0 ||
3207 nfsd_enable_stringtouid != 0))
3210 error = NFSERR_BADOWNER;
3216 cp = strchr(str0, '@');
3218 i = (int)(cp++ - str0);
3224 if (nfsrv_dnsnamelen > 0) {
3226 * If an '@' is found and the domain name matches, search for
3227 * the name with dns stripped off.
3228 * Mixed case alpahbetics will match for the domain name, but
3229 * all upper case will not.
3231 if (cnt == 0 && i < len && i > 0 &&
3232 (len - 1 - i) == nfsrv_dnsnamelen &&
3233 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3234 len -= (nfsrv_dnsnamelen + 1);
3239 * Check for the special case of "nobody".
3241 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3242 *uidp = nfsrv_defaultuid;
3247 hp = NFSUSERNAMEHASH(str, len);
3249 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3250 if (usrp->lug_namelen == len &&
3251 !NFSBCMP(usrp->lug_name, str, len)) {
3252 if (usrp->lug_expiry < NFSD_MONOSEC)
3254 hp2 = NFSUSERHASH(usrp->lug_uid);
3255 mtx_lock(&hp2->mtx);
3256 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3257 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3259 *uidp = usrp->lug_uid;
3260 mtx_unlock(&hp2->mtx);
3261 mtx_unlock(&hp->mtx);
3266 mtx_unlock(&hp->mtx);
3268 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3270 if (ret == 0 && cnt < 2)
3273 error = NFSERR_BADOWNER;
3281 * Convert a gid to a string.
3282 * gid - the group id
3283 * cpp - points to a buffer of size NFSV4_SMALLSTR
3284 * (malloc a larger one, as required)
3285 * retlenp - pointer to length to be returned
3288 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3291 struct nfsusrgrp *usrp;
3294 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3295 struct nfsrv_lughash *hp;
3299 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3301 * Always map nfsrv_defaultgid to "nogroup".
3303 if (gid == nfsrv_defaultgid) {
3304 i = nfsrv_dnsnamelen + 8;
3306 if (len > NFSV4_SMALLSTR)
3307 free(cp, M_NFSSTRING);
3308 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3314 NFSBCOPY("nogroup@", cp, 8);
3316 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3320 hp = NFSGROUPHASH(gid);
3322 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3323 if (usrp->lug_gid == gid) {
3324 if (usrp->lug_expiry < NFSD_MONOSEC)
3327 * If the name doesn't already have an '@'
3328 * in it, append @domainname to it.
3330 for (i = 0; i < usrp->lug_namelen; i++) {
3331 if (usrp->lug_name[i] == '@') {
3337 i = usrp->lug_namelen;
3339 i = usrp->lug_namelen +
3340 nfsrv_dnsnamelen + 1;
3342 mtx_unlock(&hp->mtx);
3343 if (len > NFSV4_SMALLSTR)
3344 free(cp, M_NFSSTRING);
3345 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3351 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3352 if (!hasampersand) {
3353 cp += usrp->lug_namelen;
3355 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3357 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3358 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3360 mtx_unlock(&hp->mtx);
3364 mtx_unlock(&hp->mtx);
3366 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3367 if (ret == 0 && cnt < 2)
3372 * No match, just return a string of digits.
3376 while (tmp || i == 0) {
3380 len = (i > len) ? len : i;
3384 for (i = 0; i < len; i++) {
3385 *cp-- = '0' + (tmp % 10);
3392 * Convert a string to a gid.
3393 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3395 * If this is called from a client side mount using AUTH_SYS and the
3396 * string is made up entirely of digits, just convert the string to
3400 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3403 char *cp, *endstr, *str0;
3404 struct nfsusrgrp *usrp;
3408 struct nfsrv_lughash *hp, *hp2;
3411 error = NFSERR_BADOWNER;
3414 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3416 tgid = (gid_t)strtoul(str0, &endstr, 10);
3417 if ((endstr - str0) == len) {
3418 /* A numeric string. */
3419 if ((nd->nd_flag & ND_KERBV) == 0 &&
3420 ((nd->nd_flag & ND_NFSCL) != 0 ||
3421 nfsd_enable_stringtouid != 0))
3424 error = NFSERR_BADOWNER;
3430 cp = strchr(str0, '@');
3432 i = (int)(cp++ - str0);
3438 if (nfsrv_dnsnamelen > 0) {
3440 * If an '@' is found and the dns name matches, search for the
3441 * name with the dns stripped off.
3443 if (cnt == 0 && i < len && i > 0 &&
3444 (len - 1 - i) == nfsrv_dnsnamelen &&
3445 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3446 len -= (nfsrv_dnsnamelen + 1);
3451 * Check for the special case of "nogroup".
3453 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3454 *gidp = nfsrv_defaultgid;
3459 hp = NFSGROUPNAMEHASH(str, len);
3461 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3462 if (usrp->lug_namelen == len &&
3463 !NFSBCMP(usrp->lug_name, str, len)) {
3464 if (usrp->lug_expiry < NFSD_MONOSEC)
3466 hp2 = NFSGROUPHASH(usrp->lug_gid);
3467 mtx_lock(&hp2->mtx);
3468 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3469 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3471 *gidp = usrp->lug_gid;
3472 mtx_unlock(&hp2->mtx);
3473 mtx_unlock(&hp->mtx);
3478 mtx_unlock(&hp->mtx);
3480 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3482 if (ret == 0 && cnt < 2)
3485 error = NFSERR_BADOWNER;
3493 * Cmp len chars, allowing mixed case in the first argument to match lower
3494 * case in the second, but not if the first argument is all upper case.
3495 * Return 0 for a match, 1 otherwise.
3498 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3504 for (i = 0; i < len; i++) {
3505 if (*cp >= 'A' && *cp <= 'Z') {
3506 tmp = *cp++ + ('a' - 'A');
3509 if (tmp >= 'a' && tmp <= 'z')
3522 * Set the port for the nfsuserd.
3525 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3527 struct nfssockreq *rp;
3529 struct sockaddr_in *ad;
3532 struct sockaddr_in6 *ad6;
3533 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3538 if (nfsrv_nfsuserd != NOTRUNNING) {
3543 nfsrv_nfsuserd = STARTSTOP;
3545 * Set up the socket record and connect.
3546 * Set nr_client NULL before unlocking, just to ensure that no other
3547 * process/thread/core will use a bogus old value. This could only
3548 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3551 rp = &nfsrv_nfsuserdsock;
3552 rp->nr_client = NULL;
3554 rp->nr_sotype = SOCK_DGRAM;
3555 rp->nr_soproto = IPPROTO_UDP;
3556 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3558 rp->nr_prog = RPCPROG_NFSUSERD;
3560 switch (nargs->nuserd_family) {
3563 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3565 ad = (struct sockaddr_in *)rp->nr_nam;
3566 ad->sin_len = sizeof(struct sockaddr_in);
3567 ad->sin_family = AF_INET;
3568 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3569 ad->sin_port = nargs->nuserd_port;
3574 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3576 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3577 ad6->sin6_len = sizeof(struct sockaddr_in6);
3578 ad6->sin6_family = AF_INET6;
3579 ad6->sin6_addr = in6loopback;
3580 ad6->sin6_port = nargs->nuserd_port;
3586 rp->nr_vers = RPCNFSUSERD_VERS;
3588 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3591 nfsrv_nfsuserd = RUNNING;
3594 free(rp->nr_nam, M_SONAME);
3596 nfsrv_nfsuserd = NOTRUNNING;
3605 * Delete the nfsuserd port.
3608 nfsrv_nfsuserddelport(void)
3612 if (nfsrv_nfsuserd != RUNNING) {
3616 nfsrv_nfsuserd = STARTSTOP;
3617 /* Wait for all upcalls to complete. */
3618 while (nfsrv_userdupcalls > 0)
3619 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3622 newnfs_disconnect(&nfsrv_nfsuserdsock);
3623 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3625 nfsrv_nfsuserd = NOTRUNNING;
3630 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3632 * Returns 0 upon success, non-zero otherwise.
3635 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3638 struct nfsrv_descript *nd;
3640 struct nfsrv_descript nfsd;
3645 if (nfsrv_nfsuserd != RUNNING) {
3651 * Maintain a count of upcalls in progress, so that nfsrv_X()
3652 * can wait until no upcalls are in progress.
3654 nfsrv_userdupcalls++;
3656 KASSERT(nfsrv_userdupcalls > 0,
3657 ("nfsrv_getuser: non-positive upcalls"));
3659 cred = newnfs_getcred();
3660 nd->nd_flag = ND_GSSINITREPLY;
3663 nd->nd_procnum = procnum;
3664 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3665 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3666 if (procnum == RPCNFSUSERD_GETUID)
3667 *tl = txdr_unsigned(uid);
3669 *tl = txdr_unsigned(gid);
3672 (void) nfsm_strtom(nd, name, len);
3674 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3675 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3677 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3678 wakeup(&nfsrv_userdupcalls);
3682 m_freem(nd->nd_mrep);
3683 error = nd->nd_repstat;
3691 * This function is called from the nfssvc(2) system call, to update the
3692 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3695 nfssvc_idname(struct nfsd_idargs *nidp)
3697 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3698 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3699 int i, group_locked, groupname_locked, user_locked, username_locked;
3704 static int onethread = 0;
3705 static time_t lasttime = 0;
3707 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3711 if (nidp->nid_flag & NFSID_INITIALIZE) {
3712 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3713 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
3715 free(cp, M_NFSSTRING);
3718 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3720 * Free up all the old stuff and reinitialize hash
3721 * lists. All mutexes for both lists must be locked,
3722 * with the user/group name ones before the uid/gid
3723 * ones, to avoid a LOR.
3725 for (i = 0; i < nfsrv_lughashsize; i++)
3726 mtx_lock(&nfsusernamehash[i].mtx);
3727 for (i = 0; i < nfsrv_lughashsize; i++)
3728 mtx_lock(&nfsuserhash[i].mtx);
3729 for (i = 0; i < nfsrv_lughashsize; i++)
3730 TAILQ_FOREACH_SAFE(usrp,
3731 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3732 nfsrv_removeuser(usrp, 1);
3733 for (i = 0; i < nfsrv_lughashsize; i++)
3734 mtx_unlock(&nfsuserhash[i].mtx);
3735 for (i = 0; i < nfsrv_lughashsize; i++)
3736 mtx_unlock(&nfsusernamehash[i].mtx);
3737 for (i = 0; i < nfsrv_lughashsize; i++)
3738 mtx_lock(&nfsgroupnamehash[i].mtx);
3739 for (i = 0; i < nfsrv_lughashsize; i++)
3740 mtx_lock(&nfsgrouphash[i].mtx);
3741 for (i = 0; i < nfsrv_lughashsize; i++)
3742 TAILQ_FOREACH_SAFE(usrp,
3743 &nfsgrouphash[i].lughead, lug_numhash,
3745 nfsrv_removeuser(usrp, 0);
3746 for (i = 0; i < nfsrv_lughashsize; i++)
3747 mtx_unlock(&nfsgrouphash[i].mtx);
3748 for (i = 0; i < nfsrv_lughashsize; i++)
3749 mtx_unlock(&nfsgroupnamehash[i].mtx);
3750 free(nfsrv_dnsname, M_NFSSTRING);
3751 nfsrv_dnsname = NULL;
3753 if (nfsuserhash == NULL) {
3754 /* Allocate the hash tables. */
3755 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3756 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3758 for (i = 0; i < nfsrv_lughashsize; i++)
3759 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3760 NULL, MTX_DEF | MTX_DUPOK);
3761 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3762 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3764 for (i = 0; i < nfsrv_lughashsize; i++)
3765 mtx_init(&nfsusernamehash[i].mtx,
3766 "nfsusrhash", NULL, MTX_DEF |
3768 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3769 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3771 for (i = 0; i < nfsrv_lughashsize; i++)
3772 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3773 NULL, MTX_DEF | MTX_DUPOK);
3774 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3775 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3777 for (i = 0; i < nfsrv_lughashsize; i++)
3778 mtx_init(&nfsgroupnamehash[i].mtx,
3779 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3781 /* (Re)initialize the list heads. */
3782 for (i = 0; i < nfsrv_lughashsize; i++)
3783 TAILQ_INIT(&nfsuserhash[i].lughead);
3784 for (i = 0; i < nfsrv_lughashsize; i++)
3785 TAILQ_INIT(&nfsusernamehash[i].lughead);
3786 for (i = 0; i < nfsrv_lughashsize; i++)
3787 TAILQ_INIT(&nfsgrouphash[i].lughead);
3788 for (i = 0; i < nfsrv_lughashsize; i++)
3789 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3792 * Put name in "DNS" string.
3795 nfsrv_defaultuid = nidp->nid_uid;
3796 nfsrv_defaultgid = nidp->nid_gid;
3798 nfsrv_usermax = nidp->nid_usermax;
3799 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3804 * malloc the new one now, so any potential sleep occurs before
3805 * manipulation of the lists.
3807 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3808 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3809 error = copyin(nidp->nid_name, newusrp->lug_name,
3811 if (error == 0 && nidp->nid_ngroup > 0 &&
3812 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3813 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3815 error = copyin(nidp->nid_grps, grps,
3816 sizeof(gid_t) * nidp->nid_ngroup);
3819 * Create a credential just like svc_getcred(),
3820 * but using the group list provided.
3823 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3824 crsetgroups(cr, nidp->nid_ngroup, grps);
3825 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3826 cr->cr_prison = &prison0;
3827 prison_hold(cr->cr_prison);
3829 mac_cred_associate_nfsd(cr);
3831 newusrp->lug_cred = cr;
3836 free(newusrp, M_NFSUSERGROUP);
3839 newusrp->lug_namelen = nidp->nid_namelen;
3842 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3843 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3844 * The flags user_locked, username_locked, group_locked and
3845 * groupname_locked are set to indicate all of those hash lists are
3846 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3847 * the respective one mutex is locked.
3849 user_locked = username_locked = group_locked = groupname_locked = 0;
3850 hp_name = hp_idnum = NULL;
3853 * Delete old entries, as required.
3855 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3856 /* Must lock all username hash lists first, to avoid a LOR. */
3857 for (i = 0; i < nfsrv_lughashsize; i++)
3858 mtx_lock(&nfsusernamehash[i].mtx);
3859 username_locked = 1;
3860 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3861 mtx_lock(&hp_idnum->mtx);
3862 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3864 if (usrp->lug_uid == nidp->nid_uid)
3865 nfsrv_removeuser(usrp, 1);
3867 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3868 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3869 newusrp->lug_namelen);
3870 mtx_lock(&hp_name->mtx);
3871 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3873 if (usrp->lug_namelen == newusrp->lug_namelen &&
3874 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3875 usrp->lug_namelen)) {
3876 thp = NFSUSERHASH(usrp->lug_uid);
3877 mtx_lock(&thp->mtx);
3878 nfsrv_removeuser(usrp, 1);
3879 mtx_unlock(&thp->mtx);
3882 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3883 mtx_lock(&hp_idnum->mtx);
3884 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3885 /* Must lock all groupname hash lists first, to avoid a LOR. */
3886 for (i = 0; i < nfsrv_lughashsize; i++)
3887 mtx_lock(&nfsgroupnamehash[i].mtx);
3888 groupname_locked = 1;
3889 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3890 mtx_lock(&hp_idnum->mtx);
3891 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3893 if (usrp->lug_gid == nidp->nid_gid)
3894 nfsrv_removeuser(usrp, 0);
3896 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3897 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3898 newusrp->lug_namelen);
3899 mtx_lock(&hp_name->mtx);
3900 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3902 if (usrp->lug_namelen == newusrp->lug_namelen &&
3903 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3904 usrp->lug_namelen)) {
3905 thp = NFSGROUPHASH(usrp->lug_gid);
3906 mtx_lock(&thp->mtx);
3907 nfsrv_removeuser(usrp, 0);
3908 mtx_unlock(&thp->mtx);
3911 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3912 mtx_lock(&hp_idnum->mtx);
3916 * Now, we can add the new one.
3918 if (nidp->nid_usertimeout)
3919 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3921 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3922 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3923 newusrp->lug_uid = nidp->nid_uid;
3924 thp = NFSUSERHASH(newusrp->lug_uid);
3925 mtx_assert(&thp->mtx, MA_OWNED);
3926 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3927 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3928 mtx_assert(&thp->mtx, MA_OWNED);
3929 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3930 atomic_add_int(&nfsrv_usercnt, 1);
3931 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3932 newusrp->lug_gid = nidp->nid_gid;
3933 thp = NFSGROUPHASH(newusrp->lug_gid);
3934 mtx_assert(&thp->mtx, MA_OWNED);
3935 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3936 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3937 mtx_assert(&thp->mtx, MA_OWNED);
3938 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3939 atomic_add_int(&nfsrv_usercnt, 1);
3941 if (newusrp->lug_cred != NULL)
3942 crfree(newusrp->lug_cred);
3943 free(newusrp, M_NFSUSERGROUP);
3947 * Once per second, allow one thread to trim the cache.
3949 if (lasttime < NFSD_MONOSEC &&
3950 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3952 * First, unlock the single mutexes, so that all entries
3953 * can be locked and any LOR is avoided.
3955 if (hp_name != NULL) {
3956 mtx_unlock(&hp_name->mtx);
3959 if (hp_idnum != NULL) {
3960 mtx_unlock(&hp_idnum->mtx);
3964 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3965 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3966 if (username_locked == 0) {
3967 for (i = 0; i < nfsrv_lughashsize; i++)
3968 mtx_lock(&nfsusernamehash[i].mtx);
3969 username_locked = 1;
3971 KASSERT(user_locked == 0,
3972 ("nfssvc_idname: user_locked"));
3973 for (i = 0; i < nfsrv_lughashsize; i++)
3974 mtx_lock(&nfsuserhash[i].mtx);
3976 for (i = 0; i < nfsrv_lughashsize; i++) {
3977 TAILQ_FOREACH_SAFE(usrp,
3978 &nfsuserhash[i].lughead, lug_numhash,
3980 if (usrp->lug_expiry < NFSD_MONOSEC)
3981 nfsrv_removeuser(usrp, 1);
3983 for (i = 0; i < nfsrv_lughashsize; i++) {
3985 * Trim the cache using an approximate LRU
3986 * algorithm. This code deletes the least
3987 * recently used entry on each hash list.
3989 if (nfsrv_usercnt <= nfsrv_usermax)
3991 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3993 nfsrv_removeuser(usrp, 1);
3996 if (groupname_locked == 0) {
3997 for (i = 0; i < nfsrv_lughashsize; i++)
3998 mtx_lock(&nfsgroupnamehash[i].mtx);
3999 groupname_locked = 1;
4001 KASSERT(group_locked == 0,
4002 ("nfssvc_idname: group_locked"));
4003 for (i = 0; i < nfsrv_lughashsize; i++)
4004 mtx_lock(&nfsgrouphash[i].mtx);
4006 for (i = 0; i < nfsrv_lughashsize; i++) {
4007 TAILQ_FOREACH_SAFE(usrp,
4008 &nfsgrouphash[i].lughead, lug_numhash,
4010 if (usrp->lug_expiry < NFSD_MONOSEC)
4011 nfsrv_removeuser(usrp, 0);
4013 for (i = 0; i < nfsrv_lughashsize; i++) {
4015 * Trim the cache using an approximate LRU
4016 * algorithm. This code deletes the least
4017 * recently user entry on each hash list.
4019 if (nfsrv_usercnt <= nfsrv_usermax)
4021 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4023 nfsrv_removeuser(usrp, 0);
4026 lasttime = NFSD_MONOSEC;
4027 atomic_store_rel_int(&onethread, 0);
4030 /* Now, unlock all locked mutexes. */
4031 if (hp_idnum != NULL)
4032 mtx_unlock(&hp_idnum->mtx);
4033 if (hp_name != NULL)
4034 mtx_unlock(&hp_name->mtx);
4035 if (user_locked != 0)
4036 for (i = 0; i < nfsrv_lughashsize; i++)
4037 mtx_unlock(&nfsuserhash[i].mtx);
4038 if (username_locked != 0)
4039 for (i = 0; i < nfsrv_lughashsize; i++)
4040 mtx_unlock(&nfsusernamehash[i].mtx);
4041 if (group_locked != 0)
4042 for (i = 0; i < nfsrv_lughashsize; i++)
4043 mtx_unlock(&nfsgrouphash[i].mtx);
4044 if (groupname_locked != 0)
4045 for (i = 0; i < nfsrv_lughashsize; i++)
4046 mtx_unlock(&nfsgroupnamehash[i].mtx);
4053 * Remove a user/group name element.
4056 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4058 struct nfsrv_lughash *hp;
4061 hp = NFSUSERHASH(usrp->lug_uid);
4062 mtx_assert(&hp->mtx, MA_OWNED);
4063 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4064 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4065 mtx_assert(&hp->mtx, MA_OWNED);
4066 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4068 hp = NFSGROUPHASH(usrp->lug_gid);
4069 mtx_assert(&hp->mtx, MA_OWNED);
4070 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4071 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4072 mtx_assert(&hp->mtx, MA_OWNED);
4073 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4075 atomic_add_int(&nfsrv_usercnt, -1);
4076 if (usrp->lug_cred != NULL)
4077 crfree(usrp->lug_cred);
4078 free(usrp, M_NFSUSERGROUP);
4082 * Free up all the allocations related to the name<-->id cache.
4083 * This function should only be called when the nfsuserd daemon isn't
4084 * running, since it doesn't do any locking.
4085 * This function is meant to be used when the nfscommon module is unloaded.
4088 nfsrv_cleanusergroup(void)
4090 struct nfsrv_lughash *hp, *hp2;
4091 struct nfsusrgrp *nusrp, *usrp;
4094 if (nfsuserhash == NULL)
4097 for (i = 0; i < nfsrv_lughashsize; i++) {
4098 hp = &nfsuserhash[i];
4099 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4100 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4101 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4103 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4104 if (usrp->lug_cred != NULL)
4105 crfree(usrp->lug_cred);
4106 free(usrp, M_NFSUSERGROUP);
4108 hp = &nfsgrouphash[i];
4109 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4110 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4111 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4113 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4114 if (usrp->lug_cred != NULL)
4115 crfree(usrp->lug_cred);
4116 free(usrp, M_NFSUSERGROUP);
4118 mtx_destroy(&nfsuserhash[i].mtx);
4119 mtx_destroy(&nfsusernamehash[i].mtx);
4120 mtx_destroy(&nfsgroupnamehash[i].mtx);
4121 mtx_destroy(&nfsgrouphash[i].mtx);
4123 free(nfsuserhash, M_NFSUSERGROUP);
4124 free(nfsusernamehash, M_NFSUSERGROUP);
4125 free(nfsgrouphash, M_NFSUSERGROUP);
4126 free(nfsgroupnamehash, M_NFSUSERGROUP);
4127 free(nfsrv_dnsname, M_NFSSTRING);
4131 * This function scans a byte string and checks for UTF-8 compliance.
4132 * It returns 0 if it conforms and NFSERR_INVAL if not.
4135 nfsrv_checkutf8(u_int8_t *cp, int len)
4137 u_int32_t val = 0x0;
4138 int cnt = 0, gotd = 0, shift = 0;
4140 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4144 * Here are what the variables are used for:
4145 * val - the calculated value of a multibyte char, used to check
4146 * that it was coded with the correct range
4147 * cnt - the number of 10xxxxxx bytes to follow
4148 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4149 * shift - lower order bits of range (ie. "val >> shift" should
4150 * not be 0, in other words, dividing by the lower bound
4151 * of the range should get a non-zero value)
4152 * byte - used to calculate cnt
4156 /* This handles the 10xxxxxx bytes */
4157 if ((*cp & 0xc0) != 0x80 ||
4158 (gotd && (*cp & 0x20))) {
4159 error = NFSERR_INVAL;
4164 val |= (*cp & 0x3f);
4166 if (cnt == 0 && (val >> shift) == 0x0) {
4167 error = NFSERR_INVAL;
4170 } else if (*cp & 0x80) {
4171 /* first byte of multi byte char */
4173 while ((byte & 0x40) && cnt < 6) {
4177 if (cnt == 0 || cnt == 6) {
4178 error = NFSERR_INVAL;
4181 val = (*cp & (0x3f >> cnt));
4182 shift = utf8_shift[cnt - 1];
4183 if (cnt == 2 && val == 0xd)
4184 /* Check for the 0xd800-0xdfff case */
4191 error = NFSERR_INVAL;
4199 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4200 * strings, one with the root path in it and the other with the list of
4201 * locations. The list is in the same format as is found in nfr_refs.
4202 * It is a "," separated list of entries, where each of them is of the
4203 * form <server>:<rootpath>. For example
4204 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4205 * The nilp argument is set to 1 for the special case of a null fs_root
4206 * and an empty server list.
4207 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4208 * number of xdr bytes parsed in sump.
4211 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4212 int *sump, int *nilp)
4215 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4216 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4218 SLIST_ENTRY(list) next;
4222 SLIST_HEAD(, list) head;
4229 * Get the fs_root path and check for the special case of null path
4230 * and 0 length server list.
4232 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4233 len = fxdr_unsigned(int, *tl);
4234 if (len < 0 || len > 10240) {
4235 error = NFSERR_BADXDR;
4239 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4241 error = NFSERR_BADXDR;
4245 *sump = 2 * NFSX_UNSIGNED;
4249 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4250 error = nfsrv_mtostr(nd, cp, len);
4252 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4253 cnt = fxdr_unsigned(int, *tl);
4255 error = NFSERR_BADXDR;
4261 * Now, loop through the location list and make up the srvlist.
4263 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4264 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4267 for (i = 0; i < cnt; i++) {
4269 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4270 nsrv = fxdr_unsigned(int, *tl);
4272 error = NFSERR_BADXDR;
4277 * Handle the first server by putting it in the srvstr.
4279 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4280 len = fxdr_unsigned(int, *tl);
4281 if (len <= 0 || len > 1024) {
4282 error = NFSERR_BADXDR;
4285 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4290 error = nfsrv_mtostr(nd, cp3, len);
4296 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4297 for (j = 1; j < nsrv; j++) {
4299 * Yuck, put them in an slist and process them later.
4301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4302 len = fxdr_unsigned(int, *tl);
4303 if (len <= 0 || len > 1024) {
4304 error = NFSERR_BADXDR;
4307 lsp = (struct list *)malloc(sizeof (struct list)
4308 + len, M_TEMP, M_WAITOK);
4309 error = nfsrv_mtostr(nd, lsp->host, len);
4312 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4314 SLIST_INSERT_HEAD(&head, lsp, next);
4318 * Finally, we can get the path.
4320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4321 len = fxdr_unsigned(int, *tl);
4322 if (len <= 0 || len > 1024) {
4323 error = NFSERR_BADXDR;
4326 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4327 error = nfsrv_mtostr(nd, cp3, len);
4330 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4335 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4336 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4339 NFSBCOPY(lsp->host, cp3, lsp->len);
4342 NFSBCOPY(str, cp3, stringlen);
4345 siz += (lsp->len + stringlen + 2);
4352 NFSEXITCODE2(0, nd);
4356 free(cp, M_NFSSTRING);
4358 free(cp2, M_NFSSTRING);
4359 NFSEXITCODE2(error, nd);
4364 * Make the malloc'd space large enough. This is a pain, but the xdr
4365 * doesn't set an upper bound on the side, so...
4368 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4375 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4376 NFSBCOPY(*cpp, cp, *slenp);
4377 free(*cpp, M_NFSSTRING);
4381 *slenp = siz + 1024;
4385 * Initialize the reply header data structures.
4388 nfsrvd_rephead(struct nfsrv_descript *nd)
4393 * If this is a big reply, use a cluster.
4395 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4396 nfs_bigreply[nd->nd_procnum]) {
4397 NFSMCLGET(mreq, M_WAITOK);
4405 nd->nd_bpos = mtod(mreq, caddr_t);
4408 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4409 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4413 * Lock a socket against others.
4414 * Currently used to serialize connect/disconnect attempts.
4417 newnfs_sndlock(int *flagp)
4422 while (*flagp & NFSR_SNDLOCK) {
4423 *flagp |= NFSR_WANTSND;
4426 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4427 PZERO - 1, "nfsndlck", &ts);
4429 *flagp |= NFSR_SNDLOCK;
4435 * Unlock the stream socket for others.
4438 newnfs_sndunlock(int *flagp)
4442 if ((*flagp & NFSR_SNDLOCK) == 0)
4443 panic("nfs sndunlock");
4444 *flagp &= ~NFSR_SNDLOCK;
4445 if (*flagp & NFSR_WANTSND) {
4446 *flagp &= ~NFSR_WANTSND;
4447 wakeup((caddr_t)flagp);
4453 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4454 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4456 struct in_addr saddr;
4457 uint32_t portnum, *tl;
4459 sa_family_t af = AF_UNSPEC;
4460 char addr[64], protocol[5], *cp;
4461 int cantparse = 0, error = 0;
4464 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4465 i = fxdr_unsigned(int, *tl);
4466 if (i >= 3 && i <= 4) {
4467 error = nfsrv_mtostr(nd, protocol, i);
4470 if (strcmp(protocol, "tcp") == 0) {
4473 } else if (strcmp(protocol, "udp") == 0) {
4476 } else if (strcmp(protocol, "tcp6") == 0) {
4479 } else if (strcmp(protocol, "udp6") == 0) {
4487 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4492 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4493 i = fxdr_unsigned(int, *tl);
4495 error = NFSERR_BADXDR;
4497 } else if (cantparse == 0 && i >= 11 && i < 64) {
4499 * The shortest address is 11chars and the longest is < 64.
4501 error = nfsrv_mtostr(nd, addr, i);
4505 /* Find the port# at the end and extract that. */
4509 /* Count back two '.'s from end to get port# field. */
4510 for (j = 0; j < i; j++) {
4520 * The NFSv4 port# is appended as .N.N, where N is
4521 * a decimal # in the range 0-255, just like an inet4
4522 * address. Cheat and use inet_aton(), which will
4523 * return a Class A address and then shift the high
4524 * order 8bits over to convert it to the port#.
4527 if (inet_aton(cp, &saddr) == 1) {
4528 portnum = ntohl(saddr.s_addr);
4529 portv = (uint16_t)((portnum >> 16) |
4535 if (cantparse == 0) {
4536 if (af == AF_INET) {
4537 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4538 sin->sin_len = sizeof(*sin);
4539 sin->sin_family = AF_INET;
4540 sin->sin_port = htons(portv);
4545 if (inet_pton(af, addr, &sin6->sin6_addr)
4547 sin6->sin6_len = sizeof(*sin6);
4548 sin6->sin6_family = AF_INET6;
4549 sin6->sin6_port = htons(portv);
4557 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4568 * Handle an NFSv4.1 Sequence request for the session.
4569 * If reply != NULL, use it to return the cached reply, as required.
4570 * The client gets a cached reply via this call for callbacks, however the
4571 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4574 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4575 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4582 if (slotid > maxslot)
4583 return (NFSERR_BADSLOT);
4584 if (seqid == slots[slotid].nfssl_seq) {
4586 if (slots[slotid].nfssl_inprog != 0)
4587 error = NFSERR_DELAY;
4588 else if (slots[slotid].nfssl_reply != NULL) {
4589 if (reply != NULL) {
4590 *reply = slots[slotid].nfssl_reply;
4591 slots[slotid].nfssl_reply = NULL;
4593 slots[slotid].nfssl_inprog = 1;
4594 error = NFSERR_REPLYFROMCACHE;
4596 /* No reply cached, so just do it. */
4597 slots[slotid].nfssl_inprog = 1;
4598 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4599 if (slots[slotid].nfssl_reply != NULL)
4600 m_freem(slots[slotid].nfssl_reply);
4601 slots[slotid].nfssl_reply = NULL;
4602 slots[slotid].nfssl_inprog = 1;
4603 slots[slotid].nfssl_seq++;
4605 error = NFSERR_SEQMISORDERED;
4610 * Cache this reply for the slot.
4611 * Use the "rep" argument to return the cached reply if repstat is set to
4612 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4615 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4619 if (repstat == NFSERR_REPLYFROMCACHE) {
4620 *rep = slots[slotid].nfssl_reply;
4621 slots[slotid].nfssl_reply = NULL;
4623 if (slots[slotid].nfssl_reply != NULL)
4624 m_freem(slots[slotid].nfssl_reply);
4625 slots[slotid].nfssl_reply = *rep;
4627 slots[slotid].nfssl_inprog = 0;
4631 * Generate the xdr for an NFSv4.1 Sequence Operation.
4634 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4635 struct nfsclsession *sep, int dont_replycache)
4637 uint32_t *tl, slotseq = 0;
4638 int error, maxslot, slotpos;
4639 uint8_t sessionid[NFSX_V4SESSIONID];
4641 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4643 nd->nd_maxreq = sep->nfsess_maxreq;
4644 nd->nd_maxresp = sep->nfsess_maxresp;
4646 /* Build the Sequence arguments. */
4647 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4648 nd->nd_sequence = tl;
4649 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4650 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4651 nd->nd_slotseq = tl;
4653 nd->nd_flag |= ND_HASSLOTID;
4654 nd->nd_slotid = slotpos;
4655 *tl++ = txdr_unsigned(slotseq);
4656 *tl++ = txdr_unsigned(slotpos);
4657 *tl++ = txdr_unsigned(maxslot);
4658 if (dont_replycache == 0)
4664 * There are two errors and the rest of the session can
4666 * NFSERR_BADSESSION: This bad session should just generate
4667 * the same error again when the RPC is retried.
4668 * ESTALE: A forced dismount is in progress and will cause the
4669 * RPC to fail later.
4676 nd->nd_flag |= ND_HASSEQUENCE;
4680 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4681 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4683 int i, maxslot, slotpos;
4686 /* Find an unused slot. */
4689 mtx_lock(&sep->nfsess_mtx);
4691 if (nmp != NULL && sep->nfsess_defunct != 0) {
4692 /* Just return the bad session. */
4693 bcopy(sep->nfsess_sessionid, sessionid,
4695 mtx_unlock(&sep->nfsess_mtx);
4696 return (NFSERR_BADSESSION);
4699 for (i = 0; i < sep->nfsess_foreslots; i++) {
4700 if ((bitval & sep->nfsess_slots) == 0) {
4702 sep->nfsess_slots |= bitval;
4703 sep->nfsess_slotseq[i]++;
4704 *slotseqp = sep->nfsess_slotseq[i];
4709 if (slotpos == -1) {
4711 * If a forced dismount is in progress, just return.
4712 * This RPC attempt will fail when it calls
4715 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4716 mtx_unlock(&sep->nfsess_mtx);
4719 /* Wake up once/sec, to check for a forced dismount. */
4720 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4721 PZERO, "nfsclseq", hz);
4723 } while (slotpos == -1);
4724 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4726 for (i = 0; i < 64; i++) {
4727 if ((bitval & sep->nfsess_slots) != 0)
4731 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4732 mtx_unlock(&sep->nfsess_mtx);
4733 *slotposp = slotpos;
4734 *maxslotp = maxslot;
4739 * Free a session slot.
4742 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4749 mtx_lock(&sep->nfsess_mtx);
4750 if ((bitval & sep->nfsess_slots) == 0)
4751 printf("freeing free slot!!\n");
4752 sep->nfsess_slots &= ~bitval;
4753 wakeup(&sep->nfsess_slots);
4754 mtx_unlock(&sep->nfsess_mtx);
4758 * Search for a matching pnfsd DS, based on the nmp arg.
4759 * Return one if found, NULL otherwise.
4762 nfsv4_findmirror(struct nfsmount *nmp)
4764 struct nfsdevice *ds;
4766 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4768 * Search the DS server list for a match with nmp.
4770 if (nfsrv_devidcnt == 0)
4772 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4773 if (ds->nfsdev_nmp == nmp) {
4774 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4782 * Fill in the fields of "struct nfsrv_descript".
4785 nfsm_set(struct nfsrv_descript *nd, u_int offs)
4790 nd->nd_bpos = mtod(m, char *) + offs;