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