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, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
160 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
161 { 0, 1, 0, 0, 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,
203 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
204 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
206 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
213 } nfsv4_opmap[NFSV41_NPROCS] = {
215 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
216 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
217 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
218 { NFSV4OP_ACCESS, 2, "Access", 6, },
219 { NFSV4OP_READLINK, 2, "Readlink", 8, },
220 { NFSV4OP_READ, 1, "Read", 4, },
221 { NFSV4OP_WRITE, 2, "Write", 5, },
222 { NFSV4OP_OPEN, 5, "Open", 4, },
223 { NFSV4OP_CREATE, 5, "Create", 6, },
224 { NFSV4OP_CREATE, 1, "Create", 6, },
225 { NFSV4OP_CREATE, 3, "Create", 6, },
226 { NFSV4OP_REMOVE, 1, "Remove", 6, },
227 { NFSV4OP_REMOVE, 1, "Remove", 6, },
228 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
229 { NFSV4OP_SAVEFH, 4, "Link", 4, },
230 { NFSV4OP_READDIR, 2, "Readdir", 7, },
231 { NFSV4OP_READDIR, 2, "Readdir", 7, },
232 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
233 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
234 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
235 { NFSV4OP_COMMIT, 2, "Commit", 6, },
236 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
237 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
238 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
239 { NFSV4OP_LOCK, 1, "Lock", 4, },
240 { NFSV4OP_LOCKU, 1, "LockU", 5, },
241 { NFSV4OP_OPEN, 2, "Open", 4, },
242 { NFSV4OP_CLOSE, 1, "Close", 5, },
243 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
244 { NFSV4OP_LOCKT, 1, "LockT", 5, },
245 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
246 { NFSV4OP_RENEW, 1, "Renew", 5, },
247 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
248 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
249 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
250 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
251 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
252 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
253 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
254 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
255 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
256 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
257 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
258 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
259 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
260 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
261 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
262 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
263 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
264 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
265 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
266 { NFSV4OP_READ, 1, "ReadDS", 6, },
267 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
268 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
269 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
273 * NFS RPCS that have large request message size.
275 static int nfs_bigrequest[NFSV41_NPROCS] = {
276 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
282 * Start building a request. Mostly just put the first file handle in
286 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
287 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
288 int vers, int minorvers)
293 nfsattrbit_t attrbits;
296 * First, fill in some of the fields of nd.
298 nd->nd_slotseq = NULL;
299 if (vers == NFS_VER4) {
300 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
301 if (minorvers == NFSV41_MINORVERSION)
302 nd->nd_flag |= ND_NFSV41;
303 } else if (vers == NFS_VER3)
304 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
306 if (NFSHASNFSV4(nmp)) {
307 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
308 if (NFSHASNFSV4N(nmp))
309 nd->nd_flag |= ND_NFSV41;
310 } else if (NFSHASNFSV3(nmp))
311 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
313 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
315 nd->nd_procnum = procnum;
319 * Get the first mbuf for the request.
321 if (nfs_bigrequest[procnum])
322 NFSMCLGET(mb, M_WAITOK);
326 nd->nd_mreq = nd->nd_mb = mb;
327 nd->nd_bpos = NFSMTOD(mb, caddr_t);
330 * And fill the first file handle into the request.
332 if (nd->nd_flag & ND_NFSV4) {
333 opcnt = nfsv4_opmap[procnum].opcnt +
334 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
335 if ((nd->nd_flag & ND_NFSV41) != 0) {
336 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
337 if (procnum == NFSPROC_RENEW)
339 * For the special case of Renew, just do a
343 else if (procnum == NFSPROC_WRITEDS ||
344 procnum == NFSPROC_COMMITDS)
346 * For the special case of a Writeor Commit to
347 * a DS, the opcnt == 3, for Sequence, PutFH,
353 * What should the tag really be?
355 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
356 nfsv4_opmap[procnum].taglen);
357 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
358 if ((nd->nd_flag & ND_NFSV41) != 0)
359 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
361 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
364 *tl = txdr_unsigned(opcnt);
365 if ((nd->nd_flag & ND_NFSV41) != 0 &&
366 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
367 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
369 nd->nd_flag |= ND_LOOPBADSESS;
370 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
371 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
373 sep = nfsmnt_mdssession(nmp);
374 nfsv4_setsequence(nmp, nd, sep,
375 nfs_bigreply[procnum]);
377 nfsv4_setsequence(nmp, nd, sep,
378 nfs_bigreply[procnum]);
380 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
381 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
382 *tl = txdr_unsigned(NFSV4OP_PUTFH);
383 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
384 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
385 == 2 && procnum != NFSPROC_WRITEDS &&
386 procnum != NFSPROC_COMMITDS) {
387 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
388 *tl = txdr_unsigned(NFSV4OP_GETATTR);
390 * For Lookup Ops, we want all the directory
391 * attributes, so we can load the name cache.
393 if (procnum == NFSPROC_LOOKUP ||
394 procnum == NFSPROC_LOOKUPP)
395 NFSGETATTR_ATTRBIT(&attrbits);
397 NFSWCCATTR_ATTRBIT(&attrbits);
398 nd->nd_flag |= ND_V4WCCATTR;
400 (void) nfsrv_putattrbit(nd, &attrbits);
403 if (procnum != NFSPROC_RENEW ||
404 (nd->nd_flag & ND_NFSV41) == 0) {
405 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
406 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
409 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
411 if (procnum < NFSV41_NPROCS)
412 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
416 * Put a state Id in the mbuf list.
419 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
423 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
424 if (flag == NFSSTATEID_PUTALLZERO) {
429 } else if (flag == NFSSTATEID_PUTALLONE) {
430 st->seqid = 0xffffffff;
431 st->other[0] = 0xffffffff;
432 st->other[1] = 0xffffffff;
433 st->other[2] = 0xffffffff;
434 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
436 st->other[0] = stateidp->other[0];
437 st->other[1] = stateidp->other[1];
438 st->other[2] = stateidp->other[2];
440 st->seqid = stateidp->seqid;
441 st->other[0] = stateidp->other[0];
442 st->other[1] = stateidp->other[1];
443 st->other[2] = stateidp->other[2];
448 * Fill in the setable attributes. The full argument indicates whether
449 * to fill in them all or just mode and time.
452 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
453 struct vnode *vp, int flags, u_int32_t rdev)
456 struct nfsv2_sattr *sp;
457 nfsattrbit_t attrbits;
459 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
461 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
462 if (vap->va_mode == (mode_t)VNOVAL)
463 sp->sa_mode = newnfs_xdrneg1;
465 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
466 if (vap->va_uid == (uid_t)VNOVAL)
467 sp->sa_uid = newnfs_xdrneg1;
469 sp->sa_uid = txdr_unsigned(vap->va_uid);
470 if (vap->va_gid == (gid_t)VNOVAL)
471 sp->sa_gid = newnfs_xdrneg1;
473 sp->sa_gid = txdr_unsigned(vap->va_gid);
474 if (flags & NFSSATTR_SIZE0)
476 else if (flags & NFSSATTR_SIZENEG1)
477 sp->sa_size = newnfs_xdrneg1;
478 else if (flags & NFSSATTR_SIZERDEV)
479 sp->sa_size = txdr_unsigned(rdev);
481 sp->sa_size = txdr_unsigned(vap->va_size);
482 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
483 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
486 if (vap->va_mode != (mode_t)VNOVAL) {
487 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
489 *tl = txdr_unsigned(vap->va_mode);
491 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
494 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
495 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
497 *tl = txdr_unsigned(vap->va_uid);
499 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
502 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
503 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
505 *tl = txdr_unsigned(vap->va_gid);
507 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
510 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
511 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
513 txdr_hyper(vap->va_size, tl);
515 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
518 if (vap->va_atime.tv_sec != VNOVAL) {
519 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
520 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
521 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
522 txdr_nfsv3time(&vap->va_atime, tl);
524 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
525 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
528 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
529 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
531 if (vap->va_mtime.tv_sec != VNOVAL) {
532 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
533 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
534 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
535 txdr_nfsv3time(&vap->va_mtime, tl);
537 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
538 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
542 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
546 NFSZERO_ATTRBIT(&attrbits);
547 if (vap->va_mode != (mode_t)VNOVAL)
548 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
549 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
550 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
551 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
552 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
553 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
554 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
555 if (vap->va_atime.tv_sec != VNOVAL)
556 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
557 if (vap->va_mtime.tv_sec != VNOVAL)
558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
559 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
560 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
567 * copies mbuf chain to the uio scatter/gather list
570 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
572 char *mbufcp, *uiocp;
579 mbufcp = nd->nd_dpos;
580 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
581 rem = NFSM_RNDUP(siz) - siz;
583 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
587 left = uiop->uio_iov->iov_len;
588 uiocp = uiop->uio_iov->iov_base;
599 mbufcp = NFSMTOD(mp, caddr_t);
602 ("len %d, corrupted mbuf?", len));
604 xfer = (left > len) ? len : left;
607 if (uiop->uio_iov->iov_op != NULL)
608 (*(uiop->uio_iov->iov_op))
609 (mbufcp, uiocp, xfer);
612 if (uiop->uio_segflg == UIO_SYSSPACE)
613 NFSBCOPY(mbufcp, uiocp, xfer);
615 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
620 uiop->uio_offset += xfer;
621 uiop->uio_resid -= xfer;
623 if (uiop->uio_iov->iov_len <= siz) {
627 uiop->uio_iov->iov_base = (void *)
628 ((char *)uiop->uio_iov->iov_base + uiosiz);
629 uiop->uio_iov->iov_len -= uiosiz;
633 nd->nd_dpos = mbufcp;
637 error = nfsm_advance(nd, rem, len);
643 NFSEXITCODE2(error, nd);
649 * Help break down an mbuf chain by setting the first siz bytes contiguous
650 * pointed to by returned val.
651 * This is used by the macro NFSM_DISSECT for tough
655 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
664 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
666 nd->nd_md = mbuf_next(nd->nd_md);
667 if (nd->nd_md == NULL)
669 left = mbuf_len(nd->nd_md);
670 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
675 } else if (mbuf_next(nd->nd_md) == NULL) {
677 } else if (siz > ncl_mbuf_mhlen) {
678 panic("nfs S too big");
680 MGET(mp2, MT_DATA, how);
683 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
684 mbuf_setnext(nd->nd_md, mp2);
685 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
687 retp = p = NFSMTOD(mp2, caddr_t);
688 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
691 mp2 = mbuf_next(mp2);
692 /* Loop around copying up the siz2 bytes */
696 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
698 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
699 NFSM_DATAP(mp2, xfer);
700 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
705 mp2 = mbuf_next(mp2);
707 mbuf_setlen(nd->nd_md, siz);
709 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
715 * Advance the position in the mbuf chain.
716 * If offs == 0, this is a no-op, but it is simpler to just return from
717 * here than check for offs > 0 for all calls to nfsm_advance.
718 * If left == -1, it should be calculated here.
721 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
728 * A negative offs should be considered a serious problem.
731 panic("nfsrv_advance");
734 * If left == -1, calculate it here.
737 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
741 * Loop around, advancing over the mbuf data.
743 while (offs > left) {
745 nd->nd_md = mbuf_next(nd->nd_md);
746 if (nd->nd_md == NULL) {
750 left = mbuf_len(nd->nd_md);
751 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
761 * Copy a string into mbuf(s).
762 * Return the number of bytes output, including XDR overheads.
765 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
774 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
775 *tl = txdr_unsigned(siz);
776 rem = NFSM_RNDUP(siz) - siz;
777 bytesize = NFSX_UNSIGNED + siz + rem;
780 left = M_TRAILINGSPACE(m2);
783 * Loop around copying the string to mbuf(s).
787 if (siz > ncl_mbuf_mlen)
788 NFSMCLGET(m1, M_WAITOK);
792 mbuf_setnext(m2, m1);
794 cp2 = NFSMTOD(m2, caddr_t);
795 left = M_TRAILINGSPACE(m2);
801 NFSBCOPY(cp, cp2, xfer);
803 mbuf_setlen(m2, mbuf_len(m2) + xfer);
806 if (siz == 0 && rem) {
808 panic("nfsm_strtom");
809 NFSBZERO(cp2 + xfer, rem);
810 mbuf_setlen(m2, mbuf_len(m2) + rem);
814 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
819 * Called once to initialize data structures...
824 static int nfs_inited = 0;
830 newnfs_true = txdr_unsigned(TRUE);
831 newnfs_false = txdr_unsigned(FALSE);
832 newnfs_xdrneg1 = txdr_unsigned(-1);
833 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
836 NFSSETBOOTTIME(nfsboottime);
839 * Initialize reply list and start timer
841 TAILQ_INIT(&nfsd_reqq);
846 * Put a file handle in an mbuf list.
847 * If the size argument == 0, just use the default size.
848 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
849 * Return the number of bytes output, including XDR overhead.
852 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
856 int fullsiz, rem, bytesize = 0;
860 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
862 if (size > NFSX_V2FH)
863 panic("fh size > NFSX_V2FH for NFSv2");
864 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
865 NFSBCOPY(fhp, cp, size);
866 if (size < NFSX_V2FH)
867 NFSBZERO(cp + size, NFSX_V2FH - size);
868 bytesize = NFSX_V2FH;
872 fullsiz = NFSM_RNDUP(size);
873 rem = fullsiz - size;
875 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
876 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
879 bytesize = NFSX_UNSIGNED + fullsiz;
881 (void) nfsm_strtom(nd, fhp, size);
888 * This function compares two net addresses by family and returns TRUE
889 * if they are the same host.
890 * If there is any doubt, return FALSE.
891 * The AF_INET family is handled as a special case so that address mbufs
892 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
895 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
897 struct sockaddr_in *inetaddr;
901 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
902 if (inetaddr->sin_family == AF_INET &&
903 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
909 struct sockaddr_in6 *inetaddr6;
911 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
912 /* XXX - should test sin6_scope_id ? */
913 if (inetaddr6->sin6_family == AF_INET6 &&
914 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
925 * Similar to the above, but takes to NFSSOCKADDR_T args.
928 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
930 struct sockaddr_in *addr1, *addr2;
931 struct sockaddr *inaddr;
933 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
934 switch (inaddr->sa_family) {
936 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
937 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
938 if (addr2->sin_family == AF_INET &&
939 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
945 struct sockaddr_in6 *inet6addr1, *inet6addr2;
947 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
948 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
949 /* XXX - should test sin6_scope_id ? */
950 if (inet6addr2->sin6_family == AF_INET6 &&
951 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
952 &inet6addr2->sin6_addr))
963 * Trim the stuff already dissected off the mbuf list.
966 newnfs_trimleading(nd)
967 struct nfsrv_descript *nd;
973 * First, free up leading mbufs.
975 if (nd->nd_mrep != nd->nd_md) {
977 while (mbuf_next(m) != nd->nd_md) {
978 if (mbuf_next(m) == NULL)
979 panic("nfsm trim leading");
982 mbuf_setnext(m, NULL);
983 mbuf_freem(nd->nd_mrep);
988 * Now, adjust this mbuf, based on nd_dpos.
990 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
991 if (offs == mbuf_len(m)) {
995 panic("nfsm trim leading2");
996 mbuf_setnext(n, NULL);
998 } else if (offs > 0) {
999 mbuf_setlen(m, mbuf_len(m) - offs);
1000 NFSM_DATAP(m, offs);
1001 } else if (offs < 0)
1002 panic("nfsm trimleading offs");
1005 nd->nd_dpos = NFSMTOD(m, caddr_t);
1009 * Trim trailing data off the mbuf list being built.
1012 newnfs_trimtrailing(nd, mb, bpos)
1013 struct nfsrv_descript *nd;
1018 if (mbuf_next(mb)) {
1019 mbuf_freem(mbuf_next(mb));
1020 mbuf_setnext(mb, NULL);
1022 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1028 * Dissect a file handle on the client.
1031 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1038 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1039 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1040 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1047 nfhp = malloc(sizeof (struct nfsfh) + len,
1049 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1051 free(nfhp, M_NFSFH);
1054 nfhp->nfh_len = len;
1057 NFSEXITCODE2(error, nd);
1062 * Break down the nfsv4 acl.
1063 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1066 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1067 int *aclsizep, __unused NFSPROC_T *p)
1071 int acecnt, error = 0, aceerr = 0, acesize;
1077 * Parse out the ace entries and expect them to conform to
1078 * what can be supported by R/W/X bits.
1080 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1081 aclsize = NFSX_UNSIGNED;
1082 acecnt = fxdr_unsigned(int, *tl);
1083 if (acecnt > ACL_MAX_ENTRIES)
1084 aceerr = NFSERR_ATTRNOTSUPP;
1085 if (nfsrv_useacl == 0)
1086 aceerr = NFSERR_ATTRNOTSUPP;
1087 for (i = 0; i < acecnt; i++) {
1088 if (aclp && !aceerr)
1089 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1090 &aceerr, &acesize, p);
1092 error = nfsrv_skipace(nd, &acesize);
1097 if (aclp && !aceerr)
1098 aclp->acl_cnt = acecnt;
1102 *aclsizep = aclsize;
1104 NFSEXITCODE2(error, nd);
1109 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1112 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1117 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1118 len = fxdr_unsigned(int, *(tl + 3));
1119 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1121 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1122 NFSEXITCODE2(error, nd);
1127 * Get attribute bits from an mbuf list.
1128 * Returns EBADRPC for a parsing error, 0 otherwise.
1129 * If the clearinvalid flag is set, clear the bits not supported.
1132 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1139 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1140 cnt = fxdr_unsigned(int, *tl);
1142 error = NFSERR_BADXDR;
1145 if (cnt > NFSATTRBIT_MAXWORDS)
1146 outcnt = NFSATTRBIT_MAXWORDS;
1149 NFSZERO_ATTRBIT(attrbitp);
1151 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1152 for (i = 0; i < outcnt; i++)
1153 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1155 for (i = 0; i < (cnt - outcnt); i++) {
1156 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1157 if (retnotsupp != NULL && *tl != 0)
1158 *retnotsupp = NFSERR_ATTRNOTSUPP;
1161 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1163 NFSEXITCODE2(error, nd);
1168 * Get the attributes for V4.
1169 * If the compare flag is true, test for any attribute changes,
1170 * otherwise return the attribute values.
1171 * These attributes cover fields in "struct vattr", "struct statfs",
1172 * "struct nfsfsinfo", the file handle and the lease duration.
1173 * The value of retcmpp is set to 1 if all attributes are the same,
1175 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1178 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1179 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1180 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1181 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1182 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1185 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1186 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1187 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1188 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1189 struct nfsfh *tnfhp;
1190 struct nfsreferral *refp;
1193 struct timespec temptime;
1196 u_int32_t freenum = 0, tuint;
1197 u_int64_t uquad = 0, thyp, thyp2;
1203 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1206 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1208 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1214 *retcmpp = retnotsup;
1217 * Just set default values to some of the important ones.
1220 nap->na_type = VREG;
1222 nap->na_rdev = (NFSDEV_T)0;
1223 nap->na_mtime.tv_sec = 0;
1224 nap->na_mtime.tv_nsec = 0;
1227 nap->na_blocksize = NFS_FABLKSIZE;
1230 sbp->f_bsize = NFS_FABLKSIZE;
1238 fsp->fs_rtmax = 8192;
1239 fsp->fs_rtpref = 8192;
1240 fsp->fs_maxname = NFS_MAXNAMLEN;
1241 fsp->fs_wtmax = 8192;
1242 fsp->fs_wtpref = 8192;
1243 fsp->fs_wtmult = NFS_FABLKSIZE;
1244 fsp->fs_dtpref = 8192;
1245 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1246 fsp->fs_timedelta.tv_sec = 0;
1247 fsp->fs_timedelta.tv_nsec = 1;
1248 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1249 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1252 pc->pc_linkmax = NFS_LINK_MAX;
1253 pc->pc_namemax = NAME_MAX;
1255 pc->pc_chownrestricted = 0;
1256 pc->pc_caseinsensitive = 0;
1257 pc->pc_casepreserving = 1;
1260 sfp->sf_ffiles = UINT64_MAX;
1261 sfp->sf_tfiles = UINT64_MAX;
1262 sfp->sf_afiles = UINT64_MAX;
1263 sfp->sf_fbytes = UINT64_MAX;
1264 sfp->sf_tbytes = UINT64_MAX;
1265 sfp->sf_abytes = UINT64_MAX;
1270 * Loop around getting the attributes.
1272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1273 attrsize = fxdr_unsigned(int, *tl);
1274 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1275 if (attrsum > attrsize) {
1276 error = NFSERR_BADXDR;
1279 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1281 case NFSATTRBIT_SUPPORTEDATTRS:
1283 if (compare || nap == NULL)
1284 error = nfsrv_getattrbits(nd, &retattrbits,
1287 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1291 if (compare && !(*retcmpp)) {
1292 NFSSETSUPP_ATTRBIT(&checkattrbits);
1294 /* Some filesystem do not support NFSv4ACL */
1295 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1296 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1297 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1299 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1301 *retcmpp = NFSERR_NOTSAME;
1305 case NFSATTRBIT_TYPE:
1306 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1309 if (nap->na_type != nfsv34tov_type(*tl))
1310 *retcmpp = NFSERR_NOTSAME;
1312 } else if (nap != NULL) {
1313 nap->na_type = nfsv34tov_type(*tl);
1315 attrsum += NFSX_UNSIGNED;
1317 case NFSATTRBIT_FHEXPIRETYPE:
1318 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1319 if (compare && !(*retcmpp)) {
1320 if (fxdr_unsigned(int, *tl) !=
1321 NFSV4FHTYPE_PERSISTENT)
1322 *retcmpp = NFSERR_NOTSAME;
1324 attrsum += NFSX_UNSIGNED;
1326 case NFSATTRBIT_CHANGE:
1327 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1330 if (nap->na_filerev != fxdr_hyper(tl))
1331 *retcmpp = NFSERR_NOTSAME;
1333 } else if (nap != NULL) {
1334 nap->na_filerev = fxdr_hyper(tl);
1336 attrsum += NFSX_HYPER;
1338 case NFSATTRBIT_SIZE:
1339 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1342 if (nap->na_size != fxdr_hyper(tl))
1343 *retcmpp = NFSERR_NOTSAME;
1345 } else if (nap != NULL) {
1346 nap->na_size = fxdr_hyper(tl);
1348 attrsum += NFSX_HYPER;
1350 case NFSATTRBIT_LINKSUPPORT:
1351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1354 if (fsp->fs_properties & NFSV3_FSFLINK) {
1355 if (*tl == newnfs_false)
1356 *retcmpp = NFSERR_NOTSAME;
1358 if (*tl == newnfs_true)
1359 *retcmpp = NFSERR_NOTSAME;
1362 } else if (fsp != NULL) {
1363 if (*tl == newnfs_true)
1364 fsp->fs_properties |= NFSV3_FSFLINK;
1366 fsp->fs_properties &= ~NFSV3_FSFLINK;
1368 attrsum += NFSX_UNSIGNED;
1370 case NFSATTRBIT_SYMLINKSUPPORT:
1371 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1374 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1375 if (*tl == newnfs_false)
1376 *retcmpp = NFSERR_NOTSAME;
1378 if (*tl == newnfs_true)
1379 *retcmpp = NFSERR_NOTSAME;
1382 } else if (fsp != NULL) {
1383 if (*tl == newnfs_true)
1384 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1386 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1388 attrsum += NFSX_UNSIGNED;
1390 case NFSATTRBIT_NAMEDATTR:
1391 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1392 if (compare && !(*retcmpp)) {
1393 if (*tl != newnfs_false)
1394 *retcmpp = NFSERR_NOTSAME;
1396 attrsum += NFSX_UNSIGNED;
1398 case NFSATTRBIT_FSID:
1399 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1400 thyp = fxdr_hyper(tl);
1402 thyp2 = fxdr_hyper(tl);
1404 if (*retcmpp == 0) {
1405 if (thyp != (u_int64_t)
1406 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1407 thyp2 != (u_int64_t)
1408 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1409 *retcmpp = NFSERR_NOTSAME;
1411 } else if (nap != NULL) {
1412 nap->na_filesid[0] = thyp;
1413 nap->na_filesid[1] = thyp2;
1415 attrsum += (4 * NFSX_UNSIGNED);
1417 case NFSATTRBIT_UNIQUEHANDLES:
1418 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1419 if (compare && !(*retcmpp)) {
1420 if (*tl != newnfs_true)
1421 *retcmpp = NFSERR_NOTSAME;
1423 attrsum += NFSX_UNSIGNED;
1425 case NFSATTRBIT_LEASETIME:
1426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1428 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1430 *retcmpp = NFSERR_NOTSAME;
1431 } else if (leasep != NULL) {
1432 *leasep = fxdr_unsigned(u_int32_t, *tl);
1434 attrsum += NFSX_UNSIGNED;
1436 case NFSATTRBIT_RDATTRERROR:
1437 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1440 *retcmpp = NFSERR_INVAL;
1441 } else if (rderrp != NULL) {
1442 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1444 attrsum += NFSX_UNSIGNED;
1446 case NFSATTRBIT_ACL:
1449 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1452 naclp = acl_alloc(M_WAITOK);
1453 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1459 if (aceerr || aclp == NULL ||
1460 nfsrv_compareacl(aclp, naclp))
1461 *retcmpp = NFSERR_NOTSAME;
1464 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1466 *retcmpp = NFSERR_ATTRNOTSUPP;
1470 if (vp != NULL && aclp != NULL)
1471 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1474 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1482 case NFSATTRBIT_ACLSUPPORT:
1483 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1484 if (compare && !(*retcmpp)) {
1485 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1486 if (fxdr_unsigned(u_int32_t, *tl) !=
1488 *retcmpp = NFSERR_NOTSAME;
1490 *retcmpp = NFSERR_ATTRNOTSUPP;
1493 attrsum += NFSX_UNSIGNED;
1495 case NFSATTRBIT_ARCHIVE:
1496 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1497 if (compare && !(*retcmpp))
1498 *retcmpp = NFSERR_ATTRNOTSUPP;
1499 attrsum += NFSX_UNSIGNED;
1501 case NFSATTRBIT_CANSETTIME:
1502 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1505 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1506 if (*tl == newnfs_false)
1507 *retcmpp = NFSERR_NOTSAME;
1509 if (*tl == newnfs_true)
1510 *retcmpp = NFSERR_NOTSAME;
1513 } else if (fsp != NULL) {
1514 if (*tl == newnfs_true)
1515 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1517 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1519 attrsum += NFSX_UNSIGNED;
1521 case NFSATTRBIT_CASEINSENSITIVE:
1522 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1525 if (*tl != newnfs_false)
1526 *retcmpp = NFSERR_NOTSAME;
1528 } else if (pc != NULL) {
1529 pc->pc_caseinsensitive =
1530 fxdr_unsigned(u_int32_t, *tl);
1532 attrsum += NFSX_UNSIGNED;
1534 case NFSATTRBIT_CASEPRESERVING:
1535 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1538 if (*tl != newnfs_true)
1539 *retcmpp = NFSERR_NOTSAME;
1541 } else if (pc != NULL) {
1542 pc->pc_casepreserving =
1543 fxdr_unsigned(u_int32_t, *tl);
1545 attrsum += NFSX_UNSIGNED;
1547 case NFSATTRBIT_CHOWNRESTRICTED:
1548 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1551 if (*tl != newnfs_true)
1552 *retcmpp = NFSERR_NOTSAME;
1554 } else if (pc != NULL) {
1555 pc->pc_chownrestricted =
1556 fxdr_unsigned(u_int32_t, *tl);
1558 attrsum += NFSX_UNSIGNED;
1560 case NFSATTRBIT_FILEHANDLE:
1561 error = nfsm_getfh(nd, &tnfhp);
1564 tfhsize = tnfhp->nfh_len;
1567 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1569 *retcmpp = NFSERR_NOTSAME;
1570 free(tnfhp, M_NFSFH);
1571 } else if (nfhpp != NULL) {
1574 free(tnfhp, M_NFSFH);
1576 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1578 case NFSATTRBIT_FILEID:
1579 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1580 thyp = fxdr_hyper(tl);
1583 if (nap->na_fileid != thyp)
1584 *retcmpp = NFSERR_NOTSAME;
1586 } else if (nap != NULL)
1587 nap->na_fileid = thyp;
1588 attrsum += NFSX_HYPER;
1590 case NFSATTRBIT_FILESAVAIL:
1591 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1594 sfp->sf_afiles != fxdr_hyper(tl))
1595 *retcmpp = NFSERR_NOTSAME;
1596 } else if (sfp != NULL) {
1597 sfp->sf_afiles = fxdr_hyper(tl);
1599 attrsum += NFSX_HYPER;
1601 case NFSATTRBIT_FILESFREE:
1602 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1605 sfp->sf_ffiles != fxdr_hyper(tl))
1606 *retcmpp = NFSERR_NOTSAME;
1607 } else if (sfp != NULL) {
1608 sfp->sf_ffiles = fxdr_hyper(tl);
1610 attrsum += NFSX_HYPER;
1612 case NFSATTRBIT_FILESTOTAL:
1613 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1616 sfp->sf_tfiles != fxdr_hyper(tl))
1617 *retcmpp = NFSERR_NOTSAME;
1618 } else if (sfp != NULL) {
1619 sfp->sf_tfiles = fxdr_hyper(tl);
1621 attrsum += NFSX_HYPER;
1623 case NFSATTRBIT_FSLOCATIONS:
1624 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1628 if (compare && !(*retcmpp)) {
1629 refp = nfsv4root_getreferral(vp, NULL, 0);
1631 if (cp == NULL || cp2 == NULL ||
1633 strcmp(cp2, refp->nfr_srvlist))
1634 *retcmpp = NFSERR_NOTSAME;
1635 } else if (m == 0) {
1636 *retcmpp = NFSERR_NOTSAME;
1640 free(cp, M_NFSSTRING);
1642 free(cp2, M_NFSSTRING);
1644 case NFSATTRBIT_HIDDEN:
1645 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1646 if (compare && !(*retcmpp))
1647 *retcmpp = NFSERR_ATTRNOTSUPP;
1648 attrsum += NFSX_UNSIGNED;
1650 case NFSATTRBIT_HOMOGENEOUS:
1651 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1654 if (fsp->fs_properties &
1655 NFSV3_FSFHOMOGENEOUS) {
1656 if (*tl == newnfs_false)
1657 *retcmpp = NFSERR_NOTSAME;
1659 if (*tl == newnfs_true)
1660 *retcmpp = NFSERR_NOTSAME;
1663 } else if (fsp != NULL) {
1664 if (*tl == newnfs_true)
1665 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1667 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1669 attrsum += NFSX_UNSIGNED;
1671 case NFSATTRBIT_MAXFILESIZE:
1672 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1673 tnfsquad.qval = fxdr_hyper(tl);
1676 tquad = NFSRV_MAXFILESIZE;
1677 if (tquad != tnfsquad.qval)
1678 *retcmpp = NFSERR_NOTSAME;
1680 } else if (fsp != NULL) {
1681 fsp->fs_maxfilesize = tnfsquad.qval;
1683 attrsum += NFSX_HYPER;
1685 case NFSATTRBIT_MAXLINK:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1689 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1690 *retcmpp = NFSERR_NOTSAME;
1692 } else if (pc != NULL) {
1693 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1695 attrsum += NFSX_UNSIGNED;
1697 case NFSATTRBIT_MAXNAME:
1698 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1701 if (fsp->fs_maxname !=
1702 fxdr_unsigned(u_int32_t, *tl))
1703 *retcmpp = NFSERR_NOTSAME;
1706 tuint = fxdr_unsigned(u_int32_t, *tl);
1708 * Some Linux NFSv4 servers report this
1709 * as 0 or 4billion, so I'll set it to
1710 * NFS_MAXNAMLEN. If a server actually creates
1711 * a name longer than NFS_MAXNAMLEN, it will
1712 * get an error back.
1714 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1715 tuint = NFS_MAXNAMLEN;
1717 fsp->fs_maxname = tuint;
1719 pc->pc_namemax = tuint;
1721 attrsum += NFSX_UNSIGNED;
1723 case NFSATTRBIT_MAXREAD:
1724 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1727 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1728 *(tl + 1)) || *tl != 0)
1729 *retcmpp = NFSERR_NOTSAME;
1731 } else if (fsp != NULL) {
1732 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1733 fsp->fs_rtpref = fsp->fs_rtmax;
1734 fsp->fs_dtpref = fsp->fs_rtpref;
1736 attrsum += NFSX_HYPER;
1738 case NFSATTRBIT_MAXWRITE:
1739 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1742 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1743 *(tl + 1)) || *tl != 0)
1744 *retcmpp = NFSERR_NOTSAME;
1746 } else if (fsp != NULL) {
1747 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1748 fsp->fs_wtpref = fsp->fs_wtmax;
1750 attrsum += NFSX_HYPER;
1752 case NFSATTRBIT_MIMETYPE:
1753 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1754 i = fxdr_unsigned(int, *tl);
1755 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1756 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1759 if (compare && !(*retcmpp))
1760 *retcmpp = NFSERR_ATTRNOTSUPP;
1762 case NFSATTRBIT_MODE:
1763 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1766 if (nap->na_mode != nfstov_mode(*tl))
1767 *retcmpp = NFSERR_NOTSAME;
1769 } else if (nap != NULL) {
1770 nap->na_mode = nfstov_mode(*tl);
1772 attrsum += NFSX_UNSIGNED;
1774 case NFSATTRBIT_NOTRUNC:
1775 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1778 if (*tl != newnfs_true)
1779 *retcmpp = NFSERR_NOTSAME;
1781 } else if (pc != NULL) {
1782 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1784 attrsum += NFSX_UNSIGNED;
1786 case NFSATTRBIT_NUMLINKS:
1787 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1788 tuint = fxdr_unsigned(u_int32_t, *tl);
1791 if ((u_int32_t)nap->na_nlink != tuint)
1792 *retcmpp = NFSERR_NOTSAME;
1794 } else if (nap != NULL) {
1795 nap->na_nlink = tuint;
1797 attrsum += NFSX_UNSIGNED;
1799 case NFSATTRBIT_OWNER:
1800 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1801 j = fxdr_unsigned(int, *tl);
1803 error = NFSERR_BADXDR;
1806 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1807 if (j > NFSV4_SMALLSTR)
1808 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1811 error = nfsrv_mtostr(nd, cp, j);
1813 if (j > NFSV4_SMALLSTR)
1814 free(cp, M_NFSSTRING);
1819 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1821 *retcmpp = NFSERR_NOTSAME;
1823 } else if (nap != NULL) {
1824 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1825 nap->na_uid = nfsrv_defaultuid;
1829 if (j > NFSV4_SMALLSTR)
1830 free(cp, M_NFSSTRING);
1832 case NFSATTRBIT_OWNERGROUP:
1833 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1834 j = fxdr_unsigned(int, *tl);
1836 error = NFSERR_BADXDR;
1839 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1840 if (j > NFSV4_SMALLSTR)
1841 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1844 error = nfsrv_mtostr(nd, cp, j);
1846 if (j > NFSV4_SMALLSTR)
1847 free(cp, M_NFSSTRING);
1852 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1854 *retcmpp = NFSERR_NOTSAME;
1856 } else if (nap != NULL) {
1857 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1858 nap->na_gid = nfsrv_defaultgid;
1862 if (j > NFSV4_SMALLSTR)
1863 free(cp, M_NFSSTRING);
1865 case NFSATTRBIT_QUOTAHARD:
1866 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1868 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1869 freenum = sbp->f_bfree;
1871 freenum = sbp->f_bavail;
1874 * ufs_quotactl() insists that the uid argument
1875 * equal p_ruid for non-root quota access, so
1876 * we'll just make sure that's the case.
1878 savuid = p->p_cred->p_ruid;
1879 p->p_cred->p_ruid = cred->cr_uid;
1880 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1881 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1882 freenum = min(dqb.dqb_bhardlimit, freenum);
1883 p->p_cred->p_ruid = savuid;
1885 uquad = (u_int64_t)freenum;
1886 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1888 if (compare && !(*retcmpp)) {
1889 if (uquad != fxdr_hyper(tl))
1890 *retcmpp = NFSERR_NOTSAME;
1892 attrsum += NFSX_HYPER;
1894 case NFSATTRBIT_QUOTASOFT:
1895 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1897 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1898 freenum = sbp->f_bfree;
1900 freenum = sbp->f_bavail;
1903 * ufs_quotactl() insists that the uid argument
1904 * equal p_ruid for non-root quota access, so
1905 * we'll just make sure that's the case.
1907 savuid = p->p_cred->p_ruid;
1908 p->p_cred->p_ruid = cred->cr_uid;
1909 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1910 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1911 freenum = min(dqb.dqb_bsoftlimit, freenum);
1912 p->p_cred->p_ruid = savuid;
1914 uquad = (u_int64_t)freenum;
1915 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1917 if (compare && !(*retcmpp)) {
1918 if (uquad != fxdr_hyper(tl))
1919 *retcmpp = NFSERR_NOTSAME;
1921 attrsum += NFSX_HYPER;
1923 case NFSATTRBIT_QUOTAUSED:
1924 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1929 * ufs_quotactl() insists that the uid argument
1930 * equal p_ruid for non-root quota access, so
1931 * we'll just make sure that's the case.
1933 savuid = p->p_cred->p_ruid;
1934 p->p_cred->p_ruid = cred->cr_uid;
1935 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1936 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1937 freenum = dqb.dqb_curblocks;
1938 p->p_cred->p_ruid = savuid;
1940 uquad = (u_int64_t)freenum;
1941 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1943 if (compare && !(*retcmpp)) {
1944 if (uquad != fxdr_hyper(tl))
1945 *retcmpp = NFSERR_NOTSAME;
1947 attrsum += NFSX_HYPER;
1949 case NFSATTRBIT_RAWDEV:
1950 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1951 j = fxdr_unsigned(int, *tl++);
1952 k = fxdr_unsigned(int, *tl);
1955 if (nap->na_rdev != NFSMAKEDEV(j, k))
1956 *retcmpp = NFSERR_NOTSAME;
1958 } else if (nap != NULL) {
1959 nap->na_rdev = NFSMAKEDEV(j, k);
1961 attrsum += NFSX_V4SPECDATA;
1963 case NFSATTRBIT_SPACEAVAIL:
1964 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1967 sfp->sf_abytes != fxdr_hyper(tl))
1968 *retcmpp = NFSERR_NOTSAME;
1969 } else if (sfp != NULL) {
1970 sfp->sf_abytes = fxdr_hyper(tl);
1972 attrsum += NFSX_HYPER;
1974 case NFSATTRBIT_SPACEFREE:
1975 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1978 sfp->sf_fbytes != fxdr_hyper(tl))
1979 *retcmpp = NFSERR_NOTSAME;
1980 } else if (sfp != NULL) {
1981 sfp->sf_fbytes = fxdr_hyper(tl);
1983 attrsum += NFSX_HYPER;
1985 case NFSATTRBIT_SPACETOTAL:
1986 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1989 sfp->sf_tbytes != fxdr_hyper(tl))
1990 *retcmpp = NFSERR_NOTSAME;
1991 } else if (sfp != NULL) {
1992 sfp->sf_tbytes = fxdr_hyper(tl);
1994 attrsum += NFSX_HYPER;
1996 case NFSATTRBIT_SPACEUSED:
1997 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1998 thyp = fxdr_hyper(tl);
2001 if ((u_int64_t)nap->na_bytes != thyp)
2002 *retcmpp = NFSERR_NOTSAME;
2004 } else if (nap != NULL) {
2005 nap->na_bytes = thyp;
2007 attrsum += NFSX_HYPER;
2009 case NFSATTRBIT_SYSTEM:
2010 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2011 if (compare && !(*retcmpp))
2012 *retcmpp = NFSERR_ATTRNOTSUPP;
2013 attrsum += NFSX_UNSIGNED;
2015 case NFSATTRBIT_TIMEACCESS:
2016 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2017 fxdr_nfsv4time(tl, &temptime);
2020 if (!NFS_CMPTIME(temptime, nap->na_atime))
2021 *retcmpp = NFSERR_NOTSAME;
2023 } else if (nap != NULL) {
2024 nap->na_atime = temptime;
2026 attrsum += NFSX_V4TIME;
2028 case NFSATTRBIT_TIMEACCESSSET:
2029 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2030 attrsum += NFSX_UNSIGNED;
2031 i = fxdr_unsigned(int, *tl);
2032 if (i == NFSV4SATTRTIME_TOCLIENT) {
2033 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2034 attrsum += NFSX_V4TIME;
2036 if (compare && !(*retcmpp))
2037 *retcmpp = NFSERR_INVAL;
2039 case NFSATTRBIT_TIMEBACKUP:
2040 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2041 if (compare && !(*retcmpp))
2042 *retcmpp = NFSERR_ATTRNOTSUPP;
2043 attrsum += NFSX_V4TIME;
2045 case NFSATTRBIT_TIMECREATE:
2046 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2047 if (compare && !(*retcmpp))
2048 *retcmpp = NFSERR_ATTRNOTSUPP;
2049 attrsum += NFSX_V4TIME;
2051 case NFSATTRBIT_TIMEDELTA:
2052 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2056 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2057 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2058 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2059 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2062 *retcmpp = NFSERR_NOTSAME;
2065 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2068 attrsum += NFSX_V4TIME;
2070 case NFSATTRBIT_TIMEMETADATA:
2071 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2072 fxdr_nfsv4time(tl, &temptime);
2075 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2076 *retcmpp = NFSERR_NOTSAME;
2078 } else if (nap != NULL) {
2079 nap->na_ctime = temptime;
2081 attrsum += NFSX_V4TIME;
2083 case NFSATTRBIT_TIMEMODIFY:
2084 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2085 fxdr_nfsv4time(tl, &temptime);
2088 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2089 *retcmpp = NFSERR_NOTSAME;
2091 } else if (nap != NULL) {
2092 nap->na_mtime = temptime;
2094 attrsum += NFSX_V4TIME;
2096 case NFSATTRBIT_TIMEMODIFYSET:
2097 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2098 attrsum += NFSX_UNSIGNED;
2099 i = fxdr_unsigned(int, *tl);
2100 if (i == NFSV4SATTRTIME_TOCLIENT) {
2101 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2102 attrsum += NFSX_V4TIME;
2104 if (compare && !(*retcmpp))
2105 *retcmpp = NFSERR_INVAL;
2107 case NFSATTRBIT_MOUNTEDONFILEID:
2108 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2109 thyp = fxdr_hyper(tl);
2112 if (!vp || !nfsrv_atroot(vp, &thyp2))
2113 thyp2 = nap->na_fileid;
2115 *retcmpp = NFSERR_NOTSAME;
2117 } else if (nap != NULL)
2118 nap->na_mntonfileno = thyp;
2119 attrsum += NFSX_HYPER;
2121 case NFSATTRBIT_SUPPATTREXCLCREAT:
2123 error = nfsrv_getattrbits(nd, &retattrbits,
2127 if (compare && !(*retcmpp)) {
2128 NFSSETSUPP_ATTRBIT(&checkattrbits);
2129 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
2130 NFSCLRBIT_ATTRBIT(&checkattrbits,
2131 NFSATTRBIT_TIMEACCESSSET);
2132 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2134 *retcmpp = NFSERR_NOTSAME;
2138 case NFSATTRBIT_FSLAYOUTTYPE:
2139 case NFSATTRBIT_LAYOUTTYPE:
2140 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2141 attrsum += NFSX_UNSIGNED;
2142 i = fxdr_unsigned(int, *tl);
2144 NFSM_DISSECT(tl, u_int32_t *, i *
2146 attrsum += i * NFSX_UNSIGNED;
2147 j = fxdr_unsigned(int, *tl);
2148 if (i == 1 && compare && !(*retcmpp) &&
2149 (((nfsrv_doflexfile != 0 ||
2150 nfsrv_maxpnfsmirror > 1) &&
2151 j != NFSLAYOUT_FLEXFILE) ||
2152 (nfsrv_doflexfile == 0 &&
2153 j != NFSLAYOUT_NFSV4_1_FILES)))
2154 *retcmpp = NFSERR_NOTSAME;
2156 if (nfsrv_devidcnt == 0) {
2157 if (compare && !(*retcmpp) && i > 0)
2158 *retcmpp = NFSERR_NOTSAME;
2160 if (compare && !(*retcmpp) && i != 1)
2161 *retcmpp = NFSERR_NOTSAME;
2164 case NFSATTRBIT_LAYOUTALIGNMENT:
2165 case NFSATTRBIT_LAYOUTBLKSIZE:
2166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2167 attrsum += NFSX_UNSIGNED;
2168 i = fxdr_unsigned(int, *tl);
2169 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2170 *retcmpp = NFSERR_NOTSAME;
2173 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2175 if (compare && !(*retcmpp))
2176 *retcmpp = NFSERR_ATTRNOTSUPP;
2178 * and get out of the loop, since we can't parse
2179 * the unknown attrbute data.
2181 bitpos = NFSATTRBIT_MAX;
2187 * some clients pad the attrlist, so we need to skip over the
2190 if (attrsum > attrsize) {
2191 error = NFSERR_BADXDR;
2193 attrsize = NFSM_RNDUP(attrsize);
2194 if (attrsum < attrsize)
2195 error = nfsm_advance(nd, attrsize - attrsum, -1);
2198 NFSEXITCODE2(error, nd);
2203 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2204 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2205 * The first argument is a pointer to an nfsv4lock structure.
2206 * The second argument is 1 iff a blocking lock is wanted.
2207 * If this argument is 0, the call waits until no thread either wants nor
2208 * holds an exclusive lock.
2209 * It returns 1 if the lock was acquired, 0 otherwise.
2210 * If several processes call this function concurrently wanting the exclusive
2211 * lock, one will get the lock and the rest will return without getting the
2212 * lock. (If the caller must have the lock, it simply calls this function in a
2213 * loop until the function returns 1 to indicate the lock was acquired.)
2214 * Any usecnt must be decremented by calling nfsv4_relref() before
2215 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2216 * be called in a loop.
2217 * The isleptp argument is set to indicate if the call slept, iff not NULL
2218 * and the mp argument indicates to check for a forced dismount, iff not
2222 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2223 void *mutex, struct mount *mp)
2229 * If a lock is wanted, loop around until the lock is acquired by
2230 * someone and then released. If I want the lock, try to acquire it.
2231 * For a lock to be issued, no lock must be in force and the usecnt
2235 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2236 lp->nfslock_usecnt == 0) {
2237 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2238 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2241 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2243 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2244 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2245 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2248 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2251 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2252 PZERO - 1, "nfsv4lck", NULL);
2253 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2254 lp->nfslock_usecnt == 0) {
2255 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2256 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2264 * Release the lock acquired by nfsv4_lock().
2265 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2266 * incremented, as well.
2269 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2272 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2274 lp->nfslock_usecnt++;
2279 * Release a reference cnt.
2282 nfsv4_relref(struct nfsv4lock *lp)
2285 if (lp->nfslock_usecnt <= 0)
2286 panic("nfsv4root ref cnt");
2287 lp->nfslock_usecnt--;
2288 if (lp->nfslock_usecnt == 0)
2293 * Get a reference cnt.
2294 * This function will wait for any exclusive lock to be released, but will
2295 * not wait for threads that want the exclusive lock. If priority needs
2296 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2297 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2298 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2299 * return without getting a refcnt for that case.
2302 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2310 * Wait for a lock held.
2312 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2313 if (mp != NULL && NFSCL_FORCEDISM(mp))
2315 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2318 (void) nfsmsleep(&lp->nfslock_lock, mutex,
2319 PZERO - 1, "nfsv4gr", NULL);
2321 if (mp != NULL && NFSCL_FORCEDISM(mp))
2324 lp->nfslock_usecnt++;
2328 * Get a reference as above, but return failure instead of sleeping if
2329 * an exclusive lock is held.
2332 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2335 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2338 lp->nfslock_usecnt++;
2343 * Test for a lock. Return 1 if locked, 0 otherwise.
2346 nfsv4_testlock(struct nfsv4lock *lp)
2349 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2350 lp->nfslock_usecnt == 0)
2356 * Wake up anyone sleeping, waiting for this lock.
2359 nfsv4_wanted(struct nfsv4lock *lp)
2362 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2363 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2364 wakeup((caddr_t)&lp->nfslock_lock);
2369 * Copy a string from an mbuf list into a character array.
2370 * Return EBADRPC if there is an mbuf error,
2374 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2383 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2384 rem = NFSM_RNDUP(siz) - siz;
2390 NFSBCOPY(cp, str, xfer);
2399 cp = NFSMTOD(mp, caddr_t);
2411 error = nfsm_advance(nd, rem, len);
2417 NFSEXITCODE2(error, nd);
2422 * Fill in the attributes as marked by the bitmap (V4).
2425 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2426 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2427 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2428 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2429 struct statfs *pnfssf)
2431 int bitpos, retnum = 0;
2433 int siz, prefixnum, error;
2434 u_char *cp, namestr[NFSV4_SMALLSTR];
2435 nfsattrbit_t attrbits, retbits;
2436 nfsattrbit_t *retbitp = &retbits;
2437 u_int32_t freenum, *retnump;
2440 struct nfsfsinfo fsinf;
2441 struct timespec temptime;
2442 NFSACL_T *aclp, *naclp = NULL;
2449 * First, set the bits that can be filled and get fsinfo.
2451 NFSSET_ATTRBIT(retbitp, attrbitp);
2453 * If both p and cred are NULL, it is a client side setattr call.
2454 * If both p and cred are not NULL, it is a server side reply call.
2455 * If p is not NULL and cred is NULL, it is a client side callback
2458 if (p == NULL && cred == NULL) {
2459 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2462 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2463 naclp = acl_alloc(M_WAITOK);
2466 nfsvno_getfs(&fsinf, isdgram);
2469 * Get the VFS_STATFS(), since some attributes need them.
2471 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2472 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2473 error = VFS_STATFS(mp, fs);
2476 nd->nd_repstat = NFSERR_ACCES;
2480 NFSCLRSTATFS_ATTRBIT(retbitp);
2486 * And the NFSv4 ACL...
2488 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2489 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2490 supports_nfsv4acls == 0))) {
2491 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2493 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2494 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2495 supports_nfsv4acls == 0)) {
2496 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2497 } else if (naclp != NULL) {
2498 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2499 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2501 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2503 NFSVOPUNLOCK(vp, 0);
2505 error = NFSERR_PERM;
2508 nd->nd_repstat = NFSERR_ACCES;
2512 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2518 * Put out the attribute bitmap for the ones being filled in
2519 * and get the field for the number of attributes returned.
2521 prefixnum = nfsrv_putattrbit(nd, retbitp);
2522 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2523 prefixnum += NFSX_UNSIGNED;
2526 * Now, loop around filling in the attributes for each bit set.
2528 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2529 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2531 case NFSATTRBIT_SUPPORTEDATTRS:
2532 NFSSETSUPP_ATTRBIT(&attrbits);
2533 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2534 && supports_nfsv4acls == 0)) {
2535 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2536 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2538 retnum += nfsrv_putattrbit(nd, &attrbits);
2540 case NFSATTRBIT_TYPE:
2541 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2542 *tl = vtonfsv34_type(vap->va_type);
2543 retnum += NFSX_UNSIGNED;
2545 case NFSATTRBIT_FHEXPIRETYPE:
2546 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2547 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2548 retnum += NFSX_UNSIGNED;
2550 case NFSATTRBIT_CHANGE:
2551 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2552 txdr_hyper(vap->va_filerev, tl);
2553 retnum += NFSX_HYPER;
2555 case NFSATTRBIT_SIZE:
2556 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2557 txdr_hyper(vap->va_size, tl);
2558 retnum += NFSX_HYPER;
2560 case NFSATTRBIT_LINKSUPPORT:
2561 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2562 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2566 retnum += NFSX_UNSIGNED;
2568 case NFSATTRBIT_SYMLINKSUPPORT:
2569 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2570 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2574 retnum += NFSX_UNSIGNED;
2576 case NFSATTRBIT_NAMEDATTR:
2577 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2579 retnum += NFSX_UNSIGNED;
2581 case NFSATTRBIT_FSID:
2582 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2584 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2586 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2587 retnum += NFSX_V4FSID;
2589 case NFSATTRBIT_UNIQUEHANDLES:
2590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2592 retnum += NFSX_UNSIGNED;
2594 case NFSATTRBIT_LEASETIME:
2595 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2596 *tl = txdr_unsigned(nfsrv_lease);
2597 retnum += NFSX_UNSIGNED;
2599 case NFSATTRBIT_RDATTRERROR:
2600 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2601 *tl = txdr_unsigned(rderror);
2602 retnum += NFSX_UNSIGNED;
2605 * Recommended Attributes. (Only the supported ones.)
2607 case NFSATTRBIT_ACL:
2608 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2610 case NFSATTRBIT_ACLSUPPORT:
2611 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2612 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2613 retnum += NFSX_UNSIGNED;
2615 case NFSATTRBIT_CANSETTIME:
2616 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2617 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2621 retnum += NFSX_UNSIGNED;
2623 case NFSATTRBIT_CASEINSENSITIVE:
2624 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2626 retnum += NFSX_UNSIGNED;
2628 case NFSATTRBIT_CASEPRESERVING:
2629 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2631 retnum += NFSX_UNSIGNED;
2633 case NFSATTRBIT_CHOWNRESTRICTED:
2634 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2636 retnum += NFSX_UNSIGNED;
2638 case NFSATTRBIT_FILEHANDLE:
2639 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2641 case NFSATTRBIT_FILEID:
2642 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2643 uquad = vap->va_fileid;
2644 txdr_hyper(uquad, tl);
2645 retnum += NFSX_HYPER;
2647 case NFSATTRBIT_FILESAVAIL:
2649 * Check quota and use min(quota, f_ffree).
2651 freenum = fs->f_ffree;
2654 * ufs_quotactl() insists that the uid argument
2655 * equal p_ruid for non-root quota access, so
2656 * we'll just make sure that's the case.
2658 savuid = p->p_cred->p_ruid;
2659 p->p_cred->p_ruid = cred->cr_uid;
2660 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2661 cred->cr_uid, (caddr_t)&dqb))
2662 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2664 p->p_cred->p_ruid = savuid;
2666 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2668 *tl = txdr_unsigned(freenum);
2669 retnum += NFSX_HYPER;
2671 case NFSATTRBIT_FILESFREE:
2672 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2674 *tl = txdr_unsigned(fs->f_ffree);
2675 retnum += NFSX_HYPER;
2677 case NFSATTRBIT_FILESTOTAL:
2678 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2680 *tl = txdr_unsigned(fs->f_files);
2681 retnum += NFSX_HYPER;
2683 case NFSATTRBIT_FSLOCATIONS:
2684 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2687 retnum += 2 * NFSX_UNSIGNED;
2689 case NFSATTRBIT_HOMOGENEOUS:
2690 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2691 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2695 retnum += NFSX_UNSIGNED;
2697 case NFSATTRBIT_MAXFILESIZE:
2698 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2699 uquad = NFSRV_MAXFILESIZE;
2700 txdr_hyper(uquad, tl);
2701 retnum += NFSX_HYPER;
2703 case NFSATTRBIT_MAXLINK:
2704 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2705 *tl = txdr_unsigned(NFS_LINK_MAX);
2706 retnum += NFSX_UNSIGNED;
2708 case NFSATTRBIT_MAXNAME:
2709 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2710 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2711 retnum += NFSX_UNSIGNED;
2713 case NFSATTRBIT_MAXREAD:
2714 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2716 *tl = txdr_unsigned(fsinf.fs_rtmax);
2717 retnum += NFSX_HYPER;
2719 case NFSATTRBIT_MAXWRITE:
2720 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2722 *tl = txdr_unsigned(fsinf.fs_wtmax);
2723 retnum += NFSX_HYPER;
2725 case NFSATTRBIT_MODE:
2726 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2727 *tl = vtonfsv34_mode(vap->va_mode);
2728 retnum += NFSX_UNSIGNED;
2730 case NFSATTRBIT_NOTRUNC:
2731 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2733 retnum += NFSX_UNSIGNED;
2735 case NFSATTRBIT_NUMLINKS:
2736 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2737 *tl = txdr_unsigned(vap->va_nlink);
2738 retnum += NFSX_UNSIGNED;
2740 case NFSATTRBIT_OWNER:
2742 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2743 retnum += nfsm_strtom(nd, cp, siz);
2745 free(cp, M_NFSSTRING);
2747 case NFSATTRBIT_OWNERGROUP:
2749 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2750 retnum += nfsm_strtom(nd, cp, siz);
2752 free(cp, M_NFSSTRING);
2754 case NFSATTRBIT_QUOTAHARD:
2755 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2756 freenum = fs->f_bfree;
2758 freenum = fs->f_bavail;
2761 * ufs_quotactl() insists that the uid argument
2762 * equal p_ruid for non-root quota access, so
2763 * we'll just make sure that's the case.
2765 savuid = p->p_cred->p_ruid;
2766 p->p_cred->p_ruid = cred->cr_uid;
2767 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2768 cred->cr_uid, (caddr_t)&dqb))
2769 freenum = min(dqb.dqb_bhardlimit, freenum);
2770 p->p_cred->p_ruid = savuid;
2772 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2773 uquad = (u_int64_t)freenum;
2774 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2775 txdr_hyper(uquad, tl);
2776 retnum += NFSX_HYPER;
2778 case NFSATTRBIT_QUOTASOFT:
2779 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2780 freenum = fs->f_bfree;
2782 freenum = fs->f_bavail;
2785 * ufs_quotactl() insists that the uid argument
2786 * equal p_ruid for non-root quota access, so
2787 * we'll just make sure that's the case.
2789 savuid = p->p_cred->p_ruid;
2790 p->p_cred->p_ruid = cred->cr_uid;
2791 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2792 cred->cr_uid, (caddr_t)&dqb))
2793 freenum = min(dqb.dqb_bsoftlimit, freenum);
2794 p->p_cred->p_ruid = savuid;
2796 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2797 uquad = (u_int64_t)freenum;
2798 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2799 txdr_hyper(uquad, tl);
2800 retnum += NFSX_HYPER;
2802 case NFSATTRBIT_QUOTAUSED:
2806 * ufs_quotactl() insists that the uid argument
2807 * equal p_ruid for non-root quota access, so
2808 * we'll just make sure that's the case.
2810 savuid = p->p_cred->p_ruid;
2811 p->p_cred->p_ruid = cred->cr_uid;
2812 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2813 cred->cr_uid, (caddr_t)&dqb))
2814 freenum = dqb.dqb_curblocks;
2815 p->p_cred->p_ruid = savuid;
2817 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2818 uquad = (u_int64_t)freenum;
2819 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2820 txdr_hyper(uquad, tl);
2821 retnum += NFSX_HYPER;
2823 case NFSATTRBIT_RAWDEV:
2824 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2825 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2826 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2827 retnum += NFSX_V4SPECDATA;
2829 case NFSATTRBIT_SPACEAVAIL:
2830 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2831 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) {
2833 uquad = (u_int64_t)pnfssf->f_bfree;
2835 uquad = (u_int64_t)fs->f_bfree;
2838 uquad = (u_int64_t)pnfssf->f_bavail;
2840 uquad = (u_int64_t)fs->f_bavail;
2843 uquad *= pnfssf->f_bsize;
2845 uquad *= fs->f_bsize;
2846 txdr_hyper(uquad, tl);
2847 retnum += NFSX_HYPER;
2849 case NFSATTRBIT_SPACEFREE:
2850 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2851 if (pnfssf != NULL) {
2852 uquad = (u_int64_t)pnfssf->f_bfree;
2853 uquad *= pnfssf->f_bsize;
2855 uquad = (u_int64_t)fs->f_bfree;
2856 uquad *= fs->f_bsize;
2858 txdr_hyper(uquad, tl);
2859 retnum += NFSX_HYPER;
2861 case NFSATTRBIT_SPACETOTAL:
2862 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2863 if (pnfssf != NULL) {
2864 uquad = (u_int64_t)pnfssf->f_blocks;
2865 uquad *= pnfssf->f_bsize;
2867 uquad = (u_int64_t)fs->f_blocks;
2868 uquad *= fs->f_bsize;
2870 txdr_hyper(uquad, tl);
2871 retnum += NFSX_HYPER;
2873 case NFSATTRBIT_SPACEUSED:
2874 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2875 txdr_hyper(vap->va_bytes, tl);
2876 retnum += NFSX_HYPER;
2878 case NFSATTRBIT_TIMEACCESS:
2879 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2880 txdr_nfsv4time(&vap->va_atime, tl);
2881 retnum += NFSX_V4TIME;
2883 case NFSATTRBIT_TIMEACCESSSET:
2884 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2885 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2886 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2887 txdr_nfsv4time(&vap->va_atime, tl);
2888 retnum += NFSX_V4SETTIME;
2890 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2891 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2892 retnum += NFSX_UNSIGNED;
2895 case NFSATTRBIT_TIMEDELTA:
2896 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2897 temptime.tv_sec = 0;
2898 temptime.tv_nsec = 1000000000 / hz;
2899 txdr_nfsv4time(&temptime, tl);
2900 retnum += NFSX_V4TIME;
2902 case NFSATTRBIT_TIMEMETADATA:
2903 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2904 txdr_nfsv4time(&vap->va_ctime, tl);
2905 retnum += NFSX_V4TIME;
2907 case NFSATTRBIT_TIMEMODIFY:
2908 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2909 txdr_nfsv4time(&vap->va_mtime, tl);
2910 retnum += NFSX_V4TIME;
2912 case NFSATTRBIT_TIMEMODIFYSET:
2913 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2914 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2915 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2916 txdr_nfsv4time(&vap->va_mtime, tl);
2917 retnum += NFSX_V4SETTIME;
2919 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2920 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2921 retnum += NFSX_UNSIGNED;
2924 case NFSATTRBIT_MOUNTEDONFILEID:
2925 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2927 uquad = mounted_on_fileno;
2929 uquad = vap->va_fileid;
2930 txdr_hyper(uquad, tl);
2931 retnum += NFSX_HYPER;
2933 case NFSATTRBIT_SUPPATTREXCLCREAT:
2934 NFSSETSUPP_ATTRBIT(&attrbits);
2935 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2936 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2937 retnum += nfsrv_putattrbit(nd, &attrbits);
2939 case NFSATTRBIT_FSLAYOUTTYPE:
2940 case NFSATTRBIT_LAYOUTTYPE:
2941 if (nfsrv_devidcnt == 0)
2946 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2947 *tl++ = txdr_unsigned(1); /* One entry. */
2948 if (nfsrv_doflexfile != 0 ||
2949 nfsrv_maxpnfsmirror > 1)
2950 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2952 *tl = txdr_unsigned(
2953 NFSLAYOUT_NFSV4_1_FILES);
2955 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2958 retnum += siz * NFSX_UNSIGNED;
2960 case NFSATTRBIT_LAYOUTALIGNMENT:
2961 case NFSATTRBIT_LAYOUTBLKSIZE:
2962 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2963 *tl = txdr_unsigned(NFS_SRVMAXIO);
2964 retnum += NFSX_UNSIGNED;
2967 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2974 *retnump = txdr_unsigned(retnum);
2975 return (retnum + prefixnum);
2979 * Put the attribute bits onto an mbuf list.
2980 * Return the number of bytes of output generated.
2983 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2986 int cnt, i, bytesize;
2988 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2989 if (attrbitp->bits[cnt - 1])
2991 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2992 NFSM_BUILD(tl, u_int32_t *, bytesize);
2993 *tl++ = txdr_unsigned(cnt);
2994 for (i = 0; i < cnt; i++)
2995 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3000 * Convert a uid to a string.
3001 * If the lookup fails, just output the digits.
3003 * cpp - points to a buffer of size NFSV4_SMALLSTR
3004 * (malloc a larger one, as required)
3005 * retlenp - pointer to length to be returned
3008 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
3011 struct nfsusrgrp *usrp;
3014 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3015 struct nfsrv_lughash *hp;
3019 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3021 * Always map nfsrv_defaultuid to "nobody".
3023 if (uid == nfsrv_defaultuid) {
3024 i = nfsrv_dnsnamelen + 7;
3026 if (len > NFSV4_SMALLSTR)
3027 free(cp, M_NFSSTRING);
3028 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3034 NFSBCOPY("nobody@", cp, 7);
3036 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3040 hp = NFSUSERHASH(uid);
3042 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3043 if (usrp->lug_uid == uid) {
3044 if (usrp->lug_expiry < NFSD_MONOSEC)
3047 * If the name doesn't already have an '@'
3048 * in it, append @domainname to it.
3050 for (i = 0; i < usrp->lug_namelen; i++) {
3051 if (usrp->lug_name[i] == '@') {
3057 i = usrp->lug_namelen;
3059 i = usrp->lug_namelen +
3060 nfsrv_dnsnamelen + 1;
3062 mtx_unlock(&hp->mtx);
3063 if (len > NFSV4_SMALLSTR)
3064 free(cp, M_NFSSTRING);
3065 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3071 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3072 if (!hasampersand) {
3073 cp += usrp->lug_namelen;
3075 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3077 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3078 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3080 mtx_unlock(&hp->mtx);
3084 mtx_unlock(&hp->mtx);
3086 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
3088 if (ret == 0 && cnt < 2)
3093 * No match, just return a string of digits.
3097 while (tmp || i == 0) {
3101 len = (i > len) ? len : i;
3105 for (i = 0; i < len; i++) {
3106 *cp-- = '0' + (tmp % 10);
3113 * Get a credential for the uid with the server's group list.
3114 * If none is found, just return the credential passed in after
3115 * logging a warning message.
3118 nfsrv_getgrpscred(struct ucred *oldcred)
3120 struct nfsusrgrp *usrp;
3121 struct ucred *newcred;
3124 struct nfsrv_lughash *hp;
3127 uid = oldcred->cr_uid;
3129 if (nfsrv_dnsnamelen > 0) {
3130 hp = NFSUSERHASH(uid);
3132 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3133 if (usrp->lug_uid == uid) {
3134 if (usrp->lug_expiry < NFSD_MONOSEC)
3136 if (usrp->lug_cred != NULL) {
3137 newcred = crhold(usrp->lug_cred);
3141 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3142 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3144 mtx_unlock(&hp->mtx);
3148 mtx_unlock(&hp->mtx);
3150 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
3152 if (ret == 0 && cnt < 2)
3159 * Convert a string to a uid.
3160 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3162 * If this is called from a client side mount using AUTH_SYS and the
3163 * string is made up entirely of digits, just convert the string to
3167 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, NFSPROC_T *p)
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,
3350 if (ret == 0 && cnt < 2)
3355 * No match, just return a string of digits.
3359 while (tmp || i == 0) {
3363 len = (i > len) ? len : i;
3367 for (i = 0; i < len; i++) {
3368 *cp-- = '0' + (tmp % 10);
3375 * Convert a string to a gid.
3376 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3378 * If this is called from a client side mount using AUTH_SYS and the
3379 * string is made up entirely of digits, just convert the string to
3383 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
3387 char *cp, *endstr, *str0;
3388 struct nfsusrgrp *usrp;
3392 struct nfsrv_lughash *hp, *hp2;
3395 error = NFSERR_BADOWNER;
3398 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3400 tgid = (gid_t)strtoul(str0, &endstr, 10);
3401 if ((endstr - str0) == len) {
3402 /* A numeric string. */
3403 if ((nd->nd_flag & ND_KERBV) == 0 &&
3404 ((nd->nd_flag & ND_NFSCL) != 0 ||
3405 nfsd_enable_stringtouid != 0))
3408 error = NFSERR_BADOWNER;
3414 cp = strchr(str0, '@');
3416 i = (int)(cp++ - str0);
3422 if (nfsrv_dnsnamelen > 0) {
3424 * If an '@' is found and the dns name matches, search for the
3425 * name with the dns stripped off.
3427 if (cnt == 0 && i < len && i > 0 &&
3428 (len - 1 - i) == nfsrv_dnsnamelen &&
3429 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3430 len -= (nfsrv_dnsnamelen + 1);
3435 * Check for the special case of "nogroup".
3437 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3438 *gidp = nfsrv_defaultgid;
3443 hp = NFSGROUPNAMEHASH(str, len);
3445 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3446 if (usrp->lug_namelen == len &&
3447 !NFSBCMP(usrp->lug_name, str, len)) {
3448 if (usrp->lug_expiry < NFSD_MONOSEC)
3450 hp2 = NFSGROUPHASH(usrp->lug_gid);
3451 mtx_lock(&hp2->mtx);
3452 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3453 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3455 *gidp = usrp->lug_gid;
3456 mtx_unlock(&hp2->mtx);
3457 mtx_unlock(&hp->mtx);
3462 mtx_unlock(&hp->mtx);
3464 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3466 if (ret == 0 && cnt < 2)
3469 error = NFSERR_BADOWNER;
3477 * Cmp len chars, allowing mixed case in the first argument to match lower
3478 * case in the second, but not if the first argument is all upper case.
3479 * Return 0 for a match, 1 otherwise.
3482 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3488 for (i = 0; i < len; i++) {
3489 if (*cp >= 'A' && *cp <= 'Z') {
3490 tmp = *cp++ + ('a' - 'A');
3493 if (tmp >= 'a' && tmp <= 'z')
3506 * Set the port for the nfsuserd.
3509 nfsrv_nfsuserdport(struct sockaddr *sad, u_short port, NFSPROC_T *p)
3511 struct nfssockreq *rp;
3512 struct sockaddr_in *ad;
3516 if (nfsrv_nfsuserd) {
3519 free(sad, M_SONAME);
3525 * Set up the socket record and connect.
3527 rp = &nfsrv_nfsuserdsock;
3528 rp->nr_client = NULL;
3530 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3532 /* Use the AF_LOCAL socket address passed in. */
3533 rp->nr_sotype = SOCK_STREAM;
3537 /* Use the port# for a UDP socket (old nfsuserd). */
3538 rp->nr_sotype = SOCK_DGRAM;
3539 rp->nr_soproto = IPPROTO_UDP;
3540 rp->nr_nam = malloc(sizeof(*rp->nr_nam), M_SONAME, M_WAITOK |
3542 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3543 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3544 ad->sin_family = AF_INET;
3545 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);
3546 ad->sin_port = port;
3548 rp->nr_prog = RPCPROG_NFSUSERD;
3549 rp->nr_vers = RPCNFSUSERD_VERS;
3550 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3552 free(rp->nr_nam, M_SONAME);
3561 * Delete the nfsuserd port.
3564 nfsrv_nfsuserddelport(void)
3568 if (nfsrv_nfsuserd == 0) {
3574 newnfs_disconnect(&nfsrv_nfsuserdsock);
3575 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3579 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3581 * Returns 0 upon success, non-zero otherwise.
3584 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3587 struct nfsrv_descript *nd;
3589 struct nfsrv_descript nfsd;
3594 if (nfsrv_nfsuserd == 0) {
3601 cred = newnfs_getcred();
3602 nd->nd_flag = ND_GSSINITREPLY;
3605 nd->nd_procnum = procnum;
3606 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3607 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3608 if (procnum == RPCNFSUSERD_GETUID)
3609 *tl = txdr_unsigned(uid);
3611 *tl = txdr_unsigned(gid);
3614 (void) nfsm_strtom(nd, name, len);
3616 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3617 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3620 mbuf_freem(nd->nd_mrep);
3621 error = nd->nd_repstat;
3629 * This function is called from the nfssvc(2) system call, to update the
3630 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3633 nfssvc_idname(struct nfsd_idargs *nidp)
3635 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3636 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3637 int i, group_locked, groupname_locked, user_locked, username_locked;
3642 static int onethread = 0;
3643 static time_t lasttime = 0;
3645 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3649 if (nidp->nid_flag & NFSID_INITIALIZE) {
3650 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3651 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3654 free(cp, M_NFSSTRING);
3657 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3659 * Free up all the old stuff and reinitialize hash
3660 * lists. All mutexes for both lists must be locked,
3661 * with the user/group name ones before the uid/gid
3662 * ones, to avoid a LOR.
3664 for (i = 0; i < nfsrv_lughashsize; i++)
3665 mtx_lock(&nfsusernamehash[i].mtx);
3666 for (i = 0; i < nfsrv_lughashsize; i++)
3667 mtx_lock(&nfsuserhash[i].mtx);
3668 for (i = 0; i < nfsrv_lughashsize; i++)
3669 TAILQ_FOREACH_SAFE(usrp,
3670 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3671 nfsrv_removeuser(usrp, 1);
3672 for (i = 0; i < nfsrv_lughashsize; i++)
3673 mtx_unlock(&nfsuserhash[i].mtx);
3674 for (i = 0; i < nfsrv_lughashsize; i++)
3675 mtx_unlock(&nfsusernamehash[i].mtx);
3676 for (i = 0; i < nfsrv_lughashsize; i++)
3677 mtx_lock(&nfsgroupnamehash[i].mtx);
3678 for (i = 0; i < nfsrv_lughashsize; i++)
3679 mtx_lock(&nfsgrouphash[i].mtx);
3680 for (i = 0; i < nfsrv_lughashsize; i++)
3681 TAILQ_FOREACH_SAFE(usrp,
3682 &nfsgrouphash[i].lughead, lug_numhash,
3684 nfsrv_removeuser(usrp, 0);
3685 for (i = 0; i < nfsrv_lughashsize; i++)
3686 mtx_unlock(&nfsgrouphash[i].mtx);
3687 for (i = 0; i < nfsrv_lughashsize; i++)
3688 mtx_unlock(&nfsgroupnamehash[i].mtx);
3689 free(nfsrv_dnsname, M_NFSSTRING);
3690 nfsrv_dnsname = NULL;
3692 if (nfsuserhash == NULL) {
3693 /* Allocate the hash tables. */
3694 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3695 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3697 for (i = 0; i < nfsrv_lughashsize; i++)
3698 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3699 NULL, MTX_DEF | MTX_DUPOK);
3700 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3701 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3703 for (i = 0; i < nfsrv_lughashsize; i++)
3704 mtx_init(&nfsusernamehash[i].mtx,
3705 "nfsusrhash", NULL, MTX_DEF |
3707 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3708 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3710 for (i = 0; i < nfsrv_lughashsize; i++)
3711 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3712 NULL, MTX_DEF | MTX_DUPOK);
3713 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3714 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3716 for (i = 0; i < nfsrv_lughashsize; i++)
3717 mtx_init(&nfsgroupnamehash[i].mtx,
3718 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3720 /* (Re)initialize the list heads. */
3721 for (i = 0; i < nfsrv_lughashsize; i++)
3722 TAILQ_INIT(&nfsuserhash[i].lughead);
3723 for (i = 0; i < nfsrv_lughashsize; i++)
3724 TAILQ_INIT(&nfsusernamehash[i].lughead);
3725 for (i = 0; i < nfsrv_lughashsize; i++)
3726 TAILQ_INIT(&nfsgrouphash[i].lughead);
3727 for (i = 0; i < nfsrv_lughashsize; i++)
3728 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3731 * Put name in "DNS" string.
3734 nfsrv_defaultuid = nidp->nid_uid;
3735 nfsrv_defaultgid = nidp->nid_gid;
3737 nfsrv_usermax = nidp->nid_usermax;
3738 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3743 * malloc the new one now, so any potential sleep occurs before
3744 * manipulation of the lists.
3746 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3747 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3748 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3750 if (error == 0 && nidp->nid_ngroup > 0 &&
3751 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3752 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3754 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3755 sizeof(gid_t) * nidp->nid_ngroup);
3758 * Create a credential just like svc_getcred(),
3759 * but using the group list provided.
3762 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3763 crsetgroups(cr, nidp->nid_ngroup, grps);
3764 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3765 cr->cr_prison = &prison0;
3766 prison_hold(cr->cr_prison);
3768 mac_cred_associate_nfsd(cr);
3770 newusrp->lug_cred = cr;
3775 free(newusrp, M_NFSUSERGROUP);
3778 newusrp->lug_namelen = nidp->nid_namelen;
3781 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3782 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3783 * The flags user_locked, username_locked, group_locked and
3784 * groupname_locked are set to indicate all of those hash lists are
3785 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3786 * the respective one mutex is locked.
3788 user_locked = username_locked = group_locked = groupname_locked = 0;
3789 hp_name = hp_idnum = NULL;
3792 * Delete old entries, as required.
3794 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3795 /* Must lock all username hash lists first, to avoid a LOR. */
3796 for (i = 0; i < nfsrv_lughashsize; i++)
3797 mtx_lock(&nfsusernamehash[i].mtx);
3798 username_locked = 1;
3799 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3800 mtx_lock(&hp_idnum->mtx);
3801 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3803 if (usrp->lug_uid == nidp->nid_uid)
3804 nfsrv_removeuser(usrp, 1);
3806 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3807 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3808 newusrp->lug_namelen);
3809 mtx_lock(&hp_name->mtx);
3810 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3812 if (usrp->lug_namelen == newusrp->lug_namelen &&
3813 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3814 usrp->lug_namelen)) {
3815 thp = NFSUSERHASH(usrp->lug_uid);
3816 mtx_lock(&thp->mtx);
3817 nfsrv_removeuser(usrp, 1);
3818 mtx_unlock(&thp->mtx);
3821 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3822 mtx_lock(&hp_idnum->mtx);
3823 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3824 /* Must lock all groupname hash lists first, to avoid a LOR. */
3825 for (i = 0; i < nfsrv_lughashsize; i++)
3826 mtx_lock(&nfsgroupnamehash[i].mtx);
3827 groupname_locked = 1;
3828 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3829 mtx_lock(&hp_idnum->mtx);
3830 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3832 if (usrp->lug_gid == nidp->nid_gid)
3833 nfsrv_removeuser(usrp, 0);
3835 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3836 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3837 newusrp->lug_namelen);
3838 mtx_lock(&hp_name->mtx);
3839 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3841 if (usrp->lug_namelen == newusrp->lug_namelen &&
3842 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3843 usrp->lug_namelen)) {
3844 thp = NFSGROUPHASH(usrp->lug_gid);
3845 mtx_lock(&thp->mtx);
3846 nfsrv_removeuser(usrp, 0);
3847 mtx_unlock(&thp->mtx);
3850 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3851 mtx_lock(&hp_idnum->mtx);
3855 * Now, we can add the new one.
3857 if (nidp->nid_usertimeout)
3858 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3860 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3861 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3862 newusrp->lug_uid = nidp->nid_uid;
3863 thp = NFSUSERHASH(newusrp->lug_uid);
3864 mtx_assert(&thp->mtx, MA_OWNED);
3865 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3866 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3867 mtx_assert(&thp->mtx, MA_OWNED);
3868 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3869 atomic_add_int(&nfsrv_usercnt, 1);
3870 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3871 newusrp->lug_gid = nidp->nid_gid;
3872 thp = NFSGROUPHASH(newusrp->lug_gid);
3873 mtx_assert(&thp->mtx, MA_OWNED);
3874 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3875 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3876 mtx_assert(&thp->mtx, MA_OWNED);
3877 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3878 atomic_add_int(&nfsrv_usercnt, 1);
3880 if (newusrp->lug_cred != NULL)
3881 crfree(newusrp->lug_cred);
3882 free(newusrp, M_NFSUSERGROUP);
3886 * Once per second, allow one thread to trim the cache.
3888 if (lasttime < NFSD_MONOSEC &&
3889 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3891 * First, unlock the single mutexes, so that all entries
3892 * can be locked and any LOR is avoided.
3894 if (hp_name != NULL) {
3895 mtx_unlock(&hp_name->mtx);
3898 if (hp_idnum != NULL) {
3899 mtx_unlock(&hp_idnum->mtx);
3903 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3904 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3905 if (username_locked == 0) {
3906 for (i = 0; i < nfsrv_lughashsize; i++)
3907 mtx_lock(&nfsusernamehash[i].mtx);
3908 username_locked = 1;
3910 KASSERT(user_locked == 0,
3911 ("nfssvc_idname: user_locked"));
3912 for (i = 0; i < nfsrv_lughashsize; i++)
3913 mtx_lock(&nfsuserhash[i].mtx);
3915 for (i = 0; i < nfsrv_lughashsize; i++) {
3916 TAILQ_FOREACH_SAFE(usrp,
3917 &nfsuserhash[i].lughead, lug_numhash,
3919 if (usrp->lug_expiry < NFSD_MONOSEC)
3920 nfsrv_removeuser(usrp, 1);
3922 for (i = 0; i < nfsrv_lughashsize; i++) {
3924 * Trim the cache using an approximate LRU
3925 * algorithm. This code deletes the least
3926 * recently used entry on each hash list.
3928 if (nfsrv_usercnt <= nfsrv_usermax)
3930 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3932 nfsrv_removeuser(usrp, 1);
3935 if (groupname_locked == 0) {
3936 for (i = 0; i < nfsrv_lughashsize; i++)
3937 mtx_lock(&nfsgroupnamehash[i].mtx);
3938 groupname_locked = 1;
3940 KASSERT(group_locked == 0,
3941 ("nfssvc_idname: group_locked"));
3942 for (i = 0; i < nfsrv_lughashsize; i++)
3943 mtx_lock(&nfsgrouphash[i].mtx);
3945 for (i = 0; i < nfsrv_lughashsize; i++) {
3946 TAILQ_FOREACH_SAFE(usrp,
3947 &nfsgrouphash[i].lughead, lug_numhash,
3949 if (usrp->lug_expiry < NFSD_MONOSEC)
3950 nfsrv_removeuser(usrp, 0);
3952 for (i = 0; i < nfsrv_lughashsize; i++) {
3954 * Trim the cache using an approximate LRU
3955 * algorithm. This code deletes the least
3956 * recently user entry on each hash list.
3958 if (nfsrv_usercnt <= nfsrv_usermax)
3960 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3962 nfsrv_removeuser(usrp, 0);
3965 lasttime = NFSD_MONOSEC;
3966 atomic_store_rel_int(&onethread, 0);
3969 /* Now, unlock all locked mutexes. */
3970 if (hp_idnum != NULL)
3971 mtx_unlock(&hp_idnum->mtx);
3972 if (hp_name != NULL)
3973 mtx_unlock(&hp_name->mtx);
3974 if (user_locked != 0)
3975 for (i = 0; i < nfsrv_lughashsize; i++)
3976 mtx_unlock(&nfsuserhash[i].mtx);
3977 if (username_locked != 0)
3978 for (i = 0; i < nfsrv_lughashsize; i++)
3979 mtx_unlock(&nfsusernamehash[i].mtx);
3980 if (group_locked != 0)
3981 for (i = 0; i < nfsrv_lughashsize; i++)
3982 mtx_unlock(&nfsgrouphash[i].mtx);
3983 if (groupname_locked != 0)
3984 for (i = 0; i < nfsrv_lughashsize; i++)
3985 mtx_unlock(&nfsgroupnamehash[i].mtx);
3992 * Remove a user/group name element.
3995 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3997 struct nfsrv_lughash *hp;
4000 hp = NFSUSERHASH(usrp->lug_uid);
4001 mtx_assert(&hp->mtx, MA_OWNED);
4002 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4003 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4004 mtx_assert(&hp->mtx, MA_OWNED);
4005 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4007 hp = NFSGROUPHASH(usrp->lug_gid);
4008 mtx_assert(&hp->mtx, MA_OWNED);
4009 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4010 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4011 mtx_assert(&hp->mtx, MA_OWNED);
4012 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4014 atomic_add_int(&nfsrv_usercnt, -1);
4015 if (usrp->lug_cred != NULL)
4016 crfree(usrp->lug_cred);
4017 free(usrp, M_NFSUSERGROUP);
4021 * Free up all the allocations related to the name<-->id cache.
4022 * This function should only be called when the nfsuserd daemon isn't
4023 * running, since it doesn't do any locking.
4024 * This function is meant to be used when the nfscommon module is unloaded.
4027 nfsrv_cleanusergroup(void)
4029 struct nfsrv_lughash *hp, *hp2;
4030 struct nfsusrgrp *nusrp, *usrp;
4033 if (nfsuserhash == NULL)
4036 for (i = 0; i < nfsrv_lughashsize; i++) {
4037 hp = &nfsuserhash[i];
4038 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4039 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4040 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4042 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4043 if (usrp->lug_cred != NULL)
4044 crfree(usrp->lug_cred);
4045 free(usrp, M_NFSUSERGROUP);
4047 hp = &nfsgrouphash[i];
4048 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4049 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4050 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4052 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4053 if (usrp->lug_cred != NULL)
4054 crfree(usrp->lug_cred);
4055 free(usrp, M_NFSUSERGROUP);
4057 mtx_destroy(&nfsuserhash[i].mtx);
4058 mtx_destroy(&nfsusernamehash[i].mtx);
4059 mtx_destroy(&nfsgroupnamehash[i].mtx);
4060 mtx_destroy(&nfsgrouphash[i].mtx);
4062 free(nfsuserhash, M_NFSUSERGROUP);
4063 free(nfsusernamehash, M_NFSUSERGROUP);
4064 free(nfsgrouphash, M_NFSUSERGROUP);
4065 free(nfsgroupnamehash, M_NFSUSERGROUP);
4066 free(nfsrv_dnsname, M_NFSSTRING);
4070 * This function scans a byte string and checks for UTF-8 compliance.
4071 * It returns 0 if it conforms and NFSERR_INVAL if not.
4074 nfsrv_checkutf8(u_int8_t *cp, int len)
4076 u_int32_t val = 0x0;
4077 int cnt = 0, gotd = 0, shift = 0;
4079 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4083 * Here are what the variables are used for:
4084 * val - the calculated value of a multibyte char, used to check
4085 * that it was coded with the correct range
4086 * cnt - the number of 10xxxxxx bytes to follow
4087 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4088 * shift - lower order bits of range (ie. "val >> shift" should
4089 * not be 0, in other words, dividing by the lower bound
4090 * of the range should get a non-zero value)
4091 * byte - used to calculate cnt
4095 /* This handles the 10xxxxxx bytes */
4096 if ((*cp & 0xc0) != 0x80 ||
4097 (gotd && (*cp & 0x20))) {
4098 error = NFSERR_INVAL;
4103 val |= (*cp & 0x3f);
4105 if (cnt == 0 && (val >> shift) == 0x0) {
4106 error = NFSERR_INVAL;
4109 } else if (*cp & 0x80) {
4110 /* first byte of multi byte char */
4112 while ((byte & 0x40) && cnt < 6) {
4116 if (cnt == 0 || cnt == 6) {
4117 error = NFSERR_INVAL;
4120 val = (*cp & (0x3f >> cnt));
4121 shift = utf8_shift[cnt - 1];
4122 if (cnt == 2 && val == 0xd)
4123 /* Check for the 0xd800-0xdfff case */
4130 error = NFSERR_INVAL;
4138 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4139 * strings, one with the root path in it and the other with the list of
4140 * locations. The list is in the same format as is found in nfr_refs.
4141 * It is a "," separated list of entries, where each of them is of the
4142 * form <server>:<rootpath>. For example
4143 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4144 * The nilp argument is set to 1 for the special case of a null fs_root
4145 * and an empty server list.
4146 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4147 * number of xdr bytes parsed in sump.
4150 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4151 int *sump, int *nilp)
4154 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4155 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4157 SLIST_ENTRY(list) next;
4161 SLIST_HEAD(, list) head;
4168 * Get the fs_root path and check for the special case of null path
4169 * and 0 length server list.
4171 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4172 len = fxdr_unsigned(int, *tl);
4173 if (len < 0 || len > 10240) {
4174 error = NFSERR_BADXDR;
4178 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4180 error = NFSERR_BADXDR;
4184 *sump = 2 * NFSX_UNSIGNED;
4188 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4189 error = nfsrv_mtostr(nd, cp, len);
4191 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4192 cnt = fxdr_unsigned(int, *tl);
4194 error = NFSERR_BADXDR;
4200 * Now, loop through the location list and make up the srvlist.
4202 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4203 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4206 for (i = 0; i < cnt; i++) {
4208 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4209 nsrv = fxdr_unsigned(int, *tl);
4211 error = NFSERR_BADXDR;
4216 * Handle the first server by putting it in the srvstr.
4218 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4219 len = fxdr_unsigned(int, *tl);
4220 if (len <= 0 || len > 1024) {
4221 error = NFSERR_BADXDR;
4224 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4229 error = nfsrv_mtostr(nd, cp3, len);
4235 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4236 for (j = 1; j < nsrv; j++) {
4238 * Yuck, put them in an slist and process them later.
4240 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4241 len = fxdr_unsigned(int, *tl);
4242 if (len <= 0 || len > 1024) {
4243 error = NFSERR_BADXDR;
4246 lsp = (struct list *)malloc(sizeof (struct list)
4247 + len, M_TEMP, M_WAITOK);
4248 error = nfsrv_mtostr(nd, lsp->host, len);
4251 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4253 SLIST_INSERT_HEAD(&head, lsp, next);
4257 * Finally, we can get the path.
4259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4260 len = fxdr_unsigned(int, *tl);
4261 if (len <= 0 || len > 1024) {
4262 error = NFSERR_BADXDR;
4265 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4266 error = nfsrv_mtostr(nd, cp3, len);
4269 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4274 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4275 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4278 NFSBCOPY(lsp->host, cp3, lsp->len);
4281 NFSBCOPY(str, cp3, stringlen);
4284 siz += (lsp->len + stringlen + 2);
4291 NFSEXITCODE2(0, nd);
4295 free(cp, M_NFSSTRING);
4297 free(cp2, M_NFSSTRING);
4298 NFSEXITCODE2(error, nd);
4303 * Make the malloc'd space large enough. This is a pain, but the xdr
4304 * doesn't set an upper bound on the side, so...
4307 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4314 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4315 NFSBCOPY(*cpp, cp, *slenp);
4316 free(*cpp, M_NFSSTRING);
4320 *slenp = siz + 1024;
4324 * Initialize the reply header data structures.
4327 nfsrvd_rephead(struct nfsrv_descript *nd)
4332 * If this is a big reply, use a cluster.
4334 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4335 nfs_bigreply[nd->nd_procnum]) {
4336 NFSMCLGET(mreq, M_WAITOK);
4344 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4345 mbuf_setlen(mreq, 0);
4347 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4348 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4352 * Lock a socket against others.
4353 * Currently used to serialize connect/disconnect attempts.
4356 newnfs_sndlock(int *flagp)
4361 while (*flagp & NFSR_SNDLOCK) {
4362 *flagp |= NFSR_WANTSND;
4365 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4366 PZERO - 1, "nfsndlck", &ts);
4368 *flagp |= NFSR_SNDLOCK;
4374 * Unlock the stream socket for others.
4377 newnfs_sndunlock(int *flagp)
4381 if ((*flagp & NFSR_SNDLOCK) == 0)
4382 panic("nfs sndunlock");
4383 *flagp &= ~NFSR_SNDLOCK;
4384 if (*flagp & NFSR_WANTSND) {
4385 *flagp &= ~NFSR_WANTSND;
4386 wakeup((caddr_t)flagp);
4392 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4393 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4395 struct in_addr saddr;
4396 uint32_t portnum, *tl;
4398 sa_family_t af = AF_UNSPEC;
4399 char addr[64], protocol[5], *cp;
4400 int cantparse = 0, error = 0;
4403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4404 i = fxdr_unsigned(int, *tl);
4405 if (i >= 3 && i <= 4) {
4406 error = nfsrv_mtostr(nd, protocol, i);
4409 if (strcmp(protocol, "tcp") == 0) {
4412 } else if (strcmp(protocol, "udp") == 0) {
4415 } else if (strcmp(protocol, "tcp6") == 0) {
4418 } else if (strcmp(protocol, "udp6") == 0) {
4426 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4431 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4432 i = fxdr_unsigned(int, *tl);
4434 error = NFSERR_BADXDR;
4436 } else if (cantparse == 0 && i >= 11 && i < 64) {
4438 * The shortest address is 11chars and the longest is < 64.
4440 error = nfsrv_mtostr(nd, addr, i);
4444 /* Find the port# at the end and extract that. */
4448 /* Count back two '.'s from end to get port# field. */
4449 for (j = 0; j < i; j++) {
4459 * The NFSv4 port# is appended as .N.N, where N is
4460 * a decimal # in the range 0-255, just like an inet4
4461 * address. Cheat and use inet_aton(), which will
4462 * return a Class A address and then shift the high
4463 * order 8bits over to convert it to the port#.
4466 if (inet_aton(cp, &saddr) == 1) {
4467 portnum = ntohl(saddr.s_addr);
4468 portv = (uint16_t)((portnum >> 16) |
4474 if (cantparse == 0) {
4475 if (af == AF_INET) {
4476 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4477 sin->sin_len = sizeof(*sin);
4478 sin->sin_family = AF_INET;
4479 sin->sin_port = htons(portv);
4484 if (inet_pton(af, addr, &sin6->sin6_addr)
4486 sin6->sin6_len = sizeof(*sin6);
4487 sin6->sin6_family = AF_INET6;
4488 sin6->sin6_port = htons(portv);
4496 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4507 * Handle an NFSv4.1 Sequence request for the session.
4508 * If reply != NULL, use it to return the cached reply, as required.
4509 * The client gets a cached reply via this call for callbacks, however the
4510 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4513 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4514 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4521 if (slotid > maxslot)
4522 return (NFSERR_BADSLOT);
4523 if (seqid == slots[slotid].nfssl_seq) {
4525 if (slots[slotid].nfssl_inprog != 0)
4526 error = NFSERR_DELAY;
4527 else if (slots[slotid].nfssl_reply != NULL) {
4528 if (reply != NULL) {
4529 *reply = slots[slotid].nfssl_reply;
4530 slots[slotid].nfssl_reply = NULL;
4532 slots[slotid].nfssl_inprog = 1;
4533 error = NFSERR_REPLYFROMCACHE;
4535 /* No reply cached, so just do it. */
4536 slots[slotid].nfssl_inprog = 1;
4537 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4538 if (slots[slotid].nfssl_reply != NULL)
4539 m_freem(slots[slotid].nfssl_reply);
4540 slots[slotid].nfssl_reply = NULL;
4541 slots[slotid].nfssl_inprog = 1;
4542 slots[slotid].nfssl_seq++;
4544 error = NFSERR_SEQMISORDERED;
4549 * Cache this reply for the slot.
4550 * Use the "rep" argument to return the cached reply if repstat is set to
4551 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4554 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4558 if (repstat == NFSERR_REPLYFROMCACHE) {
4559 *rep = slots[slotid].nfssl_reply;
4560 slots[slotid].nfssl_reply = NULL;
4562 if (slots[slotid].nfssl_reply != NULL)
4563 m_freem(slots[slotid].nfssl_reply);
4564 slots[slotid].nfssl_reply = *rep;
4566 slots[slotid].nfssl_inprog = 0;
4570 * Generate the xdr for an NFSv4.1 Sequence Operation.
4573 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4574 struct nfsclsession *sep, int dont_replycache)
4576 uint32_t *tl, slotseq = 0;
4577 int error, maxslot, slotpos;
4578 uint8_t sessionid[NFSX_V4SESSIONID];
4580 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4583 /* Build the Sequence arguments. */
4584 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4585 nd->nd_sequence = tl;
4586 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4587 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4588 nd->nd_slotseq = tl;
4590 nd->nd_flag |= ND_HASSLOTID;
4591 nd->nd_slotid = slotpos;
4592 *tl++ = txdr_unsigned(slotseq);
4593 *tl++ = txdr_unsigned(slotpos);
4594 *tl++ = txdr_unsigned(maxslot);
4595 if (dont_replycache == 0)
4601 * There are two errors and the rest of the session can
4603 * NFSERR_BADSESSION: This bad session should just generate
4604 * the same error again when the RPC is retried.
4605 * ESTALE: A forced dismount is in progress and will cause the
4606 * RPC to fail later.
4613 nd->nd_flag |= ND_HASSEQUENCE;
4617 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4618 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4620 int i, maxslot, slotpos;
4623 /* Find an unused slot. */
4626 mtx_lock(&sep->nfsess_mtx);
4628 if (nmp != NULL && sep->nfsess_defunct != 0) {
4629 /* Just return the bad session. */
4630 bcopy(sep->nfsess_sessionid, sessionid,
4632 mtx_unlock(&sep->nfsess_mtx);
4633 return (NFSERR_BADSESSION);
4636 for (i = 0; i < sep->nfsess_foreslots; i++) {
4637 if ((bitval & sep->nfsess_slots) == 0) {
4639 sep->nfsess_slots |= bitval;
4640 sep->nfsess_slotseq[i]++;
4641 *slotseqp = sep->nfsess_slotseq[i];
4646 if (slotpos == -1) {
4648 * If a forced dismount is in progress, just return.
4649 * This RPC attempt will fail when it calls
4652 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4653 mtx_unlock(&sep->nfsess_mtx);
4656 /* Wake up once/sec, to check for a forced dismount. */
4657 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4658 PZERO, "nfsclseq", hz);
4660 } while (slotpos == -1);
4661 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4663 for (i = 0; i < 64; i++) {
4664 if ((bitval & sep->nfsess_slots) != 0)
4668 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4669 mtx_unlock(&sep->nfsess_mtx);
4670 *slotposp = slotpos;
4671 *maxslotp = maxslot;
4676 * Free a session slot.
4679 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4686 mtx_lock(&sep->nfsess_mtx);
4687 if ((bitval & sep->nfsess_slots) == 0)
4688 printf("freeing free slot!!\n");
4689 sep->nfsess_slots &= ~bitval;
4690 wakeup(&sep->nfsess_slots);
4691 mtx_unlock(&sep->nfsess_mtx);
4695 * Search for a matching pnfsd DS, based on the nmp arg.
4696 * Return one if found, NULL otherwise.
4699 nfsv4_findmirror(struct nfsmount *nmp)
4701 struct nfsdevice *ds;
4703 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4705 * Search the DS server list for a match with nmp.
4707 if (nfsrv_devidcnt == 0)
4709 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4710 if (ds->nfsdev_nmp == nmp) {
4711 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");