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_flag & NFSID_INITIALIZE) {
3178 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3179 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3182 free(cp, M_NFSSTRING);
3185 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3187 * Free up all the old stuff and reinitialize hash
3188 * lists. All mutexes for both lists must be locked,
3189 * with the user/group name ones before the uid/gid
3190 * ones, to avoid a LOR.
3192 for (i = 0; i < nfsrv_lughashsize; i++)
3193 mtx_lock(&nfsusernamehash[i].mtx);
3194 for (i = 0; i < nfsrv_lughashsize; i++)
3195 mtx_lock(&nfsuserhash[i].mtx);
3196 for (i = 0; i < nfsrv_lughashsize; i++)
3197 TAILQ_FOREACH_SAFE(usrp,
3198 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3199 nfsrv_removeuser(usrp, 1);
3200 for (i = 0; i < nfsrv_lughashsize; i++)
3201 mtx_unlock(&nfsuserhash[i].mtx);
3202 for (i = 0; i < nfsrv_lughashsize; i++)
3203 mtx_unlock(&nfsusernamehash[i].mtx);
3204 for (i = 0; i < nfsrv_lughashsize; i++)
3205 mtx_lock(&nfsgroupnamehash[i].mtx);
3206 for (i = 0; i < nfsrv_lughashsize; i++)
3207 mtx_lock(&nfsgrouphash[i].mtx);
3208 for (i = 0; i < nfsrv_lughashsize; i++)
3209 TAILQ_FOREACH_SAFE(usrp,
3210 &nfsgrouphash[i].lughead, lug_numhash,
3212 nfsrv_removeuser(usrp, 0);
3213 for (i = 0; i < nfsrv_lughashsize; i++)
3214 mtx_unlock(&nfsgrouphash[i].mtx);
3215 for (i = 0; i < nfsrv_lughashsize; i++)
3216 mtx_unlock(&nfsgroupnamehash[i].mtx);
3217 free(nfsrv_dnsname, M_NFSSTRING);
3218 nfsrv_dnsname = NULL;
3220 if (nfsuserhash == NULL) {
3221 /* Allocate the hash tables. */
3222 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3223 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3225 for (i = 0; i < nfsrv_lughashsize; i++)
3226 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3227 NULL, MTX_DEF | MTX_DUPOK);
3228 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3229 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 mtx_init(&nfsusernamehash[i].mtx,
3233 "nfsusrhash", NULL, MTX_DEF |
3235 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3236 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3238 for (i = 0; i < nfsrv_lughashsize; i++)
3239 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3240 NULL, MTX_DEF | MTX_DUPOK);
3241 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3242 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3244 for (i = 0; i < nfsrv_lughashsize; i++)
3245 mtx_init(&nfsgroupnamehash[i].mtx,
3246 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3248 /* (Re)initialize the list heads. */
3249 for (i = 0; i < nfsrv_lughashsize; i++)
3250 TAILQ_INIT(&nfsuserhash[i].lughead);
3251 for (i = 0; i < nfsrv_lughashsize; i++)
3252 TAILQ_INIT(&nfsusernamehash[i].lughead);
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 TAILQ_INIT(&nfsgrouphash[i].lughead);
3255 for (i = 0; i < nfsrv_lughashsize; i++)
3256 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3259 * Put name in "DNS" string.
3262 nfsrv_defaultuid = nidp->nid_uid;
3263 nfsrv_defaultgid = nidp->nid_gid;
3265 nfsrv_usermax = nidp->nid_usermax;
3266 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3271 * malloc the new one now, so any potential sleep occurs before
3272 * manipulation of the lists.
3274 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3275 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3276 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3278 if (error == 0 && nidp->nid_ngroup > 0 &&
3279 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3280 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3282 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3283 sizeof(gid_t) * nidp->nid_ngroup);
3286 * Create a credential just like svc_getcred(),
3287 * but using the group list provided.
3290 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3291 crsetgroups(cr, nidp->nid_ngroup, grps);
3292 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3293 cr->cr_prison = &prison0;
3294 prison_hold(cr->cr_prison);
3296 mac_cred_associate_nfsd(cr);
3298 newusrp->lug_cred = cr;
3303 free(newusrp, M_NFSUSERGROUP);
3306 newusrp->lug_namelen = nidp->nid_namelen;
3309 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3310 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3311 * The flags user_locked, username_locked, group_locked and
3312 * groupname_locked are set to indicate all of those hash lists are
3313 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3314 * the respective one mutex is locked.
3316 user_locked = username_locked = group_locked = groupname_locked = 0;
3317 hp_name = hp_idnum = NULL;
3320 * Delete old entries, as required.
3322 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3323 /* Must lock all username hash lists first, to avoid a LOR. */
3324 for (i = 0; i < nfsrv_lughashsize; i++)
3325 mtx_lock(&nfsusernamehash[i].mtx);
3326 username_locked = 1;
3327 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3328 mtx_lock(&hp_idnum->mtx);
3329 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3331 if (usrp->lug_uid == nidp->nid_uid)
3332 nfsrv_removeuser(usrp, 1);
3334 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3335 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3336 newusrp->lug_namelen);
3337 mtx_lock(&hp_name->mtx);
3338 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3340 if (usrp->lug_namelen == newusrp->lug_namelen &&
3341 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3342 usrp->lug_namelen)) {
3343 thp = NFSUSERHASH(usrp->lug_uid);
3344 mtx_lock(&thp->mtx);
3345 nfsrv_removeuser(usrp, 1);
3346 mtx_unlock(&thp->mtx);
3349 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3350 mtx_lock(&hp_idnum->mtx);
3351 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3352 /* Must lock all groupname hash lists first, to avoid a LOR. */
3353 for (i = 0; i < nfsrv_lughashsize; i++)
3354 mtx_lock(&nfsgroupnamehash[i].mtx);
3355 groupname_locked = 1;
3356 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3357 mtx_lock(&hp_idnum->mtx);
3358 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3360 if (usrp->lug_gid == nidp->nid_gid)
3361 nfsrv_removeuser(usrp, 0);
3363 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3364 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3365 newusrp->lug_namelen);
3366 mtx_lock(&hp_name->mtx);
3367 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3369 if (usrp->lug_namelen == newusrp->lug_namelen &&
3370 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3371 usrp->lug_namelen)) {
3372 thp = NFSGROUPHASH(usrp->lug_gid);
3373 mtx_lock(&thp->mtx);
3374 nfsrv_removeuser(usrp, 0);
3375 mtx_unlock(&thp->mtx);
3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3379 mtx_lock(&hp_idnum->mtx);
3383 * Now, we can add the new one.
3385 if (nidp->nid_usertimeout)
3386 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3388 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3389 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3390 newusrp->lug_uid = nidp->nid_uid;
3391 thp = NFSUSERHASH(newusrp->lug_uid);
3392 mtx_assert(&thp->mtx, MA_OWNED);
3393 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3394 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3395 mtx_assert(&thp->mtx, MA_OWNED);
3396 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3397 atomic_add_int(&nfsrv_usercnt, 1);
3398 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3399 newusrp->lug_gid = nidp->nid_gid;
3400 thp = NFSGROUPHASH(newusrp->lug_gid);
3401 mtx_assert(&thp->mtx, MA_OWNED);
3402 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3403 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3404 mtx_assert(&thp->mtx, MA_OWNED);
3405 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3406 atomic_add_int(&nfsrv_usercnt, 1);
3408 if (newusrp->lug_cred != NULL)
3409 crfree(newusrp->lug_cred);
3410 free(newusrp, M_NFSUSERGROUP);
3414 * Once per second, allow one thread to trim the cache.
3416 if (lasttime < NFSD_MONOSEC &&
3417 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3419 * First, unlock the single mutexes, so that all entries
3420 * can be locked and any LOR is avoided.
3422 if (hp_name != NULL) {
3423 mtx_unlock(&hp_name->mtx);
3426 if (hp_idnum != NULL) {
3427 mtx_unlock(&hp_idnum->mtx);
3431 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3432 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3433 if (username_locked == 0) {
3434 for (i = 0; i < nfsrv_lughashsize; i++)
3435 mtx_lock(&nfsusernamehash[i].mtx);
3436 username_locked = 1;
3438 KASSERT(user_locked == 0,
3439 ("nfssvc_idname: user_locked"));
3440 for (i = 0; i < nfsrv_lughashsize; i++)
3441 mtx_lock(&nfsuserhash[i].mtx);
3443 for (i = 0; i < nfsrv_lughashsize; i++) {
3444 TAILQ_FOREACH_SAFE(usrp,
3445 &nfsuserhash[i].lughead, lug_numhash,
3447 if (usrp->lug_expiry < NFSD_MONOSEC)
3448 nfsrv_removeuser(usrp, 1);
3450 for (i = 0; i < nfsrv_lughashsize; i++) {
3452 * Trim the cache using an approximate LRU
3453 * algorithm. This code deletes the least
3454 * recently used entry on each hash list.
3456 if (nfsrv_usercnt <= nfsrv_usermax)
3458 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3460 nfsrv_removeuser(usrp, 1);
3463 if (groupname_locked == 0) {
3464 for (i = 0; i < nfsrv_lughashsize; i++)
3465 mtx_lock(&nfsgroupnamehash[i].mtx);
3466 groupname_locked = 1;
3468 KASSERT(group_locked == 0,
3469 ("nfssvc_idname: group_locked"));
3470 for (i = 0; i < nfsrv_lughashsize; i++)
3471 mtx_lock(&nfsgrouphash[i].mtx);
3473 for (i = 0; i < nfsrv_lughashsize; i++) {
3474 TAILQ_FOREACH_SAFE(usrp,
3475 &nfsgrouphash[i].lughead, lug_numhash,
3477 if (usrp->lug_expiry < NFSD_MONOSEC)
3478 nfsrv_removeuser(usrp, 0);
3480 for (i = 0; i < nfsrv_lughashsize; i++) {
3482 * Trim the cache using an approximate LRU
3483 * algorithm. This code deletes the least
3484 * recently user entry on each hash list.
3486 if (nfsrv_usercnt <= nfsrv_usermax)
3488 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3490 nfsrv_removeuser(usrp, 0);
3493 lasttime = NFSD_MONOSEC;
3494 atomic_store_rel_int(&onethread, 0);
3497 /* Now, unlock all locked mutexes. */
3498 if (hp_idnum != NULL)
3499 mtx_unlock(&hp_idnum->mtx);
3500 if (hp_name != NULL)
3501 mtx_unlock(&hp_name->mtx);
3502 if (user_locked != 0)
3503 for (i = 0; i < nfsrv_lughashsize; i++)
3504 mtx_unlock(&nfsuserhash[i].mtx);
3505 if (username_locked != 0)
3506 for (i = 0; i < nfsrv_lughashsize; i++)
3507 mtx_unlock(&nfsusernamehash[i].mtx);
3508 if (group_locked != 0)
3509 for (i = 0; i < nfsrv_lughashsize; i++)
3510 mtx_unlock(&nfsgrouphash[i].mtx);
3511 if (groupname_locked != 0)
3512 for (i = 0; i < nfsrv_lughashsize; i++)
3513 mtx_unlock(&nfsgroupnamehash[i].mtx);
3520 * Remove a user/group name element.
3523 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3525 struct nfsrv_lughash *hp;
3528 hp = NFSUSERHASH(usrp->lug_uid);
3529 mtx_assert(&hp->mtx, MA_OWNED);
3530 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3531 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3532 mtx_assert(&hp->mtx, MA_OWNED);
3533 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3535 hp = NFSGROUPHASH(usrp->lug_gid);
3536 mtx_assert(&hp->mtx, MA_OWNED);
3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3538 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3539 mtx_assert(&hp->mtx, MA_OWNED);
3540 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3542 atomic_add_int(&nfsrv_usercnt, -1);
3543 if (usrp->lug_cred != NULL)
3544 crfree(usrp->lug_cred);
3545 free(usrp, M_NFSUSERGROUP);
3549 * Free up all the allocations related to the name<-->id cache.
3550 * This function should only be called when the nfsuserd daemon isn't
3551 * running, since it doesn't do any locking.
3552 * This function is meant to be used when the nfscommon module is unloaded.
3555 nfsrv_cleanusergroup(void)
3557 struct nfsrv_lughash *hp, *hp2;
3558 struct nfsusrgrp *nusrp, *usrp;
3561 if (nfsuserhash == NULL)
3564 for (i = 0; i < nfsrv_lughashsize; i++) {
3565 hp = &nfsuserhash[i];
3566 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3567 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3568 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3570 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3571 if (usrp->lug_cred != NULL)
3572 crfree(usrp->lug_cred);
3573 free(usrp, M_NFSUSERGROUP);
3575 hp = &nfsgrouphash[i];
3576 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3577 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3578 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3580 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3581 if (usrp->lug_cred != NULL)
3582 crfree(usrp->lug_cred);
3583 free(usrp, M_NFSUSERGROUP);
3585 mtx_destroy(&nfsuserhash[i].mtx);
3586 mtx_destroy(&nfsusernamehash[i].mtx);
3587 mtx_destroy(&nfsgroupnamehash[i].mtx);
3588 mtx_destroy(&nfsgrouphash[i].mtx);
3590 free(nfsuserhash, M_NFSUSERGROUP);
3591 free(nfsusernamehash, M_NFSUSERGROUP);
3592 free(nfsgrouphash, M_NFSUSERGROUP);
3593 free(nfsgroupnamehash, M_NFSUSERGROUP);
3594 free(nfsrv_dnsname, M_NFSSTRING);
3598 * This function scans a byte string and checks for UTF-8 compliance.
3599 * It returns 0 if it conforms and NFSERR_INVAL if not.
3602 nfsrv_checkutf8(u_int8_t *cp, int len)
3604 u_int32_t val = 0x0;
3605 int cnt = 0, gotd = 0, shift = 0;
3607 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3611 * Here are what the variables are used for:
3612 * val - the calculated value of a multibyte char, used to check
3613 * that it was coded with the correct range
3614 * cnt - the number of 10xxxxxx bytes to follow
3615 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3616 * shift - lower order bits of range (ie. "val >> shift" should
3617 * not be 0, in other words, dividing by the lower bound
3618 * of the range should get a non-zero value)
3619 * byte - used to calculate cnt
3623 /* This handles the 10xxxxxx bytes */
3624 if ((*cp & 0xc0) != 0x80 ||
3625 (gotd && (*cp & 0x20))) {
3626 error = NFSERR_INVAL;
3631 val |= (*cp & 0x3f);
3633 if (cnt == 0 && (val >> shift) == 0x0) {
3634 error = NFSERR_INVAL;
3637 } else if (*cp & 0x80) {
3638 /* first byte of multi byte char */
3640 while ((byte & 0x40) && cnt < 6) {
3644 if (cnt == 0 || cnt == 6) {
3645 error = NFSERR_INVAL;
3648 val = (*cp & (0x3f >> cnt));
3649 shift = utf8_shift[cnt - 1];
3650 if (cnt == 2 && val == 0xd)
3651 /* Check for the 0xd800-0xdfff case */
3658 error = NFSERR_INVAL;
3666 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3667 * strings, one with the root path in it and the other with the list of
3668 * locations. The list is in the same format as is found in nfr_refs.
3669 * It is a "," separated list of entries, where each of them is of the
3670 * form <server>:<rootpath>. For example
3671 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3672 * The nilp argument is set to 1 for the special case of a null fs_root
3673 * and an empty server list.
3674 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3675 * number of xdr bytes parsed in sump.
3678 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3679 int *sump, int *nilp)
3682 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3683 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3685 SLIST_ENTRY(list) next;
3689 SLIST_HEAD(, list) head;
3696 * Get the fs_root path and check for the special case of null path
3697 * and 0 length server list.
3699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3700 len = fxdr_unsigned(int, *tl);
3701 if (len < 0 || len > 10240) {
3702 error = NFSERR_BADXDR;
3706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3708 error = NFSERR_BADXDR;
3712 *sump = 2 * NFSX_UNSIGNED;
3716 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3717 error = nfsrv_mtostr(nd, cp, len);
3719 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3720 cnt = fxdr_unsigned(int, *tl);
3722 error = NFSERR_BADXDR;
3728 * Now, loop through the location list and make up the srvlist.
3730 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3731 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3734 for (i = 0; i < cnt; i++) {
3736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3737 nsrv = fxdr_unsigned(int, *tl);
3739 error = NFSERR_BADXDR;
3744 * Handle the first server by putting it in the srvstr.
3746 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3747 len = fxdr_unsigned(int, *tl);
3748 if (len <= 0 || len > 1024) {
3749 error = NFSERR_BADXDR;
3752 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3757 error = nfsrv_mtostr(nd, cp3, len);
3763 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3764 for (j = 1; j < nsrv; j++) {
3766 * Yuck, put them in an slist and process them later.
3768 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3769 len = fxdr_unsigned(int, *tl);
3770 if (len <= 0 || len > 1024) {
3771 error = NFSERR_BADXDR;
3774 lsp = (struct list *)malloc(sizeof (struct list)
3775 + len, M_TEMP, M_WAITOK);
3776 error = nfsrv_mtostr(nd, lsp->host, len);
3779 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3781 SLIST_INSERT_HEAD(&head, lsp, next);
3785 * Finally, we can get the path.
3787 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3788 len = fxdr_unsigned(int, *tl);
3789 if (len <= 0 || len > 1024) {
3790 error = NFSERR_BADXDR;
3793 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3794 error = nfsrv_mtostr(nd, cp3, len);
3797 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3802 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3803 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3806 NFSBCOPY(lsp->host, cp3, lsp->len);
3809 NFSBCOPY(str, cp3, stringlen);
3812 siz += (lsp->len + stringlen + 2);
3813 free((caddr_t)lsp, M_TEMP);
3819 NFSEXITCODE2(0, nd);
3823 free(cp, M_NFSSTRING);
3825 free(cp2, M_NFSSTRING);
3826 NFSEXITCODE2(error, nd);
3831 * Make the malloc'd space large enough. This is a pain, but the xdr
3832 * doesn't set an upper bound on the side, so...
3835 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3842 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3843 NFSBCOPY(*cpp, cp, *slenp);
3844 free(*cpp, M_NFSSTRING);
3848 *slenp = siz + 1024;
3852 * Initialize the reply header data structures.
3855 nfsrvd_rephead(struct nfsrv_descript *nd)
3860 * If this is a big reply, use a cluster.
3862 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3863 nfs_bigreply[nd->nd_procnum]) {
3864 NFSMCLGET(mreq, M_WAITOK);
3872 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3873 mbuf_setlen(mreq, 0);
3875 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3876 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3880 * Lock a socket against others.
3881 * Currently used to serialize connect/disconnect attempts.
3884 newnfs_sndlock(int *flagp)
3889 while (*flagp & NFSR_SNDLOCK) {
3890 *flagp |= NFSR_WANTSND;
3893 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3894 PZERO - 1, "nfsndlck", &ts);
3896 *flagp |= NFSR_SNDLOCK;
3902 * Unlock the stream socket for others.
3905 newnfs_sndunlock(int *flagp)
3909 if ((*flagp & NFSR_SNDLOCK) == 0)
3910 panic("nfs sndunlock");
3911 *flagp &= ~NFSR_SNDLOCK;
3912 if (*flagp & NFSR_WANTSND) {
3913 *flagp &= ~NFSR_WANTSND;
3914 wakeup((caddr_t)flagp);
3920 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3923 struct sockaddr_in *sad;
3924 struct sockaddr_in6 *sad6;
3925 struct in_addr saddr;
3926 uint32_t portnum, *tl;
3927 int af = 0, i, j, k;
3928 char addr[64], protocol[5], *cp;
3929 int cantparse = 0, error = 0;
3932 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3933 i = fxdr_unsigned(int, *tl);
3934 if (i >= 3 && i <= 4) {
3935 error = nfsrv_mtostr(nd, protocol, i);
3938 if (strcmp(protocol, "tcp") == 0) {
3941 } else if (strcmp(protocol, "udp") == 0) {
3944 } else if (strcmp(protocol, "tcp6") == 0) {
3947 } else if (strcmp(protocol, "udp6") == 0) {
3955 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3960 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3961 i = fxdr_unsigned(int, *tl);
3963 error = NFSERR_BADXDR;
3965 } else if (cantparse == 0 && i >= 11 && i < 64) {
3967 * The shortest address is 11chars and the longest is < 64.
3969 error = nfsrv_mtostr(nd, addr, i);
3973 /* Find the port# at the end and extract that. */
3977 /* Count back two '.'s from end to get port# field. */
3978 for (j = 0; j < i; j++) {
3988 * The NFSv4 port# is appended as .N.N, where N is
3989 * a decimal # in the range 0-255, just like an inet4
3990 * address. Cheat and use inet_aton(), which will
3991 * return a Class A address and then shift the high
3992 * order 8bits over to convert it to the port#.
3995 if (inet_aton(cp, &saddr) == 1) {
3996 portnum = ntohl(saddr.s_addr);
3997 portv = (uint16_t)((portnum >> 16) |
4003 if (cantparse == 0) {
4004 if (af == AF_INET) {
4005 sad = (struct sockaddr_in *)sa;
4006 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4007 sad->sin_len = sizeof(*sad);
4008 sad->sin_family = AF_INET;
4009 sad->sin_port = htons(portv);
4013 sad6 = (struct sockaddr_in6 *)sa;
4014 if (inet_pton(af, addr, &sad6->sin6_addr)
4016 sad6->sin6_len = sizeof(*sad6);
4017 sad6->sin6_family = AF_INET6;
4018 sad6->sin6_port = htons(portv);
4025 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4036 * Handle an NFSv4.1 Sequence request for the session.
4037 * If reply != NULL, use it to return the cached reply, as required.
4038 * The client gets a cached reply via this call for callbacks, however the
4039 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4042 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4043 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4050 if (slotid > maxslot)
4051 return (NFSERR_BADSLOT);
4052 if (seqid == slots[slotid].nfssl_seq) {
4054 if (slots[slotid].nfssl_inprog != 0)
4055 error = NFSERR_DELAY;
4056 else if (slots[slotid].nfssl_reply != NULL) {
4057 if (reply != NULL) {
4058 *reply = slots[slotid].nfssl_reply;
4059 slots[slotid].nfssl_reply = NULL;
4061 slots[slotid].nfssl_inprog = 1;
4062 error = NFSERR_REPLYFROMCACHE;
4064 /* No reply cached, so just do it. */
4065 slots[slotid].nfssl_inprog = 1;
4066 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4067 if (slots[slotid].nfssl_reply != NULL)
4068 m_freem(slots[slotid].nfssl_reply);
4069 slots[slotid].nfssl_reply = NULL;
4070 slots[slotid].nfssl_inprog = 1;
4071 slots[slotid].nfssl_seq++;
4073 error = NFSERR_SEQMISORDERED;
4078 * Cache this reply for the slot.
4079 * Use the "rep" argument to return the cached reply if repstat is set to
4080 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4083 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4087 if (repstat == NFSERR_REPLYFROMCACHE) {
4088 *rep = slots[slotid].nfssl_reply;
4089 slots[slotid].nfssl_reply = NULL;
4091 if (slots[slotid].nfssl_reply != NULL)
4092 m_freem(slots[slotid].nfssl_reply);
4093 slots[slotid].nfssl_reply = *rep;
4095 slots[slotid].nfssl_inprog = 0;
4099 * Generate the xdr for an NFSv4.1 Sequence Operation.
4102 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4103 struct nfsclsession *sep, int dont_replycache)
4105 uint32_t *tl, slotseq = 0;
4106 int error, maxslot, slotpos;
4107 uint8_t sessionid[NFSX_V4SESSIONID];
4109 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4113 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
4115 /* Build the Sequence arguments. */
4116 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4117 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4118 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4119 nd->nd_slotseq = tl;
4120 *tl++ = txdr_unsigned(slotseq);
4121 *tl++ = txdr_unsigned(slotpos);
4122 *tl++ = txdr_unsigned(maxslot);
4123 if (dont_replycache == 0)
4127 nd->nd_flag |= ND_HASSEQUENCE;
4131 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4132 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4134 int i, maxslot, slotpos;
4137 /* Find an unused slot. */
4140 mtx_lock(&sep->nfsess_mtx);
4143 for (i = 0; i < sep->nfsess_foreslots; i++) {
4144 if ((bitval & sep->nfsess_slots) == 0) {
4146 sep->nfsess_slots |= bitval;
4147 sep->nfsess_slotseq[i]++;
4148 *slotseqp = sep->nfsess_slotseq[i];
4153 if (slotpos == -1) {
4155 * If a forced dismount is in progress, just return.
4156 * This RPC attempt will fail when it calls
4160 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4162 mtx_unlock(&sep->nfsess_mtx);
4165 /* Wake up once/sec, to check for a forced dismount. */
4166 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4167 PZERO, "nfsclseq", hz);
4169 } while (slotpos == -1);
4170 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4172 for (i = 0; i < 64; i++) {
4173 if ((bitval & sep->nfsess_slots) != 0)
4177 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4178 mtx_unlock(&sep->nfsess_mtx);
4179 *slotposp = slotpos;
4180 *maxslotp = maxslot;
4185 * Free a session slot.
4188 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4195 mtx_lock(&sep->nfsess_mtx);
4196 if ((bitval & sep->nfsess_slots) == 0)
4197 printf("freeing free slot!!\n");
4198 sep->nfsess_slots &= ~bitval;
4199 wakeup(&sep->nfsess_slots);
4200 mtx_unlock(&sep->nfsess_mtx);