2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
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.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
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
51 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
53 /* And other global data */
54 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
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 */
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;
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
85 * Ops that are ordered via seqid# are handled separately from these
87 * Define it here, since it is used by both the client and server.
89 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
90 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
91 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
92 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
93 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
94 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
95 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
96 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
97 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
98 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
99 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
100 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
101 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
102 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
104 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
105 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
106 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
108 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
109 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
112 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
113 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
114 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
115 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
116 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
117 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
118 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
119 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
120 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
124 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
125 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
127 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
128 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
139 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
141 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
150 #endif /* !APPLEKEXT */
152 static int ncl_mbuf_mhlen = MHLEN;
153 static int nfsrv_usercnt = 0;
154 static int nfsrv_dnsnamelen;
155 static u_char *nfsrv_dnsname = NULL;
156 static int nfsrv_usermax = 999999999;
157 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
158 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
159 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
160 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
161 static struct nfsuserlruhead nfsuserlruhead;
164 * This static array indicates whether or not the RPC generates a large
165 * reply. This is used by nfs_reply() to decide whether or not an mbuf
166 * cluster should be allocated. (If a cluster is required by an RPC
167 * marked 0 in this array, the code will still work, just not quite as
170 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
171 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,
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
174 /* local functions */
175 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
176 static void nfsv4_wanted(struct nfsv4lock *lp);
177 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
178 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
180 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
181 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
183 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
188 * copies mbuf chain to the uio scatter/gather list
191 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
193 char *mbufcp, *uiocp;
200 mbufcp = nd->nd_dpos;
201 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
202 rem = NFSM_RNDUP(siz) - siz;
204 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
208 left = uiop->uio_iov->iov_len;
209 uiocp = uiop->uio_iov->iov_base;
220 mbufcp = NFSMTOD(mp, caddr_t);
223 ("len %d, corrupted mbuf?", len));
225 xfer = (left > len) ? len : left;
228 if (uiop->uio_iov->iov_op != NULL)
229 (*(uiop->uio_iov->iov_op))
230 (mbufcp, uiocp, xfer);
233 if (uiop->uio_segflg == UIO_SYSSPACE)
234 NFSBCOPY(mbufcp, uiocp, xfer);
236 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
241 uiop->uio_offset += xfer;
242 uiop->uio_resid -= xfer;
244 if (uiop->uio_iov->iov_len <= siz) {
248 uiop->uio_iov->iov_base = (void *)
249 ((char *)uiop->uio_iov->iov_base + uiosiz);
250 uiop->uio_iov->iov_len -= uiosiz;
254 nd->nd_dpos = mbufcp;
258 error = nfsm_advance(nd, rem, len);
264 NFSEXITCODE2(error, nd);
270 * Help break down an mbuf chain by setting the first siz bytes contiguous
271 * pointed to by returned val.
272 * This is used by the macro NFSM_DISSECT for tough
276 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
285 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
287 nd->nd_md = mbuf_next(nd->nd_md);
288 if (nd->nd_md == NULL)
290 left = mbuf_len(nd->nd_md);
291 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
296 } else if (mbuf_next(nd->nd_md) == NULL) {
298 } else if (siz > ncl_mbuf_mhlen) {
299 panic("nfs S too big");
301 MGET(mp2, MT_DATA, how);
304 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
305 mbuf_setnext(nd->nd_md, mp2);
306 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
308 retp = p = NFSMTOD(mp2, caddr_t);
309 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
312 mp2 = mbuf_next(mp2);
313 /* Loop around copying up the siz2 bytes */
317 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
319 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
320 NFSM_DATAP(mp2, xfer);
321 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
326 mp2 = mbuf_next(mp2);
328 mbuf_setlen(nd->nd_md, siz);
330 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
336 * Advance the position in the mbuf chain.
337 * If offs == 0, this is a no-op, but it is simpler to just return from
338 * here than check for offs > 0 for all calls to nfsm_advance.
339 * If left == -1, it should be calculated here.
342 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
349 * A negative offs should be considered a serious problem.
352 panic("nfsrv_advance");
355 * If left == -1, calculate it here.
358 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
362 * Loop around, advancing over the mbuf data.
364 while (offs > left) {
366 nd->nd_md = mbuf_next(nd->nd_md);
367 if (nd->nd_md == NULL) {
371 left = mbuf_len(nd->nd_md);
372 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
382 * Copy a string into mbuf(s).
383 * Return the number of bytes output, including XDR overheads.
386 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
395 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
396 *tl = txdr_unsigned(siz);
397 rem = NFSM_RNDUP(siz) - siz;
398 bytesize = NFSX_UNSIGNED + siz + rem;
401 left = M_TRAILINGSPACE(m2);
404 * Loop around copying the string to mbuf(s).
408 if (siz > ncl_mbuf_mlen)
409 NFSMCLGET(m1, M_WAITOK);
413 mbuf_setnext(m2, m1);
415 cp2 = NFSMTOD(m2, caddr_t);
416 left = M_TRAILINGSPACE(m2);
422 NFSBCOPY(cp, cp2, xfer);
424 mbuf_setlen(m2, mbuf_len(m2) + xfer);
427 if (siz == 0 && rem) {
429 panic("nfsm_strtom");
430 NFSBZERO(cp2 + xfer, rem);
431 mbuf_setlen(m2, mbuf_len(m2) + rem);
435 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
440 * Called once to initialize data structures...
445 static int nfs_inited = 0;
451 newnfs_true = txdr_unsigned(TRUE);
452 newnfs_false = txdr_unsigned(FALSE);
453 newnfs_xdrneg1 = txdr_unsigned(-1);
454 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
457 NFSSETBOOTTIME(nfsboottime);
460 * Initialize reply list and start timer
462 TAILQ_INIT(&nfsd_reqq);
467 * Put a file handle in an mbuf list.
468 * If the size argument == 0, just use the default size.
469 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
470 * Return the number of bytes output, including XDR overhead.
473 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
477 int fullsiz, rem, bytesize = 0;
481 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
483 if (size > NFSX_V2FH)
484 panic("fh size > NFSX_V2FH for NFSv2");
485 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
486 NFSBCOPY(fhp, cp, size);
487 if (size < NFSX_V2FH)
488 NFSBZERO(cp + size, NFSX_V2FH - size);
489 bytesize = NFSX_V2FH;
493 fullsiz = NFSM_RNDUP(size);
494 rem = fullsiz - size;
496 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
497 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
500 bytesize = NFSX_UNSIGNED + fullsiz;
502 (void) nfsm_strtom(nd, fhp, size);
509 * This function compares two net addresses by family and returns TRUE
510 * if they are the same host.
511 * If there is any doubt, return FALSE.
512 * The AF_INET family is handled as a special case so that address mbufs
513 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
516 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
518 struct sockaddr_in *inetaddr;
522 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
523 if (inetaddr->sin_family == AF_INET &&
524 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
530 struct sockaddr_in6 *inetaddr6;
532 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
533 /* XXX - should test sin6_scope_id ? */
534 if (inetaddr6->sin6_family == AF_INET6 &&
535 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
546 * Similar to the above, but takes to NFSSOCKADDR_T args.
549 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
551 struct sockaddr_in *addr1, *addr2;
552 struct sockaddr *inaddr;
554 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
555 switch (inaddr->sa_family) {
557 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
558 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
559 if (addr2->sin_family == AF_INET &&
560 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
566 struct sockaddr_in6 *inet6addr1, *inet6addr2;
568 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
569 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
570 /* XXX - should test sin6_scope_id ? */
571 if (inet6addr2->sin6_family == AF_INET6 &&
572 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
573 &inet6addr2->sin6_addr))
584 * Trim the stuff already dissected off the mbuf list.
587 newnfs_trimleading(nd)
588 struct nfsrv_descript *nd;
594 * First, free up leading mbufs.
596 if (nd->nd_mrep != nd->nd_md) {
598 while (mbuf_next(m) != nd->nd_md) {
599 if (mbuf_next(m) == NULL)
600 panic("nfsm trim leading");
603 mbuf_setnext(m, NULL);
604 mbuf_freem(nd->nd_mrep);
609 * Now, adjust this mbuf, based on nd_dpos.
611 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
612 if (offs == mbuf_len(m)) {
616 panic("nfsm trim leading2");
617 mbuf_setnext(n, NULL);
619 } else if (offs > 0) {
620 mbuf_setlen(m, mbuf_len(m) - offs);
623 panic("nfsm trimleading offs");
626 nd->nd_dpos = NFSMTOD(m, caddr_t);
630 * Trim trailing data off the mbuf list being built.
633 newnfs_trimtrailing(nd, mb, bpos)
634 struct nfsrv_descript *nd;
640 mbuf_freem(mbuf_next(mb));
641 mbuf_setnext(mb, NULL);
643 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
649 * Dissect a file handle on the client.
652 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
659 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
660 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
661 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
668 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
670 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
672 FREE((caddr_t)nfhp, M_NFSFH);
678 NFSEXITCODE2(error, nd);
683 * Break down the nfsv4 acl.
684 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
687 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
688 int *aclsizep, __unused NFSPROC_T *p)
692 int acecnt, error = 0, aceerr = 0, acesize;
698 * Parse out the ace entries and expect them to conform to
699 * what can be supported by R/W/X bits.
701 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
702 aclsize = NFSX_UNSIGNED;
703 acecnt = fxdr_unsigned(int, *tl);
704 if (acecnt > ACL_MAX_ENTRIES)
705 aceerr = NFSERR_ATTRNOTSUPP;
706 if (nfsrv_useacl == 0)
707 aceerr = NFSERR_ATTRNOTSUPP;
708 for (i = 0; i < acecnt; i++) {
710 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
711 &aceerr, &acesize, p);
713 error = nfsrv_skipace(nd, &acesize);
719 aclp->acl_cnt = acecnt;
725 NFSEXITCODE2(error, nd);
730 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
733 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
738 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
739 len = fxdr_unsigned(int, *(tl + 3));
740 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
742 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
743 NFSEXITCODE2(error, nd);
748 * Get attribute bits from an mbuf list.
749 * Returns EBADRPC for a parsing error, 0 otherwise.
750 * If the clearinvalid flag is set, clear the bits not supported.
753 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
760 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
761 cnt = fxdr_unsigned(int, *tl);
763 error = NFSERR_BADXDR;
766 if (cnt > NFSATTRBIT_MAXWORDS)
767 outcnt = NFSATTRBIT_MAXWORDS;
770 NFSZERO_ATTRBIT(attrbitp);
772 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
773 for (i = 0; i < outcnt; i++)
774 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
776 for (i = 0; i < (cnt - outcnt); i++) {
777 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
778 if (retnotsupp != NULL && *tl != 0)
779 *retnotsupp = NFSERR_ATTRNOTSUPP;
782 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
784 NFSEXITCODE2(error, nd);
789 * Get the attributes for V4.
790 * If the compare flag is true, test for any attribute changes,
791 * otherwise return the attribute values.
792 * These attributes cover fields in "struct vattr", "struct statfs",
793 * "struct nfsfsinfo", the file handle and the lease duration.
794 * The value of retcmpp is set to 1 if all attributes are the same,
796 * Returns EBADRPC if it can't be parsed, 0 otherwise.
799 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
800 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
801 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
802 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
803 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
806 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
807 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
808 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
809 nfsattrbit_t attrbits, retattrbits, checkattrbits;
811 struct nfsreferral *refp;
814 struct timespec temptime;
818 u_int32_t freenum = 0, tuint;
819 u_int64_t uquad = 0, thyp, thyp2;
826 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
828 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
834 *retcmpp = retnotsup;
837 * Just set default values to some of the important ones.
842 nap->na_rdev = (NFSDEV_T)0;
843 nap->na_mtime.tv_sec = 0;
844 nap->na_mtime.tv_nsec = 0;
847 nap->na_blocksize = NFS_FABLKSIZE;
850 sbp->f_bsize = NFS_FABLKSIZE;
858 fsp->fs_rtmax = 8192;
859 fsp->fs_rtpref = 8192;
860 fsp->fs_maxname = NFS_MAXNAMLEN;
861 fsp->fs_wtmax = 8192;
862 fsp->fs_wtpref = 8192;
863 fsp->fs_wtmult = NFS_FABLKSIZE;
864 fsp->fs_dtpref = 8192;
865 fsp->fs_maxfilesize = 0xffffffffffffffffull;
866 fsp->fs_timedelta.tv_sec = 0;
867 fsp->fs_timedelta.tv_nsec = 1;
868 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
869 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
872 pc->pc_linkmax = LINK_MAX;
873 pc->pc_namemax = NAME_MAX;
875 pc->pc_chownrestricted = 0;
876 pc->pc_caseinsensitive = 0;
877 pc->pc_casepreserving = 1;
882 * Loop around getting the attributes.
884 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
885 attrsize = fxdr_unsigned(int, *tl);
886 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
887 if (attrsum > attrsize) {
888 error = NFSERR_BADXDR;
891 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
893 case NFSATTRBIT_SUPPORTEDATTRS:
895 if (compare || nap == NULL)
896 error = nfsrv_getattrbits(nd, &retattrbits,
899 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
903 if (compare && !(*retcmpp)) {
904 NFSSETSUPP_ATTRBIT(&checkattrbits);
906 /* Some filesystem do not support NFSv4ACL */
907 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
908 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
909 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
911 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
913 *retcmpp = NFSERR_NOTSAME;
917 case NFSATTRBIT_TYPE:
918 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
921 if (nap->na_type != nfsv34tov_type(*tl))
922 *retcmpp = NFSERR_NOTSAME;
924 } else if (nap != NULL) {
925 nap->na_type = nfsv34tov_type(*tl);
927 attrsum += NFSX_UNSIGNED;
929 case NFSATTRBIT_FHEXPIRETYPE:
930 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
931 if (compare && !(*retcmpp)) {
932 if (fxdr_unsigned(int, *tl) !=
933 NFSV4FHTYPE_PERSISTENT)
934 *retcmpp = NFSERR_NOTSAME;
936 attrsum += NFSX_UNSIGNED;
938 case NFSATTRBIT_CHANGE:
939 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
942 if (nap->na_filerev != fxdr_hyper(tl))
943 *retcmpp = NFSERR_NOTSAME;
945 } else if (nap != NULL) {
946 nap->na_filerev = fxdr_hyper(tl);
948 attrsum += NFSX_HYPER;
950 case NFSATTRBIT_SIZE:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
954 if (nap->na_size != fxdr_hyper(tl))
955 *retcmpp = NFSERR_NOTSAME;
957 } else if (nap != NULL) {
958 nap->na_size = fxdr_hyper(tl);
960 attrsum += NFSX_HYPER;
962 case NFSATTRBIT_LINKSUPPORT:
963 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
966 if (fsp->fs_properties & NFSV3_FSFLINK) {
967 if (*tl == newnfs_false)
968 *retcmpp = NFSERR_NOTSAME;
970 if (*tl == newnfs_true)
971 *retcmpp = NFSERR_NOTSAME;
974 } else if (fsp != NULL) {
975 if (*tl == newnfs_true)
976 fsp->fs_properties |= NFSV3_FSFLINK;
978 fsp->fs_properties &= ~NFSV3_FSFLINK;
980 attrsum += NFSX_UNSIGNED;
982 case NFSATTRBIT_SYMLINKSUPPORT:
983 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
986 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
987 if (*tl == newnfs_false)
988 *retcmpp = NFSERR_NOTSAME;
990 if (*tl == newnfs_true)
991 *retcmpp = NFSERR_NOTSAME;
994 } else if (fsp != NULL) {
995 if (*tl == newnfs_true)
996 fsp->fs_properties |= NFSV3_FSFSYMLINK;
998 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1000 attrsum += NFSX_UNSIGNED;
1002 case NFSATTRBIT_NAMEDATTR:
1003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1004 if (compare && !(*retcmpp)) {
1005 if (*tl != newnfs_false)
1006 *retcmpp = NFSERR_NOTSAME;
1008 attrsum += NFSX_UNSIGNED;
1010 case NFSATTRBIT_FSID:
1011 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1012 thyp = fxdr_hyper(tl);
1014 thyp2 = fxdr_hyper(tl);
1016 if (*retcmpp == 0) {
1017 if (thyp != (u_int64_t)
1018 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1019 thyp2 != (u_int64_t)
1020 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1021 *retcmpp = NFSERR_NOTSAME;
1023 } else if (nap != NULL) {
1024 nap->na_filesid[0] = thyp;
1025 nap->na_filesid[1] = thyp2;
1027 attrsum += (4 * NFSX_UNSIGNED);
1029 case NFSATTRBIT_UNIQUEHANDLES:
1030 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1031 if (compare && !(*retcmpp)) {
1032 if (*tl != newnfs_true)
1033 *retcmpp = NFSERR_NOTSAME;
1035 attrsum += NFSX_UNSIGNED;
1037 case NFSATTRBIT_LEASETIME:
1038 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1040 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1042 *retcmpp = NFSERR_NOTSAME;
1043 } else if (leasep != NULL) {
1044 *leasep = fxdr_unsigned(u_int32_t, *tl);
1046 attrsum += NFSX_UNSIGNED;
1048 case NFSATTRBIT_RDATTRERROR:
1049 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1052 *retcmpp = NFSERR_INVAL;
1053 } else if (rderrp != NULL) {
1054 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1056 attrsum += NFSX_UNSIGNED;
1058 case NFSATTRBIT_ACL:
1061 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1064 naclp = acl_alloc(M_WAITOK);
1065 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1071 if (aceerr || aclp == NULL ||
1072 nfsrv_compareacl(aclp, naclp))
1073 *retcmpp = NFSERR_NOTSAME;
1076 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1078 *retcmpp = NFSERR_ATTRNOTSUPP;
1082 if (vp != NULL && aclp != NULL)
1083 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1086 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1094 case NFSATTRBIT_ACLSUPPORT:
1095 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1096 if (compare && !(*retcmpp)) {
1097 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1098 if (fxdr_unsigned(u_int32_t, *tl) !=
1100 *retcmpp = NFSERR_NOTSAME;
1102 *retcmpp = NFSERR_ATTRNOTSUPP;
1105 attrsum += NFSX_UNSIGNED;
1107 case NFSATTRBIT_ARCHIVE:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 if (compare && !(*retcmpp))
1110 *retcmpp = NFSERR_ATTRNOTSUPP;
1111 attrsum += NFSX_UNSIGNED;
1113 case NFSATTRBIT_CANSETTIME:
1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1117 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1118 if (*tl == newnfs_false)
1119 *retcmpp = NFSERR_NOTSAME;
1121 if (*tl == newnfs_true)
1122 *retcmpp = NFSERR_NOTSAME;
1125 } else if (fsp != NULL) {
1126 if (*tl == newnfs_true)
1127 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1129 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1131 attrsum += NFSX_UNSIGNED;
1133 case NFSATTRBIT_CASEINSENSITIVE:
1134 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1137 if (*tl != newnfs_false)
1138 *retcmpp = NFSERR_NOTSAME;
1140 } else if (pc != NULL) {
1141 pc->pc_caseinsensitive =
1142 fxdr_unsigned(u_int32_t, *tl);
1144 attrsum += NFSX_UNSIGNED;
1146 case NFSATTRBIT_CASEPRESERVING:
1147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1150 if (*tl != newnfs_true)
1151 *retcmpp = NFSERR_NOTSAME;
1153 } else if (pc != NULL) {
1154 pc->pc_casepreserving =
1155 fxdr_unsigned(u_int32_t, *tl);
1157 attrsum += NFSX_UNSIGNED;
1159 case NFSATTRBIT_CHOWNRESTRICTED:
1160 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1163 if (*tl != newnfs_true)
1164 *retcmpp = NFSERR_NOTSAME;
1166 } else if (pc != NULL) {
1167 pc->pc_chownrestricted =
1168 fxdr_unsigned(u_int32_t, *tl);
1170 attrsum += NFSX_UNSIGNED;
1172 case NFSATTRBIT_FILEHANDLE:
1173 error = nfsm_getfh(nd, &tnfhp);
1176 tfhsize = tnfhp->nfh_len;
1179 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1181 *retcmpp = NFSERR_NOTSAME;
1182 FREE((caddr_t)tnfhp, M_NFSFH);
1183 } else if (nfhpp != NULL) {
1186 FREE((caddr_t)tnfhp, M_NFSFH);
1188 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1190 case NFSATTRBIT_FILEID:
1191 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1192 thyp = fxdr_hyper(tl);
1195 if ((u_int64_t)nap->na_fileid != thyp)
1196 *retcmpp = NFSERR_NOTSAME;
1198 } else if (nap != NULL) {
1200 printf("NFSv4 fileid > 32bits\n");
1201 nap->na_fileid = thyp;
1203 attrsum += NFSX_HYPER;
1205 case NFSATTRBIT_FILESAVAIL:
1206 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1209 sfp->sf_afiles != fxdr_hyper(tl))
1210 *retcmpp = NFSERR_NOTSAME;
1211 } else if (sfp != NULL) {
1212 sfp->sf_afiles = fxdr_hyper(tl);
1214 attrsum += NFSX_HYPER;
1216 case NFSATTRBIT_FILESFREE:
1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1220 sfp->sf_ffiles != fxdr_hyper(tl))
1221 *retcmpp = NFSERR_NOTSAME;
1222 } else if (sfp != NULL) {
1223 sfp->sf_ffiles = fxdr_hyper(tl);
1225 attrsum += NFSX_HYPER;
1227 case NFSATTRBIT_FILESTOTAL:
1228 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1231 sfp->sf_tfiles != fxdr_hyper(tl))
1232 *retcmpp = NFSERR_NOTSAME;
1233 } else if (sfp != NULL) {
1234 sfp->sf_tfiles = fxdr_hyper(tl);
1236 attrsum += NFSX_HYPER;
1238 case NFSATTRBIT_FSLOCATIONS:
1239 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1243 if (compare && !(*retcmpp)) {
1244 refp = nfsv4root_getreferral(vp, NULL, 0);
1246 if (cp == NULL || cp2 == NULL ||
1248 strcmp(cp2, refp->nfr_srvlist))
1249 *retcmpp = NFSERR_NOTSAME;
1250 } else if (m == 0) {
1251 *retcmpp = NFSERR_NOTSAME;
1255 free(cp, M_NFSSTRING);
1257 free(cp2, M_NFSSTRING);
1259 case NFSATTRBIT_HIDDEN:
1260 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1261 if (compare && !(*retcmpp))
1262 *retcmpp = NFSERR_ATTRNOTSUPP;
1263 attrsum += NFSX_UNSIGNED;
1265 case NFSATTRBIT_HOMOGENEOUS:
1266 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1269 if (fsp->fs_properties &
1270 NFSV3_FSFHOMOGENEOUS) {
1271 if (*tl == newnfs_false)
1272 *retcmpp = NFSERR_NOTSAME;
1274 if (*tl == newnfs_true)
1275 *retcmpp = NFSERR_NOTSAME;
1278 } else if (fsp != NULL) {
1279 if (*tl == newnfs_true)
1280 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1282 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1284 attrsum += NFSX_UNSIGNED;
1286 case NFSATTRBIT_MAXFILESIZE:
1287 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1288 tnfsquad.qval = fxdr_hyper(tl);
1291 tquad = NFSRV_MAXFILESIZE;
1292 if (tquad != tnfsquad.qval)
1293 *retcmpp = NFSERR_NOTSAME;
1295 } else if (fsp != NULL) {
1296 fsp->fs_maxfilesize = tnfsquad.qval;
1298 attrsum += NFSX_HYPER;
1300 case NFSATTRBIT_MAXLINK:
1301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1304 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1305 *retcmpp = NFSERR_NOTSAME;
1307 } else if (pc != NULL) {
1308 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1310 attrsum += NFSX_UNSIGNED;
1312 case NFSATTRBIT_MAXNAME:
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1316 if (fsp->fs_maxname !=
1317 fxdr_unsigned(u_int32_t, *tl))
1318 *retcmpp = NFSERR_NOTSAME;
1321 tuint = fxdr_unsigned(u_int32_t, *tl);
1323 * Some Linux NFSv4 servers report this
1324 * as 0 or 4billion, so I'll set it to
1325 * NFS_MAXNAMLEN. If a server actually creates
1326 * a name longer than NFS_MAXNAMLEN, it will
1327 * get an error back.
1329 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1330 tuint = NFS_MAXNAMLEN;
1332 fsp->fs_maxname = tuint;
1334 pc->pc_namemax = tuint;
1336 attrsum += NFSX_UNSIGNED;
1338 case NFSATTRBIT_MAXREAD:
1339 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1342 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1343 *(tl + 1)) || *tl != 0)
1344 *retcmpp = NFSERR_NOTSAME;
1346 } else if (fsp != NULL) {
1347 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1348 fsp->fs_rtpref = fsp->fs_rtmax;
1349 fsp->fs_dtpref = fsp->fs_rtpref;
1351 attrsum += NFSX_HYPER;
1353 case NFSATTRBIT_MAXWRITE:
1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1357 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1358 *(tl + 1)) || *tl != 0)
1359 *retcmpp = NFSERR_NOTSAME;
1361 } else if (fsp != NULL) {
1362 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1363 fsp->fs_wtpref = fsp->fs_wtmax;
1365 attrsum += NFSX_HYPER;
1367 case NFSATTRBIT_MIMETYPE:
1368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1369 i = fxdr_unsigned(int, *tl);
1370 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1371 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1374 if (compare && !(*retcmpp))
1375 *retcmpp = NFSERR_ATTRNOTSUPP;
1377 case NFSATTRBIT_MODE:
1378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1381 if (nap->na_mode != nfstov_mode(*tl))
1382 *retcmpp = NFSERR_NOTSAME;
1384 } else if (nap != NULL) {
1385 nap->na_mode = nfstov_mode(*tl);
1387 attrsum += NFSX_UNSIGNED;
1389 case NFSATTRBIT_NOTRUNC:
1390 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1393 if (*tl != newnfs_true)
1394 *retcmpp = NFSERR_NOTSAME;
1396 } else if (pc != NULL) {
1397 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1399 attrsum += NFSX_UNSIGNED;
1401 case NFSATTRBIT_NUMLINKS:
1402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1403 tuint = fxdr_unsigned(u_int32_t, *tl);
1406 if ((u_int32_t)nap->na_nlink != tuint)
1407 *retcmpp = NFSERR_NOTSAME;
1409 } else if (nap != NULL) {
1410 nap->na_nlink = tuint;
1412 attrsum += NFSX_UNSIGNED;
1414 case NFSATTRBIT_OWNER:
1415 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1416 j = fxdr_unsigned(int, *tl);
1418 error = NFSERR_BADXDR;
1421 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1422 if (j > NFSV4_SMALLSTR)
1423 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1426 error = nfsrv_mtostr(nd, cp, j);
1428 if (j > NFSV4_SMALLSTR)
1429 free(cp, M_NFSSTRING);
1434 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1436 *retcmpp = NFSERR_NOTSAME;
1438 } else if (nap != NULL) {
1439 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1440 nap->na_uid = nfsrv_defaultuid;
1444 if (j > NFSV4_SMALLSTR)
1445 free(cp, M_NFSSTRING);
1447 case NFSATTRBIT_OWNERGROUP:
1448 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1449 j = fxdr_unsigned(int, *tl);
1451 error = NFSERR_BADXDR;
1454 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1455 if (j > NFSV4_SMALLSTR)
1456 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1459 error = nfsrv_mtostr(nd, cp, j);
1461 if (j > NFSV4_SMALLSTR)
1462 free(cp, M_NFSSTRING);
1467 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1469 *retcmpp = NFSERR_NOTSAME;
1471 } else if (nap != NULL) {
1472 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1473 nap->na_gid = nfsrv_defaultgid;
1477 if (j > NFSV4_SMALLSTR)
1478 free(cp, M_NFSSTRING);
1480 case NFSATTRBIT_QUOTAHARD:
1481 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1483 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1484 freenum = sbp->f_bfree;
1486 freenum = sbp->f_bavail;
1489 * ufs_quotactl() insists that the uid argument
1490 * equal p_ruid for non-root quota access, so
1491 * we'll just make sure that's the case.
1493 savuid = p->p_cred->p_ruid;
1494 p->p_cred->p_ruid = cred->cr_uid;
1495 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1496 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1497 freenum = min(dqb.dqb_bhardlimit, freenum);
1498 p->p_cred->p_ruid = savuid;
1500 uquad = (u_int64_t)freenum;
1501 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1503 if (compare && !(*retcmpp)) {
1504 if (uquad != fxdr_hyper(tl))
1505 *retcmpp = NFSERR_NOTSAME;
1507 attrsum += NFSX_HYPER;
1509 case NFSATTRBIT_QUOTASOFT:
1510 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1512 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1513 freenum = sbp->f_bfree;
1515 freenum = sbp->f_bavail;
1518 * ufs_quotactl() insists that the uid argument
1519 * equal p_ruid for non-root quota access, so
1520 * we'll just make sure that's the case.
1522 savuid = p->p_cred->p_ruid;
1523 p->p_cred->p_ruid = cred->cr_uid;
1524 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1525 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1526 freenum = min(dqb.dqb_bsoftlimit, freenum);
1527 p->p_cred->p_ruid = savuid;
1529 uquad = (u_int64_t)freenum;
1530 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1532 if (compare && !(*retcmpp)) {
1533 if (uquad != fxdr_hyper(tl))
1534 *retcmpp = NFSERR_NOTSAME;
1536 attrsum += NFSX_HYPER;
1538 case NFSATTRBIT_QUOTAUSED:
1539 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1544 * ufs_quotactl() insists that the uid argument
1545 * equal p_ruid for non-root quota access, so
1546 * we'll just make sure that's the case.
1548 savuid = p->p_cred->p_ruid;
1549 p->p_cred->p_ruid = cred->cr_uid;
1550 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1551 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1552 freenum = dqb.dqb_curblocks;
1553 p->p_cred->p_ruid = savuid;
1555 uquad = (u_int64_t)freenum;
1556 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1558 if (compare && !(*retcmpp)) {
1559 if (uquad != fxdr_hyper(tl))
1560 *retcmpp = NFSERR_NOTSAME;
1562 attrsum += NFSX_HYPER;
1564 case NFSATTRBIT_RAWDEV:
1565 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1566 j = fxdr_unsigned(int, *tl++);
1567 k = fxdr_unsigned(int, *tl);
1570 if (nap->na_rdev != NFSMAKEDEV(j, k))
1571 *retcmpp = NFSERR_NOTSAME;
1573 } else if (nap != NULL) {
1574 nap->na_rdev = NFSMAKEDEV(j, k);
1576 attrsum += NFSX_V4SPECDATA;
1578 case NFSATTRBIT_SPACEAVAIL:
1579 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1582 sfp->sf_abytes != fxdr_hyper(tl))
1583 *retcmpp = NFSERR_NOTSAME;
1584 } else if (sfp != NULL) {
1585 sfp->sf_abytes = fxdr_hyper(tl);
1587 attrsum += NFSX_HYPER;
1589 case NFSATTRBIT_SPACEFREE:
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1593 sfp->sf_fbytes != fxdr_hyper(tl))
1594 *retcmpp = NFSERR_NOTSAME;
1595 } else if (sfp != NULL) {
1596 sfp->sf_fbytes = fxdr_hyper(tl);
1598 attrsum += NFSX_HYPER;
1600 case NFSATTRBIT_SPACETOTAL:
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1604 sfp->sf_tbytes != fxdr_hyper(tl))
1605 *retcmpp = NFSERR_NOTSAME;
1606 } else if (sfp != NULL) {
1607 sfp->sf_tbytes = fxdr_hyper(tl);
1609 attrsum += NFSX_HYPER;
1611 case NFSATTRBIT_SPACEUSED:
1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1613 thyp = fxdr_hyper(tl);
1616 if ((u_int64_t)nap->na_bytes != thyp)
1617 *retcmpp = NFSERR_NOTSAME;
1619 } else if (nap != NULL) {
1620 nap->na_bytes = thyp;
1622 attrsum += NFSX_HYPER;
1624 case NFSATTRBIT_SYSTEM:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1626 if (compare && !(*retcmpp))
1627 *retcmpp = NFSERR_ATTRNOTSUPP;
1628 attrsum += NFSX_UNSIGNED;
1630 case NFSATTRBIT_TIMEACCESS:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1632 fxdr_nfsv4time(tl, &temptime);
1635 if (!NFS_CMPTIME(temptime, nap->na_atime))
1636 *retcmpp = NFSERR_NOTSAME;
1638 } else if (nap != NULL) {
1639 nap->na_atime = temptime;
1641 attrsum += NFSX_V4TIME;
1643 case NFSATTRBIT_TIMEACCESSSET:
1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 attrsum += NFSX_UNSIGNED;
1646 i = fxdr_unsigned(int, *tl);
1647 if (i == NFSV4SATTRTIME_TOCLIENT) {
1648 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1649 attrsum += NFSX_V4TIME;
1651 if (compare && !(*retcmpp))
1652 *retcmpp = NFSERR_INVAL;
1654 case NFSATTRBIT_TIMEBACKUP:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1656 if (compare && !(*retcmpp))
1657 *retcmpp = NFSERR_ATTRNOTSUPP;
1658 attrsum += NFSX_V4TIME;
1660 case NFSATTRBIT_TIMECREATE:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1662 if (compare && !(*retcmpp))
1663 *retcmpp = NFSERR_ATTRNOTSUPP;
1664 attrsum += NFSX_V4TIME;
1666 case NFSATTRBIT_TIMEDELTA:
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1671 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1672 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1673 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1674 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1677 *retcmpp = NFSERR_NOTSAME;
1680 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMEMETADATA:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1687 fxdr_nfsv4time(tl, &temptime);
1690 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1691 *retcmpp = NFSERR_NOTSAME;
1693 } else if (nap != NULL) {
1694 nap->na_ctime = temptime;
1696 attrsum += NFSX_V4TIME;
1698 case NFSATTRBIT_TIMEMODIFY:
1699 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1700 fxdr_nfsv4time(tl, &temptime);
1703 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1704 *retcmpp = NFSERR_NOTSAME;
1706 } else if (nap != NULL) {
1707 nap->na_mtime = temptime;
1709 attrsum += NFSX_V4TIME;
1711 case NFSATTRBIT_TIMEMODIFYSET:
1712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1713 attrsum += NFSX_UNSIGNED;
1714 i = fxdr_unsigned(int, *tl);
1715 if (i == NFSV4SATTRTIME_TOCLIENT) {
1716 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1717 attrsum += NFSX_V4TIME;
1719 if (compare && !(*retcmpp))
1720 *retcmpp = NFSERR_INVAL;
1722 case NFSATTRBIT_MOUNTEDONFILEID:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1724 thyp = fxdr_hyper(tl);
1728 *retcmpp = NFSERR_NOTSAME;
1730 if (!vp || !nfsrv_atroot(vp, &fid))
1731 fid = nap->na_fileid;
1732 if ((u_int64_t)fid != thyp)
1733 *retcmpp = NFSERR_NOTSAME;
1736 } else if (nap != NULL) {
1738 printf("NFSv4 mounted on fileid > 32bits\n");
1739 nap->na_mntonfileno = thyp;
1741 attrsum += NFSX_HYPER;
1743 case NFSATTRBIT_SUPPATTREXCLCREAT:
1745 error = nfsrv_getattrbits(nd, &retattrbits,
1749 if (compare && !(*retcmpp)) {
1750 NFSSETSUPP_ATTRBIT(&checkattrbits);
1751 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1752 NFSCLRBIT_ATTRBIT(&checkattrbits,
1753 NFSATTRBIT_TIMEACCESSSET);
1754 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1756 *retcmpp = NFSERR_NOTSAME;
1761 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1763 if (compare && !(*retcmpp))
1764 *retcmpp = NFSERR_ATTRNOTSUPP;
1766 * and get out of the loop, since we can't parse
1767 * the unknown attrbute data.
1769 bitpos = NFSATTRBIT_MAX;
1775 * some clients pad the attrlist, so we need to skip over the
1778 if (attrsum > attrsize) {
1779 error = NFSERR_BADXDR;
1781 attrsize = NFSM_RNDUP(attrsize);
1782 if (attrsum < attrsize)
1783 error = nfsm_advance(nd, attrsize - attrsum, -1);
1786 NFSEXITCODE2(error, nd);
1791 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1792 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1793 * The first argument is a pointer to an nfsv4lock structure.
1794 * The second argument is 1 iff a blocking lock is wanted.
1795 * If this argument is 0, the call waits until no thread either wants nor
1796 * holds an exclusive lock.
1797 * It returns 1 if the lock was acquired, 0 otherwise.
1798 * If several processes call this function concurrently wanting the exclusive
1799 * lock, one will get the lock and the rest will return without getting the
1800 * lock. (If the caller must have the lock, it simply calls this function in a
1801 * loop until the function returns 1 to indicate the lock was acquired.)
1802 * Any usecnt must be decremented by calling nfsv4_relref() before
1803 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1804 * be called in a loop.
1805 * The isleptp argument is set to indicate if the call slept, iff not NULL
1806 * and the mp argument indicates to check for a forced dismount, iff not
1810 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1811 void *mutex, struct mount *mp)
1817 * If a lock is wanted, loop around until the lock is acquired by
1818 * someone and then released. If I want the lock, try to acquire it.
1819 * For a lock to be issued, no lock must be in force and the usecnt
1823 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1824 lp->nfslock_usecnt == 0) {
1825 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1826 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1829 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1831 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1832 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1833 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1836 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1839 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1840 PZERO - 1, "nfsv4lck", NULL);
1841 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1842 lp->nfslock_usecnt == 0) {
1843 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1844 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1852 * Release the lock acquired by nfsv4_lock().
1853 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1854 * incremented, as well.
1857 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1860 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1862 lp->nfslock_usecnt++;
1867 * Release a reference cnt.
1870 nfsv4_relref(struct nfsv4lock *lp)
1873 if (lp->nfslock_usecnt <= 0)
1874 panic("nfsv4root ref cnt");
1875 lp->nfslock_usecnt--;
1876 if (lp->nfslock_usecnt == 0)
1881 * Get a reference cnt.
1882 * This function will wait for any exclusive lock to be released, but will
1883 * not wait for threads that want the exclusive lock. If priority needs
1884 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1885 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1886 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1887 * return without getting a refcnt for that case.
1890 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1898 * Wait for a lock held.
1900 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1901 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1903 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1906 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1907 PZERO - 1, "nfsv4gr", NULL);
1909 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1912 lp->nfslock_usecnt++;
1916 * Get a reference as above, but return failure instead of sleeping if
1917 * an exclusive lock is held.
1920 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1923 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1926 lp->nfslock_usecnt++;
1931 * Test for a lock. Return 1 if locked, 0 otherwise.
1934 nfsv4_testlock(struct nfsv4lock *lp)
1937 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1938 lp->nfslock_usecnt == 0)
1944 * Wake up anyone sleeping, waiting for this lock.
1947 nfsv4_wanted(struct nfsv4lock *lp)
1950 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1951 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1952 wakeup((caddr_t)&lp->nfslock_lock);
1957 * Copy a string from an mbuf list into a character array.
1958 * Return EBADRPC if there is an mbuf error,
1962 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1971 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1972 rem = NFSM_RNDUP(siz) - siz;
1978 NFSBCOPY(cp, str, xfer);
1987 cp = NFSMTOD(mp, caddr_t);
1999 error = nfsm_advance(nd, rem, len);
2005 NFSEXITCODE2(error, nd);
2010 * Fill in the attributes as marked by the bitmap (V4).
2013 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2014 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2015 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2016 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2018 int bitpos, retnum = 0;
2020 int siz, prefixnum, error;
2021 u_char *cp, namestr[NFSV4_SMALLSTR];
2022 nfsattrbit_t attrbits, retbits;
2023 nfsattrbit_t *retbitp = &retbits;
2024 u_int32_t freenum, *retnump;
2027 struct nfsfsinfo fsinf;
2028 struct timespec temptime;
2029 NFSACL_T *aclp, *naclp = NULL;
2036 * First, set the bits that can be filled and get fsinfo.
2038 NFSSET_ATTRBIT(retbitp, attrbitp);
2040 * If both p and cred are NULL, it is a client side setattr call.
2041 * If both p and cred are not NULL, it is a server side reply call.
2042 * If p is not NULL and cred is NULL, it is a client side callback
2045 if (p == NULL && cred == NULL) {
2046 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2049 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2050 naclp = acl_alloc(M_WAITOK);
2053 nfsvno_getfs(&fsinf, isdgram);
2056 * Get the VFS_STATFS(), since some attributes need them.
2058 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2059 error = VFS_STATFS(mp, &fs);
2062 nd->nd_repstat = NFSERR_ACCES;
2065 NFSCLRSTATFS_ATTRBIT(retbitp);
2071 * And the NFSv4 ACL...
2073 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2074 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2075 supports_nfsv4acls == 0))) {
2076 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2078 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2079 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2080 supports_nfsv4acls == 0)) {
2081 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2082 } else if (naclp != NULL) {
2083 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2084 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2086 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2088 NFSVOPUNLOCK(vp, 0);
2090 error = NFSERR_PERM;
2093 nd->nd_repstat = NFSERR_ACCES;
2096 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2102 * Put out the attribute bitmap for the ones being filled in
2103 * and get the field for the number of attributes returned.
2105 prefixnum = nfsrv_putattrbit(nd, retbitp);
2106 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2107 prefixnum += NFSX_UNSIGNED;
2110 * Now, loop around filling in the attributes for each bit set.
2112 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2113 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2115 case NFSATTRBIT_SUPPORTEDATTRS:
2116 NFSSETSUPP_ATTRBIT(&attrbits);
2117 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2118 && supports_nfsv4acls == 0)) {
2119 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2120 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2122 retnum += nfsrv_putattrbit(nd, &attrbits);
2124 case NFSATTRBIT_TYPE:
2125 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2126 *tl = vtonfsv34_type(vap->va_type);
2127 retnum += NFSX_UNSIGNED;
2129 case NFSATTRBIT_FHEXPIRETYPE:
2130 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2131 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2132 retnum += NFSX_UNSIGNED;
2134 case NFSATTRBIT_CHANGE:
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2136 txdr_hyper(vap->va_filerev, tl);
2137 retnum += NFSX_HYPER;
2139 case NFSATTRBIT_SIZE:
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2141 txdr_hyper(vap->va_size, tl);
2142 retnum += NFSX_HYPER;
2144 case NFSATTRBIT_LINKSUPPORT:
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2150 retnum += NFSX_UNSIGNED;
2152 case NFSATTRBIT_SYMLINKSUPPORT:
2153 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2154 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2158 retnum += NFSX_UNSIGNED;
2160 case NFSATTRBIT_NAMEDATTR:
2161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163 retnum += NFSX_UNSIGNED;
2165 case NFSATTRBIT_FSID:
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2168 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2170 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2171 retnum += NFSX_V4FSID;
2173 case NFSATTRBIT_UNIQUEHANDLES:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2176 retnum += NFSX_UNSIGNED;
2178 case NFSATTRBIT_LEASETIME:
2179 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2180 *tl = txdr_unsigned(nfsrv_lease);
2181 retnum += NFSX_UNSIGNED;
2183 case NFSATTRBIT_RDATTRERROR:
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 *tl = txdr_unsigned(rderror);
2186 retnum += NFSX_UNSIGNED;
2189 * Recommended Attributes. (Only the supported ones.)
2191 case NFSATTRBIT_ACL:
2192 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2194 case NFSATTRBIT_ACLSUPPORT:
2195 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2196 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2197 retnum += NFSX_UNSIGNED;
2199 case NFSATTRBIT_CANSETTIME:
2200 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2201 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2205 retnum += NFSX_UNSIGNED;
2207 case NFSATTRBIT_CASEINSENSITIVE:
2208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2210 retnum += NFSX_UNSIGNED;
2212 case NFSATTRBIT_CASEPRESERVING:
2213 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2215 retnum += NFSX_UNSIGNED;
2217 case NFSATTRBIT_CHOWNRESTRICTED:
2218 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 retnum += NFSX_UNSIGNED;
2222 case NFSATTRBIT_FILEHANDLE:
2223 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2225 case NFSATTRBIT_FILEID:
2226 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2228 *tl = txdr_unsigned(vap->va_fileid);
2229 retnum += NFSX_HYPER;
2231 case NFSATTRBIT_FILESAVAIL:
2233 * Check quota and use min(quota, f_ffree).
2235 freenum = fs.f_ffree;
2238 * ufs_quotactl() insists that the uid argument
2239 * equal p_ruid for non-root quota access, so
2240 * we'll just make sure that's the case.
2242 savuid = p->p_cred->p_ruid;
2243 p->p_cred->p_ruid = cred->cr_uid;
2244 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2245 cred->cr_uid, (caddr_t)&dqb))
2246 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2248 p->p_cred->p_ruid = savuid;
2250 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 *tl = txdr_unsigned(freenum);
2253 retnum += NFSX_HYPER;
2255 case NFSATTRBIT_FILESFREE:
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2258 *tl = txdr_unsigned(fs.f_ffree);
2259 retnum += NFSX_HYPER;
2261 case NFSATTRBIT_FILESTOTAL:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2264 *tl = txdr_unsigned(fs.f_files);
2265 retnum += NFSX_HYPER;
2267 case NFSATTRBIT_FSLOCATIONS:
2268 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2271 retnum += 2 * NFSX_UNSIGNED;
2273 case NFSATTRBIT_HOMOGENEOUS:
2274 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2275 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2279 retnum += NFSX_UNSIGNED;
2281 case NFSATTRBIT_MAXFILESIZE:
2282 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2283 uquad = NFSRV_MAXFILESIZE;
2284 txdr_hyper(uquad, tl);
2285 retnum += NFSX_HYPER;
2287 case NFSATTRBIT_MAXLINK:
2288 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2289 *tl = txdr_unsigned(LINK_MAX);
2290 retnum += NFSX_UNSIGNED;
2292 case NFSATTRBIT_MAXNAME:
2293 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2294 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2295 retnum += NFSX_UNSIGNED;
2297 case NFSATTRBIT_MAXREAD:
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2300 *tl = txdr_unsigned(fsinf.fs_rtmax);
2301 retnum += NFSX_HYPER;
2303 case NFSATTRBIT_MAXWRITE:
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2306 *tl = txdr_unsigned(fsinf.fs_wtmax);
2307 retnum += NFSX_HYPER;
2309 case NFSATTRBIT_MODE:
2310 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2311 *tl = vtonfsv34_mode(vap->va_mode);
2312 retnum += NFSX_UNSIGNED;
2314 case NFSATTRBIT_NOTRUNC:
2315 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2317 retnum += NFSX_UNSIGNED;
2319 case NFSATTRBIT_NUMLINKS:
2320 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2321 *tl = txdr_unsigned(vap->va_nlink);
2322 retnum += NFSX_UNSIGNED;
2324 case NFSATTRBIT_OWNER:
2326 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2327 retnum += nfsm_strtom(nd, cp, siz);
2329 free(cp, M_NFSSTRING);
2331 case NFSATTRBIT_OWNERGROUP:
2333 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2334 retnum += nfsm_strtom(nd, cp, siz);
2336 free(cp, M_NFSSTRING);
2338 case NFSATTRBIT_QUOTAHARD:
2339 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2340 freenum = fs.f_bfree;
2342 freenum = fs.f_bavail;
2345 * ufs_quotactl() insists that the uid argument
2346 * equal p_ruid for non-root quota access, so
2347 * we'll just make sure that's the case.
2349 savuid = p->p_cred->p_ruid;
2350 p->p_cred->p_ruid = cred->cr_uid;
2351 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2352 cred->cr_uid, (caddr_t)&dqb))
2353 freenum = min(dqb.dqb_bhardlimit, freenum);
2354 p->p_cred->p_ruid = savuid;
2356 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2357 uquad = (u_int64_t)freenum;
2358 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2359 txdr_hyper(uquad, tl);
2360 retnum += NFSX_HYPER;
2362 case NFSATTRBIT_QUOTASOFT:
2363 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2364 freenum = fs.f_bfree;
2366 freenum = fs.f_bavail;
2369 * ufs_quotactl() insists that the uid argument
2370 * equal p_ruid for non-root quota access, so
2371 * we'll just make sure that's the case.
2373 savuid = p->p_cred->p_ruid;
2374 p->p_cred->p_ruid = cred->cr_uid;
2375 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2376 cred->cr_uid, (caddr_t)&dqb))
2377 freenum = min(dqb.dqb_bsoftlimit, freenum);
2378 p->p_cred->p_ruid = savuid;
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2381 uquad = (u_int64_t)freenum;
2382 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2383 txdr_hyper(uquad, tl);
2384 retnum += NFSX_HYPER;
2386 case NFSATTRBIT_QUOTAUSED:
2390 * ufs_quotactl() insists that the uid argument
2391 * equal p_ruid for non-root quota access, so
2392 * we'll just make sure that's the case.
2394 savuid = p->p_cred->p_ruid;
2395 p->p_cred->p_ruid = cred->cr_uid;
2396 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2397 cred->cr_uid, (caddr_t)&dqb))
2398 freenum = dqb.dqb_curblocks;
2399 p->p_cred->p_ruid = savuid;
2401 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2402 uquad = (u_int64_t)freenum;
2403 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2404 txdr_hyper(uquad, tl);
2405 retnum += NFSX_HYPER;
2407 case NFSATTRBIT_RAWDEV:
2408 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2409 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2410 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2411 retnum += NFSX_V4SPECDATA;
2413 case NFSATTRBIT_SPACEAVAIL:
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2415 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2416 uquad = (u_int64_t)fs.f_bfree;
2418 uquad = (u_int64_t)fs.f_bavail;
2419 uquad *= fs.f_bsize;
2420 txdr_hyper(uquad, tl);
2421 retnum += NFSX_HYPER;
2423 case NFSATTRBIT_SPACEFREE:
2424 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2425 uquad = (u_int64_t)fs.f_bfree;
2426 uquad *= fs.f_bsize;
2427 txdr_hyper(uquad, tl);
2428 retnum += NFSX_HYPER;
2430 case NFSATTRBIT_SPACETOTAL:
2431 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2432 uquad = (u_int64_t)fs.f_blocks;
2433 uquad *= fs.f_bsize;
2434 txdr_hyper(uquad, tl);
2435 retnum += NFSX_HYPER;
2437 case NFSATTRBIT_SPACEUSED:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2439 txdr_hyper(vap->va_bytes, tl);
2440 retnum += NFSX_HYPER;
2442 case NFSATTRBIT_TIMEACCESS:
2443 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2444 txdr_nfsv4time(&vap->va_atime, tl);
2445 retnum += NFSX_V4TIME;
2447 case NFSATTRBIT_TIMEACCESSSET:
2448 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2449 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2450 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2451 txdr_nfsv4time(&vap->va_atime, tl);
2452 retnum += NFSX_V4SETTIME;
2454 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2455 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2456 retnum += NFSX_UNSIGNED;
2459 case NFSATTRBIT_TIMEDELTA:
2460 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2461 temptime.tv_sec = 0;
2462 temptime.tv_nsec = 1000000000 / hz;
2463 txdr_nfsv4time(&temptime, tl);
2464 retnum += NFSX_V4TIME;
2466 case NFSATTRBIT_TIMEMETADATA:
2467 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2468 txdr_nfsv4time(&vap->va_ctime, tl);
2469 retnum += NFSX_V4TIME;
2471 case NFSATTRBIT_TIMEMODIFY:
2472 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2473 txdr_nfsv4time(&vap->va_mtime, tl);
2474 retnum += NFSX_V4TIME;
2476 case NFSATTRBIT_TIMEMODIFYSET:
2477 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2479 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2480 txdr_nfsv4time(&vap->va_mtime, tl);
2481 retnum += NFSX_V4SETTIME;
2483 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2484 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2485 retnum += NFSX_UNSIGNED;
2488 case NFSATTRBIT_MOUNTEDONFILEID:
2489 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2491 uquad = mounted_on_fileno;
2493 uquad = (u_int64_t)vap->va_fileid;
2494 txdr_hyper(uquad, tl);
2495 retnum += NFSX_HYPER;
2497 case NFSATTRBIT_SUPPATTREXCLCREAT:
2498 NFSSETSUPP_ATTRBIT(&attrbits);
2499 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2500 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2501 retnum += nfsrv_putattrbit(nd, &attrbits);
2504 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2510 *retnump = txdr_unsigned(retnum);
2511 return (retnum + prefixnum);
2515 * Put the attribute bits onto an mbuf list.
2516 * Return the number of bytes of output generated.
2519 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2522 int cnt, i, bytesize;
2524 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2525 if (attrbitp->bits[cnt - 1])
2527 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2528 NFSM_BUILD(tl, u_int32_t *, bytesize);
2529 *tl++ = txdr_unsigned(cnt);
2530 for (i = 0; i < cnt; i++)
2531 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2536 * Convert a uid to a string.
2537 * If the lookup fails, just output the digits.
2539 * cpp - points to a buffer of size NFSV4_SMALLSTR
2540 * (malloc a larger one, as required)
2541 * retlenp - pointer to length to be returned
2544 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2547 struct nfsusrgrp *usrp;
2550 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2555 if (nfsrv_dnsname) {
2557 * Always map nfsrv_defaultuid to "nobody".
2559 if (uid == nfsrv_defaultuid) {
2560 i = nfsrv_dnsnamelen + 7;
2563 if (len > NFSV4_SMALLSTR)
2564 free(cp, M_NFSSTRING);
2565 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2571 NFSBCOPY("nobody@", cp, 7);
2573 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2578 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2579 if (usrp->lug_uid == uid) {
2580 if (usrp->lug_expiry < NFSD_MONOSEC)
2583 * If the name doesn't already have an '@'
2584 * in it, append @domainname to it.
2586 for (i = 0; i < usrp->lug_namelen; i++) {
2587 if (usrp->lug_name[i] == '@') {
2593 i = usrp->lug_namelen;
2595 i = usrp->lug_namelen +
2596 nfsrv_dnsnamelen + 1;
2599 if (len > NFSV4_SMALLSTR)
2600 free(cp, M_NFSSTRING);
2601 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2607 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2608 if (!hasampersand) {
2609 cp += usrp->lug_namelen;
2611 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2613 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2614 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2621 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2623 if (ret == 0 && cnt < 2)
2630 * No match, just return a string of digits.
2634 while (tmp || i == 0) {
2638 len = (i > len) ? len : i;
2642 for (i = 0; i < len; i++) {
2643 *cp-- = '0' + (tmp % 10);
2650 * Convert a string to a uid.
2651 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2653 * If this is called from a client side mount using AUTH_SYS and the
2654 * string is made up entirely of digits, just convert the string to
2658 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2662 char *cp, *endstr, *str0;
2663 struct nfsusrgrp *usrp;
2669 error = NFSERR_BADOWNER;
2672 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2674 tuid = (uid_t)strtoul(str0, &endstr, 10);
2675 if ((endstr - str0) == len) {
2676 /* A numeric string. */
2677 if ((nd->nd_flag & ND_KERBV) == 0 &&
2678 ((nd->nd_flag & ND_NFSCL) != 0 ||
2679 nfsd_enable_stringtouid != 0))
2682 error = NFSERR_BADOWNER;
2688 cp = strchr(str0, '@');
2690 i = (int)(cp++ - str0);
2698 * If an '@' is found and the domain name matches, search for the name
2699 * with dns stripped off.
2700 * Mixed case alpahbetics will match for the domain name, but all
2701 * upper case will not.
2703 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2704 (len - 1 - i) == nfsrv_dnsnamelen &&
2705 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2706 len -= (nfsrv_dnsnamelen + 1);
2711 * Check for the special case of "nobody".
2713 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2714 *uidp = nfsrv_defaultuid;
2720 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2721 if (usrp->lug_namelen == len &&
2722 !NFSBCMP(usrp->lug_name, str, len)) {
2723 if (usrp->lug_expiry < NFSD_MONOSEC)
2725 *uidp = usrp->lug_uid;
2726 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2727 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2735 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2737 if (ret == 0 && cnt < 2)
2739 error = NFSERR_BADOWNER;
2747 * Convert a gid to a string.
2748 * gid - the group id
2749 * cpp - points to a buffer of size NFSV4_SMALLSTR
2750 * (malloc a larger one, as required)
2751 * retlenp - pointer to length to be returned
2754 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2757 struct nfsusrgrp *usrp;
2760 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2765 if (nfsrv_dnsname) {
2767 * Always map nfsrv_defaultgid to "nogroup".
2769 if (gid == nfsrv_defaultgid) {
2770 i = nfsrv_dnsnamelen + 8;
2773 if (len > NFSV4_SMALLSTR)
2774 free(cp, M_NFSSTRING);
2775 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2781 NFSBCOPY("nogroup@", cp, 8);
2783 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2788 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2789 if (usrp->lug_gid == gid) {
2790 if (usrp->lug_expiry < NFSD_MONOSEC)
2793 * If the name doesn't already have an '@'
2794 * in it, append @domainname to it.
2796 for (i = 0; i < usrp->lug_namelen; i++) {
2797 if (usrp->lug_name[i] == '@') {
2803 i = usrp->lug_namelen;
2805 i = usrp->lug_namelen +
2806 nfsrv_dnsnamelen + 1;
2809 if (len > NFSV4_SMALLSTR)
2810 free(cp, M_NFSSTRING);
2811 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2817 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2818 if (!hasampersand) {
2819 cp += usrp->lug_namelen;
2821 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2823 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2824 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2831 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2833 if (ret == 0 && cnt < 2)
2840 * No match, just return a string of digits.
2844 while (tmp || i == 0) {
2848 len = (i > len) ? len : i;
2852 for (i = 0; i < len; i++) {
2853 *cp-- = '0' + (tmp % 10);
2860 * Convert a string to a gid.
2861 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2863 * If this is called from a client side mount using AUTH_SYS and the
2864 * string is made up entirely of digits, just convert the string to
2868 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2872 char *cp, *endstr, *str0;
2873 struct nfsusrgrp *usrp;
2879 error = NFSERR_BADOWNER;
2882 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2884 tgid = (gid_t)strtoul(str0, &endstr, 10);
2885 if ((endstr - str0) == len) {
2886 /* A numeric string. */
2887 if ((nd->nd_flag & ND_KERBV) == 0 &&
2888 ((nd->nd_flag & ND_NFSCL) != 0 ||
2889 nfsd_enable_stringtouid != 0))
2892 error = NFSERR_BADOWNER;
2898 cp = strchr(str0, '@');
2900 i = (int)(cp++ - str0);
2908 * If an '@' is found and the dns name matches, search for the name
2909 * with the dns stripped off.
2911 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2912 (len - 1 - i) == nfsrv_dnsnamelen &&
2913 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2914 len -= (nfsrv_dnsnamelen + 1);
2919 * Check for the special case of "nogroup".
2921 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2922 *gidp = nfsrv_defaultgid;
2928 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2929 if (usrp->lug_namelen == len &&
2930 !NFSBCMP(usrp->lug_name, str, len)) {
2931 if (usrp->lug_expiry < NFSD_MONOSEC)
2933 *gidp = usrp->lug_gid;
2934 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2935 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2943 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2945 if (ret == 0 && cnt < 2)
2947 error = NFSERR_BADOWNER;
2955 * Cmp len chars, allowing mixed case in the first argument to match lower
2956 * case in the second, but not if the first argument is all upper case.
2957 * Return 0 for a match, 1 otherwise.
2960 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2966 for (i = 0; i < len; i++) {
2967 if (*cp >= 'A' && *cp <= 'Z') {
2968 tmp = *cp++ + ('a' - 'A');
2971 if (tmp >= 'a' && tmp <= 'z')
2984 * Set the port for the nfsuserd.
2987 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2989 struct nfssockreq *rp;
2990 struct sockaddr_in *ad;
2994 if (nfsrv_nfsuserd) {
3002 * Set up the socket record and connect.
3004 rp = &nfsrv_nfsuserdsock;
3005 rp->nr_client = NULL;
3006 rp->nr_sotype = SOCK_DGRAM;
3007 rp->nr_soproto = IPPROTO_UDP;
3008 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3010 NFSSOCKADDRALLOC(rp->nr_nam);
3011 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3012 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3013 ad->sin_family = AF_INET;
3014 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3015 ad->sin_port = port;
3016 rp->nr_prog = RPCPROG_NFSUSERD;
3017 rp->nr_vers = RPCNFSUSERD_VERS;
3018 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3020 NFSSOCKADDRFREE(rp->nr_nam);
3029 * Delete the nfsuserd port.
3032 nfsrv_nfsuserddelport(void)
3036 if (nfsrv_nfsuserd == 0) {
3042 newnfs_disconnect(&nfsrv_nfsuserdsock);
3043 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3047 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3049 * Returns 0 upon success, non-zero otherwise.
3052 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3055 struct nfsrv_descript *nd;
3057 struct nfsrv_descript nfsd;
3062 if (nfsrv_nfsuserd == 0) {
3069 cred = newnfs_getcred();
3070 nd->nd_flag = ND_GSSINITREPLY;
3073 nd->nd_procnum = procnum;
3074 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3075 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3076 if (procnum == RPCNFSUSERD_GETUID)
3077 *tl = txdr_unsigned(uid);
3079 *tl = txdr_unsigned(gid);
3082 (void) nfsm_strtom(nd, name, len);
3084 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3085 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3088 mbuf_freem(nd->nd_mrep);
3089 error = nd->nd_repstat;
3097 * This function is called from the nfssvc(2) system call, to update the
3098 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3101 nfssvc_idname(struct nfsd_idargs *nidp)
3103 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3104 struct nfsuserhashhead *hp;
3109 if (nidp->nid_flag & NFSID_INITIALIZE) {
3110 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3111 M_NFSSTRING, M_WAITOK);
3112 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3115 if (nfsrv_dnsname) {
3117 * Free up all the old stuff and reinitialize hash lists.
3119 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3120 nfsrv_removeuser(usrp);
3122 free(nfsrv_dnsname, M_NFSSTRING);
3123 nfsrv_dnsname = NULL;
3125 TAILQ_INIT(&nfsuserlruhead);
3126 for (i = 0; i < NFSUSERHASHSIZE; i++)
3127 LIST_INIT(&nfsuserhash[i]);
3128 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3129 LIST_INIT(&nfsgrouphash[i]);
3130 for (i = 0; i < NFSUSERHASHSIZE; i++)
3131 LIST_INIT(&nfsusernamehash[i]);
3132 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3133 LIST_INIT(&nfsgroupnamehash[i]);
3136 * Put name in "DNS" string.
3140 nfsrv_dnsnamelen = nidp->nid_namelen;
3141 nfsrv_defaultuid = nidp->nid_uid;
3142 nfsrv_defaultgid = nidp->nid_gid;
3144 nfsrv_usermax = nidp->nid_usermax;
3148 free(cp, M_NFSSTRING);
3153 * malloc the new one now, so any potential sleep occurs before
3154 * manipulation of the lists.
3156 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3157 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3158 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3161 free((caddr_t)newusrp, M_NFSUSERGROUP);
3164 newusrp->lug_namelen = nidp->nid_namelen;
3168 * Delete old entries, as required.
3170 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3171 hp = NFSUSERHASH(nidp->nid_uid);
3172 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3173 if (usrp->lug_uid == nidp->nid_uid)
3174 nfsrv_removeuser(usrp);
3177 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3178 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3179 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3180 if (usrp->lug_namelen == newusrp->lug_namelen &&
3181 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3183 nfsrv_removeuser(usrp);
3186 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3187 hp = NFSGROUPHASH(nidp->nid_gid);
3188 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3189 if (usrp->lug_gid == nidp->nid_gid)
3190 nfsrv_removeuser(usrp);
3193 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3194 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3195 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3196 if (usrp->lug_namelen == newusrp->lug_namelen &&
3197 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3199 nfsrv_removeuser(usrp);
3202 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3203 if (usrp->lug_expiry < NFSD_MONOSEC)
3204 nfsrv_removeuser(usrp);
3206 while (nfsrv_usercnt >= nfsrv_usermax) {
3207 usrp = TAILQ_FIRST(&nfsuserlruhead);
3208 nfsrv_removeuser(usrp);
3212 * Now, we can add the new one.
3214 if (nidp->nid_usertimeout)
3215 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3217 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3218 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3219 newusrp->lug_uid = nidp->nid_uid;
3220 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3222 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3223 newusrp->lug_namelen), newusrp, lug_namehash);
3224 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3226 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3227 newusrp->lug_gid = nidp->nid_gid;
3228 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3230 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3231 newusrp->lug_namelen), newusrp, lug_namehash);
3232 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3235 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3243 * Remove a user/group name element.
3246 nfsrv_removeuser(struct nfsusrgrp *usrp)
3249 NFSNAMEIDREQUIRED();
3250 LIST_REMOVE(usrp, lug_numhash);
3251 LIST_REMOVE(usrp, lug_namehash);
3252 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3254 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3258 * This function scans a byte string and checks for UTF-8 compliance.
3259 * It returns 0 if it conforms and NFSERR_INVAL if not.
3262 nfsrv_checkutf8(u_int8_t *cp, int len)
3264 u_int32_t val = 0x0;
3265 int cnt = 0, gotd = 0, shift = 0;
3267 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3271 * Here are what the variables are used for:
3272 * val - the calculated value of a multibyte char, used to check
3273 * that it was coded with the correct range
3274 * cnt - the number of 10xxxxxx bytes to follow
3275 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3276 * shift - lower order bits of range (ie. "val >> shift" should
3277 * not be 0, in other words, dividing by the lower bound
3278 * of the range should get a non-zero value)
3279 * byte - used to calculate cnt
3283 /* This handles the 10xxxxxx bytes */
3284 if ((*cp & 0xc0) != 0x80 ||
3285 (gotd && (*cp & 0x20))) {
3286 error = NFSERR_INVAL;
3291 val |= (*cp & 0x3f);
3293 if (cnt == 0 && (val >> shift) == 0x0) {
3294 error = NFSERR_INVAL;
3297 } else if (*cp & 0x80) {
3298 /* first byte of multi byte char */
3300 while ((byte & 0x40) && cnt < 6) {
3304 if (cnt == 0 || cnt == 6) {
3305 error = NFSERR_INVAL;
3308 val = (*cp & (0x3f >> cnt));
3309 shift = utf8_shift[cnt - 1];
3310 if (cnt == 2 && val == 0xd)
3311 /* Check for the 0xd800-0xdfff case */
3318 error = NFSERR_INVAL;
3326 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3327 * strings, one with the root path in it and the other with the list of
3328 * locations. The list is in the same format as is found in nfr_refs.
3329 * It is a "," separated list of entries, where each of them is of the
3330 * form <server>:<rootpath>. For example
3331 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3332 * The nilp argument is set to 1 for the special case of a null fs_root
3333 * and an empty server list.
3334 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3335 * number of xdr bytes parsed in sump.
3338 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3339 int *sump, int *nilp)
3342 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3343 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3345 SLIST_ENTRY(list) next;
3349 SLIST_HEAD(, list) head;
3356 * Get the fs_root path and check for the special case of null path
3357 * and 0 length server list.
3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3360 len = fxdr_unsigned(int, *tl);
3361 if (len < 0 || len > 10240) {
3362 error = NFSERR_BADXDR;
3366 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3368 error = NFSERR_BADXDR;
3372 *sump = 2 * NFSX_UNSIGNED;
3376 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3377 error = nfsrv_mtostr(nd, cp, len);
3379 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3380 cnt = fxdr_unsigned(int, *tl);
3382 error = NFSERR_BADXDR;
3388 * Now, loop through the location list and make up the srvlist.
3390 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3391 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3394 for (i = 0; i < cnt; i++) {
3396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3397 nsrv = fxdr_unsigned(int, *tl);
3399 error = NFSERR_BADXDR;
3404 * Handle the first server by putting it in the srvstr.
3406 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3407 len = fxdr_unsigned(int, *tl);
3408 if (len <= 0 || len > 1024) {
3409 error = NFSERR_BADXDR;
3412 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3417 error = nfsrv_mtostr(nd, cp3, len);
3423 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3424 for (j = 1; j < nsrv; j++) {
3426 * Yuck, put them in an slist and process them later.
3428 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3429 len = fxdr_unsigned(int, *tl);
3430 if (len <= 0 || len > 1024) {
3431 error = NFSERR_BADXDR;
3434 lsp = (struct list *)malloc(sizeof (struct list)
3435 + len, M_TEMP, M_WAITOK);
3436 error = nfsrv_mtostr(nd, lsp->host, len);
3439 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3441 SLIST_INSERT_HEAD(&head, lsp, next);
3445 * Finally, we can get the path.
3447 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3448 len = fxdr_unsigned(int, *tl);
3449 if (len <= 0 || len > 1024) {
3450 error = NFSERR_BADXDR;
3453 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3454 error = nfsrv_mtostr(nd, cp3, len);
3457 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3462 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3463 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3466 NFSBCOPY(lsp->host, cp3, lsp->len);
3469 NFSBCOPY(str, cp3, stringlen);
3472 siz += (lsp->len + stringlen + 2);
3473 free((caddr_t)lsp, M_TEMP);
3479 NFSEXITCODE2(0, nd);
3483 free(cp, M_NFSSTRING);
3485 free(cp2, M_NFSSTRING);
3486 NFSEXITCODE2(error, nd);
3491 * Make the malloc'd space large enough. This is a pain, but the xdr
3492 * doesn't set an upper bound on the side, so...
3495 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3502 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3503 NFSBCOPY(*cpp, cp, *slenp);
3504 free(*cpp, M_NFSSTRING);
3508 *slenp = siz + 1024;
3512 * Initialize the reply header data structures.
3515 nfsrvd_rephead(struct nfsrv_descript *nd)
3520 * If this is a big reply, use a cluster.
3522 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3523 nfs_bigreply[nd->nd_procnum]) {
3524 NFSMCLGET(mreq, M_WAITOK);
3532 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3533 mbuf_setlen(mreq, 0);
3535 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3536 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3540 * Lock a socket against others.
3541 * Currently used to serialize connect/disconnect attempts.
3544 newnfs_sndlock(int *flagp)
3549 while (*flagp & NFSR_SNDLOCK) {
3550 *flagp |= NFSR_WANTSND;
3553 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3554 PZERO - 1, "nfsndlck", &ts);
3556 *flagp |= NFSR_SNDLOCK;
3562 * Unlock the stream socket for others.
3565 newnfs_sndunlock(int *flagp)
3569 if ((*flagp & NFSR_SNDLOCK) == 0)
3570 panic("nfs sndunlock");
3571 *flagp &= ~NFSR_SNDLOCK;
3572 if (*flagp & NFSR_WANTSND) {
3573 *flagp &= ~NFSR_WANTSND;
3574 wakeup((caddr_t)flagp);
3580 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3583 struct sockaddr_in *sad;
3584 struct sockaddr_in6 *sad6;
3585 struct in_addr saddr;
3586 uint32_t portnum, *tl;
3587 int af = 0, i, j, k;
3588 char addr[64], protocol[5], *cp;
3589 int cantparse = 0, error = 0;
3592 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3593 i = fxdr_unsigned(int, *tl);
3594 if (i >= 3 && i <= 4) {
3595 error = nfsrv_mtostr(nd, protocol, i);
3598 if (strcmp(protocol, "tcp") == 0) {
3601 } else if (strcmp(protocol, "udp") == 0) {
3604 } else if (strcmp(protocol, "tcp6") == 0) {
3607 } else if (strcmp(protocol, "udp6") == 0) {
3615 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3620 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3621 i = fxdr_unsigned(int, *tl);
3623 error = NFSERR_BADXDR;
3625 } else if (cantparse == 0 && i >= 11 && i < 64) {
3627 * The shortest address is 11chars and the longest is < 64.
3629 error = nfsrv_mtostr(nd, addr, i);
3633 /* Find the port# at the end and extract that. */
3637 /* Count back two '.'s from end to get port# field. */
3638 for (j = 0; j < i; j++) {
3648 * The NFSv4 port# is appended as .N.N, where N is
3649 * a decimal # in the range 0-255, just like an inet4
3650 * address. Cheat and use inet_aton(), which will
3651 * return a Class A address and then shift the high
3652 * order 8bits over to convert it to the port#.
3655 if (inet_aton(cp, &saddr) == 1) {
3656 portnum = ntohl(saddr.s_addr);
3657 portv = (uint16_t)((portnum >> 16) |
3663 if (cantparse == 0) {
3664 if (af == AF_INET) {
3665 sad = (struct sockaddr_in *)sa;
3666 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3667 sad->sin_len = sizeof(*sad);
3668 sad->sin_family = AF_INET;
3669 sad->sin_port = htons(portv);
3673 sad6 = (struct sockaddr_in6 *)sa;
3674 if (inet_pton(af, addr, &sad6->sin6_addr)
3676 sad6->sin6_len = sizeof(*sad6);
3677 sad6->sin6_family = AF_INET6;
3678 sad6->sin6_port = htons(portv);
3685 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3696 * Handle an NFSv4.1 Sequence request for the session.
3697 * If reply != NULL, use it to return the cached reply, as required.
3698 * The client gets a cached reply via this call for callbacks, however the
3699 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
3702 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3703 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3710 if (slotid > maxslot)
3711 return (NFSERR_BADSLOT);
3712 if (seqid == slots[slotid].nfssl_seq) {
3714 if (slots[slotid].nfssl_inprog != 0)
3715 error = NFSERR_DELAY;
3716 else if (slots[slotid].nfssl_reply != NULL) {
3717 if (reply != NULL) {
3718 *reply = slots[slotid].nfssl_reply;
3719 slots[slotid].nfssl_reply = NULL;
3721 slots[slotid].nfssl_inprog = 1;
3722 error = NFSERR_REPLYFROMCACHE;
3724 /* No reply cached, so just do it. */
3725 slots[slotid].nfssl_inprog = 1;
3726 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3727 if (slots[slotid].nfssl_reply != NULL)
3728 m_freem(slots[slotid].nfssl_reply);
3729 slots[slotid].nfssl_reply = NULL;
3730 slots[slotid].nfssl_inprog = 1;
3731 slots[slotid].nfssl_seq++;
3733 error = NFSERR_SEQMISORDERED;
3738 * Cache this reply for the slot.
3739 * Use the "rep" argument to return the cached reply if repstat is set to
3740 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
3743 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
3747 if (repstat == NFSERR_REPLYFROMCACHE) {
3748 *rep = slots[slotid].nfssl_reply;
3749 slots[slotid].nfssl_reply = NULL;
3751 if (slots[slotid].nfssl_reply != NULL)
3752 m_freem(slots[slotid].nfssl_reply);
3753 slots[slotid].nfssl_reply = *rep;
3755 slots[slotid].nfssl_inprog = 0;
3759 * Generate the xdr for an NFSv4.1 Sequence Operation.
3762 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
3763 struct nfsclsession *sep, int dont_replycache)
3765 uint32_t *tl, slotseq = 0;
3766 int error, maxslot, slotpos;
3767 uint8_t sessionid[NFSX_V4SESSIONID];
3769 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
3773 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3775 /* Build the Sequence arguments. */
3776 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3777 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3778 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3779 nd->nd_slotseq = tl;
3780 *tl++ = txdr_unsigned(slotseq);
3781 *tl++ = txdr_unsigned(slotpos);
3782 *tl++ = txdr_unsigned(maxslot);
3783 if (dont_replycache == 0)
3787 nd->nd_flag |= ND_HASSEQUENCE;
3791 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
3792 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
3794 int i, maxslot, slotpos;
3797 /* Find an unused slot. */
3800 mtx_lock(&sep->nfsess_mtx);
3803 for (i = 0; i < sep->nfsess_foreslots; i++) {
3804 if ((bitval & sep->nfsess_slots) == 0) {
3806 sep->nfsess_slots |= bitval;
3807 sep->nfsess_slotseq[i]++;
3808 *slotseqp = sep->nfsess_slotseq[i];
3813 if (slotpos == -1) {
3815 * If a forced dismount is in progress, just return.
3816 * This RPC attempt will fail when it calls
3820 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
3822 mtx_unlock(&sep->nfsess_mtx);
3825 /* Wake up once/sec, to check for a forced dismount. */
3826 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3827 PZERO, "nfsclseq", hz);
3829 } while (slotpos == -1);
3830 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3832 for (i = 0; i < 64; i++) {
3833 if ((bitval & sep->nfsess_slots) != 0)
3837 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3838 mtx_unlock(&sep->nfsess_mtx);
3839 *slotposp = slotpos;
3840 *maxslotp = maxslot;
3845 * Free a session slot.
3848 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3855 mtx_lock(&sep->nfsess_mtx);
3856 if ((bitval & sep->nfsess_slots) == 0)
3857 printf("freeing free slot!!\n");
3858 sep->nfsess_slots &= ~bitval;
3859 wakeup(&sep->nfsess_slots);
3860 mtx_unlock(&sep->nfsess_mtx);