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;
68 int nfsd_enable_stringtouid = 0;
73 * This array of structures indicates, for V4:
74 * retfh - which of 3 types of calling args are used
75 * 0 - doesn't change cfh or use a sfh
76 * 1 - replaces cfh with a new one (unless it returns an error status)
77 * 2 - uses cfh and sfh
78 * needscfh - if the op wants a cfh and premtime
79 * 0 - doesn't use a cfh
80 * 1 - uses a cfh, but doesn't want pre-op attributes
81 * 2 - uses a cfh and wants pre-op attributes
82 * savereply - indicates a non-idempotent Op
83 * 0 - not non-idempotent
85 * Ops that are ordered via seqid# are handled separately from these
87 * Define it here, since it is used by both the client and server.
89 struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
90 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
91 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
92 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
93 { 0, 1, 0, 0, LK_SHARED }, /* Access */
94 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Close */
95 { 0, 2, 0, 1, LK_EXCLUSIVE }, /* Commit */
96 { 1, 2, 1, 1, LK_EXCLUSIVE }, /* Create */
97 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Delegpurge */
98 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Delegreturn */
99 { 0, 1, 0, 0, LK_SHARED }, /* Getattr */
100 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* GetFH */
101 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Link */
102 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Lock */
103 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockT */
104 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockU */
105 { 1, 2, 0, 0, LK_EXCLUSIVE }, /* Lookup */
106 { 1, 2, 0, 0, LK_EXCLUSIVE }, /* Lookupp */
107 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* NVerify */
108 { 1, 1, 0, 1, LK_EXCLUSIVE }, /* Open */
109 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* OpenAttr */
110 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenConfirm */
111 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenDowngrade */
112 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutFH */
113 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutPubFH */
114 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutRootFH */
115 { 0, 1, 0, 0, LK_SHARED }, /* Read */
116 { 0, 1, 0, 0, LK_SHARED }, /* Readdir */
117 { 0, 1, 0, 0, LK_SHARED }, /* ReadLink */
118 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Remove */
119 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Rename */
120 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Renew */
121 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* RestoreFH */
122 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SaveFH */
123 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SecInfo */
124 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Setattr */
125 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientID */
126 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientIDConfirm */
127 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Verify */
128 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Write */
129 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* ReleaseLockOwner */
131 #endif /* !APPLEKEXT */
133 static int ncl_mbuf_mhlen = MHLEN;
134 static int nfsrv_usercnt = 0;
135 static int nfsrv_dnsnamelen;
136 static u_char *nfsrv_dnsname = NULL;
137 static int nfsrv_usermax = 999999999;
138 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
139 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
140 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
141 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
142 static struct nfsuserlruhead nfsuserlruhead;
145 * This static array indicates whether or not the RPC generates a large
146 * reply. This is used by nfs_reply() to decide whether or not an mbuf
147 * cluster should be allocated. (If a cluster is required by an RPC
148 * marked 0 in this array, the code will still work, just not quite as
151 static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
152 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,
155 /* local functions */
156 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
157 static void nfsv4_wanted(struct nfsv4lock *lp);
158 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
159 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
161 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
162 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
164 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
169 * copies mbuf chain to the uio scatter/gather list
172 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
174 char *mbufcp, *uiocp;
181 mbufcp = nd->nd_dpos;
182 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
183 rem = NFSM_RNDUP(siz) - siz;
185 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
189 left = uiop->uio_iov->iov_len;
190 uiocp = uiop->uio_iov->iov_base;
201 mbufcp = NFSMTOD(mp, caddr_t);
203 KASSERT(len > 0, ("len %d", len));
205 xfer = (left > len) ? len : left;
208 if (uiop->uio_iov->iov_op != NULL)
209 (*(uiop->uio_iov->iov_op))
210 (mbufcp, uiocp, xfer);
213 if (uiop->uio_segflg == UIO_SYSSPACE)
214 NFSBCOPY(mbufcp, uiocp, xfer);
216 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
221 uiop->uio_offset += xfer;
222 uiop->uio_resid -= xfer;
224 if (uiop->uio_iov->iov_len <= siz) {
228 uiop->uio_iov->iov_base = (void *)
229 ((char *)uiop->uio_iov->iov_base + uiosiz);
230 uiop->uio_iov->iov_len -= uiosiz;
234 nd->nd_dpos = mbufcp;
238 error = nfsm_advance(nd, rem, len);
244 NFSEXITCODE2(error, nd);
250 * Help break down an mbuf chain by setting the first siz bytes contiguous
251 * pointed to by returned val.
252 * This is used by the macro NFSM_DISSECT for tough
256 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
265 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
267 nd->nd_md = mbuf_next(nd->nd_md);
268 if (nd->nd_md == NULL)
270 left = mbuf_len(nd->nd_md);
271 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
276 } else if (mbuf_next(nd->nd_md) == NULL) {
278 } else if (siz > ncl_mbuf_mhlen) {
279 panic("nfs S too big");
281 MGET(mp2, MT_DATA, how);
284 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
285 mbuf_setnext(nd->nd_md, mp2);
286 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
288 retp = p = NFSMTOD(mp2, caddr_t);
289 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
292 mp2 = mbuf_next(mp2);
293 /* Loop around copying up the siz2 bytes */
297 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
299 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
300 NFSM_DATAP(mp2, xfer);
301 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
306 mp2 = mbuf_next(mp2);
308 mbuf_setlen(nd->nd_md, siz);
310 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
316 * Advance the position in the mbuf chain.
317 * If offs == 0, this is a no-op, but it is simpler to just return from
318 * here than check for offs > 0 for all calls to nfsm_advance.
319 * If left == -1, it should be calculated here.
322 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
329 * A negative offs should be considered a serious problem.
332 panic("nfsrv_advance");
335 * If left == -1, calculate it here.
338 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
342 * Loop around, advancing over the mbuf data.
344 while (offs > left) {
346 nd->nd_md = mbuf_next(nd->nd_md);
347 if (nd->nd_md == NULL) {
351 left = mbuf_len(nd->nd_md);
352 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
362 * Copy a string into mbuf(s).
363 * Return the number of bytes output, including XDR overheads.
366 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
375 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
376 *tl = txdr_unsigned(siz);
377 rem = NFSM_RNDUP(siz) - siz;
378 bytesize = NFSX_UNSIGNED + siz + rem;
381 left = M_TRAILINGSPACE(m2);
384 * Loop around copying the string to mbuf(s).
388 if (siz > ncl_mbuf_mlen)
389 NFSMCLGET(m1, M_WAIT);
393 mbuf_setnext(m2, m1);
395 cp2 = NFSMTOD(m2, caddr_t);
396 left = M_TRAILINGSPACE(m2);
402 NFSBCOPY(cp, cp2, xfer);
404 mbuf_setlen(m2, mbuf_len(m2) + xfer);
407 if (siz == 0 && rem) {
409 panic("nfsm_strtom");
410 NFSBZERO(cp2 + xfer, rem);
411 mbuf_setlen(m2, mbuf_len(m2) + rem);
415 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
420 * Called once to initialize data structures...
425 static int nfs_inited = 0;
431 newnfs_true = txdr_unsigned(TRUE);
432 newnfs_false = txdr_unsigned(FALSE);
433 newnfs_xdrneg1 = txdr_unsigned(-1);
434 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
437 NFSSETBOOTTIME(nfsboottime);
440 * Initialize reply list and start timer
442 TAILQ_INIT(&nfsd_reqq);
447 * Put a file handle in an mbuf list.
448 * If the size argument == 0, just use the default size.
449 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
450 * Return the number of bytes output, including XDR overhead.
453 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
457 int fullsiz, rem, bytesize = 0;
461 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
463 if (size > NFSX_V2FH)
464 panic("fh size > NFSX_V2FH for NFSv2");
465 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
466 NFSBCOPY(fhp, cp, size);
467 if (size < NFSX_V2FH)
468 NFSBZERO(cp + size, NFSX_V2FH - size);
469 bytesize = NFSX_V2FH;
473 fullsiz = NFSM_RNDUP(size);
474 rem = fullsiz - size;
476 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
477 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
480 bytesize = NFSX_UNSIGNED + fullsiz;
482 (void) nfsm_strtom(nd, fhp, size);
489 * This function compares two net addresses by family and returns TRUE
490 * if they are the same host.
491 * If there is any doubt, return FALSE.
492 * The AF_INET family is handled as a special case so that address mbufs
493 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
496 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
498 struct sockaddr_in *inetaddr;
502 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
503 if (inetaddr->sin_family == AF_INET &&
504 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
510 struct sockaddr_in6 *inetaddr6;
512 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
513 /* XXX - should test sin6_scope_id ? */
514 if (inetaddr6->sin6_family == AF_INET6 &&
515 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
526 * Similar to the above, but takes to NFSSOCKADDR_T args.
529 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
531 struct sockaddr_in *addr1, *addr2;
532 struct sockaddr *inaddr;
534 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
535 switch (inaddr->sa_family) {
537 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
538 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
539 if (addr2->sin_family == AF_INET &&
540 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
546 struct sockaddr_in6 *inet6addr1, *inet6addr2;
548 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
549 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
550 /* XXX - should test sin6_scope_id ? */
551 if (inet6addr2->sin6_family == AF_INET6 &&
552 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
553 &inet6addr2->sin6_addr))
564 * Trim the stuff already dissected off the mbuf list.
567 newnfs_trimleading(nd)
568 struct nfsrv_descript *nd;
574 * First, free up leading mbufs.
576 if (nd->nd_mrep != nd->nd_md) {
578 while (mbuf_next(m) != nd->nd_md) {
579 if (mbuf_next(m) == NULL)
580 panic("nfsm trim leading");
583 mbuf_setnext(m, NULL);
584 mbuf_freem(nd->nd_mrep);
589 * Now, adjust this mbuf, based on nd_dpos.
591 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
592 if (offs == mbuf_len(m)) {
596 panic("nfsm trim leading2");
597 mbuf_setnext(n, NULL);
599 } else if (offs > 0) {
600 mbuf_setlen(m, mbuf_len(m) - offs);
603 panic("nfsm trimleading offs");
606 nd->nd_dpos = NFSMTOD(m, caddr_t);
610 * Trim trailing data off the mbuf list being built.
613 newnfs_trimtrailing(nd, mb, bpos)
614 struct nfsrv_descript *nd;
620 mbuf_freem(mbuf_next(mb));
621 mbuf_setnext(mb, NULL);
623 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
629 * Dissect a file handle on the client.
632 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
639 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
640 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
641 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
648 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
650 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
652 FREE((caddr_t)nfhp, M_NFSFH);
658 NFSEXITCODE2(error, nd);
663 * Break down the nfsv4 acl.
664 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
667 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
668 int *aclsizep, __unused NFSPROC_T *p)
672 int acecnt, error = 0, aceerr = 0, acesize;
678 * Parse out the ace entries and expect them to conform to
679 * what can be supported by R/W/X bits.
681 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
682 aclsize = NFSX_UNSIGNED;
683 acecnt = fxdr_unsigned(int, *tl);
684 if (acecnt > ACL_MAX_ENTRIES)
685 aceerr = NFSERR_ATTRNOTSUPP;
686 if (nfsrv_useacl == 0)
687 aceerr = NFSERR_ATTRNOTSUPP;
688 for (i = 0; i < acecnt; i++) {
690 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
691 &aceerr, &acesize, p);
693 error = nfsrv_skipace(nd, &acesize);
699 aclp->acl_cnt = acecnt;
705 NFSEXITCODE2(error, nd);
710 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
713 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
718 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
719 len = fxdr_unsigned(int, *(tl + 3));
720 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
722 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
723 NFSEXITCODE2(error, nd);
728 * Get attribute bits from an mbuf list.
729 * Returns EBADRPC for a parsing error, 0 otherwise.
730 * If the clearinvalid flag is set, clear the bits not supported.
733 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
740 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
741 cnt = fxdr_unsigned(int, *tl);
743 error = NFSERR_BADXDR;
746 if (cnt > NFSATTRBIT_MAXWORDS)
747 outcnt = NFSATTRBIT_MAXWORDS;
750 NFSZERO_ATTRBIT(attrbitp);
752 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
753 for (i = 0; i < outcnt; i++)
754 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
756 for (i = 0; i < (cnt - outcnt); i++) {
757 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
758 if (retnotsupp != NULL && *tl != 0)
759 *retnotsupp = NFSERR_ATTRNOTSUPP;
762 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
764 NFSEXITCODE2(error, nd);
769 * Get the attributes for V4.
770 * If the compare flag is true, test for any attribute changes,
771 * otherwise return the attribute values.
772 * These attributes cover fields in "struct vattr", "struct statfs",
773 * "struct nfsfsinfo", the file handle and the lease duration.
774 * The value of retcmpp is set to 1 if all attributes are the same,
776 * Returns EBADRPC if it can't be parsed, 0 otherwise.
779 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
780 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
781 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
782 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
783 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
786 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
787 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
788 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
789 nfsattrbit_t attrbits, retattrbits, checkattrbits;
791 struct nfsreferral *refp;
794 struct timespec temptime;
798 u_int32_t freenum = 0, tuint;
799 u_int64_t uquad = 0, thyp, thyp2;
807 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
809 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
815 *retcmpp = retnotsup;
818 * Just set default values to some of the important ones.
823 nap->na_rdev = (NFSDEV_T)0;
824 nap->na_mtime.tv_sec = 0;
825 nap->na_mtime.tv_nsec = 0;
828 nap->na_blocksize = NFS_FABLKSIZE;
831 sbp->f_bsize = NFS_FABLKSIZE;
839 fsp->fs_rtmax = 8192;
840 fsp->fs_rtpref = 8192;
841 fsp->fs_maxname = NFS_MAXNAMLEN;
842 fsp->fs_wtmax = 8192;
843 fsp->fs_wtpref = 8192;
844 fsp->fs_wtmult = NFS_FABLKSIZE;
845 fsp->fs_dtpref = 8192;
846 fsp->fs_maxfilesize = 0xffffffffffffffffull;
847 fsp->fs_timedelta.tv_sec = 0;
848 fsp->fs_timedelta.tv_nsec = 1;
849 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
850 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
853 pc->pc_linkmax = LINK_MAX;
854 pc->pc_namemax = NAME_MAX;
856 pc->pc_chownrestricted = 0;
857 pc->pc_caseinsensitive = 0;
858 pc->pc_casepreserving = 1;
863 * Loop around getting the attributes.
865 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
866 attrsize = fxdr_unsigned(int, *tl);
867 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
868 if (attrsum > attrsize) {
869 error = NFSERR_BADXDR;
872 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
874 case NFSATTRBIT_SUPPORTEDATTRS:
876 if (compare || nap == NULL)
877 error = nfsrv_getattrbits(nd, &retattrbits,
880 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
884 if (compare && !(*retcmpp)) {
885 NFSSETSUPP_ATTRBIT(&checkattrbits);
886 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
888 *retcmpp = NFSERR_NOTSAME;
892 case NFSATTRBIT_TYPE:
893 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
896 if (nap->na_type != nfsv34tov_type(*tl))
897 *retcmpp = NFSERR_NOTSAME;
899 } else if (nap != NULL) {
900 nap->na_type = nfsv34tov_type(*tl);
902 attrsum += NFSX_UNSIGNED;
904 case NFSATTRBIT_FHEXPIRETYPE:
905 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
906 if (compare && !(*retcmpp)) {
907 if (fxdr_unsigned(int, *tl) !=
908 NFSV4FHTYPE_PERSISTENT)
909 *retcmpp = NFSERR_NOTSAME;
911 attrsum += NFSX_UNSIGNED;
913 case NFSATTRBIT_CHANGE:
914 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
917 if (nap->na_filerev != fxdr_hyper(tl))
918 *retcmpp = NFSERR_NOTSAME;
920 } else if (nap != NULL) {
921 nap->na_filerev = fxdr_hyper(tl);
923 attrsum += NFSX_HYPER;
925 case NFSATTRBIT_SIZE:
926 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
929 if (nap->na_size != fxdr_hyper(tl))
930 *retcmpp = NFSERR_NOTSAME;
932 } else if (nap != NULL) {
933 nap->na_size = fxdr_hyper(tl);
935 attrsum += NFSX_HYPER;
937 case NFSATTRBIT_LINKSUPPORT:
938 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
941 if (fsp->fs_properties & NFSV3_FSFLINK) {
942 if (*tl == newnfs_false)
943 *retcmpp = NFSERR_NOTSAME;
945 if (*tl == newnfs_true)
946 *retcmpp = NFSERR_NOTSAME;
949 } else if (fsp != NULL) {
950 if (*tl == newnfs_true)
951 fsp->fs_properties |= NFSV3_FSFLINK;
953 fsp->fs_properties &= ~NFSV3_FSFLINK;
955 attrsum += NFSX_UNSIGNED;
957 case NFSATTRBIT_SYMLINKSUPPORT:
958 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
961 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
962 if (*tl == newnfs_false)
963 *retcmpp = NFSERR_NOTSAME;
965 if (*tl == newnfs_true)
966 *retcmpp = NFSERR_NOTSAME;
969 } else if (fsp != NULL) {
970 if (*tl == newnfs_true)
971 fsp->fs_properties |= NFSV3_FSFSYMLINK;
973 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
975 attrsum += NFSX_UNSIGNED;
977 case NFSATTRBIT_NAMEDATTR:
978 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
979 if (compare && !(*retcmpp)) {
980 if (*tl != newnfs_false)
981 *retcmpp = NFSERR_NOTSAME;
983 attrsum += NFSX_UNSIGNED;
985 case NFSATTRBIT_FSID:
986 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
987 thyp = fxdr_hyper(tl);
989 thyp2 = fxdr_hyper(tl);
992 if (thyp != (u_int64_t)
993 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
995 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
996 *retcmpp = NFSERR_NOTSAME;
998 } else if (nap != NULL) {
999 nap->na_filesid[0] = thyp;
1000 nap->na_filesid[1] = thyp2;
1002 attrsum += (4 * NFSX_UNSIGNED);
1004 case NFSATTRBIT_UNIQUEHANDLES:
1005 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1006 if (compare && !(*retcmpp)) {
1007 if (*tl != newnfs_true)
1008 *retcmpp = NFSERR_NOTSAME;
1010 attrsum += NFSX_UNSIGNED;
1012 case NFSATTRBIT_LEASETIME:
1013 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1015 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1017 *retcmpp = NFSERR_NOTSAME;
1018 } else if (leasep != NULL) {
1019 *leasep = fxdr_unsigned(u_int32_t, *tl);
1021 attrsum += NFSX_UNSIGNED;
1023 case NFSATTRBIT_RDATTRERROR:
1024 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1027 *retcmpp = NFSERR_INVAL;
1028 } else if (rderrp != NULL) {
1029 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1031 attrsum += NFSX_UNSIGNED;
1033 case NFSATTRBIT_ACL:
1039 naclp = acl_alloc(M_WAITOK);
1040 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1046 if (aceerr || aclp == NULL ||
1047 nfsrv_compareacl(aclp, naclp))
1048 *retcmpp = NFSERR_NOTSAME;
1051 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1053 *retcmpp = NFSERR_ATTRNOTSUPP;
1057 if (vp != NULL && aclp != NULL)
1058 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1061 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1068 case NFSATTRBIT_ACLSUPPORT:
1069 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1070 if (compare && !(*retcmpp)) {
1072 if (fxdr_unsigned(u_int32_t, *tl) !=
1074 *retcmpp = NFSERR_NOTSAME;
1076 *retcmpp = NFSERR_ATTRNOTSUPP;
1079 attrsum += NFSX_UNSIGNED;
1081 case NFSATTRBIT_ARCHIVE:
1082 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1083 if (compare && !(*retcmpp))
1084 *retcmpp = NFSERR_ATTRNOTSUPP;
1085 attrsum += NFSX_UNSIGNED;
1087 case NFSATTRBIT_CANSETTIME:
1088 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1091 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1092 if (*tl == newnfs_false)
1093 *retcmpp = NFSERR_NOTSAME;
1095 if (*tl == newnfs_true)
1096 *retcmpp = NFSERR_NOTSAME;
1099 } else if (fsp != NULL) {
1100 if (*tl == newnfs_true)
1101 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1103 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1105 attrsum += NFSX_UNSIGNED;
1107 case NFSATTRBIT_CASEINSENSITIVE:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1111 if (*tl != newnfs_false)
1112 *retcmpp = NFSERR_NOTSAME;
1114 } else if (pc != NULL) {
1115 pc->pc_caseinsensitive =
1116 fxdr_unsigned(u_int32_t, *tl);
1118 attrsum += NFSX_UNSIGNED;
1120 case NFSATTRBIT_CASEPRESERVING:
1121 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1124 if (*tl != newnfs_true)
1125 *retcmpp = NFSERR_NOTSAME;
1127 } else if (pc != NULL) {
1128 pc->pc_casepreserving =
1129 fxdr_unsigned(u_int32_t, *tl);
1131 attrsum += NFSX_UNSIGNED;
1133 case NFSATTRBIT_CHOWNRESTRICTED:
1134 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1137 if (*tl != newnfs_true)
1138 *retcmpp = NFSERR_NOTSAME;
1140 } else if (pc != NULL) {
1141 pc->pc_chownrestricted =
1142 fxdr_unsigned(u_int32_t, *tl);
1144 attrsum += NFSX_UNSIGNED;
1146 case NFSATTRBIT_FILEHANDLE:
1147 error = nfsm_getfh(nd, &tnfhp);
1150 tfhsize = tnfhp->nfh_len;
1153 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1155 *retcmpp = NFSERR_NOTSAME;
1156 FREE((caddr_t)tnfhp, M_NFSFH);
1157 } else if (nfhpp != NULL) {
1160 FREE((caddr_t)tnfhp, M_NFSFH);
1162 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1164 case NFSATTRBIT_FILEID:
1165 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1166 thyp = fxdr_hyper(tl);
1169 if ((u_int64_t)nap->na_fileid != thyp)
1170 *retcmpp = NFSERR_NOTSAME;
1172 } else if (nap != NULL) {
1174 printf("NFSv4 fileid > 32bits\n");
1175 nap->na_fileid = thyp;
1177 attrsum += NFSX_HYPER;
1179 case NFSATTRBIT_FILESAVAIL:
1180 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1183 sfp->sf_afiles != fxdr_hyper(tl))
1184 *retcmpp = NFSERR_NOTSAME;
1185 } else if (sfp != NULL) {
1186 sfp->sf_afiles = fxdr_hyper(tl);
1188 attrsum += NFSX_HYPER;
1190 case NFSATTRBIT_FILESFREE:
1191 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1194 sfp->sf_ffiles != fxdr_hyper(tl))
1195 *retcmpp = NFSERR_NOTSAME;
1196 } else if (sfp != NULL) {
1197 sfp->sf_ffiles = fxdr_hyper(tl);
1199 attrsum += NFSX_HYPER;
1201 case NFSATTRBIT_FILESTOTAL:
1202 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1205 sfp->sf_tfiles != fxdr_hyper(tl))
1206 *retcmpp = NFSERR_NOTSAME;
1207 } else if (sfp != NULL) {
1208 sfp->sf_tfiles = fxdr_hyper(tl);
1210 attrsum += NFSX_HYPER;
1212 case NFSATTRBIT_FSLOCATIONS:
1213 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1217 if (compare && !(*retcmpp)) {
1218 refp = nfsv4root_getreferral(vp, NULL, 0);
1220 if (cp == NULL || cp2 == NULL ||
1222 strcmp(cp2, refp->nfr_srvlist))
1223 *retcmpp = NFSERR_NOTSAME;
1224 } else if (m == 0) {
1225 *retcmpp = NFSERR_NOTSAME;
1229 free(cp, M_NFSSTRING);
1231 free(cp2, M_NFSSTRING);
1233 case NFSATTRBIT_HIDDEN:
1234 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1235 if (compare && !(*retcmpp))
1236 *retcmpp = NFSERR_ATTRNOTSUPP;
1237 attrsum += NFSX_UNSIGNED;
1239 case NFSATTRBIT_HOMOGENEOUS:
1240 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1243 if (fsp->fs_properties &
1244 NFSV3_FSFHOMOGENEOUS) {
1245 if (*tl == newnfs_false)
1246 *retcmpp = NFSERR_NOTSAME;
1248 if (*tl == newnfs_true)
1249 *retcmpp = NFSERR_NOTSAME;
1252 } else if (fsp != NULL) {
1253 if (*tl == newnfs_true)
1254 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1256 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1258 attrsum += NFSX_UNSIGNED;
1260 case NFSATTRBIT_MAXFILESIZE:
1261 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1262 tnfsquad.qval = fxdr_hyper(tl);
1265 tquad = NFSRV_MAXFILESIZE;
1266 if (tquad != tnfsquad.qval)
1267 *retcmpp = NFSERR_NOTSAME;
1269 } else if (fsp != NULL) {
1270 fsp->fs_maxfilesize = tnfsquad.qval;
1272 attrsum += NFSX_HYPER;
1274 case NFSATTRBIT_MAXLINK:
1275 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1278 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1279 *retcmpp = NFSERR_NOTSAME;
1281 } else if (pc != NULL) {
1282 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1284 attrsum += NFSX_UNSIGNED;
1286 case NFSATTRBIT_MAXNAME:
1287 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1290 if (fsp->fs_maxname !=
1291 fxdr_unsigned(u_int32_t, *tl))
1292 *retcmpp = NFSERR_NOTSAME;
1295 tuint = fxdr_unsigned(u_int32_t, *tl);
1297 * Some Linux NFSv4 servers report this
1298 * as 0 or 4billion, so I'll set it to
1299 * NFS_MAXNAMLEN. If a server actually creates
1300 * a name longer than NFS_MAXNAMLEN, it will
1301 * get an error back.
1303 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1304 tuint = NFS_MAXNAMLEN;
1306 fsp->fs_maxname = tuint;
1308 pc->pc_namemax = tuint;
1310 attrsum += NFSX_UNSIGNED;
1312 case NFSATTRBIT_MAXREAD:
1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1316 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1317 *(tl + 1)) || *tl != 0)
1318 *retcmpp = NFSERR_NOTSAME;
1320 } else if (fsp != NULL) {
1321 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1322 fsp->fs_rtpref = fsp->fs_rtmax;
1323 fsp->fs_dtpref = fsp->fs_rtpref;
1325 attrsum += NFSX_HYPER;
1327 case NFSATTRBIT_MAXWRITE:
1328 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1331 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1332 *(tl + 1)) || *tl != 0)
1333 *retcmpp = NFSERR_NOTSAME;
1335 } else if (fsp != NULL) {
1336 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1337 fsp->fs_wtpref = fsp->fs_wtmax;
1339 attrsum += NFSX_HYPER;
1341 case NFSATTRBIT_MIMETYPE:
1342 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1343 i = fxdr_unsigned(int, *tl);
1344 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1345 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1348 if (compare && !(*retcmpp))
1349 *retcmpp = NFSERR_ATTRNOTSUPP;
1351 case NFSATTRBIT_MODE:
1352 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1355 if (nap->na_mode != nfstov_mode(*tl))
1356 *retcmpp = NFSERR_NOTSAME;
1358 } else if (nap != NULL) {
1359 nap->na_mode = nfstov_mode(*tl);
1361 attrsum += NFSX_UNSIGNED;
1363 case NFSATTRBIT_NOTRUNC:
1364 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1367 if (*tl != newnfs_true)
1368 *retcmpp = NFSERR_NOTSAME;
1370 } else if (pc != NULL) {
1371 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1373 attrsum += NFSX_UNSIGNED;
1375 case NFSATTRBIT_NUMLINKS:
1376 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1377 tuint = fxdr_unsigned(u_int32_t, *tl);
1380 if ((u_int32_t)nap->na_nlink != tuint)
1381 *retcmpp = NFSERR_NOTSAME;
1383 } else if (nap != NULL) {
1384 nap->na_nlink = tuint;
1386 attrsum += NFSX_UNSIGNED;
1388 case NFSATTRBIT_OWNER:
1389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1390 j = fxdr_unsigned(int, *tl);
1392 error = NFSERR_BADXDR;
1395 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1396 if (j > NFSV4_SMALLSTR)
1397 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1400 error = nfsrv_mtostr(nd, cp, j);
1402 if (j > NFSV4_SMALLSTR)
1403 free(cp, M_NFSSTRING);
1408 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1410 *retcmpp = NFSERR_NOTSAME;
1412 } else if (nap != NULL) {
1413 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1414 nap->na_uid = nfsrv_defaultuid;
1418 if (j > NFSV4_SMALLSTR)
1419 free(cp, M_NFSSTRING);
1421 case NFSATTRBIT_OWNERGROUP:
1422 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1423 j = fxdr_unsigned(int, *tl);
1425 error = NFSERR_BADXDR;
1428 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1429 if (j > NFSV4_SMALLSTR)
1430 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1433 error = nfsrv_mtostr(nd, cp, j);
1435 if (j > NFSV4_SMALLSTR)
1436 free(cp, M_NFSSTRING);
1441 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1443 *retcmpp = NFSERR_NOTSAME;
1445 } else if (nap != NULL) {
1446 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1447 nap->na_gid = nfsrv_defaultgid;
1451 if (j > NFSV4_SMALLSTR)
1452 free(cp, M_NFSSTRING);
1454 case NFSATTRBIT_QUOTAHARD:
1455 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1457 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1458 freenum = sbp->f_bfree;
1460 freenum = sbp->f_bavail;
1463 * ufs_quotactl() insists that the uid argument
1464 * equal p_ruid for non-root quota access, so
1465 * we'll just make sure that's the case.
1467 savuid = p->p_cred->p_ruid;
1468 p->p_cred->p_ruid = cred->cr_uid;
1469 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1470 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1471 freenum = min(dqb.dqb_bhardlimit, freenum);
1472 p->p_cred->p_ruid = savuid;
1474 uquad = (u_int64_t)freenum;
1475 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1477 if (compare && !(*retcmpp)) {
1478 if (uquad != fxdr_hyper(tl))
1479 *retcmpp = NFSERR_NOTSAME;
1481 attrsum += NFSX_HYPER;
1483 case NFSATTRBIT_QUOTASOFT:
1484 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1486 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1487 freenum = sbp->f_bfree;
1489 freenum = sbp->f_bavail;
1492 * ufs_quotactl() insists that the uid argument
1493 * equal p_ruid for non-root quota access, so
1494 * we'll just make sure that's the case.
1496 savuid = p->p_cred->p_ruid;
1497 p->p_cred->p_ruid = cred->cr_uid;
1498 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1499 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1500 freenum = min(dqb.dqb_bsoftlimit, freenum);
1501 p->p_cred->p_ruid = savuid;
1503 uquad = (u_int64_t)freenum;
1504 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1506 if (compare && !(*retcmpp)) {
1507 if (uquad != fxdr_hyper(tl))
1508 *retcmpp = NFSERR_NOTSAME;
1510 attrsum += NFSX_HYPER;
1512 case NFSATTRBIT_QUOTAUSED:
1513 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1518 * ufs_quotactl() insists that the uid argument
1519 * equal p_ruid for non-root quota access, so
1520 * we'll just make sure that's the case.
1522 savuid = p->p_cred->p_ruid;
1523 p->p_cred->p_ruid = cred->cr_uid;
1524 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1525 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1526 freenum = dqb.dqb_curblocks;
1527 p->p_cred->p_ruid = savuid;
1529 uquad = (u_int64_t)freenum;
1530 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1532 if (compare && !(*retcmpp)) {
1533 if (uquad != fxdr_hyper(tl))
1534 *retcmpp = NFSERR_NOTSAME;
1536 attrsum += NFSX_HYPER;
1538 case NFSATTRBIT_RAWDEV:
1539 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1540 j = fxdr_unsigned(int, *tl++);
1541 k = fxdr_unsigned(int, *tl);
1544 if (nap->na_rdev != NFSMAKEDEV(j, k))
1545 *retcmpp = NFSERR_NOTSAME;
1547 } else if (nap != NULL) {
1548 nap->na_rdev = NFSMAKEDEV(j, k);
1550 attrsum += NFSX_V4SPECDATA;
1552 case NFSATTRBIT_SPACEAVAIL:
1553 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1556 sfp->sf_abytes != fxdr_hyper(tl))
1557 *retcmpp = NFSERR_NOTSAME;
1558 } else if (sfp != NULL) {
1559 sfp->sf_abytes = fxdr_hyper(tl);
1561 attrsum += NFSX_HYPER;
1563 case NFSATTRBIT_SPACEFREE:
1564 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1567 sfp->sf_fbytes != fxdr_hyper(tl))
1568 *retcmpp = NFSERR_NOTSAME;
1569 } else if (sfp != NULL) {
1570 sfp->sf_fbytes = fxdr_hyper(tl);
1572 attrsum += NFSX_HYPER;
1574 case NFSATTRBIT_SPACETOTAL:
1575 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1578 sfp->sf_tbytes != fxdr_hyper(tl))
1579 *retcmpp = NFSERR_NOTSAME;
1580 } else if (sfp != NULL) {
1581 sfp->sf_tbytes = fxdr_hyper(tl);
1583 attrsum += NFSX_HYPER;
1585 case NFSATTRBIT_SPACEUSED:
1586 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1587 thyp = fxdr_hyper(tl);
1590 if ((u_int64_t)nap->na_bytes != thyp)
1591 *retcmpp = NFSERR_NOTSAME;
1593 } else if (nap != NULL) {
1594 nap->na_bytes = thyp;
1596 attrsum += NFSX_HYPER;
1598 case NFSATTRBIT_SYSTEM:
1599 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1600 if (compare && !(*retcmpp))
1601 *retcmpp = NFSERR_ATTRNOTSUPP;
1602 attrsum += NFSX_UNSIGNED;
1604 case NFSATTRBIT_TIMEACCESS:
1605 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1606 fxdr_nfsv4time(tl, &temptime);
1609 if (!NFS_CMPTIME(temptime, nap->na_atime))
1610 *retcmpp = NFSERR_NOTSAME;
1612 } else if (nap != NULL) {
1613 nap->na_atime = temptime;
1615 attrsum += NFSX_V4TIME;
1617 case NFSATTRBIT_TIMEACCESSSET:
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1619 attrsum += NFSX_UNSIGNED;
1620 i = fxdr_unsigned(int, *tl);
1621 if (i == NFSV4SATTRTIME_TOCLIENT) {
1622 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1623 attrsum += NFSX_V4TIME;
1625 if (compare && !(*retcmpp))
1626 *retcmpp = NFSERR_INVAL;
1628 case NFSATTRBIT_TIMEBACKUP:
1629 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1630 if (compare && !(*retcmpp))
1631 *retcmpp = NFSERR_ATTRNOTSUPP;
1632 attrsum += NFSX_V4TIME;
1634 case NFSATTRBIT_TIMECREATE:
1635 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1636 if (compare && !(*retcmpp))
1637 *retcmpp = NFSERR_ATTRNOTSUPP;
1638 attrsum += NFSX_V4TIME;
1640 case NFSATTRBIT_TIMEDELTA:
1641 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1645 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1646 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1647 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1648 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1651 *retcmpp = NFSERR_NOTSAME;
1654 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1657 attrsum += NFSX_V4TIME;
1659 case NFSATTRBIT_TIMEMETADATA:
1660 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1661 fxdr_nfsv4time(tl, &temptime);
1664 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1665 *retcmpp = NFSERR_NOTSAME;
1667 } else if (nap != NULL) {
1668 nap->na_ctime = temptime;
1670 attrsum += NFSX_V4TIME;
1672 case NFSATTRBIT_TIMEMODIFY:
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1674 fxdr_nfsv4time(tl, &temptime);
1677 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1678 *retcmpp = NFSERR_NOTSAME;
1680 } else if (nap != NULL) {
1681 nap->na_mtime = temptime;
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMEMODIFYSET:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1687 attrsum += NFSX_UNSIGNED;
1688 i = fxdr_unsigned(int, *tl);
1689 if (i == NFSV4SATTRTIME_TOCLIENT) {
1690 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1691 attrsum += NFSX_V4TIME;
1693 if (compare && !(*retcmpp))
1694 *retcmpp = NFSERR_INVAL;
1696 case NFSATTRBIT_MOUNTEDONFILEID:
1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1698 thyp = fxdr_hyper(tl);
1702 *retcmpp = NFSERR_NOTSAME;
1704 if (!vp || !nfsrv_atroot(vp, &fid))
1705 fid = nap->na_fileid;
1706 if ((u_int64_t)fid != thyp)
1707 *retcmpp = NFSERR_NOTSAME;
1710 } else if (nap != NULL) {
1712 printf("NFSv4 mounted on fileid > 32bits\n");
1713 nap->na_mntonfileno = thyp;
1715 attrsum += NFSX_HYPER;
1718 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1720 if (compare && !(*retcmpp))
1721 *retcmpp = NFSERR_ATTRNOTSUPP;
1723 * and get out of the loop, since we can't parse
1724 * the unknown attrbute data.
1726 bitpos = NFSATTRBIT_MAX;
1732 * some clients pad the attrlist, so we need to skip over the
1735 if (attrsum > attrsize) {
1736 error = NFSERR_BADXDR;
1738 attrsize = NFSM_RNDUP(attrsize);
1739 if (attrsum < attrsize)
1740 error = nfsm_advance(nd, attrsize - attrsum, -1);
1743 NFSEXITCODE2(error, nd);
1748 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1749 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1750 * The first argument is a pointer to an nfsv4lock structure.
1751 * The second argument is 1 iff a blocking lock is wanted.
1752 * If this argument is 0, the call waits until no thread either wants nor
1753 * holds an exclusive lock.
1754 * It returns 1 if the lock was acquired, 0 otherwise.
1755 * If several processes call this function concurrently wanting the exclusive
1756 * lock, one will get the lock and the rest will return without getting the
1757 * lock. (If the caller must have the lock, it simply calls this function in a
1758 * loop until the function returns 1 to indicate the lock was acquired.)
1759 * Any usecnt must be decremented by calling nfsv4_relref() before
1760 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1761 * be called in a loop.
1762 * The isleptp argument is set to indicate if the call slept, iff not NULL
1763 * and the mp argument indicates to check for a forced dismount, iff not
1767 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1768 void *mutex, struct mount *mp)
1774 * If a lock is wanted, loop around until the lock is acquired by
1775 * someone and then released. If I want the lock, try to acquire it.
1776 * For a lock to be issued, no lock must be in force and the usecnt
1780 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1781 lp->nfslock_usecnt == 0) {
1782 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1783 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1786 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1788 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1789 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1790 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1793 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1796 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1797 PZERO - 1, "nfsv4lck", NULL);
1798 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1799 lp->nfslock_usecnt == 0) {
1800 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1801 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1809 * Release the lock acquired by nfsv4_lock().
1810 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1811 * incremented, as well.
1814 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1817 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1819 lp->nfslock_usecnt++;
1824 * Release a reference cnt.
1827 nfsv4_relref(struct nfsv4lock *lp)
1830 if (lp->nfslock_usecnt <= 0)
1831 panic("nfsv4root ref cnt");
1832 lp->nfslock_usecnt--;
1833 if (lp->nfslock_usecnt == 0)
1838 * Get a reference cnt.
1839 * This function will wait for any exclusive lock to be released, but will
1840 * not wait for threads that want the exclusive lock. If priority needs
1841 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1842 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1843 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1844 * return without getting a refcnt for that case.
1847 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1855 * Wait for a lock held.
1857 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1858 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1860 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1863 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1864 PZERO - 1, "nfsv4lck", NULL);
1866 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1869 lp->nfslock_usecnt++;
1873 * Get a reference as above, but return failure instead of sleeping if
1874 * an exclusive lock is held.
1877 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1880 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1883 lp->nfslock_usecnt++;
1888 * Test for a lock. Return 1 if locked, 0 otherwise.
1891 nfsv4_testlock(struct nfsv4lock *lp)
1894 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1895 lp->nfslock_usecnt == 0)
1901 * Wake up anyone sleeping, waiting for this lock.
1904 nfsv4_wanted(struct nfsv4lock *lp)
1907 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1908 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1909 wakeup((caddr_t)&lp->nfslock_lock);
1914 * Copy a string from an mbuf list into a character array.
1915 * Return EBADRPC if there is an mbuf error,
1919 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1928 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1929 rem = NFSM_RNDUP(siz) - siz;
1935 NFSBCOPY(cp, str, xfer);
1944 cp = NFSMTOD(mp, caddr_t);
1956 error = nfsm_advance(nd, rem, len);
1962 NFSEXITCODE2(error, nd);
1967 * Fill in the attributes as marked by the bitmap (V4).
1970 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1971 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1972 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1973 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1975 int bitpos, retnum = 0;
1977 int siz, prefixnum, error;
1978 u_char *cp, namestr[NFSV4_SMALLSTR];
1979 nfsattrbit_t attrbits, retbits;
1980 nfsattrbit_t *retbitp = &retbits;
1981 u_int32_t freenum, *retnump;
1984 struct nfsfsinfo fsinf;
1985 struct timespec temptime;
1986 NFSACL_T *aclp, *naclp = NULL;
1993 * First, set the bits that can be filled and get fsinfo.
1995 NFSSET_ATTRBIT(retbitp, attrbitp);
1997 * If both p and cred are NULL, it is a client side setattr call.
1998 * If both p and cred are not NULL, it is a server side reply call.
1999 * If p is not NULL and cred is NULL, it is a client side callback
2002 if (p == NULL && cred == NULL) {
2003 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2006 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2007 naclp = acl_alloc(M_WAITOK);
2010 nfsvno_getfs(&fsinf, isdgram);
2013 * Get the VFS_STATFS(), since some attributes need them.
2015 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2016 error = VFS_STATFS(mp, &fs);
2019 nd->nd_repstat = NFSERR_ACCES;
2022 NFSCLRSTATFS_ATTRBIT(retbitp);
2028 * And the NFSv4 ACL...
2030 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2031 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2032 supports_nfsv4acls == 0))) {
2033 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2035 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2036 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2037 supports_nfsv4acls == 0)) {
2038 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2039 } else if (naclp != NULL) {
2040 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2041 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2043 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2045 NFSVOPUNLOCK(vp, 0);
2047 error = NFSERR_PERM;
2050 nd->nd_repstat = NFSERR_ACCES;
2053 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2058 * Put out the attribute bitmap for the ones being filled in
2059 * and get the field for the number of attributes returned.
2061 prefixnum = nfsrv_putattrbit(nd, retbitp);
2062 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2063 prefixnum += NFSX_UNSIGNED;
2066 * Now, loop around filling in the attributes for each bit set.
2068 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2069 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2071 case NFSATTRBIT_SUPPORTEDATTRS:
2072 NFSSETSUPP_ATTRBIT(&attrbits);
2073 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2074 && supports_nfsv4acls == 0)) {
2075 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2076 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2078 retnum += nfsrv_putattrbit(nd, &attrbits);
2080 case NFSATTRBIT_TYPE:
2081 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2082 *tl = vtonfsv34_type(vap->va_type);
2083 retnum += NFSX_UNSIGNED;
2085 case NFSATTRBIT_FHEXPIRETYPE:
2086 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2087 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2088 retnum += NFSX_UNSIGNED;
2090 case NFSATTRBIT_CHANGE:
2091 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2092 txdr_hyper(vap->va_filerev, tl);
2093 retnum += NFSX_HYPER;
2095 case NFSATTRBIT_SIZE:
2096 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2097 txdr_hyper(vap->va_size, tl);
2098 retnum += NFSX_HYPER;
2100 case NFSATTRBIT_LINKSUPPORT:
2101 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2102 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2106 retnum += NFSX_UNSIGNED;
2108 case NFSATTRBIT_SYMLINKSUPPORT:
2109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2114 retnum += NFSX_UNSIGNED;
2116 case NFSATTRBIT_NAMEDATTR:
2117 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2119 retnum += NFSX_UNSIGNED;
2121 case NFSATTRBIT_FSID:
2122 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2124 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2126 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2127 retnum += NFSX_V4FSID;
2129 case NFSATTRBIT_UNIQUEHANDLES:
2130 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2132 retnum += NFSX_UNSIGNED;
2134 case NFSATTRBIT_LEASETIME:
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2136 *tl = txdr_unsigned(nfsrv_lease);
2137 retnum += NFSX_UNSIGNED;
2139 case NFSATTRBIT_RDATTRERROR:
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2141 *tl = txdr_unsigned(rderror);
2142 retnum += NFSX_UNSIGNED;
2145 * Recommended Attributes. (Only the supported ones.)
2147 case NFSATTRBIT_ACL:
2148 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2150 case NFSATTRBIT_ACLSUPPORT:
2151 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2152 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2153 retnum += NFSX_UNSIGNED;
2155 case NFSATTRBIT_CANSETTIME:
2156 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2157 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2161 retnum += NFSX_UNSIGNED;
2163 case NFSATTRBIT_CASEINSENSITIVE:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2166 retnum += NFSX_UNSIGNED;
2168 case NFSATTRBIT_CASEPRESERVING:
2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2171 retnum += NFSX_UNSIGNED;
2173 case NFSATTRBIT_CHOWNRESTRICTED:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2176 retnum += NFSX_UNSIGNED;
2178 case NFSATTRBIT_FILEHANDLE:
2179 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2181 case NFSATTRBIT_FILEID:
2182 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2184 *tl = txdr_unsigned(vap->va_fileid);
2185 retnum += NFSX_HYPER;
2187 case NFSATTRBIT_FILESAVAIL:
2189 * Check quota and use min(quota, f_ffree).
2191 freenum = fs.f_ffree;
2194 * ufs_quotactl() insists that the uid argument
2195 * equal p_ruid for non-root quota access, so
2196 * we'll just make sure that's the case.
2198 savuid = p->p_cred->p_ruid;
2199 p->p_cred->p_ruid = cred->cr_uid;
2200 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2201 cred->cr_uid, (caddr_t)&dqb))
2202 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2204 p->p_cred->p_ruid = savuid;
2206 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2208 *tl = txdr_unsigned(freenum);
2209 retnum += NFSX_HYPER;
2211 case NFSATTRBIT_FILESFREE:
2212 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2214 *tl = txdr_unsigned(fs.f_ffree);
2215 retnum += NFSX_HYPER;
2217 case NFSATTRBIT_FILESTOTAL:
2218 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2220 *tl = txdr_unsigned(fs.f_files);
2221 retnum += NFSX_HYPER;
2223 case NFSATTRBIT_FSLOCATIONS:
2224 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2227 retnum += 2 * NFSX_UNSIGNED;
2229 case NFSATTRBIT_HOMOGENEOUS:
2230 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2231 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2235 retnum += NFSX_UNSIGNED;
2237 case NFSATTRBIT_MAXFILESIZE:
2238 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2239 uquad = NFSRV_MAXFILESIZE;
2240 txdr_hyper(uquad, tl);
2241 retnum += NFSX_HYPER;
2243 case NFSATTRBIT_MAXLINK:
2244 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2245 *tl = txdr_unsigned(LINK_MAX);
2246 retnum += NFSX_UNSIGNED;
2248 case NFSATTRBIT_MAXNAME:
2249 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2250 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2251 retnum += NFSX_UNSIGNED;
2253 case NFSATTRBIT_MAXREAD:
2254 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2256 *tl = txdr_unsigned(fsinf.fs_rtmax);
2257 retnum += NFSX_HYPER;
2259 case NFSATTRBIT_MAXWRITE:
2260 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2262 *tl = txdr_unsigned(fsinf.fs_wtmax);
2263 retnum += NFSX_HYPER;
2265 case NFSATTRBIT_MODE:
2266 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2267 *tl = vtonfsv34_mode(vap->va_mode);
2268 retnum += NFSX_UNSIGNED;
2270 case NFSATTRBIT_NOTRUNC:
2271 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2273 retnum += NFSX_UNSIGNED;
2275 case NFSATTRBIT_NUMLINKS:
2276 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2277 *tl = txdr_unsigned(vap->va_nlink);
2278 retnum += NFSX_UNSIGNED;
2280 case NFSATTRBIT_OWNER:
2282 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2283 retnum += nfsm_strtom(nd, cp, siz);
2285 free(cp, M_NFSSTRING);
2287 case NFSATTRBIT_OWNERGROUP:
2289 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2290 retnum += nfsm_strtom(nd, cp, siz);
2292 free(cp, M_NFSSTRING);
2294 case NFSATTRBIT_QUOTAHARD:
2295 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2296 freenum = fs.f_bfree;
2298 freenum = fs.f_bavail;
2301 * ufs_quotactl() insists that the uid argument
2302 * equal p_ruid for non-root quota access, so
2303 * we'll just make sure that's the case.
2305 savuid = p->p_cred->p_ruid;
2306 p->p_cred->p_ruid = cred->cr_uid;
2307 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2308 cred->cr_uid, (caddr_t)&dqb))
2309 freenum = min(dqb.dqb_bhardlimit, freenum);
2310 p->p_cred->p_ruid = savuid;
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2313 uquad = (u_int64_t)freenum;
2314 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2315 txdr_hyper(uquad, tl);
2316 retnum += NFSX_HYPER;
2318 case NFSATTRBIT_QUOTASOFT:
2319 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2320 freenum = fs.f_bfree;
2322 freenum = fs.f_bavail;
2325 * ufs_quotactl() insists that the uid argument
2326 * equal p_ruid for non-root quota access, so
2327 * we'll just make sure that's the case.
2329 savuid = p->p_cred->p_ruid;
2330 p->p_cred->p_ruid = cred->cr_uid;
2331 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2332 cred->cr_uid, (caddr_t)&dqb))
2333 freenum = min(dqb.dqb_bsoftlimit, freenum);
2334 p->p_cred->p_ruid = savuid;
2336 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2337 uquad = (u_int64_t)freenum;
2338 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2339 txdr_hyper(uquad, tl);
2340 retnum += NFSX_HYPER;
2342 case NFSATTRBIT_QUOTAUSED:
2346 * ufs_quotactl() insists that the uid argument
2347 * equal p_ruid for non-root quota access, so
2348 * we'll just make sure that's the case.
2350 savuid = p->p_cred->p_ruid;
2351 p->p_cred->p_ruid = cred->cr_uid;
2352 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2353 cred->cr_uid, (caddr_t)&dqb))
2354 freenum = dqb.dqb_curblocks;
2355 p->p_cred->p_ruid = savuid;
2357 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2358 uquad = (u_int64_t)freenum;
2359 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2360 txdr_hyper(uquad, tl);
2361 retnum += NFSX_HYPER;
2363 case NFSATTRBIT_RAWDEV:
2364 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2365 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2366 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2367 retnum += NFSX_V4SPECDATA;
2369 case NFSATTRBIT_SPACEAVAIL:
2370 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2371 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2372 uquad = (u_int64_t)fs.f_bfree;
2374 uquad = (u_int64_t)fs.f_bavail;
2375 uquad *= fs.f_bsize;
2376 txdr_hyper(uquad, tl);
2377 retnum += NFSX_HYPER;
2379 case NFSATTRBIT_SPACEFREE:
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2381 uquad = (u_int64_t)fs.f_bfree;
2382 uquad *= fs.f_bsize;
2383 txdr_hyper(uquad, tl);
2384 retnum += NFSX_HYPER;
2386 case NFSATTRBIT_SPACETOTAL:
2387 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2388 uquad = (u_int64_t)fs.f_blocks;
2389 uquad *= fs.f_bsize;
2390 txdr_hyper(uquad, tl);
2391 retnum += NFSX_HYPER;
2393 case NFSATTRBIT_SPACEUSED:
2394 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2395 txdr_hyper(vap->va_bytes, tl);
2396 retnum += NFSX_HYPER;
2398 case NFSATTRBIT_TIMEACCESS:
2399 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2400 txdr_nfsv4time(&vap->va_atime, tl);
2401 retnum += NFSX_V4TIME;
2403 case NFSATTRBIT_TIMEACCESSSET:
2404 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2405 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2406 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2407 txdr_nfsv4time(&vap->va_atime, tl);
2408 retnum += NFSX_V4SETTIME;
2410 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2411 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2412 retnum += NFSX_UNSIGNED;
2415 case NFSATTRBIT_TIMEDELTA:
2416 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2417 temptime.tv_sec = 0;
2418 temptime.tv_nsec = 1000000000 / hz;
2419 txdr_nfsv4time(&temptime, tl);
2420 retnum += NFSX_V4TIME;
2422 case NFSATTRBIT_TIMEMETADATA:
2423 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2424 txdr_nfsv4time(&vap->va_ctime, tl);
2425 retnum += NFSX_V4TIME;
2427 case NFSATTRBIT_TIMEMODIFY:
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2429 txdr_nfsv4time(&vap->va_mtime, tl);
2430 retnum += NFSX_V4TIME;
2432 case NFSATTRBIT_TIMEMODIFYSET:
2433 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2434 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2435 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2436 txdr_nfsv4time(&vap->va_mtime, tl);
2437 retnum += NFSX_V4SETTIME;
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2440 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2441 retnum += NFSX_UNSIGNED;
2444 case NFSATTRBIT_MOUNTEDONFILEID:
2445 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2447 uquad = mounted_on_fileno;
2449 uquad = (u_int64_t)vap->va_fileid;
2450 txdr_hyper(uquad, tl);
2451 retnum += NFSX_HYPER;
2454 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2460 *retnump = txdr_unsigned(retnum);
2461 return (retnum + prefixnum);
2465 * Put the attribute bits onto an mbuf list.
2466 * Return the number of bytes of output generated.
2469 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2472 int cnt, i, bytesize;
2474 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2475 if (attrbitp->bits[cnt - 1])
2477 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2478 NFSM_BUILD(tl, u_int32_t *, bytesize);
2479 *tl++ = txdr_unsigned(cnt);
2480 for (i = 0; i < cnt; i++)
2481 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2486 * Convert a uid to a string.
2487 * If the lookup fails, just output the digits.
2489 * cpp - points to a buffer of size NFSV4_SMALLSTR
2490 * (malloc a larger one, as required)
2491 * retlenp - pointer to length to be returned
2494 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2497 struct nfsusrgrp *usrp;
2500 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2505 if (nfsrv_dnsname) {
2507 * Always map nfsrv_defaultuid to "nobody".
2509 if (uid == nfsrv_defaultuid) {
2510 i = nfsrv_dnsnamelen + 7;
2513 if (len > NFSV4_SMALLSTR)
2514 free(cp, M_NFSSTRING);
2515 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2521 NFSBCOPY("nobody@", cp, 7);
2523 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2528 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2529 if (usrp->lug_uid == uid) {
2530 if (usrp->lug_expiry < NFSD_MONOSEC)
2533 * If the name doesn't already have an '@'
2534 * in it, append @domainname to it.
2536 for (i = 0; i < usrp->lug_namelen; i++) {
2537 if (usrp->lug_name[i] == '@') {
2543 i = usrp->lug_namelen;
2545 i = usrp->lug_namelen +
2546 nfsrv_dnsnamelen + 1;
2549 if (len > NFSV4_SMALLSTR)
2550 free(cp, M_NFSSTRING);
2551 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2557 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2558 if (!hasampersand) {
2559 cp += usrp->lug_namelen;
2561 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2563 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2564 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2571 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2573 if (ret == 0 && cnt < 2)
2580 * No match, just return a string of digits.
2584 while (tmp || i == 0) {
2588 len = (i > len) ? len : i;
2592 for (i = 0; i < len; i++) {
2593 *cp-- = '0' + (tmp % 10);
2600 * Convert a string to a uid.
2601 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2603 * If this is called from a client side mount using AUTH_SYS and the
2604 * string is made up entirely of digits, just convert the string to
2608 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2612 char *cp, *endstr, *str0;
2613 struct nfsusrgrp *usrp;
2619 error = NFSERR_BADOWNER;
2622 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2624 tuid = (uid_t)strtoul(str0, &endstr, 10);
2625 if ((endstr - str0) == len) {
2626 /* A numeric string. */
2627 if ((nd->nd_flag & ND_KERBV) == 0 &&
2628 ((nd->nd_flag & ND_NFSCL) != 0 ||
2629 nfsd_enable_stringtouid != 0))
2632 error = NFSERR_BADOWNER;
2638 cp = strchr(str0, '@');
2640 i = (int)(cp++ - str0);
2648 * If an '@' is found and the domain name matches, search for the name
2649 * with dns stripped off.
2650 * Mixed case alpahbetics will match for the domain name, but all
2651 * upper case will not.
2653 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2654 (len - 1 - i) == nfsrv_dnsnamelen &&
2655 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2656 len -= (nfsrv_dnsnamelen + 1);
2661 * Check for the special case of "nobody".
2663 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2664 *uidp = nfsrv_defaultuid;
2670 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2671 if (usrp->lug_namelen == len &&
2672 !NFSBCMP(usrp->lug_name, str, len)) {
2673 if (usrp->lug_expiry < NFSD_MONOSEC)
2675 *uidp = usrp->lug_uid;
2676 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2677 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2685 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2687 if (ret == 0 && cnt < 2)
2689 error = NFSERR_BADOWNER;
2697 * Convert a gid to a string.
2698 * gid - the group id
2699 * cpp - points to a buffer of size NFSV4_SMALLSTR
2700 * (malloc a larger one, as required)
2701 * retlenp - pointer to length to be returned
2704 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2707 struct nfsusrgrp *usrp;
2710 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2715 if (nfsrv_dnsname) {
2717 * Always map nfsrv_defaultgid to "nogroup".
2719 if (gid == nfsrv_defaultgid) {
2720 i = nfsrv_dnsnamelen + 8;
2723 if (len > NFSV4_SMALLSTR)
2724 free(cp, M_NFSSTRING);
2725 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2731 NFSBCOPY("nogroup@", cp, 8);
2733 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2738 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2739 if (usrp->lug_gid == gid) {
2740 if (usrp->lug_expiry < NFSD_MONOSEC)
2743 * If the name doesn't already have an '@'
2744 * in it, append @domainname to it.
2746 for (i = 0; i < usrp->lug_namelen; i++) {
2747 if (usrp->lug_name[i] == '@') {
2753 i = usrp->lug_namelen;
2755 i = usrp->lug_namelen +
2756 nfsrv_dnsnamelen + 1;
2759 if (len > NFSV4_SMALLSTR)
2760 free(cp, M_NFSSTRING);
2761 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2767 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2768 if (!hasampersand) {
2769 cp += usrp->lug_namelen;
2771 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2773 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2774 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2781 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2783 if (ret == 0 && cnt < 2)
2790 * No match, just return a string of digits.
2794 while (tmp || i == 0) {
2798 len = (i > len) ? len : i;
2802 for (i = 0; i < len; i++) {
2803 *cp-- = '0' + (tmp % 10);
2810 * Convert a string to a gid.
2811 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2813 * If this is called from a client side mount using AUTH_SYS and the
2814 * string is made up entirely of digits, just convert the string to
2818 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2822 char *cp, *endstr, *str0;
2823 struct nfsusrgrp *usrp;
2829 error = NFSERR_BADOWNER;
2832 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2834 tgid = (gid_t)strtoul(str0, &endstr, 10);
2835 if ((endstr - str0) == len) {
2836 /* A numeric string. */
2837 if ((nd->nd_flag & ND_KERBV) == 0 &&
2838 ((nd->nd_flag & ND_NFSCL) != 0 ||
2839 nfsd_enable_stringtouid != 0))
2842 error = NFSERR_BADOWNER;
2848 cp = strchr(str0, '@');
2850 i = (int)(cp++ - str0);
2858 * If an '@' is found and the dns name matches, search for the name
2859 * with the dns stripped off.
2861 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2862 (len - 1 - i) == nfsrv_dnsnamelen &&
2863 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2864 len -= (nfsrv_dnsnamelen + 1);
2869 * Check for the special case of "nogroup".
2871 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2872 *gidp = nfsrv_defaultgid;
2878 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2879 if (usrp->lug_namelen == len &&
2880 !NFSBCMP(usrp->lug_name, str, len)) {
2881 if (usrp->lug_expiry < NFSD_MONOSEC)
2883 *gidp = usrp->lug_gid;
2884 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2885 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2893 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2895 if (ret == 0 && cnt < 2)
2897 error = NFSERR_BADOWNER;
2905 * Cmp len chars, allowing mixed case in the first argument to match lower
2906 * case in the second, but not if the first argument is all upper case.
2907 * Return 0 for a match, 1 otherwise.
2910 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2916 for (i = 0; i < len; i++) {
2917 if (*cp >= 'A' && *cp <= 'Z') {
2918 tmp = *cp++ + ('a' - 'A');
2921 if (tmp >= 'a' && tmp <= 'z')
2934 * Set the port for the nfsuserd.
2937 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2939 struct nfssockreq *rp;
2940 struct sockaddr_in *ad;
2944 if (nfsrv_nfsuserd) {
2952 * Set up the socket record and connect.
2954 rp = &nfsrv_nfsuserdsock;
2955 rp->nr_client = NULL;
2956 rp->nr_sotype = SOCK_DGRAM;
2957 rp->nr_soproto = IPPROTO_UDP;
2958 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2960 NFSSOCKADDRALLOC(rp->nr_nam);
2961 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2962 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2963 ad->sin_family = AF_INET;
2964 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2965 ad->sin_port = port;
2966 rp->nr_prog = RPCPROG_NFSUSERD;
2967 rp->nr_vers = RPCNFSUSERD_VERS;
2968 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2970 NFSSOCKADDRFREE(rp->nr_nam);
2979 * Delete the nfsuserd port.
2982 nfsrv_nfsuserddelport(void)
2986 if (nfsrv_nfsuserd == 0) {
2992 newnfs_disconnect(&nfsrv_nfsuserdsock);
2993 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2997 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2999 * Returns 0 upon success, non-zero otherwise.
3002 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3005 struct nfsrv_descript *nd;
3007 struct nfsrv_descript nfsd;
3012 if (nfsrv_nfsuserd == 0) {
3019 cred = newnfs_getcred();
3020 nd->nd_flag = ND_GSSINITREPLY;
3023 nd->nd_procnum = procnum;
3024 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3025 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3026 if (procnum == RPCNFSUSERD_GETUID)
3027 *tl = txdr_unsigned(uid);
3029 *tl = txdr_unsigned(gid);
3032 (void) nfsm_strtom(nd, name, len);
3034 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3035 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
3038 mbuf_freem(nd->nd_mrep);
3039 error = nd->nd_repstat;
3047 * This function is called from the nfssvc(2) system call, to update the
3048 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3051 nfssvc_idname(struct nfsd_idargs *nidp)
3053 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3054 struct nfsuserhashhead *hp;
3059 if (nidp->nid_flag & NFSID_INITIALIZE) {
3060 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3061 M_NFSSTRING, M_WAITOK);
3062 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3065 if (nfsrv_dnsname) {
3067 * Free up all the old stuff and reinitialize hash lists.
3069 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3070 nfsrv_removeuser(usrp);
3072 free(nfsrv_dnsname, M_NFSSTRING);
3073 nfsrv_dnsname = NULL;
3075 TAILQ_INIT(&nfsuserlruhead);
3076 for (i = 0; i < NFSUSERHASHSIZE; i++)
3077 LIST_INIT(&nfsuserhash[i]);
3078 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3079 LIST_INIT(&nfsgrouphash[i]);
3080 for (i = 0; i < NFSUSERHASHSIZE; i++)
3081 LIST_INIT(&nfsusernamehash[i]);
3082 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3083 LIST_INIT(&nfsgroupnamehash[i]);
3086 * Put name in "DNS" string.
3090 nfsrv_dnsnamelen = nidp->nid_namelen;
3091 nfsrv_defaultuid = nidp->nid_uid;
3092 nfsrv_defaultgid = nidp->nid_gid;
3094 nfsrv_usermax = nidp->nid_usermax;
3098 free(cp, M_NFSSTRING);
3103 * malloc the new one now, so any potential sleep occurs before
3104 * manipulation of the lists.
3106 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3107 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3108 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3111 free((caddr_t)newusrp, M_NFSUSERGROUP);
3114 newusrp->lug_namelen = nidp->nid_namelen;
3118 * Delete old entries, as required.
3120 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3121 hp = NFSUSERHASH(nidp->nid_uid);
3122 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3123 if (usrp->lug_uid == nidp->nid_uid)
3124 nfsrv_removeuser(usrp);
3127 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3128 hp = NFSUSERNAMEHASH(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 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3137 hp = NFSGROUPHASH(nidp->nid_gid);
3138 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3139 if (usrp->lug_gid == nidp->nid_gid)
3140 nfsrv_removeuser(usrp);
3143 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3144 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3145 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3146 if (usrp->lug_namelen == newusrp->lug_namelen &&
3147 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3149 nfsrv_removeuser(usrp);
3152 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3153 if (usrp->lug_expiry < NFSD_MONOSEC)
3154 nfsrv_removeuser(usrp);
3156 while (nfsrv_usercnt >= nfsrv_usermax) {
3157 usrp = TAILQ_FIRST(&nfsuserlruhead);
3158 nfsrv_removeuser(usrp);
3162 * Now, we can add the new one.
3164 if (nidp->nid_usertimeout)
3165 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3167 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3168 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3169 newusrp->lug_uid = nidp->nid_uid;
3170 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3172 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3173 newusrp->lug_namelen), newusrp, lug_namehash);
3174 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3176 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3177 newusrp->lug_gid = nidp->nid_gid;
3178 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3180 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3181 newusrp->lug_namelen), newusrp, lug_namehash);
3182 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3185 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3193 * Remove a user/group name element.
3196 nfsrv_removeuser(struct nfsusrgrp *usrp)
3199 NFSNAMEIDREQUIRED();
3200 LIST_REMOVE(usrp, lug_numhash);
3201 LIST_REMOVE(usrp, lug_namehash);
3202 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3204 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3208 * This function scans a byte string and checks for UTF-8 compliance.
3209 * It returns 0 if it conforms and NFSERR_INVAL if not.
3212 nfsrv_checkutf8(u_int8_t *cp, int len)
3214 u_int32_t val = 0x0;
3215 int cnt = 0, gotd = 0, shift = 0;
3217 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3221 * Here are what the variables are used for:
3222 * val - the calculated value of a multibyte char, used to check
3223 * that it was coded with the correct range
3224 * cnt - the number of 10xxxxxx bytes to follow
3225 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3226 * shift - lower order bits of range (ie. "val >> shift" should
3227 * not be 0, in other words, dividing by the lower bound
3228 * of the range should get a non-zero value)
3229 * byte - used to calculate cnt
3233 /* This handles the 10xxxxxx bytes */
3234 if ((*cp & 0xc0) != 0x80 ||
3235 (gotd && (*cp & 0x20))) {
3236 error = NFSERR_INVAL;
3241 val |= (*cp & 0x3f);
3243 if (cnt == 0 && (val >> shift) == 0x0) {
3244 error = NFSERR_INVAL;
3247 } else if (*cp & 0x80) {
3248 /* first byte of multi byte char */
3250 while ((byte & 0x40) && cnt < 6) {
3254 if (cnt == 0 || cnt == 6) {
3255 error = NFSERR_INVAL;
3258 val = (*cp & (0x3f >> cnt));
3259 shift = utf8_shift[cnt - 1];
3260 if (cnt == 2 && val == 0xd)
3261 /* Check for the 0xd800-0xdfff case */
3268 error = NFSERR_INVAL;
3276 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3277 * strings, one with the root path in it and the other with the list of
3278 * locations. The list is in the same format as is found in nfr_refs.
3279 * It is a "," separated list of entries, where each of them is of the
3280 * form <server>:<rootpath>. For example
3281 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3282 * The nilp argument is set to 1 for the special case of a null fs_root
3283 * and an empty server list.
3284 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3285 * number of xdr bytes parsed in sump.
3288 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3289 int *sump, int *nilp)
3292 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3293 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3295 SLIST_ENTRY(list) next;
3299 SLIST_HEAD(, list) head;
3306 * Get the fs_root path and check for the special case of null path
3307 * and 0 length server list.
3309 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3310 len = fxdr_unsigned(int, *tl);
3311 if (len < 0 || len > 10240) {
3312 error = NFSERR_BADXDR;
3316 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3318 error = NFSERR_BADXDR;
3322 *sump = 2 * NFSX_UNSIGNED;
3326 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3327 error = nfsrv_mtostr(nd, cp, len);
3329 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3330 cnt = fxdr_unsigned(int, *tl);
3332 error = NFSERR_BADXDR;
3338 * Now, loop through the location list and make up the srvlist.
3340 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3341 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3344 for (i = 0; i < cnt; i++) {
3346 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3347 nsrv = fxdr_unsigned(int, *tl);
3349 error = NFSERR_BADXDR;
3354 * Handle the first server by putting it in the srvstr.
3356 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3357 len = fxdr_unsigned(int, *tl);
3358 if (len <= 0 || len > 1024) {
3359 error = NFSERR_BADXDR;
3362 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3367 error = nfsrv_mtostr(nd, cp3, len);
3373 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3374 for (j = 1; j < nsrv; j++) {
3376 * Yuck, put them in an slist and process them later.
3378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3379 len = fxdr_unsigned(int, *tl);
3380 if (len <= 0 || len > 1024) {
3381 error = NFSERR_BADXDR;
3384 lsp = (struct list *)malloc(sizeof (struct list)
3385 + len, M_TEMP, M_WAITOK);
3386 error = nfsrv_mtostr(nd, lsp->host, len);
3389 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3391 SLIST_INSERT_HEAD(&head, lsp, next);
3395 * Finally, we can get the path.
3397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3398 len = fxdr_unsigned(int, *tl);
3399 if (len <= 0 || len > 1024) {
3400 error = NFSERR_BADXDR;
3403 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3404 error = nfsrv_mtostr(nd, cp3, len);
3407 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3412 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3413 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3416 NFSBCOPY(lsp->host, cp3, lsp->len);
3419 NFSBCOPY(str, cp3, stringlen);
3422 siz += (lsp->len + stringlen + 2);
3423 free((caddr_t)lsp, M_TEMP);
3429 NFSEXITCODE2(0, nd);
3433 free(cp, M_NFSSTRING);
3435 free(cp2, M_NFSSTRING);
3436 NFSEXITCODE2(error, nd);
3441 * Make the malloc'd space large enough. This is a pain, but the xdr
3442 * doesn't set an upper bound on the side, so...
3445 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3452 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3453 NFSBCOPY(*cpp, cp, *slenp);
3454 free(*cpp, M_NFSSTRING);
3458 *slenp = siz + 1024;
3462 * Initialize the reply header data structures.
3465 nfsrvd_rephead(struct nfsrv_descript *nd)
3470 * If this is a big reply, use a cluster.
3472 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3473 nfs_bigreply[nd->nd_procnum]) {
3474 NFSMCLGET(mreq, M_WAIT);
3482 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3483 mbuf_setlen(mreq, 0);
3485 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3486 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3490 * Lock a socket against others.
3491 * Currently used to serialize connect/disconnect attempts.
3494 newnfs_sndlock(int *flagp)
3499 while (*flagp & NFSR_SNDLOCK) {
3500 *flagp |= NFSR_WANTSND;
3503 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3504 PZERO - 1, "nfsndlck", &ts);
3506 *flagp |= NFSR_SNDLOCK;
3512 * Unlock the stream socket for others.
3515 newnfs_sndunlock(int *flagp)
3519 if ((*flagp & NFSR_SNDLOCK) == 0)
3520 panic("nfs sndunlock");
3521 *flagp &= ~NFSR_SNDLOCK;
3522 if (*flagp & NFSR_WANTSND) {
3523 *flagp &= ~NFSR_WANTSND;
3524 wakeup((caddr_t)flagp);