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>
48 * Data items converted to xdr at startup, since they are constant
49 * This is kinda hokey, but may save a little time doing byte swaps
51 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
53 /* And other global data */
54 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
56 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
57 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
58 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
61 struct nfssockreq nfsrv_nfsuserdsock;
62 int nfsrv_nfsuserd = 0;
63 struct nfsreqhead nfsd_reqq;
64 uid_t nfsrv_defaultuid;
65 gid_t nfsrv_defaultgid;
66 int nfsrv_lease = NFSRV_LEASE;
67 int ncl_mbuf_mlen = MLEN;
72 * This array of structures indicates, for V4:
73 * retfh - which of 3 types of calling args are used
74 * 0 - doesn't change cfh or use a sfh
75 * 1 - replaces cfh with a new one (unless it returns an error status)
76 * 2 - uses cfh and sfh
77 * needscfh - if the op wants a cfh and premtime
78 * 0 - doesn't use a cfh
79 * 1 - uses a cfh, but doesn't want pre-op attributes
80 * 2 - uses a cfh and wants pre-op attributes
81 * savereply - indicates a non-idempotent Op
82 * 0 - not non-idempotent
84 * Ops that are ordered via seqid# are handled separately from these
86 * Define it here, since it is used by both the client and server.
88 struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
89 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
90 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
91 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
92 { 0, 1, 0, 0, LK_SHARED }, /* Access */
93 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Close */
94 { 0, 2, 0, 1, LK_EXCLUSIVE }, /* Commit */
95 { 1, 2, 1, 1, LK_EXCLUSIVE }, /* Create */
96 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Delegpurge */
97 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Delegreturn */
98 { 0, 1, 0, 0, LK_SHARED }, /* Getattr */
99 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* GetFH */
100 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Link */
101 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Lock */
102 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockT */
103 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockU */
104 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* Lookup */
105 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* Lookupp */
106 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* NVerify */
107 { 1, 1, 0, 1, LK_EXCLUSIVE }, /* Open */
108 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* OpenAttr */
109 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenConfirm */
110 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenDowngrade */
111 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutFH */
112 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutPubFH */
113 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutRootFH */
114 { 0, 1, 0, 0, LK_SHARED }, /* Read */
115 { 0, 1, 0, 0, LK_SHARED }, /* Readdir */
116 { 0, 1, 0, 0, LK_SHARED }, /* ReadLink */
117 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Remove */
118 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Rename */
119 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Renew */
120 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* RestoreFH */
121 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SaveFH */
122 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SecInfo */
123 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Setattr */
124 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientID */
125 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientIDConfirm */
126 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Verify */
127 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Write */
128 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* ReleaseLockOwner */
130 #endif /* !APPLEKEXT */
132 static int ncl_mbuf_mhlen = MHLEN;
133 static int nfsrv_usercnt = 0;
134 static int nfsrv_dnsnamelen;
135 static u_char *nfsrv_dnsname = NULL;
136 static int nfsrv_usermax = 999999999;
137 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
138 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
139 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
140 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
141 static struct nfsuserlruhead nfsuserlruhead;
144 * This static array indicates whether or not the RPC generates a large
145 * reply. This is used by nfs_reply() to decide whether or not an mbuf
146 * cluster should be allocated. (If a cluster is required by an RPC
147 * marked 0 in this array, the code will still work, just not quite as
150 static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
151 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,
154 /* local functions */
155 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
156 static void nfsv4_wanted(struct nfsv4lock *lp);
157 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
158 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
160 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
161 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
163 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
168 * copies mbuf chain to the uio scatter/gather list
171 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
173 char *mbufcp, *uiocp;
180 mbufcp = nd->nd_dpos;
181 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
182 rem = NFSM_RNDUP(siz) - siz;
184 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
188 left = uiop->uio_iov->iov_len;
189 uiocp = uiop->uio_iov->iov_base;
200 mbufcp = NFSMTOD(mp, caddr_t);
202 KASSERT(len > 0, ("len %d", len));
204 xfer = (left > len) ? len : left;
207 if (uiop->uio_iov->iov_op != NULL)
208 (*(uiop->uio_iov->iov_op))
209 (mbufcp, uiocp, xfer);
212 if (uiop->uio_segflg == UIO_SYSSPACE)
213 NFSBCOPY(mbufcp, uiocp, xfer);
215 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
220 uiop->uio_offset += xfer;
221 uiop->uio_resid -= xfer;
223 if (uiop->uio_iov->iov_len <= siz) {
227 uiop->uio_iov->iov_base = (void *)
228 ((char *)uiop->uio_iov->iov_base + uiosiz);
229 uiop->uio_iov->iov_len -= uiosiz;
233 nd->nd_dpos = mbufcp;
237 error = nfsm_advance(nd, rem, len);
243 NFSEXITCODE2(error, nd);
249 * Help break down an mbuf chain by setting the first siz bytes contiguous
250 * pointed to by returned val.
251 * This is used by the macro NFSM_DISSECT for tough
255 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
264 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
266 nd->nd_md = mbuf_next(nd->nd_md);
267 if (nd->nd_md == NULL)
269 left = mbuf_len(nd->nd_md);
270 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
275 } else if (mbuf_next(nd->nd_md) == NULL) {
277 } else if (siz > ncl_mbuf_mhlen) {
278 panic("nfs S too big");
280 MGET(mp2, MT_DATA, how);
283 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
284 mbuf_setnext(nd->nd_md, mp2);
285 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
287 retp = p = NFSMTOD(mp2, caddr_t);
288 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
291 mp2 = mbuf_next(mp2);
292 /* Loop around copying up the siz2 bytes */
296 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
298 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
299 NFSM_DATAP(mp2, xfer);
300 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
305 mp2 = mbuf_next(mp2);
307 mbuf_setlen(nd->nd_md, siz);
309 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
315 * Advance the position in the mbuf chain.
316 * If offs == 0, this is a no-op, but it is simpler to just return from
317 * here than check for offs > 0 for all calls to nfsm_advance.
318 * If left == -1, it should be calculated here.
321 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
328 * A negative offs should be considered a serious problem.
331 panic("nfsrv_advance");
334 * If left == -1, calculate it here.
337 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
341 * Loop around, advancing over the mbuf data.
343 while (offs > left) {
345 nd->nd_md = mbuf_next(nd->nd_md);
346 if (nd->nd_md == NULL) {
350 left = mbuf_len(nd->nd_md);
351 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
361 * Copy a string into mbuf(s).
362 * Return the number of bytes output, including XDR overheads.
365 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
374 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
375 *tl = txdr_unsigned(siz);
376 rem = NFSM_RNDUP(siz) - siz;
377 bytesize = NFSX_UNSIGNED + siz + rem;
380 left = M_TRAILINGSPACE(m2);
383 * Loop around copying the string to mbuf(s).
387 if (siz > ncl_mbuf_mlen)
388 NFSMCLGET(m1, M_WAIT);
392 mbuf_setnext(m2, m1);
394 cp2 = NFSMTOD(m2, caddr_t);
395 left = M_TRAILINGSPACE(m2);
401 NFSBCOPY(cp, cp2, xfer);
403 mbuf_setlen(m2, mbuf_len(m2) + xfer);
406 if (siz == 0 && rem) {
408 panic("nfsm_strtom");
409 NFSBZERO(cp2 + xfer, rem);
410 mbuf_setlen(m2, mbuf_len(m2) + rem);
414 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
419 * Called once to initialize data structures...
424 static int nfs_inited = 0;
430 newnfs_true = txdr_unsigned(TRUE);
431 newnfs_false = txdr_unsigned(FALSE);
432 newnfs_xdrneg1 = txdr_unsigned(-1);
433 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
436 NFSSETBOOTTIME(nfsboottime);
439 * Initialize reply list and start timer
441 TAILQ_INIT(&nfsd_reqq);
446 * Put a file handle in an mbuf list.
447 * If the size argument == 0, just use the default size.
448 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
449 * Return the number of bytes output, including XDR overhead.
452 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
456 int fullsiz, rem, bytesize = 0;
460 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
462 if (size > NFSX_V2FH)
463 panic("fh size > NFSX_V2FH for NFSv2");
464 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
465 NFSBCOPY(fhp, cp, size);
466 if (size < NFSX_V2FH)
467 NFSBZERO(cp + size, NFSX_V2FH - size);
468 bytesize = NFSX_V2FH;
472 fullsiz = NFSM_RNDUP(size);
473 rem = fullsiz - size;
475 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
476 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
479 bytesize = NFSX_UNSIGNED + fullsiz;
481 (void) nfsm_strtom(nd, fhp, size);
488 * This function compares two net addresses by family and returns TRUE
489 * if they are the same host.
490 * If there is any doubt, return FALSE.
491 * The AF_INET family is handled as a special case so that address mbufs
492 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
495 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
497 struct sockaddr_in *inetaddr;
501 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
502 if (inetaddr->sin_family == AF_INET &&
503 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
509 struct sockaddr_in6 *inetaddr6;
511 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
512 /* XXX - should test sin6_scope_id ? */
513 if (inetaddr6->sin6_family == AF_INET6 &&
514 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
525 * Similar to the above, but takes to NFSSOCKADDR_T args.
528 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
530 struct sockaddr_in *addr1, *addr2;
531 struct sockaddr *inaddr;
533 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
534 switch (inaddr->sa_family) {
536 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
537 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
538 if (addr2->sin_family == AF_INET &&
539 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
545 struct sockaddr_in6 *inet6addr1, *inet6addr2;
547 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
548 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
549 /* XXX - should test sin6_scope_id ? */
550 if (inet6addr2->sin6_family == AF_INET6 &&
551 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
552 &inet6addr2->sin6_addr))
563 * Trim the stuff already dissected off the mbuf list.
566 newnfs_trimleading(nd)
567 struct nfsrv_descript *nd;
573 * First, free up leading mbufs.
575 if (nd->nd_mrep != nd->nd_md) {
577 while (mbuf_next(m) != nd->nd_md) {
578 if (mbuf_next(m) == NULL)
579 panic("nfsm trim leading");
582 mbuf_setnext(m, NULL);
583 mbuf_freem(nd->nd_mrep);
588 * Now, adjust this mbuf, based on nd_dpos.
590 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
591 if (offs == mbuf_len(m)) {
595 panic("nfsm trim leading2");
596 mbuf_setnext(n, NULL);
598 } else if (offs > 0) {
599 mbuf_setlen(m, mbuf_len(m) - offs);
602 panic("nfsm trimleading offs");
605 nd->nd_dpos = NFSMTOD(m, caddr_t);
609 * Trim trailing data off the mbuf list being built.
612 newnfs_trimtrailing(nd, mb, bpos)
613 struct nfsrv_descript *nd;
619 mbuf_freem(mbuf_next(mb));
620 mbuf_setnext(mb, NULL);
622 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
628 * Dissect a file handle on the client.
631 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
638 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
639 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
640 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
647 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
649 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
651 FREE((caddr_t)nfhp, M_NFSFH);
657 NFSEXITCODE2(error, nd);
662 * Break down the nfsv4 acl.
663 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
666 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
667 int *aclsizep, __unused NFSPROC_T *p)
671 int acecnt, error = 0, aceerr = 0, acesize;
677 * Parse out the ace entries and expect them to conform to
678 * what can be supported by R/W/X bits.
680 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
681 aclsize = NFSX_UNSIGNED;
682 acecnt = fxdr_unsigned(int, *tl);
683 if (acecnt > ACL_MAX_ENTRIES)
684 aceerr = NFSERR_ATTRNOTSUPP;
685 if (nfsrv_useacl == 0)
686 aceerr = NFSERR_ATTRNOTSUPP;
687 for (i = 0; i < acecnt; i++) {
689 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
690 &aceerr, &acesize, p);
692 error = nfsrv_skipace(nd, &acesize);
698 aclp->acl_cnt = acecnt;
704 NFSEXITCODE2(error, nd);
709 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
712 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
717 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
718 len = fxdr_unsigned(int, *(tl + 3));
719 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
721 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
722 NFSEXITCODE2(error, nd);
727 * Get attribute bits from an mbuf list.
728 * Returns EBADRPC for a parsing error, 0 otherwise.
729 * If the clearinvalid flag is set, clear the bits not supported.
732 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
739 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
740 cnt = fxdr_unsigned(int, *tl);
742 error = NFSERR_BADXDR;
745 if (cnt > NFSATTRBIT_MAXWORDS)
746 outcnt = NFSATTRBIT_MAXWORDS;
749 NFSZERO_ATTRBIT(attrbitp);
751 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
752 for (i = 0; i < outcnt; i++)
753 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
755 for (i = 0; i < (cnt - outcnt); i++) {
756 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
757 if (retnotsupp != NULL && *tl != 0)
758 *retnotsupp = NFSERR_ATTRNOTSUPP;
761 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
763 NFSEXITCODE2(error, nd);
768 * Get the attributes for V4.
769 * If the compare flag is true, test for any attribute changes,
770 * otherwise return the attribute values.
771 * These attributes cover fields in "struct vattr", "struct statfs",
772 * "struct nfsfsinfo", the file handle and the lease duration.
773 * The value of retcmpp is set to 1 if all attributes are the same,
775 * Returns EBADRPC if it can't be parsed, 0 otherwise.
778 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
779 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
780 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
781 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
782 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
785 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
786 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
787 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
788 nfsattrbit_t attrbits, retattrbits, checkattrbits;
790 struct nfsreferral *refp;
793 struct timespec temptime;
797 u_int32_t freenum = 0, tuint;
798 u_int64_t uquad = 0, thyp, thyp2;
806 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
808 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
814 *retcmpp = retnotsup;
817 * Just set default values to some of the important ones.
822 nap->na_rdev = (NFSDEV_T)0;
823 nap->na_mtime.tv_sec = 0;
824 nap->na_mtime.tv_nsec = 0;
827 nap->na_blocksize = NFS_FABLKSIZE;
830 sbp->f_bsize = NFS_FABLKSIZE;
838 fsp->fs_rtmax = 8192;
839 fsp->fs_rtpref = 8192;
840 fsp->fs_maxname = NFS_MAXNAMLEN;
841 fsp->fs_wtmax = 8192;
842 fsp->fs_wtpref = 8192;
843 fsp->fs_wtmult = NFS_FABLKSIZE;
844 fsp->fs_dtpref = 8192;
845 fsp->fs_maxfilesize = 0xffffffffffffffffull;
846 fsp->fs_timedelta.tv_sec = 0;
847 fsp->fs_timedelta.tv_nsec = 1;
848 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
849 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
852 pc->pc_linkmax = LINK_MAX;
853 pc->pc_namemax = NAME_MAX;
855 pc->pc_chownrestricted = 0;
856 pc->pc_caseinsensitive = 0;
857 pc->pc_casepreserving = 1;
862 * Loop around getting the attributes.
864 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
865 attrsize = fxdr_unsigned(int, *tl);
866 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
867 if (attrsum > attrsize) {
868 error = NFSERR_BADXDR;
871 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
873 case NFSATTRBIT_SUPPORTEDATTRS:
875 if (compare || nap == NULL)
876 error = nfsrv_getattrbits(nd, &retattrbits,
879 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
883 if (compare && !(*retcmpp)) {
884 NFSSETSUPP_ATTRBIT(&checkattrbits);
885 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
887 *retcmpp = NFSERR_NOTSAME;
891 case NFSATTRBIT_TYPE:
892 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
895 if (nap->na_type != nfsv34tov_type(*tl))
896 *retcmpp = NFSERR_NOTSAME;
898 } else if (nap != NULL) {
899 nap->na_type = nfsv34tov_type(*tl);
901 attrsum += NFSX_UNSIGNED;
903 case NFSATTRBIT_FHEXPIRETYPE:
904 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
905 if (compare && !(*retcmpp)) {
906 if (fxdr_unsigned(int, *tl) !=
907 NFSV4FHTYPE_PERSISTENT)
908 *retcmpp = NFSERR_NOTSAME;
910 attrsum += NFSX_UNSIGNED;
912 case NFSATTRBIT_CHANGE:
913 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
916 if (nap->na_filerev != fxdr_hyper(tl))
917 *retcmpp = NFSERR_NOTSAME;
919 } else if (nap != NULL) {
920 nap->na_filerev = fxdr_hyper(tl);
922 attrsum += NFSX_HYPER;
924 case NFSATTRBIT_SIZE:
925 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
928 if (nap->na_size != fxdr_hyper(tl))
929 *retcmpp = NFSERR_NOTSAME;
931 } else if (nap != NULL) {
932 nap->na_size = fxdr_hyper(tl);
934 attrsum += NFSX_HYPER;
936 case NFSATTRBIT_LINKSUPPORT:
937 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
940 if (fsp->fs_properties & NFSV3_FSFLINK) {
941 if (*tl == newnfs_false)
942 *retcmpp = NFSERR_NOTSAME;
944 if (*tl == newnfs_true)
945 *retcmpp = NFSERR_NOTSAME;
948 } else if (fsp != NULL) {
949 if (*tl == newnfs_true)
950 fsp->fs_properties |= NFSV3_FSFLINK;
952 fsp->fs_properties &= ~NFSV3_FSFLINK;
954 attrsum += NFSX_UNSIGNED;
956 case NFSATTRBIT_SYMLINKSUPPORT:
957 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
961 if (*tl == newnfs_false)
962 *retcmpp = NFSERR_NOTSAME;
964 if (*tl == newnfs_true)
965 *retcmpp = NFSERR_NOTSAME;
968 } else if (fsp != NULL) {
969 if (*tl == newnfs_true)
970 fsp->fs_properties |= NFSV3_FSFSYMLINK;
972 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
974 attrsum += NFSX_UNSIGNED;
976 case NFSATTRBIT_NAMEDATTR:
977 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
978 if (compare && !(*retcmpp)) {
979 if (*tl != newnfs_false)
980 *retcmpp = NFSERR_NOTSAME;
982 attrsum += NFSX_UNSIGNED;
984 case NFSATTRBIT_FSID:
985 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
986 thyp = fxdr_hyper(tl);
988 thyp2 = fxdr_hyper(tl);
991 if (thyp != (u_int64_t)
992 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
994 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
995 *retcmpp = NFSERR_NOTSAME;
997 } else if (nap != NULL) {
998 nap->na_filesid[0] = thyp;
999 nap->na_filesid[1] = thyp2;
1001 attrsum += (4 * NFSX_UNSIGNED);
1003 case NFSATTRBIT_UNIQUEHANDLES:
1004 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1005 if (compare && !(*retcmpp)) {
1006 if (*tl != newnfs_true)
1007 *retcmpp = NFSERR_NOTSAME;
1009 attrsum += NFSX_UNSIGNED;
1011 case NFSATTRBIT_LEASETIME:
1012 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1014 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1016 *retcmpp = NFSERR_NOTSAME;
1017 } else if (leasep != NULL) {
1018 *leasep = fxdr_unsigned(u_int32_t, *tl);
1020 attrsum += NFSX_UNSIGNED;
1022 case NFSATTRBIT_RDATTRERROR:
1023 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1026 *retcmpp = NFSERR_INVAL;
1027 } else if (rderrp != NULL) {
1028 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1030 attrsum += NFSX_UNSIGNED;
1032 case NFSATTRBIT_ACL:
1038 naclp = acl_alloc(M_WAITOK);
1039 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1045 if (aceerr || aclp == NULL ||
1046 nfsrv_compareacl(aclp, naclp))
1047 *retcmpp = NFSERR_NOTSAME;
1050 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1052 *retcmpp = NFSERR_ATTRNOTSUPP;
1056 if (vp != NULL && aclp != NULL)
1057 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1060 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1067 case NFSATTRBIT_ACLSUPPORT:
1068 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1069 if (compare && !(*retcmpp)) {
1071 if (fxdr_unsigned(u_int32_t, *tl) !=
1073 *retcmpp = NFSERR_NOTSAME;
1075 *retcmpp = NFSERR_ATTRNOTSUPP;
1078 attrsum += NFSX_UNSIGNED;
1080 case NFSATTRBIT_ARCHIVE:
1081 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1082 if (compare && !(*retcmpp))
1083 *retcmpp = NFSERR_ATTRNOTSUPP;
1084 attrsum += NFSX_UNSIGNED;
1086 case NFSATTRBIT_CANSETTIME:
1087 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1090 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1091 if (*tl == newnfs_false)
1092 *retcmpp = NFSERR_NOTSAME;
1094 if (*tl == newnfs_true)
1095 *retcmpp = NFSERR_NOTSAME;
1098 } else if (fsp != NULL) {
1099 if (*tl == newnfs_true)
1100 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1102 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1104 attrsum += NFSX_UNSIGNED;
1106 case NFSATTRBIT_CASEINSENSITIVE:
1107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1110 if (*tl != newnfs_false)
1111 *retcmpp = NFSERR_NOTSAME;
1113 } else if (pc != NULL) {
1114 pc->pc_caseinsensitive =
1115 fxdr_unsigned(u_int32_t, *tl);
1117 attrsum += NFSX_UNSIGNED;
1119 case NFSATTRBIT_CASEPRESERVING:
1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1123 if (*tl != newnfs_true)
1124 *retcmpp = NFSERR_NOTSAME;
1126 } else if (pc != NULL) {
1127 pc->pc_casepreserving =
1128 fxdr_unsigned(u_int32_t, *tl);
1130 attrsum += NFSX_UNSIGNED;
1132 case NFSATTRBIT_CHOWNRESTRICTED:
1133 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1136 if (*tl != newnfs_true)
1137 *retcmpp = NFSERR_NOTSAME;
1139 } else if (pc != NULL) {
1140 pc->pc_chownrestricted =
1141 fxdr_unsigned(u_int32_t, *tl);
1143 attrsum += NFSX_UNSIGNED;
1145 case NFSATTRBIT_FILEHANDLE:
1146 error = nfsm_getfh(nd, &tnfhp);
1149 tfhsize = tnfhp->nfh_len;
1152 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1154 *retcmpp = NFSERR_NOTSAME;
1155 FREE((caddr_t)tnfhp, M_NFSFH);
1156 } else if (nfhpp != NULL) {
1159 FREE((caddr_t)tnfhp, M_NFSFH);
1161 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1163 case NFSATTRBIT_FILEID:
1164 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1165 thyp = fxdr_hyper(tl);
1168 if ((u_int64_t)nap->na_fileid != thyp)
1169 *retcmpp = NFSERR_NOTSAME;
1171 } else if (nap != NULL) {
1173 printf("NFSv4 fileid > 32bits\n");
1174 nap->na_fileid = thyp;
1176 attrsum += NFSX_HYPER;
1178 case NFSATTRBIT_FILESAVAIL:
1179 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1182 sfp->sf_afiles != fxdr_hyper(tl))
1183 *retcmpp = NFSERR_NOTSAME;
1184 } else if (sfp != NULL) {
1185 sfp->sf_afiles = fxdr_hyper(tl);
1187 attrsum += NFSX_HYPER;
1189 case NFSATTRBIT_FILESFREE:
1190 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1193 sfp->sf_ffiles != fxdr_hyper(tl))
1194 *retcmpp = NFSERR_NOTSAME;
1195 } else if (sfp != NULL) {
1196 sfp->sf_ffiles = fxdr_hyper(tl);
1198 attrsum += NFSX_HYPER;
1200 case NFSATTRBIT_FILESTOTAL:
1201 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1204 sfp->sf_tfiles != fxdr_hyper(tl))
1205 *retcmpp = NFSERR_NOTSAME;
1206 } else if (sfp != NULL) {
1207 sfp->sf_tfiles = fxdr_hyper(tl);
1209 attrsum += NFSX_HYPER;
1211 case NFSATTRBIT_FSLOCATIONS:
1212 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1216 if (compare && !(*retcmpp)) {
1217 refp = nfsv4root_getreferral(vp, NULL, 0);
1219 if (cp == NULL || cp2 == NULL ||
1221 strcmp(cp2, refp->nfr_srvlist))
1222 *retcmpp = NFSERR_NOTSAME;
1223 } else if (m == 0) {
1224 *retcmpp = NFSERR_NOTSAME;
1228 free(cp, M_NFSSTRING);
1230 free(cp2, M_NFSSTRING);
1232 case NFSATTRBIT_HIDDEN:
1233 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1234 if (compare && !(*retcmpp))
1235 *retcmpp = NFSERR_ATTRNOTSUPP;
1236 attrsum += NFSX_UNSIGNED;
1238 case NFSATTRBIT_HOMOGENEOUS:
1239 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1242 if (fsp->fs_properties &
1243 NFSV3_FSFHOMOGENEOUS) {
1244 if (*tl == newnfs_false)
1245 *retcmpp = NFSERR_NOTSAME;
1247 if (*tl == newnfs_true)
1248 *retcmpp = NFSERR_NOTSAME;
1251 } else if (fsp != NULL) {
1252 if (*tl == newnfs_true)
1253 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1255 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1257 attrsum += NFSX_UNSIGNED;
1259 case NFSATTRBIT_MAXFILESIZE:
1260 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1261 tnfsquad.qval = fxdr_hyper(tl);
1264 tquad = NFSRV_MAXFILESIZE;
1265 if (tquad != tnfsquad.qval)
1266 *retcmpp = NFSERR_NOTSAME;
1268 } else if (fsp != NULL) {
1269 fsp->fs_maxfilesize = tnfsquad.qval;
1271 attrsum += NFSX_HYPER;
1273 case NFSATTRBIT_MAXLINK:
1274 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1277 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1278 *retcmpp = NFSERR_NOTSAME;
1280 } else if (pc != NULL) {
1281 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1283 attrsum += NFSX_UNSIGNED;
1285 case NFSATTRBIT_MAXNAME:
1286 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1289 if (fsp->fs_maxname !=
1290 fxdr_unsigned(u_int32_t, *tl))
1291 *retcmpp = NFSERR_NOTSAME;
1294 tuint = fxdr_unsigned(u_int32_t, *tl);
1296 * Some Linux NFSv4 servers report this
1297 * as 0 or 4billion, so I'll set it to
1298 * NFS_MAXNAMLEN. If a server actually creates
1299 * a name longer than NFS_MAXNAMLEN, it will
1300 * get an error back.
1302 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1303 tuint = NFS_MAXNAMLEN;
1305 fsp->fs_maxname = tuint;
1307 pc->pc_namemax = tuint;
1309 attrsum += NFSX_UNSIGNED;
1311 case NFSATTRBIT_MAXREAD:
1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1315 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1316 *(tl + 1)) || *tl != 0)
1317 *retcmpp = NFSERR_NOTSAME;
1319 } else if (fsp != NULL) {
1320 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1321 fsp->fs_rtpref = fsp->fs_rtmax;
1322 fsp->fs_dtpref = fsp->fs_rtpref;
1324 attrsum += NFSX_HYPER;
1326 case NFSATTRBIT_MAXWRITE:
1327 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1330 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1331 *(tl + 1)) || *tl != 0)
1332 *retcmpp = NFSERR_NOTSAME;
1334 } else if (fsp != NULL) {
1335 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1336 fsp->fs_wtpref = fsp->fs_wtmax;
1338 attrsum += NFSX_HYPER;
1340 case NFSATTRBIT_MIMETYPE:
1341 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1342 i = fxdr_unsigned(int, *tl);
1343 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1344 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1347 if (compare && !(*retcmpp))
1348 *retcmpp = NFSERR_ATTRNOTSUPP;
1350 case NFSATTRBIT_MODE:
1351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1354 if (nap->na_mode != nfstov_mode(*tl))
1355 *retcmpp = NFSERR_NOTSAME;
1357 } else if (nap != NULL) {
1358 nap->na_mode = nfstov_mode(*tl);
1360 attrsum += NFSX_UNSIGNED;
1362 case NFSATTRBIT_NOTRUNC:
1363 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1366 if (*tl != newnfs_true)
1367 *retcmpp = NFSERR_NOTSAME;
1369 } else if (pc != NULL) {
1370 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1372 attrsum += NFSX_UNSIGNED;
1374 case NFSATTRBIT_NUMLINKS:
1375 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1376 tuint = fxdr_unsigned(u_int32_t, *tl);
1379 if ((u_int32_t)nap->na_nlink != tuint)
1380 *retcmpp = NFSERR_NOTSAME;
1382 } else if (nap != NULL) {
1383 nap->na_nlink = tuint;
1385 attrsum += NFSX_UNSIGNED;
1387 case NFSATTRBIT_OWNER:
1388 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1389 j = fxdr_unsigned(int, *tl);
1391 error = NFSERR_BADXDR;
1394 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1395 if (j > NFSV4_SMALLSTR)
1396 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1399 error = nfsrv_mtostr(nd, cp, j);
1401 if (j > NFSV4_SMALLSTR)
1402 free(cp, M_NFSSTRING);
1407 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1409 *retcmpp = NFSERR_NOTSAME;
1411 } else if (nap != NULL) {
1412 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1413 nap->na_uid = nfsrv_defaultuid;
1417 if (j > NFSV4_SMALLSTR)
1418 free(cp, M_NFSSTRING);
1420 case NFSATTRBIT_OWNERGROUP:
1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 j = fxdr_unsigned(int, *tl);
1424 error = NFSERR_BADXDR;
1427 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1428 if (j > NFSV4_SMALLSTR)
1429 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1432 error = nfsrv_mtostr(nd, cp, j);
1434 if (j > NFSV4_SMALLSTR)
1435 free(cp, M_NFSSTRING);
1440 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1442 *retcmpp = NFSERR_NOTSAME;
1444 } else if (nap != NULL) {
1445 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1446 nap->na_gid = nfsrv_defaultgid;
1450 if (j > NFSV4_SMALLSTR)
1451 free(cp, M_NFSSTRING);
1453 case NFSATTRBIT_QUOTAHARD:
1454 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1456 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1457 freenum = sbp->f_bfree;
1459 freenum = sbp->f_bavail;
1462 * ufs_quotactl() insists that the uid argument
1463 * equal p_ruid for non-root quota access, so
1464 * we'll just make sure that's the case.
1466 savuid = p->p_cred->p_ruid;
1467 p->p_cred->p_ruid = cred->cr_uid;
1468 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1469 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1470 freenum = min(dqb.dqb_bhardlimit, freenum);
1471 p->p_cred->p_ruid = savuid;
1473 uquad = (u_int64_t)freenum;
1474 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1476 if (compare && !(*retcmpp)) {
1477 if (uquad != fxdr_hyper(tl))
1478 *retcmpp = NFSERR_NOTSAME;
1480 attrsum += NFSX_HYPER;
1482 case NFSATTRBIT_QUOTASOFT:
1483 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1485 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1486 freenum = sbp->f_bfree;
1488 freenum = sbp->f_bavail;
1491 * ufs_quotactl() insists that the uid argument
1492 * equal p_ruid for non-root quota access, so
1493 * we'll just make sure that's the case.
1495 savuid = p->p_cred->p_ruid;
1496 p->p_cred->p_ruid = cred->cr_uid;
1497 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1498 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1499 freenum = min(dqb.dqb_bsoftlimit, freenum);
1500 p->p_cred->p_ruid = savuid;
1502 uquad = (u_int64_t)freenum;
1503 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1505 if (compare && !(*retcmpp)) {
1506 if (uquad != fxdr_hyper(tl))
1507 *retcmpp = NFSERR_NOTSAME;
1509 attrsum += NFSX_HYPER;
1511 case NFSATTRBIT_QUOTAUSED:
1512 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1517 * ufs_quotactl() insists that the uid argument
1518 * equal p_ruid for non-root quota access, so
1519 * we'll just make sure that's the case.
1521 savuid = p->p_cred->p_ruid;
1522 p->p_cred->p_ruid = cred->cr_uid;
1523 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1524 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1525 freenum = dqb.dqb_curblocks;
1526 p->p_cred->p_ruid = savuid;
1528 uquad = (u_int64_t)freenum;
1529 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1531 if (compare && !(*retcmpp)) {
1532 if (uquad != fxdr_hyper(tl))
1533 *retcmpp = NFSERR_NOTSAME;
1535 attrsum += NFSX_HYPER;
1537 case NFSATTRBIT_RAWDEV:
1538 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1539 j = fxdr_unsigned(int, *tl++);
1540 k = fxdr_unsigned(int, *tl);
1543 if (nap->na_rdev != NFSMAKEDEV(j, k))
1544 *retcmpp = NFSERR_NOTSAME;
1546 } else if (nap != NULL) {
1547 nap->na_rdev = NFSMAKEDEV(j, k);
1549 attrsum += NFSX_V4SPECDATA;
1551 case NFSATTRBIT_SPACEAVAIL:
1552 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1555 sfp->sf_abytes != fxdr_hyper(tl))
1556 *retcmpp = NFSERR_NOTSAME;
1557 } else if (sfp != NULL) {
1558 sfp->sf_abytes = fxdr_hyper(tl);
1560 attrsum += NFSX_HYPER;
1562 case NFSATTRBIT_SPACEFREE:
1563 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1566 sfp->sf_fbytes != fxdr_hyper(tl))
1567 *retcmpp = NFSERR_NOTSAME;
1568 } else if (sfp != NULL) {
1569 sfp->sf_fbytes = fxdr_hyper(tl);
1571 attrsum += NFSX_HYPER;
1573 case NFSATTRBIT_SPACETOTAL:
1574 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1577 sfp->sf_tbytes != fxdr_hyper(tl))
1578 *retcmpp = NFSERR_NOTSAME;
1579 } else if (sfp != NULL) {
1580 sfp->sf_tbytes = fxdr_hyper(tl);
1582 attrsum += NFSX_HYPER;
1584 case NFSATTRBIT_SPACEUSED:
1585 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1586 thyp = fxdr_hyper(tl);
1589 if ((u_int64_t)nap->na_bytes != thyp)
1590 *retcmpp = NFSERR_NOTSAME;
1592 } else if (nap != NULL) {
1593 nap->na_bytes = thyp;
1595 attrsum += NFSX_HYPER;
1597 case NFSATTRBIT_SYSTEM:
1598 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1599 if (compare && !(*retcmpp))
1600 *retcmpp = NFSERR_ATTRNOTSUPP;
1601 attrsum += NFSX_UNSIGNED;
1603 case NFSATTRBIT_TIMEACCESS:
1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1605 fxdr_nfsv4time(tl, &temptime);
1608 if (!NFS_CMPTIME(temptime, nap->na_atime))
1609 *retcmpp = NFSERR_NOTSAME;
1611 } else if (nap != NULL) {
1612 nap->na_atime = temptime;
1614 attrsum += NFSX_V4TIME;
1616 case NFSATTRBIT_TIMEACCESSSET:
1617 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1618 attrsum += NFSX_UNSIGNED;
1619 i = fxdr_unsigned(int, *tl);
1620 if (i == NFSV4SATTRTIME_TOCLIENT) {
1621 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1622 attrsum += NFSX_V4TIME;
1624 if (compare && !(*retcmpp))
1625 *retcmpp = NFSERR_INVAL;
1627 case NFSATTRBIT_TIMEBACKUP:
1628 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1629 if (compare && !(*retcmpp))
1630 *retcmpp = NFSERR_ATTRNOTSUPP;
1631 attrsum += NFSX_V4TIME;
1633 case NFSATTRBIT_TIMECREATE:
1634 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1635 if (compare && !(*retcmpp))
1636 *retcmpp = NFSERR_ATTRNOTSUPP;
1637 attrsum += NFSX_V4TIME;
1639 case NFSATTRBIT_TIMEDELTA:
1640 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1644 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1645 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1646 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1647 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1650 *retcmpp = NFSERR_NOTSAME;
1653 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1656 attrsum += NFSX_V4TIME;
1658 case NFSATTRBIT_TIMEMETADATA:
1659 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1660 fxdr_nfsv4time(tl, &temptime);
1663 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1664 *retcmpp = NFSERR_NOTSAME;
1666 } else if (nap != NULL) {
1667 nap->na_ctime = temptime;
1669 attrsum += NFSX_V4TIME;
1671 case NFSATTRBIT_TIMEMODIFY:
1672 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1673 fxdr_nfsv4time(tl, &temptime);
1676 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1677 *retcmpp = NFSERR_NOTSAME;
1679 } else if (nap != NULL) {
1680 nap->na_mtime = temptime;
1682 attrsum += NFSX_V4TIME;
1684 case NFSATTRBIT_TIMEMODIFYSET:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1686 attrsum += NFSX_UNSIGNED;
1687 i = fxdr_unsigned(int, *tl);
1688 if (i == NFSV4SATTRTIME_TOCLIENT) {
1689 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1690 attrsum += NFSX_V4TIME;
1692 if (compare && !(*retcmpp))
1693 *retcmpp = NFSERR_INVAL;
1695 case NFSATTRBIT_MOUNTEDONFILEID:
1696 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1697 thyp = fxdr_hyper(tl);
1701 *retcmpp = NFSERR_NOTSAME;
1703 if (!vp || !nfsrv_atroot(vp, &fid))
1704 fid = nap->na_fileid;
1705 if ((u_int64_t)fid != thyp)
1706 *retcmpp = NFSERR_NOTSAME;
1709 } else if (nap != NULL) {
1711 printf("NFSv4 mounted on fileid > 32bits\n");
1712 nap->na_mntonfileno = thyp;
1714 attrsum += NFSX_HYPER;
1717 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1719 if (compare && !(*retcmpp))
1720 *retcmpp = NFSERR_ATTRNOTSUPP;
1722 * and get out of the loop, since we can't parse
1723 * the unknown attrbute data.
1725 bitpos = NFSATTRBIT_MAX;
1731 * some clients pad the attrlist, so we need to skip over the
1734 if (attrsum > attrsize) {
1735 error = NFSERR_BADXDR;
1737 attrsize = NFSM_RNDUP(attrsize);
1738 if (attrsum < attrsize)
1739 error = nfsm_advance(nd, attrsize - attrsum, -1);
1742 NFSEXITCODE2(error, nd);
1747 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1748 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1749 * The first argument is a pointer to an nfsv4lock structure.
1750 * The second argument is 1 iff a blocking lock is wanted.
1751 * If this argument is 0, the call waits until no thread either wants nor
1752 * holds an exclusive lock.
1753 * It returns 1 if the lock was acquired, 0 otherwise.
1754 * If several processes call this function concurrently wanting the exclusive
1755 * lock, one will get the lock and the rest will return without getting the
1756 * lock. (If the caller must have the lock, it simply calls this function in a
1757 * loop until the function returns 1 to indicate the lock was acquired.)
1758 * Any usecnt must be decremented by calling nfsv4_relref() before
1759 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1760 * be called in a loop.
1761 * The isleptp argument is set to indicate if the call slept, iff not NULL
1762 * and the mp argument indicates to check for a forced dismount, iff not
1766 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1767 void *mutex, struct mount *mp)
1773 * If a lock is wanted, loop around until the lock is acquired by
1774 * someone and then released. If I want the lock, try to acquire it.
1775 * For a lock to be issued, no lock must be in force and the usecnt
1779 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1780 lp->nfslock_usecnt == 0) {
1781 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1782 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1785 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1787 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1788 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1789 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1792 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1795 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1796 PZERO - 1, "nfsv4lck", NULL);
1797 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1798 lp->nfslock_usecnt == 0) {
1799 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1800 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1808 * Release the lock acquired by nfsv4_lock().
1809 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1810 * incremented, as well.
1813 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1816 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1818 lp->nfslock_usecnt++;
1823 * Release a reference cnt.
1826 nfsv4_relref(struct nfsv4lock *lp)
1829 if (lp->nfslock_usecnt <= 0)
1830 panic("nfsv4root ref cnt");
1831 lp->nfslock_usecnt--;
1832 if (lp->nfslock_usecnt == 0)
1837 * Get a reference cnt.
1838 * This function will wait for any exclusive lock to be released, but will
1839 * not wait for threads that want the exclusive lock. If priority needs
1840 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1841 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1842 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1843 * return without getting a refcnt for that case.
1846 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1854 * Wait for a lock held.
1856 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1857 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1859 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1862 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1863 PZERO - 1, "nfsv4lck", NULL);
1865 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1868 lp->nfslock_usecnt++;
1872 * Get a reference as above, but return failure instead of sleeping if
1873 * an exclusive lock is held.
1876 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1879 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1882 lp->nfslock_usecnt++;
1887 * Test for a lock. Return 1 if locked, 0 otherwise.
1890 nfsv4_testlock(struct nfsv4lock *lp)
1893 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1894 lp->nfslock_usecnt == 0)
1900 * Wake up anyone sleeping, waiting for this lock.
1903 nfsv4_wanted(struct nfsv4lock *lp)
1906 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1907 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1908 wakeup((caddr_t)&lp->nfslock_lock);
1913 * Copy a string from an mbuf list into a character array.
1914 * Return EBADRPC if there is an mbuf error,
1918 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1927 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1928 rem = NFSM_RNDUP(siz) - siz;
1934 NFSBCOPY(cp, str, xfer);
1943 cp = NFSMTOD(mp, caddr_t);
1955 error = nfsm_advance(nd, rem, len);
1961 NFSEXITCODE2(error, nd);
1966 * Fill in the attributes as marked by the bitmap (V4).
1969 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1970 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1971 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1972 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1974 int bitpos, retnum = 0;
1976 int siz, prefixnum, error;
1977 u_char *cp, namestr[NFSV4_SMALLSTR];
1978 nfsattrbit_t attrbits, retbits;
1979 nfsattrbit_t *retbitp = &retbits;
1980 u_int32_t freenum, *retnump;
1983 struct nfsfsinfo fsinf;
1984 struct timespec temptime;
1985 NFSACL_T *aclp, *naclp = NULL;
1992 * First, set the bits that can be filled and get fsinfo.
1994 NFSSET_ATTRBIT(retbitp, attrbitp);
1995 /* If p and cred are NULL, it is a client side call */
1996 if (p == NULL && cred == NULL) {
1997 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2000 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2001 naclp = acl_alloc(M_WAITOK);
2004 nfsvno_getfs(&fsinf, isdgram);
2007 * Get the VFS_STATFS(), since some attributes need them.
2009 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2010 error = VFS_STATFS(mp, &fs);
2013 nd->nd_repstat = NFSERR_ACCES;
2016 NFSCLRSTATFS_ATTRBIT(retbitp);
2022 * And the NFSv4 ACL...
2024 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2025 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2026 supports_nfsv4acls == 0))) {
2027 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2029 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2030 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2031 supports_nfsv4acls == 0)) {
2032 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2033 } else if (naclp != NULL) {
2034 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2035 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2037 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2039 NFSVOPUNLOCK(vp, 0);
2041 error = NFSERR_PERM;
2044 nd->nd_repstat = NFSERR_ACCES;
2047 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2052 * Put out the attribute bitmap for the ones being filled in
2053 * and get the field for the number of attributes returned.
2055 prefixnum = nfsrv_putattrbit(nd, retbitp);
2056 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2057 prefixnum += NFSX_UNSIGNED;
2060 * Now, loop around filling in the attributes for each bit set.
2062 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2063 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2065 case NFSATTRBIT_SUPPORTEDATTRS:
2066 NFSSETSUPP_ATTRBIT(&attrbits);
2067 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2068 && supports_nfsv4acls == 0)) {
2069 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2070 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2072 retnum += nfsrv_putattrbit(nd, &attrbits);
2074 case NFSATTRBIT_TYPE:
2075 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2076 *tl = vtonfsv34_type(vap->va_type);
2077 retnum += NFSX_UNSIGNED;
2079 case NFSATTRBIT_FHEXPIRETYPE:
2080 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2081 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2082 retnum += NFSX_UNSIGNED;
2084 case NFSATTRBIT_CHANGE:
2085 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2086 txdr_hyper(vap->va_filerev, tl);
2087 retnum += NFSX_HYPER;
2089 case NFSATTRBIT_SIZE:
2090 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2091 txdr_hyper(vap->va_size, tl);
2092 retnum += NFSX_HYPER;
2094 case NFSATTRBIT_LINKSUPPORT:
2095 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2096 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2100 retnum += NFSX_UNSIGNED;
2102 case NFSATTRBIT_SYMLINKSUPPORT:
2103 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2104 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2108 retnum += NFSX_UNSIGNED;
2110 case NFSATTRBIT_NAMEDATTR:
2111 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2113 retnum += NFSX_UNSIGNED;
2115 case NFSATTRBIT_FSID:
2116 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2118 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2120 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2121 retnum += NFSX_V4FSID;
2123 case NFSATTRBIT_UNIQUEHANDLES:
2124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2126 retnum += NFSX_UNSIGNED;
2128 case NFSATTRBIT_LEASETIME:
2129 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2130 *tl = txdr_unsigned(nfsrv_lease);
2131 retnum += NFSX_UNSIGNED;
2133 case NFSATTRBIT_RDATTRERROR:
2134 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2135 *tl = txdr_unsigned(rderror);
2136 retnum += NFSX_UNSIGNED;
2139 * Recommended Attributes. (Only the supported ones.)
2141 case NFSATTRBIT_ACL:
2142 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2144 case NFSATTRBIT_ACLSUPPORT:
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2147 retnum += NFSX_UNSIGNED;
2149 case NFSATTRBIT_CANSETTIME:
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2151 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2155 retnum += NFSX_UNSIGNED;
2157 case NFSATTRBIT_CASEINSENSITIVE:
2158 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2160 retnum += NFSX_UNSIGNED;
2162 case NFSATTRBIT_CASEPRESERVING:
2163 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2165 retnum += NFSX_UNSIGNED;
2167 case NFSATTRBIT_CHOWNRESTRICTED:
2168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 retnum += NFSX_UNSIGNED;
2172 case NFSATTRBIT_FILEHANDLE:
2173 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2175 case NFSATTRBIT_FILEID:
2176 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2178 *tl = txdr_unsigned(vap->va_fileid);
2179 retnum += NFSX_HYPER;
2181 case NFSATTRBIT_FILESAVAIL:
2183 * Check quota and use min(quota, f_ffree).
2185 freenum = fs.f_ffree;
2188 * ufs_quotactl() insists that the uid argument
2189 * equal p_ruid for non-root quota access, so
2190 * we'll just make sure that's the case.
2192 savuid = p->p_cred->p_ruid;
2193 p->p_cred->p_ruid = cred->cr_uid;
2194 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2195 cred->cr_uid, (caddr_t)&dqb))
2196 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2198 p->p_cred->p_ruid = savuid;
2200 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2202 *tl = txdr_unsigned(freenum);
2203 retnum += NFSX_HYPER;
2205 case NFSATTRBIT_FILESFREE:
2206 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2208 *tl = txdr_unsigned(fs.f_ffree);
2209 retnum += NFSX_HYPER;
2211 case NFSATTRBIT_FILESTOTAL:
2212 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2214 *tl = txdr_unsigned(fs.f_files);
2215 retnum += NFSX_HYPER;
2217 case NFSATTRBIT_FSLOCATIONS:
2218 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2221 retnum += 2 * NFSX_UNSIGNED;
2223 case NFSATTRBIT_HOMOGENEOUS:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2229 retnum += NFSX_UNSIGNED;
2231 case NFSATTRBIT_MAXFILESIZE:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2233 uquad = NFSRV_MAXFILESIZE;
2234 txdr_hyper(uquad, tl);
2235 retnum += NFSX_HYPER;
2237 case NFSATTRBIT_MAXLINK:
2238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2239 *tl = txdr_unsigned(LINK_MAX);
2240 retnum += NFSX_UNSIGNED;
2242 case NFSATTRBIT_MAXNAME:
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2245 retnum += NFSX_UNSIGNED;
2247 case NFSATTRBIT_MAXREAD:
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2250 *tl = txdr_unsigned(fsinf.fs_rtmax);
2251 retnum += NFSX_HYPER;
2253 case NFSATTRBIT_MAXWRITE:
2254 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2256 *tl = txdr_unsigned(fsinf.fs_wtmax);
2257 retnum += NFSX_HYPER;
2259 case NFSATTRBIT_MODE:
2260 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2261 *tl = vtonfsv34_mode(vap->va_mode);
2262 retnum += NFSX_UNSIGNED;
2264 case NFSATTRBIT_NOTRUNC:
2265 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2267 retnum += NFSX_UNSIGNED;
2269 case NFSATTRBIT_NUMLINKS:
2270 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2271 *tl = txdr_unsigned(vap->va_nlink);
2272 retnum += NFSX_UNSIGNED;
2274 case NFSATTRBIT_OWNER:
2276 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2277 retnum += nfsm_strtom(nd, cp, siz);
2279 free(cp, M_NFSSTRING);
2281 case NFSATTRBIT_OWNERGROUP:
2283 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2284 retnum += nfsm_strtom(nd, cp, siz);
2286 free(cp, M_NFSSTRING);
2288 case NFSATTRBIT_QUOTAHARD:
2289 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2290 freenum = fs.f_bfree;
2292 freenum = fs.f_bavail;
2295 * ufs_quotactl() insists that the uid argument
2296 * equal p_ruid for non-root quota access, so
2297 * we'll just make sure that's the case.
2299 savuid = p->p_cred->p_ruid;
2300 p->p_cred->p_ruid = cred->cr_uid;
2301 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2302 cred->cr_uid, (caddr_t)&dqb))
2303 freenum = min(dqb.dqb_bhardlimit, freenum);
2304 p->p_cred->p_ruid = savuid;
2306 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2307 uquad = (u_int64_t)freenum;
2308 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2309 txdr_hyper(uquad, tl);
2310 retnum += NFSX_HYPER;
2312 case NFSATTRBIT_QUOTASOFT:
2313 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2314 freenum = fs.f_bfree;
2316 freenum = fs.f_bavail;
2319 * ufs_quotactl() insists that the uid argument
2320 * equal p_ruid for non-root quota access, so
2321 * we'll just make sure that's the case.
2323 savuid = p->p_cred->p_ruid;
2324 p->p_cred->p_ruid = cred->cr_uid;
2325 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2326 cred->cr_uid, (caddr_t)&dqb))
2327 freenum = min(dqb.dqb_bsoftlimit, freenum);
2328 p->p_cred->p_ruid = savuid;
2330 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2331 uquad = (u_int64_t)freenum;
2332 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2333 txdr_hyper(uquad, tl);
2334 retnum += NFSX_HYPER;
2336 case NFSATTRBIT_QUOTAUSED:
2340 * ufs_quotactl() insists that the uid argument
2341 * equal p_ruid for non-root quota access, so
2342 * we'll just make sure that's the case.
2344 savuid = p->p_cred->p_ruid;
2345 p->p_cred->p_ruid = cred->cr_uid;
2346 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2347 cred->cr_uid, (caddr_t)&dqb))
2348 freenum = dqb.dqb_curblocks;
2349 p->p_cred->p_ruid = savuid;
2351 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2352 uquad = (u_int64_t)freenum;
2353 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2354 txdr_hyper(uquad, tl);
2355 retnum += NFSX_HYPER;
2357 case NFSATTRBIT_RAWDEV:
2358 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2359 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2360 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2361 retnum += NFSX_V4SPECDATA;
2363 case NFSATTRBIT_SPACEAVAIL:
2364 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2365 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2366 uquad = (u_int64_t)fs.f_bfree;
2368 uquad = (u_int64_t)fs.f_bavail;
2369 uquad *= fs.f_bsize;
2370 txdr_hyper(uquad, tl);
2371 retnum += NFSX_HYPER;
2373 case NFSATTRBIT_SPACEFREE:
2374 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2375 uquad = (u_int64_t)fs.f_bfree;
2376 uquad *= fs.f_bsize;
2377 txdr_hyper(uquad, tl);
2378 retnum += NFSX_HYPER;
2380 case NFSATTRBIT_SPACETOTAL:
2381 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2382 uquad = (u_int64_t)fs.f_blocks;
2383 uquad *= fs.f_bsize;
2384 txdr_hyper(uquad, tl);
2385 retnum += NFSX_HYPER;
2387 case NFSATTRBIT_SPACEUSED:
2388 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2389 txdr_hyper(vap->va_bytes, tl);
2390 retnum += NFSX_HYPER;
2392 case NFSATTRBIT_TIMEACCESS:
2393 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2394 txdr_nfsv4time(&vap->va_atime, tl);
2395 retnum += NFSX_V4TIME;
2397 case NFSATTRBIT_TIMEACCESSSET:
2398 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2399 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2400 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2401 txdr_nfsv4time(&vap->va_atime, tl);
2402 retnum += NFSX_V4SETTIME;
2404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2405 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2406 retnum += NFSX_UNSIGNED;
2409 case NFSATTRBIT_TIMEDELTA:
2410 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2411 temptime.tv_sec = 0;
2412 temptime.tv_nsec = 1000000000 / hz;
2413 txdr_nfsv4time(&temptime, tl);
2414 retnum += NFSX_V4TIME;
2416 case NFSATTRBIT_TIMEMETADATA:
2417 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2418 txdr_nfsv4time(&vap->va_ctime, tl);
2419 retnum += NFSX_V4TIME;
2421 case NFSATTRBIT_TIMEMODIFY:
2422 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2423 txdr_nfsv4time(&vap->va_mtime, tl);
2424 retnum += NFSX_V4TIME;
2426 case NFSATTRBIT_TIMEMODIFYSET:
2427 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2429 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2430 txdr_nfsv4time(&vap->va_mtime, tl);
2431 retnum += NFSX_V4SETTIME;
2433 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2434 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2435 retnum += NFSX_UNSIGNED;
2438 case NFSATTRBIT_MOUNTEDONFILEID:
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2441 uquad = mounted_on_fileno;
2443 uquad = (u_int64_t)vap->va_fileid;
2444 txdr_hyper(uquad, tl);
2445 retnum += NFSX_HYPER;
2448 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2454 *retnump = txdr_unsigned(retnum);
2455 return (retnum + prefixnum);
2459 * Put the attribute bits onto an mbuf list.
2460 * Return the number of bytes of output generated.
2463 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2466 int cnt, i, bytesize;
2468 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2469 if (attrbitp->bits[cnt - 1])
2471 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2472 NFSM_BUILD(tl, u_int32_t *, bytesize);
2473 *tl++ = txdr_unsigned(cnt);
2474 for (i = 0; i < cnt; i++)
2475 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2480 * Convert a uid to a string.
2481 * If the lookup fails, just output the digits.
2483 * cpp - points to a buffer of size NFSV4_SMALLSTR
2484 * (malloc a larger one, as required)
2485 * retlenp - pointer to length to be returned
2488 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2491 struct nfsusrgrp *usrp;
2494 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2499 if (nfsrv_dnsname) {
2501 * Always map nfsrv_defaultuid to "nobody".
2503 if (uid == nfsrv_defaultuid) {
2504 i = nfsrv_dnsnamelen + 7;
2507 if (len > NFSV4_SMALLSTR)
2508 free(cp, M_NFSSTRING);
2509 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2515 NFSBCOPY("nobody@", cp, 7);
2517 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2522 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2523 if (usrp->lug_uid == uid) {
2524 if (usrp->lug_expiry < NFSD_MONOSEC)
2527 * If the name doesn't already have an '@'
2528 * in it, append @domainname to it.
2530 for (i = 0; i < usrp->lug_namelen; i++) {
2531 if (usrp->lug_name[i] == '@') {
2537 i = usrp->lug_namelen;
2539 i = usrp->lug_namelen +
2540 nfsrv_dnsnamelen + 1;
2543 if (len > NFSV4_SMALLSTR)
2544 free(cp, M_NFSSTRING);
2545 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2551 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2552 if (!hasampersand) {
2553 cp += usrp->lug_namelen;
2555 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2557 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2558 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2565 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2567 if (ret == 0 && cnt < 2)
2574 * No match, just return a string of digits.
2578 while (tmp || i == 0) {
2582 len = (i > len) ? len : i;
2586 for (i = 0; i < len; i++) {
2587 *cp-- = '0' + (tmp % 10);
2594 * Convert a string to a uid.
2595 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2597 * If this is called from a client side mount using AUTH_SYS and the
2598 * string is made up entirely of digits, just convert the string to
2602 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2606 char *cp, *endstr, *str0;
2607 struct nfsusrgrp *usrp;
2613 error = NFSERR_BADOWNER;
2616 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2618 tuid = (uid_t)strtoul(str0, &endstr, 10);
2619 if ((endstr - str0) == len &&
2620 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2627 cp = strchr(str0, '@');
2629 i = (int)(cp++ - str0);
2637 * If an '@' is found and the domain name matches, search for the name
2638 * with dns stripped off.
2639 * Mixed case alpahbetics will match for the domain name, but all
2640 * upper case will not.
2642 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2643 (len - 1 - i) == nfsrv_dnsnamelen &&
2644 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2645 len -= (nfsrv_dnsnamelen + 1);
2650 * Check for the special case of "nobody".
2652 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2653 *uidp = nfsrv_defaultuid;
2659 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2660 if (usrp->lug_namelen == len &&
2661 !NFSBCMP(usrp->lug_name, str, len)) {
2662 if (usrp->lug_expiry < NFSD_MONOSEC)
2664 *uidp = usrp->lug_uid;
2665 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2666 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2674 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2676 if (ret == 0 && cnt < 2)
2678 error = NFSERR_BADOWNER;
2686 * Convert a gid to a string.
2687 * gid - the group id
2688 * cpp - points to a buffer of size NFSV4_SMALLSTR
2689 * (malloc a larger one, as required)
2690 * retlenp - pointer to length to be returned
2693 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2696 struct nfsusrgrp *usrp;
2699 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2704 if (nfsrv_dnsname) {
2706 * Always map nfsrv_defaultgid to "nogroup".
2708 if (gid == nfsrv_defaultgid) {
2709 i = nfsrv_dnsnamelen + 8;
2712 if (len > NFSV4_SMALLSTR)
2713 free(cp, M_NFSSTRING);
2714 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2720 NFSBCOPY("nogroup@", cp, 8);
2722 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2727 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2728 if (usrp->lug_gid == gid) {
2729 if (usrp->lug_expiry < NFSD_MONOSEC)
2732 * If the name doesn't already have an '@'
2733 * in it, append @domainname to it.
2735 for (i = 0; i < usrp->lug_namelen; i++) {
2736 if (usrp->lug_name[i] == '@') {
2742 i = usrp->lug_namelen;
2744 i = usrp->lug_namelen +
2745 nfsrv_dnsnamelen + 1;
2748 if (len > NFSV4_SMALLSTR)
2749 free(cp, M_NFSSTRING);
2750 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2756 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2757 if (!hasampersand) {
2758 cp += usrp->lug_namelen;
2760 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2762 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2763 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2770 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2772 if (ret == 0 && cnt < 2)
2779 * No match, just return a string of digits.
2783 while (tmp || i == 0) {
2787 len = (i > len) ? len : i;
2791 for (i = 0; i < len; i++) {
2792 *cp-- = '0' + (tmp % 10);
2799 * Convert a string to a gid.
2800 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2802 * If this is called from a client side mount using AUTH_SYS and the
2803 * string is made up entirely of digits, just convert the string to
2807 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2811 char *cp, *endstr, *str0;
2812 struct nfsusrgrp *usrp;
2818 error = NFSERR_BADOWNER;
2821 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2823 tgid = (gid_t)strtoul(str0, &endstr, 10);
2824 if ((endstr - str0) == len &&
2825 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2832 cp = strchr(str0, '@');
2834 i = (int)(cp++ - str0);
2842 * If an '@' is found and the dns name matches, search for the name
2843 * with the dns stripped off.
2845 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2846 (len - 1 - i) == nfsrv_dnsnamelen &&
2847 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2848 len -= (nfsrv_dnsnamelen + 1);
2853 * Check for the special case of "nogroup".
2855 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2856 *gidp = nfsrv_defaultgid;
2862 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2863 if (usrp->lug_namelen == len &&
2864 !NFSBCMP(usrp->lug_name, str, len)) {
2865 if (usrp->lug_expiry < NFSD_MONOSEC)
2867 *gidp = usrp->lug_gid;
2868 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2869 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2877 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2879 if (ret == 0 && cnt < 2)
2881 error = NFSERR_BADOWNER;
2889 * Cmp len chars, allowing mixed case in the first argument to match lower
2890 * case in the second, but not if the first argument is all upper case.
2891 * Return 0 for a match, 1 otherwise.
2894 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2900 for (i = 0; i < len; i++) {
2901 if (*cp >= 'A' && *cp <= 'Z') {
2902 tmp = *cp++ + ('a' - 'A');
2905 if (tmp >= 'a' && tmp <= 'z')
2918 * Set the port for the nfsuserd.
2921 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2923 struct nfssockreq *rp;
2924 struct sockaddr_in *ad;
2928 if (nfsrv_nfsuserd) {
2936 * Set up the socket record and connect.
2938 rp = &nfsrv_nfsuserdsock;
2939 rp->nr_client = NULL;
2940 rp->nr_sotype = SOCK_DGRAM;
2941 rp->nr_soproto = IPPROTO_UDP;
2942 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2944 NFSSOCKADDRALLOC(rp->nr_nam);
2945 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2946 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2947 ad->sin_family = AF_INET;
2948 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2949 ad->sin_port = port;
2950 rp->nr_prog = RPCPROG_NFSUSERD;
2951 rp->nr_vers = RPCNFSUSERD_VERS;
2952 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2954 NFSSOCKADDRFREE(rp->nr_nam);
2963 * Delete the nfsuserd port.
2966 nfsrv_nfsuserddelport(void)
2970 if (nfsrv_nfsuserd == 0) {
2976 newnfs_disconnect(&nfsrv_nfsuserdsock);
2977 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2981 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2983 * Returns 0 upon success, non-zero otherwise.
2986 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2989 struct nfsrv_descript *nd;
2991 struct nfsrv_descript nfsd;
2996 if (nfsrv_nfsuserd == 0) {
3003 cred = newnfs_getcred();
3004 nd->nd_flag = ND_GSSINITREPLY;
3007 nd->nd_procnum = procnum;
3008 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3009 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3010 if (procnum == RPCNFSUSERD_GETUID)
3011 *tl = txdr_unsigned(uid);
3013 *tl = txdr_unsigned(gid);
3016 (void) nfsm_strtom(nd, name, len);
3018 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3019 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
3022 mbuf_freem(nd->nd_mrep);
3023 error = nd->nd_repstat;
3031 * This function is called from the nfssvc(2) system call, to update the
3032 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3035 nfssvc_idname(struct nfsd_idargs *nidp)
3037 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3038 struct nfsuserhashhead *hp;
3043 if (nidp->nid_flag & NFSID_INITIALIZE) {
3044 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3045 M_NFSSTRING, M_WAITOK);
3046 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3049 if (nfsrv_dnsname) {
3051 * Free up all the old stuff and reinitialize hash lists.
3053 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3054 nfsrv_removeuser(usrp);
3056 free(nfsrv_dnsname, M_NFSSTRING);
3057 nfsrv_dnsname = NULL;
3059 TAILQ_INIT(&nfsuserlruhead);
3060 for (i = 0; i < NFSUSERHASHSIZE; i++)
3061 LIST_INIT(&nfsuserhash[i]);
3062 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3063 LIST_INIT(&nfsgrouphash[i]);
3064 for (i = 0; i < NFSUSERHASHSIZE; i++)
3065 LIST_INIT(&nfsusernamehash[i]);
3066 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3067 LIST_INIT(&nfsgroupnamehash[i]);
3070 * Put name in "DNS" string.
3074 nfsrv_dnsnamelen = nidp->nid_namelen;
3075 nfsrv_defaultuid = nidp->nid_uid;
3076 nfsrv_defaultgid = nidp->nid_gid;
3078 nfsrv_usermax = nidp->nid_usermax;
3082 free(cp, M_NFSSTRING);
3087 * malloc the new one now, so any potential sleep occurs before
3088 * manipulation of the lists.
3090 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3091 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3092 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3095 free((caddr_t)newusrp, M_NFSUSERGROUP);
3098 newusrp->lug_namelen = nidp->nid_namelen;
3102 * Delete old entries, as required.
3104 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3105 hp = NFSUSERHASH(nidp->nid_uid);
3106 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3107 if (usrp->lug_uid == nidp->nid_uid)
3108 nfsrv_removeuser(usrp);
3111 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3112 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3113 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3114 if (usrp->lug_namelen == newusrp->lug_namelen &&
3115 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3117 nfsrv_removeuser(usrp);
3120 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3121 hp = NFSGROUPHASH(nidp->nid_gid);
3122 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3123 if (usrp->lug_gid == nidp->nid_gid)
3124 nfsrv_removeuser(usrp);
3127 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3128 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3129 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3130 if (usrp->lug_namelen == newusrp->lug_namelen &&
3131 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3133 nfsrv_removeuser(usrp);
3136 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3137 if (usrp->lug_expiry < NFSD_MONOSEC)
3138 nfsrv_removeuser(usrp);
3140 while (nfsrv_usercnt >= nfsrv_usermax) {
3141 usrp = TAILQ_FIRST(&nfsuserlruhead);
3142 nfsrv_removeuser(usrp);
3146 * Now, we can add the new one.
3148 if (nidp->nid_usertimeout)
3149 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3151 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3152 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3153 newusrp->lug_uid = nidp->nid_uid;
3154 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3156 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3157 newusrp->lug_namelen), newusrp, lug_namehash);
3158 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3160 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3161 newusrp->lug_gid = nidp->nid_gid;
3162 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3164 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3165 newusrp->lug_namelen), newusrp, lug_namehash);
3166 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3169 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3177 * Remove a user/group name element.
3180 nfsrv_removeuser(struct nfsusrgrp *usrp)
3183 NFSNAMEIDREQUIRED();
3184 LIST_REMOVE(usrp, lug_numhash);
3185 LIST_REMOVE(usrp, lug_namehash);
3186 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3188 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3192 * This function scans a byte string and checks for UTF-8 compliance.
3193 * It returns 0 if it conforms and NFSERR_INVAL if not.
3196 nfsrv_checkutf8(u_int8_t *cp, int len)
3198 u_int32_t val = 0x0;
3199 int cnt = 0, gotd = 0, shift = 0;
3201 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3205 * Here are what the variables are used for:
3206 * val - the calculated value of a multibyte char, used to check
3207 * that it was coded with the correct range
3208 * cnt - the number of 10xxxxxx bytes to follow
3209 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3210 * shift - lower order bits of range (ie. "val >> shift" should
3211 * not be 0, in other words, dividing by the lower bound
3212 * of the range should get a non-zero value)
3213 * byte - used to calculate cnt
3217 /* This handles the 10xxxxxx bytes */
3218 if ((*cp & 0xc0) != 0x80 ||
3219 (gotd && (*cp & 0x20))) {
3220 error = NFSERR_INVAL;
3225 val |= (*cp & 0x3f);
3227 if (cnt == 0 && (val >> shift) == 0x0) {
3228 error = NFSERR_INVAL;
3231 } else if (*cp & 0x80) {
3232 /* first byte of multi byte char */
3234 while ((byte & 0x40) && cnt < 6) {
3238 if (cnt == 0 || cnt == 6) {
3239 error = NFSERR_INVAL;
3242 val = (*cp & (0x3f >> cnt));
3243 shift = utf8_shift[cnt - 1];
3244 if (cnt == 2 && val == 0xd)
3245 /* Check for the 0xd800-0xdfff case */
3252 error = NFSERR_INVAL;
3260 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3261 * strings, one with the root path in it and the other with the list of
3262 * locations. The list is in the same format as is found in nfr_refs.
3263 * It is a "," separated list of entries, where each of them is of the
3264 * form <server>:<rootpath>. For example
3265 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3266 * The nilp argument is set to 1 for the special case of a null fs_root
3267 * and an empty server list.
3268 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3269 * number of xdr bytes parsed in sump.
3272 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3273 int *sump, int *nilp)
3276 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3277 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3279 SLIST_ENTRY(list) next;
3283 SLIST_HEAD(, list) head;
3290 * Get the fs_root path and check for the special case of null path
3291 * and 0 length server list.
3293 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3294 len = fxdr_unsigned(int, *tl);
3295 if (len < 0 || len > 10240) {
3296 error = NFSERR_BADXDR;
3300 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3302 error = NFSERR_BADXDR;
3306 *sump = 2 * NFSX_UNSIGNED;
3310 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3311 error = nfsrv_mtostr(nd, cp, len);
3313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3314 cnt = fxdr_unsigned(int, *tl);
3316 error = NFSERR_BADXDR;
3322 * Now, loop through the location list and make up the srvlist.
3324 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3325 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3328 for (i = 0; i < cnt; i++) {
3330 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3331 nsrv = fxdr_unsigned(int, *tl);
3333 error = NFSERR_BADXDR;
3338 * Handle the first server by putting it in the srvstr.
3340 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3341 len = fxdr_unsigned(int, *tl);
3342 if (len <= 0 || len > 1024) {
3343 error = NFSERR_BADXDR;
3346 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3351 error = nfsrv_mtostr(nd, cp3, len);
3357 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3358 for (j = 1; j < nsrv; j++) {
3360 * Yuck, put them in an slist and process them later.
3362 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3363 len = fxdr_unsigned(int, *tl);
3364 if (len <= 0 || len > 1024) {
3365 error = NFSERR_BADXDR;
3368 lsp = (struct list *)malloc(sizeof (struct list)
3369 + len, M_TEMP, M_WAITOK);
3370 error = nfsrv_mtostr(nd, lsp->host, len);
3373 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3375 SLIST_INSERT_HEAD(&head, lsp, next);
3379 * Finally, we can get the path.
3381 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3382 len = fxdr_unsigned(int, *tl);
3383 if (len <= 0 || len > 1024) {
3384 error = NFSERR_BADXDR;
3387 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3388 error = nfsrv_mtostr(nd, cp3, len);
3391 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3396 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3397 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3400 NFSBCOPY(lsp->host, cp3, lsp->len);
3403 NFSBCOPY(str, cp3, stringlen);
3406 siz += (lsp->len + stringlen + 2);
3407 free((caddr_t)lsp, M_TEMP);
3413 NFSEXITCODE2(0, nd);
3417 free(cp, M_NFSSTRING);
3419 free(cp2, M_NFSSTRING);
3420 NFSEXITCODE2(error, nd);
3425 * Make the malloc'd space large enough. This is a pain, but the xdr
3426 * doesn't set an upper bound on the side, so...
3429 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3436 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3437 NFSBCOPY(*cpp, cp, *slenp);
3438 free(*cpp, M_NFSSTRING);
3442 *slenp = siz + 1024;
3446 * Initialize the reply header data structures.
3449 nfsrvd_rephead(struct nfsrv_descript *nd)
3454 * If this is a big reply, use a cluster.
3456 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3457 nfs_bigreply[nd->nd_procnum]) {
3458 NFSMCLGET(mreq, M_WAIT);
3466 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3467 mbuf_setlen(mreq, 0);
3469 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3470 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3474 * Lock a socket against others.
3475 * Currently used to serialize connect/disconnect attempts.
3478 newnfs_sndlock(int *flagp)
3483 while (*flagp & NFSR_SNDLOCK) {
3484 *flagp |= NFSR_WANTSND;
3487 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3488 PZERO - 1, "nfsndlck", &ts);
3490 *flagp |= NFSR_SNDLOCK;
3496 * Unlock the stream socket for others.
3499 newnfs_sndunlock(int *flagp)
3503 if ((*flagp & NFSR_SNDLOCK) == 0)
3504 panic("nfs sndunlock");
3505 *flagp &= ~NFSR_SNDLOCK;
3506 if (*flagp & NFSR_WANTSND) {
3507 *flagp &= ~NFSR_WANTSND;
3508 wakeup((caddr_t)flagp);