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