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