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 * 3. 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 = UID_NOBODY;
67 gid_t nfsrv_defaultgid = GID_NOGROUP;
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, 1 }, /* undef */
94 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
95 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
96 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
98 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
99 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
102 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
104 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
108 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
109 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
111 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
112 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
116 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
117 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
118 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
119 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
121 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
131 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* 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;
892 sfp->sf_ffiles = UINT64_MAX;
893 sfp->sf_tfiles = UINT64_MAX;
894 sfp->sf_afiles = UINT64_MAX;
895 sfp->sf_fbytes = UINT64_MAX;
896 sfp->sf_tbytes = UINT64_MAX;
897 sfp->sf_abytes = UINT64_MAX;
902 * Loop around getting the attributes.
904 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
905 attrsize = fxdr_unsigned(int, *tl);
906 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
907 if (attrsum > attrsize) {
908 error = NFSERR_BADXDR;
911 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
913 case NFSATTRBIT_SUPPORTEDATTRS:
915 if (compare || nap == NULL)
916 error = nfsrv_getattrbits(nd, &retattrbits,
919 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
923 if (compare && !(*retcmpp)) {
924 NFSSETSUPP_ATTRBIT(&checkattrbits);
926 /* Some filesystem do not support NFSv4ACL */
927 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
928 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
929 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
931 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
933 *retcmpp = NFSERR_NOTSAME;
937 case NFSATTRBIT_TYPE:
938 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
941 if (nap->na_type != nfsv34tov_type(*tl))
942 *retcmpp = NFSERR_NOTSAME;
944 } else if (nap != NULL) {
945 nap->na_type = nfsv34tov_type(*tl);
947 attrsum += NFSX_UNSIGNED;
949 case NFSATTRBIT_FHEXPIRETYPE:
950 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
951 if (compare && !(*retcmpp)) {
952 if (fxdr_unsigned(int, *tl) !=
953 NFSV4FHTYPE_PERSISTENT)
954 *retcmpp = NFSERR_NOTSAME;
956 attrsum += NFSX_UNSIGNED;
958 case NFSATTRBIT_CHANGE:
959 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
962 if (nap->na_filerev != fxdr_hyper(tl))
963 *retcmpp = NFSERR_NOTSAME;
965 } else if (nap != NULL) {
966 nap->na_filerev = fxdr_hyper(tl);
968 attrsum += NFSX_HYPER;
970 case NFSATTRBIT_SIZE:
971 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
974 if (nap->na_size != fxdr_hyper(tl))
975 *retcmpp = NFSERR_NOTSAME;
977 } else if (nap != NULL) {
978 nap->na_size = fxdr_hyper(tl);
980 attrsum += NFSX_HYPER;
982 case NFSATTRBIT_LINKSUPPORT:
983 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
986 if (fsp->fs_properties & NFSV3_FSFLINK) {
987 if (*tl == newnfs_false)
988 *retcmpp = NFSERR_NOTSAME;
990 if (*tl == newnfs_true)
991 *retcmpp = NFSERR_NOTSAME;
994 } else if (fsp != NULL) {
995 if (*tl == newnfs_true)
996 fsp->fs_properties |= NFSV3_FSFLINK;
998 fsp->fs_properties &= ~NFSV3_FSFLINK;
1000 attrsum += NFSX_UNSIGNED;
1002 case NFSATTRBIT_SYMLINKSUPPORT:
1003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1006 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1007 if (*tl == newnfs_false)
1008 *retcmpp = NFSERR_NOTSAME;
1010 if (*tl == newnfs_true)
1011 *retcmpp = NFSERR_NOTSAME;
1014 } else if (fsp != NULL) {
1015 if (*tl == newnfs_true)
1016 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1018 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1020 attrsum += NFSX_UNSIGNED;
1022 case NFSATTRBIT_NAMEDATTR:
1023 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1024 if (compare && !(*retcmpp)) {
1025 if (*tl != newnfs_false)
1026 *retcmpp = NFSERR_NOTSAME;
1028 attrsum += NFSX_UNSIGNED;
1030 case NFSATTRBIT_FSID:
1031 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1032 thyp = fxdr_hyper(tl);
1034 thyp2 = fxdr_hyper(tl);
1036 if (*retcmpp == 0) {
1037 if (thyp != (u_int64_t)
1038 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1039 thyp2 != (u_int64_t)
1040 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1041 *retcmpp = NFSERR_NOTSAME;
1043 } else if (nap != NULL) {
1044 nap->na_filesid[0] = thyp;
1045 nap->na_filesid[1] = thyp2;
1047 attrsum += (4 * NFSX_UNSIGNED);
1049 case NFSATTRBIT_UNIQUEHANDLES:
1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1051 if (compare && !(*retcmpp)) {
1052 if (*tl != newnfs_true)
1053 *retcmpp = NFSERR_NOTSAME;
1055 attrsum += NFSX_UNSIGNED;
1057 case NFSATTRBIT_LEASETIME:
1058 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1060 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1062 *retcmpp = NFSERR_NOTSAME;
1063 } else if (leasep != NULL) {
1064 *leasep = fxdr_unsigned(u_int32_t, *tl);
1066 attrsum += NFSX_UNSIGNED;
1068 case NFSATTRBIT_RDATTRERROR:
1069 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1072 *retcmpp = NFSERR_INVAL;
1073 } else if (rderrp != NULL) {
1074 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1076 attrsum += NFSX_UNSIGNED;
1078 case NFSATTRBIT_ACL:
1081 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1084 naclp = acl_alloc(M_WAITOK);
1085 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1091 if (aceerr || aclp == NULL ||
1092 nfsrv_compareacl(aclp, naclp))
1093 *retcmpp = NFSERR_NOTSAME;
1096 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1098 *retcmpp = NFSERR_ATTRNOTSUPP;
1102 if (vp != NULL && aclp != NULL)
1103 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1106 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1114 case NFSATTRBIT_ACLSUPPORT:
1115 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1116 if (compare && !(*retcmpp)) {
1117 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1118 if (fxdr_unsigned(u_int32_t, *tl) !=
1120 *retcmpp = NFSERR_NOTSAME;
1122 *retcmpp = NFSERR_ATTRNOTSUPP;
1125 attrsum += NFSX_UNSIGNED;
1127 case NFSATTRBIT_ARCHIVE:
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (compare && !(*retcmpp))
1130 *retcmpp = NFSERR_ATTRNOTSUPP;
1131 attrsum += NFSX_UNSIGNED;
1133 case NFSATTRBIT_CANSETTIME:
1134 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1137 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1138 if (*tl == newnfs_false)
1139 *retcmpp = NFSERR_NOTSAME;
1141 if (*tl == newnfs_true)
1142 *retcmpp = NFSERR_NOTSAME;
1145 } else if (fsp != NULL) {
1146 if (*tl == newnfs_true)
1147 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1149 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1151 attrsum += NFSX_UNSIGNED;
1153 case NFSATTRBIT_CASEINSENSITIVE:
1154 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1157 if (*tl != newnfs_false)
1158 *retcmpp = NFSERR_NOTSAME;
1160 } else if (pc != NULL) {
1161 pc->pc_caseinsensitive =
1162 fxdr_unsigned(u_int32_t, *tl);
1164 attrsum += NFSX_UNSIGNED;
1166 case NFSATTRBIT_CASEPRESERVING:
1167 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1170 if (*tl != newnfs_true)
1171 *retcmpp = NFSERR_NOTSAME;
1173 } else if (pc != NULL) {
1174 pc->pc_casepreserving =
1175 fxdr_unsigned(u_int32_t, *tl);
1177 attrsum += NFSX_UNSIGNED;
1179 case NFSATTRBIT_CHOWNRESTRICTED:
1180 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1183 if (*tl != newnfs_true)
1184 *retcmpp = NFSERR_NOTSAME;
1186 } else if (pc != NULL) {
1187 pc->pc_chownrestricted =
1188 fxdr_unsigned(u_int32_t, *tl);
1190 attrsum += NFSX_UNSIGNED;
1192 case NFSATTRBIT_FILEHANDLE:
1193 error = nfsm_getfh(nd, &tnfhp);
1196 tfhsize = tnfhp->nfh_len;
1199 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1201 *retcmpp = NFSERR_NOTSAME;
1202 FREE((caddr_t)tnfhp, M_NFSFH);
1203 } else if (nfhpp != NULL) {
1206 FREE((caddr_t)tnfhp, M_NFSFH);
1208 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1210 case NFSATTRBIT_FILEID:
1211 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1212 thyp = fxdr_hyper(tl);
1215 if ((u_int64_t)nap->na_fileid != thyp)
1216 *retcmpp = NFSERR_NOTSAME;
1218 } else if (nap != NULL) {
1221 if (ratecheck(&last64fileid, &warninterval)) {
1222 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1227 nap->na_fileid = thyp;
1229 attrsum += NFSX_HYPER;
1231 case NFSATTRBIT_FILESAVAIL:
1232 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1235 sfp->sf_afiles != fxdr_hyper(tl))
1236 *retcmpp = NFSERR_NOTSAME;
1237 } else if (sfp != NULL) {
1238 sfp->sf_afiles = fxdr_hyper(tl);
1240 attrsum += NFSX_HYPER;
1242 case NFSATTRBIT_FILESFREE:
1243 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1246 sfp->sf_ffiles != fxdr_hyper(tl))
1247 *retcmpp = NFSERR_NOTSAME;
1248 } else if (sfp != NULL) {
1249 sfp->sf_ffiles = fxdr_hyper(tl);
1251 attrsum += NFSX_HYPER;
1253 case NFSATTRBIT_FILESTOTAL:
1254 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1257 sfp->sf_tfiles != fxdr_hyper(tl))
1258 *retcmpp = NFSERR_NOTSAME;
1259 } else if (sfp != NULL) {
1260 sfp->sf_tfiles = fxdr_hyper(tl);
1262 attrsum += NFSX_HYPER;
1264 case NFSATTRBIT_FSLOCATIONS:
1265 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1269 if (compare && !(*retcmpp)) {
1270 refp = nfsv4root_getreferral(vp, NULL, 0);
1272 if (cp == NULL || cp2 == NULL ||
1274 strcmp(cp2, refp->nfr_srvlist))
1275 *retcmpp = NFSERR_NOTSAME;
1276 } else if (m == 0) {
1277 *retcmpp = NFSERR_NOTSAME;
1281 free(cp, M_NFSSTRING);
1283 free(cp2, M_NFSSTRING);
1285 case NFSATTRBIT_HIDDEN:
1286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1287 if (compare && !(*retcmpp))
1288 *retcmpp = NFSERR_ATTRNOTSUPP;
1289 attrsum += NFSX_UNSIGNED;
1291 case NFSATTRBIT_HOMOGENEOUS:
1292 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1295 if (fsp->fs_properties &
1296 NFSV3_FSFHOMOGENEOUS) {
1297 if (*tl == newnfs_false)
1298 *retcmpp = NFSERR_NOTSAME;
1300 if (*tl == newnfs_true)
1301 *retcmpp = NFSERR_NOTSAME;
1304 } else if (fsp != NULL) {
1305 if (*tl == newnfs_true)
1306 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1308 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1310 attrsum += NFSX_UNSIGNED;
1312 case NFSATTRBIT_MAXFILESIZE:
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1314 tnfsquad.qval = fxdr_hyper(tl);
1317 tquad = NFSRV_MAXFILESIZE;
1318 if (tquad != tnfsquad.qval)
1319 *retcmpp = NFSERR_NOTSAME;
1321 } else if (fsp != NULL) {
1322 fsp->fs_maxfilesize = tnfsquad.qval;
1324 attrsum += NFSX_HYPER;
1326 case NFSATTRBIT_MAXLINK:
1327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1330 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1331 *retcmpp = NFSERR_NOTSAME;
1333 } else if (pc != NULL) {
1334 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1336 attrsum += NFSX_UNSIGNED;
1338 case NFSATTRBIT_MAXNAME:
1339 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1342 if (fsp->fs_maxname !=
1343 fxdr_unsigned(u_int32_t, *tl))
1344 *retcmpp = NFSERR_NOTSAME;
1347 tuint = fxdr_unsigned(u_int32_t, *tl);
1349 * Some Linux NFSv4 servers report this
1350 * as 0 or 4billion, so I'll set it to
1351 * NFS_MAXNAMLEN. If a server actually creates
1352 * a name longer than NFS_MAXNAMLEN, it will
1353 * get an error back.
1355 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1356 tuint = NFS_MAXNAMLEN;
1358 fsp->fs_maxname = tuint;
1360 pc->pc_namemax = tuint;
1362 attrsum += NFSX_UNSIGNED;
1364 case NFSATTRBIT_MAXREAD:
1365 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1368 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1369 *(tl + 1)) || *tl != 0)
1370 *retcmpp = NFSERR_NOTSAME;
1372 } else if (fsp != NULL) {
1373 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1374 fsp->fs_rtpref = fsp->fs_rtmax;
1375 fsp->fs_dtpref = fsp->fs_rtpref;
1377 attrsum += NFSX_HYPER;
1379 case NFSATTRBIT_MAXWRITE:
1380 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1383 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1384 *(tl + 1)) || *tl != 0)
1385 *retcmpp = NFSERR_NOTSAME;
1387 } else if (fsp != NULL) {
1388 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1389 fsp->fs_wtpref = fsp->fs_wtmax;
1391 attrsum += NFSX_HYPER;
1393 case NFSATTRBIT_MIMETYPE:
1394 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1395 i = fxdr_unsigned(int, *tl);
1396 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1397 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1400 if (compare && !(*retcmpp))
1401 *retcmpp = NFSERR_ATTRNOTSUPP;
1403 case NFSATTRBIT_MODE:
1404 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1407 if (nap->na_mode != nfstov_mode(*tl))
1408 *retcmpp = NFSERR_NOTSAME;
1410 } else if (nap != NULL) {
1411 nap->na_mode = nfstov_mode(*tl);
1413 attrsum += NFSX_UNSIGNED;
1415 case NFSATTRBIT_NOTRUNC:
1416 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1419 if (*tl != newnfs_true)
1420 *retcmpp = NFSERR_NOTSAME;
1422 } else if (pc != NULL) {
1423 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1425 attrsum += NFSX_UNSIGNED;
1427 case NFSATTRBIT_NUMLINKS:
1428 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1429 tuint = fxdr_unsigned(u_int32_t, *tl);
1432 if ((u_int32_t)nap->na_nlink != tuint)
1433 *retcmpp = NFSERR_NOTSAME;
1435 } else if (nap != NULL) {
1436 nap->na_nlink = tuint;
1438 attrsum += NFSX_UNSIGNED;
1440 case NFSATTRBIT_OWNER:
1441 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1442 j = fxdr_unsigned(int, *tl);
1444 error = NFSERR_BADXDR;
1447 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1448 if (j > NFSV4_SMALLSTR)
1449 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1452 error = nfsrv_mtostr(nd, cp, j);
1454 if (j > NFSV4_SMALLSTR)
1455 free(cp, M_NFSSTRING);
1460 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1462 *retcmpp = NFSERR_NOTSAME;
1464 } else if (nap != NULL) {
1465 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1466 nap->na_uid = nfsrv_defaultuid;
1470 if (j > NFSV4_SMALLSTR)
1471 free(cp, M_NFSSTRING);
1473 case NFSATTRBIT_OWNERGROUP:
1474 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1475 j = fxdr_unsigned(int, *tl);
1477 error = NFSERR_BADXDR;
1480 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1481 if (j > NFSV4_SMALLSTR)
1482 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1485 error = nfsrv_mtostr(nd, cp, j);
1487 if (j > NFSV4_SMALLSTR)
1488 free(cp, M_NFSSTRING);
1493 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1495 *retcmpp = NFSERR_NOTSAME;
1497 } else if (nap != NULL) {
1498 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1499 nap->na_gid = nfsrv_defaultgid;
1503 if (j > NFSV4_SMALLSTR)
1504 free(cp, M_NFSSTRING);
1506 case NFSATTRBIT_QUOTAHARD:
1507 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1509 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1510 freenum = sbp->f_bfree;
1512 freenum = sbp->f_bavail;
1515 * ufs_quotactl() insists that the uid argument
1516 * equal p_ruid for non-root quota access, so
1517 * we'll just make sure that's the case.
1519 savuid = p->p_cred->p_ruid;
1520 p->p_cred->p_ruid = cred->cr_uid;
1521 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1522 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1523 freenum = min(dqb.dqb_bhardlimit, freenum);
1524 p->p_cred->p_ruid = savuid;
1526 uquad = (u_int64_t)freenum;
1527 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1529 if (compare && !(*retcmpp)) {
1530 if (uquad != fxdr_hyper(tl))
1531 *retcmpp = NFSERR_NOTSAME;
1533 attrsum += NFSX_HYPER;
1535 case NFSATTRBIT_QUOTASOFT:
1536 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1538 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1539 freenum = sbp->f_bfree;
1541 freenum = sbp->f_bavail;
1544 * ufs_quotactl() insists that the uid argument
1545 * equal p_ruid for non-root quota access, so
1546 * we'll just make sure that's the case.
1548 savuid = p->p_cred->p_ruid;
1549 p->p_cred->p_ruid = cred->cr_uid;
1550 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1551 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1552 freenum = min(dqb.dqb_bsoftlimit, freenum);
1553 p->p_cred->p_ruid = savuid;
1555 uquad = (u_int64_t)freenum;
1556 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1558 if (compare && !(*retcmpp)) {
1559 if (uquad != fxdr_hyper(tl))
1560 *retcmpp = NFSERR_NOTSAME;
1562 attrsum += NFSX_HYPER;
1564 case NFSATTRBIT_QUOTAUSED:
1565 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1570 * ufs_quotactl() insists that the uid argument
1571 * equal p_ruid for non-root quota access, so
1572 * we'll just make sure that's the case.
1574 savuid = p->p_cred->p_ruid;
1575 p->p_cred->p_ruid = cred->cr_uid;
1576 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1577 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1578 freenum = dqb.dqb_curblocks;
1579 p->p_cred->p_ruid = savuid;
1581 uquad = (u_int64_t)freenum;
1582 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1584 if (compare && !(*retcmpp)) {
1585 if (uquad != fxdr_hyper(tl))
1586 *retcmpp = NFSERR_NOTSAME;
1588 attrsum += NFSX_HYPER;
1590 case NFSATTRBIT_RAWDEV:
1591 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1592 j = fxdr_unsigned(int, *tl++);
1593 k = fxdr_unsigned(int, *tl);
1596 if (nap->na_rdev != NFSMAKEDEV(j, k))
1597 *retcmpp = NFSERR_NOTSAME;
1599 } else if (nap != NULL) {
1600 nap->na_rdev = NFSMAKEDEV(j, k);
1602 attrsum += NFSX_V4SPECDATA;
1604 case NFSATTRBIT_SPACEAVAIL:
1605 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1608 sfp->sf_abytes != fxdr_hyper(tl))
1609 *retcmpp = NFSERR_NOTSAME;
1610 } else if (sfp != NULL) {
1611 sfp->sf_abytes = fxdr_hyper(tl);
1613 attrsum += NFSX_HYPER;
1615 case NFSATTRBIT_SPACEFREE:
1616 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1619 sfp->sf_fbytes != fxdr_hyper(tl))
1620 *retcmpp = NFSERR_NOTSAME;
1621 } else if (sfp != NULL) {
1622 sfp->sf_fbytes = fxdr_hyper(tl);
1624 attrsum += NFSX_HYPER;
1626 case NFSATTRBIT_SPACETOTAL:
1627 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1630 sfp->sf_tbytes != fxdr_hyper(tl))
1631 *retcmpp = NFSERR_NOTSAME;
1632 } else if (sfp != NULL) {
1633 sfp->sf_tbytes = fxdr_hyper(tl);
1635 attrsum += NFSX_HYPER;
1637 case NFSATTRBIT_SPACEUSED:
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1639 thyp = fxdr_hyper(tl);
1642 if ((u_int64_t)nap->na_bytes != thyp)
1643 *retcmpp = NFSERR_NOTSAME;
1645 } else if (nap != NULL) {
1646 nap->na_bytes = thyp;
1648 attrsum += NFSX_HYPER;
1650 case NFSATTRBIT_SYSTEM:
1651 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1652 if (compare && !(*retcmpp))
1653 *retcmpp = NFSERR_ATTRNOTSUPP;
1654 attrsum += NFSX_UNSIGNED;
1656 case NFSATTRBIT_TIMEACCESS:
1657 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1658 fxdr_nfsv4time(tl, &temptime);
1661 if (!NFS_CMPTIME(temptime, nap->na_atime))
1662 *retcmpp = NFSERR_NOTSAME;
1664 } else if (nap != NULL) {
1665 nap->na_atime = temptime;
1667 attrsum += NFSX_V4TIME;
1669 case NFSATTRBIT_TIMEACCESSSET:
1670 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1671 attrsum += NFSX_UNSIGNED;
1672 i = fxdr_unsigned(int, *tl);
1673 if (i == NFSV4SATTRTIME_TOCLIENT) {
1674 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1675 attrsum += NFSX_V4TIME;
1677 if (compare && !(*retcmpp))
1678 *retcmpp = NFSERR_INVAL;
1680 case NFSATTRBIT_TIMEBACKUP:
1681 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1682 if (compare && !(*retcmpp))
1683 *retcmpp = NFSERR_ATTRNOTSUPP;
1684 attrsum += NFSX_V4TIME;
1686 case NFSATTRBIT_TIMECREATE:
1687 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1688 if (compare && !(*retcmpp))
1689 *retcmpp = NFSERR_ATTRNOTSUPP;
1690 attrsum += NFSX_V4TIME;
1692 case NFSATTRBIT_TIMEDELTA:
1693 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1697 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1698 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1699 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1700 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1703 *retcmpp = NFSERR_NOTSAME;
1706 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1709 attrsum += NFSX_V4TIME;
1711 case NFSATTRBIT_TIMEMETADATA:
1712 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1713 fxdr_nfsv4time(tl, &temptime);
1716 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1717 *retcmpp = NFSERR_NOTSAME;
1719 } else if (nap != NULL) {
1720 nap->na_ctime = temptime;
1722 attrsum += NFSX_V4TIME;
1724 case NFSATTRBIT_TIMEMODIFY:
1725 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1726 fxdr_nfsv4time(tl, &temptime);
1729 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1730 *retcmpp = NFSERR_NOTSAME;
1732 } else if (nap != NULL) {
1733 nap->na_mtime = temptime;
1735 attrsum += NFSX_V4TIME;
1737 case NFSATTRBIT_TIMEMODIFYSET:
1738 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1739 attrsum += NFSX_UNSIGNED;
1740 i = fxdr_unsigned(int, *tl);
1741 if (i == NFSV4SATTRTIME_TOCLIENT) {
1742 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1743 attrsum += NFSX_V4TIME;
1745 if (compare && !(*retcmpp))
1746 *retcmpp = NFSERR_INVAL;
1748 case NFSATTRBIT_MOUNTEDONFILEID:
1749 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1750 thyp = fxdr_hyper(tl);
1754 *retcmpp = NFSERR_NOTSAME;
1756 if (!vp || !nfsrv_atroot(vp, &fid))
1757 fid = nap->na_fileid;
1758 if ((u_int64_t)fid != thyp)
1759 *retcmpp = NFSERR_NOTSAME;
1762 } else if (nap != NULL) {
1764 count64mountfileid++;
1765 if (ratecheck(&last64mountfileid, &warninterval)) {
1766 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1767 count64mountfileid);
1768 count64mountfileid = 0;
1771 nap->na_mntonfileno = thyp;
1773 attrsum += NFSX_HYPER;
1775 case NFSATTRBIT_SUPPATTREXCLCREAT:
1777 error = nfsrv_getattrbits(nd, &retattrbits,
1781 if (compare && !(*retcmpp)) {
1782 NFSSETSUPP_ATTRBIT(&checkattrbits);
1783 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1784 NFSCLRBIT_ATTRBIT(&checkattrbits,
1785 NFSATTRBIT_TIMEACCESSSET);
1786 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1788 *retcmpp = NFSERR_NOTSAME;
1793 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1795 if (compare && !(*retcmpp))
1796 *retcmpp = NFSERR_ATTRNOTSUPP;
1798 * and get out of the loop, since we can't parse
1799 * the unknown attrbute data.
1801 bitpos = NFSATTRBIT_MAX;
1807 * some clients pad the attrlist, so we need to skip over the
1810 if (attrsum > attrsize) {
1811 error = NFSERR_BADXDR;
1813 attrsize = NFSM_RNDUP(attrsize);
1814 if (attrsum < attrsize)
1815 error = nfsm_advance(nd, attrsize - attrsum, -1);
1818 NFSEXITCODE2(error, nd);
1823 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1824 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1825 * The first argument is a pointer to an nfsv4lock structure.
1826 * The second argument is 1 iff a blocking lock is wanted.
1827 * If this argument is 0, the call waits until no thread either wants nor
1828 * holds an exclusive lock.
1829 * It returns 1 if the lock was acquired, 0 otherwise.
1830 * If several processes call this function concurrently wanting the exclusive
1831 * lock, one will get the lock and the rest will return without getting the
1832 * lock. (If the caller must have the lock, it simply calls this function in a
1833 * loop until the function returns 1 to indicate the lock was acquired.)
1834 * Any usecnt must be decremented by calling nfsv4_relref() before
1835 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1836 * be called in a loop.
1837 * The isleptp argument is set to indicate if the call slept, iff not NULL
1838 * and the mp argument indicates to check for a forced dismount, iff not
1842 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1843 void *mutex, struct mount *mp)
1849 * If a lock is wanted, loop around until the lock is acquired by
1850 * someone and then released. If I want the lock, try to acquire it.
1851 * For a lock to be issued, no lock must be in force and the usecnt
1855 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1856 lp->nfslock_usecnt == 0) {
1857 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1858 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1861 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1863 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1864 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1865 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1868 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1871 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1872 PZERO - 1, "nfsv4lck", NULL);
1873 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1874 lp->nfslock_usecnt == 0) {
1875 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1876 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1884 * Release the lock acquired by nfsv4_lock().
1885 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1886 * incremented, as well.
1889 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1892 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1894 lp->nfslock_usecnt++;
1899 * Release a reference cnt.
1902 nfsv4_relref(struct nfsv4lock *lp)
1905 if (lp->nfslock_usecnt <= 0)
1906 panic("nfsv4root ref cnt");
1907 lp->nfslock_usecnt--;
1908 if (lp->nfslock_usecnt == 0)
1913 * Get a reference cnt.
1914 * This function will wait for any exclusive lock to be released, but will
1915 * not wait for threads that want the exclusive lock. If priority needs
1916 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1917 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1918 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1919 * return without getting a refcnt for that case.
1922 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1930 * Wait for a lock held.
1932 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1933 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1935 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1938 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1939 PZERO - 1, "nfsv4gr", NULL);
1941 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1944 lp->nfslock_usecnt++;
1948 * Get a reference as above, but return failure instead of sleeping if
1949 * an exclusive lock is held.
1952 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1955 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1958 lp->nfslock_usecnt++;
1963 * Test for a lock. Return 1 if locked, 0 otherwise.
1966 nfsv4_testlock(struct nfsv4lock *lp)
1969 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1970 lp->nfslock_usecnt == 0)
1976 * Wake up anyone sleeping, waiting for this lock.
1979 nfsv4_wanted(struct nfsv4lock *lp)
1982 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1983 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1984 wakeup((caddr_t)&lp->nfslock_lock);
1989 * Copy a string from an mbuf list into a character array.
1990 * Return EBADRPC if there is an mbuf error,
1994 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2003 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2004 rem = NFSM_RNDUP(siz) - siz;
2010 NFSBCOPY(cp, str, xfer);
2019 cp = NFSMTOD(mp, caddr_t);
2031 error = nfsm_advance(nd, rem, len);
2037 NFSEXITCODE2(error, nd);
2042 * Fill in the attributes as marked by the bitmap (V4).
2045 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2046 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2047 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2048 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2050 int bitpos, retnum = 0;
2052 int siz, prefixnum, error;
2053 u_char *cp, namestr[NFSV4_SMALLSTR];
2054 nfsattrbit_t attrbits, retbits;
2055 nfsattrbit_t *retbitp = &retbits;
2056 u_int32_t freenum, *retnump;
2059 struct nfsfsinfo fsinf;
2060 struct timespec temptime;
2061 NFSACL_T *aclp, *naclp = NULL;
2068 * First, set the bits that can be filled and get fsinfo.
2070 NFSSET_ATTRBIT(retbitp, attrbitp);
2072 * If both p and cred are NULL, it is a client side setattr call.
2073 * If both p and cred are not NULL, it is a server side reply call.
2074 * If p is not NULL and cred is NULL, it is a client side callback
2077 if (p == NULL && cred == NULL) {
2078 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2081 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2082 naclp = acl_alloc(M_WAITOK);
2085 nfsvno_getfs(&fsinf, isdgram);
2088 * Get the VFS_STATFS(), since some attributes need them.
2090 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2091 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2092 error = VFS_STATFS(mp, fs);
2095 nd->nd_repstat = NFSERR_ACCES;
2099 NFSCLRSTATFS_ATTRBIT(retbitp);
2105 * And the NFSv4 ACL...
2107 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2108 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2109 supports_nfsv4acls == 0))) {
2110 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2112 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2113 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2114 supports_nfsv4acls == 0)) {
2115 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2116 } else if (naclp != NULL) {
2117 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2118 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2120 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2122 NFSVOPUNLOCK(vp, 0);
2124 error = NFSERR_PERM;
2127 nd->nd_repstat = NFSERR_ACCES;
2131 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2137 * Put out the attribute bitmap for the ones being filled in
2138 * and get the field for the number of attributes returned.
2140 prefixnum = nfsrv_putattrbit(nd, retbitp);
2141 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2142 prefixnum += NFSX_UNSIGNED;
2145 * Now, loop around filling in the attributes for each bit set.
2147 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2148 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2150 case NFSATTRBIT_SUPPORTEDATTRS:
2151 NFSSETSUPP_ATTRBIT(&attrbits);
2152 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2153 && supports_nfsv4acls == 0)) {
2154 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2155 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2157 retnum += nfsrv_putattrbit(nd, &attrbits);
2159 case NFSATTRBIT_TYPE:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2161 *tl = vtonfsv34_type(vap->va_type);
2162 retnum += NFSX_UNSIGNED;
2164 case NFSATTRBIT_FHEXPIRETYPE:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2166 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2167 retnum += NFSX_UNSIGNED;
2169 case NFSATTRBIT_CHANGE:
2170 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2171 txdr_hyper(vap->va_filerev, tl);
2172 retnum += NFSX_HYPER;
2174 case NFSATTRBIT_SIZE:
2175 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2176 txdr_hyper(vap->va_size, tl);
2177 retnum += NFSX_HYPER;
2179 case NFSATTRBIT_LINKSUPPORT:
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2181 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2185 retnum += NFSX_UNSIGNED;
2187 case NFSATTRBIT_SYMLINKSUPPORT:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2193 retnum += NFSX_UNSIGNED;
2195 case NFSATTRBIT_NAMEDATTR:
2196 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2198 retnum += NFSX_UNSIGNED;
2200 case NFSATTRBIT_FSID:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2203 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2205 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2206 retnum += NFSX_V4FSID;
2208 case NFSATTRBIT_UNIQUEHANDLES:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2211 retnum += NFSX_UNSIGNED;
2213 case NFSATTRBIT_LEASETIME:
2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2215 *tl = txdr_unsigned(nfsrv_lease);
2216 retnum += NFSX_UNSIGNED;
2218 case NFSATTRBIT_RDATTRERROR:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 *tl = txdr_unsigned(rderror);
2221 retnum += NFSX_UNSIGNED;
2224 * Recommended Attributes. (Only the supported ones.)
2226 case NFSATTRBIT_ACL:
2227 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2229 case NFSATTRBIT_ACLSUPPORT:
2230 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2231 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2232 retnum += NFSX_UNSIGNED;
2234 case NFSATTRBIT_CANSETTIME:
2235 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2236 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2240 retnum += NFSX_UNSIGNED;
2242 case NFSATTRBIT_CASEINSENSITIVE:
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2245 retnum += NFSX_UNSIGNED;
2247 case NFSATTRBIT_CASEPRESERVING:
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2250 retnum += NFSX_UNSIGNED;
2252 case NFSATTRBIT_CHOWNRESTRICTED:
2253 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2255 retnum += NFSX_UNSIGNED;
2257 case NFSATTRBIT_FILEHANDLE:
2258 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2260 case NFSATTRBIT_FILEID:
2261 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2263 *tl = txdr_unsigned(vap->va_fileid);
2264 retnum += NFSX_HYPER;
2266 case NFSATTRBIT_FILESAVAIL:
2268 * Check quota and use min(quota, f_ffree).
2270 freenum = fs->f_ffree;
2273 * ufs_quotactl() insists that the uid argument
2274 * equal p_ruid for non-root quota access, so
2275 * we'll just make sure that's the case.
2277 savuid = p->p_cred->p_ruid;
2278 p->p_cred->p_ruid = cred->cr_uid;
2279 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2280 cred->cr_uid, (caddr_t)&dqb))
2281 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2283 p->p_cred->p_ruid = savuid;
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2287 *tl = txdr_unsigned(freenum);
2288 retnum += NFSX_HYPER;
2290 case NFSATTRBIT_FILESFREE:
2291 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2293 *tl = txdr_unsigned(fs->f_ffree);
2294 retnum += NFSX_HYPER;
2296 case NFSATTRBIT_FILESTOTAL:
2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2299 *tl = txdr_unsigned(fs->f_files);
2300 retnum += NFSX_HYPER;
2302 case NFSATTRBIT_FSLOCATIONS:
2303 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2306 retnum += 2 * NFSX_UNSIGNED;
2308 case NFSATTRBIT_HOMOGENEOUS:
2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2310 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2314 retnum += NFSX_UNSIGNED;
2316 case NFSATTRBIT_MAXFILESIZE:
2317 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2318 uquad = NFSRV_MAXFILESIZE;
2319 txdr_hyper(uquad, tl);
2320 retnum += NFSX_HYPER;
2322 case NFSATTRBIT_MAXLINK:
2323 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2324 *tl = txdr_unsigned(LINK_MAX);
2325 retnum += NFSX_UNSIGNED;
2327 case NFSATTRBIT_MAXNAME:
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2329 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2330 retnum += NFSX_UNSIGNED;
2332 case NFSATTRBIT_MAXREAD:
2333 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2335 *tl = txdr_unsigned(fsinf.fs_rtmax);
2336 retnum += NFSX_HYPER;
2338 case NFSATTRBIT_MAXWRITE:
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2341 *tl = txdr_unsigned(fsinf.fs_wtmax);
2342 retnum += NFSX_HYPER;
2344 case NFSATTRBIT_MODE:
2345 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2346 *tl = vtonfsv34_mode(vap->va_mode);
2347 retnum += NFSX_UNSIGNED;
2349 case NFSATTRBIT_NOTRUNC:
2350 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2352 retnum += NFSX_UNSIGNED;
2354 case NFSATTRBIT_NUMLINKS:
2355 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2356 *tl = txdr_unsigned(vap->va_nlink);
2357 retnum += NFSX_UNSIGNED;
2359 case NFSATTRBIT_OWNER:
2361 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2362 retnum += nfsm_strtom(nd, cp, siz);
2364 free(cp, M_NFSSTRING);
2366 case NFSATTRBIT_OWNERGROUP:
2368 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2369 retnum += nfsm_strtom(nd, cp, siz);
2371 free(cp, M_NFSSTRING);
2373 case NFSATTRBIT_QUOTAHARD:
2374 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2375 freenum = fs->f_bfree;
2377 freenum = fs->f_bavail;
2380 * ufs_quotactl() insists that the uid argument
2381 * equal p_ruid for non-root quota access, so
2382 * we'll just make sure that's the case.
2384 savuid = p->p_cred->p_ruid;
2385 p->p_cred->p_ruid = cred->cr_uid;
2386 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2387 cred->cr_uid, (caddr_t)&dqb))
2388 freenum = min(dqb.dqb_bhardlimit, freenum);
2389 p->p_cred->p_ruid = savuid;
2391 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2392 uquad = (u_int64_t)freenum;
2393 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2394 txdr_hyper(uquad, tl);
2395 retnum += NFSX_HYPER;
2397 case NFSATTRBIT_QUOTASOFT:
2398 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2399 freenum = fs->f_bfree;
2401 freenum = fs->f_bavail;
2404 * ufs_quotactl() insists that the uid argument
2405 * equal p_ruid for non-root quota access, so
2406 * we'll just make sure that's the case.
2408 savuid = p->p_cred->p_ruid;
2409 p->p_cred->p_ruid = cred->cr_uid;
2410 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2411 cred->cr_uid, (caddr_t)&dqb))
2412 freenum = min(dqb.dqb_bsoftlimit, freenum);
2413 p->p_cred->p_ruid = savuid;
2415 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2416 uquad = (u_int64_t)freenum;
2417 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2418 txdr_hyper(uquad, tl);
2419 retnum += NFSX_HYPER;
2421 case NFSATTRBIT_QUOTAUSED:
2425 * ufs_quotactl() insists that the uid argument
2426 * equal p_ruid for non-root quota access, so
2427 * we'll just make sure that's the case.
2429 savuid = p->p_cred->p_ruid;
2430 p->p_cred->p_ruid = cred->cr_uid;
2431 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2432 cred->cr_uid, (caddr_t)&dqb))
2433 freenum = dqb.dqb_curblocks;
2434 p->p_cred->p_ruid = savuid;
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2437 uquad = (u_int64_t)freenum;
2438 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2439 txdr_hyper(uquad, tl);
2440 retnum += NFSX_HYPER;
2442 case NFSATTRBIT_RAWDEV:
2443 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2444 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2445 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2446 retnum += NFSX_V4SPECDATA;
2448 case NFSATTRBIT_SPACEAVAIL:
2449 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2450 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2451 uquad = (u_int64_t)fs->f_bfree;
2453 uquad = (u_int64_t)fs->f_bavail;
2454 uquad *= fs->f_bsize;
2455 txdr_hyper(uquad, tl);
2456 retnum += NFSX_HYPER;
2458 case NFSATTRBIT_SPACEFREE:
2459 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2460 uquad = (u_int64_t)fs->f_bfree;
2461 uquad *= fs->f_bsize;
2462 txdr_hyper(uquad, tl);
2463 retnum += NFSX_HYPER;
2465 case NFSATTRBIT_SPACETOTAL:
2466 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2467 uquad = (u_int64_t)fs->f_blocks;
2468 uquad *= fs->f_bsize;
2469 txdr_hyper(uquad, tl);
2470 retnum += NFSX_HYPER;
2472 case NFSATTRBIT_SPACEUSED:
2473 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2474 txdr_hyper(vap->va_bytes, tl);
2475 retnum += NFSX_HYPER;
2477 case NFSATTRBIT_TIMEACCESS:
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2479 txdr_nfsv4time(&vap->va_atime, tl);
2480 retnum += NFSX_V4TIME;
2482 case NFSATTRBIT_TIMEACCESSSET:
2483 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2484 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2485 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2486 txdr_nfsv4time(&vap->va_atime, tl);
2487 retnum += NFSX_V4SETTIME;
2489 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2490 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2491 retnum += NFSX_UNSIGNED;
2494 case NFSATTRBIT_TIMEDELTA:
2495 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2496 temptime.tv_sec = 0;
2497 temptime.tv_nsec = 1000000000 / hz;
2498 txdr_nfsv4time(&temptime, tl);
2499 retnum += NFSX_V4TIME;
2501 case NFSATTRBIT_TIMEMETADATA:
2502 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2503 txdr_nfsv4time(&vap->va_ctime, tl);
2504 retnum += NFSX_V4TIME;
2506 case NFSATTRBIT_TIMEMODIFY:
2507 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2508 txdr_nfsv4time(&vap->va_mtime, tl);
2509 retnum += NFSX_V4TIME;
2511 case NFSATTRBIT_TIMEMODIFYSET:
2512 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2513 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2514 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2515 txdr_nfsv4time(&vap->va_mtime, tl);
2516 retnum += NFSX_V4SETTIME;
2518 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2519 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2520 retnum += NFSX_UNSIGNED;
2523 case NFSATTRBIT_MOUNTEDONFILEID:
2524 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2526 uquad = mounted_on_fileno;
2528 uquad = (u_int64_t)vap->va_fileid;
2529 txdr_hyper(uquad, tl);
2530 retnum += NFSX_HYPER;
2532 case NFSATTRBIT_SUPPATTREXCLCREAT:
2533 NFSSETSUPP_ATTRBIT(&attrbits);
2534 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2535 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2536 retnum += nfsrv_putattrbit(nd, &attrbits);
2539 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2546 *retnump = txdr_unsigned(retnum);
2547 return (retnum + prefixnum);
2551 * Put the attribute bits onto an mbuf list.
2552 * Return the number of bytes of output generated.
2555 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2558 int cnt, i, bytesize;
2560 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2561 if (attrbitp->bits[cnt - 1])
2563 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2564 NFSM_BUILD(tl, u_int32_t *, bytesize);
2565 *tl++ = txdr_unsigned(cnt);
2566 for (i = 0; i < cnt; i++)
2567 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2572 * Convert a uid to a string.
2573 * If the lookup fails, just output the digits.
2575 * cpp - points to a buffer of size NFSV4_SMALLSTR
2576 * (malloc a larger one, as required)
2577 * retlenp - pointer to length to be returned
2580 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2583 struct nfsusrgrp *usrp;
2586 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2587 struct nfsrv_lughash *hp;
2591 if (nfsrv_dnsnamelen > 0) {
2593 * Always map nfsrv_defaultuid to "nobody".
2595 if (uid == nfsrv_defaultuid) {
2596 i = nfsrv_dnsnamelen + 7;
2598 if (len > NFSV4_SMALLSTR)
2599 free(cp, M_NFSSTRING);
2600 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2606 NFSBCOPY("nobody@", cp, 7);
2608 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2612 hp = NFSUSERHASH(uid);
2614 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2615 if (usrp->lug_uid == uid) {
2616 if (usrp->lug_expiry < NFSD_MONOSEC)
2619 * If the name doesn't already have an '@'
2620 * in it, append @domainname to it.
2622 for (i = 0; i < usrp->lug_namelen; i++) {
2623 if (usrp->lug_name[i] == '@') {
2629 i = usrp->lug_namelen;
2631 i = usrp->lug_namelen +
2632 nfsrv_dnsnamelen + 1;
2634 mtx_unlock(&hp->mtx);
2635 if (len > NFSV4_SMALLSTR)
2636 free(cp, M_NFSSTRING);
2637 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2643 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2644 if (!hasampersand) {
2645 cp += usrp->lug_namelen;
2647 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2649 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2650 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2652 mtx_unlock(&hp->mtx);
2656 mtx_unlock(&hp->mtx);
2658 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2660 if (ret == 0 && cnt < 2)
2665 * No match, just return a string of digits.
2669 while (tmp || i == 0) {
2673 len = (i > len) ? len : i;
2677 for (i = 0; i < len; i++) {
2678 *cp-- = '0' + (tmp % 10);
2685 * Get a credential for the uid with the server's group list.
2686 * If none is found, just return the credential passed in after
2687 * logging a warning message.
2690 nfsrv_getgrpscred(struct ucred *oldcred)
2692 struct nfsusrgrp *usrp;
2693 struct ucred *newcred;
2696 struct nfsrv_lughash *hp;
2699 uid = oldcred->cr_uid;
2701 if (nfsrv_dnsnamelen > 0) {
2702 hp = NFSUSERHASH(uid);
2704 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2705 if (usrp->lug_uid == uid) {
2706 if (usrp->lug_expiry < NFSD_MONOSEC)
2708 if (usrp->lug_cred != NULL) {
2709 newcred = crhold(usrp->lug_cred);
2713 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2714 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2716 mtx_unlock(&hp->mtx);
2720 mtx_unlock(&hp->mtx);
2722 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2724 if (ret == 0 && cnt < 2)
2731 * Convert a string to a uid.
2732 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2734 * If this is called from a client side mount using AUTH_SYS and the
2735 * string is made up entirely of digits, just convert the string to
2739 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2743 char *cp, *endstr, *str0;
2744 struct nfsusrgrp *usrp;
2748 struct nfsrv_lughash *hp, *hp2;
2751 error = NFSERR_BADOWNER;
2754 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2756 tuid = (uid_t)strtoul(str0, &endstr, 10);
2757 if ((endstr - str0) == len) {
2758 /* A numeric string. */
2759 if ((nd->nd_flag & ND_KERBV) == 0 &&
2760 ((nd->nd_flag & ND_NFSCL) != 0 ||
2761 nfsd_enable_stringtouid != 0))
2764 error = NFSERR_BADOWNER;
2770 cp = strchr(str0, '@');
2772 i = (int)(cp++ - str0);
2778 if (nfsrv_dnsnamelen > 0) {
2780 * If an '@' is found and the domain name matches, search for
2781 * the name with dns stripped off.
2782 * Mixed case alpahbetics will match for the domain name, but
2783 * all upper case will not.
2785 if (cnt == 0 && i < len && i > 0 &&
2786 (len - 1 - i) == nfsrv_dnsnamelen &&
2787 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2788 len -= (nfsrv_dnsnamelen + 1);
2793 * Check for the special case of "nobody".
2795 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2796 *uidp = nfsrv_defaultuid;
2801 hp = NFSUSERNAMEHASH(str, len);
2803 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2804 if (usrp->lug_namelen == len &&
2805 !NFSBCMP(usrp->lug_name, str, len)) {
2806 if (usrp->lug_expiry < NFSD_MONOSEC)
2808 hp2 = NFSUSERHASH(usrp->lug_uid);
2809 mtx_lock(&hp2->mtx);
2810 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2811 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2813 *uidp = usrp->lug_uid;
2814 mtx_unlock(&hp2->mtx);
2815 mtx_unlock(&hp->mtx);
2820 mtx_unlock(&hp->mtx);
2822 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2824 if (ret == 0 && cnt < 2)
2827 error = NFSERR_BADOWNER;
2835 * Convert a gid to a string.
2836 * gid - the group id
2837 * cpp - points to a buffer of size NFSV4_SMALLSTR
2838 * (malloc a larger one, as required)
2839 * retlenp - pointer to length to be returned
2842 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2845 struct nfsusrgrp *usrp;
2848 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2849 struct nfsrv_lughash *hp;
2853 if (nfsrv_dnsnamelen > 0) {
2855 * Always map nfsrv_defaultgid to "nogroup".
2857 if (gid == nfsrv_defaultgid) {
2858 i = nfsrv_dnsnamelen + 8;
2860 if (len > NFSV4_SMALLSTR)
2861 free(cp, M_NFSSTRING);
2862 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2868 NFSBCOPY("nogroup@", cp, 8);
2870 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2874 hp = NFSGROUPHASH(gid);
2876 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2877 if (usrp->lug_gid == gid) {
2878 if (usrp->lug_expiry < NFSD_MONOSEC)
2881 * If the name doesn't already have an '@'
2882 * in it, append @domainname to it.
2884 for (i = 0; i < usrp->lug_namelen; i++) {
2885 if (usrp->lug_name[i] == '@') {
2891 i = usrp->lug_namelen;
2893 i = usrp->lug_namelen +
2894 nfsrv_dnsnamelen + 1;
2896 mtx_unlock(&hp->mtx);
2897 if (len > NFSV4_SMALLSTR)
2898 free(cp, M_NFSSTRING);
2899 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2905 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2906 if (!hasampersand) {
2907 cp += usrp->lug_namelen;
2909 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2911 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2912 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2914 mtx_unlock(&hp->mtx);
2918 mtx_unlock(&hp->mtx);
2920 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2922 if (ret == 0 && cnt < 2)
2927 * No match, just return a string of digits.
2931 while (tmp || i == 0) {
2935 len = (i > len) ? len : i;
2939 for (i = 0; i < len; i++) {
2940 *cp-- = '0' + (tmp % 10);
2947 * Convert a string to a gid.
2948 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2950 * If this is called from a client side mount using AUTH_SYS and the
2951 * string is made up entirely of digits, just convert the string to
2955 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2959 char *cp, *endstr, *str0;
2960 struct nfsusrgrp *usrp;
2964 struct nfsrv_lughash *hp, *hp2;
2967 error = NFSERR_BADOWNER;
2970 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2972 tgid = (gid_t)strtoul(str0, &endstr, 10);
2973 if ((endstr - str0) == len) {
2974 /* A numeric string. */
2975 if ((nd->nd_flag & ND_KERBV) == 0 &&
2976 ((nd->nd_flag & ND_NFSCL) != 0 ||
2977 nfsd_enable_stringtouid != 0))
2980 error = NFSERR_BADOWNER;
2986 cp = strchr(str0, '@');
2988 i = (int)(cp++ - str0);
2994 if (nfsrv_dnsnamelen > 0) {
2996 * If an '@' is found and the dns name matches, search for the
2997 * name with the dns stripped off.
2999 if (cnt == 0 && i < len && i > 0 &&
3000 (len - 1 - i) == nfsrv_dnsnamelen &&
3001 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3002 len -= (nfsrv_dnsnamelen + 1);
3007 * Check for the special case of "nogroup".
3009 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3010 *gidp = nfsrv_defaultgid;
3015 hp = NFSGROUPNAMEHASH(str, len);
3017 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3018 if (usrp->lug_namelen == len &&
3019 !NFSBCMP(usrp->lug_name, str, len)) {
3020 if (usrp->lug_expiry < NFSD_MONOSEC)
3022 hp2 = NFSGROUPHASH(usrp->lug_gid);
3023 mtx_lock(&hp2->mtx);
3024 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3025 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3027 *gidp = usrp->lug_gid;
3028 mtx_unlock(&hp2->mtx);
3029 mtx_unlock(&hp->mtx);
3034 mtx_unlock(&hp->mtx);
3036 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3038 if (ret == 0 && cnt < 2)
3041 error = NFSERR_BADOWNER;
3049 * Cmp len chars, allowing mixed case in the first argument to match lower
3050 * case in the second, but not if the first argument is all upper case.
3051 * Return 0 for a match, 1 otherwise.
3054 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3060 for (i = 0; i < len; i++) {
3061 if (*cp >= 'A' && *cp <= 'Z') {
3062 tmp = *cp++ + ('a' - 'A');
3065 if (tmp >= 'a' && tmp <= 'z')
3078 * Set the port for the nfsuserd.
3081 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3083 struct nfssockreq *rp;
3084 struct sockaddr_in *ad;
3088 if (nfsrv_nfsuserd) {
3096 * Set up the socket record and connect.
3098 rp = &nfsrv_nfsuserdsock;
3099 rp->nr_client = NULL;
3100 rp->nr_sotype = SOCK_DGRAM;
3101 rp->nr_soproto = IPPROTO_UDP;
3102 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3104 NFSSOCKADDRALLOC(rp->nr_nam);
3105 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3106 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3107 ad->sin_family = AF_INET;
3108 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3109 ad->sin_port = port;
3110 rp->nr_prog = RPCPROG_NFSUSERD;
3111 rp->nr_vers = RPCNFSUSERD_VERS;
3112 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3114 NFSSOCKADDRFREE(rp->nr_nam);
3123 * Delete the nfsuserd port.
3126 nfsrv_nfsuserddelport(void)
3130 if (nfsrv_nfsuserd == 0) {
3136 newnfs_disconnect(&nfsrv_nfsuserdsock);
3137 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3141 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3143 * Returns 0 upon success, non-zero otherwise.
3146 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3149 struct nfsrv_descript *nd;
3151 struct nfsrv_descript nfsd;
3156 if (nfsrv_nfsuserd == 0) {
3163 cred = newnfs_getcred();
3164 nd->nd_flag = ND_GSSINITREPLY;
3167 nd->nd_procnum = procnum;
3168 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3170 if (procnum == RPCNFSUSERD_GETUID)
3171 *tl = txdr_unsigned(uid);
3173 *tl = txdr_unsigned(gid);
3176 (void) nfsm_strtom(nd, name, len);
3178 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3179 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3182 mbuf_freem(nd->nd_mrep);
3183 error = nd->nd_repstat;
3191 * This function is called from the nfssvc(2) system call, to update the
3192 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3195 nfssvc_idname(struct nfsd_idargs *nidp)
3197 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3198 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3199 int i, group_locked, groupname_locked, user_locked, username_locked;
3204 static int onethread = 0;
3205 static time_t lasttime = 0;
3207 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3211 if (nidp->nid_flag & NFSID_INITIALIZE) {
3212 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3213 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3216 free(cp, M_NFSSTRING);
3219 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3221 * Free up all the old stuff and reinitialize hash
3222 * lists. All mutexes for both lists must be locked,
3223 * with the user/group name ones before the uid/gid
3224 * ones, to avoid a LOR.
3226 for (i = 0; i < nfsrv_lughashsize; i++)
3227 mtx_lock(&nfsusernamehash[i].mtx);
3228 for (i = 0; i < nfsrv_lughashsize; i++)
3229 mtx_lock(&nfsuserhash[i].mtx);
3230 for (i = 0; i < nfsrv_lughashsize; i++)
3231 TAILQ_FOREACH_SAFE(usrp,
3232 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3233 nfsrv_removeuser(usrp, 1);
3234 for (i = 0; i < nfsrv_lughashsize; i++)
3235 mtx_unlock(&nfsuserhash[i].mtx);
3236 for (i = 0; i < nfsrv_lughashsize; i++)
3237 mtx_unlock(&nfsusernamehash[i].mtx);
3238 for (i = 0; i < nfsrv_lughashsize; i++)
3239 mtx_lock(&nfsgroupnamehash[i].mtx);
3240 for (i = 0; i < nfsrv_lughashsize; i++)
3241 mtx_lock(&nfsgrouphash[i].mtx);
3242 for (i = 0; i < nfsrv_lughashsize; i++)
3243 TAILQ_FOREACH_SAFE(usrp,
3244 &nfsgrouphash[i].lughead, lug_numhash,
3246 nfsrv_removeuser(usrp, 0);
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_unlock(&nfsgrouphash[i].mtx);
3249 for (i = 0; i < nfsrv_lughashsize; i++)
3250 mtx_unlock(&nfsgroupnamehash[i].mtx);
3251 free(nfsrv_dnsname, M_NFSSTRING);
3252 nfsrv_dnsname = NULL;
3254 if (nfsuserhash == NULL) {
3255 /* Allocate the hash tables. */
3256 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3257 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3259 for (i = 0; i < nfsrv_lughashsize; i++)
3260 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3261 NULL, MTX_DEF | MTX_DUPOK);
3262 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3263 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3265 for (i = 0; i < nfsrv_lughashsize; i++)
3266 mtx_init(&nfsusernamehash[i].mtx,
3267 "nfsusrhash", NULL, MTX_DEF |
3269 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3270 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3272 for (i = 0; i < nfsrv_lughashsize; i++)
3273 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3274 NULL, MTX_DEF | MTX_DUPOK);
3275 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3276 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3278 for (i = 0; i < nfsrv_lughashsize; i++)
3279 mtx_init(&nfsgroupnamehash[i].mtx,
3280 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3282 /* (Re)initialize the list heads. */
3283 for (i = 0; i < nfsrv_lughashsize; i++)
3284 TAILQ_INIT(&nfsuserhash[i].lughead);
3285 for (i = 0; i < nfsrv_lughashsize; i++)
3286 TAILQ_INIT(&nfsusernamehash[i].lughead);
3287 for (i = 0; i < nfsrv_lughashsize; i++)
3288 TAILQ_INIT(&nfsgrouphash[i].lughead);
3289 for (i = 0; i < nfsrv_lughashsize; i++)
3290 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3293 * Put name in "DNS" string.
3296 nfsrv_defaultuid = nidp->nid_uid;
3297 nfsrv_defaultgid = nidp->nid_gid;
3299 nfsrv_usermax = nidp->nid_usermax;
3300 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3305 * malloc the new one now, so any potential sleep occurs before
3306 * manipulation of the lists.
3308 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3309 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3310 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3312 if (error == 0 && nidp->nid_ngroup > 0 &&
3313 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3314 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3316 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3317 sizeof(gid_t) * nidp->nid_ngroup);
3320 * Create a credential just like svc_getcred(),
3321 * but using the group list provided.
3324 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3325 crsetgroups(cr, nidp->nid_ngroup, grps);
3326 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3327 cr->cr_prison = &prison0;
3328 prison_hold(cr->cr_prison);
3330 mac_cred_associate_nfsd(cr);
3332 newusrp->lug_cred = cr;
3337 free(newusrp, M_NFSUSERGROUP);
3340 newusrp->lug_namelen = nidp->nid_namelen;
3343 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3344 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3345 * The flags user_locked, username_locked, group_locked and
3346 * groupname_locked are set to indicate all of those hash lists are
3347 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3348 * the respective one mutex is locked.
3350 user_locked = username_locked = group_locked = groupname_locked = 0;
3351 hp_name = hp_idnum = NULL;
3354 * Delete old entries, as required.
3356 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3357 /* Must lock all username hash lists first, to avoid a LOR. */
3358 for (i = 0; i < nfsrv_lughashsize; i++)
3359 mtx_lock(&nfsusernamehash[i].mtx);
3360 username_locked = 1;
3361 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3362 mtx_lock(&hp_idnum->mtx);
3363 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3365 if (usrp->lug_uid == nidp->nid_uid)
3366 nfsrv_removeuser(usrp, 1);
3368 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3369 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3370 newusrp->lug_namelen);
3371 mtx_lock(&hp_name->mtx);
3372 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3374 if (usrp->lug_namelen == newusrp->lug_namelen &&
3375 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3376 usrp->lug_namelen)) {
3377 thp = NFSUSERHASH(usrp->lug_uid);
3378 mtx_lock(&thp->mtx);
3379 nfsrv_removeuser(usrp, 1);
3380 mtx_unlock(&thp->mtx);
3383 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3384 mtx_lock(&hp_idnum->mtx);
3385 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3386 /* Must lock all groupname hash lists first, to avoid a LOR. */
3387 for (i = 0; i < nfsrv_lughashsize; i++)
3388 mtx_lock(&nfsgroupnamehash[i].mtx);
3389 groupname_locked = 1;
3390 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3391 mtx_lock(&hp_idnum->mtx);
3392 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3394 if (usrp->lug_gid == nidp->nid_gid)
3395 nfsrv_removeuser(usrp, 0);
3397 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3398 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3399 newusrp->lug_namelen);
3400 mtx_lock(&hp_name->mtx);
3401 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3403 if (usrp->lug_namelen == newusrp->lug_namelen &&
3404 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3405 usrp->lug_namelen)) {
3406 thp = NFSGROUPHASH(usrp->lug_gid);
3407 mtx_lock(&thp->mtx);
3408 nfsrv_removeuser(usrp, 0);
3409 mtx_unlock(&thp->mtx);
3412 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3413 mtx_lock(&hp_idnum->mtx);
3417 * Now, we can add the new one.
3419 if (nidp->nid_usertimeout)
3420 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3422 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3423 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3424 newusrp->lug_uid = nidp->nid_uid;
3425 thp = NFSUSERHASH(newusrp->lug_uid);
3426 mtx_assert(&thp->mtx, MA_OWNED);
3427 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3428 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3429 mtx_assert(&thp->mtx, MA_OWNED);
3430 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3431 atomic_add_int(&nfsrv_usercnt, 1);
3432 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3433 newusrp->lug_gid = nidp->nid_gid;
3434 thp = NFSGROUPHASH(newusrp->lug_gid);
3435 mtx_assert(&thp->mtx, MA_OWNED);
3436 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3437 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3438 mtx_assert(&thp->mtx, MA_OWNED);
3439 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3440 atomic_add_int(&nfsrv_usercnt, 1);
3442 if (newusrp->lug_cred != NULL)
3443 crfree(newusrp->lug_cred);
3444 free(newusrp, M_NFSUSERGROUP);
3448 * Once per second, allow one thread to trim the cache.
3450 if (lasttime < NFSD_MONOSEC &&
3451 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3453 * First, unlock the single mutexes, so that all entries
3454 * can be locked and any LOR is avoided.
3456 if (hp_name != NULL) {
3457 mtx_unlock(&hp_name->mtx);
3460 if (hp_idnum != NULL) {
3461 mtx_unlock(&hp_idnum->mtx);
3465 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3466 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3467 if (username_locked == 0) {
3468 for (i = 0; i < nfsrv_lughashsize; i++)
3469 mtx_lock(&nfsusernamehash[i].mtx);
3470 username_locked = 1;
3472 KASSERT(user_locked == 0,
3473 ("nfssvc_idname: user_locked"));
3474 for (i = 0; i < nfsrv_lughashsize; i++)
3475 mtx_lock(&nfsuserhash[i].mtx);
3477 for (i = 0; i < nfsrv_lughashsize; i++) {
3478 TAILQ_FOREACH_SAFE(usrp,
3479 &nfsuserhash[i].lughead, lug_numhash,
3481 if (usrp->lug_expiry < NFSD_MONOSEC)
3482 nfsrv_removeuser(usrp, 1);
3484 for (i = 0; i < nfsrv_lughashsize; i++) {
3486 * Trim the cache using an approximate LRU
3487 * algorithm. This code deletes the least
3488 * recently used entry on each hash list.
3490 if (nfsrv_usercnt <= nfsrv_usermax)
3492 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3494 nfsrv_removeuser(usrp, 1);
3497 if (groupname_locked == 0) {
3498 for (i = 0; i < nfsrv_lughashsize; i++)
3499 mtx_lock(&nfsgroupnamehash[i].mtx);
3500 groupname_locked = 1;
3502 KASSERT(group_locked == 0,
3503 ("nfssvc_idname: group_locked"));
3504 for (i = 0; i < nfsrv_lughashsize; i++)
3505 mtx_lock(&nfsgrouphash[i].mtx);
3507 for (i = 0; i < nfsrv_lughashsize; i++) {
3508 TAILQ_FOREACH_SAFE(usrp,
3509 &nfsgrouphash[i].lughead, lug_numhash,
3511 if (usrp->lug_expiry < NFSD_MONOSEC)
3512 nfsrv_removeuser(usrp, 0);
3514 for (i = 0; i < nfsrv_lughashsize; i++) {
3516 * Trim the cache using an approximate LRU
3517 * algorithm. This code deletes the least
3518 * recently user entry on each hash list.
3520 if (nfsrv_usercnt <= nfsrv_usermax)
3522 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3524 nfsrv_removeuser(usrp, 0);
3527 lasttime = NFSD_MONOSEC;
3528 atomic_store_rel_int(&onethread, 0);
3531 /* Now, unlock all locked mutexes. */
3532 if (hp_idnum != NULL)
3533 mtx_unlock(&hp_idnum->mtx);
3534 if (hp_name != NULL)
3535 mtx_unlock(&hp_name->mtx);
3536 if (user_locked != 0)
3537 for (i = 0; i < nfsrv_lughashsize; i++)
3538 mtx_unlock(&nfsuserhash[i].mtx);
3539 if (username_locked != 0)
3540 for (i = 0; i < nfsrv_lughashsize; i++)
3541 mtx_unlock(&nfsusernamehash[i].mtx);
3542 if (group_locked != 0)
3543 for (i = 0; i < nfsrv_lughashsize; i++)
3544 mtx_unlock(&nfsgrouphash[i].mtx);
3545 if (groupname_locked != 0)
3546 for (i = 0; i < nfsrv_lughashsize; i++)
3547 mtx_unlock(&nfsgroupnamehash[i].mtx);
3554 * Remove a user/group name element.
3557 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3559 struct nfsrv_lughash *hp;
3562 hp = NFSUSERHASH(usrp->lug_uid);
3563 mtx_assert(&hp->mtx, MA_OWNED);
3564 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3565 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3566 mtx_assert(&hp->mtx, MA_OWNED);
3567 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3569 hp = NFSGROUPHASH(usrp->lug_gid);
3570 mtx_assert(&hp->mtx, MA_OWNED);
3571 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3572 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3573 mtx_assert(&hp->mtx, MA_OWNED);
3574 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3576 atomic_add_int(&nfsrv_usercnt, -1);
3577 if (usrp->lug_cred != NULL)
3578 crfree(usrp->lug_cred);
3579 free(usrp, M_NFSUSERGROUP);
3583 * Free up all the allocations related to the name<-->id cache.
3584 * This function should only be called when the nfsuserd daemon isn't
3585 * running, since it doesn't do any locking.
3586 * This function is meant to be used when the nfscommon module is unloaded.
3589 nfsrv_cleanusergroup(void)
3591 struct nfsrv_lughash *hp, *hp2;
3592 struct nfsusrgrp *nusrp, *usrp;
3595 if (nfsuserhash == NULL)
3598 for (i = 0; i < nfsrv_lughashsize; i++) {
3599 hp = &nfsuserhash[i];
3600 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3601 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3602 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3604 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3605 if (usrp->lug_cred != NULL)
3606 crfree(usrp->lug_cred);
3607 free(usrp, M_NFSUSERGROUP);
3609 hp = &nfsgrouphash[i];
3610 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3611 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3612 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3614 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3615 if (usrp->lug_cred != NULL)
3616 crfree(usrp->lug_cred);
3617 free(usrp, M_NFSUSERGROUP);
3619 mtx_destroy(&nfsuserhash[i].mtx);
3620 mtx_destroy(&nfsusernamehash[i].mtx);
3621 mtx_destroy(&nfsgroupnamehash[i].mtx);
3622 mtx_destroy(&nfsgrouphash[i].mtx);
3624 free(nfsuserhash, M_NFSUSERGROUP);
3625 free(nfsusernamehash, M_NFSUSERGROUP);
3626 free(nfsgrouphash, M_NFSUSERGROUP);
3627 free(nfsgroupnamehash, M_NFSUSERGROUP);
3628 free(nfsrv_dnsname, M_NFSSTRING);
3632 * This function scans a byte string and checks for UTF-8 compliance.
3633 * It returns 0 if it conforms and NFSERR_INVAL if not.
3636 nfsrv_checkutf8(u_int8_t *cp, int len)
3638 u_int32_t val = 0x0;
3639 int cnt = 0, gotd = 0, shift = 0;
3641 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3645 * Here are what the variables are used for:
3646 * val - the calculated value of a multibyte char, used to check
3647 * that it was coded with the correct range
3648 * cnt - the number of 10xxxxxx bytes to follow
3649 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3650 * shift - lower order bits of range (ie. "val >> shift" should
3651 * not be 0, in other words, dividing by the lower bound
3652 * of the range should get a non-zero value)
3653 * byte - used to calculate cnt
3657 /* This handles the 10xxxxxx bytes */
3658 if ((*cp & 0xc0) != 0x80 ||
3659 (gotd && (*cp & 0x20))) {
3660 error = NFSERR_INVAL;
3665 val |= (*cp & 0x3f);
3667 if (cnt == 0 && (val >> shift) == 0x0) {
3668 error = NFSERR_INVAL;
3671 } else if (*cp & 0x80) {
3672 /* first byte of multi byte char */
3674 while ((byte & 0x40) && cnt < 6) {
3678 if (cnt == 0 || cnt == 6) {
3679 error = NFSERR_INVAL;
3682 val = (*cp & (0x3f >> cnt));
3683 shift = utf8_shift[cnt - 1];
3684 if (cnt == 2 && val == 0xd)
3685 /* Check for the 0xd800-0xdfff case */
3692 error = NFSERR_INVAL;
3700 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3701 * strings, one with the root path in it and the other with the list of
3702 * locations. The list is in the same format as is found in nfr_refs.
3703 * It is a "," separated list of entries, where each of them is of the
3704 * form <server>:<rootpath>. For example
3705 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3706 * The nilp argument is set to 1 for the special case of a null fs_root
3707 * and an empty server list.
3708 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3709 * number of xdr bytes parsed in sump.
3712 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3713 int *sump, int *nilp)
3716 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3717 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3719 SLIST_ENTRY(list) next;
3723 SLIST_HEAD(, list) head;
3730 * Get the fs_root path and check for the special case of null path
3731 * and 0 length server list.
3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3734 len = fxdr_unsigned(int, *tl);
3735 if (len < 0 || len > 10240) {
3736 error = NFSERR_BADXDR;
3740 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3742 error = NFSERR_BADXDR;
3746 *sump = 2 * NFSX_UNSIGNED;
3750 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3751 error = nfsrv_mtostr(nd, cp, len);
3753 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3754 cnt = fxdr_unsigned(int, *tl);
3756 error = NFSERR_BADXDR;
3762 * Now, loop through the location list and make up the srvlist.
3764 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3765 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3768 for (i = 0; i < cnt; i++) {
3770 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3771 nsrv = fxdr_unsigned(int, *tl);
3773 error = NFSERR_BADXDR;
3778 * Handle the first server by putting it in the srvstr.
3780 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3781 len = fxdr_unsigned(int, *tl);
3782 if (len <= 0 || len > 1024) {
3783 error = NFSERR_BADXDR;
3786 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3791 error = nfsrv_mtostr(nd, cp3, len);
3797 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3798 for (j = 1; j < nsrv; j++) {
3800 * Yuck, put them in an slist and process them later.
3802 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3803 len = fxdr_unsigned(int, *tl);
3804 if (len <= 0 || len > 1024) {
3805 error = NFSERR_BADXDR;
3808 lsp = (struct list *)malloc(sizeof (struct list)
3809 + len, M_TEMP, M_WAITOK);
3810 error = nfsrv_mtostr(nd, lsp->host, len);
3813 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3815 SLIST_INSERT_HEAD(&head, lsp, next);
3819 * Finally, we can get the path.
3821 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3822 len = fxdr_unsigned(int, *tl);
3823 if (len <= 0 || len > 1024) {
3824 error = NFSERR_BADXDR;
3827 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3828 error = nfsrv_mtostr(nd, cp3, len);
3831 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3836 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3837 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3840 NFSBCOPY(lsp->host, cp3, lsp->len);
3843 NFSBCOPY(str, cp3, stringlen);
3846 siz += (lsp->len + stringlen + 2);
3847 free((caddr_t)lsp, M_TEMP);
3853 NFSEXITCODE2(0, nd);
3857 free(cp, M_NFSSTRING);
3859 free(cp2, M_NFSSTRING);
3860 NFSEXITCODE2(error, nd);
3865 * Make the malloc'd space large enough. This is a pain, but the xdr
3866 * doesn't set an upper bound on the side, so...
3869 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3876 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3877 NFSBCOPY(*cpp, cp, *slenp);
3878 free(*cpp, M_NFSSTRING);
3882 *slenp = siz + 1024;
3886 * Initialize the reply header data structures.
3889 nfsrvd_rephead(struct nfsrv_descript *nd)
3894 * If this is a big reply, use a cluster.
3896 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3897 nfs_bigreply[nd->nd_procnum]) {
3898 NFSMCLGET(mreq, M_WAITOK);
3906 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3907 mbuf_setlen(mreq, 0);
3909 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3910 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3914 * Lock a socket against others.
3915 * Currently used to serialize connect/disconnect attempts.
3918 newnfs_sndlock(int *flagp)
3923 while (*flagp & NFSR_SNDLOCK) {
3924 *flagp |= NFSR_WANTSND;
3927 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3928 PZERO - 1, "nfsndlck", &ts);
3930 *flagp |= NFSR_SNDLOCK;
3936 * Unlock the stream socket for others.
3939 newnfs_sndunlock(int *flagp)
3943 if ((*flagp & NFSR_SNDLOCK) == 0)
3944 panic("nfs sndunlock");
3945 *flagp &= ~NFSR_SNDLOCK;
3946 if (*flagp & NFSR_WANTSND) {
3947 *flagp &= ~NFSR_WANTSND;
3948 wakeup((caddr_t)flagp);
3954 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3957 struct sockaddr_in *sad;
3958 struct sockaddr_in6 *sad6;
3959 struct in_addr saddr;
3960 uint32_t portnum, *tl;
3961 int af = 0, i, j, k;
3962 char addr[64], protocol[5], *cp;
3963 int cantparse = 0, error = 0;
3966 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3967 i = fxdr_unsigned(int, *tl);
3968 if (i >= 3 && i <= 4) {
3969 error = nfsrv_mtostr(nd, protocol, i);
3972 if (strcmp(protocol, "tcp") == 0) {
3975 } else if (strcmp(protocol, "udp") == 0) {
3978 } else if (strcmp(protocol, "tcp6") == 0) {
3981 } else if (strcmp(protocol, "udp6") == 0) {
3989 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3994 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3995 i = fxdr_unsigned(int, *tl);
3997 error = NFSERR_BADXDR;
3999 } else if (cantparse == 0 && i >= 11 && i < 64) {
4001 * The shortest address is 11chars and the longest is < 64.
4003 error = nfsrv_mtostr(nd, addr, i);
4007 /* Find the port# at the end and extract that. */
4011 /* Count back two '.'s from end to get port# field. */
4012 for (j = 0; j < i; j++) {
4022 * The NFSv4 port# is appended as .N.N, where N is
4023 * a decimal # in the range 0-255, just like an inet4
4024 * address. Cheat and use inet_aton(), which will
4025 * return a Class A address and then shift the high
4026 * order 8bits over to convert it to the port#.
4029 if (inet_aton(cp, &saddr) == 1) {
4030 portnum = ntohl(saddr.s_addr);
4031 portv = (uint16_t)((portnum >> 16) |
4037 if (cantparse == 0) {
4038 if (af == AF_INET) {
4039 sad = (struct sockaddr_in *)sa;
4040 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4041 sad->sin_len = sizeof(*sad);
4042 sad->sin_family = AF_INET;
4043 sad->sin_port = htons(portv);
4047 sad6 = (struct sockaddr_in6 *)sa;
4048 if (inet_pton(af, addr, &sad6->sin6_addr)
4050 sad6->sin6_len = sizeof(*sad6);
4051 sad6->sin6_family = AF_INET6;
4052 sad6->sin6_port = htons(portv);
4059 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4070 * Handle an NFSv4.1 Sequence request for the session.
4071 * If reply != NULL, use it to return the cached reply, as required.
4072 * The client gets a cached reply via this call for callbacks, however the
4073 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4076 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4077 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4084 if (slotid > maxslot)
4085 return (NFSERR_BADSLOT);
4086 if (seqid == slots[slotid].nfssl_seq) {
4088 if (slots[slotid].nfssl_inprog != 0)
4089 error = NFSERR_DELAY;
4090 else if (slots[slotid].nfssl_reply != NULL) {
4091 if (reply != NULL) {
4092 *reply = slots[slotid].nfssl_reply;
4093 slots[slotid].nfssl_reply = NULL;
4095 slots[slotid].nfssl_inprog = 1;
4096 error = NFSERR_REPLYFROMCACHE;
4098 /* No reply cached, so just do it. */
4099 slots[slotid].nfssl_inprog = 1;
4100 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4101 if (slots[slotid].nfssl_reply != NULL)
4102 m_freem(slots[slotid].nfssl_reply);
4103 slots[slotid].nfssl_reply = NULL;
4104 slots[slotid].nfssl_inprog = 1;
4105 slots[slotid].nfssl_seq++;
4107 error = NFSERR_SEQMISORDERED;
4112 * Cache this reply for the slot.
4113 * Use the "rep" argument to return the cached reply if repstat is set to
4114 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4117 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4121 if (repstat == NFSERR_REPLYFROMCACHE) {
4122 *rep = slots[slotid].nfssl_reply;
4123 slots[slotid].nfssl_reply = NULL;
4125 if (slots[slotid].nfssl_reply != NULL)
4126 m_freem(slots[slotid].nfssl_reply);
4127 slots[slotid].nfssl_reply = *rep;
4129 slots[slotid].nfssl_inprog = 0;
4133 * Generate the xdr for an NFSv4.1 Sequence Operation.
4136 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4137 struct nfsclsession *sep, int dont_replycache)
4139 uint32_t *tl, slotseq = 0;
4140 int error, maxslot, slotpos;
4141 uint8_t sessionid[NFSX_V4SESSIONID];
4143 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4146 /* Build the Sequence arguments. */
4147 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4148 nd->nd_sequence = tl;
4149 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4150 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4151 nd->nd_slotseq = tl;
4153 *tl++ = txdr_unsigned(slotseq);
4154 *tl++ = txdr_unsigned(slotpos);
4155 *tl++ = txdr_unsigned(maxslot);
4156 if (dont_replycache == 0)
4162 * There are two errors and the rest of the session can
4164 * NFSERR_BADSESSION: This bad session should just generate
4165 * the same error again when the RPC is retried.
4166 * ESTALE: A forced dismount is in progress and will cause the
4167 * RPC to fail later.
4174 nd->nd_flag |= ND_HASSEQUENCE;
4178 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4179 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4181 int i, maxslot, slotpos;
4184 /* Find an unused slot. */
4187 mtx_lock(&sep->nfsess_mtx);
4189 if (nmp != NULL && sep->nfsess_defunct != 0) {
4190 /* Just return the bad session. */
4191 bcopy(sep->nfsess_sessionid, sessionid,
4193 mtx_unlock(&sep->nfsess_mtx);
4194 return (NFSERR_BADSESSION);
4197 for (i = 0; i < sep->nfsess_foreslots; i++) {
4198 if ((bitval & sep->nfsess_slots) == 0) {
4200 sep->nfsess_slots |= bitval;
4201 sep->nfsess_slotseq[i]++;
4202 *slotseqp = sep->nfsess_slotseq[i];
4207 if (slotpos == -1) {
4209 * If a forced dismount is in progress, just return.
4210 * This RPC attempt will fail when it calls
4214 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4216 mtx_unlock(&sep->nfsess_mtx);
4219 /* Wake up once/sec, to check for a forced dismount. */
4220 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4221 PZERO, "nfsclseq", hz);
4223 } while (slotpos == -1);
4224 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4226 for (i = 0; i < 64; i++) {
4227 if ((bitval & sep->nfsess_slots) != 0)
4231 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4232 mtx_unlock(&sep->nfsess_mtx);
4233 *slotposp = slotpos;
4234 *maxslotp = maxslot;
4239 * Free a session slot.
4242 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4249 mtx_lock(&sep->nfsess_mtx);
4250 if ((bitval & sep->nfsess_slots) == 0)
4251 printf("freeing free slot!!\n");
4252 sep->nfsess_slots &= ~bitval;
4253 wakeup(&sep->nfsess_slots);
4254 mtx_unlock(&sep->nfsess_mtx);