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>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid;
67 gid_t nfsrv_defaultgid;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 int nfsd_enable_stringtouid = 0;
73 extern int nfsrv_lughashsize;
76 * This array of structures indicates, for V4:
77 * retfh - which of 3 types of calling args are used
78 * 0 - doesn't change cfh or use a sfh
79 * 1 - replaces cfh with a new one (unless it returns an error status)
80 * 2 - uses cfh and sfh
81 * needscfh - if the op wants a cfh and premtime
82 * 0 - doesn't use a cfh
83 * 1 - uses a cfh, but doesn't want pre-op attributes
84 * 2 - uses a cfh and wants pre-op attributes
85 * savereply - indicates a non-idempotent Op
86 * 0 - not non-idempotent
88 * Ops that are ordered via seqid# are handled separately from these
90 * Define it here, since it is used by both the client and server.
92 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
93 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
94 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
95 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
96 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
98 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
99 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
102 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
104 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
108 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
109 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
111 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
112 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
116 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
117 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
118 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
119 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
120 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
121 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
131 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
153 #endif /* !APPLEKEXT */
155 static int ncl_mbuf_mhlen = MHLEN;
156 static int nfsrv_usercnt = 0;
157 static int nfsrv_dnsnamelen;
158 static u_char *nfsrv_dnsname = NULL;
159 static int nfsrv_usermax = 999999999;
160 struct nfsrv_lughash {
162 struct nfsuserhashhead lughead;
164 static struct nfsrv_lughash *nfsuserhash;
165 static struct nfsrv_lughash *nfsusernamehash;
166 static struct nfsrv_lughash *nfsgrouphash;
167 static struct nfsrv_lughash *nfsgroupnamehash;
170 * This static array indicates whether or not the RPC generates a large
171 * reply. This is used by nfs_reply() to decide whether or not an mbuf
172 * cluster should be allocated. (If a cluster is required by an RPC
173 * marked 0 in this array, the code will still work, just not quite as
176 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
177 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,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
180 /* local functions */
181 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
182 static void nfsv4_wanted(struct nfsv4lock *lp);
183 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
184 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
186 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
187 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
189 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
194 * copies mbuf chain to the uio scatter/gather list
197 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
199 char *mbufcp, *uiocp;
206 mbufcp = nd->nd_dpos;
207 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
208 rem = NFSM_RNDUP(siz) - siz;
210 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
214 left = uiop->uio_iov->iov_len;
215 uiocp = uiop->uio_iov->iov_base;
226 mbufcp = NFSMTOD(mp, caddr_t);
229 ("len %d, corrupted mbuf?", len));
231 xfer = (left > len) ? len : left;
234 if (uiop->uio_iov->iov_op != NULL)
235 (*(uiop->uio_iov->iov_op))
236 (mbufcp, uiocp, xfer);
239 if (uiop->uio_segflg == UIO_SYSSPACE)
240 NFSBCOPY(mbufcp, uiocp, xfer);
242 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
247 uiop->uio_offset += xfer;
248 uiop->uio_resid -= xfer;
250 if (uiop->uio_iov->iov_len <= siz) {
254 uiop->uio_iov->iov_base = (void *)
255 ((char *)uiop->uio_iov->iov_base + uiosiz);
256 uiop->uio_iov->iov_len -= uiosiz;
260 nd->nd_dpos = mbufcp;
264 error = nfsm_advance(nd, rem, len);
270 NFSEXITCODE2(error, nd);
276 * Help break down an mbuf chain by setting the first siz bytes contiguous
277 * pointed to by returned val.
278 * This is used by the macro NFSM_DISSECT for tough
282 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
291 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
293 nd->nd_md = mbuf_next(nd->nd_md);
294 if (nd->nd_md == NULL)
296 left = mbuf_len(nd->nd_md);
297 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
302 } else if (mbuf_next(nd->nd_md) == NULL) {
304 } else if (siz > ncl_mbuf_mhlen) {
305 panic("nfs S too big");
307 MGET(mp2, MT_DATA, how);
310 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
311 mbuf_setnext(nd->nd_md, mp2);
312 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
314 retp = p = NFSMTOD(mp2, caddr_t);
315 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
318 mp2 = mbuf_next(mp2);
319 /* Loop around copying up the siz2 bytes */
323 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
325 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
326 NFSM_DATAP(mp2, xfer);
327 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
332 mp2 = mbuf_next(mp2);
334 mbuf_setlen(nd->nd_md, siz);
336 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
342 * Advance the position in the mbuf chain.
343 * If offs == 0, this is a no-op, but it is simpler to just return from
344 * here than check for offs > 0 for all calls to nfsm_advance.
345 * If left == -1, it should be calculated here.
348 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
355 * A negative offs should be considered a serious problem.
358 panic("nfsrv_advance");
361 * If left == -1, calculate it here.
364 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
368 * Loop around, advancing over the mbuf data.
370 while (offs > left) {
372 nd->nd_md = mbuf_next(nd->nd_md);
373 if (nd->nd_md == NULL) {
377 left = mbuf_len(nd->nd_md);
378 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
388 * Copy a string into mbuf(s).
389 * Return the number of bytes output, including XDR overheads.
392 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
402 *tl = txdr_unsigned(siz);
403 rem = NFSM_RNDUP(siz) - siz;
404 bytesize = NFSX_UNSIGNED + siz + rem;
407 left = M_TRAILINGSPACE(m2);
410 * Loop around copying the string to mbuf(s).
414 if (siz > ncl_mbuf_mlen)
415 NFSMCLGET(m1, M_WAITOK);
419 mbuf_setnext(m2, m1);
421 cp2 = NFSMTOD(m2, caddr_t);
422 left = M_TRAILINGSPACE(m2);
428 NFSBCOPY(cp, cp2, xfer);
430 mbuf_setlen(m2, mbuf_len(m2) + xfer);
433 if (siz == 0 && rem) {
435 panic("nfsm_strtom");
436 NFSBZERO(cp2 + xfer, rem);
437 mbuf_setlen(m2, mbuf_len(m2) + rem);
441 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
446 * Called once to initialize data structures...
451 static int nfs_inited = 0;
457 newnfs_true = txdr_unsigned(TRUE);
458 newnfs_false = txdr_unsigned(FALSE);
459 newnfs_xdrneg1 = txdr_unsigned(-1);
460 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
463 NFSSETBOOTTIME(nfsboottime);
466 * Initialize reply list and start timer
468 TAILQ_INIT(&nfsd_reqq);
473 * Put a file handle in an mbuf list.
474 * If the size argument == 0, just use the default size.
475 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
476 * Return the number of bytes output, including XDR overhead.
479 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
483 int fullsiz, rem, bytesize = 0;
487 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
489 if (size > NFSX_V2FH)
490 panic("fh size > NFSX_V2FH for NFSv2");
491 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
492 NFSBCOPY(fhp, cp, size);
493 if (size < NFSX_V2FH)
494 NFSBZERO(cp + size, NFSX_V2FH - size);
495 bytesize = NFSX_V2FH;
499 fullsiz = NFSM_RNDUP(size);
500 rem = fullsiz - size;
502 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
503 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
506 bytesize = NFSX_UNSIGNED + fullsiz;
508 (void) nfsm_strtom(nd, fhp, size);
515 * This function compares two net addresses by family and returns TRUE
516 * if they are the same host.
517 * If there is any doubt, return FALSE.
518 * The AF_INET family is handled as a special case so that address mbufs
519 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
522 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
524 struct sockaddr_in *inetaddr;
528 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
529 if (inetaddr->sin_family == AF_INET &&
530 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
536 struct sockaddr_in6 *inetaddr6;
538 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
539 /* XXX - should test sin6_scope_id ? */
540 if (inetaddr6->sin6_family == AF_INET6 &&
541 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
552 * Similar to the above, but takes to NFSSOCKADDR_T args.
555 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
557 struct sockaddr_in *addr1, *addr2;
558 struct sockaddr *inaddr;
560 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
561 switch (inaddr->sa_family) {
563 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
564 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
565 if (addr2->sin_family == AF_INET &&
566 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
572 struct sockaddr_in6 *inet6addr1, *inet6addr2;
574 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
575 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
576 /* XXX - should test sin6_scope_id ? */
577 if (inet6addr2->sin6_family == AF_INET6 &&
578 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
579 &inet6addr2->sin6_addr))
590 * Trim the stuff already dissected off the mbuf list.
593 newnfs_trimleading(nd)
594 struct nfsrv_descript *nd;
600 * First, free up leading mbufs.
602 if (nd->nd_mrep != nd->nd_md) {
604 while (mbuf_next(m) != nd->nd_md) {
605 if (mbuf_next(m) == NULL)
606 panic("nfsm trim leading");
609 mbuf_setnext(m, NULL);
610 mbuf_freem(nd->nd_mrep);
615 * Now, adjust this mbuf, based on nd_dpos.
617 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
618 if (offs == mbuf_len(m)) {
622 panic("nfsm trim leading2");
623 mbuf_setnext(n, NULL);
625 } else if (offs > 0) {
626 mbuf_setlen(m, mbuf_len(m) - offs);
629 panic("nfsm trimleading offs");
632 nd->nd_dpos = NFSMTOD(m, caddr_t);
636 * Trim trailing data off the mbuf list being built.
639 newnfs_trimtrailing(nd, mb, bpos)
640 struct nfsrv_descript *nd;
646 mbuf_freem(mbuf_next(mb));
647 mbuf_setnext(mb, NULL);
649 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
655 * Dissect a file handle on the client.
658 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
665 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
667 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
674 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
676 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
678 FREE((caddr_t)nfhp, M_NFSFH);
684 NFSEXITCODE2(error, nd);
689 * Break down the nfsv4 acl.
690 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
693 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
694 int *aclsizep, __unused NFSPROC_T *p)
698 int acecnt, error = 0, aceerr = 0, acesize;
704 * Parse out the ace entries and expect them to conform to
705 * what can be supported by R/W/X bits.
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
708 aclsize = NFSX_UNSIGNED;
709 acecnt = fxdr_unsigned(int, *tl);
710 if (acecnt > ACL_MAX_ENTRIES)
711 aceerr = NFSERR_ATTRNOTSUPP;
712 if (nfsrv_useacl == 0)
713 aceerr = NFSERR_ATTRNOTSUPP;
714 for (i = 0; i < acecnt; i++) {
716 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
717 &aceerr, &acesize, p);
719 error = nfsrv_skipace(nd, &acesize);
725 aclp->acl_cnt = acecnt;
731 NFSEXITCODE2(error, nd);
736 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
739 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
745 len = fxdr_unsigned(int, *(tl + 3));
746 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
748 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
749 NFSEXITCODE2(error, nd);
754 * Get attribute bits from an mbuf list.
755 * Returns EBADRPC for a parsing error, 0 otherwise.
756 * If the clearinvalid flag is set, clear the bits not supported.
759 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
767 cnt = fxdr_unsigned(int, *tl);
769 error = NFSERR_BADXDR;
772 if (cnt > NFSATTRBIT_MAXWORDS)
773 outcnt = NFSATTRBIT_MAXWORDS;
776 NFSZERO_ATTRBIT(attrbitp);
778 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
779 for (i = 0; i < outcnt; i++)
780 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
782 for (i = 0; i < (cnt - outcnt); i++) {
783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
784 if (retnotsupp != NULL && *tl != 0)
785 *retnotsupp = NFSERR_ATTRNOTSUPP;
788 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
790 NFSEXITCODE2(error, nd);
795 * Get the attributes for V4.
796 * If the compare flag is true, test for any attribute changes,
797 * otherwise return the attribute values.
798 * These attributes cover fields in "struct vattr", "struct statfs",
799 * "struct nfsfsinfo", the file handle and the lease duration.
800 * The value of retcmpp is set to 1 if all attributes are the same,
802 * Returns EBADRPC if it can't be parsed, 0 otherwise.
805 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
806 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
807 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
808 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
809 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
812 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
813 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
814 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
815 nfsattrbit_t attrbits, retattrbits, checkattrbits;
817 struct nfsreferral *refp;
820 struct timespec temptime;
824 u_int32_t freenum = 0, tuint;
825 u_int64_t uquad = 0, thyp, thyp2;
830 static struct timeval last64fileid;
831 static size_t count64fileid;
832 static struct timeval last64mountfileid;
833 static size_t count64mountfileid;
834 static struct timeval warninterval = { 60, 0 };
838 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
840 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
846 *retcmpp = retnotsup;
849 * Just set default values to some of the important ones.
854 nap->na_rdev = (NFSDEV_T)0;
855 nap->na_mtime.tv_sec = 0;
856 nap->na_mtime.tv_nsec = 0;
859 nap->na_blocksize = NFS_FABLKSIZE;
862 sbp->f_bsize = NFS_FABLKSIZE;
870 fsp->fs_rtmax = 8192;
871 fsp->fs_rtpref = 8192;
872 fsp->fs_maxname = NFS_MAXNAMLEN;
873 fsp->fs_wtmax = 8192;
874 fsp->fs_wtpref = 8192;
875 fsp->fs_wtmult = NFS_FABLKSIZE;
876 fsp->fs_dtpref = 8192;
877 fsp->fs_maxfilesize = 0xffffffffffffffffull;
878 fsp->fs_timedelta.tv_sec = 0;
879 fsp->fs_timedelta.tv_nsec = 1;
880 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
881 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
884 pc->pc_linkmax = LINK_MAX;
885 pc->pc_namemax = NAME_MAX;
887 pc->pc_chownrestricted = 0;
888 pc->pc_caseinsensitive = 0;
889 pc->pc_casepreserving = 1;
894 * Loop around getting the attributes.
896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
897 attrsize = fxdr_unsigned(int, *tl);
898 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
899 if (attrsum > attrsize) {
900 error = NFSERR_BADXDR;
903 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
905 case NFSATTRBIT_SUPPORTEDATTRS:
907 if (compare || nap == NULL)
908 error = nfsrv_getattrbits(nd, &retattrbits,
911 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
915 if (compare && !(*retcmpp)) {
916 NFSSETSUPP_ATTRBIT(&checkattrbits);
917 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
919 *retcmpp = NFSERR_NOTSAME;
923 case NFSATTRBIT_TYPE:
924 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
927 if (nap->na_type != nfsv34tov_type(*tl))
928 *retcmpp = NFSERR_NOTSAME;
930 } else if (nap != NULL) {
931 nap->na_type = nfsv34tov_type(*tl);
933 attrsum += NFSX_UNSIGNED;
935 case NFSATTRBIT_FHEXPIRETYPE:
936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
937 if (compare && !(*retcmpp)) {
938 if (fxdr_unsigned(int, *tl) !=
939 NFSV4FHTYPE_PERSISTENT)
940 *retcmpp = NFSERR_NOTSAME;
942 attrsum += NFSX_UNSIGNED;
944 case NFSATTRBIT_CHANGE:
945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
948 if (nap->na_filerev != fxdr_hyper(tl))
949 *retcmpp = NFSERR_NOTSAME;
951 } else if (nap != NULL) {
952 nap->na_filerev = fxdr_hyper(tl);
954 attrsum += NFSX_HYPER;
956 case NFSATTRBIT_SIZE:
957 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
960 if (nap->na_size != fxdr_hyper(tl))
961 *retcmpp = NFSERR_NOTSAME;
963 } else if (nap != NULL) {
964 nap->na_size = fxdr_hyper(tl);
966 attrsum += NFSX_HYPER;
968 case NFSATTRBIT_LINKSUPPORT:
969 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
972 if (fsp->fs_properties & NFSV3_FSFLINK) {
973 if (*tl == newnfs_false)
974 *retcmpp = NFSERR_NOTSAME;
976 if (*tl == newnfs_true)
977 *retcmpp = NFSERR_NOTSAME;
980 } else if (fsp != NULL) {
981 if (*tl == newnfs_true)
982 fsp->fs_properties |= NFSV3_FSFLINK;
984 fsp->fs_properties &= ~NFSV3_FSFLINK;
986 attrsum += NFSX_UNSIGNED;
988 case NFSATTRBIT_SYMLINKSUPPORT:
989 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
992 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
993 if (*tl == newnfs_false)
994 *retcmpp = NFSERR_NOTSAME;
996 if (*tl == newnfs_true)
997 *retcmpp = NFSERR_NOTSAME;
1000 } else if (fsp != NULL) {
1001 if (*tl == newnfs_true)
1002 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1004 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1006 attrsum += NFSX_UNSIGNED;
1008 case NFSATTRBIT_NAMEDATTR:
1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1010 if (compare && !(*retcmpp)) {
1011 if (*tl != newnfs_false)
1012 *retcmpp = NFSERR_NOTSAME;
1014 attrsum += NFSX_UNSIGNED;
1016 case NFSATTRBIT_FSID:
1017 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1018 thyp = fxdr_hyper(tl);
1020 thyp2 = fxdr_hyper(tl);
1022 if (*retcmpp == 0) {
1023 if (thyp != (u_int64_t)
1024 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1025 thyp2 != (u_int64_t)
1026 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1027 *retcmpp = NFSERR_NOTSAME;
1029 } else if (nap != NULL) {
1030 nap->na_filesid[0] = thyp;
1031 nap->na_filesid[1] = thyp2;
1033 attrsum += (4 * NFSX_UNSIGNED);
1035 case NFSATTRBIT_UNIQUEHANDLES:
1036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1037 if (compare && !(*retcmpp)) {
1038 if (*tl != newnfs_true)
1039 *retcmpp = NFSERR_NOTSAME;
1041 attrsum += NFSX_UNSIGNED;
1043 case NFSATTRBIT_LEASETIME:
1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1046 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1048 *retcmpp = NFSERR_NOTSAME;
1049 } else if (leasep != NULL) {
1050 *leasep = fxdr_unsigned(u_int32_t, *tl);
1052 attrsum += NFSX_UNSIGNED;
1054 case NFSATTRBIT_RDATTRERROR:
1055 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1058 *retcmpp = NFSERR_INVAL;
1059 } else if (rderrp != NULL) {
1060 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1062 attrsum += NFSX_UNSIGNED;
1064 case NFSATTRBIT_ACL:
1070 naclp = acl_alloc(M_WAITOK);
1071 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1077 if (aceerr || aclp == NULL ||
1078 nfsrv_compareacl(aclp, naclp))
1079 *retcmpp = NFSERR_NOTSAME;
1082 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1084 *retcmpp = NFSERR_ATTRNOTSUPP;
1088 if (vp != NULL && aclp != NULL)
1089 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1092 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1099 case NFSATTRBIT_ACLSUPPORT:
1100 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1101 if (compare && !(*retcmpp)) {
1103 if (fxdr_unsigned(u_int32_t, *tl) !=
1105 *retcmpp = NFSERR_NOTSAME;
1107 *retcmpp = NFSERR_ATTRNOTSUPP;
1110 attrsum += NFSX_UNSIGNED;
1112 case NFSATTRBIT_ARCHIVE:
1113 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1114 if (compare && !(*retcmpp))
1115 *retcmpp = NFSERR_ATTRNOTSUPP;
1116 attrsum += NFSX_UNSIGNED;
1118 case NFSATTRBIT_CANSETTIME:
1119 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1122 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1123 if (*tl == newnfs_false)
1124 *retcmpp = NFSERR_NOTSAME;
1126 if (*tl == newnfs_true)
1127 *retcmpp = NFSERR_NOTSAME;
1130 } else if (fsp != NULL) {
1131 if (*tl == newnfs_true)
1132 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1134 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1136 attrsum += NFSX_UNSIGNED;
1138 case NFSATTRBIT_CASEINSENSITIVE:
1139 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1142 if (*tl != newnfs_false)
1143 *retcmpp = NFSERR_NOTSAME;
1145 } else if (pc != NULL) {
1146 pc->pc_caseinsensitive =
1147 fxdr_unsigned(u_int32_t, *tl);
1149 attrsum += NFSX_UNSIGNED;
1151 case NFSATTRBIT_CASEPRESERVING:
1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1155 if (*tl != newnfs_true)
1156 *retcmpp = NFSERR_NOTSAME;
1158 } else if (pc != NULL) {
1159 pc->pc_casepreserving =
1160 fxdr_unsigned(u_int32_t, *tl);
1162 attrsum += NFSX_UNSIGNED;
1164 case NFSATTRBIT_CHOWNRESTRICTED:
1165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1168 if (*tl != newnfs_true)
1169 *retcmpp = NFSERR_NOTSAME;
1171 } else if (pc != NULL) {
1172 pc->pc_chownrestricted =
1173 fxdr_unsigned(u_int32_t, *tl);
1175 attrsum += NFSX_UNSIGNED;
1177 case NFSATTRBIT_FILEHANDLE:
1178 error = nfsm_getfh(nd, &tnfhp);
1181 tfhsize = tnfhp->nfh_len;
1184 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1186 *retcmpp = NFSERR_NOTSAME;
1187 FREE((caddr_t)tnfhp, M_NFSFH);
1188 } else if (nfhpp != NULL) {
1191 FREE((caddr_t)tnfhp, M_NFSFH);
1193 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1195 case NFSATTRBIT_FILEID:
1196 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1197 thyp = fxdr_hyper(tl);
1200 if ((u_int64_t)nap->na_fileid != thyp)
1201 *retcmpp = NFSERR_NOTSAME;
1203 } else if (nap != NULL) {
1206 if (ratecheck(&last64fileid, &warninterval)) {
1207 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1212 nap->na_fileid = thyp;
1214 attrsum += NFSX_HYPER;
1216 case NFSATTRBIT_FILESAVAIL:
1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1220 sfp->sf_afiles != fxdr_hyper(tl))
1221 *retcmpp = NFSERR_NOTSAME;
1222 } else if (sfp != NULL) {
1223 sfp->sf_afiles = fxdr_hyper(tl);
1225 attrsum += NFSX_HYPER;
1227 case NFSATTRBIT_FILESFREE:
1228 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1231 sfp->sf_ffiles != fxdr_hyper(tl))
1232 *retcmpp = NFSERR_NOTSAME;
1233 } else if (sfp != NULL) {
1234 sfp->sf_ffiles = fxdr_hyper(tl);
1236 attrsum += NFSX_HYPER;
1238 case NFSATTRBIT_FILESTOTAL:
1239 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1242 sfp->sf_tfiles != fxdr_hyper(tl))
1243 *retcmpp = NFSERR_NOTSAME;
1244 } else if (sfp != NULL) {
1245 sfp->sf_tfiles = fxdr_hyper(tl);
1247 attrsum += NFSX_HYPER;
1249 case NFSATTRBIT_FSLOCATIONS:
1250 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1254 if (compare && !(*retcmpp)) {
1255 refp = nfsv4root_getreferral(vp, NULL, 0);
1257 if (cp == NULL || cp2 == NULL ||
1259 strcmp(cp2, refp->nfr_srvlist))
1260 *retcmpp = NFSERR_NOTSAME;
1261 } else if (m == 0) {
1262 *retcmpp = NFSERR_NOTSAME;
1266 free(cp, M_NFSSTRING);
1268 free(cp2, M_NFSSTRING);
1270 case NFSATTRBIT_HIDDEN:
1271 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1272 if (compare && !(*retcmpp))
1273 *retcmpp = NFSERR_ATTRNOTSUPP;
1274 attrsum += NFSX_UNSIGNED;
1276 case NFSATTRBIT_HOMOGENEOUS:
1277 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1280 if (fsp->fs_properties &
1281 NFSV3_FSFHOMOGENEOUS) {
1282 if (*tl == newnfs_false)
1283 *retcmpp = NFSERR_NOTSAME;
1285 if (*tl == newnfs_true)
1286 *retcmpp = NFSERR_NOTSAME;
1289 } else if (fsp != NULL) {
1290 if (*tl == newnfs_true)
1291 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1293 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1295 attrsum += NFSX_UNSIGNED;
1297 case NFSATTRBIT_MAXFILESIZE:
1298 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1299 tnfsquad.qval = fxdr_hyper(tl);
1302 tquad = NFSRV_MAXFILESIZE;
1303 if (tquad != tnfsquad.qval)
1304 *retcmpp = NFSERR_NOTSAME;
1306 } else if (fsp != NULL) {
1307 fsp->fs_maxfilesize = tnfsquad.qval;
1309 attrsum += NFSX_HYPER;
1311 case NFSATTRBIT_MAXLINK:
1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1315 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1316 *retcmpp = NFSERR_NOTSAME;
1318 } else if (pc != NULL) {
1319 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1321 attrsum += NFSX_UNSIGNED;
1323 case NFSATTRBIT_MAXNAME:
1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1327 if (fsp->fs_maxname !=
1328 fxdr_unsigned(u_int32_t, *tl))
1329 *retcmpp = NFSERR_NOTSAME;
1332 tuint = fxdr_unsigned(u_int32_t, *tl);
1334 * Some Linux NFSv4 servers report this
1335 * as 0 or 4billion, so I'll set it to
1336 * NFS_MAXNAMLEN. If a server actually creates
1337 * a name longer than NFS_MAXNAMLEN, it will
1338 * get an error back.
1340 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1341 tuint = NFS_MAXNAMLEN;
1343 fsp->fs_maxname = tuint;
1345 pc->pc_namemax = tuint;
1347 attrsum += NFSX_UNSIGNED;
1349 case NFSATTRBIT_MAXREAD:
1350 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1353 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1354 *(tl + 1)) || *tl != 0)
1355 *retcmpp = NFSERR_NOTSAME;
1357 } else if (fsp != NULL) {
1358 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1359 fsp->fs_rtpref = fsp->fs_rtmax;
1360 fsp->fs_dtpref = fsp->fs_rtpref;
1362 attrsum += NFSX_HYPER;
1364 case NFSATTRBIT_MAXWRITE:
1365 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1368 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1369 *(tl + 1)) || *tl != 0)
1370 *retcmpp = NFSERR_NOTSAME;
1372 } else if (fsp != NULL) {
1373 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1374 fsp->fs_wtpref = fsp->fs_wtmax;
1376 attrsum += NFSX_HYPER;
1378 case NFSATTRBIT_MIMETYPE:
1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1380 i = fxdr_unsigned(int, *tl);
1381 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1382 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1385 if (compare && !(*retcmpp))
1386 *retcmpp = NFSERR_ATTRNOTSUPP;
1388 case NFSATTRBIT_MODE:
1389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1392 if (nap->na_mode != nfstov_mode(*tl))
1393 *retcmpp = NFSERR_NOTSAME;
1395 } else if (nap != NULL) {
1396 nap->na_mode = nfstov_mode(*tl);
1398 attrsum += NFSX_UNSIGNED;
1400 case NFSATTRBIT_NOTRUNC:
1401 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404 if (*tl != newnfs_true)
1405 *retcmpp = NFSERR_NOTSAME;
1407 } else if (pc != NULL) {
1408 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1410 attrsum += NFSX_UNSIGNED;
1412 case NFSATTRBIT_NUMLINKS:
1413 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1414 tuint = fxdr_unsigned(u_int32_t, *tl);
1417 if ((u_int32_t)nap->na_nlink != tuint)
1418 *retcmpp = NFSERR_NOTSAME;
1420 } else if (nap != NULL) {
1421 nap->na_nlink = tuint;
1423 attrsum += NFSX_UNSIGNED;
1425 case NFSATTRBIT_OWNER:
1426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1427 j = fxdr_unsigned(int, *tl);
1429 error = NFSERR_BADXDR;
1432 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1433 if (j > NFSV4_SMALLSTR)
1434 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1437 error = nfsrv_mtostr(nd, cp, j);
1439 if (j > NFSV4_SMALLSTR)
1440 free(cp, M_NFSSTRING);
1445 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1447 *retcmpp = NFSERR_NOTSAME;
1449 } else if (nap != NULL) {
1450 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1451 nap->na_uid = nfsrv_defaultuid;
1455 if (j > NFSV4_SMALLSTR)
1456 free(cp, M_NFSSTRING);
1458 case NFSATTRBIT_OWNERGROUP:
1459 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1460 j = fxdr_unsigned(int, *tl);
1462 error = NFSERR_BADXDR;
1465 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1466 if (j > NFSV4_SMALLSTR)
1467 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1470 error = nfsrv_mtostr(nd, cp, j);
1472 if (j > NFSV4_SMALLSTR)
1473 free(cp, M_NFSSTRING);
1478 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1480 *retcmpp = NFSERR_NOTSAME;
1482 } else if (nap != NULL) {
1483 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1484 nap->na_gid = nfsrv_defaultgid;
1488 if (j > NFSV4_SMALLSTR)
1489 free(cp, M_NFSSTRING);
1491 case NFSATTRBIT_QUOTAHARD:
1492 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1494 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1495 freenum = sbp->f_bfree;
1497 freenum = sbp->f_bavail;
1500 * ufs_quotactl() insists that the uid argument
1501 * equal p_ruid for non-root quota access, so
1502 * we'll just make sure that's the case.
1504 savuid = p->p_cred->p_ruid;
1505 p->p_cred->p_ruid = cred->cr_uid;
1506 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1507 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1508 freenum = min(dqb.dqb_bhardlimit, freenum);
1509 p->p_cred->p_ruid = savuid;
1511 uquad = (u_int64_t)freenum;
1512 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1514 if (compare && !(*retcmpp)) {
1515 if (uquad != fxdr_hyper(tl))
1516 *retcmpp = NFSERR_NOTSAME;
1518 attrsum += NFSX_HYPER;
1520 case NFSATTRBIT_QUOTASOFT:
1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1523 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1524 freenum = sbp->f_bfree;
1526 freenum = sbp->f_bavail;
1529 * ufs_quotactl() insists that the uid argument
1530 * equal p_ruid for non-root quota access, so
1531 * we'll just make sure that's the case.
1533 savuid = p->p_cred->p_ruid;
1534 p->p_cred->p_ruid = cred->cr_uid;
1535 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1536 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1537 freenum = min(dqb.dqb_bsoftlimit, freenum);
1538 p->p_cred->p_ruid = savuid;
1540 uquad = (u_int64_t)freenum;
1541 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1543 if (compare && !(*retcmpp)) {
1544 if (uquad != fxdr_hyper(tl))
1545 *retcmpp = NFSERR_NOTSAME;
1547 attrsum += NFSX_HYPER;
1549 case NFSATTRBIT_QUOTAUSED:
1550 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1555 * ufs_quotactl() insists that the uid argument
1556 * equal p_ruid for non-root quota access, so
1557 * we'll just make sure that's the case.
1559 savuid = p->p_cred->p_ruid;
1560 p->p_cred->p_ruid = cred->cr_uid;
1561 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1562 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1563 freenum = dqb.dqb_curblocks;
1564 p->p_cred->p_ruid = savuid;
1566 uquad = (u_int64_t)freenum;
1567 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1569 if (compare && !(*retcmpp)) {
1570 if (uquad != fxdr_hyper(tl))
1571 *retcmpp = NFSERR_NOTSAME;
1573 attrsum += NFSX_HYPER;
1575 case NFSATTRBIT_RAWDEV:
1576 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1577 j = fxdr_unsigned(int, *tl++);
1578 k = fxdr_unsigned(int, *tl);
1581 if (nap->na_rdev != NFSMAKEDEV(j, k))
1582 *retcmpp = NFSERR_NOTSAME;
1584 } else if (nap != NULL) {
1585 nap->na_rdev = NFSMAKEDEV(j, k);
1587 attrsum += NFSX_V4SPECDATA;
1589 case NFSATTRBIT_SPACEAVAIL:
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1593 sfp->sf_abytes != fxdr_hyper(tl))
1594 *retcmpp = NFSERR_NOTSAME;
1595 } else if (sfp != NULL) {
1596 sfp->sf_abytes = fxdr_hyper(tl);
1598 attrsum += NFSX_HYPER;
1600 case NFSATTRBIT_SPACEFREE:
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1604 sfp->sf_fbytes != fxdr_hyper(tl))
1605 *retcmpp = NFSERR_NOTSAME;
1606 } else if (sfp != NULL) {
1607 sfp->sf_fbytes = fxdr_hyper(tl);
1609 attrsum += NFSX_HYPER;
1611 case NFSATTRBIT_SPACETOTAL:
1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1615 sfp->sf_tbytes != fxdr_hyper(tl))
1616 *retcmpp = NFSERR_NOTSAME;
1617 } else if (sfp != NULL) {
1618 sfp->sf_tbytes = fxdr_hyper(tl);
1620 attrsum += NFSX_HYPER;
1622 case NFSATTRBIT_SPACEUSED:
1623 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1624 thyp = fxdr_hyper(tl);
1627 if ((u_int64_t)nap->na_bytes != thyp)
1628 *retcmpp = NFSERR_NOTSAME;
1630 } else if (nap != NULL) {
1631 nap->na_bytes = thyp;
1633 attrsum += NFSX_HYPER;
1635 case NFSATTRBIT_SYSTEM:
1636 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1637 if (compare && !(*retcmpp))
1638 *retcmpp = NFSERR_ATTRNOTSUPP;
1639 attrsum += NFSX_UNSIGNED;
1641 case NFSATTRBIT_TIMEACCESS:
1642 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1643 fxdr_nfsv4time(tl, &temptime);
1646 if (!NFS_CMPTIME(temptime, nap->na_atime))
1647 *retcmpp = NFSERR_NOTSAME;
1649 } else if (nap != NULL) {
1650 nap->na_atime = temptime;
1652 attrsum += NFSX_V4TIME;
1654 case NFSATTRBIT_TIMEACCESSSET:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1656 attrsum += NFSX_UNSIGNED;
1657 i = fxdr_unsigned(int, *tl);
1658 if (i == NFSV4SATTRTIME_TOCLIENT) {
1659 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1660 attrsum += NFSX_V4TIME;
1662 if (compare && !(*retcmpp))
1663 *retcmpp = NFSERR_INVAL;
1665 case NFSATTRBIT_TIMEBACKUP:
1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1667 if (compare && !(*retcmpp))
1668 *retcmpp = NFSERR_ATTRNOTSUPP;
1669 attrsum += NFSX_V4TIME;
1671 case NFSATTRBIT_TIMECREATE:
1672 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1673 if (compare && !(*retcmpp))
1674 *retcmpp = NFSERR_ATTRNOTSUPP;
1675 attrsum += NFSX_V4TIME;
1677 case NFSATTRBIT_TIMEDELTA:
1678 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1682 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1683 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1684 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1685 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1688 *retcmpp = NFSERR_NOTSAME;
1691 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1694 attrsum += NFSX_V4TIME;
1696 case NFSATTRBIT_TIMEMETADATA:
1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1698 fxdr_nfsv4time(tl, &temptime);
1701 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1702 *retcmpp = NFSERR_NOTSAME;
1704 } else if (nap != NULL) {
1705 nap->na_ctime = temptime;
1707 attrsum += NFSX_V4TIME;
1709 case NFSATTRBIT_TIMEMODIFY:
1710 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1711 fxdr_nfsv4time(tl, &temptime);
1714 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1715 *retcmpp = NFSERR_NOTSAME;
1717 } else if (nap != NULL) {
1718 nap->na_mtime = temptime;
1720 attrsum += NFSX_V4TIME;
1722 case NFSATTRBIT_TIMEMODIFYSET:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1724 attrsum += NFSX_UNSIGNED;
1725 i = fxdr_unsigned(int, *tl);
1726 if (i == NFSV4SATTRTIME_TOCLIENT) {
1727 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1728 attrsum += NFSX_V4TIME;
1730 if (compare && !(*retcmpp))
1731 *retcmpp = NFSERR_INVAL;
1733 case NFSATTRBIT_MOUNTEDONFILEID:
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1735 thyp = fxdr_hyper(tl);
1739 *retcmpp = NFSERR_NOTSAME;
1741 if (!vp || !nfsrv_atroot(vp, &fid))
1742 fid = nap->na_fileid;
1743 if ((u_int64_t)fid != thyp)
1744 *retcmpp = NFSERR_NOTSAME;
1747 } else if (nap != NULL) {
1749 count64mountfileid++;
1750 if (ratecheck(&last64mountfileid, &warninterval)) {
1751 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1752 count64mountfileid);
1753 count64mountfileid = 0;
1756 nap->na_mntonfileno = thyp;
1758 attrsum += NFSX_HYPER;
1760 case NFSATTRBIT_SUPPATTREXCLCREAT:
1762 error = nfsrv_getattrbits(nd, &retattrbits,
1766 if (compare && !(*retcmpp)) {
1767 NFSSETSUPP_ATTRBIT(&checkattrbits);
1768 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1769 NFSCLRBIT_ATTRBIT(&checkattrbits,
1770 NFSATTRBIT_TIMEACCESSSET);
1771 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1773 *retcmpp = NFSERR_NOTSAME;
1778 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1780 if (compare && !(*retcmpp))
1781 *retcmpp = NFSERR_ATTRNOTSUPP;
1783 * and get out of the loop, since we can't parse
1784 * the unknown attrbute data.
1786 bitpos = NFSATTRBIT_MAX;
1792 * some clients pad the attrlist, so we need to skip over the
1795 if (attrsum > attrsize) {
1796 error = NFSERR_BADXDR;
1798 attrsize = NFSM_RNDUP(attrsize);
1799 if (attrsum < attrsize)
1800 error = nfsm_advance(nd, attrsize - attrsum, -1);
1803 NFSEXITCODE2(error, nd);
1808 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1809 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1810 * The first argument is a pointer to an nfsv4lock structure.
1811 * The second argument is 1 iff a blocking lock is wanted.
1812 * If this argument is 0, the call waits until no thread either wants nor
1813 * holds an exclusive lock.
1814 * It returns 1 if the lock was acquired, 0 otherwise.
1815 * If several processes call this function concurrently wanting the exclusive
1816 * lock, one will get the lock and the rest will return without getting the
1817 * lock. (If the caller must have the lock, it simply calls this function in a
1818 * loop until the function returns 1 to indicate the lock was acquired.)
1819 * Any usecnt must be decremented by calling nfsv4_relref() before
1820 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1821 * be called in a loop.
1822 * The isleptp argument is set to indicate if the call slept, iff not NULL
1823 * and the mp argument indicates to check for a forced dismount, iff not
1827 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1828 void *mutex, struct mount *mp)
1834 * If a lock is wanted, loop around until the lock is acquired by
1835 * someone and then released. If I want the lock, try to acquire it.
1836 * For a lock to be issued, no lock must be in force and the usecnt
1840 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1841 lp->nfslock_usecnt == 0) {
1842 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1843 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1846 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1848 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1849 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1850 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1853 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1856 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1857 PZERO - 1, "nfsv4lck", NULL);
1858 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1859 lp->nfslock_usecnt == 0) {
1860 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1861 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1869 * Release the lock acquired by nfsv4_lock().
1870 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1871 * incremented, as well.
1874 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1877 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1879 lp->nfslock_usecnt++;
1884 * Release a reference cnt.
1887 nfsv4_relref(struct nfsv4lock *lp)
1890 if (lp->nfslock_usecnt <= 0)
1891 panic("nfsv4root ref cnt");
1892 lp->nfslock_usecnt--;
1893 if (lp->nfslock_usecnt == 0)
1898 * Get a reference cnt.
1899 * This function will wait for any exclusive lock to be released, but will
1900 * not wait for threads that want the exclusive lock. If priority needs
1901 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1902 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1903 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1904 * return without getting a refcnt for that case.
1907 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1915 * Wait for a lock held.
1917 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1918 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1920 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1923 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1924 PZERO - 1, "nfsv4gr", NULL);
1926 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1929 lp->nfslock_usecnt++;
1933 * Get a reference as above, but return failure instead of sleeping if
1934 * an exclusive lock is held.
1937 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1940 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1943 lp->nfslock_usecnt++;
1948 * Test for a lock. Return 1 if locked, 0 otherwise.
1951 nfsv4_testlock(struct nfsv4lock *lp)
1954 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1955 lp->nfslock_usecnt == 0)
1961 * Wake up anyone sleeping, waiting for this lock.
1964 nfsv4_wanted(struct nfsv4lock *lp)
1967 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1968 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1969 wakeup((caddr_t)&lp->nfslock_lock);
1974 * Copy a string from an mbuf list into a character array.
1975 * Return EBADRPC if there is an mbuf error,
1979 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1988 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1989 rem = NFSM_RNDUP(siz) - siz;
1995 NFSBCOPY(cp, str, xfer);
2004 cp = NFSMTOD(mp, caddr_t);
2016 error = nfsm_advance(nd, rem, len);
2022 NFSEXITCODE2(error, nd);
2027 * Fill in the attributes as marked by the bitmap (V4).
2030 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2031 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2032 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2033 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2035 int bitpos, retnum = 0;
2037 int siz, prefixnum, error;
2038 u_char *cp, namestr[NFSV4_SMALLSTR];
2039 nfsattrbit_t attrbits, retbits;
2040 nfsattrbit_t *retbitp = &retbits;
2041 u_int32_t freenum, *retnump;
2044 struct nfsfsinfo fsinf;
2045 struct timespec temptime;
2046 NFSACL_T *aclp, *naclp = NULL;
2053 * First, set the bits that can be filled and get fsinfo.
2055 NFSSET_ATTRBIT(retbitp, attrbitp);
2057 * If both p and cred are NULL, it is a client side setattr call.
2058 * If both p and cred are not NULL, it is a server side reply call.
2059 * If p is not NULL and cred is NULL, it is a client side callback
2062 if (p == NULL && cred == NULL) {
2063 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2066 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2067 naclp = acl_alloc(M_WAITOK);
2070 nfsvno_getfs(&fsinf, isdgram);
2073 * Get the VFS_STATFS(), since some attributes need them.
2075 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2076 error = VFS_STATFS(mp, &fs);
2079 nd->nd_repstat = NFSERR_ACCES;
2082 NFSCLRSTATFS_ATTRBIT(retbitp);
2088 * And the NFSv4 ACL...
2090 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2091 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2092 supports_nfsv4acls == 0))) {
2093 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2095 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2096 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2097 supports_nfsv4acls == 0)) {
2098 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2099 } else if (naclp != NULL) {
2100 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2101 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2103 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2105 NFSVOPUNLOCK(vp, 0);
2107 error = NFSERR_PERM;
2110 nd->nd_repstat = NFSERR_ACCES;
2113 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2118 * Put out the attribute bitmap for the ones being filled in
2119 * and get the field for the number of attributes returned.
2121 prefixnum = nfsrv_putattrbit(nd, retbitp);
2122 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2123 prefixnum += NFSX_UNSIGNED;
2126 * Now, loop around filling in the attributes for each bit set.
2128 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2129 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2131 case NFSATTRBIT_SUPPORTEDATTRS:
2132 NFSSETSUPP_ATTRBIT(&attrbits);
2133 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2134 && supports_nfsv4acls == 0)) {
2135 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2136 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2138 retnum += nfsrv_putattrbit(nd, &attrbits);
2140 case NFSATTRBIT_TYPE:
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2142 *tl = vtonfsv34_type(vap->va_type);
2143 retnum += NFSX_UNSIGNED;
2145 case NFSATTRBIT_FHEXPIRETYPE:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2147 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2148 retnum += NFSX_UNSIGNED;
2150 case NFSATTRBIT_CHANGE:
2151 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2152 txdr_hyper(vap->va_filerev, tl);
2153 retnum += NFSX_HYPER;
2155 case NFSATTRBIT_SIZE:
2156 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2157 txdr_hyper(vap->va_size, tl);
2158 retnum += NFSX_HYPER;
2160 case NFSATTRBIT_LINKSUPPORT:
2161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2162 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2166 retnum += NFSX_UNSIGNED;
2168 case NFSATTRBIT_SYMLINKSUPPORT:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2174 retnum += NFSX_UNSIGNED;
2176 case NFSATTRBIT_NAMEDATTR:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2179 retnum += NFSX_UNSIGNED;
2181 case NFSATTRBIT_FSID:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2184 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2186 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2187 retnum += NFSX_V4FSID;
2189 case NFSATTRBIT_UNIQUEHANDLES:
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2192 retnum += NFSX_UNSIGNED;
2194 case NFSATTRBIT_LEASETIME:
2195 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2196 *tl = txdr_unsigned(nfsrv_lease);
2197 retnum += NFSX_UNSIGNED;
2199 case NFSATTRBIT_RDATTRERROR:
2200 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2201 *tl = txdr_unsigned(rderror);
2202 retnum += NFSX_UNSIGNED;
2205 * Recommended Attributes. (Only the supported ones.)
2207 case NFSATTRBIT_ACL:
2208 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2210 case NFSATTRBIT_ACLSUPPORT:
2211 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2212 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2213 retnum += NFSX_UNSIGNED;
2215 case NFSATTRBIT_CANSETTIME:
2216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2217 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2221 retnum += NFSX_UNSIGNED;
2223 case NFSATTRBIT_CASEINSENSITIVE:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2226 retnum += NFSX_UNSIGNED;
2228 case NFSATTRBIT_CASEPRESERVING:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2231 retnum += NFSX_UNSIGNED;
2233 case NFSATTRBIT_CHOWNRESTRICTED:
2234 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2236 retnum += NFSX_UNSIGNED;
2238 case NFSATTRBIT_FILEHANDLE:
2239 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2241 case NFSATTRBIT_FILEID:
2242 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2244 *tl = txdr_unsigned(vap->va_fileid);
2245 retnum += NFSX_HYPER;
2247 case NFSATTRBIT_FILESAVAIL:
2249 * Check quota and use min(quota, f_ffree).
2251 freenum = fs.f_ffree;
2254 * ufs_quotactl() insists that the uid argument
2255 * equal p_ruid for non-root quota access, so
2256 * we'll just make sure that's the case.
2258 savuid = p->p_cred->p_ruid;
2259 p->p_cred->p_ruid = cred->cr_uid;
2260 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2261 cred->cr_uid, (caddr_t)&dqb))
2262 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2264 p->p_cred->p_ruid = savuid;
2266 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2268 *tl = txdr_unsigned(freenum);
2269 retnum += NFSX_HYPER;
2271 case NFSATTRBIT_FILESFREE:
2272 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2274 *tl = txdr_unsigned(fs.f_ffree);
2275 retnum += NFSX_HYPER;
2277 case NFSATTRBIT_FILESTOTAL:
2278 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2280 *tl = txdr_unsigned(fs.f_files);
2281 retnum += NFSX_HYPER;
2283 case NFSATTRBIT_FSLOCATIONS:
2284 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2287 retnum += 2 * NFSX_UNSIGNED;
2289 case NFSATTRBIT_HOMOGENEOUS:
2290 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2291 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2295 retnum += NFSX_UNSIGNED;
2297 case NFSATTRBIT_MAXFILESIZE:
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2299 uquad = NFSRV_MAXFILESIZE;
2300 txdr_hyper(uquad, tl);
2301 retnum += NFSX_HYPER;
2303 case NFSATTRBIT_MAXLINK:
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2305 *tl = txdr_unsigned(LINK_MAX);
2306 retnum += NFSX_UNSIGNED;
2308 case NFSATTRBIT_MAXNAME:
2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2310 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2311 retnum += NFSX_UNSIGNED;
2313 case NFSATTRBIT_MAXREAD:
2314 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2316 *tl = txdr_unsigned(fsinf.fs_rtmax);
2317 retnum += NFSX_HYPER;
2319 case NFSATTRBIT_MAXWRITE:
2320 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2322 *tl = txdr_unsigned(fsinf.fs_wtmax);
2323 retnum += NFSX_HYPER;
2325 case NFSATTRBIT_MODE:
2326 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2327 *tl = vtonfsv34_mode(vap->va_mode);
2328 retnum += NFSX_UNSIGNED;
2330 case NFSATTRBIT_NOTRUNC:
2331 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2333 retnum += NFSX_UNSIGNED;
2335 case NFSATTRBIT_NUMLINKS:
2336 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2337 *tl = txdr_unsigned(vap->va_nlink);
2338 retnum += NFSX_UNSIGNED;
2340 case NFSATTRBIT_OWNER:
2342 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2343 retnum += nfsm_strtom(nd, cp, siz);
2345 free(cp, M_NFSSTRING);
2347 case NFSATTRBIT_OWNERGROUP:
2349 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2350 retnum += nfsm_strtom(nd, cp, siz);
2352 free(cp, M_NFSSTRING);
2354 case NFSATTRBIT_QUOTAHARD:
2355 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2356 freenum = fs.f_bfree;
2358 freenum = fs.f_bavail;
2361 * ufs_quotactl() insists that the uid argument
2362 * equal p_ruid for non-root quota access, so
2363 * we'll just make sure that's the case.
2365 savuid = p->p_cred->p_ruid;
2366 p->p_cred->p_ruid = cred->cr_uid;
2367 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2368 cred->cr_uid, (caddr_t)&dqb))
2369 freenum = min(dqb.dqb_bhardlimit, freenum);
2370 p->p_cred->p_ruid = savuid;
2372 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2373 uquad = (u_int64_t)freenum;
2374 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2375 txdr_hyper(uquad, tl);
2376 retnum += NFSX_HYPER;
2378 case NFSATTRBIT_QUOTASOFT:
2379 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2380 freenum = fs.f_bfree;
2382 freenum = fs.f_bavail;
2385 * ufs_quotactl() insists that the uid argument
2386 * equal p_ruid for non-root quota access, so
2387 * we'll just make sure that's the case.
2389 savuid = p->p_cred->p_ruid;
2390 p->p_cred->p_ruid = cred->cr_uid;
2391 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2392 cred->cr_uid, (caddr_t)&dqb))
2393 freenum = min(dqb.dqb_bsoftlimit, freenum);
2394 p->p_cred->p_ruid = savuid;
2396 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2397 uquad = (u_int64_t)freenum;
2398 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2399 txdr_hyper(uquad, tl);
2400 retnum += NFSX_HYPER;
2402 case NFSATTRBIT_QUOTAUSED:
2406 * ufs_quotactl() insists that the uid argument
2407 * equal p_ruid for non-root quota access, so
2408 * we'll just make sure that's the case.
2410 savuid = p->p_cred->p_ruid;
2411 p->p_cred->p_ruid = cred->cr_uid;
2412 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2413 cred->cr_uid, (caddr_t)&dqb))
2414 freenum = dqb.dqb_curblocks;
2415 p->p_cred->p_ruid = savuid;
2417 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2418 uquad = (u_int64_t)freenum;
2419 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2420 txdr_hyper(uquad, tl);
2421 retnum += NFSX_HYPER;
2423 case NFSATTRBIT_RAWDEV:
2424 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2425 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2426 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2427 retnum += NFSX_V4SPECDATA;
2429 case NFSATTRBIT_SPACEAVAIL:
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2431 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2432 uquad = (u_int64_t)fs.f_bfree;
2434 uquad = (u_int64_t)fs.f_bavail;
2435 uquad *= fs.f_bsize;
2436 txdr_hyper(uquad, tl);
2437 retnum += NFSX_HYPER;
2439 case NFSATTRBIT_SPACEFREE:
2440 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2441 uquad = (u_int64_t)fs.f_bfree;
2442 uquad *= fs.f_bsize;
2443 txdr_hyper(uquad, tl);
2444 retnum += NFSX_HYPER;
2446 case NFSATTRBIT_SPACETOTAL:
2447 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2448 uquad = (u_int64_t)fs.f_blocks;
2449 uquad *= fs.f_bsize;
2450 txdr_hyper(uquad, tl);
2451 retnum += NFSX_HYPER;
2453 case NFSATTRBIT_SPACEUSED:
2454 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2455 txdr_hyper(vap->va_bytes, tl);
2456 retnum += NFSX_HYPER;
2458 case NFSATTRBIT_TIMEACCESS:
2459 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2460 txdr_nfsv4time(&vap->va_atime, tl);
2461 retnum += NFSX_V4TIME;
2463 case NFSATTRBIT_TIMEACCESSSET:
2464 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2465 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2466 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2467 txdr_nfsv4time(&vap->va_atime, tl);
2468 retnum += NFSX_V4SETTIME;
2470 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2471 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2472 retnum += NFSX_UNSIGNED;
2475 case NFSATTRBIT_TIMEDELTA:
2476 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2477 temptime.tv_sec = 0;
2478 temptime.tv_nsec = 1000000000 / hz;
2479 txdr_nfsv4time(&temptime, tl);
2480 retnum += NFSX_V4TIME;
2482 case NFSATTRBIT_TIMEMETADATA:
2483 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2484 txdr_nfsv4time(&vap->va_ctime, tl);
2485 retnum += NFSX_V4TIME;
2487 case NFSATTRBIT_TIMEMODIFY:
2488 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2489 txdr_nfsv4time(&vap->va_mtime, tl);
2490 retnum += NFSX_V4TIME;
2492 case NFSATTRBIT_TIMEMODIFYSET:
2493 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2494 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2495 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2496 txdr_nfsv4time(&vap->va_mtime, tl);
2497 retnum += NFSX_V4SETTIME;
2499 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2500 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2501 retnum += NFSX_UNSIGNED;
2504 case NFSATTRBIT_MOUNTEDONFILEID:
2505 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2507 uquad = mounted_on_fileno;
2509 uquad = (u_int64_t)vap->va_fileid;
2510 txdr_hyper(uquad, tl);
2511 retnum += NFSX_HYPER;
2513 case NFSATTRBIT_SUPPATTREXCLCREAT:
2514 NFSSETSUPP_ATTRBIT(&attrbits);
2515 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2516 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2517 retnum += nfsrv_putattrbit(nd, &attrbits);
2520 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2526 *retnump = txdr_unsigned(retnum);
2527 return (retnum + prefixnum);
2531 * Put the attribute bits onto an mbuf list.
2532 * Return the number of bytes of output generated.
2535 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2538 int cnt, i, bytesize;
2540 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2541 if (attrbitp->bits[cnt - 1])
2543 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2544 NFSM_BUILD(tl, u_int32_t *, bytesize);
2545 *tl++ = txdr_unsigned(cnt);
2546 for (i = 0; i < cnt; i++)
2547 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2552 * Convert a uid to a string.
2553 * If the lookup fails, just output the digits.
2555 * cpp - points to a buffer of size NFSV4_SMALLSTR
2556 * (malloc a larger one, as required)
2557 * retlenp - pointer to length to be returned
2560 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2563 struct nfsusrgrp *usrp;
2566 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2567 struct nfsrv_lughash *hp;
2571 if (nfsrv_dnsnamelen > 0) {
2573 * Always map nfsrv_defaultuid to "nobody".
2575 if (uid == nfsrv_defaultuid) {
2576 i = nfsrv_dnsnamelen + 7;
2578 if (len > NFSV4_SMALLSTR)
2579 free(cp, M_NFSSTRING);
2580 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2586 NFSBCOPY("nobody@", cp, 7);
2588 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2592 hp = NFSUSERHASH(uid);
2594 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2595 if (usrp->lug_uid == uid) {
2596 if (usrp->lug_expiry < NFSD_MONOSEC)
2599 * If the name doesn't already have an '@'
2600 * in it, append @domainname to it.
2602 for (i = 0; i < usrp->lug_namelen; i++) {
2603 if (usrp->lug_name[i] == '@') {
2609 i = usrp->lug_namelen;
2611 i = usrp->lug_namelen +
2612 nfsrv_dnsnamelen + 1;
2614 mtx_unlock(&hp->mtx);
2615 if (len > NFSV4_SMALLSTR)
2616 free(cp, M_NFSSTRING);
2617 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2623 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2624 if (!hasampersand) {
2625 cp += usrp->lug_namelen;
2627 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2629 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2630 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2632 mtx_unlock(&hp->mtx);
2636 mtx_unlock(&hp->mtx);
2638 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2640 if (ret == 0 && cnt < 2)
2645 * No match, just return a string of digits.
2649 while (tmp || i == 0) {
2653 len = (i > len) ? len : i;
2657 for (i = 0; i < len; i++) {
2658 *cp-- = '0' + (tmp % 10);
2665 * Get a credential for the uid with the server's group list.
2666 * If none is found, just return the credential passed in after
2667 * logging a warning message.
2670 nfsrv_getgrpscred(struct ucred *oldcred)
2672 struct nfsusrgrp *usrp;
2673 struct ucred *newcred;
2676 struct nfsrv_lughash *hp;
2679 uid = oldcred->cr_uid;
2681 if (nfsrv_dnsnamelen > 0) {
2682 hp = NFSUSERHASH(uid);
2684 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2685 if (usrp->lug_uid == uid) {
2686 if (usrp->lug_expiry < NFSD_MONOSEC)
2688 if (usrp->lug_cred != NULL) {
2689 newcred = crhold(usrp->lug_cred);
2693 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2694 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2696 mtx_unlock(&hp->mtx);
2700 mtx_unlock(&hp->mtx);
2702 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2704 if (ret == 0 && cnt < 2)
2711 * Convert a string to a uid.
2712 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2714 * If this is called from a client side mount using AUTH_SYS and the
2715 * string is made up entirely of digits, just convert the string to
2719 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2723 char *cp, *endstr, *str0;
2724 struct nfsusrgrp *usrp;
2728 struct nfsrv_lughash *hp, *hp2;
2731 error = NFSERR_BADOWNER;
2734 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2736 tuid = (uid_t)strtoul(str0, &endstr, 10);
2737 if ((endstr - str0) == len) {
2738 /* A numeric string. */
2739 if ((nd->nd_flag & ND_KERBV) == 0 &&
2740 ((nd->nd_flag & ND_NFSCL) != 0 ||
2741 nfsd_enable_stringtouid != 0))
2744 error = NFSERR_BADOWNER;
2750 cp = strchr(str0, '@');
2752 i = (int)(cp++ - str0);
2758 if (nfsrv_dnsnamelen > 0) {
2760 * If an '@' is found and the domain name matches, search for
2761 * the name with dns stripped off.
2762 * Mixed case alpahbetics will match for the domain name, but
2763 * all upper case will not.
2765 if (cnt == 0 && i < len && i > 0 &&
2766 (len - 1 - i) == nfsrv_dnsnamelen &&
2767 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2768 len -= (nfsrv_dnsnamelen + 1);
2773 * Check for the special case of "nobody".
2775 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2776 *uidp = nfsrv_defaultuid;
2781 hp = NFSUSERNAMEHASH(str, len);
2783 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2784 if (usrp->lug_namelen == len &&
2785 !NFSBCMP(usrp->lug_name, str, len)) {
2786 if (usrp->lug_expiry < NFSD_MONOSEC)
2788 hp2 = NFSUSERHASH(usrp->lug_uid);
2789 mtx_lock(&hp2->mtx);
2790 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2791 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2793 *uidp = usrp->lug_uid;
2794 mtx_unlock(&hp2->mtx);
2795 mtx_unlock(&hp->mtx);
2800 mtx_unlock(&hp->mtx);
2802 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2804 if (ret == 0 && cnt < 2)
2807 error = NFSERR_BADOWNER;
2815 * Convert a gid to a string.
2816 * gid - the group id
2817 * cpp - points to a buffer of size NFSV4_SMALLSTR
2818 * (malloc a larger one, as required)
2819 * retlenp - pointer to length to be returned
2822 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2825 struct nfsusrgrp *usrp;
2828 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2829 struct nfsrv_lughash *hp;
2833 if (nfsrv_dnsnamelen > 0) {
2835 * Always map nfsrv_defaultgid to "nogroup".
2837 if (gid == nfsrv_defaultgid) {
2838 i = nfsrv_dnsnamelen + 8;
2840 if (len > NFSV4_SMALLSTR)
2841 free(cp, M_NFSSTRING);
2842 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2848 NFSBCOPY("nogroup@", cp, 8);
2850 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2854 hp = NFSGROUPHASH(gid);
2856 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2857 if (usrp->lug_gid == gid) {
2858 if (usrp->lug_expiry < NFSD_MONOSEC)
2861 * If the name doesn't already have an '@'
2862 * in it, append @domainname to it.
2864 for (i = 0; i < usrp->lug_namelen; i++) {
2865 if (usrp->lug_name[i] == '@') {
2871 i = usrp->lug_namelen;
2873 i = usrp->lug_namelen +
2874 nfsrv_dnsnamelen + 1;
2876 mtx_unlock(&hp->mtx);
2877 if (len > NFSV4_SMALLSTR)
2878 free(cp, M_NFSSTRING);
2879 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2885 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2886 if (!hasampersand) {
2887 cp += usrp->lug_namelen;
2889 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2891 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2892 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2894 mtx_unlock(&hp->mtx);
2898 mtx_unlock(&hp->mtx);
2900 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2902 if (ret == 0 && cnt < 2)
2907 * No match, just return a string of digits.
2911 while (tmp || i == 0) {
2915 len = (i > len) ? len : i;
2919 for (i = 0; i < len; i++) {
2920 *cp-- = '0' + (tmp % 10);
2927 * Convert a string to a gid.
2928 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2930 * If this is called from a client side mount using AUTH_SYS and the
2931 * string is made up entirely of digits, just convert the string to
2935 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2939 char *cp, *endstr, *str0;
2940 struct nfsusrgrp *usrp;
2944 struct nfsrv_lughash *hp, *hp2;
2947 error = NFSERR_BADOWNER;
2950 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2952 tgid = (gid_t)strtoul(str0, &endstr, 10);
2953 if ((endstr - str0) == len) {
2954 /* A numeric string. */
2955 if ((nd->nd_flag & ND_KERBV) == 0 &&
2956 ((nd->nd_flag & ND_NFSCL) != 0 ||
2957 nfsd_enable_stringtouid != 0))
2960 error = NFSERR_BADOWNER;
2966 cp = strchr(str0, '@');
2968 i = (int)(cp++ - str0);
2974 if (nfsrv_dnsnamelen > 0) {
2976 * If an '@' is found and the dns name matches, search for the
2977 * name with the dns stripped off.
2979 if (cnt == 0 && i < len && i > 0 &&
2980 (len - 1 - i) == nfsrv_dnsnamelen &&
2981 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2982 len -= (nfsrv_dnsnamelen + 1);
2987 * Check for the special case of "nogroup".
2989 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2990 *gidp = nfsrv_defaultgid;
2995 hp = NFSGROUPNAMEHASH(str, len);
2997 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2998 if (usrp->lug_namelen == len &&
2999 !NFSBCMP(usrp->lug_name, str, len)) {
3000 if (usrp->lug_expiry < NFSD_MONOSEC)
3002 hp2 = NFSGROUPHASH(usrp->lug_gid);
3003 mtx_lock(&hp2->mtx);
3004 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3005 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3007 *gidp = usrp->lug_gid;
3008 mtx_unlock(&hp2->mtx);
3009 mtx_unlock(&hp->mtx);
3014 mtx_unlock(&hp->mtx);
3016 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3018 if (ret == 0 && cnt < 2)
3021 error = NFSERR_BADOWNER;
3029 * Cmp len chars, allowing mixed case in the first argument to match lower
3030 * case in the second, but not if the first argument is all upper case.
3031 * Return 0 for a match, 1 otherwise.
3034 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3040 for (i = 0; i < len; i++) {
3041 if (*cp >= 'A' && *cp <= 'Z') {
3042 tmp = *cp++ + ('a' - 'A');
3045 if (tmp >= 'a' && tmp <= 'z')
3058 * Set the port for the nfsuserd.
3061 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3063 struct nfssockreq *rp;
3064 struct sockaddr_in *ad;
3068 if (nfsrv_nfsuserd) {
3076 * Set up the socket record and connect.
3078 rp = &nfsrv_nfsuserdsock;
3079 rp->nr_client = NULL;
3080 rp->nr_sotype = SOCK_DGRAM;
3081 rp->nr_soproto = IPPROTO_UDP;
3082 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3084 NFSSOCKADDRALLOC(rp->nr_nam);
3085 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3086 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3087 ad->sin_family = AF_INET;
3088 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3089 ad->sin_port = port;
3090 rp->nr_prog = RPCPROG_NFSUSERD;
3091 rp->nr_vers = RPCNFSUSERD_VERS;
3092 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3094 NFSSOCKADDRFREE(rp->nr_nam);
3103 * Delete the nfsuserd port.
3106 nfsrv_nfsuserddelport(void)
3110 if (nfsrv_nfsuserd == 0) {
3116 newnfs_disconnect(&nfsrv_nfsuserdsock);
3117 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3121 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3123 * Returns 0 upon success, non-zero otherwise.
3126 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3129 struct nfsrv_descript *nd;
3131 struct nfsrv_descript nfsd;
3136 if (nfsrv_nfsuserd == 0) {
3143 cred = newnfs_getcred();
3144 nd->nd_flag = ND_GSSINITREPLY;
3147 nd->nd_procnum = procnum;
3148 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3150 if (procnum == RPCNFSUSERD_GETUID)
3151 *tl = txdr_unsigned(uid);
3153 *tl = txdr_unsigned(gid);
3156 (void) nfsm_strtom(nd, name, len);
3158 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3159 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3162 mbuf_freem(nd->nd_mrep);
3163 error = nd->nd_repstat;
3171 * This function is called from the nfssvc(2) system call, to update the
3172 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3175 nfssvc_idname(struct nfsd_idargs *nidp)
3177 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3178 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3179 int i, group_locked, groupname_locked, user_locked, username_locked;
3184 static int onethread = 0;
3185 static time_t lasttime = 0;
3187 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3191 if (nidp->nid_flag & NFSID_INITIALIZE) {
3192 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3193 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3196 free(cp, M_NFSSTRING);
3199 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3201 * Free up all the old stuff and reinitialize hash
3202 * lists. All mutexes for both lists must be locked,
3203 * with the user/group name ones before the uid/gid
3204 * ones, to avoid a LOR.
3206 for (i = 0; i < nfsrv_lughashsize; i++)
3207 mtx_lock(&nfsusernamehash[i].mtx);
3208 for (i = 0; i < nfsrv_lughashsize; i++)
3209 mtx_lock(&nfsuserhash[i].mtx);
3210 for (i = 0; i < nfsrv_lughashsize; i++)
3211 TAILQ_FOREACH_SAFE(usrp,
3212 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3213 nfsrv_removeuser(usrp, 1);
3214 for (i = 0; i < nfsrv_lughashsize; i++)
3215 mtx_unlock(&nfsuserhash[i].mtx);
3216 for (i = 0; i < nfsrv_lughashsize; i++)
3217 mtx_unlock(&nfsusernamehash[i].mtx);
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 mtx_lock(&nfsgroupnamehash[i].mtx);
3220 for (i = 0; i < nfsrv_lughashsize; i++)
3221 mtx_lock(&nfsgrouphash[i].mtx);
3222 for (i = 0; i < nfsrv_lughashsize; i++)
3223 TAILQ_FOREACH_SAFE(usrp,
3224 &nfsgrouphash[i].lughead, lug_numhash,
3226 nfsrv_removeuser(usrp, 0);
3227 for (i = 0; i < nfsrv_lughashsize; i++)
3228 mtx_unlock(&nfsgrouphash[i].mtx);
3229 for (i = 0; i < nfsrv_lughashsize; i++)
3230 mtx_unlock(&nfsgroupnamehash[i].mtx);
3231 free(nfsrv_dnsname, M_NFSSTRING);
3232 nfsrv_dnsname = NULL;
3234 if (nfsuserhash == NULL) {
3235 /* Allocate the hash tables. */
3236 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3237 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3239 for (i = 0; i < nfsrv_lughashsize; i++)
3240 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3241 NULL, MTX_DEF | MTX_DUPOK);
3242 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3243 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3245 for (i = 0; i < nfsrv_lughashsize; i++)
3246 mtx_init(&nfsusernamehash[i].mtx,
3247 "nfsusrhash", NULL, MTX_DEF |
3249 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3250 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3252 for (i = 0; i < nfsrv_lughashsize; i++)
3253 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3254 NULL, MTX_DEF | MTX_DUPOK);
3255 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3256 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3258 for (i = 0; i < nfsrv_lughashsize; i++)
3259 mtx_init(&nfsgroupnamehash[i].mtx,
3260 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3262 /* (Re)initialize the list heads. */
3263 for (i = 0; i < nfsrv_lughashsize; i++)
3264 TAILQ_INIT(&nfsuserhash[i].lughead);
3265 for (i = 0; i < nfsrv_lughashsize; i++)
3266 TAILQ_INIT(&nfsusernamehash[i].lughead);
3267 for (i = 0; i < nfsrv_lughashsize; i++)
3268 TAILQ_INIT(&nfsgrouphash[i].lughead);
3269 for (i = 0; i < nfsrv_lughashsize; i++)
3270 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3273 * Put name in "DNS" string.
3276 nfsrv_defaultuid = nidp->nid_uid;
3277 nfsrv_defaultgid = nidp->nid_gid;
3279 nfsrv_usermax = nidp->nid_usermax;
3280 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3285 * malloc the new one now, so any potential sleep occurs before
3286 * manipulation of the lists.
3288 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3289 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3290 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3292 if (error == 0 && nidp->nid_ngroup > 0 &&
3293 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3294 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3296 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3297 sizeof(gid_t) * nidp->nid_ngroup);
3300 * Create a credential just like svc_getcred(),
3301 * but using the group list provided.
3304 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3305 crsetgroups(cr, nidp->nid_ngroup, grps);
3306 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3307 cr->cr_prison = &prison0;
3308 prison_hold(cr->cr_prison);
3310 mac_cred_associate_nfsd(cr);
3312 newusrp->lug_cred = cr;
3317 free(newusrp, M_NFSUSERGROUP);
3320 newusrp->lug_namelen = nidp->nid_namelen;
3323 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3324 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3325 * The flags user_locked, username_locked, group_locked and
3326 * groupname_locked are set to indicate all of those hash lists are
3327 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3328 * the respective one mutex is locked.
3330 user_locked = username_locked = group_locked = groupname_locked = 0;
3331 hp_name = hp_idnum = NULL;
3334 * Delete old entries, as required.
3336 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3337 /* Must lock all username hash lists first, to avoid a LOR. */
3338 for (i = 0; i < nfsrv_lughashsize; i++)
3339 mtx_lock(&nfsusernamehash[i].mtx);
3340 username_locked = 1;
3341 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3342 mtx_lock(&hp_idnum->mtx);
3343 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3345 if (usrp->lug_uid == nidp->nid_uid)
3346 nfsrv_removeuser(usrp, 1);
3348 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3349 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3350 newusrp->lug_namelen);
3351 mtx_lock(&hp_name->mtx);
3352 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3354 if (usrp->lug_namelen == newusrp->lug_namelen &&
3355 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3356 usrp->lug_namelen)) {
3357 thp = NFSUSERHASH(usrp->lug_uid);
3358 mtx_lock(&thp->mtx);
3359 nfsrv_removeuser(usrp, 1);
3360 mtx_unlock(&thp->mtx);
3363 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3364 mtx_lock(&hp_idnum->mtx);
3365 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3366 /* Must lock all groupname hash lists first, to avoid a LOR. */
3367 for (i = 0; i < nfsrv_lughashsize; i++)
3368 mtx_lock(&nfsgroupnamehash[i].mtx);
3369 groupname_locked = 1;
3370 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3371 mtx_lock(&hp_idnum->mtx);
3372 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3374 if (usrp->lug_gid == nidp->nid_gid)
3375 nfsrv_removeuser(usrp, 0);
3377 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3378 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3379 newusrp->lug_namelen);
3380 mtx_lock(&hp_name->mtx);
3381 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3383 if (usrp->lug_namelen == newusrp->lug_namelen &&
3384 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3385 usrp->lug_namelen)) {
3386 thp = NFSGROUPHASH(usrp->lug_gid);
3387 mtx_lock(&thp->mtx);
3388 nfsrv_removeuser(usrp, 0);
3389 mtx_unlock(&thp->mtx);
3392 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3393 mtx_lock(&hp_idnum->mtx);
3397 * Now, we can add the new one.
3399 if (nidp->nid_usertimeout)
3400 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3402 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3403 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3404 newusrp->lug_uid = nidp->nid_uid;
3405 thp = NFSUSERHASH(newusrp->lug_uid);
3406 mtx_assert(&thp->mtx, MA_OWNED);
3407 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3408 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3409 mtx_assert(&thp->mtx, MA_OWNED);
3410 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3411 atomic_add_int(&nfsrv_usercnt, 1);
3412 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3413 newusrp->lug_gid = nidp->nid_gid;
3414 thp = NFSGROUPHASH(newusrp->lug_gid);
3415 mtx_assert(&thp->mtx, MA_OWNED);
3416 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3417 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3418 mtx_assert(&thp->mtx, MA_OWNED);
3419 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3420 atomic_add_int(&nfsrv_usercnt, 1);
3422 if (newusrp->lug_cred != NULL)
3423 crfree(newusrp->lug_cred);
3424 free(newusrp, M_NFSUSERGROUP);
3428 * Once per second, allow one thread to trim the cache.
3430 if (lasttime < NFSD_MONOSEC &&
3431 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3433 * First, unlock the single mutexes, so that all entries
3434 * can be locked and any LOR is avoided.
3436 if (hp_name != NULL) {
3437 mtx_unlock(&hp_name->mtx);
3440 if (hp_idnum != NULL) {
3441 mtx_unlock(&hp_idnum->mtx);
3445 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3446 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3447 if (username_locked == 0) {
3448 for (i = 0; i < nfsrv_lughashsize; i++)
3449 mtx_lock(&nfsusernamehash[i].mtx);
3450 username_locked = 1;
3452 KASSERT(user_locked == 0,
3453 ("nfssvc_idname: user_locked"));
3454 for (i = 0; i < nfsrv_lughashsize; i++)
3455 mtx_lock(&nfsuserhash[i].mtx);
3457 for (i = 0; i < nfsrv_lughashsize; i++) {
3458 TAILQ_FOREACH_SAFE(usrp,
3459 &nfsuserhash[i].lughead, lug_numhash,
3461 if (usrp->lug_expiry < NFSD_MONOSEC)
3462 nfsrv_removeuser(usrp, 1);
3464 for (i = 0; i < nfsrv_lughashsize; i++) {
3466 * Trim the cache using an approximate LRU
3467 * algorithm. This code deletes the least
3468 * recently used entry on each hash list.
3470 if (nfsrv_usercnt <= nfsrv_usermax)
3472 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3474 nfsrv_removeuser(usrp, 1);
3477 if (groupname_locked == 0) {
3478 for (i = 0; i < nfsrv_lughashsize; i++)
3479 mtx_lock(&nfsgroupnamehash[i].mtx);
3480 groupname_locked = 1;
3482 KASSERT(group_locked == 0,
3483 ("nfssvc_idname: group_locked"));
3484 for (i = 0; i < nfsrv_lughashsize; i++)
3485 mtx_lock(&nfsgrouphash[i].mtx);
3487 for (i = 0; i < nfsrv_lughashsize; i++) {
3488 TAILQ_FOREACH_SAFE(usrp,
3489 &nfsgrouphash[i].lughead, lug_numhash,
3491 if (usrp->lug_expiry < NFSD_MONOSEC)
3492 nfsrv_removeuser(usrp, 0);
3494 for (i = 0; i < nfsrv_lughashsize; i++) {
3496 * Trim the cache using an approximate LRU
3497 * algorithm. This code deletes the least
3498 * recently user entry on each hash list.
3500 if (nfsrv_usercnt <= nfsrv_usermax)
3502 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3504 nfsrv_removeuser(usrp, 0);
3507 lasttime = NFSD_MONOSEC;
3508 atomic_store_rel_int(&onethread, 0);
3511 /* Now, unlock all locked mutexes. */
3512 if (hp_idnum != NULL)
3513 mtx_unlock(&hp_idnum->mtx);
3514 if (hp_name != NULL)
3515 mtx_unlock(&hp_name->mtx);
3516 if (user_locked != 0)
3517 for (i = 0; i < nfsrv_lughashsize; i++)
3518 mtx_unlock(&nfsuserhash[i].mtx);
3519 if (username_locked != 0)
3520 for (i = 0; i < nfsrv_lughashsize; i++)
3521 mtx_unlock(&nfsusernamehash[i].mtx);
3522 if (group_locked != 0)
3523 for (i = 0; i < nfsrv_lughashsize; i++)
3524 mtx_unlock(&nfsgrouphash[i].mtx);
3525 if (groupname_locked != 0)
3526 for (i = 0; i < nfsrv_lughashsize; i++)
3527 mtx_unlock(&nfsgroupnamehash[i].mtx);
3534 * Remove a user/group name element.
3537 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3539 struct nfsrv_lughash *hp;
3542 hp = NFSUSERHASH(usrp->lug_uid);
3543 mtx_assert(&hp->mtx, MA_OWNED);
3544 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3545 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3546 mtx_assert(&hp->mtx, MA_OWNED);
3547 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3549 hp = NFSGROUPHASH(usrp->lug_gid);
3550 mtx_assert(&hp->mtx, MA_OWNED);
3551 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3552 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3553 mtx_assert(&hp->mtx, MA_OWNED);
3554 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3556 atomic_add_int(&nfsrv_usercnt, -1);
3557 if (usrp->lug_cred != NULL)
3558 crfree(usrp->lug_cred);
3559 free(usrp, M_NFSUSERGROUP);
3563 * Free up all the allocations related to the name<-->id cache.
3564 * This function should only be called when the nfsuserd daemon isn't
3565 * running, since it doesn't do any locking.
3566 * This function is meant to be used when the nfscommon module is unloaded.
3569 nfsrv_cleanusergroup(void)
3571 struct nfsrv_lughash *hp, *hp2;
3572 struct nfsusrgrp *nusrp, *usrp;
3575 if (nfsuserhash == NULL)
3578 for (i = 0; i < nfsrv_lughashsize; i++) {
3579 hp = &nfsuserhash[i];
3580 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3581 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3582 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3584 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3585 if (usrp->lug_cred != NULL)
3586 crfree(usrp->lug_cred);
3587 free(usrp, M_NFSUSERGROUP);
3589 hp = &nfsgrouphash[i];
3590 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3591 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3592 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3594 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3595 if (usrp->lug_cred != NULL)
3596 crfree(usrp->lug_cred);
3597 free(usrp, M_NFSUSERGROUP);
3599 mtx_destroy(&nfsuserhash[i].mtx);
3600 mtx_destroy(&nfsusernamehash[i].mtx);
3601 mtx_destroy(&nfsgroupnamehash[i].mtx);
3602 mtx_destroy(&nfsgrouphash[i].mtx);
3604 free(nfsuserhash, M_NFSUSERGROUP);
3605 free(nfsusernamehash, M_NFSUSERGROUP);
3606 free(nfsgrouphash, M_NFSUSERGROUP);
3607 free(nfsgroupnamehash, M_NFSUSERGROUP);
3608 free(nfsrv_dnsname, M_NFSSTRING);
3612 * This function scans a byte string and checks for UTF-8 compliance.
3613 * It returns 0 if it conforms and NFSERR_INVAL if not.
3616 nfsrv_checkutf8(u_int8_t *cp, int len)
3618 u_int32_t val = 0x0;
3619 int cnt = 0, gotd = 0, shift = 0;
3621 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3625 * Here are what the variables are used for:
3626 * val - the calculated value of a multibyte char, used to check
3627 * that it was coded with the correct range
3628 * cnt - the number of 10xxxxxx bytes to follow
3629 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3630 * shift - lower order bits of range (ie. "val >> shift" should
3631 * not be 0, in other words, dividing by the lower bound
3632 * of the range should get a non-zero value)
3633 * byte - used to calculate cnt
3637 /* This handles the 10xxxxxx bytes */
3638 if ((*cp & 0xc0) != 0x80 ||
3639 (gotd && (*cp & 0x20))) {
3640 error = NFSERR_INVAL;
3645 val |= (*cp & 0x3f);
3647 if (cnt == 0 && (val >> shift) == 0x0) {
3648 error = NFSERR_INVAL;
3651 } else if (*cp & 0x80) {
3652 /* first byte of multi byte char */
3654 while ((byte & 0x40) && cnt < 6) {
3658 if (cnt == 0 || cnt == 6) {
3659 error = NFSERR_INVAL;
3662 val = (*cp & (0x3f >> cnt));
3663 shift = utf8_shift[cnt - 1];
3664 if (cnt == 2 && val == 0xd)
3665 /* Check for the 0xd800-0xdfff case */
3672 error = NFSERR_INVAL;
3680 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3681 * strings, one with the root path in it and the other with the list of
3682 * locations. The list is in the same format as is found in nfr_refs.
3683 * It is a "," separated list of entries, where each of them is of the
3684 * form <server>:<rootpath>. For example
3685 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3686 * The nilp argument is set to 1 for the special case of a null fs_root
3687 * and an empty server list.
3688 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3689 * number of xdr bytes parsed in sump.
3692 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3693 int *sump, int *nilp)
3696 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3697 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3699 SLIST_ENTRY(list) next;
3703 SLIST_HEAD(, list) head;
3710 * Get the fs_root path and check for the special case of null path
3711 * and 0 length server list.
3713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3714 len = fxdr_unsigned(int, *tl);
3715 if (len < 0 || len > 10240) {
3716 error = NFSERR_BADXDR;
3720 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3722 error = NFSERR_BADXDR;
3726 *sump = 2 * NFSX_UNSIGNED;
3730 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3731 error = nfsrv_mtostr(nd, cp, len);
3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3734 cnt = fxdr_unsigned(int, *tl);
3736 error = NFSERR_BADXDR;
3742 * Now, loop through the location list and make up the srvlist.
3744 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3745 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3748 for (i = 0; i < cnt; i++) {
3750 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3751 nsrv = fxdr_unsigned(int, *tl);
3753 error = NFSERR_BADXDR;
3758 * Handle the first server by putting it in the srvstr.
3760 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3761 len = fxdr_unsigned(int, *tl);
3762 if (len <= 0 || len > 1024) {
3763 error = NFSERR_BADXDR;
3766 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3771 error = nfsrv_mtostr(nd, cp3, len);
3777 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3778 for (j = 1; j < nsrv; j++) {
3780 * Yuck, put them in an slist and process them later.
3782 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3783 len = fxdr_unsigned(int, *tl);
3784 if (len <= 0 || len > 1024) {
3785 error = NFSERR_BADXDR;
3788 lsp = (struct list *)malloc(sizeof (struct list)
3789 + len, M_TEMP, M_WAITOK);
3790 error = nfsrv_mtostr(nd, lsp->host, len);
3793 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3795 SLIST_INSERT_HEAD(&head, lsp, next);
3799 * Finally, we can get the path.
3801 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3802 len = fxdr_unsigned(int, *tl);
3803 if (len <= 0 || len > 1024) {
3804 error = NFSERR_BADXDR;
3807 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3808 error = nfsrv_mtostr(nd, cp3, len);
3811 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3816 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3817 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3820 NFSBCOPY(lsp->host, cp3, lsp->len);
3823 NFSBCOPY(str, cp3, stringlen);
3826 siz += (lsp->len + stringlen + 2);
3827 free((caddr_t)lsp, M_TEMP);
3833 NFSEXITCODE2(0, nd);
3837 free(cp, M_NFSSTRING);
3839 free(cp2, M_NFSSTRING);
3840 NFSEXITCODE2(error, nd);
3845 * Make the malloc'd space large enough. This is a pain, but the xdr
3846 * doesn't set an upper bound on the side, so...
3849 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3856 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3857 NFSBCOPY(*cpp, cp, *slenp);
3858 free(*cpp, M_NFSSTRING);
3862 *slenp = siz + 1024;
3866 * Initialize the reply header data structures.
3869 nfsrvd_rephead(struct nfsrv_descript *nd)
3874 * If this is a big reply, use a cluster.
3876 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3877 nfs_bigreply[nd->nd_procnum]) {
3878 NFSMCLGET(mreq, M_WAITOK);
3886 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3887 mbuf_setlen(mreq, 0);
3889 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3890 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3894 * Lock a socket against others.
3895 * Currently used to serialize connect/disconnect attempts.
3898 newnfs_sndlock(int *flagp)
3903 while (*flagp & NFSR_SNDLOCK) {
3904 *flagp |= NFSR_WANTSND;
3907 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3908 PZERO - 1, "nfsndlck", &ts);
3910 *flagp |= NFSR_SNDLOCK;
3916 * Unlock the stream socket for others.
3919 newnfs_sndunlock(int *flagp)
3923 if ((*flagp & NFSR_SNDLOCK) == 0)
3924 panic("nfs sndunlock");
3925 *flagp &= ~NFSR_SNDLOCK;
3926 if (*flagp & NFSR_WANTSND) {
3927 *flagp &= ~NFSR_WANTSND;
3928 wakeup((caddr_t)flagp);
3934 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3937 struct sockaddr_in *sad;
3938 struct sockaddr_in6 *sad6;
3939 struct in_addr saddr;
3940 uint32_t portnum, *tl;
3941 int af = 0, i, j, k;
3942 char addr[64], protocol[5], *cp;
3943 int cantparse = 0, error = 0;
3946 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3947 i = fxdr_unsigned(int, *tl);
3948 if (i >= 3 && i <= 4) {
3949 error = nfsrv_mtostr(nd, protocol, i);
3952 if (strcmp(protocol, "tcp") == 0) {
3955 } else if (strcmp(protocol, "udp") == 0) {
3958 } else if (strcmp(protocol, "tcp6") == 0) {
3961 } else if (strcmp(protocol, "udp6") == 0) {
3969 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3974 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3975 i = fxdr_unsigned(int, *tl);
3977 error = NFSERR_BADXDR;
3979 } else if (cantparse == 0 && i >= 11 && i < 64) {
3981 * The shortest address is 11chars and the longest is < 64.
3983 error = nfsrv_mtostr(nd, addr, i);
3987 /* Find the port# at the end and extract that. */
3991 /* Count back two '.'s from end to get port# field. */
3992 for (j = 0; j < i; j++) {
4002 * The NFSv4 port# is appended as .N.N, where N is
4003 * a decimal # in the range 0-255, just like an inet4
4004 * address. Cheat and use inet_aton(), which will
4005 * return a Class A address and then shift the high
4006 * order 8bits over to convert it to the port#.
4009 if (inet_aton(cp, &saddr) == 1) {
4010 portnum = ntohl(saddr.s_addr);
4011 portv = (uint16_t)((portnum >> 16) |
4017 if (cantparse == 0) {
4018 if (af == AF_INET) {
4019 sad = (struct sockaddr_in *)sa;
4020 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4021 sad->sin_len = sizeof(*sad);
4022 sad->sin_family = AF_INET;
4023 sad->sin_port = htons(portv);
4027 sad6 = (struct sockaddr_in6 *)sa;
4028 if (inet_pton(af, addr, &sad6->sin6_addr)
4030 sad6->sin6_len = sizeof(*sad6);
4031 sad6->sin6_family = AF_INET6;
4032 sad6->sin6_port = htons(portv);
4039 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4050 * Handle an NFSv4.1 Sequence request for the session.
4051 * If reply != NULL, use it to return the cached reply, as required.
4052 * The client gets a cached reply via this call for callbacks, however the
4053 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4056 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4057 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4064 if (slotid > maxslot)
4065 return (NFSERR_BADSLOT);
4066 if (seqid == slots[slotid].nfssl_seq) {
4068 if (slots[slotid].nfssl_inprog != 0)
4069 error = NFSERR_DELAY;
4070 else if (slots[slotid].nfssl_reply != NULL) {
4071 if (reply != NULL) {
4072 *reply = slots[slotid].nfssl_reply;
4073 slots[slotid].nfssl_reply = NULL;
4075 slots[slotid].nfssl_inprog = 1;
4076 error = NFSERR_REPLYFROMCACHE;
4078 /* No reply cached, so just do it. */
4079 slots[slotid].nfssl_inprog = 1;
4080 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4081 if (slots[slotid].nfssl_reply != NULL)
4082 m_freem(slots[slotid].nfssl_reply);
4083 slots[slotid].nfssl_reply = NULL;
4084 slots[slotid].nfssl_inprog = 1;
4085 slots[slotid].nfssl_seq++;
4087 error = NFSERR_SEQMISORDERED;
4092 * Cache this reply for the slot.
4093 * Use the "rep" argument to return the cached reply if repstat is set to
4094 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4097 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4101 if (repstat == NFSERR_REPLYFROMCACHE) {
4102 *rep = slots[slotid].nfssl_reply;
4103 slots[slotid].nfssl_reply = NULL;
4105 if (slots[slotid].nfssl_reply != NULL)
4106 m_freem(slots[slotid].nfssl_reply);
4107 slots[slotid].nfssl_reply = *rep;
4109 slots[slotid].nfssl_inprog = 0;
4113 * Generate the xdr for an NFSv4.1 Sequence Operation.
4116 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4117 struct nfsclsession *sep, int dont_replycache)
4119 uint32_t *tl, slotseq = 0;
4120 int error, maxslot, slotpos;
4121 uint8_t sessionid[NFSX_V4SESSIONID];
4123 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4127 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
4129 /* Build the Sequence arguments. */
4130 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4131 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4132 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4133 nd->nd_slotseq = tl;
4134 *tl++ = txdr_unsigned(slotseq);
4135 *tl++ = txdr_unsigned(slotpos);
4136 *tl++ = txdr_unsigned(maxslot);
4137 if (dont_replycache == 0)
4141 nd->nd_flag |= ND_HASSEQUENCE;
4145 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4146 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4148 int i, maxslot, slotpos;
4151 /* Find an unused slot. */
4154 mtx_lock(&sep->nfsess_mtx);
4157 for (i = 0; i < sep->nfsess_foreslots; i++) {
4158 if ((bitval & sep->nfsess_slots) == 0) {
4160 sep->nfsess_slots |= bitval;
4161 sep->nfsess_slotseq[i]++;
4162 *slotseqp = sep->nfsess_slotseq[i];
4167 if (slotpos == -1) {
4169 * If a forced dismount is in progress, just return.
4170 * This RPC attempt will fail when it calls
4174 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4176 mtx_unlock(&sep->nfsess_mtx);
4179 /* Wake up once/sec, to check for a forced dismount. */
4180 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4181 PZERO, "nfsclseq", hz);
4183 } while (slotpos == -1);
4184 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4186 for (i = 0; i < 64; i++) {
4187 if ((bitval & sep->nfsess_slots) != 0)
4191 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4192 mtx_unlock(&sep->nfsess_mtx);
4193 *slotposp = slotpos;
4194 *maxslotp = maxslot;
4199 * Free a session slot.
4202 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4209 mtx_lock(&sep->nfsess_mtx);
4210 if ((bitval & sep->nfsess_slots) == 0)
4211 printf("freeing free slot!!\n");
4212 sep->nfsess_slots &= ~bitval;
4213 wakeup(&sep->nfsess_slots);
4214 mtx_unlock(&sep->nfsess_mtx);