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;
73 extern int nfsrv_lughashsize;
76 * This array of structures indicates, for V4:
77 * retfh - which of 3 types of calling args are used
78 * 0 - doesn't change cfh or use a sfh
79 * 1 - replaces cfh with a new one (unless it returns an error status)
80 * 2 - uses cfh and sfh
81 * needscfh - if the op wants a cfh and premtime
82 * 0 - doesn't use a cfh
83 * 1 - uses a cfh, but doesn't want pre-op attributes
84 * 2 - uses a cfh and wants pre-op attributes
85 * savereply - indicates a non-idempotent Op
86 * 0 - not non-idempotent
88 * Ops that are ordered via seqid# are handled separately from these
90 * Define it here, since it is used by both the client and server.
92 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
93 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
94 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
95 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
96 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
98 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
99 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
102 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
104 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
108 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
109 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
111 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
112 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
116 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
117 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
118 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
119 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
121 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
131 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
153 #endif /* !APPLEKEXT */
155 static int ncl_mbuf_mhlen = MHLEN;
156 static int nfsrv_usercnt = 0;
157 static int nfsrv_dnsnamelen;
158 static u_char *nfsrv_dnsname = NULL;
159 static int nfsrv_usermax = 999999999;
160 struct nfsrv_lughash {
162 struct nfsuserhashhead lughead;
164 static struct nfsrv_lughash *nfsuserhash;
165 static struct nfsrv_lughash *nfsusernamehash;
166 static struct nfsrv_lughash *nfsgrouphash;
167 static struct nfsrv_lughash *nfsgroupnamehash;
170 * This static array indicates whether or not the RPC generates a large
171 * reply. This is used by nfs_reply() to decide whether or not an mbuf
172 * cluster should be allocated. (If a cluster is required by an RPC
173 * marked 0 in this array, the code will still work, just not quite as
176 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
180 /* local functions */
181 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
182 static void nfsv4_wanted(struct nfsv4lock *lp);
183 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
184 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
186 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
187 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
189 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
194 * copies mbuf chain to the uio scatter/gather list
197 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
199 char *mbufcp, *uiocp;
206 mbufcp = nd->nd_dpos;
207 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
208 rem = NFSM_RNDUP(siz) - siz;
210 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
214 left = uiop->uio_iov->iov_len;
215 uiocp = uiop->uio_iov->iov_base;
226 mbufcp = NFSMTOD(mp, caddr_t);
229 ("len %d, corrupted mbuf?", len));
231 xfer = (left > len) ? len : left;
234 if (uiop->uio_iov->iov_op != NULL)
235 (*(uiop->uio_iov->iov_op))
236 (mbufcp, uiocp, xfer);
239 if (uiop->uio_segflg == UIO_SYSSPACE)
240 NFSBCOPY(mbufcp, uiocp, xfer);
242 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
247 uiop->uio_offset += xfer;
248 uiop->uio_resid -= xfer;
250 if (uiop->uio_iov->iov_len <= siz) {
254 uiop->uio_iov->iov_base = (void *)
255 ((char *)uiop->uio_iov->iov_base + uiosiz);
256 uiop->uio_iov->iov_len -= uiosiz;
260 nd->nd_dpos = mbufcp;
264 error = nfsm_advance(nd, rem, len);
270 NFSEXITCODE2(error, nd);
276 * Help break down an mbuf chain by setting the first siz bytes contiguous
277 * pointed to by returned val.
278 * This is used by the macro NFSM_DISSECT for tough
282 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
291 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
293 nd->nd_md = mbuf_next(nd->nd_md);
294 if (nd->nd_md == NULL)
296 left = mbuf_len(nd->nd_md);
297 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
302 } else if (mbuf_next(nd->nd_md) == NULL) {
304 } else if (siz > ncl_mbuf_mhlen) {
305 panic("nfs S too big");
307 MGET(mp2, MT_DATA, how);
310 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
311 mbuf_setnext(nd->nd_md, mp2);
312 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
314 retp = p = NFSMTOD(mp2, caddr_t);
315 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
318 mp2 = mbuf_next(mp2);
319 /* Loop around copying up the siz2 bytes */
323 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
325 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
326 NFSM_DATAP(mp2, xfer);
327 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
332 mp2 = mbuf_next(mp2);
334 mbuf_setlen(nd->nd_md, siz);
336 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
342 * Advance the position in the mbuf chain.
343 * If offs == 0, this is a no-op, but it is simpler to just return from
344 * here than check for offs > 0 for all calls to nfsm_advance.
345 * If left == -1, it should be calculated here.
348 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
355 * A negative offs should be considered a serious problem.
358 panic("nfsrv_advance");
361 * If left == -1, calculate it here.
364 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
368 * Loop around, advancing over the mbuf data.
370 while (offs > left) {
372 nd->nd_md = mbuf_next(nd->nd_md);
373 if (nd->nd_md == NULL) {
377 left = mbuf_len(nd->nd_md);
378 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
388 * Copy a string into mbuf(s).
389 * Return the number of bytes output, including XDR overheads.
392 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
402 *tl = txdr_unsigned(siz);
403 rem = NFSM_RNDUP(siz) - siz;
404 bytesize = NFSX_UNSIGNED + siz + rem;
407 left = M_TRAILINGSPACE(m2);
410 * Loop around copying the string to mbuf(s).
414 if (siz > ncl_mbuf_mlen)
415 NFSMCLGET(m1, M_WAITOK);
419 mbuf_setnext(m2, m1);
421 cp2 = NFSMTOD(m2, caddr_t);
422 left = M_TRAILINGSPACE(m2);
428 NFSBCOPY(cp, cp2, xfer);
430 mbuf_setlen(m2, mbuf_len(m2) + xfer);
433 if (siz == 0 && rem) {
435 panic("nfsm_strtom");
436 NFSBZERO(cp2 + xfer, rem);
437 mbuf_setlen(m2, mbuf_len(m2) + rem);
441 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
446 * Called once to initialize data structures...
451 static int nfs_inited = 0;
457 newnfs_true = txdr_unsigned(TRUE);
458 newnfs_false = txdr_unsigned(FALSE);
459 newnfs_xdrneg1 = txdr_unsigned(-1);
460 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
463 NFSSETBOOTTIME(nfsboottime);
466 * Initialize reply list and start timer
468 TAILQ_INIT(&nfsd_reqq);
473 * Put a file handle in an mbuf list.
474 * If the size argument == 0, just use the default size.
475 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
476 * Return the number of bytes output, including XDR overhead.
479 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
483 int fullsiz, rem, bytesize = 0;
487 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
489 if (size > NFSX_V2FH)
490 panic("fh size > NFSX_V2FH for NFSv2");
491 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
492 NFSBCOPY(fhp, cp, size);
493 if (size < NFSX_V2FH)
494 NFSBZERO(cp + size, NFSX_V2FH - size);
495 bytesize = NFSX_V2FH;
499 fullsiz = NFSM_RNDUP(size);
500 rem = fullsiz - size;
502 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
503 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
506 bytesize = NFSX_UNSIGNED + fullsiz;
508 (void) nfsm_strtom(nd, fhp, size);
515 * This function compares two net addresses by family and returns TRUE
516 * if they are the same host.
517 * If there is any doubt, return FALSE.
518 * The AF_INET family is handled as a special case so that address mbufs
519 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
522 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
524 struct sockaddr_in *inetaddr;
528 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
529 if (inetaddr->sin_family == AF_INET &&
530 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
536 struct sockaddr_in6 *inetaddr6;
538 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
539 /* XXX - should test sin6_scope_id ? */
540 if (inetaddr6->sin6_family == AF_INET6 &&
541 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
552 * Similar to the above, but takes to NFSSOCKADDR_T args.
555 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
557 struct sockaddr_in *addr1, *addr2;
558 struct sockaddr *inaddr;
560 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
561 switch (inaddr->sa_family) {
563 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
564 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
565 if (addr2->sin_family == AF_INET &&
566 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
572 struct sockaddr_in6 *inet6addr1, *inet6addr2;
574 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
575 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
576 /* XXX - should test sin6_scope_id ? */
577 if (inet6addr2->sin6_family == AF_INET6 &&
578 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
579 &inet6addr2->sin6_addr))
590 * Trim the stuff already dissected off the mbuf list.
593 newnfs_trimleading(nd)
594 struct nfsrv_descript *nd;
600 * First, free up leading mbufs.
602 if (nd->nd_mrep != nd->nd_md) {
604 while (mbuf_next(m) != nd->nd_md) {
605 if (mbuf_next(m) == NULL)
606 panic("nfsm trim leading");
609 mbuf_setnext(m, NULL);
610 mbuf_freem(nd->nd_mrep);
615 * Now, adjust this mbuf, based on nd_dpos.
617 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
618 if (offs == mbuf_len(m)) {
622 panic("nfsm trim leading2");
623 mbuf_setnext(n, NULL);
625 } else if (offs > 0) {
626 mbuf_setlen(m, mbuf_len(m) - offs);
629 panic("nfsm trimleading offs");
632 nd->nd_dpos = NFSMTOD(m, caddr_t);
636 * Trim trailing data off the mbuf list being built.
639 newnfs_trimtrailing(nd, mb, bpos)
640 struct nfsrv_descript *nd;
646 mbuf_freem(mbuf_next(mb));
647 mbuf_setnext(mb, NULL);
649 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
655 * Dissect a file handle on the client.
658 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
665 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
667 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
674 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
676 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
678 FREE((caddr_t)nfhp, M_NFSFH);
684 NFSEXITCODE2(error, nd);
689 * Break down the nfsv4 acl.
690 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
693 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
694 int *aclsizep, __unused NFSPROC_T *p)
698 int acecnt, error = 0, aceerr = 0, acesize;
704 * Parse out the ace entries and expect them to conform to
705 * what can be supported by R/W/X bits.
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
708 aclsize = NFSX_UNSIGNED;
709 acecnt = fxdr_unsigned(int, *tl);
710 if (acecnt > ACL_MAX_ENTRIES)
711 aceerr = NFSERR_ATTRNOTSUPP;
712 if (nfsrv_useacl == 0)
713 aceerr = NFSERR_ATTRNOTSUPP;
714 for (i = 0; i < acecnt; i++) {
716 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
717 &aceerr, &acesize, p);
719 error = nfsrv_skipace(nd, &acesize);
725 aclp->acl_cnt = acecnt;
731 NFSEXITCODE2(error, nd);
736 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
739 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
745 len = fxdr_unsigned(int, *(tl + 3));
746 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
748 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
749 NFSEXITCODE2(error, nd);
754 * Get attribute bits from an mbuf list.
755 * Returns EBADRPC for a parsing error, 0 otherwise.
756 * If the clearinvalid flag is set, clear the bits not supported.
759 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
767 cnt = fxdr_unsigned(int, *tl);
769 error = NFSERR_BADXDR;
772 if (cnt > NFSATTRBIT_MAXWORDS)
773 outcnt = NFSATTRBIT_MAXWORDS;
776 NFSZERO_ATTRBIT(attrbitp);
778 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
779 for (i = 0; i < outcnt; i++)
780 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
782 for (i = 0; i < (cnt - outcnt); i++) {
783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
784 if (retnotsupp != NULL && *tl != 0)
785 *retnotsupp = NFSERR_ATTRNOTSUPP;
788 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
790 NFSEXITCODE2(error, nd);
795 * Get the attributes for V4.
796 * If the compare flag is true, test for any attribute changes,
797 * otherwise return the attribute values.
798 * These attributes cover fields in "struct vattr", "struct statfs",
799 * "struct nfsfsinfo", the file handle and the lease duration.
800 * The value of retcmpp is set to 1 if all attributes are the same,
802 * Returns EBADRPC if it can't be parsed, 0 otherwise.
805 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
806 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
807 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
808 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
809 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
812 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
813 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
814 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
815 nfsattrbit_t attrbits, retattrbits, checkattrbits;
817 struct nfsreferral *refp;
820 struct timespec temptime;
824 u_int32_t freenum = 0, tuint;
825 u_int64_t uquad = 0, thyp, thyp2;
830 static struct timeval last64fileid;
831 static size_t count64fileid;
832 static struct timeval last64mountfileid;
833 static size_t count64mountfileid;
834 static struct timeval warninterval = { 60, 0 };
838 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
840 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
846 *retcmpp = retnotsup;
849 * Just set default values to some of the important ones.
854 nap->na_rdev = (NFSDEV_T)0;
855 nap->na_mtime.tv_sec = 0;
856 nap->na_mtime.tv_nsec = 0;
859 nap->na_blocksize = NFS_FABLKSIZE;
862 sbp->f_bsize = NFS_FABLKSIZE;
870 fsp->fs_rtmax = 8192;
871 fsp->fs_rtpref = 8192;
872 fsp->fs_maxname = NFS_MAXNAMLEN;
873 fsp->fs_wtmax = 8192;
874 fsp->fs_wtpref = 8192;
875 fsp->fs_wtmult = NFS_FABLKSIZE;
876 fsp->fs_dtpref = 8192;
877 fsp->fs_maxfilesize = 0xffffffffffffffffull;
878 fsp->fs_timedelta.tv_sec = 0;
879 fsp->fs_timedelta.tv_nsec = 1;
880 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
881 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
884 pc->pc_linkmax = LINK_MAX;
885 pc->pc_namemax = NAME_MAX;
887 pc->pc_chownrestricted = 0;
888 pc->pc_caseinsensitive = 0;
889 pc->pc_casepreserving = 1;
892 sfp->sf_ffiles = UINT64_MAX;
893 sfp->sf_tfiles = UINT64_MAX;
894 sfp->sf_afiles = UINT64_MAX;
895 sfp->sf_fbytes = UINT64_MAX;
896 sfp->sf_tbytes = UINT64_MAX;
897 sfp->sf_abytes = UINT64_MAX;
902 * Loop around getting the attributes.
904 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
905 attrsize = fxdr_unsigned(int, *tl);
906 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
907 if (attrsum > attrsize) {
908 error = NFSERR_BADXDR;
911 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
913 case NFSATTRBIT_SUPPORTEDATTRS:
915 if (compare || nap == NULL)
916 error = nfsrv_getattrbits(nd, &retattrbits,
919 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
923 if (compare && !(*retcmpp)) {
924 NFSSETSUPP_ATTRBIT(&checkattrbits);
925 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
927 *retcmpp = NFSERR_NOTSAME;
931 case NFSATTRBIT_TYPE:
932 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
935 if (nap->na_type != nfsv34tov_type(*tl))
936 *retcmpp = NFSERR_NOTSAME;
938 } else if (nap != NULL) {
939 nap->na_type = nfsv34tov_type(*tl);
941 attrsum += NFSX_UNSIGNED;
943 case NFSATTRBIT_FHEXPIRETYPE:
944 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
945 if (compare && !(*retcmpp)) {
946 if (fxdr_unsigned(int, *tl) !=
947 NFSV4FHTYPE_PERSISTENT)
948 *retcmpp = NFSERR_NOTSAME;
950 attrsum += NFSX_UNSIGNED;
952 case NFSATTRBIT_CHANGE:
953 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
956 if (nap->na_filerev != fxdr_hyper(tl))
957 *retcmpp = NFSERR_NOTSAME;
959 } else if (nap != NULL) {
960 nap->na_filerev = fxdr_hyper(tl);
962 attrsum += NFSX_HYPER;
964 case NFSATTRBIT_SIZE:
965 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
968 if (nap->na_size != fxdr_hyper(tl))
969 *retcmpp = NFSERR_NOTSAME;
971 } else if (nap != NULL) {
972 nap->na_size = fxdr_hyper(tl);
974 attrsum += NFSX_HYPER;
976 case NFSATTRBIT_LINKSUPPORT:
977 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
980 if (fsp->fs_properties & NFSV3_FSFLINK) {
981 if (*tl == newnfs_false)
982 *retcmpp = NFSERR_NOTSAME;
984 if (*tl == newnfs_true)
985 *retcmpp = NFSERR_NOTSAME;
988 } else if (fsp != NULL) {
989 if (*tl == newnfs_true)
990 fsp->fs_properties |= NFSV3_FSFLINK;
992 fsp->fs_properties &= ~NFSV3_FSFLINK;
994 attrsum += NFSX_UNSIGNED;
996 case NFSATTRBIT_SYMLINKSUPPORT:
997 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1000 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1001 if (*tl == newnfs_false)
1002 *retcmpp = NFSERR_NOTSAME;
1004 if (*tl == newnfs_true)
1005 *retcmpp = NFSERR_NOTSAME;
1008 } else if (fsp != NULL) {
1009 if (*tl == newnfs_true)
1010 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1012 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1014 attrsum += NFSX_UNSIGNED;
1016 case NFSATTRBIT_NAMEDATTR:
1017 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1018 if (compare && !(*retcmpp)) {
1019 if (*tl != newnfs_false)
1020 *retcmpp = NFSERR_NOTSAME;
1022 attrsum += NFSX_UNSIGNED;
1024 case NFSATTRBIT_FSID:
1025 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1026 thyp = fxdr_hyper(tl);
1028 thyp2 = fxdr_hyper(tl);
1030 if (*retcmpp == 0) {
1031 if (thyp != (u_int64_t)
1032 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1033 thyp2 != (u_int64_t)
1034 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1035 *retcmpp = NFSERR_NOTSAME;
1037 } else if (nap != NULL) {
1038 nap->na_filesid[0] = thyp;
1039 nap->na_filesid[1] = thyp2;
1041 attrsum += (4 * NFSX_UNSIGNED);
1043 case NFSATTRBIT_UNIQUEHANDLES:
1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1045 if (compare && !(*retcmpp)) {
1046 if (*tl != newnfs_true)
1047 *retcmpp = NFSERR_NOTSAME;
1049 attrsum += NFSX_UNSIGNED;
1051 case NFSATTRBIT_LEASETIME:
1052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1054 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1056 *retcmpp = NFSERR_NOTSAME;
1057 } else if (leasep != NULL) {
1058 *leasep = fxdr_unsigned(u_int32_t, *tl);
1060 attrsum += NFSX_UNSIGNED;
1062 case NFSATTRBIT_RDATTRERROR:
1063 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1066 *retcmpp = NFSERR_INVAL;
1067 } else if (rderrp != NULL) {
1068 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1070 attrsum += NFSX_UNSIGNED;
1072 case NFSATTRBIT_ACL:
1078 naclp = acl_alloc(M_WAITOK);
1079 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1085 if (aceerr || aclp == NULL ||
1086 nfsrv_compareacl(aclp, naclp))
1087 *retcmpp = NFSERR_NOTSAME;
1090 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1092 *retcmpp = NFSERR_ATTRNOTSUPP;
1096 if (vp != NULL && aclp != NULL)
1097 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1100 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1107 case NFSATTRBIT_ACLSUPPORT:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 if (compare && !(*retcmpp)) {
1111 if (fxdr_unsigned(u_int32_t, *tl) !=
1113 *retcmpp = NFSERR_NOTSAME;
1115 *retcmpp = NFSERR_ATTRNOTSUPP;
1118 attrsum += NFSX_UNSIGNED;
1120 case NFSATTRBIT_ARCHIVE:
1121 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1122 if (compare && !(*retcmpp))
1123 *retcmpp = NFSERR_ATTRNOTSUPP;
1124 attrsum += NFSX_UNSIGNED;
1126 case NFSATTRBIT_CANSETTIME:
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1130 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1131 if (*tl == newnfs_false)
1132 *retcmpp = NFSERR_NOTSAME;
1134 if (*tl == newnfs_true)
1135 *retcmpp = NFSERR_NOTSAME;
1138 } else if (fsp != NULL) {
1139 if (*tl == newnfs_true)
1140 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1142 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1144 attrsum += NFSX_UNSIGNED;
1146 case NFSATTRBIT_CASEINSENSITIVE:
1147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1150 if (*tl != newnfs_false)
1151 *retcmpp = NFSERR_NOTSAME;
1153 } else if (pc != NULL) {
1154 pc->pc_caseinsensitive =
1155 fxdr_unsigned(u_int32_t, *tl);
1157 attrsum += NFSX_UNSIGNED;
1159 case NFSATTRBIT_CASEPRESERVING:
1160 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1163 if (*tl != newnfs_true)
1164 *retcmpp = NFSERR_NOTSAME;
1166 } else if (pc != NULL) {
1167 pc->pc_casepreserving =
1168 fxdr_unsigned(u_int32_t, *tl);
1170 attrsum += NFSX_UNSIGNED;
1172 case NFSATTRBIT_CHOWNRESTRICTED:
1173 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1176 if (*tl != newnfs_true)
1177 *retcmpp = NFSERR_NOTSAME;
1179 } else if (pc != NULL) {
1180 pc->pc_chownrestricted =
1181 fxdr_unsigned(u_int32_t, *tl);
1183 attrsum += NFSX_UNSIGNED;
1185 case NFSATTRBIT_FILEHANDLE:
1186 error = nfsm_getfh(nd, &tnfhp);
1189 tfhsize = tnfhp->nfh_len;
1192 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1194 *retcmpp = NFSERR_NOTSAME;
1195 FREE((caddr_t)tnfhp, M_NFSFH);
1196 } else if (nfhpp != NULL) {
1199 FREE((caddr_t)tnfhp, M_NFSFH);
1201 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1203 case NFSATTRBIT_FILEID:
1204 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1205 thyp = fxdr_hyper(tl);
1208 if ((u_int64_t)nap->na_fileid != thyp)
1209 *retcmpp = NFSERR_NOTSAME;
1211 } else if (nap != NULL) {
1214 if (ratecheck(&last64fileid, &warninterval)) {
1215 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1220 nap->na_fileid = thyp;
1222 attrsum += NFSX_HYPER;
1224 case NFSATTRBIT_FILESAVAIL:
1225 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1228 sfp->sf_afiles != fxdr_hyper(tl))
1229 *retcmpp = NFSERR_NOTSAME;
1230 } else if (sfp != NULL) {
1231 sfp->sf_afiles = fxdr_hyper(tl);
1233 attrsum += NFSX_HYPER;
1235 case NFSATTRBIT_FILESFREE:
1236 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1239 sfp->sf_ffiles != fxdr_hyper(tl))
1240 *retcmpp = NFSERR_NOTSAME;
1241 } else if (sfp != NULL) {
1242 sfp->sf_ffiles = fxdr_hyper(tl);
1244 attrsum += NFSX_HYPER;
1246 case NFSATTRBIT_FILESTOTAL:
1247 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1250 sfp->sf_tfiles != fxdr_hyper(tl))
1251 *retcmpp = NFSERR_NOTSAME;
1252 } else if (sfp != NULL) {
1253 sfp->sf_tfiles = fxdr_hyper(tl);
1255 attrsum += NFSX_HYPER;
1257 case NFSATTRBIT_FSLOCATIONS:
1258 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1262 if (compare && !(*retcmpp)) {
1263 refp = nfsv4root_getreferral(vp, NULL, 0);
1265 if (cp == NULL || cp2 == NULL ||
1267 strcmp(cp2, refp->nfr_srvlist))
1268 *retcmpp = NFSERR_NOTSAME;
1269 } else if (m == 0) {
1270 *retcmpp = NFSERR_NOTSAME;
1274 free(cp, M_NFSSTRING);
1276 free(cp2, M_NFSSTRING);
1278 case NFSATTRBIT_HIDDEN:
1279 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1280 if (compare && !(*retcmpp))
1281 *retcmpp = NFSERR_ATTRNOTSUPP;
1282 attrsum += NFSX_UNSIGNED;
1284 case NFSATTRBIT_HOMOGENEOUS:
1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1288 if (fsp->fs_properties &
1289 NFSV3_FSFHOMOGENEOUS) {
1290 if (*tl == newnfs_false)
1291 *retcmpp = NFSERR_NOTSAME;
1293 if (*tl == newnfs_true)
1294 *retcmpp = NFSERR_NOTSAME;
1297 } else if (fsp != NULL) {
1298 if (*tl == newnfs_true)
1299 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1301 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1303 attrsum += NFSX_UNSIGNED;
1305 case NFSATTRBIT_MAXFILESIZE:
1306 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1307 tnfsquad.qval = fxdr_hyper(tl);
1310 tquad = NFSRV_MAXFILESIZE;
1311 if (tquad != tnfsquad.qval)
1312 *retcmpp = NFSERR_NOTSAME;
1314 } else if (fsp != NULL) {
1315 fsp->fs_maxfilesize = tnfsquad.qval;
1317 attrsum += NFSX_HYPER;
1319 case NFSATTRBIT_MAXLINK:
1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1323 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1324 *retcmpp = NFSERR_NOTSAME;
1326 } else if (pc != NULL) {
1327 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1329 attrsum += NFSX_UNSIGNED;
1331 case NFSATTRBIT_MAXNAME:
1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1335 if (fsp->fs_maxname !=
1336 fxdr_unsigned(u_int32_t, *tl))
1337 *retcmpp = NFSERR_NOTSAME;
1340 tuint = fxdr_unsigned(u_int32_t, *tl);
1342 * Some Linux NFSv4 servers report this
1343 * as 0 or 4billion, so I'll set it to
1344 * NFS_MAXNAMLEN. If a server actually creates
1345 * a name longer than NFS_MAXNAMLEN, it will
1346 * get an error back.
1348 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1349 tuint = NFS_MAXNAMLEN;
1351 fsp->fs_maxname = tuint;
1353 pc->pc_namemax = tuint;
1355 attrsum += NFSX_UNSIGNED;
1357 case NFSATTRBIT_MAXREAD:
1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1361 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1362 *(tl + 1)) || *tl != 0)
1363 *retcmpp = NFSERR_NOTSAME;
1365 } else if (fsp != NULL) {
1366 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1367 fsp->fs_rtpref = fsp->fs_rtmax;
1368 fsp->fs_dtpref = fsp->fs_rtpref;
1370 attrsum += NFSX_HYPER;
1372 case NFSATTRBIT_MAXWRITE:
1373 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1376 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1377 *(tl + 1)) || *tl != 0)
1378 *retcmpp = NFSERR_NOTSAME;
1380 } else if (fsp != NULL) {
1381 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1382 fsp->fs_wtpref = fsp->fs_wtmax;
1384 attrsum += NFSX_HYPER;
1386 case NFSATTRBIT_MIMETYPE:
1387 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1388 i = fxdr_unsigned(int, *tl);
1389 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1390 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1393 if (compare && !(*retcmpp))
1394 *retcmpp = NFSERR_ATTRNOTSUPP;
1396 case NFSATTRBIT_MODE:
1397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1400 if (nap->na_mode != nfstov_mode(*tl))
1401 *retcmpp = NFSERR_NOTSAME;
1403 } else if (nap != NULL) {
1404 nap->na_mode = nfstov_mode(*tl);
1406 attrsum += NFSX_UNSIGNED;
1408 case NFSATTRBIT_NOTRUNC:
1409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1412 if (*tl != newnfs_true)
1413 *retcmpp = NFSERR_NOTSAME;
1415 } else if (pc != NULL) {
1416 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1418 attrsum += NFSX_UNSIGNED;
1420 case NFSATTRBIT_NUMLINKS:
1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 tuint = fxdr_unsigned(u_int32_t, *tl);
1425 if ((u_int32_t)nap->na_nlink != tuint)
1426 *retcmpp = NFSERR_NOTSAME;
1428 } else if (nap != NULL) {
1429 nap->na_nlink = tuint;
1431 attrsum += NFSX_UNSIGNED;
1433 case NFSATTRBIT_OWNER:
1434 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1435 j = fxdr_unsigned(int, *tl);
1437 error = NFSERR_BADXDR;
1440 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1441 if (j > NFSV4_SMALLSTR)
1442 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1445 error = nfsrv_mtostr(nd, cp, j);
1447 if (j > NFSV4_SMALLSTR)
1448 free(cp, M_NFSSTRING);
1453 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1455 *retcmpp = NFSERR_NOTSAME;
1457 } else if (nap != NULL) {
1458 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1459 nap->na_uid = nfsrv_defaultuid;
1463 if (j > NFSV4_SMALLSTR)
1464 free(cp, M_NFSSTRING);
1466 case NFSATTRBIT_OWNERGROUP:
1467 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1468 j = fxdr_unsigned(int, *tl);
1470 error = NFSERR_BADXDR;
1473 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1474 if (j > NFSV4_SMALLSTR)
1475 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1478 error = nfsrv_mtostr(nd, cp, j);
1480 if (j > NFSV4_SMALLSTR)
1481 free(cp, M_NFSSTRING);
1486 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1488 *retcmpp = NFSERR_NOTSAME;
1490 } else if (nap != NULL) {
1491 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1492 nap->na_gid = nfsrv_defaultgid;
1496 if (j > NFSV4_SMALLSTR)
1497 free(cp, M_NFSSTRING);
1499 case NFSATTRBIT_QUOTAHARD:
1500 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1502 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1503 freenum = sbp->f_bfree;
1505 freenum = sbp->f_bavail;
1508 * ufs_quotactl() insists that the uid argument
1509 * equal p_ruid for non-root quota access, so
1510 * we'll just make sure that's the case.
1512 savuid = p->p_cred->p_ruid;
1513 p->p_cred->p_ruid = cred->cr_uid;
1514 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1515 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1516 freenum = min(dqb.dqb_bhardlimit, freenum);
1517 p->p_cred->p_ruid = savuid;
1519 uquad = (u_int64_t)freenum;
1520 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1522 if (compare && !(*retcmpp)) {
1523 if (uquad != fxdr_hyper(tl))
1524 *retcmpp = NFSERR_NOTSAME;
1526 attrsum += NFSX_HYPER;
1528 case NFSATTRBIT_QUOTASOFT:
1529 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1531 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1532 freenum = sbp->f_bfree;
1534 freenum = sbp->f_bavail;
1537 * ufs_quotactl() insists that the uid argument
1538 * equal p_ruid for non-root quota access, so
1539 * we'll just make sure that's the case.
1541 savuid = p->p_cred->p_ruid;
1542 p->p_cred->p_ruid = cred->cr_uid;
1543 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1544 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1545 freenum = min(dqb.dqb_bsoftlimit, freenum);
1546 p->p_cred->p_ruid = savuid;
1548 uquad = (u_int64_t)freenum;
1549 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1551 if (compare && !(*retcmpp)) {
1552 if (uquad != fxdr_hyper(tl))
1553 *retcmpp = NFSERR_NOTSAME;
1555 attrsum += NFSX_HYPER;
1557 case NFSATTRBIT_QUOTAUSED:
1558 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1563 * ufs_quotactl() insists that the uid argument
1564 * equal p_ruid for non-root quota access, so
1565 * we'll just make sure that's the case.
1567 savuid = p->p_cred->p_ruid;
1568 p->p_cred->p_ruid = cred->cr_uid;
1569 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1570 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1571 freenum = dqb.dqb_curblocks;
1572 p->p_cred->p_ruid = savuid;
1574 uquad = (u_int64_t)freenum;
1575 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1577 if (compare && !(*retcmpp)) {
1578 if (uquad != fxdr_hyper(tl))
1579 *retcmpp = NFSERR_NOTSAME;
1581 attrsum += NFSX_HYPER;
1583 case NFSATTRBIT_RAWDEV:
1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1585 j = fxdr_unsigned(int, *tl++);
1586 k = fxdr_unsigned(int, *tl);
1589 if (nap->na_rdev != NFSMAKEDEV(j, k))
1590 *retcmpp = NFSERR_NOTSAME;
1592 } else if (nap != NULL) {
1593 nap->na_rdev = NFSMAKEDEV(j, k);
1595 attrsum += NFSX_V4SPECDATA;
1597 case NFSATTRBIT_SPACEAVAIL:
1598 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1601 sfp->sf_abytes != fxdr_hyper(tl))
1602 *retcmpp = NFSERR_NOTSAME;
1603 } else if (sfp != NULL) {
1604 sfp->sf_abytes = fxdr_hyper(tl);
1606 attrsum += NFSX_HYPER;
1608 case NFSATTRBIT_SPACEFREE:
1609 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1612 sfp->sf_fbytes != fxdr_hyper(tl))
1613 *retcmpp = NFSERR_NOTSAME;
1614 } else if (sfp != NULL) {
1615 sfp->sf_fbytes = fxdr_hyper(tl);
1617 attrsum += NFSX_HYPER;
1619 case NFSATTRBIT_SPACETOTAL:
1620 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1623 sfp->sf_tbytes != fxdr_hyper(tl))
1624 *retcmpp = NFSERR_NOTSAME;
1625 } else if (sfp != NULL) {
1626 sfp->sf_tbytes = fxdr_hyper(tl);
1628 attrsum += NFSX_HYPER;
1630 case NFSATTRBIT_SPACEUSED:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 thyp = fxdr_hyper(tl);
1635 if ((u_int64_t)nap->na_bytes != thyp)
1636 *retcmpp = NFSERR_NOTSAME;
1638 } else if (nap != NULL) {
1639 nap->na_bytes = thyp;
1641 attrsum += NFSX_HYPER;
1643 case NFSATTRBIT_SYSTEM:
1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 if (compare && !(*retcmpp))
1646 *retcmpp = NFSERR_ATTRNOTSUPP;
1647 attrsum += NFSX_UNSIGNED;
1649 case NFSATTRBIT_TIMEACCESS:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1651 fxdr_nfsv4time(tl, &temptime);
1654 if (!NFS_CMPTIME(temptime, nap->na_atime))
1655 *retcmpp = NFSERR_NOTSAME;
1657 } else if (nap != NULL) {
1658 nap->na_atime = temptime;
1660 attrsum += NFSX_V4TIME;
1662 case NFSATTRBIT_TIMEACCESSSET:
1663 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1664 attrsum += NFSX_UNSIGNED;
1665 i = fxdr_unsigned(int, *tl);
1666 if (i == NFSV4SATTRTIME_TOCLIENT) {
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1668 attrsum += NFSX_V4TIME;
1670 if (compare && !(*retcmpp))
1671 *retcmpp = NFSERR_INVAL;
1673 case NFSATTRBIT_TIMEBACKUP:
1674 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1675 if (compare && !(*retcmpp))
1676 *retcmpp = NFSERR_ATTRNOTSUPP;
1677 attrsum += NFSX_V4TIME;
1679 case NFSATTRBIT_TIMECREATE:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1681 if (compare && !(*retcmpp))
1682 *retcmpp = NFSERR_ATTRNOTSUPP;
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMEDELTA:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1690 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1691 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1692 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1693 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1696 *retcmpp = NFSERR_NOTSAME;
1699 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1702 attrsum += NFSX_V4TIME;
1704 case NFSATTRBIT_TIMEMETADATA:
1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1706 fxdr_nfsv4time(tl, &temptime);
1709 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1710 *retcmpp = NFSERR_NOTSAME;
1712 } else if (nap != NULL) {
1713 nap->na_ctime = temptime;
1715 attrsum += NFSX_V4TIME;
1717 case NFSATTRBIT_TIMEMODIFY:
1718 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1719 fxdr_nfsv4time(tl, &temptime);
1722 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1723 *retcmpp = NFSERR_NOTSAME;
1725 } else if (nap != NULL) {
1726 nap->na_mtime = temptime;
1728 attrsum += NFSX_V4TIME;
1730 case NFSATTRBIT_TIMEMODIFYSET:
1731 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1732 attrsum += NFSX_UNSIGNED;
1733 i = fxdr_unsigned(int, *tl);
1734 if (i == NFSV4SATTRTIME_TOCLIENT) {
1735 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1736 attrsum += NFSX_V4TIME;
1738 if (compare && !(*retcmpp))
1739 *retcmpp = NFSERR_INVAL;
1741 case NFSATTRBIT_MOUNTEDONFILEID:
1742 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1743 thyp = fxdr_hyper(tl);
1747 *retcmpp = NFSERR_NOTSAME;
1749 if (!vp || !nfsrv_atroot(vp, &fid))
1750 fid = nap->na_fileid;
1751 if ((u_int64_t)fid != thyp)
1752 *retcmpp = NFSERR_NOTSAME;
1755 } else if (nap != NULL) {
1757 count64mountfileid++;
1758 if (ratecheck(&last64mountfileid, &warninterval)) {
1759 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1760 count64mountfileid);
1761 count64mountfileid = 0;
1764 nap->na_mntonfileno = thyp;
1766 attrsum += NFSX_HYPER;
1768 case NFSATTRBIT_SUPPATTREXCLCREAT:
1770 error = nfsrv_getattrbits(nd, &retattrbits,
1774 if (compare && !(*retcmpp)) {
1775 NFSSETSUPP_ATTRBIT(&checkattrbits);
1776 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1777 NFSCLRBIT_ATTRBIT(&checkattrbits,
1778 NFSATTRBIT_TIMEACCESSSET);
1779 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1781 *retcmpp = NFSERR_NOTSAME;
1786 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1788 if (compare && !(*retcmpp))
1789 *retcmpp = NFSERR_ATTRNOTSUPP;
1791 * and get out of the loop, since we can't parse
1792 * the unknown attrbute data.
1794 bitpos = NFSATTRBIT_MAX;
1800 * some clients pad the attrlist, so we need to skip over the
1803 if (attrsum > attrsize) {
1804 error = NFSERR_BADXDR;
1806 attrsize = NFSM_RNDUP(attrsize);
1807 if (attrsum < attrsize)
1808 error = nfsm_advance(nd, attrsize - attrsum, -1);
1811 NFSEXITCODE2(error, nd);
1816 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1817 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1818 * The first argument is a pointer to an nfsv4lock structure.
1819 * The second argument is 1 iff a blocking lock is wanted.
1820 * If this argument is 0, the call waits until no thread either wants nor
1821 * holds an exclusive lock.
1822 * It returns 1 if the lock was acquired, 0 otherwise.
1823 * If several processes call this function concurrently wanting the exclusive
1824 * lock, one will get the lock and the rest will return without getting the
1825 * lock. (If the caller must have the lock, it simply calls this function in a
1826 * loop until the function returns 1 to indicate the lock was acquired.)
1827 * Any usecnt must be decremented by calling nfsv4_relref() before
1828 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1829 * be called in a loop.
1830 * The isleptp argument is set to indicate if the call slept, iff not NULL
1831 * and the mp argument indicates to check for a forced dismount, iff not
1835 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1836 void *mutex, struct mount *mp)
1842 * If a lock is wanted, loop around until the lock is acquired by
1843 * someone and then released. If I want the lock, try to acquire it.
1844 * For a lock to be issued, no lock must be in force and the usecnt
1848 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1849 lp->nfslock_usecnt == 0) {
1850 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1851 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1854 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1856 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1857 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1858 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1861 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1864 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1865 PZERO - 1, "nfsv4lck", NULL);
1866 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1867 lp->nfslock_usecnt == 0) {
1868 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1869 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1877 * Release the lock acquired by nfsv4_lock().
1878 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1879 * incremented, as well.
1882 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1885 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1887 lp->nfslock_usecnt++;
1892 * Release a reference cnt.
1895 nfsv4_relref(struct nfsv4lock *lp)
1898 if (lp->nfslock_usecnt <= 0)
1899 panic("nfsv4root ref cnt");
1900 lp->nfslock_usecnt--;
1901 if (lp->nfslock_usecnt == 0)
1906 * Get a reference cnt.
1907 * This function will wait for any exclusive lock to be released, but will
1908 * not wait for threads that want the exclusive lock. If priority needs
1909 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1910 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1911 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1912 * return without getting a refcnt for that case.
1915 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1923 * Wait for a lock held.
1925 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1926 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1928 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1931 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1932 PZERO - 1, "nfsv4gr", NULL);
1934 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1937 lp->nfslock_usecnt++;
1941 * Get a reference as above, but return failure instead of sleeping if
1942 * an exclusive lock is held.
1945 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1948 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1951 lp->nfslock_usecnt++;
1956 * Test for a lock. Return 1 if locked, 0 otherwise.
1959 nfsv4_testlock(struct nfsv4lock *lp)
1962 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1963 lp->nfslock_usecnt == 0)
1969 * Wake up anyone sleeping, waiting for this lock.
1972 nfsv4_wanted(struct nfsv4lock *lp)
1975 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1976 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1977 wakeup((caddr_t)&lp->nfslock_lock);
1982 * Copy a string from an mbuf list into a character array.
1983 * Return EBADRPC if there is an mbuf error,
1987 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1996 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1997 rem = NFSM_RNDUP(siz) - siz;
2003 NFSBCOPY(cp, str, xfer);
2012 cp = NFSMTOD(mp, caddr_t);
2024 error = nfsm_advance(nd, rem, len);
2030 NFSEXITCODE2(error, nd);
2035 * Fill in the attributes as marked by the bitmap (V4).
2038 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2039 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2040 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2041 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2043 int bitpos, retnum = 0;
2045 int siz, prefixnum, error;
2046 u_char *cp, namestr[NFSV4_SMALLSTR];
2047 nfsattrbit_t attrbits, retbits;
2048 nfsattrbit_t *retbitp = &retbits;
2049 u_int32_t freenum, *retnump;
2052 struct nfsfsinfo fsinf;
2053 struct timespec temptime;
2054 NFSACL_T *aclp, *naclp = NULL;
2061 * First, set the bits that can be filled and get fsinfo.
2063 NFSSET_ATTRBIT(retbitp, attrbitp);
2065 * If both p and cred are NULL, it is a client side setattr call.
2066 * If both p and cred are not NULL, it is a server side reply call.
2067 * If p is not NULL and cred is NULL, it is a client side callback
2070 if (p == NULL && cred == NULL) {
2071 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2074 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2075 naclp = acl_alloc(M_WAITOK);
2078 nfsvno_getfs(&fsinf, isdgram);
2081 * Get the VFS_STATFS(), since some attributes need them.
2083 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2084 error = VFS_STATFS(mp, &fs);
2087 nd->nd_repstat = NFSERR_ACCES;
2090 NFSCLRSTATFS_ATTRBIT(retbitp);
2096 * And the NFSv4 ACL...
2098 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2099 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2100 supports_nfsv4acls == 0))) {
2101 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2103 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2104 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2105 supports_nfsv4acls == 0)) {
2106 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2107 } else if (naclp != NULL) {
2108 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2109 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2111 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2113 NFSVOPUNLOCK(vp, 0);
2115 error = NFSERR_PERM;
2118 nd->nd_repstat = NFSERR_ACCES;
2121 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2126 * Put out the attribute bitmap for the ones being filled in
2127 * and get the field for the number of attributes returned.
2129 prefixnum = nfsrv_putattrbit(nd, retbitp);
2130 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2131 prefixnum += NFSX_UNSIGNED;
2134 * Now, loop around filling in the attributes for each bit set.
2136 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2137 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2139 case NFSATTRBIT_SUPPORTEDATTRS:
2140 NFSSETSUPP_ATTRBIT(&attrbits);
2141 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2142 && supports_nfsv4acls == 0)) {
2143 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2144 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2146 retnum += nfsrv_putattrbit(nd, &attrbits);
2148 case NFSATTRBIT_TYPE:
2149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2150 *tl = vtonfsv34_type(vap->va_type);
2151 retnum += NFSX_UNSIGNED;
2153 case NFSATTRBIT_FHEXPIRETYPE:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2155 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_CHANGE:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2160 txdr_hyper(vap->va_filerev, tl);
2161 retnum += NFSX_HYPER;
2163 case NFSATTRBIT_SIZE:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2165 txdr_hyper(vap->va_size, tl);
2166 retnum += NFSX_HYPER;
2168 case NFSATTRBIT_LINKSUPPORT:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2174 retnum += NFSX_UNSIGNED;
2176 case NFSATTRBIT_SYMLINKSUPPORT:
2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2182 retnum += NFSX_UNSIGNED;
2184 case NFSATTRBIT_NAMEDATTR:
2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2187 retnum += NFSX_UNSIGNED;
2189 case NFSATTRBIT_FSID:
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2192 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2194 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2195 retnum += NFSX_V4FSID;
2197 case NFSATTRBIT_UNIQUEHANDLES:
2198 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2200 retnum += NFSX_UNSIGNED;
2202 case NFSATTRBIT_LEASETIME:
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2204 *tl = txdr_unsigned(nfsrv_lease);
2205 retnum += NFSX_UNSIGNED;
2207 case NFSATTRBIT_RDATTRERROR:
2208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2209 *tl = txdr_unsigned(rderror);
2210 retnum += NFSX_UNSIGNED;
2213 * Recommended Attributes. (Only the supported ones.)
2215 case NFSATTRBIT_ACL:
2216 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2218 case NFSATTRBIT_ACLSUPPORT:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2221 retnum += NFSX_UNSIGNED;
2223 case NFSATTRBIT_CANSETTIME:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2229 retnum += NFSX_UNSIGNED;
2231 case NFSATTRBIT_CASEINSENSITIVE:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2234 retnum += NFSX_UNSIGNED;
2236 case NFSATTRBIT_CASEPRESERVING:
2237 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2239 retnum += NFSX_UNSIGNED;
2241 case NFSATTRBIT_CHOWNRESTRICTED:
2242 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 retnum += NFSX_UNSIGNED;
2246 case NFSATTRBIT_FILEHANDLE:
2247 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2249 case NFSATTRBIT_FILEID:
2250 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 *tl = txdr_unsigned(vap->va_fileid);
2253 retnum += NFSX_HYPER;
2255 case NFSATTRBIT_FILESAVAIL:
2257 * Check quota and use min(quota, f_ffree).
2259 freenum = fs.f_ffree;
2262 * ufs_quotactl() insists that the uid argument
2263 * equal p_ruid for non-root quota access, so
2264 * we'll just make sure that's the case.
2266 savuid = p->p_cred->p_ruid;
2267 p->p_cred->p_ruid = cred->cr_uid;
2268 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2269 cred->cr_uid, (caddr_t)&dqb))
2270 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2272 p->p_cred->p_ruid = savuid;
2274 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2276 *tl = txdr_unsigned(freenum);
2277 retnum += NFSX_HYPER;
2279 case NFSATTRBIT_FILESFREE:
2280 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2282 *tl = txdr_unsigned(fs.f_ffree);
2283 retnum += NFSX_HYPER;
2285 case NFSATTRBIT_FILESTOTAL:
2286 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2288 *tl = txdr_unsigned(fs.f_files);
2289 retnum += NFSX_HYPER;
2291 case NFSATTRBIT_FSLOCATIONS:
2292 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2295 retnum += 2 * NFSX_UNSIGNED;
2297 case NFSATTRBIT_HOMOGENEOUS:
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2299 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2303 retnum += NFSX_UNSIGNED;
2305 case NFSATTRBIT_MAXFILESIZE:
2306 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2307 uquad = NFSRV_MAXFILESIZE;
2308 txdr_hyper(uquad, tl);
2309 retnum += NFSX_HYPER;
2311 case NFSATTRBIT_MAXLINK:
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2313 *tl = txdr_unsigned(LINK_MAX);
2314 retnum += NFSX_UNSIGNED;
2316 case NFSATTRBIT_MAXNAME:
2317 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2318 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2319 retnum += NFSX_UNSIGNED;
2321 case NFSATTRBIT_MAXREAD:
2322 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2324 *tl = txdr_unsigned(fsinf.fs_rtmax);
2325 retnum += NFSX_HYPER;
2327 case NFSATTRBIT_MAXWRITE:
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2330 *tl = txdr_unsigned(fsinf.fs_wtmax);
2331 retnum += NFSX_HYPER;
2333 case NFSATTRBIT_MODE:
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2335 *tl = vtonfsv34_mode(vap->va_mode);
2336 retnum += NFSX_UNSIGNED;
2338 case NFSATTRBIT_NOTRUNC:
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2341 retnum += NFSX_UNSIGNED;
2343 case NFSATTRBIT_NUMLINKS:
2344 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2345 *tl = txdr_unsigned(vap->va_nlink);
2346 retnum += NFSX_UNSIGNED;
2348 case NFSATTRBIT_OWNER:
2350 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2351 retnum += nfsm_strtom(nd, cp, siz);
2353 free(cp, M_NFSSTRING);
2355 case NFSATTRBIT_OWNERGROUP:
2357 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2358 retnum += nfsm_strtom(nd, cp, siz);
2360 free(cp, M_NFSSTRING);
2362 case NFSATTRBIT_QUOTAHARD:
2363 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2364 freenum = fs.f_bfree;
2366 freenum = fs.f_bavail;
2369 * ufs_quotactl() insists that the uid argument
2370 * equal p_ruid for non-root quota access, so
2371 * we'll just make sure that's the case.
2373 savuid = p->p_cred->p_ruid;
2374 p->p_cred->p_ruid = cred->cr_uid;
2375 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2376 cred->cr_uid, (caddr_t)&dqb))
2377 freenum = min(dqb.dqb_bhardlimit, freenum);
2378 p->p_cred->p_ruid = savuid;
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2381 uquad = (u_int64_t)freenum;
2382 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2383 txdr_hyper(uquad, tl);
2384 retnum += NFSX_HYPER;
2386 case NFSATTRBIT_QUOTASOFT:
2387 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2388 freenum = fs.f_bfree;
2390 freenum = fs.f_bavail;
2393 * ufs_quotactl() insists that the uid argument
2394 * equal p_ruid for non-root quota access, so
2395 * we'll just make sure that's the case.
2397 savuid = p->p_cred->p_ruid;
2398 p->p_cred->p_ruid = cred->cr_uid;
2399 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2400 cred->cr_uid, (caddr_t)&dqb))
2401 freenum = min(dqb.dqb_bsoftlimit, freenum);
2402 p->p_cred->p_ruid = savuid;
2404 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2405 uquad = (u_int64_t)freenum;
2406 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2407 txdr_hyper(uquad, tl);
2408 retnum += NFSX_HYPER;
2410 case NFSATTRBIT_QUOTAUSED:
2414 * ufs_quotactl() insists that the uid argument
2415 * equal p_ruid for non-root quota access, so
2416 * we'll just make sure that's the case.
2418 savuid = p->p_cred->p_ruid;
2419 p->p_cred->p_ruid = cred->cr_uid;
2420 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2421 cred->cr_uid, (caddr_t)&dqb))
2422 freenum = dqb.dqb_curblocks;
2423 p->p_cred->p_ruid = savuid;
2425 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2426 uquad = (u_int64_t)freenum;
2427 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2428 txdr_hyper(uquad, tl);
2429 retnum += NFSX_HYPER;
2431 case NFSATTRBIT_RAWDEV:
2432 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2433 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2434 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2435 retnum += NFSX_V4SPECDATA;
2437 case NFSATTRBIT_SPACEAVAIL:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2439 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2440 uquad = (u_int64_t)fs.f_bfree;
2442 uquad = (u_int64_t)fs.f_bavail;
2443 uquad *= fs.f_bsize;
2444 txdr_hyper(uquad, tl);
2445 retnum += NFSX_HYPER;
2447 case NFSATTRBIT_SPACEFREE:
2448 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2449 uquad = (u_int64_t)fs.f_bfree;
2450 uquad *= fs.f_bsize;
2451 txdr_hyper(uquad, tl);
2452 retnum += NFSX_HYPER;
2454 case NFSATTRBIT_SPACETOTAL:
2455 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2456 uquad = (u_int64_t)fs.f_blocks;
2457 uquad *= fs.f_bsize;
2458 txdr_hyper(uquad, tl);
2459 retnum += NFSX_HYPER;
2461 case NFSATTRBIT_SPACEUSED:
2462 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2463 txdr_hyper(vap->va_bytes, tl);
2464 retnum += NFSX_HYPER;
2466 case NFSATTRBIT_TIMEACCESS:
2467 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2468 txdr_nfsv4time(&vap->va_atime, tl);
2469 retnum += NFSX_V4TIME;
2471 case NFSATTRBIT_TIMEACCESSSET:
2472 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2474 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2475 txdr_nfsv4time(&vap->va_atime, tl);
2476 retnum += NFSX_V4SETTIME;
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2479 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2480 retnum += NFSX_UNSIGNED;
2483 case NFSATTRBIT_TIMEDELTA:
2484 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2485 temptime.tv_sec = 0;
2486 temptime.tv_nsec = 1000000000 / hz;
2487 txdr_nfsv4time(&temptime, tl);
2488 retnum += NFSX_V4TIME;
2490 case NFSATTRBIT_TIMEMETADATA:
2491 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2492 txdr_nfsv4time(&vap->va_ctime, tl);
2493 retnum += NFSX_V4TIME;
2495 case NFSATTRBIT_TIMEMODIFY:
2496 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2497 txdr_nfsv4time(&vap->va_mtime, tl);
2498 retnum += NFSX_V4TIME;
2500 case NFSATTRBIT_TIMEMODIFYSET:
2501 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2502 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2503 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2504 txdr_nfsv4time(&vap->va_mtime, tl);
2505 retnum += NFSX_V4SETTIME;
2507 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2508 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2509 retnum += NFSX_UNSIGNED;
2512 case NFSATTRBIT_MOUNTEDONFILEID:
2513 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2515 uquad = mounted_on_fileno;
2517 uquad = (u_int64_t)vap->va_fileid;
2518 txdr_hyper(uquad, tl);
2519 retnum += NFSX_HYPER;
2521 case NFSATTRBIT_SUPPATTREXCLCREAT:
2522 NFSSETSUPP_ATTRBIT(&attrbits);
2523 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2524 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2525 retnum += nfsrv_putattrbit(nd, &attrbits);
2528 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2534 *retnump = txdr_unsigned(retnum);
2535 return (retnum + prefixnum);
2539 * Put the attribute bits onto an mbuf list.
2540 * Return the number of bytes of output generated.
2543 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2546 int cnt, i, bytesize;
2548 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2549 if (attrbitp->bits[cnt - 1])
2551 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2552 NFSM_BUILD(tl, u_int32_t *, bytesize);
2553 *tl++ = txdr_unsigned(cnt);
2554 for (i = 0; i < cnt; i++)
2555 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2560 * Convert a uid to a string.
2561 * If the lookup fails, just output the digits.
2563 * cpp - points to a buffer of size NFSV4_SMALLSTR
2564 * (malloc a larger one, as required)
2565 * retlenp - pointer to length to be returned
2568 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2571 struct nfsusrgrp *usrp;
2574 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2575 struct nfsrv_lughash *hp;
2579 if (nfsrv_dnsnamelen > 0) {
2581 * Always map nfsrv_defaultuid to "nobody".
2583 if (uid == nfsrv_defaultuid) {
2584 i = nfsrv_dnsnamelen + 7;
2586 if (len > NFSV4_SMALLSTR)
2587 free(cp, M_NFSSTRING);
2588 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2594 NFSBCOPY("nobody@", cp, 7);
2596 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2600 hp = NFSUSERHASH(uid);
2602 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2603 if (usrp->lug_uid == uid) {
2604 if (usrp->lug_expiry < NFSD_MONOSEC)
2607 * If the name doesn't already have an '@'
2608 * in it, append @domainname to it.
2610 for (i = 0; i < usrp->lug_namelen; i++) {
2611 if (usrp->lug_name[i] == '@') {
2617 i = usrp->lug_namelen;
2619 i = usrp->lug_namelen +
2620 nfsrv_dnsnamelen + 1;
2622 mtx_unlock(&hp->mtx);
2623 if (len > NFSV4_SMALLSTR)
2624 free(cp, M_NFSSTRING);
2625 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2631 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2632 if (!hasampersand) {
2633 cp += usrp->lug_namelen;
2635 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2637 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2638 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2640 mtx_unlock(&hp->mtx);
2644 mtx_unlock(&hp->mtx);
2646 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2648 if (ret == 0 && cnt < 2)
2653 * No match, just return a string of digits.
2657 while (tmp || i == 0) {
2661 len = (i > len) ? len : i;
2665 for (i = 0; i < len; i++) {
2666 *cp-- = '0' + (tmp % 10);
2673 * Get a credential for the uid with the server's group list.
2674 * If none is found, just return the credential passed in after
2675 * logging a warning message.
2678 nfsrv_getgrpscred(struct ucred *oldcred)
2680 struct nfsusrgrp *usrp;
2681 struct ucred *newcred;
2684 struct nfsrv_lughash *hp;
2687 uid = oldcred->cr_uid;
2689 if (nfsrv_dnsnamelen > 0) {
2690 hp = NFSUSERHASH(uid);
2692 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2693 if (usrp->lug_uid == uid) {
2694 if (usrp->lug_expiry < NFSD_MONOSEC)
2696 if (usrp->lug_cred != NULL) {
2697 newcred = crhold(usrp->lug_cred);
2701 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2702 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2704 mtx_unlock(&hp->mtx);
2708 mtx_unlock(&hp->mtx);
2710 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2712 if (ret == 0 && cnt < 2)
2719 * Convert a string to a uid.
2720 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2722 * If this is called from a client side mount using AUTH_SYS and the
2723 * string is made up entirely of digits, just convert the string to
2727 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2731 char *cp, *endstr, *str0;
2732 struct nfsusrgrp *usrp;
2736 struct nfsrv_lughash *hp, *hp2;
2739 error = NFSERR_BADOWNER;
2742 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2744 tuid = (uid_t)strtoul(str0, &endstr, 10);
2745 if ((endstr - str0) == len) {
2746 /* A numeric string. */
2747 if ((nd->nd_flag & ND_KERBV) == 0 &&
2748 ((nd->nd_flag & ND_NFSCL) != 0 ||
2749 nfsd_enable_stringtouid != 0))
2752 error = NFSERR_BADOWNER;
2758 cp = strchr(str0, '@');
2760 i = (int)(cp++ - str0);
2766 if (nfsrv_dnsnamelen > 0) {
2768 * If an '@' is found and the domain name matches, search for
2769 * the name with dns stripped off.
2770 * Mixed case alpahbetics will match for the domain name, but
2771 * all upper case will not.
2773 if (cnt == 0 && i < len && i > 0 &&
2774 (len - 1 - i) == nfsrv_dnsnamelen &&
2775 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2776 len -= (nfsrv_dnsnamelen + 1);
2781 * Check for the special case of "nobody".
2783 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2784 *uidp = nfsrv_defaultuid;
2789 hp = NFSUSERNAMEHASH(str, len);
2791 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2792 if (usrp->lug_namelen == len &&
2793 !NFSBCMP(usrp->lug_name, str, len)) {
2794 if (usrp->lug_expiry < NFSD_MONOSEC)
2796 hp2 = NFSUSERHASH(usrp->lug_uid);
2797 mtx_lock(&hp2->mtx);
2798 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2799 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2801 *uidp = usrp->lug_uid;
2802 mtx_unlock(&hp2->mtx);
2803 mtx_unlock(&hp->mtx);
2808 mtx_unlock(&hp->mtx);
2810 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2812 if (ret == 0 && cnt < 2)
2815 error = NFSERR_BADOWNER;
2823 * Convert a gid to a string.
2824 * gid - the group id
2825 * cpp - points to a buffer of size NFSV4_SMALLSTR
2826 * (malloc a larger one, as required)
2827 * retlenp - pointer to length to be returned
2830 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2833 struct nfsusrgrp *usrp;
2836 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2837 struct nfsrv_lughash *hp;
2841 if (nfsrv_dnsnamelen > 0) {
2843 * Always map nfsrv_defaultgid to "nogroup".
2845 if (gid == nfsrv_defaultgid) {
2846 i = nfsrv_dnsnamelen + 8;
2848 if (len > NFSV4_SMALLSTR)
2849 free(cp, M_NFSSTRING);
2850 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2856 NFSBCOPY("nogroup@", cp, 8);
2858 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2862 hp = NFSGROUPHASH(gid);
2864 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2865 if (usrp->lug_gid == gid) {
2866 if (usrp->lug_expiry < NFSD_MONOSEC)
2869 * If the name doesn't already have an '@'
2870 * in it, append @domainname to it.
2872 for (i = 0; i < usrp->lug_namelen; i++) {
2873 if (usrp->lug_name[i] == '@') {
2879 i = usrp->lug_namelen;
2881 i = usrp->lug_namelen +
2882 nfsrv_dnsnamelen + 1;
2884 mtx_unlock(&hp->mtx);
2885 if (len > NFSV4_SMALLSTR)
2886 free(cp, M_NFSSTRING);
2887 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2893 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2894 if (!hasampersand) {
2895 cp += usrp->lug_namelen;
2897 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2899 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2900 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2902 mtx_unlock(&hp->mtx);
2906 mtx_unlock(&hp->mtx);
2908 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2910 if (ret == 0 && cnt < 2)
2915 * No match, just return a string of digits.
2919 while (tmp || i == 0) {
2923 len = (i > len) ? len : i;
2927 for (i = 0; i < len; i++) {
2928 *cp-- = '0' + (tmp % 10);
2935 * Convert a string to a gid.
2936 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2938 * If this is called from a client side mount using AUTH_SYS and the
2939 * string is made up entirely of digits, just convert the string to
2943 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2947 char *cp, *endstr, *str0;
2948 struct nfsusrgrp *usrp;
2952 struct nfsrv_lughash *hp, *hp2;
2955 error = NFSERR_BADOWNER;
2958 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2960 tgid = (gid_t)strtoul(str0, &endstr, 10);
2961 if ((endstr - str0) == len) {
2962 /* A numeric string. */
2963 if ((nd->nd_flag & ND_KERBV) == 0 &&
2964 ((nd->nd_flag & ND_NFSCL) != 0 ||
2965 nfsd_enable_stringtouid != 0))
2968 error = NFSERR_BADOWNER;
2974 cp = strchr(str0, '@');
2976 i = (int)(cp++ - str0);
2982 if (nfsrv_dnsnamelen > 0) {
2984 * If an '@' is found and the dns name matches, search for the
2985 * name with the dns stripped off.
2987 if (cnt == 0 && i < len && i > 0 &&
2988 (len - 1 - i) == nfsrv_dnsnamelen &&
2989 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2990 len -= (nfsrv_dnsnamelen + 1);
2995 * Check for the special case of "nogroup".
2997 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2998 *gidp = nfsrv_defaultgid;
3003 hp = NFSGROUPNAMEHASH(str, len);
3005 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3006 if (usrp->lug_namelen == len &&
3007 !NFSBCMP(usrp->lug_name, str, len)) {
3008 if (usrp->lug_expiry < NFSD_MONOSEC)
3010 hp2 = NFSGROUPHASH(usrp->lug_gid);
3011 mtx_lock(&hp2->mtx);
3012 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3013 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3015 *gidp = usrp->lug_gid;
3016 mtx_unlock(&hp2->mtx);
3017 mtx_unlock(&hp->mtx);
3022 mtx_unlock(&hp->mtx);
3024 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3026 if (ret == 0 && cnt < 2)
3029 error = NFSERR_BADOWNER;
3037 * Cmp len chars, allowing mixed case in the first argument to match lower
3038 * case in the second, but not if the first argument is all upper case.
3039 * Return 0 for a match, 1 otherwise.
3042 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3048 for (i = 0; i < len; i++) {
3049 if (*cp >= 'A' && *cp <= 'Z') {
3050 tmp = *cp++ + ('a' - 'A');
3053 if (tmp >= 'a' && tmp <= 'z')
3066 * Set the port for the nfsuserd.
3069 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3071 struct nfssockreq *rp;
3072 struct sockaddr_in *ad;
3076 if (nfsrv_nfsuserd) {
3084 * Set up the socket record and connect.
3086 rp = &nfsrv_nfsuserdsock;
3087 rp->nr_client = NULL;
3088 rp->nr_sotype = SOCK_DGRAM;
3089 rp->nr_soproto = IPPROTO_UDP;
3090 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3092 NFSSOCKADDRALLOC(rp->nr_nam);
3093 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3094 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3095 ad->sin_family = AF_INET;
3096 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3097 ad->sin_port = port;
3098 rp->nr_prog = RPCPROG_NFSUSERD;
3099 rp->nr_vers = RPCNFSUSERD_VERS;
3100 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3102 NFSSOCKADDRFREE(rp->nr_nam);
3111 * Delete the nfsuserd port.
3114 nfsrv_nfsuserddelport(void)
3118 if (nfsrv_nfsuserd == 0) {
3124 newnfs_disconnect(&nfsrv_nfsuserdsock);
3125 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3129 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3131 * Returns 0 upon success, non-zero otherwise.
3134 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3137 struct nfsrv_descript *nd;
3139 struct nfsrv_descript nfsd;
3144 if (nfsrv_nfsuserd == 0) {
3151 cred = newnfs_getcred();
3152 nd->nd_flag = ND_GSSINITREPLY;
3155 nd->nd_procnum = procnum;
3156 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3158 if (procnum == RPCNFSUSERD_GETUID)
3159 *tl = txdr_unsigned(uid);
3161 *tl = txdr_unsigned(gid);
3164 (void) nfsm_strtom(nd, name, len);
3166 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3167 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3170 mbuf_freem(nd->nd_mrep);
3171 error = nd->nd_repstat;
3179 * This function is called from the nfssvc(2) system call, to update the
3180 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3183 nfssvc_idname(struct nfsd_idargs *nidp)
3185 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3186 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3187 int i, group_locked, groupname_locked, user_locked, username_locked;
3192 static int onethread = 0;
3193 static time_t lasttime = 0;
3195 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3199 if (nidp->nid_flag & NFSID_INITIALIZE) {
3200 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3201 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3204 free(cp, M_NFSSTRING);
3207 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3209 * Free up all the old stuff and reinitialize hash
3210 * lists. All mutexes for both lists must be locked,
3211 * with the user/group name ones before the uid/gid
3212 * ones, to avoid a LOR.
3214 for (i = 0; i < nfsrv_lughashsize; i++)
3215 mtx_lock(&nfsusernamehash[i].mtx);
3216 for (i = 0; i < nfsrv_lughashsize; i++)
3217 mtx_lock(&nfsuserhash[i].mtx);
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 TAILQ_FOREACH_SAFE(usrp,
3220 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3221 nfsrv_removeuser(usrp, 1);
3222 for (i = 0; i < nfsrv_lughashsize; i++)
3223 mtx_unlock(&nfsuserhash[i].mtx);
3224 for (i = 0; i < nfsrv_lughashsize; i++)
3225 mtx_unlock(&nfsusernamehash[i].mtx);
3226 for (i = 0; i < nfsrv_lughashsize; i++)
3227 mtx_lock(&nfsgroupnamehash[i].mtx);
3228 for (i = 0; i < nfsrv_lughashsize; i++)
3229 mtx_lock(&nfsgrouphash[i].mtx);
3230 for (i = 0; i < nfsrv_lughashsize; i++)
3231 TAILQ_FOREACH_SAFE(usrp,
3232 &nfsgrouphash[i].lughead, lug_numhash,
3234 nfsrv_removeuser(usrp, 0);
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 mtx_unlock(&nfsgrouphash[i].mtx);
3237 for (i = 0; i < nfsrv_lughashsize; i++)
3238 mtx_unlock(&nfsgroupnamehash[i].mtx);
3239 free(nfsrv_dnsname, M_NFSSTRING);
3240 nfsrv_dnsname = NULL;
3242 if (nfsuserhash == NULL) {
3243 /* Allocate the hash tables. */
3244 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3245 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3249 NULL, MTX_DEF | MTX_DUPOK);
3250 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3251 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 mtx_init(&nfsusernamehash[i].mtx,
3255 "nfsusrhash", NULL, MTX_DEF |
3257 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3258 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3260 for (i = 0; i < nfsrv_lughashsize; i++)
3261 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3262 NULL, MTX_DEF | MTX_DUPOK);
3263 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3264 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3266 for (i = 0; i < nfsrv_lughashsize; i++)
3267 mtx_init(&nfsgroupnamehash[i].mtx,
3268 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3270 /* (Re)initialize the list heads. */
3271 for (i = 0; i < nfsrv_lughashsize; i++)
3272 TAILQ_INIT(&nfsuserhash[i].lughead);
3273 for (i = 0; i < nfsrv_lughashsize; i++)
3274 TAILQ_INIT(&nfsusernamehash[i].lughead);
3275 for (i = 0; i < nfsrv_lughashsize; i++)
3276 TAILQ_INIT(&nfsgrouphash[i].lughead);
3277 for (i = 0; i < nfsrv_lughashsize; i++)
3278 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3281 * Put name in "DNS" string.
3284 nfsrv_defaultuid = nidp->nid_uid;
3285 nfsrv_defaultgid = nidp->nid_gid;
3287 nfsrv_usermax = nidp->nid_usermax;
3288 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3293 * malloc the new one now, so any potential sleep occurs before
3294 * manipulation of the lists.
3296 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3297 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3298 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3300 if (error == 0 && nidp->nid_ngroup > 0 &&
3301 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3302 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3304 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3305 sizeof(gid_t) * nidp->nid_ngroup);
3308 * Create a credential just like svc_getcred(),
3309 * but using the group list provided.
3312 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3313 crsetgroups(cr, nidp->nid_ngroup, grps);
3314 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3315 cr->cr_prison = &prison0;
3316 prison_hold(cr->cr_prison);
3318 mac_cred_associate_nfsd(cr);
3320 newusrp->lug_cred = cr;
3325 free(newusrp, M_NFSUSERGROUP);
3328 newusrp->lug_namelen = nidp->nid_namelen;
3331 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3332 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3333 * The flags user_locked, username_locked, group_locked and
3334 * groupname_locked are set to indicate all of those hash lists are
3335 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3336 * the respective one mutex is locked.
3338 user_locked = username_locked = group_locked = groupname_locked = 0;
3339 hp_name = hp_idnum = NULL;
3342 * Delete old entries, as required.
3344 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3345 /* Must lock all username hash lists first, to avoid a LOR. */
3346 for (i = 0; i < nfsrv_lughashsize; i++)
3347 mtx_lock(&nfsusernamehash[i].mtx);
3348 username_locked = 1;
3349 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3350 mtx_lock(&hp_idnum->mtx);
3351 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3353 if (usrp->lug_uid == nidp->nid_uid)
3354 nfsrv_removeuser(usrp, 1);
3356 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3357 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3358 newusrp->lug_namelen);
3359 mtx_lock(&hp_name->mtx);
3360 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3362 if (usrp->lug_namelen == newusrp->lug_namelen &&
3363 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3364 usrp->lug_namelen)) {
3365 thp = NFSUSERHASH(usrp->lug_uid);
3366 mtx_lock(&thp->mtx);
3367 nfsrv_removeuser(usrp, 1);
3368 mtx_unlock(&thp->mtx);
3371 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3372 mtx_lock(&hp_idnum->mtx);
3373 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3374 /* Must lock all groupname hash lists first, to avoid a LOR. */
3375 for (i = 0; i < nfsrv_lughashsize; i++)
3376 mtx_lock(&nfsgroupnamehash[i].mtx);
3377 groupname_locked = 1;
3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3379 mtx_lock(&hp_idnum->mtx);
3380 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3382 if (usrp->lug_gid == nidp->nid_gid)
3383 nfsrv_removeuser(usrp, 0);
3385 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3386 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3387 newusrp->lug_namelen);
3388 mtx_lock(&hp_name->mtx);
3389 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3391 if (usrp->lug_namelen == newusrp->lug_namelen &&
3392 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3393 usrp->lug_namelen)) {
3394 thp = NFSGROUPHASH(usrp->lug_gid);
3395 mtx_lock(&thp->mtx);
3396 nfsrv_removeuser(usrp, 0);
3397 mtx_unlock(&thp->mtx);
3400 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3401 mtx_lock(&hp_idnum->mtx);
3405 * Now, we can add the new one.
3407 if (nidp->nid_usertimeout)
3408 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3410 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3411 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3412 newusrp->lug_uid = nidp->nid_uid;
3413 thp = NFSUSERHASH(newusrp->lug_uid);
3414 mtx_assert(&thp->mtx, MA_OWNED);
3415 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3416 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3417 mtx_assert(&thp->mtx, MA_OWNED);
3418 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3419 atomic_add_int(&nfsrv_usercnt, 1);
3420 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3421 newusrp->lug_gid = nidp->nid_gid;
3422 thp = NFSGROUPHASH(newusrp->lug_gid);
3423 mtx_assert(&thp->mtx, MA_OWNED);
3424 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3425 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3426 mtx_assert(&thp->mtx, MA_OWNED);
3427 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3428 atomic_add_int(&nfsrv_usercnt, 1);
3430 if (newusrp->lug_cred != NULL)
3431 crfree(newusrp->lug_cred);
3432 free(newusrp, M_NFSUSERGROUP);
3436 * Once per second, allow one thread to trim the cache.
3438 if (lasttime < NFSD_MONOSEC &&
3439 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3441 * First, unlock the single mutexes, so that all entries
3442 * can be locked and any LOR is avoided.
3444 if (hp_name != NULL) {
3445 mtx_unlock(&hp_name->mtx);
3448 if (hp_idnum != NULL) {
3449 mtx_unlock(&hp_idnum->mtx);
3453 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3454 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3455 if (username_locked == 0) {
3456 for (i = 0; i < nfsrv_lughashsize; i++)
3457 mtx_lock(&nfsusernamehash[i].mtx);
3458 username_locked = 1;
3460 KASSERT(user_locked == 0,
3461 ("nfssvc_idname: user_locked"));
3462 for (i = 0; i < nfsrv_lughashsize; i++)
3463 mtx_lock(&nfsuserhash[i].mtx);
3465 for (i = 0; i < nfsrv_lughashsize; i++) {
3466 TAILQ_FOREACH_SAFE(usrp,
3467 &nfsuserhash[i].lughead, lug_numhash,
3469 if (usrp->lug_expiry < NFSD_MONOSEC)
3470 nfsrv_removeuser(usrp, 1);
3472 for (i = 0; i < nfsrv_lughashsize; i++) {
3474 * Trim the cache using an approximate LRU
3475 * algorithm. This code deletes the least
3476 * recently used entry on each hash list.
3478 if (nfsrv_usercnt <= nfsrv_usermax)
3480 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3482 nfsrv_removeuser(usrp, 1);
3485 if (groupname_locked == 0) {
3486 for (i = 0; i < nfsrv_lughashsize; i++)
3487 mtx_lock(&nfsgroupnamehash[i].mtx);
3488 groupname_locked = 1;
3490 KASSERT(group_locked == 0,
3491 ("nfssvc_idname: group_locked"));
3492 for (i = 0; i < nfsrv_lughashsize; i++)
3493 mtx_lock(&nfsgrouphash[i].mtx);
3495 for (i = 0; i < nfsrv_lughashsize; i++) {
3496 TAILQ_FOREACH_SAFE(usrp,
3497 &nfsgrouphash[i].lughead, lug_numhash,
3499 if (usrp->lug_expiry < NFSD_MONOSEC)
3500 nfsrv_removeuser(usrp, 0);
3502 for (i = 0; i < nfsrv_lughashsize; i++) {
3504 * Trim the cache using an approximate LRU
3505 * algorithm. This code deletes the least
3506 * recently user entry on each hash list.
3508 if (nfsrv_usercnt <= nfsrv_usermax)
3510 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3512 nfsrv_removeuser(usrp, 0);
3515 lasttime = NFSD_MONOSEC;
3516 atomic_store_rel_int(&onethread, 0);
3519 /* Now, unlock all locked mutexes. */
3520 if (hp_idnum != NULL)
3521 mtx_unlock(&hp_idnum->mtx);
3522 if (hp_name != NULL)
3523 mtx_unlock(&hp_name->mtx);
3524 if (user_locked != 0)
3525 for (i = 0; i < nfsrv_lughashsize; i++)
3526 mtx_unlock(&nfsuserhash[i].mtx);
3527 if (username_locked != 0)
3528 for (i = 0; i < nfsrv_lughashsize; i++)
3529 mtx_unlock(&nfsusernamehash[i].mtx);
3530 if (group_locked != 0)
3531 for (i = 0; i < nfsrv_lughashsize; i++)
3532 mtx_unlock(&nfsgrouphash[i].mtx);
3533 if (groupname_locked != 0)
3534 for (i = 0; i < nfsrv_lughashsize; i++)
3535 mtx_unlock(&nfsgroupnamehash[i].mtx);
3542 * Remove a user/group name element.
3545 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3547 struct nfsrv_lughash *hp;
3550 hp = NFSUSERHASH(usrp->lug_uid);
3551 mtx_assert(&hp->mtx, MA_OWNED);
3552 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3553 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3554 mtx_assert(&hp->mtx, MA_OWNED);
3555 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3557 hp = NFSGROUPHASH(usrp->lug_gid);
3558 mtx_assert(&hp->mtx, MA_OWNED);
3559 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3560 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3561 mtx_assert(&hp->mtx, MA_OWNED);
3562 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3564 atomic_add_int(&nfsrv_usercnt, -1);
3565 if (usrp->lug_cred != NULL)
3566 crfree(usrp->lug_cred);
3567 free(usrp, M_NFSUSERGROUP);
3571 * Free up all the allocations related to the name<-->id cache.
3572 * This function should only be called when the nfsuserd daemon isn't
3573 * running, since it doesn't do any locking.
3574 * This function is meant to be used when the nfscommon module is unloaded.
3577 nfsrv_cleanusergroup(void)
3579 struct nfsrv_lughash *hp, *hp2;
3580 struct nfsusrgrp *nusrp, *usrp;
3583 if (nfsuserhash == NULL)
3586 for (i = 0; i < nfsrv_lughashsize; i++) {
3587 hp = &nfsuserhash[i];
3588 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3589 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3590 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3592 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3593 if (usrp->lug_cred != NULL)
3594 crfree(usrp->lug_cred);
3595 free(usrp, M_NFSUSERGROUP);
3597 hp = &nfsgrouphash[i];
3598 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3599 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3600 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3602 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3603 if (usrp->lug_cred != NULL)
3604 crfree(usrp->lug_cred);
3605 free(usrp, M_NFSUSERGROUP);
3607 mtx_destroy(&nfsuserhash[i].mtx);
3608 mtx_destroy(&nfsusernamehash[i].mtx);
3609 mtx_destroy(&nfsgroupnamehash[i].mtx);
3610 mtx_destroy(&nfsgrouphash[i].mtx);
3612 free(nfsuserhash, M_NFSUSERGROUP);
3613 free(nfsusernamehash, M_NFSUSERGROUP);
3614 free(nfsgrouphash, M_NFSUSERGROUP);
3615 free(nfsgroupnamehash, M_NFSUSERGROUP);
3616 free(nfsrv_dnsname, M_NFSSTRING);
3620 * This function scans a byte string and checks for UTF-8 compliance.
3621 * It returns 0 if it conforms and NFSERR_INVAL if not.
3624 nfsrv_checkutf8(u_int8_t *cp, int len)
3626 u_int32_t val = 0x0;
3627 int cnt = 0, gotd = 0, shift = 0;
3629 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3633 * Here are what the variables are used for:
3634 * val - the calculated value of a multibyte char, used to check
3635 * that it was coded with the correct range
3636 * cnt - the number of 10xxxxxx bytes to follow
3637 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3638 * shift - lower order bits of range (ie. "val >> shift" should
3639 * not be 0, in other words, dividing by the lower bound
3640 * of the range should get a non-zero value)
3641 * byte - used to calculate cnt
3645 /* This handles the 10xxxxxx bytes */
3646 if ((*cp & 0xc0) != 0x80 ||
3647 (gotd && (*cp & 0x20))) {
3648 error = NFSERR_INVAL;
3653 val |= (*cp & 0x3f);
3655 if (cnt == 0 && (val >> shift) == 0x0) {
3656 error = NFSERR_INVAL;
3659 } else if (*cp & 0x80) {
3660 /* first byte of multi byte char */
3662 while ((byte & 0x40) && cnt < 6) {
3666 if (cnt == 0 || cnt == 6) {
3667 error = NFSERR_INVAL;
3670 val = (*cp & (0x3f >> cnt));
3671 shift = utf8_shift[cnt - 1];
3672 if (cnt == 2 && val == 0xd)
3673 /* Check for the 0xd800-0xdfff case */
3680 error = NFSERR_INVAL;
3688 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3689 * strings, one with the root path in it and the other with the list of
3690 * locations. The list is in the same format as is found in nfr_refs.
3691 * It is a "," separated list of entries, where each of them is of the
3692 * form <server>:<rootpath>. For example
3693 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3694 * The nilp argument is set to 1 for the special case of a null fs_root
3695 * and an empty server list.
3696 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3697 * number of xdr bytes parsed in sump.
3700 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3701 int *sump, int *nilp)
3704 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3705 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3707 SLIST_ENTRY(list) next;
3711 SLIST_HEAD(, list) head;
3718 * Get the fs_root path and check for the special case of null path
3719 * and 0 length server list.
3721 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3722 len = fxdr_unsigned(int, *tl);
3723 if (len < 0 || len > 10240) {
3724 error = NFSERR_BADXDR;
3728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3730 error = NFSERR_BADXDR;
3734 *sump = 2 * NFSX_UNSIGNED;
3738 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3739 error = nfsrv_mtostr(nd, cp, len);
3741 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3742 cnt = fxdr_unsigned(int, *tl);
3744 error = NFSERR_BADXDR;
3750 * Now, loop through the location list and make up the srvlist.
3752 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3753 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3756 for (i = 0; i < cnt; i++) {
3758 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3759 nsrv = fxdr_unsigned(int, *tl);
3761 error = NFSERR_BADXDR;
3766 * Handle the first server by putting it in the srvstr.
3768 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3769 len = fxdr_unsigned(int, *tl);
3770 if (len <= 0 || len > 1024) {
3771 error = NFSERR_BADXDR;
3774 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3779 error = nfsrv_mtostr(nd, cp3, len);
3785 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3786 for (j = 1; j < nsrv; j++) {
3788 * Yuck, put them in an slist and process them later.
3790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3791 len = fxdr_unsigned(int, *tl);
3792 if (len <= 0 || len > 1024) {
3793 error = NFSERR_BADXDR;
3796 lsp = (struct list *)malloc(sizeof (struct list)
3797 + len, M_TEMP, M_WAITOK);
3798 error = nfsrv_mtostr(nd, lsp->host, len);
3801 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3803 SLIST_INSERT_HEAD(&head, lsp, next);
3807 * Finally, we can get the path.
3809 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3810 len = fxdr_unsigned(int, *tl);
3811 if (len <= 0 || len > 1024) {
3812 error = NFSERR_BADXDR;
3815 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3816 error = nfsrv_mtostr(nd, cp3, len);
3819 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3824 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3825 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3828 NFSBCOPY(lsp->host, cp3, lsp->len);
3831 NFSBCOPY(str, cp3, stringlen);
3834 siz += (lsp->len + stringlen + 2);
3835 free((caddr_t)lsp, M_TEMP);
3841 NFSEXITCODE2(0, nd);
3845 free(cp, M_NFSSTRING);
3847 free(cp2, M_NFSSTRING);
3848 NFSEXITCODE2(error, nd);
3853 * Make the malloc'd space large enough. This is a pain, but the xdr
3854 * doesn't set an upper bound on the side, so...
3857 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3864 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3865 NFSBCOPY(*cpp, cp, *slenp);
3866 free(*cpp, M_NFSSTRING);
3870 *slenp = siz + 1024;
3874 * Initialize the reply header data structures.
3877 nfsrvd_rephead(struct nfsrv_descript *nd)
3882 * If this is a big reply, use a cluster.
3884 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3885 nfs_bigreply[nd->nd_procnum]) {
3886 NFSMCLGET(mreq, M_WAITOK);
3894 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3895 mbuf_setlen(mreq, 0);
3897 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3898 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3902 * Lock a socket against others.
3903 * Currently used to serialize connect/disconnect attempts.
3906 newnfs_sndlock(int *flagp)
3911 while (*flagp & NFSR_SNDLOCK) {
3912 *flagp |= NFSR_WANTSND;
3915 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3916 PZERO - 1, "nfsndlck", &ts);
3918 *flagp |= NFSR_SNDLOCK;
3924 * Unlock the stream socket for others.
3927 newnfs_sndunlock(int *flagp)
3931 if ((*flagp & NFSR_SNDLOCK) == 0)
3932 panic("nfs sndunlock");
3933 *flagp &= ~NFSR_SNDLOCK;
3934 if (*flagp & NFSR_WANTSND) {
3935 *flagp &= ~NFSR_WANTSND;
3936 wakeup((caddr_t)flagp);
3942 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3945 struct sockaddr_in *sad;
3946 struct sockaddr_in6 *sad6;
3947 struct in_addr saddr;
3948 uint32_t portnum, *tl;
3949 int af = 0, i, j, k;
3950 char addr[64], protocol[5], *cp;
3951 int cantparse = 0, error = 0;
3954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3955 i = fxdr_unsigned(int, *tl);
3956 if (i >= 3 && i <= 4) {
3957 error = nfsrv_mtostr(nd, protocol, i);
3960 if (strcmp(protocol, "tcp") == 0) {
3963 } else if (strcmp(protocol, "udp") == 0) {
3966 } else if (strcmp(protocol, "tcp6") == 0) {
3969 } else if (strcmp(protocol, "udp6") == 0) {
3977 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3983 i = fxdr_unsigned(int, *tl);
3985 error = NFSERR_BADXDR;
3987 } else if (cantparse == 0 && i >= 11 && i < 64) {
3989 * The shortest address is 11chars and the longest is < 64.
3991 error = nfsrv_mtostr(nd, addr, i);
3995 /* Find the port# at the end and extract that. */
3999 /* Count back two '.'s from end to get port# field. */
4000 for (j = 0; j < i; j++) {
4010 * The NFSv4 port# is appended as .N.N, where N is
4011 * a decimal # in the range 0-255, just like an inet4
4012 * address. Cheat and use inet_aton(), which will
4013 * return a Class A address and then shift the high
4014 * order 8bits over to convert it to the port#.
4017 if (inet_aton(cp, &saddr) == 1) {
4018 portnum = ntohl(saddr.s_addr);
4019 portv = (uint16_t)((portnum >> 16) |
4025 if (cantparse == 0) {
4026 if (af == AF_INET) {
4027 sad = (struct sockaddr_in *)sa;
4028 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4029 sad->sin_len = sizeof(*sad);
4030 sad->sin_family = AF_INET;
4031 sad->sin_port = htons(portv);
4035 sad6 = (struct sockaddr_in6 *)sa;
4036 if (inet_pton(af, addr, &sad6->sin6_addr)
4038 sad6->sin6_len = sizeof(*sad6);
4039 sad6->sin6_family = AF_INET6;
4040 sad6->sin6_port = htons(portv);
4047 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4058 * Handle an NFSv4.1 Sequence request for the session.
4059 * If reply != NULL, use it to return the cached reply, as required.
4060 * The client gets a cached reply via this call for callbacks, however the
4061 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4064 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4065 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4072 if (slotid > maxslot)
4073 return (NFSERR_BADSLOT);
4074 if (seqid == slots[slotid].nfssl_seq) {
4076 if (slots[slotid].nfssl_inprog != 0)
4077 error = NFSERR_DELAY;
4078 else if (slots[slotid].nfssl_reply != NULL) {
4079 if (reply != NULL) {
4080 *reply = slots[slotid].nfssl_reply;
4081 slots[slotid].nfssl_reply = NULL;
4083 slots[slotid].nfssl_inprog = 1;
4084 error = NFSERR_REPLYFROMCACHE;
4086 /* No reply cached, so just do it. */
4087 slots[slotid].nfssl_inprog = 1;
4088 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4089 if (slots[slotid].nfssl_reply != NULL)
4090 m_freem(slots[slotid].nfssl_reply);
4091 slots[slotid].nfssl_reply = NULL;
4092 slots[slotid].nfssl_inprog = 1;
4093 slots[slotid].nfssl_seq++;
4095 error = NFSERR_SEQMISORDERED;
4100 * Cache this reply for the slot.
4101 * Use the "rep" argument to return the cached reply if repstat is set to
4102 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4105 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4109 if (repstat == NFSERR_REPLYFROMCACHE) {
4110 *rep = slots[slotid].nfssl_reply;
4111 slots[slotid].nfssl_reply = NULL;
4113 if (slots[slotid].nfssl_reply != NULL)
4114 m_freem(slots[slotid].nfssl_reply);
4115 slots[slotid].nfssl_reply = *rep;
4117 slots[slotid].nfssl_inprog = 0;
4121 * Generate the xdr for an NFSv4.1 Sequence Operation.
4124 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4125 struct nfsclsession *sep, int dont_replycache)
4127 uint32_t *tl, slotseq = 0;
4128 int error, maxslot, slotpos;
4129 uint8_t sessionid[NFSX_V4SESSIONID];
4131 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4134 /* Build the Sequence arguments. */
4135 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4136 nd->nd_sequence = tl;
4137 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4138 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4139 nd->nd_slotseq = tl;
4141 *tl++ = txdr_unsigned(slotseq);
4142 *tl++ = txdr_unsigned(slotpos);
4143 *tl++ = txdr_unsigned(maxslot);
4144 if (dont_replycache == 0)
4150 * There are two errors and the rest of the session can
4152 * NFSERR_BADSESSION: This bad session should just generate
4153 * the same error again when the RPC is retried.
4154 * ESTALE: A forced dismount is in progress and will cause the
4155 * RPC to fail later.
4162 nd->nd_flag |= ND_HASSEQUENCE;
4166 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4167 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4169 int i, maxslot, slotpos;
4172 /* Find an unused slot. */
4175 mtx_lock(&sep->nfsess_mtx);
4177 if (nmp != NULL && sep->nfsess_defunct != 0) {
4178 /* Just return the bad session. */
4179 bcopy(sep->nfsess_sessionid, sessionid,
4181 mtx_unlock(&sep->nfsess_mtx);
4182 return (NFSERR_BADSESSION);
4185 for (i = 0; i < sep->nfsess_foreslots; i++) {
4186 if ((bitval & sep->nfsess_slots) == 0) {
4188 sep->nfsess_slots |= bitval;
4189 sep->nfsess_slotseq[i]++;
4190 *slotseqp = sep->nfsess_slotseq[i];
4195 if (slotpos == -1) {
4197 * If a forced dismount is in progress, just return.
4198 * This RPC attempt will fail when it calls
4202 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4204 mtx_unlock(&sep->nfsess_mtx);
4207 /* Wake up once/sec, to check for a forced dismount. */
4208 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4209 PZERO, "nfsclseq", hz);
4211 } while (slotpos == -1);
4212 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4214 for (i = 0; i < 64; i++) {
4215 if ((bitval & sep->nfsess_slots) != 0)
4219 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4220 mtx_unlock(&sep->nfsess_mtx);
4221 *slotposp = slotpos;
4222 *maxslotp = maxslot;
4227 * Free a session slot.
4230 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4237 mtx_lock(&sep->nfsess_mtx);
4238 if ((bitval & sep->nfsess_slots) == 0)
4239 printf("freeing free slot!!\n");
4240 sep->nfsess_slots &= ~bitval;
4241 wakeup(&sep->nfsess_slots);
4242 mtx_unlock(&sep->nfsess_mtx);