2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
46 #include "opt_inet6.h"
48 #include <fs/nfs/nfsport.h>
50 #include <security/mac/mac_framework.h>
53 * Data items converted to xdr at startup, since they are constant
54 * This is kinda hokey, but may save a little time doing byte swaps
56 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
58 /* And other global data */
59 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
61 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
62 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
63 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
66 struct nfssockreq nfsrv_nfsuserdsock;
67 int nfsrv_nfsuserd = 0;
68 struct nfsreqhead nfsd_reqq;
69 uid_t nfsrv_defaultuid = UID_NOBODY;
70 gid_t nfsrv_defaultgid = GID_NOGROUP;
71 int nfsrv_lease = NFSRV_LEASE;
72 int ncl_mbuf_mlen = MLEN;
73 int nfsd_enable_stringtouid = 0;
74 int nfsrv_doflexfile = 0;
75 static int nfs_enable_uidtostring = 0;
78 extern int nfsrv_lughashsize;
79 extern struct mtx nfsrv_dslock_mtx;
80 extern volatile int nfsrv_devidcnt;
81 extern int nfscl_debuglevel;
82 extern struct nfsdevicehead nfsrv_devidhead;
83 extern struct nfsstatsv1 nfsstatsv1;
85 SYSCTL_DECL(_vfs_nfs);
86 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
87 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
89 int nfsrv_maxpnfsmirror = 1;
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
91 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
94 * This array of structures indicates, for V4:
95 * retfh - which of 3 types of calling args are used
96 * 0 - doesn't change cfh or use a sfh
97 * 1 - replaces cfh with a new one (unless it returns an error status)
98 * 2 - uses cfh and sfh
99 * needscfh - if the op wants a cfh and premtime
100 * 0 - doesn't use a cfh
101 * 1 - uses a cfh, but doesn't want pre-op attributes
102 * 2 - uses a cfh and wants pre-op attributes
103 * savereply - indicates a non-idempotent Op
104 * 0 - not non-idempotent
106 * Ops that are ordered via seqid# are handled separately from these
107 * non-idempotent Ops.
108 * Define it here, since it is used by both the client and server.
110 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
111 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
112 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
113 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
114 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
115 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
116 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
117 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
118 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
119 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
124 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
126 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
127 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
128 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
129 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
130 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
133 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
134 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
135 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
136 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
137 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
138 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
139 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
140 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
145 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
149 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
160 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
161 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
162 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
167 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
168 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
169 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
171 #endif /* !APPLEKEXT */
173 static int ncl_mbuf_mhlen = MHLEN;
174 static int nfsrv_usercnt = 0;
175 static int nfsrv_dnsnamelen;
176 static u_char *nfsrv_dnsname = NULL;
177 static int nfsrv_usermax = 999999999;
178 struct nfsrv_lughash {
180 struct nfsuserhashhead lughead;
182 static struct nfsrv_lughash *nfsuserhash;
183 static struct nfsrv_lughash *nfsusernamehash;
184 static struct nfsrv_lughash *nfsgrouphash;
185 static struct nfsrv_lughash *nfsgroupnamehash;
188 * This static array indicates whether or not the RPC generates a large
189 * reply. This is used by nfs_reply() to decide whether or not an mbuf
190 * cluster should be allocated. (If a cluster is required by an RPC
191 * marked 0 in this array, the code will still work, just not quite as
194 static int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
195 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,
196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
198 /* local functions */
199 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
200 static void nfsv4_wanted(struct nfsv4lock *lp);
201 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
202 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
203 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
204 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
206 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
213 } nfsv4_opmap[NFSV41_NPROCS] = {
215 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
216 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
217 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
218 { NFSV4OP_ACCESS, 2, "Access", 6, },
219 { NFSV4OP_READLINK, 2, "Readlink", 8, },
220 { NFSV4OP_READ, 1, "Read", 4, },
221 { NFSV4OP_WRITE, 2, "Write", 5, },
222 { NFSV4OP_OPEN, 5, "Open", 4, },
223 { NFSV4OP_CREATE, 5, "Create", 6, },
224 { NFSV4OP_CREATE, 1, "Create", 6, },
225 { NFSV4OP_CREATE, 3, "Create", 6, },
226 { NFSV4OP_REMOVE, 1, "Remove", 6, },
227 { NFSV4OP_REMOVE, 1, "Remove", 6, },
228 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
229 { NFSV4OP_SAVEFH, 4, "Link", 4, },
230 { NFSV4OP_READDIR, 2, "Readdir", 7, },
231 { NFSV4OP_READDIR, 2, "Readdir", 7, },
232 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
233 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
234 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
235 { NFSV4OP_COMMIT, 2, "Commit", 6, },
236 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
237 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
238 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
239 { NFSV4OP_LOCK, 1, "Lock", 4, },
240 { NFSV4OP_LOCKU, 1, "LockU", 5, },
241 { NFSV4OP_OPEN, 2, "Open", 4, },
242 { NFSV4OP_CLOSE, 1, "Close", 5, },
243 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
244 { NFSV4OP_LOCKT, 1, "LockT", 5, },
245 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
246 { NFSV4OP_RENEW, 1, "Renew", 5, },
247 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
248 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
249 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
250 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
251 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
252 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
253 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
254 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
255 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
256 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
257 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
258 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
259 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
260 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
261 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
262 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
263 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
264 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
265 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
266 { NFSV4OP_READ, 1, "ReadDS", 6, },
267 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
268 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
269 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
273 * NFS RPCS that have large request message size.
275 static int nfs_bigrequest[NFSV41_NPROCS] = {
276 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
282 * Start building a request. Mostly just put the first file handle in
286 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
287 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
288 int vers, int minorvers)
293 nfsattrbit_t attrbits;
296 * First, fill in some of the fields of nd.
298 nd->nd_slotseq = NULL;
299 if (vers == NFS_VER4) {
300 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
301 if (minorvers == NFSV41_MINORVERSION)
302 nd->nd_flag |= ND_NFSV41;
303 } else if (vers == NFS_VER3)
304 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
306 if (NFSHASNFSV4(nmp)) {
307 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
308 if (NFSHASNFSV4N(nmp))
309 nd->nd_flag |= ND_NFSV41;
310 } else if (NFSHASNFSV3(nmp))
311 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
313 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
315 nd->nd_procnum = procnum;
319 * Get the first mbuf for the request.
321 if (nfs_bigrequest[procnum])
322 NFSMCLGET(mb, M_WAITOK);
326 nd->nd_mreq = nd->nd_mb = mb;
327 nd->nd_bpos = NFSMTOD(mb, caddr_t);
330 * And fill the first file handle into the request.
332 if (nd->nd_flag & ND_NFSV4) {
333 opcnt = nfsv4_opmap[procnum].opcnt +
334 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
335 if ((nd->nd_flag & ND_NFSV41) != 0) {
336 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
337 if (procnum == NFSPROC_RENEW)
339 * For the special case of Renew, just do a
343 else if (procnum == NFSPROC_WRITEDS ||
344 procnum == NFSPROC_COMMITDS)
346 * For the special case of a Writeor Commit to
347 * a DS, the opcnt == 3, for Sequence, PutFH,
353 * What should the tag really be?
355 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
356 nfsv4_opmap[procnum].taglen);
357 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
358 if ((nd->nd_flag & ND_NFSV41) != 0)
359 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
361 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
364 *tl = txdr_unsigned(opcnt);
365 if ((nd->nd_flag & ND_NFSV41) != 0 &&
366 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
367 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
369 nd->nd_flag |= ND_LOOPBADSESS;
370 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
371 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
373 sep = nfsmnt_mdssession(nmp);
374 nfsv4_setsequence(nmp, nd, sep,
375 nfs_bigreply[procnum]);
377 nfsv4_setsequence(nmp, nd, sep,
378 nfs_bigreply[procnum]);
380 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
381 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
382 *tl = txdr_unsigned(NFSV4OP_PUTFH);
383 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
384 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
385 == 2 && procnum != NFSPROC_WRITEDS &&
386 procnum != NFSPROC_COMMITDS) {
387 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
388 *tl = txdr_unsigned(NFSV4OP_GETATTR);
390 * For Lookup Ops, we want all the directory
391 * attributes, so we can load the name cache.
393 if (procnum == NFSPROC_LOOKUP ||
394 procnum == NFSPROC_LOOKUPP)
395 NFSGETATTR_ATTRBIT(&attrbits);
397 NFSWCCATTR_ATTRBIT(&attrbits);
398 nd->nd_flag |= ND_V4WCCATTR;
400 (void) nfsrv_putattrbit(nd, &attrbits);
403 if (procnum != NFSPROC_RENEW ||
404 (nd->nd_flag & ND_NFSV41) == 0) {
405 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
406 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
409 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
411 if (procnum < NFSV41_NPROCS)
412 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
416 * Put a state Id in the mbuf list.
419 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
423 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
424 if (flag == NFSSTATEID_PUTALLZERO) {
429 } else if (flag == NFSSTATEID_PUTALLONE) {
430 st->seqid = 0xffffffff;
431 st->other[0] = 0xffffffff;
432 st->other[1] = 0xffffffff;
433 st->other[2] = 0xffffffff;
434 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
436 st->other[0] = stateidp->other[0];
437 st->other[1] = stateidp->other[1];
438 st->other[2] = stateidp->other[2];
440 st->seqid = stateidp->seqid;
441 st->other[0] = stateidp->other[0];
442 st->other[1] = stateidp->other[1];
443 st->other[2] = stateidp->other[2];
448 * Fill in the setable attributes. The full argument indicates whether
449 * to fill in them all or just mode and time.
452 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
453 struct vnode *vp, int flags, u_int32_t rdev)
456 struct nfsv2_sattr *sp;
457 nfsattrbit_t attrbits;
459 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
461 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
462 if (vap->va_mode == (mode_t)VNOVAL)
463 sp->sa_mode = newnfs_xdrneg1;
465 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
466 if (vap->va_uid == (uid_t)VNOVAL)
467 sp->sa_uid = newnfs_xdrneg1;
469 sp->sa_uid = txdr_unsigned(vap->va_uid);
470 if (vap->va_gid == (gid_t)VNOVAL)
471 sp->sa_gid = newnfs_xdrneg1;
473 sp->sa_gid = txdr_unsigned(vap->va_gid);
474 if (flags & NFSSATTR_SIZE0)
476 else if (flags & NFSSATTR_SIZENEG1)
477 sp->sa_size = newnfs_xdrneg1;
478 else if (flags & NFSSATTR_SIZERDEV)
479 sp->sa_size = txdr_unsigned(rdev);
481 sp->sa_size = txdr_unsigned(vap->va_size);
482 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
483 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
486 if (vap->va_mode != (mode_t)VNOVAL) {
487 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
489 *tl = txdr_unsigned(vap->va_mode);
491 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
494 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
495 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
497 *tl = txdr_unsigned(vap->va_uid);
499 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
502 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
503 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
505 *tl = txdr_unsigned(vap->va_gid);
507 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
510 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
511 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
513 txdr_hyper(vap->va_size, tl);
515 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
518 if (vap->va_atime.tv_sec != VNOVAL) {
519 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
520 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
521 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
522 txdr_nfsv3time(&vap->va_atime, tl);
524 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
525 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
528 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
529 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
531 if (vap->va_mtime.tv_sec != VNOVAL) {
532 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
533 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
534 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
535 txdr_nfsv3time(&vap->va_mtime, tl);
537 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
538 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
542 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
546 NFSZERO_ATTRBIT(&attrbits);
547 if (vap->va_mode != (mode_t)VNOVAL)
548 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
549 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
550 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
551 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
552 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
553 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
554 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
555 if (vap->va_atime.tv_sec != VNOVAL)
556 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
557 if (vap->va_mtime.tv_sec != VNOVAL)
558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
559 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
560 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
567 * copies mbuf chain to the uio scatter/gather list
570 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
572 char *mbufcp, *uiocp;
579 mbufcp = nd->nd_dpos;
580 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
581 rem = NFSM_RNDUP(siz) - siz;
583 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
587 left = uiop->uio_iov->iov_len;
588 uiocp = uiop->uio_iov->iov_base;
599 mbufcp = NFSMTOD(mp, caddr_t);
602 ("len %d, corrupted mbuf?", len));
604 xfer = (left > len) ? len : left;
607 if (uiop->uio_iov->iov_op != NULL)
608 (*(uiop->uio_iov->iov_op))
609 (mbufcp, uiocp, xfer);
612 if (uiop->uio_segflg == UIO_SYSSPACE)
613 NFSBCOPY(mbufcp, uiocp, xfer);
615 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
620 uiop->uio_offset += xfer;
621 uiop->uio_resid -= xfer;
623 if (uiop->uio_iov->iov_len <= siz) {
627 uiop->uio_iov->iov_base = (void *)
628 ((char *)uiop->uio_iov->iov_base + uiosiz);
629 uiop->uio_iov->iov_len -= uiosiz;
633 nd->nd_dpos = mbufcp;
637 error = nfsm_advance(nd, rem, len);
643 NFSEXITCODE2(error, nd);
649 * Help break down an mbuf chain by setting the first siz bytes contiguous
650 * pointed to by returned val.
651 * This is used by the macro NFSM_DISSECT for tough
655 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
664 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
666 nd->nd_md = mbuf_next(nd->nd_md);
667 if (nd->nd_md == NULL)
669 left = mbuf_len(nd->nd_md);
670 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
675 } else if (mbuf_next(nd->nd_md) == NULL) {
677 } else if (siz > ncl_mbuf_mhlen) {
678 panic("nfs S too big");
680 MGET(mp2, MT_DATA, how);
683 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
684 mbuf_setnext(nd->nd_md, mp2);
685 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
687 retp = p = NFSMTOD(mp2, caddr_t);
688 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
691 mp2 = mbuf_next(mp2);
692 /* Loop around copying up the siz2 bytes */
696 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
698 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
699 NFSM_DATAP(mp2, xfer);
700 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
705 mp2 = mbuf_next(mp2);
707 mbuf_setlen(nd->nd_md, siz);
709 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
715 * Advance the position in the mbuf chain.
716 * If offs == 0, this is a no-op, but it is simpler to just return from
717 * here than check for offs > 0 for all calls to nfsm_advance.
718 * If left == -1, it should be calculated here.
721 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
728 * A negative offs might indicate a corrupted mbuf chain and,
729 * as such, a printf is logged.
732 printf("nfsrv_advance: negative offs\n");
738 * If left == -1, calculate it here.
741 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
745 * Loop around, advancing over the mbuf data.
747 while (offs > left) {
749 nd->nd_md = mbuf_next(nd->nd_md);
750 if (nd->nd_md == NULL) {
754 left = mbuf_len(nd->nd_md);
755 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
765 * Copy a string into mbuf(s).
766 * Return the number of bytes output, including XDR overheads.
769 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
778 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
779 *tl = txdr_unsigned(siz);
780 rem = NFSM_RNDUP(siz) - siz;
781 bytesize = NFSX_UNSIGNED + siz + rem;
784 left = M_TRAILINGSPACE(m2);
787 * Loop around copying the string to mbuf(s).
791 if (siz > ncl_mbuf_mlen)
792 NFSMCLGET(m1, M_WAITOK);
796 mbuf_setnext(m2, m1);
798 cp2 = NFSMTOD(m2, caddr_t);
799 left = M_TRAILINGSPACE(m2);
805 NFSBCOPY(cp, cp2, xfer);
807 mbuf_setlen(m2, mbuf_len(m2) + xfer);
810 if (siz == 0 && rem) {
812 panic("nfsm_strtom");
813 NFSBZERO(cp2 + xfer, rem);
814 mbuf_setlen(m2, mbuf_len(m2) + rem);
818 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
823 * Called once to initialize data structures...
828 static int nfs_inited = 0;
834 newnfs_true = txdr_unsigned(TRUE);
835 newnfs_false = txdr_unsigned(FALSE);
836 newnfs_xdrneg1 = txdr_unsigned(-1);
837 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
840 NFSSETBOOTTIME(nfsboottime);
843 * Initialize reply list and start timer
845 TAILQ_INIT(&nfsd_reqq);
850 * Put a file handle in an mbuf list.
851 * If the size argument == 0, just use the default size.
852 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
853 * Return the number of bytes output, including XDR overhead.
856 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
860 int fullsiz, rem, bytesize = 0;
864 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
866 if (size > NFSX_V2FH)
867 panic("fh size > NFSX_V2FH for NFSv2");
868 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
869 NFSBCOPY(fhp, cp, size);
870 if (size < NFSX_V2FH)
871 NFSBZERO(cp + size, NFSX_V2FH - size);
872 bytesize = NFSX_V2FH;
876 fullsiz = NFSM_RNDUP(size);
877 rem = fullsiz - size;
879 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
880 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
883 bytesize = NFSX_UNSIGNED + fullsiz;
885 (void) nfsm_strtom(nd, fhp, size);
892 * This function compares two net addresses by family and returns TRUE
893 * if they are the same host.
894 * If there is any doubt, return FALSE.
895 * The AF_INET family is handled as a special case so that address mbufs
896 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
899 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
902 struct sockaddr_in *inetaddr;
908 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
909 if (inetaddr->sin_family == AF_INET &&
910 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
917 struct sockaddr_in6 *inetaddr6;
919 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
920 /* XXX - should test sin6_scope_id ? */
921 if (inetaddr6->sin6_family == AF_INET6 &&
922 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
933 * Similar to the above, but takes to NFSSOCKADDR_T args.
936 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
938 struct sockaddr_in *addr1, *addr2;
939 struct sockaddr *inaddr;
941 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
942 switch (inaddr->sa_family) {
944 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
945 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
946 if (addr2->sin_family == AF_INET &&
947 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
953 struct sockaddr_in6 *inet6addr1, *inet6addr2;
955 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
956 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
957 /* XXX - should test sin6_scope_id ? */
958 if (inet6addr2->sin6_family == AF_INET6 &&
959 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
960 &inet6addr2->sin6_addr))
971 * Trim the stuff already dissected off the mbuf list.
974 newnfs_trimleading(nd)
975 struct nfsrv_descript *nd;
981 * First, free up leading mbufs.
983 if (nd->nd_mrep != nd->nd_md) {
985 while (mbuf_next(m) != nd->nd_md) {
986 if (mbuf_next(m) == NULL)
987 panic("nfsm trim leading");
990 mbuf_setnext(m, NULL);
991 mbuf_freem(nd->nd_mrep);
996 * Now, adjust this mbuf, based on nd_dpos.
998 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
999 if (offs == mbuf_len(m)) {
1003 panic("nfsm trim leading2");
1004 mbuf_setnext(n, NULL);
1006 } else if (offs > 0) {
1007 mbuf_setlen(m, mbuf_len(m) - offs);
1008 NFSM_DATAP(m, offs);
1009 } else if (offs < 0)
1010 panic("nfsm trimleading offs");
1013 nd->nd_dpos = NFSMTOD(m, caddr_t);
1017 * Trim trailing data off the mbuf list being built.
1020 newnfs_trimtrailing(nd, mb, bpos)
1021 struct nfsrv_descript *nd;
1026 if (mbuf_next(mb)) {
1027 mbuf_freem(mbuf_next(mb));
1028 mbuf_setnext(mb, NULL);
1030 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1036 * Dissect a file handle on the client.
1039 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1046 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1047 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1048 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1055 nfhp = malloc(sizeof (struct nfsfh) + len,
1057 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1059 free(nfhp, M_NFSFH);
1062 nfhp->nfh_len = len;
1065 NFSEXITCODE2(error, nd);
1070 * Break down the nfsv4 acl.
1071 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1074 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1075 int *aclsizep, __unused NFSPROC_T *p)
1079 int acecnt, error = 0, aceerr = 0, acesize;
1085 * Parse out the ace entries and expect them to conform to
1086 * what can be supported by R/W/X bits.
1088 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1089 aclsize = NFSX_UNSIGNED;
1090 acecnt = fxdr_unsigned(int, *tl);
1091 if (acecnt > ACL_MAX_ENTRIES)
1092 aceerr = NFSERR_ATTRNOTSUPP;
1093 if (nfsrv_useacl == 0)
1094 aceerr = NFSERR_ATTRNOTSUPP;
1095 for (i = 0; i < acecnt; i++) {
1096 if (aclp && !aceerr)
1097 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1098 &aceerr, &acesize, p);
1100 error = nfsrv_skipace(nd, &acesize);
1105 if (aclp && !aceerr)
1106 aclp->acl_cnt = acecnt;
1110 *aclsizep = aclsize;
1112 NFSEXITCODE2(error, nd);
1117 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1120 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1125 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1126 len = fxdr_unsigned(int, *(tl + 3));
1127 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1129 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1130 NFSEXITCODE2(error, nd);
1135 * Get attribute bits from an mbuf list.
1136 * Returns EBADRPC for a parsing error, 0 otherwise.
1137 * If the clearinvalid flag is set, clear the bits not supported.
1140 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1148 cnt = fxdr_unsigned(int, *tl);
1150 error = NFSERR_BADXDR;
1153 if (cnt > NFSATTRBIT_MAXWORDS)
1154 outcnt = NFSATTRBIT_MAXWORDS;
1157 NFSZERO_ATTRBIT(attrbitp);
1159 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1160 for (i = 0; i < outcnt; i++)
1161 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1163 for (i = 0; i < (cnt - outcnt); i++) {
1164 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1165 if (retnotsupp != NULL && *tl != 0)
1166 *retnotsupp = NFSERR_ATTRNOTSUPP;
1169 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1171 NFSEXITCODE2(error, nd);
1176 * Get the attributes for V4.
1177 * If the compare flag is true, test for any attribute changes,
1178 * otherwise return the attribute values.
1179 * These attributes cover fields in "struct vattr", "struct statfs",
1180 * "struct nfsfsinfo", the file handle and the lease duration.
1181 * The value of retcmpp is set to 1 if all attributes are the same,
1183 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1186 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1187 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1188 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1189 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1190 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1193 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1194 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1195 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1196 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1197 struct nfsfh *tnfhp;
1198 struct nfsreferral *refp;
1201 struct timespec temptime;
1204 u_int32_t freenum = 0, tuint;
1205 u_int64_t uquad = 0, thyp, thyp2;
1211 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1214 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1216 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1222 *retcmpp = retnotsup;
1225 * Just set default values to some of the important ones.
1228 nap->na_type = VREG;
1230 nap->na_rdev = (NFSDEV_T)0;
1231 nap->na_mtime.tv_sec = 0;
1232 nap->na_mtime.tv_nsec = 0;
1235 nap->na_blocksize = NFS_FABLKSIZE;
1238 sbp->f_bsize = NFS_FABLKSIZE;
1246 fsp->fs_rtmax = 8192;
1247 fsp->fs_rtpref = 8192;
1248 fsp->fs_maxname = NFS_MAXNAMLEN;
1249 fsp->fs_wtmax = 8192;
1250 fsp->fs_wtpref = 8192;
1251 fsp->fs_wtmult = NFS_FABLKSIZE;
1252 fsp->fs_dtpref = 8192;
1253 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1254 fsp->fs_timedelta.tv_sec = 0;
1255 fsp->fs_timedelta.tv_nsec = 1;
1256 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1257 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1260 pc->pc_linkmax = NFS_LINK_MAX;
1261 pc->pc_namemax = NAME_MAX;
1263 pc->pc_chownrestricted = 0;
1264 pc->pc_caseinsensitive = 0;
1265 pc->pc_casepreserving = 1;
1268 sfp->sf_ffiles = UINT64_MAX;
1269 sfp->sf_tfiles = UINT64_MAX;
1270 sfp->sf_afiles = UINT64_MAX;
1271 sfp->sf_fbytes = UINT64_MAX;
1272 sfp->sf_tbytes = UINT64_MAX;
1273 sfp->sf_abytes = UINT64_MAX;
1278 * Loop around getting the attributes.
1280 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1281 attrsize = fxdr_unsigned(int, *tl);
1282 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1283 if (attrsum > attrsize) {
1284 error = NFSERR_BADXDR;
1287 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1289 case NFSATTRBIT_SUPPORTEDATTRS:
1291 if (compare || nap == NULL)
1292 error = nfsrv_getattrbits(nd, &retattrbits,
1295 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1299 if (compare && !(*retcmpp)) {
1300 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1302 /* Some filesystem do not support NFSv4ACL */
1303 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1304 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1305 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1307 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1309 *retcmpp = NFSERR_NOTSAME;
1313 case NFSATTRBIT_TYPE:
1314 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1317 if (nap->na_type != nfsv34tov_type(*tl))
1318 *retcmpp = NFSERR_NOTSAME;
1320 } else if (nap != NULL) {
1321 nap->na_type = nfsv34tov_type(*tl);
1323 attrsum += NFSX_UNSIGNED;
1325 case NFSATTRBIT_FHEXPIRETYPE:
1326 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1327 if (compare && !(*retcmpp)) {
1328 if (fxdr_unsigned(int, *tl) !=
1329 NFSV4FHTYPE_PERSISTENT)
1330 *retcmpp = NFSERR_NOTSAME;
1332 attrsum += NFSX_UNSIGNED;
1334 case NFSATTRBIT_CHANGE:
1335 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1338 if (nap->na_filerev != fxdr_hyper(tl))
1339 *retcmpp = NFSERR_NOTSAME;
1341 } else if (nap != NULL) {
1342 nap->na_filerev = fxdr_hyper(tl);
1344 attrsum += NFSX_HYPER;
1346 case NFSATTRBIT_SIZE:
1347 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1350 if (nap->na_size != fxdr_hyper(tl))
1351 *retcmpp = NFSERR_NOTSAME;
1353 } else if (nap != NULL) {
1354 nap->na_size = fxdr_hyper(tl);
1356 attrsum += NFSX_HYPER;
1358 case NFSATTRBIT_LINKSUPPORT:
1359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1362 if (fsp->fs_properties & NFSV3_FSFLINK) {
1363 if (*tl == newnfs_false)
1364 *retcmpp = NFSERR_NOTSAME;
1366 if (*tl == newnfs_true)
1367 *retcmpp = NFSERR_NOTSAME;
1370 } else if (fsp != NULL) {
1371 if (*tl == newnfs_true)
1372 fsp->fs_properties |= NFSV3_FSFLINK;
1374 fsp->fs_properties &= ~NFSV3_FSFLINK;
1376 attrsum += NFSX_UNSIGNED;
1378 case NFSATTRBIT_SYMLINKSUPPORT:
1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1382 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1383 if (*tl == newnfs_false)
1384 *retcmpp = NFSERR_NOTSAME;
1386 if (*tl == newnfs_true)
1387 *retcmpp = NFSERR_NOTSAME;
1390 } else if (fsp != NULL) {
1391 if (*tl == newnfs_true)
1392 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1394 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1396 attrsum += NFSX_UNSIGNED;
1398 case NFSATTRBIT_NAMEDATTR:
1399 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1400 if (compare && !(*retcmpp)) {
1401 if (*tl != newnfs_false)
1402 *retcmpp = NFSERR_NOTSAME;
1404 attrsum += NFSX_UNSIGNED;
1406 case NFSATTRBIT_FSID:
1407 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1408 thyp = fxdr_hyper(tl);
1410 thyp2 = fxdr_hyper(tl);
1412 if (*retcmpp == 0) {
1413 if (thyp != (u_int64_t)
1414 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1415 thyp2 != (u_int64_t)
1416 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1417 *retcmpp = NFSERR_NOTSAME;
1419 } else if (nap != NULL) {
1420 nap->na_filesid[0] = thyp;
1421 nap->na_filesid[1] = thyp2;
1423 attrsum += (4 * NFSX_UNSIGNED);
1425 case NFSATTRBIT_UNIQUEHANDLES:
1426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1427 if (compare && !(*retcmpp)) {
1428 if (*tl != newnfs_true)
1429 *retcmpp = NFSERR_NOTSAME;
1431 attrsum += NFSX_UNSIGNED;
1433 case NFSATTRBIT_LEASETIME:
1434 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1436 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1438 *retcmpp = NFSERR_NOTSAME;
1439 } else if (leasep != NULL) {
1440 *leasep = fxdr_unsigned(u_int32_t, *tl);
1442 attrsum += NFSX_UNSIGNED;
1444 case NFSATTRBIT_RDATTRERROR:
1445 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1448 *retcmpp = NFSERR_INVAL;
1449 } else if (rderrp != NULL) {
1450 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1452 attrsum += NFSX_UNSIGNED;
1454 case NFSATTRBIT_ACL:
1457 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1460 naclp = acl_alloc(M_WAITOK);
1461 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1467 if (aceerr || aclp == NULL ||
1468 nfsrv_compareacl(aclp, naclp))
1469 *retcmpp = NFSERR_NOTSAME;
1472 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1474 *retcmpp = NFSERR_ATTRNOTSUPP;
1478 if (vp != NULL && aclp != NULL)
1479 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1482 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1490 case NFSATTRBIT_ACLSUPPORT:
1491 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1492 if (compare && !(*retcmpp)) {
1493 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1494 if (fxdr_unsigned(u_int32_t, *tl) !=
1496 *retcmpp = NFSERR_NOTSAME;
1498 *retcmpp = NFSERR_ATTRNOTSUPP;
1501 attrsum += NFSX_UNSIGNED;
1503 case NFSATTRBIT_ARCHIVE:
1504 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1505 if (compare && !(*retcmpp))
1506 *retcmpp = NFSERR_ATTRNOTSUPP;
1507 attrsum += NFSX_UNSIGNED;
1509 case NFSATTRBIT_CANSETTIME:
1510 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1513 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1514 if (*tl == newnfs_false)
1515 *retcmpp = NFSERR_NOTSAME;
1517 if (*tl == newnfs_true)
1518 *retcmpp = NFSERR_NOTSAME;
1521 } else if (fsp != NULL) {
1522 if (*tl == newnfs_true)
1523 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1525 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1527 attrsum += NFSX_UNSIGNED;
1529 case NFSATTRBIT_CASEINSENSITIVE:
1530 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1533 if (*tl != newnfs_false)
1534 *retcmpp = NFSERR_NOTSAME;
1536 } else if (pc != NULL) {
1537 pc->pc_caseinsensitive =
1538 fxdr_unsigned(u_int32_t, *tl);
1540 attrsum += NFSX_UNSIGNED;
1542 case NFSATTRBIT_CASEPRESERVING:
1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1546 if (*tl != newnfs_true)
1547 *retcmpp = NFSERR_NOTSAME;
1549 } else if (pc != NULL) {
1550 pc->pc_casepreserving =
1551 fxdr_unsigned(u_int32_t, *tl);
1553 attrsum += NFSX_UNSIGNED;
1555 case NFSATTRBIT_CHOWNRESTRICTED:
1556 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1559 if (*tl != newnfs_true)
1560 *retcmpp = NFSERR_NOTSAME;
1562 } else if (pc != NULL) {
1563 pc->pc_chownrestricted =
1564 fxdr_unsigned(u_int32_t, *tl);
1566 attrsum += NFSX_UNSIGNED;
1568 case NFSATTRBIT_FILEHANDLE:
1569 error = nfsm_getfh(nd, &tnfhp);
1572 tfhsize = tnfhp->nfh_len;
1575 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1577 *retcmpp = NFSERR_NOTSAME;
1578 free(tnfhp, M_NFSFH);
1579 } else if (nfhpp != NULL) {
1582 free(tnfhp, M_NFSFH);
1584 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1586 case NFSATTRBIT_FILEID:
1587 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1588 thyp = fxdr_hyper(tl);
1591 if (nap->na_fileid != thyp)
1592 *retcmpp = NFSERR_NOTSAME;
1594 } else if (nap != NULL)
1595 nap->na_fileid = thyp;
1596 attrsum += NFSX_HYPER;
1598 case NFSATTRBIT_FILESAVAIL:
1599 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1602 sfp->sf_afiles != fxdr_hyper(tl))
1603 *retcmpp = NFSERR_NOTSAME;
1604 } else if (sfp != NULL) {
1605 sfp->sf_afiles = fxdr_hyper(tl);
1607 attrsum += NFSX_HYPER;
1609 case NFSATTRBIT_FILESFREE:
1610 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1613 sfp->sf_ffiles != fxdr_hyper(tl))
1614 *retcmpp = NFSERR_NOTSAME;
1615 } else if (sfp != NULL) {
1616 sfp->sf_ffiles = fxdr_hyper(tl);
1618 attrsum += NFSX_HYPER;
1620 case NFSATTRBIT_FILESTOTAL:
1621 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1624 sfp->sf_tfiles != fxdr_hyper(tl))
1625 *retcmpp = NFSERR_NOTSAME;
1626 } else if (sfp != NULL) {
1627 sfp->sf_tfiles = fxdr_hyper(tl);
1629 attrsum += NFSX_HYPER;
1631 case NFSATTRBIT_FSLOCATIONS:
1632 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1636 if (compare && !(*retcmpp)) {
1637 refp = nfsv4root_getreferral(vp, NULL, 0);
1639 if (cp == NULL || cp2 == NULL ||
1641 strcmp(cp2, refp->nfr_srvlist))
1642 *retcmpp = NFSERR_NOTSAME;
1643 } else if (m == 0) {
1644 *retcmpp = NFSERR_NOTSAME;
1648 free(cp, M_NFSSTRING);
1650 free(cp2, M_NFSSTRING);
1652 case NFSATTRBIT_HIDDEN:
1653 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1654 if (compare && !(*retcmpp))
1655 *retcmpp = NFSERR_ATTRNOTSUPP;
1656 attrsum += NFSX_UNSIGNED;
1658 case NFSATTRBIT_HOMOGENEOUS:
1659 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1662 if (fsp->fs_properties &
1663 NFSV3_FSFHOMOGENEOUS) {
1664 if (*tl == newnfs_false)
1665 *retcmpp = NFSERR_NOTSAME;
1667 if (*tl == newnfs_true)
1668 *retcmpp = NFSERR_NOTSAME;
1671 } else if (fsp != NULL) {
1672 if (*tl == newnfs_true)
1673 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1675 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1677 attrsum += NFSX_UNSIGNED;
1679 case NFSATTRBIT_MAXFILESIZE:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1681 tnfsquad.qval = fxdr_hyper(tl);
1684 tquad = NFSRV_MAXFILESIZE;
1685 if (tquad != tnfsquad.qval)
1686 *retcmpp = NFSERR_NOTSAME;
1688 } else if (fsp != NULL) {
1689 fsp->fs_maxfilesize = tnfsquad.qval;
1691 attrsum += NFSX_HYPER;
1693 case NFSATTRBIT_MAXLINK:
1694 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1697 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1698 *retcmpp = NFSERR_NOTSAME;
1700 } else if (pc != NULL) {
1701 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1703 attrsum += NFSX_UNSIGNED;
1705 case NFSATTRBIT_MAXNAME:
1706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1709 if (fsp->fs_maxname !=
1710 fxdr_unsigned(u_int32_t, *tl))
1711 *retcmpp = NFSERR_NOTSAME;
1714 tuint = fxdr_unsigned(u_int32_t, *tl);
1716 * Some Linux NFSv4 servers report this
1717 * as 0 or 4billion, so I'll set it to
1718 * NFS_MAXNAMLEN. If a server actually creates
1719 * a name longer than NFS_MAXNAMLEN, it will
1720 * get an error back.
1722 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1723 tuint = NFS_MAXNAMLEN;
1725 fsp->fs_maxname = tuint;
1727 pc->pc_namemax = tuint;
1729 attrsum += NFSX_UNSIGNED;
1731 case NFSATTRBIT_MAXREAD:
1732 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1735 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1736 *(tl + 1)) || *tl != 0)
1737 *retcmpp = NFSERR_NOTSAME;
1739 } else if (fsp != NULL) {
1740 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1741 fsp->fs_rtpref = fsp->fs_rtmax;
1742 fsp->fs_dtpref = fsp->fs_rtpref;
1744 attrsum += NFSX_HYPER;
1746 case NFSATTRBIT_MAXWRITE:
1747 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1750 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1751 *(tl + 1)) || *tl != 0)
1752 *retcmpp = NFSERR_NOTSAME;
1754 } else if (fsp != NULL) {
1755 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1756 fsp->fs_wtpref = fsp->fs_wtmax;
1758 attrsum += NFSX_HYPER;
1760 case NFSATTRBIT_MIMETYPE:
1761 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1762 i = fxdr_unsigned(int, *tl);
1763 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1764 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1767 if (compare && !(*retcmpp))
1768 *retcmpp = NFSERR_ATTRNOTSUPP;
1770 case NFSATTRBIT_MODE:
1771 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1774 if (nap->na_mode != nfstov_mode(*tl))
1775 *retcmpp = NFSERR_NOTSAME;
1777 } else if (nap != NULL) {
1778 nap->na_mode = nfstov_mode(*tl);
1780 attrsum += NFSX_UNSIGNED;
1782 case NFSATTRBIT_NOTRUNC:
1783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1786 if (*tl != newnfs_true)
1787 *retcmpp = NFSERR_NOTSAME;
1789 } else if (pc != NULL) {
1790 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1792 attrsum += NFSX_UNSIGNED;
1794 case NFSATTRBIT_NUMLINKS:
1795 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1796 tuint = fxdr_unsigned(u_int32_t, *tl);
1799 if ((u_int32_t)nap->na_nlink != tuint)
1800 *retcmpp = NFSERR_NOTSAME;
1802 } else if (nap != NULL) {
1803 nap->na_nlink = tuint;
1805 attrsum += NFSX_UNSIGNED;
1807 case NFSATTRBIT_OWNER:
1808 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1809 j = fxdr_unsigned(int, *tl);
1811 error = NFSERR_BADXDR;
1814 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1815 if (j > NFSV4_SMALLSTR)
1816 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1819 error = nfsrv_mtostr(nd, cp, j);
1821 if (j > NFSV4_SMALLSTR)
1822 free(cp, M_NFSSTRING);
1827 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1829 *retcmpp = NFSERR_NOTSAME;
1831 } else if (nap != NULL) {
1832 if (nfsv4_strtouid(nd, cp, j, &uid))
1833 nap->na_uid = nfsrv_defaultuid;
1837 if (j > NFSV4_SMALLSTR)
1838 free(cp, M_NFSSTRING);
1840 case NFSATTRBIT_OWNERGROUP:
1841 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1842 j = fxdr_unsigned(int, *tl);
1844 error = NFSERR_BADXDR;
1847 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1848 if (j > NFSV4_SMALLSTR)
1849 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1852 error = nfsrv_mtostr(nd, cp, j);
1854 if (j > NFSV4_SMALLSTR)
1855 free(cp, M_NFSSTRING);
1860 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1862 *retcmpp = NFSERR_NOTSAME;
1864 } else if (nap != NULL) {
1865 if (nfsv4_strtogid(nd, cp, j, &gid))
1866 nap->na_gid = nfsrv_defaultgid;
1870 if (j > NFSV4_SMALLSTR)
1871 free(cp, M_NFSSTRING);
1873 case NFSATTRBIT_QUOTAHARD:
1874 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1876 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1877 freenum = sbp->f_bfree;
1879 freenum = sbp->f_bavail;
1882 * ufs_quotactl() insists that the uid argument
1883 * equal p_ruid for non-root quota access, so
1884 * we'll just make sure that's the case.
1886 savuid = p->p_cred->p_ruid;
1887 p->p_cred->p_ruid = cred->cr_uid;
1888 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1889 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1890 freenum = min(dqb.dqb_bhardlimit, freenum);
1891 p->p_cred->p_ruid = savuid;
1893 uquad = (u_int64_t)freenum;
1894 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1896 if (compare && !(*retcmpp)) {
1897 if (uquad != fxdr_hyper(tl))
1898 *retcmpp = NFSERR_NOTSAME;
1900 attrsum += NFSX_HYPER;
1902 case NFSATTRBIT_QUOTASOFT:
1903 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1905 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1906 freenum = sbp->f_bfree;
1908 freenum = sbp->f_bavail;
1911 * ufs_quotactl() insists that the uid argument
1912 * equal p_ruid for non-root quota access, so
1913 * we'll just make sure that's the case.
1915 savuid = p->p_cred->p_ruid;
1916 p->p_cred->p_ruid = cred->cr_uid;
1917 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1918 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1919 freenum = min(dqb.dqb_bsoftlimit, freenum);
1920 p->p_cred->p_ruid = savuid;
1922 uquad = (u_int64_t)freenum;
1923 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1925 if (compare && !(*retcmpp)) {
1926 if (uquad != fxdr_hyper(tl))
1927 *retcmpp = NFSERR_NOTSAME;
1929 attrsum += NFSX_HYPER;
1931 case NFSATTRBIT_QUOTAUSED:
1932 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1937 * ufs_quotactl() insists that the uid argument
1938 * equal p_ruid for non-root quota access, so
1939 * we'll just make sure that's the case.
1941 savuid = p->p_cred->p_ruid;
1942 p->p_cred->p_ruid = cred->cr_uid;
1943 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1944 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1945 freenum = dqb.dqb_curblocks;
1946 p->p_cred->p_ruid = savuid;
1948 uquad = (u_int64_t)freenum;
1949 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1951 if (compare && !(*retcmpp)) {
1952 if (uquad != fxdr_hyper(tl))
1953 *retcmpp = NFSERR_NOTSAME;
1955 attrsum += NFSX_HYPER;
1957 case NFSATTRBIT_RAWDEV:
1958 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1959 j = fxdr_unsigned(int, *tl++);
1960 k = fxdr_unsigned(int, *tl);
1963 if (nap->na_rdev != NFSMAKEDEV(j, k))
1964 *retcmpp = NFSERR_NOTSAME;
1966 } else if (nap != NULL) {
1967 nap->na_rdev = NFSMAKEDEV(j, k);
1969 attrsum += NFSX_V4SPECDATA;
1971 case NFSATTRBIT_SPACEAVAIL:
1972 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1975 sfp->sf_abytes != fxdr_hyper(tl))
1976 *retcmpp = NFSERR_NOTSAME;
1977 } else if (sfp != NULL) {
1978 sfp->sf_abytes = fxdr_hyper(tl);
1980 attrsum += NFSX_HYPER;
1982 case NFSATTRBIT_SPACEFREE:
1983 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1986 sfp->sf_fbytes != fxdr_hyper(tl))
1987 *retcmpp = NFSERR_NOTSAME;
1988 } else if (sfp != NULL) {
1989 sfp->sf_fbytes = fxdr_hyper(tl);
1991 attrsum += NFSX_HYPER;
1993 case NFSATTRBIT_SPACETOTAL:
1994 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1997 sfp->sf_tbytes != fxdr_hyper(tl))
1998 *retcmpp = NFSERR_NOTSAME;
1999 } else if (sfp != NULL) {
2000 sfp->sf_tbytes = fxdr_hyper(tl);
2002 attrsum += NFSX_HYPER;
2004 case NFSATTRBIT_SPACEUSED:
2005 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2006 thyp = fxdr_hyper(tl);
2009 if ((u_int64_t)nap->na_bytes != thyp)
2010 *retcmpp = NFSERR_NOTSAME;
2012 } else if (nap != NULL) {
2013 nap->na_bytes = thyp;
2015 attrsum += NFSX_HYPER;
2017 case NFSATTRBIT_SYSTEM:
2018 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2019 if (compare && !(*retcmpp))
2020 *retcmpp = NFSERR_ATTRNOTSUPP;
2021 attrsum += NFSX_UNSIGNED;
2023 case NFSATTRBIT_TIMEACCESS:
2024 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2025 fxdr_nfsv4time(tl, &temptime);
2028 if (!NFS_CMPTIME(temptime, nap->na_atime))
2029 *retcmpp = NFSERR_NOTSAME;
2031 } else if (nap != NULL) {
2032 nap->na_atime = temptime;
2034 attrsum += NFSX_V4TIME;
2036 case NFSATTRBIT_TIMEACCESSSET:
2037 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2038 attrsum += NFSX_UNSIGNED;
2039 i = fxdr_unsigned(int, *tl);
2040 if (i == NFSV4SATTRTIME_TOCLIENT) {
2041 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2042 attrsum += NFSX_V4TIME;
2044 if (compare && !(*retcmpp))
2045 *retcmpp = NFSERR_INVAL;
2047 case NFSATTRBIT_TIMEBACKUP:
2048 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2049 if (compare && !(*retcmpp))
2050 *retcmpp = NFSERR_ATTRNOTSUPP;
2051 attrsum += NFSX_V4TIME;
2053 case NFSATTRBIT_TIMECREATE:
2054 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2055 if (compare && !(*retcmpp))
2056 *retcmpp = NFSERR_ATTRNOTSUPP;
2057 attrsum += NFSX_V4TIME;
2059 case NFSATTRBIT_TIMEDELTA:
2060 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2064 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2065 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2066 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2067 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2070 *retcmpp = NFSERR_NOTSAME;
2073 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2076 attrsum += NFSX_V4TIME;
2078 case NFSATTRBIT_TIMEMETADATA:
2079 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2080 fxdr_nfsv4time(tl, &temptime);
2083 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2084 *retcmpp = NFSERR_NOTSAME;
2086 } else if (nap != NULL) {
2087 nap->na_ctime = temptime;
2089 attrsum += NFSX_V4TIME;
2091 case NFSATTRBIT_TIMEMODIFY:
2092 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2093 fxdr_nfsv4time(tl, &temptime);
2096 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2097 *retcmpp = NFSERR_NOTSAME;
2099 } else if (nap != NULL) {
2100 nap->na_mtime = temptime;
2102 attrsum += NFSX_V4TIME;
2104 case NFSATTRBIT_TIMEMODIFYSET:
2105 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2106 attrsum += NFSX_UNSIGNED;
2107 i = fxdr_unsigned(int, *tl);
2108 if (i == NFSV4SATTRTIME_TOCLIENT) {
2109 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2110 attrsum += NFSX_V4TIME;
2112 if (compare && !(*retcmpp))
2113 *retcmpp = NFSERR_INVAL;
2115 case NFSATTRBIT_MOUNTEDONFILEID:
2116 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2117 thyp = fxdr_hyper(tl);
2120 if (!vp || !nfsrv_atroot(vp, &thyp2))
2121 thyp2 = nap->na_fileid;
2123 *retcmpp = NFSERR_NOTSAME;
2125 } else if (nap != NULL)
2126 nap->na_mntonfileno = thyp;
2127 attrsum += NFSX_HYPER;
2129 case NFSATTRBIT_SUPPATTREXCLCREAT:
2131 error = nfsrv_getattrbits(nd, &retattrbits,
2135 if (compare && !(*retcmpp)) {
2136 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2137 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2138 NFSCLRBIT_ATTRBIT(&checkattrbits,
2139 NFSATTRBIT_TIMEACCESSSET);
2140 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2142 *retcmpp = NFSERR_NOTSAME;
2146 case NFSATTRBIT_FSLAYOUTTYPE:
2147 case NFSATTRBIT_LAYOUTTYPE:
2148 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2149 attrsum += NFSX_UNSIGNED;
2150 i = fxdr_unsigned(int, *tl);
2152 NFSM_DISSECT(tl, u_int32_t *, i *
2154 attrsum += i * NFSX_UNSIGNED;
2155 j = fxdr_unsigned(int, *tl);
2156 if (i == 1 && compare && !(*retcmpp) &&
2157 (((nfsrv_doflexfile != 0 ||
2158 nfsrv_maxpnfsmirror > 1) &&
2159 j != NFSLAYOUT_FLEXFILE) ||
2160 (nfsrv_doflexfile == 0 &&
2161 j != NFSLAYOUT_NFSV4_1_FILES)))
2162 *retcmpp = NFSERR_NOTSAME;
2164 if (nfsrv_devidcnt == 0) {
2165 if (compare && !(*retcmpp) && i > 0)
2166 *retcmpp = NFSERR_NOTSAME;
2168 if (compare && !(*retcmpp) && i != 1)
2169 *retcmpp = NFSERR_NOTSAME;
2172 case NFSATTRBIT_LAYOUTALIGNMENT:
2173 case NFSATTRBIT_LAYOUTBLKSIZE:
2174 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2175 attrsum += NFSX_UNSIGNED;
2176 i = fxdr_unsigned(int, *tl);
2177 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2178 *retcmpp = NFSERR_NOTSAME;
2181 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2183 if (compare && !(*retcmpp))
2184 *retcmpp = NFSERR_ATTRNOTSUPP;
2186 * and get out of the loop, since we can't parse
2187 * the unknown attrbute data.
2189 bitpos = NFSATTRBIT_MAX;
2195 * some clients pad the attrlist, so we need to skip over the
2198 if (attrsum > attrsize) {
2199 error = NFSERR_BADXDR;
2201 attrsize = NFSM_RNDUP(attrsize);
2202 if (attrsum < attrsize)
2203 error = nfsm_advance(nd, attrsize - attrsum, -1);
2206 NFSEXITCODE2(error, nd);
2211 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2212 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2213 * The first argument is a pointer to an nfsv4lock structure.
2214 * The second argument is 1 iff a blocking lock is wanted.
2215 * If this argument is 0, the call waits until no thread either wants nor
2216 * holds an exclusive lock.
2217 * It returns 1 if the lock was acquired, 0 otherwise.
2218 * If several processes call this function concurrently wanting the exclusive
2219 * lock, one will get the lock and the rest will return without getting the
2220 * lock. (If the caller must have the lock, it simply calls this function in a
2221 * loop until the function returns 1 to indicate the lock was acquired.)
2222 * Any usecnt must be decremented by calling nfsv4_relref() before
2223 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2224 * be called in a loop.
2225 * The isleptp argument is set to indicate if the call slept, iff not NULL
2226 * and the mp argument indicates to check for a forced dismount, iff not
2230 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2231 void *mutex, struct mount *mp)
2237 * If a lock is wanted, loop around until the lock is acquired by
2238 * someone and then released. If I want the lock, try to acquire it.
2239 * For a lock to be issued, no lock must be in force and the usecnt
2243 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2244 lp->nfslock_usecnt == 0) {
2245 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2246 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2249 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2251 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2252 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2253 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2256 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2259 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2260 PZERO - 1, "nfsv4lck", NULL);
2261 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2262 lp->nfslock_usecnt == 0) {
2263 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2264 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2272 * Release the lock acquired by nfsv4_lock().
2273 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2274 * incremented, as well.
2277 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2280 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2282 lp->nfslock_usecnt++;
2287 * Release a reference cnt.
2290 nfsv4_relref(struct nfsv4lock *lp)
2293 if (lp->nfslock_usecnt <= 0)
2294 panic("nfsv4root ref cnt");
2295 lp->nfslock_usecnt--;
2296 if (lp->nfslock_usecnt == 0)
2301 * Get a reference cnt.
2302 * This function will wait for any exclusive lock to be released, but will
2303 * not wait for threads that want the exclusive lock. If priority needs
2304 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2305 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2306 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2307 * return without getting a refcnt for that case.
2310 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2318 * Wait for a lock held.
2320 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2321 if (mp != NULL && NFSCL_FORCEDISM(mp))
2323 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2326 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2327 PZERO - 1, "nfsv4gr", NULL);
2329 if (mp != NULL && NFSCL_FORCEDISM(mp))
2332 lp->nfslock_usecnt++;
2336 * Get a reference as above, but return failure instead of sleeping if
2337 * an exclusive lock is held.
2340 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2343 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2346 lp->nfslock_usecnt++;
2351 * Test for a lock. Return 1 if locked, 0 otherwise.
2354 nfsv4_testlock(struct nfsv4lock *lp)
2357 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2358 lp->nfslock_usecnt == 0)
2364 * Wake up anyone sleeping, waiting for this lock.
2367 nfsv4_wanted(struct nfsv4lock *lp)
2370 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2371 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2372 wakeup((caddr_t)&lp->nfslock_lock);
2377 * Copy a string from an mbuf list into a character array.
2378 * Return EBADRPC if there is an mbuf error,
2382 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2391 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2392 rem = NFSM_RNDUP(siz) - siz;
2398 NFSBCOPY(cp, str, xfer);
2407 cp = NFSMTOD(mp, caddr_t);
2419 error = nfsm_advance(nd, rem, len);
2425 NFSEXITCODE2(error, nd);
2430 * Fill in the attributes as marked by the bitmap (V4).
2433 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2434 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2435 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2436 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2437 struct statfs *pnfssf)
2439 int bitpos, retnum = 0;
2441 int siz, prefixnum, error;
2442 u_char *cp, namestr[NFSV4_SMALLSTR];
2443 nfsattrbit_t attrbits, retbits;
2444 nfsattrbit_t *retbitp = &retbits;
2445 u_int32_t freenum, *retnump;
2448 struct nfsfsinfo fsinf;
2449 struct timespec temptime;
2450 NFSACL_T *aclp, *naclp = NULL;
2457 * First, set the bits that can be filled and get fsinfo.
2459 NFSSET_ATTRBIT(retbitp, attrbitp);
2461 * If both p and cred are NULL, it is a client side setattr call.
2462 * If both p and cred are not NULL, it is a server side reply call.
2463 * If p is not NULL and cred is NULL, it is a client side callback
2466 if (p == NULL && cred == NULL) {
2467 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2470 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2471 naclp = acl_alloc(M_WAITOK);
2474 nfsvno_getfs(&fsinf, isdgram);
2477 * Get the VFS_STATFS(), since some attributes need them.
2479 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2480 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2481 error = VFS_STATFS(mp, fs);
2484 nd->nd_repstat = NFSERR_ACCES;
2488 NFSCLRSTATFS_ATTRBIT(retbitp);
2494 * And the NFSv4 ACL...
2496 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2497 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2498 supports_nfsv4acls == 0))) {
2499 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2501 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2502 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2503 supports_nfsv4acls == 0)) {
2504 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2505 } else if (naclp != NULL) {
2506 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2507 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2509 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2511 NFSVOPUNLOCK(vp, 0);
2513 error = NFSERR_PERM;
2516 nd->nd_repstat = NFSERR_ACCES;
2520 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2526 * Put out the attribute bitmap for the ones being filled in
2527 * and get the field for the number of attributes returned.
2529 prefixnum = nfsrv_putattrbit(nd, retbitp);
2530 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2531 prefixnum += NFSX_UNSIGNED;
2534 * Now, loop around filling in the attributes for each bit set.
2536 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2537 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2539 case NFSATTRBIT_SUPPORTEDATTRS:
2540 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2541 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2542 && supports_nfsv4acls == 0)) {
2543 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2544 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2546 retnum += nfsrv_putattrbit(nd, &attrbits);
2548 case NFSATTRBIT_TYPE:
2549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2550 *tl = vtonfsv34_type(vap->va_type);
2551 retnum += NFSX_UNSIGNED;
2553 case NFSATTRBIT_FHEXPIRETYPE:
2554 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2555 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2556 retnum += NFSX_UNSIGNED;
2558 case NFSATTRBIT_CHANGE:
2559 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2560 txdr_hyper(vap->va_filerev, tl);
2561 retnum += NFSX_HYPER;
2563 case NFSATTRBIT_SIZE:
2564 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2565 txdr_hyper(vap->va_size, tl);
2566 retnum += NFSX_HYPER;
2568 case NFSATTRBIT_LINKSUPPORT:
2569 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2570 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2574 retnum += NFSX_UNSIGNED;
2576 case NFSATTRBIT_SYMLINKSUPPORT:
2577 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2578 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2582 retnum += NFSX_UNSIGNED;
2584 case NFSATTRBIT_NAMEDATTR:
2585 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2587 retnum += NFSX_UNSIGNED;
2589 case NFSATTRBIT_FSID:
2590 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2592 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2594 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2595 retnum += NFSX_V4FSID;
2597 case NFSATTRBIT_UNIQUEHANDLES:
2598 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2600 retnum += NFSX_UNSIGNED;
2602 case NFSATTRBIT_LEASETIME:
2603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 *tl = txdr_unsigned(nfsrv_lease);
2605 retnum += NFSX_UNSIGNED;
2607 case NFSATTRBIT_RDATTRERROR:
2608 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 *tl = txdr_unsigned(rderror);
2610 retnum += NFSX_UNSIGNED;
2613 * Recommended Attributes. (Only the supported ones.)
2615 case NFSATTRBIT_ACL:
2616 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2618 case NFSATTRBIT_ACLSUPPORT:
2619 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2620 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2621 retnum += NFSX_UNSIGNED;
2623 case NFSATTRBIT_CANSETTIME:
2624 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2629 retnum += NFSX_UNSIGNED;
2631 case NFSATTRBIT_CASEINSENSITIVE:
2632 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2634 retnum += NFSX_UNSIGNED;
2636 case NFSATTRBIT_CASEPRESERVING:
2637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2639 retnum += NFSX_UNSIGNED;
2641 case NFSATTRBIT_CHOWNRESTRICTED:
2642 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2644 retnum += NFSX_UNSIGNED;
2646 case NFSATTRBIT_FILEHANDLE:
2647 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2649 case NFSATTRBIT_FILEID:
2650 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2651 uquad = vap->va_fileid;
2652 txdr_hyper(uquad, tl);
2653 retnum += NFSX_HYPER;
2655 case NFSATTRBIT_FILESAVAIL:
2657 * Check quota and use min(quota, f_ffree).
2659 freenum = fs->f_ffree;
2662 * ufs_quotactl() insists that the uid argument
2663 * equal p_ruid for non-root quota access, so
2664 * we'll just make sure that's the case.
2666 savuid = p->p_cred->p_ruid;
2667 p->p_cred->p_ruid = cred->cr_uid;
2668 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2669 cred->cr_uid, (caddr_t)&dqb))
2670 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2672 p->p_cred->p_ruid = savuid;
2674 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2676 *tl = txdr_unsigned(freenum);
2677 retnum += NFSX_HYPER;
2679 case NFSATTRBIT_FILESFREE:
2680 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2682 *tl = txdr_unsigned(fs->f_ffree);
2683 retnum += NFSX_HYPER;
2685 case NFSATTRBIT_FILESTOTAL:
2686 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2688 *tl = txdr_unsigned(fs->f_files);
2689 retnum += NFSX_HYPER;
2691 case NFSATTRBIT_FSLOCATIONS:
2692 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2695 retnum += 2 * NFSX_UNSIGNED;
2697 case NFSATTRBIT_HOMOGENEOUS:
2698 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2699 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2703 retnum += NFSX_UNSIGNED;
2705 case NFSATTRBIT_MAXFILESIZE:
2706 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2707 uquad = NFSRV_MAXFILESIZE;
2708 txdr_hyper(uquad, tl);
2709 retnum += NFSX_HYPER;
2711 case NFSATTRBIT_MAXLINK:
2712 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2713 *tl = txdr_unsigned(NFS_LINK_MAX);
2714 retnum += NFSX_UNSIGNED;
2716 case NFSATTRBIT_MAXNAME:
2717 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2718 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2719 retnum += NFSX_UNSIGNED;
2721 case NFSATTRBIT_MAXREAD:
2722 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2724 *tl = txdr_unsigned(fsinf.fs_rtmax);
2725 retnum += NFSX_HYPER;
2727 case NFSATTRBIT_MAXWRITE:
2728 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2730 *tl = txdr_unsigned(fsinf.fs_wtmax);
2731 retnum += NFSX_HYPER;
2733 case NFSATTRBIT_MODE:
2734 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2735 *tl = vtonfsv34_mode(vap->va_mode);
2736 retnum += NFSX_UNSIGNED;
2738 case NFSATTRBIT_NOTRUNC:
2739 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2741 retnum += NFSX_UNSIGNED;
2743 case NFSATTRBIT_NUMLINKS:
2744 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2745 *tl = txdr_unsigned(vap->va_nlink);
2746 retnum += NFSX_UNSIGNED;
2748 case NFSATTRBIT_OWNER:
2750 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2751 retnum += nfsm_strtom(nd, cp, siz);
2753 free(cp, M_NFSSTRING);
2755 case NFSATTRBIT_OWNERGROUP:
2757 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2758 retnum += nfsm_strtom(nd, cp, siz);
2760 free(cp, M_NFSSTRING);
2762 case NFSATTRBIT_QUOTAHARD:
2763 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2764 freenum = fs->f_bfree;
2766 freenum = fs->f_bavail;
2769 * ufs_quotactl() insists that the uid argument
2770 * equal p_ruid for non-root quota access, so
2771 * we'll just make sure that's the case.
2773 savuid = p->p_cred->p_ruid;
2774 p->p_cred->p_ruid = cred->cr_uid;
2775 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2776 cred->cr_uid, (caddr_t)&dqb))
2777 freenum = min(dqb.dqb_bhardlimit, freenum);
2778 p->p_cred->p_ruid = savuid;
2780 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2781 uquad = (u_int64_t)freenum;
2782 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2783 txdr_hyper(uquad, tl);
2784 retnum += NFSX_HYPER;
2786 case NFSATTRBIT_QUOTASOFT:
2787 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2788 freenum = fs->f_bfree;
2790 freenum = fs->f_bavail;
2793 * ufs_quotactl() insists that the uid argument
2794 * equal p_ruid for non-root quota access, so
2795 * we'll just make sure that's the case.
2797 savuid = p->p_cred->p_ruid;
2798 p->p_cred->p_ruid = cred->cr_uid;
2799 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2800 cred->cr_uid, (caddr_t)&dqb))
2801 freenum = min(dqb.dqb_bsoftlimit, freenum);
2802 p->p_cred->p_ruid = savuid;
2804 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2805 uquad = (u_int64_t)freenum;
2806 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2807 txdr_hyper(uquad, tl);
2808 retnum += NFSX_HYPER;
2810 case NFSATTRBIT_QUOTAUSED:
2814 * ufs_quotactl() insists that the uid argument
2815 * equal p_ruid for non-root quota access, so
2816 * we'll just make sure that's the case.
2818 savuid = p->p_cred->p_ruid;
2819 p->p_cred->p_ruid = cred->cr_uid;
2820 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2821 cred->cr_uid, (caddr_t)&dqb))
2822 freenum = dqb.dqb_curblocks;
2823 p->p_cred->p_ruid = savuid;
2825 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2826 uquad = (u_int64_t)freenum;
2827 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2828 txdr_hyper(uquad, tl);
2829 retnum += NFSX_HYPER;
2831 case NFSATTRBIT_RAWDEV:
2832 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2833 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2834 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2835 retnum += NFSX_V4SPECDATA;
2837 case NFSATTRBIT_SPACEAVAIL:
2838 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2839 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2841 uquad = (u_int64_t)pnfssf->f_bfree;
2843 uquad = (u_int64_t)fs->f_bfree;
2846 uquad = (u_int64_t)pnfssf->f_bavail;
2848 uquad = (u_int64_t)fs->f_bavail;
2851 uquad *= pnfssf->f_bsize;
2853 uquad *= fs->f_bsize;
2854 txdr_hyper(uquad, tl);
2855 retnum += NFSX_HYPER;
2857 case NFSATTRBIT_SPACEFREE:
2858 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2859 if (pnfssf != NULL) {
2860 uquad = (u_int64_t)pnfssf->f_bfree;
2861 uquad *= pnfssf->f_bsize;
2863 uquad = (u_int64_t)fs->f_bfree;
2864 uquad *= fs->f_bsize;
2866 txdr_hyper(uquad, tl);
2867 retnum += NFSX_HYPER;
2869 case NFSATTRBIT_SPACETOTAL:
2870 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2871 if (pnfssf != NULL) {
2872 uquad = (u_int64_t)pnfssf->f_blocks;
2873 uquad *= pnfssf->f_bsize;
2875 uquad = (u_int64_t)fs->f_blocks;
2876 uquad *= fs->f_bsize;
2878 txdr_hyper(uquad, tl);
2879 retnum += NFSX_HYPER;
2881 case NFSATTRBIT_SPACEUSED:
2882 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2883 txdr_hyper(vap->va_bytes, tl);
2884 retnum += NFSX_HYPER;
2886 case NFSATTRBIT_TIMEACCESS:
2887 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2888 txdr_nfsv4time(&vap->va_atime, tl);
2889 retnum += NFSX_V4TIME;
2891 case NFSATTRBIT_TIMEACCESSSET:
2892 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2893 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2894 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2895 txdr_nfsv4time(&vap->va_atime, tl);
2896 retnum += NFSX_V4SETTIME;
2898 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2899 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2900 retnum += NFSX_UNSIGNED;
2903 case NFSATTRBIT_TIMEDELTA:
2904 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2905 temptime.tv_sec = 0;
2906 temptime.tv_nsec = 1000000000 / hz;
2907 txdr_nfsv4time(&temptime, tl);
2908 retnum += NFSX_V4TIME;
2910 case NFSATTRBIT_TIMEMETADATA:
2911 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2912 txdr_nfsv4time(&vap->va_ctime, tl);
2913 retnum += NFSX_V4TIME;
2915 case NFSATTRBIT_TIMEMODIFY:
2916 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2917 txdr_nfsv4time(&vap->va_mtime, tl);
2918 retnum += NFSX_V4TIME;
2920 case NFSATTRBIT_TIMEMODIFYSET:
2921 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2922 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2923 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2924 txdr_nfsv4time(&vap->va_mtime, tl);
2925 retnum += NFSX_V4SETTIME;
2927 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2928 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2929 retnum += NFSX_UNSIGNED;
2932 case NFSATTRBIT_MOUNTEDONFILEID:
2933 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2935 uquad = mounted_on_fileno;
2937 uquad = vap->va_fileid;
2938 txdr_hyper(uquad, tl);
2939 retnum += NFSX_HYPER;
2941 case NFSATTRBIT_SUPPATTREXCLCREAT:
2942 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2943 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2944 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2945 retnum += nfsrv_putattrbit(nd, &attrbits);
2947 case NFSATTRBIT_FSLAYOUTTYPE:
2948 case NFSATTRBIT_LAYOUTTYPE:
2949 if (nfsrv_devidcnt == 0)
2954 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2955 *tl++ = txdr_unsigned(1); /* One entry. */
2956 if (nfsrv_doflexfile != 0 ||
2957 nfsrv_maxpnfsmirror > 1)
2958 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2960 *tl = txdr_unsigned(
2961 NFSLAYOUT_NFSV4_1_FILES);
2963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2966 retnum += siz * NFSX_UNSIGNED;
2968 case NFSATTRBIT_LAYOUTALIGNMENT:
2969 case NFSATTRBIT_LAYOUTBLKSIZE:
2970 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2971 *tl = txdr_unsigned(NFS_SRVMAXIO);
2972 retnum += NFSX_UNSIGNED;
2975 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2982 *retnump = txdr_unsigned(retnum);
2983 return (retnum + prefixnum);
2987 * Put the attribute bits onto an mbuf list.
2988 * Return the number of bytes of output generated.
2991 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2994 int cnt, i, bytesize;
2996 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2997 if (attrbitp->bits[cnt - 1])
2999 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3000 NFSM_BUILD(tl, u_int32_t *, bytesize);
3001 *tl++ = txdr_unsigned(cnt);
3002 for (i = 0; i < cnt; i++)
3003 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3008 * Convert a uid to a string.
3009 * If the lookup fails, just output the digits.
3011 * cpp - points to a buffer of size NFSV4_SMALLSTR
3012 * (malloc a larger one, as required)
3013 * retlenp - pointer to length to be returned
3016 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3019 struct nfsusrgrp *usrp;
3022 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3023 struct nfsrv_lughash *hp;
3027 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3029 * Always map nfsrv_defaultuid to "nobody".
3031 if (uid == nfsrv_defaultuid) {
3032 i = nfsrv_dnsnamelen + 7;
3034 if (len > NFSV4_SMALLSTR)
3035 free(cp, M_NFSSTRING);
3036 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3042 NFSBCOPY("nobody@", cp, 7);
3044 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3048 hp = NFSUSERHASH(uid);
3050 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3051 if (usrp->lug_uid == uid) {
3052 if (usrp->lug_expiry < NFSD_MONOSEC)
3055 * If the name doesn't already have an '@'
3056 * in it, append @domainname to it.
3058 for (i = 0; i < usrp->lug_namelen; i++) {
3059 if (usrp->lug_name[i] == '@') {
3065 i = usrp->lug_namelen;
3067 i = usrp->lug_namelen +
3068 nfsrv_dnsnamelen + 1;
3070 mtx_unlock(&hp->mtx);
3071 if (len > NFSV4_SMALLSTR)
3072 free(cp, M_NFSSTRING);
3073 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3079 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3080 if (!hasampersand) {
3081 cp += usrp->lug_namelen;
3083 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3085 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3086 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3088 mtx_unlock(&hp->mtx);
3092 mtx_unlock(&hp->mtx);
3094 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3095 if (ret == 0 && cnt < 2)
3100 * No match, just return a string of digits.
3104 while (tmp || i == 0) {
3108 len = (i > len) ? len : i;
3112 for (i = 0; i < len; i++) {
3113 *cp-- = '0' + (tmp % 10);
3120 * Get a credential for the uid with the server's group list.
3121 * If none is found, just return the credential passed in after
3122 * logging a warning message.
3125 nfsrv_getgrpscred(struct ucred *oldcred)
3127 struct nfsusrgrp *usrp;
3128 struct ucred *newcred;
3131 struct nfsrv_lughash *hp;
3134 uid = oldcred->cr_uid;
3136 if (nfsrv_dnsnamelen > 0) {
3137 hp = NFSUSERHASH(uid);
3139 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3140 if (usrp->lug_uid == uid) {
3141 if (usrp->lug_expiry < NFSD_MONOSEC)
3143 if (usrp->lug_cred != NULL) {
3144 newcred = crhold(usrp->lug_cred);
3148 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3149 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3151 mtx_unlock(&hp->mtx);
3155 mtx_unlock(&hp->mtx);
3157 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3158 if (ret == 0 && cnt < 2)
3165 * Convert a string to a uid.
3166 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3168 * If this is called from a client side mount using AUTH_SYS and the
3169 * string is made up entirely of digits, just convert the string to
3173 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3176 char *cp, *endstr, *str0;
3177 struct nfsusrgrp *usrp;
3181 struct nfsrv_lughash *hp, *hp2;
3184 error = NFSERR_BADOWNER;
3187 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3189 tuid = (uid_t)strtoul(str0, &endstr, 10);
3190 if ((endstr - str0) == len) {
3191 /* A numeric string. */
3192 if ((nd->nd_flag & ND_KERBV) == 0 &&
3193 ((nd->nd_flag & ND_NFSCL) != 0 ||
3194 nfsd_enable_stringtouid != 0))
3197 error = NFSERR_BADOWNER;
3203 cp = strchr(str0, '@');
3205 i = (int)(cp++ - str0);
3211 if (nfsrv_dnsnamelen > 0) {
3213 * If an '@' is found and the domain name matches, search for
3214 * the name with dns stripped off.
3215 * Mixed case alpahbetics will match for the domain name, but
3216 * all upper case will not.
3218 if (cnt == 0 && i < len && i > 0 &&
3219 (len - 1 - i) == nfsrv_dnsnamelen &&
3220 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3221 len -= (nfsrv_dnsnamelen + 1);
3226 * Check for the special case of "nobody".
3228 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3229 *uidp = nfsrv_defaultuid;
3234 hp = NFSUSERNAMEHASH(str, len);
3236 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3237 if (usrp->lug_namelen == len &&
3238 !NFSBCMP(usrp->lug_name, str, len)) {
3239 if (usrp->lug_expiry < NFSD_MONOSEC)
3241 hp2 = NFSUSERHASH(usrp->lug_uid);
3242 mtx_lock(&hp2->mtx);
3243 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3244 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3246 *uidp = usrp->lug_uid;
3247 mtx_unlock(&hp2->mtx);
3248 mtx_unlock(&hp->mtx);
3253 mtx_unlock(&hp->mtx);
3255 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3257 if (ret == 0 && cnt < 2)
3260 error = NFSERR_BADOWNER;
3268 * Convert a gid to a string.
3269 * gid - the group id
3270 * cpp - points to a buffer of size NFSV4_SMALLSTR
3271 * (malloc a larger one, as required)
3272 * retlenp - pointer to length to be returned
3275 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3278 struct nfsusrgrp *usrp;
3281 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3282 struct nfsrv_lughash *hp;
3286 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3288 * Always map nfsrv_defaultgid to "nogroup".
3290 if (gid == nfsrv_defaultgid) {
3291 i = nfsrv_dnsnamelen + 8;
3293 if (len > NFSV4_SMALLSTR)
3294 free(cp, M_NFSSTRING);
3295 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3301 NFSBCOPY("nogroup@", cp, 8);
3303 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3307 hp = NFSGROUPHASH(gid);
3309 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3310 if (usrp->lug_gid == gid) {
3311 if (usrp->lug_expiry < NFSD_MONOSEC)
3314 * If the name doesn't already have an '@'
3315 * in it, append @domainname to it.
3317 for (i = 0; i < usrp->lug_namelen; i++) {
3318 if (usrp->lug_name[i] == '@') {
3324 i = usrp->lug_namelen;
3326 i = usrp->lug_namelen +
3327 nfsrv_dnsnamelen + 1;
3329 mtx_unlock(&hp->mtx);
3330 if (len > NFSV4_SMALLSTR)
3331 free(cp, M_NFSSTRING);
3332 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3338 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3339 if (!hasampersand) {
3340 cp += usrp->lug_namelen;
3342 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3344 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3345 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3347 mtx_unlock(&hp->mtx);
3351 mtx_unlock(&hp->mtx);
3353 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3354 if (ret == 0 && cnt < 2)
3359 * No match, just return a string of digits.
3363 while (tmp || i == 0) {
3367 len = (i > len) ? len : i;
3371 for (i = 0; i < len; i++) {
3372 *cp-- = '0' + (tmp % 10);
3379 * Convert a string to a gid.
3380 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3382 * If this is called from a client side mount using AUTH_SYS and the
3383 * string is made up entirely of digits, just convert the string to
3387 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3390 char *cp, *endstr, *str0;
3391 struct nfsusrgrp *usrp;
3395 struct nfsrv_lughash *hp, *hp2;
3398 error = NFSERR_BADOWNER;
3401 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3403 tgid = (gid_t)strtoul(str0, &endstr, 10);
3404 if ((endstr - str0) == len) {
3405 /* A numeric string. */
3406 if ((nd->nd_flag & ND_KERBV) == 0 &&
3407 ((nd->nd_flag & ND_NFSCL) != 0 ||
3408 nfsd_enable_stringtouid != 0))
3411 error = NFSERR_BADOWNER;
3417 cp = strchr(str0, '@');
3419 i = (int)(cp++ - str0);
3425 if (nfsrv_dnsnamelen > 0) {
3427 * If an '@' is found and the dns name matches, search for the
3428 * name with the dns stripped off.
3430 if (cnt == 0 && i < len && i > 0 &&
3431 (len - 1 - i) == nfsrv_dnsnamelen &&
3432 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3433 len -= (nfsrv_dnsnamelen + 1);
3438 * Check for the special case of "nogroup".
3440 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3441 *gidp = nfsrv_defaultgid;
3446 hp = NFSGROUPNAMEHASH(str, len);
3448 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3449 if (usrp->lug_namelen == len &&
3450 !NFSBCMP(usrp->lug_name, str, len)) {
3451 if (usrp->lug_expiry < NFSD_MONOSEC)
3453 hp2 = NFSGROUPHASH(usrp->lug_gid);
3454 mtx_lock(&hp2->mtx);
3455 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3456 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3458 *gidp = usrp->lug_gid;
3459 mtx_unlock(&hp2->mtx);
3460 mtx_unlock(&hp->mtx);
3465 mtx_unlock(&hp->mtx);
3467 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3469 if (ret == 0 && cnt < 2)
3472 error = NFSERR_BADOWNER;
3480 * Cmp len chars, allowing mixed case in the first argument to match lower
3481 * case in the second, but not if the first argument is all upper case.
3482 * Return 0 for a match, 1 otherwise.
3485 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3491 for (i = 0; i < len; i++) {
3492 if (*cp >= 'A' && *cp <= 'Z') {
3493 tmp = *cp++ + ('a' - 'A');
3496 if (tmp >= 'a' && tmp <= 'z')
3509 * Set the port for the nfsuserd.
3512 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3514 struct nfssockreq *rp;
3516 struct sockaddr_in *ad;
3519 struct sockaddr_in6 *ad6;
3520 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3525 if (nfsrv_nfsuserd) {
3533 * Set up the socket record and connect.
3535 rp = &nfsrv_nfsuserdsock;
3536 rp->nr_client = NULL;
3537 rp->nr_sotype = SOCK_DGRAM;
3538 rp->nr_soproto = IPPROTO_UDP;
3539 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3541 rp->nr_prog = RPCPROG_NFSUSERD;
3543 switch (nargs->nuserd_family) {
3546 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3548 ad = (struct sockaddr_in *)rp->nr_nam;
3549 ad->sin_len = sizeof(struct sockaddr_in);
3550 ad->sin_family = AF_INET;
3551 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3552 ad->sin_port = nargs->nuserd_port;
3557 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3559 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3560 ad6->sin6_len = sizeof(struct sockaddr_in6);
3561 ad6->sin6_family = AF_INET6;
3562 ad6->sin6_addr = in6loopback;
3563 ad6->sin6_port = nargs->nuserd_port;
3569 rp->nr_vers = RPCNFSUSERD_VERS;
3571 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3573 free(rp->nr_nam, M_SONAME);
3582 * Delete the nfsuserd port.
3585 nfsrv_nfsuserddelport(void)
3589 if (nfsrv_nfsuserd == 0) {
3595 newnfs_disconnect(&nfsrv_nfsuserdsock);
3596 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3600 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3602 * Returns 0 upon success, non-zero otherwise.
3605 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3608 struct nfsrv_descript *nd;
3610 struct nfsrv_descript nfsd;
3615 if (nfsrv_nfsuserd == 0) {
3622 cred = newnfs_getcred();
3623 nd->nd_flag = ND_GSSINITREPLY;
3626 nd->nd_procnum = procnum;
3627 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3628 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3629 if (procnum == RPCNFSUSERD_GETUID)
3630 *tl = txdr_unsigned(uid);
3632 *tl = txdr_unsigned(gid);
3635 (void) nfsm_strtom(nd, name, len);
3637 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3638 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3641 mbuf_freem(nd->nd_mrep);
3642 error = nd->nd_repstat;
3650 * This function is called from the nfssvc(2) system call, to update the
3651 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3654 nfssvc_idname(struct nfsd_idargs *nidp)
3656 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3657 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3658 int i, group_locked, groupname_locked, user_locked, username_locked;
3663 static int onethread = 0;
3664 static time_t lasttime = 0;
3666 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3670 if (nidp->nid_flag & NFSID_INITIALIZE) {
3671 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3672 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3675 free(cp, M_NFSSTRING);
3678 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3680 * Free up all the old stuff and reinitialize hash
3681 * lists. All mutexes for both lists must be locked,
3682 * with the user/group name ones before the uid/gid
3683 * ones, to avoid a LOR.
3685 for (i = 0; i < nfsrv_lughashsize; i++)
3686 mtx_lock(&nfsusernamehash[i].mtx);
3687 for (i = 0; i < nfsrv_lughashsize; i++)
3688 mtx_lock(&nfsuserhash[i].mtx);
3689 for (i = 0; i < nfsrv_lughashsize; i++)
3690 TAILQ_FOREACH_SAFE(usrp,
3691 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3692 nfsrv_removeuser(usrp, 1);
3693 for (i = 0; i < nfsrv_lughashsize; i++)
3694 mtx_unlock(&nfsuserhash[i].mtx);
3695 for (i = 0; i < nfsrv_lughashsize; i++)
3696 mtx_unlock(&nfsusernamehash[i].mtx);
3697 for (i = 0; i < nfsrv_lughashsize; i++)
3698 mtx_lock(&nfsgroupnamehash[i].mtx);
3699 for (i = 0; i < nfsrv_lughashsize; i++)
3700 mtx_lock(&nfsgrouphash[i].mtx);
3701 for (i = 0; i < nfsrv_lughashsize; i++)
3702 TAILQ_FOREACH_SAFE(usrp,
3703 &nfsgrouphash[i].lughead, lug_numhash,
3705 nfsrv_removeuser(usrp, 0);
3706 for (i = 0; i < nfsrv_lughashsize; i++)
3707 mtx_unlock(&nfsgrouphash[i].mtx);
3708 for (i = 0; i < nfsrv_lughashsize; i++)
3709 mtx_unlock(&nfsgroupnamehash[i].mtx);
3710 free(nfsrv_dnsname, M_NFSSTRING);
3711 nfsrv_dnsname = NULL;
3713 if (nfsuserhash == NULL) {
3714 /* Allocate the hash tables. */
3715 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3716 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3718 for (i = 0; i < nfsrv_lughashsize; i++)
3719 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3720 NULL, MTX_DEF | MTX_DUPOK);
3721 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3722 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3724 for (i = 0; i < nfsrv_lughashsize; i++)
3725 mtx_init(&nfsusernamehash[i].mtx,
3726 "nfsusrhash", NULL, MTX_DEF |
3728 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3729 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3731 for (i = 0; i < nfsrv_lughashsize; i++)
3732 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3733 NULL, MTX_DEF | MTX_DUPOK);
3734 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3735 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3737 for (i = 0; i < nfsrv_lughashsize; i++)
3738 mtx_init(&nfsgroupnamehash[i].mtx,
3739 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3741 /* (Re)initialize the list heads. */
3742 for (i = 0; i < nfsrv_lughashsize; i++)
3743 TAILQ_INIT(&nfsuserhash[i].lughead);
3744 for (i = 0; i < nfsrv_lughashsize; i++)
3745 TAILQ_INIT(&nfsusernamehash[i].lughead);
3746 for (i = 0; i < nfsrv_lughashsize; i++)
3747 TAILQ_INIT(&nfsgrouphash[i].lughead);
3748 for (i = 0; i < nfsrv_lughashsize; i++)
3749 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3752 * Put name in "DNS" string.
3755 nfsrv_defaultuid = nidp->nid_uid;
3756 nfsrv_defaultgid = nidp->nid_gid;
3758 nfsrv_usermax = nidp->nid_usermax;
3759 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3764 * malloc the new one now, so any potential sleep occurs before
3765 * manipulation of the lists.
3767 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3768 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3769 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3771 if (error == 0 && nidp->nid_ngroup > 0 &&
3772 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3773 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3775 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3776 sizeof(gid_t) * nidp->nid_ngroup);
3779 * Create a credential just like svc_getcred(),
3780 * but using the group list provided.
3783 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3784 crsetgroups(cr, nidp->nid_ngroup, grps);
3785 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3786 cr->cr_prison = &prison0;
3787 prison_hold(cr->cr_prison);
3789 mac_cred_associate_nfsd(cr);
3791 newusrp->lug_cred = cr;
3796 free(newusrp, M_NFSUSERGROUP);
3799 newusrp->lug_namelen = nidp->nid_namelen;
3802 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3803 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3804 * The flags user_locked, username_locked, group_locked and
3805 * groupname_locked are set to indicate all of those hash lists are
3806 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3807 * the respective one mutex is locked.
3809 user_locked = username_locked = group_locked = groupname_locked = 0;
3810 hp_name = hp_idnum = NULL;
3813 * Delete old entries, as required.
3815 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3816 /* Must lock all username hash lists first, to avoid a LOR. */
3817 for (i = 0; i < nfsrv_lughashsize; i++)
3818 mtx_lock(&nfsusernamehash[i].mtx);
3819 username_locked = 1;
3820 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3821 mtx_lock(&hp_idnum->mtx);
3822 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3824 if (usrp->lug_uid == nidp->nid_uid)
3825 nfsrv_removeuser(usrp, 1);
3827 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3828 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3829 newusrp->lug_namelen);
3830 mtx_lock(&hp_name->mtx);
3831 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3833 if (usrp->lug_namelen == newusrp->lug_namelen &&
3834 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3835 usrp->lug_namelen)) {
3836 thp = NFSUSERHASH(usrp->lug_uid);
3837 mtx_lock(&thp->mtx);
3838 nfsrv_removeuser(usrp, 1);
3839 mtx_unlock(&thp->mtx);
3842 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3843 mtx_lock(&hp_idnum->mtx);
3844 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3845 /* Must lock all groupname hash lists first, to avoid a LOR. */
3846 for (i = 0; i < nfsrv_lughashsize; i++)
3847 mtx_lock(&nfsgroupnamehash[i].mtx);
3848 groupname_locked = 1;
3849 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3850 mtx_lock(&hp_idnum->mtx);
3851 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3853 if (usrp->lug_gid == nidp->nid_gid)
3854 nfsrv_removeuser(usrp, 0);
3856 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3857 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3858 newusrp->lug_namelen);
3859 mtx_lock(&hp_name->mtx);
3860 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3862 if (usrp->lug_namelen == newusrp->lug_namelen &&
3863 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3864 usrp->lug_namelen)) {
3865 thp = NFSGROUPHASH(usrp->lug_gid);
3866 mtx_lock(&thp->mtx);
3867 nfsrv_removeuser(usrp, 0);
3868 mtx_unlock(&thp->mtx);
3871 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3872 mtx_lock(&hp_idnum->mtx);
3876 * Now, we can add the new one.
3878 if (nidp->nid_usertimeout)
3879 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3881 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3882 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3883 newusrp->lug_uid = nidp->nid_uid;
3884 thp = NFSUSERHASH(newusrp->lug_uid);
3885 mtx_assert(&thp->mtx, MA_OWNED);
3886 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3887 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3888 mtx_assert(&thp->mtx, MA_OWNED);
3889 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3890 atomic_add_int(&nfsrv_usercnt, 1);
3891 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3892 newusrp->lug_gid = nidp->nid_gid;
3893 thp = NFSGROUPHASH(newusrp->lug_gid);
3894 mtx_assert(&thp->mtx, MA_OWNED);
3895 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3896 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3897 mtx_assert(&thp->mtx, MA_OWNED);
3898 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3899 atomic_add_int(&nfsrv_usercnt, 1);
3901 if (newusrp->lug_cred != NULL)
3902 crfree(newusrp->lug_cred);
3903 free(newusrp, M_NFSUSERGROUP);
3907 * Once per second, allow one thread to trim the cache.
3909 if (lasttime < NFSD_MONOSEC &&
3910 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3912 * First, unlock the single mutexes, so that all entries
3913 * can be locked and any LOR is avoided.
3915 if (hp_name != NULL) {
3916 mtx_unlock(&hp_name->mtx);
3919 if (hp_idnum != NULL) {
3920 mtx_unlock(&hp_idnum->mtx);
3924 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3925 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3926 if (username_locked == 0) {
3927 for (i = 0; i < nfsrv_lughashsize; i++)
3928 mtx_lock(&nfsusernamehash[i].mtx);
3929 username_locked = 1;
3931 KASSERT(user_locked == 0,
3932 ("nfssvc_idname: user_locked"));
3933 for (i = 0; i < nfsrv_lughashsize; i++)
3934 mtx_lock(&nfsuserhash[i].mtx);
3936 for (i = 0; i < nfsrv_lughashsize; i++) {
3937 TAILQ_FOREACH_SAFE(usrp,
3938 &nfsuserhash[i].lughead, lug_numhash,
3940 if (usrp->lug_expiry < NFSD_MONOSEC)
3941 nfsrv_removeuser(usrp, 1);
3943 for (i = 0; i < nfsrv_lughashsize; i++) {
3945 * Trim the cache using an approximate LRU
3946 * algorithm. This code deletes the least
3947 * recently used entry on each hash list.
3949 if (nfsrv_usercnt <= nfsrv_usermax)
3951 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3953 nfsrv_removeuser(usrp, 1);
3956 if (groupname_locked == 0) {
3957 for (i = 0; i < nfsrv_lughashsize; i++)
3958 mtx_lock(&nfsgroupnamehash[i].mtx);
3959 groupname_locked = 1;
3961 KASSERT(group_locked == 0,
3962 ("nfssvc_idname: group_locked"));
3963 for (i = 0; i < nfsrv_lughashsize; i++)
3964 mtx_lock(&nfsgrouphash[i].mtx);
3966 for (i = 0; i < nfsrv_lughashsize; i++) {
3967 TAILQ_FOREACH_SAFE(usrp,
3968 &nfsgrouphash[i].lughead, lug_numhash,
3970 if (usrp->lug_expiry < NFSD_MONOSEC)
3971 nfsrv_removeuser(usrp, 0);
3973 for (i = 0; i < nfsrv_lughashsize; i++) {
3975 * Trim the cache using an approximate LRU
3976 * algorithm. This code deletes the least
3977 * recently user entry on each hash list.
3979 if (nfsrv_usercnt <= nfsrv_usermax)
3981 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3983 nfsrv_removeuser(usrp, 0);
3986 lasttime = NFSD_MONOSEC;
3987 atomic_store_rel_int(&onethread, 0);
3990 /* Now, unlock all locked mutexes. */
3991 if (hp_idnum != NULL)
3992 mtx_unlock(&hp_idnum->mtx);
3993 if (hp_name != NULL)
3994 mtx_unlock(&hp_name->mtx);
3995 if (user_locked != 0)
3996 for (i = 0; i < nfsrv_lughashsize; i++)
3997 mtx_unlock(&nfsuserhash[i].mtx);
3998 if (username_locked != 0)
3999 for (i = 0; i < nfsrv_lughashsize; i++)
4000 mtx_unlock(&nfsusernamehash[i].mtx);
4001 if (group_locked != 0)
4002 for (i = 0; i < nfsrv_lughashsize; i++)
4003 mtx_unlock(&nfsgrouphash[i].mtx);
4004 if (groupname_locked != 0)
4005 for (i = 0; i < nfsrv_lughashsize; i++)
4006 mtx_unlock(&nfsgroupnamehash[i].mtx);
4013 * Remove a user/group name element.
4016 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4018 struct nfsrv_lughash *hp;
4021 hp = NFSUSERHASH(usrp->lug_uid);
4022 mtx_assert(&hp->mtx, MA_OWNED);
4023 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4024 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4025 mtx_assert(&hp->mtx, MA_OWNED);
4026 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4028 hp = NFSGROUPHASH(usrp->lug_gid);
4029 mtx_assert(&hp->mtx, MA_OWNED);
4030 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4031 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4032 mtx_assert(&hp->mtx, MA_OWNED);
4033 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4035 atomic_add_int(&nfsrv_usercnt, -1);
4036 if (usrp->lug_cred != NULL)
4037 crfree(usrp->lug_cred);
4038 free(usrp, M_NFSUSERGROUP);
4042 * Free up all the allocations related to the name<-->id cache.
4043 * This function should only be called when the nfsuserd daemon isn't
4044 * running, since it doesn't do any locking.
4045 * This function is meant to be used when the nfscommon module is unloaded.
4048 nfsrv_cleanusergroup(void)
4050 struct nfsrv_lughash *hp, *hp2;
4051 struct nfsusrgrp *nusrp, *usrp;
4054 if (nfsuserhash == NULL)
4057 for (i = 0; i < nfsrv_lughashsize; i++) {
4058 hp = &nfsuserhash[i];
4059 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4060 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4061 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4063 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4064 if (usrp->lug_cred != NULL)
4065 crfree(usrp->lug_cred);
4066 free(usrp, M_NFSUSERGROUP);
4068 hp = &nfsgrouphash[i];
4069 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4070 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4071 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4073 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4074 if (usrp->lug_cred != NULL)
4075 crfree(usrp->lug_cred);
4076 free(usrp, M_NFSUSERGROUP);
4078 mtx_destroy(&nfsuserhash[i].mtx);
4079 mtx_destroy(&nfsusernamehash[i].mtx);
4080 mtx_destroy(&nfsgroupnamehash[i].mtx);
4081 mtx_destroy(&nfsgrouphash[i].mtx);
4083 free(nfsuserhash, M_NFSUSERGROUP);
4084 free(nfsusernamehash, M_NFSUSERGROUP);
4085 free(nfsgrouphash, M_NFSUSERGROUP);
4086 free(nfsgroupnamehash, M_NFSUSERGROUP);
4087 free(nfsrv_dnsname, M_NFSSTRING);
4091 * This function scans a byte string and checks for UTF-8 compliance.
4092 * It returns 0 if it conforms and NFSERR_INVAL if not.
4095 nfsrv_checkutf8(u_int8_t *cp, int len)
4097 u_int32_t val = 0x0;
4098 int cnt = 0, gotd = 0, shift = 0;
4100 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4104 * Here are what the variables are used for:
4105 * val - the calculated value of a multibyte char, used to check
4106 * that it was coded with the correct range
4107 * cnt - the number of 10xxxxxx bytes to follow
4108 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4109 * shift - lower order bits of range (ie. "val >> shift" should
4110 * not be 0, in other words, dividing by the lower bound
4111 * of the range should get a non-zero value)
4112 * byte - used to calculate cnt
4116 /* This handles the 10xxxxxx bytes */
4117 if ((*cp & 0xc0) != 0x80 ||
4118 (gotd && (*cp & 0x20))) {
4119 error = NFSERR_INVAL;
4124 val |= (*cp & 0x3f);
4126 if (cnt == 0 && (val >> shift) == 0x0) {
4127 error = NFSERR_INVAL;
4130 } else if (*cp & 0x80) {
4131 /* first byte of multi byte char */
4133 while ((byte & 0x40) && cnt < 6) {
4137 if (cnt == 0 || cnt == 6) {
4138 error = NFSERR_INVAL;
4141 val = (*cp & (0x3f >> cnt));
4142 shift = utf8_shift[cnt - 1];
4143 if (cnt == 2 && val == 0xd)
4144 /* Check for the 0xd800-0xdfff case */
4151 error = NFSERR_INVAL;
4159 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4160 * strings, one with the root path in it and the other with the list of
4161 * locations. The list is in the same format as is found in nfr_refs.
4162 * It is a "," separated list of entries, where each of them is of the
4163 * form <server>:<rootpath>. For example
4164 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4165 * The nilp argument is set to 1 for the special case of a null fs_root
4166 * and an empty server list.
4167 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4168 * number of xdr bytes parsed in sump.
4171 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4172 int *sump, int *nilp)
4175 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4176 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4178 SLIST_ENTRY(list) next;
4182 SLIST_HEAD(, list) head;
4189 * Get the fs_root path and check for the special case of null path
4190 * and 0 length server list.
4192 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4193 len = fxdr_unsigned(int, *tl);
4194 if (len < 0 || len > 10240) {
4195 error = NFSERR_BADXDR;
4199 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4201 error = NFSERR_BADXDR;
4205 *sump = 2 * NFSX_UNSIGNED;
4209 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4210 error = nfsrv_mtostr(nd, cp, len);
4212 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4213 cnt = fxdr_unsigned(int, *tl);
4215 error = NFSERR_BADXDR;
4221 * Now, loop through the location list and make up the srvlist.
4223 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4224 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4227 for (i = 0; i < cnt; i++) {
4229 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4230 nsrv = fxdr_unsigned(int, *tl);
4232 error = NFSERR_BADXDR;
4237 * Handle the first server by putting it in the srvstr.
4239 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4240 len = fxdr_unsigned(int, *tl);
4241 if (len <= 0 || len > 1024) {
4242 error = NFSERR_BADXDR;
4245 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4250 error = nfsrv_mtostr(nd, cp3, len);
4256 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4257 for (j = 1; j < nsrv; j++) {
4259 * Yuck, put them in an slist and process them later.
4261 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4262 len = fxdr_unsigned(int, *tl);
4263 if (len <= 0 || len > 1024) {
4264 error = NFSERR_BADXDR;
4267 lsp = (struct list *)malloc(sizeof (struct list)
4268 + len, M_TEMP, M_WAITOK);
4269 error = nfsrv_mtostr(nd, lsp->host, len);
4272 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4274 SLIST_INSERT_HEAD(&head, lsp, next);
4278 * Finally, we can get the path.
4280 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4281 len = fxdr_unsigned(int, *tl);
4282 if (len <= 0 || len > 1024) {
4283 error = NFSERR_BADXDR;
4286 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4287 error = nfsrv_mtostr(nd, cp3, len);
4290 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4295 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4296 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4299 NFSBCOPY(lsp->host, cp3, lsp->len);
4302 NFSBCOPY(str, cp3, stringlen);
4305 siz += (lsp->len + stringlen + 2);
4312 NFSEXITCODE2(0, nd);
4316 free(cp, M_NFSSTRING);
4318 free(cp2, M_NFSSTRING);
4319 NFSEXITCODE2(error, nd);
4324 * Make the malloc'd space large enough. This is a pain, but the xdr
4325 * doesn't set an upper bound on the side, so...
4328 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4335 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4336 NFSBCOPY(*cpp, cp, *slenp);
4337 free(*cpp, M_NFSSTRING);
4341 *slenp = siz + 1024;
4345 * Initialize the reply header data structures.
4348 nfsrvd_rephead(struct nfsrv_descript *nd)
4353 * If this is a big reply, use a cluster.
4355 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4356 nfs_bigreply[nd->nd_procnum]) {
4357 NFSMCLGET(mreq, M_WAITOK);
4365 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4366 mbuf_setlen(mreq, 0);
4368 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4369 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4373 * Lock a socket against others.
4374 * Currently used to serialize connect/disconnect attempts.
4377 newnfs_sndlock(int *flagp)
4382 while (*flagp & NFSR_SNDLOCK) {
4383 *flagp |= NFSR_WANTSND;
4386 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4387 PZERO - 1, "nfsndlck", &ts);
4389 *flagp |= NFSR_SNDLOCK;
4395 * Unlock the stream socket for others.
4398 newnfs_sndunlock(int *flagp)
4402 if ((*flagp & NFSR_SNDLOCK) == 0)
4403 panic("nfs sndunlock");
4404 *flagp &= ~NFSR_SNDLOCK;
4405 if (*flagp & NFSR_WANTSND) {
4406 *flagp &= ~NFSR_WANTSND;
4407 wakeup((caddr_t)flagp);
4413 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4414 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4416 struct in_addr saddr;
4417 uint32_t portnum, *tl;
4419 sa_family_t af = AF_UNSPEC;
4420 char addr[64], protocol[5], *cp;
4421 int cantparse = 0, error = 0;
4424 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4425 i = fxdr_unsigned(int, *tl);
4426 if (i >= 3 && i <= 4) {
4427 error = nfsrv_mtostr(nd, protocol, i);
4430 if (strcmp(protocol, "tcp") == 0) {
4433 } else if (strcmp(protocol, "udp") == 0) {
4436 } else if (strcmp(protocol, "tcp6") == 0) {
4439 } else if (strcmp(protocol, "udp6") == 0) {
4447 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4452 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4453 i = fxdr_unsigned(int, *tl);
4455 error = NFSERR_BADXDR;
4457 } else if (cantparse == 0 && i >= 11 && i < 64) {
4459 * The shortest address is 11chars and the longest is < 64.
4461 error = nfsrv_mtostr(nd, addr, i);
4465 /* Find the port# at the end and extract that. */
4469 /* Count back two '.'s from end to get port# field. */
4470 for (j = 0; j < i; j++) {
4480 * The NFSv4 port# is appended as .N.N, where N is
4481 * a decimal # in the range 0-255, just like an inet4
4482 * address. Cheat and use inet_aton(), which will
4483 * return a Class A address and then shift the high
4484 * order 8bits over to convert it to the port#.
4487 if (inet_aton(cp, &saddr) == 1) {
4488 portnum = ntohl(saddr.s_addr);
4489 portv = (uint16_t)((portnum >> 16) |
4495 if (cantparse == 0) {
4496 if (af == AF_INET) {
4497 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4498 sin->sin_len = sizeof(*sin);
4499 sin->sin_family = AF_INET;
4500 sin->sin_port = htons(portv);
4505 if (inet_pton(af, addr, &sin6->sin6_addr)
4507 sin6->sin6_len = sizeof(*sin6);
4508 sin6->sin6_family = AF_INET6;
4509 sin6->sin6_port = htons(portv);
4517 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4528 * Handle an NFSv4.1 Sequence request for the session.
4529 * If reply != NULL, use it to return the cached reply, as required.
4530 * The client gets a cached reply via this call for callbacks, however the
4531 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4534 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4535 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4542 if (slotid > maxslot)
4543 return (NFSERR_BADSLOT);
4544 if (seqid == slots[slotid].nfssl_seq) {
4546 if (slots[slotid].nfssl_inprog != 0)
4547 error = NFSERR_DELAY;
4548 else if (slots[slotid].nfssl_reply != NULL) {
4549 if (reply != NULL) {
4550 *reply = slots[slotid].nfssl_reply;
4551 slots[slotid].nfssl_reply = NULL;
4553 slots[slotid].nfssl_inprog = 1;
4554 error = NFSERR_REPLYFROMCACHE;
4556 /* No reply cached, so just do it. */
4557 slots[slotid].nfssl_inprog = 1;
4558 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4559 if (slots[slotid].nfssl_reply != NULL)
4560 m_freem(slots[slotid].nfssl_reply);
4561 slots[slotid].nfssl_reply = NULL;
4562 slots[slotid].nfssl_inprog = 1;
4563 slots[slotid].nfssl_seq++;
4565 error = NFSERR_SEQMISORDERED;
4570 * Cache this reply for the slot.
4571 * Use the "rep" argument to return the cached reply if repstat is set to
4572 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4575 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4579 if (repstat == NFSERR_REPLYFROMCACHE) {
4580 *rep = slots[slotid].nfssl_reply;
4581 slots[slotid].nfssl_reply = NULL;
4583 if (slots[slotid].nfssl_reply != NULL)
4584 m_freem(slots[slotid].nfssl_reply);
4585 slots[slotid].nfssl_reply = *rep;
4587 slots[slotid].nfssl_inprog = 0;
4591 * Generate the xdr for an NFSv4.1 Sequence Operation.
4594 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4595 struct nfsclsession *sep, int dont_replycache)
4597 uint32_t *tl, slotseq = 0;
4598 int error, maxslot, slotpos;
4599 uint8_t sessionid[NFSX_V4SESSIONID];
4601 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4604 /* Build the Sequence arguments. */
4605 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4606 nd->nd_sequence = tl;
4607 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4608 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4609 nd->nd_slotseq = tl;
4611 nd->nd_flag |= ND_HASSLOTID;
4612 nd->nd_slotid = slotpos;
4613 *tl++ = txdr_unsigned(slotseq);
4614 *tl++ = txdr_unsigned(slotpos);
4615 *tl++ = txdr_unsigned(maxslot);
4616 if (dont_replycache == 0)
4622 * There are two errors and the rest of the session can
4624 * NFSERR_BADSESSION: This bad session should just generate
4625 * the same error again when the RPC is retried.
4626 * ESTALE: A forced dismount is in progress and will cause the
4627 * RPC to fail later.
4634 nd->nd_flag |= ND_HASSEQUENCE;
4638 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4639 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4641 int i, maxslot, slotpos;
4644 /* Find an unused slot. */
4647 mtx_lock(&sep->nfsess_mtx);
4649 if (nmp != NULL && sep->nfsess_defunct != 0) {
4650 /* Just return the bad session. */
4651 bcopy(sep->nfsess_sessionid, sessionid,
4653 mtx_unlock(&sep->nfsess_mtx);
4654 return (NFSERR_BADSESSION);
4657 for (i = 0; i < sep->nfsess_foreslots; i++) {
4658 if ((bitval & sep->nfsess_slots) == 0) {
4660 sep->nfsess_slots |= bitval;
4661 sep->nfsess_slotseq[i]++;
4662 *slotseqp = sep->nfsess_slotseq[i];
4667 if (slotpos == -1) {
4669 * If a forced dismount is in progress, just return.
4670 * This RPC attempt will fail when it calls
4673 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4674 mtx_unlock(&sep->nfsess_mtx);
4677 /* Wake up once/sec, to check for a forced dismount. */
4678 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4679 PZERO, "nfsclseq", hz);
4681 } while (slotpos == -1);
4682 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4684 for (i = 0; i < 64; i++) {
4685 if ((bitval & sep->nfsess_slots) != 0)
4689 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4690 mtx_unlock(&sep->nfsess_mtx);
4691 *slotposp = slotpos;
4692 *maxslotp = maxslot;
4697 * Free a session slot.
4700 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4707 mtx_lock(&sep->nfsess_mtx);
4708 if ((bitval & sep->nfsess_slots) == 0)
4709 printf("freeing free slot!!\n");
4710 sep->nfsess_slots &= ~bitval;
4711 wakeup(&sep->nfsess_slots);
4712 mtx_unlock(&sep->nfsess_mtx);
4716 * Search for a matching pnfsd DS, based on the nmp arg.
4717 * Return one if found, NULL otherwise.
4720 nfsv4_findmirror(struct nfsmount *nmp)
4722 struct nfsdevice *ds;
4724 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4726 * Search the DS server list for a match with nmp.
4728 if (nfsrv_devidcnt == 0)
4730 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4731 if (ds->nfsdev_nmp == nmp) {
4732 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");