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;
833 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
835 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
841 *retcmpp = retnotsup;
844 * Just set default values to some of the important ones.
849 nap->na_rdev = (NFSDEV_T)0;
850 nap->na_mtime.tv_sec = 0;
851 nap->na_mtime.tv_nsec = 0;
854 nap->na_blocksize = NFS_FABLKSIZE;
857 sbp->f_bsize = NFS_FABLKSIZE;
865 fsp->fs_rtmax = 8192;
866 fsp->fs_rtpref = 8192;
867 fsp->fs_maxname = NFS_MAXNAMLEN;
868 fsp->fs_wtmax = 8192;
869 fsp->fs_wtpref = 8192;
870 fsp->fs_wtmult = NFS_FABLKSIZE;
871 fsp->fs_dtpref = 8192;
872 fsp->fs_maxfilesize = 0xffffffffffffffffull;
873 fsp->fs_timedelta.tv_sec = 0;
874 fsp->fs_timedelta.tv_nsec = 1;
875 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
876 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
879 pc->pc_linkmax = LINK_MAX;
880 pc->pc_namemax = NAME_MAX;
882 pc->pc_chownrestricted = 0;
883 pc->pc_caseinsensitive = 0;
884 pc->pc_casepreserving = 1;
889 * Loop around getting the attributes.
891 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
892 attrsize = fxdr_unsigned(int, *tl);
893 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
894 if (attrsum > attrsize) {
895 error = NFSERR_BADXDR;
898 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
900 case NFSATTRBIT_SUPPORTEDATTRS:
902 if (compare || nap == NULL)
903 error = nfsrv_getattrbits(nd, &retattrbits,
906 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
910 if (compare && !(*retcmpp)) {
911 NFSSETSUPP_ATTRBIT(&checkattrbits);
912 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
914 *retcmpp = NFSERR_NOTSAME;
918 case NFSATTRBIT_TYPE:
919 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
922 if (nap->na_type != nfsv34tov_type(*tl))
923 *retcmpp = NFSERR_NOTSAME;
925 } else if (nap != NULL) {
926 nap->na_type = nfsv34tov_type(*tl);
928 attrsum += NFSX_UNSIGNED;
930 case NFSATTRBIT_FHEXPIRETYPE:
931 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
932 if (compare && !(*retcmpp)) {
933 if (fxdr_unsigned(int, *tl) !=
934 NFSV4FHTYPE_PERSISTENT)
935 *retcmpp = NFSERR_NOTSAME;
937 attrsum += NFSX_UNSIGNED;
939 case NFSATTRBIT_CHANGE:
940 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
943 if (nap->na_filerev != fxdr_hyper(tl))
944 *retcmpp = NFSERR_NOTSAME;
946 } else if (nap != NULL) {
947 nap->na_filerev = fxdr_hyper(tl);
949 attrsum += NFSX_HYPER;
951 case NFSATTRBIT_SIZE:
952 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
955 if (nap->na_size != fxdr_hyper(tl))
956 *retcmpp = NFSERR_NOTSAME;
958 } else if (nap != NULL) {
959 nap->na_size = fxdr_hyper(tl);
961 attrsum += NFSX_HYPER;
963 case NFSATTRBIT_LINKSUPPORT:
964 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
967 if (fsp->fs_properties & NFSV3_FSFLINK) {
968 if (*tl == newnfs_false)
969 *retcmpp = NFSERR_NOTSAME;
971 if (*tl == newnfs_true)
972 *retcmpp = NFSERR_NOTSAME;
975 } else if (fsp != NULL) {
976 if (*tl == newnfs_true)
977 fsp->fs_properties |= NFSV3_FSFLINK;
979 fsp->fs_properties &= ~NFSV3_FSFLINK;
981 attrsum += NFSX_UNSIGNED;
983 case NFSATTRBIT_SYMLINKSUPPORT:
984 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
988 if (*tl == newnfs_false)
989 *retcmpp = NFSERR_NOTSAME;
991 if (*tl == newnfs_true)
992 *retcmpp = NFSERR_NOTSAME;
995 } else if (fsp != NULL) {
996 if (*tl == newnfs_true)
997 fsp->fs_properties |= NFSV3_FSFSYMLINK;
999 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1001 attrsum += NFSX_UNSIGNED;
1003 case NFSATTRBIT_NAMEDATTR:
1004 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1005 if (compare && !(*retcmpp)) {
1006 if (*tl != newnfs_false)
1007 *retcmpp = NFSERR_NOTSAME;
1009 attrsum += NFSX_UNSIGNED;
1011 case NFSATTRBIT_FSID:
1012 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1013 thyp = fxdr_hyper(tl);
1015 thyp2 = fxdr_hyper(tl);
1017 if (*retcmpp == 0) {
1018 if (thyp != (u_int64_t)
1019 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1020 thyp2 != (u_int64_t)
1021 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1022 *retcmpp = NFSERR_NOTSAME;
1024 } else if (nap != NULL) {
1025 nap->na_filesid[0] = thyp;
1026 nap->na_filesid[1] = thyp2;
1028 attrsum += (4 * NFSX_UNSIGNED);
1030 case NFSATTRBIT_UNIQUEHANDLES:
1031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1032 if (compare && !(*retcmpp)) {
1033 if (*tl != newnfs_true)
1034 *retcmpp = NFSERR_NOTSAME;
1036 attrsum += NFSX_UNSIGNED;
1038 case NFSATTRBIT_LEASETIME:
1039 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1041 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1043 *retcmpp = NFSERR_NOTSAME;
1044 } else if (leasep != NULL) {
1045 *leasep = fxdr_unsigned(u_int32_t, *tl);
1047 attrsum += NFSX_UNSIGNED;
1049 case NFSATTRBIT_RDATTRERROR:
1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053 *retcmpp = NFSERR_INVAL;
1054 } else if (rderrp != NULL) {
1055 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1057 attrsum += NFSX_UNSIGNED;
1059 case NFSATTRBIT_ACL:
1065 naclp = acl_alloc(M_WAITOK);
1066 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1072 if (aceerr || aclp == NULL ||
1073 nfsrv_compareacl(aclp, naclp))
1074 *retcmpp = NFSERR_NOTSAME;
1077 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1079 *retcmpp = NFSERR_ATTRNOTSUPP;
1083 if (vp != NULL && aclp != NULL)
1084 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1087 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1094 case NFSATTRBIT_ACLSUPPORT:
1095 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1096 if (compare && !(*retcmpp)) {
1098 if (fxdr_unsigned(u_int32_t, *tl) !=
1100 *retcmpp = NFSERR_NOTSAME;
1102 *retcmpp = NFSERR_ATTRNOTSUPP;
1105 attrsum += NFSX_UNSIGNED;
1107 case NFSATTRBIT_ARCHIVE:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 if (compare && !(*retcmpp))
1110 *retcmpp = NFSERR_ATTRNOTSUPP;
1111 attrsum += NFSX_UNSIGNED;
1113 case NFSATTRBIT_CANSETTIME:
1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1117 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1118 if (*tl == newnfs_false)
1119 *retcmpp = NFSERR_NOTSAME;
1121 if (*tl == newnfs_true)
1122 *retcmpp = NFSERR_NOTSAME;
1125 } else if (fsp != NULL) {
1126 if (*tl == newnfs_true)
1127 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1129 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1131 attrsum += NFSX_UNSIGNED;
1133 case NFSATTRBIT_CASEINSENSITIVE:
1134 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1137 if (*tl != newnfs_false)
1138 *retcmpp = NFSERR_NOTSAME;
1140 } else if (pc != NULL) {
1141 pc->pc_caseinsensitive =
1142 fxdr_unsigned(u_int32_t, *tl);
1144 attrsum += NFSX_UNSIGNED;
1146 case NFSATTRBIT_CASEPRESERVING:
1147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1150 if (*tl != newnfs_true)
1151 *retcmpp = NFSERR_NOTSAME;
1153 } else if (pc != NULL) {
1154 pc->pc_casepreserving =
1155 fxdr_unsigned(u_int32_t, *tl);
1157 attrsum += NFSX_UNSIGNED;
1159 case NFSATTRBIT_CHOWNRESTRICTED:
1160 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1163 if (*tl != newnfs_true)
1164 *retcmpp = NFSERR_NOTSAME;
1166 } else if (pc != NULL) {
1167 pc->pc_chownrestricted =
1168 fxdr_unsigned(u_int32_t, *tl);
1170 attrsum += NFSX_UNSIGNED;
1172 case NFSATTRBIT_FILEHANDLE:
1173 error = nfsm_getfh(nd, &tnfhp);
1176 tfhsize = tnfhp->nfh_len;
1179 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1181 *retcmpp = NFSERR_NOTSAME;
1182 FREE((caddr_t)tnfhp, M_NFSFH);
1183 } else if (nfhpp != NULL) {
1186 FREE((caddr_t)tnfhp, M_NFSFH);
1188 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1190 case NFSATTRBIT_FILEID:
1191 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1192 thyp = fxdr_hyper(tl);
1195 if ((u_int64_t)nap->na_fileid != thyp)
1196 *retcmpp = NFSERR_NOTSAME;
1198 } else if (nap != NULL) {
1200 printf("NFSv4 fileid > 32bits\n");
1201 nap->na_fileid = thyp;
1203 attrsum += NFSX_HYPER;
1205 case NFSATTRBIT_FILESAVAIL:
1206 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1209 sfp->sf_afiles != fxdr_hyper(tl))
1210 *retcmpp = NFSERR_NOTSAME;
1211 } else if (sfp != NULL) {
1212 sfp->sf_afiles = fxdr_hyper(tl);
1214 attrsum += NFSX_HYPER;
1216 case NFSATTRBIT_FILESFREE:
1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1220 sfp->sf_ffiles != fxdr_hyper(tl))
1221 *retcmpp = NFSERR_NOTSAME;
1222 } else if (sfp != NULL) {
1223 sfp->sf_ffiles = fxdr_hyper(tl);
1225 attrsum += NFSX_HYPER;
1227 case NFSATTRBIT_FILESTOTAL:
1228 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1231 sfp->sf_tfiles != fxdr_hyper(tl))
1232 *retcmpp = NFSERR_NOTSAME;
1233 } else if (sfp != NULL) {
1234 sfp->sf_tfiles = fxdr_hyper(tl);
1236 attrsum += NFSX_HYPER;
1238 case NFSATTRBIT_FSLOCATIONS:
1239 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1243 if (compare && !(*retcmpp)) {
1244 refp = nfsv4root_getreferral(vp, NULL, 0);
1246 if (cp == NULL || cp2 == NULL ||
1248 strcmp(cp2, refp->nfr_srvlist))
1249 *retcmpp = NFSERR_NOTSAME;
1250 } else if (m == 0) {
1251 *retcmpp = NFSERR_NOTSAME;
1255 free(cp, M_NFSSTRING);
1257 free(cp2, M_NFSSTRING);
1259 case NFSATTRBIT_HIDDEN:
1260 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1261 if (compare && !(*retcmpp))
1262 *retcmpp = NFSERR_ATTRNOTSUPP;
1263 attrsum += NFSX_UNSIGNED;
1265 case NFSATTRBIT_HOMOGENEOUS:
1266 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1269 if (fsp->fs_properties &
1270 NFSV3_FSFHOMOGENEOUS) {
1271 if (*tl == newnfs_false)
1272 *retcmpp = NFSERR_NOTSAME;
1274 if (*tl == newnfs_true)
1275 *retcmpp = NFSERR_NOTSAME;
1278 } else if (fsp != NULL) {
1279 if (*tl == newnfs_true)
1280 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1282 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1284 attrsum += NFSX_UNSIGNED;
1286 case NFSATTRBIT_MAXFILESIZE:
1287 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1288 tnfsquad.qval = fxdr_hyper(tl);
1291 tquad = NFSRV_MAXFILESIZE;
1292 if (tquad != tnfsquad.qval)
1293 *retcmpp = NFSERR_NOTSAME;
1295 } else if (fsp != NULL) {
1296 fsp->fs_maxfilesize = tnfsquad.qval;
1298 attrsum += NFSX_HYPER;
1300 case NFSATTRBIT_MAXLINK:
1301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1304 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1305 *retcmpp = NFSERR_NOTSAME;
1307 } else if (pc != NULL) {
1308 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1310 attrsum += NFSX_UNSIGNED;
1312 case NFSATTRBIT_MAXNAME:
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1316 if (fsp->fs_maxname !=
1317 fxdr_unsigned(u_int32_t, *tl))
1318 *retcmpp = NFSERR_NOTSAME;
1321 tuint = fxdr_unsigned(u_int32_t, *tl);
1323 * Some Linux NFSv4 servers report this
1324 * as 0 or 4billion, so I'll set it to
1325 * NFS_MAXNAMLEN. If a server actually creates
1326 * a name longer than NFS_MAXNAMLEN, it will
1327 * get an error back.
1329 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1330 tuint = NFS_MAXNAMLEN;
1332 fsp->fs_maxname = tuint;
1334 pc->pc_namemax = tuint;
1336 attrsum += NFSX_UNSIGNED;
1338 case NFSATTRBIT_MAXREAD:
1339 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1342 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1343 *(tl + 1)) || *tl != 0)
1344 *retcmpp = NFSERR_NOTSAME;
1346 } else if (fsp != NULL) {
1347 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1348 fsp->fs_rtpref = fsp->fs_rtmax;
1349 fsp->fs_dtpref = fsp->fs_rtpref;
1351 attrsum += NFSX_HYPER;
1353 case NFSATTRBIT_MAXWRITE:
1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1357 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1358 *(tl + 1)) || *tl != 0)
1359 *retcmpp = NFSERR_NOTSAME;
1361 } else if (fsp != NULL) {
1362 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1363 fsp->fs_wtpref = fsp->fs_wtmax;
1365 attrsum += NFSX_HYPER;
1367 case NFSATTRBIT_MIMETYPE:
1368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1369 i = fxdr_unsigned(int, *tl);
1370 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1371 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1374 if (compare && !(*retcmpp))
1375 *retcmpp = NFSERR_ATTRNOTSUPP;
1377 case NFSATTRBIT_MODE:
1378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1381 if (nap->na_mode != nfstov_mode(*tl))
1382 *retcmpp = NFSERR_NOTSAME;
1384 } else if (nap != NULL) {
1385 nap->na_mode = nfstov_mode(*tl);
1387 attrsum += NFSX_UNSIGNED;
1389 case NFSATTRBIT_NOTRUNC:
1390 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1393 if (*tl != newnfs_true)
1394 *retcmpp = NFSERR_NOTSAME;
1396 } else if (pc != NULL) {
1397 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1399 attrsum += NFSX_UNSIGNED;
1401 case NFSATTRBIT_NUMLINKS:
1402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1403 tuint = fxdr_unsigned(u_int32_t, *tl);
1406 if ((u_int32_t)nap->na_nlink != tuint)
1407 *retcmpp = NFSERR_NOTSAME;
1409 } else if (nap != NULL) {
1410 nap->na_nlink = tuint;
1412 attrsum += NFSX_UNSIGNED;
1414 case NFSATTRBIT_OWNER:
1415 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1416 j = fxdr_unsigned(int, *tl);
1418 error = NFSERR_BADXDR;
1421 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1422 if (j > NFSV4_SMALLSTR)
1423 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1426 error = nfsrv_mtostr(nd, cp, j);
1428 if (j > NFSV4_SMALLSTR)
1429 free(cp, M_NFSSTRING);
1434 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1436 *retcmpp = NFSERR_NOTSAME;
1438 } else if (nap != NULL) {
1439 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1440 nap->na_uid = nfsrv_defaultuid;
1444 if (j > NFSV4_SMALLSTR)
1445 free(cp, M_NFSSTRING);
1447 case NFSATTRBIT_OWNERGROUP:
1448 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1449 j = fxdr_unsigned(int, *tl);
1451 error = NFSERR_BADXDR;
1454 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1455 if (j > NFSV4_SMALLSTR)
1456 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1459 error = nfsrv_mtostr(nd, cp, j);
1461 if (j > NFSV4_SMALLSTR)
1462 free(cp, M_NFSSTRING);
1467 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1469 *retcmpp = NFSERR_NOTSAME;
1471 } else if (nap != NULL) {
1472 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1473 nap->na_gid = nfsrv_defaultgid;
1477 if (j > NFSV4_SMALLSTR)
1478 free(cp, M_NFSSTRING);
1480 case NFSATTRBIT_QUOTAHARD:
1481 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1483 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1484 freenum = sbp->f_bfree;
1486 freenum = sbp->f_bavail;
1489 * ufs_quotactl() insists that the uid argument
1490 * equal p_ruid for non-root quota access, so
1491 * we'll just make sure that's the case.
1493 savuid = p->p_cred->p_ruid;
1494 p->p_cred->p_ruid = cred->cr_uid;
1495 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1496 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1497 freenum = min(dqb.dqb_bhardlimit, freenum);
1498 p->p_cred->p_ruid = savuid;
1500 uquad = (u_int64_t)freenum;
1501 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1503 if (compare && !(*retcmpp)) {
1504 if (uquad != fxdr_hyper(tl))
1505 *retcmpp = NFSERR_NOTSAME;
1507 attrsum += NFSX_HYPER;
1509 case NFSATTRBIT_QUOTASOFT:
1510 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1512 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1513 freenum = sbp->f_bfree;
1515 freenum = sbp->f_bavail;
1518 * ufs_quotactl() insists that the uid argument
1519 * equal p_ruid for non-root quota access, so
1520 * we'll just make sure that's the case.
1522 savuid = p->p_cred->p_ruid;
1523 p->p_cred->p_ruid = cred->cr_uid;
1524 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1525 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1526 freenum = min(dqb.dqb_bsoftlimit, freenum);
1527 p->p_cred->p_ruid = savuid;
1529 uquad = (u_int64_t)freenum;
1530 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1532 if (compare && !(*retcmpp)) {
1533 if (uquad != fxdr_hyper(tl))
1534 *retcmpp = NFSERR_NOTSAME;
1536 attrsum += NFSX_HYPER;
1538 case NFSATTRBIT_QUOTAUSED:
1539 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1544 * ufs_quotactl() insists that the uid argument
1545 * equal p_ruid for non-root quota access, so
1546 * we'll just make sure that's the case.
1548 savuid = p->p_cred->p_ruid;
1549 p->p_cred->p_ruid = cred->cr_uid;
1550 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1551 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1552 freenum = dqb.dqb_curblocks;
1553 p->p_cred->p_ruid = savuid;
1555 uquad = (u_int64_t)freenum;
1556 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1558 if (compare && !(*retcmpp)) {
1559 if (uquad != fxdr_hyper(tl))
1560 *retcmpp = NFSERR_NOTSAME;
1562 attrsum += NFSX_HYPER;
1564 case NFSATTRBIT_RAWDEV:
1565 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1566 j = fxdr_unsigned(int, *tl++);
1567 k = fxdr_unsigned(int, *tl);
1570 if (nap->na_rdev != NFSMAKEDEV(j, k))
1571 *retcmpp = NFSERR_NOTSAME;
1573 } else if (nap != NULL) {
1574 nap->na_rdev = NFSMAKEDEV(j, k);
1576 attrsum += NFSX_V4SPECDATA;
1578 case NFSATTRBIT_SPACEAVAIL:
1579 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1582 sfp->sf_abytes != fxdr_hyper(tl))
1583 *retcmpp = NFSERR_NOTSAME;
1584 } else if (sfp != NULL) {
1585 sfp->sf_abytes = fxdr_hyper(tl);
1587 attrsum += NFSX_HYPER;
1589 case NFSATTRBIT_SPACEFREE:
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1593 sfp->sf_fbytes != fxdr_hyper(tl))
1594 *retcmpp = NFSERR_NOTSAME;
1595 } else if (sfp != NULL) {
1596 sfp->sf_fbytes = fxdr_hyper(tl);
1598 attrsum += NFSX_HYPER;
1600 case NFSATTRBIT_SPACETOTAL:
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1604 sfp->sf_tbytes != fxdr_hyper(tl))
1605 *retcmpp = NFSERR_NOTSAME;
1606 } else if (sfp != NULL) {
1607 sfp->sf_tbytes = fxdr_hyper(tl);
1609 attrsum += NFSX_HYPER;
1611 case NFSATTRBIT_SPACEUSED:
1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1613 thyp = fxdr_hyper(tl);
1616 if ((u_int64_t)nap->na_bytes != thyp)
1617 *retcmpp = NFSERR_NOTSAME;
1619 } else if (nap != NULL) {
1620 nap->na_bytes = thyp;
1622 attrsum += NFSX_HYPER;
1624 case NFSATTRBIT_SYSTEM:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1626 if (compare && !(*retcmpp))
1627 *retcmpp = NFSERR_ATTRNOTSUPP;
1628 attrsum += NFSX_UNSIGNED;
1630 case NFSATTRBIT_TIMEACCESS:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1632 fxdr_nfsv4time(tl, &temptime);
1635 if (!NFS_CMPTIME(temptime, nap->na_atime))
1636 *retcmpp = NFSERR_NOTSAME;
1638 } else if (nap != NULL) {
1639 nap->na_atime = temptime;
1641 attrsum += NFSX_V4TIME;
1643 case NFSATTRBIT_TIMEACCESSSET:
1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 attrsum += NFSX_UNSIGNED;
1646 i = fxdr_unsigned(int, *tl);
1647 if (i == NFSV4SATTRTIME_TOCLIENT) {
1648 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1649 attrsum += NFSX_V4TIME;
1651 if (compare && !(*retcmpp))
1652 *retcmpp = NFSERR_INVAL;
1654 case NFSATTRBIT_TIMEBACKUP:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1656 if (compare && !(*retcmpp))
1657 *retcmpp = NFSERR_ATTRNOTSUPP;
1658 attrsum += NFSX_V4TIME;
1660 case NFSATTRBIT_TIMECREATE:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1662 if (compare && !(*retcmpp))
1663 *retcmpp = NFSERR_ATTRNOTSUPP;
1664 attrsum += NFSX_V4TIME;
1666 case NFSATTRBIT_TIMEDELTA:
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1671 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1672 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1673 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1674 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1677 *retcmpp = NFSERR_NOTSAME;
1680 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMEMETADATA:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1687 fxdr_nfsv4time(tl, &temptime);
1690 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1691 *retcmpp = NFSERR_NOTSAME;
1693 } else if (nap != NULL) {
1694 nap->na_ctime = temptime;
1696 attrsum += NFSX_V4TIME;
1698 case NFSATTRBIT_TIMEMODIFY:
1699 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1700 fxdr_nfsv4time(tl, &temptime);
1703 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1704 *retcmpp = NFSERR_NOTSAME;
1706 } else if (nap != NULL) {
1707 nap->na_mtime = temptime;
1709 attrsum += NFSX_V4TIME;
1711 case NFSATTRBIT_TIMEMODIFYSET:
1712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1713 attrsum += NFSX_UNSIGNED;
1714 i = fxdr_unsigned(int, *tl);
1715 if (i == NFSV4SATTRTIME_TOCLIENT) {
1716 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1717 attrsum += NFSX_V4TIME;
1719 if (compare && !(*retcmpp))
1720 *retcmpp = NFSERR_INVAL;
1722 case NFSATTRBIT_MOUNTEDONFILEID:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1724 thyp = fxdr_hyper(tl);
1728 *retcmpp = NFSERR_NOTSAME;
1730 if (!vp || !nfsrv_atroot(vp, &fid))
1731 fid = nap->na_fileid;
1732 if ((u_int64_t)fid != thyp)
1733 *retcmpp = NFSERR_NOTSAME;
1736 } else if (nap != NULL) {
1738 printf("NFSv4 mounted on fileid > 32bits\n");
1739 nap->na_mntonfileno = thyp;
1741 attrsum += NFSX_HYPER;
1743 case NFSATTRBIT_SUPPATTREXCLCREAT:
1745 error = nfsrv_getattrbits(nd, &retattrbits,
1749 if (compare && !(*retcmpp)) {
1750 NFSSETSUPP_ATTRBIT(&checkattrbits);
1751 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1752 NFSCLRBIT_ATTRBIT(&checkattrbits,
1753 NFSATTRBIT_TIMEACCESSSET);
1754 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1756 *retcmpp = NFSERR_NOTSAME;
1761 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1763 if (compare && !(*retcmpp))
1764 *retcmpp = NFSERR_ATTRNOTSUPP;
1766 * and get out of the loop, since we can't parse
1767 * the unknown attrbute data.
1769 bitpos = NFSATTRBIT_MAX;
1775 * some clients pad the attrlist, so we need to skip over the
1778 if (attrsum > attrsize) {
1779 error = NFSERR_BADXDR;
1781 attrsize = NFSM_RNDUP(attrsize);
1782 if (attrsum < attrsize)
1783 error = nfsm_advance(nd, attrsize - attrsum, -1);
1786 NFSEXITCODE2(error, nd);
1791 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1792 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1793 * The first argument is a pointer to an nfsv4lock structure.
1794 * The second argument is 1 iff a blocking lock is wanted.
1795 * If this argument is 0, the call waits until no thread either wants nor
1796 * holds an exclusive lock.
1797 * It returns 1 if the lock was acquired, 0 otherwise.
1798 * If several processes call this function concurrently wanting the exclusive
1799 * lock, one will get the lock and the rest will return without getting the
1800 * lock. (If the caller must have the lock, it simply calls this function in a
1801 * loop until the function returns 1 to indicate the lock was acquired.)
1802 * Any usecnt must be decremented by calling nfsv4_relref() before
1803 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1804 * be called in a loop.
1805 * The isleptp argument is set to indicate if the call slept, iff not NULL
1806 * and the mp argument indicates to check for a forced dismount, iff not
1810 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1811 void *mutex, struct mount *mp)
1817 * If a lock is wanted, loop around until the lock is acquired by
1818 * someone and then released. If I want the lock, try to acquire it.
1819 * For a lock to be issued, no lock must be in force and the usecnt
1823 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1824 lp->nfslock_usecnt == 0) {
1825 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1826 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1829 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1831 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1832 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1833 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1836 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1839 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1840 PZERO - 1, "nfsv4lck", NULL);
1841 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1842 lp->nfslock_usecnt == 0) {
1843 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1844 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1852 * Release the lock acquired by nfsv4_lock().
1853 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1854 * incremented, as well.
1857 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1860 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1862 lp->nfslock_usecnt++;
1867 * Release a reference cnt.
1870 nfsv4_relref(struct nfsv4lock *lp)
1873 if (lp->nfslock_usecnt <= 0)
1874 panic("nfsv4root ref cnt");
1875 lp->nfslock_usecnt--;
1876 if (lp->nfslock_usecnt == 0)
1881 * Get a reference cnt.
1882 * This function will wait for any exclusive lock to be released, but will
1883 * not wait for threads that want the exclusive lock. If priority needs
1884 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1885 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1886 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1887 * return without getting a refcnt for that case.
1890 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1898 * Wait for a lock held.
1900 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1901 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1903 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1906 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1907 PZERO - 1, "nfsv4gr", NULL);
1909 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1912 lp->nfslock_usecnt++;
1916 * Get a reference as above, but return failure instead of sleeping if
1917 * an exclusive lock is held.
1920 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1923 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1926 lp->nfslock_usecnt++;
1931 * Test for a lock. Return 1 if locked, 0 otherwise.
1934 nfsv4_testlock(struct nfsv4lock *lp)
1937 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1938 lp->nfslock_usecnt == 0)
1944 * Wake up anyone sleeping, waiting for this lock.
1947 nfsv4_wanted(struct nfsv4lock *lp)
1950 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1951 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1952 wakeup((caddr_t)&lp->nfslock_lock);
1957 * Copy a string from an mbuf list into a character array.
1958 * Return EBADRPC if there is an mbuf error,
1962 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1971 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1972 rem = NFSM_RNDUP(siz) - siz;
1978 NFSBCOPY(cp, str, xfer);
1987 cp = NFSMTOD(mp, caddr_t);
1999 error = nfsm_advance(nd, rem, len);
2005 NFSEXITCODE2(error, nd);
2010 * Fill in the attributes as marked by the bitmap (V4).
2013 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2014 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2015 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2016 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2018 int bitpos, retnum = 0;
2020 int siz, prefixnum, error;
2021 u_char *cp, namestr[NFSV4_SMALLSTR];
2022 nfsattrbit_t attrbits, retbits;
2023 nfsattrbit_t *retbitp = &retbits;
2024 u_int32_t freenum, *retnump;
2027 struct nfsfsinfo fsinf;
2028 struct timespec temptime;
2029 NFSACL_T *aclp, *naclp = NULL;
2036 * First, set the bits that can be filled and get fsinfo.
2038 NFSSET_ATTRBIT(retbitp, attrbitp);
2040 * If both p and cred are NULL, it is a client side setattr call.
2041 * If both p and cred are not NULL, it is a server side reply call.
2042 * If p is not NULL and cred is NULL, it is a client side callback
2045 if (p == NULL && cred == NULL) {
2046 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2049 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2050 naclp = acl_alloc(M_WAITOK);
2053 nfsvno_getfs(&fsinf, isdgram);
2056 * Get the VFS_STATFS(), since some attributes need them.
2058 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2059 error = VFS_STATFS(mp, &fs);
2062 nd->nd_repstat = NFSERR_ACCES;
2065 NFSCLRSTATFS_ATTRBIT(retbitp);
2071 * And the NFSv4 ACL...
2073 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2074 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2075 supports_nfsv4acls == 0))) {
2076 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2078 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2079 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2080 supports_nfsv4acls == 0)) {
2081 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2082 } else if (naclp != NULL) {
2083 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2084 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2086 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2088 NFSVOPUNLOCK(vp, 0);
2090 error = NFSERR_PERM;
2093 nd->nd_repstat = NFSERR_ACCES;
2096 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2101 * Put out the attribute bitmap for the ones being filled in
2102 * and get the field for the number of attributes returned.
2104 prefixnum = nfsrv_putattrbit(nd, retbitp);
2105 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2106 prefixnum += NFSX_UNSIGNED;
2109 * Now, loop around filling in the attributes for each bit set.
2111 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2112 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2114 case NFSATTRBIT_SUPPORTEDATTRS:
2115 NFSSETSUPP_ATTRBIT(&attrbits);
2116 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2117 && supports_nfsv4acls == 0)) {
2118 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2119 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2121 retnum += nfsrv_putattrbit(nd, &attrbits);
2123 case NFSATTRBIT_TYPE:
2124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2125 *tl = vtonfsv34_type(vap->va_type);
2126 retnum += NFSX_UNSIGNED;
2128 case NFSATTRBIT_FHEXPIRETYPE:
2129 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2130 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2131 retnum += NFSX_UNSIGNED;
2133 case NFSATTRBIT_CHANGE:
2134 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2135 txdr_hyper(vap->va_filerev, tl);
2136 retnum += NFSX_HYPER;
2138 case NFSATTRBIT_SIZE:
2139 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2140 txdr_hyper(vap->va_size, tl);
2141 retnum += NFSX_HYPER;
2143 case NFSATTRBIT_LINKSUPPORT:
2144 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2145 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2149 retnum += NFSX_UNSIGNED;
2151 case NFSATTRBIT_SYMLINKSUPPORT:
2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2153 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2157 retnum += NFSX_UNSIGNED;
2159 case NFSATTRBIT_NAMEDATTR:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2162 retnum += NFSX_UNSIGNED;
2164 case NFSATTRBIT_FSID:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2167 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2169 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2170 retnum += NFSX_V4FSID;
2172 case NFSATTRBIT_UNIQUEHANDLES:
2173 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 retnum += NFSX_UNSIGNED;
2177 case NFSATTRBIT_LEASETIME:
2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2179 *tl = txdr_unsigned(nfsrv_lease);
2180 retnum += NFSX_UNSIGNED;
2182 case NFSATTRBIT_RDATTRERROR:
2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2184 *tl = txdr_unsigned(rderror);
2185 retnum += NFSX_UNSIGNED;
2188 * Recommended Attributes. (Only the supported ones.)
2190 case NFSATTRBIT_ACL:
2191 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2193 case NFSATTRBIT_ACLSUPPORT:
2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2195 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2196 retnum += NFSX_UNSIGNED;
2198 case NFSATTRBIT_CANSETTIME:
2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2200 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2204 retnum += NFSX_UNSIGNED;
2206 case NFSATTRBIT_CASEINSENSITIVE:
2207 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2209 retnum += NFSX_UNSIGNED;
2211 case NFSATTRBIT_CASEPRESERVING:
2212 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2214 retnum += NFSX_UNSIGNED;
2216 case NFSATTRBIT_CHOWNRESTRICTED:
2217 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2219 retnum += NFSX_UNSIGNED;
2221 case NFSATTRBIT_FILEHANDLE:
2222 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2224 case NFSATTRBIT_FILEID:
2225 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2227 *tl = txdr_unsigned(vap->va_fileid);
2228 retnum += NFSX_HYPER;
2230 case NFSATTRBIT_FILESAVAIL:
2232 * Check quota and use min(quota, f_ffree).
2234 freenum = fs.f_ffree;
2237 * ufs_quotactl() insists that the uid argument
2238 * equal p_ruid for non-root quota access, so
2239 * we'll just make sure that's the case.
2241 savuid = p->p_cred->p_ruid;
2242 p->p_cred->p_ruid = cred->cr_uid;
2243 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2244 cred->cr_uid, (caddr_t)&dqb))
2245 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2247 p->p_cred->p_ruid = savuid;
2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2251 *tl = txdr_unsigned(freenum);
2252 retnum += NFSX_HYPER;
2254 case NFSATTRBIT_FILESFREE:
2255 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2257 *tl = txdr_unsigned(fs.f_ffree);
2258 retnum += NFSX_HYPER;
2260 case NFSATTRBIT_FILESTOTAL:
2261 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2263 *tl = txdr_unsigned(fs.f_files);
2264 retnum += NFSX_HYPER;
2266 case NFSATTRBIT_FSLOCATIONS:
2267 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2270 retnum += 2 * NFSX_UNSIGNED;
2272 case NFSATTRBIT_HOMOGENEOUS:
2273 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2274 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2278 retnum += NFSX_UNSIGNED;
2280 case NFSATTRBIT_MAXFILESIZE:
2281 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2282 uquad = NFSRV_MAXFILESIZE;
2283 txdr_hyper(uquad, tl);
2284 retnum += NFSX_HYPER;
2286 case NFSATTRBIT_MAXLINK:
2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2288 *tl = txdr_unsigned(LINK_MAX);
2289 retnum += NFSX_UNSIGNED;
2291 case NFSATTRBIT_MAXNAME:
2292 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2293 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2294 retnum += NFSX_UNSIGNED;
2296 case NFSATTRBIT_MAXREAD:
2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2299 *tl = txdr_unsigned(fsinf.fs_rtmax);
2300 retnum += NFSX_HYPER;
2302 case NFSATTRBIT_MAXWRITE:
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2305 *tl = txdr_unsigned(fsinf.fs_wtmax);
2306 retnum += NFSX_HYPER;
2308 case NFSATTRBIT_MODE:
2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2310 *tl = vtonfsv34_mode(vap->va_mode);
2311 retnum += NFSX_UNSIGNED;
2313 case NFSATTRBIT_NOTRUNC:
2314 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2316 retnum += NFSX_UNSIGNED;
2318 case NFSATTRBIT_NUMLINKS:
2319 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2320 *tl = txdr_unsigned(vap->va_nlink);
2321 retnum += NFSX_UNSIGNED;
2323 case NFSATTRBIT_OWNER:
2325 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2326 retnum += nfsm_strtom(nd, cp, siz);
2328 free(cp, M_NFSSTRING);
2330 case NFSATTRBIT_OWNERGROUP:
2332 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2333 retnum += nfsm_strtom(nd, cp, siz);
2335 free(cp, M_NFSSTRING);
2337 case NFSATTRBIT_QUOTAHARD:
2338 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2339 freenum = fs.f_bfree;
2341 freenum = fs.f_bavail;
2344 * ufs_quotactl() insists that the uid argument
2345 * equal p_ruid for non-root quota access, so
2346 * we'll just make sure that's the case.
2348 savuid = p->p_cred->p_ruid;
2349 p->p_cred->p_ruid = cred->cr_uid;
2350 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2351 cred->cr_uid, (caddr_t)&dqb))
2352 freenum = min(dqb.dqb_bhardlimit, freenum);
2353 p->p_cred->p_ruid = savuid;
2355 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2356 uquad = (u_int64_t)freenum;
2357 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2358 txdr_hyper(uquad, tl);
2359 retnum += NFSX_HYPER;
2361 case NFSATTRBIT_QUOTASOFT:
2362 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2363 freenum = fs.f_bfree;
2365 freenum = fs.f_bavail;
2368 * ufs_quotactl() insists that the uid argument
2369 * equal p_ruid for non-root quota access, so
2370 * we'll just make sure that's the case.
2372 savuid = p->p_cred->p_ruid;
2373 p->p_cred->p_ruid = cred->cr_uid;
2374 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2375 cred->cr_uid, (caddr_t)&dqb))
2376 freenum = min(dqb.dqb_bsoftlimit, freenum);
2377 p->p_cred->p_ruid = savuid;
2379 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2380 uquad = (u_int64_t)freenum;
2381 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2382 txdr_hyper(uquad, tl);
2383 retnum += NFSX_HYPER;
2385 case NFSATTRBIT_QUOTAUSED:
2389 * ufs_quotactl() insists that the uid argument
2390 * equal p_ruid for non-root quota access, so
2391 * we'll just make sure that's the case.
2393 savuid = p->p_cred->p_ruid;
2394 p->p_cred->p_ruid = cred->cr_uid;
2395 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2396 cred->cr_uid, (caddr_t)&dqb))
2397 freenum = dqb.dqb_curblocks;
2398 p->p_cred->p_ruid = savuid;
2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2401 uquad = (u_int64_t)freenum;
2402 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2403 txdr_hyper(uquad, tl);
2404 retnum += NFSX_HYPER;
2406 case NFSATTRBIT_RAWDEV:
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2408 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2409 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2410 retnum += NFSX_V4SPECDATA;
2412 case NFSATTRBIT_SPACEAVAIL:
2413 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2414 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2415 uquad = (u_int64_t)fs.f_bfree;
2417 uquad = (u_int64_t)fs.f_bavail;
2418 uquad *= fs.f_bsize;
2419 txdr_hyper(uquad, tl);
2420 retnum += NFSX_HYPER;
2422 case NFSATTRBIT_SPACEFREE:
2423 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2424 uquad = (u_int64_t)fs.f_bfree;
2425 uquad *= fs.f_bsize;
2426 txdr_hyper(uquad, tl);
2427 retnum += NFSX_HYPER;
2429 case NFSATTRBIT_SPACETOTAL:
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2431 uquad = (u_int64_t)fs.f_blocks;
2432 uquad *= fs.f_bsize;
2433 txdr_hyper(uquad, tl);
2434 retnum += NFSX_HYPER;
2436 case NFSATTRBIT_SPACEUSED:
2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2438 txdr_hyper(vap->va_bytes, tl);
2439 retnum += NFSX_HYPER;
2441 case NFSATTRBIT_TIMEACCESS:
2442 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2443 txdr_nfsv4time(&vap->va_atime, tl);
2444 retnum += NFSX_V4TIME;
2446 case NFSATTRBIT_TIMEACCESSSET:
2447 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2448 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2449 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2450 txdr_nfsv4time(&vap->va_atime, tl);
2451 retnum += NFSX_V4SETTIME;
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2454 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2455 retnum += NFSX_UNSIGNED;
2458 case NFSATTRBIT_TIMEDELTA:
2459 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2460 temptime.tv_sec = 0;
2461 temptime.tv_nsec = 1000000000 / hz;
2462 txdr_nfsv4time(&temptime, tl);
2463 retnum += NFSX_V4TIME;
2465 case NFSATTRBIT_TIMEMETADATA:
2466 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2467 txdr_nfsv4time(&vap->va_ctime, tl);
2468 retnum += NFSX_V4TIME;
2470 case NFSATTRBIT_TIMEMODIFY:
2471 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2472 txdr_nfsv4time(&vap->va_mtime, tl);
2473 retnum += NFSX_V4TIME;
2475 case NFSATTRBIT_TIMEMODIFYSET:
2476 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2477 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2478 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2479 txdr_nfsv4time(&vap->va_mtime, tl);
2480 retnum += NFSX_V4SETTIME;
2482 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2483 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2484 retnum += NFSX_UNSIGNED;
2487 case NFSATTRBIT_MOUNTEDONFILEID:
2488 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2490 uquad = mounted_on_fileno;
2492 uquad = (u_int64_t)vap->va_fileid;
2493 txdr_hyper(uquad, tl);
2494 retnum += NFSX_HYPER;
2496 case NFSATTRBIT_SUPPATTREXCLCREAT:
2497 NFSSETSUPP_ATTRBIT(&attrbits);
2498 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2499 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2500 retnum += nfsrv_putattrbit(nd, &attrbits);
2503 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2509 *retnump = txdr_unsigned(retnum);
2510 return (retnum + prefixnum);
2514 * Put the attribute bits onto an mbuf list.
2515 * Return the number of bytes of output generated.
2518 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2521 int cnt, i, bytesize;
2523 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2524 if (attrbitp->bits[cnt - 1])
2526 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2527 NFSM_BUILD(tl, u_int32_t *, bytesize);
2528 *tl++ = txdr_unsigned(cnt);
2529 for (i = 0; i < cnt; i++)
2530 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2535 * Convert a uid to a string.
2536 * If the lookup fails, just output the digits.
2538 * cpp - points to a buffer of size NFSV4_SMALLSTR
2539 * (malloc a larger one, as required)
2540 * retlenp - pointer to length to be returned
2543 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2546 struct nfsusrgrp *usrp;
2549 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2550 struct nfsrv_lughash *hp;
2554 if (nfsrv_dnsnamelen > 0) {
2556 * Always map nfsrv_defaultuid to "nobody".
2558 if (uid == nfsrv_defaultuid) {
2559 i = nfsrv_dnsnamelen + 7;
2561 if (len > NFSV4_SMALLSTR)
2562 free(cp, M_NFSSTRING);
2563 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2569 NFSBCOPY("nobody@", cp, 7);
2571 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2575 hp = NFSUSERHASH(uid);
2577 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2578 if (usrp->lug_uid == uid) {
2579 if (usrp->lug_expiry < NFSD_MONOSEC)
2582 * If the name doesn't already have an '@'
2583 * in it, append @domainname to it.
2585 for (i = 0; i < usrp->lug_namelen; i++) {
2586 if (usrp->lug_name[i] == '@') {
2592 i = usrp->lug_namelen;
2594 i = usrp->lug_namelen +
2595 nfsrv_dnsnamelen + 1;
2597 mtx_unlock(&hp->mtx);
2598 if (len > NFSV4_SMALLSTR)
2599 free(cp, M_NFSSTRING);
2600 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2606 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2607 if (!hasampersand) {
2608 cp += usrp->lug_namelen;
2610 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2612 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2613 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2615 mtx_unlock(&hp->mtx);
2619 mtx_unlock(&hp->mtx);
2621 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2623 if (ret == 0 && cnt < 2)
2628 * No match, just return a string of digits.
2632 while (tmp || i == 0) {
2636 len = (i > len) ? len : i;
2640 for (i = 0; i < len; i++) {
2641 *cp-- = '0' + (tmp % 10);
2648 * Get a credential for the uid with the server's group list.
2649 * If none is found, just return the credential passed in after
2650 * logging a warning message.
2653 nfsrv_getgrpscred(struct ucred *oldcred)
2655 struct nfsusrgrp *usrp;
2656 struct ucred *newcred;
2659 struct nfsrv_lughash *hp;
2662 uid = oldcred->cr_uid;
2664 if (nfsrv_dnsnamelen > 0) {
2665 hp = NFSUSERHASH(uid);
2667 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2668 if (usrp->lug_uid == uid) {
2669 if (usrp->lug_expiry < NFSD_MONOSEC)
2671 if (usrp->lug_cred != NULL) {
2672 newcred = crhold(usrp->lug_cred);
2676 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2677 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2679 mtx_unlock(&hp->mtx);
2683 mtx_unlock(&hp->mtx);
2685 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2687 if (ret == 0 && cnt < 2)
2694 * Convert a string to a uid.
2695 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2697 * If this is called from a client side mount using AUTH_SYS and the
2698 * string is made up entirely of digits, just convert the string to
2702 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2706 char *cp, *endstr, *str0;
2707 struct nfsusrgrp *usrp;
2711 struct nfsrv_lughash *hp, *hp2;
2714 error = NFSERR_BADOWNER;
2717 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2719 tuid = (uid_t)strtoul(str0, &endstr, 10);
2720 if ((endstr - str0) == len) {
2721 /* A numeric string. */
2722 if ((nd->nd_flag & ND_KERBV) == 0 &&
2723 ((nd->nd_flag & ND_NFSCL) != 0 ||
2724 nfsd_enable_stringtouid != 0))
2727 error = NFSERR_BADOWNER;
2733 cp = strchr(str0, '@');
2735 i = (int)(cp++ - str0);
2741 if (nfsrv_dnsnamelen > 0) {
2743 * If an '@' is found and the domain name matches, search for
2744 * the name with dns stripped off.
2745 * Mixed case alpahbetics will match for the domain name, but
2746 * all upper case will not.
2748 if (cnt == 0 && i < len && i > 0 &&
2749 (len - 1 - i) == nfsrv_dnsnamelen &&
2750 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2751 len -= (nfsrv_dnsnamelen + 1);
2756 * Check for the special case of "nobody".
2758 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2759 *uidp = nfsrv_defaultuid;
2764 hp = NFSUSERNAMEHASH(str, len);
2766 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2767 if (usrp->lug_namelen == len &&
2768 !NFSBCMP(usrp->lug_name, str, len)) {
2769 if (usrp->lug_expiry < NFSD_MONOSEC)
2771 hp2 = NFSUSERHASH(usrp->lug_uid);
2772 mtx_lock(&hp2->mtx);
2773 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2774 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2776 *uidp = usrp->lug_uid;
2777 mtx_unlock(&hp2->mtx);
2778 mtx_unlock(&hp->mtx);
2783 mtx_unlock(&hp->mtx);
2785 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2787 if (ret == 0 && cnt < 2)
2790 error = NFSERR_BADOWNER;
2798 * Convert a gid to a string.
2799 * gid - the group id
2800 * cpp - points to a buffer of size NFSV4_SMALLSTR
2801 * (malloc a larger one, as required)
2802 * retlenp - pointer to length to be returned
2805 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2808 struct nfsusrgrp *usrp;
2811 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2812 struct nfsrv_lughash *hp;
2816 if (nfsrv_dnsnamelen > 0) {
2818 * Always map nfsrv_defaultgid to "nogroup".
2820 if (gid == nfsrv_defaultgid) {
2821 i = nfsrv_dnsnamelen + 8;
2823 if (len > NFSV4_SMALLSTR)
2824 free(cp, M_NFSSTRING);
2825 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2831 NFSBCOPY("nogroup@", cp, 8);
2833 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2837 hp = NFSGROUPHASH(gid);
2839 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2840 if (usrp->lug_gid == gid) {
2841 if (usrp->lug_expiry < NFSD_MONOSEC)
2844 * If the name doesn't already have an '@'
2845 * in it, append @domainname to it.
2847 for (i = 0; i < usrp->lug_namelen; i++) {
2848 if (usrp->lug_name[i] == '@') {
2854 i = usrp->lug_namelen;
2856 i = usrp->lug_namelen +
2857 nfsrv_dnsnamelen + 1;
2859 mtx_unlock(&hp->mtx);
2860 if (len > NFSV4_SMALLSTR)
2861 free(cp, M_NFSSTRING);
2862 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2868 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2869 if (!hasampersand) {
2870 cp += usrp->lug_namelen;
2872 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2874 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2875 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2877 mtx_unlock(&hp->mtx);
2881 mtx_unlock(&hp->mtx);
2883 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2885 if (ret == 0 && cnt < 2)
2890 * No match, just return a string of digits.
2894 while (tmp || i == 0) {
2898 len = (i > len) ? len : i;
2902 for (i = 0; i < len; i++) {
2903 *cp-- = '0' + (tmp % 10);
2910 * Convert a string to a gid.
2911 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2913 * If this is called from a client side mount using AUTH_SYS and the
2914 * string is made up entirely of digits, just convert the string to
2918 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2922 char *cp, *endstr, *str0;
2923 struct nfsusrgrp *usrp;
2927 struct nfsrv_lughash *hp, *hp2;
2930 error = NFSERR_BADOWNER;
2933 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2935 tgid = (gid_t)strtoul(str0, &endstr, 10);
2936 if ((endstr - str0) == len) {
2937 /* A numeric string. */
2938 if ((nd->nd_flag & ND_KERBV) == 0 &&
2939 ((nd->nd_flag & ND_NFSCL) != 0 ||
2940 nfsd_enable_stringtouid != 0))
2943 error = NFSERR_BADOWNER;
2949 cp = strchr(str0, '@');
2951 i = (int)(cp++ - str0);
2957 if (nfsrv_dnsnamelen > 0) {
2959 * If an '@' is found and the dns name matches, search for the
2960 * name with the dns stripped off.
2962 if (cnt == 0 && i < len && i > 0 &&
2963 (len - 1 - i) == nfsrv_dnsnamelen &&
2964 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2965 len -= (nfsrv_dnsnamelen + 1);
2970 * Check for the special case of "nogroup".
2972 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2973 *gidp = nfsrv_defaultgid;
2978 hp = NFSGROUPNAMEHASH(str, len);
2980 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2981 if (usrp->lug_namelen == len &&
2982 !NFSBCMP(usrp->lug_name, str, len)) {
2983 if (usrp->lug_expiry < NFSD_MONOSEC)
2985 hp2 = NFSGROUPHASH(usrp->lug_gid);
2986 mtx_lock(&hp2->mtx);
2987 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2988 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2990 *gidp = usrp->lug_gid;
2991 mtx_unlock(&hp2->mtx);
2992 mtx_unlock(&hp->mtx);
2997 mtx_unlock(&hp->mtx);
2999 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3001 if (ret == 0 && cnt < 2)
3004 error = NFSERR_BADOWNER;
3012 * Cmp len chars, allowing mixed case in the first argument to match lower
3013 * case in the second, but not if the first argument is all upper case.
3014 * Return 0 for a match, 1 otherwise.
3017 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3023 for (i = 0; i < len; i++) {
3024 if (*cp >= 'A' && *cp <= 'Z') {
3025 tmp = *cp++ + ('a' - 'A');
3028 if (tmp >= 'a' && tmp <= 'z')
3041 * Set the port for the nfsuserd.
3044 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3046 struct nfssockreq *rp;
3047 struct sockaddr_in *ad;
3051 if (nfsrv_nfsuserd) {
3059 * Set up the socket record and connect.
3061 rp = &nfsrv_nfsuserdsock;
3062 rp->nr_client = NULL;
3063 rp->nr_sotype = SOCK_DGRAM;
3064 rp->nr_soproto = IPPROTO_UDP;
3065 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3067 NFSSOCKADDRALLOC(rp->nr_nam);
3068 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3069 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3070 ad->sin_family = AF_INET;
3071 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3072 ad->sin_port = port;
3073 rp->nr_prog = RPCPROG_NFSUSERD;
3074 rp->nr_vers = RPCNFSUSERD_VERS;
3075 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3077 NFSSOCKADDRFREE(rp->nr_nam);
3086 * Delete the nfsuserd port.
3089 nfsrv_nfsuserddelport(void)
3093 if (nfsrv_nfsuserd == 0) {
3099 newnfs_disconnect(&nfsrv_nfsuserdsock);
3100 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3104 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3106 * Returns 0 upon success, non-zero otherwise.
3109 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3112 struct nfsrv_descript *nd;
3114 struct nfsrv_descript nfsd;
3119 if (nfsrv_nfsuserd == 0) {
3126 cred = newnfs_getcred();
3127 nd->nd_flag = ND_GSSINITREPLY;
3130 nd->nd_procnum = procnum;
3131 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3132 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3133 if (procnum == RPCNFSUSERD_GETUID)
3134 *tl = txdr_unsigned(uid);
3136 *tl = txdr_unsigned(gid);
3139 (void) nfsm_strtom(nd, name, len);
3141 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3142 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3145 mbuf_freem(nd->nd_mrep);
3146 error = nd->nd_repstat;
3154 * This function is called from the nfssvc(2) system call, to update the
3155 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3158 nfssvc_idname(struct nfsd_idargs *nidp)
3160 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3161 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3162 int i, group_locked, groupname_locked, user_locked, username_locked;
3167 static int onethread = 0;
3168 static time_t lasttime = 0;
3170 if (nidp->nid_flag & NFSID_INITIALIZE) {
3171 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3172 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3175 free(cp, M_NFSSTRING);
3178 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3180 * Free up all the old stuff and reinitialize hash
3181 * lists. All mutexes for both lists must be locked,
3182 * with the user/group name ones before the uid/gid
3183 * ones, to avoid a LOR.
3185 for (i = 0; i < nfsrv_lughashsize; i++)
3186 mtx_lock(&nfsusernamehash[i].mtx);
3187 for (i = 0; i < nfsrv_lughashsize; i++)
3188 mtx_lock(&nfsuserhash[i].mtx);
3189 for (i = 0; i < nfsrv_lughashsize; i++)
3190 TAILQ_FOREACH_SAFE(usrp,
3191 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3192 nfsrv_removeuser(usrp, 1);
3193 for (i = 0; i < nfsrv_lughashsize; i++)
3194 mtx_unlock(&nfsuserhash[i].mtx);
3195 for (i = 0; i < nfsrv_lughashsize; i++)
3196 mtx_unlock(&nfsusernamehash[i].mtx);
3197 for (i = 0; i < nfsrv_lughashsize; i++)
3198 mtx_lock(&nfsgroupnamehash[i].mtx);
3199 for (i = 0; i < nfsrv_lughashsize; i++)
3200 mtx_lock(&nfsgrouphash[i].mtx);
3201 for (i = 0; i < nfsrv_lughashsize; i++)
3202 TAILQ_FOREACH_SAFE(usrp,
3203 &nfsgrouphash[i].lughead, lug_numhash,
3205 nfsrv_removeuser(usrp, 0);
3206 for (i = 0; i < nfsrv_lughashsize; i++)
3207 mtx_unlock(&nfsgrouphash[i].mtx);
3208 for (i = 0; i < nfsrv_lughashsize; i++)
3209 mtx_unlock(&nfsgroupnamehash[i].mtx);
3210 free(nfsrv_dnsname, M_NFSSTRING);
3211 nfsrv_dnsname = NULL;
3213 if (nfsuserhash == NULL) {
3214 /* Allocate the hash tables. */
3215 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3216 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3220 NULL, MTX_DEF | MTX_DUPOK);
3221 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3222 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3224 for (i = 0; i < nfsrv_lughashsize; i++)
3225 mtx_init(&nfsusernamehash[i].mtx,
3226 "nfsusrhash", NULL, MTX_DEF |
3228 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3229 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3233 NULL, MTX_DEF | MTX_DUPOK);
3234 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3235 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3237 for (i = 0; i < nfsrv_lughashsize; i++)
3238 mtx_init(&nfsgroupnamehash[i].mtx,
3239 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3241 /* (Re)initialize the list heads. */
3242 for (i = 0; i < nfsrv_lughashsize; i++)
3243 TAILQ_INIT(&nfsuserhash[i].lughead);
3244 for (i = 0; i < nfsrv_lughashsize; i++)
3245 TAILQ_INIT(&nfsusernamehash[i].lughead);
3246 for (i = 0; i < nfsrv_lughashsize; i++)
3247 TAILQ_INIT(&nfsgrouphash[i].lughead);
3248 for (i = 0; i < nfsrv_lughashsize; i++)
3249 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3252 * Put name in "DNS" string.
3255 nfsrv_defaultuid = nidp->nid_uid;
3256 nfsrv_defaultgid = nidp->nid_gid;
3258 nfsrv_usermax = nidp->nid_usermax;
3259 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3264 * malloc the new one now, so any potential sleep occurs before
3265 * manipulation of the lists.
3267 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3268 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3269 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3271 if (error == 0 && nidp->nid_ngroup > 0 &&
3272 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3273 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3275 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3276 sizeof(gid_t) * nidp->nid_ngroup);
3279 * Create a credential just like svc_getcred(),
3280 * but using the group list provided.
3283 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3284 crsetgroups(cr, nidp->nid_ngroup, grps);
3285 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3286 cr->cr_prison = &prison0;
3287 prison_hold(cr->cr_prison);
3289 mac_cred_associate_nfsd(cr);
3291 newusrp->lug_cred = cr;
3296 free(newusrp, M_NFSUSERGROUP);
3299 newusrp->lug_namelen = nidp->nid_namelen;
3302 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3303 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3304 * The flags user_locked, username_locked, group_locked and
3305 * groupname_locked are set to indicate all of those hash lists are
3306 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3307 * the respective one mutex is locked.
3309 user_locked = username_locked = group_locked = groupname_locked = 0;
3310 hp_name = hp_idnum = NULL;
3313 * Delete old entries, as required.
3315 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3316 /* Must lock all username hash lists first, to avoid a LOR. */
3317 for (i = 0; i < nfsrv_lughashsize; i++)
3318 mtx_lock(&nfsusernamehash[i].mtx);
3319 username_locked = 1;
3320 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3321 mtx_lock(&hp_idnum->mtx);
3322 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3324 if (usrp->lug_uid == nidp->nid_uid)
3325 nfsrv_removeuser(usrp, 1);
3327 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3328 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3329 newusrp->lug_namelen);
3330 mtx_lock(&hp_name->mtx);
3331 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3333 if (usrp->lug_namelen == newusrp->lug_namelen &&
3334 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3335 usrp->lug_namelen)) {
3336 thp = NFSUSERHASH(usrp->lug_uid);
3337 mtx_lock(&thp->mtx);
3338 nfsrv_removeuser(usrp, 1);
3339 mtx_unlock(&thp->mtx);
3342 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3343 mtx_lock(&hp_idnum->mtx);
3344 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3345 /* Must lock all groupname hash lists first, to avoid a LOR. */
3346 for (i = 0; i < nfsrv_lughashsize; i++)
3347 mtx_lock(&nfsgroupnamehash[i].mtx);
3348 groupname_locked = 1;
3349 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3350 mtx_lock(&hp_idnum->mtx);
3351 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3353 if (usrp->lug_gid == nidp->nid_gid)
3354 nfsrv_removeuser(usrp, 0);
3356 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3357 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3358 newusrp->lug_namelen);
3359 mtx_lock(&hp_name->mtx);
3360 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3362 if (usrp->lug_namelen == newusrp->lug_namelen &&
3363 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3364 usrp->lug_namelen)) {
3365 thp = NFSGROUPHASH(usrp->lug_gid);
3366 mtx_lock(&thp->mtx);
3367 nfsrv_removeuser(usrp, 0);
3368 mtx_unlock(&thp->mtx);
3371 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3372 mtx_lock(&hp_idnum->mtx);
3376 * Now, we can add the new one.
3378 if (nidp->nid_usertimeout)
3379 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3381 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3382 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3383 newusrp->lug_uid = nidp->nid_uid;
3384 thp = NFSUSERHASH(newusrp->lug_uid);
3385 mtx_assert(&thp->mtx, MA_OWNED);
3386 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3387 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3388 mtx_assert(&thp->mtx, MA_OWNED);
3389 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3390 atomic_add_int(&nfsrv_usercnt, 1);
3391 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3392 newusrp->lug_gid = nidp->nid_gid;
3393 thp = NFSGROUPHASH(newusrp->lug_gid);
3394 mtx_assert(&thp->mtx, MA_OWNED);
3395 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3396 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3397 mtx_assert(&thp->mtx, MA_OWNED);
3398 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3399 atomic_add_int(&nfsrv_usercnt, 1);
3401 if (newusrp->lug_cred != NULL)
3402 crfree(newusrp->lug_cred);
3403 free(newusrp, M_NFSUSERGROUP);
3407 * Once per second, allow one thread to trim the cache.
3409 if (lasttime < NFSD_MONOSEC &&
3410 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3412 * First, unlock the single mutexes, so that all entries
3413 * can be locked and any LOR is avoided.
3415 if (hp_name != NULL) {
3416 mtx_unlock(&hp_name->mtx);
3419 if (hp_idnum != NULL) {
3420 mtx_unlock(&hp_idnum->mtx);
3424 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3425 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3426 if (username_locked == 0) {
3427 for (i = 0; i < nfsrv_lughashsize; i++)
3428 mtx_lock(&nfsusernamehash[i].mtx);
3429 username_locked = 1;
3431 KASSERT(user_locked == 0,
3432 ("nfssvc_idname: user_locked"));
3433 for (i = 0; i < nfsrv_lughashsize; i++)
3434 mtx_lock(&nfsuserhash[i].mtx);
3436 for (i = 0; i < nfsrv_lughashsize; i++) {
3437 TAILQ_FOREACH_SAFE(usrp,
3438 &nfsuserhash[i].lughead, lug_numhash,
3440 if (usrp->lug_expiry < NFSD_MONOSEC)
3441 nfsrv_removeuser(usrp, 1);
3443 for (i = 0; i < nfsrv_lughashsize; i++) {
3445 * Trim the cache using an approximate LRU
3446 * algorithm. This code deletes the least
3447 * recently used entry on each hash list.
3449 if (nfsrv_usercnt <= nfsrv_usermax)
3451 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3453 nfsrv_removeuser(usrp, 1);
3456 if (groupname_locked == 0) {
3457 for (i = 0; i < nfsrv_lughashsize; i++)
3458 mtx_lock(&nfsgroupnamehash[i].mtx);
3459 groupname_locked = 1;
3461 KASSERT(group_locked == 0,
3462 ("nfssvc_idname: group_locked"));
3463 for (i = 0; i < nfsrv_lughashsize; i++)
3464 mtx_lock(&nfsgrouphash[i].mtx);
3466 for (i = 0; i < nfsrv_lughashsize; i++) {
3467 TAILQ_FOREACH_SAFE(usrp,
3468 &nfsgrouphash[i].lughead, lug_numhash,
3470 if (usrp->lug_expiry < NFSD_MONOSEC)
3471 nfsrv_removeuser(usrp, 0);
3473 for (i = 0; i < nfsrv_lughashsize; i++) {
3475 * Trim the cache using an approximate LRU
3476 * algorithm. This code deletes the least
3477 * recently user entry on each hash list.
3479 if (nfsrv_usercnt <= nfsrv_usermax)
3481 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3483 nfsrv_removeuser(usrp, 0);
3486 lasttime = NFSD_MONOSEC;
3487 atomic_store_rel_int(&onethread, 0);
3490 /* Now, unlock all locked mutexes. */
3491 if (hp_idnum != NULL)
3492 mtx_unlock(&hp_idnum->mtx);
3493 if (hp_name != NULL)
3494 mtx_unlock(&hp_name->mtx);
3495 if (user_locked != 0)
3496 for (i = 0; i < nfsrv_lughashsize; i++)
3497 mtx_unlock(&nfsuserhash[i].mtx);
3498 if (username_locked != 0)
3499 for (i = 0; i < nfsrv_lughashsize; i++)
3500 mtx_unlock(&nfsusernamehash[i].mtx);
3501 if (group_locked != 0)
3502 for (i = 0; i < nfsrv_lughashsize; i++)
3503 mtx_unlock(&nfsgrouphash[i].mtx);
3504 if (groupname_locked != 0)
3505 for (i = 0; i < nfsrv_lughashsize; i++)
3506 mtx_unlock(&nfsgroupnamehash[i].mtx);
3513 * Remove a user/group name element.
3516 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3518 struct nfsrv_lughash *hp;
3521 hp = NFSUSERHASH(usrp->lug_uid);
3522 mtx_assert(&hp->mtx, MA_OWNED);
3523 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3524 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3525 mtx_assert(&hp->mtx, MA_OWNED);
3526 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3528 hp = NFSGROUPHASH(usrp->lug_gid);
3529 mtx_assert(&hp->mtx, MA_OWNED);
3530 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3531 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3532 mtx_assert(&hp->mtx, MA_OWNED);
3533 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3535 atomic_add_int(&nfsrv_usercnt, -1);
3536 if (usrp->lug_cred != NULL)
3537 crfree(usrp->lug_cred);
3538 free(usrp, M_NFSUSERGROUP);
3542 * Free up all the allocations related to the name<-->id cache.
3543 * This function should only be called when the nfsuserd daemon isn't
3544 * running, since it doesn't do any locking.
3545 * This function is meant to be used when the nfscommon module is unloaded.
3548 nfsrv_cleanusergroup(void)
3550 struct nfsrv_lughash *hp, *hp2;
3551 struct nfsusrgrp *nusrp, *usrp;
3554 if (nfsuserhash == NULL)
3557 for (i = 0; i < nfsrv_lughashsize; i++) {
3558 hp = &nfsuserhash[i];
3559 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3560 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3561 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3563 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3564 if (usrp->lug_cred != NULL)
3565 crfree(usrp->lug_cred);
3566 free(usrp, M_NFSUSERGROUP);
3568 hp = &nfsgrouphash[i];
3569 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3570 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3571 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3573 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3574 if (usrp->lug_cred != NULL)
3575 crfree(usrp->lug_cred);
3576 free(usrp, M_NFSUSERGROUP);
3578 mtx_destroy(&nfsuserhash[i].mtx);
3579 mtx_destroy(&nfsusernamehash[i].mtx);
3580 mtx_destroy(&nfsgroupnamehash[i].mtx);
3581 mtx_destroy(&nfsgrouphash[i].mtx);
3583 free(nfsuserhash, M_NFSUSERGROUP);
3584 free(nfsusernamehash, M_NFSUSERGROUP);
3585 free(nfsgrouphash, M_NFSUSERGROUP);
3586 free(nfsgroupnamehash, M_NFSUSERGROUP);
3587 free(nfsrv_dnsname, M_NFSSTRING);
3591 * This function scans a byte string and checks for UTF-8 compliance.
3592 * It returns 0 if it conforms and NFSERR_INVAL if not.
3595 nfsrv_checkutf8(u_int8_t *cp, int len)
3597 u_int32_t val = 0x0;
3598 int cnt = 0, gotd = 0, shift = 0;
3600 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3604 * Here are what the variables are used for:
3605 * val - the calculated value of a multibyte char, used to check
3606 * that it was coded with the correct range
3607 * cnt - the number of 10xxxxxx bytes to follow
3608 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3609 * shift - lower order bits of range (ie. "val >> shift" should
3610 * not be 0, in other words, dividing by the lower bound
3611 * of the range should get a non-zero value)
3612 * byte - used to calculate cnt
3616 /* This handles the 10xxxxxx bytes */
3617 if ((*cp & 0xc0) != 0x80 ||
3618 (gotd && (*cp & 0x20))) {
3619 error = NFSERR_INVAL;
3624 val |= (*cp & 0x3f);
3626 if (cnt == 0 && (val >> shift) == 0x0) {
3627 error = NFSERR_INVAL;
3630 } else if (*cp & 0x80) {
3631 /* first byte of multi byte char */
3633 while ((byte & 0x40) && cnt < 6) {
3637 if (cnt == 0 || cnt == 6) {
3638 error = NFSERR_INVAL;
3641 val = (*cp & (0x3f >> cnt));
3642 shift = utf8_shift[cnt - 1];
3643 if (cnt == 2 && val == 0xd)
3644 /* Check for the 0xd800-0xdfff case */
3651 error = NFSERR_INVAL;
3659 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3660 * strings, one with the root path in it and the other with the list of
3661 * locations. The list is in the same format as is found in nfr_refs.
3662 * It is a "," separated list of entries, where each of them is of the
3663 * form <server>:<rootpath>. For example
3664 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3665 * The nilp argument is set to 1 for the special case of a null fs_root
3666 * and an empty server list.
3667 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3668 * number of xdr bytes parsed in sump.
3671 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3672 int *sump, int *nilp)
3675 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3676 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3678 SLIST_ENTRY(list) next;
3682 SLIST_HEAD(, list) head;
3689 * Get the fs_root path and check for the special case of null path
3690 * and 0 length server list.
3692 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3693 len = fxdr_unsigned(int, *tl);
3694 if (len < 0 || len > 10240) {
3695 error = NFSERR_BADXDR;
3699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3701 error = NFSERR_BADXDR;
3705 *sump = 2 * NFSX_UNSIGNED;
3709 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3710 error = nfsrv_mtostr(nd, cp, len);
3712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3713 cnt = fxdr_unsigned(int, *tl);
3715 error = NFSERR_BADXDR;
3721 * Now, loop through the location list and make up the srvlist.
3723 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3724 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3727 for (i = 0; i < cnt; i++) {
3729 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3730 nsrv = fxdr_unsigned(int, *tl);
3732 error = NFSERR_BADXDR;
3737 * Handle the first server by putting it in the srvstr.
3739 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3740 len = fxdr_unsigned(int, *tl);
3741 if (len <= 0 || len > 1024) {
3742 error = NFSERR_BADXDR;
3745 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3750 error = nfsrv_mtostr(nd, cp3, len);
3756 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3757 for (j = 1; j < nsrv; j++) {
3759 * Yuck, put them in an slist and process them later.
3761 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3762 len = fxdr_unsigned(int, *tl);
3763 if (len <= 0 || len > 1024) {
3764 error = NFSERR_BADXDR;
3767 lsp = (struct list *)malloc(sizeof (struct list)
3768 + len, M_TEMP, M_WAITOK);
3769 error = nfsrv_mtostr(nd, lsp->host, len);
3772 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3774 SLIST_INSERT_HEAD(&head, lsp, next);
3778 * Finally, we can get the path.
3780 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3781 len = fxdr_unsigned(int, *tl);
3782 if (len <= 0 || len > 1024) {
3783 error = NFSERR_BADXDR;
3786 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3787 error = nfsrv_mtostr(nd, cp3, len);
3790 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3795 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3796 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3799 NFSBCOPY(lsp->host, cp3, lsp->len);
3802 NFSBCOPY(str, cp3, stringlen);
3805 siz += (lsp->len + stringlen + 2);
3806 free((caddr_t)lsp, M_TEMP);
3812 NFSEXITCODE2(0, nd);
3816 free(cp, M_NFSSTRING);
3818 free(cp2, M_NFSSTRING);
3819 NFSEXITCODE2(error, nd);
3824 * Make the malloc'd space large enough. This is a pain, but the xdr
3825 * doesn't set an upper bound on the side, so...
3828 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3835 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3836 NFSBCOPY(*cpp, cp, *slenp);
3837 free(*cpp, M_NFSSTRING);
3841 *slenp = siz + 1024;
3845 * Initialize the reply header data structures.
3848 nfsrvd_rephead(struct nfsrv_descript *nd)
3853 * If this is a big reply, use a cluster.
3855 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3856 nfs_bigreply[nd->nd_procnum]) {
3857 NFSMCLGET(mreq, M_WAITOK);
3865 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3866 mbuf_setlen(mreq, 0);
3868 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3869 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3873 * Lock a socket against others.
3874 * Currently used to serialize connect/disconnect attempts.
3877 newnfs_sndlock(int *flagp)
3882 while (*flagp & NFSR_SNDLOCK) {
3883 *flagp |= NFSR_WANTSND;
3886 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3887 PZERO - 1, "nfsndlck", &ts);
3889 *flagp |= NFSR_SNDLOCK;
3895 * Unlock the stream socket for others.
3898 newnfs_sndunlock(int *flagp)
3902 if ((*flagp & NFSR_SNDLOCK) == 0)
3903 panic("nfs sndunlock");
3904 *flagp &= ~NFSR_SNDLOCK;
3905 if (*flagp & NFSR_WANTSND) {
3906 *flagp &= ~NFSR_WANTSND;
3907 wakeup((caddr_t)flagp);
3913 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3916 struct sockaddr_in *sad;
3917 struct sockaddr_in6 *sad6;
3918 struct in_addr saddr;
3919 uint32_t portnum, *tl;
3920 int af = 0, i, j, k;
3921 char addr[64], protocol[5], *cp;
3922 int cantparse = 0, error = 0;
3925 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3926 i = fxdr_unsigned(int, *tl);
3927 if (i >= 3 && i <= 4) {
3928 error = nfsrv_mtostr(nd, protocol, i);
3931 if (strcmp(protocol, "tcp") == 0) {
3934 } else if (strcmp(protocol, "udp") == 0) {
3937 } else if (strcmp(protocol, "tcp6") == 0) {
3940 } else if (strcmp(protocol, "udp6") == 0) {
3948 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3953 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3954 i = fxdr_unsigned(int, *tl);
3956 error = NFSERR_BADXDR;
3958 } else if (cantparse == 0 && i >= 11 && i < 64) {
3960 * The shortest address is 11chars and the longest is < 64.
3962 error = nfsrv_mtostr(nd, addr, i);
3966 /* Find the port# at the end and extract that. */
3970 /* Count back two '.'s from end to get port# field. */
3971 for (j = 0; j < i; j++) {
3981 * The NFSv4 port# is appended as .N.N, where N is
3982 * a decimal # in the range 0-255, just like an inet4
3983 * address. Cheat and use inet_aton(), which will
3984 * return a Class A address and then shift the high
3985 * order 8bits over to convert it to the port#.
3988 if (inet_aton(cp, &saddr) == 1) {
3989 portnum = ntohl(saddr.s_addr);
3990 portv = (uint16_t)((portnum >> 16) |
3996 if (cantparse == 0) {
3997 if (af == AF_INET) {
3998 sad = (struct sockaddr_in *)sa;
3999 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4000 sad->sin_len = sizeof(*sad);
4001 sad->sin_family = AF_INET;
4002 sad->sin_port = htons(portv);
4006 sad6 = (struct sockaddr_in6 *)sa;
4007 if (inet_pton(af, addr, &sad6->sin6_addr)
4009 sad6->sin6_len = sizeof(*sad6);
4010 sad6->sin6_family = AF_INET6;
4011 sad6->sin6_port = htons(portv);
4018 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4029 * Handle an NFSv4.1 Sequence request for the session.
4030 * If reply != NULL, use it to return the cached reply, as required.
4031 * The client gets a cached reply via this call for callbacks, however the
4032 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4035 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4036 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4043 if (slotid > maxslot)
4044 return (NFSERR_BADSLOT);
4045 if (seqid == slots[slotid].nfssl_seq) {
4047 if (slots[slotid].nfssl_inprog != 0)
4048 error = NFSERR_DELAY;
4049 else if (slots[slotid].nfssl_reply != NULL) {
4050 if (reply != NULL) {
4051 *reply = slots[slotid].nfssl_reply;
4052 slots[slotid].nfssl_reply = NULL;
4054 slots[slotid].nfssl_inprog = 1;
4055 error = NFSERR_REPLYFROMCACHE;
4057 /* No reply cached, so just do it. */
4058 slots[slotid].nfssl_inprog = 1;
4059 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4060 if (slots[slotid].nfssl_reply != NULL)
4061 m_freem(slots[slotid].nfssl_reply);
4062 slots[slotid].nfssl_reply = NULL;
4063 slots[slotid].nfssl_inprog = 1;
4064 slots[slotid].nfssl_seq++;
4066 error = NFSERR_SEQMISORDERED;
4071 * Cache this reply for the slot.
4072 * Use the "rep" argument to return the cached reply if repstat is set to
4073 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4076 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4080 if (repstat == NFSERR_REPLYFROMCACHE) {
4081 *rep = slots[slotid].nfssl_reply;
4082 slots[slotid].nfssl_reply = NULL;
4084 if (slots[slotid].nfssl_reply != NULL)
4085 m_freem(slots[slotid].nfssl_reply);
4086 slots[slotid].nfssl_reply = *rep;
4088 slots[slotid].nfssl_inprog = 0;
4092 * Generate the xdr for an NFSv4.1 Sequence Operation.
4095 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4096 struct nfsclsession *sep, int dont_replycache)
4098 uint32_t *tl, slotseq = 0;
4099 int error, maxslot, slotpos;
4100 uint8_t sessionid[NFSX_V4SESSIONID];
4102 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4106 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
4108 /* Build the Sequence arguments. */
4109 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4110 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4111 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4112 nd->nd_slotseq = tl;
4113 *tl++ = txdr_unsigned(slotseq);
4114 *tl++ = txdr_unsigned(slotpos);
4115 *tl++ = txdr_unsigned(maxslot);
4116 if (dont_replycache == 0)
4120 nd->nd_flag |= ND_HASSEQUENCE;
4124 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4125 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4127 int i, maxslot, slotpos;
4130 /* Find an unused slot. */
4133 mtx_lock(&sep->nfsess_mtx);
4136 for (i = 0; i < sep->nfsess_foreslots; i++) {
4137 if ((bitval & sep->nfsess_slots) == 0) {
4139 sep->nfsess_slots |= bitval;
4140 sep->nfsess_slotseq[i]++;
4141 *slotseqp = sep->nfsess_slotseq[i];
4146 if (slotpos == -1) {
4148 * If a forced dismount is in progress, just return.
4149 * This RPC attempt will fail when it calls
4153 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4155 mtx_unlock(&sep->nfsess_mtx);
4158 /* Wake up once/sec, to check for a forced dismount. */
4159 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4160 PZERO, "nfsclseq", hz);
4162 } while (slotpos == -1);
4163 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4165 for (i = 0; i < 64; i++) {
4166 if ((bitval & sep->nfsess_slots) != 0)
4170 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4171 mtx_unlock(&sep->nfsess_mtx);
4172 *slotposp = slotpos;
4173 *maxslotp = maxslot;
4178 * Free a session slot.
4181 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4188 mtx_lock(&sep->nfsess_mtx);
4189 if ((bitval & sep->nfsess_slots) == 0)
4190 printf("freeing free slot!!\n");
4191 sep->nfsess_slots &= ~bitval;
4192 wakeup(&sep->nfsess_slots);
4193 mtx_unlock(&sep->nfsess_mtx);