Deleted Added
sdiff udiff text old ( 200069 ) new ( 205941 )
full compact
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: head/sys/fs/nfs/nfs_commonsubs.c 205941 2010-03-30 23:11:50Z rmacklem $");
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 <fs/nfs/nfsport.h>
44
45/*
46 * Data items converted to xdr at startup, since they are constant
47 * This is kinda hokey, but may save a little time doing byte swaps
48 */
49u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
50
51/* And other global data */
52nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
53 NFFIFO, NFNON };
54enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
55enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
56struct timeval nfsboottime; /* Copy boottime once, so it never changes */
57int nfscl_ticks;
58int nfsrv_useacl = 1;
59struct nfssockreq nfsrv_nfsuserdsock;
60int nfsrv_nfsuserd = 0;
61struct nfsreqhead nfsd_reqq;
62uid_t nfsrv_defaultuid;
63gid_t nfsrv_defaultgid;
64int nfsrv_lease = NFSRV_LEASE;
65int ncl_mbuf_mlen = MLEN;
66NFSNAMEIDMUTEX;
67NFSSOCKMUTEX;
68
69/*
70 * This array of structures indicates, for V4:
71 * retfh - which of 3 types of calling args are used
72 * 0 - doesn't change cfh or use a sfh
73 * 1 - replaces cfh with a new one (unless it returns an error status)
74 * 2 - uses cfh and sfh
75 * needscfh - if the op wants a cfh and premtime
76 * 0 - doesn't use a cfh
77 * 1 - uses a cfh, but doesn't want pre-op attributes
78 * 2 - uses a cfh and wants pre-op attributes
79 * savereply - indicates a non-idempotent Op
80 * 0 - not non-idempotent
81 * 1 - non-idempotent
82 * Ops that are ordered via seqid# are handled separately from these
83 * non-idempotent Ops.
84 * Define it here, since it is used by both the client and server.
85 */
86struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
87 { 0, 0, 0, 0 }, /* undef */
88 { 0, 0, 0, 0 }, /* undef */
89 { 0, 0, 0, 0 }, /* undef */
90 { 0, 1, 0, 0 }, /* Access */
91 { 0, 1, 0, 0 }, /* Close */
92 { 0, 2, 0, 1 }, /* Commit */
93 { 1, 2, 1, 1 }, /* Create */
94 { 0, 0, 0, 0 }, /* Delegpurge */
95 { 0, 1, 0, 0 }, /* Delegreturn */
96 { 0, 1, 0, 0 }, /* Getattr */
97 { 0, 1, 0, 0 }, /* GetFH */
98 { 2, 1, 1, 1 }, /* Link */
99 { 0, 1, 0, 0 }, /* Lock */
100 { 0, 1, 0, 0 }, /* LockT */
101 { 0, 1, 0, 0 }, /* LockU */
102 { 1, 1, 0, 0 }, /* Lookup */
103 { 1, 1, 0, 0 }, /* Lookupp */
104 { 0, 1, 0, 0 }, /* NVerify */
105 { 1, 1, 0, 1 }, /* Open */
106 { 1, 1, 0, 0 }, /* OpenAttr */
107 { 0, 1, 0, 0 }, /* OpenConfirm */
108 { 0, 1, 0, 0 }, /* OpenDowngrade */
109 { 1, 0, 0, 0 }, /* PutFH */
110 { 1, 0, 0, 0 }, /* PutPubFH */
111 { 1, 0, 0, 0 }, /* PutRootFH */
112 { 0, 1, 0, 0 }, /* Read */
113 { 0, 1, 0, 0 }, /* Readdir */
114 { 0, 1, 0, 0 }, /* ReadLink */
115 { 0, 2, 1, 1 }, /* Remove */
116 { 2, 1, 1, 1 }, /* Rename */
117 { 0, 0, 0, 0 }, /* Renew */
118 { 0, 0, 0, 0 }, /* RestoreFH */
119 { 0, 1, 0, 0 }, /* SaveFH */
120 { 0, 1, 0, 0 }, /* SecInfo */
121 { 0, 2, 1, 1 }, /* Setattr */
122 { 0, 0, 0, 0 }, /* SetClientID */
123 { 0, 0, 0, 0 }, /* SetClientIDConfirm */
124 { 0, 1, 0, 0 }, /* Verify */
125 { 0, 2, 1, 1 }, /* Write */
126 { 0, 0, 0, 0 }, /* ReleaseLockOwner */
127};
128#endif /* !APPLEKEXT */
129
130static int ncl_mbuf_mhlen = MHLEN;
131static int nfsrv_usercnt = 0;
132static int nfsrv_dnsnamelen;
133static u_char *nfsrv_dnsname = NULL;
134static int nfsrv_usermax = 999999999;
135static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
136static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
137static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
138static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
139static struct nfsuserlruhead nfsuserlruhead;
140
141/*
142 * This static array indicates whether or not the RPC generates a large
143 * reply. This is used by nfs_reply() to decide whether or not an mbuf
144 * cluster should be allocated. (If a cluster is required by an RPC
145 * marked 0 in this array, the code will still work, just not quite as
146 * efficiently.)
147 */
148static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
149 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,
150 0, 0, 0, 0, 0 };
151
152/* local functions */
153static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
154static void nfsv4_wanted(struct nfsv4lock *lp);
155static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
156static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
157 NFSPROC_T *p);
158static void nfsrv_removeuser(struct nfsusrgrp *usrp);
159static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
160 int *, int *);
161static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
162
163
164#ifndef APPLE
165/*
166 * copies mbuf chain to the uio scatter/gather list
167 */
168int
169nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
170{
171 char *mbufcp, *uiocp;
172 int xfer, left, len;
173 mbuf_t mp;
174 long uiosiz, rem;
175 int error = 0;
176
177 mp = nd->nd_md;
178 mbufcp = nd->nd_dpos;
179 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
180 rem = NFSM_RNDUP(siz) - siz;
181 while (siz > 0) {
182 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
183 return (EBADRPC);
184 left = uiop->uio_iov->iov_len;
185 uiocp = uiop->uio_iov->iov_base;
186 if (left > siz)
187 left = siz;
188 uiosiz = left;
189 while (left > 0) {
190 while (len == 0) {
191 mp = mbuf_next(mp);
192 if (mp == NULL)
193 return (EBADRPC);
194 mbufcp = NFSMTOD(mp, caddr_t);
195 len = mbuf_len(mp);
196 }
197 xfer = (left > len) ? len : left;
198#ifdef notdef
199 /* Not Yet.. */
200 if (uiop->uio_iov->iov_op != NULL)
201 (*(uiop->uio_iov->iov_op))
202 (mbufcp, uiocp, xfer);
203 else
204#endif
205 if (uiop->uio_segflg == UIO_SYSSPACE)
206 NFSBCOPY(mbufcp, uiocp, xfer);
207 else
208 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
209 left -= xfer;
210 len -= xfer;
211 mbufcp += xfer;
212 uiocp += xfer;
213 uiop->uio_offset += xfer;
214 uiop->uio_resid -= xfer;
215 }
216 if (uiop->uio_iov->iov_len <= siz) {
217 uiop->uio_iovcnt--;
218 uiop->uio_iov++;
219 } else {
220 uiop->uio_iov->iov_base = (void *)
221 ((char *)uiop->uio_iov->iov_base + uiosiz);
222 uiop->uio_iov->iov_len -= uiosiz;
223 }
224 siz -= uiosiz;
225 }
226 nd->nd_dpos = mbufcp;
227 nd->nd_md = mp;
228 if (rem > 0) {
229 if (len < rem)
230 error = nfsm_advance(nd, rem, len);
231 else
232 nd->nd_dpos += rem;
233 }
234 return (error);
235}
236#endif /* !APPLE */
237
238/*
239 * Help break down an mbuf chain by setting the first siz bytes contiguous
240 * pointed to by returned val.
241 * This is used by the macro NFSM_DISSECT for tough
242 * cases.
243 */
244APPLESTATIC void *
245nfsm_dissct(struct nfsrv_descript *nd, int siz)
246{
247 mbuf_t mp2;
248 int siz2, xfer;
249 caddr_t p;
250 int left;
251 caddr_t retp;
252
253 retp = NULL;
254 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
255 while (left == 0) {
256 nd->nd_md = mbuf_next(nd->nd_md);
257 if (nd->nd_md == NULL)
258 return (retp);
259 left = mbuf_len(nd->nd_md);
260 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
261 }
262 if (left >= siz) {
263 retp = nd->nd_dpos;
264 nd->nd_dpos += siz;
265 } else if (mbuf_next(nd->nd_md) == NULL) {
266 return (retp);
267 } else if (siz > ncl_mbuf_mhlen) {
268 panic("nfs S too big");
269 } else {
270 NFSMGET(mp2);
271 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
272 mbuf_setnext(nd->nd_md, mp2);
273 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
274 nd->nd_md = mp2;
275 retp = p = NFSMTOD(mp2, caddr_t);
276 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
277 siz2 = siz - left;
278 p += left;
279 mp2 = mbuf_next(mp2);
280 /* Loop around copying up the siz2 bytes */
281 while (siz2 > 0) {
282 if (mp2 == NULL)
283 return (NULL);
284 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
285 if (xfer > 0) {
286 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
287 NFSM_DATAP(mp2, xfer);
288 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
289 p += xfer;
290 siz2 -= xfer;
291 }
292 if (siz2 > 0)
293 mp2 = mbuf_next(mp2);
294 }
295 mbuf_setlen(nd->nd_md, siz);
296 nd->nd_md = mp2;
297 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
298 }
299 return (retp);
300}
301
302/*
303 * Advance the position in the mbuf chain.
304 * If offs == 0, this is a no-op, but it is simpler to just return from
305 * here than check for offs > 0 for all calls to nfsm_advance.
306 * If left == -1, it should be calculated here.
307 */
308APPLESTATIC int
309nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
310{
311
312 if (offs == 0)
313 return (0);
314 /*
315 * A negative offs should be considered a serious problem.
316 */
317 if (offs < 0)
318 panic("nfsrv_advance");
319
320 /*
321 * If left == -1, calculate it here.
322 */
323 if (left == -1)
324 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
325 nd->nd_dpos;
326
327 /*
328 * Loop around, advancing over the mbuf data.
329 */
330 while (offs > left) {
331 offs -= left;
332 nd->nd_md = mbuf_next(nd->nd_md);
333 if (nd->nd_md == NULL)
334 return (EBADRPC);
335 left = mbuf_len(nd->nd_md);
336 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
337 }
338 nd->nd_dpos += offs;
339 return (0);
340}
341
342/*
343 * Copy a string into mbuf(s).
344 * Return the number of bytes output, including XDR overheads.
345 */
346APPLESTATIC int
347nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
348{
349 mbuf_t m2;
350 int xfer, left;
351 mbuf_t m1;
352 int rem, bytesize;
353 u_int32_t *tl;
354 char *cp2;
355
356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
357 *tl = txdr_unsigned(siz);
358 rem = NFSM_RNDUP(siz) - siz;
359 bytesize = NFSX_UNSIGNED + siz + rem;
360 m2 = nd->nd_mb;
361 cp2 = nd->nd_bpos;
362 left = M_TRAILINGSPACE(m2);
363
364 /*
365 * Loop around copying the string to mbuf(s).
366 */
367 while (siz > 0) {
368 if (left == 0) {
369 if (siz > ncl_mbuf_mlen)
370 NFSMCLGET(m1, M_WAIT);
371 else
372 NFSMGET(m1);
373 mbuf_setlen(m1, 0);
374 mbuf_setnext(m2, m1);
375 m2 = m1;
376 cp2 = NFSMTOD(m2, caddr_t);
377 left = M_TRAILINGSPACE(m2);
378 }
379 if (left >= siz)
380 xfer = siz;
381 else
382 xfer = left;
383 NFSBCOPY(cp, cp2, xfer);
384 cp += xfer;
385 mbuf_setlen(m2, mbuf_len(m2) + xfer);
386 siz -= xfer;
387 left -= xfer;
388 if (siz == 0 && rem) {
389 if (left < rem)
390 panic("nfsm_strtom");
391 NFSBZERO(cp2 + xfer, rem);
392 mbuf_setlen(m2, mbuf_len(m2) + rem);
393 }
394 }
395 nd->nd_mb = m2;
396 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
397 return (bytesize);
398}
399
400/*
401 * Called once to initialize data structures...
402 */
403APPLESTATIC void
404newnfs_init(void)
405{
406 static int nfs_inited = 0;
407
408 if (nfs_inited)
409 return;
410 nfs_inited = 1;
411
412 newnfs_true = txdr_unsigned(TRUE);
413 newnfs_false = txdr_unsigned(FALSE);
414 newnfs_xdrneg1 = txdr_unsigned(-1);
415 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
416 if (nfscl_ticks < 1)
417 nfscl_ticks = 1;
418 NFSSETBOOTTIME(nfsboottime);
419
420 /*
421 * Initialize reply list and start timer
422 */
423 TAILQ_INIT(&nfsd_reqq);
424 NFS_TIMERINIT;
425}
426
427/*
428 * Put a file handle in an mbuf list.
429 * If the size argument == 0, just use the default size.
430 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
431 * Return the number of bytes output, including XDR overhead.
432 */
433APPLESTATIC int
434nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
435{
436 u_int32_t *tl;
437 u_int8_t *cp;
438 int fullsiz, rem, bytesize = 0;
439
440 if (size == 0)
441 size = NFSX_MYFH;
442 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
443 case ND_NFSV2:
444 if (size > NFSX_V2FH)
445 panic("fh size > NFSX_V2FH for NFSv2");
446 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
447 NFSBCOPY(fhp, cp, size);
448 if (size < NFSX_V2FH)
449 NFSBZERO(cp + size, NFSX_V2FH - size);
450 bytesize = NFSX_V2FH;
451 break;
452 case ND_NFSV3:
453 case ND_NFSV4:
454 fullsiz = NFSM_RNDUP(size);
455 rem = fullsiz - size;
456 if (set_true) {
457 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
458 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
459 *tl = newnfs_true;
460 } else {
461 bytesize = NFSX_UNSIGNED + fullsiz;
462 }
463 (void) nfsm_strtom(nd, fhp, size);
464 break;
465 };
466 return (bytesize);
467}
468
469/*
470 * This function compares two net addresses by family and returns TRUE
471 * if they are the same host.
472 * If there is any doubt, return FALSE.
473 * The AF_INET family is handled as a special case so that address mbufs
474 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
475 */
476APPLESTATIC int
477nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
478{
479 struct sockaddr_in *inetaddr;
480
481 switch (family) {
482 case AF_INET:
483 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
484 if (inetaddr->sin_family == AF_INET &&
485 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
486 return (1);
487 break;
488#ifdef INET6
489 case AF_INET6:
490 {
491 struct sockaddr_in6 *inetaddr6;
492
493 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
494 /* XXX - should test sin6_scope_id ? */
495 if (inetaddr6->sin6_family == AF_INET6 &&
496 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
497 &haddr->had_inet6))
498 return (1);
499 }
500 break;
501#endif
502 };
503 return (0);
504}
505
506/*
507 * Similar to the above, but takes to NFSSOCKADDR_T args.
508 */
509APPLESTATIC int
510nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
511{
512 struct sockaddr_in *addr1, *addr2;
513 struct sockaddr *inaddr;
514
515 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
516 switch (inaddr->sa_family) {
517 case AF_INET:
518 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
519 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
520 if (addr2->sin_family == AF_INET &&
521 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
522 return (1);
523 break;
524#ifdef INET6
525 case AF_INET6:
526 {
527 struct sockaddr_in6 *inet6addr1, *inet6addr2;
528
529 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
530 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
531 /* XXX - should test sin6_scope_id ? */
532 if (inet6addr2->sin6_family == AF_INET6 &&
533 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
534 &inet6addr2->sin6_addr))
535 return (1);
536 }
537 break;
538#endif
539 };
540 return (0);
541}
542
543
544/*
545 * Trim the stuff already dissected off the mbuf list.
546 */
547APPLESTATIC void
548newnfs_trimleading(nd)
549 struct nfsrv_descript *nd;
550{
551 mbuf_t m, n;
552 int offs;
553
554 /*
555 * First, free up leading mbufs.
556 */
557 if (nd->nd_mrep != nd->nd_md) {
558 m = nd->nd_mrep;
559 while (mbuf_next(m) != nd->nd_md) {
560 if (mbuf_next(m) == NULL)
561 panic("nfsm trim leading");
562 m = mbuf_next(m);
563 }
564 mbuf_setnext(m, NULL);
565 mbuf_freem(nd->nd_mrep);
566 }
567 m = nd->nd_md;
568
569 /*
570 * Now, adjust this mbuf, based on nd_dpos.
571 */
572 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
573 if (offs == mbuf_len(m)) {
574 n = m;
575 m = mbuf_next(m);
576 if (m == NULL)
577 panic("nfsm trim leading2");
578 mbuf_setnext(n, NULL);
579 mbuf_freem(n);
580 } else if (offs > 0) {
581 mbuf_setlen(m, mbuf_len(m) - offs);
582 NFSM_DATAP(m, offs);
583 } else if (offs < 0)
584 panic("nfsm trimleading offs");
585 nd->nd_mrep = m;
586 nd->nd_md = m;
587 nd->nd_dpos = NFSMTOD(m, caddr_t);
588}
589
590/*
591 * Trim trailing data off the mbuf list being built.
592 */
593APPLESTATIC void
594newnfs_trimtrailing(nd, mb, bpos)
595 struct nfsrv_descript *nd;
596 mbuf_t mb;
597 caddr_t bpos;
598{
599
600 if (mbuf_next(mb)) {
601 mbuf_freem(mbuf_next(mb));
602 mbuf_setnext(mb, NULL);
603 }
604 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
605 nd->nd_mb = mb;
606 nd->nd_bpos = bpos;
607}
608
609/*
610 * Dissect a file handle on the client.
611 */
612APPLESTATIC int
613nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
614{
615 u_int32_t *tl;
616 struct nfsfh *nfhp;
617 int error, len;
618
619 *nfhpp = NULL;
620 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
621 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
622 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
623 len > NFSX_FHMAX)
624 return (EBADRPC);
625 } else
626 len = NFSX_V2FH;
627 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
628 M_NFSFH, M_WAITOK);
629 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
630 if (error) {
631 FREE((caddr_t)nfhp, M_NFSFH);
632 return (error);
633 }
634 nfhp->nfh_len = len;
635 *nfhpp = nfhp;
636nfsmout:
637 return (error);
638}
639
640/*
641 * Break down the nfsv4 acl.
642 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
643 */
644APPLESTATIC int
645nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
646 int *aclsizep, __unused NFSPROC_T *p)
647{
648 u_int32_t *tl;
649 int i, aclsize;
650 int acecnt, error = 0, aceerr = 0, acesize;
651
652 *aclerrp = 0;
653 if (aclp)
654 aclp->acl_cnt = 0;
655 /*
656 * Parse out the ace entries and expect them to conform to
657 * what can be supported by R/W/X bits.
658 */
659 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
660 aclsize = NFSX_UNSIGNED;
661 acecnt = fxdr_unsigned(int, *tl);
662 if (acecnt > ACL_MAX_ENTRIES)
663 aceerr = 1;
664 if (nfsrv_useacl == 0)
665 aceerr = 1;
666 for (i = 0; i < acecnt; i++) {
667 if (aclp && !aceerr)
668 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
669 &aceerr, &acesize, p);
670 else
671 error = nfsrv_skipace(nd, &acesize);
672 if (error)
673 return (error);
674 aclsize += acesize;
675 }
676 if (aclp && !aceerr)
677 aclp->acl_cnt = acecnt;
678 if (aceerr)
679 *aclerrp = aceerr;
680 if (aclsizep)
681 *aclsizep = aclsize;
682nfsmout:
683 return (error);
684}
685
686/*
687 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
688 */
689static int
690nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
691{
692 u_int32_t *tl;
693 int error, len = 0;
694
695 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
696 len = fxdr_unsigned(int, *(tl + 3));
697 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
698nfsmout:
699 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
700 return (error);
701}
702
703/*
704 * Get attribute bits from an mbuf list.
705 * Returns EBADRPC for a parsing error, 0 otherwise.
706 * If the clearinvalid flag is set, clear the bits not supported.
707 */
708APPLESTATIC int
709nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
710 int *retnotsupp)
711{
712 u_int32_t *tl;
713 int cnt, i, outcnt;
714 int error = 0;
715
716 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
717 cnt = fxdr_unsigned(int, *tl);
718 if (cnt < 0)
719 return (NFSERR_BADXDR);
720 if (cnt > NFSATTRBIT_MAXWORDS) {
721 outcnt = NFSATTRBIT_MAXWORDS;
722 if (retnotsupp)
723 *retnotsupp = NFSERR_ATTRNOTSUPP;
724 } else {
725 outcnt = cnt;
726 }
727 NFSZERO_ATTRBIT(attrbitp);
728 if (outcnt > 0) {
729 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
730 for (i = 0; i < outcnt; i++)
731 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
732 }
733 if (cnt > outcnt)
734 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
735 if (cntp)
736 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
737nfsmout:
738 return (error);
739}
740
741/*
742 * Get the attributes for V4.
743 * If the compare flag is true, test for any attribute changes,
744 * otherwise return the attribute values.
745 * These attributes cover fields in "struct vattr", "struct statfs",
746 * "struct nfsfsinfo", the file handle and the lease duration.
747 * The value of retcmpp is set to 1 if all attributes are the same,
748 * and 0 otherwise.
749 * Returns EBADRPC if it can't be parsed, 0 otherwise.
750 */
751APPLESTATIC int
752nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
753 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
754 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
755 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
756 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
757{
758 u_int32_t *tl;
759 int i = 0, j, k, l, m, bitpos, attrsum = 0;
760 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
761 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
762 nfsattrbit_t attrbits, retattrbits, checkattrbits;
763 struct nfsfh *tnfhp;
764 struct nfsreferral *refp;
765 u_quad_t tquad;
766 nfsquad_t tnfsquad;
767 struct timespec temptime;
768 uid_t uid;
769 gid_t gid;
770 long fid;
771 u_int32_t freenum = 0, tuint;
772 u_int64_t uquad = 0, thyp, thyp2;
773#ifdef QUOTA
774 struct dqblk dqb;
775 uid_t savuid;
776#endif
777
778 if (compare) {
779 retnotsup = 0;
780 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
781 } else {
782 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
783 }
784 if (error)
785 return (error);
786
787 if (compare) {
788 *retcmpp = retnotsup;
789 } else {
790 /*
791 * Just set default values to some of the important ones.
792 */
793 if (nap != NULL) {
794 nap->na_type = VREG;
795 nap->na_mode = 0;
796 nap->na_rdev = (NFSDEV_T)0;
797 nap->na_mtime.tv_sec = 0;
798 nap->na_mtime.tv_nsec = 0;
799 nap->na_gen = 0;
800 nap->na_flags = 0;
801 nap->na_blocksize = NFS_FABLKSIZE;
802 }
803 if (sbp != NULL) {
804 sbp->f_bsize = NFS_FABLKSIZE;
805 sbp->f_blocks = 0;
806 sbp->f_bfree = 0;
807 sbp->f_bavail = 0;
808 sbp->f_files = 0;
809 sbp->f_ffree = 0;
810 }
811 if (fsp != NULL) {
812 fsp->fs_rtmax = 8192;
813 fsp->fs_rtpref = 8192;
814 fsp->fs_maxname = NFS_MAXNAMLEN;
815 fsp->fs_wtmax = 8192;
816 fsp->fs_wtpref = 8192;
817 fsp->fs_wtmult = NFS_FABLKSIZE;
818 fsp->fs_dtpref = 8192;
819 fsp->fs_maxfilesize = 0xffffffffffffffffull;
820 fsp->fs_timedelta.tv_sec = 0;
821 fsp->fs_timedelta.tv_nsec = 1;
822 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
823 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
824 }
825 if (pc != NULL) {
826 pc->pc_linkmax = LINK_MAX;
827 pc->pc_namemax = NAME_MAX;
828 pc->pc_notrunc = 0;
829 pc->pc_chownrestricted = 0;
830 pc->pc_caseinsensitive = 0;
831 pc->pc_casepreserving = 1;
832 }
833 }
834
835 /*
836 * Loop around getting the attributes.
837 */
838 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
839 attrsize = fxdr_unsigned(int, *tl);
840 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
841 if (attrsum > attrsize) {
842 error = NFSERR_BADXDR;
843 goto nfsmout;
844 }
845 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
846 switch (bitpos) {
847 case NFSATTRBIT_SUPPORTEDATTRS:
848 retnotsup = 0;
849 if (compare || nap == NULL)
850 error = nfsrv_getattrbits(nd, &retattrbits,
851 &cnt, &retnotsup);
852 else
853 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
854 &cnt, &retnotsup);
855 if (error)
856 return (error);
857 if (compare && !(*retcmpp)) {
858 NFSSETSUPP_ATTRBIT(&checkattrbits);
859 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
860 || retnotsup)
861 *retcmpp = NFSERR_NOTSAME;
862 }
863 attrsum += cnt;
864 break;
865 case NFSATTRBIT_TYPE:
866 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
867 if (compare) {
868 if (!(*retcmpp)) {
869 if (nap->na_type != nfsv34tov_type(*tl))
870 *retcmpp = NFSERR_NOTSAME;
871 }
872 } else if (nap != NULL) {
873 nap->na_type = nfsv34tov_type(*tl);
874 }
875 attrsum += NFSX_UNSIGNED;
876 break;
877 case NFSATTRBIT_FHEXPIRETYPE:
878 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
879 if (compare && !(*retcmpp)) {
880 if (fxdr_unsigned(int, *tl) !=
881 NFSV4FHTYPE_PERSISTENT)
882 *retcmpp = NFSERR_NOTSAME;
883 }
884 attrsum += NFSX_UNSIGNED;
885 break;
886 case NFSATTRBIT_CHANGE:
887 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
888 if (compare) {
889 if (!(*retcmpp)) {
890 if (nap->na_filerev != fxdr_hyper(tl))
891 *retcmpp = NFSERR_NOTSAME;
892 }
893 } else if (nap != NULL) {
894 nap->na_filerev = fxdr_hyper(tl);
895 }
896 attrsum += NFSX_HYPER;
897 break;
898 case NFSATTRBIT_SIZE:
899 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
900 if (compare) {
901 if (!(*retcmpp)) {
902 if (nap->na_size != fxdr_hyper(tl))
903 *retcmpp = NFSERR_NOTSAME;
904 }
905 } else if (nap != NULL) {
906 nap->na_size = fxdr_hyper(tl);
907 }
908 attrsum += NFSX_HYPER;
909 break;
910 case NFSATTRBIT_LINKSUPPORT:
911 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
912 if (compare) {
913 if (!(*retcmpp)) {
914 if (fsp->fs_properties & NFSV3_FSFLINK) {
915 if (*tl == newnfs_false)
916 *retcmpp = NFSERR_NOTSAME;
917 } else {
918 if (*tl == newnfs_true)
919 *retcmpp = NFSERR_NOTSAME;
920 }
921 }
922 } else if (fsp != NULL) {
923 if (*tl == newnfs_true)
924 fsp->fs_properties |= NFSV3_FSFLINK;
925 else
926 fsp->fs_properties &= ~NFSV3_FSFLINK;
927 }
928 attrsum += NFSX_UNSIGNED;
929 break;
930 case NFSATTRBIT_SYMLINKSUPPORT:
931 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
932 if (compare) {
933 if (!(*retcmpp)) {
934 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
935 if (*tl == newnfs_false)
936 *retcmpp = NFSERR_NOTSAME;
937 } else {
938 if (*tl == newnfs_true)
939 *retcmpp = NFSERR_NOTSAME;
940 }
941 }
942 } else if (fsp != NULL) {
943 if (*tl == newnfs_true)
944 fsp->fs_properties |= NFSV3_FSFSYMLINK;
945 else
946 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
947 }
948 attrsum += NFSX_UNSIGNED;
949 break;
950 case NFSATTRBIT_NAMEDATTR:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
952 if (compare && !(*retcmpp)) {
953 if (*tl != newnfs_false)
954 *retcmpp = NFSERR_NOTSAME;
955 }
956 attrsum += NFSX_UNSIGNED;
957 break;
958 case NFSATTRBIT_FSID:
959 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
960 thyp = fxdr_hyper(tl);
961 tl += 2;
962 thyp2 = fxdr_hyper(tl);
963 if (compare) {
964 if (*retcmpp == 0) {
965 if (thyp != (u_int64_t)
966 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
967 thyp2 != (u_int64_t)
968 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
969 *retcmpp = NFSERR_NOTSAME;
970 }
971 } else if (nap != NULL) {
972 nap->na_filesid[0] = thyp;
973 nap->na_filesid[1] = thyp2;
974 }
975 attrsum += (4 * NFSX_UNSIGNED);
976 break;
977 case NFSATTRBIT_UNIQUEHANDLES:
978 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
979 if (compare && !(*retcmpp)) {
980 if (*tl != newnfs_true)
981 *retcmpp = NFSERR_NOTSAME;
982 }
983 attrsum += NFSX_UNSIGNED;
984 break;
985 case NFSATTRBIT_LEASETIME:
986 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987 if (compare) {
988 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
989 !(*retcmpp))
990 *retcmpp = NFSERR_NOTSAME;
991 } else if (leasep != NULL) {
992 *leasep = fxdr_unsigned(u_int32_t, *tl);
993 }
994 attrsum += NFSX_UNSIGNED;
995 break;
996 case NFSATTRBIT_RDATTRERROR:
997 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
998 if (compare) {
999 if (!(*retcmpp))
1000 *retcmpp = NFSERR_INVAL;
1001 } else if (rderrp != NULL) {
1002 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1003 }
1004 attrsum += NFSX_UNSIGNED;
1005 break;
1006 case NFSATTRBIT_ACL:
1007 if (compare) {
1008 if (!(*retcmpp)) {
1009 if (nfsrv_useacl) {
1010 NFSACL_T *naclp;
1011
1012 naclp = acl_alloc(M_WAITOK);
1013 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1014 &cnt, p);
1015 if (error) {
1016 acl_free(naclp);
1017 return (error);
1018 }
1019 if (aceerr || nfsrv_compareacl(aclp, naclp))
1020 *retcmpp = NFSERR_NOTSAME;
1021 acl_free(naclp);
1022 } else {
1023 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1024 &cnt, p);
1025 *retcmpp = NFSERR_ATTRNOTSUPP;
1026 }
1027 }
1028 } else {
1029 if (vp != NULL && aclp != NULL)
1030 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1031 &cnt, p);
1032 else
1033 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1034 &cnt, p);
1035 if (error)
1036 return (error);
1037 }
1038 attrsum += cnt;
1039 break;
1040 case NFSATTRBIT_ACLSUPPORT:
1041 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1042 if (compare && !(*retcmpp)) {
1043 if (nfsrv_useacl) {
1044 if (fxdr_unsigned(u_int32_t, *tl) !=
1045 NFSV4ACE_SUPTYPES)
1046 *retcmpp = NFSERR_NOTSAME;
1047 } else {
1048 *retcmpp = NFSERR_ATTRNOTSUPP;
1049 }
1050 }
1051 attrsum += NFSX_UNSIGNED;
1052 break;
1053 case NFSATTRBIT_ARCHIVE:
1054 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1055 if (compare && !(*retcmpp))
1056 *retcmpp = NFSERR_ATTRNOTSUPP;
1057 attrsum += NFSX_UNSIGNED;
1058 break;
1059 case NFSATTRBIT_CANSETTIME:
1060 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1061 if (compare) {
1062 if (!(*retcmpp)) {
1063 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1064 if (*tl == newnfs_false)
1065 *retcmpp = NFSERR_NOTSAME;
1066 } else {
1067 if (*tl == newnfs_true)
1068 *retcmpp = NFSERR_NOTSAME;
1069 }
1070 }
1071 } else if (fsp != NULL) {
1072 if (*tl == newnfs_true)
1073 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1074 else
1075 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1076 }
1077 attrsum += NFSX_UNSIGNED;
1078 break;
1079 case NFSATTRBIT_CASEINSENSITIVE:
1080 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1081 if (compare) {
1082 if (!(*retcmpp)) {
1083 if (*tl != newnfs_false)
1084 *retcmpp = NFSERR_NOTSAME;
1085 }
1086 } else if (pc != NULL) {
1087 pc->pc_caseinsensitive =
1088 fxdr_unsigned(u_int32_t, *tl);
1089 }
1090 attrsum += NFSX_UNSIGNED;
1091 break;
1092 case NFSATTRBIT_CASEPRESERVING:
1093 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1094 if (compare) {
1095 if (!(*retcmpp)) {
1096 if (*tl != newnfs_true)
1097 *retcmpp = NFSERR_NOTSAME;
1098 }
1099 } else if (pc != NULL) {
1100 pc->pc_casepreserving =
1101 fxdr_unsigned(u_int32_t, *tl);
1102 }
1103 attrsum += NFSX_UNSIGNED;
1104 break;
1105 case NFSATTRBIT_CHOWNRESTRICTED:
1106 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1107 if (compare) {
1108 if (!(*retcmpp)) {
1109 if (*tl != newnfs_true)
1110 *retcmpp = NFSERR_NOTSAME;
1111 }
1112 } else if (pc != NULL) {
1113 pc->pc_chownrestricted =
1114 fxdr_unsigned(u_int32_t, *tl);
1115 }
1116 attrsum += NFSX_UNSIGNED;
1117 break;
1118 case NFSATTRBIT_FILEHANDLE:
1119 error = nfsm_getfh(nd, &tnfhp);
1120 if (error)
1121 return (error);
1122 tfhsize = tnfhp->nfh_len;
1123 if (compare) {
1124 if (!(*retcmpp) &&
1125 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1126 fhp, fhsize))
1127 *retcmpp = NFSERR_NOTSAME;
1128 FREE((caddr_t)tnfhp, M_NFSFH);
1129 } else if (nfhpp != NULL) {
1130 *nfhpp = tnfhp;
1131 } else {
1132 FREE((caddr_t)tnfhp, M_NFSFH);
1133 }
1134 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1135 break;
1136 case NFSATTRBIT_FILEID:
1137 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1138 thyp = fxdr_hyper(tl);
1139 if (compare) {
1140 if (!(*retcmpp)) {
1141 if ((u_int64_t)nap->na_fileid != thyp)
1142 *retcmpp = NFSERR_NOTSAME;
1143 }
1144 } else if (nap != NULL) {
1145 if (*tl++)
1146 printf("NFSv4 fileid > 32bits\n");
1147 nap->na_fileid = thyp;
1148 }
1149 attrsum += NFSX_HYPER;
1150 break;
1151 case NFSATTRBIT_FILESAVAIL:
1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1153 if (compare) {
1154 if (!(*retcmpp) &&
1155 sfp->sf_afiles != fxdr_hyper(tl))
1156 *retcmpp = NFSERR_NOTSAME;
1157 } else if (sfp != NULL) {
1158 sfp->sf_afiles = fxdr_hyper(tl);
1159 }
1160 attrsum += NFSX_HYPER;
1161 break;
1162 case NFSATTRBIT_FILESFREE:
1163 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1164 if (compare) {
1165 if (!(*retcmpp) &&
1166 sfp->sf_ffiles != fxdr_hyper(tl))
1167 *retcmpp = NFSERR_NOTSAME;
1168 } else if (sfp != NULL) {
1169 sfp->sf_ffiles = fxdr_hyper(tl);
1170 }
1171 attrsum += NFSX_HYPER;
1172 break;
1173 case NFSATTRBIT_FILESTOTAL:
1174 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1175 if (compare) {
1176 if (!(*retcmpp) &&
1177 sfp->sf_tfiles != fxdr_hyper(tl))
1178 *retcmpp = NFSERR_NOTSAME;
1179 } else if (sfp != NULL) {
1180 sfp->sf_tfiles = fxdr_hyper(tl);
1181 }
1182 attrsum += NFSX_HYPER;
1183 break;
1184 case NFSATTRBIT_FSLOCATIONS:
1185 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1186 if (error)
1187 return (error);
1188 attrsum += l;
1189 if (compare && !(*retcmpp)) {
1190 refp = nfsv4root_getreferral(vp, NULL, 0);
1191 if (refp != NULL) {
1192 if (cp == NULL || cp2 == NULL ||
1193 strcmp(cp, "/") ||
1194 strcmp(cp2, refp->nfr_srvlist))
1195 *retcmpp = NFSERR_NOTSAME;
1196 } else if (m == 0) {
1197 *retcmpp = NFSERR_NOTSAME;
1198 }
1199 }
1200 if (cp != NULL)
1201 free(cp, M_NFSSTRING);
1202 if (cp2 != NULL)
1203 free(cp2, M_NFSSTRING);
1204 break;
1205 case NFSATTRBIT_HIDDEN:
1206 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1207 if (compare && !(*retcmpp))
1208 *retcmpp = NFSERR_ATTRNOTSUPP;
1209 attrsum += NFSX_UNSIGNED;
1210 break;
1211 case NFSATTRBIT_HOMOGENEOUS:
1212 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1213 if (compare) {
1214 if (!(*retcmpp)) {
1215 if (fsp->fs_properties &
1216 NFSV3_FSFHOMOGENEOUS) {
1217 if (*tl == newnfs_false)
1218 *retcmpp = NFSERR_NOTSAME;
1219 } else {
1220 if (*tl == newnfs_true)
1221 *retcmpp = NFSERR_NOTSAME;
1222 }
1223 }
1224 } else if (fsp != NULL) {
1225 if (*tl == newnfs_true)
1226 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1227 else
1228 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1229 }
1230 attrsum += NFSX_UNSIGNED;
1231 break;
1232 case NFSATTRBIT_MAXFILESIZE:
1233 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1234 tnfsquad.qval = fxdr_hyper(tl);
1235 if (compare) {
1236 if (!(*retcmpp)) {
1237 tquad = NFSRV_MAXFILESIZE;
1238 if (tquad != tnfsquad.qval)
1239 *retcmpp = NFSERR_NOTSAME;
1240 }
1241 } else if (fsp != NULL) {
1242 fsp->fs_maxfilesize = tnfsquad.qval;
1243 }
1244 attrsum += NFSX_HYPER;
1245 break;
1246 case NFSATTRBIT_MAXLINK:
1247 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1248 if (compare) {
1249 if (!(*retcmpp)) {
1250 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1251 *retcmpp = NFSERR_NOTSAME;
1252 }
1253 } else if (pc != NULL) {
1254 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1255 }
1256 attrsum += NFSX_UNSIGNED;
1257 break;
1258 case NFSATTRBIT_MAXNAME:
1259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1260 if (compare) {
1261 if (!(*retcmpp)) {
1262 if (fsp->fs_maxname !=
1263 fxdr_unsigned(u_int32_t, *tl))
1264 *retcmpp = NFSERR_NOTSAME;
1265 }
1266 } else {
1267 tuint = fxdr_unsigned(u_int32_t, *tl);
1268 /*
1269 * Some Linux NFSv4 servers report this
1270 * as 0 or 4billion, so I'll set it to
1271 * NFS_MAXNAMLEN. If a server actually creates
1272 * a name longer than NFS_MAXNAMLEN, it will
1273 * get an error back.
1274 */
1275 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1276 tuint = NFS_MAXNAMLEN;
1277 if (fsp != NULL)
1278 fsp->fs_maxname = tuint;
1279 if (pc != NULL)
1280 pc->pc_namemax = tuint;
1281 }
1282 attrsum += NFSX_UNSIGNED;
1283 break;
1284 case NFSATTRBIT_MAXREAD:
1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1286 if (compare) {
1287 if (!(*retcmpp)) {
1288 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1289 *(tl + 1)) || *tl != 0)
1290 *retcmpp = NFSERR_NOTSAME;
1291 }
1292 } else if (fsp != NULL) {
1293 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1294 fsp->fs_rtpref = fsp->fs_rtmax;
1295 fsp->fs_dtpref = fsp->fs_rtpref;
1296 }
1297 attrsum += NFSX_HYPER;
1298 break;
1299 case NFSATTRBIT_MAXWRITE:
1300 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1301 if (compare) {
1302 if (!(*retcmpp)) {
1303 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1304 *(tl + 1)) || *tl != 0)
1305 *retcmpp = NFSERR_NOTSAME;
1306 }
1307 } else if (fsp != NULL) {
1308 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1309 fsp->fs_wtpref = fsp->fs_wtmax;
1310 }
1311 attrsum += NFSX_HYPER;
1312 break;
1313 case NFSATTRBIT_MIMETYPE:
1314 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1315 i = fxdr_unsigned(int, *tl);
1316 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1317 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1318 if (error)
1319 goto nfsmout;
1320 if (compare && !(*retcmpp))
1321 *retcmpp = NFSERR_ATTRNOTSUPP;
1322 break;
1323 case NFSATTRBIT_MODE:
1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1325 if (compare) {
1326 if (!(*retcmpp)) {
1327 if (nap->na_mode != nfstov_mode(*tl))
1328 *retcmpp = NFSERR_NOTSAME;
1329 }
1330 } else if (nap != NULL) {
1331 nap->na_mode = nfstov_mode(*tl);
1332 }
1333 attrsum += NFSX_UNSIGNED;
1334 break;
1335 case NFSATTRBIT_NOTRUNC:
1336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1337 if (compare) {
1338 if (!(*retcmpp)) {
1339 if (*tl != newnfs_true)
1340 *retcmpp = NFSERR_NOTSAME;
1341 }
1342 } else if (pc != NULL) {
1343 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1344 }
1345 attrsum += NFSX_UNSIGNED;
1346 break;
1347 case NFSATTRBIT_NUMLINKS:
1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1349 tuint = fxdr_unsigned(u_int32_t, *tl);
1350 if (compare) {
1351 if (!(*retcmpp)) {
1352 if ((u_int32_t)nap->na_nlink != tuint)
1353 *retcmpp = NFSERR_NOTSAME;
1354 }
1355 } else if (nap != NULL) {
1356 nap->na_nlink = tuint;
1357 }
1358 attrsum += NFSX_UNSIGNED;
1359 break;
1360 case NFSATTRBIT_OWNER:
1361 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1362 j = fxdr_unsigned(int, *tl);
1363 if (j < 0)
1364 return (NFSERR_BADXDR);
1365 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1366 if (j > NFSV4_SMALLSTR)
1367 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1368 else
1369 cp = namestr;
1370 error = nfsrv_mtostr(nd, cp, j);
1371 if (error) {
1372 if (j > NFSV4_SMALLSTR)
1373 free(cp, M_NFSSTRING);
1374 return (error);
1375 }
1376 if (compare) {
1377 if (!(*retcmpp)) {
1378 if (nfsv4_strtouid(cp, j, &uid, p) ||
1379 nap->na_uid != uid)
1380 *retcmpp = NFSERR_NOTSAME;
1381 }
1382 } else if (nap != NULL) {
1383 if (nfsv4_strtouid(cp, j, &uid, p))
1384 nap->na_uid = nfsrv_defaultuid;
1385 else
1386 nap->na_uid = uid;
1387 }
1388 if (j > NFSV4_SMALLSTR)
1389 free(cp, M_NFSSTRING);
1390 break;
1391 case NFSATTRBIT_OWNERGROUP:
1392 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1393 j = fxdr_unsigned(int, *tl);
1394 if (j < 0)
1395 return (NFSERR_BADXDR);
1396 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1397 if (j > NFSV4_SMALLSTR)
1398 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1399 else
1400 cp = namestr;
1401 error = nfsrv_mtostr(nd, cp, j);
1402 if (error) {
1403 if (j > NFSV4_SMALLSTR)
1404 free(cp, M_NFSSTRING);
1405 return (error);
1406 }
1407 if (compare) {
1408 if (!(*retcmpp)) {
1409 if (nfsv4_strtogid(cp, j, &gid, p) ||
1410 nap->na_gid != gid)
1411 *retcmpp = NFSERR_NOTSAME;
1412 }
1413 } else if (nap != NULL) {
1414 if (nfsv4_strtogid(cp, j, &gid, p))
1415 nap->na_gid = nfsrv_defaultgid;
1416 else
1417 nap->na_gid = gid;
1418 }
1419 if (j > NFSV4_SMALLSTR)
1420 free(cp, M_NFSSTRING);
1421 break;
1422 case NFSATTRBIT_QUOTAHARD:
1423 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1424 if (sbp != NULL) {
1425 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1426 freenum = sbp->f_bfree;
1427 else
1428 freenum = sbp->f_bavail;
1429#ifdef QUOTA
1430 /*
1431 * ufs_quotactl() insists that the uid argument
1432 * equal p_ruid for non-root quota access, so
1433 * we'll just make sure that's the case.
1434 */
1435 savuid = p->p_cred->p_ruid;
1436 p->p_cred->p_ruid = cred->cr_uid;
1437 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1438 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1439 freenum = min(dqb.dqb_bhardlimit, freenum);
1440 p->p_cred->p_ruid = savuid;
1441#endif /* QUOTA */
1442 uquad = (u_int64_t)freenum;
1443 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1444 }
1445 if (compare && !(*retcmpp)) {
1446 if (uquad != fxdr_hyper(tl))
1447 *retcmpp = NFSERR_NOTSAME;
1448 }
1449 attrsum += NFSX_HYPER;
1450 break;
1451 case NFSATTRBIT_QUOTASOFT:
1452 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1453 if (sbp != NULL) {
1454 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1455 freenum = sbp->f_bfree;
1456 else
1457 freenum = sbp->f_bavail;
1458#ifdef QUOTA
1459 /*
1460 * ufs_quotactl() insists that the uid argument
1461 * equal p_ruid for non-root quota access, so
1462 * we'll just make sure that's the case.
1463 */
1464 savuid = p->p_cred->p_ruid;
1465 p->p_cred->p_ruid = cred->cr_uid;
1466 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1467 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1468 freenum = min(dqb.dqb_bsoftlimit, freenum);
1469 p->p_cred->p_ruid = savuid;
1470#endif /* QUOTA */
1471 uquad = (u_int64_t)freenum;
1472 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1473 }
1474 if (compare && !(*retcmpp)) {
1475 if (uquad != fxdr_hyper(tl))
1476 *retcmpp = NFSERR_NOTSAME;
1477 }
1478 attrsum += NFSX_HYPER;
1479 break;
1480 case NFSATTRBIT_QUOTAUSED:
1481 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1482 if (sbp != NULL) {
1483 freenum = 0;
1484#ifdef QUOTA
1485 /*
1486 * ufs_quotactl() insists that the uid argument
1487 * equal p_ruid for non-root quota access, so
1488 * we'll just make sure that's the case.
1489 */
1490 savuid = p->p_cred->p_ruid;
1491 p->p_cred->p_ruid = cred->cr_uid;
1492 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1493 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1494 freenum = dqb.dqb_curblocks;
1495 p->p_cred->p_ruid = savuid;
1496#endif /* QUOTA */
1497 uquad = (u_int64_t)freenum;
1498 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1499 }
1500 if (compare && !(*retcmpp)) {
1501 if (uquad != fxdr_hyper(tl))
1502 *retcmpp = NFSERR_NOTSAME;
1503 }
1504 attrsum += NFSX_HYPER;
1505 break;
1506 case NFSATTRBIT_RAWDEV:
1507 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1508 j = fxdr_unsigned(int, *tl++);
1509 k = fxdr_unsigned(int, *tl);
1510 if (compare) {
1511 if (!(*retcmpp)) {
1512 if (nap->na_rdev != NFSMAKEDEV(j, k))
1513 *retcmpp = NFSERR_NOTSAME;
1514 }
1515 } else if (nap != NULL) {
1516 nap->na_rdev = NFSMAKEDEV(j, k);
1517 }
1518 attrsum += NFSX_V4SPECDATA;
1519 break;
1520 case NFSATTRBIT_SPACEAVAIL:
1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1522 if (compare) {
1523 if (!(*retcmpp) &&
1524 sfp->sf_abytes != fxdr_hyper(tl))
1525 *retcmpp = NFSERR_NOTSAME;
1526 } else if (sfp != NULL) {
1527 sfp->sf_abytes = fxdr_hyper(tl);
1528 }
1529 attrsum += NFSX_HYPER;
1530 break;
1531 case NFSATTRBIT_SPACEFREE:
1532 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1533 if (compare) {
1534 if (!(*retcmpp) &&
1535 sfp->sf_fbytes != fxdr_hyper(tl))
1536 *retcmpp = NFSERR_NOTSAME;
1537 } else if (sfp != NULL) {
1538 sfp->sf_fbytes = fxdr_hyper(tl);
1539 }
1540 attrsum += NFSX_HYPER;
1541 break;
1542 case NFSATTRBIT_SPACETOTAL:
1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1544 if (compare) {
1545 if (!(*retcmpp) &&
1546 sfp->sf_tbytes != fxdr_hyper(tl))
1547 *retcmpp = NFSERR_NOTSAME;
1548 } else if (sfp != NULL) {
1549 sfp->sf_tbytes = fxdr_hyper(tl);
1550 }
1551 attrsum += NFSX_HYPER;
1552 break;
1553 case NFSATTRBIT_SPACEUSED:
1554 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1555 thyp = fxdr_hyper(tl);
1556 if (compare) {
1557 if (!(*retcmpp)) {
1558 if ((u_int64_t)nap->na_bytes != thyp)
1559 *retcmpp = NFSERR_NOTSAME;
1560 }
1561 } else if (nap != NULL) {
1562 nap->na_bytes = thyp;
1563 }
1564 attrsum += NFSX_HYPER;
1565 break;
1566 case NFSATTRBIT_SYSTEM:
1567 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1568 if (compare && !(*retcmpp))
1569 *retcmpp = NFSERR_ATTRNOTSUPP;
1570 attrsum += NFSX_UNSIGNED;
1571 break;
1572 case NFSATTRBIT_TIMEACCESS:
1573 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1574 fxdr_nfsv4time(tl, &temptime);
1575 if (compare) {
1576 if (!(*retcmpp)) {
1577 if (!NFS_CMPTIME(temptime, nap->na_atime))
1578 *retcmpp = NFSERR_NOTSAME;
1579 }
1580 } else if (nap != NULL) {
1581 nap->na_atime = temptime;
1582 }
1583 attrsum += NFSX_V4TIME;
1584 break;
1585 case NFSATTRBIT_TIMEACCESSSET:
1586 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1587 attrsum += NFSX_UNSIGNED;
1588 i = fxdr_unsigned(int, *tl);
1589 if (i == NFSV4SATTRTIME_TOCLIENT) {
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1591 attrsum += NFSX_V4TIME;
1592 }
1593 if (compare && !(*retcmpp))
1594 *retcmpp = NFSERR_INVAL;
1595 break;
1596 case NFSATTRBIT_TIMEBACKUP:
1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1598 if (compare && !(*retcmpp))
1599 *retcmpp = NFSERR_ATTRNOTSUPP;
1600 attrsum += NFSX_V4TIME;
1601 break;
1602 case NFSATTRBIT_TIMECREATE:
1603 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1604 if (compare && !(*retcmpp))
1605 *retcmpp = NFSERR_ATTRNOTSUPP;
1606 attrsum += NFSX_V4TIME;
1607 break;
1608 case NFSATTRBIT_TIMEDELTA:
1609 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1610 if (fsp != NULL) {
1611 if (compare) {
1612 if (!(*retcmpp)) {
1613 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1614 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1615 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1616 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1617 1000000000) ||
1618 *tl != 0)
1619 *retcmpp = NFSERR_NOTSAME;
1620 }
1621 } else {
1622 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1623 }
1624 }
1625 attrsum += NFSX_V4TIME;
1626 break;
1627 case NFSATTRBIT_TIMEMETADATA:
1628 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1629 fxdr_nfsv4time(tl, &temptime);
1630 if (compare) {
1631 if (!(*retcmpp)) {
1632 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1633 *retcmpp = NFSERR_NOTSAME;
1634 }
1635 } else if (nap != NULL) {
1636 nap->na_ctime = temptime;
1637 }
1638 attrsum += NFSX_V4TIME;
1639 break;
1640 case NFSATTRBIT_TIMEMODIFY:
1641 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1642 fxdr_nfsv4time(tl, &temptime);
1643 if (compare) {
1644 if (!(*retcmpp)) {
1645 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1646 *retcmpp = NFSERR_NOTSAME;
1647 }
1648 } else if (nap != NULL) {
1649 nap->na_mtime = temptime;
1650 }
1651 attrsum += NFSX_V4TIME;
1652 break;
1653 case NFSATTRBIT_TIMEMODIFYSET:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1655 attrsum += NFSX_UNSIGNED;
1656 i = fxdr_unsigned(int, *tl);
1657 if (i == NFSV4SATTRTIME_TOCLIENT) {
1658 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1659 attrsum += NFSX_V4TIME;
1660 }
1661 if (compare && !(*retcmpp))
1662 *retcmpp = NFSERR_INVAL;
1663 break;
1664 case NFSATTRBIT_MOUNTEDONFILEID:
1665 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1666 thyp = fxdr_hyper(tl);
1667 if (compare) {
1668 if (!(*retcmpp)) {
1669 if (*tl++) {
1670 *retcmpp = NFSERR_NOTSAME;
1671 } else {
1672 if (!vp || !nfsrv_atroot(vp, &fid))
1673 fid = nap->na_fileid;
1674 if ((u_int64_t)fid != thyp)
1675 *retcmpp = NFSERR_NOTSAME;
1676 }
1677 }
1678 } else if (nap != NULL) {
1679 if (*tl++)
1680 printf("NFSv4 mounted on fileid > 32bits\n");
1681 nap->na_mntonfileno = thyp;
1682 }
1683 attrsum += NFSX_HYPER;
1684 break;
1685 default:
1686 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1687 bitpos);
1688 if (compare && !(*retcmpp))
1689 *retcmpp = NFSERR_ATTRNOTSUPP;
1690 /*
1691 * and get out of the loop, since we can't parse
1692 * the unknown attrbute data.
1693 */
1694 bitpos = NFSATTRBIT_MAX;
1695 break;
1696 };
1697 }
1698
1699 /*
1700 * some clients pad the attrlist, so we need to skip over the
1701 * padding.
1702 */
1703 if (attrsum > attrsize) {
1704 error = NFSERR_BADXDR;
1705 } else {
1706 attrsize = NFSM_RNDUP(attrsize);
1707 if (attrsum < attrsize)
1708 error = nfsm_advance(nd, attrsize - attrsum, -1);
1709 }
1710nfsmout:
1711 return (error);
1712}
1713
1714/*
1715 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1716 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1717 * The first argument is a pointer to an nfsv4lock structure.
1718 * The second argument is 1 iff a blocking lock is wanted.
1719 * If this argument is 0, the call waits until no thread either wants nor
1720 * holds an exclusive lock.
1721 * It returns 1 if the lock was acquired, 0 otherwise.
1722 * If several processes call this function concurrently wanting the exclusive
1723 * lock, one will get the lock and the rest will return without getting the
1724 * lock. (If the caller must have the lock, it simply calls this function in a
1725 * loop until the function returns 1 to indicate the lock was acquired.)
1726 * Any usecnt must be decremented by calling nfsv4_relref() before
1727 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1728 * be called in a loop.
1729 * The last argument is set to indicate if the call slept, iff not NULL.
1730 */
1731APPLESTATIC int
1732nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1733 void *mutex)
1734{
1735
1736 if (isleptp)
1737 *isleptp = 0;
1738 /*
1739 * If a lock is wanted, loop around until the lock is acquired by
1740 * someone and then released. If I want the lock, try to acquire it.
1741 * For a lock to be issued, no lock must be in force and the usecnt
1742 * must be zero.
1743 */
1744 if (iwantlock) {
1745 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1746 lp->nfslock_usecnt == 0) {
1747 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1748 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1749 return (1);
1750 }
1751 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1752 }
1753 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1754 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1755 if (isleptp)
1756 *isleptp = 1;
1757 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1758 PZERO - 1, "nfsv4lck", NULL);
1759 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1760 lp->nfslock_usecnt == 0) {
1761 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1762 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1763 return (1);
1764 }
1765 }
1766 return (0);
1767}
1768
1769/*
1770 * Release the lock acquired by nfsv4_lock().
1771 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1772 * incremented, as well.
1773 */
1774APPLESTATIC void
1775nfsv4_unlock(struct nfsv4lock *lp, int incref)
1776{
1777
1778 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1779 if (incref)
1780 lp->nfslock_usecnt++;
1781 nfsv4_wanted(lp);
1782}
1783
1784/*
1785 * Release a reference cnt.
1786 */
1787APPLESTATIC void
1788nfsv4_relref(struct nfsv4lock *lp)
1789{
1790
1791 if (lp->nfslock_usecnt <= 0)
1792 panic("nfsv4root ref cnt");
1793 lp->nfslock_usecnt--;
1794 if (lp->nfslock_usecnt == 0)
1795 nfsv4_wanted(lp);
1796}
1797
1798/*
1799 * Get a reference cnt.
1800 * This function will wait for any exclusive lock to be released, but will
1801 * not wait for threads that want the exclusive lock. If priority needs
1802 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1803 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1804 */
1805APPLESTATIC void
1806nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
1807{
1808
1809 if (isleptp)
1810 *isleptp = 0;
1811
1812 /*
1813 * Wait for a lock held.
1814 */
1815 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1816 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1817 if (isleptp)
1818 *isleptp = 1;
1819 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1820 PZERO - 1, "nfsv4lck", NULL);
1821 }
1822
1823 lp->nfslock_usecnt++;
1824}
1825
1826/*
1827 * Test for a lock. Return 1 if locked, 0 otherwise.
1828 */
1829APPLESTATIC int
1830nfsv4_testlock(struct nfsv4lock *lp)
1831{
1832
1833 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1834 lp->nfslock_usecnt == 0)
1835 return (0);
1836 return (1);
1837}
1838
1839/*
1840 * Wake up anyone sleeping, waiting for this lock.
1841 */
1842static void
1843nfsv4_wanted(struct nfsv4lock *lp)
1844{
1845
1846 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1847 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1848 wakeup((caddr_t)&lp->nfslock_lock);
1849 }
1850}
1851
1852/*
1853 * Copy a string from an mbuf list into a character array.
1854 * Return EBADRPC if there is an mbuf error,
1855 * 0 otherwise.
1856 */
1857APPLESTATIC int
1858nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1859{
1860 char *cp;
1861 int xfer, len;
1862 mbuf_t mp;
1863 int rem, error = 0;
1864
1865 mp = nd->nd_md;
1866 cp = nd->nd_dpos;
1867 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1868 rem = NFSM_RNDUP(siz) - siz;
1869 while (siz > 0) {
1870 if (len > siz)
1871 xfer = siz;
1872 else
1873 xfer = len;
1874 NFSBCOPY(cp, str, xfer);
1875 str += xfer;
1876 siz -= xfer;
1877 if (siz > 0) {
1878 mp = mbuf_next(mp);
1879 if (mp == NULL)
1880 return (EBADRPC);
1881 cp = NFSMTOD(mp, caddr_t);
1882 len = mbuf_len(mp);
1883 } else {
1884 cp += xfer;
1885 len -= xfer;
1886 }
1887 }
1888 *str = '\0';
1889 nd->nd_dpos = cp;
1890 nd->nd_md = mp;
1891 if (rem > 0) {
1892 if (len < rem)
1893 error = nfsm_advance(nd, rem, len);
1894 else
1895 nd->nd_dpos += rem;
1896 }
1897 return (error);
1898}
1899
1900/*
1901 * Fill in the attributes as marked by the bitmap (V4).
1902 */
1903APPLESTATIC int
1904nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
1905 struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1906 struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
1907{
1908 int bitpos, retnum = 0;
1909 u_int32_t *tl;
1910 int siz, prefixnum, error;
1911 u_char *cp, namestr[NFSV4_SMALLSTR];
1912 nfsattrbit_t attrbits, retbits;
1913 nfsattrbit_t *retbitp = &retbits;
1914 u_int32_t freenum, *retnump;
1915 u_int64_t uquad;
1916 long fid;
1917 struct statfs fs;
1918 struct nfsfsinfo fsinf;
1919 struct timespec temptime;
1920 struct timeval curtime;
1921 NFSACL_T *aclp, *naclp = NULL;
1922#ifdef QUOTA
1923 struct dqblk dqb;
1924 uid_t savuid;
1925#endif
1926
1927 /*
1928 * First, set the bits that can be filled and get fsinfo.
1929 */
1930 NFSSET_ATTRBIT(retbitp, attrbitp);
1931 /* If p and cred are NULL, it is a client side call */
1932 if (p == NULL && cred == NULL) {
1933 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1934 aclp = saclp;
1935 } else {
1936 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1937 naclp = acl_alloc(M_WAITOK);
1938 aclp = naclp;
1939 }
1940 nfsvno_getfs(&fsinf, isdgram);
1941#ifndef APPLE
1942 /*
1943 * Get the VFS_STATFS(), since some attributes need them.
1944 */
1945 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
1946 error = VFS_STATFS(vnode_mount(vp), &fs);
1947 if (error != 0) {
1948 if (reterr) {
1949 nd->nd_repstat = NFSERR_ACCES;
1950 return (0);
1951 }
1952 NFSCLRSTATFS_ATTRBIT(retbitp);
1953 }
1954 }
1955#endif
1956
1957 /*
1958 * And the NFSv4 ACL...
1959 */
1960 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
1961 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1962 !NFSHASNFS4ACL(vnode_mount(vp))))) {
1963 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1964 }
1965 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1966 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1967 !NFSHASNFS4ACL(vnode_mount(vp)))) {
1968 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1969 } else if (naclp != NULL) {
1970 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
1971 error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
1972 if (error == 0)
1973 error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
1974 cred, p);
1975 NFSVOPUNLOCK(vp, 0, p);
1976 if (error != 0) {
1977 if (reterr) {
1978 nd->nd_repstat = NFSERR_ACCES;
1979 return (0);
1980 }
1981 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1982 }
1983 }
1984 }
1985 /*
1986 * Put out the attribute bitmap for the ones being filled in
1987 * and get the field for the number of attributes returned.
1988 */
1989 prefixnum = nfsrv_putattrbit(nd, retbitp);
1990 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1991 prefixnum += NFSX_UNSIGNED;
1992
1993 /*
1994 * Now, loop around filling in the attributes for each bit set.
1995 */
1996 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1997 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
1998 switch (bitpos) {
1999 case NFSATTRBIT_SUPPORTEDATTRS:
2000 NFSSETSUPP_ATTRBIT(&attrbits);
2001 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2002 && !NFSHASNFS4ACL(vnode_mount(vp)))) {
2003 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2004 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2005 }
2006 retnum += nfsrv_putattrbit(nd, &attrbits);
2007 break;
2008 case NFSATTRBIT_TYPE:
2009 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2010 *tl = vtonfsv34_type(vap->va_type);
2011 retnum += NFSX_UNSIGNED;
2012 break;
2013 case NFSATTRBIT_FHEXPIRETYPE:
2014 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2015 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2016 retnum += NFSX_UNSIGNED;
2017 break;
2018 case NFSATTRBIT_CHANGE:
2019 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2020 txdr_hyper(vap->va_filerev, tl);
2021 retnum += NFSX_HYPER;
2022 break;
2023 case NFSATTRBIT_SIZE:
2024 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2025 txdr_hyper(vap->va_size, tl);
2026 retnum += NFSX_HYPER;
2027 break;
2028 case NFSATTRBIT_LINKSUPPORT:
2029 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2030 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2031 *tl = newnfs_true;
2032 else
2033 *tl = newnfs_false;
2034 retnum += NFSX_UNSIGNED;
2035 break;
2036 case NFSATTRBIT_SYMLINKSUPPORT:
2037 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2038 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2039 *tl = newnfs_true;
2040 else
2041 *tl = newnfs_false;
2042 retnum += NFSX_UNSIGNED;
2043 break;
2044 case NFSATTRBIT_NAMEDATTR:
2045 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2046 *tl = newnfs_false;
2047 retnum += NFSX_UNSIGNED;
2048 break;
2049 case NFSATTRBIT_FSID:
2050 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2051 *tl++ = 0;
2052 *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
2053 *tl++ = 0;
2054 *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
2055 retnum += NFSX_V4FSID;
2056 break;
2057 case NFSATTRBIT_UNIQUEHANDLES:
2058 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2059 *tl = newnfs_true;
2060 retnum += NFSX_UNSIGNED;
2061 break;
2062 case NFSATTRBIT_LEASETIME:
2063 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2064 *tl = txdr_unsigned(nfsrv_lease);
2065 retnum += NFSX_UNSIGNED;
2066 break;
2067 case NFSATTRBIT_RDATTRERROR:
2068 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2069 *tl = txdr_unsigned(rderror);
2070 retnum += NFSX_UNSIGNED;
2071 break;
2072 /*
2073 * Recommended Attributes. (Only the supported ones.)
2074 */
2075 case NFSATTRBIT_ACL:
2076 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2077 break;
2078 case NFSATTRBIT_ACLSUPPORT:
2079 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2080 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2081 retnum += NFSX_UNSIGNED;
2082 break;
2083 case NFSATTRBIT_CANSETTIME:
2084 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2085 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2086 *tl = newnfs_true;
2087 else
2088 *tl = newnfs_false;
2089 retnum += NFSX_UNSIGNED;
2090 break;
2091 case NFSATTRBIT_CASEINSENSITIVE:
2092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2093 *tl = newnfs_false;
2094 retnum += NFSX_UNSIGNED;
2095 break;
2096 case NFSATTRBIT_CASEPRESERVING:
2097 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2098 *tl = newnfs_true;
2099 retnum += NFSX_UNSIGNED;
2100 break;
2101 case NFSATTRBIT_CHOWNRESTRICTED:
2102 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2103 *tl = newnfs_true;
2104 retnum += NFSX_UNSIGNED;
2105 break;
2106 case NFSATTRBIT_FILEHANDLE:
2107 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2108 break;
2109 case NFSATTRBIT_FILEID:
2110 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2111 *tl++ = 0;
2112 *tl = txdr_unsigned(vap->va_fileid);
2113 retnum += NFSX_HYPER;
2114 break;
2115 case NFSATTRBIT_FILESAVAIL:
2116 /*
2117 * Check quota and use min(quota, f_ffree).
2118 */
2119 freenum = fs.f_ffree;
2120#ifdef QUOTA
2121 /*
2122 * ufs_quotactl() insists that the uid argument
2123 * equal p_ruid for non-root quota access, so
2124 * we'll just make sure that's the case.
2125 */
2126 savuid = p->p_cred->p_ruid;
2127 p->p_cred->p_ruid = cred->cr_uid;
2128 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2129 cred->cr_uid, (caddr_t)&dqb))
2130 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2131 freenum);
2132 p->p_cred->p_ruid = savuid;
2133#endif /* QUOTA */
2134 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2135 *tl++ = 0;
2136 *tl = txdr_unsigned(freenum);
2137 retnum += NFSX_HYPER;
2138 break;
2139 case NFSATTRBIT_FILESFREE:
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2141 *tl++ = 0;
2142 *tl = txdr_unsigned(fs.f_ffree);
2143 retnum += NFSX_HYPER;
2144 break;
2145 case NFSATTRBIT_FILESTOTAL:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2147 *tl++ = 0;
2148 *tl = txdr_unsigned(fs.f_files);
2149 retnum += NFSX_HYPER;
2150 break;
2151 case NFSATTRBIT_FSLOCATIONS:
2152 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2153 *tl++ = 0;
2154 *tl = 0;
2155 retnum += 2 * NFSX_UNSIGNED;
2156 break;
2157 case NFSATTRBIT_HOMOGENEOUS:
2158 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2159 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2160 *tl = newnfs_true;
2161 else
2162 *tl = newnfs_false;
2163 retnum += NFSX_UNSIGNED;
2164 break;
2165 case NFSATTRBIT_MAXFILESIZE:
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2167 uquad = NFSRV_MAXFILESIZE;
2168 txdr_hyper(uquad, tl);
2169 retnum += NFSX_HYPER;
2170 break;
2171 case NFSATTRBIT_MAXLINK:
2172 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2173 *tl = txdr_unsigned(LINK_MAX);
2174 retnum += NFSX_UNSIGNED;
2175 break;
2176 case NFSATTRBIT_MAXNAME:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2179 retnum += NFSX_UNSIGNED;
2180 break;
2181 case NFSATTRBIT_MAXREAD:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2183 *tl++ = 0;
2184 *tl = txdr_unsigned(fsinf.fs_rtmax);
2185 retnum += NFSX_HYPER;
2186 break;
2187 case NFSATTRBIT_MAXWRITE:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2189 *tl++ = 0;
2190 *tl = txdr_unsigned(fsinf.fs_wtmax);
2191 retnum += NFSX_HYPER;
2192 break;
2193 case NFSATTRBIT_MODE:
2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2195 *tl = vtonfsv34_mode(vap->va_mode);
2196 retnum += NFSX_UNSIGNED;
2197 break;
2198 case NFSATTRBIT_NOTRUNC:
2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2200 *tl = newnfs_true;
2201 retnum += NFSX_UNSIGNED;
2202 break;
2203 case NFSATTRBIT_NUMLINKS:
2204 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2205 *tl = txdr_unsigned(vap->va_nlink);
2206 retnum += NFSX_UNSIGNED;
2207 break;
2208 case NFSATTRBIT_OWNER:
2209 cp = namestr;
2210 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2211 retnum += nfsm_strtom(nd, cp, siz);
2212 if (cp != namestr)
2213 free(cp, M_NFSSTRING);
2214 break;
2215 case NFSATTRBIT_OWNERGROUP:
2216 cp = namestr;
2217 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2218 retnum += nfsm_strtom(nd, cp, siz);
2219 if (cp != namestr)
2220 free(cp, M_NFSSTRING);
2221 break;
2222 case NFSATTRBIT_QUOTAHARD:
2223 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2224 freenum = fs.f_bfree;
2225 else
2226 freenum = fs.f_bavail;
2227#ifdef QUOTA
2228 /*
2229 * ufs_quotactl() insists that the uid argument
2230 * equal p_ruid for non-root quota access, so
2231 * we'll just make sure that's the case.
2232 */
2233 savuid = p->p_cred->p_ruid;
2234 p->p_cred->p_ruid = cred->cr_uid;
2235 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2236 cred->cr_uid, (caddr_t)&dqb))
2237 freenum = min(dqb.dqb_bhardlimit, freenum);
2238 p->p_cred->p_ruid = savuid;
2239#endif /* QUOTA */
2240 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2241 uquad = (u_int64_t)freenum;
2242 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2243 txdr_hyper(uquad, tl);
2244 retnum += NFSX_HYPER;
2245 break;
2246 case NFSATTRBIT_QUOTASOFT:
2247 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2248 freenum = fs.f_bfree;
2249 else
2250 freenum = fs.f_bavail;
2251#ifdef QUOTA
2252 /*
2253 * ufs_quotactl() insists that the uid argument
2254 * equal p_ruid for non-root quota access, so
2255 * we'll just make sure that's the case.
2256 */
2257 savuid = p->p_cred->p_ruid;
2258 p->p_cred->p_ruid = cred->cr_uid;
2259 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2260 cred->cr_uid, (caddr_t)&dqb))
2261 freenum = min(dqb.dqb_bsoftlimit, freenum);
2262 p->p_cred->p_ruid = savuid;
2263#endif /* QUOTA */
2264 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2265 uquad = (u_int64_t)freenum;
2266 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2267 txdr_hyper(uquad, tl);
2268 retnum += NFSX_HYPER;
2269 break;
2270 case NFSATTRBIT_QUOTAUSED:
2271 freenum = 0;
2272#ifdef QUOTA
2273 /*
2274 * ufs_quotactl() insists that the uid argument
2275 * equal p_ruid for non-root quota access, so
2276 * we'll just make sure that's the case.
2277 */
2278 savuid = p->p_cred->p_ruid;
2279 p->p_cred->p_ruid = cred->cr_uid;
2280 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2281 cred->cr_uid, (caddr_t)&dqb))
2282 freenum = dqb.dqb_curblocks;
2283 p->p_cred->p_ruid = savuid;
2284#endif /* QUOTA */
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2286 uquad = (u_int64_t)freenum;
2287 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2288 txdr_hyper(uquad, tl);
2289 retnum += NFSX_HYPER;
2290 break;
2291 case NFSATTRBIT_RAWDEV:
2292 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2293 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2294 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2295 retnum += NFSX_V4SPECDATA;
2296 break;
2297 case NFSATTRBIT_SPACEAVAIL:
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2299 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2300 uquad = (u_int64_t)fs.f_bfree;
2301 else
2302 uquad = (u_int64_t)fs.f_bavail;
2303 uquad *= fs.f_bsize;
2304 txdr_hyper(uquad, tl);
2305 retnum += NFSX_HYPER;
2306 break;
2307 case NFSATTRBIT_SPACEFREE:
2308 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2309 uquad = (u_int64_t)fs.f_bfree;
2310 uquad *= fs.f_bsize;
2311 txdr_hyper(uquad, tl);
2312 retnum += NFSX_HYPER;
2313 break;
2314 case NFSATTRBIT_SPACETOTAL:
2315 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2316 uquad = (u_int64_t)fs.f_blocks;
2317 uquad *= fs.f_bsize;
2318 txdr_hyper(uquad, tl);
2319 retnum += NFSX_HYPER;
2320 break;
2321 case NFSATTRBIT_SPACEUSED:
2322 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2323 txdr_hyper(vap->va_bytes, tl);
2324 retnum += NFSX_HYPER;
2325 break;
2326 case NFSATTRBIT_TIMEACCESS:
2327 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2328 txdr_nfsv4time(&vap->va_atime, tl);
2329 retnum += NFSX_V4TIME;
2330 break;
2331 case NFSATTRBIT_TIMEACCESSSET:
2332 NFSGETTIME(&curtime);
2333 if (vap->va_atime.tv_sec != curtime.tv_sec) {
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2335 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2336 txdr_nfsv4time(&vap->va_atime, tl);
2337 retnum += NFSX_V4SETTIME;
2338 } else {
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2340 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2341 retnum += NFSX_UNSIGNED;
2342 }
2343 break;
2344 case NFSATTRBIT_TIMEDELTA:
2345 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2346 temptime.tv_sec = 0;
2347 temptime.tv_nsec = 1000000000 / hz;
2348 txdr_nfsv4time(&temptime, tl);
2349 retnum += NFSX_V4TIME;
2350 break;
2351 case NFSATTRBIT_TIMEMETADATA:
2352 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2353 txdr_nfsv4time(&vap->va_ctime, tl);
2354 retnum += NFSX_V4TIME;
2355 break;
2356 case NFSATTRBIT_TIMEMODIFY:
2357 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2358 txdr_nfsv4time(&vap->va_mtime, tl);
2359 retnum += NFSX_V4TIME;
2360 break;
2361 case NFSATTRBIT_TIMEMODIFYSET:
2362 NFSGETTIME(&curtime);
2363 if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2364 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2365 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2366 txdr_nfsv4time(&vap->va_mtime, tl);
2367 retnum += NFSX_V4SETTIME;
2368 } else {
2369 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2370 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2371 retnum += NFSX_UNSIGNED;
2372 }
2373 break;
2374 case NFSATTRBIT_MOUNTEDONFILEID:
2375 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2376 *tl++ = 0;
2377 if (nfsrv_atroot(vp, &fid))
2378 *tl = txdr_unsigned(fid);
2379 else
2380 *tl = txdr_unsigned(vap->va_fileid);
2381 retnum += NFSX_HYPER;
2382 break;
2383 default:
2384 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2385 };
2386 }
2387 }
2388 if (naclp != NULL)
2389 acl_free(naclp);
2390 *retnump = txdr_unsigned(retnum);
2391 return (retnum + prefixnum);
2392}
2393
2394/*
2395 * Put the attribute bits onto an mbuf list.
2396 * Return the number of bytes of output generated.
2397 */
2398APPLESTATIC int
2399nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2400{
2401 u_int32_t *tl;
2402 int cnt, i, bytesize;
2403
2404 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2405 if (attrbitp->bits[cnt - 1])
2406 break;
2407 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2408 NFSM_BUILD(tl, u_int32_t *, bytesize);
2409 *tl++ = txdr_unsigned(cnt);
2410 for (i = 0; i < cnt; i++)
2411 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2412 return (bytesize);
2413}
2414
2415/*
2416 * Convert a uid to a string.
2417 * If the lookup fails, just output the digits.
2418 * uid - the user id
2419 * cpp - points to a buffer of size NFSV4_SMALLSTR
2420 * (malloc a larger one, as required)
2421 * retlenp - pointer to length to be returned
2422 */
2423APPLESTATIC void
2424nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2425{
2426 int i;
2427 struct nfsusrgrp *usrp;
2428 u_char *cp = *cpp;
2429 uid_t tmp;
2430 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2431
2432 cnt = 0;
2433tryagain:
2434 NFSLOCKNAMEID();
2435 if (nfsrv_dnsname) {
2436 /*
2437 * Always map nfsrv_defaultuid to "nobody".
2438 */
2439 if (uid == nfsrv_defaultuid) {
2440 i = nfsrv_dnsnamelen + 7;
2441 if (i > len) {
2442 NFSUNLOCKNAMEID();
2443 if (len > NFSV4_SMALLSTR)
2444 free(cp, M_NFSSTRING);
2445 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2446 *cpp = cp;
2447 len = i;
2448 goto tryagain;
2449 }
2450 *retlenp = i;
2451 NFSBCOPY("nobody@", cp, 7);
2452 cp += 7;
2453 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2454 NFSUNLOCKNAMEID();
2455 return;
2456 }
2457 hasampersand = 0;
2458 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2459 if (usrp->lug_uid == uid) {
2460 if (usrp->lug_expiry < NFSD_MONOSEC)
2461 break;
2462 /*
2463 * If the name doesn't already have an '@'
2464 * in it, append @domainname to it.
2465 */
2466 for (i = 0; i < usrp->lug_namelen; i++) {
2467 if (usrp->lug_name[i] == '@') {
2468 hasampersand = 1;
2469 break;
2470 }
2471 }
2472 if (hasampersand)
2473 i = usrp->lug_namelen;
2474 else
2475 i = usrp->lug_namelen +
2476 nfsrv_dnsnamelen + 1;
2477 if (i > len) {
2478 NFSUNLOCKNAMEID();
2479 if (len > NFSV4_SMALLSTR)
2480 free(cp, M_NFSSTRING);
2481 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2482 *cpp = cp;
2483 len = i;
2484 goto tryagain;
2485 }
2486 *retlenp = i;
2487 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2488 if (!hasampersand) {
2489 cp += usrp->lug_namelen;
2490 *cp++ = '@';
2491 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2492 }
2493 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2494 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2495 NFSUNLOCKNAMEID();
2496 return;
2497 }
2498 }
2499 NFSUNLOCKNAMEID();
2500 cnt++;
2501 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2502 NULL, p);
2503 if (ret == 0 && cnt < 2)
2504 goto tryagain;
2505 } else {
2506 NFSUNLOCKNAMEID();
2507 }
2508
2509 /*
2510 * No match, just return a string of digits.
2511 */
2512 tmp = uid;
2513 i = 0;
2514 while (tmp || i == 0) {
2515 tmp /= 10;
2516 i++;
2517 }
2518 len = (i > len) ? len : i;
2519 *retlenp = len;
2520 cp += (len - 1);
2521 tmp = uid;
2522 for (i = 0; i < len; i++) {
2523 *cp-- = '0' + (tmp % 10);
2524 tmp /= 10;
2525 }
2526 return;
2527}
2528
2529/*
2530 * Convert a string to a uid.
2531 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2532 * return 0.
2533 */
2534APPLESTATIC int
2535nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2536{
2537 int i;
2538 u_char *cp;
2539 struct nfsusrgrp *usrp;
2540 int cnt, ret;
2541
2542 if (len == 0)
2543 return (NFSERR_BADOWNER);
2544 /*
2545 * Look for an '@'.
2546 */
2547 cp = str;
2548 for (i = 0; i < len; i++)
2549 if (*cp++ == '@')
2550 break;
2551
2552 cnt = 0;
2553tryagain:
2554 NFSLOCKNAMEID();
2555 /*
2556 * If an '@' is found and the domain name matches, search for the name
2557 * with dns stripped off.
2558 * Mixed case alpahbetics will match for the domain name, but all
2559 * upper case will not.
2560 */
2561 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2562 (len - 1 - i) == nfsrv_dnsnamelen &&
2563 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2564 len -= (nfsrv_dnsnamelen + 1);
2565 *(cp - 1) = '\0';
2566 }
2567
2568 /*
2569 * Check for the special case of "nobody".
2570 */
2571 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2572 *uidp = nfsrv_defaultuid;
2573 NFSUNLOCKNAMEID();
2574 return (0);
2575 }
2576
2577 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2578 if (usrp->lug_namelen == len &&
2579 !NFSBCMP(usrp->lug_name, str, len)) {
2580 if (usrp->lug_expiry < NFSD_MONOSEC)
2581 break;
2582 *uidp = usrp->lug_uid;
2583 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2584 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2585 NFSUNLOCKNAMEID();
2586 return (0);
2587 }
2588 }
2589 NFSUNLOCKNAMEID();
2590 cnt++;
2591 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2592 str, p);
2593 if (ret == 0 && cnt < 2)
2594 goto tryagain;
2595 return (NFSERR_BADOWNER);
2596}
2597
2598/*
2599 * Convert a gid to a string.
2600 * gid - the group id
2601 * cpp - points to a buffer of size NFSV4_SMALLSTR
2602 * (malloc a larger one, as required)
2603 * retlenp - pointer to length to be returned
2604 */
2605APPLESTATIC void
2606nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2607{
2608 int i;
2609 struct nfsusrgrp *usrp;
2610 u_char *cp = *cpp;
2611 gid_t tmp;
2612 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2613
2614 cnt = 0;
2615tryagain:
2616 NFSLOCKNAMEID();
2617 if (nfsrv_dnsname) {
2618 /*
2619 * Always map nfsrv_defaultgid to "nogroup".
2620 */
2621 if (gid == nfsrv_defaultgid) {
2622 i = nfsrv_dnsnamelen + 8;
2623 if (i > len) {
2624 NFSUNLOCKNAMEID();
2625 if (len > NFSV4_SMALLSTR)
2626 free(cp, M_NFSSTRING);
2627 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2628 *cpp = cp;
2629 len = i;
2630 goto tryagain;
2631 }
2632 *retlenp = i;
2633 NFSBCOPY("nogroup@", cp, 8);
2634 cp += 8;
2635 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2636 NFSUNLOCKNAMEID();
2637 return;
2638 }
2639 hasampersand = 0;
2640 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2641 if (usrp->lug_gid == gid) {
2642 if (usrp->lug_expiry < NFSD_MONOSEC)
2643 break;
2644 /*
2645 * If the name doesn't already have an '@'
2646 * in it, append @domainname to it.
2647 */
2648 for (i = 0; i < usrp->lug_namelen; i++) {
2649 if (usrp->lug_name[i] == '@') {
2650 hasampersand = 1;
2651 break;
2652 }
2653 }
2654 if (hasampersand)
2655 i = usrp->lug_namelen;
2656 else
2657 i = usrp->lug_namelen +
2658 nfsrv_dnsnamelen + 1;
2659 if (i > len) {
2660 NFSUNLOCKNAMEID();
2661 if (len > NFSV4_SMALLSTR)
2662 free(cp, M_NFSSTRING);
2663 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2664 *cpp = cp;
2665 len = i;
2666 goto tryagain;
2667 }
2668 *retlenp = i;
2669 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2670 if (!hasampersand) {
2671 cp += usrp->lug_namelen;
2672 *cp++ = '@';
2673 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2674 }
2675 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2676 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2677 NFSUNLOCKNAMEID();
2678 return;
2679 }
2680 }
2681 NFSUNLOCKNAMEID();
2682 cnt++;
2683 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2684 NULL, p);
2685 if (ret == 0 && cnt < 2)
2686 goto tryagain;
2687 } else {
2688 NFSUNLOCKNAMEID();
2689 }
2690
2691 /*
2692 * No match, just return a string of digits.
2693 */
2694 tmp = gid;
2695 i = 0;
2696 while (tmp || i == 0) {
2697 tmp /= 10;
2698 i++;
2699 }
2700 len = (i > len) ? len : i;
2701 *retlenp = len;
2702 cp += (len - 1);
2703 tmp = gid;
2704 for (i = 0; i < len; i++) {
2705 *cp-- = '0' + (tmp % 10);
2706 tmp /= 10;
2707 }
2708 return;
2709}
2710
2711/*
2712 * Convert a string to a gid.
2713 */
2714APPLESTATIC int
2715nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2716{
2717 int i;
2718 u_char *cp;
2719 struct nfsusrgrp *usrp;
2720 int cnt, ret;
2721
2722 if (len == 0)
2723 return (NFSERR_BADOWNER);
2724 /*
2725 * Look for an '@'.
2726 */
2727 cp = str;
2728 for (i = 0; i < len; i++)
2729 if (*cp++ == '@')
2730 break;
2731
2732 cnt = 0;
2733tryagain:
2734 NFSLOCKNAMEID();
2735 /*
2736 * If an '@' is found and the dns name matches, search for the name
2737 * with the dns stripped off.
2738 */
2739 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2740 (len - 1 - i) == nfsrv_dnsnamelen &&
2741 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2742 len -= (nfsrv_dnsnamelen + 1);
2743 *(cp - 1) = '\0';
2744 }
2745
2746 /*
2747 * Check for the special case of "nogroup".
2748 */
2749 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2750 *gidp = nfsrv_defaultgid;
2751 NFSUNLOCKNAMEID();
2752 return (0);
2753 }
2754
2755 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2756 if (usrp->lug_namelen == len &&
2757 !NFSBCMP(usrp->lug_name, str, len)) {
2758 if (usrp->lug_expiry < NFSD_MONOSEC)
2759 break;
2760 *gidp = usrp->lug_gid;
2761 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2762 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2763 NFSUNLOCKNAMEID();
2764 return (0);
2765 }
2766 }
2767 NFSUNLOCKNAMEID();
2768 cnt++;
2769 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2770 str, p);
2771 if (ret == 0 && cnt < 2)
2772 goto tryagain;
2773 return (NFSERR_BADOWNER);
2774}
2775
2776/*
2777 * Cmp len chars, allowing mixed case in the first argument to match lower
2778 * case in the second, but not if the first argument is all upper case.
2779 * Return 0 for a match, 1 otherwise.
2780 */
2781static int
2782nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2783{
2784 int i;
2785 u_char tmp;
2786 int fndlower = 0;
2787
2788 for (i = 0; i < len; i++) {
2789 if (*cp >= 'A' && *cp <= 'Z') {
2790 tmp = *cp++ + ('a' - 'A');
2791 } else {
2792 tmp = *cp++;
2793 if (tmp >= 'a' && tmp <= 'z')
2794 fndlower = 1;
2795 }
2796 if (tmp != *cp2++)
2797 return (1);
2798 }
2799 if (fndlower)
2800 return (0);
2801 else
2802 return (1);
2803}
2804
2805/*
2806 * Set the port for the nfsuserd.
2807 */
2808APPLESTATIC int
2809nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2810{
2811 struct nfssockreq *rp;
2812 struct sockaddr_in *ad;
2813 int error;
2814
2815 NFSLOCKNAMEID();
2816 if (nfsrv_nfsuserd) {
2817 NFSUNLOCKNAMEID();
2818 return (EPERM);
2819 }
2820 nfsrv_nfsuserd = 1;
2821 NFSUNLOCKNAMEID();
2822 /*
2823 * Set up the socket record and connect.
2824 */
2825 rp = &nfsrv_nfsuserdsock;
2826 rp->nr_client = NULL;
2827 rp->nr_sotype = SOCK_DGRAM;
2828 rp->nr_soproto = IPPROTO_UDP;
2829 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2830 rp->nr_cred = NULL;
2831 NFSSOCKADDRALLOC(rp->nr_nam);
2832 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2833 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2834 ad->sin_family = AF_INET;
2835 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2836 ad->sin_port = port;
2837 rp->nr_prog = RPCPROG_NFSUSERD;
2838 rp->nr_vers = RPCNFSUSERD_VERS;
2839 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2840 if (error) {
2841 NFSSOCKADDRFREE(rp->nr_nam);
2842 nfsrv_nfsuserd = 0;
2843 }
2844 return (error);
2845}
2846
2847/*
2848 * Delete the nfsuserd port.
2849 */
2850APPLESTATIC void
2851nfsrv_nfsuserddelport(void)
2852{
2853
2854 NFSLOCKNAMEID();
2855 if (nfsrv_nfsuserd == 0) {
2856 NFSUNLOCKNAMEID();
2857 return;
2858 }
2859 nfsrv_nfsuserd = 0;
2860 NFSUNLOCKNAMEID();
2861 newnfs_disconnect(&nfsrv_nfsuserdsock);
2862 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2863}
2864
2865/*
2866 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2867 * name<-->id cache.
2868 * Returns 0 upon success, non-zero otherwise.
2869 */
2870static int
2871nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2872{
2873 u_int32_t *tl;
2874 struct nfsrv_descript *nd;
2875 int len;
2876 struct nfsrv_descript nfsd;
2877 struct ucred *cred;
2878 int error;
2879
2880 NFSLOCKNAMEID();
2881 if (nfsrv_nfsuserd == 0) {
2882 NFSUNLOCKNAMEID();
2883 return (EPERM);
2884 }
2885 NFSUNLOCKNAMEID();
2886 nd = &nfsd;
2887 cred = newnfs_getcred();
2888 nd->nd_flag = ND_GSSINITREPLY;
2889 nfsrvd_rephead(nd);
2890
2891 nd->nd_procnum = procnum;
2892 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2893 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2894 if (procnum == RPCNFSUSERD_GETUID)
2895 *tl = txdr_unsigned(uid);
2896 else
2897 *tl = txdr_unsigned(gid);
2898 } else {
2899 len = strlen(name);
2900 (void) nfsm_strtom(nd, name, len);
2901 }
2902 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2903 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2904 NFSFREECRED(cred);
2905 if (!error) {
2906 mbuf_freem(nd->nd_mrep);
2907 error = nd->nd_repstat;
2908 }
2909 return (error);
2910}
2911
2912/*
2913 * This function is called from the nfssvc(2) system call, to update the
2914 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2915 */
2916APPLESTATIC int
2917nfssvc_idname(struct nfsd_idargs *nidp)
2918{
2919 struct nfsusrgrp *nusrp, *usrp, *newusrp;
2920 struct nfsuserhashhead *hp;
2921 int i;
2922 int error = 0;
2923 u_char *cp;
2924
2925 if (nidp->nid_flag & NFSID_INITIALIZE) {
2926 cp = (u_char *)malloc(nidp->nid_namelen + 1,
2927 M_NFSSTRING, M_WAITOK);
2928 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2929 nidp->nid_namelen);
2930 NFSLOCKNAMEID();
2931 if (nfsrv_dnsname) {
2932 /*
2933 * Free up all the old stuff and reinitialize hash lists.
2934 */
2935 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2936 nfsrv_removeuser(usrp);
2937 }
2938 free(nfsrv_dnsname, M_NFSSTRING);
2939 nfsrv_dnsname = NULL;
2940 }
2941 TAILQ_INIT(&nfsuserlruhead);
2942 for (i = 0; i < NFSUSERHASHSIZE; i++)
2943 LIST_INIT(&nfsuserhash[i]);
2944 for (i = 0; i < NFSGROUPHASHSIZE; i++)
2945 LIST_INIT(&nfsgrouphash[i]);
2946 for (i = 0; i < NFSUSERHASHSIZE; i++)
2947 LIST_INIT(&nfsusernamehash[i]);
2948 for (i = 0; i < NFSGROUPHASHSIZE; i++)
2949 LIST_INIT(&nfsgroupnamehash[i]);
2950
2951 /*
2952 * Put name in "DNS" string.
2953 */
2954 if (!error) {
2955 nfsrv_dnsname = cp;
2956 nfsrv_dnsnamelen = nidp->nid_namelen;
2957 nfsrv_defaultuid = nidp->nid_uid;
2958 nfsrv_defaultgid = nidp->nid_gid;
2959 nfsrv_usercnt = 0;
2960 nfsrv_usermax = nidp->nid_usermax;
2961 }
2962 NFSUNLOCKNAMEID();
2963 if (error)
2964 free(cp, M_NFSSTRING);
2965 return (error);
2966 }
2967
2968 /*
2969 * malloc the new one now, so any potential sleep occurs before
2970 * manipulation of the lists.
2971 */
2972 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
2973 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
2974 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
2975 nidp->nid_namelen);
2976 if (error) {
2977 free((caddr_t)newusrp, M_NFSUSERGROUP);
2978 return (error);
2979 }
2980 newusrp->lug_namelen = nidp->nid_namelen;
2981
2982 NFSLOCKNAMEID();
2983 /*
2984 * Delete old entries, as required.
2985 */
2986 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
2987 hp = NFSUSERHASH(nidp->nid_uid);
2988 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
2989 if (usrp->lug_uid == nidp->nid_uid)
2990 nfsrv_removeuser(usrp);
2991 }
2992 }
2993 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
2994 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
2995 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
2996 if (usrp->lug_namelen == newusrp->lug_namelen &&
2997 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
2998 usrp->lug_namelen))
2999 nfsrv_removeuser(usrp);
3000 }
3001 }
3002 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3003 hp = NFSGROUPHASH(nidp->nid_gid);
3004 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3005 if (usrp->lug_gid == nidp->nid_gid)
3006 nfsrv_removeuser(usrp);
3007 }
3008 }
3009 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3010 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3011 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3012 if (usrp->lug_namelen == newusrp->lug_namelen &&
3013 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3014 usrp->lug_namelen))
3015 nfsrv_removeuser(usrp);
3016 }
3017 }
3018 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3019 if (usrp->lug_expiry < NFSD_MONOSEC)
3020 nfsrv_removeuser(usrp);
3021 }
3022 while (nfsrv_usercnt >= nfsrv_usermax) {
3023 usrp = TAILQ_FIRST(&nfsuserlruhead);
3024 nfsrv_removeuser(usrp);
3025 }
3026
3027 /*
3028 * Now, we can add the new one.
3029 */
3030 if (nidp->nid_usertimeout)
3031 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3032 else
3033 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3034 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3035 newusrp->lug_uid = nidp->nid_uid;
3036 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3037 lug_numhash);
3038 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3039 newusrp->lug_namelen), newusrp, lug_namehash);
3040 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3041 nfsrv_usercnt++;
3042 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3043 newusrp->lug_gid = nidp->nid_gid;
3044 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3045 lug_numhash);
3046 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3047 newusrp->lug_namelen), newusrp, lug_namehash);
3048 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3049 nfsrv_usercnt++;
3050 } else
3051 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3052 NFSUNLOCKNAMEID();
3053 return (error);
3054}
3055
3056/*
3057 * Remove a user/group name element.
3058 */
3059static void
3060nfsrv_removeuser(struct nfsusrgrp *usrp)
3061{
3062
3063 NFSNAMEIDREQUIRED();
3064 LIST_REMOVE(usrp, lug_numhash);
3065 LIST_REMOVE(usrp, lug_namehash);
3066 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3067 nfsrv_usercnt--;
3068 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3069}
3070
3071/*
3072 * This function scans a byte string and checks for UTF-8 compliance.
3073 * It returns 0 if it conforms and NFSERR_INVAL if not.
3074 */
3075APPLESTATIC int
3076nfsrv_checkutf8(u_int8_t *cp, int len)
3077{
3078 u_int32_t val = 0x0;
3079 int cnt = 0, gotd = 0, shift = 0;
3080 u_int8_t byte;
3081 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3082
3083 /*
3084 * Here are what the variables are used for:
3085 * val - the calculated value of a multibyte char, used to check
3086 * that it was coded with the correct range
3087 * cnt - the number of 10xxxxxx bytes to follow
3088 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3089 * shift - lower order bits of range (ie. "val >> shift" should
3090 * not be 0, in other words, dividing by the lower bound
3091 * of the range should get a non-zero value)
3092 * byte - used to calculate cnt
3093 */
3094 while (len > 0) {
3095 if (cnt > 0) {
3096 /* This handles the 10xxxxxx bytes */
3097 if ((*cp & 0xc0) != 0x80 ||
3098 (gotd && (*cp & 0x20)))
3099 return (NFSERR_INVAL);
3100 gotd = 0;
3101 val <<= 6;
3102 val |= (*cp & 0x3f);
3103 cnt--;
3104 if (cnt == 0 && (val >> shift) == 0x0)
3105 return (NFSERR_INVAL);
3106 } else if (*cp & 0x80) {
3107 /* first byte of multi byte char */
3108 byte = *cp;
3109 while ((byte & 0x40) && cnt < 6) {
3110 cnt++;
3111 byte <<= 1;
3112 }
3113 if (cnt == 0 || cnt == 6)
3114 return (NFSERR_INVAL);
3115 val = (*cp & (0x3f >> cnt));
3116 shift = utf8_shift[cnt - 1];
3117 if (cnt == 2 && val == 0xd)
3118 /* Check for the 0xd800-0xdfff case */
3119 gotd = 1;
3120 }
3121 cp++;
3122 len--;
3123 }
3124 if (cnt > 0)
3125 return (NFSERR_INVAL);
3126 return (0);
3127}
3128
3129/*
3130 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3131 * strings, one with the root path in it and the other with the list of
3132 * locations. The list is in the same format as is found in nfr_refs.
3133 * It is a "," separated list of entries, where each of them is of the
3134 * form <server>:<rootpath>. For example
3135 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3136 * The nilp argument is set to 1 for the special case of a null fs_root
3137 * and an empty server list.
3138 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3139 * number of xdr bytes parsed in sump.
3140 */
3141static int
3142nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3143 int *sump, int *nilp)
3144{
3145 u_int32_t *tl;
3146 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3147 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3148 struct list {
3149 SLIST_ENTRY(list) next;
3150 int len;
3151 u_char host[1];
3152 } *lsp, *nlsp;
3153 SLIST_HEAD(, list) head;
3154
3155 *fsrootp = NULL;
3156 *srvp = NULL;
3157 *nilp = 0;
3158
3159 /*
3160 * Get the fs_root path and check for the special case of null path
3161 * and 0 length server list.
3162 */
3163 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3164 len = fxdr_unsigned(int, *tl);
3165 if (len < 0 || len > 10240)
3166 return (NFSERR_BADXDR);
3167 if (len == 0) {
3168 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3169 if (*tl != 0)
3170 return (NFSERR_BADXDR);
3171 *nilp = 1;
3172 *sump = 2 * NFSX_UNSIGNED;
3173 return (0);
3174 }
3175 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3176 error = nfsrv_mtostr(nd, cp, len);
3177 if (!error) {
3178 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3179 cnt = fxdr_unsigned(int, *tl);
3180 if (cnt <= 0)
3181 error = NFSERR_BADXDR;
3182 }
3183 if (error) {
3184 free(cp, M_NFSSTRING);
3185 return (error);
3186 }
3187
3188 /*
3189 * Now, loop through the location list and make up the srvlist.
3190 */
3191 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3192 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3193 slen = 1024;
3194 siz = 0;
3195 for (i = 0; i < cnt; i++) {
3196 SLIST_INIT(&head);
3197 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3198 nsrv = fxdr_unsigned(int, *tl);
3199 if (nsrv <= 0) {
3200 free(cp, M_NFSSTRING);
3201 free(cp2, M_NFSSTRING);
3202 return (NFSERR_BADXDR);
3203 }
3204
3205 /*
3206 * Handle the first server by putting it in the srvstr.
3207 */
3208 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3209 len = fxdr_unsigned(int, *tl);
3210 if (len <= 0 || len > 1024) {
3211 free(cp, M_NFSSTRING);
3212 free(cp2, M_NFSSTRING);
3213 return (NFSERR_BADXDR);
3214 }
3215 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3216 if (cp3 != cp2) {
3217 *cp3++ = ',';
3218 siz++;
3219 }
3220 error = nfsrv_mtostr(nd, cp3, len);
3221 if (error) {
3222 free(cp, M_NFSSTRING);
3223 free(cp2, M_NFSSTRING);
3224 return (error);
3225 }
3226 cp3 += len;
3227 *cp3++ = ':';
3228 siz += (len + 1);
3229 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3230 for (j = 1; j < nsrv; j++) {
3231 /*
3232 * Yuck, put them in an slist and process them later.
3233 */
3234 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3235 len = fxdr_unsigned(int, *tl);
3236 if (len <= 0 || len > 1024) {
3237 free(cp, M_NFSSTRING);
3238 free(cp2, M_NFSSTRING);
3239 return (NFSERR_BADXDR);
3240 }
3241 lsp = (struct list *)malloc(sizeof (struct list)
3242 + len, M_TEMP, M_WAITOK);
3243 error = nfsrv_mtostr(nd, lsp->host, len);
3244 if (error) {
3245 free(cp, M_NFSSTRING);
3246 free(cp2, M_NFSSTRING);
3247 return (error);
3248 }
3249 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3250 lsp->len = len;
3251 SLIST_INSERT_HEAD(&head, lsp, next);
3252 }
3253
3254 /*
3255 * Finally, we can get the path.
3256 */
3257 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3258 len = fxdr_unsigned(int, *tl);
3259 if (len <= 0 || len > 1024) {
3260 free(cp, M_NFSSTRING);
3261 free(cp2, M_NFSSTRING);
3262 return (NFSERR_BADXDR);
3263 }
3264 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3265 error = nfsrv_mtostr(nd, cp3, len);
3266 if (error) {
3267 free(cp, M_NFSSTRING);
3268 free(cp2, M_NFSSTRING);
3269 return (error);
3270 }
3271 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3272 str = cp3;
3273 stringlen = len;
3274 cp3 += len;
3275 siz += len;
3276 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3277 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3278 &cp2, &cp3, &slen);
3279 *cp3++ = ',';
3280 NFSBCOPY(lsp->host, cp3, lsp->len);
3281 cp3 += lsp->len;
3282 *cp3++ = ':';
3283 NFSBCOPY(str, cp3, stringlen);
3284 cp3 += stringlen;
3285 *cp3 = '\0';
3286 siz += (lsp->len + stringlen + 2);
3287 free((caddr_t)lsp, M_TEMP);
3288 }
3289 }
3290 *fsrootp = cp;
3291 *srvp = cp2;
3292 *sump = xdrsum;
3293 return (0);
3294nfsmout:
3295 if (cp != NULL)
3296 free(cp, M_NFSSTRING);
3297 if (cp2 != NULL)
3298 free(cp2, M_NFSSTRING);
3299 return (error);
3300}
3301
3302/*
3303 * Make the malloc'd space large enough. This is a pain, but the xdr
3304 * doesn't set an upper bound on the side, so...
3305 */
3306static void
3307nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3308{
3309 u_char *cp;
3310 int i;
3311
3312 if (siz <= *slenp)
3313 return;
3314 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3315 NFSBCOPY(*cpp, cp, *slenp);
3316 free(*cpp, M_NFSSTRING);
3317 i = *cpp2 - *cpp;
3318 *cpp = cp;
3319 *cpp2 = cp + i;
3320 *slenp = siz + 1024;
3321}
3322
3323/*
3324 * Initialize the reply header data structures.
3325 */
3326APPLESTATIC void
3327nfsrvd_rephead(struct nfsrv_descript *nd)
3328{
3329 mbuf_t mreq;
3330
3331 /*
3332 * If this is a big reply, use a cluster.
3333 */
3334 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3335 nfs_bigreply[nd->nd_procnum]) {
3336 NFSMCLGET(mreq, M_WAIT);
3337 nd->nd_mreq = mreq;
3338 nd->nd_mb = mreq;
3339 } else {
3340 NFSMGET(mreq);
3341 nd->nd_mreq = mreq;
3342 nd->nd_mb = mreq;
3343 }
3344 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3345 mbuf_setlen(mreq, 0);
3346
3347 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3348 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3349}
3350
3351/*
3352 * Lock a socket against others.
3353 * Currently used to serialize connect/disconnect attempts.
3354 */
3355int
3356newnfs_sndlock(int *flagp)
3357{
3358 struct timespec ts;
3359
3360 NFSLOCKSOCK();
3361 while (*flagp & NFSR_SNDLOCK) {
3362 *flagp |= NFSR_WANTSND;
3363 ts.tv_sec = 0;
3364 ts.tv_nsec = 0;
3365 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3366 PZERO - 1, "nfsndlck", &ts);
3367 }
3368 *flagp |= NFSR_SNDLOCK;
3369 NFSUNLOCKSOCK();
3370 return (0);
3371}
3372
3373/*
3374 * Unlock the stream socket for others.
3375 */
3376void
3377newnfs_sndunlock(int *flagp)
3378{
3379
3380 NFSLOCKSOCK();
3381 if ((*flagp & NFSR_SNDLOCK) == 0)
3382 panic("nfs sndunlock");
3383 *flagp &= ~NFSR_SNDLOCK;
3384 if (*flagp & NFSR_WANTSND) {
3385 *flagp &= ~NFSR_WANTSND;
3386 wakeup((caddr_t)flagp);
3387 }
3388 NFSUNLOCKSOCK();
3389}
3390