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