2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid = 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;
71 static int nfs_enable_uidtostring = 0;
72 static int nfs_suppress_32bits_warning = 0;
75 extern int nfsrv_lughashsize;
77 SYSCTL_DECL(_vfs_nfs);
78 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
79 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
80 SYSCTL_INT(_vfs_nfs, OID_AUTO, suppress_32bits_warning, CTLFLAG_RW,
81 &nfs_suppress_32bits_warning, 0, "Suppress \"> 32 bits\" warnings");
84 * This array of structures indicates, for V4:
85 * retfh - which of 3 types of calling args are used
86 * 0 - doesn't change cfh or use a sfh
87 * 1 - replaces cfh with a new one (unless it returns an error status)
88 * 2 - uses cfh and sfh
89 * needscfh - if the op wants a cfh and premtime
90 * 0 - doesn't use a cfh
91 * 1 - uses a cfh, but doesn't want pre-op attributes
92 * 2 - uses a cfh and wants pre-op attributes
93 * savereply - indicates a non-idempotent Op
94 * 0 - not non-idempotent
96 * Ops that are ordered via seqid# are handled separately from these
98 * Define it here, since it is used by both the client and server.
100 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
101 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
102 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
103 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
104 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
106 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
107 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
108 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
109 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
110 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
112 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
115 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
116 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
117 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
118 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
119 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
120 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
123 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
124 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
125 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
126 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
127 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
128 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
129 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
130 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
134 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
135 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
138 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
139 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
152 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
161 #endif /* !APPLEKEXT */
163 static int ncl_mbuf_mhlen = MHLEN;
164 static int nfsrv_usercnt = 0;
165 static int nfsrv_dnsnamelen;
166 static u_char *nfsrv_dnsname = NULL;
167 static int nfsrv_usermax = 999999999;
168 struct nfsrv_lughash {
170 struct nfsuserhashhead lughead;
172 static struct nfsrv_lughash *nfsuserhash;
173 static struct nfsrv_lughash *nfsusernamehash;
174 static struct nfsrv_lughash *nfsgrouphash;
175 static struct nfsrv_lughash *nfsgroupnamehash;
178 * This static array indicates whether or not the RPC generates a large
179 * reply. This is used by nfs_reply() to decide whether or not an mbuf
180 * cluster should be allocated. (If a cluster is required by an RPC
181 * marked 0 in this array, the code will still work, just not quite as
184 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
185 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,
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
188 /* local functions */
189 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
190 static void nfsv4_wanted(struct nfsv4lock *lp);
191 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
192 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
194 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
195 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
197 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
202 * copies mbuf chain to the uio scatter/gather list
205 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
207 char *mbufcp, *uiocp;
214 mbufcp = nd->nd_dpos;
215 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
216 rem = NFSM_RNDUP(siz) - siz;
218 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
222 left = uiop->uio_iov->iov_len;
223 uiocp = uiop->uio_iov->iov_base;
234 mbufcp = NFSMTOD(mp, caddr_t);
237 ("len %d, corrupted mbuf?", len));
239 xfer = (left > len) ? len : left;
242 if (uiop->uio_iov->iov_op != NULL)
243 (*(uiop->uio_iov->iov_op))
244 (mbufcp, uiocp, xfer);
247 if (uiop->uio_segflg == UIO_SYSSPACE)
248 NFSBCOPY(mbufcp, uiocp, xfer);
250 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
255 uiop->uio_offset += xfer;
256 uiop->uio_resid -= xfer;
258 if (uiop->uio_iov->iov_len <= siz) {
262 uiop->uio_iov->iov_base = (void *)
263 ((char *)uiop->uio_iov->iov_base + uiosiz);
264 uiop->uio_iov->iov_len -= uiosiz;
268 nd->nd_dpos = mbufcp;
272 error = nfsm_advance(nd, rem, len);
278 NFSEXITCODE2(error, nd);
284 * Help break down an mbuf chain by setting the first siz bytes contiguous
285 * pointed to by returned val.
286 * This is used by the macro NFSM_DISSECT for tough
290 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
299 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
301 nd->nd_md = mbuf_next(nd->nd_md);
302 if (nd->nd_md == NULL)
304 left = mbuf_len(nd->nd_md);
305 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
310 } else if (mbuf_next(nd->nd_md) == NULL) {
312 } else if (siz > ncl_mbuf_mhlen) {
313 panic("nfs S too big");
315 MGET(mp2, MT_DATA, how);
318 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
319 mbuf_setnext(nd->nd_md, mp2);
320 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
322 retp = p = NFSMTOD(mp2, caddr_t);
323 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
326 mp2 = mbuf_next(mp2);
327 /* Loop around copying up the siz2 bytes */
331 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
333 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
334 NFSM_DATAP(mp2, xfer);
335 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
340 mp2 = mbuf_next(mp2);
342 mbuf_setlen(nd->nd_md, siz);
344 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
350 * Advance the position in the mbuf chain.
351 * If offs == 0, this is a no-op, but it is simpler to just return from
352 * here than check for offs > 0 for all calls to nfsm_advance.
353 * If left == -1, it should be calculated here.
356 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
363 * A negative offs should be considered a serious problem.
366 panic("nfsrv_advance");
369 * If left == -1, calculate it here.
372 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
376 * Loop around, advancing over the mbuf data.
378 while (offs > left) {
380 nd->nd_md = mbuf_next(nd->nd_md);
381 if (nd->nd_md == NULL) {
385 left = mbuf_len(nd->nd_md);
386 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
396 * Copy a string into mbuf(s).
397 * Return the number of bytes output, including XDR overheads.
400 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
409 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
410 *tl = txdr_unsigned(siz);
411 rem = NFSM_RNDUP(siz) - siz;
412 bytesize = NFSX_UNSIGNED + siz + rem;
415 left = M_TRAILINGSPACE(m2);
418 * Loop around copying the string to mbuf(s).
422 if (siz > ncl_mbuf_mlen)
423 NFSMCLGET(m1, M_WAITOK);
427 mbuf_setnext(m2, m1);
429 cp2 = NFSMTOD(m2, caddr_t);
430 left = M_TRAILINGSPACE(m2);
436 NFSBCOPY(cp, cp2, xfer);
438 mbuf_setlen(m2, mbuf_len(m2) + xfer);
441 if (siz == 0 && rem) {
443 panic("nfsm_strtom");
444 NFSBZERO(cp2 + xfer, rem);
445 mbuf_setlen(m2, mbuf_len(m2) + rem);
449 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
454 * Called once to initialize data structures...
459 static int nfs_inited = 0;
465 newnfs_true = txdr_unsigned(TRUE);
466 newnfs_false = txdr_unsigned(FALSE);
467 newnfs_xdrneg1 = txdr_unsigned(-1);
468 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
471 NFSSETBOOTTIME(nfsboottime);
474 * Initialize reply list and start timer
476 TAILQ_INIT(&nfsd_reqq);
481 * Put a file handle in an mbuf list.
482 * If the size argument == 0, just use the default size.
483 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
484 * Return the number of bytes output, including XDR overhead.
487 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
491 int fullsiz, rem, bytesize = 0;
495 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
497 if (size > NFSX_V2FH)
498 panic("fh size > NFSX_V2FH for NFSv2");
499 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
500 NFSBCOPY(fhp, cp, size);
501 if (size < NFSX_V2FH)
502 NFSBZERO(cp + size, NFSX_V2FH - size);
503 bytesize = NFSX_V2FH;
507 fullsiz = NFSM_RNDUP(size);
508 rem = fullsiz - size;
510 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
511 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
514 bytesize = NFSX_UNSIGNED + fullsiz;
516 (void) nfsm_strtom(nd, fhp, size);
523 * This function compares two net addresses by family and returns TRUE
524 * if they are the same host.
525 * If there is any doubt, return FALSE.
526 * The AF_INET family is handled as a special case so that address mbufs
527 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
530 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
532 struct sockaddr_in *inetaddr;
536 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
537 if (inetaddr->sin_family == AF_INET &&
538 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
544 struct sockaddr_in6 *inetaddr6;
546 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
547 /* XXX - should test sin6_scope_id ? */
548 if (inetaddr6->sin6_family == AF_INET6 &&
549 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
560 * Similar to the above, but takes to NFSSOCKADDR_T args.
563 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
565 struct sockaddr_in *addr1, *addr2;
566 struct sockaddr *inaddr;
568 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
569 switch (inaddr->sa_family) {
571 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
572 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
573 if (addr2->sin_family == AF_INET &&
574 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
580 struct sockaddr_in6 *inet6addr1, *inet6addr2;
582 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
583 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
584 /* XXX - should test sin6_scope_id ? */
585 if (inet6addr2->sin6_family == AF_INET6 &&
586 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
587 &inet6addr2->sin6_addr))
598 * Trim the stuff already dissected off the mbuf list.
601 newnfs_trimleading(nd)
602 struct nfsrv_descript *nd;
608 * First, free up leading mbufs.
610 if (nd->nd_mrep != nd->nd_md) {
612 while (mbuf_next(m) != nd->nd_md) {
613 if (mbuf_next(m) == NULL)
614 panic("nfsm trim leading");
617 mbuf_setnext(m, NULL);
618 mbuf_freem(nd->nd_mrep);
623 * Now, adjust this mbuf, based on nd_dpos.
625 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
626 if (offs == mbuf_len(m)) {
630 panic("nfsm trim leading2");
631 mbuf_setnext(n, NULL);
633 } else if (offs > 0) {
634 mbuf_setlen(m, mbuf_len(m) - offs);
637 panic("nfsm trimleading offs");
640 nd->nd_dpos = NFSMTOD(m, caddr_t);
644 * Trim trailing data off the mbuf list being built.
647 newnfs_trimtrailing(nd, mb, bpos)
648 struct nfsrv_descript *nd;
654 mbuf_freem(mbuf_next(mb));
655 mbuf_setnext(mb, NULL);
657 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
663 * Dissect a file handle on the client.
666 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
673 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
674 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
675 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
682 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
684 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
686 FREE((caddr_t)nfhp, M_NFSFH);
692 NFSEXITCODE2(error, nd);
697 * Break down the nfsv4 acl.
698 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
701 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
702 int *aclsizep, __unused NFSPROC_T *p)
706 int acecnt, error = 0, aceerr = 0, acesize;
712 * Parse out the ace entries and expect them to conform to
713 * what can be supported by R/W/X bits.
715 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
716 aclsize = NFSX_UNSIGNED;
717 acecnt = fxdr_unsigned(int, *tl);
718 if (acecnt > ACL_MAX_ENTRIES)
719 aceerr = NFSERR_ATTRNOTSUPP;
720 if (nfsrv_useacl == 0)
721 aceerr = NFSERR_ATTRNOTSUPP;
722 for (i = 0; i < acecnt; i++) {
724 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
725 &aceerr, &acesize, p);
727 error = nfsrv_skipace(nd, &acesize);
733 aclp->acl_cnt = acecnt;
739 NFSEXITCODE2(error, nd);
744 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
747 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
752 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
753 len = fxdr_unsigned(int, *(tl + 3));
754 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
756 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
757 NFSEXITCODE2(error, nd);
762 * Get attribute bits from an mbuf list.
763 * Returns EBADRPC for a parsing error, 0 otherwise.
764 * If the clearinvalid flag is set, clear the bits not supported.
767 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
774 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
775 cnt = fxdr_unsigned(int, *tl);
777 error = NFSERR_BADXDR;
780 if (cnt > NFSATTRBIT_MAXWORDS)
781 outcnt = NFSATTRBIT_MAXWORDS;
784 NFSZERO_ATTRBIT(attrbitp);
786 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
787 for (i = 0; i < outcnt; i++)
788 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
790 for (i = 0; i < (cnt - outcnt); i++) {
791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
792 if (retnotsupp != NULL && *tl != 0)
793 *retnotsupp = NFSERR_ATTRNOTSUPP;
796 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
798 NFSEXITCODE2(error, nd);
803 * Get the attributes for V4.
804 * If the compare flag is true, test for any attribute changes,
805 * otherwise return the attribute values.
806 * These attributes cover fields in "struct vattr", "struct statfs",
807 * "struct nfsfsinfo", the file handle and the lease duration.
808 * The value of retcmpp is set to 1 if all attributes are the same,
810 * Returns EBADRPC if it can't be parsed, 0 otherwise.
813 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
814 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
815 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
816 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
817 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
820 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
821 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
822 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
823 nfsattrbit_t attrbits, retattrbits, checkattrbits;
825 struct nfsreferral *refp;
828 struct timespec temptime;
832 u_int32_t freenum = 0, tuint;
833 u_int64_t uquad = 0, thyp, thyp2;
838 static struct timeval last64fileid;
839 static size_t count64fileid;
840 static struct timeval last64mountfileid;
841 static size_t count64mountfileid;
842 struct timeval warninterval =
843 { nfs_suppress_32bits_warning ? 86400 : 60, 0 };
847 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
849 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
855 *retcmpp = retnotsup;
858 * Just set default values to some of the important ones.
863 nap->na_rdev = (NFSDEV_T)0;
864 nap->na_mtime.tv_sec = 0;
865 nap->na_mtime.tv_nsec = 0;
868 nap->na_blocksize = NFS_FABLKSIZE;
871 sbp->f_bsize = NFS_FABLKSIZE;
879 fsp->fs_rtmax = 8192;
880 fsp->fs_rtpref = 8192;
881 fsp->fs_maxname = NFS_MAXNAMLEN;
882 fsp->fs_wtmax = 8192;
883 fsp->fs_wtpref = 8192;
884 fsp->fs_wtmult = NFS_FABLKSIZE;
885 fsp->fs_dtpref = 8192;
886 fsp->fs_maxfilesize = 0xffffffffffffffffull;
887 fsp->fs_timedelta.tv_sec = 0;
888 fsp->fs_timedelta.tv_nsec = 1;
889 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
890 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
893 pc->pc_linkmax = LINK_MAX;
894 pc->pc_namemax = NAME_MAX;
896 pc->pc_chownrestricted = 0;
897 pc->pc_caseinsensitive = 0;
898 pc->pc_casepreserving = 1;
901 sfp->sf_ffiles = UINT64_MAX;
902 sfp->sf_tfiles = UINT64_MAX;
903 sfp->sf_afiles = UINT64_MAX;
904 sfp->sf_fbytes = UINT64_MAX;
905 sfp->sf_tbytes = UINT64_MAX;
906 sfp->sf_abytes = UINT64_MAX;
911 * Loop around getting the attributes.
913 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
914 attrsize = fxdr_unsigned(int, *tl);
915 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
916 if (attrsum > attrsize) {
917 error = NFSERR_BADXDR;
920 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
922 case NFSATTRBIT_SUPPORTEDATTRS:
924 if (compare || nap == NULL)
925 error = nfsrv_getattrbits(nd, &retattrbits,
928 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
932 if (compare && !(*retcmpp)) {
933 NFSSETSUPP_ATTRBIT(&checkattrbits);
935 /* Some filesystem do not support NFSv4ACL */
936 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
937 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
938 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
940 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
942 *retcmpp = NFSERR_NOTSAME;
946 case NFSATTRBIT_TYPE:
947 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
950 if (nap->na_type != nfsv34tov_type(*tl))
951 *retcmpp = NFSERR_NOTSAME;
953 } else if (nap != NULL) {
954 nap->na_type = nfsv34tov_type(*tl);
956 attrsum += NFSX_UNSIGNED;
958 case NFSATTRBIT_FHEXPIRETYPE:
959 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960 if (compare && !(*retcmpp)) {
961 if (fxdr_unsigned(int, *tl) !=
962 NFSV4FHTYPE_PERSISTENT)
963 *retcmpp = NFSERR_NOTSAME;
965 attrsum += NFSX_UNSIGNED;
967 case NFSATTRBIT_CHANGE:
968 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
971 if (nap->na_filerev != fxdr_hyper(tl))
972 *retcmpp = NFSERR_NOTSAME;
974 } else if (nap != NULL) {
975 nap->na_filerev = fxdr_hyper(tl);
977 attrsum += NFSX_HYPER;
979 case NFSATTRBIT_SIZE:
980 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
983 if (nap->na_size != fxdr_hyper(tl))
984 *retcmpp = NFSERR_NOTSAME;
986 } else if (nap != NULL) {
987 nap->na_size = fxdr_hyper(tl);
989 attrsum += NFSX_HYPER;
991 case NFSATTRBIT_LINKSUPPORT:
992 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
995 if (fsp->fs_properties & NFSV3_FSFLINK) {
996 if (*tl == newnfs_false)
997 *retcmpp = NFSERR_NOTSAME;
999 if (*tl == newnfs_true)
1000 *retcmpp = NFSERR_NOTSAME;
1003 } else if (fsp != NULL) {
1004 if (*tl == newnfs_true)
1005 fsp->fs_properties |= NFSV3_FSFLINK;
1007 fsp->fs_properties &= ~NFSV3_FSFLINK;
1009 attrsum += NFSX_UNSIGNED;
1011 case NFSATTRBIT_SYMLINKSUPPORT:
1012 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1015 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1016 if (*tl == newnfs_false)
1017 *retcmpp = NFSERR_NOTSAME;
1019 if (*tl == newnfs_true)
1020 *retcmpp = NFSERR_NOTSAME;
1023 } else if (fsp != NULL) {
1024 if (*tl == newnfs_true)
1025 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1027 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1029 attrsum += NFSX_UNSIGNED;
1031 case NFSATTRBIT_NAMEDATTR:
1032 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1033 if (compare && !(*retcmpp)) {
1034 if (*tl != newnfs_false)
1035 *retcmpp = NFSERR_NOTSAME;
1037 attrsum += NFSX_UNSIGNED;
1039 case NFSATTRBIT_FSID:
1040 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1041 thyp = fxdr_hyper(tl);
1043 thyp2 = fxdr_hyper(tl);
1045 if (*retcmpp == 0) {
1046 if (thyp != (u_int64_t)
1047 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1048 thyp2 != (u_int64_t)
1049 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1050 *retcmpp = NFSERR_NOTSAME;
1052 } else if (nap != NULL) {
1053 nap->na_filesid[0] = thyp;
1054 nap->na_filesid[1] = thyp2;
1056 attrsum += (4 * NFSX_UNSIGNED);
1058 case NFSATTRBIT_UNIQUEHANDLES:
1059 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1060 if (compare && !(*retcmpp)) {
1061 if (*tl != newnfs_true)
1062 *retcmpp = NFSERR_NOTSAME;
1064 attrsum += NFSX_UNSIGNED;
1066 case NFSATTRBIT_LEASETIME:
1067 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1069 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1071 *retcmpp = NFSERR_NOTSAME;
1072 } else if (leasep != NULL) {
1073 *leasep = fxdr_unsigned(u_int32_t, *tl);
1075 attrsum += NFSX_UNSIGNED;
1077 case NFSATTRBIT_RDATTRERROR:
1078 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1081 *retcmpp = NFSERR_INVAL;
1082 } else if (rderrp != NULL) {
1083 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1085 attrsum += NFSX_UNSIGNED;
1087 case NFSATTRBIT_ACL:
1090 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1093 naclp = acl_alloc(M_WAITOK);
1094 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1100 if (aceerr || aclp == NULL ||
1101 nfsrv_compareacl(aclp, naclp))
1102 *retcmpp = NFSERR_NOTSAME;
1105 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1107 *retcmpp = NFSERR_ATTRNOTSUPP;
1111 if (vp != NULL && aclp != NULL)
1112 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1115 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1123 case NFSATTRBIT_ACLSUPPORT:
1124 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1125 if (compare && !(*retcmpp)) {
1126 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1127 if (fxdr_unsigned(u_int32_t, *tl) !=
1129 *retcmpp = NFSERR_NOTSAME;
1131 *retcmpp = NFSERR_ATTRNOTSUPP;
1134 attrsum += NFSX_UNSIGNED;
1136 case NFSATTRBIT_ARCHIVE:
1137 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1138 if (compare && !(*retcmpp))
1139 *retcmpp = NFSERR_ATTRNOTSUPP;
1140 attrsum += NFSX_UNSIGNED;
1142 case NFSATTRBIT_CANSETTIME:
1143 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1146 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1147 if (*tl == newnfs_false)
1148 *retcmpp = NFSERR_NOTSAME;
1150 if (*tl == newnfs_true)
1151 *retcmpp = NFSERR_NOTSAME;
1154 } else if (fsp != NULL) {
1155 if (*tl == newnfs_true)
1156 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1158 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1160 attrsum += NFSX_UNSIGNED;
1162 case NFSATTRBIT_CASEINSENSITIVE:
1163 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1166 if (*tl != newnfs_false)
1167 *retcmpp = NFSERR_NOTSAME;
1169 } else if (pc != NULL) {
1170 pc->pc_caseinsensitive =
1171 fxdr_unsigned(u_int32_t, *tl);
1173 attrsum += NFSX_UNSIGNED;
1175 case NFSATTRBIT_CASEPRESERVING:
1176 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1179 if (*tl != newnfs_true)
1180 *retcmpp = NFSERR_NOTSAME;
1182 } else if (pc != NULL) {
1183 pc->pc_casepreserving =
1184 fxdr_unsigned(u_int32_t, *tl);
1186 attrsum += NFSX_UNSIGNED;
1188 case NFSATTRBIT_CHOWNRESTRICTED:
1189 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1192 if (*tl != newnfs_true)
1193 *retcmpp = NFSERR_NOTSAME;
1195 } else if (pc != NULL) {
1196 pc->pc_chownrestricted =
1197 fxdr_unsigned(u_int32_t, *tl);
1199 attrsum += NFSX_UNSIGNED;
1201 case NFSATTRBIT_FILEHANDLE:
1202 error = nfsm_getfh(nd, &tnfhp);
1205 tfhsize = tnfhp->nfh_len;
1208 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1210 *retcmpp = NFSERR_NOTSAME;
1211 FREE((caddr_t)tnfhp, M_NFSFH);
1212 } else if (nfhpp != NULL) {
1215 FREE((caddr_t)tnfhp, M_NFSFH);
1217 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1219 case NFSATTRBIT_FILEID:
1220 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1221 thyp = fxdr_hyper(tl);
1224 if ((u_int64_t)nap->na_fileid != thyp)
1225 *retcmpp = NFSERR_NOTSAME;
1227 } else if (nap != NULL) {
1230 if (ratecheck(&last64fileid, &warninterval)) {
1231 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1236 nap->na_fileid = thyp;
1238 attrsum += NFSX_HYPER;
1240 case NFSATTRBIT_FILESAVAIL:
1241 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1244 sfp->sf_afiles != fxdr_hyper(tl))
1245 *retcmpp = NFSERR_NOTSAME;
1246 } else if (sfp != NULL) {
1247 sfp->sf_afiles = fxdr_hyper(tl);
1249 attrsum += NFSX_HYPER;
1251 case NFSATTRBIT_FILESFREE:
1252 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1255 sfp->sf_ffiles != fxdr_hyper(tl))
1256 *retcmpp = NFSERR_NOTSAME;
1257 } else if (sfp != NULL) {
1258 sfp->sf_ffiles = fxdr_hyper(tl);
1260 attrsum += NFSX_HYPER;
1262 case NFSATTRBIT_FILESTOTAL:
1263 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1266 sfp->sf_tfiles != fxdr_hyper(tl))
1267 *retcmpp = NFSERR_NOTSAME;
1268 } else if (sfp != NULL) {
1269 sfp->sf_tfiles = fxdr_hyper(tl);
1271 attrsum += NFSX_HYPER;
1273 case NFSATTRBIT_FSLOCATIONS:
1274 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1278 if (compare && !(*retcmpp)) {
1279 refp = nfsv4root_getreferral(vp, NULL, 0);
1281 if (cp == NULL || cp2 == NULL ||
1283 strcmp(cp2, refp->nfr_srvlist))
1284 *retcmpp = NFSERR_NOTSAME;
1285 } else if (m == 0) {
1286 *retcmpp = NFSERR_NOTSAME;
1290 free(cp, M_NFSSTRING);
1292 free(cp2, M_NFSSTRING);
1294 case NFSATTRBIT_HIDDEN:
1295 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1296 if (compare && !(*retcmpp))
1297 *retcmpp = NFSERR_ATTRNOTSUPP;
1298 attrsum += NFSX_UNSIGNED;
1300 case NFSATTRBIT_HOMOGENEOUS:
1301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1304 if (fsp->fs_properties &
1305 NFSV3_FSFHOMOGENEOUS) {
1306 if (*tl == newnfs_false)
1307 *retcmpp = NFSERR_NOTSAME;
1309 if (*tl == newnfs_true)
1310 *retcmpp = NFSERR_NOTSAME;
1313 } else if (fsp != NULL) {
1314 if (*tl == newnfs_true)
1315 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1317 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1319 attrsum += NFSX_UNSIGNED;
1321 case NFSATTRBIT_MAXFILESIZE:
1322 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1323 tnfsquad.qval = fxdr_hyper(tl);
1326 tquad = NFSRV_MAXFILESIZE;
1327 if (tquad != tnfsquad.qval)
1328 *retcmpp = NFSERR_NOTSAME;
1330 } else if (fsp != NULL) {
1331 fsp->fs_maxfilesize = tnfsquad.qval;
1333 attrsum += NFSX_HYPER;
1335 case NFSATTRBIT_MAXLINK:
1336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1339 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1340 *retcmpp = NFSERR_NOTSAME;
1342 } else if (pc != NULL) {
1343 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1345 attrsum += NFSX_UNSIGNED;
1347 case NFSATTRBIT_MAXNAME:
1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1351 if (fsp->fs_maxname !=
1352 fxdr_unsigned(u_int32_t, *tl))
1353 *retcmpp = NFSERR_NOTSAME;
1356 tuint = fxdr_unsigned(u_int32_t, *tl);
1358 * Some Linux NFSv4 servers report this
1359 * as 0 or 4billion, so I'll set it to
1360 * NFS_MAXNAMLEN. If a server actually creates
1361 * a name longer than NFS_MAXNAMLEN, it will
1362 * get an error back.
1364 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1365 tuint = NFS_MAXNAMLEN;
1367 fsp->fs_maxname = tuint;
1369 pc->pc_namemax = tuint;
1371 attrsum += NFSX_UNSIGNED;
1373 case NFSATTRBIT_MAXREAD:
1374 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1377 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1378 *(tl + 1)) || *tl != 0)
1379 *retcmpp = NFSERR_NOTSAME;
1381 } else if (fsp != NULL) {
1382 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1383 fsp->fs_rtpref = fsp->fs_rtmax;
1384 fsp->fs_dtpref = fsp->fs_rtpref;
1386 attrsum += NFSX_HYPER;
1388 case NFSATTRBIT_MAXWRITE:
1389 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1392 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1393 *(tl + 1)) || *tl != 0)
1394 *retcmpp = NFSERR_NOTSAME;
1396 } else if (fsp != NULL) {
1397 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1398 fsp->fs_wtpref = fsp->fs_wtmax;
1400 attrsum += NFSX_HYPER;
1402 case NFSATTRBIT_MIMETYPE:
1403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404 i = fxdr_unsigned(int, *tl);
1405 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1406 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1409 if (compare && !(*retcmpp))
1410 *retcmpp = NFSERR_ATTRNOTSUPP;
1412 case NFSATTRBIT_MODE:
1413 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1416 if (nap->na_mode != nfstov_mode(*tl))
1417 *retcmpp = NFSERR_NOTSAME;
1419 } else if (nap != NULL) {
1420 nap->na_mode = nfstov_mode(*tl);
1422 attrsum += NFSX_UNSIGNED;
1424 case NFSATTRBIT_NOTRUNC:
1425 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1428 if (*tl != newnfs_true)
1429 *retcmpp = NFSERR_NOTSAME;
1431 } else if (pc != NULL) {
1432 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1434 attrsum += NFSX_UNSIGNED;
1436 case NFSATTRBIT_NUMLINKS:
1437 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1438 tuint = fxdr_unsigned(u_int32_t, *tl);
1441 if ((u_int32_t)nap->na_nlink != tuint)
1442 *retcmpp = NFSERR_NOTSAME;
1444 } else if (nap != NULL) {
1445 nap->na_nlink = tuint;
1447 attrsum += NFSX_UNSIGNED;
1449 case NFSATTRBIT_OWNER:
1450 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1451 j = fxdr_unsigned(int, *tl);
1453 error = NFSERR_BADXDR;
1456 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1457 if (j > NFSV4_SMALLSTR)
1458 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1461 error = nfsrv_mtostr(nd, cp, j);
1463 if (j > NFSV4_SMALLSTR)
1464 free(cp, M_NFSSTRING);
1469 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1471 *retcmpp = NFSERR_NOTSAME;
1473 } else if (nap != NULL) {
1474 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1475 nap->na_uid = nfsrv_defaultuid;
1479 if (j > NFSV4_SMALLSTR)
1480 free(cp, M_NFSSTRING);
1482 case NFSATTRBIT_OWNERGROUP:
1483 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1484 j = fxdr_unsigned(int, *tl);
1486 error = NFSERR_BADXDR;
1489 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1490 if (j > NFSV4_SMALLSTR)
1491 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1494 error = nfsrv_mtostr(nd, cp, j);
1496 if (j > NFSV4_SMALLSTR)
1497 free(cp, M_NFSSTRING);
1502 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1504 *retcmpp = NFSERR_NOTSAME;
1506 } else if (nap != NULL) {
1507 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1508 nap->na_gid = nfsrv_defaultgid;
1512 if (j > NFSV4_SMALLSTR)
1513 free(cp, M_NFSSTRING);
1515 case NFSATTRBIT_QUOTAHARD:
1516 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1518 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1519 freenum = sbp->f_bfree;
1521 freenum = sbp->f_bavail;
1524 * ufs_quotactl() insists that the uid argument
1525 * equal p_ruid for non-root quota access, so
1526 * we'll just make sure that's the case.
1528 savuid = p->p_cred->p_ruid;
1529 p->p_cred->p_ruid = cred->cr_uid;
1530 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1531 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1532 freenum = min(dqb.dqb_bhardlimit, freenum);
1533 p->p_cred->p_ruid = savuid;
1535 uquad = (u_int64_t)freenum;
1536 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1538 if (compare && !(*retcmpp)) {
1539 if (uquad != fxdr_hyper(tl))
1540 *retcmpp = NFSERR_NOTSAME;
1542 attrsum += NFSX_HYPER;
1544 case NFSATTRBIT_QUOTASOFT:
1545 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1547 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1548 freenum = sbp->f_bfree;
1550 freenum = sbp->f_bavail;
1553 * ufs_quotactl() insists that the uid argument
1554 * equal p_ruid for non-root quota access, so
1555 * we'll just make sure that's the case.
1557 savuid = p->p_cred->p_ruid;
1558 p->p_cred->p_ruid = cred->cr_uid;
1559 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1560 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1561 freenum = min(dqb.dqb_bsoftlimit, freenum);
1562 p->p_cred->p_ruid = savuid;
1564 uquad = (u_int64_t)freenum;
1565 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1567 if (compare && !(*retcmpp)) {
1568 if (uquad != fxdr_hyper(tl))
1569 *retcmpp = NFSERR_NOTSAME;
1571 attrsum += NFSX_HYPER;
1573 case NFSATTRBIT_QUOTAUSED:
1574 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1579 * ufs_quotactl() insists that the uid argument
1580 * equal p_ruid for non-root quota access, so
1581 * we'll just make sure that's the case.
1583 savuid = p->p_cred->p_ruid;
1584 p->p_cred->p_ruid = cred->cr_uid;
1585 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1586 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1587 freenum = dqb.dqb_curblocks;
1588 p->p_cred->p_ruid = savuid;
1590 uquad = (u_int64_t)freenum;
1591 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1593 if (compare && !(*retcmpp)) {
1594 if (uquad != fxdr_hyper(tl))
1595 *retcmpp = NFSERR_NOTSAME;
1597 attrsum += NFSX_HYPER;
1599 case NFSATTRBIT_RAWDEV:
1600 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1601 j = fxdr_unsigned(int, *tl++);
1602 k = fxdr_unsigned(int, *tl);
1605 if (nap->na_rdev != NFSMAKEDEV(j, k))
1606 *retcmpp = NFSERR_NOTSAME;
1608 } else if (nap != NULL) {
1609 nap->na_rdev = NFSMAKEDEV(j, k);
1611 attrsum += NFSX_V4SPECDATA;
1613 case NFSATTRBIT_SPACEAVAIL:
1614 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1617 sfp->sf_abytes != fxdr_hyper(tl))
1618 *retcmpp = NFSERR_NOTSAME;
1619 } else if (sfp != NULL) {
1620 sfp->sf_abytes = fxdr_hyper(tl);
1622 attrsum += NFSX_HYPER;
1624 case NFSATTRBIT_SPACEFREE:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1628 sfp->sf_fbytes != fxdr_hyper(tl))
1629 *retcmpp = NFSERR_NOTSAME;
1630 } else if (sfp != NULL) {
1631 sfp->sf_fbytes = fxdr_hyper(tl);
1633 attrsum += NFSX_HYPER;
1635 case NFSATTRBIT_SPACETOTAL:
1636 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1639 sfp->sf_tbytes != fxdr_hyper(tl))
1640 *retcmpp = NFSERR_NOTSAME;
1641 } else if (sfp != NULL) {
1642 sfp->sf_tbytes = fxdr_hyper(tl);
1644 attrsum += NFSX_HYPER;
1646 case NFSATTRBIT_SPACEUSED:
1647 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1648 thyp = fxdr_hyper(tl);
1651 if ((u_int64_t)nap->na_bytes != thyp)
1652 *retcmpp = NFSERR_NOTSAME;
1654 } else if (nap != NULL) {
1655 nap->na_bytes = thyp;
1657 attrsum += NFSX_HYPER;
1659 case NFSATTRBIT_SYSTEM:
1660 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1661 if (compare && !(*retcmpp))
1662 *retcmpp = NFSERR_ATTRNOTSUPP;
1663 attrsum += NFSX_UNSIGNED;
1665 case NFSATTRBIT_TIMEACCESS:
1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1667 fxdr_nfsv4time(tl, &temptime);
1670 if (!NFS_CMPTIME(temptime, nap->na_atime))
1671 *retcmpp = NFSERR_NOTSAME;
1673 } else if (nap != NULL) {
1674 nap->na_atime = temptime;
1676 attrsum += NFSX_V4TIME;
1678 case NFSATTRBIT_TIMEACCESSSET:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1680 attrsum += NFSX_UNSIGNED;
1681 i = fxdr_unsigned(int, *tl);
1682 if (i == NFSV4SATTRTIME_TOCLIENT) {
1683 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1684 attrsum += NFSX_V4TIME;
1686 if (compare && !(*retcmpp))
1687 *retcmpp = NFSERR_INVAL;
1689 case NFSATTRBIT_TIMEBACKUP:
1690 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1691 if (compare && !(*retcmpp))
1692 *retcmpp = NFSERR_ATTRNOTSUPP;
1693 attrsum += NFSX_V4TIME;
1695 case NFSATTRBIT_TIMECREATE:
1696 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1697 if (compare && !(*retcmpp))
1698 *retcmpp = NFSERR_ATTRNOTSUPP;
1699 attrsum += NFSX_V4TIME;
1701 case NFSATTRBIT_TIMEDELTA:
1702 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1706 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1707 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1708 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1709 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1712 *retcmpp = NFSERR_NOTSAME;
1715 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1718 attrsum += NFSX_V4TIME;
1720 case NFSATTRBIT_TIMEMETADATA:
1721 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1722 fxdr_nfsv4time(tl, &temptime);
1725 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1726 *retcmpp = NFSERR_NOTSAME;
1728 } else if (nap != NULL) {
1729 nap->na_ctime = temptime;
1731 attrsum += NFSX_V4TIME;
1733 case NFSATTRBIT_TIMEMODIFY:
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1735 fxdr_nfsv4time(tl, &temptime);
1738 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1739 *retcmpp = NFSERR_NOTSAME;
1741 } else if (nap != NULL) {
1742 nap->na_mtime = temptime;
1744 attrsum += NFSX_V4TIME;
1746 case NFSATTRBIT_TIMEMODIFYSET:
1747 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1748 attrsum += NFSX_UNSIGNED;
1749 i = fxdr_unsigned(int, *tl);
1750 if (i == NFSV4SATTRTIME_TOCLIENT) {
1751 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1752 attrsum += NFSX_V4TIME;
1754 if (compare && !(*retcmpp))
1755 *retcmpp = NFSERR_INVAL;
1757 case NFSATTRBIT_MOUNTEDONFILEID:
1758 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1759 thyp = fxdr_hyper(tl);
1763 *retcmpp = NFSERR_NOTSAME;
1765 if (!vp || !nfsrv_atroot(vp, &fid))
1766 fid = nap->na_fileid;
1767 if ((u_int64_t)fid != thyp)
1768 *retcmpp = NFSERR_NOTSAME;
1771 } else if (nap != NULL) {
1773 count64mountfileid++;
1774 if (ratecheck(&last64mountfileid, &warninterval)) {
1775 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1776 count64mountfileid);
1777 count64mountfileid = 0;
1780 nap->na_mntonfileno = thyp;
1782 attrsum += NFSX_HYPER;
1784 case NFSATTRBIT_SUPPATTREXCLCREAT:
1786 error = nfsrv_getattrbits(nd, &retattrbits,
1790 if (compare && !(*retcmpp)) {
1791 NFSSETSUPP_ATTRBIT(&checkattrbits);
1792 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1793 NFSCLRBIT_ATTRBIT(&checkattrbits,
1794 NFSATTRBIT_TIMEACCESSSET);
1795 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1797 *retcmpp = NFSERR_NOTSAME;
1802 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1804 if (compare && !(*retcmpp))
1805 *retcmpp = NFSERR_ATTRNOTSUPP;
1807 * and get out of the loop, since we can't parse
1808 * the unknown attrbute data.
1810 bitpos = NFSATTRBIT_MAX;
1816 * some clients pad the attrlist, so we need to skip over the
1819 if (attrsum > attrsize) {
1820 error = NFSERR_BADXDR;
1822 attrsize = NFSM_RNDUP(attrsize);
1823 if (attrsum < attrsize)
1824 error = nfsm_advance(nd, attrsize - attrsum, -1);
1827 NFSEXITCODE2(error, nd);
1832 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1833 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1834 * The first argument is a pointer to an nfsv4lock structure.
1835 * The second argument is 1 iff a blocking lock is wanted.
1836 * If this argument is 0, the call waits until no thread either wants nor
1837 * holds an exclusive lock.
1838 * It returns 1 if the lock was acquired, 0 otherwise.
1839 * If several processes call this function concurrently wanting the exclusive
1840 * lock, one will get the lock and the rest will return without getting the
1841 * lock. (If the caller must have the lock, it simply calls this function in a
1842 * loop until the function returns 1 to indicate the lock was acquired.)
1843 * Any usecnt must be decremented by calling nfsv4_relref() before
1844 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1845 * be called in a loop.
1846 * The isleptp argument is set to indicate if the call slept, iff not NULL
1847 * and the mp argument indicates to check for a forced dismount, iff not
1851 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1852 void *mutex, struct mount *mp)
1858 * If a lock is wanted, loop around until the lock is acquired by
1859 * someone and then released. If I want the lock, try to acquire it.
1860 * For a lock to be issued, no lock must be in force and the usecnt
1864 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1865 lp->nfslock_usecnt == 0) {
1866 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1867 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1870 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1872 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1873 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
1874 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1877 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1880 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1881 PZERO - 1, "nfsv4lck", NULL);
1882 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1883 lp->nfslock_usecnt == 0) {
1884 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1885 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1893 * Release the lock acquired by nfsv4_lock().
1894 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1895 * incremented, as well.
1898 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1901 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1903 lp->nfslock_usecnt++;
1908 * Release a reference cnt.
1911 nfsv4_relref(struct nfsv4lock *lp)
1914 if (lp->nfslock_usecnt <= 0)
1915 panic("nfsv4root ref cnt");
1916 lp->nfslock_usecnt--;
1917 if (lp->nfslock_usecnt == 0)
1922 * Get a reference cnt.
1923 * This function will wait for any exclusive lock to be released, but will
1924 * not wait for threads that want the exclusive lock. If priority needs
1925 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1926 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1927 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
1928 * return without getting a refcnt for that case.
1931 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1939 * Wait for a lock held.
1941 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1942 if (mp != NULL && NFSCL_FORCEDISM(mp))
1944 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1947 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1948 PZERO - 1, "nfsv4gr", NULL);
1950 if (mp != NULL && NFSCL_FORCEDISM(mp))
1953 lp->nfslock_usecnt++;
1957 * Get a reference as above, but return failure instead of sleeping if
1958 * an exclusive lock is held.
1961 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1964 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1967 lp->nfslock_usecnt++;
1972 * Test for a lock. Return 1 if locked, 0 otherwise.
1975 nfsv4_testlock(struct nfsv4lock *lp)
1978 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1979 lp->nfslock_usecnt == 0)
1985 * Wake up anyone sleeping, waiting for this lock.
1988 nfsv4_wanted(struct nfsv4lock *lp)
1991 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1992 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1993 wakeup((caddr_t)&lp->nfslock_lock);
1998 * Copy a string from an mbuf list into a character array.
1999 * Return EBADRPC if there is an mbuf error,
2003 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2012 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2013 rem = NFSM_RNDUP(siz) - siz;
2019 NFSBCOPY(cp, str, xfer);
2028 cp = NFSMTOD(mp, caddr_t);
2040 error = nfsm_advance(nd, rem, len);
2046 NFSEXITCODE2(error, nd);
2051 * Fill in the attributes as marked by the bitmap (V4).
2054 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2055 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2056 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2057 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2059 int bitpos, retnum = 0;
2061 int siz, prefixnum, error;
2062 u_char *cp, namestr[NFSV4_SMALLSTR];
2063 nfsattrbit_t attrbits, retbits;
2064 nfsattrbit_t *retbitp = &retbits;
2065 u_int32_t freenum, *retnump;
2068 struct nfsfsinfo fsinf;
2069 struct timespec temptime;
2070 NFSACL_T *aclp, *naclp = NULL;
2077 * First, set the bits that can be filled and get fsinfo.
2079 NFSSET_ATTRBIT(retbitp, attrbitp);
2081 * If both p and cred are NULL, it is a client side setattr call.
2082 * If both p and cred are not NULL, it is a server side reply call.
2083 * If p is not NULL and cred is NULL, it is a client side callback
2086 if (p == NULL && cred == NULL) {
2087 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2090 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2091 naclp = acl_alloc(M_WAITOK);
2094 nfsvno_getfs(&fsinf, isdgram);
2097 * Get the VFS_STATFS(), since some attributes need them.
2099 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2100 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2101 error = VFS_STATFS(mp, fs);
2104 nd->nd_repstat = NFSERR_ACCES;
2108 NFSCLRSTATFS_ATTRBIT(retbitp);
2114 * And the NFSv4 ACL...
2116 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2117 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2118 supports_nfsv4acls == 0))) {
2119 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2121 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2122 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2123 supports_nfsv4acls == 0)) {
2124 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2125 } else if (naclp != NULL) {
2126 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2127 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2129 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2131 NFSVOPUNLOCK(vp, 0);
2133 error = NFSERR_PERM;
2136 nd->nd_repstat = NFSERR_ACCES;
2140 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2146 * Put out the attribute bitmap for the ones being filled in
2147 * and get the field for the number of attributes returned.
2149 prefixnum = nfsrv_putattrbit(nd, retbitp);
2150 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2151 prefixnum += NFSX_UNSIGNED;
2154 * Now, loop around filling in the attributes for each bit set.
2156 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2157 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2159 case NFSATTRBIT_SUPPORTEDATTRS:
2160 NFSSETSUPP_ATTRBIT(&attrbits);
2161 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2162 && supports_nfsv4acls == 0)) {
2163 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2164 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2166 retnum += nfsrv_putattrbit(nd, &attrbits);
2168 case NFSATTRBIT_TYPE:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 *tl = vtonfsv34_type(vap->va_type);
2171 retnum += NFSX_UNSIGNED;
2173 case NFSATTRBIT_FHEXPIRETYPE:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2176 retnum += NFSX_UNSIGNED;
2178 case NFSATTRBIT_CHANGE:
2179 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2180 txdr_hyper(vap->va_filerev, tl);
2181 retnum += NFSX_HYPER;
2183 case NFSATTRBIT_SIZE:
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2185 txdr_hyper(vap->va_size, tl);
2186 retnum += NFSX_HYPER;
2188 case NFSATTRBIT_LINKSUPPORT:
2189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2194 retnum += NFSX_UNSIGNED;
2196 case NFSATTRBIT_SYMLINKSUPPORT:
2197 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2198 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2202 retnum += NFSX_UNSIGNED;
2204 case NFSATTRBIT_NAMEDATTR:
2205 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2207 retnum += NFSX_UNSIGNED;
2209 case NFSATTRBIT_FSID:
2210 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2212 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2214 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2215 retnum += NFSX_V4FSID;
2217 case NFSATTRBIT_UNIQUEHANDLES:
2218 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 retnum += NFSX_UNSIGNED;
2222 case NFSATTRBIT_LEASETIME:
2223 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2224 *tl = txdr_unsigned(nfsrv_lease);
2225 retnum += NFSX_UNSIGNED;
2227 case NFSATTRBIT_RDATTRERROR:
2228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2229 *tl = txdr_unsigned(rderror);
2230 retnum += NFSX_UNSIGNED;
2233 * Recommended Attributes. (Only the supported ones.)
2235 case NFSATTRBIT_ACL:
2236 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2238 case NFSATTRBIT_ACLSUPPORT:
2239 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2240 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2241 retnum += NFSX_UNSIGNED;
2243 case NFSATTRBIT_CANSETTIME:
2244 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2245 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2249 retnum += NFSX_UNSIGNED;
2251 case NFSATTRBIT_CASEINSENSITIVE:
2252 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2254 retnum += NFSX_UNSIGNED;
2256 case NFSATTRBIT_CASEPRESERVING:
2257 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2259 retnum += NFSX_UNSIGNED;
2261 case NFSATTRBIT_CHOWNRESTRICTED:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2264 retnum += NFSX_UNSIGNED;
2266 case NFSATTRBIT_FILEHANDLE:
2267 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2269 case NFSATTRBIT_FILEID:
2270 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2272 *tl = txdr_unsigned(vap->va_fileid);
2273 retnum += NFSX_HYPER;
2275 case NFSATTRBIT_FILESAVAIL:
2277 * Check quota and use min(quota, f_ffree).
2279 freenum = fs->f_ffree;
2282 * ufs_quotactl() insists that the uid argument
2283 * equal p_ruid for non-root quota access, so
2284 * we'll just make sure that's the case.
2286 savuid = p->p_cred->p_ruid;
2287 p->p_cred->p_ruid = cred->cr_uid;
2288 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2289 cred->cr_uid, (caddr_t)&dqb))
2290 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2292 p->p_cred->p_ruid = savuid;
2294 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2296 *tl = txdr_unsigned(freenum);
2297 retnum += NFSX_HYPER;
2299 case NFSATTRBIT_FILESFREE:
2300 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2302 *tl = txdr_unsigned(fs->f_ffree);
2303 retnum += NFSX_HYPER;
2305 case NFSATTRBIT_FILESTOTAL:
2306 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2308 *tl = txdr_unsigned(fs->f_files);
2309 retnum += NFSX_HYPER;
2311 case NFSATTRBIT_FSLOCATIONS:
2312 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2315 retnum += 2 * NFSX_UNSIGNED;
2317 case NFSATTRBIT_HOMOGENEOUS:
2318 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2319 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2323 retnum += NFSX_UNSIGNED;
2325 case NFSATTRBIT_MAXFILESIZE:
2326 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2327 uquad = NFSRV_MAXFILESIZE;
2328 txdr_hyper(uquad, tl);
2329 retnum += NFSX_HYPER;
2331 case NFSATTRBIT_MAXLINK:
2332 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2333 *tl = txdr_unsigned(LINK_MAX);
2334 retnum += NFSX_UNSIGNED;
2336 case NFSATTRBIT_MAXNAME:
2337 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2338 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2339 retnum += NFSX_UNSIGNED;
2341 case NFSATTRBIT_MAXREAD:
2342 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2344 *tl = txdr_unsigned(fsinf.fs_rtmax);
2345 retnum += NFSX_HYPER;
2347 case NFSATTRBIT_MAXWRITE:
2348 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2350 *tl = txdr_unsigned(fsinf.fs_wtmax);
2351 retnum += NFSX_HYPER;
2353 case NFSATTRBIT_MODE:
2354 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2355 *tl = vtonfsv34_mode(vap->va_mode);
2356 retnum += NFSX_UNSIGNED;
2358 case NFSATTRBIT_NOTRUNC:
2359 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2361 retnum += NFSX_UNSIGNED;
2363 case NFSATTRBIT_NUMLINKS:
2364 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2365 *tl = txdr_unsigned(vap->va_nlink);
2366 retnum += NFSX_UNSIGNED;
2368 case NFSATTRBIT_OWNER:
2370 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2371 retnum += nfsm_strtom(nd, cp, siz);
2373 free(cp, M_NFSSTRING);
2375 case NFSATTRBIT_OWNERGROUP:
2377 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2378 retnum += nfsm_strtom(nd, cp, siz);
2380 free(cp, M_NFSSTRING);
2382 case NFSATTRBIT_QUOTAHARD:
2383 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2384 freenum = fs->f_bfree;
2386 freenum = fs->f_bavail;
2389 * ufs_quotactl() insists that the uid argument
2390 * equal p_ruid for non-root quota access, so
2391 * we'll just make sure that's the case.
2393 savuid = p->p_cred->p_ruid;
2394 p->p_cred->p_ruid = cred->cr_uid;
2395 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2396 cred->cr_uid, (caddr_t)&dqb))
2397 freenum = min(dqb.dqb_bhardlimit, freenum);
2398 p->p_cred->p_ruid = savuid;
2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2401 uquad = (u_int64_t)freenum;
2402 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2403 txdr_hyper(uquad, tl);
2404 retnum += NFSX_HYPER;
2406 case NFSATTRBIT_QUOTASOFT:
2407 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2408 freenum = fs->f_bfree;
2410 freenum = fs->f_bavail;
2413 * ufs_quotactl() insists that the uid argument
2414 * equal p_ruid for non-root quota access, so
2415 * we'll just make sure that's the case.
2417 savuid = p->p_cred->p_ruid;
2418 p->p_cred->p_ruid = cred->cr_uid;
2419 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2420 cred->cr_uid, (caddr_t)&dqb))
2421 freenum = min(dqb.dqb_bsoftlimit, freenum);
2422 p->p_cred->p_ruid = savuid;
2424 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2425 uquad = (u_int64_t)freenum;
2426 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2427 txdr_hyper(uquad, tl);
2428 retnum += NFSX_HYPER;
2430 case NFSATTRBIT_QUOTAUSED:
2434 * ufs_quotactl() insists that the uid argument
2435 * equal p_ruid for non-root quota access, so
2436 * we'll just make sure that's the case.
2438 savuid = p->p_cred->p_ruid;
2439 p->p_cred->p_ruid = cred->cr_uid;
2440 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2441 cred->cr_uid, (caddr_t)&dqb))
2442 freenum = dqb.dqb_curblocks;
2443 p->p_cred->p_ruid = savuid;
2445 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2446 uquad = (u_int64_t)freenum;
2447 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2448 txdr_hyper(uquad, tl);
2449 retnum += NFSX_HYPER;
2451 case NFSATTRBIT_RAWDEV:
2452 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2453 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2454 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2455 retnum += NFSX_V4SPECDATA;
2457 case NFSATTRBIT_SPACEAVAIL:
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2459 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2460 uquad = (u_int64_t)fs->f_bfree;
2462 uquad = (u_int64_t)fs->f_bavail;
2463 uquad *= fs->f_bsize;
2464 txdr_hyper(uquad, tl);
2465 retnum += NFSX_HYPER;
2467 case NFSATTRBIT_SPACEFREE:
2468 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2469 uquad = (u_int64_t)fs->f_bfree;
2470 uquad *= fs->f_bsize;
2471 txdr_hyper(uquad, tl);
2472 retnum += NFSX_HYPER;
2474 case NFSATTRBIT_SPACETOTAL:
2475 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2476 uquad = (u_int64_t)fs->f_blocks;
2477 uquad *= fs->f_bsize;
2478 txdr_hyper(uquad, tl);
2479 retnum += NFSX_HYPER;
2481 case NFSATTRBIT_SPACEUSED:
2482 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2483 txdr_hyper(vap->va_bytes, tl);
2484 retnum += NFSX_HYPER;
2486 case NFSATTRBIT_TIMEACCESS:
2487 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2488 txdr_nfsv4time(&vap->va_atime, tl);
2489 retnum += NFSX_V4TIME;
2491 case NFSATTRBIT_TIMEACCESSSET:
2492 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2493 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2494 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2495 txdr_nfsv4time(&vap->va_atime, tl);
2496 retnum += NFSX_V4SETTIME;
2498 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2499 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2500 retnum += NFSX_UNSIGNED;
2503 case NFSATTRBIT_TIMEDELTA:
2504 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2505 temptime.tv_sec = 0;
2506 temptime.tv_nsec = 1000000000 / hz;
2507 txdr_nfsv4time(&temptime, tl);
2508 retnum += NFSX_V4TIME;
2510 case NFSATTRBIT_TIMEMETADATA:
2511 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2512 txdr_nfsv4time(&vap->va_ctime, tl);
2513 retnum += NFSX_V4TIME;
2515 case NFSATTRBIT_TIMEMODIFY:
2516 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2517 txdr_nfsv4time(&vap->va_mtime, tl);
2518 retnum += NFSX_V4TIME;
2520 case NFSATTRBIT_TIMEMODIFYSET:
2521 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2522 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2523 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2524 txdr_nfsv4time(&vap->va_mtime, tl);
2525 retnum += NFSX_V4SETTIME;
2527 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2528 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2529 retnum += NFSX_UNSIGNED;
2532 case NFSATTRBIT_MOUNTEDONFILEID:
2533 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2535 uquad = mounted_on_fileno;
2537 uquad = (u_int64_t)vap->va_fileid;
2538 txdr_hyper(uquad, tl);
2539 retnum += NFSX_HYPER;
2541 case NFSATTRBIT_SUPPATTREXCLCREAT:
2542 NFSSETSUPP_ATTRBIT(&attrbits);
2543 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2544 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2545 retnum += nfsrv_putattrbit(nd, &attrbits);
2548 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2555 *retnump = txdr_unsigned(retnum);
2556 return (retnum + prefixnum);
2560 * Put the attribute bits onto an mbuf list.
2561 * Return the number of bytes of output generated.
2564 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2567 int cnt, i, bytesize;
2569 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2570 if (attrbitp->bits[cnt - 1])
2572 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2573 NFSM_BUILD(tl, u_int32_t *, bytesize);
2574 *tl++ = txdr_unsigned(cnt);
2575 for (i = 0; i < cnt; i++)
2576 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2581 * Convert a uid to a string.
2582 * If the lookup fails, just output the digits.
2584 * cpp - points to a buffer of size NFSV4_SMALLSTR
2585 * (malloc a larger one, as required)
2586 * retlenp - pointer to length to be returned
2589 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2592 struct nfsusrgrp *usrp;
2595 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2596 struct nfsrv_lughash *hp;
2600 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2602 * Always map nfsrv_defaultuid to "nobody".
2604 if (uid == nfsrv_defaultuid) {
2605 i = nfsrv_dnsnamelen + 7;
2607 if (len > NFSV4_SMALLSTR)
2608 free(cp, M_NFSSTRING);
2609 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2615 NFSBCOPY("nobody@", cp, 7);
2617 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2621 hp = NFSUSERHASH(uid);
2623 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2624 if (usrp->lug_uid == uid) {
2625 if (usrp->lug_expiry < NFSD_MONOSEC)
2628 * If the name doesn't already have an '@'
2629 * in it, append @domainname to it.
2631 for (i = 0; i < usrp->lug_namelen; i++) {
2632 if (usrp->lug_name[i] == '@') {
2638 i = usrp->lug_namelen;
2640 i = usrp->lug_namelen +
2641 nfsrv_dnsnamelen + 1;
2643 mtx_unlock(&hp->mtx);
2644 if (len > NFSV4_SMALLSTR)
2645 free(cp, M_NFSSTRING);
2646 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2652 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2653 if (!hasampersand) {
2654 cp += usrp->lug_namelen;
2656 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2658 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2659 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2661 mtx_unlock(&hp->mtx);
2665 mtx_unlock(&hp->mtx);
2667 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2669 if (ret == 0 && cnt < 2)
2674 * No match, just return a string of digits.
2678 while (tmp || i == 0) {
2682 len = (i > len) ? len : i;
2686 for (i = 0; i < len; i++) {
2687 *cp-- = '0' + (tmp % 10);
2694 * Get a credential for the uid with the server's group list.
2695 * If none is found, just return the credential passed in after
2696 * logging a warning message.
2699 nfsrv_getgrpscred(struct ucred *oldcred)
2701 struct nfsusrgrp *usrp;
2702 struct ucred *newcred;
2705 struct nfsrv_lughash *hp;
2708 uid = oldcred->cr_uid;
2710 if (nfsrv_dnsnamelen > 0) {
2711 hp = NFSUSERHASH(uid);
2713 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2714 if (usrp->lug_uid == uid) {
2715 if (usrp->lug_expiry < NFSD_MONOSEC)
2717 if (usrp->lug_cred != NULL) {
2718 newcred = crhold(usrp->lug_cred);
2722 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2723 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2725 mtx_unlock(&hp->mtx);
2729 mtx_unlock(&hp->mtx);
2731 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2733 if (ret == 0 && cnt < 2)
2740 * Convert a string to a uid.
2741 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2743 * If this is called from a client side mount using AUTH_SYS and the
2744 * string is made up entirely of digits, just convert the string to
2748 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2752 char *cp, *endstr, *str0;
2753 struct nfsusrgrp *usrp;
2757 struct nfsrv_lughash *hp, *hp2;
2760 error = NFSERR_BADOWNER;
2763 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2765 tuid = (uid_t)strtoul(str0, &endstr, 10);
2766 if ((endstr - str0) == len) {
2767 /* A numeric string. */
2768 if ((nd->nd_flag & ND_KERBV) == 0 &&
2769 ((nd->nd_flag & ND_NFSCL) != 0 ||
2770 nfsd_enable_stringtouid != 0))
2773 error = NFSERR_BADOWNER;
2779 cp = strchr(str0, '@');
2781 i = (int)(cp++ - str0);
2787 if (nfsrv_dnsnamelen > 0) {
2789 * If an '@' is found and the domain name matches, search for
2790 * the name with dns stripped off.
2791 * Mixed case alpahbetics will match for the domain name, but
2792 * all upper case will not.
2794 if (cnt == 0 && i < len && i > 0 &&
2795 (len - 1 - i) == nfsrv_dnsnamelen &&
2796 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2797 len -= (nfsrv_dnsnamelen + 1);
2802 * Check for the special case of "nobody".
2804 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2805 *uidp = nfsrv_defaultuid;
2810 hp = NFSUSERNAMEHASH(str, len);
2812 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2813 if (usrp->lug_namelen == len &&
2814 !NFSBCMP(usrp->lug_name, str, len)) {
2815 if (usrp->lug_expiry < NFSD_MONOSEC)
2817 hp2 = NFSUSERHASH(usrp->lug_uid);
2818 mtx_lock(&hp2->mtx);
2819 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2820 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2822 *uidp = usrp->lug_uid;
2823 mtx_unlock(&hp2->mtx);
2824 mtx_unlock(&hp->mtx);
2829 mtx_unlock(&hp->mtx);
2831 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2833 if (ret == 0 && cnt < 2)
2836 error = NFSERR_BADOWNER;
2844 * Convert a gid to a string.
2845 * gid - the group id
2846 * cpp - points to a buffer of size NFSV4_SMALLSTR
2847 * (malloc a larger one, as required)
2848 * retlenp - pointer to length to be returned
2851 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2854 struct nfsusrgrp *usrp;
2857 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2858 struct nfsrv_lughash *hp;
2862 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2864 * Always map nfsrv_defaultgid to "nogroup".
2866 if (gid == nfsrv_defaultgid) {
2867 i = nfsrv_dnsnamelen + 8;
2869 if (len > NFSV4_SMALLSTR)
2870 free(cp, M_NFSSTRING);
2871 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2877 NFSBCOPY("nogroup@", cp, 8);
2879 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2883 hp = NFSGROUPHASH(gid);
2885 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2886 if (usrp->lug_gid == gid) {
2887 if (usrp->lug_expiry < NFSD_MONOSEC)
2890 * If the name doesn't already have an '@'
2891 * in it, append @domainname to it.
2893 for (i = 0; i < usrp->lug_namelen; i++) {
2894 if (usrp->lug_name[i] == '@') {
2900 i = usrp->lug_namelen;
2902 i = usrp->lug_namelen +
2903 nfsrv_dnsnamelen + 1;
2905 mtx_unlock(&hp->mtx);
2906 if (len > NFSV4_SMALLSTR)
2907 free(cp, M_NFSSTRING);
2908 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2914 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2915 if (!hasampersand) {
2916 cp += usrp->lug_namelen;
2918 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2920 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2921 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2923 mtx_unlock(&hp->mtx);
2927 mtx_unlock(&hp->mtx);
2929 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2931 if (ret == 0 && cnt < 2)
2936 * No match, just return a string of digits.
2940 while (tmp || i == 0) {
2944 len = (i > len) ? len : i;
2948 for (i = 0; i < len; i++) {
2949 *cp-- = '0' + (tmp % 10);
2956 * Convert a string to a gid.
2957 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2959 * If this is called from a client side mount using AUTH_SYS and the
2960 * string is made up entirely of digits, just convert the string to
2964 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2968 char *cp, *endstr, *str0;
2969 struct nfsusrgrp *usrp;
2973 struct nfsrv_lughash *hp, *hp2;
2976 error = NFSERR_BADOWNER;
2979 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2981 tgid = (gid_t)strtoul(str0, &endstr, 10);
2982 if ((endstr - str0) == len) {
2983 /* A numeric string. */
2984 if ((nd->nd_flag & ND_KERBV) == 0 &&
2985 ((nd->nd_flag & ND_NFSCL) != 0 ||
2986 nfsd_enable_stringtouid != 0))
2989 error = NFSERR_BADOWNER;
2995 cp = strchr(str0, '@');
2997 i = (int)(cp++ - str0);
3003 if (nfsrv_dnsnamelen > 0) {
3005 * If an '@' is found and the dns name matches, search for the
3006 * name with the dns stripped off.
3008 if (cnt == 0 && i < len && i > 0 &&
3009 (len - 1 - i) == nfsrv_dnsnamelen &&
3010 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3011 len -= (nfsrv_dnsnamelen + 1);
3016 * Check for the special case of "nogroup".
3018 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3019 *gidp = nfsrv_defaultgid;
3024 hp = NFSGROUPNAMEHASH(str, len);
3026 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3027 if (usrp->lug_namelen == len &&
3028 !NFSBCMP(usrp->lug_name, str, len)) {
3029 if (usrp->lug_expiry < NFSD_MONOSEC)
3031 hp2 = NFSGROUPHASH(usrp->lug_gid);
3032 mtx_lock(&hp2->mtx);
3033 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3034 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3036 *gidp = usrp->lug_gid;
3037 mtx_unlock(&hp2->mtx);
3038 mtx_unlock(&hp->mtx);
3043 mtx_unlock(&hp->mtx);
3045 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3047 if (ret == 0 && cnt < 2)
3050 error = NFSERR_BADOWNER;
3058 * Cmp len chars, allowing mixed case in the first argument to match lower
3059 * case in the second, but not if the first argument is all upper case.
3060 * Return 0 for a match, 1 otherwise.
3063 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3069 for (i = 0; i < len; i++) {
3070 if (*cp >= 'A' && *cp <= 'Z') {
3071 tmp = *cp++ + ('a' - 'A');
3074 if (tmp >= 'a' && tmp <= 'z')
3087 * Set the port for the nfsuserd.
3090 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3092 struct nfssockreq *rp;
3093 struct sockaddr_in *ad;
3097 if (nfsrv_nfsuserd) {
3105 * Set up the socket record and connect.
3107 rp = &nfsrv_nfsuserdsock;
3108 rp->nr_client = NULL;
3109 rp->nr_sotype = SOCK_DGRAM;
3110 rp->nr_soproto = IPPROTO_UDP;
3111 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3113 NFSSOCKADDRALLOC(rp->nr_nam);
3114 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3115 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3116 ad->sin_family = AF_INET;
3117 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3118 ad->sin_port = port;
3119 rp->nr_prog = RPCPROG_NFSUSERD;
3120 rp->nr_vers = RPCNFSUSERD_VERS;
3121 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3123 NFSSOCKADDRFREE(rp->nr_nam);
3132 * Delete the nfsuserd port.
3135 nfsrv_nfsuserddelport(void)
3139 if (nfsrv_nfsuserd == 0) {
3145 newnfs_disconnect(&nfsrv_nfsuserdsock);
3146 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3150 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3152 * Returns 0 upon success, non-zero otherwise.
3155 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3158 struct nfsrv_descript *nd;
3160 struct nfsrv_descript nfsd;
3165 if (nfsrv_nfsuserd == 0) {
3172 cred = newnfs_getcred();
3173 nd->nd_flag = ND_GSSINITREPLY;
3176 nd->nd_procnum = procnum;
3177 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3179 if (procnum == RPCNFSUSERD_GETUID)
3180 *tl = txdr_unsigned(uid);
3182 *tl = txdr_unsigned(gid);
3185 (void) nfsm_strtom(nd, name, len);
3187 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3188 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3191 mbuf_freem(nd->nd_mrep);
3192 error = nd->nd_repstat;
3200 * This function is called from the nfssvc(2) system call, to update the
3201 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3204 nfssvc_idname(struct nfsd_idargs *nidp)
3206 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3207 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3208 int i, group_locked, groupname_locked, user_locked, username_locked;
3213 static int onethread = 0;
3214 static time_t lasttime = 0;
3216 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3220 if (nidp->nid_flag & NFSID_INITIALIZE) {
3221 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3222 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3225 free(cp, M_NFSSTRING);
3228 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3230 * Free up all the old stuff and reinitialize hash
3231 * lists. All mutexes for both lists must be locked,
3232 * with the user/group name ones before the uid/gid
3233 * ones, to avoid a LOR.
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 mtx_lock(&nfsusernamehash[i].mtx);
3237 for (i = 0; i < nfsrv_lughashsize; i++)
3238 mtx_lock(&nfsuserhash[i].mtx);
3239 for (i = 0; i < nfsrv_lughashsize; i++)
3240 TAILQ_FOREACH_SAFE(usrp,
3241 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3242 nfsrv_removeuser(usrp, 1);
3243 for (i = 0; i < nfsrv_lughashsize; i++)
3244 mtx_unlock(&nfsuserhash[i].mtx);
3245 for (i = 0; i < nfsrv_lughashsize; i++)
3246 mtx_unlock(&nfsusernamehash[i].mtx);
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_lock(&nfsgroupnamehash[i].mtx);
3249 for (i = 0; i < nfsrv_lughashsize; i++)
3250 mtx_lock(&nfsgrouphash[i].mtx);
3251 for (i = 0; i < nfsrv_lughashsize; i++)
3252 TAILQ_FOREACH_SAFE(usrp,
3253 &nfsgrouphash[i].lughead, lug_numhash,
3255 nfsrv_removeuser(usrp, 0);
3256 for (i = 0; i < nfsrv_lughashsize; i++)
3257 mtx_unlock(&nfsgrouphash[i].mtx);
3258 for (i = 0; i < nfsrv_lughashsize; i++)
3259 mtx_unlock(&nfsgroupnamehash[i].mtx);
3260 free(nfsrv_dnsname, M_NFSSTRING);
3261 nfsrv_dnsname = NULL;
3263 if (nfsuserhash == NULL) {
3264 /* Allocate the hash tables. */
3265 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3266 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3268 for (i = 0; i < nfsrv_lughashsize; i++)
3269 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3270 NULL, MTX_DEF | MTX_DUPOK);
3271 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3272 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3274 for (i = 0; i < nfsrv_lughashsize; i++)
3275 mtx_init(&nfsusernamehash[i].mtx,
3276 "nfsusrhash", NULL, MTX_DEF |
3278 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3279 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3281 for (i = 0; i < nfsrv_lughashsize; i++)
3282 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3283 NULL, MTX_DEF | MTX_DUPOK);
3284 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3285 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3287 for (i = 0; i < nfsrv_lughashsize; i++)
3288 mtx_init(&nfsgroupnamehash[i].mtx,
3289 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3291 /* (Re)initialize the list heads. */
3292 for (i = 0; i < nfsrv_lughashsize; i++)
3293 TAILQ_INIT(&nfsuserhash[i].lughead);
3294 for (i = 0; i < nfsrv_lughashsize; i++)
3295 TAILQ_INIT(&nfsusernamehash[i].lughead);
3296 for (i = 0; i < nfsrv_lughashsize; i++)
3297 TAILQ_INIT(&nfsgrouphash[i].lughead);
3298 for (i = 0; i < nfsrv_lughashsize; i++)
3299 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3302 * Put name in "DNS" string.
3305 nfsrv_defaultuid = nidp->nid_uid;
3306 nfsrv_defaultgid = nidp->nid_gid;
3308 nfsrv_usermax = nidp->nid_usermax;
3309 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3314 * malloc the new one now, so any potential sleep occurs before
3315 * manipulation of the lists.
3317 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3318 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3319 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3321 if (error == 0 && nidp->nid_ngroup > 0 &&
3322 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3323 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3325 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3326 sizeof(gid_t) * nidp->nid_ngroup);
3329 * Create a credential just like svc_getcred(),
3330 * but using the group list provided.
3333 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3334 crsetgroups(cr, nidp->nid_ngroup, grps);
3335 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3336 cr->cr_prison = &prison0;
3337 prison_hold(cr->cr_prison);
3339 mac_cred_associate_nfsd(cr);
3341 newusrp->lug_cred = cr;
3346 free(newusrp, M_NFSUSERGROUP);
3349 newusrp->lug_namelen = nidp->nid_namelen;
3352 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3353 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3354 * The flags user_locked, username_locked, group_locked and
3355 * groupname_locked are set to indicate all of those hash lists are
3356 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3357 * the respective one mutex is locked.
3359 user_locked = username_locked = group_locked = groupname_locked = 0;
3360 hp_name = hp_idnum = NULL;
3363 * Delete old entries, as required.
3365 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3366 /* Must lock all username hash lists first, to avoid a LOR. */
3367 for (i = 0; i < nfsrv_lughashsize; i++)
3368 mtx_lock(&nfsusernamehash[i].mtx);
3369 username_locked = 1;
3370 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3371 mtx_lock(&hp_idnum->mtx);
3372 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3374 if (usrp->lug_uid == nidp->nid_uid)
3375 nfsrv_removeuser(usrp, 1);
3377 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3378 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3379 newusrp->lug_namelen);
3380 mtx_lock(&hp_name->mtx);
3381 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3383 if (usrp->lug_namelen == newusrp->lug_namelen &&
3384 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3385 usrp->lug_namelen)) {
3386 thp = NFSUSERHASH(usrp->lug_uid);
3387 mtx_lock(&thp->mtx);
3388 nfsrv_removeuser(usrp, 1);
3389 mtx_unlock(&thp->mtx);
3392 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3393 mtx_lock(&hp_idnum->mtx);
3394 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3395 /* Must lock all groupname hash lists first, to avoid a LOR. */
3396 for (i = 0; i < nfsrv_lughashsize; i++)
3397 mtx_lock(&nfsgroupnamehash[i].mtx);
3398 groupname_locked = 1;
3399 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3400 mtx_lock(&hp_idnum->mtx);
3401 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3403 if (usrp->lug_gid == nidp->nid_gid)
3404 nfsrv_removeuser(usrp, 0);
3406 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3407 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3408 newusrp->lug_namelen);
3409 mtx_lock(&hp_name->mtx);
3410 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3412 if (usrp->lug_namelen == newusrp->lug_namelen &&
3413 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3414 usrp->lug_namelen)) {
3415 thp = NFSGROUPHASH(usrp->lug_gid);
3416 mtx_lock(&thp->mtx);
3417 nfsrv_removeuser(usrp, 0);
3418 mtx_unlock(&thp->mtx);
3421 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3422 mtx_lock(&hp_idnum->mtx);
3426 * Now, we can add the new one.
3428 if (nidp->nid_usertimeout)
3429 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3431 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3432 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3433 newusrp->lug_uid = nidp->nid_uid;
3434 thp = NFSUSERHASH(newusrp->lug_uid);
3435 mtx_assert(&thp->mtx, MA_OWNED);
3436 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3437 thp = NFSUSERNAMEHASH(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);
3441 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3442 newusrp->lug_gid = nidp->nid_gid;
3443 thp = NFSGROUPHASH(newusrp->lug_gid);
3444 mtx_assert(&thp->mtx, MA_OWNED);
3445 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3446 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3447 mtx_assert(&thp->mtx, MA_OWNED);
3448 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3449 atomic_add_int(&nfsrv_usercnt, 1);
3451 if (newusrp->lug_cred != NULL)
3452 crfree(newusrp->lug_cred);
3453 free(newusrp, M_NFSUSERGROUP);
3457 * Once per second, allow one thread to trim the cache.
3459 if (lasttime < NFSD_MONOSEC &&
3460 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3462 * First, unlock the single mutexes, so that all entries
3463 * can be locked and any LOR is avoided.
3465 if (hp_name != NULL) {
3466 mtx_unlock(&hp_name->mtx);
3469 if (hp_idnum != NULL) {
3470 mtx_unlock(&hp_idnum->mtx);
3474 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3475 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3476 if (username_locked == 0) {
3477 for (i = 0; i < nfsrv_lughashsize; i++)
3478 mtx_lock(&nfsusernamehash[i].mtx);
3479 username_locked = 1;
3481 KASSERT(user_locked == 0,
3482 ("nfssvc_idname: user_locked"));
3483 for (i = 0; i < nfsrv_lughashsize; i++)
3484 mtx_lock(&nfsuserhash[i].mtx);
3486 for (i = 0; i < nfsrv_lughashsize; i++) {
3487 TAILQ_FOREACH_SAFE(usrp,
3488 &nfsuserhash[i].lughead, lug_numhash,
3490 if (usrp->lug_expiry < NFSD_MONOSEC)
3491 nfsrv_removeuser(usrp, 1);
3493 for (i = 0; i < nfsrv_lughashsize; i++) {
3495 * Trim the cache using an approximate LRU
3496 * algorithm. This code deletes the least
3497 * recently used entry on each hash list.
3499 if (nfsrv_usercnt <= nfsrv_usermax)
3501 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3503 nfsrv_removeuser(usrp, 1);
3506 if (groupname_locked == 0) {
3507 for (i = 0; i < nfsrv_lughashsize; i++)
3508 mtx_lock(&nfsgroupnamehash[i].mtx);
3509 groupname_locked = 1;
3511 KASSERT(group_locked == 0,
3512 ("nfssvc_idname: group_locked"));
3513 for (i = 0; i < nfsrv_lughashsize; i++)
3514 mtx_lock(&nfsgrouphash[i].mtx);
3516 for (i = 0; i < nfsrv_lughashsize; i++) {
3517 TAILQ_FOREACH_SAFE(usrp,
3518 &nfsgrouphash[i].lughead, lug_numhash,
3520 if (usrp->lug_expiry < NFSD_MONOSEC)
3521 nfsrv_removeuser(usrp, 0);
3523 for (i = 0; i < nfsrv_lughashsize; i++) {
3525 * Trim the cache using an approximate LRU
3526 * algorithm. This code deletes the least
3527 * recently user entry on each hash list.
3529 if (nfsrv_usercnt <= nfsrv_usermax)
3531 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3533 nfsrv_removeuser(usrp, 0);
3536 lasttime = NFSD_MONOSEC;
3537 atomic_store_rel_int(&onethread, 0);
3540 /* Now, unlock all locked mutexes. */
3541 if (hp_idnum != NULL)
3542 mtx_unlock(&hp_idnum->mtx);
3543 if (hp_name != NULL)
3544 mtx_unlock(&hp_name->mtx);
3545 if (user_locked != 0)
3546 for (i = 0; i < nfsrv_lughashsize; i++)
3547 mtx_unlock(&nfsuserhash[i].mtx);
3548 if (username_locked != 0)
3549 for (i = 0; i < nfsrv_lughashsize; i++)
3550 mtx_unlock(&nfsusernamehash[i].mtx);
3551 if (group_locked != 0)
3552 for (i = 0; i < nfsrv_lughashsize; i++)
3553 mtx_unlock(&nfsgrouphash[i].mtx);
3554 if (groupname_locked != 0)
3555 for (i = 0; i < nfsrv_lughashsize; i++)
3556 mtx_unlock(&nfsgroupnamehash[i].mtx);
3563 * Remove a user/group name element.
3566 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3568 struct nfsrv_lughash *hp;
3571 hp = NFSUSERHASH(usrp->lug_uid);
3572 mtx_assert(&hp->mtx, MA_OWNED);
3573 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3574 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3575 mtx_assert(&hp->mtx, MA_OWNED);
3576 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3578 hp = NFSGROUPHASH(usrp->lug_gid);
3579 mtx_assert(&hp->mtx, MA_OWNED);
3580 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3581 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3582 mtx_assert(&hp->mtx, MA_OWNED);
3583 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3585 atomic_add_int(&nfsrv_usercnt, -1);
3586 if (usrp->lug_cred != NULL)
3587 crfree(usrp->lug_cred);
3588 free(usrp, M_NFSUSERGROUP);
3592 * Free up all the allocations related to the name<-->id cache.
3593 * This function should only be called when the nfsuserd daemon isn't
3594 * running, since it doesn't do any locking.
3595 * This function is meant to be used when the nfscommon module is unloaded.
3598 nfsrv_cleanusergroup(void)
3600 struct nfsrv_lughash *hp, *hp2;
3601 struct nfsusrgrp *nusrp, *usrp;
3604 if (nfsuserhash == NULL)
3607 for (i = 0; i < nfsrv_lughashsize; i++) {
3608 hp = &nfsuserhash[i];
3609 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3610 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3611 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3613 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3614 if (usrp->lug_cred != NULL)
3615 crfree(usrp->lug_cred);
3616 free(usrp, M_NFSUSERGROUP);
3618 hp = &nfsgrouphash[i];
3619 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3620 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3621 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3623 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3624 if (usrp->lug_cred != NULL)
3625 crfree(usrp->lug_cred);
3626 free(usrp, M_NFSUSERGROUP);
3628 mtx_destroy(&nfsuserhash[i].mtx);
3629 mtx_destroy(&nfsusernamehash[i].mtx);
3630 mtx_destroy(&nfsgroupnamehash[i].mtx);
3631 mtx_destroy(&nfsgrouphash[i].mtx);
3633 free(nfsuserhash, M_NFSUSERGROUP);
3634 free(nfsusernamehash, M_NFSUSERGROUP);
3635 free(nfsgrouphash, M_NFSUSERGROUP);
3636 free(nfsgroupnamehash, M_NFSUSERGROUP);
3637 free(nfsrv_dnsname, M_NFSSTRING);
3641 * This function scans a byte string and checks for UTF-8 compliance.
3642 * It returns 0 if it conforms and NFSERR_INVAL if not.
3645 nfsrv_checkutf8(u_int8_t *cp, int len)
3647 u_int32_t val = 0x0;
3648 int cnt = 0, gotd = 0, shift = 0;
3650 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3654 * Here are what the variables are used for:
3655 * val - the calculated value of a multibyte char, used to check
3656 * that it was coded with the correct range
3657 * cnt - the number of 10xxxxxx bytes to follow
3658 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3659 * shift - lower order bits of range (ie. "val >> shift" should
3660 * not be 0, in other words, dividing by the lower bound
3661 * of the range should get a non-zero value)
3662 * byte - used to calculate cnt
3666 /* This handles the 10xxxxxx bytes */
3667 if ((*cp & 0xc0) != 0x80 ||
3668 (gotd && (*cp & 0x20))) {
3669 error = NFSERR_INVAL;
3674 val |= (*cp & 0x3f);
3676 if (cnt == 0 && (val >> shift) == 0x0) {
3677 error = NFSERR_INVAL;
3680 } else if (*cp & 0x80) {
3681 /* first byte of multi byte char */
3683 while ((byte & 0x40) && cnt < 6) {
3687 if (cnt == 0 || cnt == 6) {
3688 error = NFSERR_INVAL;
3691 val = (*cp & (0x3f >> cnt));
3692 shift = utf8_shift[cnt - 1];
3693 if (cnt == 2 && val == 0xd)
3694 /* Check for the 0xd800-0xdfff case */
3701 error = NFSERR_INVAL;
3709 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3710 * strings, one with the root path in it and the other with the list of
3711 * locations. The list is in the same format as is found in nfr_refs.
3712 * It is a "," separated list of entries, where each of them is of the
3713 * form <server>:<rootpath>. For example
3714 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3715 * The nilp argument is set to 1 for the special case of a null fs_root
3716 * and an empty server list.
3717 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3718 * number of xdr bytes parsed in sump.
3721 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3722 int *sump, int *nilp)
3725 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3726 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3728 SLIST_ENTRY(list) next;
3732 SLIST_HEAD(, list) head;
3739 * Get the fs_root path and check for the special case of null path
3740 * and 0 length server list.
3742 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3743 len = fxdr_unsigned(int, *tl);
3744 if (len < 0 || len > 10240) {
3745 error = NFSERR_BADXDR;
3749 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3751 error = NFSERR_BADXDR;
3755 *sump = 2 * NFSX_UNSIGNED;
3759 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3760 error = nfsrv_mtostr(nd, cp, len);
3762 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3763 cnt = fxdr_unsigned(int, *tl);
3765 error = NFSERR_BADXDR;
3771 * Now, loop through the location list and make up the srvlist.
3773 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3774 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3777 for (i = 0; i < cnt; i++) {
3779 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3780 nsrv = fxdr_unsigned(int, *tl);
3782 error = NFSERR_BADXDR;
3787 * Handle the first server by putting it in the srvstr.
3789 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3790 len = fxdr_unsigned(int, *tl);
3791 if (len <= 0 || len > 1024) {
3792 error = NFSERR_BADXDR;
3795 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3800 error = nfsrv_mtostr(nd, cp3, len);
3806 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3807 for (j = 1; j < nsrv; j++) {
3809 * Yuck, put them in an slist and process them later.
3811 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3812 len = fxdr_unsigned(int, *tl);
3813 if (len <= 0 || len > 1024) {
3814 error = NFSERR_BADXDR;
3817 lsp = (struct list *)malloc(sizeof (struct list)
3818 + len, M_TEMP, M_WAITOK);
3819 error = nfsrv_mtostr(nd, lsp->host, len);
3822 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3824 SLIST_INSERT_HEAD(&head, lsp, next);
3828 * Finally, we can get the path.
3830 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3831 len = fxdr_unsigned(int, *tl);
3832 if (len <= 0 || len > 1024) {
3833 error = NFSERR_BADXDR;
3836 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3837 error = nfsrv_mtostr(nd, cp3, len);
3840 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3845 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3846 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3849 NFSBCOPY(lsp->host, cp3, lsp->len);
3852 NFSBCOPY(str, cp3, stringlen);
3855 siz += (lsp->len + stringlen + 2);
3856 free((caddr_t)lsp, M_TEMP);
3862 NFSEXITCODE2(0, nd);
3866 free(cp, M_NFSSTRING);
3868 free(cp2, M_NFSSTRING);
3869 NFSEXITCODE2(error, nd);
3874 * Make the malloc'd space large enough. This is a pain, but the xdr
3875 * doesn't set an upper bound on the side, so...
3878 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3885 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3886 NFSBCOPY(*cpp, cp, *slenp);
3887 free(*cpp, M_NFSSTRING);
3891 *slenp = siz + 1024;
3895 * Initialize the reply header data structures.
3898 nfsrvd_rephead(struct nfsrv_descript *nd)
3903 * If this is a big reply, use a cluster.
3905 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3906 nfs_bigreply[nd->nd_procnum]) {
3907 NFSMCLGET(mreq, M_WAITOK);
3915 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3916 mbuf_setlen(mreq, 0);
3918 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3919 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3923 * Lock a socket against others.
3924 * Currently used to serialize connect/disconnect attempts.
3927 newnfs_sndlock(int *flagp)
3932 while (*flagp & NFSR_SNDLOCK) {
3933 *flagp |= NFSR_WANTSND;
3936 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3937 PZERO - 1, "nfsndlck", &ts);
3939 *flagp |= NFSR_SNDLOCK;
3945 * Unlock the stream socket for others.
3948 newnfs_sndunlock(int *flagp)
3952 if ((*flagp & NFSR_SNDLOCK) == 0)
3953 panic("nfs sndunlock");
3954 *flagp &= ~NFSR_SNDLOCK;
3955 if (*flagp & NFSR_WANTSND) {
3956 *flagp &= ~NFSR_WANTSND;
3957 wakeup((caddr_t)flagp);
3963 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3966 struct sockaddr_in *sad;
3967 struct sockaddr_in6 *sad6;
3968 struct in_addr saddr;
3969 uint32_t portnum, *tl;
3970 int af = 0, i, j, k;
3971 char addr[64], protocol[5], *cp;
3972 int cantparse = 0, error = 0;
3975 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3976 i = fxdr_unsigned(int, *tl);
3977 if (i >= 3 && i <= 4) {
3978 error = nfsrv_mtostr(nd, protocol, i);
3981 if (strcmp(protocol, "tcp") == 0) {
3984 } else if (strcmp(protocol, "udp") == 0) {
3987 } else if (strcmp(protocol, "tcp6") == 0) {
3990 } else if (strcmp(protocol, "udp6") == 0) {
3998 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4004 i = fxdr_unsigned(int, *tl);
4006 error = NFSERR_BADXDR;
4008 } else if (cantparse == 0 && i >= 11 && i < 64) {
4010 * The shortest address is 11chars and the longest is < 64.
4012 error = nfsrv_mtostr(nd, addr, i);
4016 /* Find the port# at the end and extract that. */
4020 /* Count back two '.'s from end to get port# field. */
4021 for (j = 0; j < i; j++) {
4031 * The NFSv4 port# is appended as .N.N, where N is
4032 * a decimal # in the range 0-255, just like an inet4
4033 * address. Cheat and use inet_aton(), which will
4034 * return a Class A address and then shift the high
4035 * order 8bits over to convert it to the port#.
4038 if (inet_aton(cp, &saddr) == 1) {
4039 portnum = ntohl(saddr.s_addr);
4040 portv = (uint16_t)((portnum >> 16) |
4046 if (cantparse == 0) {
4047 if (af == AF_INET) {
4048 sad = (struct sockaddr_in *)sa;
4049 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4050 sad->sin_len = sizeof(*sad);
4051 sad->sin_family = AF_INET;
4052 sad->sin_port = htons(portv);
4056 sad6 = (struct sockaddr_in6 *)sa;
4057 if (inet_pton(af, addr, &sad6->sin6_addr)
4059 sad6->sin6_len = sizeof(*sad6);
4060 sad6->sin6_family = AF_INET6;
4061 sad6->sin6_port = htons(portv);
4068 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4079 * Handle an NFSv4.1 Sequence request for the session.
4080 * If reply != NULL, use it to return the cached reply, as required.
4081 * The client gets a cached reply via this call for callbacks, however the
4082 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4085 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4086 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4093 if (slotid > maxslot)
4094 return (NFSERR_BADSLOT);
4095 if (seqid == slots[slotid].nfssl_seq) {
4097 if (slots[slotid].nfssl_inprog != 0)
4098 error = NFSERR_DELAY;
4099 else if (slots[slotid].nfssl_reply != NULL) {
4100 if (reply != NULL) {
4101 *reply = slots[slotid].nfssl_reply;
4102 slots[slotid].nfssl_reply = NULL;
4104 slots[slotid].nfssl_inprog = 1;
4105 error = NFSERR_REPLYFROMCACHE;
4107 /* No reply cached, so just do it. */
4108 slots[slotid].nfssl_inprog = 1;
4109 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4110 if (slots[slotid].nfssl_reply != NULL)
4111 m_freem(slots[slotid].nfssl_reply);
4112 slots[slotid].nfssl_reply = NULL;
4113 slots[slotid].nfssl_inprog = 1;
4114 slots[slotid].nfssl_seq++;
4116 error = NFSERR_SEQMISORDERED;
4121 * Cache this reply for the slot.
4122 * Use the "rep" argument to return the cached reply if repstat is set to
4123 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4126 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4130 if (repstat == NFSERR_REPLYFROMCACHE) {
4131 *rep = slots[slotid].nfssl_reply;
4132 slots[slotid].nfssl_reply = NULL;
4134 if (slots[slotid].nfssl_reply != NULL)
4135 m_freem(slots[slotid].nfssl_reply);
4136 slots[slotid].nfssl_reply = *rep;
4138 slots[slotid].nfssl_inprog = 0;
4142 * Generate the xdr for an NFSv4.1 Sequence Operation.
4145 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4146 struct nfsclsession *sep, int dont_replycache)
4148 uint32_t *tl, slotseq = 0;
4149 int error, maxslot, slotpos;
4150 uint8_t sessionid[NFSX_V4SESSIONID];
4152 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4155 /* Build the Sequence arguments. */
4156 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4157 nd->nd_sequence = tl;
4158 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4159 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4160 nd->nd_slotseq = tl;
4162 *tl++ = txdr_unsigned(slotseq);
4163 *tl++ = txdr_unsigned(slotpos);
4164 *tl++ = txdr_unsigned(maxslot);
4165 if (dont_replycache == 0)
4171 * There are two errors and the rest of the session can
4173 * NFSERR_BADSESSION: This bad session should just generate
4174 * the same error again when the RPC is retried.
4175 * ESTALE: A forced dismount is in progress and will cause the
4176 * RPC to fail later.
4183 nd->nd_flag |= ND_HASSEQUENCE;
4187 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4188 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4190 int i, maxslot, slotpos;
4193 /* Find an unused slot. */
4196 mtx_lock(&sep->nfsess_mtx);
4198 if (nmp != NULL && sep->nfsess_defunct != 0) {
4199 /* Just return the bad session. */
4200 bcopy(sep->nfsess_sessionid, sessionid,
4202 mtx_unlock(&sep->nfsess_mtx);
4203 return (NFSERR_BADSESSION);
4206 for (i = 0; i < sep->nfsess_foreslots; i++) {
4207 if ((bitval & sep->nfsess_slots) == 0) {
4209 sep->nfsess_slots |= bitval;
4210 sep->nfsess_slotseq[i]++;
4211 *slotseqp = sep->nfsess_slotseq[i];
4216 if (slotpos == -1) {
4218 * If a forced dismount is in progress, just return.
4219 * This RPC attempt will fail when it calls
4222 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4223 mtx_unlock(&sep->nfsess_mtx);
4226 /* Wake up once/sec, to check for a forced dismount. */
4227 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4228 PZERO, "nfsclseq", hz);
4230 } while (slotpos == -1);
4231 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4233 for (i = 0; i < 64; i++) {
4234 if ((bitval & sep->nfsess_slots) != 0)
4238 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4239 mtx_unlock(&sep->nfsess_mtx);
4240 *slotposp = slotpos;
4241 *maxslotp = maxslot;
4246 * Free a session slot.
4249 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4256 mtx_lock(&sep->nfsess_mtx);
4257 if ((bitval & sep->nfsess_slots) == 0)
4258 printf("freeing free slot!!\n");
4259 sep->nfsess_slots &= ~bitval;
4260 wakeup(&sep->nfsess_slots);
4261 mtx_unlock(&sep->nfsess_mtx);