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;
827 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
829 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
835 *retcmpp = retnotsup;
838 * Just set default values to some of the important ones.
843 nap->na_rdev = (NFSDEV_T)0;
844 nap->na_mtime.tv_sec = 0;
845 nap->na_mtime.tv_nsec = 0;
848 nap->na_blocksize = NFS_FABLKSIZE;
851 sbp->f_bsize = NFS_FABLKSIZE;
859 fsp->fs_rtmax = 8192;
860 fsp->fs_rtpref = 8192;
861 fsp->fs_maxname = NFS_MAXNAMLEN;
862 fsp->fs_wtmax = 8192;
863 fsp->fs_wtpref = 8192;
864 fsp->fs_wtmult = NFS_FABLKSIZE;
865 fsp->fs_dtpref = 8192;
866 fsp->fs_maxfilesize = 0xffffffffffffffffull;
867 fsp->fs_timedelta.tv_sec = 0;
868 fsp->fs_timedelta.tv_nsec = 1;
869 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
870 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
873 pc->pc_linkmax = LINK_MAX;
874 pc->pc_namemax = NAME_MAX;
876 pc->pc_chownrestricted = 0;
877 pc->pc_caseinsensitive = 0;
878 pc->pc_casepreserving = 1;
883 * Loop around getting the attributes.
885 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
886 attrsize = fxdr_unsigned(int, *tl);
887 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
888 if (attrsum > attrsize) {
889 error = NFSERR_BADXDR;
892 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
894 case NFSATTRBIT_SUPPORTEDATTRS:
896 if (compare || nap == NULL)
897 error = nfsrv_getattrbits(nd, &retattrbits,
900 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
904 if (compare && !(*retcmpp)) {
905 NFSSETSUPP_ATTRBIT(&checkattrbits);
906 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
908 *retcmpp = NFSERR_NOTSAME;
912 case NFSATTRBIT_TYPE:
913 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
916 if (nap->na_type != nfsv34tov_type(*tl))
917 *retcmpp = NFSERR_NOTSAME;
919 } else if (nap != NULL) {
920 nap->na_type = nfsv34tov_type(*tl);
922 attrsum += NFSX_UNSIGNED;
924 case NFSATTRBIT_FHEXPIRETYPE:
925 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
926 if (compare && !(*retcmpp)) {
927 if (fxdr_unsigned(int, *tl) !=
928 NFSV4FHTYPE_PERSISTENT)
929 *retcmpp = NFSERR_NOTSAME;
931 attrsum += NFSX_UNSIGNED;
933 case NFSATTRBIT_CHANGE:
934 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
937 if (nap->na_filerev != fxdr_hyper(tl))
938 *retcmpp = NFSERR_NOTSAME;
940 } else if (nap != NULL) {
941 nap->na_filerev = fxdr_hyper(tl);
943 attrsum += NFSX_HYPER;
945 case NFSATTRBIT_SIZE:
946 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
949 if (nap->na_size != fxdr_hyper(tl))
950 *retcmpp = NFSERR_NOTSAME;
952 } else if (nap != NULL) {
953 nap->na_size = fxdr_hyper(tl);
955 attrsum += NFSX_HYPER;
957 case NFSATTRBIT_LINKSUPPORT:
958 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
961 if (fsp->fs_properties & NFSV3_FSFLINK) {
962 if (*tl == newnfs_false)
963 *retcmpp = NFSERR_NOTSAME;
965 if (*tl == newnfs_true)
966 *retcmpp = NFSERR_NOTSAME;
969 } else if (fsp != NULL) {
970 if (*tl == newnfs_true)
971 fsp->fs_properties |= NFSV3_FSFLINK;
973 fsp->fs_properties &= ~NFSV3_FSFLINK;
975 attrsum += NFSX_UNSIGNED;
977 case NFSATTRBIT_SYMLINKSUPPORT:
978 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
981 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
982 if (*tl == newnfs_false)
983 *retcmpp = NFSERR_NOTSAME;
985 if (*tl == newnfs_true)
986 *retcmpp = NFSERR_NOTSAME;
989 } else if (fsp != NULL) {
990 if (*tl == newnfs_true)
991 fsp->fs_properties |= NFSV3_FSFSYMLINK;
993 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
995 attrsum += NFSX_UNSIGNED;
997 case NFSATTRBIT_NAMEDATTR:
998 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
999 if (compare && !(*retcmpp)) {
1000 if (*tl != newnfs_false)
1001 *retcmpp = NFSERR_NOTSAME;
1003 attrsum += NFSX_UNSIGNED;
1005 case NFSATTRBIT_FSID:
1006 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1007 thyp = fxdr_hyper(tl);
1009 thyp2 = fxdr_hyper(tl);
1011 if (*retcmpp == 0) {
1012 if (thyp != (u_int64_t)
1013 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1014 thyp2 != (u_int64_t)
1015 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1016 *retcmpp = NFSERR_NOTSAME;
1018 } else if (nap != NULL) {
1019 nap->na_filesid[0] = thyp;
1020 nap->na_filesid[1] = thyp2;
1022 attrsum += (4 * NFSX_UNSIGNED);
1024 case NFSATTRBIT_UNIQUEHANDLES:
1025 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1026 if (compare && !(*retcmpp)) {
1027 if (*tl != newnfs_true)
1028 *retcmpp = NFSERR_NOTSAME;
1030 attrsum += NFSX_UNSIGNED;
1032 case NFSATTRBIT_LEASETIME:
1033 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1035 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1037 *retcmpp = NFSERR_NOTSAME;
1038 } else if (leasep != NULL) {
1039 *leasep = fxdr_unsigned(u_int32_t, *tl);
1041 attrsum += NFSX_UNSIGNED;
1043 case NFSATTRBIT_RDATTRERROR:
1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1047 *retcmpp = NFSERR_INVAL;
1048 } else if (rderrp != NULL) {
1049 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1051 attrsum += NFSX_UNSIGNED;
1053 case NFSATTRBIT_ACL:
1059 naclp = acl_alloc(M_WAITOK);
1060 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1066 if (aceerr || aclp == NULL ||
1067 nfsrv_compareacl(aclp, naclp))
1068 *retcmpp = NFSERR_NOTSAME;
1071 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1073 *retcmpp = NFSERR_ATTRNOTSUPP;
1077 if (vp != NULL && aclp != NULL)
1078 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1081 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1088 case NFSATTRBIT_ACLSUPPORT:
1089 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1090 if (compare && !(*retcmpp)) {
1092 if (fxdr_unsigned(u_int32_t, *tl) !=
1094 *retcmpp = NFSERR_NOTSAME;
1096 *retcmpp = NFSERR_ATTRNOTSUPP;
1099 attrsum += NFSX_UNSIGNED;
1101 case NFSATTRBIT_ARCHIVE:
1102 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1103 if (compare && !(*retcmpp))
1104 *retcmpp = NFSERR_ATTRNOTSUPP;
1105 attrsum += NFSX_UNSIGNED;
1107 case NFSATTRBIT_CANSETTIME:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1111 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1112 if (*tl == newnfs_false)
1113 *retcmpp = NFSERR_NOTSAME;
1115 if (*tl == newnfs_true)
1116 *retcmpp = NFSERR_NOTSAME;
1119 } else if (fsp != NULL) {
1120 if (*tl == newnfs_true)
1121 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1123 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1125 attrsum += NFSX_UNSIGNED;
1127 case NFSATTRBIT_CASEINSENSITIVE:
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1131 if (*tl != newnfs_false)
1132 *retcmpp = NFSERR_NOTSAME;
1134 } else if (pc != NULL) {
1135 pc->pc_caseinsensitive =
1136 fxdr_unsigned(u_int32_t, *tl);
1138 attrsum += NFSX_UNSIGNED;
1140 case NFSATTRBIT_CASEPRESERVING:
1141 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1144 if (*tl != newnfs_true)
1145 *retcmpp = NFSERR_NOTSAME;
1147 } else if (pc != NULL) {
1148 pc->pc_casepreserving =
1149 fxdr_unsigned(u_int32_t, *tl);
1151 attrsum += NFSX_UNSIGNED;
1153 case NFSATTRBIT_CHOWNRESTRICTED:
1154 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1157 if (*tl != newnfs_true)
1158 *retcmpp = NFSERR_NOTSAME;
1160 } else if (pc != NULL) {
1161 pc->pc_chownrestricted =
1162 fxdr_unsigned(u_int32_t, *tl);
1164 attrsum += NFSX_UNSIGNED;
1166 case NFSATTRBIT_FILEHANDLE:
1167 error = nfsm_getfh(nd, &tnfhp);
1170 tfhsize = tnfhp->nfh_len;
1173 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1175 *retcmpp = NFSERR_NOTSAME;
1176 FREE((caddr_t)tnfhp, M_NFSFH);
1177 } else if (nfhpp != NULL) {
1180 FREE((caddr_t)tnfhp, M_NFSFH);
1182 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1184 case NFSATTRBIT_FILEID:
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1186 thyp = fxdr_hyper(tl);
1189 if ((u_int64_t)nap->na_fileid != thyp)
1190 *retcmpp = NFSERR_NOTSAME;
1192 } else if (nap != NULL) {
1194 printf("NFSv4 fileid > 32bits\n");
1195 nap->na_fileid = thyp;
1197 attrsum += NFSX_HYPER;
1199 case NFSATTRBIT_FILESAVAIL:
1200 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1203 sfp->sf_afiles != fxdr_hyper(tl))
1204 *retcmpp = NFSERR_NOTSAME;
1205 } else if (sfp != NULL) {
1206 sfp->sf_afiles = fxdr_hyper(tl);
1208 attrsum += NFSX_HYPER;
1210 case NFSATTRBIT_FILESFREE:
1211 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1214 sfp->sf_ffiles != fxdr_hyper(tl))
1215 *retcmpp = NFSERR_NOTSAME;
1216 } else if (sfp != NULL) {
1217 sfp->sf_ffiles = fxdr_hyper(tl);
1219 attrsum += NFSX_HYPER;
1221 case NFSATTRBIT_FILESTOTAL:
1222 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1225 sfp->sf_tfiles != fxdr_hyper(tl))
1226 *retcmpp = NFSERR_NOTSAME;
1227 } else if (sfp != NULL) {
1228 sfp->sf_tfiles = fxdr_hyper(tl);
1230 attrsum += NFSX_HYPER;
1232 case NFSATTRBIT_FSLOCATIONS:
1233 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1237 if (compare && !(*retcmpp)) {
1238 refp = nfsv4root_getreferral(vp, NULL, 0);
1240 if (cp == NULL || cp2 == NULL ||
1242 strcmp(cp2, refp->nfr_srvlist))
1243 *retcmpp = NFSERR_NOTSAME;
1244 } else if (m == 0) {
1245 *retcmpp = NFSERR_NOTSAME;
1249 free(cp, M_NFSSTRING);
1251 free(cp2, M_NFSSTRING);
1253 case NFSATTRBIT_HIDDEN:
1254 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1255 if (compare && !(*retcmpp))
1256 *retcmpp = NFSERR_ATTRNOTSUPP;
1257 attrsum += NFSX_UNSIGNED;
1259 case NFSATTRBIT_HOMOGENEOUS:
1260 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1263 if (fsp->fs_properties &
1264 NFSV3_FSFHOMOGENEOUS) {
1265 if (*tl == newnfs_false)
1266 *retcmpp = NFSERR_NOTSAME;
1268 if (*tl == newnfs_true)
1269 *retcmpp = NFSERR_NOTSAME;
1272 } else if (fsp != NULL) {
1273 if (*tl == newnfs_true)
1274 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1276 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1278 attrsum += NFSX_UNSIGNED;
1280 case NFSATTRBIT_MAXFILESIZE:
1281 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1282 tnfsquad.qval = fxdr_hyper(tl);
1285 tquad = NFSRV_MAXFILESIZE;
1286 if (tquad != tnfsquad.qval)
1287 *retcmpp = NFSERR_NOTSAME;
1289 } else if (fsp != NULL) {
1290 fsp->fs_maxfilesize = tnfsquad.qval;
1292 attrsum += NFSX_HYPER;
1294 case NFSATTRBIT_MAXLINK:
1295 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1298 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1299 *retcmpp = NFSERR_NOTSAME;
1301 } else if (pc != NULL) {
1302 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1304 attrsum += NFSX_UNSIGNED;
1306 case NFSATTRBIT_MAXNAME:
1307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1310 if (fsp->fs_maxname !=
1311 fxdr_unsigned(u_int32_t, *tl))
1312 *retcmpp = NFSERR_NOTSAME;
1315 tuint = fxdr_unsigned(u_int32_t, *tl);
1317 * Some Linux NFSv4 servers report this
1318 * as 0 or 4billion, so I'll set it to
1319 * NFS_MAXNAMLEN. If a server actually creates
1320 * a name longer than NFS_MAXNAMLEN, it will
1321 * get an error back.
1323 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1324 tuint = NFS_MAXNAMLEN;
1326 fsp->fs_maxname = tuint;
1328 pc->pc_namemax = tuint;
1330 attrsum += NFSX_UNSIGNED;
1332 case NFSATTRBIT_MAXREAD:
1333 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1336 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1337 *(tl + 1)) || *tl != 0)
1338 *retcmpp = NFSERR_NOTSAME;
1340 } else if (fsp != NULL) {
1341 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1342 fsp->fs_rtpref = fsp->fs_rtmax;
1343 fsp->fs_dtpref = fsp->fs_rtpref;
1345 attrsum += NFSX_HYPER;
1347 case NFSATTRBIT_MAXWRITE:
1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1351 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1352 *(tl + 1)) || *tl != 0)
1353 *retcmpp = NFSERR_NOTSAME;
1355 } else if (fsp != NULL) {
1356 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1357 fsp->fs_wtpref = fsp->fs_wtmax;
1359 attrsum += NFSX_HYPER;
1361 case NFSATTRBIT_MIMETYPE:
1362 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1363 i = fxdr_unsigned(int, *tl);
1364 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1365 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1368 if (compare && !(*retcmpp))
1369 *retcmpp = NFSERR_ATTRNOTSUPP;
1371 case NFSATTRBIT_MODE:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1375 if (nap->na_mode != nfstov_mode(*tl))
1376 *retcmpp = NFSERR_NOTSAME;
1378 } else if (nap != NULL) {
1379 nap->na_mode = nfstov_mode(*tl);
1381 attrsum += NFSX_UNSIGNED;
1383 case NFSATTRBIT_NOTRUNC:
1384 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1387 if (*tl != newnfs_true)
1388 *retcmpp = NFSERR_NOTSAME;
1390 } else if (pc != NULL) {
1391 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1393 attrsum += NFSX_UNSIGNED;
1395 case NFSATTRBIT_NUMLINKS:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1397 tuint = fxdr_unsigned(u_int32_t, *tl);
1400 if ((u_int32_t)nap->na_nlink != tuint)
1401 *retcmpp = NFSERR_NOTSAME;
1403 } else if (nap != NULL) {
1404 nap->na_nlink = tuint;
1406 attrsum += NFSX_UNSIGNED;
1408 case NFSATTRBIT_OWNER:
1409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1410 j = fxdr_unsigned(int, *tl);
1412 error = NFSERR_BADXDR;
1415 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1416 if (j > NFSV4_SMALLSTR)
1417 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1420 error = nfsrv_mtostr(nd, cp, j);
1422 if (j > NFSV4_SMALLSTR)
1423 free(cp, M_NFSSTRING);
1428 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1430 *retcmpp = NFSERR_NOTSAME;
1432 } else if (nap != NULL) {
1433 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1434 nap->na_uid = nfsrv_defaultuid;
1438 if (j > NFSV4_SMALLSTR)
1439 free(cp, M_NFSSTRING);
1441 case NFSATTRBIT_OWNERGROUP:
1442 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1443 j = fxdr_unsigned(int, *tl);
1445 error = NFSERR_BADXDR;
1448 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1449 if (j > NFSV4_SMALLSTR)
1450 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1453 error = nfsrv_mtostr(nd, cp, j);
1455 if (j > NFSV4_SMALLSTR)
1456 free(cp, M_NFSSTRING);
1461 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1463 *retcmpp = NFSERR_NOTSAME;
1465 } else if (nap != NULL) {
1466 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1467 nap->na_gid = nfsrv_defaultgid;
1471 if (j > NFSV4_SMALLSTR)
1472 free(cp, M_NFSSTRING);
1474 case NFSATTRBIT_QUOTAHARD:
1475 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1477 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1478 freenum = sbp->f_bfree;
1480 freenum = sbp->f_bavail;
1483 * ufs_quotactl() insists that the uid argument
1484 * equal p_ruid for non-root quota access, so
1485 * we'll just make sure that's the case.
1487 savuid = p->p_cred->p_ruid;
1488 p->p_cred->p_ruid = cred->cr_uid;
1489 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1490 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1491 freenum = min(dqb.dqb_bhardlimit, freenum);
1492 p->p_cred->p_ruid = savuid;
1494 uquad = (u_int64_t)freenum;
1495 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1497 if (compare && !(*retcmpp)) {
1498 if (uquad != fxdr_hyper(tl))
1499 *retcmpp = NFSERR_NOTSAME;
1501 attrsum += NFSX_HYPER;
1503 case NFSATTRBIT_QUOTASOFT:
1504 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1506 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1507 freenum = sbp->f_bfree;
1509 freenum = sbp->f_bavail;
1512 * ufs_quotactl() insists that the uid argument
1513 * equal p_ruid for non-root quota access, so
1514 * we'll just make sure that's the case.
1516 savuid = p->p_cred->p_ruid;
1517 p->p_cred->p_ruid = cred->cr_uid;
1518 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1519 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1520 freenum = min(dqb.dqb_bsoftlimit, freenum);
1521 p->p_cred->p_ruid = savuid;
1523 uquad = (u_int64_t)freenum;
1524 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1526 if (compare && !(*retcmpp)) {
1527 if (uquad != fxdr_hyper(tl))
1528 *retcmpp = NFSERR_NOTSAME;
1530 attrsum += NFSX_HYPER;
1532 case NFSATTRBIT_QUOTAUSED:
1533 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1538 * ufs_quotactl() insists that the uid argument
1539 * equal p_ruid for non-root quota access, so
1540 * we'll just make sure that's the case.
1542 savuid = p->p_cred->p_ruid;
1543 p->p_cred->p_ruid = cred->cr_uid;
1544 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1545 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1546 freenum = dqb.dqb_curblocks;
1547 p->p_cred->p_ruid = savuid;
1549 uquad = (u_int64_t)freenum;
1550 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1552 if (compare && !(*retcmpp)) {
1553 if (uquad != fxdr_hyper(tl))
1554 *retcmpp = NFSERR_NOTSAME;
1556 attrsum += NFSX_HYPER;
1558 case NFSATTRBIT_RAWDEV:
1559 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1560 j = fxdr_unsigned(int, *tl++);
1561 k = fxdr_unsigned(int, *tl);
1564 if (nap->na_rdev != NFSMAKEDEV(j, k))
1565 *retcmpp = NFSERR_NOTSAME;
1567 } else if (nap != NULL) {
1568 nap->na_rdev = NFSMAKEDEV(j, k);
1570 attrsum += NFSX_V4SPECDATA;
1572 case NFSATTRBIT_SPACEAVAIL:
1573 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1576 sfp->sf_abytes != fxdr_hyper(tl))
1577 *retcmpp = NFSERR_NOTSAME;
1578 } else if (sfp != NULL) {
1579 sfp->sf_abytes = fxdr_hyper(tl);
1581 attrsum += NFSX_HYPER;
1583 case NFSATTRBIT_SPACEFREE:
1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1587 sfp->sf_fbytes != fxdr_hyper(tl))
1588 *retcmpp = NFSERR_NOTSAME;
1589 } else if (sfp != NULL) {
1590 sfp->sf_fbytes = fxdr_hyper(tl);
1592 attrsum += NFSX_HYPER;
1594 case NFSATTRBIT_SPACETOTAL:
1595 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1598 sfp->sf_tbytes != fxdr_hyper(tl))
1599 *retcmpp = NFSERR_NOTSAME;
1600 } else if (sfp != NULL) {
1601 sfp->sf_tbytes = fxdr_hyper(tl);
1603 attrsum += NFSX_HYPER;
1605 case NFSATTRBIT_SPACEUSED:
1606 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1607 thyp = fxdr_hyper(tl);
1610 if ((u_int64_t)nap->na_bytes != thyp)
1611 *retcmpp = NFSERR_NOTSAME;
1613 } else if (nap != NULL) {
1614 nap->na_bytes = thyp;
1616 attrsum += NFSX_HYPER;
1618 case NFSATTRBIT_SYSTEM:
1619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1620 if (compare && !(*retcmpp))
1621 *retcmpp = NFSERR_ATTRNOTSUPP;
1622 attrsum += NFSX_UNSIGNED;
1624 case NFSATTRBIT_TIMEACCESS:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1626 fxdr_nfsv4time(tl, &temptime);
1629 if (!NFS_CMPTIME(temptime, nap->na_atime))
1630 *retcmpp = NFSERR_NOTSAME;
1632 } else if (nap != NULL) {
1633 nap->na_atime = temptime;
1635 attrsum += NFSX_V4TIME;
1637 case NFSATTRBIT_TIMEACCESSSET:
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1639 attrsum += NFSX_UNSIGNED;
1640 i = fxdr_unsigned(int, *tl);
1641 if (i == NFSV4SATTRTIME_TOCLIENT) {
1642 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1643 attrsum += NFSX_V4TIME;
1645 if (compare && !(*retcmpp))
1646 *retcmpp = NFSERR_INVAL;
1648 case NFSATTRBIT_TIMEBACKUP:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1650 if (compare && !(*retcmpp))
1651 *retcmpp = NFSERR_ATTRNOTSUPP;
1652 attrsum += NFSX_V4TIME;
1654 case NFSATTRBIT_TIMECREATE:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1656 if (compare && !(*retcmpp))
1657 *retcmpp = NFSERR_ATTRNOTSUPP;
1658 attrsum += NFSX_V4TIME;
1660 case NFSATTRBIT_TIMEDELTA:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1665 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1666 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1667 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1668 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1671 *retcmpp = NFSERR_NOTSAME;
1674 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1677 attrsum += NFSX_V4TIME;
1679 case NFSATTRBIT_TIMEMETADATA:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1681 fxdr_nfsv4time(tl, &temptime);
1684 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1685 *retcmpp = NFSERR_NOTSAME;
1687 } else if (nap != NULL) {
1688 nap->na_ctime = temptime;
1690 attrsum += NFSX_V4TIME;
1692 case NFSATTRBIT_TIMEMODIFY:
1693 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1694 fxdr_nfsv4time(tl, &temptime);
1697 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1698 *retcmpp = NFSERR_NOTSAME;
1700 } else if (nap != NULL) {
1701 nap->na_mtime = temptime;
1703 attrsum += NFSX_V4TIME;
1705 case NFSATTRBIT_TIMEMODIFYSET:
1706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1707 attrsum += NFSX_UNSIGNED;
1708 i = fxdr_unsigned(int, *tl);
1709 if (i == NFSV4SATTRTIME_TOCLIENT) {
1710 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1711 attrsum += NFSX_V4TIME;
1713 if (compare && !(*retcmpp))
1714 *retcmpp = NFSERR_INVAL;
1716 case NFSATTRBIT_MOUNTEDONFILEID:
1717 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1718 thyp = fxdr_hyper(tl);
1722 *retcmpp = NFSERR_NOTSAME;
1724 if (!vp || !nfsrv_atroot(vp, &fid))
1725 fid = nap->na_fileid;
1726 if ((u_int64_t)fid != thyp)
1727 *retcmpp = NFSERR_NOTSAME;
1730 } else if (nap != NULL) {
1732 printf("NFSv4 mounted on fileid > 32bits\n");
1733 nap->na_mntonfileno = thyp;
1735 attrsum += NFSX_HYPER;
1737 case NFSATTRBIT_SUPPATTREXCLCREAT:
1739 error = nfsrv_getattrbits(nd, &retattrbits,
1743 if (compare && !(*retcmpp)) {
1744 NFSSETSUPP_ATTRBIT(&checkattrbits);
1745 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1746 NFSCLRBIT_ATTRBIT(&checkattrbits,
1747 NFSATTRBIT_TIMEACCESSSET);
1748 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1750 *retcmpp = NFSERR_NOTSAME;
1755 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1757 if (compare && !(*retcmpp))
1758 *retcmpp = NFSERR_ATTRNOTSUPP;
1760 * and get out of the loop, since we can't parse
1761 * the unknown attrbute data.
1763 bitpos = NFSATTRBIT_MAX;
1769 * some clients pad the attrlist, so we need to skip over the
1772 if (attrsum > attrsize) {
1773 error = NFSERR_BADXDR;
1775 attrsize = NFSM_RNDUP(attrsize);
1776 if (attrsum < attrsize)
1777 error = nfsm_advance(nd, attrsize - attrsum, -1);
1780 NFSEXITCODE2(error, nd);
1785 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1786 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1787 * The first argument is a pointer to an nfsv4lock structure.
1788 * The second argument is 1 iff a blocking lock is wanted.
1789 * If this argument is 0, the call waits until no thread either wants nor
1790 * holds an exclusive lock.
1791 * It returns 1 if the lock was acquired, 0 otherwise.
1792 * If several processes call this function concurrently wanting the exclusive
1793 * lock, one will get the lock and the rest will return without getting the
1794 * lock. (If the caller must have the lock, it simply calls this function in a
1795 * loop until the function returns 1 to indicate the lock was acquired.)
1796 * Any usecnt must be decremented by calling nfsv4_relref() before
1797 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1798 * be called in a loop.
1799 * The isleptp argument is set to indicate if the call slept, iff not NULL
1800 * and the mp argument indicates to check for a forced dismount, iff not
1804 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1805 void *mutex, struct mount *mp)
1811 * If a lock is wanted, loop around until the lock is acquired by
1812 * someone and then released. If I want the lock, try to acquire it.
1813 * For a lock to be issued, no lock must be in force and the usecnt
1817 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1818 lp->nfslock_usecnt == 0) {
1819 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1820 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1823 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1825 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1826 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1827 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1830 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1833 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1834 PZERO - 1, "nfsv4lck", NULL);
1835 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1836 lp->nfslock_usecnt == 0) {
1837 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1838 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1846 * Release the lock acquired by nfsv4_lock().
1847 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1848 * incremented, as well.
1851 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1854 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1856 lp->nfslock_usecnt++;
1861 * Release a reference cnt.
1864 nfsv4_relref(struct nfsv4lock *lp)
1867 if (lp->nfslock_usecnt <= 0)
1868 panic("nfsv4root ref cnt");
1869 lp->nfslock_usecnt--;
1870 if (lp->nfslock_usecnt == 0)
1875 * Get a reference cnt.
1876 * This function will wait for any exclusive lock to be released, but will
1877 * not wait for threads that want the exclusive lock. If priority needs
1878 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1879 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1880 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1881 * return without getting a refcnt for that case.
1884 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1892 * Wait for a lock held.
1894 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1895 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1897 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1900 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1901 PZERO - 1, "nfsv4gr", NULL);
1903 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1906 lp->nfslock_usecnt++;
1910 * Get a reference as above, but return failure instead of sleeping if
1911 * an exclusive lock is held.
1914 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1917 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1920 lp->nfslock_usecnt++;
1925 * Test for a lock. Return 1 if locked, 0 otherwise.
1928 nfsv4_testlock(struct nfsv4lock *lp)
1931 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1932 lp->nfslock_usecnt == 0)
1938 * Wake up anyone sleeping, waiting for this lock.
1941 nfsv4_wanted(struct nfsv4lock *lp)
1944 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1945 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1946 wakeup((caddr_t)&lp->nfslock_lock);
1951 * Copy a string from an mbuf list into a character array.
1952 * Return EBADRPC if there is an mbuf error,
1956 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1965 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1966 rem = NFSM_RNDUP(siz) - siz;
1972 NFSBCOPY(cp, str, xfer);
1981 cp = NFSMTOD(mp, caddr_t);
1993 error = nfsm_advance(nd, rem, len);
1999 NFSEXITCODE2(error, nd);
2004 * Fill in the attributes as marked by the bitmap (V4).
2007 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2008 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2009 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2010 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2012 int bitpos, retnum = 0;
2014 int siz, prefixnum, error;
2015 u_char *cp, namestr[NFSV4_SMALLSTR];
2016 nfsattrbit_t attrbits, retbits;
2017 nfsattrbit_t *retbitp = &retbits;
2018 u_int32_t freenum, *retnump;
2021 struct nfsfsinfo fsinf;
2022 struct timespec temptime;
2023 NFSACL_T *aclp, *naclp = NULL;
2030 * First, set the bits that can be filled and get fsinfo.
2032 NFSSET_ATTRBIT(retbitp, attrbitp);
2034 * If both p and cred are NULL, it is a client side setattr call.
2035 * If both p and cred are not NULL, it is a server side reply call.
2036 * If p is not NULL and cred is NULL, it is a client side callback
2039 if (p == NULL && cred == NULL) {
2040 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2043 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2044 naclp = acl_alloc(M_WAITOK);
2047 nfsvno_getfs(&fsinf, isdgram);
2050 * Get the VFS_STATFS(), since some attributes need them.
2052 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2053 error = VFS_STATFS(mp, &fs);
2056 nd->nd_repstat = NFSERR_ACCES;
2059 NFSCLRSTATFS_ATTRBIT(retbitp);
2065 * And the NFSv4 ACL...
2067 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2068 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2069 supports_nfsv4acls == 0))) {
2070 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2072 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2073 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2074 supports_nfsv4acls == 0)) {
2075 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2076 } else if (naclp != NULL) {
2077 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2078 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2080 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2082 NFSVOPUNLOCK(vp, 0);
2084 error = NFSERR_PERM;
2087 nd->nd_repstat = NFSERR_ACCES;
2090 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2095 * Put out the attribute bitmap for the ones being filled in
2096 * and get the field for the number of attributes returned.
2098 prefixnum = nfsrv_putattrbit(nd, retbitp);
2099 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2100 prefixnum += NFSX_UNSIGNED;
2103 * Now, loop around filling in the attributes for each bit set.
2105 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2106 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2108 case NFSATTRBIT_SUPPORTEDATTRS:
2109 NFSSETSUPP_ATTRBIT(&attrbits);
2110 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2111 && supports_nfsv4acls == 0)) {
2112 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2113 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2115 retnum += nfsrv_putattrbit(nd, &attrbits);
2117 case NFSATTRBIT_TYPE:
2118 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2119 *tl = vtonfsv34_type(vap->va_type);
2120 retnum += NFSX_UNSIGNED;
2122 case NFSATTRBIT_FHEXPIRETYPE:
2123 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2124 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2125 retnum += NFSX_UNSIGNED;
2127 case NFSATTRBIT_CHANGE:
2128 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2129 txdr_hyper(vap->va_filerev, tl);
2130 retnum += NFSX_HYPER;
2132 case NFSATTRBIT_SIZE:
2133 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2134 txdr_hyper(vap->va_size, tl);
2135 retnum += NFSX_HYPER;
2137 case NFSATTRBIT_LINKSUPPORT:
2138 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2139 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2143 retnum += NFSX_UNSIGNED;
2145 case NFSATTRBIT_SYMLINKSUPPORT:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2147 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2151 retnum += NFSX_UNSIGNED;
2153 case NFSATTRBIT_NAMEDATTR:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_FSID:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2161 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2163 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2164 retnum += NFSX_V4FSID;
2166 case NFSATTRBIT_UNIQUEHANDLES:
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2169 retnum += NFSX_UNSIGNED;
2171 case NFSATTRBIT_LEASETIME:
2172 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2173 *tl = txdr_unsigned(nfsrv_lease);
2174 retnum += NFSX_UNSIGNED;
2176 case NFSATTRBIT_RDATTRERROR:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 *tl = txdr_unsigned(rderror);
2179 retnum += NFSX_UNSIGNED;
2182 * Recommended Attributes. (Only the supported ones.)
2184 case NFSATTRBIT_ACL:
2185 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2187 case NFSATTRBIT_ACLSUPPORT:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2190 retnum += NFSX_UNSIGNED;
2192 case NFSATTRBIT_CANSETTIME:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2194 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2198 retnum += NFSX_UNSIGNED;
2200 case NFSATTRBIT_CASEINSENSITIVE:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2203 retnum += NFSX_UNSIGNED;
2205 case NFSATTRBIT_CASEPRESERVING:
2206 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2208 retnum += NFSX_UNSIGNED;
2210 case NFSATTRBIT_CHOWNRESTRICTED:
2211 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2213 retnum += NFSX_UNSIGNED;
2215 case NFSATTRBIT_FILEHANDLE:
2216 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2218 case NFSATTRBIT_FILEID:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2221 *tl = txdr_unsigned(vap->va_fileid);
2222 retnum += NFSX_HYPER;
2224 case NFSATTRBIT_FILESAVAIL:
2226 * Check quota and use min(quota, f_ffree).
2228 freenum = fs.f_ffree;
2231 * ufs_quotactl() insists that the uid argument
2232 * equal p_ruid for non-root quota access, so
2233 * we'll just make sure that's the case.
2235 savuid = p->p_cred->p_ruid;
2236 p->p_cred->p_ruid = cred->cr_uid;
2237 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2238 cred->cr_uid, (caddr_t)&dqb))
2239 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2241 p->p_cred->p_ruid = savuid;
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2245 *tl = txdr_unsigned(freenum);
2246 retnum += NFSX_HYPER;
2248 case NFSATTRBIT_FILESFREE:
2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2251 *tl = txdr_unsigned(fs.f_ffree);
2252 retnum += NFSX_HYPER;
2254 case NFSATTRBIT_FILESTOTAL:
2255 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2257 *tl = txdr_unsigned(fs.f_files);
2258 retnum += NFSX_HYPER;
2260 case NFSATTRBIT_FSLOCATIONS:
2261 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2264 retnum += 2 * NFSX_UNSIGNED;
2266 case NFSATTRBIT_HOMOGENEOUS:
2267 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2268 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2272 retnum += NFSX_UNSIGNED;
2274 case NFSATTRBIT_MAXFILESIZE:
2275 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2276 uquad = NFSRV_MAXFILESIZE;
2277 txdr_hyper(uquad, tl);
2278 retnum += NFSX_HYPER;
2280 case NFSATTRBIT_MAXLINK:
2281 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2282 *tl = txdr_unsigned(LINK_MAX);
2283 retnum += NFSX_UNSIGNED;
2285 case NFSATTRBIT_MAXNAME:
2286 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2287 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2288 retnum += NFSX_UNSIGNED;
2290 case NFSATTRBIT_MAXREAD:
2291 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2293 *tl = txdr_unsigned(fsinf.fs_rtmax);
2294 retnum += NFSX_HYPER;
2296 case NFSATTRBIT_MAXWRITE:
2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2299 *tl = txdr_unsigned(fsinf.fs_wtmax);
2300 retnum += NFSX_HYPER;
2302 case NFSATTRBIT_MODE:
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2304 *tl = vtonfsv34_mode(vap->va_mode);
2305 retnum += NFSX_UNSIGNED;
2307 case NFSATTRBIT_NOTRUNC:
2308 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2310 retnum += NFSX_UNSIGNED;
2312 case NFSATTRBIT_NUMLINKS:
2313 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2314 *tl = txdr_unsigned(vap->va_nlink);
2315 retnum += NFSX_UNSIGNED;
2317 case NFSATTRBIT_OWNER:
2319 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2320 retnum += nfsm_strtom(nd, cp, siz);
2322 free(cp, M_NFSSTRING);
2324 case NFSATTRBIT_OWNERGROUP:
2326 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2327 retnum += nfsm_strtom(nd, cp, siz);
2329 free(cp, M_NFSSTRING);
2331 case NFSATTRBIT_QUOTAHARD:
2332 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2333 freenum = fs.f_bfree;
2335 freenum = fs.f_bavail;
2338 * ufs_quotactl() insists that the uid argument
2339 * equal p_ruid for non-root quota access, so
2340 * we'll just make sure that's the case.
2342 savuid = p->p_cred->p_ruid;
2343 p->p_cred->p_ruid = cred->cr_uid;
2344 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2345 cred->cr_uid, (caddr_t)&dqb))
2346 freenum = min(dqb.dqb_bhardlimit, freenum);
2347 p->p_cred->p_ruid = savuid;
2349 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2350 uquad = (u_int64_t)freenum;
2351 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2352 txdr_hyper(uquad, tl);
2353 retnum += NFSX_HYPER;
2355 case NFSATTRBIT_QUOTASOFT:
2356 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2357 freenum = fs.f_bfree;
2359 freenum = fs.f_bavail;
2362 * ufs_quotactl() insists that the uid argument
2363 * equal p_ruid for non-root quota access, so
2364 * we'll just make sure that's the case.
2366 savuid = p->p_cred->p_ruid;
2367 p->p_cred->p_ruid = cred->cr_uid;
2368 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2369 cred->cr_uid, (caddr_t)&dqb))
2370 freenum = min(dqb.dqb_bsoftlimit, freenum);
2371 p->p_cred->p_ruid = savuid;
2373 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2374 uquad = (u_int64_t)freenum;
2375 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2376 txdr_hyper(uquad, tl);
2377 retnum += NFSX_HYPER;
2379 case NFSATTRBIT_QUOTAUSED:
2383 * ufs_quotactl() insists that the uid argument
2384 * equal p_ruid for non-root quota access, so
2385 * we'll just make sure that's the case.
2387 savuid = p->p_cred->p_ruid;
2388 p->p_cred->p_ruid = cred->cr_uid;
2389 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2390 cred->cr_uid, (caddr_t)&dqb))
2391 freenum = dqb.dqb_curblocks;
2392 p->p_cred->p_ruid = savuid;
2394 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2395 uquad = (u_int64_t)freenum;
2396 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2397 txdr_hyper(uquad, tl);
2398 retnum += NFSX_HYPER;
2400 case NFSATTRBIT_RAWDEV:
2401 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2402 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2403 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2404 retnum += NFSX_V4SPECDATA;
2406 case NFSATTRBIT_SPACEAVAIL:
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2408 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2409 uquad = (u_int64_t)fs.f_bfree;
2411 uquad = (u_int64_t)fs.f_bavail;
2412 uquad *= fs.f_bsize;
2413 txdr_hyper(uquad, tl);
2414 retnum += NFSX_HYPER;
2416 case NFSATTRBIT_SPACEFREE:
2417 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2418 uquad = (u_int64_t)fs.f_bfree;
2419 uquad *= fs.f_bsize;
2420 txdr_hyper(uquad, tl);
2421 retnum += NFSX_HYPER;
2423 case NFSATTRBIT_SPACETOTAL:
2424 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2425 uquad = (u_int64_t)fs.f_blocks;
2426 uquad *= fs.f_bsize;
2427 txdr_hyper(uquad, tl);
2428 retnum += NFSX_HYPER;
2430 case NFSATTRBIT_SPACEUSED:
2431 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2432 txdr_hyper(vap->va_bytes, tl);
2433 retnum += NFSX_HYPER;
2435 case NFSATTRBIT_TIMEACCESS:
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2437 txdr_nfsv4time(&vap->va_atime, tl);
2438 retnum += NFSX_V4TIME;
2440 case NFSATTRBIT_TIMEACCESSSET:
2441 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2442 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2443 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2444 txdr_nfsv4time(&vap->va_atime, tl);
2445 retnum += NFSX_V4SETTIME;
2447 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2448 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2449 retnum += NFSX_UNSIGNED;
2452 case NFSATTRBIT_TIMEDELTA:
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2454 temptime.tv_sec = 0;
2455 temptime.tv_nsec = 1000000000 / hz;
2456 txdr_nfsv4time(&temptime, tl);
2457 retnum += NFSX_V4TIME;
2459 case NFSATTRBIT_TIMEMETADATA:
2460 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2461 txdr_nfsv4time(&vap->va_ctime, tl);
2462 retnum += NFSX_V4TIME;
2464 case NFSATTRBIT_TIMEMODIFY:
2465 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2466 txdr_nfsv4time(&vap->va_mtime, tl);
2467 retnum += NFSX_V4TIME;
2469 case NFSATTRBIT_TIMEMODIFYSET:
2470 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2471 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2472 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2473 txdr_nfsv4time(&vap->va_mtime, tl);
2474 retnum += NFSX_V4SETTIME;
2476 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2477 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2478 retnum += NFSX_UNSIGNED;
2481 case NFSATTRBIT_MOUNTEDONFILEID:
2482 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2484 uquad = mounted_on_fileno;
2486 uquad = (u_int64_t)vap->va_fileid;
2487 txdr_hyper(uquad, tl);
2488 retnum += NFSX_HYPER;
2490 case NFSATTRBIT_SUPPATTREXCLCREAT:
2491 NFSSETSUPP_ATTRBIT(&attrbits);
2492 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2493 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2494 retnum += nfsrv_putattrbit(nd, &attrbits);
2497 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2503 *retnump = txdr_unsigned(retnum);
2504 return (retnum + prefixnum);
2508 * Put the attribute bits onto an mbuf list.
2509 * Return the number of bytes of output generated.
2512 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2515 int cnt, i, bytesize;
2517 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2518 if (attrbitp->bits[cnt - 1])
2520 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2521 NFSM_BUILD(tl, u_int32_t *, bytesize);
2522 *tl++ = txdr_unsigned(cnt);
2523 for (i = 0; i < cnt; i++)
2524 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2529 * Convert a uid to a string.
2530 * If the lookup fails, just output the digits.
2532 * cpp - points to a buffer of size NFSV4_SMALLSTR
2533 * (malloc a larger one, as required)
2534 * retlenp - pointer to length to be returned
2537 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2540 struct nfsusrgrp *usrp;
2543 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2548 if (nfsrv_dnsname) {
2550 * Always map nfsrv_defaultuid to "nobody".
2552 if (uid == nfsrv_defaultuid) {
2553 i = nfsrv_dnsnamelen + 7;
2556 if (len > NFSV4_SMALLSTR)
2557 free(cp, M_NFSSTRING);
2558 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2564 NFSBCOPY("nobody@", cp, 7);
2566 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2571 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2572 if (usrp->lug_uid == uid) {
2573 if (usrp->lug_expiry < NFSD_MONOSEC)
2576 * If the name doesn't already have an '@'
2577 * in it, append @domainname to it.
2579 for (i = 0; i < usrp->lug_namelen; i++) {
2580 if (usrp->lug_name[i] == '@') {
2586 i = usrp->lug_namelen;
2588 i = usrp->lug_namelen +
2589 nfsrv_dnsnamelen + 1;
2592 if (len > NFSV4_SMALLSTR)
2593 free(cp, M_NFSSTRING);
2594 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2600 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2601 if (!hasampersand) {
2602 cp += usrp->lug_namelen;
2604 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2606 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2607 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2614 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2616 if (ret == 0 && cnt < 2)
2623 * No match, just return a string of digits.
2627 while (tmp || i == 0) {
2631 len = (i > len) ? len : i;
2635 for (i = 0; i < len; i++) {
2636 *cp-- = '0' + (tmp % 10);
2643 * Convert a string to a uid.
2644 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2646 * If this is called from a client side mount using AUTH_SYS and the
2647 * string is made up entirely of digits, just convert the string to
2651 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2655 char *cp, *endstr, *str0;
2656 struct nfsusrgrp *usrp;
2662 error = NFSERR_BADOWNER;
2665 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2667 tuid = (uid_t)strtoul(str0, &endstr, 10);
2668 if ((endstr - str0) == len) {
2669 /* A numeric string. */
2670 if ((nd->nd_flag & ND_KERBV) == 0 &&
2671 ((nd->nd_flag & ND_NFSCL) != 0 ||
2672 nfsd_enable_stringtouid != 0))
2675 error = NFSERR_BADOWNER;
2681 cp = strchr(str0, '@');
2683 i = (int)(cp++ - str0);
2691 * If an '@' is found and the domain name matches, search for the name
2692 * with dns stripped off.
2693 * Mixed case alpahbetics will match for the domain name, but all
2694 * upper case will not.
2696 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2697 (len - 1 - i) == nfsrv_dnsnamelen &&
2698 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2699 len -= (nfsrv_dnsnamelen + 1);
2704 * Check for the special case of "nobody".
2706 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2707 *uidp = nfsrv_defaultuid;
2713 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2714 if (usrp->lug_namelen == len &&
2715 !NFSBCMP(usrp->lug_name, str, len)) {
2716 if (usrp->lug_expiry < NFSD_MONOSEC)
2718 *uidp = usrp->lug_uid;
2719 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2720 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2728 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2730 if (ret == 0 && cnt < 2)
2732 error = NFSERR_BADOWNER;
2740 * Convert a gid to a string.
2741 * gid - the group id
2742 * cpp - points to a buffer of size NFSV4_SMALLSTR
2743 * (malloc a larger one, as required)
2744 * retlenp - pointer to length to be returned
2747 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2750 struct nfsusrgrp *usrp;
2753 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2758 if (nfsrv_dnsname) {
2760 * Always map nfsrv_defaultgid to "nogroup".
2762 if (gid == nfsrv_defaultgid) {
2763 i = nfsrv_dnsnamelen + 8;
2766 if (len > NFSV4_SMALLSTR)
2767 free(cp, M_NFSSTRING);
2768 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2774 NFSBCOPY("nogroup@", cp, 8);
2776 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2781 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2782 if (usrp->lug_gid == gid) {
2783 if (usrp->lug_expiry < NFSD_MONOSEC)
2786 * If the name doesn't already have an '@'
2787 * in it, append @domainname to it.
2789 for (i = 0; i < usrp->lug_namelen; i++) {
2790 if (usrp->lug_name[i] == '@') {
2796 i = usrp->lug_namelen;
2798 i = usrp->lug_namelen +
2799 nfsrv_dnsnamelen + 1;
2802 if (len > NFSV4_SMALLSTR)
2803 free(cp, M_NFSSTRING);
2804 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2810 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2811 if (!hasampersand) {
2812 cp += usrp->lug_namelen;
2814 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2816 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2817 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2824 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2826 if (ret == 0 && cnt < 2)
2833 * No match, just return a string of digits.
2837 while (tmp || i == 0) {
2841 len = (i > len) ? len : i;
2845 for (i = 0; i < len; i++) {
2846 *cp-- = '0' + (tmp % 10);
2853 * Convert a string to a gid.
2854 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2856 * If this is called from a client side mount using AUTH_SYS and the
2857 * string is made up entirely of digits, just convert the string to
2861 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2865 char *cp, *endstr, *str0;
2866 struct nfsusrgrp *usrp;
2872 error = NFSERR_BADOWNER;
2875 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2877 tgid = (gid_t)strtoul(str0, &endstr, 10);
2878 if ((endstr - str0) == len) {
2879 /* A numeric string. */
2880 if ((nd->nd_flag & ND_KERBV) == 0 &&
2881 ((nd->nd_flag & ND_NFSCL) != 0 ||
2882 nfsd_enable_stringtouid != 0))
2885 error = NFSERR_BADOWNER;
2891 cp = strchr(str0, '@');
2893 i = (int)(cp++ - str0);
2901 * If an '@' is found and the dns name matches, search for the name
2902 * with the dns stripped off.
2904 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2905 (len - 1 - i) == nfsrv_dnsnamelen &&
2906 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2907 len -= (nfsrv_dnsnamelen + 1);
2912 * Check for the special case of "nogroup".
2914 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2915 *gidp = nfsrv_defaultgid;
2921 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2922 if (usrp->lug_namelen == len &&
2923 !NFSBCMP(usrp->lug_name, str, len)) {
2924 if (usrp->lug_expiry < NFSD_MONOSEC)
2926 *gidp = usrp->lug_gid;
2927 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2928 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2936 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2938 if (ret == 0 && cnt < 2)
2940 error = NFSERR_BADOWNER;
2948 * Cmp len chars, allowing mixed case in the first argument to match lower
2949 * case in the second, but not if the first argument is all upper case.
2950 * Return 0 for a match, 1 otherwise.
2953 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2959 for (i = 0; i < len; i++) {
2960 if (*cp >= 'A' && *cp <= 'Z') {
2961 tmp = *cp++ + ('a' - 'A');
2964 if (tmp >= 'a' && tmp <= 'z')
2977 * Set the port for the nfsuserd.
2980 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2982 struct nfssockreq *rp;
2983 struct sockaddr_in *ad;
2987 if (nfsrv_nfsuserd) {
2995 * Set up the socket record and connect.
2997 rp = &nfsrv_nfsuserdsock;
2998 rp->nr_client = NULL;
2999 rp->nr_sotype = SOCK_DGRAM;
3000 rp->nr_soproto = IPPROTO_UDP;
3001 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3003 NFSSOCKADDRALLOC(rp->nr_nam);
3004 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3005 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3006 ad->sin_family = AF_INET;
3007 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3008 ad->sin_port = port;
3009 rp->nr_prog = RPCPROG_NFSUSERD;
3010 rp->nr_vers = RPCNFSUSERD_VERS;
3011 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3013 NFSSOCKADDRFREE(rp->nr_nam);
3022 * Delete the nfsuserd port.
3025 nfsrv_nfsuserddelport(void)
3029 if (nfsrv_nfsuserd == 0) {
3035 newnfs_disconnect(&nfsrv_nfsuserdsock);
3036 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3040 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3042 * Returns 0 upon success, non-zero otherwise.
3045 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3048 struct nfsrv_descript *nd;
3050 struct nfsrv_descript nfsd;
3055 if (nfsrv_nfsuserd == 0) {
3062 cred = newnfs_getcred();
3063 nd->nd_flag = ND_GSSINITREPLY;
3066 nd->nd_procnum = procnum;
3067 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3068 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3069 if (procnum == RPCNFSUSERD_GETUID)
3070 *tl = txdr_unsigned(uid);
3072 *tl = txdr_unsigned(gid);
3075 (void) nfsm_strtom(nd, name, len);
3077 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3078 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3081 mbuf_freem(nd->nd_mrep);
3082 error = nd->nd_repstat;
3090 * This function is called from the nfssvc(2) system call, to update the
3091 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3094 nfssvc_idname(struct nfsd_idargs *nidp)
3096 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3097 struct nfsuserhashhead *hp;
3102 if (nidp->nid_flag & NFSID_INITIALIZE) {
3103 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3104 M_NFSSTRING, M_WAITOK);
3105 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3108 if (nfsrv_dnsname) {
3110 * Free up all the old stuff and reinitialize hash lists.
3112 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3113 nfsrv_removeuser(usrp);
3115 free(nfsrv_dnsname, M_NFSSTRING);
3116 nfsrv_dnsname = NULL;
3118 TAILQ_INIT(&nfsuserlruhead);
3119 for (i = 0; i < NFSUSERHASHSIZE; i++)
3120 LIST_INIT(&nfsuserhash[i]);
3121 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3122 LIST_INIT(&nfsgrouphash[i]);
3123 for (i = 0; i < NFSUSERHASHSIZE; i++)
3124 LIST_INIT(&nfsusernamehash[i]);
3125 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3126 LIST_INIT(&nfsgroupnamehash[i]);
3129 * Put name in "DNS" string.
3133 nfsrv_dnsnamelen = nidp->nid_namelen;
3134 nfsrv_defaultuid = nidp->nid_uid;
3135 nfsrv_defaultgid = nidp->nid_gid;
3137 nfsrv_usermax = nidp->nid_usermax;
3141 free(cp, M_NFSSTRING);
3146 * malloc the new one now, so any potential sleep occurs before
3147 * manipulation of the lists.
3149 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3150 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3151 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3154 free((caddr_t)newusrp, M_NFSUSERGROUP);
3157 newusrp->lug_namelen = nidp->nid_namelen;
3161 * Delete old entries, as required.
3163 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3164 hp = NFSUSERHASH(nidp->nid_uid);
3165 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3166 if (usrp->lug_uid == nidp->nid_uid)
3167 nfsrv_removeuser(usrp);
3170 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3171 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3172 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3173 if (usrp->lug_namelen == newusrp->lug_namelen &&
3174 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3176 nfsrv_removeuser(usrp);
3179 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3180 hp = NFSGROUPHASH(nidp->nid_gid);
3181 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3182 if (usrp->lug_gid == nidp->nid_gid)
3183 nfsrv_removeuser(usrp);
3186 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3187 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3188 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3189 if (usrp->lug_namelen == newusrp->lug_namelen &&
3190 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3192 nfsrv_removeuser(usrp);
3195 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3196 if (usrp->lug_expiry < NFSD_MONOSEC)
3197 nfsrv_removeuser(usrp);
3199 while (nfsrv_usercnt >= nfsrv_usermax) {
3200 usrp = TAILQ_FIRST(&nfsuserlruhead);
3201 nfsrv_removeuser(usrp);
3205 * Now, we can add the new one.
3207 if (nidp->nid_usertimeout)
3208 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3210 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3211 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3212 newusrp->lug_uid = nidp->nid_uid;
3213 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3215 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3216 newusrp->lug_namelen), newusrp, lug_namehash);
3217 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3219 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3220 newusrp->lug_gid = nidp->nid_gid;
3221 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3223 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3224 newusrp->lug_namelen), newusrp, lug_namehash);
3225 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3228 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3236 * Remove a user/group name element.
3239 nfsrv_removeuser(struct nfsusrgrp *usrp)
3242 NFSNAMEIDREQUIRED();
3243 LIST_REMOVE(usrp, lug_numhash);
3244 LIST_REMOVE(usrp, lug_namehash);
3245 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3247 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3251 * This function scans a byte string and checks for UTF-8 compliance.
3252 * It returns 0 if it conforms and NFSERR_INVAL if not.
3255 nfsrv_checkutf8(u_int8_t *cp, int len)
3257 u_int32_t val = 0x0;
3258 int cnt = 0, gotd = 0, shift = 0;
3260 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3264 * Here are what the variables are used for:
3265 * val - the calculated value of a multibyte char, used to check
3266 * that it was coded with the correct range
3267 * cnt - the number of 10xxxxxx bytes to follow
3268 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3269 * shift - lower order bits of range (ie. "val >> shift" should
3270 * not be 0, in other words, dividing by the lower bound
3271 * of the range should get a non-zero value)
3272 * byte - used to calculate cnt
3276 /* This handles the 10xxxxxx bytes */
3277 if ((*cp & 0xc0) != 0x80 ||
3278 (gotd && (*cp & 0x20))) {
3279 error = NFSERR_INVAL;
3284 val |= (*cp & 0x3f);
3286 if (cnt == 0 && (val >> shift) == 0x0) {
3287 error = NFSERR_INVAL;
3290 } else if (*cp & 0x80) {
3291 /* first byte of multi byte char */
3293 while ((byte & 0x40) && cnt < 6) {
3297 if (cnt == 0 || cnt == 6) {
3298 error = NFSERR_INVAL;
3301 val = (*cp & (0x3f >> cnt));
3302 shift = utf8_shift[cnt - 1];
3303 if (cnt == 2 && val == 0xd)
3304 /* Check for the 0xd800-0xdfff case */
3311 error = NFSERR_INVAL;
3319 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3320 * strings, one with the root path in it and the other with the list of
3321 * locations. The list is in the same format as is found in nfr_refs.
3322 * It is a "," separated list of entries, where each of them is of the
3323 * form <server>:<rootpath>. For example
3324 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3325 * The nilp argument is set to 1 for the special case of a null fs_root
3326 * and an empty server list.
3327 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3328 * number of xdr bytes parsed in sump.
3331 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3332 int *sump, int *nilp)
3335 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3336 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3338 SLIST_ENTRY(list) next;
3342 SLIST_HEAD(, list) head;
3349 * Get the fs_root path and check for the special case of null path
3350 * and 0 length server list.
3352 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3353 len = fxdr_unsigned(int, *tl);
3354 if (len < 0 || len > 10240) {
3355 error = NFSERR_BADXDR;
3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3361 error = NFSERR_BADXDR;
3365 *sump = 2 * NFSX_UNSIGNED;
3369 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3370 error = nfsrv_mtostr(nd, cp, len);
3372 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3373 cnt = fxdr_unsigned(int, *tl);
3375 error = NFSERR_BADXDR;
3381 * Now, loop through the location list and make up the srvlist.
3383 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3384 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3387 for (i = 0; i < cnt; i++) {
3389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3390 nsrv = fxdr_unsigned(int, *tl);
3392 error = NFSERR_BADXDR;
3397 * Handle the first server by putting it in the srvstr.
3399 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3400 len = fxdr_unsigned(int, *tl);
3401 if (len <= 0 || len > 1024) {
3402 error = NFSERR_BADXDR;
3405 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3410 error = nfsrv_mtostr(nd, cp3, len);
3416 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3417 for (j = 1; j < nsrv; j++) {
3419 * Yuck, put them in an slist and process them later.
3421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3422 len = fxdr_unsigned(int, *tl);
3423 if (len <= 0 || len > 1024) {
3424 error = NFSERR_BADXDR;
3427 lsp = (struct list *)malloc(sizeof (struct list)
3428 + len, M_TEMP, M_WAITOK);
3429 error = nfsrv_mtostr(nd, lsp->host, len);
3432 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3434 SLIST_INSERT_HEAD(&head, lsp, next);
3438 * Finally, we can get the path.
3440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3441 len = fxdr_unsigned(int, *tl);
3442 if (len <= 0 || len > 1024) {
3443 error = NFSERR_BADXDR;
3446 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3447 error = nfsrv_mtostr(nd, cp3, len);
3450 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3455 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3456 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3459 NFSBCOPY(lsp->host, cp3, lsp->len);
3462 NFSBCOPY(str, cp3, stringlen);
3465 siz += (lsp->len + stringlen + 2);
3466 free((caddr_t)lsp, M_TEMP);
3472 NFSEXITCODE2(0, nd);
3476 free(cp, M_NFSSTRING);
3478 free(cp2, M_NFSSTRING);
3479 NFSEXITCODE2(error, nd);
3484 * Make the malloc'd space large enough. This is a pain, but the xdr
3485 * doesn't set an upper bound on the side, so...
3488 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3495 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3496 NFSBCOPY(*cpp, cp, *slenp);
3497 free(*cpp, M_NFSSTRING);
3501 *slenp = siz + 1024;
3505 * Initialize the reply header data structures.
3508 nfsrvd_rephead(struct nfsrv_descript *nd)
3513 * If this is a big reply, use a cluster.
3515 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3516 nfs_bigreply[nd->nd_procnum]) {
3517 NFSMCLGET(mreq, M_WAITOK);
3525 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3526 mbuf_setlen(mreq, 0);
3528 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3529 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3533 * Lock a socket against others.
3534 * Currently used to serialize connect/disconnect attempts.
3537 newnfs_sndlock(int *flagp)
3542 while (*flagp & NFSR_SNDLOCK) {
3543 *flagp |= NFSR_WANTSND;
3546 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3547 PZERO - 1, "nfsndlck", &ts);
3549 *flagp |= NFSR_SNDLOCK;
3555 * Unlock the stream socket for others.
3558 newnfs_sndunlock(int *flagp)
3562 if ((*flagp & NFSR_SNDLOCK) == 0)
3563 panic("nfs sndunlock");
3564 *flagp &= ~NFSR_SNDLOCK;
3565 if (*flagp & NFSR_WANTSND) {
3566 *flagp &= ~NFSR_WANTSND;
3567 wakeup((caddr_t)flagp);
3573 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3576 struct sockaddr_in *sad;
3577 struct sockaddr_in6 *sad6;
3578 struct in_addr saddr;
3579 uint32_t portnum, *tl;
3580 int af = 0, i, j, k;
3581 char addr[64], protocol[5], *cp;
3582 int cantparse = 0, error = 0;
3585 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3586 i = fxdr_unsigned(int, *tl);
3587 if (i >= 3 && i <= 4) {
3588 error = nfsrv_mtostr(nd, protocol, i);
3591 if (strcmp(protocol, "tcp") == 0) {
3594 } else if (strcmp(protocol, "udp") == 0) {
3597 } else if (strcmp(protocol, "tcp6") == 0) {
3600 } else if (strcmp(protocol, "udp6") == 0) {
3608 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3613 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3614 i = fxdr_unsigned(int, *tl);
3616 error = NFSERR_BADXDR;
3618 } else if (cantparse == 0 && i >= 11 && i < 64) {
3620 * The shortest address is 11chars and the longest is < 64.
3622 error = nfsrv_mtostr(nd, addr, i);
3626 /* Find the port# at the end and extract that. */
3630 /* Count back two '.'s from end to get port# field. */
3631 for (j = 0; j < i; j++) {
3641 * The NFSv4 port# is appended as .N.N, where N is
3642 * a decimal # in the range 0-255, just like an inet4
3643 * address. Cheat and use inet_aton(), which will
3644 * return a Class A address and then shift the high
3645 * order 8bits over to convert it to the port#.
3648 if (inet_aton(cp, &saddr) == 1) {
3649 portnum = ntohl(saddr.s_addr);
3650 portv = (uint16_t)((portnum >> 16) |
3656 if (cantparse == 0) {
3657 if (af == AF_INET) {
3658 sad = (struct sockaddr_in *)sa;
3659 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3660 sad->sin_len = sizeof(*sad);
3661 sad->sin_family = AF_INET;
3662 sad->sin_port = htons(portv);
3666 sad6 = (struct sockaddr_in6 *)sa;
3667 if (inet_pton(af, addr, &sad6->sin6_addr)
3669 sad6->sin6_len = sizeof(*sad6);
3670 sad6->sin6_family = AF_INET6;
3671 sad6->sin6_port = htons(portv);
3678 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3689 * Handle an NFSv4.1 Sequence request for the session.
3690 * If reply != NULL, use it to return the cached reply, as required.
3691 * The client gets a cached reply via this call for callbacks, however the
3692 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
3695 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3696 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3703 if (slotid > maxslot)
3704 return (NFSERR_BADSLOT);
3705 if (seqid == slots[slotid].nfssl_seq) {
3707 if (slots[slotid].nfssl_inprog != 0)
3708 error = NFSERR_DELAY;
3709 else if (slots[slotid].nfssl_reply != NULL) {
3710 if (reply != NULL) {
3711 *reply = slots[slotid].nfssl_reply;
3712 slots[slotid].nfssl_reply = NULL;
3714 slots[slotid].nfssl_inprog = 1;
3715 error = NFSERR_REPLYFROMCACHE;
3717 /* No reply cached, so just do it. */
3718 slots[slotid].nfssl_inprog = 1;
3719 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3720 if (slots[slotid].nfssl_reply != NULL)
3721 m_freem(slots[slotid].nfssl_reply);
3722 slots[slotid].nfssl_reply = NULL;
3723 slots[slotid].nfssl_inprog = 1;
3724 slots[slotid].nfssl_seq++;
3726 error = NFSERR_SEQMISORDERED;
3731 * Cache this reply for the slot.
3732 * Use the "rep" argument to return the cached reply if repstat is set to
3733 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
3736 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
3740 if (repstat == NFSERR_REPLYFROMCACHE) {
3741 *rep = slots[slotid].nfssl_reply;
3742 slots[slotid].nfssl_reply = NULL;
3744 if (slots[slotid].nfssl_reply != NULL)
3745 m_freem(slots[slotid].nfssl_reply);
3746 slots[slotid].nfssl_reply = *rep;
3748 slots[slotid].nfssl_inprog = 0;
3752 * Generate the xdr for an NFSv4.1 Sequence Operation.
3755 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
3756 struct nfsclsession *sep, int dont_replycache)
3758 uint32_t *tl, slotseq = 0;
3759 int error, maxslot, slotpos;
3760 uint8_t sessionid[NFSX_V4SESSIONID];
3762 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
3766 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3768 /* Build the Sequence arguments. */
3769 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3770 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3771 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3772 nd->nd_slotseq = tl;
3773 *tl++ = txdr_unsigned(slotseq);
3774 *tl++ = txdr_unsigned(slotpos);
3775 *tl++ = txdr_unsigned(maxslot);
3776 if (dont_replycache == 0)
3780 nd->nd_flag |= ND_HASSEQUENCE;
3784 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
3785 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
3787 int i, maxslot, slotpos;
3790 /* Find an unused slot. */
3793 mtx_lock(&sep->nfsess_mtx);
3796 for (i = 0; i < sep->nfsess_foreslots; i++) {
3797 if ((bitval & sep->nfsess_slots) == 0) {
3799 sep->nfsess_slots |= bitval;
3800 sep->nfsess_slotseq[i]++;
3801 *slotseqp = sep->nfsess_slotseq[i];
3806 if (slotpos == -1) {
3808 * If a forced dismount is in progress, just return.
3809 * This RPC attempt will fail when it calls
3813 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
3815 mtx_unlock(&sep->nfsess_mtx);
3818 /* Wake up once/sec, to check for a forced dismount. */
3819 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3820 PZERO, "nfsclseq", hz);
3822 } while (slotpos == -1);
3823 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3825 for (i = 0; i < 64; i++) {
3826 if ((bitval & sep->nfsess_slots) != 0)
3830 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3831 mtx_unlock(&sep->nfsess_mtx);
3832 *slotposp = slotpos;
3833 *maxslotp = maxslot;
3838 * Free a session slot.
3841 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3848 mtx_lock(&sep->nfsess_mtx);
3849 if ((bitval & sep->nfsess_slots) == 0)
3850 printf("freeing free slot!!\n");
3851 sep->nfsess_slots &= ~bitval;
3852 wakeup(&sep->nfsess_slots);
3853 mtx_unlock(&sep->nfsess_mtx);