1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: releng/8.4/sys/fs/nfs/nfs_commonsubs.c 247503 2013-02-28 21:58:07Z jhb $");
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 */
51 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
52
53 /* And other global data */
54 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
55 NFFIFO, NFNON };
56 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
57 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
58 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
59 int nfscl_ticks;
60 int nfsrv_useacl = 1;
61 struct nfssockreq nfsrv_nfsuserdsock;
62 int nfsrv_nfsuserd = 0;
63 struct nfsreqhead nfsd_reqq;
64 uid_t nfsrv_defaultuid;
65 gid_t nfsrv_defaultgid;
66 int nfsrv_lease = NFSRV_LEASE;
67 int ncl_mbuf_mlen = MLEN;
68 NFSNAMEIDMUTEX;
69 NFSSOCKMUTEX;
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 */
88 struct 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
132 static int ncl_mbuf_mhlen = MHLEN;
133 static int nfsrv_usercnt = 0;
134 static int nfsrv_dnsnamelen;
135 static u_char *nfsrv_dnsname = NULL;
136 static int nfsrv_usermax = 999999999;
137 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
138 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
139 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
140 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
141 static 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 */
150 static 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 */
155 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
156 static void nfsv4_wanted(struct nfsv4lock *lp);
157 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
158 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
159 NFSPROC_T *p);
160 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
161 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
162 int *, int *);
163 static 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 */
170 int
171 nfsm_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
241 out:
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 */
253 APPLESTATIC void *
254 nfsm_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 */
317 APPLESTATIC int
318 nfsm_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
352 out:
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 */
361 APPLESTATIC int
362 nfsm_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 */
418 APPLESTATIC void
419 newnfs_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 */
448 APPLESTATIC int
449 nfsm_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 */
491 APPLESTATIC int
492 nfsaddr_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 */
524 APPLESTATIC int
525 nfsaddr2_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 */
562 APPLESTATIC void
563 newnfs_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 */
608 APPLESTATIC void
609 newnfs_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 */
627 APPLESTATIC int
628 nfsm_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;
653 nfsmout:
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 */
662 APPLESTATIC int
663 nfsrv_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;
700 nfsmout:
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 */
708 static int
709 nfsrv_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);
717 nfsmout:
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 */
728 APPLESTATIC int
729 nfsrv_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);
759 nfsmout:
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 */
774 APPLESTATIC int
775 nfsv4_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 }
1738 nfsmout:
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 */
1762 APPLESTATIC int
1763 nfsv4_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 */
1809 APPLESTATIC void
1810 nfsv4_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 */
1822 APPLESTATIC void
1823 nfsv4_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 */
1842 APPLESTATIC void
1843 nfsv4_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 */
1872 APPLESTATIC int
1873 nfsv4_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 */
1886 APPLESTATIC int
1887 nfsv4_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 */
1899 static void
1900 nfsv4_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 */
1914 APPLESTATIC int
1915 nfsrv_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
1957 out:
1958 NFSEXITCODE2(error, nd);
1959 return (error);
1960 }
1961
1962 /*
1963 * Fill in the attributes as marked by the bitmap (V4).
1964 */
1965 APPLESTATIC int
1966 nfsv4_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 NFSACL_T *aclp, *naclp = NULL;
1983 #ifdef QUOTA
1984 struct dqblk dqb;
1985 uid_t savuid;
1986 #endif
1987
1988 /*
1989 * First, set the bits that can be filled and get fsinfo.
1990 */
1991 NFSSET_ATTRBIT(retbitp, attrbitp);
1992 /* If p and cred are NULL, it is a client side call */
1993 if (p == NULL && cred == NULL) {
1994 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1995 aclp = saclp;
1996 } else {
1997 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1998 naclp = acl_alloc(M_WAITOK);
1999 aclp = naclp;
2000 }
2001 nfsvno_getfs(&fsinf, isdgram);
2002 #ifndef APPLE
2003 /*
2004 * Get the VFS_STATFS(), since some attributes need them.
2005 */
2006 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2007 error = VFS_STATFS(mp, &fs);
2008 if (error != 0) {
2009 if (reterr) {
2010 nd->nd_repstat = NFSERR_ACCES;
2011 return (0);
2012 }
2013 NFSCLRSTATFS_ATTRBIT(retbitp);
2014 }
2015 }
2016 #endif
2017
2018 /*
2019 * And the NFSv4 ACL...
2020 */
2021 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2022 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2023 supports_nfsv4acls == 0))) {
2024 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2025 }
2026 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2027 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2028 supports_nfsv4acls == 0)) {
2029 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2030 } else if (naclp != NULL) {
2031 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2032 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2033 if (error == 0)
2034 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2035 naclp, cred, p);
2036 NFSVOPUNLOCK(vp, 0);
2037 } else
2038 error = NFSERR_PERM;
2039 if (error != 0) {
2040 if (reterr) {
2041 nd->nd_repstat = NFSERR_ACCES;
2042 return (0);
2043 }
2044 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2045 }
2046 }
2047 }
2048 /*
2049 * Put out the attribute bitmap for the ones being filled in
2050 * and get the field for the number of attributes returned.
2051 */
2052 prefixnum = nfsrv_putattrbit(nd, retbitp);
2053 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2054 prefixnum += NFSX_UNSIGNED;
2055
2056 /*
2057 * Now, loop around filling in the attributes for each bit set.
2058 */
2059 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2060 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2061 switch (bitpos) {
2062 case NFSATTRBIT_SUPPORTEDATTRS:
2063 NFSSETSUPP_ATTRBIT(&attrbits);
2064 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2065 && supports_nfsv4acls == 0)) {
2066 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2067 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2068 }
2069 retnum += nfsrv_putattrbit(nd, &attrbits);
2070 break;
2071 case NFSATTRBIT_TYPE:
2072 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2073 *tl = vtonfsv34_type(vap->va_type);
2074 retnum += NFSX_UNSIGNED;
2075 break;
2076 case NFSATTRBIT_FHEXPIRETYPE:
2077 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2078 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2079 retnum += NFSX_UNSIGNED;
2080 break;
2081 case NFSATTRBIT_CHANGE:
2082 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2083 txdr_hyper(vap->va_filerev, tl);
2084 retnum += NFSX_HYPER;
2085 break;
2086 case NFSATTRBIT_SIZE:
2087 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2088 txdr_hyper(vap->va_size, tl);
2089 retnum += NFSX_HYPER;
2090 break;
2091 case NFSATTRBIT_LINKSUPPORT:
2092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2093 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2094 *tl = newnfs_true;
2095 else
2096 *tl = newnfs_false;
2097 retnum += NFSX_UNSIGNED;
2098 break;
2099 case NFSATTRBIT_SYMLINKSUPPORT:
2100 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2101 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2102 *tl = newnfs_true;
2103 else
2104 *tl = newnfs_false;
2105 retnum += NFSX_UNSIGNED;
2106 break;
2107 case NFSATTRBIT_NAMEDATTR:
2108 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2109 *tl = newnfs_false;
2110 retnum += NFSX_UNSIGNED;
2111 break;
2112 case NFSATTRBIT_FSID:
2113 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2114 *tl++ = 0;
2115 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2116 *tl++ = 0;
2117 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2118 retnum += NFSX_V4FSID;
2119 break;
2120 case NFSATTRBIT_UNIQUEHANDLES:
2121 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2122 *tl = newnfs_true;
2123 retnum += NFSX_UNSIGNED;
2124 break;
2125 case NFSATTRBIT_LEASETIME:
2126 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2127 *tl = txdr_unsigned(nfsrv_lease);
2128 retnum += NFSX_UNSIGNED;
2129 break;
2130 case NFSATTRBIT_RDATTRERROR:
2131 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2132 *tl = txdr_unsigned(rderror);
2133 retnum += NFSX_UNSIGNED;
2134 break;
2135 /*
2136 * Recommended Attributes. (Only the supported ones.)
2137 */
2138 case NFSATTRBIT_ACL:
2139 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2140 break;
2141 case NFSATTRBIT_ACLSUPPORT:
2142 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2143 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2144 retnum += NFSX_UNSIGNED;
2145 break;
2146 case NFSATTRBIT_CANSETTIME:
2147 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2148 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2149 *tl = newnfs_true;
2150 else
2151 *tl = newnfs_false;
2152 retnum += NFSX_UNSIGNED;
2153 break;
2154 case NFSATTRBIT_CASEINSENSITIVE:
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2156 *tl = newnfs_false;
2157 retnum += NFSX_UNSIGNED;
2158 break;
2159 case NFSATTRBIT_CASEPRESERVING:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2161 *tl = newnfs_true;
2162 retnum += NFSX_UNSIGNED;
2163 break;
2164 case NFSATTRBIT_CHOWNRESTRICTED:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2166 *tl = newnfs_true;
2167 retnum += NFSX_UNSIGNED;
2168 break;
2169 case NFSATTRBIT_FILEHANDLE:
2170 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2171 break;
2172 case NFSATTRBIT_FILEID:
2173 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2174 *tl++ = 0;
2175 *tl = txdr_unsigned(vap->va_fileid);
2176 retnum += NFSX_HYPER;
2177 break;
2178 case NFSATTRBIT_FILESAVAIL:
2179 /*
2180 * Check quota and use min(quota, f_ffree).
2181 */
2182 freenum = fs.f_ffree;
2183 #ifdef QUOTA
2184 /*
2185 * ufs_quotactl() insists that the uid argument
2186 * equal p_ruid for non-root quota access, so
2187 * we'll just make sure that's the case.
2188 */
2189 savuid = p->p_cred->p_ruid;
2190 p->p_cred->p_ruid = cred->cr_uid;
2191 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2192 cred->cr_uid, (caddr_t)&dqb))
2193 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2194 freenum);
2195 p->p_cred->p_ruid = savuid;
2196 #endif /* QUOTA */
2197 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2198 *tl++ = 0;
2199 *tl = txdr_unsigned(freenum);
2200 retnum += NFSX_HYPER;
2201 break;
2202 case NFSATTRBIT_FILESFREE:
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2204 *tl++ = 0;
2205 *tl = txdr_unsigned(fs.f_ffree);
2206 retnum += NFSX_HYPER;
2207 break;
2208 case NFSATTRBIT_FILESTOTAL:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2210 *tl++ = 0;
2211 *tl = txdr_unsigned(fs.f_files);
2212 retnum += NFSX_HYPER;
2213 break;
2214 case NFSATTRBIT_FSLOCATIONS:
2215 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2216 *tl++ = 0;
2217 *tl = 0;
2218 retnum += 2 * NFSX_UNSIGNED;
2219 break;
2220 case NFSATTRBIT_HOMOGENEOUS:
2221 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2222 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2223 *tl = newnfs_true;
2224 else
2225 *tl = newnfs_false;
2226 retnum += NFSX_UNSIGNED;
2227 break;
2228 case NFSATTRBIT_MAXFILESIZE:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2230 uquad = NFSRV_MAXFILESIZE;
2231 txdr_hyper(uquad, tl);
2232 retnum += NFSX_HYPER;
2233 break;
2234 case NFSATTRBIT_MAXLINK:
2235 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2236 *tl = txdr_unsigned(LINK_MAX);
2237 retnum += NFSX_UNSIGNED;
2238 break;
2239 case NFSATTRBIT_MAXNAME:
2240 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2241 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2242 retnum += NFSX_UNSIGNED;
2243 break;
2244 case NFSATTRBIT_MAXREAD:
2245 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2246 *tl++ = 0;
2247 *tl = txdr_unsigned(fsinf.fs_rtmax);
2248 retnum += NFSX_HYPER;
2249 break;
2250 case NFSATTRBIT_MAXWRITE:
2251 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 *tl++ = 0;
2253 *tl = txdr_unsigned(fsinf.fs_wtmax);
2254 retnum += NFSX_HYPER;
2255 break;
2256 case NFSATTRBIT_MODE:
2257 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2258 *tl = vtonfsv34_mode(vap->va_mode);
2259 retnum += NFSX_UNSIGNED;
2260 break;
2261 case NFSATTRBIT_NOTRUNC:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 *tl = newnfs_true;
2264 retnum += NFSX_UNSIGNED;
2265 break;
2266 case NFSATTRBIT_NUMLINKS:
2267 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2268 *tl = txdr_unsigned(vap->va_nlink);
2269 retnum += NFSX_UNSIGNED;
2270 break;
2271 case NFSATTRBIT_OWNER:
2272 cp = namestr;
2273 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2274 retnum += nfsm_strtom(nd, cp, siz);
2275 if (cp != namestr)
2276 free(cp, M_NFSSTRING);
2277 break;
2278 case NFSATTRBIT_OWNERGROUP:
2279 cp = namestr;
2280 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2281 retnum += nfsm_strtom(nd, cp, siz);
2282 if (cp != namestr)
2283 free(cp, M_NFSSTRING);
2284 break;
2285 case NFSATTRBIT_QUOTAHARD:
2286 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2287 freenum = fs.f_bfree;
2288 else
2289 freenum = fs.f_bavail;
2290 #ifdef QUOTA
2291 /*
2292 * ufs_quotactl() insists that the uid argument
2293 * equal p_ruid for non-root quota access, so
2294 * we'll just make sure that's the case.
2295 */
2296 savuid = p->p_cred->p_ruid;
2297 p->p_cred->p_ruid = cred->cr_uid;
2298 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2299 cred->cr_uid, (caddr_t)&dqb))
2300 freenum = min(dqb.dqb_bhardlimit, freenum);
2301 p->p_cred->p_ruid = savuid;
2302 #endif /* QUOTA */
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2304 uquad = (u_int64_t)freenum;
2305 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2306 txdr_hyper(uquad, tl);
2307 retnum += NFSX_HYPER;
2308 break;
2309 case NFSATTRBIT_QUOTASOFT:
2310 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2311 freenum = fs.f_bfree;
2312 else
2313 freenum = fs.f_bavail;
2314 #ifdef QUOTA
2315 /*
2316 * ufs_quotactl() insists that the uid argument
2317 * equal p_ruid for non-root quota access, so
2318 * we'll just make sure that's the case.
2319 */
2320 savuid = p->p_cred->p_ruid;
2321 p->p_cred->p_ruid = cred->cr_uid;
2322 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2323 cred->cr_uid, (caddr_t)&dqb))
2324 freenum = min(dqb.dqb_bsoftlimit, freenum);
2325 p->p_cred->p_ruid = savuid;
2326 #endif /* QUOTA */
2327 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2328 uquad = (u_int64_t)freenum;
2329 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2330 txdr_hyper(uquad, tl);
2331 retnum += NFSX_HYPER;
2332 break;
2333 case NFSATTRBIT_QUOTAUSED:
2334 freenum = 0;
2335 #ifdef QUOTA
2336 /*
2337 * ufs_quotactl() insists that the uid argument
2338 * equal p_ruid for non-root quota access, so
2339 * we'll just make sure that's the case.
2340 */
2341 savuid = p->p_cred->p_ruid;
2342 p->p_cred->p_ruid = cred->cr_uid;
2343 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2344 cred->cr_uid, (caddr_t)&dqb))
2345 freenum = dqb.dqb_curblocks;
2346 p->p_cred->p_ruid = savuid;
2347 #endif /* QUOTA */
2348 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2349 uquad = (u_int64_t)freenum;
2350 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2351 txdr_hyper(uquad, tl);
2352 retnum += NFSX_HYPER;
2353 break;
2354 case NFSATTRBIT_RAWDEV:
2355 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2356 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2357 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2358 retnum += NFSX_V4SPECDATA;
2359 break;
2360 case NFSATTRBIT_SPACEAVAIL:
2361 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2362 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2363 uquad = (u_int64_t)fs.f_bfree;
2364 else
2365 uquad = (u_int64_t)fs.f_bavail;
2366 uquad *= fs.f_bsize;
2367 txdr_hyper(uquad, tl);
2368 retnum += NFSX_HYPER;
2369 break;
2370 case NFSATTRBIT_SPACEFREE:
2371 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2372 uquad = (u_int64_t)fs.f_bfree;
2373 uquad *= fs.f_bsize;
2374 txdr_hyper(uquad, tl);
2375 retnum += NFSX_HYPER;
2376 break;
2377 case NFSATTRBIT_SPACETOTAL:
2378 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2379 uquad = (u_int64_t)fs.f_blocks;
2380 uquad *= fs.f_bsize;
2381 txdr_hyper(uquad, tl);
2382 retnum += NFSX_HYPER;
2383 break;
2384 case NFSATTRBIT_SPACEUSED:
2385 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2386 txdr_hyper(vap->va_bytes, tl);
2387 retnum += NFSX_HYPER;
2388 break;
2389 case NFSATTRBIT_TIMEACCESS:
2390 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2391 txdr_nfsv4time(&vap->va_atime, tl);
2392 retnum += NFSX_V4TIME;
2393 break;
2394 case NFSATTRBIT_TIMEACCESSSET:
2395 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2396 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2397 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2398 txdr_nfsv4time(&vap->va_atime, tl);
2399 retnum += NFSX_V4SETTIME;
2400 } else {
2401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2402 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2403 retnum += NFSX_UNSIGNED;
2404 }
2405 break;
2406 case NFSATTRBIT_TIMEDELTA:
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2408 temptime.tv_sec = 0;
2409 temptime.tv_nsec = 1000000000 / hz;
2410 txdr_nfsv4time(&temptime, tl);
2411 retnum += NFSX_V4TIME;
2412 break;
2413 case NFSATTRBIT_TIMEMETADATA:
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2415 txdr_nfsv4time(&vap->va_ctime, tl);
2416 retnum += NFSX_V4TIME;
2417 break;
2418 case NFSATTRBIT_TIMEMODIFY:
2419 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2420 txdr_nfsv4time(&vap->va_mtime, tl);
2421 retnum += NFSX_V4TIME;
2422 break;
2423 case NFSATTRBIT_TIMEMODIFYSET:
2424 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2425 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2426 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2427 txdr_nfsv4time(&vap->va_mtime, tl);
2428 retnum += NFSX_V4SETTIME;
2429 } else {
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2431 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2432 retnum += NFSX_UNSIGNED;
2433 }
2434 break;
2435 case NFSATTRBIT_MOUNTEDONFILEID:
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2437 if (at_root != 0)
2438 uquad = mounted_on_fileno;
2439 else
2440 uquad = (u_int64_t)vap->va_fileid;
2441 txdr_hyper(uquad, tl);
2442 retnum += NFSX_HYPER;
2443 break;
2444 default:
2445 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2446 };
2447 }
2448 }
2449 if (naclp != NULL)
2450 acl_free(naclp);
2451 *retnump = txdr_unsigned(retnum);
2452 return (retnum + prefixnum);
2453 }
2454
2455 /*
2456 * Put the attribute bits onto an mbuf list.
2457 * Return the number of bytes of output generated.
2458 */
2459 APPLESTATIC int
2460 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2461 {
2462 u_int32_t *tl;
2463 int cnt, i, bytesize;
2464
2465 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2466 if (attrbitp->bits[cnt - 1])
2467 break;
2468 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2469 NFSM_BUILD(tl, u_int32_t *, bytesize);
2470 *tl++ = txdr_unsigned(cnt);
2471 for (i = 0; i < cnt; i++)
2472 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2473 return (bytesize);
2474 }
2475
2476 /*
2477 * Convert a uid to a string.
2478 * If the lookup fails, just output the digits.
2479 * uid - the user id
2480 * cpp - points to a buffer of size NFSV4_SMALLSTR
2481 * (malloc a larger one, as required)
2482 * retlenp - pointer to length to be returned
2483 */
2484 APPLESTATIC void
2485 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2486 {
2487 int i;
2488 struct nfsusrgrp *usrp;
2489 u_char *cp = *cpp;
2490 uid_t tmp;
2491 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2492
2493 cnt = 0;
2494 tryagain:
2495 NFSLOCKNAMEID();
2496 if (nfsrv_dnsname) {
2497 /*
2498 * Always map nfsrv_defaultuid to "nobody".
2499 */
2500 if (uid == nfsrv_defaultuid) {
2501 i = nfsrv_dnsnamelen + 7;
2502 if (i > len) {
2503 NFSUNLOCKNAMEID();
2504 if (len > NFSV4_SMALLSTR)
2505 free(cp, M_NFSSTRING);
2506 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2507 *cpp = cp;
2508 len = i;
2509 goto tryagain;
2510 }
2511 *retlenp = i;
2512 NFSBCOPY("nobody@", cp, 7);
2513 cp += 7;
2514 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2515 NFSUNLOCKNAMEID();
2516 return;
2517 }
2518 hasampersand = 0;
2519 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2520 if (usrp->lug_uid == uid) {
2521 if (usrp->lug_expiry < NFSD_MONOSEC)
2522 break;
2523 /*
2524 * If the name doesn't already have an '@'
2525 * in it, append @domainname to it.
2526 */
2527 for (i = 0; i < usrp->lug_namelen; i++) {
2528 if (usrp->lug_name[i] == '@') {
2529 hasampersand = 1;
2530 break;
2531 }
2532 }
2533 if (hasampersand)
2534 i = usrp->lug_namelen;
2535 else
2536 i = usrp->lug_namelen +
2537 nfsrv_dnsnamelen + 1;
2538 if (i > len) {
2539 NFSUNLOCKNAMEID();
2540 if (len > NFSV4_SMALLSTR)
2541 free(cp, M_NFSSTRING);
2542 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2543 *cpp = cp;
2544 len = i;
2545 goto tryagain;
2546 }
2547 *retlenp = i;
2548 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2549 if (!hasampersand) {
2550 cp += usrp->lug_namelen;
2551 *cp++ = '@';
2552 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2553 }
2554 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2555 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2556 NFSUNLOCKNAMEID();
2557 return;
2558 }
2559 }
2560 NFSUNLOCKNAMEID();
2561 cnt++;
2562 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2563 NULL, p);
2564 if (ret == 0 && cnt < 2)
2565 goto tryagain;
2566 } else {
2567 NFSUNLOCKNAMEID();
2568 }
2569
2570 /*
2571 * No match, just return a string of digits.
2572 */
2573 tmp = uid;
2574 i = 0;
2575 while (tmp || i == 0) {
2576 tmp /= 10;
2577 i++;
2578 }
2579 len = (i > len) ? len : i;
2580 *retlenp = len;
2581 cp += (len - 1);
2582 tmp = uid;
2583 for (i = 0; i < len; i++) {
2584 *cp-- = '' + (tmp % 10);
2585 tmp /= 10;
2586 }
2587 return;
2588 }
2589
2590 /*
2591 * Convert a string to a uid.
2592 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2593 * return 0.
2594 * If this is called from a client side mount using AUTH_SYS and the
2595 * string is made up entirely of digits, just convert the string to
2596 * a number.
2597 */
2598 APPLESTATIC int
2599 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2600 NFSPROC_T *p)
2601 {
2602 int i;
2603 char *cp, *endstr, *str0;
2604 struct nfsusrgrp *usrp;
2605 int cnt, ret;
2606 int error = 0;
2607 uid_t tuid;
2608
2609 if (len == 0) {
2610 error = NFSERR_BADOWNER;
2611 goto out;
2612 }
2613 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2614 str0 = str;
2615 tuid = (uid_t)strtoul(str0, &endstr, 10);
2616 if ((endstr - str0) == len &&
2617 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2618 *uidp = tuid;
2619 goto out;
2620 }
2621 /*
2622 * Look for an '@'.
2623 */
2624 cp = strchr(str0, '@');
2625 if (cp != NULL)
2626 i = (int)(cp++ - str0);
2627 else
2628 i = len;
2629
2630 cnt = 0;
2631 tryagain:
2632 NFSLOCKNAMEID();
2633 /*
2634 * If an '@' is found and the domain name matches, search for the name
2635 * with dns stripped off.
2636 * Mixed case alpahbetics will match for the domain name, but all
2637 * upper case will not.
2638 */
2639 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2640 (len - 1 - i) == nfsrv_dnsnamelen &&
2641 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2642 len -= (nfsrv_dnsnamelen + 1);
2643 *(cp - 1) = '\0';
2644 }
2645
2646 /*
2647 * Check for the special case of "nobody".
2648 */
2649 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2650 *uidp = nfsrv_defaultuid;
2651 NFSUNLOCKNAMEID();
2652 error = 0;
2653 goto out;
2654 }
2655
2656 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2657 if (usrp->lug_namelen == len &&
2658 !NFSBCMP(usrp->lug_name, str, len)) {
2659 if (usrp->lug_expiry < NFSD_MONOSEC)
2660 break;
2661 *uidp = usrp->lug_uid;
2662 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2663 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2664 NFSUNLOCKNAMEID();
2665 error = 0;
2666 goto out;
2667 }
2668 }
2669 NFSUNLOCKNAMEID();
2670 cnt++;
2671 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2672 str, p);
2673 if (ret == 0 && cnt < 2)
2674 goto tryagain;
2675 error = NFSERR_BADOWNER;
2676
2677 out:
2678 NFSEXITCODE(error);
2679 return (error);
2680 }
2681
2682 /*
2683 * Convert a gid to a string.
2684 * gid - the group id
2685 * cpp - points to a buffer of size NFSV4_SMALLSTR
2686 * (malloc a larger one, as required)
2687 * retlenp - pointer to length to be returned
2688 */
2689 APPLESTATIC void
2690 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2691 {
2692 int i;
2693 struct nfsusrgrp *usrp;
2694 u_char *cp = *cpp;
2695 gid_t tmp;
2696 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2697
2698 cnt = 0;
2699 tryagain:
2700 NFSLOCKNAMEID();
2701 if (nfsrv_dnsname) {
2702 /*
2703 * Always map nfsrv_defaultgid to "nogroup".
2704 */
2705 if (gid == nfsrv_defaultgid) {
2706 i = nfsrv_dnsnamelen + 8;
2707 if (i > len) {
2708 NFSUNLOCKNAMEID();
2709 if (len > NFSV4_SMALLSTR)
2710 free(cp, M_NFSSTRING);
2711 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2712 *cpp = cp;
2713 len = i;
2714 goto tryagain;
2715 }
2716 *retlenp = i;
2717 NFSBCOPY("nogroup@", cp, 8);
2718 cp += 8;
2719 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2720 NFSUNLOCKNAMEID();
2721 return;
2722 }
2723 hasampersand = 0;
2724 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2725 if (usrp->lug_gid == gid) {
2726 if (usrp->lug_expiry < NFSD_MONOSEC)
2727 break;
2728 /*
2729 * If the name doesn't already have an '@'
2730 * in it, append @domainname to it.
2731 */
2732 for (i = 0; i < usrp->lug_namelen; i++) {
2733 if (usrp->lug_name[i] == '@') {
2734 hasampersand = 1;
2735 break;
2736 }
2737 }
2738 if (hasampersand)
2739 i = usrp->lug_namelen;
2740 else
2741 i = usrp->lug_namelen +
2742 nfsrv_dnsnamelen + 1;
2743 if (i > len) {
2744 NFSUNLOCKNAMEID();
2745 if (len > NFSV4_SMALLSTR)
2746 free(cp, M_NFSSTRING);
2747 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2748 *cpp = cp;
2749 len = i;
2750 goto tryagain;
2751 }
2752 *retlenp = i;
2753 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2754 if (!hasampersand) {
2755 cp += usrp->lug_namelen;
2756 *cp++ = '@';
2757 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2758 }
2759 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2760 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2761 NFSUNLOCKNAMEID();
2762 return;
2763 }
2764 }
2765 NFSUNLOCKNAMEID();
2766 cnt++;
2767 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2768 NULL, p);
2769 if (ret == 0 && cnt < 2)
2770 goto tryagain;
2771 } else {
2772 NFSUNLOCKNAMEID();
2773 }
2774
2775 /*
2776 * No match, just return a string of digits.
2777 */
2778 tmp = gid;
2779 i = 0;
2780 while (tmp || i == 0) {
2781 tmp /= 10;
2782 i++;
2783 }
2784 len = (i > len) ? len : i;
2785 *retlenp = len;
2786 cp += (len - 1);
2787 tmp = gid;
2788 for (i = 0; i < len; i++) {
2789 *cp-- = '' + (tmp % 10);
2790 tmp /= 10;
2791 }
2792 return;
2793 }
2794
2795 /*
2796 * Convert a string to a gid.
2797 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2798 * return 0.
2799 * If this is called from a client side mount using AUTH_SYS and the
2800 * string is made up entirely of digits, just convert the string to
2801 * a number.
2802 */
2803 APPLESTATIC int
2804 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2805 NFSPROC_T *p)
2806 {
2807 int i;
2808 char *cp, *endstr, *str0;
2809 struct nfsusrgrp *usrp;
2810 int cnt, ret;
2811 int error = 0;
2812 gid_t tgid;
2813
2814 if (len == 0) {
2815 error = NFSERR_BADOWNER;
2816 goto out;
2817 }
2818 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2819 str0 = str;
2820 tgid = (gid_t)strtoul(str0, &endstr, 10);
2821 if ((endstr - str0) == len &&
2822 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2823 *gidp = tgid;
2824 goto out;
2825 }
2826 /*
2827 * Look for an '@'.
2828 */
2829 cp = strchr(str0, '@');
2830 if (cp != NULL)
2831 i = (int)(cp++ - str0);
2832 else
2833 i = len;
2834
2835 cnt = 0;
2836 tryagain:
2837 NFSLOCKNAMEID();
2838 /*
2839 * If an '@' is found and the dns name matches, search for the name
2840 * with the dns stripped off.
2841 */
2842 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2843 (len - 1 - i) == nfsrv_dnsnamelen &&
2844 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2845 len -= (nfsrv_dnsnamelen + 1);
2846 *(cp - 1) = '\0';
2847 }
2848
2849 /*
2850 * Check for the special case of "nogroup".
2851 */
2852 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2853 *gidp = nfsrv_defaultgid;
2854 NFSUNLOCKNAMEID();
2855 error = 0;
2856 goto out;
2857 }
2858
2859 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2860 if (usrp->lug_namelen == len &&
2861 !NFSBCMP(usrp->lug_name, str, len)) {
2862 if (usrp->lug_expiry < NFSD_MONOSEC)
2863 break;
2864 *gidp = usrp->lug_gid;
2865 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2866 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2867 NFSUNLOCKNAMEID();
2868 error = 0;
2869 goto out;
2870 }
2871 }
2872 NFSUNLOCKNAMEID();
2873 cnt++;
2874 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2875 str, p);
2876 if (ret == 0 && cnt < 2)
2877 goto tryagain;
2878 error = NFSERR_BADOWNER;
2879
2880 out:
2881 NFSEXITCODE(error);
2882 return (error);
2883 }
2884
2885 /*
2886 * Cmp len chars, allowing mixed case in the first argument to match lower
2887 * case in the second, but not if the first argument is all upper case.
2888 * Return 0 for a match, 1 otherwise.
2889 */
2890 static int
2891 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2892 {
2893 int i;
2894 u_char tmp;
2895 int fndlower = 0;
2896
2897 for (i = 0; i < len; i++) {
2898 if (*cp >= 'A' && *cp <= 'Z') {
2899 tmp = *cp++ + ('a' - 'A');
2900 } else {
2901 tmp = *cp++;
2902 if (tmp >= 'a' && tmp <= 'z')
2903 fndlower = 1;
2904 }
2905 if (tmp != *cp2++)
2906 return (1);
2907 }
2908 if (fndlower)
2909 return (0);
2910 else
2911 return (1);
2912 }
2913
2914 /*
2915 * Set the port for the nfsuserd.
2916 */
2917 APPLESTATIC int
2918 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2919 {
2920 struct nfssockreq *rp;
2921 struct sockaddr_in *ad;
2922 int error;
2923
2924 NFSLOCKNAMEID();
2925 if (nfsrv_nfsuserd) {
2926 NFSUNLOCKNAMEID();
2927 error = EPERM;
2928 goto out;
2929 }
2930 nfsrv_nfsuserd = 1;
2931 NFSUNLOCKNAMEID();
2932 /*
2933 * Set up the socket record and connect.
2934 */
2935 rp = &nfsrv_nfsuserdsock;
2936 rp->nr_client = NULL;
2937 rp->nr_sotype = SOCK_DGRAM;
2938 rp->nr_soproto = IPPROTO_UDP;
2939 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2940 rp->nr_cred = NULL;
2941 NFSSOCKADDRALLOC(rp->nr_nam);
2942 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2943 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2944 ad->sin_family = AF_INET;
2945 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2946 ad->sin_port = port;
2947 rp->nr_prog = RPCPROG_NFSUSERD;
2948 rp->nr_vers = RPCNFSUSERD_VERS;
2949 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2950 if (error) {
2951 NFSSOCKADDRFREE(rp->nr_nam);
2952 nfsrv_nfsuserd = 0;
2953 }
2954 out:
2955 NFSEXITCODE(error);
2956 return (error);
2957 }
2958
2959 /*
2960 * Delete the nfsuserd port.
2961 */
2962 APPLESTATIC void
2963 nfsrv_nfsuserddelport(void)
2964 {
2965
2966 NFSLOCKNAMEID();
2967 if (nfsrv_nfsuserd == 0) {
2968 NFSUNLOCKNAMEID();
2969 return;
2970 }
2971 nfsrv_nfsuserd = 0;
2972 NFSUNLOCKNAMEID();
2973 newnfs_disconnect(&nfsrv_nfsuserdsock);
2974 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2975 }
2976
2977 /*
2978 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2979 * name<-->id cache.
2980 * Returns 0 upon success, non-zero otherwise.
2981 */
2982 static int
2983 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2984 {
2985 u_int32_t *tl;
2986 struct nfsrv_descript *nd;
2987 int len;
2988 struct nfsrv_descript nfsd;
2989 struct ucred *cred;
2990 int error;
2991
2992 NFSLOCKNAMEID();
2993 if (nfsrv_nfsuserd == 0) {
2994 NFSUNLOCKNAMEID();
2995 error = EPERM;
2996 goto out;
2997 }
2998 NFSUNLOCKNAMEID();
2999 nd = &nfsd;
3000 cred = newnfs_getcred();
3001 nd->nd_flag = ND_GSSINITREPLY;
3002 nfsrvd_rephead(nd);
3003
3004 nd->nd_procnum = procnum;
3005 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3006 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3007 if (procnum == RPCNFSUSERD_GETUID)
3008 *tl = txdr_unsigned(uid);
3009 else
3010 *tl = txdr_unsigned(gid);
3011 } else {
3012 len = strlen(name);
3013 (void) nfsm_strtom(nd, name, len);
3014 }
3015 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3016 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
3017 NFSFREECRED(cred);
3018 if (!error) {
3019 mbuf_freem(nd->nd_mrep);
3020 error = nd->nd_repstat;
3021 }
3022 out:
3023 NFSEXITCODE(error);
3024 return (error);
3025 }
3026
3027 /*
3028 * This function is called from the nfssvc(2) system call, to update the
3029 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3030 */
3031 APPLESTATIC int
3032 nfssvc_idname(struct nfsd_idargs *nidp)
3033 {
3034 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3035 struct nfsuserhashhead *hp;
3036 int i;
3037 int error = 0;
3038 u_char *cp;
3039
3040 if (nidp->nid_flag & NFSID_INITIALIZE) {
3041 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3042 M_NFSSTRING, M_WAITOK);
3043 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3044 nidp->nid_namelen);
3045 NFSLOCKNAMEID();
3046 if (nfsrv_dnsname) {
3047 /*
3048 * Free up all the old stuff and reinitialize hash lists.
3049 */
3050 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3051 nfsrv_removeuser(usrp);
3052 }
3053 free(nfsrv_dnsname, M_NFSSTRING);
3054 nfsrv_dnsname = NULL;
3055 }
3056 TAILQ_INIT(&nfsuserlruhead);
3057 for (i = 0; i < NFSUSERHASHSIZE; i++)
3058 LIST_INIT(&nfsuserhash[i]);
3059 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3060 LIST_INIT(&nfsgrouphash[i]);
3061 for (i = 0; i < NFSUSERHASHSIZE; i++)
3062 LIST_INIT(&nfsusernamehash[i]);
3063 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3064 LIST_INIT(&nfsgroupnamehash[i]);
3065
3066 /*
3067 * Put name in "DNS" string.
3068 */
3069 if (!error) {
3070 nfsrv_dnsname = cp;
3071 nfsrv_dnsnamelen = nidp->nid_namelen;
3072 nfsrv_defaultuid = nidp->nid_uid;
3073 nfsrv_defaultgid = nidp->nid_gid;
3074 nfsrv_usercnt = 0;
3075 nfsrv_usermax = nidp->nid_usermax;
3076 }
3077 NFSUNLOCKNAMEID();
3078 if (error)
3079 free(cp, M_NFSSTRING);
3080 goto out;
3081 }
3082
3083 /*
3084 * malloc the new one now, so any potential sleep occurs before
3085 * manipulation of the lists.
3086 */
3087 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3088 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3089 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3090 nidp->nid_namelen);
3091 if (error) {
3092 free((caddr_t)newusrp, M_NFSUSERGROUP);
3093 goto out;
3094 }
3095 newusrp->lug_namelen = nidp->nid_namelen;
3096
3097 NFSLOCKNAMEID();
3098 /*
3099 * Delete old entries, as required.
3100 */
3101 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3102 hp = NFSUSERHASH(nidp->nid_uid);
3103 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3104 if (usrp->lug_uid == nidp->nid_uid)
3105 nfsrv_removeuser(usrp);
3106 }
3107 }
3108 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3109 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3110 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3111 if (usrp->lug_namelen == newusrp->lug_namelen &&
3112 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3113 usrp->lug_namelen))
3114 nfsrv_removeuser(usrp);
3115 }
3116 }
3117 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3118 hp = NFSGROUPHASH(nidp->nid_gid);
3119 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3120 if (usrp->lug_gid == nidp->nid_gid)
3121 nfsrv_removeuser(usrp);
3122 }
3123 }
3124 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3125 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3126 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3127 if (usrp->lug_namelen == newusrp->lug_namelen &&
3128 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3129 usrp->lug_namelen))
3130 nfsrv_removeuser(usrp);
3131 }
3132 }
3133 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3134 if (usrp->lug_expiry < NFSD_MONOSEC)
3135 nfsrv_removeuser(usrp);
3136 }
3137 while (nfsrv_usercnt >= nfsrv_usermax) {
3138 usrp = TAILQ_FIRST(&nfsuserlruhead);
3139 nfsrv_removeuser(usrp);
3140 }
3141
3142 /*
3143 * Now, we can add the new one.
3144 */
3145 if (nidp->nid_usertimeout)
3146 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3147 else
3148 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3149 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3150 newusrp->lug_uid = nidp->nid_uid;
3151 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3152 lug_numhash);
3153 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3154 newusrp->lug_namelen), newusrp, lug_namehash);
3155 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3156 nfsrv_usercnt++;
3157 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3158 newusrp->lug_gid = nidp->nid_gid;
3159 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3160 lug_numhash);
3161 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3162 newusrp->lug_namelen), newusrp, lug_namehash);
3163 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3164 nfsrv_usercnt++;
3165 } else
3166 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3167 NFSUNLOCKNAMEID();
3168 out:
3169 NFSEXITCODE(error);
3170 return (error);
3171 }
3172
3173 /*
3174 * Remove a user/group name element.
3175 */
3176 static void
3177 nfsrv_removeuser(struct nfsusrgrp *usrp)
3178 {
3179
3180 NFSNAMEIDREQUIRED();
3181 LIST_REMOVE(usrp, lug_numhash);
3182 LIST_REMOVE(usrp, lug_namehash);
3183 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3184 nfsrv_usercnt--;
3185 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3186 }
3187
3188 /*
3189 * This function scans a byte string and checks for UTF-8 compliance.
3190 * It returns 0 if it conforms and NFSERR_INVAL if not.
3191 */
3192 APPLESTATIC int
3193 nfsrv_checkutf8(u_int8_t *cp, int len)
3194 {
3195 u_int32_t val = 0x0;
3196 int cnt = 0, gotd = 0, shift = 0;
3197 u_int8_t byte;
3198 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3199 int error = 0;
3200
3201 /*
3202 * Here are what the variables are used for:
3203 * val - the calculated value of a multibyte char, used to check
3204 * that it was coded with the correct range
3205 * cnt - the number of 10xxxxxx bytes to follow
3206 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3207 * shift - lower order bits of range (ie. "val >> shift" should
3208 * not be 0, in other words, dividing by the lower bound
3209 * of the range should get a non-zero value)
3210 * byte - used to calculate cnt
3211 */
3212 while (len > 0) {
3213 if (cnt > 0) {
3214 /* This handles the 10xxxxxx bytes */
3215 if ((*cp & 0xc0) != 0x80 ||
3216 (gotd && (*cp & 0x20))) {
3217 error = NFSERR_INVAL;
3218 goto out;
3219 }
3220 gotd = 0;
3221 val <<= 6;
3222 val |= (*cp & 0x3f);
3223 cnt--;
3224 if (cnt == 0 && (val >> shift) == 0x0) {
3225 error = NFSERR_INVAL;
3226 goto out;
3227 }
3228 } else if (*cp & 0x80) {
3229 /* first byte of multi byte char */
3230 byte = *cp;
3231 while ((byte & 0x40) && cnt < 6) {
3232 cnt++;
3233 byte <<= 1;
3234 }
3235 if (cnt == 0 || cnt == 6) {
3236 error = NFSERR_INVAL;
3237 goto out;
3238 }
3239 val = (*cp & (0x3f >> cnt));
3240 shift = utf8_shift[cnt - 1];
3241 if (cnt == 2 && val == 0xd)
3242 /* Check for the 0xd800-0xdfff case */
3243 gotd = 1;
3244 }
3245 cp++;
3246 len--;
3247 }
3248 if (cnt > 0)
3249 error = NFSERR_INVAL;
3250
3251 out:
3252 NFSEXITCODE(error);
3253 return (error);
3254 }
3255
3256 /*
3257 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3258 * strings, one with the root path in it and the other with the list of
3259 * locations. The list is in the same format as is found in nfr_refs.
3260 * It is a "," separated list of entries, where each of them is of the
3261 * form <server>:<rootpath>. For example
3262 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3263 * The nilp argument is set to 1 for the special case of a null fs_root
3264 * and an empty server list.
3265 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3266 * number of xdr bytes parsed in sump.
3267 */
3268 static int
3269 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3270 int *sump, int *nilp)
3271 {
3272 u_int32_t *tl;
3273 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3274 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3275 struct list {
3276 SLIST_ENTRY(list) next;
3277 int len;
3278 u_char host[1];
3279 } *lsp, *nlsp;
3280 SLIST_HEAD(, list) head;
3281
3282 *fsrootp = NULL;
3283 *srvp = NULL;
3284 *nilp = 0;
3285
3286 /*
3287 * Get the fs_root path and check for the special case of null path
3288 * and 0 length server list.
3289 */
3290 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3291 len = fxdr_unsigned(int, *tl);
3292 if (len < 0 || len > 10240) {
3293 error = NFSERR_BADXDR;
3294 goto nfsmout;
3295 }
3296 if (len == 0) {
3297 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3298 if (*tl != 0) {
3299 error = NFSERR_BADXDR;
3300 goto nfsmout;
3301 }
3302 *nilp = 1;
3303 *sump = 2 * NFSX_UNSIGNED;
3304 error = 0;
3305 goto nfsmout;
3306 }
3307 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3308 error = nfsrv_mtostr(nd, cp, len);
3309 if (!error) {
3310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3311 cnt = fxdr_unsigned(int, *tl);
3312 if (cnt <= 0)
3313 error = NFSERR_BADXDR;
3314 }
3315 if (error)
3316 goto nfsmout;
3317
3318 /*
3319 * Now, loop through the location list and make up the srvlist.
3320 */
3321 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3322 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3323 slen = 1024;
3324 siz = 0;
3325 for (i = 0; i < cnt; i++) {
3326 SLIST_INIT(&head);
3327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3328 nsrv = fxdr_unsigned(int, *tl);
3329 if (nsrv <= 0) {
3330 error = NFSERR_BADXDR;
3331 goto nfsmout;
3332 }
3333
3334 /*
3335 * Handle the first server by putting it in the srvstr.
3336 */
3337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3338 len = fxdr_unsigned(int, *tl);
3339 if (len <= 0 || len > 1024) {
3340 error = NFSERR_BADXDR;
3341 goto nfsmout;
3342 }
3343 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3344 if (cp3 != cp2) {
3345 *cp3++ = ',';
3346 siz++;
3347 }
3348 error = nfsrv_mtostr(nd, cp3, len);
3349 if (error)
3350 goto nfsmout;
3351 cp3 += len;
3352 *cp3++ = ':';
3353 siz += (len + 1);
3354 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3355 for (j = 1; j < nsrv; j++) {
3356 /*
3357 * Yuck, put them in an slist and process them later.
3358 */
3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3360 len = fxdr_unsigned(int, *tl);
3361 if (len <= 0 || len > 1024) {
3362 error = NFSERR_BADXDR;
3363 goto nfsmout;
3364 }
3365 lsp = (struct list *)malloc(sizeof (struct list)
3366 + len, M_TEMP, M_WAITOK);
3367 error = nfsrv_mtostr(nd, lsp->host, len);
3368 if (error)
3369 goto nfsmout;
3370 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3371 lsp->len = len;
3372 SLIST_INSERT_HEAD(&head, lsp, next);
3373 }
3374
3375 /*
3376 * Finally, we can get the path.
3377 */
3378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3379 len = fxdr_unsigned(int, *tl);
3380 if (len <= 0 || len > 1024) {
3381 error = NFSERR_BADXDR;
3382 goto nfsmout;
3383 }
3384 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3385 error = nfsrv_mtostr(nd, cp3, len);
3386 if (error)
3387 goto nfsmout;
3388 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3389 str = cp3;
3390 stringlen = len;
3391 cp3 += len;
3392 siz += len;
3393 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3394 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3395 &cp2, &cp3, &slen);
3396 *cp3++ = ',';
3397 NFSBCOPY(lsp->host, cp3, lsp->len);
3398 cp3 += lsp->len;
3399 *cp3++ = ':';
3400 NFSBCOPY(str, cp3, stringlen);
3401 cp3 += stringlen;
3402 *cp3 = '\0';
3403 siz += (lsp->len + stringlen + 2);
3404 free((caddr_t)lsp, M_TEMP);
3405 }
3406 }
3407 *fsrootp = cp;
3408 *srvp = cp2;
3409 *sump = xdrsum;
3410 NFSEXITCODE2(0, nd);
3411 return (0);
3412 nfsmout:
3413 if (cp != NULL)
3414 free(cp, M_NFSSTRING);
3415 if (cp2 != NULL)
3416 free(cp2, M_NFSSTRING);
3417 NFSEXITCODE2(error, nd);
3418 return (error);
3419 }
3420
3421 /*
3422 * Make the malloc'd space large enough. This is a pain, but the xdr
3423 * doesn't set an upper bound on the side, so...
3424 */
3425 static void
3426 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3427 {
3428 u_char *cp;
3429 int i;
3430
3431 if (siz <= *slenp)
3432 return;
3433 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3434 NFSBCOPY(*cpp, cp, *slenp);
3435 free(*cpp, M_NFSSTRING);
3436 i = *cpp2 - *cpp;
3437 *cpp = cp;
3438 *cpp2 = cp + i;
3439 *slenp = siz + 1024;
3440 }
3441
3442 /*
3443 * Initialize the reply header data structures.
3444 */
3445 APPLESTATIC void
3446 nfsrvd_rephead(struct nfsrv_descript *nd)
3447 {
3448 mbuf_t mreq;
3449
3450 /*
3451 * If this is a big reply, use a cluster.
3452 */
3453 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3454 nfs_bigreply[nd->nd_procnum]) {
3455 NFSMCLGET(mreq, M_WAIT);
3456 nd->nd_mreq = mreq;
3457 nd->nd_mb = mreq;
3458 } else {
3459 NFSMGET(mreq);
3460 nd->nd_mreq = mreq;
3461 nd->nd_mb = mreq;
3462 }
3463 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3464 mbuf_setlen(mreq, 0);
3465
3466 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3467 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3468 }
3469
3470 /*
3471 * Lock a socket against others.
3472 * Currently used to serialize connect/disconnect attempts.
3473 */
3474 int
3475 newnfs_sndlock(int *flagp)
3476 {
3477 struct timespec ts;
3478
3479 NFSLOCKSOCK();
3480 while (*flagp & NFSR_SNDLOCK) {
3481 *flagp |= NFSR_WANTSND;
3482 ts.tv_sec = 0;
3483 ts.tv_nsec = 0;
3484 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3485 PZERO - 1, "nfsndlck", &ts);
3486 }
3487 *flagp |= NFSR_SNDLOCK;
3488 NFSUNLOCKSOCK();
3489 return (0);
3490 }
3491
3492 /*
3493 * Unlock the stream socket for others.
3494 */
3495 void
3496 newnfs_sndunlock(int *flagp)
3497 {
3498
3499 NFSLOCKSOCK();
3500 if ((*flagp & NFSR_SNDLOCK) == 0)
3501 panic("nfs sndunlock");
3502 *flagp &= ~NFSR_SNDLOCK;
3503 if (*flagp & NFSR_WANTSND) {
3504 *flagp &= ~NFSR_WANTSND;
3505 wakeup((caddr_t)flagp);
3506 }
3507 NFSUNLOCKSOCK();
3508 }
3509
Cache object: e63c0dff40370005b3f6e00f3cb9cbd2
|