2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid = UID_NOBODY;
67 gid_t nfsrv_defaultgid = GID_NOGROUP;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 int nfsd_enable_stringtouid = 0;
71 static int nfs_enable_uidtostring = 0;
74 extern int nfsrv_lughashsize;
76 SYSCTL_DECL(_vfs_nfs);
77 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
78 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
81 * This array of structures indicates, for V4:
82 * retfh - which of 3 types of calling args are used
83 * 0 - doesn't change cfh or use a sfh
84 * 1 - replaces cfh with a new one (unless it returns an error status)
85 * 2 - uses cfh and sfh
86 * needscfh - if the op wants a cfh and premtime
87 * 0 - doesn't use a cfh
88 * 1 - uses a cfh, but doesn't want pre-op attributes
89 * 2 - uses a cfh and wants pre-op attributes
90 * savereply - indicates a non-idempotent Op
91 * 0 - not non-idempotent
93 * Ops that are ordered via seqid# are handled separately from these
95 * Define it here, since it is used by both the client and server.
97 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
98 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
99 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
101 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
102 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
103 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
104 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
105 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
107 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
108 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
109 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
112 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
113 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
114 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
115 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
116 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
117 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
118 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
119 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
120 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
121 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
122 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
123 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
124 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
125 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
126 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
127 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
132 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
135 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
136 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
147 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
158 #endif /* !APPLEKEXT */
160 static int ncl_mbuf_mhlen = MHLEN;
161 static int nfsrv_usercnt = 0;
162 static int nfsrv_dnsnamelen;
163 static u_char *nfsrv_dnsname = NULL;
164 static int nfsrv_usermax = 999999999;
165 struct nfsrv_lughash {
167 struct nfsuserhashhead lughead;
169 static struct nfsrv_lughash *nfsuserhash;
170 static struct nfsrv_lughash *nfsusernamehash;
171 static struct nfsrv_lughash *nfsgrouphash;
172 static struct nfsrv_lughash *nfsgroupnamehash;
175 * This static array indicates whether or not the RPC generates a large
176 * reply. This is used by nfs_reply() to decide whether or not an mbuf
177 * cluster should be allocated. (If a cluster is required by an RPC
178 * marked 0 in this array, the code will still work, just not quite as
181 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
182 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,
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
185 /* local functions */
186 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
187 static void nfsv4_wanted(struct nfsv4lock *lp);
188 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
189 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
191 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
192 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
194 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
199 * copies mbuf chain to the uio scatter/gather list
202 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
204 char *mbufcp, *uiocp;
211 mbufcp = nd->nd_dpos;
212 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
213 rem = NFSM_RNDUP(siz) - siz;
215 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
219 left = uiop->uio_iov->iov_len;
220 uiocp = uiop->uio_iov->iov_base;
231 mbufcp = NFSMTOD(mp, caddr_t);
234 ("len %d, corrupted mbuf?", len));
236 xfer = (left > len) ? len : left;
239 if (uiop->uio_iov->iov_op != NULL)
240 (*(uiop->uio_iov->iov_op))
241 (mbufcp, uiocp, xfer);
244 if (uiop->uio_segflg == UIO_SYSSPACE)
245 NFSBCOPY(mbufcp, uiocp, xfer);
247 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
252 uiop->uio_offset += xfer;
253 uiop->uio_resid -= xfer;
255 if (uiop->uio_iov->iov_len <= siz) {
259 uiop->uio_iov->iov_base = (void *)
260 ((char *)uiop->uio_iov->iov_base + uiosiz);
261 uiop->uio_iov->iov_len -= uiosiz;
265 nd->nd_dpos = mbufcp;
269 error = nfsm_advance(nd, rem, len);
275 NFSEXITCODE2(error, nd);
281 * Help break down an mbuf chain by setting the first siz bytes contiguous
282 * pointed to by returned val.
283 * This is used by the macro NFSM_DISSECT for tough
287 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
296 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
298 nd->nd_md = mbuf_next(nd->nd_md);
299 if (nd->nd_md == NULL)
301 left = mbuf_len(nd->nd_md);
302 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
307 } else if (mbuf_next(nd->nd_md) == NULL) {
309 } else if (siz > ncl_mbuf_mhlen) {
310 panic("nfs S too big");
312 MGET(mp2, MT_DATA, how);
315 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
316 mbuf_setnext(nd->nd_md, mp2);
317 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
319 retp = p = NFSMTOD(mp2, caddr_t);
320 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
323 mp2 = mbuf_next(mp2);
324 /* Loop around copying up the siz2 bytes */
328 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
330 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
331 NFSM_DATAP(mp2, xfer);
332 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
337 mp2 = mbuf_next(mp2);
339 mbuf_setlen(nd->nd_md, siz);
341 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
347 * Advance the position in the mbuf chain.
348 * If offs == 0, this is a no-op, but it is simpler to just return from
349 * here than check for offs > 0 for all calls to nfsm_advance.
350 * If left == -1, it should be calculated here.
353 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
360 * A negative offs should be considered a serious problem.
363 panic("nfsrv_advance");
366 * If left == -1, calculate it here.
369 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
373 * Loop around, advancing over the mbuf data.
375 while (offs > left) {
377 nd->nd_md = mbuf_next(nd->nd_md);
378 if (nd->nd_md == NULL) {
382 left = mbuf_len(nd->nd_md);
383 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
393 * Copy a string into mbuf(s).
394 * Return the number of bytes output, including XDR overheads.
397 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
406 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
407 *tl = txdr_unsigned(siz);
408 rem = NFSM_RNDUP(siz) - siz;
409 bytesize = NFSX_UNSIGNED + siz + rem;
412 left = M_TRAILINGSPACE(m2);
415 * Loop around copying the string to mbuf(s).
419 if (siz > ncl_mbuf_mlen)
420 NFSMCLGET(m1, M_WAITOK);
424 mbuf_setnext(m2, m1);
426 cp2 = NFSMTOD(m2, caddr_t);
427 left = M_TRAILINGSPACE(m2);
433 NFSBCOPY(cp, cp2, xfer);
435 mbuf_setlen(m2, mbuf_len(m2) + xfer);
438 if (siz == 0 && rem) {
440 panic("nfsm_strtom");
441 NFSBZERO(cp2 + xfer, rem);
442 mbuf_setlen(m2, mbuf_len(m2) + rem);
446 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
451 * Called once to initialize data structures...
456 static int nfs_inited = 0;
462 newnfs_true = txdr_unsigned(TRUE);
463 newnfs_false = txdr_unsigned(FALSE);
464 newnfs_xdrneg1 = txdr_unsigned(-1);
465 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
468 NFSSETBOOTTIME(nfsboottime);
471 * Initialize reply list and start timer
473 TAILQ_INIT(&nfsd_reqq);
478 * Put a file handle in an mbuf list.
479 * If the size argument == 0, just use the default size.
480 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
481 * Return the number of bytes output, including XDR overhead.
484 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
488 int fullsiz, rem, bytesize = 0;
492 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
494 if (size > NFSX_V2FH)
495 panic("fh size > NFSX_V2FH for NFSv2");
496 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
497 NFSBCOPY(fhp, cp, size);
498 if (size < NFSX_V2FH)
499 NFSBZERO(cp + size, NFSX_V2FH - size);
500 bytesize = NFSX_V2FH;
504 fullsiz = NFSM_RNDUP(size);
505 rem = fullsiz - size;
507 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
508 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
511 bytesize = NFSX_UNSIGNED + fullsiz;
513 (void) nfsm_strtom(nd, fhp, size);
520 * This function compares two net addresses by family and returns TRUE
521 * if they are the same host.
522 * If there is any doubt, return FALSE.
523 * The AF_INET family is handled as a special case so that address mbufs
524 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
527 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
529 struct sockaddr_in *inetaddr;
533 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
534 if (inetaddr->sin_family == AF_INET &&
535 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
541 struct sockaddr_in6 *inetaddr6;
543 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
544 /* XXX - should test sin6_scope_id ? */
545 if (inetaddr6->sin6_family == AF_INET6 &&
546 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
557 * Similar to the above, but takes to NFSSOCKADDR_T args.
560 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
562 struct sockaddr_in *addr1, *addr2;
563 struct sockaddr *inaddr;
565 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
566 switch (inaddr->sa_family) {
568 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
569 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
570 if (addr2->sin_family == AF_INET &&
571 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
577 struct sockaddr_in6 *inet6addr1, *inet6addr2;
579 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
580 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
581 /* XXX - should test sin6_scope_id ? */
582 if (inet6addr2->sin6_family == AF_INET6 &&
583 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
584 &inet6addr2->sin6_addr))
595 * Trim the stuff already dissected off the mbuf list.
598 newnfs_trimleading(nd)
599 struct nfsrv_descript *nd;
605 * First, free up leading mbufs.
607 if (nd->nd_mrep != nd->nd_md) {
609 while (mbuf_next(m) != nd->nd_md) {
610 if (mbuf_next(m) == NULL)
611 panic("nfsm trim leading");
614 mbuf_setnext(m, NULL);
615 mbuf_freem(nd->nd_mrep);
620 * Now, adjust this mbuf, based on nd_dpos.
622 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
623 if (offs == mbuf_len(m)) {
627 panic("nfsm trim leading2");
628 mbuf_setnext(n, NULL);
630 } else if (offs > 0) {
631 mbuf_setlen(m, mbuf_len(m) - offs);
634 panic("nfsm trimleading offs");
637 nd->nd_dpos = NFSMTOD(m, caddr_t);
641 * Trim trailing data off the mbuf list being built.
644 newnfs_trimtrailing(nd, mb, bpos)
645 struct nfsrv_descript *nd;
651 mbuf_freem(mbuf_next(mb));
652 mbuf_setnext(mb, NULL);
654 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
660 * Dissect a file handle on the client.
663 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
670 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
671 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
672 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
679 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
681 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
683 FREE((caddr_t)nfhp, M_NFSFH);
689 NFSEXITCODE2(error, nd);
694 * Break down the nfsv4 acl.
695 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
698 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
699 int *aclsizep, __unused NFSPROC_T *p)
703 int acecnt, error = 0, aceerr = 0, acesize;
709 * Parse out the ace entries and expect them to conform to
710 * what can be supported by R/W/X bits.
712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
713 aclsize = NFSX_UNSIGNED;
714 acecnt = fxdr_unsigned(int, *tl);
715 if (acecnt > ACL_MAX_ENTRIES)
716 aceerr = NFSERR_ATTRNOTSUPP;
717 if (nfsrv_useacl == 0)
718 aceerr = NFSERR_ATTRNOTSUPP;
719 for (i = 0; i < acecnt; i++) {
721 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
722 &aceerr, &acesize, p);
724 error = nfsrv_skipace(nd, &acesize);
730 aclp->acl_cnt = acecnt;
736 NFSEXITCODE2(error, nd);
741 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
744 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
749 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
750 len = fxdr_unsigned(int, *(tl + 3));
751 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
753 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
754 NFSEXITCODE2(error, nd);
759 * Get attribute bits from an mbuf list.
760 * Returns EBADRPC for a parsing error, 0 otherwise.
761 * If the clearinvalid flag is set, clear the bits not supported.
764 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
771 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
772 cnt = fxdr_unsigned(int, *tl);
774 error = NFSERR_BADXDR;
777 if (cnt > NFSATTRBIT_MAXWORDS)
778 outcnt = NFSATTRBIT_MAXWORDS;
781 NFSZERO_ATTRBIT(attrbitp);
783 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
784 for (i = 0; i < outcnt; i++)
785 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
787 for (i = 0; i < (cnt - outcnt); i++) {
788 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
789 if (retnotsupp != NULL && *tl != 0)
790 *retnotsupp = NFSERR_ATTRNOTSUPP;
793 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
795 NFSEXITCODE2(error, nd);
800 * Get the attributes for V4.
801 * If the compare flag is true, test for any attribute changes,
802 * otherwise return the attribute values.
803 * These attributes cover fields in "struct vattr", "struct statfs",
804 * "struct nfsfsinfo", the file handle and the lease duration.
805 * The value of retcmpp is set to 1 if all attributes are the same,
807 * Returns EBADRPC if it can't be parsed, 0 otherwise.
810 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
811 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
812 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
813 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
814 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
817 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
818 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
819 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
820 nfsattrbit_t attrbits, retattrbits, checkattrbits;
822 struct nfsreferral *refp;
825 struct timespec temptime;
829 u_int32_t freenum = 0, tuint;
830 u_int64_t uquad = 0, thyp, thyp2;
835 static struct timeval last64fileid;
836 static size_t count64fileid;
837 static struct timeval last64mountfileid;
838 static size_t count64mountfileid;
839 static struct timeval warninterval = { 60, 0 };
843 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
845 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
851 *retcmpp = retnotsup;
854 * Just set default values to some of the important ones.
859 nap->na_rdev = (NFSDEV_T)0;
860 nap->na_mtime.tv_sec = 0;
861 nap->na_mtime.tv_nsec = 0;
864 nap->na_blocksize = NFS_FABLKSIZE;
867 sbp->f_bsize = NFS_FABLKSIZE;
875 fsp->fs_rtmax = 8192;
876 fsp->fs_rtpref = 8192;
877 fsp->fs_maxname = NFS_MAXNAMLEN;
878 fsp->fs_wtmax = 8192;
879 fsp->fs_wtpref = 8192;
880 fsp->fs_wtmult = NFS_FABLKSIZE;
881 fsp->fs_dtpref = 8192;
882 fsp->fs_maxfilesize = 0xffffffffffffffffull;
883 fsp->fs_timedelta.tv_sec = 0;
884 fsp->fs_timedelta.tv_nsec = 1;
885 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
886 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
889 pc->pc_linkmax = LINK_MAX;
890 pc->pc_namemax = NAME_MAX;
892 pc->pc_chownrestricted = 0;
893 pc->pc_caseinsensitive = 0;
894 pc->pc_casepreserving = 1;
897 sfp->sf_ffiles = UINT64_MAX;
898 sfp->sf_tfiles = UINT64_MAX;
899 sfp->sf_afiles = UINT64_MAX;
900 sfp->sf_fbytes = UINT64_MAX;
901 sfp->sf_tbytes = UINT64_MAX;
902 sfp->sf_abytes = UINT64_MAX;
907 * Loop around getting the attributes.
909 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
910 attrsize = fxdr_unsigned(int, *tl);
911 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
912 if (attrsum > attrsize) {
913 error = NFSERR_BADXDR;
916 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
918 case NFSATTRBIT_SUPPORTEDATTRS:
920 if (compare || nap == NULL)
921 error = nfsrv_getattrbits(nd, &retattrbits,
924 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
928 if (compare && !(*retcmpp)) {
929 NFSSETSUPP_ATTRBIT(&checkattrbits);
930 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
932 *retcmpp = NFSERR_NOTSAME;
936 case NFSATTRBIT_TYPE:
937 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
940 if (nap->na_type != nfsv34tov_type(*tl))
941 *retcmpp = NFSERR_NOTSAME;
943 } else if (nap != NULL) {
944 nap->na_type = nfsv34tov_type(*tl);
946 attrsum += NFSX_UNSIGNED;
948 case NFSATTRBIT_FHEXPIRETYPE:
949 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
950 if (compare && !(*retcmpp)) {
951 if (fxdr_unsigned(int, *tl) !=
952 NFSV4FHTYPE_PERSISTENT)
953 *retcmpp = NFSERR_NOTSAME;
955 attrsum += NFSX_UNSIGNED;
957 case NFSATTRBIT_CHANGE:
958 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
961 if (nap->na_filerev != fxdr_hyper(tl))
962 *retcmpp = NFSERR_NOTSAME;
964 } else if (nap != NULL) {
965 nap->na_filerev = fxdr_hyper(tl);
967 attrsum += NFSX_HYPER;
969 case NFSATTRBIT_SIZE:
970 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
973 if (nap->na_size != fxdr_hyper(tl))
974 *retcmpp = NFSERR_NOTSAME;
976 } else if (nap != NULL) {
977 nap->na_size = fxdr_hyper(tl);
979 attrsum += NFSX_HYPER;
981 case NFSATTRBIT_LINKSUPPORT:
982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
985 if (fsp->fs_properties & NFSV3_FSFLINK) {
986 if (*tl == newnfs_false)
987 *retcmpp = NFSERR_NOTSAME;
989 if (*tl == newnfs_true)
990 *retcmpp = NFSERR_NOTSAME;
993 } else if (fsp != NULL) {
994 if (*tl == newnfs_true)
995 fsp->fs_properties |= NFSV3_FSFLINK;
997 fsp->fs_properties &= ~NFSV3_FSFLINK;
999 attrsum += NFSX_UNSIGNED;
1001 case NFSATTRBIT_SYMLINKSUPPORT:
1002 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1005 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1006 if (*tl == newnfs_false)
1007 *retcmpp = NFSERR_NOTSAME;
1009 if (*tl == newnfs_true)
1010 *retcmpp = NFSERR_NOTSAME;
1013 } else if (fsp != NULL) {
1014 if (*tl == newnfs_true)
1015 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1017 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1019 attrsum += NFSX_UNSIGNED;
1021 case NFSATTRBIT_NAMEDATTR:
1022 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1023 if (compare && !(*retcmpp)) {
1024 if (*tl != newnfs_false)
1025 *retcmpp = NFSERR_NOTSAME;
1027 attrsum += NFSX_UNSIGNED;
1029 case NFSATTRBIT_FSID:
1030 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1031 thyp = fxdr_hyper(tl);
1033 thyp2 = fxdr_hyper(tl);
1035 if (*retcmpp == 0) {
1036 if (thyp != (u_int64_t)
1037 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1038 thyp2 != (u_int64_t)
1039 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1040 *retcmpp = NFSERR_NOTSAME;
1042 } else if (nap != NULL) {
1043 nap->na_filesid[0] = thyp;
1044 nap->na_filesid[1] = thyp2;
1046 attrsum += (4 * NFSX_UNSIGNED);
1048 case NFSATTRBIT_UNIQUEHANDLES:
1049 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1050 if (compare && !(*retcmpp)) {
1051 if (*tl != newnfs_true)
1052 *retcmpp = NFSERR_NOTSAME;
1054 attrsum += NFSX_UNSIGNED;
1056 case NFSATTRBIT_LEASETIME:
1057 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1059 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1061 *retcmpp = NFSERR_NOTSAME;
1062 } else if (leasep != NULL) {
1063 *leasep = fxdr_unsigned(u_int32_t, *tl);
1065 attrsum += NFSX_UNSIGNED;
1067 case NFSATTRBIT_RDATTRERROR:
1068 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1071 *retcmpp = NFSERR_INVAL;
1072 } else if (rderrp != NULL) {
1073 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1075 attrsum += NFSX_UNSIGNED;
1077 case NFSATTRBIT_ACL:
1083 naclp = acl_alloc(M_WAITOK);
1084 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1090 if (aceerr || aclp == NULL ||
1091 nfsrv_compareacl(aclp, naclp))
1092 *retcmpp = NFSERR_NOTSAME;
1095 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1097 *retcmpp = NFSERR_ATTRNOTSUPP;
1101 if (vp != NULL && aclp != NULL)
1102 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1105 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1112 case NFSATTRBIT_ACLSUPPORT:
1113 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1114 if (compare && !(*retcmpp)) {
1116 if (fxdr_unsigned(u_int32_t, *tl) !=
1118 *retcmpp = NFSERR_NOTSAME;
1120 *retcmpp = NFSERR_ATTRNOTSUPP;
1123 attrsum += NFSX_UNSIGNED;
1125 case NFSATTRBIT_ARCHIVE:
1126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1127 if (compare && !(*retcmpp))
1128 *retcmpp = NFSERR_ATTRNOTSUPP;
1129 attrsum += NFSX_UNSIGNED;
1131 case NFSATTRBIT_CANSETTIME:
1132 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1135 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1136 if (*tl == newnfs_false)
1137 *retcmpp = NFSERR_NOTSAME;
1139 if (*tl == newnfs_true)
1140 *retcmpp = NFSERR_NOTSAME;
1143 } else if (fsp != NULL) {
1144 if (*tl == newnfs_true)
1145 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1147 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1149 attrsum += NFSX_UNSIGNED;
1151 case NFSATTRBIT_CASEINSENSITIVE:
1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1155 if (*tl != newnfs_false)
1156 *retcmpp = NFSERR_NOTSAME;
1158 } else if (pc != NULL) {
1159 pc->pc_caseinsensitive =
1160 fxdr_unsigned(u_int32_t, *tl);
1162 attrsum += NFSX_UNSIGNED;
1164 case NFSATTRBIT_CASEPRESERVING:
1165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1168 if (*tl != newnfs_true)
1169 *retcmpp = NFSERR_NOTSAME;
1171 } else if (pc != NULL) {
1172 pc->pc_casepreserving =
1173 fxdr_unsigned(u_int32_t, *tl);
1175 attrsum += NFSX_UNSIGNED;
1177 case NFSATTRBIT_CHOWNRESTRICTED:
1178 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1181 if (*tl != newnfs_true)
1182 *retcmpp = NFSERR_NOTSAME;
1184 } else if (pc != NULL) {
1185 pc->pc_chownrestricted =
1186 fxdr_unsigned(u_int32_t, *tl);
1188 attrsum += NFSX_UNSIGNED;
1190 case NFSATTRBIT_FILEHANDLE:
1191 error = nfsm_getfh(nd, &tnfhp);
1194 tfhsize = tnfhp->nfh_len;
1197 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1199 *retcmpp = NFSERR_NOTSAME;
1200 FREE((caddr_t)tnfhp, M_NFSFH);
1201 } else if (nfhpp != NULL) {
1204 FREE((caddr_t)tnfhp, M_NFSFH);
1206 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1208 case NFSATTRBIT_FILEID:
1209 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1210 thyp = fxdr_hyper(tl);
1213 if ((u_int64_t)nap->na_fileid != thyp)
1214 *retcmpp = NFSERR_NOTSAME;
1216 } else if (nap != NULL) {
1219 if (ratecheck(&last64fileid, &warninterval)) {
1220 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1225 nap->na_fileid = thyp;
1227 attrsum += NFSX_HYPER;
1229 case NFSATTRBIT_FILESAVAIL:
1230 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1233 sfp->sf_afiles != fxdr_hyper(tl))
1234 *retcmpp = NFSERR_NOTSAME;
1235 } else if (sfp != NULL) {
1236 sfp->sf_afiles = fxdr_hyper(tl);
1238 attrsum += NFSX_HYPER;
1240 case NFSATTRBIT_FILESFREE:
1241 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1244 sfp->sf_ffiles != fxdr_hyper(tl))
1245 *retcmpp = NFSERR_NOTSAME;
1246 } else if (sfp != NULL) {
1247 sfp->sf_ffiles = fxdr_hyper(tl);
1249 attrsum += NFSX_HYPER;
1251 case NFSATTRBIT_FILESTOTAL:
1252 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1255 sfp->sf_tfiles != fxdr_hyper(tl))
1256 *retcmpp = NFSERR_NOTSAME;
1257 } else if (sfp != NULL) {
1258 sfp->sf_tfiles = fxdr_hyper(tl);
1260 attrsum += NFSX_HYPER;
1262 case NFSATTRBIT_FSLOCATIONS:
1263 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1267 if (compare && !(*retcmpp)) {
1268 refp = nfsv4root_getreferral(vp, NULL, 0);
1270 if (cp == NULL || cp2 == NULL ||
1272 strcmp(cp2, refp->nfr_srvlist))
1273 *retcmpp = NFSERR_NOTSAME;
1274 } else if (m == 0) {
1275 *retcmpp = NFSERR_NOTSAME;
1279 free(cp, M_NFSSTRING);
1281 free(cp2, M_NFSSTRING);
1283 case NFSATTRBIT_HIDDEN:
1284 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1285 if (compare && !(*retcmpp))
1286 *retcmpp = NFSERR_ATTRNOTSUPP;
1287 attrsum += NFSX_UNSIGNED;
1289 case NFSATTRBIT_HOMOGENEOUS:
1290 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1293 if (fsp->fs_properties &
1294 NFSV3_FSFHOMOGENEOUS) {
1295 if (*tl == newnfs_false)
1296 *retcmpp = NFSERR_NOTSAME;
1298 if (*tl == newnfs_true)
1299 *retcmpp = NFSERR_NOTSAME;
1302 } else if (fsp != NULL) {
1303 if (*tl == newnfs_true)
1304 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1306 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1308 attrsum += NFSX_UNSIGNED;
1310 case NFSATTRBIT_MAXFILESIZE:
1311 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1312 tnfsquad.qval = fxdr_hyper(tl);
1315 tquad = NFSRV_MAXFILESIZE;
1316 if (tquad != tnfsquad.qval)
1317 *retcmpp = NFSERR_NOTSAME;
1319 } else if (fsp != NULL) {
1320 fsp->fs_maxfilesize = tnfsquad.qval;
1322 attrsum += NFSX_HYPER;
1324 case NFSATTRBIT_MAXLINK:
1325 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1328 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1329 *retcmpp = NFSERR_NOTSAME;
1331 } else if (pc != NULL) {
1332 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1334 attrsum += NFSX_UNSIGNED;
1336 case NFSATTRBIT_MAXNAME:
1337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1340 if (fsp->fs_maxname !=
1341 fxdr_unsigned(u_int32_t, *tl))
1342 *retcmpp = NFSERR_NOTSAME;
1345 tuint = fxdr_unsigned(u_int32_t, *tl);
1347 * Some Linux NFSv4 servers report this
1348 * as 0 or 4billion, so I'll set it to
1349 * NFS_MAXNAMLEN. If a server actually creates
1350 * a name longer than NFS_MAXNAMLEN, it will
1351 * get an error back.
1353 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1354 tuint = NFS_MAXNAMLEN;
1356 fsp->fs_maxname = tuint;
1358 pc->pc_namemax = tuint;
1360 attrsum += NFSX_UNSIGNED;
1362 case NFSATTRBIT_MAXREAD:
1363 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1366 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1367 *(tl + 1)) || *tl != 0)
1368 *retcmpp = NFSERR_NOTSAME;
1370 } else if (fsp != NULL) {
1371 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1372 fsp->fs_rtpref = fsp->fs_rtmax;
1373 fsp->fs_dtpref = fsp->fs_rtpref;
1375 attrsum += NFSX_HYPER;
1377 case NFSATTRBIT_MAXWRITE:
1378 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1381 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1382 *(tl + 1)) || *tl != 0)
1383 *retcmpp = NFSERR_NOTSAME;
1385 } else if (fsp != NULL) {
1386 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1387 fsp->fs_wtpref = fsp->fs_wtmax;
1389 attrsum += NFSX_HYPER;
1391 case NFSATTRBIT_MIMETYPE:
1392 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1393 i = fxdr_unsigned(int, *tl);
1394 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1395 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1398 if (compare && !(*retcmpp))
1399 *retcmpp = NFSERR_ATTRNOTSUPP;
1401 case NFSATTRBIT_MODE:
1402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1405 if (nap->na_mode != nfstov_mode(*tl))
1406 *retcmpp = NFSERR_NOTSAME;
1408 } else if (nap != NULL) {
1409 nap->na_mode = nfstov_mode(*tl);
1411 attrsum += NFSX_UNSIGNED;
1413 case NFSATTRBIT_NOTRUNC:
1414 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1417 if (*tl != newnfs_true)
1418 *retcmpp = NFSERR_NOTSAME;
1420 } else if (pc != NULL) {
1421 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1423 attrsum += NFSX_UNSIGNED;
1425 case NFSATTRBIT_NUMLINKS:
1426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1427 tuint = fxdr_unsigned(u_int32_t, *tl);
1430 if ((u_int32_t)nap->na_nlink != tuint)
1431 *retcmpp = NFSERR_NOTSAME;
1433 } else if (nap != NULL) {
1434 nap->na_nlink = tuint;
1436 attrsum += NFSX_UNSIGNED;
1438 case NFSATTRBIT_OWNER:
1439 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1440 j = fxdr_unsigned(int, *tl);
1442 error = NFSERR_BADXDR;
1445 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1446 if (j > NFSV4_SMALLSTR)
1447 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1450 error = nfsrv_mtostr(nd, cp, j);
1452 if (j > NFSV4_SMALLSTR)
1453 free(cp, M_NFSSTRING);
1458 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1460 *retcmpp = NFSERR_NOTSAME;
1462 } else if (nap != NULL) {
1463 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1464 nap->na_uid = nfsrv_defaultuid;
1468 if (j > NFSV4_SMALLSTR)
1469 free(cp, M_NFSSTRING);
1471 case NFSATTRBIT_OWNERGROUP:
1472 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1473 j = fxdr_unsigned(int, *tl);
1475 error = NFSERR_BADXDR;
1478 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1479 if (j > NFSV4_SMALLSTR)
1480 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1483 error = nfsrv_mtostr(nd, cp, j);
1485 if (j > NFSV4_SMALLSTR)
1486 free(cp, M_NFSSTRING);
1491 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1493 *retcmpp = NFSERR_NOTSAME;
1495 } else if (nap != NULL) {
1496 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1497 nap->na_gid = nfsrv_defaultgid;
1501 if (j > NFSV4_SMALLSTR)
1502 free(cp, M_NFSSTRING);
1504 case NFSATTRBIT_QUOTAHARD:
1505 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1507 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1508 freenum = sbp->f_bfree;
1510 freenum = sbp->f_bavail;
1513 * ufs_quotactl() insists that the uid argument
1514 * equal p_ruid for non-root quota access, so
1515 * we'll just make sure that's the case.
1517 savuid = p->p_cred->p_ruid;
1518 p->p_cred->p_ruid = cred->cr_uid;
1519 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1520 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1521 freenum = min(dqb.dqb_bhardlimit, freenum);
1522 p->p_cred->p_ruid = savuid;
1524 uquad = (u_int64_t)freenum;
1525 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1527 if (compare && !(*retcmpp)) {
1528 if (uquad != fxdr_hyper(tl))
1529 *retcmpp = NFSERR_NOTSAME;
1531 attrsum += NFSX_HYPER;
1533 case NFSATTRBIT_QUOTASOFT:
1534 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1536 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1537 freenum = sbp->f_bfree;
1539 freenum = sbp->f_bavail;
1542 * ufs_quotactl() insists that the uid argument
1543 * equal p_ruid for non-root quota access, so
1544 * we'll just make sure that's the case.
1546 savuid = p->p_cred->p_ruid;
1547 p->p_cred->p_ruid = cred->cr_uid;
1548 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1549 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1550 freenum = min(dqb.dqb_bsoftlimit, freenum);
1551 p->p_cred->p_ruid = savuid;
1553 uquad = (u_int64_t)freenum;
1554 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1556 if (compare && !(*retcmpp)) {
1557 if (uquad != fxdr_hyper(tl))
1558 *retcmpp = NFSERR_NOTSAME;
1560 attrsum += NFSX_HYPER;
1562 case NFSATTRBIT_QUOTAUSED:
1563 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1568 * ufs_quotactl() insists that the uid argument
1569 * equal p_ruid for non-root quota access, so
1570 * we'll just make sure that's the case.
1572 savuid = p->p_cred->p_ruid;
1573 p->p_cred->p_ruid = cred->cr_uid;
1574 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1575 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1576 freenum = dqb.dqb_curblocks;
1577 p->p_cred->p_ruid = savuid;
1579 uquad = (u_int64_t)freenum;
1580 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1582 if (compare && !(*retcmpp)) {
1583 if (uquad != fxdr_hyper(tl))
1584 *retcmpp = NFSERR_NOTSAME;
1586 attrsum += NFSX_HYPER;
1588 case NFSATTRBIT_RAWDEV:
1589 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1590 j = fxdr_unsigned(int, *tl++);
1591 k = fxdr_unsigned(int, *tl);
1594 if (nap->na_rdev != NFSMAKEDEV(j, k))
1595 *retcmpp = NFSERR_NOTSAME;
1597 } else if (nap != NULL) {
1598 nap->na_rdev = NFSMAKEDEV(j, k);
1600 attrsum += NFSX_V4SPECDATA;
1602 case NFSATTRBIT_SPACEAVAIL:
1603 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1606 sfp->sf_abytes != fxdr_hyper(tl))
1607 *retcmpp = NFSERR_NOTSAME;
1608 } else if (sfp != NULL) {
1609 sfp->sf_abytes = fxdr_hyper(tl);
1611 attrsum += NFSX_HYPER;
1613 case NFSATTRBIT_SPACEFREE:
1614 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1617 sfp->sf_fbytes != fxdr_hyper(tl))
1618 *retcmpp = NFSERR_NOTSAME;
1619 } else if (sfp != NULL) {
1620 sfp->sf_fbytes = fxdr_hyper(tl);
1622 attrsum += NFSX_HYPER;
1624 case NFSATTRBIT_SPACETOTAL:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1628 sfp->sf_tbytes != fxdr_hyper(tl))
1629 *retcmpp = NFSERR_NOTSAME;
1630 } else if (sfp != NULL) {
1631 sfp->sf_tbytes = fxdr_hyper(tl);
1633 attrsum += NFSX_HYPER;
1635 case NFSATTRBIT_SPACEUSED:
1636 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1637 thyp = fxdr_hyper(tl);
1640 if ((u_int64_t)nap->na_bytes != thyp)
1641 *retcmpp = NFSERR_NOTSAME;
1643 } else if (nap != NULL) {
1644 nap->na_bytes = thyp;
1646 attrsum += NFSX_HYPER;
1648 case NFSATTRBIT_SYSTEM:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1650 if (compare && !(*retcmpp))
1651 *retcmpp = NFSERR_ATTRNOTSUPP;
1652 attrsum += NFSX_UNSIGNED;
1654 case NFSATTRBIT_TIMEACCESS:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1656 fxdr_nfsv4time(tl, &temptime);
1659 if (!NFS_CMPTIME(temptime, nap->na_atime))
1660 *retcmpp = NFSERR_NOTSAME;
1662 } else if (nap != NULL) {
1663 nap->na_atime = temptime;
1665 attrsum += NFSX_V4TIME;
1667 case NFSATTRBIT_TIMEACCESSSET:
1668 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1669 attrsum += NFSX_UNSIGNED;
1670 i = fxdr_unsigned(int, *tl);
1671 if (i == NFSV4SATTRTIME_TOCLIENT) {
1672 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1673 attrsum += NFSX_V4TIME;
1675 if (compare && !(*retcmpp))
1676 *retcmpp = NFSERR_INVAL;
1678 case NFSATTRBIT_TIMEBACKUP:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1680 if (compare && !(*retcmpp))
1681 *retcmpp = NFSERR_ATTRNOTSUPP;
1682 attrsum += NFSX_V4TIME;
1684 case NFSATTRBIT_TIMECREATE:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1686 if (compare && !(*retcmpp))
1687 *retcmpp = NFSERR_ATTRNOTSUPP;
1688 attrsum += NFSX_V4TIME;
1690 case NFSATTRBIT_TIMEDELTA:
1691 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1695 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1696 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1697 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1698 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1701 *retcmpp = NFSERR_NOTSAME;
1704 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1707 attrsum += NFSX_V4TIME;
1709 case NFSATTRBIT_TIMEMETADATA:
1710 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1711 fxdr_nfsv4time(tl, &temptime);
1714 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1715 *retcmpp = NFSERR_NOTSAME;
1717 } else if (nap != NULL) {
1718 nap->na_ctime = temptime;
1720 attrsum += NFSX_V4TIME;
1722 case NFSATTRBIT_TIMEMODIFY:
1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1724 fxdr_nfsv4time(tl, &temptime);
1727 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1728 *retcmpp = NFSERR_NOTSAME;
1730 } else if (nap != NULL) {
1731 nap->na_mtime = temptime;
1733 attrsum += NFSX_V4TIME;
1735 case NFSATTRBIT_TIMEMODIFYSET:
1736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1737 attrsum += NFSX_UNSIGNED;
1738 i = fxdr_unsigned(int, *tl);
1739 if (i == NFSV4SATTRTIME_TOCLIENT) {
1740 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1741 attrsum += NFSX_V4TIME;
1743 if (compare && !(*retcmpp))
1744 *retcmpp = NFSERR_INVAL;
1746 case NFSATTRBIT_MOUNTEDONFILEID:
1747 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1748 thyp = fxdr_hyper(tl);
1752 *retcmpp = NFSERR_NOTSAME;
1754 if (!vp || !nfsrv_atroot(vp, &fid))
1755 fid = nap->na_fileid;
1756 if ((u_int64_t)fid != thyp)
1757 *retcmpp = NFSERR_NOTSAME;
1760 } else if (nap != NULL) {
1762 count64mountfileid++;
1763 if (ratecheck(&last64mountfileid, &warninterval)) {
1764 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1765 count64mountfileid);
1766 count64mountfileid = 0;
1769 nap->na_mntonfileno = thyp;
1771 attrsum += NFSX_HYPER;
1773 case NFSATTRBIT_SUPPATTREXCLCREAT:
1775 error = nfsrv_getattrbits(nd, &retattrbits,
1779 if (compare && !(*retcmpp)) {
1780 NFSSETSUPP_ATTRBIT(&checkattrbits);
1781 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1782 NFSCLRBIT_ATTRBIT(&checkattrbits,
1783 NFSATTRBIT_TIMEACCESSSET);
1784 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1786 *retcmpp = NFSERR_NOTSAME;
1791 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1793 if (compare && !(*retcmpp))
1794 *retcmpp = NFSERR_ATTRNOTSUPP;
1796 * and get out of the loop, since we can't parse
1797 * the unknown attrbute data.
1799 bitpos = NFSATTRBIT_MAX;
1805 * some clients pad the attrlist, so we need to skip over the
1808 if (attrsum > attrsize) {
1809 error = NFSERR_BADXDR;
1811 attrsize = NFSM_RNDUP(attrsize);
1812 if (attrsum < attrsize)
1813 error = nfsm_advance(nd, attrsize - attrsum, -1);
1816 NFSEXITCODE2(error, nd);
1821 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1822 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1823 * The first argument is a pointer to an nfsv4lock structure.
1824 * The second argument is 1 iff a blocking lock is wanted.
1825 * If this argument is 0, the call waits until no thread either wants nor
1826 * holds an exclusive lock.
1827 * It returns 1 if the lock was acquired, 0 otherwise.
1828 * If several processes call this function concurrently wanting the exclusive
1829 * lock, one will get the lock and the rest will return without getting the
1830 * lock. (If the caller must have the lock, it simply calls this function in a
1831 * loop until the function returns 1 to indicate the lock was acquired.)
1832 * Any usecnt must be decremented by calling nfsv4_relref() before
1833 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1834 * be called in a loop.
1835 * The isleptp argument is set to indicate if the call slept, iff not NULL
1836 * and the mp argument indicates to check for a forced dismount, iff not
1840 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1841 void *mutex, struct mount *mp)
1847 * If a lock is wanted, loop around until the lock is acquired by
1848 * someone and then released. If I want the lock, try to acquire it.
1849 * For a lock to be issued, no lock must be in force and the usecnt
1853 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1854 lp->nfslock_usecnt == 0) {
1855 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1856 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1859 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1861 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1862 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1863 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1866 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1869 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1870 PZERO - 1, "nfsv4lck", NULL);
1871 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1872 lp->nfslock_usecnt == 0) {
1873 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1874 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1882 * Release the lock acquired by nfsv4_lock().
1883 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1884 * incremented, as well.
1887 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1890 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1892 lp->nfslock_usecnt++;
1897 * Release a reference cnt.
1900 nfsv4_relref(struct nfsv4lock *lp)
1903 if (lp->nfslock_usecnt <= 0)
1904 panic("nfsv4root ref cnt");
1905 lp->nfslock_usecnt--;
1906 if (lp->nfslock_usecnt == 0)
1911 * Get a reference cnt.
1912 * This function will wait for any exclusive lock to be released, but will
1913 * not wait for threads that want the exclusive lock. If priority needs
1914 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1915 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1916 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1917 * return without getting a refcnt for that case.
1920 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1928 * Wait for a lock held.
1930 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1931 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1933 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1936 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1937 PZERO - 1, "nfsv4gr", NULL);
1939 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1942 lp->nfslock_usecnt++;
1946 * Get a reference as above, but return failure instead of sleeping if
1947 * an exclusive lock is held.
1950 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1953 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1956 lp->nfslock_usecnt++;
1961 * Test for a lock. Return 1 if locked, 0 otherwise.
1964 nfsv4_testlock(struct nfsv4lock *lp)
1967 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1968 lp->nfslock_usecnt == 0)
1974 * Wake up anyone sleeping, waiting for this lock.
1977 nfsv4_wanted(struct nfsv4lock *lp)
1980 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1981 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1982 wakeup((caddr_t)&lp->nfslock_lock);
1987 * Copy a string from an mbuf list into a character array.
1988 * Return EBADRPC if there is an mbuf error,
1992 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2001 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2002 rem = NFSM_RNDUP(siz) - siz;
2008 NFSBCOPY(cp, str, xfer);
2017 cp = NFSMTOD(mp, caddr_t);
2029 error = nfsm_advance(nd, rem, len);
2035 NFSEXITCODE2(error, nd);
2040 * Fill in the attributes as marked by the bitmap (V4).
2043 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2044 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2045 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2046 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2048 int bitpos, retnum = 0;
2050 int siz, prefixnum, error;
2051 u_char *cp, namestr[NFSV4_SMALLSTR];
2052 nfsattrbit_t attrbits, retbits;
2053 nfsattrbit_t *retbitp = &retbits;
2054 u_int32_t freenum, *retnump;
2057 struct nfsfsinfo fsinf;
2058 struct timespec temptime;
2059 NFSACL_T *aclp, *naclp = NULL;
2066 * First, set the bits that can be filled and get fsinfo.
2068 NFSSET_ATTRBIT(retbitp, attrbitp);
2070 * If both p and cred are NULL, it is a client side setattr call.
2071 * If both p and cred are not NULL, it is a server side reply call.
2072 * If p is not NULL and cred is NULL, it is a client side callback
2075 if (p == NULL && cred == NULL) {
2076 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2079 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2080 naclp = acl_alloc(M_WAITOK);
2083 nfsvno_getfs(&fsinf, isdgram);
2086 * Get the VFS_STATFS(), since some attributes need them.
2088 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2089 error = VFS_STATFS(mp, &fs);
2092 nd->nd_repstat = NFSERR_ACCES;
2095 NFSCLRSTATFS_ATTRBIT(retbitp);
2101 * And the NFSv4 ACL...
2103 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2104 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2105 supports_nfsv4acls == 0))) {
2106 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2108 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2109 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2110 supports_nfsv4acls == 0)) {
2111 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2112 } else if (naclp != NULL) {
2113 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2114 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2116 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2118 NFSVOPUNLOCK(vp, 0);
2120 error = NFSERR_PERM;
2123 nd->nd_repstat = NFSERR_ACCES;
2126 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2131 * Put out the attribute bitmap for the ones being filled in
2132 * and get the field for the number of attributes returned.
2134 prefixnum = nfsrv_putattrbit(nd, retbitp);
2135 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2136 prefixnum += NFSX_UNSIGNED;
2139 * Now, loop around filling in the attributes for each bit set.
2141 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2142 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2144 case NFSATTRBIT_SUPPORTEDATTRS:
2145 NFSSETSUPP_ATTRBIT(&attrbits);
2146 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2147 && supports_nfsv4acls == 0)) {
2148 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2149 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2151 retnum += nfsrv_putattrbit(nd, &attrbits);
2153 case NFSATTRBIT_TYPE:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2155 *tl = vtonfsv34_type(vap->va_type);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_FHEXPIRETYPE:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2160 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2161 retnum += NFSX_UNSIGNED;
2163 case NFSATTRBIT_CHANGE:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2165 txdr_hyper(vap->va_filerev, tl);
2166 retnum += NFSX_HYPER;
2168 case NFSATTRBIT_SIZE:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2170 txdr_hyper(vap->va_size, tl);
2171 retnum += NFSX_HYPER;
2173 case NFSATTRBIT_LINKSUPPORT:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2175 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2179 retnum += NFSX_UNSIGNED;
2181 case NFSATTRBIT_SYMLINKSUPPORT:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2183 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2187 retnum += NFSX_UNSIGNED;
2189 case NFSATTRBIT_NAMEDATTR:
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2192 retnum += NFSX_UNSIGNED;
2194 case NFSATTRBIT_FSID:
2195 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2197 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2199 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2200 retnum += NFSX_V4FSID;
2202 case NFSATTRBIT_UNIQUEHANDLES:
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2205 retnum += NFSX_UNSIGNED;
2207 case NFSATTRBIT_LEASETIME:
2208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2209 *tl = txdr_unsigned(nfsrv_lease);
2210 retnum += NFSX_UNSIGNED;
2212 case NFSATTRBIT_RDATTRERROR:
2213 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2214 *tl = txdr_unsigned(rderror);
2215 retnum += NFSX_UNSIGNED;
2218 * Recommended Attributes. (Only the supported ones.)
2220 case NFSATTRBIT_ACL:
2221 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2223 case NFSATTRBIT_ACLSUPPORT:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2226 retnum += NFSX_UNSIGNED;
2228 case NFSATTRBIT_CANSETTIME:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2230 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2234 retnum += NFSX_UNSIGNED;
2236 case NFSATTRBIT_CASEINSENSITIVE:
2237 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2239 retnum += NFSX_UNSIGNED;
2241 case NFSATTRBIT_CASEPRESERVING:
2242 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 retnum += NFSX_UNSIGNED;
2246 case NFSATTRBIT_CHOWNRESTRICTED:
2247 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2249 retnum += NFSX_UNSIGNED;
2251 case NFSATTRBIT_FILEHANDLE:
2252 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2254 case NFSATTRBIT_FILEID:
2255 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2257 *tl = txdr_unsigned(vap->va_fileid);
2258 retnum += NFSX_HYPER;
2260 case NFSATTRBIT_FILESAVAIL:
2262 * Check quota and use min(quota, f_ffree).
2264 freenum = fs.f_ffree;
2267 * ufs_quotactl() insists that the uid argument
2268 * equal p_ruid for non-root quota access, so
2269 * we'll just make sure that's the case.
2271 savuid = p->p_cred->p_ruid;
2272 p->p_cred->p_ruid = cred->cr_uid;
2273 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2274 cred->cr_uid, (caddr_t)&dqb))
2275 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2277 p->p_cred->p_ruid = savuid;
2279 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2281 *tl = txdr_unsigned(freenum);
2282 retnum += NFSX_HYPER;
2284 case NFSATTRBIT_FILESFREE:
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2287 *tl = txdr_unsigned(fs.f_ffree);
2288 retnum += NFSX_HYPER;
2290 case NFSATTRBIT_FILESTOTAL:
2291 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2293 *tl = txdr_unsigned(fs.f_files);
2294 retnum += NFSX_HYPER;
2296 case NFSATTRBIT_FSLOCATIONS:
2297 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2300 retnum += 2 * NFSX_UNSIGNED;
2302 case NFSATTRBIT_HOMOGENEOUS:
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2304 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2308 retnum += NFSX_UNSIGNED;
2310 case NFSATTRBIT_MAXFILESIZE:
2311 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2312 uquad = NFSRV_MAXFILESIZE;
2313 txdr_hyper(uquad, tl);
2314 retnum += NFSX_HYPER;
2316 case NFSATTRBIT_MAXLINK:
2317 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2318 *tl = txdr_unsigned(LINK_MAX);
2319 retnum += NFSX_UNSIGNED;
2321 case NFSATTRBIT_MAXNAME:
2322 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2323 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2324 retnum += NFSX_UNSIGNED;
2326 case NFSATTRBIT_MAXREAD:
2327 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2329 *tl = txdr_unsigned(fsinf.fs_rtmax);
2330 retnum += NFSX_HYPER;
2332 case NFSATTRBIT_MAXWRITE:
2333 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2335 *tl = txdr_unsigned(fsinf.fs_wtmax);
2336 retnum += NFSX_HYPER;
2338 case NFSATTRBIT_MODE:
2339 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2340 *tl = vtonfsv34_mode(vap->va_mode);
2341 retnum += NFSX_UNSIGNED;
2343 case NFSATTRBIT_NOTRUNC:
2344 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2346 retnum += NFSX_UNSIGNED;
2348 case NFSATTRBIT_NUMLINKS:
2349 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2350 *tl = txdr_unsigned(vap->va_nlink);
2351 retnum += NFSX_UNSIGNED;
2353 case NFSATTRBIT_OWNER:
2355 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2356 retnum += nfsm_strtom(nd, cp, siz);
2358 free(cp, M_NFSSTRING);
2360 case NFSATTRBIT_OWNERGROUP:
2362 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2363 retnum += nfsm_strtom(nd, cp, siz);
2365 free(cp, M_NFSSTRING);
2367 case NFSATTRBIT_QUOTAHARD:
2368 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2369 freenum = fs.f_bfree;
2371 freenum = fs.f_bavail;
2374 * ufs_quotactl() insists that the uid argument
2375 * equal p_ruid for non-root quota access, so
2376 * we'll just make sure that's the case.
2378 savuid = p->p_cred->p_ruid;
2379 p->p_cred->p_ruid = cred->cr_uid;
2380 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2381 cred->cr_uid, (caddr_t)&dqb))
2382 freenum = min(dqb.dqb_bhardlimit, freenum);
2383 p->p_cred->p_ruid = savuid;
2385 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2386 uquad = (u_int64_t)freenum;
2387 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2388 txdr_hyper(uquad, tl);
2389 retnum += NFSX_HYPER;
2391 case NFSATTRBIT_QUOTASOFT:
2392 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2393 freenum = fs.f_bfree;
2395 freenum = fs.f_bavail;
2398 * ufs_quotactl() insists that the uid argument
2399 * equal p_ruid for non-root quota access, so
2400 * we'll just make sure that's the case.
2402 savuid = p->p_cred->p_ruid;
2403 p->p_cred->p_ruid = cred->cr_uid;
2404 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2405 cred->cr_uid, (caddr_t)&dqb))
2406 freenum = min(dqb.dqb_bsoftlimit, freenum);
2407 p->p_cred->p_ruid = savuid;
2409 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2410 uquad = (u_int64_t)freenum;
2411 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2412 txdr_hyper(uquad, tl);
2413 retnum += NFSX_HYPER;
2415 case NFSATTRBIT_QUOTAUSED:
2419 * ufs_quotactl() insists that the uid argument
2420 * equal p_ruid for non-root quota access, so
2421 * we'll just make sure that's the case.
2423 savuid = p->p_cred->p_ruid;
2424 p->p_cred->p_ruid = cred->cr_uid;
2425 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2426 cred->cr_uid, (caddr_t)&dqb))
2427 freenum = dqb.dqb_curblocks;
2428 p->p_cred->p_ruid = savuid;
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2431 uquad = (u_int64_t)freenum;
2432 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2433 txdr_hyper(uquad, tl);
2434 retnum += NFSX_HYPER;
2436 case NFSATTRBIT_RAWDEV:
2437 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2438 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2439 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2440 retnum += NFSX_V4SPECDATA;
2442 case NFSATTRBIT_SPACEAVAIL:
2443 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2444 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2445 uquad = (u_int64_t)fs.f_bfree;
2447 uquad = (u_int64_t)fs.f_bavail;
2448 uquad *= fs.f_bsize;
2449 txdr_hyper(uquad, tl);
2450 retnum += NFSX_HYPER;
2452 case NFSATTRBIT_SPACEFREE:
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2454 uquad = (u_int64_t)fs.f_bfree;
2455 uquad *= fs.f_bsize;
2456 txdr_hyper(uquad, tl);
2457 retnum += NFSX_HYPER;
2459 case NFSATTRBIT_SPACETOTAL:
2460 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2461 uquad = (u_int64_t)fs.f_blocks;
2462 uquad *= fs.f_bsize;
2463 txdr_hyper(uquad, tl);
2464 retnum += NFSX_HYPER;
2466 case NFSATTRBIT_SPACEUSED:
2467 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2468 txdr_hyper(vap->va_bytes, tl);
2469 retnum += NFSX_HYPER;
2471 case NFSATTRBIT_TIMEACCESS:
2472 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2473 txdr_nfsv4time(&vap->va_atime, tl);
2474 retnum += NFSX_V4TIME;
2476 case NFSATTRBIT_TIMEACCESSSET:
2477 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2478 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2479 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2480 txdr_nfsv4time(&vap->va_atime, tl);
2481 retnum += NFSX_V4SETTIME;
2483 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2484 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2485 retnum += NFSX_UNSIGNED;
2488 case NFSATTRBIT_TIMEDELTA:
2489 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2490 temptime.tv_sec = 0;
2491 temptime.tv_nsec = 1000000000 / hz;
2492 txdr_nfsv4time(&temptime, tl);
2493 retnum += NFSX_V4TIME;
2495 case NFSATTRBIT_TIMEMETADATA:
2496 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2497 txdr_nfsv4time(&vap->va_ctime, tl);
2498 retnum += NFSX_V4TIME;
2500 case NFSATTRBIT_TIMEMODIFY:
2501 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2502 txdr_nfsv4time(&vap->va_mtime, tl);
2503 retnum += NFSX_V4TIME;
2505 case NFSATTRBIT_TIMEMODIFYSET:
2506 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2507 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2508 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2509 txdr_nfsv4time(&vap->va_mtime, tl);
2510 retnum += NFSX_V4SETTIME;
2512 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2513 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2514 retnum += NFSX_UNSIGNED;
2517 case NFSATTRBIT_MOUNTEDONFILEID:
2518 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2520 uquad = mounted_on_fileno;
2522 uquad = (u_int64_t)vap->va_fileid;
2523 txdr_hyper(uquad, tl);
2524 retnum += NFSX_HYPER;
2526 case NFSATTRBIT_SUPPATTREXCLCREAT:
2527 NFSSETSUPP_ATTRBIT(&attrbits);
2528 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2529 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2530 retnum += nfsrv_putattrbit(nd, &attrbits);
2533 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2539 *retnump = txdr_unsigned(retnum);
2540 return (retnum + prefixnum);
2544 * Put the attribute bits onto an mbuf list.
2545 * Return the number of bytes of output generated.
2548 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2551 int cnt, i, bytesize;
2553 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2554 if (attrbitp->bits[cnt - 1])
2556 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2557 NFSM_BUILD(tl, u_int32_t *, bytesize);
2558 *tl++ = txdr_unsigned(cnt);
2559 for (i = 0; i < cnt; i++)
2560 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2565 * Convert a uid to a string.
2566 * If the lookup fails, just output the digits.
2568 * cpp - points to a buffer of size NFSV4_SMALLSTR
2569 * (malloc a larger one, as required)
2570 * retlenp - pointer to length to be returned
2573 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2576 struct nfsusrgrp *usrp;
2579 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2580 struct nfsrv_lughash *hp;
2584 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2586 * Always map nfsrv_defaultuid to "nobody".
2588 if (uid == nfsrv_defaultuid) {
2589 i = nfsrv_dnsnamelen + 7;
2591 if (len > NFSV4_SMALLSTR)
2592 free(cp, M_NFSSTRING);
2593 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2599 NFSBCOPY("nobody@", cp, 7);
2601 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2605 hp = NFSUSERHASH(uid);
2607 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2608 if (usrp->lug_uid == uid) {
2609 if (usrp->lug_expiry < NFSD_MONOSEC)
2612 * If the name doesn't already have an '@'
2613 * in it, append @domainname to it.
2615 for (i = 0; i < usrp->lug_namelen; i++) {
2616 if (usrp->lug_name[i] == '@') {
2622 i = usrp->lug_namelen;
2624 i = usrp->lug_namelen +
2625 nfsrv_dnsnamelen + 1;
2627 mtx_unlock(&hp->mtx);
2628 if (len > NFSV4_SMALLSTR)
2629 free(cp, M_NFSSTRING);
2630 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2636 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2637 if (!hasampersand) {
2638 cp += usrp->lug_namelen;
2640 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2642 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2643 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2645 mtx_unlock(&hp->mtx);
2649 mtx_unlock(&hp->mtx);
2651 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2653 if (ret == 0 && cnt < 2)
2658 * No match, just return a string of digits.
2662 while (tmp || i == 0) {
2666 len = (i > len) ? len : i;
2670 for (i = 0; i < len; i++) {
2671 *cp-- = '0' + (tmp % 10);
2678 * Get a credential for the uid with the server's group list.
2679 * If none is found, just return the credential passed in after
2680 * logging a warning message.
2683 nfsrv_getgrpscred(struct ucred *oldcred)
2685 struct nfsusrgrp *usrp;
2686 struct ucred *newcred;
2689 struct nfsrv_lughash *hp;
2692 uid = oldcred->cr_uid;
2694 if (nfsrv_dnsnamelen > 0) {
2695 hp = NFSUSERHASH(uid);
2697 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2698 if (usrp->lug_uid == uid) {
2699 if (usrp->lug_expiry < NFSD_MONOSEC)
2701 if (usrp->lug_cred != NULL) {
2702 newcred = crhold(usrp->lug_cred);
2706 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2707 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2709 mtx_unlock(&hp->mtx);
2713 mtx_unlock(&hp->mtx);
2715 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2717 if (ret == 0 && cnt < 2)
2724 * Convert a string to a uid.
2725 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2727 * If this is called from a client side mount using AUTH_SYS and the
2728 * string is made up entirely of digits, just convert the string to
2732 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2736 char *cp, *endstr, *str0;
2737 struct nfsusrgrp *usrp;
2741 struct nfsrv_lughash *hp, *hp2;
2744 error = NFSERR_BADOWNER;
2747 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2749 tuid = (uid_t)strtoul(str0, &endstr, 10);
2750 if ((endstr - str0) == len) {
2751 /* A numeric string. */
2752 if ((nd->nd_flag & ND_KERBV) == 0 &&
2753 ((nd->nd_flag & ND_NFSCL) != 0 ||
2754 nfsd_enable_stringtouid != 0))
2757 error = NFSERR_BADOWNER;
2763 cp = strchr(str0, '@');
2765 i = (int)(cp++ - str0);
2771 if (nfsrv_dnsnamelen > 0) {
2773 * If an '@' is found and the domain name matches, search for
2774 * the name with dns stripped off.
2775 * Mixed case alpahbetics will match for the domain name, but
2776 * all upper case will not.
2778 if (cnt == 0 && i < len && i > 0 &&
2779 (len - 1 - i) == nfsrv_dnsnamelen &&
2780 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2781 len -= (nfsrv_dnsnamelen + 1);
2786 * Check for the special case of "nobody".
2788 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2789 *uidp = nfsrv_defaultuid;
2794 hp = NFSUSERNAMEHASH(str, len);
2796 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2797 if (usrp->lug_namelen == len &&
2798 !NFSBCMP(usrp->lug_name, str, len)) {
2799 if (usrp->lug_expiry < NFSD_MONOSEC)
2801 hp2 = NFSUSERHASH(usrp->lug_uid);
2802 mtx_lock(&hp2->mtx);
2803 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2804 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2806 *uidp = usrp->lug_uid;
2807 mtx_unlock(&hp2->mtx);
2808 mtx_unlock(&hp->mtx);
2813 mtx_unlock(&hp->mtx);
2815 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2817 if (ret == 0 && cnt < 2)
2820 error = NFSERR_BADOWNER;
2828 * Convert a gid to a string.
2829 * gid - the group id
2830 * cpp - points to a buffer of size NFSV4_SMALLSTR
2831 * (malloc a larger one, as required)
2832 * retlenp - pointer to length to be returned
2835 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2838 struct nfsusrgrp *usrp;
2841 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2842 struct nfsrv_lughash *hp;
2846 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2848 * Always map nfsrv_defaultgid to "nogroup".
2850 if (gid == nfsrv_defaultgid) {
2851 i = nfsrv_dnsnamelen + 8;
2853 if (len > NFSV4_SMALLSTR)
2854 free(cp, M_NFSSTRING);
2855 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2861 NFSBCOPY("nogroup@", cp, 8);
2863 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2867 hp = NFSGROUPHASH(gid);
2869 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2870 if (usrp->lug_gid == gid) {
2871 if (usrp->lug_expiry < NFSD_MONOSEC)
2874 * If the name doesn't already have an '@'
2875 * in it, append @domainname to it.
2877 for (i = 0; i < usrp->lug_namelen; i++) {
2878 if (usrp->lug_name[i] == '@') {
2884 i = usrp->lug_namelen;
2886 i = usrp->lug_namelen +
2887 nfsrv_dnsnamelen + 1;
2889 mtx_unlock(&hp->mtx);
2890 if (len > NFSV4_SMALLSTR)
2891 free(cp, M_NFSSTRING);
2892 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2898 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2899 if (!hasampersand) {
2900 cp += usrp->lug_namelen;
2902 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2904 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2905 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2907 mtx_unlock(&hp->mtx);
2911 mtx_unlock(&hp->mtx);
2913 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2915 if (ret == 0 && cnt < 2)
2920 * No match, just return a string of digits.
2924 while (tmp || i == 0) {
2928 len = (i > len) ? len : i;
2932 for (i = 0; i < len; i++) {
2933 *cp-- = '0' + (tmp % 10);
2940 * Convert a string to a gid.
2941 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2943 * If this is called from a client side mount using AUTH_SYS and the
2944 * string is made up entirely of digits, just convert the string to
2948 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2952 char *cp, *endstr, *str0;
2953 struct nfsusrgrp *usrp;
2957 struct nfsrv_lughash *hp, *hp2;
2960 error = NFSERR_BADOWNER;
2963 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2965 tgid = (gid_t)strtoul(str0, &endstr, 10);
2966 if ((endstr - str0) == len) {
2967 /* A numeric string. */
2968 if ((nd->nd_flag & ND_KERBV) == 0 &&
2969 ((nd->nd_flag & ND_NFSCL) != 0 ||
2970 nfsd_enable_stringtouid != 0))
2973 error = NFSERR_BADOWNER;
2979 cp = strchr(str0, '@');
2981 i = (int)(cp++ - str0);
2987 if (nfsrv_dnsnamelen > 0) {
2989 * If an '@' is found and the dns name matches, search for the
2990 * name with the dns stripped off.
2992 if (cnt == 0 && i < len && i > 0 &&
2993 (len - 1 - i) == nfsrv_dnsnamelen &&
2994 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2995 len -= (nfsrv_dnsnamelen + 1);
3000 * Check for the special case of "nogroup".
3002 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3003 *gidp = nfsrv_defaultgid;
3008 hp = NFSGROUPNAMEHASH(str, len);
3010 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3011 if (usrp->lug_namelen == len &&
3012 !NFSBCMP(usrp->lug_name, str, len)) {
3013 if (usrp->lug_expiry < NFSD_MONOSEC)
3015 hp2 = NFSGROUPHASH(usrp->lug_gid);
3016 mtx_lock(&hp2->mtx);
3017 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3018 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3020 *gidp = usrp->lug_gid;
3021 mtx_unlock(&hp2->mtx);
3022 mtx_unlock(&hp->mtx);
3027 mtx_unlock(&hp->mtx);
3029 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3031 if (ret == 0 && cnt < 2)
3034 error = NFSERR_BADOWNER;
3042 * Cmp len chars, allowing mixed case in the first argument to match lower
3043 * case in the second, but not if the first argument is all upper case.
3044 * Return 0 for a match, 1 otherwise.
3047 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3053 for (i = 0; i < len; i++) {
3054 if (*cp >= 'A' && *cp <= 'Z') {
3055 tmp = *cp++ + ('a' - 'A');
3058 if (tmp >= 'a' && tmp <= 'z')
3071 * Set the port for the nfsuserd.
3074 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3076 struct nfssockreq *rp;
3077 struct sockaddr_in *ad;
3081 if (nfsrv_nfsuserd) {
3089 * Set up the socket record and connect.
3091 rp = &nfsrv_nfsuserdsock;
3092 rp->nr_client = NULL;
3093 rp->nr_sotype = SOCK_DGRAM;
3094 rp->nr_soproto = IPPROTO_UDP;
3095 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3097 NFSSOCKADDRALLOC(rp->nr_nam);
3098 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3099 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3100 ad->sin_family = AF_INET;
3101 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3102 ad->sin_port = port;
3103 rp->nr_prog = RPCPROG_NFSUSERD;
3104 rp->nr_vers = RPCNFSUSERD_VERS;
3105 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3107 NFSSOCKADDRFREE(rp->nr_nam);
3116 * Delete the nfsuserd port.
3119 nfsrv_nfsuserddelport(void)
3123 if (nfsrv_nfsuserd == 0) {
3129 newnfs_disconnect(&nfsrv_nfsuserdsock);
3130 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3134 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3136 * Returns 0 upon success, non-zero otherwise.
3139 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3142 struct nfsrv_descript *nd;
3144 struct nfsrv_descript nfsd;
3149 if (nfsrv_nfsuserd == 0) {
3156 cred = newnfs_getcred();
3157 nd->nd_flag = ND_GSSINITREPLY;
3160 nd->nd_procnum = procnum;
3161 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3163 if (procnum == RPCNFSUSERD_GETUID)
3164 *tl = txdr_unsigned(uid);
3166 *tl = txdr_unsigned(gid);
3169 (void) nfsm_strtom(nd, name, len);
3171 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3172 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3175 mbuf_freem(nd->nd_mrep);
3176 error = nd->nd_repstat;
3184 * This function is called from the nfssvc(2) system call, to update the
3185 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3188 nfssvc_idname(struct nfsd_idargs *nidp)
3190 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3191 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3192 int i, group_locked, groupname_locked, user_locked, username_locked;
3197 static int onethread = 0;
3198 static time_t lasttime = 0;
3200 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3204 if (nidp->nid_flag & NFSID_INITIALIZE) {
3205 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3206 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3209 free(cp, M_NFSSTRING);
3212 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3214 * Free up all the old stuff and reinitialize hash
3215 * lists. All mutexes for both lists must be locked,
3216 * with the user/group name ones before the uid/gid
3217 * ones, to avoid a LOR.
3219 for (i = 0; i < nfsrv_lughashsize; i++)
3220 mtx_lock(&nfsusernamehash[i].mtx);
3221 for (i = 0; i < nfsrv_lughashsize; i++)
3222 mtx_lock(&nfsuserhash[i].mtx);
3223 for (i = 0; i < nfsrv_lughashsize; i++)
3224 TAILQ_FOREACH_SAFE(usrp,
3225 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3226 nfsrv_removeuser(usrp, 1);
3227 for (i = 0; i < nfsrv_lughashsize; i++)
3228 mtx_unlock(&nfsuserhash[i].mtx);
3229 for (i = 0; i < nfsrv_lughashsize; i++)
3230 mtx_unlock(&nfsusernamehash[i].mtx);
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 mtx_lock(&nfsgroupnamehash[i].mtx);
3233 for (i = 0; i < nfsrv_lughashsize; i++)
3234 mtx_lock(&nfsgrouphash[i].mtx);
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 TAILQ_FOREACH_SAFE(usrp,
3237 &nfsgrouphash[i].lughead, lug_numhash,
3239 nfsrv_removeuser(usrp, 0);
3240 for (i = 0; i < nfsrv_lughashsize; i++)
3241 mtx_unlock(&nfsgrouphash[i].mtx);
3242 for (i = 0; i < nfsrv_lughashsize; i++)
3243 mtx_unlock(&nfsgroupnamehash[i].mtx);
3244 free(nfsrv_dnsname, M_NFSSTRING);
3245 nfsrv_dnsname = NULL;
3247 if (nfsuserhash == NULL) {
3248 /* Allocate the hash tables. */
3249 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3250 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3252 for (i = 0; i < nfsrv_lughashsize; i++)
3253 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3254 NULL, MTX_DEF | MTX_DUPOK);
3255 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3256 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3258 for (i = 0; i < nfsrv_lughashsize; i++)
3259 mtx_init(&nfsusernamehash[i].mtx,
3260 "nfsusrhash", NULL, MTX_DEF |
3262 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3263 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3265 for (i = 0; i < nfsrv_lughashsize; i++)
3266 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3267 NULL, MTX_DEF | MTX_DUPOK);
3268 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3269 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3271 for (i = 0; i < nfsrv_lughashsize; i++)
3272 mtx_init(&nfsgroupnamehash[i].mtx,
3273 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3275 /* (Re)initialize the list heads. */
3276 for (i = 0; i < nfsrv_lughashsize; i++)
3277 TAILQ_INIT(&nfsuserhash[i].lughead);
3278 for (i = 0; i < nfsrv_lughashsize; i++)
3279 TAILQ_INIT(&nfsusernamehash[i].lughead);
3280 for (i = 0; i < nfsrv_lughashsize; i++)
3281 TAILQ_INIT(&nfsgrouphash[i].lughead);
3282 for (i = 0; i < nfsrv_lughashsize; i++)
3283 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3286 * Put name in "DNS" string.
3289 nfsrv_defaultuid = nidp->nid_uid;
3290 nfsrv_defaultgid = nidp->nid_gid;
3292 nfsrv_usermax = nidp->nid_usermax;
3293 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3298 * malloc the new one now, so any potential sleep occurs before
3299 * manipulation of the lists.
3301 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3302 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3303 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3305 if (error == 0 && nidp->nid_ngroup > 0 &&
3306 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3307 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3309 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3310 sizeof(gid_t) * nidp->nid_ngroup);
3313 * Create a credential just like svc_getcred(),
3314 * but using the group list provided.
3317 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3318 crsetgroups(cr, nidp->nid_ngroup, grps);
3319 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3320 cr->cr_prison = &prison0;
3321 prison_hold(cr->cr_prison);
3323 mac_cred_associate_nfsd(cr);
3325 newusrp->lug_cred = cr;
3330 free(newusrp, M_NFSUSERGROUP);
3333 newusrp->lug_namelen = nidp->nid_namelen;
3336 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3337 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3338 * The flags user_locked, username_locked, group_locked and
3339 * groupname_locked are set to indicate all of those hash lists are
3340 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3341 * the respective one mutex is locked.
3343 user_locked = username_locked = group_locked = groupname_locked = 0;
3344 hp_name = hp_idnum = NULL;
3347 * Delete old entries, as required.
3349 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3350 /* Must lock all username hash lists first, to avoid a LOR. */
3351 for (i = 0; i < nfsrv_lughashsize; i++)
3352 mtx_lock(&nfsusernamehash[i].mtx);
3353 username_locked = 1;
3354 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3355 mtx_lock(&hp_idnum->mtx);
3356 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3358 if (usrp->lug_uid == nidp->nid_uid)
3359 nfsrv_removeuser(usrp, 1);
3361 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3362 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3363 newusrp->lug_namelen);
3364 mtx_lock(&hp_name->mtx);
3365 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3367 if (usrp->lug_namelen == newusrp->lug_namelen &&
3368 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3369 usrp->lug_namelen)) {
3370 thp = NFSUSERHASH(usrp->lug_uid);
3371 mtx_lock(&thp->mtx);
3372 nfsrv_removeuser(usrp, 1);
3373 mtx_unlock(&thp->mtx);
3376 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3377 mtx_lock(&hp_idnum->mtx);
3378 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3379 /* Must lock all groupname hash lists first, to avoid a LOR. */
3380 for (i = 0; i < nfsrv_lughashsize; i++)
3381 mtx_lock(&nfsgroupnamehash[i].mtx);
3382 groupname_locked = 1;
3383 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3384 mtx_lock(&hp_idnum->mtx);
3385 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3387 if (usrp->lug_gid == nidp->nid_gid)
3388 nfsrv_removeuser(usrp, 0);
3390 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3391 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3392 newusrp->lug_namelen);
3393 mtx_lock(&hp_name->mtx);
3394 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3396 if (usrp->lug_namelen == newusrp->lug_namelen &&
3397 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3398 usrp->lug_namelen)) {
3399 thp = NFSGROUPHASH(usrp->lug_gid);
3400 mtx_lock(&thp->mtx);
3401 nfsrv_removeuser(usrp, 0);
3402 mtx_unlock(&thp->mtx);
3405 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3406 mtx_lock(&hp_idnum->mtx);
3410 * Now, we can add the new one.
3412 if (nidp->nid_usertimeout)
3413 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3415 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3416 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3417 newusrp->lug_uid = nidp->nid_uid;
3418 thp = NFSUSERHASH(newusrp->lug_uid);
3419 mtx_assert(&thp->mtx, MA_OWNED);
3420 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3421 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3422 mtx_assert(&thp->mtx, MA_OWNED);
3423 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3424 atomic_add_int(&nfsrv_usercnt, 1);
3425 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3426 newusrp->lug_gid = nidp->nid_gid;
3427 thp = NFSGROUPHASH(newusrp->lug_gid);
3428 mtx_assert(&thp->mtx, MA_OWNED);
3429 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3430 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3431 mtx_assert(&thp->mtx, MA_OWNED);
3432 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3433 atomic_add_int(&nfsrv_usercnt, 1);
3435 if (newusrp->lug_cred != NULL)
3436 crfree(newusrp->lug_cred);
3437 free(newusrp, M_NFSUSERGROUP);
3441 * Once per second, allow one thread to trim the cache.
3443 if (lasttime < NFSD_MONOSEC &&
3444 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3446 * First, unlock the single mutexes, so that all entries
3447 * can be locked and any LOR is avoided.
3449 if (hp_name != NULL) {
3450 mtx_unlock(&hp_name->mtx);
3453 if (hp_idnum != NULL) {
3454 mtx_unlock(&hp_idnum->mtx);
3458 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3459 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3460 if (username_locked == 0) {
3461 for (i = 0; i < nfsrv_lughashsize; i++)
3462 mtx_lock(&nfsusernamehash[i].mtx);
3463 username_locked = 1;
3465 KASSERT(user_locked == 0,
3466 ("nfssvc_idname: user_locked"));
3467 for (i = 0; i < nfsrv_lughashsize; i++)
3468 mtx_lock(&nfsuserhash[i].mtx);
3470 for (i = 0; i < nfsrv_lughashsize; i++) {
3471 TAILQ_FOREACH_SAFE(usrp,
3472 &nfsuserhash[i].lughead, lug_numhash,
3474 if (usrp->lug_expiry < NFSD_MONOSEC)
3475 nfsrv_removeuser(usrp, 1);
3477 for (i = 0; i < nfsrv_lughashsize; i++) {
3479 * Trim the cache using an approximate LRU
3480 * algorithm. This code deletes the least
3481 * recently used entry on each hash list.
3483 if (nfsrv_usercnt <= nfsrv_usermax)
3485 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3487 nfsrv_removeuser(usrp, 1);
3490 if (groupname_locked == 0) {
3491 for (i = 0; i < nfsrv_lughashsize; i++)
3492 mtx_lock(&nfsgroupnamehash[i].mtx);
3493 groupname_locked = 1;
3495 KASSERT(group_locked == 0,
3496 ("nfssvc_idname: group_locked"));
3497 for (i = 0; i < nfsrv_lughashsize; i++)
3498 mtx_lock(&nfsgrouphash[i].mtx);
3500 for (i = 0; i < nfsrv_lughashsize; i++) {
3501 TAILQ_FOREACH_SAFE(usrp,
3502 &nfsgrouphash[i].lughead, lug_numhash,
3504 if (usrp->lug_expiry < NFSD_MONOSEC)
3505 nfsrv_removeuser(usrp, 0);
3507 for (i = 0; i < nfsrv_lughashsize; i++) {
3509 * Trim the cache using an approximate LRU
3510 * algorithm. This code deletes the least
3511 * recently user entry on each hash list.
3513 if (nfsrv_usercnt <= nfsrv_usermax)
3515 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3517 nfsrv_removeuser(usrp, 0);
3520 lasttime = NFSD_MONOSEC;
3521 atomic_store_rel_int(&onethread, 0);
3524 /* Now, unlock all locked mutexes. */
3525 if (hp_idnum != NULL)
3526 mtx_unlock(&hp_idnum->mtx);
3527 if (hp_name != NULL)
3528 mtx_unlock(&hp_name->mtx);
3529 if (user_locked != 0)
3530 for (i = 0; i < nfsrv_lughashsize; i++)
3531 mtx_unlock(&nfsuserhash[i].mtx);
3532 if (username_locked != 0)
3533 for (i = 0; i < nfsrv_lughashsize; i++)
3534 mtx_unlock(&nfsusernamehash[i].mtx);
3535 if (group_locked != 0)
3536 for (i = 0; i < nfsrv_lughashsize; i++)
3537 mtx_unlock(&nfsgrouphash[i].mtx);
3538 if (groupname_locked != 0)
3539 for (i = 0; i < nfsrv_lughashsize; i++)
3540 mtx_unlock(&nfsgroupnamehash[i].mtx);
3547 * Remove a user/group name element.
3550 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3552 struct nfsrv_lughash *hp;
3555 hp = NFSUSERHASH(usrp->lug_uid);
3556 mtx_assert(&hp->mtx, MA_OWNED);
3557 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3558 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3559 mtx_assert(&hp->mtx, MA_OWNED);
3560 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3562 hp = NFSGROUPHASH(usrp->lug_gid);
3563 mtx_assert(&hp->mtx, MA_OWNED);
3564 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3565 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3566 mtx_assert(&hp->mtx, MA_OWNED);
3567 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3569 atomic_add_int(&nfsrv_usercnt, -1);
3570 if (usrp->lug_cred != NULL)
3571 crfree(usrp->lug_cred);
3572 free(usrp, M_NFSUSERGROUP);
3576 * Free up all the allocations related to the name<-->id cache.
3577 * This function should only be called when the nfsuserd daemon isn't
3578 * running, since it doesn't do any locking.
3579 * This function is meant to be used when the nfscommon module is unloaded.
3582 nfsrv_cleanusergroup(void)
3584 struct nfsrv_lughash *hp, *hp2;
3585 struct nfsusrgrp *nusrp, *usrp;
3588 if (nfsuserhash == NULL)
3591 for (i = 0; i < nfsrv_lughashsize; i++) {
3592 hp = &nfsuserhash[i];
3593 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3594 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3595 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3597 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3598 if (usrp->lug_cred != NULL)
3599 crfree(usrp->lug_cred);
3600 free(usrp, M_NFSUSERGROUP);
3602 hp = &nfsgrouphash[i];
3603 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3604 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3605 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3607 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3608 if (usrp->lug_cred != NULL)
3609 crfree(usrp->lug_cred);
3610 free(usrp, M_NFSUSERGROUP);
3612 mtx_destroy(&nfsuserhash[i].mtx);
3613 mtx_destroy(&nfsusernamehash[i].mtx);
3614 mtx_destroy(&nfsgroupnamehash[i].mtx);
3615 mtx_destroy(&nfsgrouphash[i].mtx);
3617 free(nfsuserhash, M_NFSUSERGROUP);
3618 free(nfsusernamehash, M_NFSUSERGROUP);
3619 free(nfsgrouphash, M_NFSUSERGROUP);
3620 free(nfsgroupnamehash, M_NFSUSERGROUP);
3621 free(nfsrv_dnsname, M_NFSSTRING);
3625 * This function scans a byte string and checks for UTF-8 compliance.
3626 * It returns 0 if it conforms and NFSERR_INVAL if not.
3629 nfsrv_checkutf8(u_int8_t *cp, int len)
3631 u_int32_t val = 0x0;
3632 int cnt = 0, gotd = 0, shift = 0;
3634 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3638 * Here are what the variables are used for:
3639 * val - the calculated value of a multibyte char, used to check
3640 * that it was coded with the correct range
3641 * cnt - the number of 10xxxxxx bytes to follow
3642 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3643 * shift - lower order bits of range (ie. "val >> shift" should
3644 * not be 0, in other words, dividing by the lower bound
3645 * of the range should get a non-zero value)
3646 * byte - used to calculate cnt
3650 /* This handles the 10xxxxxx bytes */
3651 if ((*cp & 0xc0) != 0x80 ||
3652 (gotd && (*cp & 0x20))) {
3653 error = NFSERR_INVAL;
3658 val |= (*cp & 0x3f);
3660 if (cnt == 0 && (val >> shift) == 0x0) {
3661 error = NFSERR_INVAL;
3664 } else if (*cp & 0x80) {
3665 /* first byte of multi byte char */
3667 while ((byte & 0x40) && cnt < 6) {
3671 if (cnt == 0 || cnt == 6) {
3672 error = NFSERR_INVAL;
3675 val = (*cp & (0x3f >> cnt));
3676 shift = utf8_shift[cnt - 1];
3677 if (cnt == 2 && val == 0xd)
3678 /* Check for the 0xd800-0xdfff case */
3685 error = NFSERR_INVAL;
3693 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3694 * strings, one with the root path in it and the other with the list of
3695 * locations. The list is in the same format as is found in nfr_refs.
3696 * It is a "," separated list of entries, where each of them is of the
3697 * form <server>:<rootpath>. For example
3698 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3699 * The nilp argument is set to 1 for the special case of a null fs_root
3700 * and an empty server list.
3701 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3702 * number of xdr bytes parsed in sump.
3705 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3706 int *sump, int *nilp)
3709 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3710 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3712 SLIST_ENTRY(list) next;
3716 SLIST_HEAD(, list) head;
3723 * Get the fs_root path and check for the special case of null path
3724 * and 0 length server list.
3726 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3727 len = fxdr_unsigned(int, *tl);
3728 if (len < 0 || len > 10240) {
3729 error = NFSERR_BADXDR;
3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3735 error = NFSERR_BADXDR;
3739 *sump = 2 * NFSX_UNSIGNED;
3743 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3744 error = nfsrv_mtostr(nd, cp, len);
3746 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3747 cnt = fxdr_unsigned(int, *tl);
3749 error = NFSERR_BADXDR;
3755 * Now, loop through the location list and make up the srvlist.
3757 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3758 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3761 for (i = 0; i < cnt; i++) {
3763 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3764 nsrv = fxdr_unsigned(int, *tl);
3766 error = NFSERR_BADXDR;
3771 * Handle the first server by putting it in the srvstr.
3773 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3774 len = fxdr_unsigned(int, *tl);
3775 if (len <= 0 || len > 1024) {
3776 error = NFSERR_BADXDR;
3779 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3784 error = nfsrv_mtostr(nd, cp3, len);
3790 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3791 for (j = 1; j < nsrv; j++) {
3793 * Yuck, put them in an slist and process them later.
3795 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3796 len = fxdr_unsigned(int, *tl);
3797 if (len <= 0 || len > 1024) {
3798 error = NFSERR_BADXDR;
3801 lsp = (struct list *)malloc(sizeof (struct list)
3802 + len, M_TEMP, M_WAITOK);
3803 error = nfsrv_mtostr(nd, lsp->host, len);
3806 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3808 SLIST_INSERT_HEAD(&head, lsp, next);
3812 * Finally, we can get the path.
3814 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3815 len = fxdr_unsigned(int, *tl);
3816 if (len <= 0 || len > 1024) {
3817 error = NFSERR_BADXDR;
3820 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3821 error = nfsrv_mtostr(nd, cp3, len);
3824 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3829 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3830 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3833 NFSBCOPY(lsp->host, cp3, lsp->len);
3836 NFSBCOPY(str, cp3, stringlen);
3839 siz += (lsp->len + stringlen + 2);
3840 free((caddr_t)lsp, M_TEMP);
3846 NFSEXITCODE2(0, nd);
3850 free(cp, M_NFSSTRING);
3852 free(cp2, M_NFSSTRING);
3853 NFSEXITCODE2(error, nd);
3858 * Make the malloc'd space large enough. This is a pain, but the xdr
3859 * doesn't set an upper bound on the side, so...
3862 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3869 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3870 NFSBCOPY(*cpp, cp, *slenp);
3871 free(*cpp, M_NFSSTRING);
3875 *slenp = siz + 1024;
3879 * Initialize the reply header data structures.
3882 nfsrvd_rephead(struct nfsrv_descript *nd)
3887 * If this is a big reply, use a cluster.
3889 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3890 nfs_bigreply[nd->nd_procnum]) {
3891 NFSMCLGET(mreq, M_WAITOK);
3899 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3900 mbuf_setlen(mreq, 0);
3902 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3903 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3907 * Lock a socket against others.
3908 * Currently used to serialize connect/disconnect attempts.
3911 newnfs_sndlock(int *flagp)
3916 while (*flagp & NFSR_SNDLOCK) {
3917 *flagp |= NFSR_WANTSND;
3920 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3921 PZERO - 1, "nfsndlck", &ts);
3923 *flagp |= NFSR_SNDLOCK;
3929 * Unlock the stream socket for others.
3932 newnfs_sndunlock(int *flagp)
3936 if ((*flagp & NFSR_SNDLOCK) == 0)
3937 panic("nfs sndunlock");
3938 *flagp &= ~NFSR_SNDLOCK;
3939 if (*flagp & NFSR_WANTSND) {
3940 *flagp &= ~NFSR_WANTSND;
3941 wakeup((caddr_t)flagp);
3947 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3950 struct sockaddr_in *sad;
3951 struct sockaddr_in6 *sad6;
3952 struct in_addr saddr;
3953 uint32_t portnum, *tl;
3954 int af = 0, i, j, k;
3955 char addr[64], protocol[5], *cp;
3956 int cantparse = 0, error = 0;
3959 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3960 i = fxdr_unsigned(int, *tl);
3961 if (i >= 3 && i <= 4) {
3962 error = nfsrv_mtostr(nd, protocol, i);
3965 if (strcmp(protocol, "tcp") == 0) {
3968 } else if (strcmp(protocol, "udp") == 0) {
3971 } else if (strcmp(protocol, "tcp6") == 0) {
3974 } else if (strcmp(protocol, "udp6") == 0) {
3982 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3987 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3988 i = fxdr_unsigned(int, *tl);
3990 error = NFSERR_BADXDR;
3992 } else if (cantparse == 0 && i >= 11 && i < 64) {
3994 * The shortest address is 11chars and the longest is < 64.
3996 error = nfsrv_mtostr(nd, addr, i);
4000 /* Find the port# at the end and extract that. */
4004 /* Count back two '.'s from end to get port# field. */
4005 for (j = 0; j < i; j++) {
4015 * The NFSv4 port# is appended as .N.N, where N is
4016 * a decimal # in the range 0-255, just like an inet4
4017 * address. Cheat and use inet_aton(), which will
4018 * return a Class A address and then shift the high
4019 * order 8bits over to convert it to the port#.
4022 if (inet_aton(cp, &saddr) == 1) {
4023 portnum = ntohl(saddr.s_addr);
4024 portv = (uint16_t)((portnum >> 16) |
4030 if (cantparse == 0) {
4031 if (af == AF_INET) {
4032 sad = (struct sockaddr_in *)sa;
4033 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4034 sad->sin_len = sizeof(*sad);
4035 sad->sin_family = AF_INET;
4036 sad->sin_port = htons(portv);
4040 sad6 = (struct sockaddr_in6 *)sa;
4041 if (inet_pton(af, addr, &sad6->sin6_addr)
4043 sad6->sin6_len = sizeof(*sad6);
4044 sad6->sin6_family = AF_INET6;
4045 sad6->sin6_port = htons(portv);
4052 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4063 * Handle an NFSv4.1 Sequence request for the session.
4064 * If reply != NULL, use it to return the cached reply, as required.
4065 * The client gets a cached reply via this call for callbacks, however the
4066 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4069 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4070 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4077 if (slotid > maxslot)
4078 return (NFSERR_BADSLOT);
4079 if (seqid == slots[slotid].nfssl_seq) {
4081 if (slots[slotid].nfssl_inprog != 0)
4082 error = NFSERR_DELAY;
4083 else if (slots[slotid].nfssl_reply != NULL) {
4084 if (reply != NULL) {
4085 *reply = slots[slotid].nfssl_reply;
4086 slots[slotid].nfssl_reply = NULL;
4088 slots[slotid].nfssl_inprog = 1;
4089 error = NFSERR_REPLYFROMCACHE;
4091 /* No reply cached, so just do it. */
4092 slots[slotid].nfssl_inprog = 1;
4093 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4094 if (slots[slotid].nfssl_reply != NULL)
4095 m_freem(slots[slotid].nfssl_reply);
4096 slots[slotid].nfssl_reply = NULL;
4097 slots[slotid].nfssl_inprog = 1;
4098 slots[slotid].nfssl_seq++;
4100 error = NFSERR_SEQMISORDERED;
4105 * Cache this reply for the slot.
4106 * Use the "rep" argument to return the cached reply if repstat is set to
4107 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4110 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4114 if (repstat == NFSERR_REPLYFROMCACHE) {
4115 *rep = slots[slotid].nfssl_reply;
4116 slots[slotid].nfssl_reply = NULL;
4118 if (slots[slotid].nfssl_reply != NULL)
4119 m_freem(slots[slotid].nfssl_reply);
4120 slots[slotid].nfssl_reply = *rep;
4122 slots[slotid].nfssl_inprog = 0;
4126 * Generate the xdr for an NFSv4.1 Sequence Operation.
4129 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4130 struct nfsclsession *sep, int dont_replycache)
4132 uint32_t *tl, slotseq = 0;
4133 int error, maxslot, slotpos;
4134 uint8_t sessionid[NFSX_V4SESSIONID];
4136 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4139 /* Build the Sequence arguments. */
4140 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4141 nd->nd_sequence = tl;
4142 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4143 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4144 nd->nd_slotseq = tl;
4146 *tl++ = txdr_unsigned(slotseq);
4147 *tl++ = txdr_unsigned(slotpos);
4148 *tl++ = txdr_unsigned(maxslot);
4149 if (dont_replycache == 0)
4155 * There are two errors and the rest of the session can
4157 * NFSERR_BADSESSION: This bad session should just generate
4158 * the same error again when the RPC is retried.
4159 * ESTALE: A forced dismount is in progress and will cause the
4160 * RPC to fail later.
4167 nd->nd_flag |= ND_HASSEQUENCE;
4171 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4172 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4174 int i, maxslot, slotpos;
4177 /* Find an unused slot. */
4180 mtx_lock(&sep->nfsess_mtx);
4182 if (nmp != NULL && sep->nfsess_defunct != 0) {
4183 /* Just return the bad session. */
4184 bcopy(sep->nfsess_sessionid, sessionid,
4186 mtx_unlock(&sep->nfsess_mtx);
4187 return (NFSERR_BADSESSION);
4190 for (i = 0; i < sep->nfsess_foreslots; i++) {
4191 if ((bitval & sep->nfsess_slots) == 0) {
4193 sep->nfsess_slots |= bitval;
4194 sep->nfsess_slotseq[i]++;
4195 *slotseqp = sep->nfsess_slotseq[i];
4200 if (slotpos == -1) {
4202 * If a forced dismount is in progress, just return.
4203 * This RPC attempt will fail when it calls
4207 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4209 mtx_unlock(&sep->nfsess_mtx);
4212 /* Wake up once/sec, to check for a forced dismount. */
4213 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4214 PZERO, "nfsclseq", hz);
4216 } while (slotpos == -1);
4217 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4219 for (i = 0; i < 64; i++) {
4220 if ((bitval & sep->nfsess_slots) != 0)
4224 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4225 mtx_unlock(&sep->nfsess_mtx);
4226 *slotposp = slotpos;
4227 *maxslotp = maxslot;
4232 * Free a session slot.
4235 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4242 mtx_lock(&sep->nfsess_mtx);
4243 if ((bitval & sep->nfsess_slots) == 0)
4244 printf("freeing free slot!!\n");
4245 sep->nfsess_slots &= ~bitval;
4246 wakeup(&sep->nfsess_slots);
4247 mtx_unlock(&sep->nfsess_mtx);