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;
832 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
834 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
840 *retcmpp = retnotsup;
843 * Just set default values to some of the important ones.
848 nap->na_rdev = (NFSDEV_T)0;
849 nap->na_mtime.tv_sec = 0;
850 nap->na_mtime.tv_nsec = 0;
853 nap->na_blocksize = NFS_FABLKSIZE;
856 sbp->f_bsize = NFS_FABLKSIZE;
864 fsp->fs_rtmax = 8192;
865 fsp->fs_rtpref = 8192;
866 fsp->fs_maxname = NFS_MAXNAMLEN;
867 fsp->fs_wtmax = 8192;
868 fsp->fs_wtpref = 8192;
869 fsp->fs_wtmult = NFS_FABLKSIZE;
870 fsp->fs_dtpref = 8192;
871 fsp->fs_maxfilesize = 0xffffffffffffffffull;
872 fsp->fs_timedelta.tv_sec = 0;
873 fsp->fs_timedelta.tv_nsec = 1;
874 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
875 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
878 pc->pc_linkmax = LINK_MAX;
879 pc->pc_namemax = NAME_MAX;
881 pc->pc_chownrestricted = 0;
882 pc->pc_caseinsensitive = 0;
883 pc->pc_casepreserving = 1;
888 * Loop around getting the attributes.
890 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
891 attrsize = fxdr_unsigned(int, *tl);
892 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
893 if (attrsum > attrsize) {
894 error = NFSERR_BADXDR;
897 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
899 case NFSATTRBIT_SUPPORTEDATTRS:
901 if (compare || nap == NULL)
902 error = nfsrv_getattrbits(nd, &retattrbits,
905 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
909 if (compare && !(*retcmpp)) {
910 NFSSETSUPP_ATTRBIT(&checkattrbits);
912 /* Some filesystem do not support NFSv4ACL */
913 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
914 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
915 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
917 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
919 *retcmpp = NFSERR_NOTSAME;
923 case NFSATTRBIT_TYPE:
924 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
927 if (nap->na_type != nfsv34tov_type(*tl))
928 *retcmpp = NFSERR_NOTSAME;
930 } else if (nap != NULL) {
931 nap->na_type = nfsv34tov_type(*tl);
933 attrsum += NFSX_UNSIGNED;
935 case NFSATTRBIT_FHEXPIRETYPE:
936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
937 if (compare && !(*retcmpp)) {
938 if (fxdr_unsigned(int, *tl) !=
939 NFSV4FHTYPE_PERSISTENT)
940 *retcmpp = NFSERR_NOTSAME;
942 attrsum += NFSX_UNSIGNED;
944 case NFSATTRBIT_CHANGE:
945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
948 if (nap->na_filerev != fxdr_hyper(tl))
949 *retcmpp = NFSERR_NOTSAME;
951 } else if (nap != NULL) {
952 nap->na_filerev = fxdr_hyper(tl);
954 attrsum += NFSX_HYPER;
956 case NFSATTRBIT_SIZE:
957 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
960 if (nap->na_size != fxdr_hyper(tl))
961 *retcmpp = NFSERR_NOTSAME;
963 } else if (nap != NULL) {
964 nap->na_size = fxdr_hyper(tl);
966 attrsum += NFSX_HYPER;
968 case NFSATTRBIT_LINKSUPPORT:
969 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
972 if (fsp->fs_properties & NFSV3_FSFLINK) {
973 if (*tl == newnfs_false)
974 *retcmpp = NFSERR_NOTSAME;
976 if (*tl == newnfs_true)
977 *retcmpp = NFSERR_NOTSAME;
980 } else if (fsp != NULL) {
981 if (*tl == newnfs_true)
982 fsp->fs_properties |= NFSV3_FSFLINK;
984 fsp->fs_properties &= ~NFSV3_FSFLINK;
986 attrsum += NFSX_UNSIGNED;
988 case NFSATTRBIT_SYMLINKSUPPORT:
989 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
992 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
993 if (*tl == newnfs_false)
994 *retcmpp = NFSERR_NOTSAME;
996 if (*tl == newnfs_true)
997 *retcmpp = NFSERR_NOTSAME;
1000 } else if (fsp != NULL) {
1001 if (*tl == newnfs_true)
1002 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1004 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1006 attrsum += NFSX_UNSIGNED;
1008 case NFSATTRBIT_NAMEDATTR:
1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1010 if (compare && !(*retcmpp)) {
1011 if (*tl != newnfs_false)
1012 *retcmpp = NFSERR_NOTSAME;
1014 attrsum += NFSX_UNSIGNED;
1016 case NFSATTRBIT_FSID:
1017 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1018 thyp = fxdr_hyper(tl);
1020 thyp2 = fxdr_hyper(tl);
1022 if (*retcmpp == 0) {
1023 if (thyp != (u_int64_t)
1024 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1025 thyp2 != (u_int64_t)
1026 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1027 *retcmpp = NFSERR_NOTSAME;
1029 } else if (nap != NULL) {
1030 nap->na_filesid[0] = thyp;
1031 nap->na_filesid[1] = thyp2;
1033 attrsum += (4 * NFSX_UNSIGNED);
1035 case NFSATTRBIT_UNIQUEHANDLES:
1036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1037 if (compare && !(*retcmpp)) {
1038 if (*tl != newnfs_true)
1039 *retcmpp = NFSERR_NOTSAME;
1041 attrsum += NFSX_UNSIGNED;
1043 case NFSATTRBIT_LEASETIME:
1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1046 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1048 *retcmpp = NFSERR_NOTSAME;
1049 } else if (leasep != NULL) {
1050 *leasep = fxdr_unsigned(u_int32_t, *tl);
1052 attrsum += NFSX_UNSIGNED;
1054 case NFSATTRBIT_RDATTRERROR:
1055 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1058 *retcmpp = NFSERR_INVAL;
1059 } else if (rderrp != NULL) {
1060 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1062 attrsum += NFSX_UNSIGNED;
1064 case NFSATTRBIT_ACL:
1067 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1070 naclp = acl_alloc(M_WAITOK);
1071 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1077 if (aceerr || aclp == NULL ||
1078 nfsrv_compareacl(aclp, naclp))
1079 *retcmpp = NFSERR_NOTSAME;
1082 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1084 *retcmpp = NFSERR_ATTRNOTSUPP;
1088 if (vp != NULL && aclp != NULL)
1089 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1092 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1100 case NFSATTRBIT_ACLSUPPORT:
1101 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1102 if (compare && !(*retcmpp)) {
1103 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1104 if (fxdr_unsigned(u_int32_t, *tl) !=
1106 *retcmpp = NFSERR_NOTSAME;
1108 *retcmpp = NFSERR_ATTRNOTSUPP;
1111 attrsum += NFSX_UNSIGNED;
1113 case NFSATTRBIT_ARCHIVE:
1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1115 if (compare && !(*retcmpp))
1116 *retcmpp = NFSERR_ATTRNOTSUPP;
1117 attrsum += NFSX_UNSIGNED;
1119 case NFSATTRBIT_CANSETTIME:
1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1123 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1124 if (*tl == newnfs_false)
1125 *retcmpp = NFSERR_NOTSAME;
1127 if (*tl == newnfs_true)
1128 *retcmpp = NFSERR_NOTSAME;
1131 } else if (fsp != NULL) {
1132 if (*tl == newnfs_true)
1133 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1135 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1137 attrsum += NFSX_UNSIGNED;
1139 case NFSATTRBIT_CASEINSENSITIVE:
1140 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1143 if (*tl != newnfs_false)
1144 *retcmpp = NFSERR_NOTSAME;
1146 } else if (pc != NULL) {
1147 pc->pc_caseinsensitive =
1148 fxdr_unsigned(u_int32_t, *tl);
1150 attrsum += NFSX_UNSIGNED;
1152 case NFSATTRBIT_CASEPRESERVING:
1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1156 if (*tl != newnfs_true)
1157 *retcmpp = NFSERR_NOTSAME;
1159 } else if (pc != NULL) {
1160 pc->pc_casepreserving =
1161 fxdr_unsigned(u_int32_t, *tl);
1163 attrsum += NFSX_UNSIGNED;
1165 case NFSATTRBIT_CHOWNRESTRICTED:
1166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1169 if (*tl != newnfs_true)
1170 *retcmpp = NFSERR_NOTSAME;
1172 } else if (pc != NULL) {
1173 pc->pc_chownrestricted =
1174 fxdr_unsigned(u_int32_t, *tl);
1176 attrsum += NFSX_UNSIGNED;
1178 case NFSATTRBIT_FILEHANDLE:
1179 error = nfsm_getfh(nd, &tnfhp);
1182 tfhsize = tnfhp->nfh_len;
1185 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1187 *retcmpp = NFSERR_NOTSAME;
1188 FREE((caddr_t)tnfhp, M_NFSFH);
1189 } else if (nfhpp != NULL) {
1192 FREE((caddr_t)tnfhp, M_NFSFH);
1194 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1196 case NFSATTRBIT_FILEID:
1197 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1198 thyp = fxdr_hyper(tl);
1201 if ((u_int64_t)nap->na_fileid != thyp)
1202 *retcmpp = NFSERR_NOTSAME;
1204 } else if (nap != NULL) {
1206 printf("NFSv4 fileid > 32bits\n");
1207 nap->na_fileid = thyp;
1209 attrsum += NFSX_HYPER;
1211 case NFSATTRBIT_FILESAVAIL:
1212 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1215 sfp->sf_afiles != fxdr_hyper(tl))
1216 *retcmpp = NFSERR_NOTSAME;
1217 } else if (sfp != NULL) {
1218 sfp->sf_afiles = fxdr_hyper(tl);
1220 attrsum += NFSX_HYPER;
1222 case NFSATTRBIT_FILESFREE:
1223 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1226 sfp->sf_ffiles != fxdr_hyper(tl))
1227 *retcmpp = NFSERR_NOTSAME;
1228 } else if (sfp != NULL) {
1229 sfp->sf_ffiles = fxdr_hyper(tl);
1231 attrsum += NFSX_HYPER;
1233 case NFSATTRBIT_FILESTOTAL:
1234 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1237 sfp->sf_tfiles != fxdr_hyper(tl))
1238 *retcmpp = NFSERR_NOTSAME;
1239 } else if (sfp != NULL) {
1240 sfp->sf_tfiles = fxdr_hyper(tl);
1242 attrsum += NFSX_HYPER;
1244 case NFSATTRBIT_FSLOCATIONS:
1245 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1249 if (compare && !(*retcmpp)) {
1250 refp = nfsv4root_getreferral(vp, NULL, 0);
1252 if (cp == NULL || cp2 == NULL ||
1254 strcmp(cp2, refp->nfr_srvlist))
1255 *retcmpp = NFSERR_NOTSAME;
1256 } else if (m == 0) {
1257 *retcmpp = NFSERR_NOTSAME;
1261 free(cp, M_NFSSTRING);
1263 free(cp2, M_NFSSTRING);
1265 case NFSATTRBIT_HIDDEN:
1266 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1267 if (compare && !(*retcmpp))
1268 *retcmpp = NFSERR_ATTRNOTSUPP;
1269 attrsum += NFSX_UNSIGNED;
1271 case NFSATTRBIT_HOMOGENEOUS:
1272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1275 if (fsp->fs_properties &
1276 NFSV3_FSFHOMOGENEOUS) {
1277 if (*tl == newnfs_false)
1278 *retcmpp = NFSERR_NOTSAME;
1280 if (*tl == newnfs_true)
1281 *retcmpp = NFSERR_NOTSAME;
1284 } else if (fsp != NULL) {
1285 if (*tl == newnfs_true)
1286 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1288 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1290 attrsum += NFSX_UNSIGNED;
1292 case NFSATTRBIT_MAXFILESIZE:
1293 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1294 tnfsquad.qval = fxdr_hyper(tl);
1297 tquad = NFSRV_MAXFILESIZE;
1298 if (tquad != tnfsquad.qval)
1299 *retcmpp = NFSERR_NOTSAME;
1301 } else if (fsp != NULL) {
1302 fsp->fs_maxfilesize = tnfsquad.qval;
1304 attrsum += NFSX_HYPER;
1306 case NFSATTRBIT_MAXLINK:
1307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1310 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1311 *retcmpp = NFSERR_NOTSAME;
1313 } else if (pc != NULL) {
1314 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1316 attrsum += NFSX_UNSIGNED;
1318 case NFSATTRBIT_MAXNAME:
1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1322 if (fsp->fs_maxname !=
1323 fxdr_unsigned(u_int32_t, *tl))
1324 *retcmpp = NFSERR_NOTSAME;
1327 tuint = fxdr_unsigned(u_int32_t, *tl);
1329 * Some Linux NFSv4 servers report this
1330 * as 0 or 4billion, so I'll set it to
1331 * NFS_MAXNAMLEN. If a server actually creates
1332 * a name longer than NFS_MAXNAMLEN, it will
1333 * get an error back.
1335 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1336 tuint = NFS_MAXNAMLEN;
1338 fsp->fs_maxname = tuint;
1340 pc->pc_namemax = tuint;
1342 attrsum += NFSX_UNSIGNED;
1344 case NFSATTRBIT_MAXREAD:
1345 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1348 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1349 *(tl + 1)) || *tl != 0)
1350 *retcmpp = NFSERR_NOTSAME;
1352 } else if (fsp != NULL) {
1353 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1354 fsp->fs_rtpref = fsp->fs_rtmax;
1355 fsp->fs_dtpref = fsp->fs_rtpref;
1357 attrsum += NFSX_HYPER;
1359 case NFSATTRBIT_MAXWRITE:
1360 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1363 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1364 *(tl + 1)) || *tl != 0)
1365 *retcmpp = NFSERR_NOTSAME;
1367 } else if (fsp != NULL) {
1368 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1369 fsp->fs_wtpref = fsp->fs_wtmax;
1371 attrsum += NFSX_HYPER;
1373 case NFSATTRBIT_MIMETYPE:
1374 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1375 i = fxdr_unsigned(int, *tl);
1376 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1377 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1380 if (compare && !(*retcmpp))
1381 *retcmpp = NFSERR_ATTRNOTSUPP;
1383 case NFSATTRBIT_MODE:
1384 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1387 if (nap->na_mode != nfstov_mode(*tl))
1388 *retcmpp = NFSERR_NOTSAME;
1390 } else if (nap != NULL) {
1391 nap->na_mode = nfstov_mode(*tl);
1393 attrsum += NFSX_UNSIGNED;
1395 case NFSATTRBIT_NOTRUNC:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1399 if (*tl != newnfs_true)
1400 *retcmpp = NFSERR_NOTSAME;
1402 } else if (pc != NULL) {
1403 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1405 attrsum += NFSX_UNSIGNED;
1407 case NFSATTRBIT_NUMLINKS:
1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1409 tuint = fxdr_unsigned(u_int32_t, *tl);
1412 if ((u_int32_t)nap->na_nlink != tuint)
1413 *retcmpp = NFSERR_NOTSAME;
1415 } else if (nap != NULL) {
1416 nap->na_nlink = tuint;
1418 attrsum += NFSX_UNSIGNED;
1420 case NFSATTRBIT_OWNER:
1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 j = fxdr_unsigned(int, *tl);
1424 error = NFSERR_BADXDR;
1427 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1428 if (j > NFSV4_SMALLSTR)
1429 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1432 error = nfsrv_mtostr(nd, cp, j);
1434 if (j > NFSV4_SMALLSTR)
1435 free(cp, M_NFSSTRING);
1440 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1442 *retcmpp = NFSERR_NOTSAME;
1444 } else if (nap != NULL) {
1445 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1446 nap->na_uid = nfsrv_defaultuid;
1450 if (j > NFSV4_SMALLSTR)
1451 free(cp, M_NFSSTRING);
1453 case NFSATTRBIT_OWNERGROUP:
1454 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1455 j = fxdr_unsigned(int, *tl);
1457 error = NFSERR_BADXDR;
1460 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1461 if (j > NFSV4_SMALLSTR)
1462 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1465 error = nfsrv_mtostr(nd, cp, j);
1467 if (j > NFSV4_SMALLSTR)
1468 free(cp, M_NFSSTRING);
1473 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1475 *retcmpp = NFSERR_NOTSAME;
1477 } else if (nap != NULL) {
1478 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1479 nap->na_gid = nfsrv_defaultgid;
1483 if (j > NFSV4_SMALLSTR)
1484 free(cp, M_NFSSTRING);
1486 case NFSATTRBIT_QUOTAHARD:
1487 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1489 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1490 freenum = sbp->f_bfree;
1492 freenum = sbp->f_bavail;
1495 * ufs_quotactl() insists that the uid argument
1496 * equal p_ruid for non-root quota access, so
1497 * we'll just make sure that's the case.
1499 savuid = p->p_cred->p_ruid;
1500 p->p_cred->p_ruid = cred->cr_uid;
1501 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1502 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1503 freenum = min(dqb.dqb_bhardlimit, freenum);
1504 p->p_cred->p_ruid = savuid;
1506 uquad = (u_int64_t)freenum;
1507 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1509 if (compare && !(*retcmpp)) {
1510 if (uquad != fxdr_hyper(tl))
1511 *retcmpp = NFSERR_NOTSAME;
1513 attrsum += NFSX_HYPER;
1515 case NFSATTRBIT_QUOTASOFT:
1516 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1518 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1519 freenum = sbp->f_bfree;
1521 freenum = sbp->f_bavail;
1524 * ufs_quotactl() insists that the uid argument
1525 * equal p_ruid for non-root quota access, so
1526 * we'll just make sure that's the case.
1528 savuid = p->p_cred->p_ruid;
1529 p->p_cred->p_ruid = cred->cr_uid;
1530 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1531 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1532 freenum = min(dqb.dqb_bsoftlimit, freenum);
1533 p->p_cred->p_ruid = savuid;
1535 uquad = (u_int64_t)freenum;
1536 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1538 if (compare && !(*retcmpp)) {
1539 if (uquad != fxdr_hyper(tl))
1540 *retcmpp = NFSERR_NOTSAME;
1542 attrsum += NFSX_HYPER;
1544 case NFSATTRBIT_QUOTAUSED:
1545 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1550 * ufs_quotactl() insists that the uid argument
1551 * equal p_ruid for non-root quota access, so
1552 * we'll just make sure that's the case.
1554 savuid = p->p_cred->p_ruid;
1555 p->p_cred->p_ruid = cred->cr_uid;
1556 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1557 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1558 freenum = dqb.dqb_curblocks;
1559 p->p_cred->p_ruid = savuid;
1561 uquad = (u_int64_t)freenum;
1562 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1564 if (compare && !(*retcmpp)) {
1565 if (uquad != fxdr_hyper(tl))
1566 *retcmpp = NFSERR_NOTSAME;
1568 attrsum += NFSX_HYPER;
1570 case NFSATTRBIT_RAWDEV:
1571 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1572 j = fxdr_unsigned(int, *tl++);
1573 k = fxdr_unsigned(int, *tl);
1576 if (nap->na_rdev != NFSMAKEDEV(j, k))
1577 *retcmpp = NFSERR_NOTSAME;
1579 } else if (nap != NULL) {
1580 nap->na_rdev = NFSMAKEDEV(j, k);
1582 attrsum += NFSX_V4SPECDATA;
1584 case NFSATTRBIT_SPACEAVAIL:
1585 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1588 sfp->sf_abytes != fxdr_hyper(tl))
1589 *retcmpp = NFSERR_NOTSAME;
1590 } else if (sfp != NULL) {
1591 sfp->sf_abytes = fxdr_hyper(tl);
1593 attrsum += NFSX_HYPER;
1595 case NFSATTRBIT_SPACEFREE:
1596 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1599 sfp->sf_fbytes != fxdr_hyper(tl))
1600 *retcmpp = NFSERR_NOTSAME;
1601 } else if (sfp != NULL) {
1602 sfp->sf_fbytes = fxdr_hyper(tl);
1604 attrsum += NFSX_HYPER;
1606 case NFSATTRBIT_SPACETOTAL:
1607 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1610 sfp->sf_tbytes != fxdr_hyper(tl))
1611 *retcmpp = NFSERR_NOTSAME;
1612 } else if (sfp != NULL) {
1613 sfp->sf_tbytes = fxdr_hyper(tl);
1615 attrsum += NFSX_HYPER;
1617 case NFSATTRBIT_SPACEUSED:
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 thyp = fxdr_hyper(tl);
1622 if ((u_int64_t)nap->na_bytes != thyp)
1623 *retcmpp = NFSERR_NOTSAME;
1625 } else if (nap != NULL) {
1626 nap->na_bytes = thyp;
1628 attrsum += NFSX_HYPER;
1630 case NFSATTRBIT_SYSTEM:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1632 if (compare && !(*retcmpp))
1633 *retcmpp = NFSERR_ATTRNOTSUPP;
1634 attrsum += NFSX_UNSIGNED;
1636 case NFSATTRBIT_TIMEACCESS:
1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1638 fxdr_nfsv4time(tl, &temptime);
1641 if (!NFS_CMPTIME(temptime, nap->na_atime))
1642 *retcmpp = NFSERR_NOTSAME;
1644 } else if (nap != NULL) {
1645 nap->na_atime = temptime;
1647 attrsum += NFSX_V4TIME;
1649 case NFSATTRBIT_TIMEACCESSSET:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1651 attrsum += NFSX_UNSIGNED;
1652 i = fxdr_unsigned(int, *tl);
1653 if (i == NFSV4SATTRTIME_TOCLIENT) {
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1655 attrsum += NFSX_V4TIME;
1657 if (compare && !(*retcmpp))
1658 *retcmpp = NFSERR_INVAL;
1660 case NFSATTRBIT_TIMEBACKUP:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1662 if (compare && !(*retcmpp))
1663 *retcmpp = NFSERR_ATTRNOTSUPP;
1664 attrsum += NFSX_V4TIME;
1666 case NFSATTRBIT_TIMECREATE:
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1668 if (compare && !(*retcmpp))
1669 *retcmpp = NFSERR_ATTRNOTSUPP;
1670 attrsum += NFSX_V4TIME;
1672 case NFSATTRBIT_TIMEDELTA:
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1677 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1678 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1679 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1680 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1683 *retcmpp = NFSERR_NOTSAME;
1686 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1689 attrsum += NFSX_V4TIME;
1691 case NFSATTRBIT_TIMEMETADATA:
1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1693 fxdr_nfsv4time(tl, &temptime);
1696 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1697 *retcmpp = NFSERR_NOTSAME;
1699 } else if (nap != NULL) {
1700 nap->na_ctime = temptime;
1702 attrsum += NFSX_V4TIME;
1704 case NFSATTRBIT_TIMEMODIFY:
1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1706 fxdr_nfsv4time(tl, &temptime);
1709 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1710 *retcmpp = NFSERR_NOTSAME;
1712 } else if (nap != NULL) {
1713 nap->na_mtime = temptime;
1715 attrsum += NFSX_V4TIME;
1717 case NFSATTRBIT_TIMEMODIFYSET:
1718 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1719 attrsum += NFSX_UNSIGNED;
1720 i = fxdr_unsigned(int, *tl);
1721 if (i == NFSV4SATTRTIME_TOCLIENT) {
1722 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1723 attrsum += NFSX_V4TIME;
1725 if (compare && !(*retcmpp))
1726 *retcmpp = NFSERR_INVAL;
1728 case NFSATTRBIT_MOUNTEDONFILEID:
1729 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1730 thyp = fxdr_hyper(tl);
1734 *retcmpp = NFSERR_NOTSAME;
1736 if (!vp || !nfsrv_atroot(vp, &fid))
1737 fid = nap->na_fileid;
1738 if ((u_int64_t)fid != thyp)
1739 *retcmpp = NFSERR_NOTSAME;
1742 } else if (nap != NULL) {
1744 printf("NFSv4 mounted on fileid > 32bits\n");
1745 nap->na_mntonfileno = thyp;
1747 attrsum += NFSX_HYPER;
1749 case NFSATTRBIT_SUPPATTREXCLCREAT:
1751 error = nfsrv_getattrbits(nd, &retattrbits,
1755 if (compare && !(*retcmpp)) {
1756 NFSSETSUPP_ATTRBIT(&checkattrbits);
1757 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1758 NFSCLRBIT_ATTRBIT(&checkattrbits,
1759 NFSATTRBIT_TIMEACCESSSET);
1760 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1762 *retcmpp = NFSERR_NOTSAME;
1767 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1769 if (compare && !(*retcmpp))
1770 *retcmpp = NFSERR_ATTRNOTSUPP;
1772 * and get out of the loop, since we can't parse
1773 * the unknown attrbute data.
1775 bitpos = NFSATTRBIT_MAX;
1781 * some clients pad the attrlist, so we need to skip over the
1784 if (attrsum > attrsize) {
1785 error = NFSERR_BADXDR;
1787 attrsize = NFSM_RNDUP(attrsize);
1788 if (attrsum < attrsize)
1789 error = nfsm_advance(nd, attrsize - attrsum, -1);
1792 NFSEXITCODE2(error, nd);
1797 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1798 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1799 * The first argument is a pointer to an nfsv4lock structure.
1800 * The second argument is 1 iff a blocking lock is wanted.
1801 * If this argument is 0, the call waits until no thread either wants nor
1802 * holds an exclusive lock.
1803 * It returns 1 if the lock was acquired, 0 otherwise.
1804 * If several processes call this function concurrently wanting the exclusive
1805 * lock, one will get the lock and the rest will return without getting the
1806 * lock. (If the caller must have the lock, it simply calls this function in a
1807 * loop until the function returns 1 to indicate the lock was acquired.)
1808 * Any usecnt must be decremented by calling nfsv4_relref() before
1809 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1810 * be called in a loop.
1811 * The isleptp argument is set to indicate if the call slept, iff not NULL
1812 * and the mp argument indicates to check for a forced dismount, iff not
1816 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1817 void *mutex, struct mount *mp)
1823 * If a lock is wanted, loop around until the lock is acquired by
1824 * someone and then released. If I want the lock, try to acquire it.
1825 * For a lock to be issued, no lock must be in force and the usecnt
1829 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1830 lp->nfslock_usecnt == 0) {
1831 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1832 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1835 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1837 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1838 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1839 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1842 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1845 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1846 PZERO - 1, "nfsv4lck", NULL);
1847 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1848 lp->nfslock_usecnt == 0) {
1849 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1850 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1858 * Release the lock acquired by nfsv4_lock().
1859 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1860 * incremented, as well.
1863 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1866 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1868 lp->nfslock_usecnt++;
1873 * Release a reference cnt.
1876 nfsv4_relref(struct nfsv4lock *lp)
1879 if (lp->nfslock_usecnt <= 0)
1880 panic("nfsv4root ref cnt");
1881 lp->nfslock_usecnt--;
1882 if (lp->nfslock_usecnt == 0)
1887 * Get a reference cnt.
1888 * This function will wait for any exclusive lock to be released, but will
1889 * not wait for threads that want the exclusive lock. If priority needs
1890 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1891 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1892 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1893 * return without getting a refcnt for that case.
1896 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1904 * Wait for a lock held.
1906 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1907 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1909 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1912 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1913 PZERO - 1, "nfsv4gr", NULL);
1915 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1918 lp->nfslock_usecnt++;
1922 * Get a reference as above, but return failure instead of sleeping if
1923 * an exclusive lock is held.
1926 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1929 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1932 lp->nfslock_usecnt++;
1937 * Test for a lock. Return 1 if locked, 0 otherwise.
1940 nfsv4_testlock(struct nfsv4lock *lp)
1943 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1944 lp->nfslock_usecnt == 0)
1950 * Wake up anyone sleeping, waiting for this lock.
1953 nfsv4_wanted(struct nfsv4lock *lp)
1956 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1957 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1958 wakeup((caddr_t)&lp->nfslock_lock);
1963 * Copy a string from an mbuf list into a character array.
1964 * Return EBADRPC if there is an mbuf error,
1968 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1977 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1978 rem = NFSM_RNDUP(siz) - siz;
1984 NFSBCOPY(cp, str, xfer);
1993 cp = NFSMTOD(mp, caddr_t);
2005 error = nfsm_advance(nd, rem, len);
2011 NFSEXITCODE2(error, nd);
2016 * Fill in the attributes as marked by the bitmap (V4).
2019 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2020 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2021 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2022 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2024 int bitpos, retnum = 0;
2026 int siz, prefixnum, error;
2027 u_char *cp, namestr[NFSV4_SMALLSTR];
2028 nfsattrbit_t attrbits, retbits;
2029 nfsattrbit_t *retbitp = &retbits;
2030 u_int32_t freenum, *retnump;
2033 struct nfsfsinfo fsinf;
2034 struct timespec temptime;
2035 NFSACL_T *aclp, *naclp = NULL;
2042 * First, set the bits that can be filled and get fsinfo.
2044 NFSSET_ATTRBIT(retbitp, attrbitp);
2046 * If both p and cred are NULL, it is a client side setattr call.
2047 * If both p and cred are not NULL, it is a server side reply call.
2048 * If p is not NULL and cred is NULL, it is a client side callback
2051 if (p == NULL && cred == NULL) {
2052 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2055 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2056 naclp = acl_alloc(M_WAITOK);
2059 nfsvno_getfs(&fsinf, isdgram);
2062 * Get the VFS_STATFS(), since some attributes need them.
2064 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2065 error = VFS_STATFS(mp, &fs);
2068 nd->nd_repstat = NFSERR_ACCES;
2071 NFSCLRSTATFS_ATTRBIT(retbitp);
2077 * And the NFSv4 ACL...
2079 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2080 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2081 supports_nfsv4acls == 0))) {
2082 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2084 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2085 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2086 supports_nfsv4acls == 0)) {
2087 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2088 } else if (naclp != NULL) {
2089 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2090 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2092 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2094 NFSVOPUNLOCK(vp, 0);
2096 error = NFSERR_PERM;
2099 nd->nd_repstat = NFSERR_ACCES;
2102 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2108 * Put out the attribute bitmap for the ones being filled in
2109 * and get the field for the number of attributes returned.
2111 prefixnum = nfsrv_putattrbit(nd, retbitp);
2112 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2113 prefixnum += NFSX_UNSIGNED;
2116 * Now, loop around filling in the attributes for each bit set.
2118 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2119 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2121 case NFSATTRBIT_SUPPORTEDATTRS:
2122 NFSSETSUPP_ATTRBIT(&attrbits);
2123 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2124 && supports_nfsv4acls == 0)) {
2125 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2126 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2128 retnum += nfsrv_putattrbit(nd, &attrbits);
2130 case NFSATTRBIT_TYPE:
2131 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2132 *tl = vtonfsv34_type(vap->va_type);
2133 retnum += NFSX_UNSIGNED;
2135 case NFSATTRBIT_FHEXPIRETYPE:
2136 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2137 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2138 retnum += NFSX_UNSIGNED;
2140 case NFSATTRBIT_CHANGE:
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2142 txdr_hyper(vap->va_filerev, tl);
2143 retnum += NFSX_HYPER;
2145 case NFSATTRBIT_SIZE:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2147 txdr_hyper(vap->va_size, tl);
2148 retnum += NFSX_HYPER;
2150 case NFSATTRBIT_LINKSUPPORT:
2151 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2152 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_SYMLINKSUPPORT:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2160 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2164 retnum += NFSX_UNSIGNED;
2166 case NFSATTRBIT_NAMEDATTR:
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2169 retnum += NFSX_UNSIGNED;
2171 case NFSATTRBIT_FSID:
2172 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2174 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2176 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2177 retnum += NFSX_V4FSID;
2179 case NFSATTRBIT_UNIQUEHANDLES:
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2182 retnum += NFSX_UNSIGNED;
2184 case NFSATTRBIT_LEASETIME:
2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2186 *tl = txdr_unsigned(nfsrv_lease);
2187 retnum += NFSX_UNSIGNED;
2189 case NFSATTRBIT_RDATTRERROR:
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2191 *tl = txdr_unsigned(rderror);
2192 retnum += NFSX_UNSIGNED;
2195 * Recommended Attributes. (Only the supported ones.)
2197 case NFSATTRBIT_ACL:
2198 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2200 case NFSATTRBIT_ACLSUPPORT:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2202 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2203 retnum += NFSX_UNSIGNED;
2205 case NFSATTRBIT_CANSETTIME:
2206 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2207 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2211 retnum += NFSX_UNSIGNED;
2213 case NFSATTRBIT_CASEINSENSITIVE:
2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2216 retnum += NFSX_UNSIGNED;
2218 case NFSATTRBIT_CASEPRESERVING:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2221 retnum += NFSX_UNSIGNED;
2223 case NFSATTRBIT_CHOWNRESTRICTED:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2226 retnum += NFSX_UNSIGNED;
2228 case NFSATTRBIT_FILEHANDLE:
2229 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2231 case NFSATTRBIT_FILEID:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2234 *tl = txdr_unsigned(vap->va_fileid);
2235 retnum += NFSX_HYPER;
2237 case NFSATTRBIT_FILESAVAIL:
2239 * Check quota and use min(quota, f_ffree).
2241 freenum = fs.f_ffree;
2244 * ufs_quotactl() insists that the uid argument
2245 * equal p_ruid for non-root quota access, so
2246 * we'll just make sure that's the case.
2248 savuid = p->p_cred->p_ruid;
2249 p->p_cred->p_ruid = cred->cr_uid;
2250 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2251 cred->cr_uid, (caddr_t)&dqb))
2252 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2254 p->p_cred->p_ruid = savuid;
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2258 *tl = txdr_unsigned(freenum);
2259 retnum += NFSX_HYPER;
2261 case NFSATTRBIT_FILESFREE:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2264 *tl = txdr_unsigned(fs.f_ffree);
2265 retnum += NFSX_HYPER;
2267 case NFSATTRBIT_FILESTOTAL:
2268 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2270 *tl = txdr_unsigned(fs.f_files);
2271 retnum += NFSX_HYPER;
2273 case NFSATTRBIT_FSLOCATIONS:
2274 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2277 retnum += 2 * NFSX_UNSIGNED;
2279 case NFSATTRBIT_HOMOGENEOUS:
2280 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2281 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2285 retnum += NFSX_UNSIGNED;
2287 case NFSATTRBIT_MAXFILESIZE:
2288 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2289 uquad = NFSRV_MAXFILESIZE;
2290 txdr_hyper(uquad, tl);
2291 retnum += NFSX_HYPER;
2293 case NFSATTRBIT_MAXLINK:
2294 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2295 *tl = txdr_unsigned(LINK_MAX);
2296 retnum += NFSX_UNSIGNED;
2298 case NFSATTRBIT_MAXNAME:
2299 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2300 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2301 retnum += NFSX_UNSIGNED;
2303 case NFSATTRBIT_MAXREAD:
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2306 *tl = txdr_unsigned(fsinf.fs_rtmax);
2307 retnum += NFSX_HYPER;
2309 case NFSATTRBIT_MAXWRITE:
2310 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2312 *tl = txdr_unsigned(fsinf.fs_wtmax);
2313 retnum += NFSX_HYPER;
2315 case NFSATTRBIT_MODE:
2316 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2317 *tl = vtonfsv34_mode(vap->va_mode);
2318 retnum += NFSX_UNSIGNED;
2320 case NFSATTRBIT_NOTRUNC:
2321 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2323 retnum += NFSX_UNSIGNED;
2325 case NFSATTRBIT_NUMLINKS:
2326 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2327 *tl = txdr_unsigned(vap->va_nlink);
2328 retnum += NFSX_UNSIGNED;
2330 case NFSATTRBIT_OWNER:
2332 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2333 retnum += nfsm_strtom(nd, cp, siz);
2335 free(cp, M_NFSSTRING);
2337 case NFSATTRBIT_OWNERGROUP:
2339 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2340 retnum += nfsm_strtom(nd, cp, siz);
2342 free(cp, M_NFSSTRING);
2344 case NFSATTRBIT_QUOTAHARD:
2345 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2346 freenum = fs.f_bfree;
2348 freenum = fs.f_bavail;
2351 * ufs_quotactl() insists that the uid argument
2352 * equal p_ruid for non-root quota access, so
2353 * we'll just make sure that's the case.
2355 savuid = p->p_cred->p_ruid;
2356 p->p_cred->p_ruid = cred->cr_uid;
2357 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2358 cred->cr_uid, (caddr_t)&dqb))
2359 freenum = min(dqb.dqb_bhardlimit, freenum);
2360 p->p_cred->p_ruid = savuid;
2362 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2363 uquad = (u_int64_t)freenum;
2364 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2365 txdr_hyper(uquad, tl);
2366 retnum += NFSX_HYPER;
2368 case NFSATTRBIT_QUOTASOFT:
2369 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2370 freenum = fs.f_bfree;
2372 freenum = fs.f_bavail;
2375 * ufs_quotactl() insists that the uid argument
2376 * equal p_ruid for non-root quota access, so
2377 * we'll just make sure that's the case.
2379 savuid = p->p_cred->p_ruid;
2380 p->p_cred->p_ruid = cred->cr_uid;
2381 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2382 cred->cr_uid, (caddr_t)&dqb))
2383 freenum = min(dqb.dqb_bsoftlimit, freenum);
2384 p->p_cred->p_ruid = savuid;
2386 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2387 uquad = (u_int64_t)freenum;
2388 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2389 txdr_hyper(uquad, tl);
2390 retnum += NFSX_HYPER;
2392 case NFSATTRBIT_QUOTAUSED:
2396 * ufs_quotactl() insists that the uid argument
2397 * equal p_ruid for non-root quota access, so
2398 * we'll just make sure that's the case.
2400 savuid = p->p_cred->p_ruid;
2401 p->p_cred->p_ruid = cred->cr_uid;
2402 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2403 cred->cr_uid, (caddr_t)&dqb))
2404 freenum = dqb.dqb_curblocks;
2405 p->p_cred->p_ruid = savuid;
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2408 uquad = (u_int64_t)freenum;
2409 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2410 txdr_hyper(uquad, tl);
2411 retnum += NFSX_HYPER;
2413 case NFSATTRBIT_RAWDEV:
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2415 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2416 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2417 retnum += NFSX_V4SPECDATA;
2419 case NFSATTRBIT_SPACEAVAIL:
2420 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2421 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2422 uquad = (u_int64_t)fs.f_bfree;
2424 uquad = (u_int64_t)fs.f_bavail;
2425 uquad *= fs.f_bsize;
2426 txdr_hyper(uquad, tl);
2427 retnum += NFSX_HYPER;
2429 case NFSATTRBIT_SPACEFREE:
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2431 uquad = (u_int64_t)fs.f_bfree;
2432 uquad *= fs.f_bsize;
2433 txdr_hyper(uquad, tl);
2434 retnum += NFSX_HYPER;
2436 case NFSATTRBIT_SPACETOTAL:
2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2438 uquad = (u_int64_t)fs.f_blocks;
2439 uquad *= fs.f_bsize;
2440 txdr_hyper(uquad, tl);
2441 retnum += NFSX_HYPER;
2443 case NFSATTRBIT_SPACEUSED:
2444 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2445 txdr_hyper(vap->va_bytes, tl);
2446 retnum += NFSX_HYPER;
2448 case NFSATTRBIT_TIMEACCESS:
2449 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2450 txdr_nfsv4time(&vap->va_atime, tl);
2451 retnum += NFSX_V4TIME;
2453 case NFSATTRBIT_TIMEACCESSSET:
2454 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2455 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2456 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2457 txdr_nfsv4time(&vap->va_atime, tl);
2458 retnum += NFSX_V4SETTIME;
2460 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2461 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2462 retnum += NFSX_UNSIGNED;
2465 case NFSATTRBIT_TIMEDELTA:
2466 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2467 temptime.tv_sec = 0;
2468 temptime.tv_nsec = 1000000000 / hz;
2469 txdr_nfsv4time(&temptime, tl);
2470 retnum += NFSX_V4TIME;
2472 case NFSATTRBIT_TIMEMETADATA:
2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2474 txdr_nfsv4time(&vap->va_ctime, tl);
2475 retnum += NFSX_V4TIME;
2477 case NFSATTRBIT_TIMEMODIFY:
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2479 txdr_nfsv4time(&vap->va_mtime, tl);
2480 retnum += NFSX_V4TIME;
2482 case NFSATTRBIT_TIMEMODIFYSET:
2483 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2484 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2485 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2486 txdr_nfsv4time(&vap->va_mtime, tl);
2487 retnum += NFSX_V4SETTIME;
2489 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2490 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2491 retnum += NFSX_UNSIGNED;
2494 case NFSATTRBIT_MOUNTEDONFILEID:
2495 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2497 uquad = mounted_on_fileno;
2499 uquad = (u_int64_t)vap->va_fileid;
2500 txdr_hyper(uquad, tl);
2501 retnum += NFSX_HYPER;
2503 case NFSATTRBIT_SUPPATTREXCLCREAT:
2504 NFSSETSUPP_ATTRBIT(&attrbits);
2505 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2506 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2507 retnum += nfsrv_putattrbit(nd, &attrbits);
2510 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2516 *retnump = txdr_unsigned(retnum);
2517 return (retnum + prefixnum);
2521 * Put the attribute bits onto an mbuf list.
2522 * Return the number of bytes of output generated.
2525 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2528 int cnt, i, bytesize;
2530 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2531 if (attrbitp->bits[cnt - 1])
2533 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2534 NFSM_BUILD(tl, u_int32_t *, bytesize);
2535 *tl++ = txdr_unsigned(cnt);
2536 for (i = 0; i < cnt; i++)
2537 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2542 * Convert a uid to a string.
2543 * If the lookup fails, just output the digits.
2545 * cpp - points to a buffer of size NFSV4_SMALLSTR
2546 * (malloc a larger one, as required)
2547 * retlenp - pointer to length to be returned
2550 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2553 struct nfsusrgrp *usrp;
2556 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2557 struct nfsrv_lughash *hp;
2561 if (nfsrv_dnsnamelen > 0) {
2563 * Always map nfsrv_defaultuid to "nobody".
2565 if (uid == nfsrv_defaultuid) {
2566 i = nfsrv_dnsnamelen + 7;
2568 if (len > NFSV4_SMALLSTR)
2569 free(cp, M_NFSSTRING);
2570 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2576 NFSBCOPY("nobody@", cp, 7);
2578 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2582 hp = NFSUSERHASH(uid);
2584 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2585 if (usrp->lug_uid == uid) {
2586 if (usrp->lug_expiry < NFSD_MONOSEC)
2589 * If the name doesn't already have an '@'
2590 * in it, append @domainname to it.
2592 for (i = 0; i < usrp->lug_namelen; i++) {
2593 if (usrp->lug_name[i] == '@') {
2599 i = usrp->lug_namelen;
2601 i = usrp->lug_namelen +
2602 nfsrv_dnsnamelen + 1;
2604 mtx_unlock(&hp->mtx);
2605 if (len > NFSV4_SMALLSTR)
2606 free(cp, M_NFSSTRING);
2607 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2613 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2614 if (!hasampersand) {
2615 cp += usrp->lug_namelen;
2617 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2619 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2620 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2622 mtx_unlock(&hp->mtx);
2626 mtx_unlock(&hp->mtx);
2628 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2630 if (ret == 0 && cnt < 2)
2635 * No match, just return a string of digits.
2639 while (tmp || i == 0) {
2643 len = (i > len) ? len : i;
2647 for (i = 0; i < len; i++) {
2648 *cp-- = '0' + (tmp % 10);
2655 * Get a credential for the uid with the server's group list.
2656 * If none is found, just return the credential passed in after
2657 * logging a warning message.
2660 nfsrv_getgrpscred(struct ucred *oldcred)
2662 struct nfsusrgrp *usrp;
2663 struct ucred *newcred;
2666 struct nfsrv_lughash *hp;
2669 uid = oldcred->cr_uid;
2671 if (nfsrv_dnsnamelen > 0) {
2672 hp = NFSUSERHASH(uid);
2674 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2675 if (usrp->lug_uid == uid) {
2676 if (usrp->lug_expiry < NFSD_MONOSEC)
2678 if (usrp->lug_cred != NULL) {
2679 newcred = crhold(usrp->lug_cred);
2683 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2684 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2686 mtx_unlock(&hp->mtx);
2690 mtx_unlock(&hp->mtx);
2692 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2694 if (ret == 0 && cnt < 2)
2701 * Convert a string to a uid.
2702 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2704 * If this is called from a client side mount using AUTH_SYS and the
2705 * string is made up entirely of digits, just convert the string to
2709 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2713 char *cp, *endstr, *str0;
2714 struct nfsusrgrp *usrp;
2718 struct nfsrv_lughash *hp, *hp2;
2721 error = NFSERR_BADOWNER;
2724 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2726 tuid = (uid_t)strtoul(str0, &endstr, 10);
2727 if ((endstr - str0) == len) {
2728 /* A numeric string. */
2729 if ((nd->nd_flag & ND_KERBV) == 0 &&
2730 ((nd->nd_flag & ND_NFSCL) != 0 ||
2731 nfsd_enable_stringtouid != 0))
2734 error = NFSERR_BADOWNER;
2740 cp = strchr(str0, '@');
2742 i = (int)(cp++ - str0);
2748 if (nfsrv_dnsnamelen > 0) {
2750 * If an '@' is found and the domain name matches, search for
2751 * the name with dns stripped off.
2752 * Mixed case alpahbetics will match for the domain name, but
2753 * all upper case will not.
2755 if (cnt == 0 && i < len && i > 0 &&
2756 (len - 1 - i) == nfsrv_dnsnamelen &&
2757 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2758 len -= (nfsrv_dnsnamelen + 1);
2763 * Check for the special case of "nobody".
2765 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2766 *uidp = nfsrv_defaultuid;
2771 hp = NFSUSERNAMEHASH(str, len);
2773 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2774 if (usrp->lug_namelen == len &&
2775 !NFSBCMP(usrp->lug_name, str, len)) {
2776 if (usrp->lug_expiry < NFSD_MONOSEC)
2778 hp2 = NFSUSERHASH(usrp->lug_uid);
2779 mtx_lock(&hp2->mtx);
2780 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2781 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2783 *uidp = usrp->lug_uid;
2784 mtx_unlock(&hp2->mtx);
2785 mtx_unlock(&hp->mtx);
2790 mtx_unlock(&hp->mtx);
2792 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2794 if (ret == 0 && cnt < 2)
2797 error = NFSERR_BADOWNER;
2805 * Convert a gid to a string.
2806 * gid - the group id
2807 * cpp - points to a buffer of size NFSV4_SMALLSTR
2808 * (malloc a larger one, as required)
2809 * retlenp - pointer to length to be returned
2812 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2815 struct nfsusrgrp *usrp;
2818 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2819 struct nfsrv_lughash *hp;
2823 if (nfsrv_dnsnamelen > 0) {
2825 * Always map nfsrv_defaultgid to "nogroup".
2827 if (gid == nfsrv_defaultgid) {
2828 i = nfsrv_dnsnamelen + 8;
2830 if (len > NFSV4_SMALLSTR)
2831 free(cp, M_NFSSTRING);
2832 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2838 NFSBCOPY("nogroup@", cp, 8);
2840 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2844 hp = NFSGROUPHASH(gid);
2846 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2847 if (usrp->lug_gid == gid) {
2848 if (usrp->lug_expiry < NFSD_MONOSEC)
2851 * If the name doesn't already have an '@'
2852 * in it, append @domainname to it.
2854 for (i = 0; i < usrp->lug_namelen; i++) {
2855 if (usrp->lug_name[i] == '@') {
2861 i = usrp->lug_namelen;
2863 i = usrp->lug_namelen +
2864 nfsrv_dnsnamelen + 1;
2866 mtx_unlock(&hp->mtx);
2867 if (len > NFSV4_SMALLSTR)
2868 free(cp, M_NFSSTRING);
2869 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2875 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2876 if (!hasampersand) {
2877 cp += usrp->lug_namelen;
2879 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2881 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2882 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2884 mtx_unlock(&hp->mtx);
2888 mtx_unlock(&hp->mtx);
2890 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2892 if (ret == 0 && cnt < 2)
2897 * No match, just return a string of digits.
2901 while (tmp || i == 0) {
2905 len = (i > len) ? len : i;
2909 for (i = 0; i < len; i++) {
2910 *cp-- = '0' + (tmp % 10);
2917 * Convert a string to a gid.
2918 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2920 * If this is called from a client side mount using AUTH_SYS and the
2921 * string is made up entirely of digits, just convert the string to
2925 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2929 char *cp, *endstr, *str0;
2930 struct nfsusrgrp *usrp;
2934 struct nfsrv_lughash *hp, *hp2;
2937 error = NFSERR_BADOWNER;
2940 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2942 tgid = (gid_t)strtoul(str0, &endstr, 10);
2943 if ((endstr - str0) == len) {
2944 /* A numeric string. */
2945 if ((nd->nd_flag & ND_KERBV) == 0 &&
2946 ((nd->nd_flag & ND_NFSCL) != 0 ||
2947 nfsd_enable_stringtouid != 0))
2950 error = NFSERR_BADOWNER;
2956 cp = strchr(str0, '@');
2958 i = (int)(cp++ - str0);
2964 if (nfsrv_dnsnamelen > 0) {
2966 * If an '@' is found and the dns name matches, search for the
2967 * name with the dns stripped off.
2969 if (cnt == 0 && i < len && i > 0 &&
2970 (len - 1 - i) == nfsrv_dnsnamelen &&
2971 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2972 len -= (nfsrv_dnsnamelen + 1);
2977 * Check for the special case of "nogroup".
2979 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2980 *gidp = nfsrv_defaultgid;
2985 hp = NFSGROUPNAMEHASH(str, len);
2987 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2988 if (usrp->lug_namelen == len &&
2989 !NFSBCMP(usrp->lug_name, str, len)) {
2990 if (usrp->lug_expiry < NFSD_MONOSEC)
2992 hp2 = NFSGROUPHASH(usrp->lug_gid);
2993 mtx_lock(&hp2->mtx);
2994 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2995 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2997 *gidp = usrp->lug_gid;
2998 mtx_unlock(&hp2->mtx);
2999 mtx_unlock(&hp->mtx);
3004 mtx_unlock(&hp->mtx);
3006 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3008 if (ret == 0 && cnt < 2)
3011 error = NFSERR_BADOWNER;
3019 * Cmp len chars, allowing mixed case in the first argument to match lower
3020 * case in the second, but not if the first argument is all upper case.
3021 * Return 0 for a match, 1 otherwise.
3024 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3030 for (i = 0; i < len; i++) {
3031 if (*cp >= 'A' && *cp <= 'Z') {
3032 tmp = *cp++ + ('a' - 'A');
3035 if (tmp >= 'a' && tmp <= 'z')
3048 * Set the port for the nfsuserd.
3051 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3053 struct nfssockreq *rp;
3054 struct sockaddr_in *ad;
3058 if (nfsrv_nfsuserd) {
3066 * Set up the socket record and connect.
3068 rp = &nfsrv_nfsuserdsock;
3069 rp->nr_client = NULL;
3070 rp->nr_sotype = SOCK_DGRAM;
3071 rp->nr_soproto = IPPROTO_UDP;
3072 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3074 NFSSOCKADDRALLOC(rp->nr_nam);
3075 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3076 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3077 ad->sin_family = AF_INET;
3078 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3079 ad->sin_port = port;
3080 rp->nr_prog = RPCPROG_NFSUSERD;
3081 rp->nr_vers = RPCNFSUSERD_VERS;
3082 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3084 NFSSOCKADDRFREE(rp->nr_nam);
3093 * Delete the nfsuserd port.
3096 nfsrv_nfsuserddelport(void)
3100 if (nfsrv_nfsuserd == 0) {
3106 newnfs_disconnect(&nfsrv_nfsuserdsock);
3107 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3111 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3113 * Returns 0 upon success, non-zero otherwise.
3116 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3119 struct nfsrv_descript *nd;
3121 struct nfsrv_descript nfsd;
3126 if (nfsrv_nfsuserd == 0) {
3133 cred = newnfs_getcred();
3134 nd->nd_flag = ND_GSSINITREPLY;
3137 nd->nd_procnum = procnum;
3138 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3139 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3140 if (procnum == RPCNFSUSERD_GETUID)
3141 *tl = txdr_unsigned(uid);
3143 *tl = txdr_unsigned(gid);
3146 (void) nfsm_strtom(nd, name, len);
3148 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3149 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3152 mbuf_freem(nd->nd_mrep);
3153 error = nd->nd_repstat;
3161 * This function is called from the nfssvc(2) system call, to update the
3162 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3165 nfssvc_idname(struct nfsd_idargs *nidp)
3167 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3168 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3169 int i, group_locked, groupname_locked, user_locked, username_locked;
3174 static int onethread = 0;
3175 static time_t lasttime = 0;
3177 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3181 if (nidp->nid_flag & NFSID_INITIALIZE) {
3182 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3183 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3186 free(cp, M_NFSSTRING);
3189 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3191 * Free up all the old stuff and reinitialize hash
3192 * lists. All mutexes for both lists must be locked,
3193 * with the user/group name ones before the uid/gid
3194 * ones, to avoid a LOR.
3196 for (i = 0; i < nfsrv_lughashsize; i++)
3197 mtx_lock(&nfsusernamehash[i].mtx);
3198 for (i = 0; i < nfsrv_lughashsize; i++)
3199 mtx_lock(&nfsuserhash[i].mtx);
3200 for (i = 0; i < nfsrv_lughashsize; i++)
3201 TAILQ_FOREACH_SAFE(usrp,
3202 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3203 nfsrv_removeuser(usrp, 1);
3204 for (i = 0; i < nfsrv_lughashsize; i++)
3205 mtx_unlock(&nfsuserhash[i].mtx);
3206 for (i = 0; i < nfsrv_lughashsize; i++)
3207 mtx_unlock(&nfsusernamehash[i].mtx);
3208 for (i = 0; i < nfsrv_lughashsize; i++)
3209 mtx_lock(&nfsgroupnamehash[i].mtx);
3210 for (i = 0; i < nfsrv_lughashsize; i++)
3211 mtx_lock(&nfsgrouphash[i].mtx);
3212 for (i = 0; i < nfsrv_lughashsize; i++)
3213 TAILQ_FOREACH_SAFE(usrp,
3214 &nfsgrouphash[i].lughead, lug_numhash,
3216 nfsrv_removeuser(usrp, 0);
3217 for (i = 0; i < nfsrv_lughashsize; i++)
3218 mtx_unlock(&nfsgrouphash[i].mtx);
3219 for (i = 0; i < nfsrv_lughashsize; i++)
3220 mtx_unlock(&nfsgroupnamehash[i].mtx);
3221 free(nfsrv_dnsname, M_NFSSTRING);
3222 nfsrv_dnsname = NULL;
3224 if (nfsuserhash == NULL) {
3225 /* Allocate the hash tables. */
3226 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3227 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3229 for (i = 0; i < nfsrv_lughashsize; i++)
3230 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3231 NULL, MTX_DEF | MTX_DUPOK);
3232 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3233 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 mtx_init(&nfsusernamehash[i].mtx,
3237 "nfsusrhash", NULL, MTX_DEF |
3239 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3240 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3242 for (i = 0; i < nfsrv_lughashsize; i++)
3243 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3244 NULL, MTX_DEF | MTX_DUPOK);
3245 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3246 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3248 for (i = 0; i < nfsrv_lughashsize; i++)
3249 mtx_init(&nfsgroupnamehash[i].mtx,
3250 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3252 /* (Re)initialize the list heads. */
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 TAILQ_INIT(&nfsuserhash[i].lughead);
3255 for (i = 0; i < nfsrv_lughashsize; i++)
3256 TAILQ_INIT(&nfsusernamehash[i].lughead);
3257 for (i = 0; i < nfsrv_lughashsize; i++)
3258 TAILQ_INIT(&nfsgrouphash[i].lughead);
3259 for (i = 0; i < nfsrv_lughashsize; i++)
3260 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3263 * Put name in "DNS" string.
3266 nfsrv_defaultuid = nidp->nid_uid;
3267 nfsrv_defaultgid = nidp->nid_gid;
3269 nfsrv_usermax = nidp->nid_usermax;
3270 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3275 * malloc the new one now, so any potential sleep occurs before
3276 * manipulation of the lists.
3278 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3279 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3280 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3282 if (error == 0 && nidp->nid_ngroup > 0 &&
3283 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3284 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3286 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3287 sizeof(gid_t) * nidp->nid_ngroup);
3290 * Create a credential just like svc_getcred(),
3291 * but using the group list provided.
3294 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3295 crsetgroups(cr, nidp->nid_ngroup, grps);
3296 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3297 cr->cr_prison = &prison0;
3298 prison_hold(cr->cr_prison);
3300 mac_cred_associate_nfsd(cr);
3302 newusrp->lug_cred = cr;
3307 free(newusrp, M_NFSUSERGROUP);
3310 newusrp->lug_namelen = nidp->nid_namelen;
3313 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3314 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3315 * The flags user_locked, username_locked, group_locked and
3316 * groupname_locked are set to indicate all of those hash lists are
3317 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3318 * the respective one mutex is locked.
3320 user_locked = username_locked = group_locked = groupname_locked = 0;
3321 hp_name = hp_idnum = NULL;
3324 * Delete old entries, as required.
3326 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3327 /* Must lock all username hash lists first, to avoid a LOR. */
3328 for (i = 0; i < nfsrv_lughashsize; i++)
3329 mtx_lock(&nfsusernamehash[i].mtx);
3330 username_locked = 1;
3331 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3332 mtx_lock(&hp_idnum->mtx);
3333 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3335 if (usrp->lug_uid == nidp->nid_uid)
3336 nfsrv_removeuser(usrp, 1);
3338 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3339 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3340 newusrp->lug_namelen);
3341 mtx_lock(&hp_name->mtx);
3342 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3344 if (usrp->lug_namelen == newusrp->lug_namelen &&
3345 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3346 usrp->lug_namelen)) {
3347 thp = NFSUSERHASH(usrp->lug_uid);
3348 mtx_lock(&thp->mtx);
3349 nfsrv_removeuser(usrp, 1);
3350 mtx_unlock(&thp->mtx);
3353 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3354 mtx_lock(&hp_idnum->mtx);
3355 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3356 /* Must lock all groupname hash lists first, to avoid a LOR. */
3357 for (i = 0; i < nfsrv_lughashsize; i++)
3358 mtx_lock(&nfsgroupnamehash[i].mtx);
3359 groupname_locked = 1;
3360 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3361 mtx_lock(&hp_idnum->mtx);
3362 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3364 if (usrp->lug_gid == nidp->nid_gid)
3365 nfsrv_removeuser(usrp, 0);
3367 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3368 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3369 newusrp->lug_namelen);
3370 mtx_lock(&hp_name->mtx);
3371 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3373 if (usrp->lug_namelen == newusrp->lug_namelen &&
3374 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3375 usrp->lug_namelen)) {
3376 thp = NFSGROUPHASH(usrp->lug_gid);
3377 mtx_lock(&thp->mtx);
3378 nfsrv_removeuser(usrp, 0);
3379 mtx_unlock(&thp->mtx);
3382 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3383 mtx_lock(&hp_idnum->mtx);
3387 * Now, we can add the new one.
3389 if (nidp->nid_usertimeout)
3390 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3392 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3393 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3394 newusrp->lug_uid = nidp->nid_uid;
3395 thp = NFSUSERHASH(newusrp->lug_uid);
3396 mtx_assert(&thp->mtx, MA_OWNED);
3397 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3398 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3399 mtx_assert(&thp->mtx, MA_OWNED);
3400 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3401 atomic_add_int(&nfsrv_usercnt, 1);
3402 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3403 newusrp->lug_gid = nidp->nid_gid;
3404 thp = NFSGROUPHASH(newusrp->lug_gid);
3405 mtx_assert(&thp->mtx, MA_OWNED);
3406 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3407 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3408 mtx_assert(&thp->mtx, MA_OWNED);
3409 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3410 atomic_add_int(&nfsrv_usercnt, 1);
3412 if (newusrp->lug_cred != NULL)
3413 crfree(newusrp->lug_cred);
3414 free(newusrp, M_NFSUSERGROUP);
3418 * Once per second, allow one thread to trim the cache.
3420 if (lasttime < NFSD_MONOSEC &&
3421 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3423 * First, unlock the single mutexes, so that all entries
3424 * can be locked and any LOR is avoided.
3426 if (hp_name != NULL) {
3427 mtx_unlock(&hp_name->mtx);
3430 if (hp_idnum != NULL) {
3431 mtx_unlock(&hp_idnum->mtx);
3435 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3436 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3437 if (username_locked == 0) {
3438 for (i = 0; i < nfsrv_lughashsize; i++)
3439 mtx_lock(&nfsusernamehash[i].mtx);
3440 username_locked = 1;
3442 KASSERT(user_locked == 0,
3443 ("nfssvc_idname: user_locked"));
3444 for (i = 0; i < nfsrv_lughashsize; i++)
3445 mtx_lock(&nfsuserhash[i].mtx);
3447 for (i = 0; i < nfsrv_lughashsize; i++) {
3448 TAILQ_FOREACH_SAFE(usrp,
3449 &nfsuserhash[i].lughead, lug_numhash,
3451 if (usrp->lug_expiry < NFSD_MONOSEC)
3452 nfsrv_removeuser(usrp, 1);
3454 for (i = 0; i < nfsrv_lughashsize; i++) {
3456 * Trim the cache using an approximate LRU
3457 * algorithm. This code deletes the least
3458 * recently used entry on each hash list.
3460 if (nfsrv_usercnt <= nfsrv_usermax)
3462 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3464 nfsrv_removeuser(usrp, 1);
3467 if (groupname_locked == 0) {
3468 for (i = 0; i < nfsrv_lughashsize; i++)
3469 mtx_lock(&nfsgroupnamehash[i].mtx);
3470 groupname_locked = 1;
3472 KASSERT(group_locked == 0,
3473 ("nfssvc_idname: group_locked"));
3474 for (i = 0; i < nfsrv_lughashsize; i++)
3475 mtx_lock(&nfsgrouphash[i].mtx);
3477 for (i = 0; i < nfsrv_lughashsize; i++) {
3478 TAILQ_FOREACH_SAFE(usrp,
3479 &nfsgrouphash[i].lughead, lug_numhash,
3481 if (usrp->lug_expiry < NFSD_MONOSEC)
3482 nfsrv_removeuser(usrp, 0);
3484 for (i = 0; i < nfsrv_lughashsize; i++) {
3486 * Trim the cache using an approximate LRU
3487 * algorithm. This code deletes the least
3488 * recently user entry on each hash list.
3490 if (nfsrv_usercnt <= nfsrv_usermax)
3492 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3494 nfsrv_removeuser(usrp, 0);
3497 lasttime = NFSD_MONOSEC;
3498 atomic_store_rel_int(&onethread, 0);
3501 /* Now, unlock all locked mutexes. */
3502 if (hp_idnum != NULL)
3503 mtx_unlock(&hp_idnum->mtx);
3504 if (hp_name != NULL)
3505 mtx_unlock(&hp_name->mtx);
3506 if (user_locked != 0)
3507 for (i = 0; i < nfsrv_lughashsize; i++)
3508 mtx_unlock(&nfsuserhash[i].mtx);
3509 if (username_locked != 0)
3510 for (i = 0; i < nfsrv_lughashsize; i++)
3511 mtx_unlock(&nfsusernamehash[i].mtx);
3512 if (group_locked != 0)
3513 for (i = 0; i < nfsrv_lughashsize; i++)
3514 mtx_unlock(&nfsgrouphash[i].mtx);
3515 if (groupname_locked != 0)
3516 for (i = 0; i < nfsrv_lughashsize; i++)
3517 mtx_unlock(&nfsgroupnamehash[i].mtx);
3524 * Remove a user/group name element.
3527 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3529 struct nfsrv_lughash *hp;
3532 hp = NFSUSERHASH(usrp->lug_uid);
3533 mtx_assert(&hp->mtx, MA_OWNED);
3534 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3535 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3536 mtx_assert(&hp->mtx, MA_OWNED);
3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3539 hp = NFSGROUPHASH(usrp->lug_gid);
3540 mtx_assert(&hp->mtx, MA_OWNED);
3541 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3542 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3543 mtx_assert(&hp->mtx, MA_OWNED);
3544 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3546 atomic_add_int(&nfsrv_usercnt, -1);
3547 if (usrp->lug_cred != NULL)
3548 crfree(usrp->lug_cred);
3549 free(usrp, M_NFSUSERGROUP);
3553 * Free up all the allocations related to the name<-->id cache.
3554 * This function should only be called when the nfsuserd daemon isn't
3555 * running, since it doesn't do any locking.
3556 * This function is meant to be used when the nfscommon module is unloaded.
3559 nfsrv_cleanusergroup(void)
3561 struct nfsrv_lughash *hp, *hp2;
3562 struct nfsusrgrp *nusrp, *usrp;
3565 if (nfsuserhash == NULL)
3568 for (i = 0; i < nfsrv_lughashsize; i++) {
3569 hp = &nfsuserhash[i];
3570 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3571 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3572 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3574 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3575 if (usrp->lug_cred != NULL)
3576 crfree(usrp->lug_cred);
3577 free(usrp, M_NFSUSERGROUP);
3579 hp = &nfsgrouphash[i];
3580 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3581 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3582 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3584 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3585 if (usrp->lug_cred != NULL)
3586 crfree(usrp->lug_cred);
3587 free(usrp, M_NFSUSERGROUP);
3589 mtx_destroy(&nfsuserhash[i].mtx);
3590 mtx_destroy(&nfsusernamehash[i].mtx);
3591 mtx_destroy(&nfsgroupnamehash[i].mtx);
3592 mtx_destroy(&nfsgrouphash[i].mtx);
3594 free(nfsuserhash, M_NFSUSERGROUP);
3595 free(nfsusernamehash, M_NFSUSERGROUP);
3596 free(nfsgrouphash, M_NFSUSERGROUP);
3597 free(nfsgroupnamehash, M_NFSUSERGROUP);
3598 free(nfsrv_dnsname, M_NFSSTRING);
3602 * This function scans a byte string and checks for UTF-8 compliance.
3603 * It returns 0 if it conforms and NFSERR_INVAL if not.
3606 nfsrv_checkutf8(u_int8_t *cp, int len)
3608 u_int32_t val = 0x0;
3609 int cnt = 0, gotd = 0, shift = 0;
3611 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3615 * Here are what the variables are used for:
3616 * val - the calculated value of a multibyte char, used to check
3617 * that it was coded with the correct range
3618 * cnt - the number of 10xxxxxx bytes to follow
3619 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3620 * shift - lower order bits of range (ie. "val >> shift" should
3621 * not be 0, in other words, dividing by the lower bound
3622 * of the range should get a non-zero value)
3623 * byte - used to calculate cnt
3627 /* This handles the 10xxxxxx bytes */
3628 if ((*cp & 0xc0) != 0x80 ||
3629 (gotd && (*cp & 0x20))) {
3630 error = NFSERR_INVAL;
3635 val |= (*cp & 0x3f);
3637 if (cnt == 0 && (val >> shift) == 0x0) {
3638 error = NFSERR_INVAL;
3641 } else if (*cp & 0x80) {
3642 /* first byte of multi byte char */
3644 while ((byte & 0x40) && cnt < 6) {
3648 if (cnt == 0 || cnt == 6) {
3649 error = NFSERR_INVAL;
3652 val = (*cp & (0x3f >> cnt));
3653 shift = utf8_shift[cnt - 1];
3654 if (cnt == 2 && val == 0xd)
3655 /* Check for the 0xd800-0xdfff case */
3662 error = NFSERR_INVAL;
3670 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3671 * strings, one with the root path in it and the other with the list of
3672 * locations. The list is in the same format as is found in nfr_refs.
3673 * It is a "," separated list of entries, where each of them is of the
3674 * form <server>:<rootpath>. For example
3675 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3676 * The nilp argument is set to 1 for the special case of a null fs_root
3677 * and an empty server list.
3678 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3679 * number of xdr bytes parsed in sump.
3682 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3683 int *sump, int *nilp)
3686 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3687 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3689 SLIST_ENTRY(list) next;
3693 SLIST_HEAD(, list) head;
3700 * Get the fs_root path and check for the special case of null path
3701 * and 0 length server list.
3703 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3704 len = fxdr_unsigned(int, *tl);
3705 if (len < 0 || len > 10240) {
3706 error = NFSERR_BADXDR;
3710 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3712 error = NFSERR_BADXDR;
3716 *sump = 2 * NFSX_UNSIGNED;
3720 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3721 error = nfsrv_mtostr(nd, cp, len);
3723 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3724 cnt = fxdr_unsigned(int, *tl);
3726 error = NFSERR_BADXDR;
3732 * Now, loop through the location list and make up the srvlist.
3734 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3735 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3738 for (i = 0; i < cnt; i++) {
3740 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3741 nsrv = fxdr_unsigned(int, *tl);
3743 error = NFSERR_BADXDR;
3748 * Handle the first server by putting it in the srvstr.
3750 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3751 len = fxdr_unsigned(int, *tl);
3752 if (len <= 0 || len > 1024) {
3753 error = NFSERR_BADXDR;
3756 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3761 error = nfsrv_mtostr(nd, cp3, len);
3767 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3768 for (j = 1; j < nsrv; j++) {
3770 * Yuck, put them in an slist and process them later.
3772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3773 len = fxdr_unsigned(int, *tl);
3774 if (len <= 0 || len > 1024) {
3775 error = NFSERR_BADXDR;
3778 lsp = (struct list *)malloc(sizeof (struct list)
3779 + len, M_TEMP, M_WAITOK);
3780 error = nfsrv_mtostr(nd, lsp->host, len);
3783 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3785 SLIST_INSERT_HEAD(&head, lsp, next);
3789 * Finally, we can get the path.
3791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3792 len = fxdr_unsigned(int, *tl);
3793 if (len <= 0 || len > 1024) {
3794 error = NFSERR_BADXDR;
3797 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3798 error = nfsrv_mtostr(nd, cp3, len);
3801 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3806 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3807 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3810 NFSBCOPY(lsp->host, cp3, lsp->len);
3813 NFSBCOPY(str, cp3, stringlen);
3816 siz += (lsp->len + stringlen + 2);
3817 free((caddr_t)lsp, M_TEMP);
3823 NFSEXITCODE2(0, nd);
3827 free(cp, M_NFSSTRING);
3829 free(cp2, M_NFSSTRING);
3830 NFSEXITCODE2(error, nd);
3835 * Make the malloc'd space large enough. This is a pain, but the xdr
3836 * doesn't set an upper bound on the side, so...
3839 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3846 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3847 NFSBCOPY(*cpp, cp, *slenp);
3848 free(*cpp, M_NFSSTRING);
3852 *slenp = siz + 1024;
3856 * Initialize the reply header data structures.
3859 nfsrvd_rephead(struct nfsrv_descript *nd)
3864 * If this is a big reply, use a cluster.
3866 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3867 nfs_bigreply[nd->nd_procnum]) {
3868 NFSMCLGET(mreq, M_WAITOK);
3876 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3877 mbuf_setlen(mreq, 0);
3879 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3880 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3884 * Lock a socket against others.
3885 * Currently used to serialize connect/disconnect attempts.
3888 newnfs_sndlock(int *flagp)
3893 while (*flagp & NFSR_SNDLOCK) {
3894 *flagp |= NFSR_WANTSND;
3897 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3898 PZERO - 1, "nfsndlck", &ts);
3900 *flagp |= NFSR_SNDLOCK;
3906 * Unlock the stream socket for others.
3909 newnfs_sndunlock(int *flagp)
3913 if ((*flagp & NFSR_SNDLOCK) == 0)
3914 panic("nfs sndunlock");
3915 *flagp &= ~NFSR_SNDLOCK;
3916 if (*flagp & NFSR_WANTSND) {
3917 *flagp &= ~NFSR_WANTSND;
3918 wakeup((caddr_t)flagp);
3924 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3927 struct sockaddr_in *sad;
3928 struct sockaddr_in6 *sad6;
3929 struct in_addr saddr;
3930 uint32_t portnum, *tl;
3931 int af = 0, i, j, k;
3932 char addr[64], protocol[5], *cp;
3933 int cantparse = 0, error = 0;
3936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3937 i = fxdr_unsigned(int, *tl);
3938 if (i >= 3 && i <= 4) {
3939 error = nfsrv_mtostr(nd, protocol, i);
3942 if (strcmp(protocol, "tcp") == 0) {
3945 } else if (strcmp(protocol, "udp") == 0) {
3948 } else if (strcmp(protocol, "tcp6") == 0) {
3951 } else if (strcmp(protocol, "udp6") == 0) {
3959 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3964 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3965 i = fxdr_unsigned(int, *tl);
3967 error = NFSERR_BADXDR;
3969 } else if (cantparse == 0 && i >= 11 && i < 64) {
3971 * The shortest address is 11chars and the longest is < 64.
3973 error = nfsrv_mtostr(nd, addr, i);
3977 /* Find the port# at the end and extract that. */
3981 /* Count back two '.'s from end to get port# field. */
3982 for (j = 0; j < i; j++) {
3992 * The NFSv4 port# is appended as .N.N, where N is
3993 * a decimal # in the range 0-255, just like an inet4
3994 * address. Cheat and use inet_aton(), which will
3995 * return a Class A address and then shift the high
3996 * order 8bits over to convert it to the port#.
3999 if (inet_aton(cp, &saddr) == 1) {
4000 portnum = ntohl(saddr.s_addr);
4001 portv = (uint16_t)((portnum >> 16) |
4007 if (cantparse == 0) {
4008 if (af == AF_INET) {
4009 sad = (struct sockaddr_in *)sa;
4010 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4011 sad->sin_len = sizeof(*sad);
4012 sad->sin_family = AF_INET;
4013 sad->sin_port = htons(portv);
4017 sad6 = (struct sockaddr_in6 *)sa;
4018 if (inet_pton(af, addr, &sad6->sin6_addr)
4020 sad6->sin6_len = sizeof(*sad6);
4021 sad6->sin6_family = AF_INET6;
4022 sad6->sin6_port = htons(portv);
4029 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4040 * Handle an NFSv4.1 Sequence request for the session.
4041 * If reply != NULL, use it to return the cached reply, as required.
4042 * The client gets a cached reply via this call for callbacks, however the
4043 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4046 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4047 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4054 if (slotid > maxslot)
4055 return (NFSERR_BADSLOT);
4056 if (seqid == slots[slotid].nfssl_seq) {
4058 if (slots[slotid].nfssl_inprog != 0)
4059 error = NFSERR_DELAY;
4060 else if (slots[slotid].nfssl_reply != NULL) {
4061 if (reply != NULL) {
4062 *reply = slots[slotid].nfssl_reply;
4063 slots[slotid].nfssl_reply = NULL;
4065 slots[slotid].nfssl_inprog = 1;
4066 error = NFSERR_REPLYFROMCACHE;
4068 /* No reply cached, so just do it. */
4069 slots[slotid].nfssl_inprog = 1;
4070 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4071 if (slots[slotid].nfssl_reply != NULL)
4072 m_freem(slots[slotid].nfssl_reply);
4073 slots[slotid].nfssl_reply = NULL;
4074 slots[slotid].nfssl_inprog = 1;
4075 slots[slotid].nfssl_seq++;
4077 error = NFSERR_SEQMISORDERED;
4082 * Cache this reply for the slot.
4083 * Use the "rep" argument to return the cached reply if repstat is set to
4084 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4087 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4091 if (repstat == NFSERR_REPLYFROMCACHE) {
4092 *rep = slots[slotid].nfssl_reply;
4093 slots[slotid].nfssl_reply = NULL;
4095 if (slots[slotid].nfssl_reply != NULL)
4096 m_freem(slots[slotid].nfssl_reply);
4097 slots[slotid].nfssl_reply = *rep;
4099 slots[slotid].nfssl_inprog = 0;
4103 * Generate the xdr for an NFSv4.1 Sequence Operation.
4106 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4107 struct nfsclsession *sep, int dont_replycache)
4109 uint32_t *tl, slotseq = 0;
4110 int error, maxslot, slotpos;
4111 uint8_t sessionid[NFSX_V4SESSIONID];
4113 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4117 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
4119 /* Build the Sequence arguments. */
4120 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4121 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4122 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4123 nd->nd_slotseq = tl;
4124 *tl++ = txdr_unsigned(slotseq);
4125 *tl++ = txdr_unsigned(slotpos);
4126 *tl++ = txdr_unsigned(maxslot);
4127 if (dont_replycache == 0)
4131 nd->nd_flag |= ND_HASSEQUENCE;
4135 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4136 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4138 int i, maxslot, slotpos;
4141 /* Find an unused slot. */
4144 mtx_lock(&sep->nfsess_mtx);
4147 for (i = 0; i < sep->nfsess_foreslots; i++) {
4148 if ((bitval & sep->nfsess_slots) == 0) {
4150 sep->nfsess_slots |= bitval;
4151 sep->nfsess_slotseq[i]++;
4152 *slotseqp = sep->nfsess_slotseq[i];
4157 if (slotpos == -1) {
4159 * If a forced dismount is in progress, just return.
4160 * This RPC attempt will fail when it calls
4164 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4166 mtx_unlock(&sep->nfsess_mtx);
4169 /* Wake up once/sec, to check for a forced dismount. */
4170 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4171 PZERO, "nfsclseq", hz);
4173 } while (slotpos == -1);
4174 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4176 for (i = 0; i < 64; i++) {
4177 if ((bitval & sep->nfsess_slots) != 0)
4181 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4182 mtx_unlock(&sep->nfsess_mtx);
4183 *slotposp = slotpos;
4184 *maxslotp = maxslot;
4189 * Free a session slot.
4192 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4199 mtx_lock(&sep->nfsess_mtx);
4200 if ((bitval & sep->nfsess_slots) == 0)
4201 printf("freeing free slot!!\n");
4202 sep->nfsess_slots &= ~bitval;
4203 wakeup(&sep->nfsess_slots);
4204 mtx_unlock(&sep->nfsess_mtx);