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);
203 xfer = (left > len) ? len : left;
206 if (uiop->uio_iov->iov_op != NULL)
207 (*(uiop->uio_iov->iov_op))
208 (mbufcp, uiocp, xfer);
211 if (uiop->uio_segflg == UIO_SYSSPACE)
212 NFSBCOPY(mbufcp, uiocp, xfer);
214 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
219 uiop->uio_offset += xfer;
220 uiop->uio_resid -= xfer;
222 if (uiop->uio_iov->iov_len <= siz) {
226 uiop->uio_iov->iov_base = (void *)
227 ((char *)uiop->uio_iov->iov_base + uiosiz);
228 uiop->uio_iov->iov_len -= uiosiz;
232 nd->nd_dpos = mbufcp;
236 error = nfsm_advance(nd, rem, len);
242 NFSEXITCODE2(error, nd);
248 * Help break down an mbuf chain by setting the first siz bytes contiguous
249 * pointed to by returned val.
250 * This is used by the macro NFSM_DISSECT for tough
254 nfsm_dissct(struct nfsrv_descript *nd, int siz)
263 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
265 nd->nd_md = mbuf_next(nd->nd_md);
266 if (nd->nd_md == NULL)
268 left = mbuf_len(nd->nd_md);
269 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
274 } else if (mbuf_next(nd->nd_md) == NULL) {
276 } else if (siz > ncl_mbuf_mhlen) {
277 panic("nfs S too big");
280 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
281 mbuf_setnext(nd->nd_md, mp2);
282 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
284 retp = p = NFSMTOD(mp2, caddr_t);
285 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
288 mp2 = mbuf_next(mp2);
289 /* Loop around copying up the siz2 bytes */
293 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
295 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
296 NFSM_DATAP(mp2, xfer);
297 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
302 mp2 = mbuf_next(mp2);
304 mbuf_setlen(nd->nd_md, siz);
306 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
312 * Advance the position in the mbuf chain.
313 * If offs == 0, this is a no-op, but it is simpler to just return from
314 * here than check for offs > 0 for all calls to nfsm_advance.
315 * If left == -1, it should be calculated here.
318 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
325 * A negative offs should be considered a serious problem.
328 panic("nfsrv_advance");
331 * If left == -1, calculate it here.
334 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
338 * Loop around, advancing over the mbuf data.
340 while (offs > left) {
342 nd->nd_md = mbuf_next(nd->nd_md);
343 if (nd->nd_md == NULL) {
347 left = mbuf_len(nd->nd_md);
348 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
358 * Copy a string into mbuf(s).
359 * Return the number of bytes output, including XDR overheads.
362 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
371 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
372 *tl = txdr_unsigned(siz);
373 rem = NFSM_RNDUP(siz) - siz;
374 bytesize = NFSX_UNSIGNED + siz + rem;
377 left = M_TRAILINGSPACE(m2);
380 * Loop around copying the string to mbuf(s).
384 if (siz > ncl_mbuf_mlen)
385 NFSMCLGET(m1, M_WAIT);
389 mbuf_setnext(m2, m1);
391 cp2 = NFSMTOD(m2, caddr_t);
392 left = M_TRAILINGSPACE(m2);
398 NFSBCOPY(cp, cp2, xfer);
400 mbuf_setlen(m2, mbuf_len(m2) + xfer);
403 if (siz == 0 && rem) {
405 panic("nfsm_strtom");
406 NFSBZERO(cp2 + xfer, rem);
407 mbuf_setlen(m2, mbuf_len(m2) + rem);
411 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
416 * Called once to initialize data structures...
421 static int nfs_inited = 0;
427 newnfs_true = txdr_unsigned(TRUE);
428 newnfs_false = txdr_unsigned(FALSE);
429 newnfs_xdrneg1 = txdr_unsigned(-1);
430 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
433 NFSSETBOOTTIME(nfsboottime);
436 * Initialize reply list and start timer
438 TAILQ_INIT(&nfsd_reqq);
443 * Put a file handle in an mbuf list.
444 * If the size argument == 0, just use the default size.
445 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
446 * Return the number of bytes output, including XDR overhead.
449 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
453 int fullsiz, rem, bytesize = 0;
457 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
459 if (size > NFSX_V2FH)
460 panic("fh size > NFSX_V2FH for NFSv2");
461 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
462 NFSBCOPY(fhp, cp, size);
463 if (size < NFSX_V2FH)
464 NFSBZERO(cp + size, NFSX_V2FH - size);
465 bytesize = NFSX_V2FH;
469 fullsiz = NFSM_RNDUP(size);
470 rem = fullsiz - size;
472 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
473 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
476 bytesize = NFSX_UNSIGNED + fullsiz;
478 (void) nfsm_strtom(nd, fhp, size);
485 * This function compares two net addresses by family and returns TRUE
486 * if they are the same host.
487 * If there is any doubt, return FALSE.
488 * The AF_INET family is handled as a special case so that address mbufs
489 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
492 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
494 struct sockaddr_in *inetaddr;
498 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
499 if (inetaddr->sin_family == AF_INET &&
500 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
506 struct sockaddr_in6 *inetaddr6;
508 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
509 /* XXX - should test sin6_scope_id ? */
510 if (inetaddr6->sin6_family == AF_INET6 &&
511 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
522 * Similar to the above, but takes to NFSSOCKADDR_T args.
525 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
527 struct sockaddr_in *addr1, *addr2;
528 struct sockaddr *inaddr;
530 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
531 switch (inaddr->sa_family) {
533 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
534 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
535 if (addr2->sin_family == AF_INET &&
536 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
542 struct sockaddr_in6 *inet6addr1, *inet6addr2;
544 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
545 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
546 /* XXX - should test sin6_scope_id ? */
547 if (inet6addr2->sin6_family == AF_INET6 &&
548 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
549 &inet6addr2->sin6_addr))
560 * Trim the stuff already dissected off the mbuf list.
563 newnfs_trimleading(nd)
564 struct nfsrv_descript *nd;
570 * First, free up leading mbufs.
572 if (nd->nd_mrep != nd->nd_md) {
574 while (mbuf_next(m) != nd->nd_md) {
575 if (mbuf_next(m) == NULL)
576 panic("nfsm trim leading");
579 mbuf_setnext(m, NULL);
580 mbuf_freem(nd->nd_mrep);
585 * Now, adjust this mbuf, based on nd_dpos.
587 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
588 if (offs == mbuf_len(m)) {
592 panic("nfsm trim leading2");
593 mbuf_setnext(n, NULL);
595 } else if (offs > 0) {
596 mbuf_setlen(m, mbuf_len(m) - offs);
599 panic("nfsm trimleading offs");
602 nd->nd_dpos = NFSMTOD(m, caddr_t);
606 * Trim trailing data off the mbuf list being built.
609 newnfs_trimtrailing(nd, mb, bpos)
610 struct nfsrv_descript *nd;
616 mbuf_freem(mbuf_next(mb));
617 mbuf_setnext(mb, NULL);
619 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
625 * Dissect a file handle on the client.
628 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
635 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
636 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
637 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
644 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
646 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
648 FREE((caddr_t)nfhp, M_NFSFH);
654 NFSEXITCODE2(error, nd);
659 * Break down the nfsv4 acl.
660 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
663 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
664 int *aclsizep, __unused NFSPROC_T *p)
668 int acecnt, error = 0, aceerr = 0, acesize;
674 * Parse out the ace entries and expect them to conform to
675 * what can be supported by R/W/X bits.
677 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
678 aclsize = NFSX_UNSIGNED;
679 acecnt = fxdr_unsigned(int, *tl);
680 if (acecnt > ACL_MAX_ENTRIES)
681 aceerr = NFSERR_ATTRNOTSUPP;
682 if (nfsrv_useacl == 0)
683 aceerr = NFSERR_ATTRNOTSUPP;
684 for (i = 0; i < acecnt; i++) {
686 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
687 &aceerr, &acesize, p);
689 error = nfsrv_skipace(nd, &acesize);
695 aclp->acl_cnt = acecnt;
701 NFSEXITCODE2(error, nd);
706 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
709 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
714 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
715 len = fxdr_unsigned(int, *(tl + 3));
716 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
718 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
719 NFSEXITCODE2(error, nd);
724 * Get attribute bits from an mbuf list.
725 * Returns EBADRPC for a parsing error, 0 otherwise.
726 * If the clearinvalid flag is set, clear the bits not supported.
729 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
737 cnt = fxdr_unsigned(int, *tl);
739 error = NFSERR_BADXDR;
742 if (cnt > NFSATTRBIT_MAXWORDS) {
743 outcnt = NFSATTRBIT_MAXWORDS;
745 *retnotsupp = NFSERR_ATTRNOTSUPP;
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++);
756 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
758 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
760 NFSEXITCODE2(error, nd);
765 * Get the attributes for V4.
766 * If the compare flag is true, test for any attribute changes,
767 * otherwise return the attribute values.
768 * These attributes cover fields in "struct vattr", "struct statfs",
769 * "struct nfsfsinfo", the file handle and the lease duration.
770 * The value of retcmpp is set to 1 if all attributes are the same,
772 * Returns EBADRPC if it can't be parsed, 0 otherwise.
775 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
776 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
777 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
778 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
779 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
782 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
783 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
784 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
785 nfsattrbit_t attrbits, retattrbits, checkattrbits;
787 struct nfsreferral *refp;
790 struct timespec temptime;
794 u_int32_t freenum = 0, tuint;
795 u_int64_t uquad = 0, thyp, thyp2;
803 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
805 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
811 *retcmpp = retnotsup;
814 * Just set default values to some of the important ones.
819 nap->na_rdev = (NFSDEV_T)0;
820 nap->na_mtime.tv_sec = 0;
821 nap->na_mtime.tv_nsec = 0;
824 nap->na_blocksize = NFS_FABLKSIZE;
827 sbp->f_bsize = NFS_FABLKSIZE;
835 fsp->fs_rtmax = 8192;
836 fsp->fs_rtpref = 8192;
837 fsp->fs_maxname = NFS_MAXNAMLEN;
838 fsp->fs_wtmax = 8192;
839 fsp->fs_wtpref = 8192;
840 fsp->fs_wtmult = NFS_FABLKSIZE;
841 fsp->fs_dtpref = 8192;
842 fsp->fs_maxfilesize = 0xffffffffffffffffull;
843 fsp->fs_timedelta.tv_sec = 0;
844 fsp->fs_timedelta.tv_nsec = 1;
845 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
846 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
849 pc->pc_linkmax = LINK_MAX;
850 pc->pc_namemax = NAME_MAX;
852 pc->pc_chownrestricted = 0;
853 pc->pc_caseinsensitive = 0;
854 pc->pc_casepreserving = 1;
859 * Loop around getting the attributes.
861 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
862 attrsize = fxdr_unsigned(int, *tl);
863 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
864 if (attrsum > attrsize) {
865 error = NFSERR_BADXDR;
868 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
870 case NFSATTRBIT_SUPPORTEDATTRS:
872 if (compare || nap == NULL)
873 error = nfsrv_getattrbits(nd, &retattrbits,
876 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
880 if (compare && !(*retcmpp)) {
881 NFSSETSUPP_ATTRBIT(&checkattrbits);
882 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
884 *retcmpp = NFSERR_NOTSAME;
888 case NFSATTRBIT_TYPE:
889 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
892 if (nap->na_type != nfsv34tov_type(*tl))
893 *retcmpp = NFSERR_NOTSAME;
895 } else if (nap != NULL) {
896 nap->na_type = nfsv34tov_type(*tl);
898 attrsum += NFSX_UNSIGNED;
900 case NFSATTRBIT_FHEXPIRETYPE:
901 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
902 if (compare && !(*retcmpp)) {
903 if (fxdr_unsigned(int, *tl) !=
904 NFSV4FHTYPE_PERSISTENT)
905 *retcmpp = NFSERR_NOTSAME;
907 attrsum += NFSX_UNSIGNED;
909 case NFSATTRBIT_CHANGE:
910 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
913 if (nap->na_filerev != fxdr_hyper(tl))
914 *retcmpp = NFSERR_NOTSAME;
916 } else if (nap != NULL) {
917 nap->na_filerev = fxdr_hyper(tl);
919 attrsum += NFSX_HYPER;
921 case NFSATTRBIT_SIZE:
922 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
925 if (nap->na_size != fxdr_hyper(tl))
926 *retcmpp = NFSERR_NOTSAME;
928 } else if (nap != NULL) {
929 nap->na_size = fxdr_hyper(tl);
931 attrsum += NFSX_HYPER;
933 case NFSATTRBIT_LINKSUPPORT:
934 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
937 if (fsp->fs_properties & NFSV3_FSFLINK) {
938 if (*tl == newnfs_false)
939 *retcmpp = NFSERR_NOTSAME;
941 if (*tl == newnfs_true)
942 *retcmpp = NFSERR_NOTSAME;
945 } else if (fsp != NULL) {
946 if (*tl == newnfs_true)
947 fsp->fs_properties |= NFSV3_FSFLINK;
949 fsp->fs_properties &= ~NFSV3_FSFLINK;
951 attrsum += NFSX_UNSIGNED;
953 case NFSATTRBIT_SYMLINKSUPPORT:
954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
957 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
958 if (*tl == newnfs_false)
959 *retcmpp = NFSERR_NOTSAME;
961 if (*tl == newnfs_true)
962 *retcmpp = NFSERR_NOTSAME;
965 } else if (fsp != NULL) {
966 if (*tl == newnfs_true)
967 fsp->fs_properties |= NFSV3_FSFSYMLINK;
969 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
971 attrsum += NFSX_UNSIGNED;
973 case NFSATTRBIT_NAMEDATTR:
974 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
975 if (compare && !(*retcmpp)) {
976 if (*tl != newnfs_false)
977 *retcmpp = NFSERR_NOTSAME;
979 attrsum += NFSX_UNSIGNED;
981 case NFSATTRBIT_FSID:
982 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
983 thyp = fxdr_hyper(tl);
985 thyp2 = fxdr_hyper(tl);
988 if (thyp != (u_int64_t)
989 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
991 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
992 *retcmpp = NFSERR_NOTSAME;
994 } else if (nap != NULL) {
995 nap->na_filesid[0] = thyp;
996 nap->na_filesid[1] = thyp2;
998 attrsum += (4 * NFSX_UNSIGNED);
1000 case NFSATTRBIT_UNIQUEHANDLES:
1001 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1002 if (compare && !(*retcmpp)) {
1003 if (*tl != newnfs_true)
1004 *retcmpp = NFSERR_NOTSAME;
1006 attrsum += NFSX_UNSIGNED;
1008 case NFSATTRBIT_LEASETIME:
1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1011 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1013 *retcmpp = NFSERR_NOTSAME;
1014 } else if (leasep != NULL) {
1015 *leasep = fxdr_unsigned(u_int32_t, *tl);
1017 attrsum += NFSX_UNSIGNED;
1019 case NFSATTRBIT_RDATTRERROR:
1020 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1023 *retcmpp = NFSERR_INVAL;
1024 } else if (rderrp != NULL) {
1025 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1027 attrsum += NFSX_UNSIGNED;
1029 case NFSATTRBIT_ACL:
1035 naclp = acl_alloc(M_WAITOK);
1036 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1042 if (aceerr || aclp == NULL ||
1043 nfsrv_compareacl(aclp, naclp))
1044 *retcmpp = NFSERR_NOTSAME;
1047 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1049 *retcmpp = NFSERR_ATTRNOTSUPP;
1053 if (vp != NULL && aclp != NULL)
1054 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1057 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1064 case NFSATTRBIT_ACLSUPPORT:
1065 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1066 if (compare && !(*retcmpp)) {
1068 if (fxdr_unsigned(u_int32_t, *tl) !=
1070 *retcmpp = NFSERR_NOTSAME;
1072 *retcmpp = NFSERR_ATTRNOTSUPP;
1075 attrsum += NFSX_UNSIGNED;
1077 case NFSATTRBIT_ARCHIVE:
1078 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1079 if (compare && !(*retcmpp))
1080 *retcmpp = NFSERR_ATTRNOTSUPP;
1081 attrsum += NFSX_UNSIGNED;
1083 case NFSATTRBIT_CANSETTIME:
1084 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1087 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1088 if (*tl == newnfs_false)
1089 *retcmpp = NFSERR_NOTSAME;
1091 if (*tl == newnfs_true)
1092 *retcmpp = NFSERR_NOTSAME;
1095 } else if (fsp != NULL) {
1096 if (*tl == newnfs_true)
1097 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1099 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1101 attrsum += NFSX_UNSIGNED;
1103 case NFSATTRBIT_CASEINSENSITIVE:
1104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1107 if (*tl != newnfs_false)
1108 *retcmpp = NFSERR_NOTSAME;
1110 } else if (pc != NULL) {
1111 pc->pc_caseinsensitive =
1112 fxdr_unsigned(u_int32_t, *tl);
1114 attrsum += NFSX_UNSIGNED;
1116 case NFSATTRBIT_CASEPRESERVING:
1117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1120 if (*tl != newnfs_true)
1121 *retcmpp = NFSERR_NOTSAME;
1123 } else if (pc != NULL) {
1124 pc->pc_casepreserving =
1125 fxdr_unsigned(u_int32_t, *tl);
1127 attrsum += NFSX_UNSIGNED;
1129 case NFSATTRBIT_CHOWNRESTRICTED:
1130 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1133 if (*tl != newnfs_true)
1134 *retcmpp = NFSERR_NOTSAME;
1136 } else if (pc != NULL) {
1137 pc->pc_chownrestricted =
1138 fxdr_unsigned(u_int32_t, *tl);
1140 attrsum += NFSX_UNSIGNED;
1142 case NFSATTRBIT_FILEHANDLE:
1143 error = nfsm_getfh(nd, &tnfhp);
1146 tfhsize = tnfhp->nfh_len;
1149 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1151 *retcmpp = NFSERR_NOTSAME;
1152 FREE((caddr_t)tnfhp, M_NFSFH);
1153 } else if (nfhpp != NULL) {
1156 FREE((caddr_t)tnfhp, M_NFSFH);
1158 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1160 case NFSATTRBIT_FILEID:
1161 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1162 thyp = fxdr_hyper(tl);
1165 if ((u_int64_t)nap->na_fileid != thyp)
1166 *retcmpp = NFSERR_NOTSAME;
1168 } else if (nap != NULL) {
1170 printf("NFSv4 fileid > 32bits\n");
1171 nap->na_fileid = thyp;
1173 attrsum += NFSX_HYPER;
1175 case NFSATTRBIT_FILESAVAIL:
1176 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1179 sfp->sf_afiles != fxdr_hyper(tl))
1180 *retcmpp = NFSERR_NOTSAME;
1181 } else if (sfp != NULL) {
1182 sfp->sf_afiles = fxdr_hyper(tl);
1184 attrsum += NFSX_HYPER;
1186 case NFSATTRBIT_FILESFREE:
1187 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1190 sfp->sf_ffiles != fxdr_hyper(tl))
1191 *retcmpp = NFSERR_NOTSAME;
1192 } else if (sfp != NULL) {
1193 sfp->sf_ffiles = fxdr_hyper(tl);
1195 attrsum += NFSX_HYPER;
1197 case NFSATTRBIT_FILESTOTAL:
1198 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1201 sfp->sf_tfiles != fxdr_hyper(tl))
1202 *retcmpp = NFSERR_NOTSAME;
1203 } else if (sfp != NULL) {
1204 sfp->sf_tfiles = fxdr_hyper(tl);
1206 attrsum += NFSX_HYPER;
1208 case NFSATTRBIT_FSLOCATIONS:
1209 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1213 if (compare && !(*retcmpp)) {
1214 refp = nfsv4root_getreferral(vp, NULL, 0);
1216 if (cp == NULL || cp2 == NULL ||
1218 strcmp(cp2, refp->nfr_srvlist))
1219 *retcmpp = NFSERR_NOTSAME;
1220 } else if (m == 0) {
1221 *retcmpp = NFSERR_NOTSAME;
1225 free(cp, M_NFSSTRING);
1227 free(cp2, M_NFSSTRING);
1229 case NFSATTRBIT_HIDDEN:
1230 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1231 if (compare && !(*retcmpp))
1232 *retcmpp = NFSERR_ATTRNOTSUPP;
1233 attrsum += NFSX_UNSIGNED;
1235 case NFSATTRBIT_HOMOGENEOUS:
1236 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1239 if (fsp->fs_properties &
1240 NFSV3_FSFHOMOGENEOUS) {
1241 if (*tl == newnfs_false)
1242 *retcmpp = NFSERR_NOTSAME;
1244 if (*tl == newnfs_true)
1245 *retcmpp = NFSERR_NOTSAME;
1248 } else if (fsp != NULL) {
1249 if (*tl == newnfs_true)
1250 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1252 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1254 attrsum += NFSX_UNSIGNED;
1256 case NFSATTRBIT_MAXFILESIZE:
1257 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1258 tnfsquad.qval = fxdr_hyper(tl);
1261 tquad = NFSRV_MAXFILESIZE;
1262 if (tquad != tnfsquad.qval)
1263 *retcmpp = NFSERR_NOTSAME;
1265 } else if (fsp != NULL) {
1266 fsp->fs_maxfilesize = tnfsquad.qval;
1268 attrsum += NFSX_HYPER;
1270 case NFSATTRBIT_MAXLINK:
1271 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1274 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1275 *retcmpp = NFSERR_NOTSAME;
1277 } else if (pc != NULL) {
1278 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1280 attrsum += NFSX_UNSIGNED;
1282 case NFSATTRBIT_MAXNAME:
1283 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1286 if (fsp->fs_maxname !=
1287 fxdr_unsigned(u_int32_t, *tl))
1288 *retcmpp = NFSERR_NOTSAME;
1291 tuint = fxdr_unsigned(u_int32_t, *tl);
1293 * Some Linux NFSv4 servers report this
1294 * as 0 or 4billion, so I'll set it to
1295 * NFS_MAXNAMLEN. If a server actually creates
1296 * a name longer than NFS_MAXNAMLEN, it will
1297 * get an error back.
1299 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1300 tuint = NFS_MAXNAMLEN;
1302 fsp->fs_maxname = tuint;
1304 pc->pc_namemax = tuint;
1306 attrsum += NFSX_UNSIGNED;
1308 case NFSATTRBIT_MAXREAD:
1309 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1312 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1313 *(tl + 1)) || *tl != 0)
1314 *retcmpp = NFSERR_NOTSAME;
1316 } else if (fsp != NULL) {
1317 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1318 fsp->fs_rtpref = fsp->fs_rtmax;
1319 fsp->fs_dtpref = fsp->fs_rtpref;
1321 attrsum += NFSX_HYPER;
1323 case NFSATTRBIT_MAXWRITE:
1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1327 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1328 *(tl + 1)) || *tl != 0)
1329 *retcmpp = NFSERR_NOTSAME;
1331 } else if (fsp != NULL) {
1332 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1333 fsp->fs_wtpref = fsp->fs_wtmax;
1335 attrsum += NFSX_HYPER;
1337 case NFSATTRBIT_MIMETYPE:
1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1339 i = fxdr_unsigned(int, *tl);
1340 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1341 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1344 if (compare && !(*retcmpp))
1345 *retcmpp = NFSERR_ATTRNOTSUPP;
1347 case NFSATTRBIT_MODE:
1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1351 if (nap->na_mode != nfstov_mode(*tl))
1352 *retcmpp = NFSERR_NOTSAME;
1354 } else if (nap != NULL) {
1355 nap->na_mode = nfstov_mode(*tl);
1357 attrsum += NFSX_UNSIGNED;
1359 case NFSATTRBIT_NOTRUNC:
1360 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1363 if (*tl != newnfs_true)
1364 *retcmpp = NFSERR_NOTSAME;
1366 } else if (pc != NULL) {
1367 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1369 attrsum += NFSX_UNSIGNED;
1371 case NFSATTRBIT_NUMLINKS:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 tuint = fxdr_unsigned(u_int32_t, *tl);
1376 if ((u_int32_t)nap->na_nlink != tuint)
1377 *retcmpp = NFSERR_NOTSAME;
1379 } else if (nap != NULL) {
1380 nap->na_nlink = tuint;
1382 attrsum += NFSX_UNSIGNED;
1384 case NFSATTRBIT_OWNER:
1385 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1386 j = fxdr_unsigned(int, *tl);
1388 error = NFSERR_BADXDR;
1391 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1392 if (j > NFSV4_SMALLSTR)
1393 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1396 error = nfsrv_mtostr(nd, cp, j);
1398 if (j > NFSV4_SMALLSTR)
1399 free(cp, M_NFSSTRING);
1404 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1406 *retcmpp = NFSERR_NOTSAME;
1408 } else if (nap != NULL) {
1409 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1410 nap->na_uid = nfsrv_defaultuid;
1414 if (j > NFSV4_SMALLSTR)
1415 free(cp, M_NFSSTRING);
1417 case NFSATTRBIT_OWNERGROUP:
1418 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1419 j = fxdr_unsigned(int, *tl);
1421 error = NFSERR_BADXDR;
1424 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1425 if (j > NFSV4_SMALLSTR)
1426 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1429 error = nfsrv_mtostr(nd, cp, j);
1431 if (j > NFSV4_SMALLSTR)
1432 free(cp, M_NFSSTRING);
1437 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1439 *retcmpp = NFSERR_NOTSAME;
1441 } else if (nap != NULL) {
1442 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1443 nap->na_gid = nfsrv_defaultgid;
1447 if (j > NFSV4_SMALLSTR)
1448 free(cp, M_NFSSTRING);
1450 case NFSATTRBIT_QUOTAHARD:
1451 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1453 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1454 freenum = sbp->f_bfree;
1456 freenum = sbp->f_bavail;
1459 * ufs_quotactl() insists that the uid argument
1460 * equal p_ruid for non-root quota access, so
1461 * we'll just make sure that's the case.
1463 savuid = p->p_cred->p_ruid;
1464 p->p_cred->p_ruid = cred->cr_uid;
1465 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1466 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1467 freenum = min(dqb.dqb_bhardlimit, freenum);
1468 p->p_cred->p_ruid = savuid;
1470 uquad = (u_int64_t)freenum;
1471 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1473 if (compare && !(*retcmpp)) {
1474 if (uquad != fxdr_hyper(tl))
1475 *retcmpp = NFSERR_NOTSAME;
1477 attrsum += NFSX_HYPER;
1479 case NFSATTRBIT_QUOTASOFT:
1480 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1482 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1483 freenum = sbp->f_bfree;
1485 freenum = sbp->f_bavail;
1488 * ufs_quotactl() insists that the uid argument
1489 * equal p_ruid for non-root quota access, so
1490 * we'll just make sure that's the case.
1492 savuid = p->p_cred->p_ruid;
1493 p->p_cred->p_ruid = cred->cr_uid;
1494 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1495 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1496 freenum = min(dqb.dqb_bsoftlimit, freenum);
1497 p->p_cred->p_ruid = savuid;
1499 uquad = (u_int64_t)freenum;
1500 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1502 if (compare && !(*retcmpp)) {
1503 if (uquad != fxdr_hyper(tl))
1504 *retcmpp = NFSERR_NOTSAME;
1506 attrsum += NFSX_HYPER;
1508 case NFSATTRBIT_QUOTAUSED:
1509 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1514 * ufs_quotactl() insists that the uid argument
1515 * equal p_ruid for non-root quota access, so
1516 * we'll just make sure that's the case.
1518 savuid = p->p_cred->p_ruid;
1519 p->p_cred->p_ruid = cred->cr_uid;
1520 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1521 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1522 freenum = dqb.dqb_curblocks;
1523 p->p_cred->p_ruid = savuid;
1525 uquad = (u_int64_t)freenum;
1526 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1528 if (compare && !(*retcmpp)) {
1529 if (uquad != fxdr_hyper(tl))
1530 *retcmpp = NFSERR_NOTSAME;
1532 attrsum += NFSX_HYPER;
1534 case NFSATTRBIT_RAWDEV:
1535 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1536 j = fxdr_unsigned(int, *tl++);
1537 k = fxdr_unsigned(int, *tl);
1540 if (nap->na_rdev != NFSMAKEDEV(j, k))
1541 *retcmpp = NFSERR_NOTSAME;
1543 } else if (nap != NULL) {
1544 nap->na_rdev = NFSMAKEDEV(j, k);
1546 attrsum += NFSX_V4SPECDATA;
1548 case NFSATTRBIT_SPACEAVAIL:
1549 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1552 sfp->sf_abytes != fxdr_hyper(tl))
1553 *retcmpp = NFSERR_NOTSAME;
1554 } else if (sfp != NULL) {
1555 sfp->sf_abytes = fxdr_hyper(tl);
1557 attrsum += NFSX_HYPER;
1559 case NFSATTRBIT_SPACEFREE:
1560 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1563 sfp->sf_fbytes != fxdr_hyper(tl))
1564 *retcmpp = NFSERR_NOTSAME;
1565 } else if (sfp != NULL) {
1566 sfp->sf_fbytes = fxdr_hyper(tl);
1568 attrsum += NFSX_HYPER;
1570 case NFSATTRBIT_SPACETOTAL:
1571 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1574 sfp->sf_tbytes != fxdr_hyper(tl))
1575 *retcmpp = NFSERR_NOTSAME;
1576 } else if (sfp != NULL) {
1577 sfp->sf_tbytes = fxdr_hyper(tl);
1579 attrsum += NFSX_HYPER;
1581 case NFSATTRBIT_SPACEUSED:
1582 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1583 thyp = fxdr_hyper(tl);
1586 if ((u_int64_t)nap->na_bytes != thyp)
1587 *retcmpp = NFSERR_NOTSAME;
1589 } else if (nap != NULL) {
1590 nap->na_bytes = thyp;
1592 attrsum += NFSX_HYPER;
1594 case NFSATTRBIT_SYSTEM:
1595 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1596 if (compare && !(*retcmpp))
1597 *retcmpp = NFSERR_ATTRNOTSUPP;
1598 attrsum += NFSX_UNSIGNED;
1600 case NFSATTRBIT_TIMEACCESS:
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1602 fxdr_nfsv4time(tl, &temptime);
1605 if (!NFS_CMPTIME(temptime, nap->na_atime))
1606 *retcmpp = NFSERR_NOTSAME;
1608 } else if (nap != NULL) {
1609 nap->na_atime = temptime;
1611 attrsum += NFSX_V4TIME;
1613 case NFSATTRBIT_TIMEACCESSSET:
1614 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1615 attrsum += NFSX_UNSIGNED;
1616 i = fxdr_unsigned(int, *tl);
1617 if (i == NFSV4SATTRTIME_TOCLIENT) {
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1619 attrsum += NFSX_V4TIME;
1621 if (compare && !(*retcmpp))
1622 *retcmpp = NFSERR_INVAL;
1624 case NFSATTRBIT_TIMEBACKUP:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1626 if (compare && !(*retcmpp))
1627 *retcmpp = NFSERR_ATTRNOTSUPP;
1628 attrsum += NFSX_V4TIME;
1630 case NFSATTRBIT_TIMECREATE:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1632 if (compare && !(*retcmpp))
1633 *retcmpp = NFSERR_ATTRNOTSUPP;
1634 attrsum += NFSX_V4TIME;
1636 case NFSATTRBIT_TIMEDELTA:
1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1641 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1642 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1643 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1644 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1647 *retcmpp = NFSERR_NOTSAME;
1650 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1653 attrsum += NFSX_V4TIME;
1655 case NFSATTRBIT_TIMEMETADATA:
1656 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1657 fxdr_nfsv4time(tl, &temptime);
1660 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1661 *retcmpp = NFSERR_NOTSAME;
1663 } else if (nap != NULL) {
1664 nap->na_ctime = temptime;
1666 attrsum += NFSX_V4TIME;
1668 case NFSATTRBIT_TIMEMODIFY:
1669 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1670 fxdr_nfsv4time(tl, &temptime);
1673 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1674 *retcmpp = NFSERR_NOTSAME;
1676 } else if (nap != NULL) {
1677 nap->na_mtime = temptime;
1679 attrsum += NFSX_V4TIME;
1681 case NFSATTRBIT_TIMEMODIFYSET:
1682 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1683 attrsum += NFSX_UNSIGNED;
1684 i = fxdr_unsigned(int, *tl);
1685 if (i == NFSV4SATTRTIME_TOCLIENT) {
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1687 attrsum += NFSX_V4TIME;
1689 if (compare && !(*retcmpp))
1690 *retcmpp = NFSERR_INVAL;
1692 case NFSATTRBIT_MOUNTEDONFILEID:
1693 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1694 thyp = fxdr_hyper(tl);
1698 *retcmpp = NFSERR_NOTSAME;
1700 if (!vp || !nfsrv_atroot(vp, &fid))
1701 fid = nap->na_fileid;
1702 if ((u_int64_t)fid != thyp)
1703 *retcmpp = NFSERR_NOTSAME;
1706 } else if (nap != NULL) {
1708 printf("NFSv4 mounted on fileid > 32bits\n");
1709 nap->na_mntonfileno = thyp;
1711 attrsum += NFSX_HYPER;
1714 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1716 if (compare && !(*retcmpp))
1717 *retcmpp = NFSERR_ATTRNOTSUPP;
1719 * and get out of the loop, since we can't parse
1720 * the unknown attrbute data.
1722 bitpos = NFSATTRBIT_MAX;
1728 * some clients pad the attrlist, so we need to skip over the
1731 if (attrsum > attrsize) {
1732 error = NFSERR_BADXDR;
1734 attrsize = NFSM_RNDUP(attrsize);
1735 if (attrsum < attrsize)
1736 error = nfsm_advance(nd, attrsize - attrsum, -1);
1739 NFSEXITCODE2(error, nd);
1744 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1745 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1746 * The first argument is a pointer to an nfsv4lock structure.
1747 * The second argument is 1 iff a blocking lock is wanted.
1748 * If this argument is 0, the call waits until no thread either wants nor
1749 * holds an exclusive lock.
1750 * It returns 1 if the lock was acquired, 0 otherwise.
1751 * If several processes call this function concurrently wanting the exclusive
1752 * lock, one will get the lock and the rest will return without getting the
1753 * lock. (If the caller must have the lock, it simply calls this function in a
1754 * loop until the function returns 1 to indicate the lock was acquired.)
1755 * Any usecnt must be decremented by calling nfsv4_relref() before
1756 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1757 * be called in a loop.
1758 * The isleptp argument is set to indicate if the call slept, iff not NULL
1759 * and the mp argument indicates to check for a forced dismount, iff not
1763 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1764 void *mutex, struct mount *mp)
1770 * If a lock is wanted, loop around until the lock is acquired by
1771 * someone and then released. If I want the lock, try to acquire it.
1772 * For a lock to be issued, no lock must be in force and the usecnt
1776 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1777 lp->nfslock_usecnt == 0) {
1778 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1779 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1782 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1784 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1785 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1786 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1789 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1792 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1793 PZERO - 1, "nfsv4lck", NULL);
1794 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1795 lp->nfslock_usecnt == 0) {
1796 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1797 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1805 * Release the lock acquired by nfsv4_lock().
1806 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1807 * incremented, as well.
1810 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1813 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1815 lp->nfslock_usecnt++;
1820 * Release a reference cnt.
1823 nfsv4_relref(struct nfsv4lock *lp)
1826 if (lp->nfslock_usecnt <= 0)
1827 panic("nfsv4root ref cnt");
1828 lp->nfslock_usecnt--;
1829 if (lp->nfslock_usecnt == 0)
1834 * Get a reference cnt.
1835 * This function will wait for any exclusive lock to be released, but will
1836 * not wait for threads that want the exclusive lock. If priority needs
1837 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1838 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1839 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1840 * return without getting a refcnt for that case.
1843 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1851 * Wait for a lock held.
1853 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1854 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1856 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1859 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1860 PZERO - 1, "nfsv4lck", NULL);
1862 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1865 lp->nfslock_usecnt++;
1869 * Get a reference as above, but return failure instead of sleeping if
1870 * an exclusive lock is held.
1873 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1876 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1879 lp->nfslock_usecnt++;
1884 * Test for a lock. Return 1 if locked, 0 otherwise.
1887 nfsv4_testlock(struct nfsv4lock *lp)
1890 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1891 lp->nfslock_usecnt == 0)
1897 * Wake up anyone sleeping, waiting for this lock.
1900 nfsv4_wanted(struct nfsv4lock *lp)
1903 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1904 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1905 wakeup((caddr_t)&lp->nfslock_lock);
1910 * Copy a string from an mbuf list into a character array.
1911 * Return EBADRPC if there is an mbuf error,
1915 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1924 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1925 rem = NFSM_RNDUP(siz) - siz;
1931 NFSBCOPY(cp, str, xfer);
1940 cp = NFSMTOD(mp, caddr_t);
1952 error = nfsm_advance(nd, rem, len);
1958 NFSEXITCODE2(error, nd);
1963 * Fill in the attributes as marked by the bitmap (V4).
1966 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1967 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1968 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1969 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1971 int bitpos, retnum = 0;
1973 int siz, prefixnum, error;
1974 u_char *cp, namestr[NFSV4_SMALLSTR];
1975 nfsattrbit_t attrbits, retbits;
1976 nfsattrbit_t *retbitp = &retbits;
1977 u_int32_t freenum, *retnump;
1980 struct nfsfsinfo fsinf;
1981 struct timespec temptime;
1982 NFSACL_T *aclp, *naclp = NULL;
1989 * First, set the bits that can be filled and get fsinfo.
1991 NFSSET_ATTRBIT(retbitp, attrbitp);
1992 /* If p and cred are NULL, it is a client side call */
1993 if (p == NULL && cred == NULL) {
1994 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1997 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1998 naclp = acl_alloc(M_WAITOK);
2001 nfsvno_getfs(&fsinf, isdgram);
2004 * Get the VFS_STATFS(), since some attributes need them.
2006 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2007 error = VFS_STATFS(mp, &fs);
2010 nd->nd_repstat = NFSERR_ACCES;
2013 NFSCLRSTATFS_ATTRBIT(retbitp);
2019 * And the NFSv4 ACL...
2021 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2022 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2023 supports_nfsv4acls == 0))) {
2024 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2026 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2027 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2028 supports_nfsv4acls == 0)) {
2029 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2030 } else if (naclp != NULL) {
2031 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2032 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2034 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2036 NFSVOPUNLOCK(vp, 0);
2038 error = NFSERR_PERM;
2041 nd->nd_repstat = NFSERR_ACCES;
2044 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2049 * Put out the attribute bitmap for the ones being filled in
2050 * and get the field for the number of attributes returned.
2052 prefixnum = nfsrv_putattrbit(nd, retbitp);
2053 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2054 prefixnum += NFSX_UNSIGNED;
2057 * Now, loop around filling in the attributes for each bit set.
2059 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2060 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2062 case NFSATTRBIT_SUPPORTEDATTRS:
2063 NFSSETSUPP_ATTRBIT(&attrbits);
2064 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2065 && supports_nfsv4acls == 0)) {
2066 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2067 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2069 retnum += nfsrv_putattrbit(nd, &attrbits);
2071 case NFSATTRBIT_TYPE:
2072 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2073 *tl = vtonfsv34_type(vap->va_type);
2074 retnum += NFSX_UNSIGNED;
2076 case NFSATTRBIT_FHEXPIRETYPE:
2077 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2078 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2079 retnum += NFSX_UNSIGNED;
2081 case NFSATTRBIT_CHANGE:
2082 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2083 txdr_hyper(vap->va_filerev, tl);
2084 retnum += NFSX_HYPER;
2086 case NFSATTRBIT_SIZE:
2087 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2088 txdr_hyper(vap->va_size, tl);
2089 retnum += NFSX_HYPER;
2091 case NFSATTRBIT_LINKSUPPORT:
2092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2093 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2097 retnum += NFSX_UNSIGNED;
2099 case NFSATTRBIT_SYMLINKSUPPORT:
2100 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2101 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2105 retnum += NFSX_UNSIGNED;
2107 case NFSATTRBIT_NAMEDATTR:
2108 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110 retnum += NFSX_UNSIGNED;
2112 case NFSATTRBIT_FSID:
2113 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2115 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2117 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2118 retnum += NFSX_V4FSID;
2120 case NFSATTRBIT_UNIQUEHANDLES:
2121 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2123 retnum += NFSX_UNSIGNED;
2125 case NFSATTRBIT_LEASETIME:
2126 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2127 *tl = txdr_unsigned(nfsrv_lease);
2128 retnum += NFSX_UNSIGNED;
2130 case NFSATTRBIT_RDATTRERROR:
2131 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2132 *tl = txdr_unsigned(rderror);
2133 retnum += NFSX_UNSIGNED;
2136 * Recommended Attributes. (Only the supported ones.)
2138 case NFSATTRBIT_ACL:
2139 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2141 case NFSATTRBIT_ACLSUPPORT:
2142 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2143 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2144 retnum += NFSX_UNSIGNED;
2146 case NFSATTRBIT_CANSETTIME:
2147 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2148 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2152 retnum += NFSX_UNSIGNED;
2154 case NFSATTRBIT_CASEINSENSITIVE:
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2157 retnum += NFSX_UNSIGNED;
2159 case NFSATTRBIT_CASEPRESERVING:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2162 retnum += NFSX_UNSIGNED;
2164 case NFSATTRBIT_CHOWNRESTRICTED:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2167 retnum += NFSX_UNSIGNED;
2169 case NFSATTRBIT_FILEHANDLE:
2170 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2172 case NFSATTRBIT_FILEID:
2173 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2175 *tl = txdr_unsigned(vap->va_fileid);
2176 retnum += NFSX_HYPER;
2178 case NFSATTRBIT_FILESAVAIL:
2180 * Check quota and use min(quota, f_ffree).
2182 freenum = fs.f_ffree;
2185 * ufs_quotactl() insists that the uid argument
2186 * equal p_ruid for non-root quota access, so
2187 * we'll just make sure that's the case.
2189 savuid = p->p_cred->p_ruid;
2190 p->p_cred->p_ruid = cred->cr_uid;
2191 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2192 cred->cr_uid, (caddr_t)&dqb))
2193 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2195 p->p_cred->p_ruid = savuid;
2197 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2199 *tl = txdr_unsigned(freenum);
2200 retnum += NFSX_HYPER;
2202 case NFSATTRBIT_FILESFREE:
2203 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2205 *tl = txdr_unsigned(fs.f_ffree);
2206 retnum += NFSX_HYPER;
2208 case NFSATTRBIT_FILESTOTAL:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2211 *tl = txdr_unsigned(fs.f_files);
2212 retnum += NFSX_HYPER;
2214 case NFSATTRBIT_FSLOCATIONS:
2215 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2218 retnum += 2 * NFSX_UNSIGNED;
2220 case NFSATTRBIT_HOMOGENEOUS:
2221 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2222 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2226 retnum += NFSX_UNSIGNED;
2228 case NFSATTRBIT_MAXFILESIZE:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2230 uquad = NFSRV_MAXFILESIZE;
2231 txdr_hyper(uquad, tl);
2232 retnum += NFSX_HYPER;
2234 case NFSATTRBIT_MAXLINK:
2235 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2236 *tl = txdr_unsigned(LINK_MAX);
2237 retnum += NFSX_UNSIGNED;
2239 case NFSATTRBIT_MAXNAME:
2240 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2241 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2242 retnum += NFSX_UNSIGNED;
2244 case NFSATTRBIT_MAXREAD:
2245 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2247 *tl = txdr_unsigned(fsinf.fs_rtmax);
2248 retnum += NFSX_HYPER;
2250 case NFSATTRBIT_MAXWRITE:
2251 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2253 *tl = txdr_unsigned(fsinf.fs_wtmax);
2254 retnum += NFSX_HYPER;
2256 case NFSATTRBIT_MODE:
2257 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2258 *tl = vtonfsv34_mode(vap->va_mode);
2259 retnum += NFSX_UNSIGNED;
2261 case NFSATTRBIT_NOTRUNC:
2262 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2264 retnum += NFSX_UNSIGNED;
2266 case NFSATTRBIT_NUMLINKS:
2267 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2268 *tl = txdr_unsigned(vap->va_nlink);
2269 retnum += NFSX_UNSIGNED;
2271 case NFSATTRBIT_OWNER:
2273 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2274 retnum += nfsm_strtom(nd, cp, siz);
2276 free(cp, M_NFSSTRING);
2278 case NFSATTRBIT_OWNERGROUP:
2280 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2281 retnum += nfsm_strtom(nd, cp, siz);
2283 free(cp, M_NFSSTRING);
2285 case NFSATTRBIT_QUOTAHARD:
2286 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2287 freenum = fs.f_bfree;
2289 freenum = fs.f_bavail;
2292 * ufs_quotactl() insists that the uid argument
2293 * equal p_ruid for non-root quota access, so
2294 * we'll just make sure that's the case.
2296 savuid = p->p_cred->p_ruid;
2297 p->p_cred->p_ruid = cred->cr_uid;
2298 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2299 cred->cr_uid, (caddr_t)&dqb))
2300 freenum = min(dqb.dqb_bhardlimit, freenum);
2301 p->p_cred->p_ruid = savuid;
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2304 uquad = (u_int64_t)freenum;
2305 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2306 txdr_hyper(uquad, tl);
2307 retnum += NFSX_HYPER;
2309 case NFSATTRBIT_QUOTASOFT:
2310 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2311 freenum = fs.f_bfree;
2313 freenum = fs.f_bavail;
2316 * ufs_quotactl() insists that the uid argument
2317 * equal p_ruid for non-root quota access, so
2318 * we'll just make sure that's the case.
2320 savuid = p->p_cred->p_ruid;
2321 p->p_cred->p_ruid = cred->cr_uid;
2322 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2323 cred->cr_uid, (caddr_t)&dqb))
2324 freenum = min(dqb.dqb_bsoftlimit, freenum);
2325 p->p_cred->p_ruid = savuid;
2327 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2328 uquad = (u_int64_t)freenum;
2329 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2330 txdr_hyper(uquad, tl);
2331 retnum += NFSX_HYPER;
2333 case NFSATTRBIT_QUOTAUSED:
2337 * ufs_quotactl() insists that the uid argument
2338 * equal p_ruid for non-root quota access, so
2339 * we'll just make sure that's the case.
2341 savuid = p->p_cred->p_ruid;
2342 p->p_cred->p_ruid = cred->cr_uid;
2343 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2344 cred->cr_uid, (caddr_t)&dqb))
2345 freenum = dqb.dqb_curblocks;
2346 p->p_cred->p_ruid = savuid;
2348 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2349 uquad = (u_int64_t)freenum;
2350 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2351 txdr_hyper(uquad, tl);
2352 retnum += NFSX_HYPER;
2354 case NFSATTRBIT_RAWDEV:
2355 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2356 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2357 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2358 retnum += NFSX_V4SPECDATA;
2360 case NFSATTRBIT_SPACEAVAIL:
2361 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2362 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2363 uquad = (u_int64_t)fs.f_bfree;
2365 uquad = (u_int64_t)fs.f_bavail;
2366 uquad *= fs.f_bsize;
2367 txdr_hyper(uquad, tl);
2368 retnum += NFSX_HYPER;
2370 case NFSATTRBIT_SPACEFREE:
2371 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2372 uquad = (u_int64_t)fs.f_bfree;
2373 uquad *= fs.f_bsize;
2374 txdr_hyper(uquad, tl);
2375 retnum += NFSX_HYPER;
2377 case NFSATTRBIT_SPACETOTAL:
2378 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2379 uquad = (u_int64_t)fs.f_blocks;
2380 uquad *= fs.f_bsize;
2381 txdr_hyper(uquad, tl);
2382 retnum += NFSX_HYPER;
2384 case NFSATTRBIT_SPACEUSED:
2385 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2386 txdr_hyper(vap->va_bytes, tl);
2387 retnum += NFSX_HYPER;
2389 case NFSATTRBIT_TIMEACCESS:
2390 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2391 txdr_nfsv4time(&vap->va_atime, tl);
2392 retnum += NFSX_V4TIME;
2394 case NFSATTRBIT_TIMEACCESSSET:
2395 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2396 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2397 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2398 txdr_nfsv4time(&vap->va_atime, tl);
2399 retnum += NFSX_V4SETTIME;
2401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2402 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2403 retnum += NFSX_UNSIGNED;
2406 case NFSATTRBIT_TIMEDELTA:
2407 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2408 temptime.tv_sec = 0;
2409 temptime.tv_nsec = 1000000000 / hz;
2410 txdr_nfsv4time(&temptime, tl);
2411 retnum += NFSX_V4TIME;
2413 case NFSATTRBIT_TIMEMETADATA:
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2415 txdr_nfsv4time(&vap->va_ctime, tl);
2416 retnum += NFSX_V4TIME;
2418 case NFSATTRBIT_TIMEMODIFY:
2419 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2420 txdr_nfsv4time(&vap->va_mtime, tl);
2421 retnum += NFSX_V4TIME;
2423 case NFSATTRBIT_TIMEMODIFYSET:
2424 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2425 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2426 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2427 txdr_nfsv4time(&vap->va_mtime, tl);
2428 retnum += NFSX_V4SETTIME;
2430 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2431 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2432 retnum += NFSX_UNSIGNED;
2435 case NFSATTRBIT_MOUNTEDONFILEID:
2436 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2438 uquad = mounted_on_fileno;
2440 uquad = (u_int64_t)vap->va_fileid;
2441 txdr_hyper(uquad, tl);
2442 retnum += NFSX_HYPER;
2445 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2451 *retnump = txdr_unsigned(retnum);
2452 return (retnum + prefixnum);
2456 * Put the attribute bits onto an mbuf list.
2457 * Return the number of bytes of output generated.
2460 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2463 int cnt, i, bytesize;
2465 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2466 if (attrbitp->bits[cnt - 1])
2468 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2469 NFSM_BUILD(tl, u_int32_t *, bytesize);
2470 *tl++ = txdr_unsigned(cnt);
2471 for (i = 0; i < cnt; i++)
2472 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2477 * Convert a uid to a string.
2478 * If the lookup fails, just output the digits.
2480 * cpp - points to a buffer of size NFSV4_SMALLSTR
2481 * (malloc a larger one, as required)
2482 * retlenp - pointer to length to be returned
2485 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2488 struct nfsusrgrp *usrp;
2491 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2496 if (nfsrv_dnsname) {
2498 * Always map nfsrv_defaultuid to "nobody".
2500 if (uid == nfsrv_defaultuid) {
2501 i = nfsrv_dnsnamelen + 7;
2504 if (len > NFSV4_SMALLSTR)
2505 free(cp, M_NFSSTRING);
2506 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2512 NFSBCOPY("nobody@", cp, 7);
2514 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2519 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2520 if (usrp->lug_uid == uid) {
2521 if (usrp->lug_expiry < NFSD_MONOSEC)
2524 * If the name doesn't already have an '@'
2525 * in it, append @domainname to it.
2527 for (i = 0; i < usrp->lug_namelen; i++) {
2528 if (usrp->lug_name[i] == '@') {
2534 i = usrp->lug_namelen;
2536 i = usrp->lug_namelen +
2537 nfsrv_dnsnamelen + 1;
2540 if (len > NFSV4_SMALLSTR)
2541 free(cp, M_NFSSTRING);
2542 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2548 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2549 if (!hasampersand) {
2550 cp += usrp->lug_namelen;
2552 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2554 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2555 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2562 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2564 if (ret == 0 && cnt < 2)
2571 * No match, just return a string of digits.
2575 while (tmp || i == 0) {
2579 len = (i > len) ? len : i;
2583 for (i = 0; i < len; i++) {
2584 *cp-- = '0' + (tmp % 10);
2591 * Convert a string to a uid.
2592 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2594 * If this is called from a client side mount using AUTH_SYS and the
2595 * string is made up entirely of digits, just convert the string to
2599 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2603 char *cp, *endstr, *str0;
2604 struct nfsusrgrp *usrp;
2610 error = NFSERR_BADOWNER;
2613 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2615 tuid = (uid_t)strtoul(str0, &endstr, 10);
2616 if ((endstr - str0) == len &&
2617 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2624 cp = strchr(str0, '@');
2626 i = (int)(cp++ - str0);
2634 * If an '@' is found and the domain name matches, search for the name
2635 * with dns stripped off.
2636 * Mixed case alpahbetics will match for the domain name, but all
2637 * upper case will not.
2639 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2640 (len - 1 - i) == nfsrv_dnsnamelen &&
2641 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2642 len -= (nfsrv_dnsnamelen + 1);
2647 * Check for the special case of "nobody".
2649 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2650 *uidp = nfsrv_defaultuid;
2656 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2657 if (usrp->lug_namelen == len &&
2658 !NFSBCMP(usrp->lug_name, str, len)) {
2659 if (usrp->lug_expiry < NFSD_MONOSEC)
2661 *uidp = usrp->lug_uid;
2662 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2663 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2671 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2673 if (ret == 0 && cnt < 2)
2675 error = NFSERR_BADOWNER;
2683 * Convert a gid to a string.
2684 * gid - the group id
2685 * cpp - points to a buffer of size NFSV4_SMALLSTR
2686 * (malloc a larger one, as required)
2687 * retlenp - pointer to length to be returned
2690 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2693 struct nfsusrgrp *usrp;
2696 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2701 if (nfsrv_dnsname) {
2703 * Always map nfsrv_defaultgid to "nogroup".
2705 if (gid == nfsrv_defaultgid) {
2706 i = nfsrv_dnsnamelen + 8;
2709 if (len > NFSV4_SMALLSTR)
2710 free(cp, M_NFSSTRING);
2711 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2717 NFSBCOPY("nogroup@", cp, 8);
2719 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2724 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2725 if (usrp->lug_gid == gid) {
2726 if (usrp->lug_expiry < NFSD_MONOSEC)
2729 * If the name doesn't already have an '@'
2730 * in it, append @domainname to it.
2732 for (i = 0; i < usrp->lug_namelen; i++) {
2733 if (usrp->lug_name[i] == '@') {
2739 i = usrp->lug_namelen;
2741 i = usrp->lug_namelen +
2742 nfsrv_dnsnamelen + 1;
2745 if (len > NFSV4_SMALLSTR)
2746 free(cp, M_NFSSTRING);
2747 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2753 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2754 if (!hasampersand) {
2755 cp += usrp->lug_namelen;
2757 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2759 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2760 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2767 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2769 if (ret == 0 && cnt < 2)
2776 * No match, just return a string of digits.
2780 while (tmp || i == 0) {
2784 len = (i > len) ? len : i;
2788 for (i = 0; i < len; i++) {
2789 *cp-- = '0' + (tmp % 10);
2796 * Convert a string to a gid.
2797 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2799 * If this is called from a client side mount using AUTH_SYS and the
2800 * string is made up entirely of digits, just convert the string to
2804 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2808 char *cp, *endstr, *str0;
2809 struct nfsusrgrp *usrp;
2815 error = NFSERR_BADOWNER;
2818 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2820 tgid = (gid_t)strtoul(str0, &endstr, 10);
2821 if ((endstr - str0) == len &&
2822 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2829 cp = strchr(str0, '@');
2831 i = (int)(cp++ - str0);
2839 * If an '@' is found and the dns name matches, search for the name
2840 * with the dns stripped off.
2842 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2843 (len - 1 - i) == nfsrv_dnsnamelen &&
2844 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2845 len -= (nfsrv_dnsnamelen + 1);
2850 * Check for the special case of "nogroup".
2852 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2853 *gidp = nfsrv_defaultgid;
2859 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2860 if (usrp->lug_namelen == len &&
2861 !NFSBCMP(usrp->lug_name, str, len)) {
2862 if (usrp->lug_expiry < NFSD_MONOSEC)
2864 *gidp = usrp->lug_gid;
2865 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2866 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2874 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2876 if (ret == 0 && cnt < 2)
2878 error = NFSERR_BADOWNER;
2886 * Cmp len chars, allowing mixed case in the first argument to match lower
2887 * case in the second, but not if the first argument is all upper case.
2888 * Return 0 for a match, 1 otherwise.
2891 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2897 for (i = 0; i < len; i++) {
2898 if (*cp >= 'A' && *cp <= 'Z') {
2899 tmp = *cp++ + ('a' - 'A');
2902 if (tmp >= 'a' && tmp <= 'z')
2915 * Set the port for the nfsuserd.
2918 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2920 struct nfssockreq *rp;
2921 struct sockaddr_in *ad;
2925 if (nfsrv_nfsuserd) {
2933 * Set up the socket record and connect.
2935 rp = &nfsrv_nfsuserdsock;
2936 rp->nr_client = NULL;
2937 rp->nr_sotype = SOCK_DGRAM;
2938 rp->nr_soproto = IPPROTO_UDP;
2939 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2941 NFSSOCKADDRALLOC(rp->nr_nam);
2942 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2943 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2944 ad->sin_family = AF_INET;
2945 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2946 ad->sin_port = port;
2947 rp->nr_prog = RPCPROG_NFSUSERD;
2948 rp->nr_vers = RPCNFSUSERD_VERS;
2949 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2951 NFSSOCKADDRFREE(rp->nr_nam);
2960 * Delete the nfsuserd port.
2963 nfsrv_nfsuserddelport(void)
2967 if (nfsrv_nfsuserd == 0) {
2973 newnfs_disconnect(&nfsrv_nfsuserdsock);
2974 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2978 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2980 * Returns 0 upon success, non-zero otherwise.
2983 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2986 struct nfsrv_descript *nd;
2988 struct nfsrv_descript nfsd;
2993 if (nfsrv_nfsuserd == 0) {
3000 cred = newnfs_getcred();
3001 nd->nd_flag = ND_GSSINITREPLY;
3004 nd->nd_procnum = procnum;
3005 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3006 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3007 if (procnum == RPCNFSUSERD_GETUID)
3008 *tl = txdr_unsigned(uid);
3010 *tl = txdr_unsigned(gid);
3013 (void) nfsm_strtom(nd, name, len);
3015 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3016 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
3019 mbuf_freem(nd->nd_mrep);
3020 error = nd->nd_repstat;
3028 * This function is called from the nfssvc(2) system call, to update the
3029 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3032 nfssvc_idname(struct nfsd_idargs *nidp)
3034 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3035 struct nfsuserhashhead *hp;
3040 if (nidp->nid_flag & NFSID_INITIALIZE) {
3041 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3042 M_NFSSTRING, M_WAITOK);
3043 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3046 if (nfsrv_dnsname) {
3048 * Free up all the old stuff and reinitialize hash lists.
3050 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3051 nfsrv_removeuser(usrp);
3053 free(nfsrv_dnsname, M_NFSSTRING);
3054 nfsrv_dnsname = NULL;
3056 TAILQ_INIT(&nfsuserlruhead);
3057 for (i = 0; i < NFSUSERHASHSIZE; i++)
3058 LIST_INIT(&nfsuserhash[i]);
3059 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3060 LIST_INIT(&nfsgrouphash[i]);
3061 for (i = 0; i < NFSUSERHASHSIZE; i++)
3062 LIST_INIT(&nfsusernamehash[i]);
3063 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3064 LIST_INIT(&nfsgroupnamehash[i]);
3067 * Put name in "DNS" string.
3071 nfsrv_dnsnamelen = nidp->nid_namelen;
3072 nfsrv_defaultuid = nidp->nid_uid;
3073 nfsrv_defaultgid = nidp->nid_gid;
3075 nfsrv_usermax = nidp->nid_usermax;
3079 free(cp, M_NFSSTRING);
3084 * malloc the new one now, so any potential sleep occurs before
3085 * manipulation of the lists.
3087 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3088 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3089 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3092 free((caddr_t)newusrp, M_NFSUSERGROUP);
3095 newusrp->lug_namelen = nidp->nid_namelen;
3099 * Delete old entries, as required.
3101 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3102 hp = NFSUSERHASH(nidp->nid_uid);
3103 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3104 if (usrp->lug_uid == nidp->nid_uid)
3105 nfsrv_removeuser(usrp);
3108 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3109 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3110 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3111 if (usrp->lug_namelen == newusrp->lug_namelen &&
3112 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3114 nfsrv_removeuser(usrp);
3117 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3118 hp = NFSGROUPHASH(nidp->nid_gid);
3119 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3120 if (usrp->lug_gid == nidp->nid_gid)
3121 nfsrv_removeuser(usrp);
3124 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3125 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3126 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3127 if (usrp->lug_namelen == newusrp->lug_namelen &&
3128 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3130 nfsrv_removeuser(usrp);
3133 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3134 if (usrp->lug_expiry < NFSD_MONOSEC)
3135 nfsrv_removeuser(usrp);
3137 while (nfsrv_usercnt >= nfsrv_usermax) {
3138 usrp = TAILQ_FIRST(&nfsuserlruhead);
3139 nfsrv_removeuser(usrp);
3143 * Now, we can add the new one.
3145 if (nidp->nid_usertimeout)
3146 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3148 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3149 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3150 newusrp->lug_uid = nidp->nid_uid;
3151 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3153 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3154 newusrp->lug_namelen), newusrp, lug_namehash);
3155 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3157 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3158 newusrp->lug_gid = nidp->nid_gid;
3159 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3161 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3162 newusrp->lug_namelen), newusrp, lug_namehash);
3163 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3166 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3174 * Remove a user/group name element.
3177 nfsrv_removeuser(struct nfsusrgrp *usrp)
3180 NFSNAMEIDREQUIRED();
3181 LIST_REMOVE(usrp, lug_numhash);
3182 LIST_REMOVE(usrp, lug_namehash);
3183 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3185 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3189 * This function scans a byte string and checks for UTF-8 compliance.
3190 * It returns 0 if it conforms and NFSERR_INVAL if not.
3193 nfsrv_checkutf8(u_int8_t *cp, int len)
3195 u_int32_t val = 0x0;
3196 int cnt = 0, gotd = 0, shift = 0;
3198 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3202 * Here are what the variables are used for:
3203 * val - the calculated value of a multibyte char, used to check
3204 * that it was coded with the correct range
3205 * cnt - the number of 10xxxxxx bytes to follow
3206 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3207 * shift - lower order bits of range (ie. "val >> shift" should
3208 * not be 0, in other words, dividing by the lower bound
3209 * of the range should get a non-zero value)
3210 * byte - used to calculate cnt
3214 /* This handles the 10xxxxxx bytes */
3215 if ((*cp & 0xc0) != 0x80 ||
3216 (gotd && (*cp & 0x20))) {
3217 error = NFSERR_INVAL;
3222 val |= (*cp & 0x3f);
3224 if (cnt == 0 && (val >> shift) == 0x0) {
3225 error = NFSERR_INVAL;
3228 } else if (*cp & 0x80) {
3229 /* first byte of multi byte char */
3231 while ((byte & 0x40) && cnt < 6) {
3235 if (cnt == 0 || cnt == 6) {
3236 error = NFSERR_INVAL;
3239 val = (*cp & (0x3f >> cnt));
3240 shift = utf8_shift[cnt - 1];
3241 if (cnt == 2 && val == 0xd)
3242 /* Check for the 0xd800-0xdfff case */
3249 error = NFSERR_INVAL;
3257 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3258 * strings, one with the root path in it and the other with the list of
3259 * locations. The list is in the same format as is found in nfr_refs.
3260 * It is a "," separated list of entries, where each of them is of the
3261 * form <server>:<rootpath>. For example
3262 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3263 * The nilp argument is set to 1 for the special case of a null fs_root
3264 * and an empty server list.
3265 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3266 * number of xdr bytes parsed in sump.
3269 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3270 int *sump, int *nilp)
3273 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3274 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3276 SLIST_ENTRY(list) next;
3280 SLIST_HEAD(, list) head;
3287 * Get the fs_root path and check for the special case of null path
3288 * and 0 length server list.
3290 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3291 len = fxdr_unsigned(int, *tl);
3292 if (len < 0 || len > 10240) {
3293 error = NFSERR_BADXDR;
3297 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3299 error = NFSERR_BADXDR;
3303 *sump = 2 * NFSX_UNSIGNED;
3307 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3308 error = nfsrv_mtostr(nd, cp, len);
3310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3311 cnt = fxdr_unsigned(int, *tl);
3313 error = NFSERR_BADXDR;
3319 * Now, loop through the location list and make up the srvlist.
3321 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3322 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3325 for (i = 0; i < cnt; i++) {
3327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3328 nsrv = fxdr_unsigned(int, *tl);
3330 error = NFSERR_BADXDR;
3335 * Handle the first server by putting it in the srvstr.
3337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3338 len = fxdr_unsigned(int, *tl);
3339 if (len <= 0 || len > 1024) {
3340 error = NFSERR_BADXDR;
3343 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3348 error = nfsrv_mtostr(nd, cp3, len);
3354 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3355 for (j = 1; j < nsrv; j++) {
3357 * Yuck, put them in an slist and process them later.
3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3360 len = fxdr_unsigned(int, *tl);
3361 if (len <= 0 || len > 1024) {
3362 error = NFSERR_BADXDR;
3365 lsp = (struct list *)malloc(sizeof (struct list)
3366 + len, M_TEMP, M_WAITOK);
3367 error = nfsrv_mtostr(nd, lsp->host, len);
3370 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3372 SLIST_INSERT_HEAD(&head, lsp, next);
3376 * Finally, we can get the path.
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 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3385 error = nfsrv_mtostr(nd, cp3, len);
3388 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3393 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3394 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3397 NFSBCOPY(lsp->host, cp3, lsp->len);
3400 NFSBCOPY(str, cp3, stringlen);
3403 siz += (lsp->len + stringlen + 2);
3404 free((caddr_t)lsp, M_TEMP);
3410 NFSEXITCODE2(0, nd);
3414 free(cp, M_NFSSTRING);
3416 free(cp2, M_NFSSTRING);
3417 NFSEXITCODE2(error, nd);
3422 * Make the malloc'd space large enough. This is a pain, but the xdr
3423 * doesn't set an upper bound on the side, so...
3426 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3433 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3434 NFSBCOPY(*cpp, cp, *slenp);
3435 free(*cpp, M_NFSSTRING);
3439 *slenp = siz + 1024;
3443 * Initialize the reply header data structures.
3446 nfsrvd_rephead(struct nfsrv_descript *nd)
3451 * If this is a big reply, use a cluster.
3453 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3454 nfs_bigreply[nd->nd_procnum]) {
3455 NFSMCLGET(mreq, M_WAIT);
3463 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3464 mbuf_setlen(mreq, 0);
3466 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3467 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3471 * Lock a socket against others.
3472 * Currently used to serialize connect/disconnect attempts.
3475 newnfs_sndlock(int *flagp)
3480 while (*flagp & NFSR_SNDLOCK) {
3481 *flagp |= NFSR_WANTSND;
3484 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3485 PZERO - 1, "nfsndlck", &ts);
3487 *flagp |= NFSR_SNDLOCK;
3493 * Unlock the stream socket for others.
3496 newnfs_sndunlock(int *flagp)
3500 if ((*flagp & NFSR_SNDLOCK) == 0)
3501 panic("nfs sndunlock");
3502 *flagp &= ~NFSR_SNDLOCK;
3503 if (*flagp & NFSR_WANTSND) {
3504 *flagp &= ~NFSR_WANTSND;
3505 wakeup((caddr_t)flagp);