1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD: stable/12/sys/fs/nfs/nfs_commonsubs.c 372730 2022-11-11 04:36:35Z gbe $");
38
39 /*
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.
43 */
44 #include "opt_inet.h"
45 #include "opt_inet6.h"
46
47 #include <fs/nfs/nfsport.h>
48
49 #include <security/mac/mac_framework.h>
50
51 /*
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
54 */
55 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
56
57 /* And other global data */
58 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
59 NFFIFO, NFNON };
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 */
63 int nfscl_ticks;
64 int nfsrv_useacl = 1;
65 struct nfssockreq nfsrv_nfsuserdsock;
66 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
67 static int nfsrv_userdupcalls = 0;
68 struct nfsreqhead nfsd_reqq;
69 uid_t nfsrv_defaultuid = UID_NOBODY;
70 gid_t nfsrv_defaultgid = GID_NOGROUP;
71 int nfsrv_lease = NFSRV_LEASE;
72 int ncl_mbuf_mlen = MLEN;
73 int nfsd_enable_stringtouid = 0;
74 int nfsrv_doflexfile = 0;
75 static int nfs_enable_uidtostring = 0;
76 NFSNAMEIDMUTEX;
77 NFSSOCKMUTEX;
78 extern int nfsrv_lughashsize;
79 extern struct mtx nfsrv_dslock_mtx;
80 extern volatile int nfsrv_devidcnt;
81 extern int nfscl_debuglevel;
82 extern struct nfsdevicehead nfsrv_devidhead;
83 extern struct nfsstatsv1 nfsstatsv1;
84
85 SYSCTL_DECL(_vfs_nfs);
86 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
87 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
88
89 int nfsrv_maxpnfsmirror = 1;
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
91 &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
92
93 /*
94 * This array of structures indicates, for V4:
95 * retfh - which of 3 types of calling args are used
96 * 0 - doesn't change cfh or use a sfh
97 * 1 - replaces cfh with a new one (unless it returns an error status)
98 * 2 - uses cfh and sfh
99 * needscfh - if the op wants a cfh and premtime
100 * 0 - doesn't use a cfh
101 * 1 - uses a cfh, but doesn't want pre-op attributes
102 * 2 - uses a cfh and wants pre-op attributes
103 * savereply - indicates a non-idempotent Op
104 * 0 - not non-idempotent
105 * 1 - non-idempotent
106 * Ops that are ordered via seqid# are handled separately from these
107 * non-idempotent Ops.
108 * Define it here, since it is used by both the client and server.
109 */
110 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
111 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
112 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
113 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
114 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
115 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
116 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
117 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
118 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
119 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
124 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
126 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
127 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
128 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
129 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
130 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
133 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
134 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
135 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
136 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
137 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
138 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
139 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
140 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
145 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
149 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
160 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
161 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
162 { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
163 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
164 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
165 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
166 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
167 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
168 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
169 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
170 };
171
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 {
178 struct mtx mtx;
179 struct nfsuserhashhead lughead;
180 };
181 static struct nfsrv_lughash *nfsuserhash;
182 static struct nfsrv_lughash *nfsusernamehash;
183 static struct nfsrv_lughash *nfsgrouphash;
184 static struct nfsrv_lughash *nfsgroupnamehash;
185
186 /*
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
191 * efficiently.)
192 */
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, 0 };
196
197 /* local functions */
198 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
199 static void nfsv4_wanted(struct nfsv4lock *lp);
200 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
201 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
202 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
203 NFSPROC_T *p);
204 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
205 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
206 int *, int *);
207 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
208
209 static struct {
210 int op;
211 int opcnt;
212 const u_char *tag;
213 int taglen;
214 } nfsv4_opmap[NFSV41_NPROCS] = {
215 { 0, 1, "Null", 4 },
216 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
217 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
218 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
219 { NFSV4OP_ACCESS, 2, "Access", 6, },
220 { NFSV4OP_READLINK, 2, "Readlink", 8, },
221 { NFSV4OP_READ, 1, "Read", 4, },
222 { NFSV4OP_WRITE, 2, "Write", 5, },
223 { NFSV4OP_OPEN, 5, "Open", 4, },
224 { NFSV4OP_CREATE, 5, "Create", 6, },
225 { NFSV4OP_CREATE, 1, "Create", 6, },
226 { NFSV4OP_CREATE, 3, "Create", 6, },
227 { NFSV4OP_REMOVE, 1, "Remove", 6, },
228 { NFSV4OP_REMOVE, 1, "Remove", 6, },
229 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
230 { NFSV4OP_SAVEFH, 4, "Link", 4, },
231 { NFSV4OP_READDIR, 2, "Readdir", 7, },
232 { NFSV4OP_READDIR, 2, "Readdir", 7, },
233 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
234 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
235 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
236 { NFSV4OP_COMMIT, 2, "Commit", 6, },
237 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
238 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
239 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
240 { NFSV4OP_LOCK, 1, "Lock", 4, },
241 { NFSV4OP_LOCKU, 1, "LockU", 5, },
242 { NFSV4OP_OPEN, 2, "Open", 4, },
243 { NFSV4OP_CLOSE, 1, "Close", 5, },
244 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
245 { NFSV4OP_LOCKT, 1, "LockT", 5, },
246 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
247 { NFSV4OP_RENEW, 1, "Renew", 5, },
248 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
249 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
250 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
251 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
252 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
253 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
254 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
255 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
256 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
257 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
258 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
259 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
260 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
261 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
262 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
263 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
264 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
265 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
266 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
267 { NFSV4OP_READ, 1, "ReadDS", 6, },
268 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
269 { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
270 { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
271 { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, },
272 };
273
274 /*
275 * NFS RPCS that have large request message size.
276 */
277 static int nfs_bigrequest[NFSV41_NPROCS] = {
278 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
281 };
282
283 /*
284 * Start building a request. Mostly just put the first file handle in
285 * place.
286 */
287 void
nfscl_reqstart(struct nfsrv_descript * nd,int procnum,struct nfsmount * nmp,u_int8_t * nfhp,int fhlen,u_int32_t ** opcntpp,struct nfsclsession * sep,int vers,int minorvers)288 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
289 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
290 int vers, int minorvers)
291 {
292 struct mbuf *mb;
293 u_int32_t *tl;
294 int opcnt;
295 nfsattrbit_t attrbits;
296
297 /*
298 * First, fill in some of the fields of nd.
299 */
300 nd->nd_slotseq = NULL;
301 if (vers == NFS_VER4) {
302 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
303 if (minorvers == NFSV41_MINORVERSION)
304 nd->nd_flag |= ND_NFSV41;
305 } else if (vers == NFS_VER3)
306 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
307 else {
308 if (NFSHASNFSV4(nmp)) {
309 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
310 if (NFSHASNFSV4N(nmp))
311 nd->nd_flag |= ND_NFSV41;
312 } else if (NFSHASNFSV3(nmp))
313 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
314 else
315 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
316 }
317 nd->nd_procnum = procnum;
318 nd->nd_repstat = 0;
319
320 /*
321 * Get the first mbuf for the request.
322 */
323 if (nfs_bigrequest[procnum])
324 NFSMCLGET(mb, M_WAITOK);
325 else
326 NFSMGET(mb);
327 mbuf_setlen(mb, 0);
328 nd->nd_mreq = nd->nd_mb = mb;
329 nd->nd_bpos = NFSMTOD(mb, caddr_t);
330
331 /*
332 * And fill the first file handle into the request.
333 */
334 if (nd->nd_flag & ND_NFSV4) {
335 opcnt = nfsv4_opmap[procnum].opcnt +
336 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
337 if ((nd->nd_flag & ND_NFSV41) != 0) {
338 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
339 if (procnum == NFSPROC_RENEW)
340 /*
341 * For the special case of Renew, just do a
342 * Sequence Op.
343 */
344 opcnt = 1;
345 else if (procnum == NFSPROC_WRITEDS ||
346 procnum == NFSPROC_COMMITDS)
347 /*
348 * For the special case of a Writeor Commit to
349 * a DS, the opcnt == 3, for Sequence, PutFH,
350 * Write/Commit.
351 */
352 opcnt = 3;
353 }
354 /*
355 * What should the tag really be?
356 */
357 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
358 nfsv4_opmap[procnum].taglen);
359 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
360 if ((nd->nd_flag & ND_NFSV41) != 0)
361 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
362 else
363 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
364 if (opcntpp != NULL)
365 *opcntpp = tl;
366 *tl = txdr_unsigned(opcnt);
367 if ((nd->nd_flag & ND_NFSV41) != 0 &&
368 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
369 if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
370 0)
371 nd->nd_flag |= ND_LOOPBADSESS;
372 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
373 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
374 if (sep == NULL) {
375 sep = nfsmnt_mdssession(nmp);
376 nfsv4_setsequence(nmp, nd, sep,
377 nfs_bigreply[procnum]);
378 } else
379 nfsv4_setsequence(nmp, nd, sep,
380 nfs_bigreply[procnum]);
381 }
382 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
383 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
384 *tl = txdr_unsigned(NFSV4OP_PUTFH);
385 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
386 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
387 == 2 && procnum != NFSPROC_WRITEDS &&
388 procnum != NFSPROC_COMMITDS) {
389 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
390 *tl = txdr_unsigned(NFSV4OP_GETATTR);
391 /*
392 * For Lookup Ops, we want all the directory
393 * attributes, so we can load the name cache.
394 */
395 if (procnum == NFSPROC_LOOKUP ||
396 procnum == NFSPROC_LOOKUPP)
397 NFSGETATTR_ATTRBIT(&attrbits);
398 else {
399 NFSWCCATTR_ATTRBIT(&attrbits);
400 nd->nd_flag |= ND_V4WCCATTR;
401 }
402 (void) nfsrv_putattrbit(nd, &attrbits);
403 }
404 }
405 if (procnum != NFSPROC_RENEW ||
406 (nd->nd_flag & ND_NFSV41) == 0) {
407 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
408 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
409 }
410 } else {
411 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
412 }
413 if (procnum < NFSV41_NPROCS)
414 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
415 }
416
417 /*
418 * Put a state Id in the mbuf list.
419 */
420 void
nfsm_stateidtom(struct nfsrv_descript * nd,nfsv4stateid_t * stateidp,int flag)421 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
422 {
423 nfsv4stateid_t *st;
424
425 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
426 if (flag == NFSSTATEID_PUTALLZERO) {
427 st->seqid = 0;
428 st->other[0] = 0;
429 st->other[1] = 0;
430 st->other[2] = 0;
431 } else if (flag == NFSSTATEID_PUTALLONE) {
432 st->seqid = 0xffffffff;
433 st->other[0] = 0xffffffff;
434 st->other[1] = 0xffffffff;
435 st->other[2] = 0xffffffff;
436 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
437 st->seqid = 0;
438 st->other[0] = stateidp->other[0];
439 st->other[1] = stateidp->other[1];
440 st->other[2] = stateidp->other[2];
441 } else {
442 st->seqid = stateidp->seqid;
443 st->other[0] = stateidp->other[0];
444 st->other[1] = stateidp->other[1];
445 st->other[2] = stateidp->other[2];
446 }
447 }
448
449 /*
450 * Fill in the setable attributes. The full argument indicates whether
451 * to fill in them all or just mode and time.
452 */
453 void
nfscl_fillsattr(struct nfsrv_descript * nd,struct vattr * vap,struct vnode * vp,int flags,u_int32_t rdev)454 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
455 struct vnode *vp, int flags, u_int32_t rdev)
456 {
457 u_int32_t *tl;
458 struct nfsv2_sattr *sp;
459 nfsattrbit_t attrbits;
460
461 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
462 case ND_NFSV2:
463 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
464 if (vap->va_mode == (mode_t)VNOVAL)
465 sp->sa_mode = newnfs_xdrneg1;
466 else
467 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
468 if (vap->va_uid == (uid_t)VNOVAL)
469 sp->sa_uid = newnfs_xdrneg1;
470 else
471 sp->sa_uid = txdr_unsigned(vap->va_uid);
472 if (vap->va_gid == (gid_t)VNOVAL)
473 sp->sa_gid = newnfs_xdrneg1;
474 else
475 sp->sa_gid = txdr_unsigned(vap->va_gid);
476 if (flags & NFSSATTR_SIZE0)
477 sp->sa_size = 0;
478 else if (flags & NFSSATTR_SIZENEG1)
479 sp->sa_size = newnfs_xdrneg1;
480 else if (flags & NFSSATTR_SIZERDEV)
481 sp->sa_size = txdr_unsigned(rdev);
482 else
483 sp->sa_size = txdr_unsigned(vap->va_size);
484 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
485 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
486 break;
487 case ND_NFSV3:
488 if (vap->va_mode != (mode_t)VNOVAL) {
489 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
490 *tl++ = newnfs_true;
491 *tl = txdr_unsigned(vap->va_mode);
492 } else {
493 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
494 *tl = newnfs_false;
495 }
496 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
497 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
498 *tl++ = newnfs_true;
499 *tl = txdr_unsigned(vap->va_uid);
500 } else {
501 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
502 *tl = newnfs_false;
503 }
504 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
505 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
506 *tl++ = newnfs_true;
507 *tl = txdr_unsigned(vap->va_gid);
508 } else {
509 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
510 *tl = newnfs_false;
511 }
512 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
513 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
514 *tl++ = newnfs_true;
515 txdr_hyper(vap->va_size, tl);
516 } else {
517 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
518 *tl = newnfs_false;
519 }
520 if (vap->va_atime.tv_sec != VNOVAL) {
521 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
522 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
523 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
524 txdr_nfsv3time(&vap->va_atime, tl);
525 } else {
526 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
527 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
528 }
529 } else {
530 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
531 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
532 }
533 if (vap->va_mtime.tv_sec != VNOVAL) {
534 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
535 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
536 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
537 txdr_nfsv3time(&vap->va_mtime, tl);
538 } else {
539 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
540 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
541 }
542 } else {
543 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
544 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
545 }
546 break;
547 case ND_NFSV4:
548 NFSZERO_ATTRBIT(&attrbits);
549 if (vap->va_mode != (mode_t)VNOVAL)
550 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
551 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
552 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
553 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
554 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
555 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
556 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
557 if (vap->va_atime.tv_sec != VNOVAL)
558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
559 if (vap->va_mtime.tv_sec != VNOVAL)
560 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
561 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
562 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
563 break;
564 }
565 }
566
567 #ifndef APPLE
568 /*
569 * copies mbuf chain to the uio scatter/gather list
570 */
571 int
nfsm_mbufuio(struct nfsrv_descript * nd,struct uio * uiop,int siz)572 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
573 {
574 char *mbufcp, *uiocp;
575 int xfer, left, len;
576 mbuf_t mp;
577 long uiosiz, rem;
578 int error = 0;
579
580 mp = nd->nd_md;
581 mbufcp = nd->nd_dpos;
582 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
583 rem = NFSM_RNDUP(siz) - siz;
584 while (siz > 0) {
585 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
586 error = EBADRPC;
587 goto out;
588 }
589 left = uiop->uio_iov->iov_len;
590 uiocp = uiop->uio_iov->iov_base;
591 if (left > siz)
592 left = siz;
593 uiosiz = left;
594 while (left > 0) {
595 while (len == 0) {
596 mp = mbuf_next(mp);
597 if (mp == NULL) {
598 error = EBADRPC;
599 goto out;
600 }
601 mbufcp = NFSMTOD(mp, caddr_t);
602 len = mbuf_len(mp);
603 KASSERT(len >= 0,
604 ("len %d, corrupted mbuf?", len));
605 }
606 xfer = (left > len) ? len : left;
607 #ifdef notdef
608 /* Not Yet.. */
609 if (uiop->uio_iov->iov_op != NULL)
610 (*(uiop->uio_iov->iov_op))
611 (mbufcp, uiocp, xfer);
612 else
613 #endif
614 if (uiop->uio_segflg == UIO_SYSSPACE)
615 NFSBCOPY(mbufcp, uiocp, xfer);
616 else
617 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
618 left -= xfer;
619 len -= xfer;
620 mbufcp += xfer;
621 uiocp += xfer;
622 uiop->uio_offset += xfer;
623 uiop->uio_resid -= xfer;
624 }
625 if (uiop->uio_iov->iov_len <= siz) {
626 uiop->uio_iovcnt--;
627 uiop->uio_iov++;
628 } else {
629 uiop->uio_iov->iov_base = (void *)
630 ((char *)uiop->uio_iov->iov_base + uiosiz);
631 uiop->uio_iov->iov_len -= uiosiz;
632 }
633 siz -= uiosiz;
634 }
635 nd->nd_dpos = mbufcp;
636 nd->nd_md = mp;
637 if (rem > 0) {
638 if (len < rem)
639 error = nfsm_advance(nd, rem, len);
640 else
641 nd->nd_dpos += rem;
642 }
643
644 out:
645 NFSEXITCODE2(error, nd);
646 return (error);
647 }
648 #endif /* !APPLE */
649
650 /*
651 * Help break down an mbuf chain by setting the first siz bytes contiguous
652 * pointed to by returned val.
653 * This is used by the macro NFSM_DISSECT for tough
654 * cases.
655 */
656 void *
nfsm_dissct(struct nfsrv_descript * nd,int siz,int how)657 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
658 {
659 mbuf_t mp2;
660 int siz2, xfer;
661 caddr_t p;
662 int left;
663 caddr_t retp;
664
665 retp = NULL;
666 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
667 while (left == 0) {
668 nd->nd_md = mbuf_next(nd->nd_md);
669 if (nd->nd_md == NULL)
670 return (retp);
671 left = mbuf_len(nd->nd_md);
672 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
673 }
674 if (left >= siz) {
675 retp = nd->nd_dpos;
676 nd->nd_dpos += siz;
677 } else if (mbuf_next(nd->nd_md) == NULL) {
678 return (retp);
679 } else if (siz > ncl_mbuf_mhlen) {
680 panic("nfs S too big");
681 } else {
682 MGET(mp2, how, MT_DATA);
683 if (mp2 == NULL)
684 return (NULL);
685 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
686 mbuf_setnext(nd->nd_md, mp2);
687 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
688 nd->nd_md = mp2;
689 retp = p = NFSMTOD(mp2, caddr_t);
690 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
691 siz2 = siz - left;
692 p += left;
693 mp2 = mbuf_next(mp2);
694 /* Loop around copying up the siz2 bytes */
695 while (siz2 > 0) {
696 if (mp2 == NULL)
697 return (NULL);
698 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
699 if (xfer > 0) {
700 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
701 NFSM_DATAP(mp2, xfer);
702 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
703 p += xfer;
704 siz2 -= xfer;
705 }
706 if (siz2 > 0)
707 mp2 = mbuf_next(mp2);
708 }
709 mbuf_setlen(nd->nd_md, siz);
710 nd->nd_md = mp2;
711 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
712 }
713 return (retp);
714 }
715
716 /*
717 * Advance the position in the mbuf chain.
718 * If offs == 0, this is a no-op, but it is simpler to just return from
719 * here than check for offs > 0 for all calls to nfsm_advance.
720 * If left == -1, it should be calculated here.
721 */
722 int
nfsm_advance(struct nfsrv_descript * nd,int offs,int left)723 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
724 {
725 int error = 0;
726
727 if (offs == 0)
728 goto out;
729 /*
730 * A negative offs might indicate a corrupted mbuf chain and,
731 * as such, a printf is logged.
732 */
733 if (offs < 0) {
734 printf("nfsrv_advance: negative offs\n");
735 error = EBADRPC;
736 goto out;
737 }
738
739 /*
740 * If left == -1, calculate it here.
741 */
742 if (left == -1)
743 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
744 nd->nd_dpos;
745
746 /*
747 * Loop around, advancing over the mbuf data.
748 */
749 while (offs > left) {
750 offs -= left;
751 nd->nd_md = mbuf_next(nd->nd_md);
752 if (nd->nd_md == NULL) {
753 error = EBADRPC;
754 goto out;
755 }
756 left = mbuf_len(nd->nd_md);
757 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
758 }
759 nd->nd_dpos += offs;
760
761 out:
762 NFSEXITCODE(error);
763 return (error);
764 }
765
766 /*
767 * Copy a string into mbuf(s).
768 * Return the number of bytes output, including XDR overheads.
769 */
770 int
nfsm_strtom(struct nfsrv_descript * nd,const char * cp,int siz)771 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
772 {
773 mbuf_t m2;
774 int xfer, left;
775 mbuf_t m1;
776 int rem, bytesize;
777 u_int32_t *tl;
778 char *cp2;
779
780 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
781 *tl = txdr_unsigned(siz);
782 rem = NFSM_RNDUP(siz) - siz;
783 bytesize = NFSX_UNSIGNED + siz + rem;
784 m2 = nd->nd_mb;
785 cp2 = nd->nd_bpos;
786 left = M_TRAILINGSPACE(m2);
787
788 /*
789 * Loop around copying the string to mbuf(s).
790 */
791 while (siz > 0) {
792 if (left == 0) {
793 if (siz > ncl_mbuf_mlen)
794 NFSMCLGET(m1, M_WAITOK);
795 else
796 NFSMGET(m1);
797 mbuf_setlen(m1, 0);
798 mbuf_setnext(m2, m1);
799 m2 = m1;
800 cp2 = NFSMTOD(m2, caddr_t);
801 left = M_TRAILINGSPACE(m2);
802 }
803 if (left >= siz)
804 xfer = siz;
805 else
806 xfer = left;
807 NFSBCOPY(cp, cp2, xfer);
808 cp += xfer;
809 mbuf_setlen(m2, mbuf_len(m2) + xfer);
810 siz -= xfer;
811 left -= xfer;
812 if (siz == 0 && rem) {
813 if (left < rem)
814 panic("nfsm_strtom");
815 NFSBZERO(cp2 + xfer, rem);
816 mbuf_setlen(m2, mbuf_len(m2) + rem);
817 }
818 }
819 nd->nd_mb = m2;
820 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
821 return (bytesize);
822 }
823
824 /*
825 * Called once to initialize data structures...
826 */
827 void
newnfs_init(void)828 newnfs_init(void)
829 {
830 static int nfs_inited = 0;
831
832 if (nfs_inited)
833 return;
834 nfs_inited = 1;
835
836 newnfs_true = txdr_unsigned(TRUE);
837 newnfs_false = txdr_unsigned(FALSE);
838 newnfs_xdrneg1 = txdr_unsigned(-1);
839 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
840 if (nfscl_ticks < 1)
841 nfscl_ticks = 1;
842 NFSSETBOOTTIME(nfsboottime);
843
844 /*
845 * Initialize reply list and start timer
846 */
847 TAILQ_INIT(&nfsd_reqq);
848 NFS_TIMERINIT;
849 }
850
851 /*
852 * Put a file handle in an mbuf list.
853 * If the size argument == 0, just use the default size.
854 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
855 * Return the number of bytes output, including XDR overhead.
856 */
857 int
nfsm_fhtom(struct nfsrv_descript * nd,u_int8_t * fhp,int size,int set_true)858 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
859 {
860 u_int32_t *tl;
861 u_int8_t *cp;
862 int fullsiz, rem, bytesize = 0;
863
864 if (size == 0)
865 size = NFSX_MYFH;
866 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
867 case ND_NFSV2:
868 if (size > NFSX_V2FH)
869 panic("fh size > NFSX_V2FH for NFSv2");
870 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
871 NFSBCOPY(fhp, cp, size);
872 if (size < NFSX_V2FH)
873 NFSBZERO(cp + size, NFSX_V2FH - size);
874 bytesize = NFSX_V2FH;
875 break;
876 case ND_NFSV3:
877 case ND_NFSV4:
878 fullsiz = NFSM_RNDUP(size);
879 rem = fullsiz - size;
880 if (set_true) {
881 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
882 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
883 *tl = newnfs_true;
884 } else {
885 bytesize = NFSX_UNSIGNED + fullsiz;
886 }
887 (void) nfsm_strtom(nd, fhp, size);
888 break;
889 }
890 return (bytesize);
891 }
892
893 /*
894 * This function compares two net addresses by family and returns TRUE
895 * if they are the same host.
896 * If there is any doubt, return FALSE.
897 * The AF_INET family is handled as a special case so that address mbufs
898 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
899 */
900 int
nfsaddr_match(int family,union nethostaddr * haddr,NFSSOCKADDR_T nam)901 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
902 {
903 struct sockaddr_in *inetaddr;
904
905 switch (family) {
906 case AF_INET:
907 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
908 if (inetaddr->sin_family == AF_INET &&
909 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
910 return (1);
911 break;
912 #ifdef INET6
913 case AF_INET6:
914 {
915 struct sockaddr_in6 *inetaddr6;
916
917 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
918 /* XXX - should test sin6_scope_id ? */
919 if (inetaddr6->sin6_family == AF_INET6 &&
920 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
921 &haddr->had_inet6))
922 return (1);
923 }
924 break;
925 #endif
926 }
927 return (0);
928 }
929
930 /*
931 * Similar to the above, but takes to NFSSOCKADDR_T args.
932 */
933 int
nfsaddr2_match(NFSSOCKADDR_T nam1,NFSSOCKADDR_T nam2)934 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
935 {
936 struct sockaddr_in *addr1, *addr2;
937 struct sockaddr *inaddr;
938
939 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
940 switch (inaddr->sa_family) {
941 case AF_INET:
942 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
943 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
944 if (addr2->sin_family == AF_INET &&
945 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
946 return (1);
947 break;
948 #ifdef INET6
949 case AF_INET6:
950 {
951 struct sockaddr_in6 *inet6addr1, *inet6addr2;
952
953 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
954 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
955 /* XXX - should test sin6_scope_id ? */
956 if (inet6addr2->sin6_family == AF_INET6 &&
957 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
958 &inet6addr2->sin6_addr))
959 return (1);
960 }
961 break;
962 #endif
963 }
964 return (0);
965 }
966
967
968 /*
969 * Trim the stuff already dissected off the mbuf list.
970 */
971 void
newnfs_trimleading(nd)972 newnfs_trimleading(nd)
973 struct nfsrv_descript *nd;
974 {
975 mbuf_t m, n;
976 int offs;
977
978 /*
979 * First, free up leading mbufs.
980 */
981 if (nd->nd_mrep != nd->nd_md) {
982 m = nd->nd_mrep;
983 while (mbuf_next(m) != nd->nd_md) {
984 if (mbuf_next(m) == NULL)
985 panic("nfsm trim leading");
986 m = mbuf_next(m);
987 }
988 mbuf_setnext(m, NULL);
989 mbuf_freem(nd->nd_mrep);
990 }
991 m = nd->nd_md;
992
993 /*
994 * Now, adjust this mbuf, based on nd_dpos.
995 */
996 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
997 if (offs == mbuf_len(m)) {
998 n = m;
999 m = mbuf_next(m);
1000 if (m == NULL)
1001 panic("nfsm trim leading2");
1002 mbuf_setnext(n, NULL);
1003 mbuf_freem(n);
1004 } else if (offs > 0) {
1005 mbuf_setlen(m, mbuf_len(m) - offs);
1006 NFSM_DATAP(m, offs);
1007 } else if (offs < 0)
1008 panic("nfsm trimleading offs");
1009 nd->nd_mrep = m;
1010 nd->nd_md = m;
1011 nd->nd_dpos = NFSMTOD(m, caddr_t);
1012 }
1013
1014 /*
1015 * Trim trailing data off the mbuf list being built.
1016 */
1017 void
newnfs_trimtrailing(nd,mb,bpos)1018 newnfs_trimtrailing(nd, mb, bpos)
1019 struct nfsrv_descript *nd;
1020 mbuf_t mb;
1021 caddr_t bpos;
1022 {
1023
1024 if (mbuf_next(mb)) {
1025 mbuf_freem(mbuf_next(mb));
1026 mbuf_setnext(mb, NULL);
1027 }
1028 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1029 nd->nd_mb = mb;
1030 nd->nd_bpos = bpos;
1031 }
1032
1033 /*
1034 * Dissect a file handle on the client.
1035 */
1036 int
nfsm_getfh(struct nfsrv_descript * nd,struct nfsfh ** nfhpp)1037 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1038 {
1039 u_int32_t *tl;
1040 struct nfsfh *nfhp;
1041 int error, len;
1042
1043 *nfhpp = NULL;
1044 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1045 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1046 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1047 len > NFSX_FHMAX) {
1048 error = EBADRPC;
1049 goto nfsmout;
1050 }
1051 } else
1052 len = NFSX_V2FH;
1053 nfhp = malloc(sizeof (struct nfsfh) + len,
1054 M_NFSFH, M_WAITOK);
1055 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1056 if (error) {
1057 free(nfhp, M_NFSFH);
1058 goto nfsmout;
1059 }
1060 nfhp->nfh_len = len;
1061 *nfhpp = nfhp;
1062 nfsmout:
1063 NFSEXITCODE2(error, nd);
1064 return (error);
1065 }
1066
1067 /*
1068 * Break down the nfsv4 acl.
1069 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1070 */
1071 int
nfsrv_dissectacl(struct nfsrv_descript * nd,NFSACL_T * aclp,int * aclerrp,int * aclsizep,__unused NFSPROC_T * p)1072 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1073 int *aclsizep, __unused NFSPROC_T *p)
1074 {
1075 u_int32_t *tl;
1076 int i, aclsize;
1077 int acecnt, error = 0, aceerr = 0, acesize;
1078
1079 *aclerrp = 0;
1080 if (aclp)
1081 aclp->acl_cnt = 0;
1082 /*
1083 * Parse out the ace entries and expect them to conform to
1084 * what can be supported by R/W/X bits.
1085 */
1086 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1087 aclsize = NFSX_UNSIGNED;
1088 acecnt = fxdr_unsigned(int, *tl);
1089 /*
1090 * The RFCs do not define a fixed limit to the number of ACEs in
1091 * an ACL, but 10240 should be more than sufficient.
1092 */
1093 if (acecnt < 0 || acecnt > 10240) {
1094 error = NFSERR_BADXDR;
1095 goto nfsmout;
1096 }
1097 if (acecnt > ACL_MAX_ENTRIES)
1098 aceerr = NFSERR_ATTRNOTSUPP;
1099 if (nfsrv_useacl == 0)
1100 aceerr = NFSERR_ATTRNOTSUPP;
1101 for (i = 0; i < acecnt; i++) {
1102 if (aclp && !aceerr)
1103 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1104 &aceerr, &acesize, p);
1105 else
1106 error = nfsrv_skipace(nd, &acesize);
1107 if (error)
1108 goto nfsmout;
1109 aclsize += acesize;
1110 }
1111 if (aclp && !aceerr)
1112 aclp->acl_cnt = acecnt;
1113 if (aceerr)
1114 *aclerrp = aceerr;
1115 if (aclsizep)
1116 *aclsizep = aclsize;
1117 nfsmout:
1118 NFSEXITCODE2(error, nd);
1119 return (error);
1120 }
1121
1122 /*
1123 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1124 */
1125 static int
nfsrv_skipace(struct nfsrv_descript * nd,int * acesizep)1126 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1127 {
1128 u_int32_t *tl;
1129 int error, len = 0;
1130
1131 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1132 len = fxdr_unsigned(int, *(tl + 3));
1133 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1134 nfsmout:
1135 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1136 NFSEXITCODE2(error, nd);
1137 return (error);
1138 }
1139
1140 /*
1141 * Get attribute bits from an mbuf list.
1142 * Returns EBADRPC for a parsing error, 0 otherwise.
1143 * If the clearinvalid flag is set, clear the bits not supported.
1144 */
1145 int
nfsrv_getattrbits(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp,int * cntp,int * retnotsupp)1146 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1147 int *retnotsupp)
1148 {
1149 u_int32_t *tl;
1150 int cnt, i, outcnt;
1151 int error = 0;
1152
1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1154 cnt = fxdr_unsigned(int, *tl);
1155 if (cnt < 0) {
1156 error = NFSERR_BADXDR;
1157 goto nfsmout;
1158 }
1159 if (cnt > NFSATTRBIT_MAXWORDS)
1160 outcnt = NFSATTRBIT_MAXWORDS;
1161 else
1162 outcnt = cnt;
1163 NFSZERO_ATTRBIT(attrbitp);
1164 if (outcnt > 0) {
1165 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1166 for (i = 0; i < outcnt; i++)
1167 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1168 }
1169 for (i = 0; i < (cnt - outcnt); i++) {
1170 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1171 if (retnotsupp != NULL && *tl != 0)
1172 *retnotsupp = NFSERR_ATTRNOTSUPP;
1173 }
1174 if (cntp)
1175 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1176 nfsmout:
1177 NFSEXITCODE2(error, nd);
1178 return (error);
1179 }
1180
1181 /*
1182 * Get the attributes for V4.
1183 * If the compare flag is true, test for any attribute changes,
1184 * otherwise return the attribute values.
1185 * These attributes cover fields in "struct vattr", "struct statfs",
1186 * "struct nfsfsinfo", the file handle and the lease duration.
1187 * The value of retcmpp is set to 1 if all attributes are the same,
1188 * and 0 otherwise.
1189 * Returns EBADRPC if it can't be parsed, 0 otherwise.
1190 */
1191 int
nfsv4_loadattr(struct nfsrv_descript * nd,vnode_t vp,struct nfsvattr * nap,struct nfsfh ** nfhpp,fhandle_t * fhp,int fhsize,struct nfsv3_pathconf * pc,struct statfs * sbp,struct nfsstatfs * sfp,struct nfsfsinfo * fsp,NFSACL_T * aclp,int compare,int * retcmpp,u_int32_t * leasep,u_int32_t * rderrp,NFSPROC_T * p,struct ucred * cred)1192 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1193 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1194 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1195 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1196 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1197 {
1198 u_int32_t *tl;
1199 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1200 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1201 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1202 nfsattrbit_t attrbits, retattrbits, checkattrbits;
1203 struct nfsfh *tnfhp;
1204 struct nfsreferral *refp;
1205 u_quad_t tquad;
1206 nfsquad_t tnfsquad;
1207 struct timespec temptime;
1208 uid_t uid;
1209 gid_t gid;
1210 u_int32_t freenum = 0, tuint;
1211 u_int64_t uquad = 0, thyp, thyp2;
1212 #ifdef QUOTA
1213 struct dqblk dqb;
1214 uid_t savuid;
1215 #endif
1216
1217 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1218 if (compare) {
1219 retnotsup = 0;
1220 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1221 } else {
1222 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1223 }
1224 if (error)
1225 goto nfsmout;
1226
1227 if (compare) {
1228 *retcmpp = retnotsup;
1229 } else {
1230 /*
1231 * Just set default values to some of the important ones.
1232 */
1233 if (nap != NULL) {
1234 nap->na_type = VREG;
1235 nap->na_mode = 0;
1236 nap->na_rdev = (NFSDEV_T)0;
1237 nap->na_mtime.tv_sec = 0;
1238 nap->na_mtime.tv_nsec = 0;
1239 nap->na_gen = 0;
1240 nap->na_flags = 0;
1241 nap->na_blocksize = NFS_FABLKSIZE;
1242 }
1243 if (sbp != NULL) {
1244 sbp->f_bsize = NFS_FABLKSIZE;
1245 sbp->f_blocks = 0;
1246 sbp->f_bfree = 0;
1247 sbp->f_bavail = 0;
1248 sbp->f_files = 0;
1249 sbp->f_ffree = 0;
1250 }
1251 if (fsp != NULL) {
1252 fsp->fs_rtmax = 8192;
1253 fsp->fs_rtpref = 8192;
1254 fsp->fs_maxname = NFS_MAXNAMLEN;
1255 fsp->fs_wtmax = 8192;
1256 fsp->fs_wtpref = 8192;
1257 fsp->fs_wtmult = NFS_FABLKSIZE;
1258 fsp->fs_dtpref = 8192;
1259 fsp->fs_maxfilesize = 0xffffffffffffffffull;
1260 fsp->fs_timedelta.tv_sec = 0;
1261 fsp->fs_timedelta.tv_nsec = 1;
1262 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1263 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1264 }
1265 if (pc != NULL) {
1266 pc->pc_linkmax = NFS_LINK_MAX;
1267 pc->pc_namemax = NAME_MAX;
1268 pc->pc_notrunc = 0;
1269 pc->pc_chownrestricted = 0;
1270 pc->pc_caseinsensitive = 0;
1271 pc->pc_casepreserving = 1;
1272 }
1273 if (sfp != NULL) {
1274 sfp->sf_ffiles = UINT64_MAX;
1275 sfp->sf_tfiles = UINT64_MAX;
1276 sfp->sf_afiles = UINT64_MAX;
1277 sfp->sf_fbytes = UINT64_MAX;
1278 sfp->sf_tbytes = UINT64_MAX;
1279 sfp->sf_abytes = UINT64_MAX;
1280 }
1281 }
1282
1283 /*
1284 * Loop around getting the attributes.
1285 */
1286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1287 attrsize = fxdr_unsigned(int, *tl);
1288 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1289 if (attrsum > attrsize) {
1290 error = NFSERR_BADXDR;
1291 goto nfsmout;
1292 }
1293 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1294 switch (bitpos) {
1295 case NFSATTRBIT_SUPPORTEDATTRS:
1296 retnotsup = 0;
1297 if (compare || nap == NULL)
1298 error = nfsrv_getattrbits(nd, &retattrbits,
1299 &cnt, &retnotsup);
1300 else
1301 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1302 &cnt, &retnotsup);
1303 if (error)
1304 goto nfsmout;
1305 if (compare && !(*retcmpp)) {
1306 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1307
1308 /* Some filesystem do not support NFSv4ACL */
1309 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1310 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1311 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1312 }
1313 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1314 || retnotsup)
1315 *retcmpp = NFSERR_NOTSAME;
1316 }
1317 attrsum += cnt;
1318 break;
1319 case NFSATTRBIT_TYPE:
1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1321 if (compare) {
1322 if (!(*retcmpp)) {
1323 if (nap->na_type != nfsv34tov_type(*tl))
1324 *retcmpp = NFSERR_NOTSAME;
1325 }
1326 } else if (nap != NULL) {
1327 nap->na_type = nfsv34tov_type(*tl);
1328 }
1329 attrsum += NFSX_UNSIGNED;
1330 break;
1331 case NFSATTRBIT_FHEXPIRETYPE:
1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1333 if (compare && !(*retcmpp)) {
1334 if (fxdr_unsigned(int, *tl) !=
1335 NFSV4FHTYPE_PERSISTENT)
1336 *retcmpp = NFSERR_NOTSAME;
1337 }
1338 attrsum += NFSX_UNSIGNED;
1339 break;
1340 case NFSATTRBIT_CHANGE:
1341 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1342 if (compare) {
1343 if (!(*retcmpp)) {
1344 if (nap->na_filerev != fxdr_hyper(tl))
1345 *retcmpp = NFSERR_NOTSAME;
1346 }
1347 } else if (nap != NULL) {
1348 nap->na_filerev = fxdr_hyper(tl);
1349 }
1350 attrsum += NFSX_HYPER;
1351 break;
1352 case NFSATTRBIT_SIZE:
1353 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1354 if (compare) {
1355 if (!(*retcmpp)) {
1356 if (nap->na_size != fxdr_hyper(tl))
1357 *retcmpp = NFSERR_NOTSAME;
1358 }
1359 } else if (nap != NULL) {
1360 nap->na_size = fxdr_hyper(tl);
1361 }
1362 attrsum += NFSX_HYPER;
1363 break;
1364 case NFSATTRBIT_LINKSUPPORT:
1365 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1366 if (compare) {
1367 if (!(*retcmpp)) {
1368 if (fsp->fs_properties & NFSV3_FSFLINK) {
1369 if (*tl == newnfs_false)
1370 *retcmpp = NFSERR_NOTSAME;
1371 } else {
1372 if (*tl == newnfs_true)
1373 *retcmpp = NFSERR_NOTSAME;
1374 }
1375 }
1376 } else if (fsp != NULL) {
1377 if (*tl == newnfs_true)
1378 fsp->fs_properties |= NFSV3_FSFLINK;
1379 else
1380 fsp->fs_properties &= ~NFSV3_FSFLINK;
1381 }
1382 attrsum += NFSX_UNSIGNED;
1383 break;
1384 case NFSATTRBIT_SYMLINKSUPPORT:
1385 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1386 if (compare) {
1387 if (!(*retcmpp)) {
1388 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1389 if (*tl == newnfs_false)
1390 *retcmpp = NFSERR_NOTSAME;
1391 } else {
1392 if (*tl == newnfs_true)
1393 *retcmpp = NFSERR_NOTSAME;
1394 }
1395 }
1396 } else if (fsp != NULL) {
1397 if (*tl == newnfs_true)
1398 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1399 else
1400 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1401 }
1402 attrsum += NFSX_UNSIGNED;
1403 break;
1404 case NFSATTRBIT_NAMEDATTR:
1405 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1406 if (compare && !(*retcmpp)) {
1407 if (*tl != newnfs_false)
1408 *retcmpp = NFSERR_NOTSAME;
1409 }
1410 attrsum += NFSX_UNSIGNED;
1411 break;
1412 case NFSATTRBIT_FSID:
1413 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1414 thyp = fxdr_hyper(tl);
1415 tl += 2;
1416 thyp2 = fxdr_hyper(tl);
1417 if (compare) {
1418 if (*retcmpp == 0) {
1419 if (thyp != (u_int64_t)
1420 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1421 thyp2 != (u_int64_t)
1422 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1423 *retcmpp = NFSERR_NOTSAME;
1424 }
1425 } else if (nap != NULL) {
1426 nap->na_filesid[0] = thyp;
1427 nap->na_filesid[1] = thyp2;
1428 }
1429 attrsum += (4 * NFSX_UNSIGNED);
1430 break;
1431 case NFSATTRBIT_UNIQUEHANDLES:
1432 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1433 if (compare && !(*retcmpp)) {
1434 if (*tl != newnfs_true)
1435 *retcmpp = NFSERR_NOTSAME;
1436 }
1437 attrsum += NFSX_UNSIGNED;
1438 break;
1439 case NFSATTRBIT_LEASETIME:
1440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1441 if (compare) {
1442 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1443 !(*retcmpp))
1444 *retcmpp = NFSERR_NOTSAME;
1445 } else if (leasep != NULL) {
1446 *leasep = fxdr_unsigned(u_int32_t, *tl);
1447 }
1448 attrsum += NFSX_UNSIGNED;
1449 break;
1450 case NFSATTRBIT_RDATTRERROR:
1451 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1452 if (compare) {
1453 if (!(*retcmpp))
1454 *retcmpp = NFSERR_INVAL;
1455 } else if (rderrp != NULL) {
1456 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1457 }
1458 attrsum += NFSX_UNSIGNED;
1459 break;
1460 case NFSATTRBIT_ACL:
1461 if (compare) {
1462 if (!(*retcmpp)) {
1463 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1464 NFSACL_T *naclp;
1465
1466 naclp = acl_alloc(M_WAITOK);
1467 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1468 &cnt, p);
1469 if (error) {
1470 acl_free(naclp);
1471 goto nfsmout;
1472 }
1473 if (aceerr || aclp == NULL ||
1474 nfsrv_compareacl(aclp, naclp))
1475 *retcmpp = NFSERR_NOTSAME;
1476 acl_free(naclp);
1477 } else {
1478 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1479 &cnt, p);
1480 if (error)
1481 goto nfsmout;
1482 *retcmpp = NFSERR_ATTRNOTSUPP;
1483 }
1484 }
1485 } else {
1486 if (vp != NULL && aclp != NULL)
1487 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1488 &cnt, p);
1489 else
1490 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1491 &cnt, p);
1492 if (error)
1493 goto nfsmout;
1494 }
1495
1496 attrsum += cnt;
1497 break;
1498 case NFSATTRBIT_ACLSUPPORT:
1499 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1500 if (compare && !(*retcmpp)) {
1501 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1502 if (fxdr_unsigned(u_int32_t, *tl) !=
1503 NFSV4ACE_SUPTYPES)
1504 *retcmpp = NFSERR_NOTSAME;
1505 } else {
1506 *retcmpp = NFSERR_ATTRNOTSUPP;
1507 }
1508 }
1509 attrsum += NFSX_UNSIGNED;
1510 break;
1511 case NFSATTRBIT_ARCHIVE:
1512 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1513 if (compare && !(*retcmpp))
1514 *retcmpp = NFSERR_ATTRNOTSUPP;
1515 attrsum += NFSX_UNSIGNED;
1516 break;
1517 case NFSATTRBIT_CANSETTIME:
1518 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1519 if (compare) {
1520 if (!(*retcmpp)) {
1521 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1522 if (*tl == newnfs_false)
1523 *retcmpp = NFSERR_NOTSAME;
1524 } else {
1525 if (*tl == newnfs_true)
1526 *retcmpp = NFSERR_NOTSAME;
1527 }
1528 }
1529 } else if (fsp != NULL) {
1530 if (*tl == newnfs_true)
1531 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1532 else
1533 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1534 }
1535 attrsum += NFSX_UNSIGNED;
1536 break;
1537 case NFSATTRBIT_CASEINSENSITIVE:
1538 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1539 if (compare) {
1540 if (!(*retcmpp)) {
1541 if (*tl != newnfs_false)
1542 *retcmpp = NFSERR_NOTSAME;
1543 }
1544 } else if (pc != NULL) {
1545 pc->pc_caseinsensitive =
1546 fxdr_unsigned(u_int32_t, *tl);
1547 }
1548 attrsum += NFSX_UNSIGNED;
1549 break;
1550 case NFSATTRBIT_CASEPRESERVING:
1551 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1552 if (compare) {
1553 if (!(*retcmpp)) {
1554 if (*tl != newnfs_true)
1555 *retcmpp = NFSERR_NOTSAME;
1556 }
1557 } else if (pc != NULL) {
1558 pc->pc_casepreserving =
1559 fxdr_unsigned(u_int32_t, *tl);
1560 }
1561 attrsum += NFSX_UNSIGNED;
1562 break;
1563 case NFSATTRBIT_CHOWNRESTRICTED:
1564 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1565 if (compare) {
1566 if (!(*retcmpp)) {
1567 if (*tl != newnfs_true)
1568 *retcmpp = NFSERR_NOTSAME;
1569 }
1570 } else if (pc != NULL) {
1571 pc->pc_chownrestricted =
1572 fxdr_unsigned(u_int32_t, *tl);
1573 }
1574 attrsum += NFSX_UNSIGNED;
1575 break;
1576 case NFSATTRBIT_FILEHANDLE:
1577 error = nfsm_getfh(nd, &tnfhp);
1578 if (error)
1579 goto nfsmout;
1580 tfhsize = tnfhp->nfh_len;
1581 if (compare) {
1582 if (!(*retcmpp) &&
1583 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1584 fhp, fhsize))
1585 *retcmpp = NFSERR_NOTSAME;
1586 free(tnfhp, M_NFSFH);
1587 } else if (nfhpp != NULL) {
1588 *nfhpp = tnfhp;
1589 } else {
1590 free(tnfhp, M_NFSFH);
1591 }
1592 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1593 break;
1594 case NFSATTRBIT_FILEID:
1595 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1596 thyp = fxdr_hyper(tl);
1597 if (compare) {
1598 if (!(*retcmpp)) {
1599 if (nap->na_fileid != thyp)
1600 *retcmpp = NFSERR_NOTSAME;
1601 }
1602 } else if (nap != NULL)
1603 nap->na_fileid = thyp;
1604 attrsum += NFSX_HYPER;
1605 break;
1606 case NFSATTRBIT_FILESAVAIL:
1607 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1608 if (compare) {
1609 uquad = nfsv4_filesavail(sbp, vp->v_mount);
1610 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1611 *retcmpp = NFSERR_NOTSAME;
1612 } else if (sfp != NULL) {
1613 sfp->sf_afiles = fxdr_hyper(tl);
1614 }
1615 attrsum += NFSX_HYPER;
1616 break;
1617 case NFSATTRBIT_FILESFREE:
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 if (compare) {
1620 uquad = (uint64_t)sbp->f_ffree;
1621 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1622 *retcmpp = NFSERR_NOTSAME;
1623 } else if (sfp != NULL) {
1624 sfp->sf_ffiles = fxdr_hyper(tl);
1625 }
1626 attrsum += NFSX_HYPER;
1627 break;
1628 case NFSATTRBIT_FILESTOTAL:
1629 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1630 if (compare) {
1631 uquad = sbp->f_files;
1632 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1633 *retcmpp = NFSERR_NOTSAME;
1634 } else if (sfp != NULL) {
1635 sfp->sf_tfiles = fxdr_hyper(tl);
1636 }
1637 attrsum += NFSX_HYPER;
1638 break;
1639 case NFSATTRBIT_FSLOCATIONS:
1640 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1641 if (error)
1642 goto nfsmout;
1643 attrsum += l;
1644 if (compare && !(*retcmpp)) {
1645 refp = nfsv4root_getreferral(vp, NULL, 0);
1646 if (refp != NULL) {
1647 if (cp == NULL || cp2 == NULL ||
1648 strcmp(cp, "/") ||
1649 strcmp(cp2, refp->nfr_srvlist))
1650 *retcmpp = NFSERR_NOTSAME;
1651 } else if (m == 0) {
1652 *retcmpp = NFSERR_NOTSAME;
1653 }
1654 }
1655 if (cp != NULL)
1656 free(cp, M_NFSSTRING);
1657 if (cp2 != NULL)
1658 free(cp2, M_NFSSTRING);
1659 break;
1660 case NFSATTRBIT_HIDDEN:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1662 if (compare && !(*retcmpp))
1663 *retcmpp = NFSERR_ATTRNOTSUPP;
1664 attrsum += NFSX_UNSIGNED;
1665 break;
1666 case NFSATTRBIT_HOMOGENEOUS:
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1668 if (compare) {
1669 if (!(*retcmpp)) {
1670 if (fsp->fs_properties &
1671 NFSV3_FSFHOMOGENEOUS) {
1672 if (*tl == newnfs_false)
1673 *retcmpp = NFSERR_NOTSAME;
1674 } else {
1675 if (*tl == newnfs_true)
1676 *retcmpp = NFSERR_NOTSAME;
1677 }
1678 }
1679 } else if (fsp != NULL) {
1680 if (*tl == newnfs_true)
1681 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1682 else
1683 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1684 }
1685 attrsum += NFSX_UNSIGNED;
1686 break;
1687 case NFSATTRBIT_MAXFILESIZE:
1688 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1689 tnfsquad.qval = fxdr_hyper(tl);
1690 if (compare) {
1691 if (!(*retcmpp)) {
1692 tquad = NFSRV_MAXFILESIZE;
1693 if (tquad != tnfsquad.qval)
1694 *retcmpp = NFSERR_NOTSAME;
1695 }
1696 } else if (fsp != NULL) {
1697 fsp->fs_maxfilesize = tnfsquad.qval;
1698 }
1699 attrsum += NFSX_HYPER;
1700 break;
1701 case NFSATTRBIT_MAXLINK:
1702 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1703 if (compare) {
1704 if (!(*retcmpp)) {
1705 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1706 *retcmpp = NFSERR_NOTSAME;
1707 }
1708 } else if (pc != NULL) {
1709 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1710 }
1711 attrsum += NFSX_UNSIGNED;
1712 break;
1713 case NFSATTRBIT_MAXNAME:
1714 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1715 if (compare) {
1716 if (!(*retcmpp)) {
1717 if (fsp->fs_maxname !=
1718 fxdr_unsigned(u_int32_t, *tl))
1719 *retcmpp = NFSERR_NOTSAME;
1720 }
1721 } else {
1722 tuint = fxdr_unsigned(u_int32_t, *tl);
1723 /*
1724 * Some Linux NFSv4 servers report this
1725 * as 0 or 4billion, so I'll set it to
1726 * NFS_MAXNAMLEN. If a server actually creates
1727 * a name longer than NFS_MAXNAMLEN, it will
1728 * get an error back.
1729 */
1730 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1731 tuint = NFS_MAXNAMLEN;
1732 if (fsp != NULL)
1733 fsp->fs_maxname = tuint;
1734 if (pc != NULL)
1735 pc->pc_namemax = tuint;
1736 }
1737 attrsum += NFSX_UNSIGNED;
1738 break;
1739 case NFSATTRBIT_MAXREAD:
1740 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1741 if (compare) {
1742 if (!(*retcmpp)) {
1743 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1744 *(tl + 1)) || *tl != 0)
1745 *retcmpp = NFSERR_NOTSAME;
1746 }
1747 } else if (fsp != NULL) {
1748 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1749 fsp->fs_rtpref = fsp->fs_rtmax;
1750 fsp->fs_dtpref = fsp->fs_rtpref;
1751 }
1752 attrsum += NFSX_HYPER;
1753 break;
1754 case NFSATTRBIT_MAXWRITE:
1755 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1756 if (compare) {
1757 if (!(*retcmpp)) {
1758 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1759 *(tl + 1)) || *tl != 0)
1760 *retcmpp = NFSERR_NOTSAME;
1761 }
1762 } else if (fsp != NULL) {
1763 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1764 fsp->fs_wtpref = fsp->fs_wtmax;
1765 }
1766 attrsum += NFSX_HYPER;
1767 break;
1768 case NFSATTRBIT_MIMETYPE:
1769 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1770 i = fxdr_unsigned(int, *tl);
1771 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1772 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1773 if (error)
1774 goto nfsmout;
1775 if (compare && !(*retcmpp))
1776 *retcmpp = NFSERR_ATTRNOTSUPP;
1777 break;
1778 case NFSATTRBIT_MODE:
1779 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1780 if (compare) {
1781 if (!(*retcmpp)) {
1782 if (nap->na_mode != nfstov_mode(*tl))
1783 *retcmpp = NFSERR_NOTSAME;
1784 }
1785 } else if (nap != NULL) {
1786 nap->na_mode = nfstov_mode(*tl);
1787 }
1788 attrsum += NFSX_UNSIGNED;
1789 break;
1790 case NFSATTRBIT_NOTRUNC:
1791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1792 if (compare) {
1793 if (!(*retcmpp)) {
1794 if (*tl != newnfs_true)
1795 *retcmpp = NFSERR_NOTSAME;
1796 }
1797 } else if (pc != NULL) {
1798 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1799 }
1800 attrsum += NFSX_UNSIGNED;
1801 break;
1802 case NFSATTRBIT_NUMLINKS:
1803 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1804 tuint = fxdr_unsigned(u_int32_t, *tl);
1805 if (compare) {
1806 if (!(*retcmpp)) {
1807 if ((u_int32_t)nap->na_nlink != tuint)
1808 *retcmpp = NFSERR_NOTSAME;
1809 }
1810 } else if (nap != NULL) {
1811 nap->na_nlink = tuint;
1812 }
1813 attrsum += NFSX_UNSIGNED;
1814 break;
1815 case NFSATTRBIT_OWNER:
1816 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1817 j = fxdr_unsigned(int, *tl);
1818 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1819 error = NFSERR_BADXDR;
1820 goto nfsmout;
1821 }
1822 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1823 if (j > NFSV4_SMALLSTR)
1824 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1825 else
1826 cp = namestr;
1827 error = nfsrv_mtostr(nd, cp, j);
1828 if (error) {
1829 if (j > NFSV4_SMALLSTR)
1830 free(cp, M_NFSSTRING);
1831 goto nfsmout;
1832 }
1833 if (compare) {
1834 if (!(*retcmpp)) {
1835 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1836 nap->na_uid != uid)
1837 *retcmpp = NFSERR_NOTSAME;
1838 }
1839 } else if (nap != NULL) {
1840 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1841 nap->na_uid = nfsrv_defaultuid;
1842 else
1843 nap->na_uid = uid;
1844 }
1845 if (j > NFSV4_SMALLSTR)
1846 free(cp, M_NFSSTRING);
1847 break;
1848 case NFSATTRBIT_OWNERGROUP:
1849 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1850 j = fxdr_unsigned(int, *tl);
1851 if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1852 error = NFSERR_BADXDR;
1853 goto nfsmout;
1854 }
1855 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1856 if (j > NFSV4_SMALLSTR)
1857 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1858 else
1859 cp = namestr;
1860 error = nfsrv_mtostr(nd, cp, j);
1861 if (error) {
1862 if (j > NFSV4_SMALLSTR)
1863 free(cp, M_NFSSTRING);
1864 goto nfsmout;
1865 }
1866 if (compare) {
1867 if (!(*retcmpp)) {
1868 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1869 nap->na_gid != gid)
1870 *retcmpp = NFSERR_NOTSAME;
1871 }
1872 } else if (nap != NULL) {
1873 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1874 nap->na_gid = nfsrv_defaultgid;
1875 else
1876 nap->na_gid = gid;
1877 }
1878 if (j > NFSV4_SMALLSTR)
1879 free(cp, M_NFSSTRING);
1880 break;
1881 case NFSATTRBIT_QUOTAHARD:
1882 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1883 if (sbp != NULL) {
1884 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1885 freenum = sbp->f_bfree;
1886 else
1887 freenum = sbp->f_bavail;
1888 #ifdef QUOTA
1889 /*
1890 * ufs_quotactl() insists that the uid argument
1891 * equal p_ruid for non-root quota access, so
1892 * we'll just make sure that's the case.
1893 */
1894 savuid = p->p_cred->p_ruid;
1895 p->p_cred->p_ruid = cred->cr_uid;
1896 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1897 USRQUOTA), cred->cr_uid, &dqb))
1898 freenum = min(dqb.dqb_bhardlimit, freenum);
1899 p->p_cred->p_ruid = savuid;
1900 #endif /* QUOTA */
1901 uquad = (u_int64_t)freenum;
1902 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1903 }
1904 if (compare && !(*retcmpp)) {
1905 if (uquad != fxdr_hyper(tl))
1906 *retcmpp = NFSERR_NOTSAME;
1907 }
1908 attrsum += NFSX_HYPER;
1909 break;
1910 case NFSATTRBIT_QUOTASOFT:
1911 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1912 if (sbp != NULL) {
1913 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1914 freenum = sbp->f_bfree;
1915 else
1916 freenum = sbp->f_bavail;
1917 #ifdef QUOTA
1918 /*
1919 * ufs_quotactl() insists that the uid argument
1920 * equal p_ruid for non-root quota access, so
1921 * we'll just make sure that's the case.
1922 */
1923 savuid = p->p_cred->p_ruid;
1924 p->p_cred->p_ruid = cred->cr_uid;
1925 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1926 USRQUOTA), cred->cr_uid, &dqb))
1927 freenum = min(dqb.dqb_bsoftlimit, freenum);
1928 p->p_cred->p_ruid = savuid;
1929 #endif /* QUOTA */
1930 uquad = (u_int64_t)freenum;
1931 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1932 }
1933 if (compare && !(*retcmpp)) {
1934 if (uquad != fxdr_hyper(tl))
1935 *retcmpp = NFSERR_NOTSAME;
1936 }
1937 attrsum += NFSX_HYPER;
1938 break;
1939 case NFSATTRBIT_QUOTAUSED:
1940 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1941 if (sbp != NULL) {
1942 freenum = 0;
1943 #ifdef QUOTA
1944 /*
1945 * ufs_quotactl() insists that the uid argument
1946 * equal p_ruid for non-root quota access, so
1947 * we'll just make sure that's the case.
1948 */
1949 savuid = p->p_cred->p_ruid;
1950 p->p_cred->p_ruid = cred->cr_uid;
1951 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1952 USRQUOTA), cred->cr_uid, &dqb))
1953 freenum = dqb.dqb_curblocks;
1954 p->p_cred->p_ruid = savuid;
1955 #endif /* QUOTA */
1956 uquad = (u_int64_t)freenum;
1957 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1958 }
1959 if (compare && !(*retcmpp)) {
1960 if (uquad != fxdr_hyper(tl))
1961 *retcmpp = NFSERR_NOTSAME;
1962 }
1963 attrsum += NFSX_HYPER;
1964 break;
1965 case NFSATTRBIT_RAWDEV:
1966 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1967 j = fxdr_unsigned(int, *tl++);
1968 k = fxdr_unsigned(int, *tl);
1969 if (compare) {
1970 if (!(*retcmpp)) {
1971 if (nap->na_rdev != NFSMAKEDEV(j, k))
1972 *retcmpp = NFSERR_NOTSAME;
1973 }
1974 } else if (nap != NULL) {
1975 nap->na_rdev = NFSMAKEDEV(j, k);
1976 }
1977 attrsum += NFSX_V4SPECDATA;
1978 break;
1979 case NFSATTRBIT_SPACEAVAIL:
1980 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1981 if (compare) {
1982 if (priv_check_cred(cred,
1983 PRIV_VFS_BLOCKRESERVE, 0))
1984 uquad = sbp->f_bfree;
1985 else
1986 uquad = (uint64_t)sbp->f_bavail;
1987 uquad *= sbp->f_bsize;
1988 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1989 *retcmpp = NFSERR_NOTSAME;
1990 } else if (sfp != NULL) {
1991 sfp->sf_abytes = fxdr_hyper(tl);
1992 }
1993 attrsum += NFSX_HYPER;
1994 break;
1995 case NFSATTRBIT_SPACEFREE:
1996 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1997 if (compare) {
1998 uquad = sbp->f_bfree;
1999 uquad *= sbp->f_bsize;
2000 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2001 *retcmpp = NFSERR_NOTSAME;
2002 } else if (sfp != NULL) {
2003 sfp->sf_fbytes = fxdr_hyper(tl);
2004 }
2005 attrsum += NFSX_HYPER;
2006 break;
2007 case NFSATTRBIT_SPACETOTAL:
2008 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2009 if (compare) {
2010 uquad = sbp->f_blocks;
2011 uquad *= sbp->f_bsize;
2012 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2013 *retcmpp = NFSERR_NOTSAME;
2014 } else if (sfp != NULL) {
2015 sfp->sf_tbytes = fxdr_hyper(tl);
2016 }
2017 attrsum += NFSX_HYPER;
2018 break;
2019 case NFSATTRBIT_SPACEUSED:
2020 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2021 thyp = fxdr_hyper(tl);
2022 if (compare) {
2023 if (!(*retcmpp)) {
2024 if ((u_int64_t)nap->na_bytes != thyp)
2025 *retcmpp = NFSERR_NOTSAME;
2026 }
2027 } else if (nap != NULL) {
2028 nap->na_bytes = thyp;
2029 }
2030 attrsum += NFSX_HYPER;
2031 break;
2032 case NFSATTRBIT_SYSTEM:
2033 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2034 if (compare && !(*retcmpp))
2035 *retcmpp = NFSERR_ATTRNOTSUPP;
2036 attrsum += NFSX_UNSIGNED;
2037 break;
2038 case NFSATTRBIT_TIMEACCESS:
2039 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2040 fxdr_nfsv4time(tl, &temptime);
2041 if (compare) {
2042 if (!(*retcmpp)) {
2043 if (!NFS_CMPTIME(temptime, nap->na_atime))
2044 *retcmpp = NFSERR_NOTSAME;
2045 }
2046 } else if (nap != NULL) {
2047 nap->na_atime = temptime;
2048 }
2049 attrsum += NFSX_V4TIME;
2050 break;
2051 case NFSATTRBIT_TIMEACCESSSET:
2052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2053 attrsum += NFSX_UNSIGNED;
2054 i = fxdr_unsigned(int, *tl);
2055 if (i == NFSV4SATTRTIME_TOCLIENT) {
2056 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2057 attrsum += NFSX_V4TIME;
2058 }
2059 if (compare && !(*retcmpp))
2060 *retcmpp = NFSERR_INVAL;
2061 break;
2062 case NFSATTRBIT_TIMEBACKUP:
2063 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2064 if (compare && !(*retcmpp))
2065 *retcmpp = NFSERR_ATTRNOTSUPP;
2066 attrsum += NFSX_V4TIME;
2067 break;
2068 case NFSATTRBIT_TIMECREATE:
2069 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2070 if (compare && !(*retcmpp))
2071 *retcmpp = NFSERR_ATTRNOTSUPP;
2072 attrsum += NFSX_V4TIME;
2073 break;
2074 case NFSATTRBIT_TIMEDELTA:
2075 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2076 if (fsp != NULL) {
2077 if (compare) {
2078 if (!(*retcmpp)) {
2079 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2080 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2081 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2082 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
2083 1000000000) ||
2084 *tl != 0)
2085 *retcmpp = NFSERR_NOTSAME;
2086 }
2087 } else {
2088 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2089 }
2090 }
2091 attrsum += NFSX_V4TIME;
2092 break;
2093 case NFSATTRBIT_TIMEMETADATA:
2094 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2095 fxdr_nfsv4time(tl, &temptime);
2096 if (compare) {
2097 if (!(*retcmpp)) {
2098 if (!NFS_CMPTIME(temptime, nap->na_ctime))
2099 *retcmpp = NFSERR_NOTSAME;
2100 }
2101 } else if (nap != NULL) {
2102 nap->na_ctime = temptime;
2103 }
2104 attrsum += NFSX_V4TIME;
2105 break;
2106 case NFSATTRBIT_TIMEMODIFY:
2107 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2108 fxdr_nfsv4time(tl, &temptime);
2109 if (compare) {
2110 if (!(*retcmpp)) {
2111 if (!NFS_CMPTIME(temptime, nap->na_mtime))
2112 *retcmpp = NFSERR_NOTSAME;
2113 }
2114 } else if (nap != NULL) {
2115 nap->na_mtime = temptime;
2116 }
2117 attrsum += NFSX_V4TIME;
2118 break;
2119 case NFSATTRBIT_TIMEMODIFYSET:
2120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2121 attrsum += NFSX_UNSIGNED;
2122 i = fxdr_unsigned(int, *tl);
2123 if (i == NFSV4SATTRTIME_TOCLIENT) {
2124 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2125 attrsum += NFSX_V4TIME;
2126 }
2127 if (compare && !(*retcmpp))
2128 *retcmpp = NFSERR_INVAL;
2129 break;
2130 case NFSATTRBIT_MOUNTEDONFILEID:
2131 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2132 thyp = fxdr_hyper(tl);
2133 if (compare) {
2134 if (!(*retcmpp)) {
2135 if (!vp || !nfsrv_atroot(vp, &thyp2))
2136 thyp2 = nap->na_fileid;
2137 if (thyp2 != thyp)
2138 *retcmpp = NFSERR_NOTSAME;
2139 }
2140 } else if (nap != NULL)
2141 nap->na_mntonfileno = thyp;
2142 attrsum += NFSX_HYPER;
2143 break;
2144 case NFSATTRBIT_SUPPATTREXCLCREAT:
2145 retnotsup = 0;
2146 error = nfsrv_getattrbits(nd, &retattrbits,
2147 &cnt, &retnotsup);
2148 if (error)
2149 goto nfsmout;
2150 if (compare && !(*retcmpp)) {
2151 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2152 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2153 NFSCLRBIT_ATTRBIT(&checkattrbits,
2154 NFSATTRBIT_TIMEACCESSSET);
2155 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2156 || retnotsup)
2157 *retcmpp = NFSERR_NOTSAME;
2158 }
2159 attrsum += cnt;
2160 break;
2161 case NFSATTRBIT_FSLAYOUTTYPE:
2162 case NFSATTRBIT_LAYOUTTYPE:
2163 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2164 attrsum += NFSX_UNSIGNED;
2165 i = fxdr_unsigned(int, *tl);
2166 /*
2167 * The RFCs do not define an upper limit for the
2168 * number of layout types, but 32 should be more
2169 * than enough.
2170 */
2171 if (i < 0 || i > 32) {
2172 error = NFSERR_BADXDR;
2173 goto nfsmout;
2174 }
2175 if (i > 0) {
2176 NFSM_DISSECT(tl, u_int32_t *, i *
2177 NFSX_UNSIGNED);
2178 attrsum += i * NFSX_UNSIGNED;
2179 j = fxdr_unsigned(int, *tl);
2180 if (i == 1 && compare && !(*retcmpp) &&
2181 (((nfsrv_doflexfile != 0 ||
2182 nfsrv_maxpnfsmirror > 1) &&
2183 j != NFSLAYOUT_FLEXFILE) ||
2184 (nfsrv_doflexfile == 0 &&
2185 j != NFSLAYOUT_NFSV4_1_FILES)))
2186 *retcmpp = NFSERR_NOTSAME;
2187 }
2188 if (nfsrv_devidcnt == 0) {
2189 if (compare && !(*retcmpp) && i > 0)
2190 *retcmpp = NFSERR_NOTSAME;
2191 } else {
2192 if (compare && !(*retcmpp) && i != 1)
2193 *retcmpp = NFSERR_NOTSAME;
2194 }
2195 break;
2196 case NFSATTRBIT_LAYOUTALIGNMENT:
2197 case NFSATTRBIT_LAYOUTBLKSIZE:
2198 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2199 attrsum += NFSX_UNSIGNED;
2200 i = fxdr_unsigned(int, *tl);
2201 if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2202 *retcmpp = NFSERR_NOTSAME;
2203 break;
2204 default:
2205 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2206 bitpos);
2207 if (compare && !(*retcmpp))
2208 *retcmpp = NFSERR_ATTRNOTSUPP;
2209 /*
2210 * and get out of the loop, since we can't parse
2211 * the unknown attribute data.
2212 */
2213 bitpos = NFSATTRBIT_MAX;
2214 break;
2215 }
2216 }
2217
2218 /*
2219 * some clients pad the attrlist, so we need to skip over the
2220 * padding.
2221 */
2222 if (attrsum > attrsize) {
2223 error = NFSERR_BADXDR;
2224 } else {
2225 attrsize = NFSM_RNDUP(attrsize);
2226 if (attrsum < attrsize)
2227 error = nfsm_advance(nd, attrsize - attrsum, -1);
2228 }
2229 nfsmout:
2230 NFSEXITCODE2(error, nd);
2231 return (error);
2232 }
2233
2234 /*
2235 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2236 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2237 * The first argument is a pointer to an nfsv4lock structure.
2238 * The second argument is 1 iff a blocking lock is wanted.
2239 * If this argument is 0, the call waits until no thread either wants nor
2240 * holds an exclusive lock.
2241 * It returns 1 if the lock was acquired, 0 otherwise.
2242 * If several processes call this function concurrently wanting the exclusive
2243 * lock, one will get the lock and the rest will return without getting the
2244 * lock. (If the caller must have the lock, it simply calls this function in a
2245 * loop until the function returns 1 to indicate the lock was acquired.)
2246 * Any usecnt must be decremented by calling nfsv4_relref() before
2247 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2248 * be called in a loop.
2249 * The isleptp argument is set to indicate if the call slept, iff not NULL
2250 * and the mp argument indicates to check for a forced dismount, iff not
2251 * NULL.
2252 */
2253 int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,struct mtx * mutex,struct mount * mp)2254 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2255 struct mtx *mutex, struct mount *mp)
2256 {
2257
2258 if (isleptp)
2259 *isleptp = 0;
2260 /*
2261 * If a lock is wanted, loop around until the lock is acquired by
2262 * someone and then released. If I want the lock, try to acquire it.
2263 * For a lock to be issued, no lock must be in force and the usecnt
2264 * must be zero.
2265 */
2266 if (iwantlock) {
2267 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2268 lp->nfslock_usecnt == 0) {
2269 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2270 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2271 return (1);
2272 }
2273 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2274 }
2275 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2276 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2277 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2278 return (0);
2279 }
2280 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2281 if (isleptp)
2282 *isleptp = 1;
2283 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2284 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2285 lp->nfslock_usecnt == 0) {
2286 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2287 lp->nfslock_lock |= NFSV4LOCK_LOCK;
2288 return (1);
2289 }
2290 }
2291 return (0);
2292 }
2293
2294 /*
2295 * Release the lock acquired by nfsv4_lock().
2296 * The second argument is set to 1 to indicate the nfslock_usecnt should be
2297 * incremented, as well.
2298 */
2299 void
nfsv4_unlock(struct nfsv4lock * lp,int incref)2300 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2301 {
2302
2303 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2304 if (incref)
2305 lp->nfslock_usecnt++;
2306 nfsv4_wanted(lp);
2307 }
2308
2309 /*
2310 * Release a reference cnt.
2311 */
2312 void
nfsv4_relref(struct nfsv4lock * lp)2313 nfsv4_relref(struct nfsv4lock *lp)
2314 {
2315
2316 if (lp->nfslock_usecnt <= 0)
2317 panic("nfsv4root ref cnt");
2318 lp->nfslock_usecnt--;
2319 if (lp->nfslock_usecnt == 0)
2320 nfsv4_wanted(lp);
2321 }
2322
2323 /*
2324 * Get a reference cnt.
2325 * This function will wait for any exclusive lock to be released, but will
2326 * not wait for threads that want the exclusive lock. If priority needs
2327 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2328 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2329 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2330 * return without getting a refcnt for that case.
2331 */
2332 void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,struct mtx * mutex,struct mount * mp)2333 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2334 struct mount *mp)
2335 {
2336
2337 if (isleptp)
2338 *isleptp = 0;
2339
2340 /*
2341 * Wait for a lock held.
2342 */
2343 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2344 if (mp != NULL && NFSCL_FORCEDISM(mp))
2345 return;
2346 lp->nfslock_lock |= NFSV4LOCK_WANTED;
2347 if (isleptp)
2348 *isleptp = 1;
2349 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2350 }
2351 if (mp != NULL && NFSCL_FORCEDISM(mp))
2352 return;
2353
2354 lp->nfslock_usecnt++;
2355 }
2356
2357 /*
2358 * Get a reference as above, but return failure instead of sleeping if
2359 * an exclusive lock is held.
2360 */
2361 int
nfsv4_getref_nonblock(struct nfsv4lock * lp)2362 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2363 {
2364
2365 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2366 return (0);
2367
2368 lp->nfslock_usecnt++;
2369 return (1);
2370 }
2371
2372 /*
2373 * Test for a lock. Return 1 if locked, 0 otherwise.
2374 */
2375 int
nfsv4_testlock(struct nfsv4lock * lp)2376 nfsv4_testlock(struct nfsv4lock *lp)
2377 {
2378
2379 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2380 lp->nfslock_usecnt == 0)
2381 return (0);
2382 return (1);
2383 }
2384
2385 /*
2386 * Wake up anyone sleeping, waiting for this lock.
2387 */
2388 static void
nfsv4_wanted(struct nfsv4lock * lp)2389 nfsv4_wanted(struct nfsv4lock *lp)
2390 {
2391
2392 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2393 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2394 wakeup((caddr_t)&lp->nfslock_lock);
2395 }
2396 }
2397
2398 /*
2399 * Copy a string from an mbuf list into a character array.
2400 * Return EBADRPC if there is an mbuf error,
2401 * 0 otherwise.
2402 */
2403 int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)2404 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2405 {
2406 char *cp;
2407 int xfer, len;
2408 mbuf_t mp;
2409 int rem, error = 0;
2410
2411 mp = nd->nd_md;
2412 cp = nd->nd_dpos;
2413 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2414 rem = NFSM_RNDUP(siz) - siz;
2415 while (siz > 0) {
2416 if (len > siz)
2417 xfer = siz;
2418 else
2419 xfer = len;
2420 NFSBCOPY(cp, str, xfer);
2421 str += xfer;
2422 siz -= xfer;
2423 if (siz > 0) {
2424 mp = mbuf_next(mp);
2425 if (mp == NULL) {
2426 error = EBADRPC;
2427 goto out;
2428 }
2429 cp = NFSMTOD(mp, caddr_t);
2430 len = mbuf_len(mp);
2431 } else {
2432 cp += xfer;
2433 len -= xfer;
2434 }
2435 }
2436 *str = '\0';
2437 nd->nd_dpos = cp;
2438 nd->nd_md = mp;
2439 if (rem > 0) {
2440 if (len < rem)
2441 error = nfsm_advance(nd, rem, len);
2442 else
2443 nd->nd_dpos += rem;
2444 }
2445
2446 out:
2447 NFSEXITCODE2(error, nd);
2448 return (error);
2449 }
2450
2451 /*
2452 * Fill in the attributes as marked by the bitmap (V4).
2453 */
2454 int
nfsv4_fillattr(struct nfsrv_descript * nd,struct mount * mp,vnode_t vp,NFSACL_T * saclp,struct vattr * vap,fhandle_t * fhp,int rderror,nfsattrbit_t * attrbitp,struct ucred * cred,NFSPROC_T * p,int isdgram,int reterr,int supports_nfsv4acls,int at_root,uint64_t mounted_on_fileno,struct statfs * pnfssf)2455 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2456 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2457 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2458 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2459 struct statfs *pnfssf)
2460 {
2461 int bitpos, retnum = 0;
2462 u_int32_t *tl;
2463 int siz, prefixnum, error;
2464 u_char *cp, namestr[NFSV4_SMALLSTR];
2465 nfsattrbit_t attrbits, retbits;
2466 nfsattrbit_t *retbitp = &retbits;
2467 u_int32_t freenum, *retnump;
2468 u_int64_t uquad;
2469 struct statfs *fs;
2470 struct nfsfsinfo fsinf;
2471 struct timespec temptime;
2472 NFSACL_T *aclp, *naclp = NULL;
2473 #ifdef QUOTA
2474 struct dqblk dqb;
2475 uid_t savuid;
2476 #endif
2477
2478 /*
2479 * First, set the bits that can be filled and get fsinfo.
2480 */
2481 NFSSET_ATTRBIT(retbitp, attrbitp);
2482 /*
2483 * If both p and cred are NULL, it is a client side setattr call.
2484 * If both p and cred are not NULL, it is a server side reply call.
2485 * If p is not NULL and cred is NULL, it is a client side callback
2486 * reply call.
2487 */
2488 if (p == NULL && cred == NULL) {
2489 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2490 aclp = saclp;
2491 } else {
2492 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2493 naclp = acl_alloc(M_WAITOK);
2494 aclp = naclp;
2495 }
2496 nfsvno_getfs(&fsinf, isdgram);
2497 #ifndef APPLE
2498 /*
2499 * Get the VFS_STATFS(), since some attributes need them.
2500 */
2501 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2502 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2503 error = VFS_STATFS(mp, fs);
2504 if (error != 0) {
2505 if (reterr) {
2506 nd->nd_repstat = NFSERR_ACCES;
2507 free(fs, M_STATFS);
2508 return (0);
2509 }
2510 NFSCLRSTATFS_ATTRBIT(retbitp);
2511 }
2512 /*
2513 * Since NFS handles these values as unsigned on the
2514 * wire, there is no way to represent negative values,
2515 * so set them to 0. Without this, they will appear
2516 * to be very large positive values for clients like
2517 * Solaris10.
2518 */
2519 if (fs->f_bavail < 0)
2520 fs->f_bavail = 0;
2521 if (fs->f_ffree < 0)
2522 fs->f_ffree = 0;
2523 }
2524 #endif
2525
2526 /*
2527 * And the NFSv4 ACL...
2528 */
2529 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2530 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2531 supports_nfsv4acls == 0))) {
2532 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2533 }
2534 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2535 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2536 supports_nfsv4acls == 0)) {
2537 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2538 } else if (naclp != NULL) {
2539 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2540 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2541 if (error == 0)
2542 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2543 naclp, cred, p);
2544 NFSVOPUNLOCK(vp, 0);
2545 } else
2546 error = NFSERR_PERM;
2547 if (error != 0) {
2548 if (reterr) {
2549 nd->nd_repstat = NFSERR_ACCES;
2550 free(fs, M_STATFS);
2551 return (0);
2552 }
2553 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2554 }
2555 }
2556 }
2557
2558 /*
2559 * Put out the attribute bitmap for the ones being filled in
2560 * and get the field for the number of attributes returned.
2561 */
2562 prefixnum = nfsrv_putattrbit(nd, retbitp);
2563 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2564 prefixnum += NFSX_UNSIGNED;
2565
2566 /*
2567 * Now, loop around filling in the attributes for each bit set.
2568 */
2569 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2570 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2571 switch (bitpos) {
2572 case NFSATTRBIT_SUPPORTEDATTRS:
2573 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2574 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2575 && supports_nfsv4acls == 0)) {
2576 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2577 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2578 }
2579 retnum += nfsrv_putattrbit(nd, &attrbits);
2580 break;
2581 case NFSATTRBIT_TYPE:
2582 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2583 *tl = vtonfsv34_type(vap->va_type);
2584 retnum += NFSX_UNSIGNED;
2585 break;
2586 case NFSATTRBIT_FHEXPIRETYPE:
2587 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2588 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2589 retnum += NFSX_UNSIGNED;
2590 break;
2591 case NFSATTRBIT_CHANGE:
2592 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2593 txdr_hyper(vap->va_filerev, tl);
2594 retnum += NFSX_HYPER;
2595 break;
2596 case NFSATTRBIT_SIZE:
2597 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2598 txdr_hyper(vap->va_size, tl);
2599 retnum += NFSX_HYPER;
2600 break;
2601 case NFSATTRBIT_LINKSUPPORT:
2602 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2603 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2604 *tl = newnfs_true;
2605 else
2606 *tl = newnfs_false;
2607 retnum += NFSX_UNSIGNED;
2608 break;
2609 case NFSATTRBIT_SYMLINKSUPPORT:
2610 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2611 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2612 *tl = newnfs_true;
2613 else
2614 *tl = newnfs_false;
2615 retnum += NFSX_UNSIGNED;
2616 break;
2617 case NFSATTRBIT_NAMEDATTR:
2618 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2619 *tl = newnfs_false;
2620 retnum += NFSX_UNSIGNED;
2621 break;
2622 case NFSATTRBIT_FSID:
2623 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2624 *tl++ = 0;
2625 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2626 *tl++ = 0;
2627 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2628 retnum += NFSX_V4FSID;
2629 break;
2630 case NFSATTRBIT_UNIQUEHANDLES:
2631 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2632 *tl = newnfs_true;
2633 retnum += NFSX_UNSIGNED;
2634 break;
2635 case NFSATTRBIT_LEASETIME:
2636 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2637 *tl = txdr_unsigned(nfsrv_lease);
2638 retnum += NFSX_UNSIGNED;
2639 break;
2640 case NFSATTRBIT_RDATTRERROR:
2641 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2642 *tl = txdr_unsigned(rderror);
2643 retnum += NFSX_UNSIGNED;
2644 break;
2645 /*
2646 * Recommended Attributes. (Only the supported ones.)
2647 */
2648 case NFSATTRBIT_ACL:
2649 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2650 break;
2651 case NFSATTRBIT_ACLSUPPORT:
2652 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2653 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2654 retnum += NFSX_UNSIGNED;
2655 break;
2656 case NFSATTRBIT_CANSETTIME:
2657 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2658 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2659 *tl = newnfs_true;
2660 else
2661 *tl = newnfs_false;
2662 retnum += NFSX_UNSIGNED;
2663 break;
2664 case NFSATTRBIT_CASEINSENSITIVE:
2665 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2666 *tl = newnfs_false;
2667 retnum += NFSX_UNSIGNED;
2668 break;
2669 case NFSATTRBIT_CASEPRESERVING:
2670 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2671 *tl = newnfs_true;
2672 retnum += NFSX_UNSIGNED;
2673 break;
2674 case NFSATTRBIT_CHOWNRESTRICTED:
2675 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2676 *tl = newnfs_true;
2677 retnum += NFSX_UNSIGNED;
2678 break;
2679 case NFSATTRBIT_FILEHANDLE:
2680 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2681 break;
2682 case NFSATTRBIT_FILEID:
2683 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2684 uquad = vap->va_fileid;
2685 txdr_hyper(uquad, tl);
2686 retnum += NFSX_HYPER;
2687 break;
2688 case NFSATTRBIT_FILESAVAIL:
2689 freenum = nfsv4_filesavail(fs, mp);
2690 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2691 *tl++ = 0;
2692 *tl = txdr_unsigned(freenum);
2693 retnum += NFSX_HYPER;
2694 break;
2695 case NFSATTRBIT_FILESFREE:
2696 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2697 *tl++ = 0;
2698 *tl = txdr_unsigned(fs->f_ffree);
2699 retnum += NFSX_HYPER;
2700 break;
2701 case NFSATTRBIT_FILESTOTAL:
2702 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2703 *tl++ = 0;
2704 *tl = txdr_unsigned(fs->f_files);
2705 retnum += NFSX_HYPER;
2706 break;
2707 case NFSATTRBIT_FSLOCATIONS:
2708 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2709 *tl++ = 0;
2710 *tl = 0;
2711 retnum += 2 * NFSX_UNSIGNED;
2712 break;
2713 case NFSATTRBIT_HOMOGENEOUS:
2714 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2715 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2716 *tl = newnfs_true;
2717 else
2718 *tl = newnfs_false;
2719 retnum += NFSX_UNSIGNED;
2720 break;
2721 case NFSATTRBIT_MAXFILESIZE:
2722 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2723 uquad = NFSRV_MAXFILESIZE;
2724 txdr_hyper(uquad, tl);
2725 retnum += NFSX_HYPER;
2726 break;
2727 case NFSATTRBIT_MAXLINK:
2728 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2729 *tl = txdr_unsigned(NFS_LINK_MAX);
2730 retnum += NFSX_UNSIGNED;
2731 break;
2732 case NFSATTRBIT_MAXNAME:
2733 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2734 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2735 retnum += NFSX_UNSIGNED;
2736 break;
2737 case NFSATTRBIT_MAXREAD:
2738 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2739 *tl++ = 0;
2740 *tl = txdr_unsigned(fsinf.fs_rtmax);
2741 retnum += NFSX_HYPER;
2742 break;
2743 case NFSATTRBIT_MAXWRITE:
2744 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2745 *tl++ = 0;
2746 *tl = txdr_unsigned(fsinf.fs_wtmax);
2747 retnum += NFSX_HYPER;
2748 break;
2749 case NFSATTRBIT_MODE:
2750 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2751 *tl = vtonfsv34_mode(vap->va_mode);
2752 retnum += NFSX_UNSIGNED;
2753 break;
2754 case NFSATTRBIT_NOTRUNC:
2755 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2756 *tl = newnfs_true;
2757 retnum += NFSX_UNSIGNED;
2758 break;
2759 case NFSATTRBIT_NUMLINKS:
2760 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2761 *tl = txdr_unsigned(vap->va_nlink);
2762 retnum += NFSX_UNSIGNED;
2763 break;
2764 case NFSATTRBIT_OWNER:
2765 cp = namestr;
2766 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2767 retnum += nfsm_strtom(nd, cp, siz);
2768 if (cp != namestr)
2769 free(cp, M_NFSSTRING);
2770 break;
2771 case NFSATTRBIT_OWNERGROUP:
2772 cp = namestr;
2773 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2774 retnum += nfsm_strtom(nd, cp, siz);
2775 if (cp != namestr)
2776 free(cp, M_NFSSTRING);
2777 break;
2778 case NFSATTRBIT_QUOTAHARD:
2779 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2780 freenum = fs->f_bfree;
2781 else
2782 freenum = fs->f_bavail;
2783 #ifdef QUOTA
2784 /*
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.
2788 */
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, &dqb))
2793 freenum = min(dqb.dqb_bhardlimit, freenum);
2794 p->p_cred->p_ruid = savuid;
2795 #endif /* QUOTA */
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;
2801 break;
2802 case NFSATTRBIT_QUOTASOFT:
2803 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2804 freenum = fs->f_bfree;
2805 else
2806 freenum = fs->f_bavail;
2807 #ifdef QUOTA
2808 /*
2809 * ufs_quotactl() insists that the uid argument
2810 * equal p_ruid for non-root quota access, so
2811 * we'll just make sure that's the case.
2812 */
2813 savuid = p->p_cred->p_ruid;
2814 p->p_cred->p_ruid = cred->cr_uid;
2815 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2816 cred->cr_uid, &dqb))
2817 freenum = min(dqb.dqb_bsoftlimit, freenum);
2818 p->p_cred->p_ruid = savuid;
2819 #endif /* QUOTA */
2820 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2821 uquad = (u_int64_t)freenum;
2822 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2823 txdr_hyper(uquad, tl);
2824 retnum += NFSX_HYPER;
2825 break;
2826 case NFSATTRBIT_QUOTAUSED:
2827 freenum = 0;
2828 #ifdef QUOTA
2829 /*
2830 * ufs_quotactl() insists that the uid argument
2831 * equal p_ruid for non-root quota access, so
2832 * we'll just make sure that's the case.
2833 */
2834 savuid = p->p_cred->p_ruid;
2835 p->p_cred->p_ruid = cred->cr_uid;
2836 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2837 cred->cr_uid, &dqb))
2838 freenum = dqb.dqb_curblocks;
2839 p->p_cred->p_ruid = savuid;
2840 #endif /* QUOTA */
2841 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2842 uquad = (u_int64_t)freenum;
2843 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2844 txdr_hyper(uquad, tl);
2845 retnum += NFSX_HYPER;
2846 break;
2847 case NFSATTRBIT_RAWDEV:
2848 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2849 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2850 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2851 retnum += NFSX_V4SPECDATA;
2852 break;
2853 case NFSATTRBIT_SPACEAVAIL:
2854 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2855 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) {
2856 if (pnfssf != NULL)
2857 uquad = (u_int64_t)pnfssf->f_bfree;
2858 else
2859 uquad = (u_int64_t)fs->f_bfree;
2860 } else {
2861 if (pnfssf != NULL)
2862 uquad = (u_int64_t)pnfssf->f_bavail;
2863 else
2864 uquad = (u_int64_t)fs->f_bavail;
2865 }
2866 if (pnfssf != NULL)
2867 uquad *= pnfssf->f_bsize;
2868 else
2869 uquad *= fs->f_bsize;
2870 txdr_hyper(uquad, tl);
2871 retnum += NFSX_HYPER;
2872 break;
2873 case NFSATTRBIT_SPACEFREE:
2874 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2875 if (pnfssf != NULL) {
2876 uquad = (u_int64_t)pnfssf->f_bfree;
2877 uquad *= pnfssf->f_bsize;
2878 } else {
2879 uquad = (u_int64_t)fs->f_bfree;
2880 uquad *= fs->f_bsize;
2881 }
2882 txdr_hyper(uquad, tl);
2883 retnum += NFSX_HYPER;
2884 break;
2885 case NFSATTRBIT_SPACETOTAL:
2886 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2887 if (pnfssf != NULL) {
2888 uquad = (u_int64_t)pnfssf->f_blocks;
2889 uquad *= pnfssf->f_bsize;
2890 } else {
2891 uquad = (u_int64_t)fs->f_blocks;
2892 uquad *= fs->f_bsize;
2893 }
2894 txdr_hyper(uquad, tl);
2895 retnum += NFSX_HYPER;
2896 break;
2897 case NFSATTRBIT_SPACEUSED:
2898 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2899 txdr_hyper(vap->va_bytes, tl);
2900 retnum += NFSX_HYPER;
2901 break;
2902 case NFSATTRBIT_TIMEACCESS:
2903 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2904 txdr_nfsv4time(&vap->va_atime, tl);
2905 retnum += NFSX_V4TIME;
2906 break;
2907 case NFSATTRBIT_TIMEACCESSSET:
2908 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2909 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2910 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2911 txdr_nfsv4time(&vap->va_atime, tl);
2912 retnum += NFSX_V4SETTIME;
2913 } else {
2914 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2915 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2916 retnum += NFSX_UNSIGNED;
2917 }
2918 break;
2919 case NFSATTRBIT_TIMEDELTA:
2920 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2921 temptime.tv_sec = 0;
2922 temptime.tv_nsec = 1000000000 / hz;
2923 txdr_nfsv4time(&temptime, tl);
2924 retnum += NFSX_V4TIME;
2925 break;
2926 case NFSATTRBIT_TIMEMETADATA:
2927 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2928 txdr_nfsv4time(&vap->va_ctime, tl);
2929 retnum += NFSX_V4TIME;
2930 break;
2931 case NFSATTRBIT_TIMEMODIFY:
2932 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2933 txdr_nfsv4time(&vap->va_mtime, tl);
2934 retnum += NFSX_V4TIME;
2935 break;
2936 case NFSATTRBIT_TIMEMODIFYSET:
2937 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2938 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2939 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2940 txdr_nfsv4time(&vap->va_mtime, tl);
2941 retnum += NFSX_V4SETTIME;
2942 } else {
2943 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2944 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2945 retnum += NFSX_UNSIGNED;
2946 }
2947 break;
2948 case NFSATTRBIT_MOUNTEDONFILEID:
2949 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2950 if (at_root != 0)
2951 uquad = mounted_on_fileno;
2952 else
2953 uquad = vap->va_fileid;
2954 txdr_hyper(uquad, tl);
2955 retnum += NFSX_HYPER;
2956 break;
2957 case NFSATTRBIT_SUPPATTREXCLCREAT:
2958 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2959 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2960 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2961 retnum += nfsrv_putattrbit(nd, &attrbits);
2962 break;
2963 case NFSATTRBIT_FSLAYOUTTYPE:
2964 case NFSATTRBIT_LAYOUTTYPE:
2965 if (nfsrv_devidcnt == 0)
2966 siz = 1;
2967 else
2968 siz = 2;
2969 if (siz == 2) {
2970 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2971 *tl++ = txdr_unsigned(1); /* One entry. */
2972 if (nfsrv_doflexfile != 0 ||
2973 nfsrv_maxpnfsmirror > 1)
2974 *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2975 else
2976 *tl = txdr_unsigned(
2977 NFSLAYOUT_NFSV4_1_FILES);
2978 } else {
2979 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2980 *tl = 0;
2981 }
2982 retnum += siz * NFSX_UNSIGNED;
2983 break;
2984 case NFSATTRBIT_LAYOUTALIGNMENT:
2985 case NFSATTRBIT_LAYOUTBLKSIZE:
2986 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2987 *tl = txdr_unsigned(NFS_SRVMAXIO);
2988 retnum += NFSX_UNSIGNED;
2989 break;
2990 default:
2991 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2992 }
2993 }
2994 }
2995 if (naclp != NULL)
2996 acl_free(naclp);
2997 free(fs, M_STATFS);
2998 *retnump = txdr_unsigned(retnum);
2999 return (retnum + prefixnum);
3000 }
3001
3002 /*
3003 * Calculate the files available attribute value.
3004 */
3005 static uint32_t
nfsv4_filesavail(struct statfs * fs,struct mount * mp)3006 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3007 {
3008 uint32_t freenum;
3009 #ifdef QUOTA
3010 struct dqblk dqb;
3011 uid_t savuid;
3012 NFSPROC_T *p;
3013 #endif
3014
3015 /*
3016 * Check quota and use min(quota, f_ffree).
3017 */
3018 freenum = fs->f_ffree;
3019 #ifdef QUOTA
3020 /*
3021 * This is old OpenBSD code that does not build
3022 * for FreeBSD. I do not know if doing this is
3023 * useful, so I will just leave the code here.
3024 */
3025 p = curthread();
3026 /*
3027 * ufs_quotactl() insists that the uid argument
3028 * equal p_ruid for non-root quota access, so
3029 * we'll just make sure that's the case.
3030 */
3031 savuid = p->p_cred->p_ruid;
3032 p->p_cred->p_ruid = cred->cr_uid;
3033 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3034 cred->cr_uid, &dqb))
3035 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3036 freenum);
3037 p->p_cred->p_ruid = savuid;
3038 #endif /* QUOTA */
3039 return (freenum);
3040 }
3041
3042 /*
3043 * Put the attribute bits onto an mbuf list.
3044 * Return the number of bytes of output generated.
3045 */
3046 int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)3047 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3048 {
3049 u_int32_t *tl;
3050 int cnt, i, bytesize;
3051
3052 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3053 if (attrbitp->bits[cnt - 1])
3054 break;
3055 bytesize = (cnt + 1) * NFSX_UNSIGNED;
3056 NFSM_BUILD(tl, u_int32_t *, bytesize);
3057 *tl++ = txdr_unsigned(cnt);
3058 for (i = 0; i < cnt; i++)
3059 *tl++ = txdr_unsigned(attrbitp->bits[i]);
3060 return (bytesize);
3061 }
3062
3063 /*
3064 * Convert a uid to a string.
3065 * If the lookup fails, just output the digits.
3066 * uid - the user id
3067 * cpp - points to a buffer of size NFSV4_SMALLSTR
3068 * (malloc a larger one, as required)
3069 * retlenp - pointer to length to be returned
3070 */
3071 void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp,NFSPROC_T * p)3072 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
3073 {
3074 int i;
3075 struct nfsusrgrp *usrp;
3076 u_char *cp = *cpp;
3077 uid_t tmp;
3078 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3079 struct nfsrv_lughash *hp;
3080
3081 cnt = 0;
3082 tryagain:
3083 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3084 /*
3085 * Always map nfsrv_defaultuid to "nobody".
3086 */
3087 if (uid == nfsrv_defaultuid) {
3088 i = nfsrv_dnsnamelen + 7;
3089 if (i > len) {
3090 if (len > NFSV4_SMALLSTR)
3091 free(cp, M_NFSSTRING);
3092 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3093 *cpp = cp;
3094 len = i;
3095 goto tryagain;
3096 }
3097 *retlenp = i;
3098 NFSBCOPY("nobody@", cp, 7);
3099 cp += 7;
3100 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3101 return;
3102 }
3103 hasampersand = 0;
3104 hp = NFSUSERHASH(uid);
3105 mtx_lock(&hp->mtx);
3106 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3107 if (usrp->lug_uid == uid) {
3108 if (usrp->lug_expiry < NFSD_MONOSEC)
3109 break;
3110 /*
3111 * If the name doesn't already have an '@'
3112 * in it, append @domainname to it.
3113 */
3114 for (i = 0; i < usrp->lug_namelen; i++) {
3115 if (usrp->lug_name[i] == '@') {
3116 hasampersand = 1;
3117 break;
3118 }
3119 }
3120 if (hasampersand)
3121 i = usrp->lug_namelen;
3122 else
3123 i = usrp->lug_namelen +
3124 nfsrv_dnsnamelen + 1;
3125 if (i > len) {
3126 mtx_unlock(&hp->mtx);
3127 if (len > NFSV4_SMALLSTR)
3128 free(cp, M_NFSSTRING);
3129 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3130 *cpp = cp;
3131 len = i;
3132 goto tryagain;
3133 }
3134 *retlenp = i;
3135 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3136 if (!hasampersand) {
3137 cp += usrp->lug_namelen;
3138 *cp++ = '@';
3139 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3140 }
3141 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3142 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3143 lug_numhash);
3144 mtx_unlock(&hp->mtx);
3145 return;
3146 }
3147 }
3148 mtx_unlock(&hp->mtx);
3149 cnt++;
3150 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
3151 NULL, p);
3152 if (ret == 0 && cnt < 2)
3153 goto tryagain;
3154 }
3155
3156 /*
3157 * No match, just return a string of digits.
3158 */
3159 tmp = uid;
3160 i = 0;
3161 while (tmp || i == 0) {
3162 tmp /= 10;
3163 i++;
3164 }
3165 len = (i > len) ? len : i;
3166 *retlenp = len;
3167 cp += (len - 1);
3168 tmp = uid;
3169 for (i = 0; i < len; i++) {
3170 *cp-- = '0' + (tmp % 10);
3171 tmp /= 10;
3172 }
3173 return;
3174 }
3175
3176 /*
3177 * Get a credential for the uid with the server's group list.
3178 * If none is found, just return the credential passed in after
3179 * logging a warning message.
3180 */
3181 struct ucred *
nfsrv_getgrpscred(struct ucred * oldcred)3182 nfsrv_getgrpscred(struct ucred *oldcred)
3183 {
3184 struct nfsusrgrp *usrp;
3185 struct ucred *newcred;
3186 int cnt, ret;
3187 uid_t uid;
3188 struct nfsrv_lughash *hp;
3189
3190 cnt = 0;
3191 uid = oldcred->cr_uid;
3192 tryagain:
3193 if (nfsrv_dnsnamelen > 0) {
3194 hp = NFSUSERHASH(uid);
3195 mtx_lock(&hp->mtx);
3196 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3197 if (usrp->lug_uid == uid) {
3198 if (usrp->lug_expiry < NFSD_MONOSEC)
3199 break;
3200 if (usrp->lug_cred != NULL) {
3201 newcred = crhold(usrp->lug_cred);
3202 crfree(oldcred);
3203 } else
3204 newcred = oldcred;
3205 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3206 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3207 lug_numhash);
3208 mtx_unlock(&hp->mtx);
3209 return (newcred);
3210 }
3211 }
3212 mtx_unlock(&hp->mtx);
3213 cnt++;
3214 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
3215 NULL, curthread);
3216 if (ret == 0 && cnt < 2)
3217 goto tryagain;
3218 }
3219 return (oldcred);
3220 }
3221
3222 /*
3223 * Convert a string to a uid.
3224 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3225 * return 0.
3226 * If this is called from a client side mount using AUTH_SYS and the
3227 * string is made up entirely of digits, just convert the string to
3228 * a number.
3229 */
3230 int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp,NFSPROC_T * p)3231 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
3232 NFSPROC_T *p)
3233 {
3234 int i;
3235 char *cp, *endstr, *str0;
3236 struct nfsusrgrp *usrp;
3237 int cnt, ret;
3238 int error = 0;
3239 uid_t tuid;
3240 struct nfsrv_lughash *hp, *hp2;
3241
3242 if (len == 0) {
3243 error = NFSERR_BADOWNER;
3244 goto out;
3245 }
3246 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3247 str0 = str;
3248 tuid = (uid_t)strtoul(str0, &endstr, 10);
3249 if ((endstr - str0) == len) {
3250 /* A numeric string. */
3251 if ((nd->nd_flag & ND_KERBV) == 0 &&
3252 ((nd->nd_flag & ND_NFSCL) != 0 ||
3253 nfsd_enable_stringtouid != 0))
3254 *uidp = tuid;
3255 else
3256 error = NFSERR_BADOWNER;
3257 goto out;
3258 }
3259 /*
3260 * Look for an '@'.
3261 */
3262 cp = strchr(str0, '@');
3263 if (cp != NULL)
3264 i = (int)(cp++ - str0);
3265 else
3266 i = len;
3267
3268 cnt = 0;
3269 tryagain:
3270 if (nfsrv_dnsnamelen > 0) {
3271 /*
3272 * If an '@' is found and the domain name matches, search for
3273 * the name with dns stripped off.
3274 * Mixed case alpahbetics will match for the domain name, but
3275 * all upper case will not.
3276 */
3277 if (cnt == 0 && i < len && i > 0 &&
3278 (len - 1 - i) == nfsrv_dnsnamelen &&
3279 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3280 len -= (nfsrv_dnsnamelen + 1);
3281 *(cp - 1) = '\0';
3282 }
3283
3284 /*
3285 * Check for the special case of "nobody".
3286 */
3287 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3288 *uidp = nfsrv_defaultuid;
3289 error = 0;
3290 goto out;
3291 }
3292
3293 hp = NFSUSERNAMEHASH(str, len);
3294 mtx_lock(&hp->mtx);
3295 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3296 if (usrp->lug_namelen == len &&
3297 !NFSBCMP(usrp->lug_name, str, len)) {
3298 if (usrp->lug_expiry < NFSD_MONOSEC)
3299 break;
3300 hp2 = NFSUSERHASH(usrp->lug_uid);
3301 mtx_lock(&hp2->mtx);
3302 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3303 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3304 lug_numhash);
3305 *uidp = usrp->lug_uid;
3306 mtx_unlock(&hp2->mtx);
3307 mtx_unlock(&hp->mtx);
3308 error = 0;
3309 goto out;
3310 }
3311 }
3312 mtx_unlock(&hp->mtx);
3313 cnt++;
3314 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3315 str, p);
3316 if (ret == 0 && cnt < 2)
3317 goto tryagain;
3318 }
3319 error = NFSERR_BADOWNER;
3320
3321 out:
3322 NFSEXITCODE(error);
3323 return (error);
3324 }
3325
3326 /*
3327 * Convert a gid to a string.
3328 * gid - the group id
3329 * cpp - points to a buffer of size NFSV4_SMALLSTR
3330 * (malloc a larger one, as required)
3331 * retlenp - pointer to length to be returned
3332 */
3333 void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp,NFSPROC_T * p)3334 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
3335 {
3336 int i;
3337 struct nfsusrgrp *usrp;
3338 u_char *cp = *cpp;
3339 gid_t tmp;
3340 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3341 struct nfsrv_lughash *hp;
3342
3343 cnt = 0;
3344 tryagain:
3345 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3346 /*
3347 * Always map nfsrv_defaultgid to "nogroup".
3348 */
3349 if (gid == nfsrv_defaultgid) {
3350 i = nfsrv_dnsnamelen + 8;
3351 if (i > len) {
3352 if (len > NFSV4_SMALLSTR)
3353 free(cp, M_NFSSTRING);
3354 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3355 *cpp = cp;
3356 len = i;
3357 goto tryagain;
3358 }
3359 *retlenp = i;
3360 NFSBCOPY("nogroup@", cp, 8);
3361 cp += 8;
3362 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3363 return;
3364 }
3365 hasampersand = 0;
3366 hp = NFSGROUPHASH(gid);
3367 mtx_lock(&hp->mtx);
3368 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3369 if (usrp->lug_gid == gid) {
3370 if (usrp->lug_expiry < NFSD_MONOSEC)
3371 break;
3372 /*
3373 * If the name doesn't already have an '@'
3374 * in it, append @domainname to it.
3375 */
3376 for (i = 0; i < usrp->lug_namelen; i++) {
3377 if (usrp->lug_name[i] == '@') {
3378 hasampersand = 1;
3379 break;
3380 }
3381 }
3382 if (hasampersand)
3383 i = usrp->lug_namelen;
3384 else
3385 i = usrp->lug_namelen +
3386 nfsrv_dnsnamelen + 1;
3387 if (i > len) {
3388 mtx_unlock(&hp->mtx);
3389 if (len > NFSV4_SMALLSTR)
3390 free(cp, M_NFSSTRING);
3391 cp = malloc(i, M_NFSSTRING, M_WAITOK);
3392 *cpp = cp;
3393 len = i;
3394 goto tryagain;
3395 }
3396 *retlenp = i;
3397 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3398 if (!hasampersand) {
3399 cp += usrp->lug_namelen;
3400 *cp++ = '@';
3401 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3402 }
3403 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3404 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3405 lug_numhash);
3406 mtx_unlock(&hp->mtx);
3407 return;
3408 }
3409 }
3410 mtx_unlock(&hp->mtx);
3411 cnt++;
3412 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
3413 NULL, p);
3414 if (ret == 0 && cnt < 2)
3415 goto tryagain;
3416 }
3417
3418 /*
3419 * No match, just return a string of digits.
3420 */
3421 tmp = gid;
3422 i = 0;
3423 while (tmp || i == 0) {
3424 tmp /= 10;
3425 i++;
3426 }
3427 len = (i > len) ? len : i;
3428 *retlenp = len;
3429 cp += (len - 1);
3430 tmp = gid;
3431 for (i = 0; i < len; i++) {
3432 *cp-- = '0' + (tmp % 10);
3433 tmp /= 10;
3434 }
3435 return;
3436 }
3437
3438 /*
3439 * Convert a string to a gid.
3440 * If no conversion is possible return NFSERR_BADOWNER, otherwise
3441 * return 0.
3442 * If this is called from a client side mount using AUTH_SYS and the
3443 * string is made up entirely of digits, just convert the string to
3444 * a number.
3445 */
3446 int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp,NFSPROC_T * p)3447 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
3448 NFSPROC_T *p)
3449 {
3450 int i;
3451 char *cp, *endstr, *str0;
3452 struct nfsusrgrp *usrp;
3453 int cnt, ret;
3454 int error = 0;
3455 gid_t tgid;
3456 struct nfsrv_lughash *hp, *hp2;
3457
3458 if (len == 0) {
3459 error = NFSERR_BADOWNER;
3460 goto out;
3461 }
3462 /* If a string of digits and an AUTH_SYS mount, just convert it. */
3463 str0 = str;
3464 tgid = (gid_t)strtoul(str0, &endstr, 10);
3465 if ((endstr - str0) == len) {
3466 /* A numeric string. */
3467 if ((nd->nd_flag & ND_KERBV) == 0 &&
3468 ((nd->nd_flag & ND_NFSCL) != 0 ||
3469 nfsd_enable_stringtouid != 0))
3470 *gidp = tgid;
3471 else
3472 error = NFSERR_BADOWNER;
3473 goto out;
3474 }
3475 /*
3476 * Look for an '@'.
3477 */
3478 cp = strchr(str0, '@');
3479 if (cp != NULL)
3480 i = (int)(cp++ - str0);
3481 else
3482 i = len;
3483
3484 cnt = 0;
3485 tryagain:
3486 if (nfsrv_dnsnamelen > 0) {
3487 /*
3488 * If an '@' is found and the dns name matches, search for the
3489 * name with the dns stripped off.
3490 */
3491 if (cnt == 0 && i < len && i > 0 &&
3492 (len - 1 - i) == nfsrv_dnsnamelen &&
3493 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3494 len -= (nfsrv_dnsnamelen + 1);
3495 *(cp - 1) = '\0';
3496 }
3497
3498 /*
3499 * Check for the special case of "nogroup".
3500 */
3501 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3502 *gidp = nfsrv_defaultgid;
3503 error = 0;
3504 goto out;
3505 }
3506
3507 hp = NFSGROUPNAMEHASH(str, len);
3508 mtx_lock(&hp->mtx);
3509 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3510 if (usrp->lug_namelen == len &&
3511 !NFSBCMP(usrp->lug_name, str, len)) {
3512 if (usrp->lug_expiry < NFSD_MONOSEC)
3513 break;
3514 hp2 = NFSGROUPHASH(usrp->lug_gid);
3515 mtx_lock(&hp2->mtx);
3516 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3517 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3518 lug_numhash);
3519 *gidp = usrp->lug_gid;
3520 mtx_unlock(&hp2->mtx);
3521 mtx_unlock(&hp->mtx);
3522 error = 0;
3523 goto out;
3524 }
3525 }
3526 mtx_unlock(&hp->mtx);
3527 cnt++;
3528 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3529 str, p);
3530 if (ret == 0 && cnt < 2)
3531 goto tryagain;
3532 }
3533 error = NFSERR_BADOWNER;
3534
3535 out:
3536 NFSEXITCODE(error);
3537 return (error);
3538 }
3539
3540 /*
3541 * Cmp len chars, allowing mixed case in the first argument to match lower
3542 * case in the second, but not if the first argument is all upper case.
3543 * Return 0 for a match, 1 otherwise.
3544 */
3545 static int
nfsrv_cmpmixedcase(u_char * cp,u_char * cp2,int len)3546 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3547 {
3548 int i;
3549 u_char tmp;
3550 int fndlower = 0;
3551
3552 for (i = 0; i < len; i++) {
3553 if (*cp >= 'A' && *cp <= 'Z') {
3554 tmp = *cp++ + ('a' - 'A');
3555 } else {
3556 tmp = *cp++;
3557 if (tmp >= 'a' && tmp <= 'z')
3558 fndlower = 1;
3559 }
3560 if (tmp != *cp2++)
3561 return (1);
3562 }
3563 if (fndlower)
3564 return (0);
3565 else
3566 return (1);
3567 }
3568
3569 /*
3570 * Set the port for the nfsuserd.
3571 */
3572 int
nfsrv_nfsuserdport(struct nfsuserd_args * nargs,NFSPROC_T * p)3573 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3574 {
3575 struct nfssockreq *rp;
3576 #ifdef INET
3577 struct sockaddr_in *ad;
3578 #endif
3579 #ifdef INET6
3580 struct sockaddr_in6 *ad6;
3581 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3582 #endif
3583 int error;
3584
3585 NFSLOCKNAMEID();
3586 if (nfsrv_nfsuserd != NOTRUNNING) {
3587 NFSUNLOCKNAMEID();
3588 error = EPERM;
3589 goto out;
3590 }
3591 nfsrv_nfsuserd = STARTSTOP;
3592 /*
3593 * Set up the socket record and connect.
3594 * Set nr_client NULL before unlocking, just to ensure that no other
3595 * process/thread/core will use a bogus old value. This could only
3596 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3597 * broken.
3598 */
3599 rp = &nfsrv_nfsuserdsock;
3600 rp->nr_client = NULL;
3601 NFSUNLOCKNAMEID();
3602 rp->nr_sotype = SOCK_DGRAM;
3603 rp->nr_soproto = IPPROTO_UDP;
3604 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3605 rp->nr_cred = NULL;
3606 rp->nr_prog = RPCPROG_NFSUSERD;
3607 error = 0;
3608 switch (nargs->nuserd_family) {
3609 #ifdef INET
3610 case AF_INET:
3611 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3612 M_WAITOK | M_ZERO);
3613 ad = (struct sockaddr_in *)rp->nr_nam;
3614 ad->sin_len = sizeof(struct sockaddr_in);
3615 ad->sin_family = AF_INET;
3616 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3617 ad->sin_port = nargs->nuserd_port;
3618 break;
3619 #endif
3620 #ifdef INET6
3621 case AF_INET6:
3622 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3623 M_WAITOK | M_ZERO);
3624 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3625 ad6->sin6_len = sizeof(struct sockaddr_in6);
3626 ad6->sin6_family = AF_INET6;
3627 ad6->sin6_addr = in6loopback;
3628 ad6->sin6_port = nargs->nuserd_port;
3629 break;
3630 #endif
3631 default:
3632 error = ENXIO;
3633 }
3634 rp->nr_vers = RPCNFSUSERD_VERS;
3635 if (error == 0)
3636 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3637 if (error == 0) {
3638 NFSLOCKNAMEID();
3639 nfsrv_nfsuserd = RUNNING;
3640 NFSUNLOCKNAMEID();
3641 } else {
3642 free(rp->nr_nam, M_SONAME);
3643 NFSLOCKNAMEID();
3644 nfsrv_nfsuserd = NOTRUNNING;
3645 NFSUNLOCKNAMEID();
3646 }
3647 out:
3648 NFSEXITCODE(error);
3649 return (error);
3650 }
3651
3652 /*
3653 * Delete the nfsuserd port.
3654 */
3655 void
nfsrv_nfsuserddelport(void)3656 nfsrv_nfsuserddelport(void)
3657 {
3658
3659 NFSLOCKNAMEID();
3660 if (nfsrv_nfsuserd != RUNNING) {
3661 NFSUNLOCKNAMEID();
3662 return;
3663 }
3664 nfsrv_nfsuserd = STARTSTOP;
3665 /* Wait for all upcalls to complete. */
3666 while (nfsrv_userdupcalls > 0)
3667 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
3668 "nfsupcalls", 0);
3669 NFSUNLOCKNAMEID();
3670 newnfs_disconnect(&nfsrv_nfsuserdsock);
3671 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3672 NFSLOCKNAMEID();
3673 nfsrv_nfsuserd = NOTRUNNING;
3674 NFSUNLOCKNAMEID();
3675 }
3676
3677 /*
3678 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3679 * name<-->id cache.
3680 * Returns 0 upon success, non-zero otherwise.
3681 */
3682 static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name,NFSPROC_T * p)3683 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3684 {
3685 u_int32_t *tl;
3686 struct nfsrv_descript *nd;
3687 int len;
3688 struct nfsrv_descript nfsd;
3689 struct ucred *cred;
3690 int error;
3691
3692 NFSLOCKNAMEID();
3693 if (nfsrv_nfsuserd != RUNNING) {
3694 NFSUNLOCKNAMEID();
3695 error = EPERM;
3696 goto out;
3697 }
3698 /*
3699 * Maintain a count of upcalls in progress, so that nfsrv_X()
3700 * can wait until no upcalls are in progress.
3701 */
3702 nfsrv_userdupcalls++;
3703 NFSUNLOCKNAMEID();
3704 KASSERT(nfsrv_userdupcalls > 0,
3705 ("nfsrv_getuser: non-positive upcalls"));
3706 nd = &nfsd;
3707 cred = newnfs_getcred();
3708 nd->nd_flag = ND_GSSINITREPLY;
3709 nfsrvd_rephead(nd);
3710
3711 nd->nd_procnum = procnum;
3712 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3713 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3714 if (procnum == RPCNFSUSERD_GETUID)
3715 *tl = txdr_unsigned(uid);
3716 else
3717 *tl = txdr_unsigned(gid);
3718 } else {
3719 len = strlen(name);
3720 (void) nfsm_strtom(nd, name, len);
3721 }
3722 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3723 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3724 NFSLOCKNAMEID();
3725 if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
3726 wakeup(&nfsrv_userdupcalls);
3727 NFSUNLOCKNAMEID();
3728 NFSFREECRED(cred);
3729 if (!error) {
3730 mbuf_freem(nd->nd_mrep);
3731 error = nd->nd_repstat;
3732 }
3733 out:
3734 NFSEXITCODE(error);
3735 return (error);
3736 }
3737
3738 /*
3739 * This function is called from the nfssvc(2) system call, to update the
3740 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3741 */
3742 int
nfssvc_idname(struct nfsd_idargs * nidp)3743 nfssvc_idname(struct nfsd_idargs *nidp)
3744 {
3745 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3746 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3747 int i, group_locked, groupname_locked, user_locked, username_locked;
3748 int error = 0;
3749 u_char *cp;
3750 gid_t *grps;
3751 struct ucred *cr;
3752 static int onethread = 0;
3753 static time_t lasttime = 0;
3754
3755 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3756 error = EINVAL;
3757 goto out;
3758 }
3759 if (nidp->nid_flag & NFSID_INITIALIZE) {
3760 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3761 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3762 nidp->nid_namelen);
3763 if (error != 0) {
3764 free(cp, M_NFSSTRING);
3765 goto out;
3766 }
3767 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3768 /*
3769 * Free up all the old stuff and reinitialize hash
3770 * lists. All mutexes for both lists must be locked,
3771 * with the user/group name ones before the uid/gid
3772 * ones, to avoid a LOR.
3773 */
3774 for (i = 0; i < nfsrv_lughashsize; i++)
3775 mtx_lock(&nfsusernamehash[i].mtx);
3776 for (i = 0; i < nfsrv_lughashsize; i++)
3777 mtx_lock(&nfsuserhash[i].mtx);
3778 for (i = 0; i < nfsrv_lughashsize; i++)
3779 TAILQ_FOREACH_SAFE(usrp,
3780 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3781 nfsrv_removeuser(usrp, 1);
3782 for (i = 0; i < nfsrv_lughashsize; i++)
3783 mtx_unlock(&nfsuserhash[i].mtx);
3784 for (i = 0; i < nfsrv_lughashsize; i++)
3785 mtx_unlock(&nfsusernamehash[i].mtx);
3786 for (i = 0; i < nfsrv_lughashsize; i++)
3787 mtx_lock(&nfsgroupnamehash[i].mtx);
3788 for (i = 0; i < nfsrv_lughashsize; i++)
3789 mtx_lock(&nfsgrouphash[i].mtx);
3790 for (i = 0; i < nfsrv_lughashsize; i++)
3791 TAILQ_FOREACH_SAFE(usrp,
3792 &nfsgrouphash[i].lughead, lug_numhash,
3793 nusrp)
3794 nfsrv_removeuser(usrp, 0);
3795 for (i = 0; i < nfsrv_lughashsize; i++)
3796 mtx_unlock(&nfsgrouphash[i].mtx);
3797 for (i = 0; i < nfsrv_lughashsize; i++)
3798 mtx_unlock(&nfsgroupnamehash[i].mtx);
3799 free(nfsrv_dnsname, M_NFSSTRING);
3800 nfsrv_dnsname = NULL;
3801 }
3802 if (nfsuserhash == NULL) {
3803 /* Allocate the hash tables. */
3804 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3805 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3806 M_ZERO);
3807 for (i = 0; i < nfsrv_lughashsize; i++)
3808 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3809 NULL, MTX_DEF | MTX_DUPOK);
3810 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3811 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3812 M_ZERO);
3813 for (i = 0; i < nfsrv_lughashsize; i++)
3814 mtx_init(&nfsusernamehash[i].mtx,
3815 "nfsusrhash", NULL, MTX_DEF |
3816 MTX_DUPOK);
3817 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3818 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3819 M_ZERO);
3820 for (i = 0; i < nfsrv_lughashsize; i++)
3821 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3822 NULL, MTX_DEF | MTX_DUPOK);
3823 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3824 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3825 M_ZERO);
3826 for (i = 0; i < nfsrv_lughashsize; i++)
3827 mtx_init(&nfsgroupnamehash[i].mtx,
3828 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3829 }
3830 /* (Re)initialize the list heads. */
3831 for (i = 0; i < nfsrv_lughashsize; i++)
3832 TAILQ_INIT(&nfsuserhash[i].lughead);
3833 for (i = 0; i < nfsrv_lughashsize; i++)
3834 TAILQ_INIT(&nfsusernamehash[i].lughead);
3835 for (i = 0; i < nfsrv_lughashsize; i++)
3836 TAILQ_INIT(&nfsgrouphash[i].lughead);
3837 for (i = 0; i < nfsrv_lughashsize; i++)
3838 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3839
3840 /*
3841 * Put name in "DNS" string.
3842 */
3843 nfsrv_dnsname = cp;
3844 nfsrv_defaultuid = nidp->nid_uid;
3845 nfsrv_defaultgid = nidp->nid_gid;
3846 nfsrv_usercnt = 0;
3847 nfsrv_usermax = nidp->nid_usermax;
3848 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3849 goto out;
3850 }
3851
3852 /*
3853 * malloc the new one now, so any potential sleep occurs before
3854 * manipulation of the lists.
3855 */
3856 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3857 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3858 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3859 nidp->nid_namelen);
3860 if (error == 0 && nidp->nid_ngroup > 0 &&
3861 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3862 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3863 M_WAITOK);
3864 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3865 sizeof(gid_t) * nidp->nid_ngroup);
3866 if (error == 0) {
3867 /*
3868 * Create a credential just like svc_getcred(),
3869 * but using the group list provided.
3870 */
3871 cr = crget();
3872 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3873 crsetgroups(cr, nidp->nid_ngroup, grps);
3874 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3875 cr->cr_prison = &prison0;
3876 prison_hold(cr->cr_prison);
3877 #ifdef MAC
3878 mac_cred_associate_nfsd(cr);
3879 #endif
3880 newusrp->lug_cred = cr;
3881 }
3882 free(grps, M_TEMP);
3883 }
3884 if (error) {
3885 free(newusrp, M_NFSUSERGROUP);
3886 goto out;
3887 }
3888 newusrp->lug_namelen = nidp->nid_namelen;
3889
3890 /*
3891 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3892 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3893 * The flags user_locked, username_locked, group_locked and
3894 * groupname_locked are set to indicate all of those hash lists are
3895 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3896 * the respective one mutex is locked.
3897 */
3898 user_locked = username_locked = group_locked = groupname_locked = 0;
3899 hp_name = hp_idnum = NULL;
3900
3901 /*
3902 * Delete old entries, as required.
3903 */
3904 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3905 /* Must lock all username hash lists first, to avoid a LOR. */
3906 for (i = 0; i < nfsrv_lughashsize; i++)
3907 mtx_lock(&nfsusernamehash[i].mtx);
3908 username_locked = 1;
3909 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3910 mtx_lock(&hp_idnum->mtx);
3911 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3912 nusrp) {
3913 if (usrp->lug_uid == nidp->nid_uid)
3914 nfsrv_removeuser(usrp, 1);
3915 }
3916 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3917 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3918 newusrp->lug_namelen);
3919 mtx_lock(&hp_name->mtx);
3920 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3921 nusrp) {
3922 if (usrp->lug_namelen == newusrp->lug_namelen &&
3923 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3924 usrp->lug_namelen)) {
3925 thp = NFSUSERHASH(usrp->lug_uid);
3926 mtx_lock(&thp->mtx);
3927 nfsrv_removeuser(usrp, 1);
3928 mtx_unlock(&thp->mtx);
3929 }
3930 }
3931 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3932 mtx_lock(&hp_idnum->mtx);
3933 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3934 /* Must lock all groupname hash lists first, to avoid a LOR. */
3935 for (i = 0; i < nfsrv_lughashsize; i++)
3936 mtx_lock(&nfsgroupnamehash[i].mtx);
3937 groupname_locked = 1;
3938 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3939 mtx_lock(&hp_idnum->mtx);
3940 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3941 nusrp) {
3942 if (usrp->lug_gid == nidp->nid_gid)
3943 nfsrv_removeuser(usrp, 0);
3944 }
3945 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3946 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3947 newusrp->lug_namelen);
3948 mtx_lock(&hp_name->mtx);
3949 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3950 nusrp) {
3951 if (usrp->lug_namelen == newusrp->lug_namelen &&
3952 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3953 usrp->lug_namelen)) {
3954 thp = NFSGROUPHASH(usrp->lug_gid);
3955 mtx_lock(&thp->mtx);
3956 nfsrv_removeuser(usrp, 0);
3957 mtx_unlock(&thp->mtx);
3958 }
3959 }
3960 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3961 mtx_lock(&hp_idnum->mtx);
3962 }
3963
3964 /*
3965 * Now, we can add the new one.
3966 */
3967 if (nidp->nid_usertimeout)
3968 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3969 else
3970 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3971 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3972 newusrp->lug_uid = nidp->nid_uid;
3973 thp = NFSUSERHASH(newusrp->lug_uid);
3974 mtx_assert(&thp->mtx, MA_OWNED);
3975 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3976 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3977 mtx_assert(&thp->mtx, MA_OWNED);
3978 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3979 atomic_add_int(&nfsrv_usercnt, 1);
3980 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3981 newusrp->lug_gid = nidp->nid_gid;
3982 thp = NFSGROUPHASH(newusrp->lug_gid);
3983 mtx_assert(&thp->mtx, MA_OWNED);
3984 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3985 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3986 mtx_assert(&thp->mtx, MA_OWNED);
3987 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3988 atomic_add_int(&nfsrv_usercnt, 1);
3989 } else {
3990 if (newusrp->lug_cred != NULL)
3991 crfree(newusrp->lug_cred);
3992 free(newusrp, M_NFSUSERGROUP);
3993 }
3994
3995 /*
3996 * Once per second, allow one thread to trim the cache.
3997 */
3998 if (lasttime < NFSD_MONOSEC &&
3999 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4000 /*
4001 * First, unlock the single mutexes, so that all entries
4002 * can be locked and any LOR is avoided.
4003 */
4004 if (hp_name != NULL) {
4005 mtx_unlock(&hp_name->mtx);
4006 hp_name = NULL;
4007 }
4008 if (hp_idnum != NULL) {
4009 mtx_unlock(&hp_idnum->mtx);
4010 hp_idnum = NULL;
4011 }
4012
4013 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4014 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4015 if (username_locked == 0) {
4016 for (i = 0; i < nfsrv_lughashsize; i++)
4017 mtx_lock(&nfsusernamehash[i].mtx);
4018 username_locked = 1;
4019 }
4020 KASSERT(user_locked == 0,
4021 ("nfssvc_idname: user_locked"));
4022 for (i = 0; i < nfsrv_lughashsize; i++)
4023 mtx_lock(&nfsuserhash[i].mtx);
4024 user_locked = 1;
4025 for (i = 0; i < nfsrv_lughashsize; i++) {
4026 TAILQ_FOREACH_SAFE(usrp,
4027 &nfsuserhash[i].lughead, lug_numhash,
4028 nusrp)
4029 if (usrp->lug_expiry < NFSD_MONOSEC)
4030 nfsrv_removeuser(usrp, 1);
4031 }
4032 for (i = 0; i < nfsrv_lughashsize; i++) {
4033 /*
4034 * Trim the cache using an approximate LRU
4035 * algorithm. This code deletes the least
4036 * recently used entry on each hash list.
4037 */
4038 if (nfsrv_usercnt <= nfsrv_usermax)
4039 break;
4040 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
4041 if (usrp != NULL)
4042 nfsrv_removeuser(usrp, 1);
4043 }
4044 } else {
4045 if (groupname_locked == 0) {
4046 for (i = 0; i < nfsrv_lughashsize; i++)
4047 mtx_lock(&nfsgroupnamehash[i].mtx);
4048 groupname_locked = 1;
4049 }
4050 KASSERT(group_locked == 0,
4051 ("nfssvc_idname: group_locked"));
4052 for (i = 0; i < nfsrv_lughashsize; i++)
4053 mtx_lock(&nfsgrouphash[i].mtx);
4054 group_locked = 1;
4055 for (i = 0; i < nfsrv_lughashsize; i++) {
4056 TAILQ_FOREACH_SAFE(usrp,
4057 &nfsgrouphash[i].lughead, lug_numhash,
4058 nusrp)
4059 if (usrp->lug_expiry < NFSD_MONOSEC)
4060 nfsrv_removeuser(usrp, 0);
4061 }
4062 for (i = 0; i < nfsrv_lughashsize; i++) {
4063 /*
4064 * Trim the cache using an approximate LRU
4065 * algorithm. This code deletes the least
4066 * recently user entry on each hash list.
4067 */
4068 if (nfsrv_usercnt <= nfsrv_usermax)
4069 break;
4070 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
4071 if (usrp != NULL)
4072 nfsrv_removeuser(usrp, 0);
4073 }
4074 }
4075 lasttime = NFSD_MONOSEC;
4076 atomic_store_rel_int(&onethread, 0);
4077 }
4078
4079 /* Now, unlock all locked mutexes. */
4080 if (hp_idnum != NULL)
4081 mtx_unlock(&hp_idnum->mtx);
4082 if (hp_name != NULL)
4083 mtx_unlock(&hp_name->mtx);
4084 if (user_locked != 0)
4085 for (i = 0; i < nfsrv_lughashsize; i++)
4086 mtx_unlock(&nfsuserhash[i].mtx);
4087 if (username_locked != 0)
4088 for (i = 0; i < nfsrv_lughashsize; i++)
4089 mtx_unlock(&nfsusernamehash[i].mtx);
4090 if (group_locked != 0)
4091 for (i = 0; i < nfsrv_lughashsize; i++)
4092 mtx_unlock(&nfsgrouphash[i].mtx);
4093 if (groupname_locked != 0)
4094 for (i = 0; i < nfsrv_lughashsize; i++)
4095 mtx_unlock(&nfsgroupnamehash[i].mtx);
4096 out:
4097 NFSEXITCODE(error);
4098 return (error);
4099 }
4100
4101 /*
4102 * Remove a user/group name element.
4103 */
4104 static void
nfsrv_removeuser(struct nfsusrgrp * usrp,int isuser)4105 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4106 {
4107 struct nfsrv_lughash *hp;
4108
4109 if (isuser != 0) {
4110 hp = NFSUSERHASH(usrp->lug_uid);
4111 mtx_assert(&hp->mtx, MA_OWNED);
4112 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4113 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4114 mtx_assert(&hp->mtx, MA_OWNED);
4115 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4116 } else {
4117 hp = NFSGROUPHASH(usrp->lug_gid);
4118 mtx_assert(&hp->mtx, MA_OWNED);
4119 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4120 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4121 mtx_assert(&hp->mtx, MA_OWNED);
4122 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4123 }
4124 atomic_add_int(&nfsrv_usercnt, -1);
4125 if (usrp->lug_cred != NULL)
4126 crfree(usrp->lug_cred);
4127 free(usrp, M_NFSUSERGROUP);
4128 }
4129
4130 /*
4131 * Free up all the allocations related to the name<-->id cache.
4132 * This function should only be called when the nfsuserd daemon isn't
4133 * running, since it doesn't do any locking.
4134 * This function is meant to be used when the nfscommon module is unloaded.
4135 */
4136 void
nfsrv_cleanusergroup(void)4137 nfsrv_cleanusergroup(void)
4138 {
4139 struct nfsrv_lughash *hp, *hp2;
4140 struct nfsusrgrp *nusrp, *usrp;
4141 int i;
4142
4143 if (nfsuserhash == NULL)
4144 return;
4145
4146 for (i = 0; i < nfsrv_lughashsize; i++) {
4147 hp = &nfsuserhash[i];
4148 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4149 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4150 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4151 usrp->lug_namelen);
4152 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4153 if (usrp->lug_cred != NULL)
4154 crfree(usrp->lug_cred);
4155 free(usrp, M_NFSUSERGROUP);
4156 }
4157 hp = &nfsgrouphash[i];
4158 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4159 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4160 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4161 usrp->lug_namelen);
4162 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4163 if (usrp->lug_cred != NULL)
4164 crfree(usrp->lug_cred);
4165 free(usrp, M_NFSUSERGROUP);
4166 }
4167 mtx_destroy(&nfsuserhash[i].mtx);
4168 mtx_destroy(&nfsusernamehash[i].mtx);
4169 mtx_destroy(&nfsgroupnamehash[i].mtx);
4170 mtx_destroy(&nfsgrouphash[i].mtx);
4171 }
4172 free(nfsuserhash, M_NFSUSERGROUP);
4173 free(nfsusernamehash, M_NFSUSERGROUP);
4174 free(nfsgrouphash, M_NFSUSERGROUP);
4175 free(nfsgroupnamehash, M_NFSUSERGROUP);
4176 free(nfsrv_dnsname, M_NFSSTRING);
4177 }
4178
4179 /*
4180 * This function scans a byte string and checks for UTF-8 compliance.
4181 * It returns 0 if it conforms and NFSERR_INVAL if not.
4182 */
4183 int
nfsrv_checkutf8(u_int8_t * cp,int len)4184 nfsrv_checkutf8(u_int8_t *cp, int len)
4185 {
4186 u_int32_t val = 0x0;
4187 int cnt = 0, gotd = 0, shift = 0;
4188 u_int8_t byte;
4189 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4190 int error = 0;
4191
4192 /*
4193 * Here are what the variables are used for:
4194 * val - the calculated value of a multibyte char, used to check
4195 * that it was coded with the correct range
4196 * cnt - the number of 10xxxxxx bytes to follow
4197 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4198 * shift - lower order bits of range (ie. "val >> shift" should
4199 * not be 0, in other words, dividing by the lower bound
4200 * of the range should get a non-zero value)
4201 * byte - used to calculate cnt
4202 */
4203 while (len > 0) {
4204 if (cnt > 0) {
4205 /* This handles the 10xxxxxx bytes */
4206 if ((*cp & 0xc0) != 0x80 ||
4207 (gotd && (*cp & 0x20))) {
4208 error = NFSERR_INVAL;
4209 goto out;
4210 }
4211 gotd = 0;
4212 val <<= 6;
4213 val |= (*cp & 0x3f);
4214 cnt--;
4215 if (cnt == 0 && (val >> shift) == 0x0) {
4216 error = NFSERR_INVAL;
4217 goto out;
4218 }
4219 } else if (*cp & 0x80) {
4220 /* first byte of multi byte char */
4221 byte = *cp;
4222 while ((byte & 0x40) && cnt < 6) {
4223 cnt++;
4224 byte <<= 1;
4225 }
4226 if (cnt == 0 || cnt == 6) {
4227 error = NFSERR_INVAL;
4228 goto out;
4229 }
4230 val = (*cp & (0x3f >> cnt));
4231 shift = utf8_shift[cnt - 1];
4232 if (cnt == 2 && val == 0xd)
4233 /* Check for the 0xd800-0xdfff case */
4234 gotd = 1;
4235 }
4236 cp++;
4237 len--;
4238 }
4239 if (cnt > 0)
4240 error = NFSERR_INVAL;
4241
4242 out:
4243 NFSEXITCODE(error);
4244 return (error);
4245 }
4246
4247 /*
4248 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4249 * strings, one with the root path in it and the other with the list of
4250 * locations. The list is in the same format as is found in nfr_refs.
4251 * It is a "," separated list of entries, where each of them is of the
4252 * form <server>:<rootpath>. For example
4253 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4254 * The nilp argument is set to 1 for the special case of a null fs_root
4255 * and an empty server list.
4256 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4257 * number of xdr bytes parsed in sump.
4258 */
4259 static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)4260 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4261 int *sump, int *nilp)
4262 {
4263 u_int32_t *tl;
4264 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4265 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4266 struct list {
4267 SLIST_ENTRY(list) next;
4268 int len;
4269 u_char host[1];
4270 } *lsp, *nlsp;
4271 SLIST_HEAD(, list) head;
4272
4273 *fsrootp = NULL;
4274 *srvp = NULL;
4275 *nilp = 0;
4276
4277 /*
4278 * Get the fs_root path and check for the special case of null path
4279 * and 0 length server list.
4280 */
4281 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4282 len = fxdr_unsigned(int, *tl);
4283 if (len < 0 || len > 10240) {
4284 error = NFSERR_BADXDR;
4285 goto nfsmout;
4286 }
4287 if (len == 0) {
4288 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4289 if (*tl != 0) {
4290 error = NFSERR_BADXDR;
4291 goto nfsmout;
4292 }
4293 *nilp = 1;
4294 *sump = 2 * NFSX_UNSIGNED;
4295 error = 0;
4296 goto nfsmout;
4297 }
4298 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4299 error = nfsrv_mtostr(nd, cp, len);
4300 if (!error) {
4301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4302 cnt = fxdr_unsigned(int, *tl);
4303 if (cnt <= 0)
4304 error = NFSERR_BADXDR;
4305 }
4306 if (error)
4307 goto nfsmout;
4308
4309 /*
4310 * Now, loop through the location list and make up the srvlist.
4311 */
4312 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4313 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4314 slen = 1024;
4315 siz = 0;
4316 for (i = 0; i < cnt; i++) {
4317 SLIST_INIT(&head);
4318 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4319 nsrv = fxdr_unsigned(int, *tl);
4320 if (nsrv <= 0) {
4321 error = NFSERR_BADXDR;
4322 goto nfsmout;
4323 }
4324
4325 /*
4326 * Handle the first server by putting it in the srvstr.
4327 */
4328 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4329 len = fxdr_unsigned(int, *tl);
4330 if (len <= 0 || len > 1024) {
4331 error = NFSERR_BADXDR;
4332 goto nfsmout;
4333 }
4334 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4335 if (cp3 != cp2) {
4336 *cp3++ = ',';
4337 siz++;
4338 }
4339 error = nfsrv_mtostr(nd, cp3, len);
4340 if (error)
4341 goto nfsmout;
4342 cp3 += len;
4343 *cp3++ = ':';
4344 siz += (len + 1);
4345 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4346 for (j = 1; j < nsrv; j++) {
4347 /*
4348 * Yuck, put them in an slist and process them later.
4349 */
4350 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4351 len = fxdr_unsigned(int, *tl);
4352 if (len <= 0 || len > 1024) {
4353 error = NFSERR_BADXDR;
4354 goto nfsmout;
4355 }
4356 lsp = (struct list *)malloc(sizeof (struct list)
4357 + len, M_TEMP, M_WAITOK);
4358 error = nfsrv_mtostr(nd, lsp->host, len);
4359 if (error)
4360 goto nfsmout;
4361 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4362 lsp->len = len;
4363 SLIST_INSERT_HEAD(&head, lsp, next);
4364 }
4365
4366 /*
4367 * Finally, we can get the path.
4368 */
4369 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4370 len = fxdr_unsigned(int, *tl);
4371 if (len <= 0 || len > 1024) {
4372 error = NFSERR_BADXDR;
4373 goto nfsmout;
4374 }
4375 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4376 error = nfsrv_mtostr(nd, cp3, len);
4377 if (error)
4378 goto nfsmout;
4379 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4380 str = cp3;
4381 stringlen = len;
4382 cp3 += len;
4383 siz += len;
4384 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4385 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4386 &cp2, &cp3, &slen);
4387 *cp3++ = ',';
4388 NFSBCOPY(lsp->host, cp3, lsp->len);
4389 cp3 += lsp->len;
4390 *cp3++ = ':';
4391 NFSBCOPY(str, cp3, stringlen);
4392 cp3 += stringlen;
4393 *cp3 = '\0';
4394 siz += (lsp->len + stringlen + 2);
4395 free(lsp, M_TEMP);
4396 }
4397 }
4398 *fsrootp = cp;
4399 *srvp = cp2;
4400 *sump = xdrsum;
4401 NFSEXITCODE2(0, nd);
4402 return (0);
4403 nfsmout:
4404 if (cp != NULL)
4405 free(cp, M_NFSSTRING);
4406 if (cp2 != NULL)
4407 free(cp2, M_NFSSTRING);
4408 NFSEXITCODE2(error, nd);
4409 return (error);
4410 }
4411
4412 /*
4413 * Make the malloc'd space large enough. This is a pain, but the xdr
4414 * doesn't set an upper bound on the side, so...
4415 */
4416 static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)4417 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4418 {
4419 u_char *cp;
4420 int i;
4421
4422 if (siz <= *slenp)
4423 return;
4424 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4425 NFSBCOPY(*cpp, cp, *slenp);
4426 free(*cpp, M_NFSSTRING);
4427 i = *cpp2 - *cpp;
4428 *cpp = cp;
4429 *cpp2 = cp + i;
4430 *slenp = siz + 1024;
4431 }
4432
4433 /*
4434 * Initialize the reply header data structures.
4435 */
4436 void
nfsrvd_rephead(struct nfsrv_descript * nd)4437 nfsrvd_rephead(struct nfsrv_descript *nd)
4438 {
4439 mbuf_t mreq;
4440
4441 /*
4442 * If this is a big reply, use a cluster.
4443 */
4444 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4445 nfs_bigreply[nd->nd_procnum]) {
4446 NFSMCLGET(mreq, M_WAITOK);
4447 nd->nd_mreq = mreq;
4448 nd->nd_mb = mreq;
4449 } else {
4450 NFSMGET(mreq);
4451 nd->nd_mreq = mreq;
4452 nd->nd_mb = mreq;
4453 }
4454 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4455 mbuf_setlen(mreq, 0);
4456
4457 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4458 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4459 }
4460
4461 /*
4462 * Lock a socket against others.
4463 * Currently used to serialize connect/disconnect attempts.
4464 */
4465 int
newnfs_sndlock(int * flagp)4466 newnfs_sndlock(int *flagp)
4467 {
4468 struct timespec ts;
4469
4470 NFSLOCKSOCK();
4471 while (*flagp & NFSR_SNDLOCK) {
4472 *flagp |= NFSR_WANTSND;
4473 ts.tv_sec = 0;
4474 ts.tv_nsec = 0;
4475 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4476 PZERO - 1, "nfsndlck", &ts);
4477 }
4478 *flagp |= NFSR_SNDLOCK;
4479 NFSUNLOCKSOCK();
4480 return (0);
4481 }
4482
4483 /*
4484 * Unlock the stream socket for others.
4485 */
4486 void
newnfs_sndunlock(int * flagp)4487 newnfs_sndunlock(int *flagp)
4488 {
4489
4490 NFSLOCKSOCK();
4491 if ((*flagp & NFSR_SNDLOCK) == 0)
4492 panic("nfs sndunlock");
4493 *flagp &= ~NFSR_SNDLOCK;
4494 if (*flagp & NFSR_WANTSND) {
4495 *flagp &= ~NFSR_WANTSND;
4496 wakeup((caddr_t)flagp);
4497 }
4498 NFSUNLOCKSOCK();
4499 }
4500
4501 int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_in * sin,struct sockaddr_in6 * sin6,sa_family_t * saf,int * isudp)4502 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4503 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4504 {
4505 struct in_addr saddr;
4506 uint32_t portnum, *tl;
4507 int i, j, k;
4508 sa_family_t af = AF_UNSPEC;
4509 char addr[64], protocol[5], *cp;
4510 int cantparse = 0, error = 0;
4511 uint16_t portv;
4512
4513 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4514 i = fxdr_unsigned(int, *tl);
4515 if (i >= 3 && i <= 4) {
4516 error = nfsrv_mtostr(nd, protocol, i);
4517 if (error)
4518 goto nfsmout;
4519 if (strcmp(protocol, "tcp") == 0) {
4520 af = AF_INET;
4521 *isudp = 0;
4522 } else if (strcmp(protocol, "udp") == 0) {
4523 af = AF_INET;
4524 *isudp = 1;
4525 } else if (strcmp(protocol, "tcp6") == 0) {
4526 af = AF_INET6;
4527 *isudp = 0;
4528 } else if (strcmp(protocol, "udp6") == 0) {
4529 af = AF_INET6;
4530 *isudp = 1;
4531 } else
4532 cantparse = 1;
4533 } else {
4534 cantparse = 1;
4535 if (i > 0) {
4536 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4537 if (error)
4538 goto nfsmout;
4539 }
4540 }
4541 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4542 i = fxdr_unsigned(int, *tl);
4543 if (i < 0) {
4544 error = NFSERR_BADXDR;
4545 goto nfsmout;
4546 } else if (cantparse == 0 && i >= 11 && i < 64) {
4547 /*
4548 * The shortest address is 11chars and the longest is < 64.
4549 */
4550 error = nfsrv_mtostr(nd, addr, i);
4551 if (error)
4552 goto nfsmout;
4553
4554 /* Find the port# at the end and extract that. */
4555 i = strlen(addr);
4556 k = 0;
4557 cp = &addr[i - 1];
4558 /* Count back two '.'s from end to get port# field. */
4559 for (j = 0; j < i; j++) {
4560 if (*cp == '.') {
4561 k++;
4562 if (k == 2)
4563 break;
4564 }
4565 cp--;
4566 }
4567 if (k == 2) {
4568 /*
4569 * The NFSv4 port# is appended as .N.N, where N is
4570 * a decimal # in the range 0-255, just like an inet4
4571 * address. Cheat and use inet_aton(), which will
4572 * return a Class A address and then shift the high
4573 * order 8bits over to convert it to the port#.
4574 */
4575 *cp++ = '\0';
4576 if (inet_aton(cp, &saddr) == 1) {
4577 portnum = ntohl(saddr.s_addr);
4578 portv = (uint16_t)((portnum >> 16) |
4579 (portnum & 0xff));
4580 } else
4581 cantparse = 1;
4582 } else
4583 cantparse = 1;
4584 if (cantparse == 0) {
4585 if (af == AF_INET) {
4586 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4587 sin->sin_len = sizeof(*sin);
4588 sin->sin_family = AF_INET;
4589 sin->sin_port = htons(portv);
4590 *saf = af;
4591 return (0);
4592 }
4593 } else {
4594 if (inet_pton(af, addr, &sin6->sin6_addr)
4595 == 1) {
4596 sin6->sin6_len = sizeof(*sin6);
4597 sin6->sin6_family = AF_INET6;
4598 sin6->sin6_port = htons(portv);
4599 *saf = af;
4600 return (0);
4601 }
4602 }
4603 }
4604 } else {
4605 if (i > 0) {
4606 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4607 if (error)
4608 goto nfsmout;
4609 }
4610 }
4611 error = EPERM;
4612 nfsmout:
4613 return (error);
4614 }
4615
4616 /*
4617 * Handle an NFSv4.1 Sequence request for the session.
4618 * If reply != NULL, use it to return the cached reply, as required.
4619 * The client gets a cached reply via this call for callbacks, however the
4620 * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4621 */
4622 int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)4623 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4624 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4625 {
4626 struct mbuf *m;
4627 int error;
4628
4629 error = 0;
4630 if (reply != NULL)
4631 *reply = NULL;
4632 if (slotid > maxslot)
4633 return (NFSERR_BADSLOT);
4634 if (seqid == slots[slotid].nfssl_seq) {
4635 /* A retry. */
4636 if (slots[slotid].nfssl_inprog != 0)
4637 error = NFSERR_DELAY;
4638 else if (slots[slotid].nfssl_reply != NULL) {
4639 if (reply != NULL) {
4640 m = m_copym(slots[slotid].nfssl_reply, 0,
4641 M_COPYALL, M_NOWAIT);
4642 if (m != NULL)
4643 *reply = m;
4644 else {
4645 *reply = slots[slotid].nfssl_reply;
4646 slots[slotid].nfssl_reply = NULL;
4647 }
4648 }
4649 slots[slotid].nfssl_inprog = 1;
4650 error = NFSERR_REPLYFROMCACHE;
4651 } else
4652 /* No reply cached, so just do it. */
4653 slots[slotid].nfssl_inprog = 1;
4654 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4655 if (slots[slotid].nfssl_reply != NULL)
4656 m_freem(slots[slotid].nfssl_reply);
4657 slots[slotid].nfssl_reply = NULL;
4658 slots[slotid].nfssl_inprog = 1;
4659 slots[slotid].nfssl_seq++;
4660 } else
4661 error = NFSERR_SEQMISORDERED;
4662 return (error);
4663 }
4664
4665 /*
4666 * Cache this reply for the slot.
4667 * Use the "rep" argument to return the cached reply if repstat is set to
4668 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4669 */
4670 void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,int repstat,struct mbuf ** rep)4671 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4672 struct mbuf **rep)
4673 {
4674 struct mbuf *m;
4675
4676 if (repstat == NFSERR_REPLYFROMCACHE) {
4677 if (slots[slotid].nfssl_reply != NULL) {
4678 /*
4679 * We cannot sleep here, but copy will usually
4680 * succeed.
4681 */
4682 m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
4683 M_NOWAIT);
4684 if (m != NULL)
4685 *rep = m;
4686 else {
4687 /*
4688 * Multiple retries would be extremely rare,
4689 * so using the cached reply will likely
4690 * be ok.
4691 */
4692 *rep = slots[slotid].nfssl_reply;
4693 slots[slotid].nfssl_reply = NULL;
4694 }
4695 } else
4696 *rep = NULL;
4697 } else {
4698 if (slots[slotid].nfssl_reply != NULL)
4699 m_freem(slots[slotid].nfssl_reply);
4700 slots[slotid].nfssl_reply = *rep;
4701 }
4702 slots[slotid].nfssl_inprog = 0;
4703 }
4704
4705 /*
4706 * Generate the xdr for an NFSv4.1 Sequence Operation.
4707 */
4708 void
nfsv4_setsequence(struct nfsmount * nmp,struct nfsrv_descript * nd,struct nfsclsession * sep,int dont_replycache)4709 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4710 struct nfsclsession *sep, int dont_replycache)
4711 {
4712 uint32_t *tl, slotseq = 0;
4713 int error, maxslot, slotpos;
4714 uint8_t sessionid[NFSX_V4SESSIONID];
4715
4716 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4717 sessionid);
4718
4719 /* Build the Sequence arguments. */
4720 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4721 nd->nd_sequence = tl;
4722 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4723 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4724 nd->nd_slotseq = tl;
4725 if (error == 0) {
4726 nd->nd_flag |= ND_HASSLOTID;
4727 nd->nd_slotid = slotpos;
4728 *tl++ = txdr_unsigned(slotseq);
4729 *tl++ = txdr_unsigned(slotpos);
4730 *tl++ = txdr_unsigned(maxslot);
4731 if (dont_replycache == 0)
4732 *tl = newnfs_true;
4733 else
4734 *tl = newnfs_false;
4735 } else {
4736 /*
4737 * There are two errors and the rest of the session can
4738 * just be zeros.
4739 * NFSERR_BADSESSION: This bad session should just generate
4740 * the same error again when the RPC is retried.
4741 * ESTALE: A forced dismount is in progress and will cause the
4742 * RPC to fail later.
4743 */
4744 *tl++ = 0;
4745 *tl++ = 0;
4746 *tl++ = 0;
4747 *tl = 0;
4748 }
4749 nd->nd_flag |= ND_HASSEQUENCE;
4750 }
4751
4752 int
nfsv4_sequencelookup(struct nfsmount * nmp,struct nfsclsession * sep,int * slotposp,int * maxslotp,uint32_t * slotseqp,uint8_t * sessionid)4753 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4754 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4755 {
4756 int i, maxslot, slotpos;
4757 uint64_t bitval;
4758
4759 /* Find an unused slot. */
4760 slotpos = -1;
4761 maxslot = -1;
4762 mtx_lock(&sep->nfsess_mtx);
4763 do {
4764 if (nmp != NULL && sep->nfsess_defunct != 0) {
4765 /* Just return the bad session. */
4766 bcopy(sep->nfsess_sessionid, sessionid,
4767 NFSX_V4SESSIONID);
4768 mtx_unlock(&sep->nfsess_mtx);
4769 return (NFSERR_BADSESSION);
4770 }
4771 bitval = 1;
4772 for (i = 0; i < sep->nfsess_foreslots; i++) {
4773 if ((bitval & sep->nfsess_slots) == 0) {
4774 slotpos = i;
4775 sep->nfsess_slots |= bitval;
4776 sep->nfsess_slotseq[i]++;
4777 *slotseqp = sep->nfsess_slotseq[i];
4778 break;
4779 }
4780 bitval <<= 1;
4781 }
4782 if (slotpos == -1) {
4783 /*
4784 * If a forced dismount is in progress, just return.
4785 * This RPC attempt will fail when it calls
4786 * newnfs_request().
4787 */
4788 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4789 mtx_unlock(&sep->nfsess_mtx);
4790 return (ESTALE);
4791 }
4792 /* Wake up once/sec, to check for a forced dismount. */
4793 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4794 PZERO, "nfsclseq", hz);
4795 }
4796 } while (slotpos == -1);
4797 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4798 bitval = 1;
4799 for (i = 0; i < 64; i++) {
4800 if ((bitval & sep->nfsess_slots) != 0)
4801 maxslot = i;
4802 bitval <<= 1;
4803 }
4804 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4805 mtx_unlock(&sep->nfsess_mtx);
4806 *slotposp = slotpos;
4807 *maxslotp = maxslot;
4808 return (0);
4809 }
4810
4811 /*
4812 * Free a session slot.
4813 */
4814 void
nfsv4_freeslot(struct nfsclsession * sep,int slot,bool resetseq)4815 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
4816 {
4817 uint64_t bitval;
4818
4819 bitval = 1;
4820 if (slot > 0)
4821 bitval <<= slot;
4822 mtx_lock(&sep->nfsess_mtx);
4823 if (resetseq)
4824 sep->nfsess_slotseq[slot]--;
4825 if ((bitval & sep->nfsess_slots) == 0)
4826 printf("freeing free slot!!\n");
4827 sep->nfsess_slots &= ~bitval;
4828 wakeup(&sep->nfsess_slots);
4829 mtx_unlock(&sep->nfsess_mtx);
4830 }
4831
4832 /*
4833 * Search for a matching pnfsd DS, based on the nmp arg.
4834 * Return one if found, NULL otherwise.
4835 */
4836 struct nfsdevice *
nfsv4_findmirror(struct nfsmount * nmp)4837 nfsv4_findmirror(struct nfsmount *nmp)
4838 {
4839 struct nfsdevice *ds;
4840
4841 mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4842 /*
4843 * Search the DS server list for a match with nmp.
4844 */
4845 if (nfsrv_devidcnt == 0)
4846 return (NULL);
4847 TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4848 if (ds->nfsdev_nmp == nmp) {
4849 NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4850 break;
4851 }
4852 }
4853 return (ds);
4854 }
4855
4856