2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
45 #include "opt_inet6.h"
47 #include <fs/nfs/nfsport.h>
49 #include <security/mac/mac_framework.h>
52 * Data items converted to xdr at startup, since they are constant
53 * This is kinda hokey, but may save a little time doing byte swaps
55 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
57 /* And other global data */
58 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
60 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
61 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
62 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
65 struct nfssockreq nfsrv_nfsuserdsock;
66 int nfsrv_nfsuserd = 0;
67 struct nfsreqhead nfsd_reqq;
68 uid_t nfsrv_defaultuid = UID_NOBODY;
69 gid_t nfsrv_defaultgid = GID_NOGROUP;
70 int nfsrv_lease = NFSRV_LEASE;
71 int ncl_mbuf_mlen = MLEN;
72 int nfsd_enable_stringtouid = 0;
73 int nfsrv_doflexfile = 0;
74 static int nfs_enable_uidtostring = 0;
77 extern int nfsrv_lughashsize;
78 extern struct mtx nfsrv_dslock_mtx;
79 extern volatile int nfsrv_devidcnt;
80 extern int nfscl_debuglevel;
81 extern struct nfsdevicehead nfsrv_devidhead;
82 extern struct nfsstatsv1 nfsstatsv1;
84 SYSCTL_DECL(_vfs_nfs);
85 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
86 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
88 int nfsrv_maxpnfsmirror = 1;
89 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
90 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
93 * This array of structures indicates, for V4:
94 * retfh - which of 3 types of calling args are used
95 * 0 - doesn't change cfh or use a sfh
96 * 1 - replaces cfh with a new one (unless it returns an error status)
97 * 2 - uses cfh and sfh
98 * needscfh - if the op wants a cfh and premtime
99 * 0 - doesn't use a cfh
100 * 1 - uses a cfh, but doesn't want pre-op attributes
101 * 2 - uses a cfh and wants pre-op attributes
102 * savereply - indicates a non-idempotent Op
103 * 0 - not non-idempotent
105 * Ops that are ordered via seqid# are handled separately from these
106 * non-idempotent Ops.
107 * Define it here, since it is used by both the client and server.
109 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
110 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
111 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
112 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
113 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
115 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
116 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
117 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
118 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
119 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
120 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
121 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
124 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
125 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
126 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
128 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
129 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
132 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
133 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
134 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
135 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
136 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
137 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
138 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
139 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
144 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
147 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
148 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
159 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
160 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
161 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
162 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
167 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
168 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
170 #endif /* !APPLEKEXT */
172 static int ncl_mbuf_mhlen = MHLEN;
173 static int nfsrv_usercnt = 0;
174 static int nfsrv_dnsnamelen;
175 static u_char *nfsrv_dnsname = NULL;
176 static int nfsrv_usermax = 999999999;
177 struct nfsrv_lughash {
179 struct nfsuserhashhead lughead;
181 static struct nfsrv_lughash *nfsuserhash;
182 static struct nfsrv_lughash *nfsusernamehash;
183 static struct nfsrv_lughash *nfsgrouphash;
184 static struct nfsrv_lughash *nfsgroupnamehash;
187 * This static array indicates whether or not the RPC generates a large
188 * reply. This is used by nfs_reply() to decide whether or not an mbuf
189 * cluster should be allocated. (If a cluster is required by an RPC
190 * marked 0 in this array, the code will still work, just not quite as
193 static int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
194 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,
195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
197 /* local functions */
198 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
199 static void nfsv4_wanted(struct nfsv4lock *lp);
200 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
201 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
202 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
203 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
205 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
212 } nfsv4_opmap[NFSV41_NPROCS] = {
214 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
215 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
216 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
217 { NFSV4OP_ACCESS, 2, "Access", 6, },
218 { NFSV4OP_READLINK, 2, "Readlink", 8, },
219 { NFSV4OP_READ, 1, "Read", 4, },
220 { NFSV4OP_WRITE, 2, "Write", 5, },
221 { NFSV4OP_OPEN, 5, "Open", 4, },
222 { NFSV4OP_CREATE, 5, "Create", 6, },
223 { NFSV4OP_CREATE, 1, "Create", 6, },
224 { NFSV4OP_CREATE, 3, "Create", 6, },
225 { NFSV4OP_REMOVE, 1, "Remove", 6, },
226 { NFSV4OP_REMOVE, 1, "Remove", 6, },
227 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
228 { NFSV4OP_SAVEFH, 4, "Link", 4, },
229 { NFSV4OP_READDIR, 2, "Readdir", 7, },
230 { NFSV4OP_READDIR, 2, "Readdir", 7, },
231 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
232 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
233 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
234 { NFSV4OP_COMMIT, 2, "Commit", 6, },
235 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
236 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
237 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
238 { NFSV4OP_LOCK, 1, "Lock", 4, },
239 { NFSV4OP_LOCKU, 1, "LockU", 5, },
240 { NFSV4OP_OPEN, 2, "Open", 4, },
241 { NFSV4OP_CLOSE, 1, "Close", 5, },
242 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
243 { NFSV4OP_LOCKT, 1, "LockT", 5, },
244 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
245 { NFSV4OP_RENEW, 1, "Renew", 5, },
246 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
247 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
248 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
249 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
250 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
251 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
252 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
253 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
254 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
255 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
256 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
257 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
258 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
259 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
260 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
261 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
262 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
263 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
264 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
265 { NFSV4OP_READ, 1, "ReadDS", 6, },
266 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
267 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
268 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
272 * NFS RPCS that have large request message size.
274 static int nfs_bigrequest[NFSV41_NPROCS] = {
275 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
281 * Start building a request. Mostly just put the first file handle in
285 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
286 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
287 int vers, int minorvers)
292 nfsattrbit_t attrbits;
295 * First, fill in some of the fields of nd.
297 nd->nd_slotseq = NULL;
298 if (vers == NFS_VER4) {
299 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
300 if (minorvers == NFSV41_MINORVERSION)
301 nd->nd_flag |= ND_NFSV41;
302 } else if (vers == NFS_VER3)
303 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
305 if (NFSHASNFSV4(nmp)) {
306 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
307 if (NFSHASNFSV4N(nmp))
308 nd->nd_flag |= ND_NFSV41;
309 } else if (NFSHASNFSV3(nmp))
310 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
312 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
314 nd->nd_procnum = procnum;
318 * Get the first mbuf for the request.
320 if (nfs_bigrequest[procnum])
321 NFSMCLGET(mb, M_WAITOK);
325 nd->nd_mreq = nd->nd_mb = mb;
326 nd->nd_bpos = NFSMTOD(mb, caddr_t);
329 * And fill the first file handle into the request.
331 if (nd->nd_flag & ND_NFSV4) {
332 opcnt = nfsv4_opmap[procnum].opcnt +
333 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
334 if ((nd->nd_flag & ND_NFSV41) != 0) {
335 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
336 if (procnum == NFSPROC_RENEW)
338 * For the special case of Renew, just do a
342 else if (procnum == NFSPROC_WRITEDS ||
343 procnum == NFSPROC_COMMITDS)
345 * For the special case of a Writeor Commit to
346 * a DS, the opcnt == 3, for Sequence, PutFH,
352 * What should the tag really be?
354 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
355 nfsv4_opmap[procnum].taglen);
356 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
357 if ((nd->nd_flag & ND_NFSV41) != 0)
358 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
360 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
363 *tl = txdr_unsigned(opcnt);
364 if ((nd->nd_flag & ND_NFSV41) != 0 &&
365 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
366 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
368 nd->nd_flag |= ND_LOOPBADSESS;
369 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
370 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
372 sep = nfsmnt_mdssession(nmp);
373 nfsv4_setsequence(nmp, nd, sep,
374 nfs_bigreply[procnum]);
376 nfsv4_setsequence(nmp, nd, sep,
377 nfs_bigreply[procnum]);
379 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
380 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
381 *tl = txdr_unsigned(NFSV4OP_PUTFH);
382 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
383 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
384 == 2 && procnum != NFSPROC_WRITEDS &&
385 procnum != NFSPROC_COMMITDS) {
386 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
387 *tl = txdr_unsigned(NFSV4OP_GETATTR);
389 * For Lookup Ops, we want all the directory
390 * attributes, so we can load the name cache.
392 if (procnum == NFSPROC_LOOKUP ||
393 procnum == NFSPROC_LOOKUPP)
394 NFSGETATTR_ATTRBIT(&attrbits);
396 NFSWCCATTR_ATTRBIT(&attrbits);
397 nd->nd_flag |= ND_V4WCCATTR;
399 (void) nfsrv_putattrbit(nd, &attrbits);
402 if (procnum != NFSPROC_RENEW ||
403 (nd->nd_flag & ND_NFSV41) == 0) {
404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
405 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
408 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
410 if (procnum < NFSV41_NPROCS)
411 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
415 * Put a state Id in the mbuf list.
418 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
422 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
423 if (flag == NFSSTATEID_PUTALLZERO) {
428 } else if (flag == NFSSTATEID_PUTALLONE) {
429 st->seqid = 0xffffffff;
430 st->other[0] = 0xffffffff;
431 st->other[1] = 0xffffffff;
432 st->other[2] = 0xffffffff;
433 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
435 st->other[0] = stateidp->other[0];
436 st->other[1] = stateidp->other[1];
437 st->other[2] = stateidp->other[2];
439 st->seqid = stateidp->seqid;
440 st->other[0] = stateidp->other[0];
441 st->other[1] = stateidp->other[1];
442 st->other[2] = stateidp->other[2];
447 * Fill in the setable attributes. The full argument indicates whether
448 * to fill in them all or just mode and time.
451 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
452 struct vnode *vp, int flags, u_int32_t rdev)
455 struct nfsv2_sattr *sp;
456 nfsattrbit_t attrbits;
458 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
460 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
461 if (vap->va_mode == (mode_t)VNOVAL)
462 sp->sa_mode = newnfs_xdrneg1;
464 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
465 if (vap->va_uid == (uid_t)VNOVAL)
466 sp->sa_uid = newnfs_xdrneg1;
468 sp->sa_uid = txdr_unsigned(vap->va_uid);
469 if (vap->va_gid == (gid_t)VNOVAL)
470 sp->sa_gid = newnfs_xdrneg1;
472 sp->sa_gid = txdr_unsigned(vap->va_gid);
473 if (flags & NFSSATTR_SIZE0)
475 else if (flags & NFSSATTR_SIZENEG1)
476 sp->sa_size = newnfs_xdrneg1;
477 else if (flags & NFSSATTR_SIZERDEV)
478 sp->sa_size = txdr_unsigned(rdev);
480 sp->sa_size = txdr_unsigned(vap->va_size);
481 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
482 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
485 if (vap->va_mode != (mode_t)VNOVAL) {
486 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
488 *tl = txdr_unsigned(vap->va_mode);
490 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
493 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
494 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
496 *tl = txdr_unsigned(vap->va_uid);
498 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
501 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
502 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
504 *tl = txdr_unsigned(vap->va_gid);
506 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
509 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
510 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
512 txdr_hyper(vap->va_size, tl);
514 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
517 if (vap->va_atime.tv_sec != VNOVAL) {
518 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
519 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
520 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
521 txdr_nfsv3time(&vap->va_atime, tl);
523 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
524 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
527 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
528 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
530 if (vap->va_mtime.tv_sec != VNOVAL) {
531 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
532 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
533 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
534 txdr_nfsv3time(&vap->va_mtime, tl);
536 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
537 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
540 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
541 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
545 NFSZERO_ATTRBIT(&attrbits);
546 if (vap->va_mode != (mode_t)VNOVAL)
547 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
548 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
549 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
550 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
551 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
552 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
553 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
554 if (vap->va_atime.tv_sec != VNOVAL)
555 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
556 if (vap->va_mtime.tv_sec != VNOVAL)
557 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
558 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
559 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
566 * copies mbuf chain to the uio scatter/gather list
569 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
571 char *mbufcp, *uiocp;
578 mbufcp = nd->nd_dpos;
579 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
580 rem = NFSM_RNDUP(siz) - siz;
582 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
586 left = uiop->uio_iov->iov_len;
587 uiocp = uiop->uio_iov->iov_base;
598 mbufcp = NFSMTOD(mp, caddr_t);
601 ("len %d, corrupted mbuf?", len));
603 xfer = (left > len) ? len : left;
606 if (uiop->uio_iov->iov_op != NULL)
607 (*(uiop->uio_iov->iov_op))
608 (mbufcp, uiocp, xfer);
611 if (uiop->uio_segflg == UIO_SYSSPACE)
612 NFSBCOPY(mbufcp, uiocp, xfer);
614 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
619 uiop->uio_offset += xfer;
620 uiop->uio_resid -= xfer;
622 if (uiop->uio_iov->iov_len <= siz) {
626 uiop->uio_iov->iov_base = (void *)
627 ((char *)uiop->uio_iov->iov_base + uiosiz);
628 uiop->uio_iov->iov_len -= uiosiz;
632 nd->nd_dpos = mbufcp;
636 error = nfsm_advance(nd, rem, len);
642 NFSEXITCODE2(error, nd);
648 * Help break down an mbuf chain by setting the first siz bytes contiguous
649 * pointed to by returned val.
650 * This is used by the macro NFSM_DISSECT for tough
654 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
663 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
665 nd->nd_md = mbuf_next(nd->nd_md);
666 if (nd->nd_md == NULL)
668 left = mbuf_len(nd->nd_md);
669 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
674 } else if (mbuf_next(nd->nd_md) == NULL) {
676 } else if (siz > ncl_mbuf_mhlen) {
677 panic("nfs S too big");
679 MGET(mp2, MT_DATA, how);
682 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
683 mbuf_setnext(nd->nd_md, mp2);
684 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
686 retp = p = NFSMTOD(mp2, caddr_t);
687 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
690 mp2 = mbuf_next(mp2);
691 /* Loop around copying up the siz2 bytes */
695 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
697 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
698 NFSM_DATAP(mp2, xfer);
699 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
704 mp2 = mbuf_next(mp2);
706 mbuf_setlen(nd->nd_md, siz);
708 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
714 * Advance the position in the mbuf chain.
715 * If offs == 0, this is a no-op, but it is simpler to just return from
716 * here than check for offs > 0 for all calls to nfsm_advance.
717 * If left == -1, it should be calculated here.
720 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
727 * A negative offs might indicate a corrupted mbuf chain and,
728 * as such, a printf is logged.
731 printf("nfsrv_advance: negative offs\n");
737 * If left == -1, calculate it here.
740 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
744 * Loop around, advancing over the mbuf data.
746 while (offs > left) {
748 nd->nd_md = mbuf_next(nd->nd_md);
749 if (nd->nd_md == NULL) {
753 left = mbuf_len(nd->nd_md);
754 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
764 * Copy a string into mbuf(s).
765 * Return the number of bytes output, including XDR overheads.
768 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
778 *tl = txdr_unsigned(siz);
779 rem = NFSM_RNDUP(siz) - siz;
780 bytesize = NFSX_UNSIGNED + siz + rem;
783 left = M_TRAILINGSPACE(m2);
786 * Loop around copying the string to mbuf(s).
790 if (siz > ncl_mbuf_mlen)
791 NFSMCLGET(m1, M_WAITOK);
795 mbuf_setnext(m2, m1);
797 cp2 = NFSMTOD(m2, caddr_t);
798 left = M_TRAILINGSPACE(m2);
804 NFSBCOPY(cp, cp2, xfer);
806 mbuf_setlen(m2, mbuf_len(m2) + xfer);
809 if (siz == 0 && rem) {
811 panic("nfsm_strtom");
812 NFSBZERO(cp2 + xfer, rem);
813 mbuf_setlen(m2, mbuf_len(m2) + rem);
817 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
822 * Called once to initialize data structures...
827 static int nfs_inited = 0;
833 newnfs_true = txdr_unsigned(TRUE);
834 newnfs_false = txdr_unsigned(FALSE);
835 newnfs_xdrneg1 = txdr_unsigned(-1);
836 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
839 NFSSETBOOTTIME(nfsboottime);
842 * Initialize reply list and start timer
844 TAILQ_INIT(&nfsd_reqq);
849 * Put a file handle in an mbuf list.
850 * If the size argument == 0, just use the default size.
851 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
852 * Return the number of bytes output, including XDR overhead.
855 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
859 int fullsiz, rem, bytesize = 0;
863 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
865 if (size > NFSX_V2FH)
866 panic("fh size > NFSX_V2FH for NFSv2");
867 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
868 NFSBCOPY(fhp, cp, size);
869 if (size < NFSX_V2FH)
870 NFSBZERO(cp + size, NFSX_V2FH - size);
871 bytesize = NFSX_V2FH;
875 fullsiz = NFSM_RNDUP(size);
876 rem = fullsiz - size;
878 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
879 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
882 bytesize = NFSX_UNSIGNED + fullsiz;
884 (void) nfsm_strtom(nd, fhp, size);
891 * This function compares two net addresses by family and returns TRUE
892 * if they are the same host.
893 * If there is any doubt, return FALSE.
894 * The AF_INET family is handled as a special case so that address mbufs
895 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
898 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
900 struct sockaddr_in *inetaddr;
904 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
905 if (inetaddr->sin_family == AF_INET &&
906 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
912 struct sockaddr_in6 *inetaddr6;
914 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
915 /* XXX - should test sin6_scope_id ? */
916 if (inetaddr6->sin6_family == AF_INET6 &&
917 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
928 * Similar to the above, but takes to NFSSOCKADDR_T args.
931 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
933 struct sockaddr_in *addr1, *addr2;
934 struct sockaddr *inaddr;
936 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
937 switch (inaddr->sa_family) {
939 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
940 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
941 if (addr2->sin_family == AF_INET &&
942 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
948 struct sockaddr_in6 *inet6addr1, *inet6addr2;
950 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
951 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
952 /* XXX - should test sin6_scope_id ? */
953 if (inet6addr2->sin6_family == AF_INET6 &&
954 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
955 &inet6addr2->sin6_addr))
966 * Trim the stuff already dissected off the mbuf list.
969 newnfs_trimleading(nd)
970 struct nfsrv_descript *nd;
976 * First, free up leading mbufs.
978 if (nd->nd_mrep != nd->nd_md) {
980 while (mbuf_next(m) != nd->nd_md) {
981 if (mbuf_next(m) == NULL)
982 panic("nfsm trim leading");
985 mbuf_setnext(m, NULL);
986 mbuf_freem(nd->nd_mrep);
991 * Now, adjust this mbuf, based on nd_dpos.
993 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
994 if (offs == mbuf_len(m)) {
998 panic("nfsm trim leading2");
999 mbuf_setnext(n, NULL);
1001 } else if (offs > 0) {
1002 mbuf_setlen(m, mbuf_len(m) - offs);
1003 NFSM_DATAP(m, offs);
1004 } else if (offs < 0)
1005 panic("nfsm trimleading offs");
1008 nd->nd_dpos = NFSMTOD(m, caddr_t);
1012 * Trim trailing data off the mbuf list being built.
1015 newnfs_trimtrailing(nd, mb, bpos)
1016 struct nfsrv_descript *nd;
1021 if (mbuf_next(mb)) {
1022 mbuf_freem(mbuf_next(mb));
1023 mbuf_setnext(mb, NULL);
1025 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1031 * Dissect a file handle on the client.
1034 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1041 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1042 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1043 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1050 nfhp = malloc(sizeof (struct nfsfh) + len,
1052 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1054 free(nfhp, M_NFSFH);
1057 nfhp->nfh_len = len;
1060 NFSEXITCODE2(error, nd);
1065 * Break down the nfsv4 acl.
1066 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1069 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1070 int *aclsizep, __unused NFSPROC_T *p)
1074 int acecnt, error = 0, aceerr = 0, acesize;
1080 * Parse out the ace entries and expect them to conform to
1081 * what can be supported by R/W/X bits.
1083 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1084 aclsize = NFSX_UNSIGNED;
1085 acecnt = fxdr_unsigned(int, *tl);
1086 if (acecnt > ACL_MAX_ENTRIES)
1087 aceerr = NFSERR_ATTRNOTSUPP;
1088 if (nfsrv_useacl == 0)
1089 aceerr = NFSERR_ATTRNOTSUPP;
1090 for (i = 0; i < acecnt; i++) {
1091 if (aclp && !aceerr)
1092 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1093 &aceerr, &acesize, p);
1095 error = nfsrv_skipace(nd, &acesize);
1100 if (aclp && !aceerr)
1101 aclp->acl_cnt = acecnt;
1105 *aclsizep = aclsize;
1107 NFSEXITCODE2(error, nd);
1112 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1115 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1120 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1121 len = fxdr_unsigned(int, *(tl + 3));
1122 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1124 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1125 NFSEXITCODE2(error, nd);
1130 * Get attribute bits from an mbuf list.
1131 * Returns EBADRPC for a parsing error, 0 otherwise.
1132 * If the clearinvalid flag is set, clear the bits not supported.
1135 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1142 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1143 cnt = fxdr_unsigned(int, *tl);
1145 error = NFSERR_BADXDR;
1148 if (cnt > NFSATTRBIT_MAXWORDS)
1149 outcnt = NFSATTRBIT_MAXWORDS;
1152 NFSZERO_ATTRBIT(attrbitp);
1154 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1155 for (i = 0; i < outcnt; i++)
1156 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1158 for (i = 0; i < (cnt - outcnt); i++) {
1159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1160 if (retnotsupp != NULL && *tl != 0)
1161 *retnotsupp = NFSERR_ATTRNOTSUPP;
1164 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1166 NFSEXITCODE2(error, nd);
1171 * Get the attributes for V4.
1172 * If the compare flag is true, test for any attribute changes,
1173 * otherwise return the attribute values.
1174 * These attributes cover fields in "struct vattr", "struct statfs",
1175 * "struct nfsfsinfo", the file handle and the lease duration.
1176 * The value of retcmpp is set to 1 if all attributes are the same,
1178 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1181 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1182 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1183 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1184 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1185 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1188 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1189 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1190 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1191 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1192 struct nfsfh *tnfhp;
1193 struct nfsreferral *refp;
1196 struct timespec temptime;
1199 u_int32_t freenum = 0, tuint;
1200 u_int64_t uquad = 0, thyp, thyp2;
1206 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1209 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1211 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1217 *retcmpp = retnotsup;
1220 * Just set default values to some of the important ones.
1223 nap->na_type = VREG;
1225 nap->na_rdev = (NFSDEV_T)0;
1226 nap->na_mtime.tv_sec = 0;
1227 nap->na_mtime.tv_nsec = 0;
1230 nap->na_blocksize = NFS_FABLKSIZE;
1233 sbp->f_bsize = NFS_FABLKSIZE;
1241 fsp->fs_rtmax = 8192;
1242 fsp->fs_rtpref = 8192;
1243 fsp->fs_maxname = NFS_MAXNAMLEN;
1244 fsp->fs_wtmax = 8192;
1245 fsp->fs_wtpref = 8192;
1246 fsp->fs_wtmult = NFS_FABLKSIZE;
1247 fsp->fs_dtpref = 8192;
1248 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1249 fsp->fs_timedelta.tv_sec = 0;
1250 fsp->fs_timedelta.tv_nsec = 1;
1251 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1252 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1255 pc->pc_linkmax = NFS_LINK_MAX;
1256 pc->pc_namemax = NAME_MAX;
1258 pc->pc_chownrestricted = 0;
1259 pc->pc_caseinsensitive = 0;
1260 pc->pc_casepreserving = 1;
1263 sfp->sf_ffiles = UINT64_MAX;
1264 sfp->sf_tfiles = UINT64_MAX;
1265 sfp->sf_afiles = UINT64_MAX;
1266 sfp->sf_fbytes = UINT64_MAX;
1267 sfp->sf_tbytes = UINT64_MAX;
1268 sfp->sf_abytes = UINT64_MAX;
1273 * Loop around getting the attributes.
1275 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1276 attrsize = fxdr_unsigned(int, *tl);
1277 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1278 if (attrsum > attrsize) {
1279 error = NFSERR_BADXDR;
1282 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1284 case NFSATTRBIT_SUPPORTEDATTRS:
1286 if (compare || nap == NULL)
1287 error = nfsrv_getattrbits(nd, &retattrbits,
1290 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1294 if (compare && !(*retcmpp)) {
1295 NFSSETSUPP_ATTRBIT(&checkattrbits);
1297 /* Some filesystem do not support NFSv4ACL */
1298 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1299 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1300 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1302 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1304 *retcmpp = NFSERR_NOTSAME;
1308 case NFSATTRBIT_TYPE:
1309 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1312 if (nap->na_type != nfsv34tov_type(*tl))
1313 *retcmpp = NFSERR_NOTSAME;
1315 } else if (nap != NULL) {
1316 nap->na_type = nfsv34tov_type(*tl);
1318 attrsum += NFSX_UNSIGNED;
1320 case NFSATTRBIT_FHEXPIRETYPE:
1321 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1322 if (compare && !(*retcmpp)) {
1323 if (fxdr_unsigned(int, *tl) !=
1324 NFSV4FHTYPE_PERSISTENT)
1325 *retcmpp = NFSERR_NOTSAME;
1327 attrsum += NFSX_UNSIGNED;
1329 case NFSATTRBIT_CHANGE:
1330 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1333 if (nap->na_filerev != fxdr_hyper(tl))
1334 *retcmpp = NFSERR_NOTSAME;
1336 } else if (nap != NULL) {
1337 nap->na_filerev = fxdr_hyper(tl);
1339 attrsum += NFSX_HYPER;
1341 case NFSATTRBIT_SIZE:
1342 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1345 if (nap->na_size != fxdr_hyper(tl))
1346 *retcmpp = NFSERR_NOTSAME;
1348 } else if (nap != NULL) {
1349 nap->na_size = fxdr_hyper(tl);
1351 attrsum += NFSX_HYPER;
1353 case NFSATTRBIT_LINKSUPPORT:
1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1357 if (fsp->fs_properties & NFSV3_FSFLINK) {
1358 if (*tl == newnfs_false)
1359 *retcmpp = NFSERR_NOTSAME;
1361 if (*tl == newnfs_true)
1362 *retcmpp = NFSERR_NOTSAME;
1365 } else if (fsp != NULL) {
1366 if (*tl == newnfs_true)
1367 fsp->fs_properties |= NFSV3_FSFLINK;
1369 fsp->fs_properties &= ~NFSV3_FSFLINK;
1371 attrsum += NFSX_UNSIGNED;
1373 case NFSATTRBIT_SYMLINKSUPPORT:
1374 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1377 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1378 if (*tl == newnfs_false)
1379 *retcmpp = NFSERR_NOTSAME;
1381 if (*tl == newnfs_true)
1382 *retcmpp = NFSERR_NOTSAME;
1385 } else if (fsp != NULL) {
1386 if (*tl == newnfs_true)
1387 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1389 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1391 attrsum += NFSX_UNSIGNED;
1393 case NFSATTRBIT_NAMEDATTR:
1394 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1395 if (compare && !(*retcmpp)) {
1396 if (*tl != newnfs_false)
1397 *retcmpp = NFSERR_NOTSAME;
1399 attrsum += NFSX_UNSIGNED;
1401 case NFSATTRBIT_FSID:
1402 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1403 thyp = fxdr_hyper(tl);
1405 thyp2 = fxdr_hyper(tl);
1407 if (*retcmpp == 0) {
1408 if (thyp != (u_int64_t)
1409 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1410 thyp2 != (u_int64_t)
1411 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1412 *retcmpp = NFSERR_NOTSAME;
1414 } else if (nap != NULL) {
1415 nap->na_filesid[0] = thyp;
1416 nap->na_filesid[1] = thyp2;
1418 attrsum += (4 * NFSX_UNSIGNED);
1420 case NFSATTRBIT_UNIQUEHANDLES:
1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 if (compare && !(*retcmpp)) {
1423 if (*tl != newnfs_true)
1424 *retcmpp = NFSERR_NOTSAME;
1426 attrsum += NFSX_UNSIGNED;
1428 case NFSATTRBIT_LEASETIME:
1429 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1431 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1433 *retcmpp = NFSERR_NOTSAME;
1434 } else if (leasep != NULL) {
1435 *leasep = fxdr_unsigned(u_int32_t, *tl);
1437 attrsum += NFSX_UNSIGNED;
1439 case NFSATTRBIT_RDATTRERROR:
1440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1443 *retcmpp = NFSERR_INVAL;
1444 } else if (rderrp != NULL) {
1445 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1447 attrsum += NFSX_UNSIGNED;
1449 case NFSATTRBIT_ACL:
1452 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1455 naclp = acl_alloc(M_WAITOK);
1456 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1462 if (aceerr || aclp == NULL ||
1463 nfsrv_compareacl(aclp, naclp))
1464 *retcmpp = NFSERR_NOTSAME;
1467 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1469 *retcmpp = NFSERR_ATTRNOTSUPP;
1473 if (vp != NULL && aclp != NULL)
1474 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1477 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1485 case NFSATTRBIT_ACLSUPPORT:
1486 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1487 if (compare && !(*retcmpp)) {
1488 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1489 if (fxdr_unsigned(u_int32_t, *tl) !=
1491 *retcmpp = NFSERR_NOTSAME;
1493 *retcmpp = NFSERR_ATTRNOTSUPP;
1496 attrsum += NFSX_UNSIGNED;
1498 case NFSATTRBIT_ARCHIVE:
1499 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1500 if (compare && !(*retcmpp))
1501 *retcmpp = NFSERR_ATTRNOTSUPP;
1502 attrsum += NFSX_UNSIGNED;
1504 case NFSATTRBIT_CANSETTIME:
1505 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1508 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1509 if (*tl == newnfs_false)
1510 *retcmpp = NFSERR_NOTSAME;
1512 if (*tl == newnfs_true)
1513 *retcmpp = NFSERR_NOTSAME;
1516 } else if (fsp != NULL) {
1517 if (*tl == newnfs_true)
1518 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1520 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1522 attrsum += NFSX_UNSIGNED;
1524 case NFSATTRBIT_CASEINSENSITIVE:
1525 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1528 if (*tl != newnfs_false)
1529 *retcmpp = NFSERR_NOTSAME;
1531 } else if (pc != NULL) {
1532 pc->pc_caseinsensitive =
1533 fxdr_unsigned(u_int32_t, *tl);
1535 attrsum += NFSX_UNSIGNED;
1537 case NFSATTRBIT_CASEPRESERVING:
1538 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1541 if (*tl != newnfs_true)
1542 *retcmpp = NFSERR_NOTSAME;
1544 } else if (pc != NULL) {
1545 pc->pc_casepreserving =
1546 fxdr_unsigned(u_int32_t, *tl);
1548 attrsum += NFSX_UNSIGNED;
1550 case NFSATTRBIT_CHOWNRESTRICTED:
1551 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1554 if (*tl != newnfs_true)
1555 *retcmpp = NFSERR_NOTSAME;
1557 } else if (pc != NULL) {
1558 pc->pc_chownrestricted =
1559 fxdr_unsigned(u_int32_t, *tl);
1561 attrsum += NFSX_UNSIGNED;
1563 case NFSATTRBIT_FILEHANDLE:
1564 error = nfsm_getfh(nd, &tnfhp);
1567 tfhsize = tnfhp->nfh_len;
1570 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1572 *retcmpp = NFSERR_NOTSAME;
1573 free(tnfhp, M_NFSFH);
1574 } else if (nfhpp != NULL) {
1577 free(tnfhp, M_NFSFH);
1579 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1581 case NFSATTRBIT_FILEID:
1582 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1583 thyp = fxdr_hyper(tl);
1586 if (nap->na_fileid != thyp)
1587 *retcmpp = NFSERR_NOTSAME;
1589 } else if (nap != NULL)
1590 nap->na_fileid = thyp;
1591 attrsum += NFSX_HYPER;
1593 case NFSATTRBIT_FILESAVAIL:
1594 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1597 sfp->sf_afiles != fxdr_hyper(tl))
1598 *retcmpp = NFSERR_NOTSAME;
1599 } else if (sfp != NULL) {
1600 sfp->sf_afiles = fxdr_hyper(tl);
1602 attrsum += NFSX_HYPER;
1604 case NFSATTRBIT_FILESFREE:
1605 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1608 sfp->sf_ffiles != fxdr_hyper(tl))
1609 *retcmpp = NFSERR_NOTSAME;
1610 } else if (sfp != NULL) {
1611 sfp->sf_ffiles = fxdr_hyper(tl);
1613 attrsum += NFSX_HYPER;
1615 case NFSATTRBIT_FILESTOTAL:
1616 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 sfp->sf_tfiles != fxdr_hyper(tl))
1620 *retcmpp = NFSERR_NOTSAME;
1621 } else if (sfp != NULL) {
1622 sfp->sf_tfiles = fxdr_hyper(tl);
1624 attrsum += NFSX_HYPER;
1626 case NFSATTRBIT_FSLOCATIONS:
1627 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1631 if (compare && !(*retcmpp)) {
1632 refp = nfsv4root_getreferral(vp, NULL, 0);
1634 if (cp == NULL || cp2 == NULL ||
1636 strcmp(cp2, refp->nfr_srvlist))
1637 *retcmpp = NFSERR_NOTSAME;
1638 } else if (m == 0) {
1639 *retcmpp = NFSERR_NOTSAME;
1643 free(cp, M_NFSSTRING);
1645 free(cp2, M_NFSSTRING);
1647 case NFSATTRBIT_HIDDEN:
1648 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1649 if (compare && !(*retcmpp))
1650 *retcmpp = NFSERR_ATTRNOTSUPP;
1651 attrsum += NFSX_UNSIGNED;
1653 case NFSATTRBIT_HOMOGENEOUS:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1657 if (fsp->fs_properties &
1658 NFSV3_FSFHOMOGENEOUS) {
1659 if (*tl == newnfs_false)
1660 *retcmpp = NFSERR_NOTSAME;
1662 if (*tl == newnfs_true)
1663 *retcmpp = NFSERR_NOTSAME;
1666 } else if (fsp != NULL) {
1667 if (*tl == newnfs_true)
1668 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1670 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1672 attrsum += NFSX_UNSIGNED;
1674 case NFSATTRBIT_MAXFILESIZE:
1675 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1676 tnfsquad.qval = fxdr_hyper(tl);
1679 tquad = NFSRV_MAXFILESIZE;
1680 if (tquad != tnfsquad.qval)
1681 *retcmpp = NFSERR_NOTSAME;
1683 } else if (fsp != NULL) {
1684 fsp->fs_maxfilesize = tnfsquad.qval;
1686 attrsum += NFSX_HYPER;
1688 case NFSATTRBIT_MAXLINK:
1689 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1692 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1693 *retcmpp = NFSERR_NOTSAME;
1695 } else if (pc != NULL) {
1696 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1698 attrsum += NFSX_UNSIGNED;
1700 case NFSATTRBIT_MAXNAME:
1701 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1704 if (fsp->fs_maxname !=
1705 fxdr_unsigned(u_int32_t, *tl))
1706 *retcmpp = NFSERR_NOTSAME;
1709 tuint = fxdr_unsigned(u_int32_t, *tl);
1711 * Some Linux NFSv4 servers report this
1712 * as 0 or 4billion, so I'll set it to
1713 * NFS_MAXNAMLEN. If a server actually creates
1714 * a name longer than NFS_MAXNAMLEN, it will
1715 * get an error back.
1717 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1718 tuint = NFS_MAXNAMLEN;
1720 fsp->fs_maxname = tuint;
1722 pc->pc_namemax = tuint;
1724 attrsum += NFSX_UNSIGNED;
1726 case NFSATTRBIT_MAXREAD:
1727 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1730 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1731 *(tl + 1)) || *tl != 0)
1732 *retcmpp = NFSERR_NOTSAME;
1734 } else if (fsp != NULL) {
1735 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1736 fsp->fs_rtpref = fsp->fs_rtmax;
1737 fsp->fs_dtpref = fsp->fs_rtpref;
1739 attrsum += NFSX_HYPER;
1741 case NFSATTRBIT_MAXWRITE:
1742 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1745 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1746 *(tl + 1)) || *tl != 0)
1747 *retcmpp = NFSERR_NOTSAME;
1749 } else if (fsp != NULL) {
1750 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1751 fsp->fs_wtpref = fsp->fs_wtmax;
1753 attrsum += NFSX_HYPER;
1755 case NFSATTRBIT_MIMETYPE:
1756 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1757 i = fxdr_unsigned(int, *tl);
1758 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1759 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1762 if (compare && !(*retcmpp))
1763 *retcmpp = NFSERR_ATTRNOTSUPP;
1765 case NFSATTRBIT_MODE:
1766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1769 if (nap->na_mode != nfstov_mode(*tl))
1770 *retcmpp = NFSERR_NOTSAME;
1772 } else if (nap != NULL) {
1773 nap->na_mode = nfstov_mode(*tl);
1775 attrsum += NFSX_UNSIGNED;
1777 case NFSATTRBIT_NOTRUNC:
1778 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1781 if (*tl != newnfs_true)
1782 *retcmpp = NFSERR_NOTSAME;
1784 } else if (pc != NULL) {
1785 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1787 attrsum += NFSX_UNSIGNED;
1789 case NFSATTRBIT_NUMLINKS:
1790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1791 tuint = fxdr_unsigned(u_int32_t, *tl);
1794 if ((u_int32_t)nap->na_nlink != tuint)
1795 *retcmpp = NFSERR_NOTSAME;
1797 } else if (nap != NULL) {
1798 nap->na_nlink = tuint;
1800 attrsum += NFSX_UNSIGNED;
1802 case NFSATTRBIT_OWNER:
1803 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1804 j = fxdr_unsigned(int, *tl);
1806 error = NFSERR_BADXDR;
1809 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1810 if (j > NFSV4_SMALLSTR)
1811 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1814 error = nfsrv_mtostr(nd, cp, j);
1816 if (j > NFSV4_SMALLSTR)
1817 free(cp, M_NFSSTRING);
1822 if (nfsv4_strtouid(nd, cp, j, &uid) ||
1824 *retcmpp = NFSERR_NOTSAME;
1826 } else if (nap != NULL) {
1827 if (nfsv4_strtouid(nd, cp, j, &uid))
1828 nap->na_uid = nfsrv_defaultuid;
1832 if (j > NFSV4_SMALLSTR)
1833 free(cp, M_NFSSTRING);
1835 case NFSATTRBIT_OWNERGROUP:
1836 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1837 j = fxdr_unsigned(int, *tl);
1839 error = NFSERR_BADXDR;
1842 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1843 if (j > NFSV4_SMALLSTR)
1844 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1847 error = nfsrv_mtostr(nd, cp, j);
1849 if (j > NFSV4_SMALLSTR)
1850 free(cp, M_NFSSTRING);
1855 if (nfsv4_strtogid(nd, cp, j, &gid) ||
1857 *retcmpp = NFSERR_NOTSAME;
1859 } else if (nap != NULL) {
1860 if (nfsv4_strtogid(nd, cp, j, &gid))
1861 nap->na_gid = nfsrv_defaultgid;
1865 if (j > NFSV4_SMALLSTR)
1866 free(cp, M_NFSSTRING);
1868 case NFSATTRBIT_QUOTAHARD:
1869 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1871 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1872 freenum = sbp->f_bfree;
1874 freenum = sbp->f_bavail;
1877 * ufs_quotactl() insists that the uid argument
1878 * equal p_ruid for non-root quota access, so
1879 * we'll just make sure that's the case.
1881 savuid = p->p_cred->p_ruid;
1882 p->p_cred->p_ruid = cred->cr_uid;
1883 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1884 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1885 freenum = min(dqb.dqb_bhardlimit, freenum);
1886 p->p_cred->p_ruid = savuid;
1888 uquad = (u_int64_t)freenum;
1889 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1891 if (compare && !(*retcmpp)) {
1892 if (uquad != fxdr_hyper(tl))
1893 *retcmpp = NFSERR_NOTSAME;
1895 attrsum += NFSX_HYPER;
1897 case NFSATTRBIT_QUOTASOFT:
1898 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1900 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1901 freenum = sbp->f_bfree;
1903 freenum = sbp->f_bavail;
1906 * ufs_quotactl() insists that the uid argument
1907 * equal p_ruid for non-root quota access, so
1908 * we'll just make sure that's the case.
1910 savuid = p->p_cred->p_ruid;
1911 p->p_cred->p_ruid = cred->cr_uid;
1912 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1913 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1914 freenum = min(dqb.dqb_bsoftlimit, freenum);
1915 p->p_cred->p_ruid = savuid;
1917 uquad = (u_int64_t)freenum;
1918 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1920 if (compare && !(*retcmpp)) {
1921 if (uquad != fxdr_hyper(tl))
1922 *retcmpp = NFSERR_NOTSAME;
1924 attrsum += NFSX_HYPER;
1926 case NFSATTRBIT_QUOTAUSED:
1927 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1932 * ufs_quotactl() insists that the uid argument
1933 * equal p_ruid for non-root quota access, so
1934 * we'll just make sure that's the case.
1936 savuid = p->p_cred->p_ruid;
1937 p->p_cred->p_ruid = cred->cr_uid;
1938 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1939 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1940 freenum = dqb.dqb_curblocks;
1941 p->p_cred->p_ruid = savuid;
1943 uquad = (u_int64_t)freenum;
1944 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1946 if (compare && !(*retcmpp)) {
1947 if (uquad != fxdr_hyper(tl))
1948 *retcmpp = NFSERR_NOTSAME;
1950 attrsum += NFSX_HYPER;
1952 case NFSATTRBIT_RAWDEV:
1953 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1954 j = fxdr_unsigned(int, *tl++);
1955 k = fxdr_unsigned(int, *tl);
1958 if (nap->na_rdev != NFSMAKEDEV(j, k))
1959 *retcmpp = NFSERR_NOTSAME;
1961 } else if (nap != NULL) {
1962 nap->na_rdev = NFSMAKEDEV(j, k);
1964 attrsum += NFSX_V4SPECDATA;
1966 case NFSATTRBIT_SPACEAVAIL:
1967 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1970 sfp->sf_abytes != fxdr_hyper(tl))
1971 *retcmpp = NFSERR_NOTSAME;
1972 } else if (sfp != NULL) {
1973 sfp->sf_abytes = fxdr_hyper(tl);
1975 attrsum += NFSX_HYPER;
1977 case NFSATTRBIT_SPACEFREE:
1978 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1981 sfp->sf_fbytes != fxdr_hyper(tl))
1982 *retcmpp = NFSERR_NOTSAME;
1983 } else if (sfp != NULL) {
1984 sfp->sf_fbytes = fxdr_hyper(tl);
1986 attrsum += NFSX_HYPER;
1988 case NFSATTRBIT_SPACETOTAL:
1989 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1992 sfp->sf_tbytes != fxdr_hyper(tl))
1993 *retcmpp = NFSERR_NOTSAME;
1994 } else if (sfp != NULL) {
1995 sfp->sf_tbytes = fxdr_hyper(tl);
1997 attrsum += NFSX_HYPER;
1999 case NFSATTRBIT_SPACEUSED:
2000 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2001 thyp = fxdr_hyper(tl);
2004 if ((u_int64_t)nap->na_bytes != thyp)
2005 *retcmpp = NFSERR_NOTSAME;
2007 } else if (nap != NULL) {
2008 nap->na_bytes = thyp;
2010 attrsum += NFSX_HYPER;
2012 case NFSATTRBIT_SYSTEM:
2013 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2014 if (compare && !(*retcmpp))
2015 *retcmpp = NFSERR_ATTRNOTSUPP;
2016 attrsum += NFSX_UNSIGNED;
2018 case NFSATTRBIT_TIMEACCESS:
2019 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2020 fxdr_nfsv4time(tl, &temptime);
2023 if (!NFS_CMPTIME(temptime, nap->na_atime))
2024 *retcmpp = NFSERR_NOTSAME;
2026 } else if (nap != NULL) {
2027 nap->na_atime = temptime;
2029 attrsum += NFSX_V4TIME;
2031 case NFSATTRBIT_TIMEACCESSSET:
2032 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2033 attrsum += NFSX_UNSIGNED;
2034 i = fxdr_unsigned(int, *tl);
2035 if (i == NFSV4SATTRTIME_TOCLIENT) {
2036 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2037 attrsum += NFSX_V4TIME;
2039 if (compare && !(*retcmpp))
2040 *retcmpp = NFSERR_INVAL;
2042 case NFSATTRBIT_TIMEBACKUP:
2043 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2044 if (compare && !(*retcmpp))
2045 *retcmpp = NFSERR_ATTRNOTSUPP;
2046 attrsum += NFSX_V4TIME;
2048 case NFSATTRBIT_TIMECREATE:
2049 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2050 if (compare && !(*retcmpp))
2051 *retcmpp = NFSERR_ATTRNOTSUPP;
2052 attrsum += NFSX_V4TIME;
2054 case NFSATTRBIT_TIMEDELTA:
2055 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2059 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2060 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2061 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2062 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2065 *retcmpp = NFSERR_NOTSAME;
2068 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2071 attrsum += NFSX_V4TIME;
2073 case NFSATTRBIT_TIMEMETADATA:
2074 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2075 fxdr_nfsv4time(tl, &temptime);
2078 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2079 *retcmpp = NFSERR_NOTSAME;
2081 } else if (nap != NULL) {
2082 nap->na_ctime = temptime;
2084 attrsum += NFSX_V4TIME;
2086 case NFSATTRBIT_TIMEMODIFY:
2087 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2088 fxdr_nfsv4time(tl, &temptime);
2091 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2092 *retcmpp = NFSERR_NOTSAME;
2094 } else if (nap != NULL) {
2095 nap->na_mtime = temptime;
2097 attrsum += NFSX_V4TIME;
2099 case NFSATTRBIT_TIMEMODIFYSET:
2100 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2101 attrsum += NFSX_UNSIGNED;
2102 i = fxdr_unsigned(int, *tl);
2103 if (i == NFSV4SATTRTIME_TOCLIENT) {
2104 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2105 attrsum += NFSX_V4TIME;
2107 if (compare && !(*retcmpp))
2108 *retcmpp = NFSERR_INVAL;
2110 case NFSATTRBIT_MOUNTEDONFILEID:
2111 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2112 thyp = fxdr_hyper(tl);
2115 if (!vp || !nfsrv_atroot(vp, &thyp2))
2116 thyp2 = nap->na_fileid;
2118 *retcmpp = NFSERR_NOTSAME;
2120 } else if (nap != NULL)
2121 nap->na_mntonfileno = thyp;
2122 attrsum += NFSX_HYPER;
2124 case NFSATTRBIT_SUPPATTREXCLCREAT:
2126 error = nfsrv_getattrbits(nd, &retattrbits,
2130 if (compare && !(*retcmpp)) {
2131 NFSSETSUPP_ATTRBIT(&checkattrbits);
2132 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
2133 NFSCLRBIT_ATTRBIT(&checkattrbits,
2134 NFSATTRBIT_TIMEACCESSSET);
2135 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2137 *retcmpp = NFSERR_NOTSAME;
2141 case NFSATTRBIT_FSLAYOUTTYPE:
2142 case NFSATTRBIT_LAYOUTTYPE:
2143 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2144 attrsum += NFSX_UNSIGNED;
2145 i = fxdr_unsigned(int, *tl);
2147 NFSM_DISSECT(tl, u_int32_t *, i *
2149 attrsum += i * NFSX_UNSIGNED;
2150 j = fxdr_unsigned(int, *tl);
2151 if (i == 1 && compare && !(*retcmpp) &&
2152 (((nfsrv_doflexfile != 0 ||
2153 nfsrv_maxpnfsmirror > 1) &&
2154 j != NFSLAYOUT_FLEXFILE) ||
2155 (nfsrv_doflexfile == 0 &&
2156 j != NFSLAYOUT_NFSV4_1_FILES)))
2157 *retcmpp = NFSERR_NOTSAME;
2159 if (nfsrv_devidcnt == 0) {
2160 if (compare && !(*retcmpp) && i > 0)
2161 *retcmpp = NFSERR_NOTSAME;
2163 if (compare && !(*retcmpp) && i != 1)
2164 *retcmpp = NFSERR_NOTSAME;
2167 case NFSATTRBIT_LAYOUTALIGNMENT:
2168 case NFSATTRBIT_LAYOUTBLKSIZE:
2169 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2170 attrsum += NFSX_UNSIGNED;
2171 i = fxdr_unsigned(int, *tl);
2172 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2173 *retcmpp = NFSERR_NOTSAME;
2176 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2178 if (compare && !(*retcmpp))
2179 *retcmpp = NFSERR_ATTRNOTSUPP;
2181 * and get out of the loop, since we can't parse
2182 * the unknown attrbute data.
2184 bitpos = NFSATTRBIT_MAX;
2190 * some clients pad the attrlist, so we need to skip over the
2193 if (attrsum > attrsize) {
2194 error = NFSERR_BADXDR;
2196 attrsize = NFSM_RNDUP(attrsize);
2197 if (attrsum < attrsize)
2198 error = nfsm_advance(nd, attrsize - attrsum, -1);
2201 NFSEXITCODE2(error, nd);
2206 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2207 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2208 * The first argument is a pointer to an nfsv4lock structure.
2209 * The second argument is 1 iff a blocking lock is wanted.
2210 * If this argument is 0, the call waits until no thread either wants nor
2211 * holds an exclusive lock.
2212 * It returns 1 if the lock was acquired, 0 otherwise.
2213 * If several processes call this function concurrently wanting the exclusive
2214 * lock, one will get the lock and the rest will return without getting the
2215 * lock. (If the caller must have the lock, it simply calls this function in a
2216 * loop until the function returns 1 to indicate the lock was acquired.)
2217 * Any usecnt must be decremented by calling nfsv4_relref() before
2218 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2219 * be called in a loop.
2220 * The isleptp argument is set to indicate if the call slept, iff not NULL
2221 * and the mp argument indicates to check for a forced dismount, iff not
2225 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2226 void *mutex, struct mount *mp)
2232 * If a lock is wanted, loop around until the lock is acquired by
2233 * someone and then released. If I want the lock, try to acquire it.
2234 * For a lock to be issued, no lock must be in force and the usecnt
2238 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2239 lp->nfslock_usecnt == 0) {
2240 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2241 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2244 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2246 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2247 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2248 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2251 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2254 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2255 PZERO - 1, "nfsv4lck", NULL);
2256 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2257 lp->nfslock_usecnt == 0) {
2258 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2259 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2267 * Release the lock acquired by nfsv4_lock().
2268 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2269 * incremented, as well.
2272 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2275 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2277 lp->nfslock_usecnt++;
2282 * Release a reference cnt.
2285 nfsv4_relref(struct nfsv4lock *lp)
2288 if (lp->nfslock_usecnt <= 0)
2289 panic("nfsv4root ref cnt");
2290 lp->nfslock_usecnt--;
2291 if (lp->nfslock_usecnt == 0)
2296 * Get a reference cnt.
2297 * This function will wait for any exclusive lock to be released, but will
2298 * not wait for threads that want the exclusive lock. If priority needs
2299 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2300 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2301 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2302 * return without getting a refcnt for that case.
2305 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2313 * Wait for a lock held.
2315 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2316 if (mp != NULL && NFSCL_FORCEDISM(mp))
2318 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2321 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2322 PZERO - 1, "nfsv4gr", NULL);
2324 if (mp != NULL && NFSCL_FORCEDISM(mp))
2327 lp->nfslock_usecnt++;
2331 * Get a reference as above, but return failure instead of sleeping if
2332 * an exclusive lock is held.
2335 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2338 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2341 lp->nfslock_usecnt++;
2346 * Test for a lock. Return 1 if locked, 0 otherwise.
2349 nfsv4_testlock(struct nfsv4lock *lp)
2352 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2353 lp->nfslock_usecnt == 0)
2359 * Wake up anyone sleeping, waiting for this lock.
2362 nfsv4_wanted(struct nfsv4lock *lp)
2365 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2366 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2367 wakeup((caddr_t)&lp->nfslock_lock);
2372 * Copy a string from an mbuf list into a character array.
2373 * Return EBADRPC if there is an mbuf error,
2377 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2386 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2387 rem = NFSM_RNDUP(siz) - siz;
2393 NFSBCOPY(cp, str, xfer);
2402 cp = NFSMTOD(mp, caddr_t);
2414 error = nfsm_advance(nd, rem, len);
2420 NFSEXITCODE2(error, nd);
2425 * Fill in the attributes as marked by the bitmap (V4).
2428 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2429 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2430 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2431 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2432 struct statfs *pnfssf)
2434 int bitpos, retnum = 0;
2436 int siz, prefixnum, error;
2437 u_char *cp, namestr[NFSV4_SMALLSTR];
2438 nfsattrbit_t attrbits, retbits;
2439 nfsattrbit_t *retbitp = &retbits;
2440 u_int32_t freenum, *retnump;
2443 struct nfsfsinfo fsinf;
2444 struct timespec temptime;
2445 NFSACL_T *aclp, *naclp = NULL;
2452 * First, set the bits that can be filled and get fsinfo.
2454 NFSSET_ATTRBIT(retbitp, attrbitp);
2456 * If both p and cred are NULL, it is a client side setattr call.
2457 * If both p and cred are not NULL, it is a server side reply call.
2458 * If p is not NULL and cred is NULL, it is a client side callback
2461 if (p == NULL && cred == NULL) {
2462 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2465 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2466 naclp = acl_alloc(M_WAITOK);
2469 nfsvno_getfs(&fsinf, isdgram);
2472 * Get the VFS_STATFS(), since some attributes need them.
2474 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2475 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2476 error = VFS_STATFS(mp, fs);
2479 nd->nd_repstat = NFSERR_ACCES;
2483 NFSCLRSTATFS_ATTRBIT(retbitp);
2489 * And the NFSv4 ACL...
2491 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2492 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2493 supports_nfsv4acls == 0))) {
2494 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2496 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2497 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2498 supports_nfsv4acls == 0)) {
2499 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2500 } else if (naclp != NULL) {
2501 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2502 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2504 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2506 NFSVOPUNLOCK(vp, 0);
2508 error = NFSERR_PERM;
2511 nd->nd_repstat = NFSERR_ACCES;
2515 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2521 * Put out the attribute bitmap for the ones being filled in
2522 * and get the field for the number of attributes returned.
2524 prefixnum = nfsrv_putattrbit(nd, retbitp);
2525 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2526 prefixnum += NFSX_UNSIGNED;
2529 * Now, loop around filling in the attributes for each bit set.
2531 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2532 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2534 case NFSATTRBIT_SUPPORTEDATTRS:
2535 NFSSETSUPP_ATTRBIT(&attrbits);
2536 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2537 && supports_nfsv4acls == 0)) {
2538 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2539 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2541 retnum += nfsrv_putattrbit(nd, &attrbits);
2543 case NFSATTRBIT_TYPE:
2544 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2545 *tl = vtonfsv34_type(vap->va_type);
2546 retnum += NFSX_UNSIGNED;
2548 case NFSATTRBIT_FHEXPIRETYPE:
2549 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2550 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2551 retnum += NFSX_UNSIGNED;
2553 case NFSATTRBIT_CHANGE:
2554 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2555 txdr_hyper(vap->va_filerev, tl);
2556 retnum += NFSX_HYPER;
2558 case NFSATTRBIT_SIZE:
2559 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2560 txdr_hyper(vap->va_size, tl);
2561 retnum += NFSX_HYPER;
2563 case NFSATTRBIT_LINKSUPPORT:
2564 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2565 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2569 retnum += NFSX_UNSIGNED;
2571 case NFSATTRBIT_SYMLINKSUPPORT:
2572 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2573 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2577 retnum += NFSX_UNSIGNED;
2579 case NFSATTRBIT_NAMEDATTR:
2580 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2582 retnum += NFSX_UNSIGNED;
2584 case NFSATTRBIT_FSID:
2585 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2587 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2589 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2590 retnum += NFSX_V4FSID;
2592 case NFSATTRBIT_UNIQUEHANDLES:
2593 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2595 retnum += NFSX_UNSIGNED;
2597 case NFSATTRBIT_LEASETIME:
2598 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2599 *tl = txdr_unsigned(nfsrv_lease);
2600 retnum += NFSX_UNSIGNED;
2602 case NFSATTRBIT_RDATTRERROR:
2603 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 *tl = txdr_unsigned(rderror);
2605 retnum += NFSX_UNSIGNED;
2608 * Recommended Attributes. (Only the supported ones.)
2610 case NFSATTRBIT_ACL:
2611 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2613 case NFSATTRBIT_ACLSUPPORT:
2614 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2615 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2616 retnum += NFSX_UNSIGNED;
2618 case NFSATTRBIT_CANSETTIME:
2619 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2620 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2624 retnum += NFSX_UNSIGNED;
2626 case NFSATTRBIT_CASEINSENSITIVE:
2627 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2629 retnum += NFSX_UNSIGNED;
2631 case NFSATTRBIT_CASEPRESERVING:
2632 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2634 retnum += NFSX_UNSIGNED;
2636 case NFSATTRBIT_CHOWNRESTRICTED:
2637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2639 retnum += NFSX_UNSIGNED;
2641 case NFSATTRBIT_FILEHANDLE:
2642 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2644 case NFSATTRBIT_FILEID:
2645 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2646 uquad = vap->va_fileid;
2647 txdr_hyper(uquad, tl);
2648 retnum += NFSX_HYPER;
2650 case NFSATTRBIT_FILESAVAIL:
2652 * Check quota and use min(quota, f_ffree).
2654 freenum = fs->f_ffree;
2657 * ufs_quotactl() insists that the uid argument
2658 * equal p_ruid for non-root quota access, so
2659 * we'll just make sure that's the case.
2661 savuid = p->p_cred->p_ruid;
2662 p->p_cred->p_ruid = cred->cr_uid;
2663 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2664 cred->cr_uid, (caddr_t)&dqb))
2665 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2667 p->p_cred->p_ruid = savuid;
2669 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2671 *tl = txdr_unsigned(freenum);
2672 retnum += NFSX_HYPER;
2674 case NFSATTRBIT_FILESFREE:
2675 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2677 *tl = txdr_unsigned(fs->f_ffree);
2678 retnum += NFSX_HYPER;
2680 case NFSATTRBIT_FILESTOTAL:
2681 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2683 *tl = txdr_unsigned(fs->f_files);
2684 retnum += NFSX_HYPER;
2686 case NFSATTRBIT_FSLOCATIONS:
2687 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2690 retnum += 2 * NFSX_UNSIGNED;
2692 case NFSATTRBIT_HOMOGENEOUS:
2693 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2694 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2698 retnum += NFSX_UNSIGNED;
2700 case NFSATTRBIT_MAXFILESIZE:
2701 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2702 uquad = NFSRV_MAXFILESIZE;
2703 txdr_hyper(uquad, tl);
2704 retnum += NFSX_HYPER;
2706 case NFSATTRBIT_MAXLINK:
2707 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2708 *tl = txdr_unsigned(NFS_LINK_MAX);
2709 retnum += NFSX_UNSIGNED;
2711 case NFSATTRBIT_MAXNAME:
2712 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2713 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2714 retnum += NFSX_UNSIGNED;
2716 case NFSATTRBIT_MAXREAD:
2717 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2719 *tl = txdr_unsigned(fsinf.fs_rtmax);
2720 retnum += NFSX_HYPER;
2722 case NFSATTRBIT_MAXWRITE:
2723 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2725 *tl = txdr_unsigned(fsinf.fs_wtmax);
2726 retnum += NFSX_HYPER;
2728 case NFSATTRBIT_MODE:
2729 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2730 *tl = vtonfsv34_mode(vap->va_mode);
2731 retnum += NFSX_UNSIGNED;
2733 case NFSATTRBIT_NOTRUNC:
2734 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2736 retnum += NFSX_UNSIGNED;
2738 case NFSATTRBIT_NUMLINKS:
2739 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2740 *tl = txdr_unsigned(vap->va_nlink);
2741 retnum += NFSX_UNSIGNED;
2743 case NFSATTRBIT_OWNER:
2745 nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2746 retnum += nfsm_strtom(nd, cp, siz);
2748 free(cp, M_NFSSTRING);
2750 case NFSATTRBIT_OWNERGROUP:
2752 nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2753 retnum += nfsm_strtom(nd, cp, siz);
2755 free(cp, M_NFSSTRING);
2757 case NFSATTRBIT_QUOTAHARD:
2758 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2759 freenum = fs->f_bfree;
2761 freenum = fs->f_bavail;
2764 * ufs_quotactl() insists that the uid argument
2765 * equal p_ruid for non-root quota access, so
2766 * we'll just make sure that's the case.
2768 savuid = p->p_cred->p_ruid;
2769 p->p_cred->p_ruid = cred->cr_uid;
2770 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2771 cred->cr_uid, (caddr_t)&dqb))
2772 freenum = min(dqb.dqb_bhardlimit, freenum);
2773 p->p_cred->p_ruid = savuid;
2775 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2776 uquad = (u_int64_t)freenum;
2777 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2778 txdr_hyper(uquad, tl);
2779 retnum += NFSX_HYPER;
2781 case NFSATTRBIT_QUOTASOFT:
2782 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2783 freenum = fs->f_bfree;
2785 freenum = fs->f_bavail;
2788 * ufs_quotactl() insists that the uid argument
2789 * equal p_ruid for non-root quota access, so
2790 * we'll just make sure that's the case.
2792 savuid = p->p_cred->p_ruid;
2793 p->p_cred->p_ruid = cred->cr_uid;
2794 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2795 cred->cr_uid, (caddr_t)&dqb))
2796 freenum = min(dqb.dqb_bsoftlimit, freenum);
2797 p->p_cred->p_ruid = savuid;
2799 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2800 uquad = (u_int64_t)freenum;
2801 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2802 txdr_hyper(uquad, tl);
2803 retnum += NFSX_HYPER;
2805 case NFSATTRBIT_QUOTAUSED:
2809 * ufs_quotactl() insists that the uid argument
2810 * equal p_ruid for non-root quota access, so
2811 * we'll just make sure that's the case.
2813 savuid = p->p_cred->p_ruid;
2814 p->p_cred->p_ruid = cred->cr_uid;
2815 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2816 cred->cr_uid, (caddr_t)&dqb))
2817 freenum = dqb.dqb_curblocks;
2818 p->p_cred->p_ruid = savuid;
2820 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2821 uquad = (u_int64_t)freenum;
2822 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2823 txdr_hyper(uquad, tl);
2824 retnum += NFSX_HYPER;
2826 case NFSATTRBIT_RAWDEV:
2827 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2828 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2829 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2830 retnum += NFSX_V4SPECDATA;
2832 case NFSATTRBIT_SPACEAVAIL:
2833 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2834 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2836 uquad = (u_int64_t)pnfssf->f_bfree;
2838 uquad = (u_int64_t)fs->f_bfree;
2841 uquad = (u_int64_t)pnfssf->f_bavail;
2843 uquad = (u_int64_t)fs->f_bavail;
2846 uquad *= pnfssf->f_bsize;
2848 uquad *= fs->f_bsize;
2849 txdr_hyper(uquad, tl);
2850 retnum += NFSX_HYPER;
2852 case NFSATTRBIT_SPACEFREE:
2853 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2854 if (pnfssf != NULL) {
2855 uquad = (u_int64_t)pnfssf->f_bfree;
2856 uquad *= pnfssf->f_bsize;
2858 uquad = (u_int64_t)fs->f_bfree;
2859 uquad *= fs->f_bsize;
2861 txdr_hyper(uquad, tl);
2862 retnum += NFSX_HYPER;
2864 case NFSATTRBIT_SPACETOTAL:
2865 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2866 if (pnfssf != NULL) {
2867 uquad = (u_int64_t)pnfssf->f_blocks;
2868 uquad *= pnfssf->f_bsize;
2870 uquad = (u_int64_t)fs->f_blocks;
2871 uquad *= fs->f_bsize;
2873 txdr_hyper(uquad, tl);
2874 retnum += NFSX_HYPER;
2876 case NFSATTRBIT_SPACEUSED:
2877 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2878 txdr_hyper(vap->va_bytes, tl);
2879 retnum += NFSX_HYPER;
2881 case NFSATTRBIT_TIMEACCESS:
2882 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2883 txdr_nfsv4time(&vap->va_atime, tl);
2884 retnum += NFSX_V4TIME;
2886 case NFSATTRBIT_TIMEACCESSSET:
2887 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2888 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2889 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2890 txdr_nfsv4time(&vap->va_atime, tl);
2891 retnum += NFSX_V4SETTIME;
2893 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2894 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2895 retnum += NFSX_UNSIGNED;
2898 case NFSATTRBIT_TIMEDELTA:
2899 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2900 temptime.tv_sec = 0;
2901 temptime.tv_nsec = 1000000000 / hz;
2902 txdr_nfsv4time(&temptime, tl);
2903 retnum += NFSX_V4TIME;
2905 case NFSATTRBIT_TIMEMETADATA:
2906 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2907 txdr_nfsv4time(&vap->va_ctime, tl);
2908 retnum += NFSX_V4TIME;
2910 case NFSATTRBIT_TIMEMODIFY:
2911 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2912 txdr_nfsv4time(&vap->va_mtime, tl);
2913 retnum += NFSX_V4TIME;
2915 case NFSATTRBIT_TIMEMODIFYSET:
2916 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2917 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2918 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2919 txdr_nfsv4time(&vap->va_mtime, tl);
2920 retnum += NFSX_V4SETTIME;
2922 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2923 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2924 retnum += NFSX_UNSIGNED;
2927 case NFSATTRBIT_MOUNTEDONFILEID:
2928 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2930 uquad = mounted_on_fileno;
2932 uquad = vap->va_fileid;
2933 txdr_hyper(uquad, tl);
2934 retnum += NFSX_HYPER;
2936 case NFSATTRBIT_SUPPATTREXCLCREAT:
2937 NFSSETSUPP_ATTRBIT(&attrbits);
2938 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2939 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2940 retnum += nfsrv_putattrbit(nd, &attrbits);
2942 case NFSATTRBIT_FSLAYOUTTYPE:
2943 case NFSATTRBIT_LAYOUTTYPE:
2944 if (nfsrv_devidcnt == 0)
2949 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2950 *tl++ = txdr_unsigned(1); /* One entry. */
2951 if (nfsrv_doflexfile != 0 ||
2952 nfsrv_maxpnfsmirror > 1)
2953 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2955 *tl = txdr_unsigned(
2956 NFSLAYOUT_NFSV4_1_FILES);
2958 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2961 retnum += siz * NFSX_UNSIGNED;
2963 case NFSATTRBIT_LAYOUTALIGNMENT:
2964 case NFSATTRBIT_LAYOUTBLKSIZE:
2965 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2966 *tl = txdr_unsigned(NFS_SRVMAXIO);
2967 retnum += NFSX_UNSIGNED;
2970 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2977 *retnump = txdr_unsigned(retnum);
2978 return (retnum + prefixnum);
2982 * Put the attribute bits onto an mbuf list.
2983 * Return the number of bytes of output generated.
2986 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2989 int cnt, i, bytesize;
2991 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2992 if (attrbitp->bits[cnt - 1])
2994 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2995 NFSM_BUILD(tl, u_int32_t *, bytesize);
2996 *tl++ = txdr_unsigned(cnt);
2997 for (i = 0; i < cnt; i++)
2998 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3003 * Convert a uid to a string.
3004 * If the lookup fails, just output the digits.
3006 * cpp - points to a buffer of size NFSV4_SMALLSTR
3007 * (malloc a larger one, as required)
3008 * retlenp - pointer to length to be returned
3011 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3014 struct nfsusrgrp *usrp;
3017 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3018 struct nfsrv_lughash *hp;
3022 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3024 * Always map nfsrv_defaultuid to "nobody".
3026 if (uid == nfsrv_defaultuid) {
3027 i = nfsrv_dnsnamelen + 7;
3029 if (len > NFSV4_SMALLSTR)
3030 free(cp, M_NFSSTRING);
3031 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3037 NFSBCOPY("nobody@", cp, 7);
3039 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3043 hp = NFSUSERHASH(uid);
3045 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3046 if (usrp->lug_uid == uid) {
3047 if (usrp->lug_expiry < NFSD_MONOSEC)
3050 * If the name doesn't already have an '@'
3051 * in it, append @domainname to it.
3053 for (i = 0; i < usrp->lug_namelen; i++) {
3054 if (usrp->lug_name[i] == '@') {
3060 i = usrp->lug_namelen;
3062 i = usrp->lug_namelen +
3063 nfsrv_dnsnamelen + 1;
3065 mtx_unlock(&hp->mtx);
3066 if (len > NFSV4_SMALLSTR)
3067 free(cp, M_NFSSTRING);
3068 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3074 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3075 if (!hasampersand) {
3076 cp += usrp->lug_namelen;
3078 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3080 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3081 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3083 mtx_unlock(&hp->mtx);
3087 mtx_unlock(&hp->mtx);
3089 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3090 if (ret == 0 && cnt < 2)
3095 * No match, just return a string of digits.
3099 while (tmp || i == 0) {
3103 len = (i > len) ? len : i;
3107 for (i = 0; i < len; i++) {
3108 *cp-- = '0' + (tmp % 10);
3115 * Get a credential for the uid with the server's group list.
3116 * If none is found, just return the credential passed in after
3117 * logging a warning message.
3120 nfsrv_getgrpscred(struct ucred *oldcred)
3122 struct nfsusrgrp *usrp;
3123 struct ucred *newcred;
3126 struct nfsrv_lughash *hp;
3129 uid = oldcred->cr_uid;
3131 if (nfsrv_dnsnamelen > 0) {
3132 hp = NFSUSERHASH(uid);
3134 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3135 if (usrp->lug_uid == uid) {
3136 if (usrp->lug_expiry < NFSD_MONOSEC)
3138 if (usrp->lug_cred != NULL) {
3139 newcred = crhold(usrp->lug_cred);
3143 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3144 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3146 mtx_unlock(&hp->mtx);
3150 mtx_unlock(&hp->mtx);
3152 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3153 if (ret == 0 && cnt < 2)
3160 * Convert a string to a uid.
3161 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3163 * If this is called from a client side mount using AUTH_SYS and the
3164 * string is made up entirely of digits, just convert the string to
3168 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3171 char *cp, *endstr, *str0;
3172 struct nfsusrgrp *usrp;
3176 struct nfsrv_lughash *hp, *hp2;
3179 error = NFSERR_BADOWNER;
3182 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3184 tuid = (uid_t)strtoul(str0, &endstr, 10);
3185 if ((endstr - str0) == len) {
3186 /* A numeric string. */
3187 if ((nd->nd_flag & ND_KERBV) == 0 &&
3188 ((nd->nd_flag & ND_NFSCL) != 0 ||
3189 nfsd_enable_stringtouid != 0))
3192 error = NFSERR_BADOWNER;
3198 cp = strchr(str0, '@');
3200 i = (int)(cp++ - str0);
3206 if (nfsrv_dnsnamelen > 0) {
3208 * If an '@' is found and the domain name matches, search for
3209 * the name with dns stripped off.
3210 * Mixed case alpahbetics will match for the domain name, but
3211 * all upper case will not.
3213 if (cnt == 0 && i < len && i > 0 &&
3214 (len - 1 - i) == nfsrv_dnsnamelen &&
3215 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3216 len -= (nfsrv_dnsnamelen + 1);
3221 * Check for the special case of "nobody".
3223 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3224 *uidp = nfsrv_defaultuid;
3229 hp = NFSUSERNAMEHASH(str, len);
3231 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3232 if (usrp->lug_namelen == len &&
3233 !NFSBCMP(usrp->lug_name, str, len)) {
3234 if (usrp->lug_expiry < NFSD_MONOSEC)
3236 hp2 = NFSUSERHASH(usrp->lug_uid);
3237 mtx_lock(&hp2->mtx);
3238 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3239 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3241 *uidp = usrp->lug_uid;
3242 mtx_unlock(&hp2->mtx);
3243 mtx_unlock(&hp->mtx);
3248 mtx_unlock(&hp->mtx);
3250 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3252 if (ret == 0 && cnt < 2)
3255 error = NFSERR_BADOWNER;
3263 * Convert a gid to a string.
3264 * gid - the group id
3265 * cpp - points to a buffer of size NFSV4_SMALLSTR
3266 * (malloc a larger one, as required)
3267 * retlenp - pointer to length to be returned
3270 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3273 struct nfsusrgrp *usrp;
3276 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3277 struct nfsrv_lughash *hp;
3281 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3283 * Always map nfsrv_defaultgid to "nogroup".
3285 if (gid == nfsrv_defaultgid) {
3286 i = nfsrv_dnsnamelen + 8;
3288 if (len > NFSV4_SMALLSTR)
3289 free(cp, M_NFSSTRING);
3290 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3296 NFSBCOPY("nogroup@", cp, 8);
3298 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3302 hp = NFSGROUPHASH(gid);
3304 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3305 if (usrp->lug_gid == gid) {
3306 if (usrp->lug_expiry < NFSD_MONOSEC)
3309 * If the name doesn't already have an '@'
3310 * in it, append @domainname to it.
3312 for (i = 0; i < usrp->lug_namelen; i++) {
3313 if (usrp->lug_name[i] == '@') {
3319 i = usrp->lug_namelen;
3321 i = usrp->lug_namelen +
3322 nfsrv_dnsnamelen + 1;
3324 mtx_unlock(&hp->mtx);
3325 if (len > NFSV4_SMALLSTR)
3326 free(cp, M_NFSSTRING);
3327 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3333 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3334 if (!hasampersand) {
3335 cp += usrp->lug_namelen;
3337 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3339 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3340 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3342 mtx_unlock(&hp->mtx);
3346 mtx_unlock(&hp->mtx);
3348 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3349 if (ret == 0 && cnt < 2)
3354 * No match, just return a string of digits.
3358 while (tmp || i == 0) {
3362 len = (i > len) ? len : i;
3366 for (i = 0; i < len; i++) {
3367 *cp-- = '0' + (tmp % 10);
3374 * Convert a string to a gid.
3375 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3377 * If this is called from a client side mount using AUTH_SYS and the
3378 * string is made up entirely of digits, just convert the string to
3382 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3385 char *cp, *endstr, *str0;
3386 struct nfsusrgrp *usrp;
3390 struct nfsrv_lughash *hp, *hp2;
3393 error = NFSERR_BADOWNER;
3396 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3398 tgid = (gid_t)strtoul(str0, &endstr, 10);
3399 if ((endstr - str0) == len) {
3400 /* A numeric string. */
3401 if ((nd->nd_flag & ND_KERBV) == 0 &&
3402 ((nd->nd_flag & ND_NFSCL) != 0 ||
3403 nfsd_enable_stringtouid != 0))
3406 error = NFSERR_BADOWNER;
3412 cp = strchr(str0, '@');
3414 i = (int)(cp++ - str0);
3420 if (nfsrv_dnsnamelen > 0) {
3422 * If an '@' is found and the dns name matches, search for the
3423 * name with the dns stripped off.
3425 if (cnt == 0 && i < len && i > 0 &&
3426 (len - 1 - i) == nfsrv_dnsnamelen &&
3427 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3428 len -= (nfsrv_dnsnamelen + 1);
3433 * Check for the special case of "nogroup".
3435 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3436 *gidp = nfsrv_defaultgid;
3441 hp = NFSGROUPNAMEHASH(str, len);
3443 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3444 if (usrp->lug_namelen == len &&
3445 !NFSBCMP(usrp->lug_name, str, len)) {
3446 if (usrp->lug_expiry < NFSD_MONOSEC)
3448 hp2 = NFSGROUPHASH(usrp->lug_gid);
3449 mtx_lock(&hp2->mtx);
3450 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3451 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3453 *gidp = usrp->lug_gid;
3454 mtx_unlock(&hp2->mtx);
3455 mtx_unlock(&hp->mtx);
3460 mtx_unlock(&hp->mtx);
3462 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3464 if (ret == 0 && cnt < 2)
3467 error = NFSERR_BADOWNER;
3475 * Cmp len chars, allowing mixed case in the first argument to match lower
3476 * case in the second, but not if the first argument is all upper case.
3477 * Return 0 for a match, 1 otherwise.
3480 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3486 for (i = 0; i < len; i++) {
3487 if (*cp >= 'A' && *cp <= 'Z') {
3488 tmp = *cp++ + ('a' - 'A');
3491 if (tmp >= 'a' && tmp <= 'z')
3504 * Set the port for the nfsuserd.
3507 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3509 struct nfssockreq *rp;
3510 struct sockaddr_in *ad;
3514 if (nfsrv_nfsuserd) {
3522 * Set up the socket record and connect.
3524 rp = &nfsrv_nfsuserdsock;
3525 rp->nr_client = NULL;
3526 rp->nr_sotype = SOCK_DGRAM;
3527 rp->nr_soproto = IPPROTO_UDP;
3528 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3530 rp->nr_nam = malloc(sizeof(*rp->nr_nam), M_SONAME, M_WAITOK | M_ZERO);
3531 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3532 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3533 ad->sin_family = AF_INET;
3534 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3535 ad->sin_port = port;
3536 rp->nr_prog = RPCPROG_NFSUSERD;
3537 rp->nr_vers = RPCNFSUSERD_VERS;
3538 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3540 free(rp->nr_nam, M_SONAME);
3549 * Delete the nfsuserd port.
3552 nfsrv_nfsuserddelport(void)
3556 if (nfsrv_nfsuserd == 0) {
3562 newnfs_disconnect(&nfsrv_nfsuserdsock);
3563 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3567 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3569 * Returns 0 upon success, non-zero otherwise.
3572 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3575 struct nfsrv_descript *nd;
3577 struct nfsrv_descript nfsd;
3582 if (nfsrv_nfsuserd == 0) {
3589 cred = newnfs_getcred();
3590 nd->nd_flag = ND_GSSINITREPLY;
3593 nd->nd_procnum = procnum;
3594 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3595 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3596 if (procnum == RPCNFSUSERD_GETUID)
3597 *tl = txdr_unsigned(uid);
3599 *tl = txdr_unsigned(gid);
3602 (void) nfsm_strtom(nd, name, len);
3604 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3605 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3608 mbuf_freem(nd->nd_mrep);
3609 error = nd->nd_repstat;
3617 * This function is called from the nfssvc(2) system call, to update the
3618 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3621 nfssvc_idname(struct nfsd_idargs *nidp)
3623 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3624 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3625 int i, group_locked, groupname_locked, user_locked, username_locked;
3630 static int onethread = 0;
3631 static time_t lasttime = 0;
3633 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3637 if (nidp->nid_flag & NFSID_INITIALIZE) {
3638 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3639 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3642 free(cp, M_NFSSTRING);
3645 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3647 * Free up all the old stuff and reinitialize hash
3648 * lists. All mutexes for both lists must be locked,
3649 * with the user/group name ones before the uid/gid
3650 * ones, to avoid a LOR.
3652 for (i = 0; i < nfsrv_lughashsize; i++)
3653 mtx_lock(&nfsusernamehash[i].mtx);
3654 for (i = 0; i < nfsrv_lughashsize; i++)
3655 mtx_lock(&nfsuserhash[i].mtx);
3656 for (i = 0; i < nfsrv_lughashsize; i++)
3657 TAILQ_FOREACH_SAFE(usrp,
3658 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3659 nfsrv_removeuser(usrp, 1);
3660 for (i = 0; i < nfsrv_lughashsize; i++)
3661 mtx_unlock(&nfsuserhash[i].mtx);
3662 for (i = 0; i < nfsrv_lughashsize; i++)
3663 mtx_unlock(&nfsusernamehash[i].mtx);
3664 for (i = 0; i < nfsrv_lughashsize; i++)
3665 mtx_lock(&nfsgroupnamehash[i].mtx);
3666 for (i = 0; i < nfsrv_lughashsize; i++)
3667 mtx_lock(&nfsgrouphash[i].mtx);
3668 for (i = 0; i < nfsrv_lughashsize; i++)
3669 TAILQ_FOREACH_SAFE(usrp,
3670 &nfsgrouphash[i].lughead, lug_numhash,
3672 nfsrv_removeuser(usrp, 0);
3673 for (i = 0; i < nfsrv_lughashsize; i++)
3674 mtx_unlock(&nfsgrouphash[i].mtx);
3675 for (i = 0; i < nfsrv_lughashsize; i++)
3676 mtx_unlock(&nfsgroupnamehash[i].mtx);
3677 free(nfsrv_dnsname, M_NFSSTRING);
3678 nfsrv_dnsname = NULL;
3680 if (nfsuserhash == NULL) {
3681 /* Allocate the hash tables. */
3682 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3683 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3685 for (i = 0; i < nfsrv_lughashsize; i++)
3686 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3687 NULL, MTX_DEF | MTX_DUPOK);
3688 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3689 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3691 for (i = 0; i < nfsrv_lughashsize; i++)
3692 mtx_init(&nfsusernamehash[i].mtx,
3693 "nfsusrhash", NULL, MTX_DEF |
3695 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3696 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3698 for (i = 0; i < nfsrv_lughashsize; i++)
3699 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3700 NULL, MTX_DEF | MTX_DUPOK);
3701 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3702 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3704 for (i = 0; i < nfsrv_lughashsize; i++)
3705 mtx_init(&nfsgroupnamehash[i].mtx,
3706 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3708 /* (Re)initialize the list heads. */
3709 for (i = 0; i < nfsrv_lughashsize; i++)
3710 TAILQ_INIT(&nfsuserhash[i].lughead);
3711 for (i = 0; i < nfsrv_lughashsize; i++)
3712 TAILQ_INIT(&nfsusernamehash[i].lughead);
3713 for (i = 0; i < nfsrv_lughashsize; i++)
3714 TAILQ_INIT(&nfsgrouphash[i].lughead);
3715 for (i = 0; i < nfsrv_lughashsize; i++)
3716 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3719 * Put name in "DNS" string.
3722 nfsrv_defaultuid = nidp->nid_uid;
3723 nfsrv_defaultgid = nidp->nid_gid;
3725 nfsrv_usermax = nidp->nid_usermax;
3726 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3731 * malloc the new one now, so any potential sleep occurs before
3732 * manipulation of the lists.
3734 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3735 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3736 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3738 if (error == 0 && nidp->nid_ngroup > 0 &&
3739 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3740 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3742 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3743 sizeof(gid_t) * nidp->nid_ngroup);
3746 * Create a credential just like svc_getcred(),
3747 * but using the group list provided.
3750 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3751 crsetgroups(cr, nidp->nid_ngroup, grps);
3752 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3753 cr->cr_prison = &prison0;
3754 prison_hold(cr->cr_prison);
3756 mac_cred_associate_nfsd(cr);
3758 newusrp->lug_cred = cr;
3763 free(newusrp, M_NFSUSERGROUP);
3766 newusrp->lug_namelen = nidp->nid_namelen;
3769 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3770 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3771 * The flags user_locked, username_locked, group_locked and
3772 * groupname_locked are set to indicate all of those hash lists are
3773 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3774 * the respective one mutex is locked.
3776 user_locked = username_locked = group_locked = groupname_locked = 0;
3777 hp_name = hp_idnum = NULL;
3780 * Delete old entries, as required.
3782 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3783 /* Must lock all username hash lists first, to avoid a LOR. */
3784 for (i = 0; i < nfsrv_lughashsize; i++)
3785 mtx_lock(&nfsusernamehash[i].mtx);
3786 username_locked = 1;
3787 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3788 mtx_lock(&hp_idnum->mtx);
3789 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3791 if (usrp->lug_uid == nidp->nid_uid)
3792 nfsrv_removeuser(usrp, 1);
3794 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3795 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3796 newusrp->lug_namelen);
3797 mtx_lock(&hp_name->mtx);
3798 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3800 if (usrp->lug_namelen == newusrp->lug_namelen &&
3801 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3802 usrp->lug_namelen)) {
3803 thp = NFSUSERHASH(usrp->lug_uid);
3804 mtx_lock(&thp->mtx);
3805 nfsrv_removeuser(usrp, 1);
3806 mtx_unlock(&thp->mtx);
3809 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3810 mtx_lock(&hp_idnum->mtx);
3811 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3812 /* Must lock all groupname hash lists first, to avoid a LOR. */
3813 for (i = 0; i < nfsrv_lughashsize; i++)
3814 mtx_lock(&nfsgroupnamehash[i].mtx);
3815 groupname_locked = 1;
3816 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3817 mtx_lock(&hp_idnum->mtx);
3818 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3820 if (usrp->lug_gid == nidp->nid_gid)
3821 nfsrv_removeuser(usrp, 0);
3823 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3824 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3825 newusrp->lug_namelen);
3826 mtx_lock(&hp_name->mtx);
3827 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3829 if (usrp->lug_namelen == newusrp->lug_namelen &&
3830 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3831 usrp->lug_namelen)) {
3832 thp = NFSGROUPHASH(usrp->lug_gid);
3833 mtx_lock(&thp->mtx);
3834 nfsrv_removeuser(usrp, 0);
3835 mtx_unlock(&thp->mtx);
3838 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3839 mtx_lock(&hp_idnum->mtx);
3843 * Now, we can add the new one.
3845 if (nidp->nid_usertimeout)
3846 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3848 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3849 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3850 newusrp->lug_uid = nidp->nid_uid;
3851 thp = NFSUSERHASH(newusrp->lug_uid);
3852 mtx_assert(&thp->mtx, MA_OWNED);
3853 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3854 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3855 mtx_assert(&thp->mtx, MA_OWNED);
3856 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3857 atomic_add_int(&nfsrv_usercnt, 1);
3858 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3859 newusrp->lug_gid = nidp->nid_gid;
3860 thp = NFSGROUPHASH(newusrp->lug_gid);
3861 mtx_assert(&thp->mtx, MA_OWNED);
3862 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3863 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3864 mtx_assert(&thp->mtx, MA_OWNED);
3865 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3866 atomic_add_int(&nfsrv_usercnt, 1);
3868 if (newusrp->lug_cred != NULL)
3869 crfree(newusrp->lug_cred);
3870 free(newusrp, M_NFSUSERGROUP);
3874 * Once per second, allow one thread to trim the cache.
3876 if (lasttime < NFSD_MONOSEC &&
3877 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3879 * First, unlock the single mutexes, so that all entries
3880 * can be locked and any LOR is avoided.
3882 if (hp_name != NULL) {
3883 mtx_unlock(&hp_name->mtx);
3886 if (hp_idnum != NULL) {
3887 mtx_unlock(&hp_idnum->mtx);
3891 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3892 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3893 if (username_locked == 0) {
3894 for (i = 0; i < nfsrv_lughashsize; i++)
3895 mtx_lock(&nfsusernamehash[i].mtx);
3896 username_locked = 1;
3898 KASSERT(user_locked == 0,
3899 ("nfssvc_idname: user_locked"));
3900 for (i = 0; i < nfsrv_lughashsize; i++)
3901 mtx_lock(&nfsuserhash[i].mtx);
3903 for (i = 0; i < nfsrv_lughashsize; i++) {
3904 TAILQ_FOREACH_SAFE(usrp,
3905 &nfsuserhash[i].lughead, lug_numhash,
3907 if (usrp->lug_expiry < NFSD_MONOSEC)
3908 nfsrv_removeuser(usrp, 1);
3910 for (i = 0; i < nfsrv_lughashsize; i++) {
3912 * Trim the cache using an approximate LRU
3913 * algorithm. This code deletes the least
3914 * recently used entry on each hash list.
3916 if (nfsrv_usercnt <= nfsrv_usermax)
3918 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3920 nfsrv_removeuser(usrp, 1);
3923 if (groupname_locked == 0) {
3924 for (i = 0; i < nfsrv_lughashsize; i++)
3925 mtx_lock(&nfsgroupnamehash[i].mtx);
3926 groupname_locked = 1;
3928 KASSERT(group_locked == 0,
3929 ("nfssvc_idname: group_locked"));
3930 for (i = 0; i < nfsrv_lughashsize; i++)
3931 mtx_lock(&nfsgrouphash[i].mtx);
3933 for (i = 0; i < nfsrv_lughashsize; i++) {
3934 TAILQ_FOREACH_SAFE(usrp,
3935 &nfsgrouphash[i].lughead, lug_numhash,
3937 if (usrp->lug_expiry < NFSD_MONOSEC)
3938 nfsrv_removeuser(usrp, 0);
3940 for (i = 0; i < nfsrv_lughashsize; i++) {
3942 * Trim the cache using an approximate LRU
3943 * algorithm. This code deletes the least
3944 * recently user entry on each hash list.
3946 if (nfsrv_usercnt <= nfsrv_usermax)
3948 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3950 nfsrv_removeuser(usrp, 0);
3953 lasttime = NFSD_MONOSEC;
3954 atomic_store_rel_int(&onethread, 0);
3957 /* Now, unlock all locked mutexes. */
3958 if (hp_idnum != NULL)
3959 mtx_unlock(&hp_idnum->mtx);
3960 if (hp_name != NULL)
3961 mtx_unlock(&hp_name->mtx);
3962 if (user_locked != 0)
3963 for (i = 0; i < nfsrv_lughashsize; i++)
3964 mtx_unlock(&nfsuserhash[i].mtx);
3965 if (username_locked != 0)
3966 for (i = 0; i < nfsrv_lughashsize; i++)
3967 mtx_unlock(&nfsusernamehash[i].mtx);
3968 if (group_locked != 0)
3969 for (i = 0; i < nfsrv_lughashsize; i++)
3970 mtx_unlock(&nfsgrouphash[i].mtx);
3971 if (groupname_locked != 0)
3972 for (i = 0; i < nfsrv_lughashsize; i++)
3973 mtx_unlock(&nfsgroupnamehash[i].mtx);
3980 * Remove a user/group name element.
3983 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3985 struct nfsrv_lughash *hp;
3988 hp = NFSUSERHASH(usrp->lug_uid);
3989 mtx_assert(&hp->mtx, MA_OWNED);
3990 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3991 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3992 mtx_assert(&hp->mtx, MA_OWNED);
3993 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3995 hp = NFSGROUPHASH(usrp->lug_gid);
3996 mtx_assert(&hp->mtx, MA_OWNED);
3997 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3998 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3999 mtx_assert(&hp->mtx, MA_OWNED);
4000 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4002 atomic_add_int(&nfsrv_usercnt, -1);
4003 if (usrp->lug_cred != NULL)
4004 crfree(usrp->lug_cred);
4005 free(usrp, M_NFSUSERGROUP);
4009 * Free up all the allocations related to the name<-->id cache.
4010 * This function should only be called when the nfsuserd daemon isn't
4011 * running, since it doesn't do any locking.
4012 * This function is meant to be used when the nfscommon module is unloaded.
4015 nfsrv_cleanusergroup(void)
4017 struct nfsrv_lughash *hp, *hp2;
4018 struct nfsusrgrp *nusrp, *usrp;
4021 if (nfsuserhash == NULL)
4024 for (i = 0; i < nfsrv_lughashsize; i++) {
4025 hp = &nfsuserhash[i];
4026 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4027 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4028 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4030 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4031 if (usrp->lug_cred != NULL)
4032 crfree(usrp->lug_cred);
4033 free(usrp, M_NFSUSERGROUP);
4035 hp = &nfsgrouphash[i];
4036 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4037 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4038 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4040 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4041 if (usrp->lug_cred != NULL)
4042 crfree(usrp->lug_cred);
4043 free(usrp, M_NFSUSERGROUP);
4045 mtx_destroy(&nfsuserhash[i].mtx);
4046 mtx_destroy(&nfsusernamehash[i].mtx);
4047 mtx_destroy(&nfsgroupnamehash[i].mtx);
4048 mtx_destroy(&nfsgrouphash[i].mtx);
4050 free(nfsuserhash, M_NFSUSERGROUP);
4051 free(nfsusernamehash, M_NFSUSERGROUP);
4052 free(nfsgrouphash, M_NFSUSERGROUP);
4053 free(nfsgroupnamehash, M_NFSUSERGROUP);
4054 free(nfsrv_dnsname, M_NFSSTRING);
4058 * This function scans a byte string and checks for UTF-8 compliance.
4059 * It returns 0 if it conforms and NFSERR_INVAL if not.
4062 nfsrv_checkutf8(u_int8_t *cp, int len)
4064 u_int32_t val = 0x0;
4065 int cnt = 0, gotd = 0, shift = 0;
4067 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4071 * Here are what the variables are used for:
4072 * val - the calculated value of a multibyte char, used to check
4073 * that it was coded with the correct range
4074 * cnt - the number of 10xxxxxx bytes to follow
4075 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4076 * shift - lower order bits of range (ie. "val >> shift" should
4077 * not be 0, in other words, dividing by the lower bound
4078 * of the range should get a non-zero value)
4079 * byte - used to calculate cnt
4083 /* This handles the 10xxxxxx bytes */
4084 if ((*cp & 0xc0) != 0x80 ||
4085 (gotd && (*cp & 0x20))) {
4086 error = NFSERR_INVAL;
4091 val |= (*cp & 0x3f);
4093 if (cnt == 0 && (val >> shift) == 0x0) {
4094 error = NFSERR_INVAL;
4097 } else if (*cp & 0x80) {
4098 /* first byte of multi byte char */
4100 while ((byte & 0x40) && cnt < 6) {
4104 if (cnt == 0 || cnt == 6) {
4105 error = NFSERR_INVAL;
4108 val = (*cp & (0x3f >> cnt));
4109 shift = utf8_shift[cnt - 1];
4110 if (cnt == 2 && val == 0xd)
4111 /* Check for the 0xd800-0xdfff case */
4118 error = NFSERR_INVAL;
4126 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4127 * strings, one with the root path in it and the other with the list of
4128 * locations. The list is in the same format as is found in nfr_refs.
4129 * It is a "," separated list of entries, where each of them is of the
4130 * form <server>:<rootpath>. For example
4131 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4132 * The nilp argument is set to 1 for the special case of a null fs_root
4133 * and an empty server list.
4134 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4135 * number of xdr bytes parsed in sump.
4138 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4139 int *sump, int *nilp)
4142 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4143 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4145 SLIST_ENTRY(list) next;
4149 SLIST_HEAD(, list) head;
4156 * Get the fs_root path and check for the special case of null path
4157 * and 0 length server list.
4159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4160 len = fxdr_unsigned(int, *tl);
4161 if (len < 0 || len > 10240) {
4162 error = NFSERR_BADXDR;
4166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4168 error = NFSERR_BADXDR;
4172 *sump = 2 * NFSX_UNSIGNED;
4176 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4177 error = nfsrv_mtostr(nd, cp, len);
4179 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4180 cnt = fxdr_unsigned(int, *tl);
4182 error = NFSERR_BADXDR;
4188 * Now, loop through the location list and make up the srvlist.
4190 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4191 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4194 for (i = 0; i < cnt; i++) {
4196 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4197 nsrv = fxdr_unsigned(int, *tl);
4199 error = NFSERR_BADXDR;
4204 * Handle the first server by putting it in the srvstr.
4206 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4207 len = fxdr_unsigned(int, *tl);
4208 if (len <= 0 || len > 1024) {
4209 error = NFSERR_BADXDR;
4212 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4217 error = nfsrv_mtostr(nd, cp3, len);
4223 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4224 for (j = 1; j < nsrv; j++) {
4226 * Yuck, put them in an slist and process them later.
4228 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4229 len = fxdr_unsigned(int, *tl);
4230 if (len <= 0 || len > 1024) {
4231 error = NFSERR_BADXDR;
4234 lsp = (struct list *)malloc(sizeof (struct list)
4235 + len, M_TEMP, M_WAITOK);
4236 error = nfsrv_mtostr(nd, lsp->host, len);
4239 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4241 SLIST_INSERT_HEAD(&head, lsp, next);
4245 * Finally, we can get the path.
4247 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4248 len = fxdr_unsigned(int, *tl);
4249 if (len <= 0 || len > 1024) {
4250 error = NFSERR_BADXDR;
4253 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4254 error = nfsrv_mtostr(nd, cp3, len);
4257 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4262 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4263 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4266 NFSBCOPY(lsp->host, cp3, lsp->len);
4269 NFSBCOPY(str, cp3, stringlen);
4272 siz += (lsp->len + stringlen + 2);
4279 NFSEXITCODE2(0, nd);
4283 free(cp, M_NFSSTRING);
4285 free(cp2, M_NFSSTRING);
4286 NFSEXITCODE2(error, nd);
4291 * Make the malloc'd space large enough. This is a pain, but the xdr
4292 * doesn't set an upper bound on the side, so...
4295 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4302 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4303 NFSBCOPY(*cpp, cp, *slenp);
4304 free(*cpp, M_NFSSTRING);
4308 *slenp = siz + 1024;
4312 * Initialize the reply header data structures.
4315 nfsrvd_rephead(struct nfsrv_descript *nd)
4320 * If this is a big reply, use a cluster.
4322 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4323 nfs_bigreply[nd->nd_procnum]) {
4324 NFSMCLGET(mreq, M_WAITOK);
4332 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4333 mbuf_setlen(mreq, 0);
4335 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4336 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4340 * Lock a socket against others.
4341 * Currently used to serialize connect/disconnect attempts.
4344 newnfs_sndlock(int *flagp)
4349 while (*flagp & NFSR_SNDLOCK) {
4350 *flagp |= NFSR_WANTSND;
4353 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4354 PZERO - 1, "nfsndlck", &ts);
4356 *flagp |= NFSR_SNDLOCK;
4362 * Unlock the stream socket for others.
4365 newnfs_sndunlock(int *flagp)
4369 if ((*flagp & NFSR_SNDLOCK) == 0)
4370 panic("nfs sndunlock");
4371 *flagp &= ~NFSR_SNDLOCK;
4372 if (*flagp & NFSR_WANTSND) {
4373 *flagp &= ~NFSR_WANTSND;
4374 wakeup((caddr_t)flagp);
4380 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4381 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4383 struct in_addr saddr;
4384 uint32_t portnum, *tl;
4386 sa_family_t af = AF_UNSPEC;
4387 char addr[64], protocol[5], *cp;
4388 int cantparse = 0, error = 0;
4391 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4392 i = fxdr_unsigned(int, *tl);
4393 if (i >= 3 && i <= 4) {
4394 error = nfsrv_mtostr(nd, protocol, i);
4397 if (strcmp(protocol, "tcp") == 0) {
4400 } else if (strcmp(protocol, "udp") == 0) {
4403 } else if (strcmp(protocol, "tcp6") == 0) {
4406 } else if (strcmp(protocol, "udp6") == 0) {
4414 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4419 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4420 i = fxdr_unsigned(int, *tl);
4422 error = NFSERR_BADXDR;
4424 } else if (cantparse == 0 && i >= 11 && i < 64) {
4426 * The shortest address is 11chars and the longest is < 64.
4428 error = nfsrv_mtostr(nd, addr, i);
4432 /* Find the port# at the end and extract that. */
4436 /* Count back two '.'s from end to get port# field. */
4437 for (j = 0; j < i; j++) {
4447 * The NFSv4 port# is appended as .N.N, where N is
4448 * a decimal # in the range 0-255, just like an inet4
4449 * address. Cheat and use inet_aton(), which will
4450 * return a Class A address and then shift the high
4451 * order 8bits over to convert it to the port#.
4454 if (inet_aton(cp, &saddr) == 1) {
4455 portnum = ntohl(saddr.s_addr);
4456 portv = (uint16_t)((portnum >> 16) |
4462 if (cantparse == 0) {
4463 if (af == AF_INET) {
4464 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4465 sin->sin_len = sizeof(*sin);
4466 sin->sin_family = AF_INET;
4467 sin->sin_port = htons(portv);
4472 if (inet_pton(af, addr, &sin6->sin6_addr)
4474 sin6->sin6_len = sizeof(*sin6);
4475 sin6->sin6_family = AF_INET6;
4476 sin6->sin6_port = htons(portv);
4484 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4495 * Handle an NFSv4.1 Sequence request for the session.
4496 * If reply != NULL, use it to return the cached reply, as required.
4497 * The client gets a cached reply via this call for callbacks, however the
4498 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4501 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4502 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4509 if (slotid > maxslot)
4510 return (NFSERR_BADSLOT);
4511 if (seqid == slots[slotid].nfssl_seq) {
4513 if (slots[slotid].nfssl_inprog != 0)
4514 error = NFSERR_DELAY;
4515 else if (slots[slotid].nfssl_reply != NULL) {
4516 if (reply != NULL) {
4517 *reply = slots[slotid].nfssl_reply;
4518 slots[slotid].nfssl_reply = NULL;
4520 slots[slotid].nfssl_inprog = 1;
4521 error = NFSERR_REPLYFROMCACHE;
4523 /* No reply cached, so just do it. */
4524 slots[slotid].nfssl_inprog = 1;
4525 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4526 if (slots[slotid].nfssl_reply != NULL)
4527 m_freem(slots[slotid].nfssl_reply);
4528 slots[slotid].nfssl_reply = NULL;
4529 slots[slotid].nfssl_inprog = 1;
4530 slots[slotid].nfssl_seq++;
4532 error = NFSERR_SEQMISORDERED;
4537 * Cache this reply for the slot.
4538 * Use the "rep" argument to return the cached reply if repstat is set to
4539 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4542 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4546 if (repstat == NFSERR_REPLYFROMCACHE) {
4547 *rep = slots[slotid].nfssl_reply;
4548 slots[slotid].nfssl_reply = NULL;
4550 if (slots[slotid].nfssl_reply != NULL)
4551 m_freem(slots[slotid].nfssl_reply);
4552 slots[slotid].nfssl_reply = *rep;
4554 slots[slotid].nfssl_inprog = 0;
4558 * Generate the xdr for an NFSv4.1 Sequence Operation.
4561 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4562 struct nfsclsession *sep, int dont_replycache)
4564 uint32_t *tl, slotseq = 0;
4565 int error, maxslot, slotpos;
4566 uint8_t sessionid[NFSX_V4SESSIONID];
4568 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4571 /* Build the Sequence arguments. */
4572 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4573 nd->nd_sequence = tl;
4574 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4575 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4576 nd->nd_slotseq = tl;
4578 nd->nd_flag |= ND_HASSLOTID;
4579 nd->nd_slotid = slotpos;
4580 *tl++ = txdr_unsigned(slotseq);
4581 *tl++ = txdr_unsigned(slotpos);
4582 *tl++ = txdr_unsigned(maxslot);
4583 if (dont_replycache == 0)
4589 * There are two errors and the rest of the session can
4591 * NFSERR_BADSESSION: This bad session should just generate
4592 * the same error again when the RPC is retried.
4593 * ESTALE: A forced dismount is in progress and will cause the
4594 * RPC to fail later.
4601 nd->nd_flag |= ND_HASSEQUENCE;
4605 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4606 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4608 int i, maxslot, slotpos;
4611 /* Find an unused slot. */
4614 mtx_lock(&sep->nfsess_mtx);
4616 if (nmp != NULL && sep->nfsess_defunct != 0) {
4617 /* Just return the bad session. */
4618 bcopy(sep->nfsess_sessionid, sessionid,
4620 mtx_unlock(&sep->nfsess_mtx);
4621 return (NFSERR_BADSESSION);
4624 for (i = 0; i < sep->nfsess_foreslots; i++) {
4625 if ((bitval & sep->nfsess_slots) == 0) {
4627 sep->nfsess_slots |= bitval;
4628 sep->nfsess_slotseq[i]++;
4629 *slotseqp = sep->nfsess_slotseq[i];
4634 if (slotpos == -1) {
4636 * If a forced dismount is in progress, just return.
4637 * This RPC attempt will fail when it calls
4640 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4641 mtx_unlock(&sep->nfsess_mtx);
4644 /* Wake up once/sec, to check for a forced dismount. */
4645 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4646 PZERO, "nfsclseq", hz);
4648 } while (slotpos == -1);
4649 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4651 for (i = 0; i < 64; i++) {
4652 if ((bitval & sep->nfsess_slots) != 0)
4656 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4657 mtx_unlock(&sep->nfsess_mtx);
4658 *slotposp = slotpos;
4659 *maxslotp = maxslot;
4664 * Free a session slot.
4667 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4674 mtx_lock(&sep->nfsess_mtx);
4675 if ((bitval & sep->nfsess_slots) == 0)
4676 printf("freeing free slot!!\n");
4677 sep->nfsess_slots &= ~bitval;
4678 wakeup(&sep->nfsess_slots);
4679 mtx_unlock(&sep->nfsess_mtx);
4683 * Search for a matching pnfsd DS, based on the nmp arg.
4684 * Return one if found, NULL otherwise.
4687 nfsv4_findmirror(struct nfsmount *nmp)
4689 struct nfsdevice *ds;
4691 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4693 * Search the DS server list for a match with nmp.
4695 if (nfsrv_devidcnt == 0)
4697 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4698 if (ds->nfsdev_nmp == nmp) {
4699 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");