2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid;
67 gid_t nfsrv_defaultgid;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 int nfsd_enable_stringtouid = 0;
73 extern int nfsrv_lughashsize;
76 * This array of structures indicates, for V4:
77 * retfh - which of 3 types of calling args are used
78 * 0 - doesn't change cfh or use a sfh
79 * 1 - replaces cfh with a new one (unless it returns an error status)
80 * 2 - uses cfh and sfh
81 * needscfh - if the op wants a cfh and premtime
82 * 0 - doesn't use a cfh
83 * 1 - uses a cfh, but doesn't want pre-op attributes
84 * 2 - uses a cfh and wants pre-op attributes
85 * savereply - indicates a non-idempotent Op
86 * 0 - not non-idempotent
88 * Ops that are ordered via seqid# are handled separately from these
90 * Define it here, since it is used by both the client and server.
92 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
93 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
94 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
95 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
96 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
97 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
98 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
99 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
102 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
104 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
106 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
108 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
109 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
111 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
112 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
116 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
117 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
118 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
119 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
120 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
121 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
122 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
123 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
124 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
125 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
126 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
128 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
130 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
131 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
143 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
144 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
150 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
153 #endif /* !APPLEKEXT */
155 static int ncl_mbuf_mhlen = MHLEN;
156 static int nfsrv_usercnt = 0;
157 static int nfsrv_dnsnamelen;
158 static u_char *nfsrv_dnsname = NULL;
159 static int nfsrv_usermax = 999999999;
160 struct nfsrv_lughash {
162 struct nfsuserhashhead lughead;
164 static struct nfsrv_lughash *nfsuserhash;
165 static struct nfsrv_lughash *nfsusernamehash;
166 static struct nfsrv_lughash *nfsgrouphash;
167 static struct nfsrv_lughash *nfsgroupnamehash;
170 * This static array indicates whether or not the RPC generates a large
171 * reply. This is used by nfs_reply() to decide whether or not an mbuf
172 * cluster should be allocated. (If a cluster is required by an RPC
173 * marked 0 in this array, the code will still work, just not quite as
176 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
180 /* local functions */
181 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
182 static void nfsv4_wanted(struct nfsv4lock *lp);
183 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
184 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
186 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
187 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
189 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
194 * copies mbuf chain to the uio scatter/gather list
197 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
199 char *mbufcp, *uiocp;
206 mbufcp = nd->nd_dpos;
207 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
208 rem = NFSM_RNDUP(siz) - siz;
210 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
214 left = uiop->uio_iov->iov_len;
215 uiocp = uiop->uio_iov->iov_base;
226 mbufcp = NFSMTOD(mp, caddr_t);
229 ("len %d, corrupted mbuf?", len));
231 xfer = (left > len) ? len : left;
234 if (uiop->uio_iov->iov_op != NULL)
235 (*(uiop->uio_iov->iov_op))
236 (mbufcp, uiocp, xfer);
239 if (uiop->uio_segflg == UIO_SYSSPACE)
240 NFSBCOPY(mbufcp, uiocp, xfer);
242 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
247 uiop->uio_offset += xfer;
248 uiop->uio_resid -= xfer;
250 if (uiop->uio_iov->iov_len <= siz) {
254 uiop->uio_iov->iov_base = (void *)
255 ((char *)uiop->uio_iov->iov_base + uiosiz);
256 uiop->uio_iov->iov_len -= uiosiz;
260 nd->nd_dpos = mbufcp;
264 error = nfsm_advance(nd, rem, len);
270 NFSEXITCODE2(error, nd);
276 * Help break down an mbuf chain by setting the first siz bytes contiguous
277 * pointed to by returned val.
278 * This is used by the macro NFSM_DISSECT for tough
282 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
291 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
293 nd->nd_md = mbuf_next(nd->nd_md);
294 if (nd->nd_md == NULL)
296 left = mbuf_len(nd->nd_md);
297 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
302 } else if (mbuf_next(nd->nd_md) == NULL) {
304 } else if (siz > ncl_mbuf_mhlen) {
305 panic("nfs S too big");
307 MGET(mp2, MT_DATA, how);
310 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
311 mbuf_setnext(nd->nd_md, mp2);
312 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
314 retp = p = NFSMTOD(mp2, caddr_t);
315 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
318 mp2 = mbuf_next(mp2);
319 /* Loop around copying up the siz2 bytes */
323 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
325 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
326 NFSM_DATAP(mp2, xfer);
327 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
332 mp2 = mbuf_next(mp2);
334 mbuf_setlen(nd->nd_md, siz);
336 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
342 * Advance the position in the mbuf chain.
343 * If offs == 0, this is a no-op, but it is simpler to just return from
344 * here than check for offs > 0 for all calls to nfsm_advance.
345 * If left == -1, it should be calculated here.
348 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
355 * A negative offs should be considered a serious problem.
358 panic("nfsrv_advance");
361 * If left == -1, calculate it here.
364 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
368 * Loop around, advancing over the mbuf data.
370 while (offs > left) {
372 nd->nd_md = mbuf_next(nd->nd_md);
373 if (nd->nd_md == NULL) {
377 left = mbuf_len(nd->nd_md);
378 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
388 * Copy a string into mbuf(s).
389 * Return the number of bytes output, including XDR overheads.
392 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
402 *tl = txdr_unsigned(siz);
403 rem = NFSM_RNDUP(siz) - siz;
404 bytesize = NFSX_UNSIGNED + siz + rem;
407 left = M_TRAILINGSPACE(m2);
410 * Loop around copying the string to mbuf(s).
414 if (siz > ncl_mbuf_mlen)
415 NFSMCLGET(m1, M_WAITOK);
419 mbuf_setnext(m2, m1);
421 cp2 = NFSMTOD(m2, caddr_t);
422 left = M_TRAILINGSPACE(m2);
428 NFSBCOPY(cp, cp2, xfer);
430 mbuf_setlen(m2, mbuf_len(m2) + xfer);
433 if (siz == 0 && rem) {
435 panic("nfsm_strtom");
436 NFSBZERO(cp2 + xfer, rem);
437 mbuf_setlen(m2, mbuf_len(m2) + rem);
441 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
446 * Called once to initialize data structures...
451 static int nfs_inited = 0;
457 newnfs_true = txdr_unsigned(TRUE);
458 newnfs_false = txdr_unsigned(FALSE);
459 newnfs_xdrneg1 = txdr_unsigned(-1);
460 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
463 NFSSETBOOTTIME(nfsboottime);
466 * Initialize reply list and start timer
468 TAILQ_INIT(&nfsd_reqq);
473 * Put a file handle in an mbuf list.
474 * If the size argument == 0, just use the default size.
475 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
476 * Return the number of bytes output, including XDR overhead.
479 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
483 int fullsiz, rem, bytesize = 0;
487 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
489 if (size > NFSX_V2FH)
490 panic("fh size > NFSX_V2FH for NFSv2");
491 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
492 NFSBCOPY(fhp, cp, size);
493 if (size < NFSX_V2FH)
494 NFSBZERO(cp + size, NFSX_V2FH - size);
495 bytesize = NFSX_V2FH;
499 fullsiz = NFSM_RNDUP(size);
500 rem = fullsiz - size;
502 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
503 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
506 bytesize = NFSX_UNSIGNED + fullsiz;
508 (void) nfsm_strtom(nd, fhp, size);
515 * This function compares two net addresses by family and returns TRUE
516 * if they are the same host.
517 * If there is any doubt, return FALSE.
518 * The AF_INET family is handled as a special case so that address mbufs
519 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
522 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
524 struct sockaddr_in *inetaddr;
528 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
529 if (inetaddr->sin_family == AF_INET &&
530 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
536 struct sockaddr_in6 *inetaddr6;
538 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
539 /* XXX - should test sin6_scope_id ? */
540 if (inetaddr6->sin6_family == AF_INET6 &&
541 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
552 * Similar to the above, but takes to NFSSOCKADDR_T args.
555 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
557 struct sockaddr_in *addr1, *addr2;
558 struct sockaddr *inaddr;
560 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
561 switch (inaddr->sa_family) {
563 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
564 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
565 if (addr2->sin_family == AF_INET &&
566 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
572 struct sockaddr_in6 *inet6addr1, *inet6addr2;
574 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
575 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
576 /* XXX - should test sin6_scope_id ? */
577 if (inet6addr2->sin6_family == AF_INET6 &&
578 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
579 &inet6addr2->sin6_addr))
590 * Trim the stuff already dissected off the mbuf list.
593 newnfs_trimleading(nd)
594 struct nfsrv_descript *nd;
600 * First, free up leading mbufs.
602 if (nd->nd_mrep != nd->nd_md) {
604 while (mbuf_next(m) != nd->nd_md) {
605 if (mbuf_next(m) == NULL)
606 panic("nfsm trim leading");
609 mbuf_setnext(m, NULL);
610 mbuf_freem(nd->nd_mrep);
615 * Now, adjust this mbuf, based on nd_dpos.
617 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
618 if (offs == mbuf_len(m)) {
622 panic("nfsm trim leading2");
623 mbuf_setnext(n, NULL);
625 } else if (offs > 0) {
626 mbuf_setlen(m, mbuf_len(m) - offs);
629 panic("nfsm trimleading offs");
632 nd->nd_dpos = NFSMTOD(m, caddr_t);
636 * Trim trailing data off the mbuf list being built.
639 newnfs_trimtrailing(nd, mb, bpos)
640 struct nfsrv_descript *nd;
646 mbuf_freem(mbuf_next(mb));
647 mbuf_setnext(mb, NULL);
649 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
655 * Dissect a file handle on the client.
658 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
665 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
667 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
674 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
676 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
678 FREE((caddr_t)nfhp, M_NFSFH);
684 NFSEXITCODE2(error, nd);
689 * Break down the nfsv4 acl.
690 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
693 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
694 int *aclsizep, __unused NFSPROC_T *p)
698 int acecnt, error = 0, aceerr = 0, acesize;
704 * Parse out the ace entries and expect them to conform to
705 * what can be supported by R/W/X bits.
707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
708 aclsize = NFSX_UNSIGNED;
709 acecnt = fxdr_unsigned(int, *tl);
710 if (acecnt > ACL_MAX_ENTRIES)
711 aceerr = NFSERR_ATTRNOTSUPP;
712 if (nfsrv_useacl == 0)
713 aceerr = NFSERR_ATTRNOTSUPP;
714 for (i = 0; i < acecnt; i++) {
716 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
717 &aceerr, &acesize, p);
719 error = nfsrv_skipace(nd, &acesize);
725 aclp->acl_cnt = acecnt;
731 NFSEXITCODE2(error, nd);
736 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
739 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
745 len = fxdr_unsigned(int, *(tl + 3));
746 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
748 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
749 NFSEXITCODE2(error, nd);
754 * Get attribute bits from an mbuf list.
755 * Returns EBADRPC for a parsing error, 0 otherwise.
756 * If the clearinvalid flag is set, clear the bits not supported.
759 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
767 cnt = fxdr_unsigned(int, *tl);
769 error = NFSERR_BADXDR;
772 if (cnt > NFSATTRBIT_MAXWORDS)
773 outcnt = NFSATTRBIT_MAXWORDS;
776 NFSZERO_ATTRBIT(attrbitp);
778 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
779 for (i = 0; i < outcnt; i++)
780 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
782 for (i = 0; i < (cnt - outcnt); i++) {
783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
784 if (retnotsupp != NULL && *tl != 0)
785 *retnotsupp = NFSERR_ATTRNOTSUPP;
788 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
790 NFSEXITCODE2(error, nd);
795 * Get the attributes for V4.
796 * If the compare flag is true, test for any attribute changes,
797 * otherwise return the attribute values.
798 * These attributes cover fields in "struct vattr", "struct statfs",
799 * "struct nfsfsinfo", the file handle and the lease duration.
800 * The value of retcmpp is set to 1 if all attributes are the same,
802 * Returns EBADRPC if it can't be parsed, 0 otherwise.
805 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
806 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
807 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
808 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
809 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
812 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
813 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
814 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
815 nfsattrbit_t attrbits, retattrbits, checkattrbits;
817 struct nfsreferral *refp;
820 struct timespec temptime;
824 u_int32_t freenum = 0, tuint;
825 u_int64_t uquad = 0, thyp, thyp2;
830 static struct timeval last64fileid;
831 static size_t count64fileid;
832 static struct timeval last64mountfileid;
833 static size_t count64mountfileid;
834 static struct timeval warninterval = { 60, 0 };
838 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
840 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
846 *retcmpp = retnotsup;
849 * Just set default values to some of the important ones.
854 nap->na_rdev = (NFSDEV_T)0;
855 nap->na_mtime.tv_sec = 0;
856 nap->na_mtime.tv_nsec = 0;
859 nap->na_blocksize = NFS_FABLKSIZE;
862 sbp->f_bsize = NFS_FABLKSIZE;
870 fsp->fs_rtmax = 8192;
871 fsp->fs_rtpref = 8192;
872 fsp->fs_maxname = NFS_MAXNAMLEN;
873 fsp->fs_wtmax = 8192;
874 fsp->fs_wtpref = 8192;
875 fsp->fs_wtmult = NFS_FABLKSIZE;
876 fsp->fs_dtpref = 8192;
877 fsp->fs_maxfilesize = 0xffffffffffffffffull;
878 fsp->fs_timedelta.tv_sec = 0;
879 fsp->fs_timedelta.tv_nsec = 1;
880 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
881 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
884 pc->pc_linkmax = LINK_MAX;
885 pc->pc_namemax = NAME_MAX;
887 pc->pc_chownrestricted = 0;
888 pc->pc_caseinsensitive = 0;
889 pc->pc_casepreserving = 1;
894 * Loop around getting the attributes.
896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
897 attrsize = fxdr_unsigned(int, *tl);
898 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
899 if (attrsum > attrsize) {
900 error = NFSERR_BADXDR;
903 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
905 case NFSATTRBIT_SUPPORTEDATTRS:
907 if (compare || nap == NULL)
908 error = nfsrv_getattrbits(nd, &retattrbits,
911 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
915 if (compare && !(*retcmpp)) {
916 NFSSETSUPP_ATTRBIT(&checkattrbits);
918 /* Some filesystem do not support NFSv4ACL */
919 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
920 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
921 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
923 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
925 *retcmpp = NFSERR_NOTSAME;
929 case NFSATTRBIT_TYPE:
930 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
933 if (nap->na_type != nfsv34tov_type(*tl))
934 *retcmpp = NFSERR_NOTSAME;
936 } else if (nap != NULL) {
937 nap->na_type = nfsv34tov_type(*tl);
939 attrsum += NFSX_UNSIGNED;
941 case NFSATTRBIT_FHEXPIRETYPE:
942 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
943 if (compare && !(*retcmpp)) {
944 if (fxdr_unsigned(int, *tl) !=
945 NFSV4FHTYPE_PERSISTENT)
946 *retcmpp = NFSERR_NOTSAME;
948 attrsum += NFSX_UNSIGNED;
950 case NFSATTRBIT_CHANGE:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
954 if (nap->na_filerev != fxdr_hyper(tl))
955 *retcmpp = NFSERR_NOTSAME;
957 } else if (nap != NULL) {
958 nap->na_filerev = fxdr_hyper(tl);
960 attrsum += NFSX_HYPER;
962 case NFSATTRBIT_SIZE:
963 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
966 if (nap->na_size != fxdr_hyper(tl))
967 *retcmpp = NFSERR_NOTSAME;
969 } else if (nap != NULL) {
970 nap->na_size = fxdr_hyper(tl);
972 attrsum += NFSX_HYPER;
974 case NFSATTRBIT_LINKSUPPORT:
975 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
978 if (fsp->fs_properties & NFSV3_FSFLINK) {
979 if (*tl == newnfs_false)
980 *retcmpp = NFSERR_NOTSAME;
982 if (*tl == newnfs_true)
983 *retcmpp = NFSERR_NOTSAME;
986 } else if (fsp != NULL) {
987 if (*tl == newnfs_true)
988 fsp->fs_properties |= NFSV3_FSFLINK;
990 fsp->fs_properties &= ~NFSV3_FSFLINK;
992 attrsum += NFSX_UNSIGNED;
994 case NFSATTRBIT_SYMLINKSUPPORT:
995 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
998 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
999 if (*tl == newnfs_false)
1000 *retcmpp = NFSERR_NOTSAME;
1002 if (*tl == newnfs_true)
1003 *retcmpp = NFSERR_NOTSAME;
1006 } else if (fsp != NULL) {
1007 if (*tl == newnfs_true)
1008 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1010 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1012 attrsum += NFSX_UNSIGNED;
1014 case NFSATTRBIT_NAMEDATTR:
1015 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1016 if (compare && !(*retcmpp)) {
1017 if (*tl != newnfs_false)
1018 *retcmpp = NFSERR_NOTSAME;
1020 attrsum += NFSX_UNSIGNED;
1022 case NFSATTRBIT_FSID:
1023 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1024 thyp = fxdr_hyper(tl);
1026 thyp2 = fxdr_hyper(tl);
1028 if (*retcmpp == 0) {
1029 if (thyp != (u_int64_t)
1030 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1031 thyp2 != (u_int64_t)
1032 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1033 *retcmpp = NFSERR_NOTSAME;
1035 } else if (nap != NULL) {
1036 nap->na_filesid[0] = thyp;
1037 nap->na_filesid[1] = thyp2;
1039 attrsum += (4 * NFSX_UNSIGNED);
1041 case NFSATTRBIT_UNIQUEHANDLES:
1042 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1043 if (compare && !(*retcmpp)) {
1044 if (*tl != newnfs_true)
1045 *retcmpp = NFSERR_NOTSAME;
1047 attrsum += NFSX_UNSIGNED;
1049 case NFSATTRBIT_LEASETIME:
1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1052 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1054 *retcmpp = NFSERR_NOTSAME;
1055 } else if (leasep != NULL) {
1056 *leasep = fxdr_unsigned(u_int32_t, *tl);
1058 attrsum += NFSX_UNSIGNED;
1060 case NFSATTRBIT_RDATTRERROR:
1061 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1064 *retcmpp = NFSERR_INVAL;
1065 } else if (rderrp != NULL) {
1066 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1068 attrsum += NFSX_UNSIGNED;
1070 case NFSATTRBIT_ACL:
1073 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1076 naclp = acl_alloc(M_WAITOK);
1077 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1083 if (aceerr || aclp == NULL ||
1084 nfsrv_compareacl(aclp, naclp))
1085 *retcmpp = NFSERR_NOTSAME;
1088 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1090 *retcmpp = NFSERR_ATTRNOTSUPP;
1094 if (vp != NULL && aclp != NULL)
1095 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1098 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1106 case NFSATTRBIT_ACLSUPPORT:
1107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1108 if (compare && !(*retcmpp)) {
1109 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1110 if (fxdr_unsigned(u_int32_t, *tl) !=
1112 *retcmpp = NFSERR_NOTSAME;
1114 *retcmpp = NFSERR_ATTRNOTSUPP;
1117 attrsum += NFSX_UNSIGNED;
1119 case NFSATTRBIT_ARCHIVE:
1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1121 if (compare && !(*retcmpp))
1122 *retcmpp = NFSERR_ATTRNOTSUPP;
1123 attrsum += NFSX_UNSIGNED;
1125 case NFSATTRBIT_CANSETTIME:
1126 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1130 if (*tl == newnfs_false)
1131 *retcmpp = NFSERR_NOTSAME;
1133 if (*tl == newnfs_true)
1134 *retcmpp = NFSERR_NOTSAME;
1137 } else if (fsp != NULL) {
1138 if (*tl == newnfs_true)
1139 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1141 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1143 attrsum += NFSX_UNSIGNED;
1145 case NFSATTRBIT_CASEINSENSITIVE:
1146 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1149 if (*tl != newnfs_false)
1150 *retcmpp = NFSERR_NOTSAME;
1152 } else if (pc != NULL) {
1153 pc->pc_caseinsensitive =
1154 fxdr_unsigned(u_int32_t, *tl);
1156 attrsum += NFSX_UNSIGNED;
1158 case NFSATTRBIT_CASEPRESERVING:
1159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1162 if (*tl != newnfs_true)
1163 *retcmpp = NFSERR_NOTSAME;
1165 } else if (pc != NULL) {
1166 pc->pc_casepreserving =
1167 fxdr_unsigned(u_int32_t, *tl);
1169 attrsum += NFSX_UNSIGNED;
1171 case NFSATTRBIT_CHOWNRESTRICTED:
1172 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1175 if (*tl != newnfs_true)
1176 *retcmpp = NFSERR_NOTSAME;
1178 } else if (pc != NULL) {
1179 pc->pc_chownrestricted =
1180 fxdr_unsigned(u_int32_t, *tl);
1182 attrsum += NFSX_UNSIGNED;
1184 case NFSATTRBIT_FILEHANDLE:
1185 error = nfsm_getfh(nd, &tnfhp);
1188 tfhsize = tnfhp->nfh_len;
1191 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1193 *retcmpp = NFSERR_NOTSAME;
1194 FREE((caddr_t)tnfhp, M_NFSFH);
1195 } else if (nfhpp != NULL) {
1198 FREE((caddr_t)tnfhp, M_NFSFH);
1200 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1202 case NFSATTRBIT_FILEID:
1203 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1204 thyp = fxdr_hyper(tl);
1207 if ((u_int64_t)nap->na_fileid != thyp)
1208 *retcmpp = NFSERR_NOTSAME;
1210 } else if (nap != NULL) {
1213 if (ratecheck(&last64fileid, &warninterval)) {
1214 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1219 nap->na_fileid = thyp;
1221 attrsum += NFSX_HYPER;
1223 case NFSATTRBIT_FILESAVAIL:
1224 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1227 sfp->sf_afiles != fxdr_hyper(tl))
1228 *retcmpp = NFSERR_NOTSAME;
1229 } else if (sfp != NULL) {
1230 sfp->sf_afiles = fxdr_hyper(tl);
1232 attrsum += NFSX_HYPER;
1234 case NFSATTRBIT_FILESFREE:
1235 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1238 sfp->sf_ffiles != fxdr_hyper(tl))
1239 *retcmpp = NFSERR_NOTSAME;
1240 } else if (sfp != NULL) {
1241 sfp->sf_ffiles = fxdr_hyper(tl);
1243 attrsum += NFSX_HYPER;
1245 case NFSATTRBIT_FILESTOTAL:
1246 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1249 sfp->sf_tfiles != fxdr_hyper(tl))
1250 *retcmpp = NFSERR_NOTSAME;
1251 } else if (sfp != NULL) {
1252 sfp->sf_tfiles = fxdr_hyper(tl);
1254 attrsum += NFSX_HYPER;
1256 case NFSATTRBIT_FSLOCATIONS:
1257 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1261 if (compare && !(*retcmpp)) {
1262 refp = nfsv4root_getreferral(vp, NULL, 0);
1264 if (cp == NULL || cp2 == NULL ||
1266 strcmp(cp2, refp->nfr_srvlist))
1267 *retcmpp = NFSERR_NOTSAME;
1268 } else if (m == 0) {
1269 *retcmpp = NFSERR_NOTSAME;
1273 free(cp, M_NFSSTRING);
1275 free(cp2, M_NFSSTRING);
1277 case NFSATTRBIT_HIDDEN:
1278 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1279 if (compare && !(*retcmpp))
1280 *retcmpp = NFSERR_ATTRNOTSUPP;
1281 attrsum += NFSX_UNSIGNED;
1283 case NFSATTRBIT_HOMOGENEOUS:
1284 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1287 if (fsp->fs_properties &
1288 NFSV3_FSFHOMOGENEOUS) {
1289 if (*tl == newnfs_false)
1290 *retcmpp = NFSERR_NOTSAME;
1292 if (*tl == newnfs_true)
1293 *retcmpp = NFSERR_NOTSAME;
1296 } else if (fsp != NULL) {
1297 if (*tl == newnfs_true)
1298 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1300 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1302 attrsum += NFSX_UNSIGNED;
1304 case NFSATTRBIT_MAXFILESIZE:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1306 tnfsquad.qval = fxdr_hyper(tl);
1309 tquad = NFSRV_MAXFILESIZE;
1310 if (tquad != tnfsquad.qval)
1311 *retcmpp = NFSERR_NOTSAME;
1313 } else if (fsp != NULL) {
1314 fsp->fs_maxfilesize = tnfsquad.qval;
1316 attrsum += NFSX_HYPER;
1318 case NFSATTRBIT_MAXLINK:
1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1322 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1323 *retcmpp = NFSERR_NOTSAME;
1325 } else if (pc != NULL) {
1326 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1328 attrsum += NFSX_UNSIGNED;
1330 case NFSATTRBIT_MAXNAME:
1331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1334 if (fsp->fs_maxname !=
1335 fxdr_unsigned(u_int32_t, *tl))
1336 *retcmpp = NFSERR_NOTSAME;
1339 tuint = fxdr_unsigned(u_int32_t, *tl);
1341 * Some Linux NFSv4 servers report this
1342 * as 0 or 4billion, so I'll set it to
1343 * NFS_MAXNAMLEN. If a server actually creates
1344 * a name longer than NFS_MAXNAMLEN, it will
1345 * get an error back.
1347 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1348 tuint = NFS_MAXNAMLEN;
1350 fsp->fs_maxname = tuint;
1352 pc->pc_namemax = tuint;
1354 attrsum += NFSX_UNSIGNED;
1356 case NFSATTRBIT_MAXREAD:
1357 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1360 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1361 *(tl + 1)) || *tl != 0)
1362 *retcmpp = NFSERR_NOTSAME;
1364 } else if (fsp != NULL) {
1365 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1366 fsp->fs_rtpref = fsp->fs_rtmax;
1367 fsp->fs_dtpref = fsp->fs_rtpref;
1369 attrsum += NFSX_HYPER;
1371 case NFSATTRBIT_MAXWRITE:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1375 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1376 *(tl + 1)) || *tl != 0)
1377 *retcmpp = NFSERR_NOTSAME;
1379 } else if (fsp != NULL) {
1380 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1381 fsp->fs_wtpref = fsp->fs_wtmax;
1383 attrsum += NFSX_HYPER;
1385 case NFSATTRBIT_MIMETYPE:
1386 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1387 i = fxdr_unsigned(int, *tl);
1388 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1389 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1392 if (compare && !(*retcmpp))
1393 *retcmpp = NFSERR_ATTRNOTSUPP;
1395 case NFSATTRBIT_MODE:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1399 if (nap->na_mode != nfstov_mode(*tl))
1400 *retcmpp = NFSERR_NOTSAME;
1402 } else if (nap != NULL) {
1403 nap->na_mode = nfstov_mode(*tl);
1405 attrsum += NFSX_UNSIGNED;
1407 case NFSATTRBIT_NOTRUNC:
1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1411 if (*tl != newnfs_true)
1412 *retcmpp = NFSERR_NOTSAME;
1414 } else if (pc != NULL) {
1415 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1417 attrsum += NFSX_UNSIGNED;
1419 case NFSATTRBIT_NUMLINKS:
1420 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1421 tuint = fxdr_unsigned(u_int32_t, *tl);
1424 if ((u_int32_t)nap->na_nlink != tuint)
1425 *retcmpp = NFSERR_NOTSAME;
1427 } else if (nap != NULL) {
1428 nap->na_nlink = tuint;
1430 attrsum += NFSX_UNSIGNED;
1432 case NFSATTRBIT_OWNER:
1433 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1434 j = fxdr_unsigned(int, *tl);
1436 error = NFSERR_BADXDR;
1439 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1440 if (j > NFSV4_SMALLSTR)
1441 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1444 error = nfsrv_mtostr(nd, cp, j);
1446 if (j > NFSV4_SMALLSTR)
1447 free(cp, M_NFSSTRING);
1452 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1454 *retcmpp = NFSERR_NOTSAME;
1456 } else if (nap != NULL) {
1457 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1458 nap->na_uid = nfsrv_defaultuid;
1462 if (j > NFSV4_SMALLSTR)
1463 free(cp, M_NFSSTRING);
1465 case NFSATTRBIT_OWNERGROUP:
1466 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1467 j = fxdr_unsigned(int, *tl);
1469 error = NFSERR_BADXDR;
1472 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1473 if (j > NFSV4_SMALLSTR)
1474 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1477 error = nfsrv_mtostr(nd, cp, j);
1479 if (j > NFSV4_SMALLSTR)
1480 free(cp, M_NFSSTRING);
1485 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1487 *retcmpp = NFSERR_NOTSAME;
1489 } else if (nap != NULL) {
1490 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1491 nap->na_gid = nfsrv_defaultgid;
1495 if (j > NFSV4_SMALLSTR)
1496 free(cp, M_NFSSTRING);
1498 case NFSATTRBIT_QUOTAHARD:
1499 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1501 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1502 freenum = sbp->f_bfree;
1504 freenum = sbp->f_bavail;
1507 * ufs_quotactl() insists that the uid argument
1508 * equal p_ruid for non-root quota access, so
1509 * we'll just make sure that's the case.
1511 savuid = p->p_cred->p_ruid;
1512 p->p_cred->p_ruid = cred->cr_uid;
1513 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1514 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1515 freenum = min(dqb.dqb_bhardlimit, freenum);
1516 p->p_cred->p_ruid = savuid;
1518 uquad = (u_int64_t)freenum;
1519 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1521 if (compare && !(*retcmpp)) {
1522 if (uquad != fxdr_hyper(tl))
1523 *retcmpp = NFSERR_NOTSAME;
1525 attrsum += NFSX_HYPER;
1527 case NFSATTRBIT_QUOTASOFT:
1528 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1530 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1531 freenum = sbp->f_bfree;
1533 freenum = sbp->f_bavail;
1536 * ufs_quotactl() insists that the uid argument
1537 * equal p_ruid for non-root quota access, so
1538 * we'll just make sure that's the case.
1540 savuid = p->p_cred->p_ruid;
1541 p->p_cred->p_ruid = cred->cr_uid;
1542 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1543 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1544 freenum = min(dqb.dqb_bsoftlimit, freenum);
1545 p->p_cred->p_ruid = savuid;
1547 uquad = (u_int64_t)freenum;
1548 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1550 if (compare && !(*retcmpp)) {
1551 if (uquad != fxdr_hyper(tl))
1552 *retcmpp = NFSERR_NOTSAME;
1554 attrsum += NFSX_HYPER;
1556 case NFSATTRBIT_QUOTAUSED:
1557 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1562 * ufs_quotactl() insists that the uid argument
1563 * equal p_ruid for non-root quota access, so
1564 * we'll just make sure that's the case.
1566 savuid = p->p_cred->p_ruid;
1567 p->p_cred->p_ruid = cred->cr_uid;
1568 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1569 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1570 freenum = dqb.dqb_curblocks;
1571 p->p_cred->p_ruid = savuid;
1573 uquad = (u_int64_t)freenum;
1574 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1576 if (compare && !(*retcmpp)) {
1577 if (uquad != fxdr_hyper(tl))
1578 *retcmpp = NFSERR_NOTSAME;
1580 attrsum += NFSX_HYPER;
1582 case NFSATTRBIT_RAWDEV:
1583 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1584 j = fxdr_unsigned(int, *tl++);
1585 k = fxdr_unsigned(int, *tl);
1588 if (nap->na_rdev != NFSMAKEDEV(j, k))
1589 *retcmpp = NFSERR_NOTSAME;
1591 } else if (nap != NULL) {
1592 nap->na_rdev = NFSMAKEDEV(j, k);
1594 attrsum += NFSX_V4SPECDATA;
1596 case NFSATTRBIT_SPACEAVAIL:
1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1600 sfp->sf_abytes != fxdr_hyper(tl))
1601 *retcmpp = NFSERR_NOTSAME;
1602 } else if (sfp != NULL) {
1603 sfp->sf_abytes = fxdr_hyper(tl);
1605 attrsum += NFSX_HYPER;
1607 case NFSATTRBIT_SPACEFREE:
1608 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1611 sfp->sf_fbytes != fxdr_hyper(tl))
1612 *retcmpp = NFSERR_NOTSAME;
1613 } else if (sfp != NULL) {
1614 sfp->sf_fbytes = fxdr_hyper(tl);
1616 attrsum += NFSX_HYPER;
1618 case NFSATTRBIT_SPACETOTAL:
1619 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1622 sfp->sf_tbytes != fxdr_hyper(tl))
1623 *retcmpp = NFSERR_NOTSAME;
1624 } else if (sfp != NULL) {
1625 sfp->sf_tbytes = fxdr_hyper(tl);
1627 attrsum += NFSX_HYPER;
1629 case NFSATTRBIT_SPACEUSED:
1630 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1631 thyp = fxdr_hyper(tl);
1634 if ((u_int64_t)nap->na_bytes != thyp)
1635 *retcmpp = NFSERR_NOTSAME;
1637 } else if (nap != NULL) {
1638 nap->na_bytes = thyp;
1640 attrsum += NFSX_HYPER;
1642 case NFSATTRBIT_SYSTEM:
1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1644 if (compare && !(*retcmpp))
1645 *retcmpp = NFSERR_ATTRNOTSUPP;
1646 attrsum += NFSX_UNSIGNED;
1648 case NFSATTRBIT_TIMEACCESS:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1650 fxdr_nfsv4time(tl, &temptime);
1653 if (!NFS_CMPTIME(temptime, nap->na_atime))
1654 *retcmpp = NFSERR_NOTSAME;
1656 } else if (nap != NULL) {
1657 nap->na_atime = temptime;
1659 attrsum += NFSX_V4TIME;
1661 case NFSATTRBIT_TIMEACCESSSET:
1662 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1663 attrsum += NFSX_UNSIGNED;
1664 i = fxdr_unsigned(int, *tl);
1665 if (i == NFSV4SATTRTIME_TOCLIENT) {
1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1667 attrsum += NFSX_V4TIME;
1669 if (compare && !(*retcmpp))
1670 *retcmpp = NFSERR_INVAL;
1672 case NFSATTRBIT_TIMEBACKUP:
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1674 if (compare && !(*retcmpp))
1675 *retcmpp = NFSERR_ATTRNOTSUPP;
1676 attrsum += NFSX_V4TIME;
1678 case NFSATTRBIT_TIMECREATE:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1680 if (compare && !(*retcmpp))
1681 *retcmpp = NFSERR_ATTRNOTSUPP;
1682 attrsum += NFSX_V4TIME;
1684 case NFSATTRBIT_TIMEDELTA:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1689 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1690 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1691 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1692 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1695 *retcmpp = NFSERR_NOTSAME;
1698 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1701 attrsum += NFSX_V4TIME;
1703 case NFSATTRBIT_TIMEMETADATA:
1704 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1705 fxdr_nfsv4time(tl, &temptime);
1708 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1709 *retcmpp = NFSERR_NOTSAME;
1711 } else if (nap != NULL) {
1712 nap->na_ctime = temptime;
1714 attrsum += NFSX_V4TIME;
1716 case NFSATTRBIT_TIMEMODIFY:
1717 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1718 fxdr_nfsv4time(tl, &temptime);
1721 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1722 *retcmpp = NFSERR_NOTSAME;
1724 } else if (nap != NULL) {
1725 nap->na_mtime = temptime;
1727 attrsum += NFSX_V4TIME;
1729 case NFSATTRBIT_TIMEMODIFYSET:
1730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1731 attrsum += NFSX_UNSIGNED;
1732 i = fxdr_unsigned(int, *tl);
1733 if (i == NFSV4SATTRTIME_TOCLIENT) {
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1735 attrsum += NFSX_V4TIME;
1737 if (compare && !(*retcmpp))
1738 *retcmpp = NFSERR_INVAL;
1740 case NFSATTRBIT_MOUNTEDONFILEID:
1741 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1742 thyp = fxdr_hyper(tl);
1746 *retcmpp = NFSERR_NOTSAME;
1748 if (!vp || !nfsrv_atroot(vp, &fid))
1749 fid = nap->na_fileid;
1750 if ((u_int64_t)fid != thyp)
1751 *retcmpp = NFSERR_NOTSAME;
1754 } else if (nap != NULL) {
1756 count64mountfileid++;
1757 if (ratecheck(&last64mountfileid, &warninterval)) {
1758 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1759 count64mountfileid);
1760 count64mountfileid = 0;
1763 nap->na_mntonfileno = thyp;
1765 attrsum += NFSX_HYPER;
1767 case NFSATTRBIT_SUPPATTREXCLCREAT:
1769 error = nfsrv_getattrbits(nd, &retattrbits,
1773 if (compare && !(*retcmpp)) {
1774 NFSSETSUPP_ATTRBIT(&checkattrbits);
1775 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1776 NFSCLRBIT_ATTRBIT(&checkattrbits,
1777 NFSATTRBIT_TIMEACCESSSET);
1778 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1780 *retcmpp = NFSERR_NOTSAME;
1785 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1787 if (compare && !(*retcmpp))
1788 *retcmpp = NFSERR_ATTRNOTSUPP;
1790 * and get out of the loop, since we can't parse
1791 * the unknown attrbute data.
1793 bitpos = NFSATTRBIT_MAX;
1799 * some clients pad the attrlist, so we need to skip over the
1802 if (attrsum > attrsize) {
1803 error = NFSERR_BADXDR;
1805 attrsize = NFSM_RNDUP(attrsize);
1806 if (attrsum < attrsize)
1807 error = nfsm_advance(nd, attrsize - attrsum, -1);
1810 NFSEXITCODE2(error, nd);
1815 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1816 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1817 * The first argument is a pointer to an nfsv4lock structure.
1818 * The second argument is 1 iff a blocking lock is wanted.
1819 * If this argument is 0, the call waits until no thread either wants nor
1820 * holds an exclusive lock.
1821 * It returns 1 if the lock was acquired, 0 otherwise.
1822 * If several processes call this function concurrently wanting the exclusive
1823 * lock, one will get the lock and the rest will return without getting the
1824 * lock. (If the caller must have the lock, it simply calls this function in a
1825 * loop until the function returns 1 to indicate the lock was acquired.)
1826 * Any usecnt must be decremented by calling nfsv4_relref() before
1827 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1828 * be called in a loop.
1829 * The isleptp argument is set to indicate if the call slept, iff not NULL
1830 * and the mp argument indicates to check for a forced dismount, iff not
1834 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1835 void *mutex, struct mount *mp)
1841 * If a lock is wanted, loop around until the lock is acquired by
1842 * someone and then released. If I want the lock, try to acquire it.
1843 * For a lock to be issued, no lock must be in force and the usecnt
1847 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1848 lp->nfslock_usecnt == 0) {
1849 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1850 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1853 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1855 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1856 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1857 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1860 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1863 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1864 PZERO - 1, "nfsv4lck", NULL);
1865 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1866 lp->nfslock_usecnt == 0) {
1867 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1868 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1876 * Release the lock acquired by nfsv4_lock().
1877 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1878 * incremented, as well.
1881 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1884 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1886 lp->nfslock_usecnt++;
1891 * Release a reference cnt.
1894 nfsv4_relref(struct nfsv4lock *lp)
1897 if (lp->nfslock_usecnt <= 0)
1898 panic("nfsv4root ref cnt");
1899 lp->nfslock_usecnt--;
1900 if (lp->nfslock_usecnt == 0)
1905 * Get a reference cnt.
1906 * This function will wait for any exclusive lock to be released, but will
1907 * not wait for threads that want the exclusive lock. If priority needs
1908 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1909 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1910 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1911 * return without getting a refcnt for that case.
1914 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1922 * Wait for a lock held.
1924 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1925 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1927 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1930 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1931 PZERO - 1, "nfsv4gr", NULL);
1933 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1936 lp->nfslock_usecnt++;
1940 * Get a reference as above, but return failure instead of sleeping if
1941 * an exclusive lock is held.
1944 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1947 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1950 lp->nfslock_usecnt++;
1955 * Test for a lock. Return 1 if locked, 0 otherwise.
1958 nfsv4_testlock(struct nfsv4lock *lp)
1961 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1962 lp->nfslock_usecnt == 0)
1968 * Wake up anyone sleeping, waiting for this lock.
1971 nfsv4_wanted(struct nfsv4lock *lp)
1974 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1975 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1976 wakeup((caddr_t)&lp->nfslock_lock);
1981 * Copy a string from an mbuf list into a character array.
1982 * Return EBADRPC if there is an mbuf error,
1986 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1995 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1996 rem = NFSM_RNDUP(siz) - siz;
2002 NFSBCOPY(cp, str, xfer);
2011 cp = NFSMTOD(mp, caddr_t);
2023 error = nfsm_advance(nd, rem, len);
2029 NFSEXITCODE2(error, nd);
2034 * Fill in the attributes as marked by the bitmap (V4).
2037 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2038 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2039 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2040 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2042 int bitpos, retnum = 0;
2044 int siz, prefixnum, error;
2045 u_char *cp, namestr[NFSV4_SMALLSTR];
2046 nfsattrbit_t attrbits, retbits;
2047 nfsattrbit_t *retbitp = &retbits;
2048 u_int32_t freenum, *retnump;
2051 struct nfsfsinfo fsinf;
2052 struct timespec temptime;
2053 NFSACL_T *aclp, *naclp = NULL;
2060 * First, set the bits that can be filled and get fsinfo.
2062 NFSSET_ATTRBIT(retbitp, attrbitp);
2064 * If both p and cred are NULL, it is a client side setattr call.
2065 * If both p and cred are not NULL, it is a server side reply call.
2066 * If p is not NULL and cred is NULL, it is a client side callback
2069 if (p == NULL && cred == NULL) {
2070 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2073 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2074 naclp = acl_alloc(M_WAITOK);
2077 nfsvno_getfs(&fsinf, isdgram);
2080 * Get the VFS_STATFS(), since some attributes need them.
2082 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2083 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2084 error = VFS_STATFS(mp, fs);
2087 nd->nd_repstat = NFSERR_ACCES;
2091 NFSCLRSTATFS_ATTRBIT(retbitp);
2097 * And the NFSv4 ACL...
2099 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2100 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2101 supports_nfsv4acls == 0))) {
2102 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2104 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2105 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2106 supports_nfsv4acls == 0)) {
2107 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2108 } else if (naclp != NULL) {
2109 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2110 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2112 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2114 NFSVOPUNLOCK(vp, 0);
2116 error = NFSERR_PERM;
2119 nd->nd_repstat = NFSERR_ACCES;
2123 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2129 * Put out the attribute bitmap for the ones being filled in
2130 * and get the field for the number of attributes returned.
2132 prefixnum = nfsrv_putattrbit(nd, retbitp);
2133 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2134 prefixnum += NFSX_UNSIGNED;
2137 * Now, loop around filling in the attributes for each bit set.
2139 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2140 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2142 case NFSATTRBIT_SUPPORTEDATTRS:
2143 NFSSETSUPP_ATTRBIT(&attrbits);
2144 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2145 && supports_nfsv4acls == 0)) {
2146 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2147 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2149 retnum += nfsrv_putattrbit(nd, &attrbits);
2151 case NFSATTRBIT_TYPE:
2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2153 *tl = vtonfsv34_type(vap->va_type);
2154 retnum += NFSX_UNSIGNED;
2156 case NFSATTRBIT_FHEXPIRETYPE:
2157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2158 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2159 retnum += NFSX_UNSIGNED;
2161 case NFSATTRBIT_CHANGE:
2162 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2163 txdr_hyper(vap->va_filerev, tl);
2164 retnum += NFSX_HYPER;
2166 case NFSATTRBIT_SIZE:
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2168 txdr_hyper(vap->va_size, tl);
2169 retnum += NFSX_HYPER;
2171 case NFSATTRBIT_LINKSUPPORT:
2172 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2173 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2177 retnum += NFSX_UNSIGNED;
2179 case NFSATTRBIT_SYMLINKSUPPORT:
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2181 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2185 retnum += NFSX_UNSIGNED;
2187 case NFSATTRBIT_NAMEDATTR:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 retnum += NFSX_UNSIGNED;
2192 case NFSATTRBIT_FSID:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2195 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2197 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2198 retnum += NFSX_V4FSID;
2200 case NFSATTRBIT_UNIQUEHANDLES:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2203 retnum += NFSX_UNSIGNED;
2205 case NFSATTRBIT_LEASETIME:
2206 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2207 *tl = txdr_unsigned(nfsrv_lease);
2208 retnum += NFSX_UNSIGNED;
2210 case NFSATTRBIT_RDATTRERROR:
2211 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2212 *tl = txdr_unsigned(rderror);
2213 retnum += NFSX_UNSIGNED;
2216 * Recommended Attributes. (Only the supported ones.)
2218 case NFSATTRBIT_ACL:
2219 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2221 case NFSATTRBIT_ACLSUPPORT:
2222 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2223 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2224 retnum += NFSX_UNSIGNED;
2226 case NFSATTRBIT_CANSETTIME:
2227 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2228 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2232 retnum += NFSX_UNSIGNED;
2234 case NFSATTRBIT_CASEINSENSITIVE:
2235 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2237 retnum += NFSX_UNSIGNED;
2239 case NFSATTRBIT_CASEPRESERVING:
2240 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2242 retnum += NFSX_UNSIGNED;
2244 case NFSATTRBIT_CHOWNRESTRICTED:
2245 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2247 retnum += NFSX_UNSIGNED;
2249 case NFSATTRBIT_FILEHANDLE:
2250 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2252 case NFSATTRBIT_FILEID:
2253 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2255 *tl = txdr_unsigned(vap->va_fileid);
2256 retnum += NFSX_HYPER;
2258 case NFSATTRBIT_FILESAVAIL:
2260 * Check quota and use min(quota, f_ffree).
2262 freenum = fs->f_ffree;
2265 * ufs_quotactl() insists that the uid argument
2266 * equal p_ruid for non-root quota access, so
2267 * we'll just make sure that's the case.
2269 savuid = p->p_cred->p_ruid;
2270 p->p_cred->p_ruid = cred->cr_uid;
2271 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2272 cred->cr_uid, (caddr_t)&dqb))
2273 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2275 p->p_cred->p_ruid = savuid;
2277 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2279 *tl = txdr_unsigned(freenum);
2280 retnum += NFSX_HYPER;
2282 case NFSATTRBIT_FILESFREE:
2283 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2285 *tl = txdr_unsigned(fs->f_ffree);
2286 retnum += NFSX_HYPER;
2288 case NFSATTRBIT_FILESTOTAL:
2289 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2291 *tl = txdr_unsigned(fs->f_files);
2292 retnum += NFSX_HYPER;
2294 case NFSATTRBIT_FSLOCATIONS:
2295 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2298 retnum += 2 * NFSX_UNSIGNED;
2300 case NFSATTRBIT_HOMOGENEOUS:
2301 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2302 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2306 retnum += NFSX_UNSIGNED;
2308 case NFSATTRBIT_MAXFILESIZE:
2309 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2310 uquad = NFSRV_MAXFILESIZE;
2311 txdr_hyper(uquad, tl);
2312 retnum += NFSX_HYPER;
2314 case NFSATTRBIT_MAXLINK:
2315 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2316 *tl = txdr_unsigned(LINK_MAX);
2317 retnum += NFSX_UNSIGNED;
2319 case NFSATTRBIT_MAXNAME:
2320 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2321 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2322 retnum += NFSX_UNSIGNED;
2324 case NFSATTRBIT_MAXREAD:
2325 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2327 *tl = txdr_unsigned(fsinf.fs_rtmax);
2328 retnum += NFSX_HYPER;
2330 case NFSATTRBIT_MAXWRITE:
2331 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2333 *tl = txdr_unsigned(fsinf.fs_wtmax);
2334 retnum += NFSX_HYPER;
2336 case NFSATTRBIT_MODE:
2337 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2338 *tl = vtonfsv34_mode(vap->va_mode);
2339 retnum += NFSX_UNSIGNED;
2341 case NFSATTRBIT_NOTRUNC:
2342 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2344 retnum += NFSX_UNSIGNED;
2346 case NFSATTRBIT_NUMLINKS:
2347 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2348 *tl = txdr_unsigned(vap->va_nlink);
2349 retnum += NFSX_UNSIGNED;
2351 case NFSATTRBIT_OWNER:
2353 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2354 retnum += nfsm_strtom(nd, cp, siz);
2356 free(cp, M_NFSSTRING);
2358 case NFSATTRBIT_OWNERGROUP:
2360 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2361 retnum += nfsm_strtom(nd, cp, siz);
2363 free(cp, M_NFSSTRING);
2365 case NFSATTRBIT_QUOTAHARD:
2366 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2367 freenum = fs->f_bfree;
2369 freenum = fs->f_bavail;
2372 * ufs_quotactl() insists that the uid argument
2373 * equal p_ruid for non-root quota access, so
2374 * we'll just make sure that's the case.
2376 savuid = p->p_cred->p_ruid;
2377 p->p_cred->p_ruid = cred->cr_uid;
2378 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2379 cred->cr_uid, (caddr_t)&dqb))
2380 freenum = min(dqb.dqb_bhardlimit, freenum);
2381 p->p_cred->p_ruid = savuid;
2383 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2384 uquad = (u_int64_t)freenum;
2385 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2386 txdr_hyper(uquad, tl);
2387 retnum += NFSX_HYPER;
2389 case NFSATTRBIT_QUOTASOFT:
2390 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2391 freenum = fs->f_bfree;
2393 freenum = fs->f_bavail;
2396 * ufs_quotactl() insists that the uid argument
2397 * equal p_ruid for non-root quota access, so
2398 * we'll just make sure that's the case.
2400 savuid = p->p_cred->p_ruid;
2401 p->p_cred->p_ruid = cred->cr_uid;
2402 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2403 cred->cr_uid, (caddr_t)&dqb))
2404 freenum = min(dqb.dqb_bsoftlimit, freenum);
2405 p->p_cred->p_ruid = savuid;
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2408 uquad = (u_int64_t)freenum;
2409 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2410 txdr_hyper(uquad, tl);
2411 retnum += NFSX_HYPER;
2413 case NFSATTRBIT_QUOTAUSED:
2417 * ufs_quotactl() insists that the uid argument
2418 * equal p_ruid for non-root quota access, so
2419 * we'll just make sure that's the case.
2421 savuid = p->p_cred->p_ruid;
2422 p->p_cred->p_ruid = cred->cr_uid;
2423 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2424 cred->cr_uid, (caddr_t)&dqb))
2425 freenum = dqb.dqb_curblocks;
2426 p->p_cred->p_ruid = savuid;
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2429 uquad = (u_int64_t)freenum;
2430 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2431 txdr_hyper(uquad, tl);
2432 retnum += NFSX_HYPER;
2434 case NFSATTRBIT_RAWDEV:
2435 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2436 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2437 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2438 retnum += NFSX_V4SPECDATA;
2440 case NFSATTRBIT_SPACEAVAIL:
2441 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2442 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2443 uquad = (u_int64_t)fs->f_bfree;
2445 uquad = (u_int64_t)fs->f_bavail;
2446 uquad *= fs->f_bsize;
2447 txdr_hyper(uquad, tl);
2448 retnum += NFSX_HYPER;
2450 case NFSATTRBIT_SPACEFREE:
2451 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2452 uquad = (u_int64_t)fs->f_bfree;
2453 uquad *= fs->f_bsize;
2454 txdr_hyper(uquad, tl);
2455 retnum += NFSX_HYPER;
2457 case NFSATTRBIT_SPACETOTAL:
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2459 uquad = (u_int64_t)fs->f_blocks;
2460 uquad *= fs->f_bsize;
2461 txdr_hyper(uquad, tl);
2462 retnum += NFSX_HYPER;
2464 case NFSATTRBIT_SPACEUSED:
2465 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2466 txdr_hyper(vap->va_bytes, tl);
2467 retnum += NFSX_HYPER;
2469 case NFSATTRBIT_TIMEACCESS:
2470 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2471 txdr_nfsv4time(&vap->va_atime, tl);
2472 retnum += NFSX_V4TIME;
2474 case NFSATTRBIT_TIMEACCESSSET:
2475 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2476 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2477 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2478 txdr_nfsv4time(&vap->va_atime, tl);
2479 retnum += NFSX_V4SETTIME;
2481 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2482 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2483 retnum += NFSX_UNSIGNED;
2486 case NFSATTRBIT_TIMEDELTA:
2487 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2488 temptime.tv_sec = 0;
2489 temptime.tv_nsec = 1000000000 / hz;
2490 txdr_nfsv4time(&temptime, tl);
2491 retnum += NFSX_V4TIME;
2493 case NFSATTRBIT_TIMEMETADATA:
2494 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2495 txdr_nfsv4time(&vap->va_ctime, tl);
2496 retnum += NFSX_V4TIME;
2498 case NFSATTRBIT_TIMEMODIFY:
2499 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2500 txdr_nfsv4time(&vap->va_mtime, tl);
2501 retnum += NFSX_V4TIME;
2503 case NFSATTRBIT_TIMEMODIFYSET:
2504 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2505 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2506 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2507 txdr_nfsv4time(&vap->va_mtime, tl);
2508 retnum += NFSX_V4SETTIME;
2510 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2511 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2512 retnum += NFSX_UNSIGNED;
2515 case NFSATTRBIT_MOUNTEDONFILEID:
2516 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2518 uquad = mounted_on_fileno;
2520 uquad = (u_int64_t)vap->va_fileid;
2521 txdr_hyper(uquad, tl);
2522 retnum += NFSX_HYPER;
2524 case NFSATTRBIT_SUPPATTREXCLCREAT:
2525 NFSSETSUPP_ATTRBIT(&attrbits);
2526 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2527 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2528 retnum += nfsrv_putattrbit(nd, &attrbits);
2531 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2538 *retnump = txdr_unsigned(retnum);
2539 return (retnum + prefixnum);
2543 * Put the attribute bits onto an mbuf list.
2544 * Return the number of bytes of output generated.
2547 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2550 int cnt, i, bytesize;
2552 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2553 if (attrbitp->bits[cnt - 1])
2555 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2556 NFSM_BUILD(tl, u_int32_t *, bytesize);
2557 *tl++ = txdr_unsigned(cnt);
2558 for (i = 0; i < cnt; i++)
2559 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2564 * Convert a uid to a string.
2565 * If the lookup fails, just output the digits.
2567 * cpp - points to a buffer of size NFSV4_SMALLSTR
2568 * (malloc a larger one, as required)
2569 * retlenp - pointer to length to be returned
2572 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2575 struct nfsusrgrp *usrp;
2578 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2579 struct nfsrv_lughash *hp;
2583 if (nfsrv_dnsnamelen > 0) {
2585 * Always map nfsrv_defaultuid to "nobody".
2587 if (uid == nfsrv_defaultuid) {
2588 i = nfsrv_dnsnamelen + 7;
2590 if (len > NFSV4_SMALLSTR)
2591 free(cp, M_NFSSTRING);
2592 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2598 NFSBCOPY("nobody@", cp, 7);
2600 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2604 hp = NFSUSERHASH(uid);
2606 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2607 if (usrp->lug_uid == uid) {
2608 if (usrp->lug_expiry < NFSD_MONOSEC)
2611 * If the name doesn't already have an '@'
2612 * in it, append @domainname to it.
2614 for (i = 0; i < usrp->lug_namelen; i++) {
2615 if (usrp->lug_name[i] == '@') {
2621 i = usrp->lug_namelen;
2623 i = usrp->lug_namelen +
2624 nfsrv_dnsnamelen + 1;
2626 mtx_unlock(&hp->mtx);
2627 if (len > NFSV4_SMALLSTR)
2628 free(cp, M_NFSSTRING);
2629 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2635 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2636 if (!hasampersand) {
2637 cp += usrp->lug_namelen;
2639 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2641 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2642 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2644 mtx_unlock(&hp->mtx);
2648 mtx_unlock(&hp->mtx);
2650 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2652 if (ret == 0 && cnt < 2)
2657 * No match, just return a string of digits.
2661 while (tmp || i == 0) {
2665 len = (i > len) ? len : i;
2669 for (i = 0; i < len; i++) {
2670 *cp-- = '0' + (tmp % 10);
2677 * Get a credential for the uid with the server's group list.
2678 * If none is found, just return the credential passed in after
2679 * logging a warning message.
2682 nfsrv_getgrpscred(struct ucred *oldcred)
2684 struct nfsusrgrp *usrp;
2685 struct ucred *newcred;
2688 struct nfsrv_lughash *hp;
2691 uid = oldcred->cr_uid;
2693 if (nfsrv_dnsnamelen > 0) {
2694 hp = NFSUSERHASH(uid);
2696 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2697 if (usrp->lug_uid == uid) {
2698 if (usrp->lug_expiry < NFSD_MONOSEC)
2700 if (usrp->lug_cred != NULL) {
2701 newcred = crhold(usrp->lug_cred);
2705 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2706 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2708 mtx_unlock(&hp->mtx);
2712 mtx_unlock(&hp->mtx);
2714 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2716 if (ret == 0 && cnt < 2)
2723 * Convert a string to a uid.
2724 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2726 * If this is called from a client side mount using AUTH_SYS and the
2727 * string is made up entirely of digits, just convert the string to
2731 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2735 char *cp, *endstr, *str0;
2736 struct nfsusrgrp *usrp;
2740 struct nfsrv_lughash *hp, *hp2;
2743 error = NFSERR_BADOWNER;
2746 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2748 tuid = (uid_t)strtoul(str0, &endstr, 10);
2749 if ((endstr - str0) == len) {
2750 /* A numeric string. */
2751 if ((nd->nd_flag & ND_KERBV) == 0 &&
2752 ((nd->nd_flag & ND_NFSCL) != 0 ||
2753 nfsd_enable_stringtouid != 0))
2756 error = NFSERR_BADOWNER;
2762 cp = strchr(str0, '@');
2764 i = (int)(cp++ - str0);
2770 if (nfsrv_dnsnamelen > 0) {
2772 * If an '@' is found and the domain name matches, search for
2773 * the name with dns stripped off.
2774 * Mixed case alpahbetics will match for the domain name, but
2775 * all upper case will not.
2777 if (cnt == 0 && i < len && i > 0 &&
2778 (len - 1 - i) == nfsrv_dnsnamelen &&
2779 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2780 len -= (nfsrv_dnsnamelen + 1);
2785 * Check for the special case of "nobody".
2787 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2788 *uidp = nfsrv_defaultuid;
2793 hp = NFSUSERNAMEHASH(str, len);
2795 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2796 if (usrp->lug_namelen == len &&
2797 !NFSBCMP(usrp->lug_name, str, len)) {
2798 if (usrp->lug_expiry < NFSD_MONOSEC)
2800 hp2 = NFSUSERHASH(usrp->lug_uid);
2801 mtx_lock(&hp2->mtx);
2802 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2803 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2805 *uidp = usrp->lug_uid;
2806 mtx_unlock(&hp2->mtx);
2807 mtx_unlock(&hp->mtx);
2812 mtx_unlock(&hp->mtx);
2814 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2816 if (ret == 0 && cnt < 2)
2819 error = NFSERR_BADOWNER;
2827 * Convert a gid to a string.
2828 * gid - the group id
2829 * cpp - points to a buffer of size NFSV4_SMALLSTR
2830 * (malloc a larger one, as required)
2831 * retlenp - pointer to length to be returned
2834 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2837 struct nfsusrgrp *usrp;
2840 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2841 struct nfsrv_lughash *hp;
2845 if (nfsrv_dnsnamelen > 0) {
2847 * Always map nfsrv_defaultgid to "nogroup".
2849 if (gid == nfsrv_defaultgid) {
2850 i = nfsrv_dnsnamelen + 8;
2852 if (len > NFSV4_SMALLSTR)
2853 free(cp, M_NFSSTRING);
2854 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2860 NFSBCOPY("nogroup@", cp, 8);
2862 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2866 hp = NFSGROUPHASH(gid);
2868 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2869 if (usrp->lug_gid == gid) {
2870 if (usrp->lug_expiry < NFSD_MONOSEC)
2873 * If the name doesn't already have an '@'
2874 * in it, append @domainname to it.
2876 for (i = 0; i < usrp->lug_namelen; i++) {
2877 if (usrp->lug_name[i] == '@') {
2883 i = usrp->lug_namelen;
2885 i = usrp->lug_namelen +
2886 nfsrv_dnsnamelen + 1;
2888 mtx_unlock(&hp->mtx);
2889 if (len > NFSV4_SMALLSTR)
2890 free(cp, M_NFSSTRING);
2891 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2897 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2898 if (!hasampersand) {
2899 cp += usrp->lug_namelen;
2901 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2903 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2904 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2906 mtx_unlock(&hp->mtx);
2910 mtx_unlock(&hp->mtx);
2912 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2914 if (ret == 0 && cnt < 2)
2919 * No match, just return a string of digits.
2923 while (tmp || i == 0) {
2927 len = (i > len) ? len : i;
2931 for (i = 0; i < len; i++) {
2932 *cp-- = '0' + (tmp % 10);
2939 * Convert a string to a gid.
2940 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2942 * If this is called from a client side mount using AUTH_SYS and the
2943 * string is made up entirely of digits, just convert the string to
2947 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2951 char *cp, *endstr, *str0;
2952 struct nfsusrgrp *usrp;
2956 struct nfsrv_lughash *hp, *hp2;
2959 error = NFSERR_BADOWNER;
2962 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2964 tgid = (gid_t)strtoul(str0, &endstr, 10);
2965 if ((endstr - str0) == len) {
2966 /* A numeric string. */
2967 if ((nd->nd_flag & ND_KERBV) == 0 &&
2968 ((nd->nd_flag & ND_NFSCL) != 0 ||
2969 nfsd_enable_stringtouid != 0))
2972 error = NFSERR_BADOWNER;
2978 cp = strchr(str0, '@');
2980 i = (int)(cp++ - str0);
2986 if (nfsrv_dnsnamelen > 0) {
2988 * If an '@' is found and the dns name matches, search for the
2989 * name with the dns stripped off.
2991 if (cnt == 0 && i < len && i > 0 &&
2992 (len - 1 - i) == nfsrv_dnsnamelen &&
2993 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2994 len -= (nfsrv_dnsnamelen + 1);
2999 * Check for the special case of "nogroup".
3001 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3002 *gidp = nfsrv_defaultgid;
3007 hp = NFSGROUPNAMEHASH(str, len);
3009 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3010 if (usrp->lug_namelen == len &&
3011 !NFSBCMP(usrp->lug_name, str, len)) {
3012 if (usrp->lug_expiry < NFSD_MONOSEC)
3014 hp2 = NFSGROUPHASH(usrp->lug_gid);
3015 mtx_lock(&hp2->mtx);
3016 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3017 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3019 *gidp = usrp->lug_gid;
3020 mtx_unlock(&hp2->mtx);
3021 mtx_unlock(&hp->mtx);
3026 mtx_unlock(&hp->mtx);
3028 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3030 if (ret == 0 && cnt < 2)
3033 error = NFSERR_BADOWNER;
3041 * Cmp len chars, allowing mixed case in the first argument to match lower
3042 * case in the second, but not if the first argument is all upper case.
3043 * Return 0 for a match, 1 otherwise.
3046 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3052 for (i = 0; i < len; i++) {
3053 if (*cp >= 'A' && *cp <= 'Z') {
3054 tmp = *cp++ + ('a' - 'A');
3057 if (tmp >= 'a' && tmp <= 'z')
3070 * Set the port for the nfsuserd.
3073 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3075 struct nfssockreq *rp;
3076 struct sockaddr_in *ad;
3080 if (nfsrv_nfsuserd) {
3088 * Set up the socket record and connect.
3090 rp = &nfsrv_nfsuserdsock;
3091 rp->nr_client = NULL;
3092 rp->nr_sotype = SOCK_DGRAM;
3093 rp->nr_soproto = IPPROTO_UDP;
3094 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3096 NFSSOCKADDRALLOC(rp->nr_nam);
3097 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3098 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3099 ad->sin_family = AF_INET;
3100 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3101 ad->sin_port = port;
3102 rp->nr_prog = RPCPROG_NFSUSERD;
3103 rp->nr_vers = RPCNFSUSERD_VERS;
3104 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3106 NFSSOCKADDRFREE(rp->nr_nam);
3115 * Delete the nfsuserd port.
3118 nfsrv_nfsuserddelport(void)
3122 if (nfsrv_nfsuserd == 0) {
3128 newnfs_disconnect(&nfsrv_nfsuserdsock);
3129 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3133 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3135 * Returns 0 upon success, non-zero otherwise.
3138 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3141 struct nfsrv_descript *nd;
3143 struct nfsrv_descript nfsd;
3148 if (nfsrv_nfsuserd == 0) {
3155 cred = newnfs_getcred();
3156 nd->nd_flag = ND_GSSINITREPLY;
3159 nd->nd_procnum = procnum;
3160 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3162 if (procnum == RPCNFSUSERD_GETUID)
3163 *tl = txdr_unsigned(uid);
3165 *tl = txdr_unsigned(gid);
3168 (void) nfsm_strtom(nd, name, len);
3170 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3171 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3174 mbuf_freem(nd->nd_mrep);
3175 error = nd->nd_repstat;
3183 * This function is called from the nfssvc(2) system call, to update the
3184 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3187 nfssvc_idname(struct nfsd_idargs *nidp)
3189 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3190 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3191 int i, group_locked, groupname_locked, user_locked, username_locked;
3196 static int onethread = 0;
3197 static time_t lasttime = 0;
3199 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3203 if (nidp->nid_flag & NFSID_INITIALIZE) {
3204 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3205 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3208 free(cp, M_NFSSTRING);
3211 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3213 * Free up all the old stuff and reinitialize hash
3214 * lists. All mutexes for both lists must be locked,
3215 * with the user/group name ones before the uid/gid
3216 * ones, to avoid a LOR.
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 mtx_lock(&nfsusernamehash[i].mtx);
3220 for (i = 0; i < nfsrv_lughashsize; i++)
3221 mtx_lock(&nfsuserhash[i].mtx);
3222 for (i = 0; i < nfsrv_lughashsize; i++)
3223 TAILQ_FOREACH_SAFE(usrp,
3224 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3225 nfsrv_removeuser(usrp, 1);
3226 for (i = 0; i < nfsrv_lughashsize; i++)
3227 mtx_unlock(&nfsuserhash[i].mtx);
3228 for (i = 0; i < nfsrv_lughashsize; i++)
3229 mtx_unlock(&nfsusernamehash[i].mtx);
3230 for (i = 0; i < nfsrv_lughashsize; i++)
3231 mtx_lock(&nfsgroupnamehash[i].mtx);
3232 for (i = 0; i < nfsrv_lughashsize; i++)
3233 mtx_lock(&nfsgrouphash[i].mtx);
3234 for (i = 0; i < nfsrv_lughashsize; i++)
3235 TAILQ_FOREACH_SAFE(usrp,
3236 &nfsgrouphash[i].lughead, lug_numhash,
3238 nfsrv_removeuser(usrp, 0);
3239 for (i = 0; i < nfsrv_lughashsize; i++)
3240 mtx_unlock(&nfsgrouphash[i].mtx);
3241 for (i = 0; i < nfsrv_lughashsize; i++)
3242 mtx_unlock(&nfsgroupnamehash[i].mtx);
3243 free(nfsrv_dnsname, M_NFSSTRING);
3244 nfsrv_dnsname = NULL;
3246 if (nfsuserhash == NULL) {
3247 /* Allocate the hash tables. */
3248 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3249 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3251 for (i = 0; i < nfsrv_lughashsize; i++)
3252 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3253 NULL, MTX_DEF | MTX_DUPOK);
3254 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3255 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3257 for (i = 0; i < nfsrv_lughashsize; i++)
3258 mtx_init(&nfsusernamehash[i].mtx,
3259 "nfsusrhash", NULL, MTX_DEF |
3261 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3262 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3264 for (i = 0; i < nfsrv_lughashsize; i++)
3265 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3266 NULL, MTX_DEF | MTX_DUPOK);
3267 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3268 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3270 for (i = 0; i < nfsrv_lughashsize; i++)
3271 mtx_init(&nfsgroupnamehash[i].mtx,
3272 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3274 /* (Re)initialize the list heads. */
3275 for (i = 0; i < nfsrv_lughashsize; i++)
3276 TAILQ_INIT(&nfsuserhash[i].lughead);
3277 for (i = 0; i < nfsrv_lughashsize; i++)
3278 TAILQ_INIT(&nfsusernamehash[i].lughead);
3279 for (i = 0; i < nfsrv_lughashsize; i++)
3280 TAILQ_INIT(&nfsgrouphash[i].lughead);
3281 for (i = 0; i < nfsrv_lughashsize; i++)
3282 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3285 * Put name in "DNS" string.
3288 nfsrv_defaultuid = nidp->nid_uid;
3289 nfsrv_defaultgid = nidp->nid_gid;
3291 nfsrv_usermax = nidp->nid_usermax;
3292 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3297 * malloc the new one now, so any potential sleep occurs before
3298 * manipulation of the lists.
3300 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3301 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3302 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3304 if (error == 0 && nidp->nid_ngroup > 0 &&
3305 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3306 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3308 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3309 sizeof(gid_t) * nidp->nid_ngroup);
3312 * Create a credential just like svc_getcred(),
3313 * but using the group list provided.
3316 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3317 crsetgroups(cr, nidp->nid_ngroup, grps);
3318 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3319 cr->cr_prison = &prison0;
3320 prison_hold(cr->cr_prison);
3322 mac_cred_associate_nfsd(cr);
3324 newusrp->lug_cred = cr;
3329 free(newusrp, M_NFSUSERGROUP);
3332 newusrp->lug_namelen = nidp->nid_namelen;
3335 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3336 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3337 * The flags user_locked, username_locked, group_locked and
3338 * groupname_locked are set to indicate all of those hash lists are
3339 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3340 * the respective one mutex is locked.
3342 user_locked = username_locked = group_locked = groupname_locked = 0;
3343 hp_name = hp_idnum = NULL;
3346 * Delete old entries, as required.
3348 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3349 /* Must lock all username hash lists first, to avoid a LOR. */
3350 for (i = 0; i < nfsrv_lughashsize; i++)
3351 mtx_lock(&nfsusernamehash[i].mtx);
3352 username_locked = 1;
3353 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3354 mtx_lock(&hp_idnum->mtx);
3355 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3357 if (usrp->lug_uid == nidp->nid_uid)
3358 nfsrv_removeuser(usrp, 1);
3360 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3361 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3362 newusrp->lug_namelen);
3363 mtx_lock(&hp_name->mtx);
3364 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3366 if (usrp->lug_namelen == newusrp->lug_namelen &&
3367 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3368 usrp->lug_namelen)) {
3369 thp = NFSUSERHASH(usrp->lug_uid);
3370 mtx_lock(&thp->mtx);
3371 nfsrv_removeuser(usrp, 1);
3372 mtx_unlock(&thp->mtx);
3375 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3376 mtx_lock(&hp_idnum->mtx);
3377 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3378 /* Must lock all groupname hash lists first, to avoid a LOR. */
3379 for (i = 0; i < nfsrv_lughashsize; i++)
3380 mtx_lock(&nfsgroupnamehash[i].mtx);
3381 groupname_locked = 1;
3382 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3383 mtx_lock(&hp_idnum->mtx);
3384 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3386 if (usrp->lug_gid == nidp->nid_gid)
3387 nfsrv_removeuser(usrp, 0);
3389 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3390 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3391 newusrp->lug_namelen);
3392 mtx_lock(&hp_name->mtx);
3393 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3395 if (usrp->lug_namelen == newusrp->lug_namelen &&
3396 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3397 usrp->lug_namelen)) {
3398 thp = NFSGROUPHASH(usrp->lug_gid);
3399 mtx_lock(&thp->mtx);
3400 nfsrv_removeuser(usrp, 0);
3401 mtx_unlock(&thp->mtx);
3404 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3405 mtx_lock(&hp_idnum->mtx);
3409 * Now, we can add the new one.
3411 if (nidp->nid_usertimeout)
3412 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3414 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3415 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3416 newusrp->lug_uid = nidp->nid_uid;
3417 thp = NFSUSERHASH(newusrp->lug_uid);
3418 mtx_assert(&thp->mtx, MA_OWNED);
3419 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3420 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3421 mtx_assert(&thp->mtx, MA_OWNED);
3422 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3423 atomic_add_int(&nfsrv_usercnt, 1);
3424 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3425 newusrp->lug_gid = nidp->nid_gid;
3426 thp = NFSGROUPHASH(newusrp->lug_gid);
3427 mtx_assert(&thp->mtx, MA_OWNED);
3428 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3429 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3430 mtx_assert(&thp->mtx, MA_OWNED);
3431 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3432 atomic_add_int(&nfsrv_usercnt, 1);
3434 if (newusrp->lug_cred != NULL)
3435 crfree(newusrp->lug_cred);
3436 free(newusrp, M_NFSUSERGROUP);
3440 * Once per second, allow one thread to trim the cache.
3442 if (lasttime < NFSD_MONOSEC &&
3443 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3445 * First, unlock the single mutexes, so that all entries
3446 * can be locked and any LOR is avoided.
3448 if (hp_name != NULL) {
3449 mtx_unlock(&hp_name->mtx);
3452 if (hp_idnum != NULL) {
3453 mtx_unlock(&hp_idnum->mtx);
3457 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3458 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3459 if (username_locked == 0) {
3460 for (i = 0; i < nfsrv_lughashsize; i++)
3461 mtx_lock(&nfsusernamehash[i].mtx);
3462 username_locked = 1;
3464 KASSERT(user_locked == 0,
3465 ("nfssvc_idname: user_locked"));
3466 for (i = 0; i < nfsrv_lughashsize; i++)
3467 mtx_lock(&nfsuserhash[i].mtx);
3469 for (i = 0; i < nfsrv_lughashsize; i++) {
3470 TAILQ_FOREACH_SAFE(usrp,
3471 &nfsuserhash[i].lughead, lug_numhash,
3473 if (usrp->lug_expiry < NFSD_MONOSEC)
3474 nfsrv_removeuser(usrp, 1);
3476 for (i = 0; i < nfsrv_lughashsize; i++) {
3478 * Trim the cache using an approximate LRU
3479 * algorithm. This code deletes the least
3480 * recently used entry on each hash list.
3482 if (nfsrv_usercnt <= nfsrv_usermax)
3484 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3486 nfsrv_removeuser(usrp, 1);
3489 if (groupname_locked == 0) {
3490 for (i = 0; i < nfsrv_lughashsize; i++)
3491 mtx_lock(&nfsgroupnamehash[i].mtx);
3492 groupname_locked = 1;
3494 KASSERT(group_locked == 0,
3495 ("nfssvc_idname: group_locked"));
3496 for (i = 0; i < nfsrv_lughashsize; i++)
3497 mtx_lock(&nfsgrouphash[i].mtx);
3499 for (i = 0; i < nfsrv_lughashsize; i++) {
3500 TAILQ_FOREACH_SAFE(usrp,
3501 &nfsgrouphash[i].lughead, lug_numhash,
3503 if (usrp->lug_expiry < NFSD_MONOSEC)
3504 nfsrv_removeuser(usrp, 0);
3506 for (i = 0; i < nfsrv_lughashsize; i++) {
3508 * Trim the cache using an approximate LRU
3509 * algorithm. This code deletes the least
3510 * recently user entry on each hash list.
3512 if (nfsrv_usercnt <= nfsrv_usermax)
3514 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3516 nfsrv_removeuser(usrp, 0);
3519 lasttime = NFSD_MONOSEC;
3520 atomic_store_rel_int(&onethread, 0);
3523 /* Now, unlock all locked mutexes. */
3524 if (hp_idnum != NULL)
3525 mtx_unlock(&hp_idnum->mtx);
3526 if (hp_name != NULL)
3527 mtx_unlock(&hp_name->mtx);
3528 if (user_locked != 0)
3529 for (i = 0; i < nfsrv_lughashsize; i++)
3530 mtx_unlock(&nfsuserhash[i].mtx);
3531 if (username_locked != 0)
3532 for (i = 0; i < nfsrv_lughashsize; i++)
3533 mtx_unlock(&nfsusernamehash[i].mtx);
3534 if (group_locked != 0)
3535 for (i = 0; i < nfsrv_lughashsize; i++)
3536 mtx_unlock(&nfsgrouphash[i].mtx);
3537 if (groupname_locked != 0)
3538 for (i = 0; i < nfsrv_lughashsize; i++)
3539 mtx_unlock(&nfsgroupnamehash[i].mtx);
3546 * Remove a user/group name element.
3549 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3551 struct nfsrv_lughash *hp;
3554 hp = NFSUSERHASH(usrp->lug_uid);
3555 mtx_assert(&hp->mtx, MA_OWNED);
3556 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3557 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3558 mtx_assert(&hp->mtx, MA_OWNED);
3559 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3561 hp = NFSGROUPHASH(usrp->lug_gid);
3562 mtx_assert(&hp->mtx, MA_OWNED);
3563 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3564 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3565 mtx_assert(&hp->mtx, MA_OWNED);
3566 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3568 atomic_add_int(&nfsrv_usercnt, -1);
3569 if (usrp->lug_cred != NULL)
3570 crfree(usrp->lug_cred);
3571 free(usrp, M_NFSUSERGROUP);
3575 * Free up all the allocations related to the name<-->id cache.
3576 * This function should only be called when the nfsuserd daemon isn't
3577 * running, since it doesn't do any locking.
3578 * This function is meant to be used when the nfscommon module is unloaded.
3581 nfsrv_cleanusergroup(void)
3583 struct nfsrv_lughash *hp, *hp2;
3584 struct nfsusrgrp *nusrp, *usrp;
3587 if (nfsuserhash == NULL)
3590 for (i = 0; i < nfsrv_lughashsize; i++) {
3591 hp = &nfsuserhash[i];
3592 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3593 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3594 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3596 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3597 if (usrp->lug_cred != NULL)
3598 crfree(usrp->lug_cred);
3599 free(usrp, M_NFSUSERGROUP);
3601 hp = &nfsgrouphash[i];
3602 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3603 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3604 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3606 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3607 if (usrp->lug_cred != NULL)
3608 crfree(usrp->lug_cred);
3609 free(usrp, M_NFSUSERGROUP);
3611 mtx_destroy(&nfsuserhash[i].mtx);
3612 mtx_destroy(&nfsusernamehash[i].mtx);
3613 mtx_destroy(&nfsgroupnamehash[i].mtx);
3614 mtx_destroy(&nfsgrouphash[i].mtx);
3616 free(nfsuserhash, M_NFSUSERGROUP);
3617 free(nfsusernamehash, M_NFSUSERGROUP);
3618 free(nfsgrouphash, M_NFSUSERGROUP);
3619 free(nfsgroupnamehash, M_NFSUSERGROUP);
3620 free(nfsrv_dnsname, M_NFSSTRING);
3624 * This function scans a byte string and checks for UTF-8 compliance.
3625 * It returns 0 if it conforms and NFSERR_INVAL if not.
3628 nfsrv_checkutf8(u_int8_t *cp, int len)
3630 u_int32_t val = 0x0;
3631 int cnt = 0, gotd = 0, shift = 0;
3633 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3637 * Here are what the variables are used for:
3638 * val - the calculated value of a multibyte char, used to check
3639 * that it was coded with the correct range
3640 * cnt - the number of 10xxxxxx bytes to follow
3641 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3642 * shift - lower order bits of range (ie. "val >> shift" should
3643 * not be 0, in other words, dividing by the lower bound
3644 * of the range should get a non-zero value)
3645 * byte - used to calculate cnt
3649 /* This handles the 10xxxxxx bytes */
3650 if ((*cp & 0xc0) != 0x80 ||
3651 (gotd && (*cp & 0x20))) {
3652 error = NFSERR_INVAL;
3657 val |= (*cp & 0x3f);
3659 if (cnt == 0 && (val >> shift) == 0x0) {
3660 error = NFSERR_INVAL;
3663 } else if (*cp & 0x80) {
3664 /* first byte of multi byte char */
3666 while ((byte & 0x40) && cnt < 6) {
3670 if (cnt == 0 || cnt == 6) {
3671 error = NFSERR_INVAL;
3674 val = (*cp & (0x3f >> cnt));
3675 shift = utf8_shift[cnt - 1];
3676 if (cnt == 2 && val == 0xd)
3677 /* Check for the 0xd800-0xdfff case */
3684 error = NFSERR_INVAL;
3692 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3693 * strings, one with the root path in it and the other with the list of
3694 * locations. The list is in the same format as is found in nfr_refs.
3695 * It is a "," separated list of entries, where each of them is of the
3696 * form <server>:<rootpath>. For example
3697 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3698 * The nilp argument is set to 1 for the special case of a null fs_root
3699 * and an empty server list.
3700 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3701 * number of xdr bytes parsed in sump.
3704 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3705 int *sump, int *nilp)
3708 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3709 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3711 SLIST_ENTRY(list) next;
3715 SLIST_HEAD(, list) head;
3722 * Get the fs_root path and check for the special case of null path
3723 * and 0 length server list.
3725 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3726 len = fxdr_unsigned(int, *tl);
3727 if (len < 0 || len > 10240) {
3728 error = NFSERR_BADXDR;
3732 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3734 error = NFSERR_BADXDR;
3738 *sump = 2 * NFSX_UNSIGNED;
3742 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3743 error = nfsrv_mtostr(nd, cp, len);
3745 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3746 cnt = fxdr_unsigned(int, *tl);
3748 error = NFSERR_BADXDR;
3754 * Now, loop through the location list and make up the srvlist.
3756 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3757 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3760 for (i = 0; i < cnt; i++) {
3762 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3763 nsrv = fxdr_unsigned(int, *tl);
3765 error = NFSERR_BADXDR;
3770 * Handle the first server by putting it in the srvstr.
3772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3773 len = fxdr_unsigned(int, *tl);
3774 if (len <= 0 || len > 1024) {
3775 error = NFSERR_BADXDR;
3778 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3783 error = nfsrv_mtostr(nd, cp3, len);
3789 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3790 for (j = 1; j < nsrv; j++) {
3792 * Yuck, put them in an slist and process them later.
3794 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3795 len = fxdr_unsigned(int, *tl);
3796 if (len <= 0 || len > 1024) {
3797 error = NFSERR_BADXDR;
3800 lsp = (struct list *)malloc(sizeof (struct list)
3801 + len, M_TEMP, M_WAITOK);
3802 error = nfsrv_mtostr(nd, lsp->host, len);
3805 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3807 SLIST_INSERT_HEAD(&head, lsp, next);
3811 * Finally, we can get the path.
3813 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3814 len = fxdr_unsigned(int, *tl);
3815 if (len <= 0 || len > 1024) {
3816 error = NFSERR_BADXDR;
3819 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3820 error = nfsrv_mtostr(nd, cp3, len);
3823 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3828 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3829 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3832 NFSBCOPY(lsp->host, cp3, lsp->len);
3835 NFSBCOPY(str, cp3, stringlen);
3838 siz += (lsp->len + stringlen + 2);
3839 free((caddr_t)lsp, M_TEMP);
3845 NFSEXITCODE2(0, nd);
3849 free(cp, M_NFSSTRING);
3851 free(cp2, M_NFSSTRING);
3852 NFSEXITCODE2(error, nd);
3857 * Make the malloc'd space large enough. This is a pain, but the xdr
3858 * doesn't set an upper bound on the side, so...
3861 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3868 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3869 NFSBCOPY(*cpp, cp, *slenp);
3870 free(*cpp, M_NFSSTRING);
3874 *slenp = siz + 1024;
3878 * Initialize the reply header data structures.
3881 nfsrvd_rephead(struct nfsrv_descript *nd)
3886 * If this is a big reply, use a cluster.
3888 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3889 nfs_bigreply[nd->nd_procnum]) {
3890 NFSMCLGET(mreq, M_WAITOK);
3898 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3899 mbuf_setlen(mreq, 0);
3901 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3902 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3906 * Lock a socket against others.
3907 * Currently used to serialize connect/disconnect attempts.
3910 newnfs_sndlock(int *flagp)
3915 while (*flagp & NFSR_SNDLOCK) {
3916 *flagp |= NFSR_WANTSND;
3919 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3920 PZERO - 1, "nfsndlck", &ts);
3922 *flagp |= NFSR_SNDLOCK;
3928 * Unlock the stream socket for others.
3931 newnfs_sndunlock(int *flagp)
3935 if ((*flagp & NFSR_SNDLOCK) == 0)
3936 panic("nfs sndunlock");
3937 *flagp &= ~NFSR_SNDLOCK;
3938 if (*flagp & NFSR_WANTSND) {
3939 *flagp &= ~NFSR_WANTSND;
3940 wakeup((caddr_t)flagp);
3946 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3949 struct sockaddr_in *sad;
3950 struct sockaddr_in6 *sad6;
3951 struct in_addr saddr;
3952 uint32_t portnum, *tl;
3953 int af = 0, i, j, k;
3954 char addr[64], protocol[5], *cp;
3955 int cantparse = 0, error = 0;
3958 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3959 i = fxdr_unsigned(int, *tl);
3960 if (i >= 3 && i <= 4) {
3961 error = nfsrv_mtostr(nd, protocol, i);
3964 if (strcmp(protocol, "tcp") == 0) {
3967 } else if (strcmp(protocol, "udp") == 0) {
3970 } else if (strcmp(protocol, "tcp6") == 0) {
3973 } else if (strcmp(protocol, "udp6") == 0) {
3981 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3986 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3987 i = fxdr_unsigned(int, *tl);
3989 error = NFSERR_BADXDR;
3991 } else if (cantparse == 0 && i >= 11 && i < 64) {
3993 * The shortest address is 11chars and the longest is < 64.
3995 error = nfsrv_mtostr(nd, addr, i);
3999 /* Find the port# at the end and extract that. */
4003 /* Count back two '.'s from end to get port# field. */
4004 for (j = 0; j < i; j++) {
4014 * The NFSv4 port# is appended as .N.N, where N is
4015 * a decimal # in the range 0-255, just like an inet4
4016 * address. Cheat and use inet_aton(), which will
4017 * return a Class A address and then shift the high
4018 * order 8bits over to convert it to the port#.
4021 if (inet_aton(cp, &saddr) == 1) {
4022 portnum = ntohl(saddr.s_addr);
4023 portv = (uint16_t)((portnum >> 16) |
4029 if (cantparse == 0) {
4030 if (af == AF_INET) {
4031 sad = (struct sockaddr_in *)sa;
4032 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4033 sad->sin_len = sizeof(*sad);
4034 sad->sin_family = AF_INET;
4035 sad->sin_port = htons(portv);
4039 sad6 = (struct sockaddr_in6 *)sa;
4040 if (inet_pton(af, addr, &sad6->sin6_addr)
4042 sad6->sin6_len = sizeof(*sad6);
4043 sad6->sin6_family = AF_INET6;
4044 sad6->sin6_port = htons(portv);
4051 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4062 * Handle an NFSv4.1 Sequence request for the session.
4063 * If reply != NULL, use it to return the cached reply, as required.
4064 * The client gets a cached reply via this call for callbacks, however the
4065 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4068 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4069 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4076 if (slotid > maxslot)
4077 return (NFSERR_BADSLOT);
4078 if (seqid == slots[slotid].nfssl_seq) {
4080 if (slots[slotid].nfssl_inprog != 0)
4081 error = NFSERR_DELAY;
4082 else if (slots[slotid].nfssl_reply != NULL) {
4083 if (reply != NULL) {
4084 *reply = slots[slotid].nfssl_reply;
4085 slots[slotid].nfssl_reply = NULL;
4087 slots[slotid].nfssl_inprog = 1;
4088 error = NFSERR_REPLYFROMCACHE;
4090 /* No reply cached, so just do it. */
4091 slots[slotid].nfssl_inprog = 1;
4092 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4093 if (slots[slotid].nfssl_reply != NULL)
4094 m_freem(slots[slotid].nfssl_reply);
4095 slots[slotid].nfssl_reply = NULL;
4096 slots[slotid].nfssl_inprog = 1;
4097 slots[slotid].nfssl_seq++;
4099 error = NFSERR_SEQMISORDERED;
4104 * Cache this reply for the slot.
4105 * Use the "rep" argument to return the cached reply if repstat is set to
4106 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4109 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4113 if (repstat == NFSERR_REPLYFROMCACHE) {
4114 *rep = slots[slotid].nfssl_reply;
4115 slots[slotid].nfssl_reply = NULL;
4117 if (slots[slotid].nfssl_reply != NULL)
4118 m_freem(slots[slotid].nfssl_reply);
4119 slots[slotid].nfssl_reply = *rep;
4121 slots[slotid].nfssl_inprog = 0;
4125 * Generate the xdr for an NFSv4.1 Sequence Operation.
4128 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4129 struct nfsclsession *sep, int dont_replycache)
4131 uint32_t *tl, slotseq = 0;
4132 int error, maxslot, slotpos;
4133 uint8_t sessionid[NFSX_V4SESSIONID];
4135 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4138 /* Build the Sequence arguments. */
4139 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4140 nd->nd_sequence = tl;
4141 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4142 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4143 nd->nd_slotseq = tl;
4145 *tl++ = txdr_unsigned(slotseq);
4146 *tl++ = txdr_unsigned(slotpos);
4147 *tl++ = txdr_unsigned(maxslot);
4148 if (dont_replycache == 0)
4154 * There are two errors and the rest of the session can
4156 * NFSERR_BADSESSION: This bad session should just generate
4157 * the same error again when the RPC is retried.
4158 * ESTALE: A forced dismount is in progress and will cause the
4159 * RPC to fail later.
4166 nd->nd_flag |= ND_HASSEQUENCE;
4170 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4171 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4173 int i, maxslot, slotpos;
4176 /* Find an unused slot. */
4179 mtx_lock(&sep->nfsess_mtx);
4181 if (nmp != NULL && sep->nfsess_defunct != 0) {
4182 /* Just return the bad session. */
4183 bcopy(sep->nfsess_sessionid, sessionid,
4185 mtx_unlock(&sep->nfsess_mtx);
4186 return (NFSERR_BADSESSION);
4189 for (i = 0; i < sep->nfsess_foreslots; i++) {
4190 if ((bitval & sep->nfsess_slots) == 0) {
4192 sep->nfsess_slots |= bitval;
4193 sep->nfsess_slotseq[i]++;
4194 *slotseqp = sep->nfsess_slotseq[i];
4199 if (slotpos == -1) {
4201 * If a forced dismount is in progress, just return.
4202 * This RPC attempt will fail when it calls
4206 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4208 mtx_unlock(&sep->nfsess_mtx);
4211 /* Wake up once/sec, to check for a forced dismount. */
4212 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4213 PZERO, "nfsclseq", hz);
4215 } while (slotpos == -1);
4216 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4218 for (i = 0; i < 64; i++) {
4219 if ((bitval & sep->nfsess_slots) != 0)
4223 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4224 mtx_unlock(&sep->nfsess_mtx);
4225 *slotposp = slotpos;
4226 *maxslotp = maxslot;
4231 * Free a session slot.
4234 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4241 mtx_lock(&sep->nfsess_mtx);
4242 if ((bitval & sep->nfsess_slots) == 0)
4243 printf("freeing free slot!!\n");
4244 sep->nfsess_slots &= ~bitval;
4245 wakeup(&sep->nfsess_slots);
4246 mtx_unlock(&sep->nfsess_mtx);