2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid;
67 gid_t nfsrv_defaultgid;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 int nfsd_enable_stringtouid = 0;
73 extern int nfsrv_lughashsize;
76 * This array of structures indicates, for V4:
77 * retfh - which of 3 types of calling args are used
78 * 0 - doesn't change cfh or use a sfh
79 * 1 - replaces cfh with a new one (unless it returns an error status)
80 * 2 - uses cfh and sfh
81 * needscfh - if the op wants a cfh and premtime
82 * 0 - doesn't use a cfh
83 * 1 - uses a cfh, but doesn't want pre-op attributes
84 * 2 - uses a cfh and wants pre-op attributes
85 * savereply - indicates a non-idempotent Op
86 * 0 - not non-idempotent
88 * Ops that are ordered via seqid# are handled separately from these
90 * Define it here, since it is used by both the client and server.
92 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
93 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
94 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
95 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
96 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
98 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
99 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
102 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
104 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
108 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
109 { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
111 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
112 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
116 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
117 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
118 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
119 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
120 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
121 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
131 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
153 #endif /* !APPLEKEXT */
155 static int ncl_mbuf_mhlen = MHLEN;
156 static int nfsrv_usercnt = 0;
157 static int nfsrv_dnsnamelen;
158 static u_char *nfsrv_dnsname = NULL;
159 static int nfsrv_usermax = 999999999;
160 struct nfsrv_lughash {
162 struct nfsuserhashhead lughead;
164 static struct nfsrv_lughash *nfsuserhash;
165 static struct nfsrv_lughash *nfsusernamehash;
166 static struct nfsrv_lughash *nfsgrouphash;
167 static struct nfsrv_lughash *nfsgroupnamehash;
170 * This static array indicates whether or not the RPC generates a large
171 * reply. This is used by nfs_reply() to decide whether or not an mbuf
172 * cluster should be allocated. (If a cluster is required by an RPC
173 * marked 0 in this array, the code will still work, just not quite as
176 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
180 /* local functions */
181 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
182 static void nfsv4_wanted(struct nfsv4lock *lp);
183 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
184 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
186 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
187 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
189 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
194 * copies mbuf chain to the uio scatter/gather list
197 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
199 char *mbufcp, *uiocp;
206 mbufcp = nd->nd_dpos;
207 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
208 rem = NFSM_RNDUP(siz) - siz;
210 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
214 left = uiop->uio_iov->iov_len;
215 uiocp = uiop->uio_iov->iov_base;
226 mbufcp = NFSMTOD(mp, caddr_t);
229 ("len %d, corrupted mbuf?", len));
231 xfer = (left > len) ? len : left;
234 if (uiop->uio_iov->iov_op != NULL)
235 (*(uiop->uio_iov->iov_op))
236 (mbufcp, uiocp, xfer);
239 if (uiop->uio_segflg == UIO_SYSSPACE)
240 NFSBCOPY(mbufcp, uiocp, xfer);
242 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
247 uiop->uio_offset += xfer;
248 uiop->uio_resid -= xfer;
250 if (uiop->uio_iov->iov_len <= siz) {
254 uiop->uio_iov->iov_base = (void *)
255 ((char *)uiop->uio_iov->iov_base + uiosiz);
256 uiop->uio_iov->iov_len -= uiosiz;
260 nd->nd_dpos = mbufcp;
264 error = nfsm_advance(nd, rem, len);
270 NFSEXITCODE2(error, nd);
276 * Help break down an mbuf chain by setting the first siz bytes contiguous
277 * pointed to by returned val.
278 * This is used by the macro NFSM_DISSECT for tough
282 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
291 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
293 nd->nd_md = mbuf_next(nd->nd_md);
294 if (nd->nd_md == NULL)
296 left = mbuf_len(nd->nd_md);
297 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
302 } else if (mbuf_next(nd->nd_md) == NULL) {
304 } else if (siz > ncl_mbuf_mhlen) {
305 panic("nfs S too big");
307 MGET(mp2, MT_DATA, how);
310 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
311 mbuf_setnext(nd->nd_md, mp2);
312 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
314 retp = p = NFSMTOD(mp2, caddr_t);
315 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
318 mp2 = mbuf_next(mp2);
319 /* Loop around copying up the siz2 bytes */
323 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
325 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
326 NFSM_DATAP(mp2, xfer);
327 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
332 mp2 = mbuf_next(mp2);
334 mbuf_setlen(nd->nd_md, siz);
336 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
342 * Advance the position in the mbuf chain.
343 * If offs == 0, this is a no-op, but it is simpler to just return from
344 * here than check for offs > 0 for all calls to nfsm_advance.
345 * If left == -1, it should be calculated here.
348 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
355 * A negative offs should be considered a serious problem.
358 panic("nfsrv_advance");
361 * If left == -1, calculate it here.
364 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
368 * Loop around, advancing over the mbuf data.
370 while (offs > left) {
372 nd->nd_md = mbuf_next(nd->nd_md);
373 if (nd->nd_md == NULL) {
377 left = mbuf_len(nd->nd_md);
378 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
388 * Copy a string into mbuf(s).
389 * Return the number of bytes output, including XDR overheads.
392 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
402 *tl = txdr_unsigned(siz);
403 rem = NFSM_RNDUP(siz) - siz;
404 bytesize = NFSX_UNSIGNED + siz + rem;
407 left = M_TRAILINGSPACE(m2);
410 * Loop around copying the string to mbuf(s).
414 if (siz > ncl_mbuf_mlen)
415 NFSMCLGET(m1, M_WAITOK);
419 mbuf_setnext(m2, m1);
421 cp2 = NFSMTOD(m2, caddr_t);
422 left = M_TRAILINGSPACE(m2);
428 NFSBCOPY(cp, cp2, xfer);
430 mbuf_setlen(m2, mbuf_len(m2) + xfer);
433 if (siz == 0 && rem) {
435 panic("nfsm_strtom");
436 NFSBZERO(cp2 + xfer, rem);
437 mbuf_setlen(m2, mbuf_len(m2) + rem);
441 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
446 * Called once to initialize data structures...
451 static int nfs_inited = 0;
457 newnfs_true = txdr_unsigned(TRUE);
458 newnfs_false = txdr_unsigned(FALSE);
459 newnfs_xdrneg1 = txdr_unsigned(-1);
460 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
463 NFSSETBOOTTIME(nfsboottime);
466 * Initialize reply list and start timer
468 TAILQ_INIT(&nfsd_reqq);
473 * Put a file handle in an mbuf list.
474 * If the size argument == 0, just use the default size.
475 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
476 * Return the number of bytes output, including XDR overhead.
479 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
483 int fullsiz, rem, bytesize = 0;
487 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
489 if (size > NFSX_V2FH)
490 panic("fh size > NFSX_V2FH for NFSv2");
491 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
492 NFSBCOPY(fhp, cp, size);
493 if (size < NFSX_V2FH)
494 NFSBZERO(cp + size, NFSX_V2FH - size);
495 bytesize = NFSX_V2FH;
499 fullsiz = NFSM_RNDUP(size);
500 rem = fullsiz - size;
502 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
503 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
506 bytesize = NFSX_UNSIGNED + fullsiz;
508 (void) nfsm_strtom(nd, fhp, size);
515 * This function compares two net addresses by family and returns TRUE
516 * if they are the same host.
517 * If there is any doubt, return FALSE.
518 * The AF_INET family is handled as a special case so that address mbufs
519 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
522 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
524 struct sockaddr_in *inetaddr;
528 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
529 if (inetaddr->sin_family == AF_INET &&
530 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
536 struct sockaddr_in6 *inetaddr6;
538 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
539 /* XXX - should test sin6_scope_id ? */
540 if (inetaddr6->sin6_family == AF_INET6 &&
541 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
552 * Similar to the above, but takes to NFSSOCKADDR_T args.
555 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
557 struct sockaddr_in *addr1, *addr2;
558 struct sockaddr *inaddr;
560 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
561 switch (inaddr->sa_family) {
563 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
564 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
565 if (addr2->sin_family == AF_INET &&
566 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
572 struct sockaddr_in6 *inet6addr1, *inet6addr2;
574 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
575 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
576 /* XXX - should test sin6_scope_id ? */
577 if (inet6addr2->sin6_family == AF_INET6 &&
578 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
579 &inet6addr2->sin6_addr))
590 * Trim the stuff already dissected off the mbuf list.
593 newnfs_trimleading(nd)
594 struct nfsrv_descript *nd;
600 * First, free up leading mbufs.
602 if (nd->nd_mrep != nd->nd_md) {
604 while (mbuf_next(m) != nd->nd_md) {
605 if (mbuf_next(m) == NULL)
606 panic("nfsm trim leading");
609 mbuf_setnext(m, NULL);
610 mbuf_freem(nd->nd_mrep);
615 * Now, adjust this mbuf, based on nd_dpos.
617 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
618 if (offs == mbuf_len(m)) {
622 panic("nfsm trim leading2");
623 mbuf_setnext(n, NULL);
625 } else if (offs > 0) {
626 mbuf_setlen(m, mbuf_len(m) - offs);
629 panic("nfsm trimleading offs");
632 nd->nd_dpos = NFSMTOD(m, caddr_t);
636 * Trim trailing data off the mbuf list being built.
639 newnfs_trimtrailing(nd, mb, bpos)
640 struct nfsrv_descript *nd;
646 mbuf_freem(mbuf_next(mb));
647 mbuf_setnext(mb, NULL);
649 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
655 * Dissect a file handle on the client.
658 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
665 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
667 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
674 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
676 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
678 FREE((caddr_t)nfhp, M_NFSFH);
684 NFSEXITCODE2(error, nd);
689 * Break down the nfsv4 acl.
690 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
693 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
694 int *aclsizep, __unused NFSPROC_T *p)
698 int acecnt, error = 0, aceerr = 0, acesize;
704 * Parse out the ace entries and expect them to conform to
705 * what can be supported by R/W/X bits.
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
708 aclsize = NFSX_UNSIGNED;
709 acecnt = fxdr_unsigned(int, *tl);
710 if (acecnt > ACL_MAX_ENTRIES)
711 aceerr = NFSERR_ATTRNOTSUPP;
712 if (nfsrv_useacl == 0)
713 aceerr = NFSERR_ATTRNOTSUPP;
714 for (i = 0; i < acecnt; i++) {
716 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
717 &aceerr, &acesize, p);
719 error = nfsrv_skipace(nd, &acesize);
725 aclp->acl_cnt = acecnt;
731 NFSEXITCODE2(error, nd);
736 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
739 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
745 len = fxdr_unsigned(int, *(tl + 3));
746 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
748 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
749 NFSEXITCODE2(error, nd);
754 * Get attribute bits from an mbuf list.
755 * Returns EBADRPC for a parsing error, 0 otherwise.
756 * If the clearinvalid flag is set, clear the bits not supported.
759 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
767 cnt = fxdr_unsigned(int, *tl);
769 error = NFSERR_BADXDR;
772 if (cnt > NFSATTRBIT_MAXWORDS)
773 outcnt = NFSATTRBIT_MAXWORDS;
776 NFSZERO_ATTRBIT(attrbitp);
778 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
779 for (i = 0; i < outcnt; i++)
780 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
782 for (i = 0; i < (cnt - outcnt); i++) {
783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
784 if (retnotsupp != NULL && *tl != 0)
785 *retnotsupp = NFSERR_ATTRNOTSUPP;
788 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
790 NFSEXITCODE2(error, nd);
795 * Get the attributes for V4.
796 * If the compare flag is true, test for any attribute changes,
797 * otherwise return the attribute values.
798 * These attributes cover fields in "struct vattr", "struct statfs",
799 * "struct nfsfsinfo", the file handle and the lease duration.
800 * The value of retcmpp is set to 1 if all attributes are the same,
802 * Returns EBADRPC if it can't be parsed, 0 otherwise.
805 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
806 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
807 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
808 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
809 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
812 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
813 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
814 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
815 nfsattrbit_t attrbits, retattrbits, checkattrbits;
817 struct nfsreferral *refp;
820 struct timespec temptime;
824 u_int32_t freenum = 0, tuint;
825 u_int64_t uquad = 0, thyp, thyp2;
830 static struct timeval last64fileid;
831 static size_t count64fileid;
832 static struct timeval last64mountfileid;
833 static size_t count64mountfileid;
834 static struct timeval warninterval = { 60, 0 };
838 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
840 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
846 *retcmpp = retnotsup;
849 * Just set default values to some of the important ones.
854 nap->na_rdev = (NFSDEV_T)0;
855 nap->na_mtime.tv_sec = 0;
856 nap->na_mtime.tv_nsec = 0;
859 nap->na_blocksize = NFS_FABLKSIZE;
862 sbp->f_bsize = NFS_FABLKSIZE;
870 fsp->fs_rtmax = 8192;
871 fsp->fs_rtpref = 8192;
872 fsp->fs_maxname = NFS_MAXNAMLEN;
873 fsp->fs_wtmax = 8192;
874 fsp->fs_wtpref = 8192;
875 fsp->fs_wtmult = NFS_FABLKSIZE;
876 fsp->fs_dtpref = 8192;
877 fsp->fs_maxfilesize = 0xffffffffffffffffull;
878 fsp->fs_timedelta.tv_sec = 0;
879 fsp->fs_timedelta.tv_nsec = 1;
880 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
881 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
884 pc->pc_linkmax = LINK_MAX;
885 pc->pc_namemax = NAME_MAX;
887 pc->pc_chownrestricted = 0;
888 pc->pc_caseinsensitive = 0;
889 pc->pc_casepreserving = 1;
894 * Loop around getting the attributes.
896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
897 attrsize = fxdr_unsigned(int, *tl);
898 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
899 if (attrsum > attrsize) {
900 error = NFSERR_BADXDR;
903 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
905 case NFSATTRBIT_SUPPORTEDATTRS:
907 if (compare || nap == NULL)
908 error = nfsrv_getattrbits(nd, &retattrbits,
911 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
915 if (compare && !(*retcmpp)) {
916 NFSSETSUPP_ATTRBIT(&checkattrbits);
918 /* Some filesystem do not support NFSv4ACL */
919 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
920 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
921 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
923 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
925 *retcmpp = NFSERR_NOTSAME;
929 case NFSATTRBIT_TYPE:
930 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
933 if (nap->na_type != nfsv34tov_type(*tl))
934 *retcmpp = NFSERR_NOTSAME;
936 } else if (nap != NULL) {
937 nap->na_type = nfsv34tov_type(*tl);
939 attrsum += NFSX_UNSIGNED;
941 case NFSATTRBIT_FHEXPIRETYPE:
942 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
943 if (compare && !(*retcmpp)) {
944 if (fxdr_unsigned(int, *tl) !=
945 NFSV4FHTYPE_PERSISTENT)
946 *retcmpp = NFSERR_NOTSAME;
948 attrsum += NFSX_UNSIGNED;
950 case NFSATTRBIT_CHANGE:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
954 if (nap->na_filerev != fxdr_hyper(tl))
955 *retcmpp = NFSERR_NOTSAME;
957 } else if (nap != NULL) {
958 nap->na_filerev = fxdr_hyper(tl);
960 attrsum += NFSX_HYPER;
962 case NFSATTRBIT_SIZE:
963 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
966 if (nap->na_size != fxdr_hyper(tl))
967 *retcmpp = NFSERR_NOTSAME;
969 } else if (nap != NULL) {
970 nap->na_size = fxdr_hyper(tl);
972 attrsum += NFSX_HYPER;
974 case NFSATTRBIT_LINKSUPPORT:
975 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
978 if (fsp->fs_properties & NFSV3_FSFLINK) {
979 if (*tl == newnfs_false)
980 *retcmpp = NFSERR_NOTSAME;
982 if (*tl == newnfs_true)
983 *retcmpp = NFSERR_NOTSAME;
986 } else if (fsp != NULL) {
987 if (*tl == newnfs_true)
988 fsp->fs_properties |= NFSV3_FSFLINK;
990 fsp->fs_properties &= ~NFSV3_FSFLINK;
992 attrsum += NFSX_UNSIGNED;
994 case NFSATTRBIT_SYMLINKSUPPORT:
995 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
998 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
999 if (*tl == newnfs_false)
1000 *retcmpp = NFSERR_NOTSAME;
1002 if (*tl == newnfs_true)
1003 *retcmpp = NFSERR_NOTSAME;
1006 } else if (fsp != NULL) {
1007 if (*tl == newnfs_true)
1008 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1010 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1012 attrsum += NFSX_UNSIGNED;
1014 case NFSATTRBIT_NAMEDATTR:
1015 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1016 if (compare && !(*retcmpp)) {
1017 if (*tl != newnfs_false)
1018 *retcmpp = NFSERR_NOTSAME;
1020 attrsum += NFSX_UNSIGNED;
1022 case NFSATTRBIT_FSID:
1023 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1024 thyp = fxdr_hyper(tl);
1026 thyp2 = fxdr_hyper(tl);
1028 if (*retcmpp == 0) {
1029 if (thyp != (u_int64_t)
1030 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1031 thyp2 != (u_int64_t)
1032 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1033 *retcmpp = NFSERR_NOTSAME;
1035 } else if (nap != NULL) {
1036 nap->na_filesid[0] = thyp;
1037 nap->na_filesid[1] = thyp2;
1039 attrsum += (4 * NFSX_UNSIGNED);
1041 case NFSATTRBIT_UNIQUEHANDLES:
1042 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1043 if (compare && !(*retcmpp)) {
1044 if (*tl != newnfs_true)
1045 *retcmpp = NFSERR_NOTSAME;
1047 attrsum += NFSX_UNSIGNED;
1049 case NFSATTRBIT_LEASETIME:
1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1052 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1054 *retcmpp = NFSERR_NOTSAME;
1055 } else if (leasep != NULL) {
1056 *leasep = fxdr_unsigned(u_int32_t, *tl);
1058 attrsum += NFSX_UNSIGNED;
1060 case NFSATTRBIT_RDATTRERROR:
1061 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1064 *retcmpp = NFSERR_INVAL;
1065 } else if (rderrp != NULL) {
1066 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1068 attrsum += NFSX_UNSIGNED;
1070 case NFSATTRBIT_ACL:
1073 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1076 naclp = acl_alloc(M_WAITOK);
1077 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1083 if (aceerr || aclp == NULL ||
1084 nfsrv_compareacl(aclp, naclp))
1085 *retcmpp = NFSERR_NOTSAME;
1088 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1090 *retcmpp = NFSERR_ATTRNOTSUPP;
1094 if (vp != NULL && aclp != NULL)
1095 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1098 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1106 case NFSATTRBIT_ACLSUPPORT:
1107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1108 if (compare && !(*retcmpp)) {
1109 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1110 if (fxdr_unsigned(u_int32_t, *tl) !=
1112 *retcmpp = NFSERR_NOTSAME;
1114 *retcmpp = NFSERR_ATTRNOTSUPP;
1117 attrsum += NFSX_UNSIGNED;
1119 case NFSATTRBIT_ARCHIVE:
1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1121 if (compare && !(*retcmpp))
1122 *retcmpp = NFSERR_ATTRNOTSUPP;
1123 attrsum += NFSX_UNSIGNED;
1125 case NFSATTRBIT_CANSETTIME:
1126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1130 if (*tl == newnfs_false)
1131 *retcmpp = NFSERR_NOTSAME;
1133 if (*tl == newnfs_true)
1134 *retcmpp = NFSERR_NOTSAME;
1137 } else if (fsp != NULL) {
1138 if (*tl == newnfs_true)
1139 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1141 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1143 attrsum += NFSX_UNSIGNED;
1145 case NFSATTRBIT_CASEINSENSITIVE:
1146 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1149 if (*tl != newnfs_false)
1150 *retcmpp = NFSERR_NOTSAME;
1152 } else if (pc != NULL) {
1153 pc->pc_caseinsensitive =
1154 fxdr_unsigned(u_int32_t, *tl);
1156 attrsum += NFSX_UNSIGNED;
1158 case NFSATTRBIT_CASEPRESERVING:
1159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1162 if (*tl != newnfs_true)
1163 *retcmpp = NFSERR_NOTSAME;
1165 } else if (pc != NULL) {
1166 pc->pc_casepreserving =
1167 fxdr_unsigned(u_int32_t, *tl);
1169 attrsum += NFSX_UNSIGNED;
1171 case NFSATTRBIT_CHOWNRESTRICTED:
1172 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1175 if (*tl != newnfs_true)
1176 *retcmpp = NFSERR_NOTSAME;
1178 } else if (pc != NULL) {
1179 pc->pc_chownrestricted =
1180 fxdr_unsigned(u_int32_t, *tl);
1182 attrsum += NFSX_UNSIGNED;
1184 case NFSATTRBIT_FILEHANDLE:
1185 error = nfsm_getfh(nd, &tnfhp);
1188 tfhsize = tnfhp->nfh_len;
1191 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1193 *retcmpp = NFSERR_NOTSAME;
1194 FREE((caddr_t)tnfhp, M_NFSFH);
1195 } else if (nfhpp != NULL) {
1198 FREE((caddr_t)tnfhp, M_NFSFH);
1200 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1202 case NFSATTRBIT_FILEID:
1203 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1204 thyp = fxdr_hyper(tl);
1207 if ((u_int64_t)nap->na_fileid != thyp)
1208 *retcmpp = NFSERR_NOTSAME;
1210 } else if (nap != NULL) {
1213 if (ratecheck(&last64fileid, &warninterval)) {
1214 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1219 nap->na_fileid = thyp;
1221 attrsum += NFSX_HYPER;
1223 case NFSATTRBIT_FILESAVAIL:
1224 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1227 sfp->sf_afiles != fxdr_hyper(tl))
1228 *retcmpp = NFSERR_NOTSAME;
1229 } else if (sfp != NULL) {
1230 sfp->sf_afiles = fxdr_hyper(tl);
1232 attrsum += NFSX_HYPER;
1234 case NFSATTRBIT_FILESFREE:
1235 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1238 sfp->sf_ffiles != fxdr_hyper(tl))
1239 *retcmpp = NFSERR_NOTSAME;
1240 } else if (sfp != NULL) {
1241 sfp->sf_ffiles = fxdr_hyper(tl);
1243 attrsum += NFSX_HYPER;
1245 case NFSATTRBIT_FILESTOTAL:
1246 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1249 sfp->sf_tfiles != fxdr_hyper(tl))
1250 *retcmpp = NFSERR_NOTSAME;
1251 } else if (sfp != NULL) {
1252 sfp->sf_tfiles = fxdr_hyper(tl);
1254 attrsum += NFSX_HYPER;
1256 case NFSATTRBIT_FSLOCATIONS:
1257 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1261 if (compare && !(*retcmpp)) {
1262 refp = nfsv4root_getreferral(vp, NULL, 0);
1264 if (cp == NULL || cp2 == NULL ||
1266 strcmp(cp2, refp->nfr_srvlist))
1267 *retcmpp = NFSERR_NOTSAME;
1268 } else if (m == 0) {
1269 *retcmpp = NFSERR_NOTSAME;
1273 free(cp, M_NFSSTRING);
1275 free(cp2, M_NFSSTRING);
1277 case NFSATTRBIT_HIDDEN:
1278 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1279 if (compare && !(*retcmpp))
1280 *retcmpp = NFSERR_ATTRNOTSUPP;
1281 attrsum += NFSX_UNSIGNED;
1283 case NFSATTRBIT_HOMOGENEOUS:
1284 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1287 if (fsp->fs_properties &
1288 NFSV3_FSFHOMOGENEOUS) {
1289 if (*tl == newnfs_false)
1290 *retcmpp = NFSERR_NOTSAME;
1292 if (*tl == newnfs_true)
1293 *retcmpp = NFSERR_NOTSAME;
1296 } else if (fsp != NULL) {
1297 if (*tl == newnfs_true)
1298 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1300 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1302 attrsum += NFSX_UNSIGNED;
1304 case NFSATTRBIT_MAXFILESIZE:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1306 tnfsquad.qval = fxdr_hyper(tl);
1309 tquad = NFSRV_MAXFILESIZE;
1310 if (tquad != tnfsquad.qval)
1311 *retcmpp = NFSERR_NOTSAME;
1313 } else if (fsp != NULL) {
1314 fsp->fs_maxfilesize = tnfsquad.qval;
1316 attrsum += NFSX_HYPER;
1318 case NFSATTRBIT_MAXLINK:
1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1322 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1323 *retcmpp = NFSERR_NOTSAME;
1325 } else if (pc != NULL) {
1326 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1328 attrsum += NFSX_UNSIGNED;
1330 case NFSATTRBIT_MAXNAME:
1331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1334 if (fsp->fs_maxname !=
1335 fxdr_unsigned(u_int32_t, *tl))
1336 *retcmpp = NFSERR_NOTSAME;
1339 tuint = fxdr_unsigned(u_int32_t, *tl);
1341 * Some Linux NFSv4 servers report this
1342 * as 0 or 4billion, so I'll set it to
1343 * NFS_MAXNAMLEN. If a server actually creates
1344 * a name longer than NFS_MAXNAMLEN, it will
1345 * get an error back.
1347 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1348 tuint = NFS_MAXNAMLEN;
1350 fsp->fs_maxname = tuint;
1352 pc->pc_namemax = tuint;
1354 attrsum += NFSX_UNSIGNED;
1356 case NFSATTRBIT_MAXREAD:
1357 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1360 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1361 *(tl + 1)) || *tl != 0)
1362 *retcmpp = NFSERR_NOTSAME;
1364 } else if (fsp != NULL) {
1365 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1366 fsp->fs_rtpref = fsp->fs_rtmax;
1367 fsp->fs_dtpref = fsp->fs_rtpref;
1369 attrsum += NFSX_HYPER;
1371 case NFSATTRBIT_MAXWRITE:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1375 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1376 *(tl + 1)) || *tl != 0)
1377 *retcmpp = NFSERR_NOTSAME;
1379 } else if (fsp != NULL) {
1380 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1381 fsp->fs_wtpref = fsp->fs_wtmax;
1383 attrsum += NFSX_HYPER;
1385 case NFSATTRBIT_MIMETYPE:
1386 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1387 i = fxdr_unsigned(int, *tl);
1388 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1389 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1392 if (compare && !(*retcmpp))
1393 *retcmpp = NFSERR_ATTRNOTSUPP;
1395 case NFSATTRBIT_MODE:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1399 if (nap->na_mode != nfstov_mode(*tl))
1400 *retcmpp = NFSERR_NOTSAME;
1402 } else if (nap != NULL) {
1403 nap->na_mode = nfstov_mode(*tl);
1405 attrsum += NFSX_UNSIGNED;
1407 case NFSATTRBIT_NOTRUNC:
1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1411 if (*tl != newnfs_true)
1412 *retcmpp = NFSERR_NOTSAME;
1414 } else if (pc != NULL) {
1415 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1417 attrsum += NFSX_UNSIGNED;
1419 case NFSATTRBIT_NUMLINKS:
1420 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1421 tuint = fxdr_unsigned(u_int32_t, *tl);
1424 if ((u_int32_t)nap->na_nlink != tuint)
1425 *retcmpp = NFSERR_NOTSAME;
1427 } else if (nap != NULL) {
1428 nap->na_nlink = tuint;
1430 attrsum += NFSX_UNSIGNED;
1432 case NFSATTRBIT_OWNER:
1433 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1434 j = fxdr_unsigned(int, *tl);
1436 error = NFSERR_BADXDR;
1439 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1440 if (j > NFSV4_SMALLSTR)
1441 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1444 error = nfsrv_mtostr(nd, cp, j);
1446 if (j > NFSV4_SMALLSTR)
1447 free(cp, M_NFSSTRING);
1452 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1454 *retcmpp = NFSERR_NOTSAME;
1456 } else if (nap != NULL) {
1457 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1458 nap->na_uid = nfsrv_defaultuid;
1462 if (j > NFSV4_SMALLSTR)
1463 free(cp, M_NFSSTRING);
1465 case NFSATTRBIT_OWNERGROUP:
1466 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1467 j = fxdr_unsigned(int, *tl);
1469 error = NFSERR_BADXDR;
1472 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1473 if (j > NFSV4_SMALLSTR)
1474 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1477 error = nfsrv_mtostr(nd, cp, j);
1479 if (j > NFSV4_SMALLSTR)
1480 free(cp, M_NFSSTRING);
1485 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1487 *retcmpp = NFSERR_NOTSAME;
1489 } else if (nap != NULL) {
1490 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1491 nap->na_gid = nfsrv_defaultgid;
1495 if (j > NFSV4_SMALLSTR)
1496 free(cp, M_NFSSTRING);
1498 case NFSATTRBIT_QUOTAHARD:
1499 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1501 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1502 freenum = sbp->f_bfree;
1504 freenum = sbp->f_bavail;
1507 * ufs_quotactl() insists that the uid argument
1508 * equal p_ruid for non-root quota access, so
1509 * we'll just make sure that's the case.
1511 savuid = p->p_cred->p_ruid;
1512 p->p_cred->p_ruid = cred->cr_uid;
1513 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1514 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1515 freenum = min(dqb.dqb_bhardlimit, freenum);
1516 p->p_cred->p_ruid = savuid;
1518 uquad = (u_int64_t)freenum;
1519 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1521 if (compare && !(*retcmpp)) {
1522 if (uquad != fxdr_hyper(tl))
1523 *retcmpp = NFSERR_NOTSAME;
1525 attrsum += NFSX_HYPER;
1527 case NFSATTRBIT_QUOTASOFT:
1528 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1530 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1531 freenum = sbp->f_bfree;
1533 freenum = sbp->f_bavail;
1536 * ufs_quotactl() insists that the uid argument
1537 * equal p_ruid for non-root quota access, so
1538 * we'll just make sure that's the case.
1540 savuid = p->p_cred->p_ruid;
1541 p->p_cred->p_ruid = cred->cr_uid;
1542 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1543 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1544 freenum = min(dqb.dqb_bsoftlimit, freenum);
1545 p->p_cred->p_ruid = savuid;
1547 uquad = (u_int64_t)freenum;
1548 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1550 if (compare && !(*retcmpp)) {
1551 if (uquad != fxdr_hyper(tl))
1552 *retcmpp = NFSERR_NOTSAME;
1554 attrsum += NFSX_HYPER;
1556 case NFSATTRBIT_QUOTAUSED:
1557 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1562 * ufs_quotactl() insists that the uid argument
1563 * equal p_ruid for non-root quota access, so
1564 * we'll just make sure that's the case.
1566 savuid = p->p_cred->p_ruid;
1567 p->p_cred->p_ruid = cred->cr_uid;
1568 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1569 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1570 freenum = dqb.dqb_curblocks;
1571 p->p_cred->p_ruid = savuid;
1573 uquad = (u_int64_t)freenum;
1574 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1576 if (compare && !(*retcmpp)) {
1577 if (uquad != fxdr_hyper(tl))
1578 *retcmpp = NFSERR_NOTSAME;
1580 attrsum += NFSX_HYPER;
1582 case NFSATTRBIT_RAWDEV:
1583 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1584 j = fxdr_unsigned(int, *tl++);
1585 k = fxdr_unsigned(int, *tl);
1588 if (nap->na_rdev != NFSMAKEDEV(j, k))
1589 *retcmpp = NFSERR_NOTSAME;
1591 } else if (nap != NULL) {
1592 nap->na_rdev = NFSMAKEDEV(j, k);
1594 attrsum += NFSX_V4SPECDATA;
1596 case NFSATTRBIT_SPACEAVAIL:
1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1600 sfp->sf_abytes != fxdr_hyper(tl))
1601 *retcmpp = NFSERR_NOTSAME;
1602 } else if (sfp != NULL) {
1603 sfp->sf_abytes = fxdr_hyper(tl);
1605 attrsum += NFSX_HYPER;
1607 case NFSATTRBIT_SPACEFREE:
1608 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1611 sfp->sf_fbytes != fxdr_hyper(tl))
1612 *retcmpp = NFSERR_NOTSAME;
1613 } else if (sfp != NULL) {
1614 sfp->sf_fbytes = fxdr_hyper(tl);
1616 attrsum += NFSX_HYPER;
1618 case NFSATTRBIT_SPACETOTAL:
1619 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1622 sfp->sf_tbytes != fxdr_hyper(tl))
1623 *retcmpp = NFSERR_NOTSAME;
1624 } else if (sfp != NULL) {
1625 sfp->sf_tbytes = fxdr_hyper(tl);
1627 attrsum += NFSX_HYPER;
1629 case NFSATTRBIT_SPACEUSED:
1630 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1631 thyp = fxdr_hyper(tl);
1634 if ((u_int64_t)nap->na_bytes != thyp)
1635 *retcmpp = NFSERR_NOTSAME;
1637 } else if (nap != NULL) {
1638 nap->na_bytes = thyp;
1640 attrsum += NFSX_HYPER;
1642 case NFSATTRBIT_SYSTEM:
1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1644 if (compare && !(*retcmpp))
1645 *retcmpp = NFSERR_ATTRNOTSUPP;
1646 attrsum += NFSX_UNSIGNED;
1648 case NFSATTRBIT_TIMEACCESS:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1650 fxdr_nfsv4time(tl, &temptime);
1653 if (!NFS_CMPTIME(temptime, nap->na_atime))
1654 *retcmpp = NFSERR_NOTSAME;
1656 } else if (nap != NULL) {
1657 nap->na_atime = temptime;
1659 attrsum += NFSX_V4TIME;
1661 case NFSATTRBIT_TIMEACCESSSET:
1662 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1663 attrsum += NFSX_UNSIGNED;
1664 i = fxdr_unsigned(int, *tl);
1665 if (i == NFSV4SATTRTIME_TOCLIENT) {
1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1667 attrsum += NFSX_V4TIME;
1669 if (compare && !(*retcmpp))
1670 *retcmpp = NFSERR_INVAL;
1672 case NFSATTRBIT_TIMEBACKUP:
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1674 if (compare && !(*retcmpp))
1675 *retcmpp = NFSERR_ATTRNOTSUPP;
1676 attrsum += NFSX_V4TIME;
1678 case NFSATTRBIT_TIMECREATE:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1680 if (compare && !(*retcmpp))
1681 *retcmpp = NFSERR_ATTRNOTSUPP;
1682 attrsum += NFSX_V4TIME;
1684 case NFSATTRBIT_TIMEDELTA:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1689 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1690 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1691 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1692 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1695 *retcmpp = NFSERR_NOTSAME;
1698 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1701 attrsum += NFSX_V4TIME;
1703 case NFSATTRBIT_TIMEMETADATA:
1704 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1705 fxdr_nfsv4time(tl, &temptime);
1708 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1709 *retcmpp = NFSERR_NOTSAME;
1711 } else if (nap != NULL) {
1712 nap->na_ctime = temptime;
1714 attrsum += NFSX_V4TIME;
1716 case NFSATTRBIT_TIMEMODIFY:
1717 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1718 fxdr_nfsv4time(tl, &temptime);
1721 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1722 *retcmpp = NFSERR_NOTSAME;
1724 } else if (nap != NULL) {
1725 nap->na_mtime = temptime;
1727 attrsum += NFSX_V4TIME;
1729 case NFSATTRBIT_TIMEMODIFYSET:
1730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1731 attrsum += NFSX_UNSIGNED;
1732 i = fxdr_unsigned(int, *tl);
1733 if (i == NFSV4SATTRTIME_TOCLIENT) {
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1735 attrsum += NFSX_V4TIME;
1737 if (compare && !(*retcmpp))
1738 *retcmpp = NFSERR_INVAL;
1740 case NFSATTRBIT_MOUNTEDONFILEID:
1741 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1742 thyp = fxdr_hyper(tl);
1746 *retcmpp = NFSERR_NOTSAME;
1748 if (!vp || !nfsrv_atroot(vp, &fid))
1749 fid = nap->na_fileid;
1750 if ((u_int64_t)fid != thyp)
1751 *retcmpp = NFSERR_NOTSAME;
1754 } else if (nap != NULL) {
1756 count64mountfileid++;
1757 if (ratecheck(&last64mountfileid, &warninterval)) {
1758 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1759 count64mountfileid);
1760 count64mountfileid = 0;
1763 nap->na_mntonfileno = thyp;
1765 attrsum += NFSX_HYPER;
1767 case NFSATTRBIT_SUPPATTREXCLCREAT:
1769 error = nfsrv_getattrbits(nd, &retattrbits,
1773 if (compare && !(*retcmpp)) {
1774 NFSSETSUPP_ATTRBIT(&checkattrbits);
1775 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1776 NFSCLRBIT_ATTRBIT(&checkattrbits,
1777 NFSATTRBIT_TIMEACCESSSET);
1778 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1780 *retcmpp = NFSERR_NOTSAME;
1785 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1787 if (compare && !(*retcmpp))
1788 *retcmpp = NFSERR_ATTRNOTSUPP;
1790 * and get out of the loop, since we can't parse
1791 * the unknown attrbute data.
1793 bitpos = NFSATTRBIT_MAX;
1799 * some clients pad the attrlist, so we need to skip over the
1802 if (attrsum > attrsize) {
1803 error = NFSERR_BADXDR;
1805 attrsize = NFSM_RNDUP(attrsize);
1806 if (attrsum < attrsize)
1807 error = nfsm_advance(nd, attrsize - attrsum, -1);
1810 NFSEXITCODE2(error, nd);
1815 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1816 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1817 * The first argument is a pointer to an nfsv4lock structure.
1818 * The second argument is 1 iff a blocking lock is wanted.
1819 * If this argument is 0, the call waits until no thread either wants nor
1820 * holds an exclusive lock.
1821 * It returns 1 if the lock was acquired, 0 otherwise.
1822 * If several processes call this function concurrently wanting the exclusive
1823 * lock, one will get the lock and the rest will return without getting the
1824 * lock. (If the caller must have the lock, it simply calls this function in a
1825 * loop until the function returns 1 to indicate the lock was acquired.)
1826 * Any usecnt must be decremented by calling nfsv4_relref() before
1827 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1828 * be called in a loop.
1829 * The isleptp argument is set to indicate if the call slept, iff not NULL
1830 * and the mp argument indicates to check for a forced dismount, iff not
1834 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1835 void *mutex, struct mount *mp)
1841 * If a lock is wanted, loop around until the lock is acquired by
1842 * someone and then released. If I want the lock, try to acquire it.
1843 * For a lock to be issued, no lock must be in force and the usecnt
1847 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1848 lp->nfslock_usecnt == 0) {
1849 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1850 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1853 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1855 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1856 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1857 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1860 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1863 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1864 PZERO - 1, "nfsv4lck", NULL);
1865 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1866 lp->nfslock_usecnt == 0) {
1867 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1868 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1876 * Release the lock acquired by nfsv4_lock().
1877 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1878 * incremented, as well.
1881 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1884 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1886 lp->nfslock_usecnt++;
1891 * Release a reference cnt.
1894 nfsv4_relref(struct nfsv4lock *lp)
1897 if (lp->nfslock_usecnt <= 0)
1898 panic("nfsv4root ref cnt");
1899 lp->nfslock_usecnt--;
1900 if (lp->nfslock_usecnt == 0)
1905 * Get a reference cnt.
1906 * This function will wait for any exclusive lock to be released, but will
1907 * not wait for threads that want the exclusive lock. If priority needs
1908 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1909 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1910 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1911 * return without getting a refcnt for that case.
1914 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1922 * Wait for a lock held.
1924 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1925 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1927 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1930 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1931 PZERO - 1, "nfsv4gr", NULL);
1933 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1936 lp->nfslock_usecnt++;
1940 * Get a reference as above, but return failure instead of sleeping if
1941 * an exclusive lock is held.
1944 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1947 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1950 lp->nfslock_usecnt++;
1955 * Test for a lock. Return 1 if locked, 0 otherwise.
1958 nfsv4_testlock(struct nfsv4lock *lp)
1961 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1962 lp->nfslock_usecnt == 0)
1968 * Wake up anyone sleeping, waiting for this lock.
1971 nfsv4_wanted(struct nfsv4lock *lp)
1974 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1975 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1976 wakeup((caddr_t)&lp->nfslock_lock);
1981 * Copy a string from an mbuf list into a character array.
1982 * Return EBADRPC if there is an mbuf error,
1986 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1995 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1996 rem = NFSM_RNDUP(siz) - siz;
2002 NFSBCOPY(cp, str, xfer);
2011 cp = NFSMTOD(mp, caddr_t);
2023 error = nfsm_advance(nd, rem, len);
2029 NFSEXITCODE2(error, nd);
2034 * Fill in the attributes as marked by the bitmap (V4).
2037 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2038 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2039 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2040 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2042 int bitpos, retnum = 0;
2044 int siz, prefixnum, error;
2045 u_char *cp, namestr[NFSV4_SMALLSTR];
2046 nfsattrbit_t attrbits, retbits;
2047 nfsattrbit_t *retbitp = &retbits;
2048 u_int32_t freenum, *retnump;
2051 struct nfsfsinfo fsinf;
2052 struct timespec temptime;
2053 NFSACL_T *aclp, *naclp = NULL;
2060 * First, set the bits that can be filled and get fsinfo.
2062 NFSSET_ATTRBIT(retbitp, attrbitp);
2064 * If both p and cred are NULL, it is a client side setattr call.
2065 * If both p and cred are not NULL, it is a server side reply call.
2066 * If p is not NULL and cred is NULL, it is a client side callback
2069 if (p == NULL && cred == NULL) {
2070 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2073 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2074 naclp = acl_alloc(M_WAITOK);
2077 nfsvno_getfs(&fsinf, isdgram);
2080 * Get the VFS_STATFS(), since some attributes need them.
2082 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2083 error = VFS_STATFS(mp, &fs);
2086 nd->nd_repstat = NFSERR_ACCES;
2089 NFSCLRSTATFS_ATTRBIT(retbitp);
2095 * And the NFSv4 ACL...
2097 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2098 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2099 supports_nfsv4acls == 0))) {
2100 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2102 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2103 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2104 supports_nfsv4acls == 0)) {
2105 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2106 } else if (naclp != NULL) {
2107 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2108 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2110 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2112 NFSVOPUNLOCK(vp, 0);
2114 error = NFSERR_PERM;
2117 nd->nd_repstat = NFSERR_ACCES;
2120 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2126 * Put out the attribute bitmap for the ones being filled in
2127 * and get the field for the number of attributes returned.
2129 prefixnum = nfsrv_putattrbit(nd, retbitp);
2130 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2131 prefixnum += NFSX_UNSIGNED;
2134 * Now, loop around filling in the attributes for each bit set.
2136 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2137 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2139 case NFSATTRBIT_SUPPORTEDATTRS:
2140 NFSSETSUPP_ATTRBIT(&attrbits);
2141 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2142 && supports_nfsv4acls == 0)) {
2143 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2144 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2146 retnum += nfsrv_putattrbit(nd, &attrbits);
2148 case NFSATTRBIT_TYPE:
2149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2150 *tl = vtonfsv34_type(vap->va_type);
2151 retnum += NFSX_UNSIGNED;
2153 case NFSATTRBIT_FHEXPIRETYPE:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2155 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_CHANGE:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2160 txdr_hyper(vap->va_filerev, tl);
2161 retnum += NFSX_HYPER;
2163 case NFSATTRBIT_SIZE:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2165 txdr_hyper(vap->va_size, tl);
2166 retnum += NFSX_HYPER;
2168 case NFSATTRBIT_LINKSUPPORT:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2174 retnum += NFSX_UNSIGNED;
2176 case NFSATTRBIT_SYMLINKSUPPORT:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2182 retnum += NFSX_UNSIGNED;
2184 case NFSATTRBIT_NAMEDATTR:
2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2187 retnum += NFSX_UNSIGNED;
2189 case NFSATTRBIT_FSID:
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2192 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2194 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2195 retnum += NFSX_V4FSID;
2197 case NFSATTRBIT_UNIQUEHANDLES:
2198 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2200 retnum += NFSX_UNSIGNED;
2202 case NFSATTRBIT_LEASETIME:
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2204 *tl = txdr_unsigned(nfsrv_lease);
2205 retnum += NFSX_UNSIGNED;
2207 case NFSATTRBIT_RDATTRERROR:
2208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2209 *tl = txdr_unsigned(rderror);
2210 retnum += NFSX_UNSIGNED;
2213 * Recommended Attributes. (Only the supported ones.)
2215 case NFSATTRBIT_ACL:
2216 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2218 case NFSATTRBIT_ACLSUPPORT:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2221 retnum += NFSX_UNSIGNED;
2223 case NFSATTRBIT_CANSETTIME:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2229 retnum += NFSX_UNSIGNED;
2231 case NFSATTRBIT_CASEINSENSITIVE:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2234 retnum += NFSX_UNSIGNED;
2236 case NFSATTRBIT_CASEPRESERVING:
2237 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2239 retnum += NFSX_UNSIGNED;
2241 case NFSATTRBIT_CHOWNRESTRICTED:
2242 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 retnum += NFSX_UNSIGNED;
2246 case NFSATTRBIT_FILEHANDLE:
2247 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2249 case NFSATTRBIT_FILEID:
2250 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 *tl = txdr_unsigned(vap->va_fileid);
2253 retnum += NFSX_HYPER;
2255 case NFSATTRBIT_FILESAVAIL:
2257 * Check quota and use min(quota, f_ffree).
2259 freenum = fs.f_ffree;
2262 * ufs_quotactl() insists that the uid argument
2263 * equal p_ruid for non-root quota access, so
2264 * we'll just make sure that's the case.
2266 savuid = p->p_cred->p_ruid;
2267 p->p_cred->p_ruid = cred->cr_uid;
2268 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2269 cred->cr_uid, (caddr_t)&dqb))
2270 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2272 p->p_cred->p_ruid = savuid;
2274 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2276 *tl = txdr_unsigned(freenum);
2277 retnum += NFSX_HYPER;
2279 case NFSATTRBIT_FILESFREE:
2280 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2282 *tl = txdr_unsigned(fs.f_ffree);
2283 retnum += NFSX_HYPER;
2285 case NFSATTRBIT_FILESTOTAL:
2286 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2288 *tl = txdr_unsigned(fs.f_files);
2289 retnum += NFSX_HYPER;
2291 case NFSATTRBIT_FSLOCATIONS:
2292 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2295 retnum += 2 * NFSX_UNSIGNED;
2297 case NFSATTRBIT_HOMOGENEOUS:
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2299 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2303 retnum += NFSX_UNSIGNED;
2305 case NFSATTRBIT_MAXFILESIZE:
2306 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2307 uquad = NFSRV_MAXFILESIZE;
2308 txdr_hyper(uquad, tl);
2309 retnum += NFSX_HYPER;
2311 case NFSATTRBIT_MAXLINK:
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2313 *tl = txdr_unsigned(LINK_MAX);
2314 retnum += NFSX_UNSIGNED;
2316 case NFSATTRBIT_MAXNAME:
2317 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2318 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2319 retnum += NFSX_UNSIGNED;
2321 case NFSATTRBIT_MAXREAD:
2322 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2324 *tl = txdr_unsigned(fsinf.fs_rtmax);
2325 retnum += NFSX_HYPER;
2327 case NFSATTRBIT_MAXWRITE:
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2330 *tl = txdr_unsigned(fsinf.fs_wtmax);
2331 retnum += NFSX_HYPER;
2333 case NFSATTRBIT_MODE:
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2335 *tl = vtonfsv34_mode(vap->va_mode);
2336 retnum += NFSX_UNSIGNED;
2338 case NFSATTRBIT_NOTRUNC:
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2341 retnum += NFSX_UNSIGNED;
2343 case NFSATTRBIT_NUMLINKS:
2344 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2345 *tl = txdr_unsigned(vap->va_nlink);
2346 retnum += NFSX_UNSIGNED;
2348 case NFSATTRBIT_OWNER:
2350 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2351 retnum += nfsm_strtom(nd, cp, siz);
2353 free(cp, M_NFSSTRING);
2355 case NFSATTRBIT_OWNERGROUP:
2357 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2358 retnum += nfsm_strtom(nd, cp, siz);
2360 free(cp, M_NFSSTRING);
2362 case NFSATTRBIT_QUOTAHARD:
2363 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2364 freenum = fs.f_bfree;
2366 freenum = fs.f_bavail;
2369 * ufs_quotactl() insists that the uid argument
2370 * equal p_ruid for non-root quota access, so
2371 * we'll just make sure that's the case.
2373 savuid = p->p_cred->p_ruid;
2374 p->p_cred->p_ruid = cred->cr_uid;
2375 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2376 cred->cr_uid, (caddr_t)&dqb))
2377 freenum = min(dqb.dqb_bhardlimit, freenum);
2378 p->p_cred->p_ruid = savuid;
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2381 uquad = (u_int64_t)freenum;
2382 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2383 txdr_hyper(uquad, tl);
2384 retnum += NFSX_HYPER;
2386 case NFSATTRBIT_QUOTASOFT:
2387 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2388 freenum = fs.f_bfree;
2390 freenum = fs.f_bavail;
2393 * ufs_quotactl() insists that the uid argument
2394 * equal p_ruid for non-root quota access, so
2395 * we'll just make sure that's the case.
2397 savuid = p->p_cred->p_ruid;
2398 p->p_cred->p_ruid = cred->cr_uid;
2399 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2400 cred->cr_uid, (caddr_t)&dqb))
2401 freenum = min(dqb.dqb_bsoftlimit, freenum);
2402 p->p_cred->p_ruid = savuid;
2404 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2405 uquad = (u_int64_t)freenum;
2406 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2407 txdr_hyper(uquad, tl);
2408 retnum += NFSX_HYPER;
2410 case NFSATTRBIT_QUOTAUSED:
2414 * ufs_quotactl() insists that the uid argument
2415 * equal p_ruid for non-root quota access, so
2416 * we'll just make sure that's the case.
2418 savuid = p->p_cred->p_ruid;
2419 p->p_cred->p_ruid = cred->cr_uid;
2420 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2421 cred->cr_uid, (caddr_t)&dqb))
2422 freenum = dqb.dqb_curblocks;
2423 p->p_cred->p_ruid = savuid;
2425 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2426 uquad = (u_int64_t)freenum;
2427 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2428 txdr_hyper(uquad, tl);
2429 retnum += NFSX_HYPER;
2431 case NFSATTRBIT_RAWDEV:
2432 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2433 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2434 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2435 retnum += NFSX_V4SPECDATA;
2437 case NFSATTRBIT_SPACEAVAIL:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2439 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2440 uquad = (u_int64_t)fs.f_bfree;
2442 uquad = (u_int64_t)fs.f_bavail;
2443 uquad *= fs.f_bsize;
2444 txdr_hyper(uquad, tl);
2445 retnum += NFSX_HYPER;
2447 case NFSATTRBIT_SPACEFREE:
2448 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2449 uquad = (u_int64_t)fs.f_bfree;
2450 uquad *= fs.f_bsize;
2451 txdr_hyper(uquad, tl);
2452 retnum += NFSX_HYPER;
2454 case NFSATTRBIT_SPACETOTAL:
2455 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2456 uquad = (u_int64_t)fs.f_blocks;
2457 uquad *= fs.f_bsize;
2458 txdr_hyper(uquad, tl);
2459 retnum += NFSX_HYPER;
2461 case NFSATTRBIT_SPACEUSED:
2462 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2463 txdr_hyper(vap->va_bytes, tl);
2464 retnum += NFSX_HYPER;
2466 case NFSATTRBIT_TIMEACCESS:
2467 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2468 txdr_nfsv4time(&vap->va_atime, tl);
2469 retnum += NFSX_V4TIME;
2471 case NFSATTRBIT_TIMEACCESSSET:
2472 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2474 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2475 txdr_nfsv4time(&vap->va_atime, tl);
2476 retnum += NFSX_V4SETTIME;
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2479 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2480 retnum += NFSX_UNSIGNED;
2483 case NFSATTRBIT_TIMEDELTA:
2484 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2485 temptime.tv_sec = 0;
2486 temptime.tv_nsec = 1000000000 / hz;
2487 txdr_nfsv4time(&temptime, tl);
2488 retnum += NFSX_V4TIME;
2490 case NFSATTRBIT_TIMEMETADATA:
2491 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2492 txdr_nfsv4time(&vap->va_ctime, tl);
2493 retnum += NFSX_V4TIME;
2495 case NFSATTRBIT_TIMEMODIFY:
2496 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2497 txdr_nfsv4time(&vap->va_mtime, tl);
2498 retnum += NFSX_V4TIME;
2500 case NFSATTRBIT_TIMEMODIFYSET:
2501 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2502 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2503 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2504 txdr_nfsv4time(&vap->va_mtime, tl);
2505 retnum += NFSX_V4SETTIME;
2507 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2508 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2509 retnum += NFSX_UNSIGNED;
2512 case NFSATTRBIT_MOUNTEDONFILEID:
2513 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2515 uquad = mounted_on_fileno;
2517 uquad = (u_int64_t)vap->va_fileid;
2518 txdr_hyper(uquad, tl);
2519 retnum += NFSX_HYPER;
2521 case NFSATTRBIT_SUPPATTREXCLCREAT:
2522 NFSSETSUPP_ATTRBIT(&attrbits);
2523 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2524 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2525 retnum += nfsrv_putattrbit(nd, &attrbits);
2528 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2534 *retnump = txdr_unsigned(retnum);
2535 return (retnum + prefixnum);
2539 * Put the attribute bits onto an mbuf list.
2540 * Return the number of bytes of output generated.
2543 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2546 int cnt, i, bytesize;
2548 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2549 if (attrbitp->bits[cnt - 1])
2551 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2552 NFSM_BUILD(tl, u_int32_t *, bytesize);
2553 *tl++ = txdr_unsigned(cnt);
2554 for (i = 0; i < cnt; i++)
2555 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2560 * Convert a uid to a string.
2561 * If the lookup fails, just output the digits.
2563 * cpp - points to a buffer of size NFSV4_SMALLSTR
2564 * (malloc a larger one, as required)
2565 * retlenp - pointer to length to be returned
2568 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2571 struct nfsusrgrp *usrp;
2574 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2575 struct nfsrv_lughash *hp;
2579 if (nfsrv_dnsnamelen > 0) {
2581 * Always map nfsrv_defaultuid to "nobody".
2583 if (uid == nfsrv_defaultuid) {
2584 i = nfsrv_dnsnamelen + 7;
2586 if (len > NFSV4_SMALLSTR)
2587 free(cp, M_NFSSTRING);
2588 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2594 NFSBCOPY("nobody@", cp, 7);
2596 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2600 hp = NFSUSERHASH(uid);
2602 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2603 if (usrp->lug_uid == uid) {
2604 if (usrp->lug_expiry < NFSD_MONOSEC)
2607 * If the name doesn't already have an '@'
2608 * in it, append @domainname to it.
2610 for (i = 0; i < usrp->lug_namelen; i++) {
2611 if (usrp->lug_name[i] == '@') {
2617 i = usrp->lug_namelen;
2619 i = usrp->lug_namelen +
2620 nfsrv_dnsnamelen + 1;
2622 mtx_unlock(&hp->mtx);
2623 if (len > NFSV4_SMALLSTR)
2624 free(cp, M_NFSSTRING);
2625 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2631 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2632 if (!hasampersand) {
2633 cp += usrp->lug_namelen;
2635 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2637 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2638 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2640 mtx_unlock(&hp->mtx);
2644 mtx_unlock(&hp->mtx);
2646 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2648 if (ret == 0 && cnt < 2)
2653 * No match, just return a string of digits.
2657 while (tmp || i == 0) {
2661 len = (i > len) ? len : i;
2665 for (i = 0; i < len; i++) {
2666 *cp-- = '0' + (tmp % 10);
2673 * Get a credential for the uid with the server's group list.
2674 * If none is found, just return the credential passed in after
2675 * logging a warning message.
2678 nfsrv_getgrpscred(struct ucred *oldcred)
2680 struct nfsusrgrp *usrp;
2681 struct ucred *newcred;
2684 struct nfsrv_lughash *hp;
2687 uid = oldcred->cr_uid;
2689 if (nfsrv_dnsnamelen > 0) {
2690 hp = NFSUSERHASH(uid);
2692 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2693 if (usrp->lug_uid == uid) {
2694 if (usrp->lug_expiry < NFSD_MONOSEC)
2696 if (usrp->lug_cred != NULL) {
2697 newcred = crhold(usrp->lug_cred);
2701 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2702 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2704 mtx_unlock(&hp->mtx);
2708 mtx_unlock(&hp->mtx);
2710 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2712 if (ret == 0 && cnt < 2)
2719 * Convert a string to a uid.
2720 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2722 * If this is called from a client side mount using AUTH_SYS and the
2723 * string is made up entirely of digits, just convert the string to
2727 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2731 char *cp, *endstr, *str0;
2732 struct nfsusrgrp *usrp;
2736 struct nfsrv_lughash *hp, *hp2;
2739 error = NFSERR_BADOWNER;
2742 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2744 tuid = (uid_t)strtoul(str0, &endstr, 10);
2745 if ((endstr - str0) == len) {
2746 /* A numeric string. */
2747 if ((nd->nd_flag & ND_KERBV) == 0 &&
2748 ((nd->nd_flag & ND_NFSCL) != 0 ||
2749 nfsd_enable_stringtouid != 0))
2752 error = NFSERR_BADOWNER;
2758 cp = strchr(str0, '@');
2760 i = (int)(cp++ - str0);
2766 if (nfsrv_dnsnamelen > 0) {
2768 * If an '@' is found and the domain name matches, search for
2769 * the name with dns stripped off.
2770 * Mixed case alpahbetics will match for the domain name, but
2771 * all upper case will not.
2773 if (cnt == 0 && i < len && i > 0 &&
2774 (len - 1 - i) == nfsrv_dnsnamelen &&
2775 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2776 len -= (nfsrv_dnsnamelen + 1);
2781 * Check for the special case of "nobody".
2783 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2784 *uidp = nfsrv_defaultuid;
2789 hp = NFSUSERNAMEHASH(str, len);
2791 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2792 if (usrp->lug_namelen == len &&
2793 !NFSBCMP(usrp->lug_name, str, len)) {
2794 if (usrp->lug_expiry < NFSD_MONOSEC)
2796 hp2 = NFSUSERHASH(usrp->lug_uid);
2797 mtx_lock(&hp2->mtx);
2798 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2799 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2801 *uidp = usrp->lug_uid;
2802 mtx_unlock(&hp2->mtx);
2803 mtx_unlock(&hp->mtx);
2808 mtx_unlock(&hp->mtx);
2810 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2812 if (ret == 0 && cnt < 2)
2815 error = NFSERR_BADOWNER;
2823 * Convert a gid to a string.
2824 * gid - the group id
2825 * cpp - points to a buffer of size NFSV4_SMALLSTR
2826 * (malloc a larger one, as required)
2827 * retlenp - pointer to length to be returned
2830 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2833 struct nfsusrgrp *usrp;
2836 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2837 struct nfsrv_lughash *hp;
2841 if (nfsrv_dnsnamelen > 0) {
2843 * Always map nfsrv_defaultgid to "nogroup".
2845 if (gid == nfsrv_defaultgid) {
2846 i = nfsrv_dnsnamelen + 8;
2848 if (len > NFSV4_SMALLSTR)
2849 free(cp, M_NFSSTRING);
2850 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2856 NFSBCOPY("nogroup@", cp, 8);
2858 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2862 hp = NFSGROUPHASH(gid);
2864 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2865 if (usrp->lug_gid == gid) {
2866 if (usrp->lug_expiry < NFSD_MONOSEC)
2869 * If the name doesn't already have an '@'
2870 * in it, append @domainname to it.
2872 for (i = 0; i < usrp->lug_namelen; i++) {
2873 if (usrp->lug_name[i] == '@') {
2879 i = usrp->lug_namelen;
2881 i = usrp->lug_namelen +
2882 nfsrv_dnsnamelen + 1;
2884 mtx_unlock(&hp->mtx);
2885 if (len > NFSV4_SMALLSTR)
2886 free(cp, M_NFSSTRING);
2887 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2893 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2894 if (!hasampersand) {
2895 cp += usrp->lug_namelen;
2897 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2899 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2900 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2902 mtx_unlock(&hp->mtx);
2906 mtx_unlock(&hp->mtx);
2908 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2910 if (ret == 0 && cnt < 2)
2915 * No match, just return a string of digits.
2919 while (tmp || i == 0) {
2923 len = (i > len) ? len : i;
2927 for (i = 0; i < len; i++) {
2928 *cp-- = '0' + (tmp % 10);
2935 * Convert a string to a gid.
2936 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2938 * If this is called from a client side mount using AUTH_SYS and the
2939 * string is made up entirely of digits, just convert the string to
2943 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2947 char *cp, *endstr, *str0;
2948 struct nfsusrgrp *usrp;
2952 struct nfsrv_lughash *hp, *hp2;
2955 error = NFSERR_BADOWNER;
2958 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2960 tgid = (gid_t)strtoul(str0, &endstr, 10);
2961 if ((endstr - str0) == len) {
2962 /* A numeric string. */
2963 if ((nd->nd_flag & ND_KERBV) == 0 &&
2964 ((nd->nd_flag & ND_NFSCL) != 0 ||
2965 nfsd_enable_stringtouid != 0))
2968 error = NFSERR_BADOWNER;
2974 cp = strchr(str0, '@');
2976 i = (int)(cp++ - str0);
2982 if (nfsrv_dnsnamelen > 0) {
2984 * If an '@' is found and the dns name matches, search for the
2985 * name with the dns stripped off.
2987 if (cnt == 0 && i < len && i > 0 &&
2988 (len - 1 - i) == nfsrv_dnsnamelen &&
2989 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2990 len -= (nfsrv_dnsnamelen + 1);
2995 * Check for the special case of "nogroup".
2997 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2998 *gidp = nfsrv_defaultgid;
3003 hp = NFSGROUPNAMEHASH(str, len);
3005 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3006 if (usrp->lug_namelen == len &&
3007 !NFSBCMP(usrp->lug_name, str, len)) {
3008 if (usrp->lug_expiry < NFSD_MONOSEC)
3010 hp2 = NFSGROUPHASH(usrp->lug_gid);
3011 mtx_lock(&hp2->mtx);
3012 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3013 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3015 *gidp = usrp->lug_gid;
3016 mtx_unlock(&hp2->mtx);
3017 mtx_unlock(&hp->mtx);
3022 mtx_unlock(&hp->mtx);
3024 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3026 if (ret == 0 && cnt < 2)
3029 error = NFSERR_BADOWNER;
3037 * Cmp len chars, allowing mixed case in the first argument to match lower
3038 * case in the second, but not if the first argument is all upper case.
3039 * Return 0 for a match, 1 otherwise.
3042 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3048 for (i = 0; i < len; i++) {
3049 if (*cp >= 'A' && *cp <= 'Z') {
3050 tmp = *cp++ + ('a' - 'A');
3053 if (tmp >= 'a' && tmp <= 'z')
3066 * Set the port for the nfsuserd.
3069 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3071 struct nfssockreq *rp;
3072 struct sockaddr_in *ad;
3076 if (nfsrv_nfsuserd) {
3084 * Set up the socket record and connect.
3086 rp = &nfsrv_nfsuserdsock;
3087 rp->nr_client = NULL;
3088 rp->nr_sotype = SOCK_DGRAM;
3089 rp->nr_soproto = IPPROTO_UDP;
3090 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3092 NFSSOCKADDRALLOC(rp->nr_nam);
3093 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3094 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3095 ad->sin_family = AF_INET;
3096 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3097 ad->sin_port = port;
3098 rp->nr_prog = RPCPROG_NFSUSERD;
3099 rp->nr_vers = RPCNFSUSERD_VERS;
3100 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3102 NFSSOCKADDRFREE(rp->nr_nam);
3111 * Delete the nfsuserd port.
3114 nfsrv_nfsuserddelport(void)
3118 if (nfsrv_nfsuserd == 0) {
3124 newnfs_disconnect(&nfsrv_nfsuserdsock);
3125 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3129 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3131 * Returns 0 upon success, non-zero otherwise.
3134 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3137 struct nfsrv_descript *nd;
3139 struct nfsrv_descript nfsd;
3144 if (nfsrv_nfsuserd == 0) {
3151 cred = newnfs_getcred();
3152 nd->nd_flag = ND_GSSINITREPLY;
3155 nd->nd_procnum = procnum;
3156 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3158 if (procnum == RPCNFSUSERD_GETUID)
3159 *tl = txdr_unsigned(uid);
3161 *tl = txdr_unsigned(gid);
3164 (void) nfsm_strtom(nd, name, len);
3166 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3167 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3170 mbuf_freem(nd->nd_mrep);
3171 error = nd->nd_repstat;
3179 * This function is called from the nfssvc(2) system call, to update the
3180 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3183 nfssvc_idname(struct nfsd_idargs *nidp)
3185 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3186 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3187 int i, group_locked, groupname_locked, user_locked, username_locked;
3192 static int onethread = 0;
3193 static time_t lasttime = 0;
3195 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3199 if (nidp->nid_flag & NFSID_INITIALIZE) {
3200 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3201 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3204 free(cp, M_NFSSTRING);
3207 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3209 * Free up all the old stuff and reinitialize hash
3210 * lists. All mutexes for both lists must be locked,
3211 * with the user/group name ones before the uid/gid
3212 * ones, to avoid a LOR.
3214 for (i = 0; i < nfsrv_lughashsize; i++)
3215 mtx_lock(&nfsusernamehash[i].mtx);
3216 for (i = 0; i < nfsrv_lughashsize; i++)
3217 mtx_lock(&nfsuserhash[i].mtx);
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 TAILQ_FOREACH_SAFE(usrp,
3220 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3221 nfsrv_removeuser(usrp, 1);
3222 for (i = 0; i < nfsrv_lughashsize; i++)
3223 mtx_unlock(&nfsuserhash[i].mtx);
3224 for (i = 0; i < nfsrv_lughashsize; i++)
3225 mtx_unlock(&nfsusernamehash[i].mtx);
3226 for (i = 0; i < nfsrv_lughashsize; i++)
3227 mtx_lock(&nfsgroupnamehash[i].mtx);
3228 for (i = 0; i < nfsrv_lughashsize; i++)
3229 mtx_lock(&nfsgrouphash[i].mtx);
3230 for (i = 0; i < nfsrv_lughashsize; i++)
3231 TAILQ_FOREACH_SAFE(usrp,
3232 &nfsgrouphash[i].lughead, lug_numhash,
3234 nfsrv_removeuser(usrp, 0);
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 mtx_unlock(&nfsgrouphash[i].mtx);
3237 for (i = 0; i < nfsrv_lughashsize; i++)
3238 mtx_unlock(&nfsgroupnamehash[i].mtx);
3239 free(nfsrv_dnsname, M_NFSSTRING);
3240 nfsrv_dnsname = NULL;
3242 if (nfsuserhash == NULL) {
3243 /* Allocate the hash tables. */
3244 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3245 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3249 NULL, MTX_DEF | MTX_DUPOK);
3250 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3251 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 mtx_init(&nfsusernamehash[i].mtx,
3255 "nfsusrhash", NULL, MTX_DEF |
3257 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3258 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3260 for (i = 0; i < nfsrv_lughashsize; i++)
3261 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3262 NULL, MTX_DEF | MTX_DUPOK);
3263 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3264 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3266 for (i = 0; i < nfsrv_lughashsize; i++)
3267 mtx_init(&nfsgroupnamehash[i].mtx,
3268 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3270 /* (Re)initialize the list heads. */
3271 for (i = 0; i < nfsrv_lughashsize; i++)
3272 TAILQ_INIT(&nfsuserhash[i].lughead);
3273 for (i = 0; i < nfsrv_lughashsize; i++)
3274 TAILQ_INIT(&nfsusernamehash[i].lughead);
3275 for (i = 0; i < nfsrv_lughashsize; i++)
3276 TAILQ_INIT(&nfsgrouphash[i].lughead);
3277 for (i = 0; i < nfsrv_lughashsize; i++)
3278 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3281 * Put name in "DNS" string.
3284 nfsrv_defaultuid = nidp->nid_uid;
3285 nfsrv_defaultgid = nidp->nid_gid;
3287 nfsrv_usermax = nidp->nid_usermax;
3288 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3293 * malloc the new one now, so any potential sleep occurs before
3294 * manipulation of the lists.
3296 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3297 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3298 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3300 if (error == 0 && nidp->nid_ngroup > 0 &&
3301 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3302 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3304 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3305 sizeof(gid_t) * nidp->nid_ngroup);
3308 * Create a credential just like svc_getcred(),
3309 * but using the group list provided.
3312 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3313 crsetgroups(cr, nidp->nid_ngroup, grps);
3314 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3315 cr->cr_prison = &prison0;
3316 prison_hold(cr->cr_prison);
3318 mac_cred_associate_nfsd(cr);
3320 newusrp->lug_cred = cr;
3325 free(newusrp, M_NFSUSERGROUP);
3328 newusrp->lug_namelen = nidp->nid_namelen;
3331 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3332 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3333 * The flags user_locked, username_locked, group_locked and
3334 * groupname_locked are set to indicate all of those hash lists are
3335 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3336 * the respective one mutex is locked.
3338 user_locked = username_locked = group_locked = groupname_locked = 0;
3339 hp_name = hp_idnum = NULL;
3342 * Delete old entries, as required.
3344 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3345 /* Must lock all username hash lists first, to avoid a LOR. */
3346 for (i = 0; i < nfsrv_lughashsize; i++)
3347 mtx_lock(&nfsusernamehash[i].mtx);
3348 username_locked = 1;
3349 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3350 mtx_lock(&hp_idnum->mtx);
3351 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3353 if (usrp->lug_uid == nidp->nid_uid)
3354 nfsrv_removeuser(usrp, 1);
3356 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3357 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3358 newusrp->lug_namelen);
3359 mtx_lock(&hp_name->mtx);
3360 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3362 if (usrp->lug_namelen == newusrp->lug_namelen &&
3363 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3364 usrp->lug_namelen)) {
3365 thp = NFSUSERHASH(usrp->lug_uid);
3366 mtx_lock(&thp->mtx);
3367 nfsrv_removeuser(usrp, 1);
3368 mtx_unlock(&thp->mtx);
3371 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3372 mtx_lock(&hp_idnum->mtx);
3373 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3374 /* Must lock all groupname hash lists first, to avoid a LOR. */
3375 for (i = 0; i < nfsrv_lughashsize; i++)
3376 mtx_lock(&nfsgroupnamehash[i].mtx);
3377 groupname_locked = 1;
3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3379 mtx_lock(&hp_idnum->mtx);
3380 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3382 if (usrp->lug_gid == nidp->nid_gid)
3383 nfsrv_removeuser(usrp, 0);
3385 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3386 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3387 newusrp->lug_namelen);
3388 mtx_lock(&hp_name->mtx);
3389 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3391 if (usrp->lug_namelen == newusrp->lug_namelen &&
3392 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3393 usrp->lug_namelen)) {
3394 thp = NFSGROUPHASH(usrp->lug_gid);
3395 mtx_lock(&thp->mtx);
3396 nfsrv_removeuser(usrp, 0);
3397 mtx_unlock(&thp->mtx);
3400 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3401 mtx_lock(&hp_idnum->mtx);
3405 * Now, we can add the new one.
3407 if (nidp->nid_usertimeout)
3408 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3410 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3411 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3412 newusrp->lug_uid = nidp->nid_uid;
3413 thp = NFSUSERHASH(newusrp->lug_uid);
3414 mtx_assert(&thp->mtx, MA_OWNED);
3415 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3416 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3417 mtx_assert(&thp->mtx, MA_OWNED);
3418 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3419 atomic_add_int(&nfsrv_usercnt, 1);
3420 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3421 newusrp->lug_gid = nidp->nid_gid;
3422 thp = NFSGROUPHASH(newusrp->lug_gid);
3423 mtx_assert(&thp->mtx, MA_OWNED);
3424 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3425 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3426 mtx_assert(&thp->mtx, MA_OWNED);
3427 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3428 atomic_add_int(&nfsrv_usercnt, 1);
3430 if (newusrp->lug_cred != NULL)
3431 crfree(newusrp->lug_cred);
3432 free(newusrp, M_NFSUSERGROUP);
3436 * Once per second, allow one thread to trim the cache.
3438 if (lasttime < NFSD_MONOSEC &&
3439 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3441 * First, unlock the single mutexes, so that all entries
3442 * can be locked and any LOR is avoided.
3444 if (hp_name != NULL) {
3445 mtx_unlock(&hp_name->mtx);
3448 if (hp_idnum != NULL) {
3449 mtx_unlock(&hp_idnum->mtx);
3453 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3454 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3455 if (username_locked == 0) {
3456 for (i = 0; i < nfsrv_lughashsize; i++)
3457 mtx_lock(&nfsusernamehash[i].mtx);
3458 username_locked = 1;
3460 KASSERT(user_locked == 0,
3461 ("nfssvc_idname: user_locked"));
3462 for (i = 0; i < nfsrv_lughashsize; i++)
3463 mtx_lock(&nfsuserhash[i].mtx);
3465 for (i = 0; i < nfsrv_lughashsize; i++) {
3466 TAILQ_FOREACH_SAFE(usrp,
3467 &nfsuserhash[i].lughead, lug_numhash,
3469 if (usrp->lug_expiry < NFSD_MONOSEC)
3470 nfsrv_removeuser(usrp, 1);
3472 for (i = 0; i < nfsrv_lughashsize; i++) {
3474 * Trim the cache using an approximate LRU
3475 * algorithm. This code deletes the least
3476 * recently used entry on each hash list.
3478 if (nfsrv_usercnt <= nfsrv_usermax)
3480 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3482 nfsrv_removeuser(usrp, 1);
3485 if (groupname_locked == 0) {
3486 for (i = 0; i < nfsrv_lughashsize; i++)
3487 mtx_lock(&nfsgroupnamehash[i].mtx);
3488 groupname_locked = 1;
3490 KASSERT(group_locked == 0,
3491 ("nfssvc_idname: group_locked"));
3492 for (i = 0; i < nfsrv_lughashsize; i++)
3493 mtx_lock(&nfsgrouphash[i].mtx);
3495 for (i = 0; i < nfsrv_lughashsize; i++) {
3496 TAILQ_FOREACH_SAFE(usrp,
3497 &nfsgrouphash[i].lughead, lug_numhash,
3499 if (usrp->lug_expiry < NFSD_MONOSEC)
3500 nfsrv_removeuser(usrp, 0);
3502 for (i = 0; i < nfsrv_lughashsize; i++) {
3504 * Trim the cache using an approximate LRU
3505 * algorithm. This code deletes the least
3506 * recently user entry on each hash list.
3508 if (nfsrv_usercnt <= nfsrv_usermax)
3510 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3512 nfsrv_removeuser(usrp, 0);
3515 lasttime = NFSD_MONOSEC;
3516 atomic_store_rel_int(&onethread, 0);
3519 /* Now, unlock all locked mutexes. */
3520 if (hp_idnum != NULL)
3521 mtx_unlock(&hp_idnum->mtx);
3522 if (hp_name != NULL)
3523 mtx_unlock(&hp_name->mtx);
3524 if (user_locked != 0)
3525 for (i = 0; i < nfsrv_lughashsize; i++)
3526 mtx_unlock(&nfsuserhash[i].mtx);
3527 if (username_locked != 0)
3528 for (i = 0; i < nfsrv_lughashsize; i++)
3529 mtx_unlock(&nfsusernamehash[i].mtx);
3530 if (group_locked != 0)
3531 for (i = 0; i < nfsrv_lughashsize; i++)
3532 mtx_unlock(&nfsgrouphash[i].mtx);
3533 if (groupname_locked != 0)
3534 for (i = 0; i < nfsrv_lughashsize; i++)
3535 mtx_unlock(&nfsgroupnamehash[i].mtx);
3542 * Remove a user/group name element.
3545 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3547 struct nfsrv_lughash *hp;
3550 hp = NFSUSERHASH(usrp->lug_uid);
3551 mtx_assert(&hp->mtx, MA_OWNED);
3552 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3553 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3554 mtx_assert(&hp->mtx, MA_OWNED);
3555 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3557 hp = NFSGROUPHASH(usrp->lug_gid);
3558 mtx_assert(&hp->mtx, MA_OWNED);
3559 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3560 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3561 mtx_assert(&hp->mtx, MA_OWNED);
3562 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3564 atomic_add_int(&nfsrv_usercnt, -1);
3565 if (usrp->lug_cred != NULL)
3566 crfree(usrp->lug_cred);
3567 free(usrp, M_NFSUSERGROUP);
3571 * Free up all the allocations related to the name<-->id cache.
3572 * This function should only be called when the nfsuserd daemon isn't
3573 * running, since it doesn't do any locking.
3574 * This function is meant to be used when the nfscommon module is unloaded.
3577 nfsrv_cleanusergroup(void)
3579 struct nfsrv_lughash *hp, *hp2;
3580 struct nfsusrgrp *nusrp, *usrp;
3583 if (nfsuserhash == NULL)
3586 for (i = 0; i < nfsrv_lughashsize; i++) {
3587 hp = &nfsuserhash[i];
3588 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3589 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3590 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3592 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3593 if (usrp->lug_cred != NULL)
3594 crfree(usrp->lug_cred);
3595 free(usrp, M_NFSUSERGROUP);
3597 hp = &nfsgrouphash[i];
3598 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3599 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3600 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3602 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3603 if (usrp->lug_cred != NULL)
3604 crfree(usrp->lug_cred);
3605 free(usrp, M_NFSUSERGROUP);
3607 mtx_destroy(&nfsuserhash[i].mtx);
3608 mtx_destroy(&nfsusernamehash[i].mtx);
3609 mtx_destroy(&nfsgroupnamehash[i].mtx);
3610 mtx_destroy(&nfsgrouphash[i].mtx);
3612 free(nfsuserhash, M_NFSUSERGROUP);
3613 free(nfsusernamehash, M_NFSUSERGROUP);
3614 free(nfsgrouphash, M_NFSUSERGROUP);
3615 free(nfsgroupnamehash, M_NFSUSERGROUP);
3616 free(nfsrv_dnsname, M_NFSSTRING);
3620 * This function scans a byte string and checks for UTF-8 compliance.
3621 * It returns 0 if it conforms and NFSERR_INVAL if not.
3624 nfsrv_checkutf8(u_int8_t *cp, int len)
3626 u_int32_t val = 0x0;
3627 int cnt = 0, gotd = 0, shift = 0;
3629 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3633 * Here are what the variables are used for:
3634 * val - the calculated value of a multibyte char, used to check
3635 * that it was coded with the correct range
3636 * cnt - the number of 10xxxxxx bytes to follow
3637 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3638 * shift - lower order bits of range (ie. "val >> shift" should
3639 * not be 0, in other words, dividing by the lower bound
3640 * of the range should get a non-zero value)
3641 * byte - used to calculate cnt
3645 /* This handles the 10xxxxxx bytes */
3646 if ((*cp & 0xc0) != 0x80 ||
3647 (gotd && (*cp & 0x20))) {
3648 error = NFSERR_INVAL;
3653 val |= (*cp & 0x3f);
3655 if (cnt == 0 && (val >> shift) == 0x0) {
3656 error = NFSERR_INVAL;
3659 } else if (*cp & 0x80) {
3660 /* first byte of multi byte char */
3662 while ((byte & 0x40) && cnt < 6) {
3666 if (cnt == 0 || cnt == 6) {
3667 error = NFSERR_INVAL;
3670 val = (*cp & (0x3f >> cnt));
3671 shift = utf8_shift[cnt - 1];
3672 if (cnt == 2 && val == 0xd)
3673 /* Check for the 0xd800-0xdfff case */
3680 error = NFSERR_INVAL;
3688 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3689 * strings, one with the root path in it and the other with the list of
3690 * locations. The list is in the same format as is found in nfr_refs.
3691 * It is a "," separated list of entries, where each of them is of the
3692 * form <server>:<rootpath>. For example
3693 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3694 * The nilp argument is set to 1 for the special case of a null fs_root
3695 * and an empty server list.
3696 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3697 * number of xdr bytes parsed in sump.
3700 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3701 int *sump, int *nilp)
3704 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3705 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3707 SLIST_ENTRY(list) next;
3711 SLIST_HEAD(, list) head;
3718 * Get the fs_root path and check for the special case of null path
3719 * and 0 length server list.
3721 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3722 len = fxdr_unsigned(int, *tl);
3723 if (len < 0 || len > 10240) {
3724 error = NFSERR_BADXDR;
3728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3730 error = NFSERR_BADXDR;
3734 *sump = 2 * NFSX_UNSIGNED;
3738 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3739 error = nfsrv_mtostr(nd, cp, len);
3741 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3742 cnt = fxdr_unsigned(int, *tl);
3744 error = NFSERR_BADXDR;
3750 * Now, loop through the location list and make up the srvlist.
3752 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3753 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3756 for (i = 0; i < cnt; i++) {
3758 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3759 nsrv = fxdr_unsigned(int, *tl);
3761 error = NFSERR_BADXDR;
3766 * Handle the first server by putting it in the srvstr.
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 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3779 error = nfsrv_mtostr(nd, cp3, len);
3785 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3786 for (j = 1; j < nsrv; j++) {
3788 * Yuck, put them in an slist and process them later.
3790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3791 len = fxdr_unsigned(int, *tl);
3792 if (len <= 0 || len > 1024) {
3793 error = NFSERR_BADXDR;
3796 lsp = (struct list *)malloc(sizeof (struct list)
3797 + len, M_TEMP, M_WAITOK);
3798 error = nfsrv_mtostr(nd, lsp->host, len);
3801 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3803 SLIST_INSERT_HEAD(&head, lsp, next);
3807 * Finally, we can get the path.
3809 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3810 len = fxdr_unsigned(int, *tl);
3811 if (len <= 0 || len > 1024) {
3812 error = NFSERR_BADXDR;
3815 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3816 error = nfsrv_mtostr(nd, cp3, len);
3819 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3824 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3825 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3828 NFSBCOPY(lsp->host, cp3, lsp->len);
3831 NFSBCOPY(str, cp3, stringlen);
3834 siz += (lsp->len + stringlen + 2);
3835 free((caddr_t)lsp, M_TEMP);
3841 NFSEXITCODE2(0, nd);
3845 free(cp, M_NFSSTRING);
3847 free(cp2, M_NFSSTRING);
3848 NFSEXITCODE2(error, nd);
3853 * Make the malloc'd space large enough. This is a pain, but the xdr
3854 * doesn't set an upper bound on the side, so...
3857 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3864 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3865 NFSBCOPY(*cpp, cp, *slenp);
3866 free(*cpp, M_NFSSTRING);
3870 *slenp = siz + 1024;
3874 * Initialize the reply header data structures.
3877 nfsrvd_rephead(struct nfsrv_descript *nd)
3882 * If this is a big reply, use a cluster.
3884 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3885 nfs_bigreply[nd->nd_procnum]) {
3886 NFSMCLGET(mreq, M_WAITOK);
3894 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3895 mbuf_setlen(mreq, 0);
3897 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3898 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3902 * Lock a socket against others.
3903 * Currently used to serialize connect/disconnect attempts.
3906 newnfs_sndlock(int *flagp)
3911 while (*flagp & NFSR_SNDLOCK) {
3912 *flagp |= NFSR_WANTSND;
3915 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3916 PZERO - 1, "nfsndlck", &ts);
3918 *flagp |= NFSR_SNDLOCK;
3924 * Unlock the stream socket for others.
3927 newnfs_sndunlock(int *flagp)
3931 if ((*flagp & NFSR_SNDLOCK) == 0)
3932 panic("nfs sndunlock");
3933 *flagp &= ~NFSR_SNDLOCK;
3934 if (*flagp & NFSR_WANTSND) {
3935 *flagp &= ~NFSR_WANTSND;
3936 wakeup((caddr_t)flagp);
3942 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3945 struct sockaddr_in *sad;
3946 struct sockaddr_in6 *sad6;
3947 struct in_addr saddr;
3948 uint32_t portnum, *tl;
3949 int af = 0, i, j, k;
3950 char addr[64], protocol[5], *cp;
3951 int cantparse = 0, error = 0;
3954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3955 i = fxdr_unsigned(int, *tl);
3956 if (i >= 3 && i <= 4) {
3957 error = nfsrv_mtostr(nd, protocol, i);
3960 if (strcmp(protocol, "tcp") == 0) {
3963 } else if (strcmp(protocol, "udp") == 0) {
3966 } else if (strcmp(protocol, "tcp6") == 0) {
3969 } else if (strcmp(protocol, "udp6") == 0) {
3977 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3983 i = fxdr_unsigned(int, *tl);
3985 error = NFSERR_BADXDR;
3987 } else if (cantparse == 0 && i >= 11 && i < 64) {
3989 * The shortest address is 11chars and the longest is < 64.
3991 error = nfsrv_mtostr(nd, addr, i);
3995 /* Find the port# at the end and extract that. */
3999 /* Count back two '.'s from end to get port# field. */
4000 for (j = 0; j < i; j++) {
4010 * The NFSv4 port# is appended as .N.N, where N is
4011 * a decimal # in the range 0-255, just like an inet4
4012 * address. Cheat and use inet_aton(), which will
4013 * return a Class A address and then shift the high
4014 * order 8bits over to convert it to the port#.
4017 if (inet_aton(cp, &saddr) == 1) {
4018 portnum = ntohl(saddr.s_addr);
4019 portv = (uint16_t)((portnum >> 16) |
4025 if (cantparse == 0) {
4026 if (af == AF_INET) {
4027 sad = (struct sockaddr_in *)sa;
4028 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4029 sad->sin_len = sizeof(*sad);
4030 sad->sin_family = AF_INET;
4031 sad->sin_port = htons(portv);
4035 sad6 = (struct sockaddr_in6 *)sa;
4036 if (inet_pton(af, addr, &sad6->sin6_addr)
4038 sad6->sin6_len = sizeof(*sad6);
4039 sad6->sin6_family = AF_INET6;
4040 sad6->sin6_port = htons(portv);
4047 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4058 * Handle an NFSv4.1 Sequence request for the session.
4059 * If reply != NULL, use it to return the cached reply, as required.
4060 * The client gets a cached reply via this call for callbacks, however the
4061 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4064 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4065 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4072 if (slotid > maxslot)
4073 return (NFSERR_BADSLOT);
4074 if (seqid == slots[slotid].nfssl_seq) {
4076 if (slots[slotid].nfssl_inprog != 0)
4077 error = NFSERR_DELAY;
4078 else if (slots[slotid].nfssl_reply != NULL) {
4079 if (reply != NULL) {
4080 *reply = slots[slotid].nfssl_reply;
4081 slots[slotid].nfssl_reply = NULL;
4083 slots[slotid].nfssl_inprog = 1;
4084 error = NFSERR_REPLYFROMCACHE;
4086 /* No reply cached, so just do it. */
4087 slots[slotid].nfssl_inprog = 1;
4088 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4089 if (slots[slotid].nfssl_reply != NULL)
4090 m_freem(slots[slotid].nfssl_reply);
4091 slots[slotid].nfssl_reply = NULL;
4092 slots[slotid].nfssl_inprog = 1;
4093 slots[slotid].nfssl_seq++;
4095 error = NFSERR_SEQMISORDERED;
4100 * Cache this reply for the slot.
4101 * Use the "rep" argument to return the cached reply if repstat is set to
4102 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4105 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4109 if (repstat == NFSERR_REPLYFROMCACHE) {
4110 *rep = slots[slotid].nfssl_reply;
4111 slots[slotid].nfssl_reply = NULL;
4113 if (slots[slotid].nfssl_reply != NULL)
4114 m_freem(slots[slotid].nfssl_reply);
4115 slots[slotid].nfssl_reply = *rep;
4117 slots[slotid].nfssl_inprog = 0;
4121 * Generate the xdr for an NFSv4.1 Sequence Operation.
4124 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4125 struct nfsclsession *sep, int dont_replycache)
4127 uint32_t *tl, slotseq = 0;
4128 int error, maxslot, slotpos;
4129 uint8_t sessionid[NFSX_V4SESSIONID];
4131 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4135 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
4137 /* Build the Sequence arguments. */
4138 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4139 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4140 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4141 nd->nd_slotseq = tl;
4142 *tl++ = txdr_unsigned(slotseq);
4143 *tl++ = txdr_unsigned(slotpos);
4144 *tl++ = txdr_unsigned(maxslot);
4145 if (dont_replycache == 0)
4149 nd->nd_flag |= ND_HASSEQUENCE;
4153 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4154 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4156 int i, maxslot, slotpos;
4159 /* Find an unused slot. */
4162 mtx_lock(&sep->nfsess_mtx);
4165 for (i = 0; i < sep->nfsess_foreslots; i++) {
4166 if ((bitval & sep->nfsess_slots) == 0) {
4168 sep->nfsess_slots |= bitval;
4169 sep->nfsess_slotseq[i]++;
4170 *slotseqp = sep->nfsess_slotseq[i];
4175 if (slotpos == -1) {
4177 * If a forced dismount is in progress, just return.
4178 * This RPC attempt will fail when it calls
4182 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4184 mtx_unlock(&sep->nfsess_mtx);
4187 /* Wake up once/sec, to check for a forced dismount. */
4188 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4189 PZERO, "nfsclseq", hz);
4191 } while (slotpos == -1);
4192 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4194 for (i = 0; i < 64; i++) {
4195 if ((bitval & sep->nfsess_slots) != 0)
4199 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4200 mtx_unlock(&sep->nfsess_mtx);
4201 *slotposp = slotpos;
4202 *maxslotp = maxslot;
4207 * Free a session slot.
4210 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4217 mtx_lock(&sep->nfsess_mtx);
4218 if ((bitval & sep->nfsess_slots) == 0)
4219 printf("freeing free slot!!\n");
4220 sep->nfsess_slots &= ~bitval;
4221 wakeup(&sep->nfsess_slots);
4222 mtx_unlock(&sep->nfsess_mtx);