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(cp, j, &uid, p) ||
1406 *retcmpp = NFSERR_NOTSAME;
1408 } else if (nap != NULL) {
1409 if (nfsv4_strtouid(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(cp, j, &gid, p) ||
1439 *retcmpp = NFSERR_NOTSAME;
1441 } else if (nap != NULL) {
1442 if (nfsv4_strtogid(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 struct timeval curtime;
1983 NFSACL_T *aclp, *naclp = NULL;
1990 * First, set the bits that can be filled and get fsinfo.
1992 NFSSET_ATTRBIT(retbitp, attrbitp);
1993 /* If p and cred are NULL, it is a client side call */
1994 if (p == NULL && cred == NULL) {
1995 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1998 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1999 naclp = acl_alloc(M_WAITOK);
2002 nfsvno_getfs(&fsinf, isdgram);
2005 * Get the VFS_STATFS(), since some attributes need them.
2007 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2008 error = VFS_STATFS(mp, &fs);
2011 nd->nd_repstat = NFSERR_ACCES;
2014 NFSCLRSTATFS_ATTRBIT(retbitp);
2020 * And the NFSv4 ACL...
2022 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2023 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2024 supports_nfsv4acls == 0))) {
2025 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2027 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2028 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2029 supports_nfsv4acls == 0)) {
2030 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2031 } else if (naclp != NULL) {
2032 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2033 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2035 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2037 NFSVOPUNLOCK(vp, 0);
2039 error = NFSERR_PERM;
2042 nd->nd_repstat = NFSERR_ACCES;
2045 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2050 * Put out the attribute bitmap for the ones being filled in
2051 * and get the field for the number of attributes returned.
2053 prefixnum = nfsrv_putattrbit(nd, retbitp);
2054 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2055 prefixnum += NFSX_UNSIGNED;
2058 * Now, loop around filling in the attributes for each bit set.
2060 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2061 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2063 case NFSATTRBIT_SUPPORTEDATTRS:
2064 NFSSETSUPP_ATTRBIT(&attrbits);
2065 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2066 && supports_nfsv4acls == 0)) {
2067 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2068 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2070 retnum += nfsrv_putattrbit(nd, &attrbits);
2072 case NFSATTRBIT_TYPE:
2073 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2074 *tl = vtonfsv34_type(vap->va_type);
2075 retnum += NFSX_UNSIGNED;
2077 case NFSATTRBIT_FHEXPIRETYPE:
2078 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2079 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2080 retnum += NFSX_UNSIGNED;
2082 case NFSATTRBIT_CHANGE:
2083 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2084 txdr_hyper(vap->va_filerev, tl);
2085 retnum += NFSX_HYPER;
2087 case NFSATTRBIT_SIZE:
2088 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2089 txdr_hyper(vap->va_size, tl);
2090 retnum += NFSX_HYPER;
2092 case NFSATTRBIT_LINKSUPPORT:
2093 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2094 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2098 retnum += NFSX_UNSIGNED;
2100 case NFSATTRBIT_SYMLINKSUPPORT:
2101 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2102 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2106 retnum += NFSX_UNSIGNED;
2108 case NFSATTRBIT_NAMEDATTR:
2109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2111 retnum += NFSX_UNSIGNED;
2113 case NFSATTRBIT_FSID:
2114 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2116 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2118 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2119 retnum += NFSX_V4FSID;
2121 case NFSATTRBIT_UNIQUEHANDLES:
2122 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2124 retnum += NFSX_UNSIGNED;
2126 case NFSATTRBIT_LEASETIME:
2127 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2128 *tl = txdr_unsigned(nfsrv_lease);
2129 retnum += NFSX_UNSIGNED;
2131 case NFSATTRBIT_RDATTRERROR:
2132 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2133 *tl = txdr_unsigned(rderror);
2134 retnum += NFSX_UNSIGNED;
2137 * Recommended Attributes. (Only the supported ones.)
2139 case NFSATTRBIT_ACL:
2140 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2142 case NFSATTRBIT_ACLSUPPORT:
2143 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2144 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2145 retnum += NFSX_UNSIGNED;
2147 case NFSATTRBIT_CANSETTIME:
2148 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2149 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2153 retnum += NFSX_UNSIGNED;
2155 case NFSATTRBIT_CASEINSENSITIVE:
2156 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2158 retnum += NFSX_UNSIGNED;
2160 case NFSATTRBIT_CASEPRESERVING:
2161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163 retnum += NFSX_UNSIGNED;
2165 case NFSATTRBIT_CHOWNRESTRICTED:
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2168 retnum += NFSX_UNSIGNED;
2170 case NFSATTRBIT_FILEHANDLE:
2171 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2173 case NFSATTRBIT_FILEID:
2174 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2176 *tl = txdr_unsigned(vap->va_fileid);
2177 retnum += NFSX_HYPER;
2179 case NFSATTRBIT_FILESAVAIL:
2181 * Check quota and use min(quota, f_ffree).
2183 freenum = fs.f_ffree;
2186 * ufs_quotactl() insists that the uid argument
2187 * equal p_ruid for non-root quota access, so
2188 * we'll just make sure that's the case.
2190 savuid = p->p_cred->p_ruid;
2191 p->p_cred->p_ruid = cred->cr_uid;
2192 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2193 cred->cr_uid, (caddr_t)&dqb))
2194 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2196 p->p_cred->p_ruid = savuid;
2198 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2200 *tl = txdr_unsigned(freenum);
2201 retnum += NFSX_HYPER;
2203 case NFSATTRBIT_FILESFREE:
2204 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2206 *tl = txdr_unsigned(fs.f_ffree);
2207 retnum += NFSX_HYPER;
2209 case NFSATTRBIT_FILESTOTAL:
2210 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2212 *tl = txdr_unsigned(fs.f_files);
2213 retnum += NFSX_HYPER;
2215 case NFSATTRBIT_FSLOCATIONS:
2216 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2219 retnum += 2 * NFSX_UNSIGNED;
2221 case NFSATTRBIT_HOMOGENEOUS:
2222 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2223 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2227 retnum += NFSX_UNSIGNED;
2229 case NFSATTRBIT_MAXFILESIZE:
2230 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2231 uquad = NFSRV_MAXFILESIZE;
2232 txdr_hyper(uquad, tl);
2233 retnum += NFSX_HYPER;
2235 case NFSATTRBIT_MAXLINK:
2236 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2237 *tl = txdr_unsigned(LINK_MAX);
2238 retnum += NFSX_UNSIGNED;
2240 case NFSATTRBIT_MAXNAME:
2241 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2242 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2243 retnum += NFSX_UNSIGNED;
2245 case NFSATTRBIT_MAXREAD:
2246 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2248 *tl = txdr_unsigned(fsinf.fs_rtmax);
2249 retnum += NFSX_HYPER;
2251 case NFSATTRBIT_MAXWRITE:
2252 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2254 *tl = txdr_unsigned(fsinf.fs_wtmax);
2255 retnum += NFSX_HYPER;
2257 case NFSATTRBIT_MODE:
2258 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2259 *tl = vtonfsv34_mode(vap->va_mode);
2260 retnum += NFSX_UNSIGNED;
2262 case NFSATTRBIT_NOTRUNC:
2263 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2265 retnum += NFSX_UNSIGNED;
2267 case NFSATTRBIT_NUMLINKS:
2268 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2269 *tl = txdr_unsigned(vap->va_nlink);
2270 retnum += NFSX_UNSIGNED;
2272 case NFSATTRBIT_OWNER:
2274 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2275 retnum += nfsm_strtom(nd, cp, siz);
2277 free(cp, M_NFSSTRING);
2279 case NFSATTRBIT_OWNERGROUP:
2281 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2282 retnum += nfsm_strtom(nd, cp, siz);
2284 free(cp, M_NFSSTRING);
2286 case NFSATTRBIT_QUOTAHARD:
2287 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2288 freenum = fs.f_bfree;
2290 freenum = fs.f_bavail;
2293 * ufs_quotactl() insists that the uid argument
2294 * equal p_ruid for non-root quota access, so
2295 * we'll just make sure that's the case.
2297 savuid = p->p_cred->p_ruid;
2298 p->p_cred->p_ruid = cred->cr_uid;
2299 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2300 cred->cr_uid, (caddr_t)&dqb))
2301 freenum = min(dqb.dqb_bhardlimit, freenum);
2302 p->p_cred->p_ruid = savuid;
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2305 uquad = (u_int64_t)freenum;
2306 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2307 txdr_hyper(uquad, tl);
2308 retnum += NFSX_HYPER;
2310 case NFSATTRBIT_QUOTASOFT:
2311 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2312 freenum = fs.f_bfree;
2314 freenum = fs.f_bavail;
2317 * ufs_quotactl() insists that the uid argument
2318 * equal p_ruid for non-root quota access, so
2319 * we'll just make sure that's the case.
2321 savuid = p->p_cred->p_ruid;
2322 p->p_cred->p_ruid = cred->cr_uid;
2323 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2324 cred->cr_uid, (caddr_t)&dqb))
2325 freenum = min(dqb.dqb_bsoftlimit, freenum);
2326 p->p_cred->p_ruid = savuid;
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2329 uquad = (u_int64_t)freenum;
2330 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2331 txdr_hyper(uquad, tl);
2332 retnum += NFSX_HYPER;
2334 case NFSATTRBIT_QUOTAUSED:
2338 * ufs_quotactl() insists that the uid argument
2339 * equal p_ruid for non-root quota access, so
2340 * we'll just make sure that's the case.
2342 savuid = p->p_cred->p_ruid;
2343 p->p_cred->p_ruid = cred->cr_uid;
2344 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2345 cred->cr_uid, (caddr_t)&dqb))
2346 freenum = dqb.dqb_curblocks;
2347 p->p_cred->p_ruid = savuid;
2349 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2350 uquad = (u_int64_t)freenum;
2351 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2352 txdr_hyper(uquad, tl);
2353 retnum += NFSX_HYPER;
2355 case NFSATTRBIT_RAWDEV:
2356 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2357 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2358 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2359 retnum += NFSX_V4SPECDATA;
2361 case NFSATTRBIT_SPACEAVAIL:
2362 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2363 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2364 uquad = (u_int64_t)fs.f_bfree;
2366 uquad = (u_int64_t)fs.f_bavail;
2367 uquad *= fs.f_bsize;
2368 txdr_hyper(uquad, tl);
2369 retnum += NFSX_HYPER;
2371 case NFSATTRBIT_SPACEFREE:
2372 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2373 uquad = (u_int64_t)fs.f_bfree;
2374 uquad *= fs.f_bsize;
2375 txdr_hyper(uquad, tl);
2376 retnum += NFSX_HYPER;
2378 case NFSATTRBIT_SPACETOTAL:
2379 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2380 uquad = (u_int64_t)fs.f_blocks;
2381 uquad *= fs.f_bsize;
2382 txdr_hyper(uquad, tl);
2383 retnum += NFSX_HYPER;
2385 case NFSATTRBIT_SPACEUSED:
2386 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2387 txdr_hyper(vap->va_bytes, tl);
2388 retnum += NFSX_HYPER;
2390 case NFSATTRBIT_TIMEACCESS:
2391 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2392 txdr_nfsv4time(&vap->va_atime, tl);
2393 retnum += NFSX_V4TIME;
2395 case NFSATTRBIT_TIMEACCESSSET:
2396 NFSGETTIME(&curtime);
2397 if (vap->va_atime.tv_sec != curtime.tv_sec) {
2398 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2399 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2400 txdr_nfsv4time(&vap->va_atime, tl);
2401 retnum += NFSX_V4SETTIME;
2403 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2404 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2405 retnum += NFSX_UNSIGNED;
2408 case NFSATTRBIT_TIMEDELTA:
2409 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2410 temptime.tv_sec = 0;
2411 temptime.tv_nsec = 1000000000 / hz;
2412 txdr_nfsv4time(&temptime, tl);
2413 retnum += NFSX_V4TIME;
2415 case NFSATTRBIT_TIMEMETADATA:
2416 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2417 txdr_nfsv4time(&vap->va_ctime, tl);
2418 retnum += NFSX_V4TIME;
2420 case NFSATTRBIT_TIMEMODIFY:
2421 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2422 txdr_nfsv4time(&vap->va_mtime, tl);
2423 retnum += NFSX_V4TIME;
2425 case NFSATTRBIT_TIMEMODIFYSET:
2426 NFSGETTIME(&curtime);
2427 if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2429 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2430 txdr_nfsv4time(&vap->va_mtime, tl);
2431 retnum += NFSX_V4SETTIME;
2433 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2434 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2435 retnum += NFSX_UNSIGNED;
2438 case NFSATTRBIT_MOUNTEDONFILEID:
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2441 uquad = mounted_on_fileno;
2443 uquad = (u_int64_t)vap->va_fileid;
2444 txdr_hyper(uquad, tl);
2445 retnum += NFSX_HYPER;
2448 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2454 *retnump = txdr_unsigned(retnum);
2455 return (retnum + prefixnum);
2459 * Put the attribute bits onto an mbuf list.
2460 * Return the number of bytes of output generated.
2463 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2466 int cnt, i, bytesize;
2468 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2469 if (attrbitp->bits[cnt - 1])
2471 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2472 NFSM_BUILD(tl, u_int32_t *, bytesize);
2473 *tl++ = txdr_unsigned(cnt);
2474 for (i = 0; i < cnt; i++)
2475 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2480 * Convert a uid to a string.
2481 * If the lookup fails, just output the digits.
2483 * cpp - points to a buffer of size NFSV4_SMALLSTR
2484 * (malloc a larger one, as required)
2485 * retlenp - pointer to length to be returned
2488 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2491 struct nfsusrgrp *usrp;
2494 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2499 if (nfsrv_dnsname) {
2501 * Always map nfsrv_defaultuid to "nobody".
2503 if (uid == nfsrv_defaultuid) {
2504 i = nfsrv_dnsnamelen + 7;
2507 if (len > NFSV4_SMALLSTR)
2508 free(cp, M_NFSSTRING);
2509 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2515 NFSBCOPY("nobody@", cp, 7);
2517 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2522 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2523 if (usrp->lug_uid == uid) {
2524 if (usrp->lug_expiry < NFSD_MONOSEC)
2527 * If the name doesn't already have an '@'
2528 * in it, append @domainname to it.
2530 for (i = 0; i < usrp->lug_namelen; i++) {
2531 if (usrp->lug_name[i] == '@') {
2537 i = usrp->lug_namelen;
2539 i = usrp->lug_namelen +
2540 nfsrv_dnsnamelen + 1;
2543 if (len > NFSV4_SMALLSTR)
2544 free(cp, M_NFSSTRING);
2545 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2551 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2552 if (!hasampersand) {
2553 cp += usrp->lug_namelen;
2555 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2557 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2558 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2565 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2567 if (ret == 0 && cnt < 2)
2574 * No match, just return a string of digits.
2578 while (tmp || i == 0) {
2582 len = (i > len) ? len : i;
2586 for (i = 0; i < len; i++) {
2587 *cp-- = '0' + (tmp % 10);
2594 * Convert a string to a uid.
2595 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2599 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2603 struct nfsusrgrp *usrp;
2608 error = NFSERR_BADOWNER;
2615 for (i = 0; i < len; i++)
2623 * If an '@' is found and the domain name matches, search for the name
2624 * with dns stripped off.
2625 * Mixed case alpahbetics will match for the domain name, but all
2626 * upper case will not.
2628 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2629 (len - 1 - i) == nfsrv_dnsnamelen &&
2630 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2631 len -= (nfsrv_dnsnamelen + 1);
2636 * Check for the special case of "nobody".
2638 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2639 *uidp = nfsrv_defaultuid;
2645 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2646 if (usrp->lug_namelen == len &&
2647 !NFSBCMP(usrp->lug_name, str, len)) {
2648 if (usrp->lug_expiry < NFSD_MONOSEC)
2650 *uidp = usrp->lug_uid;
2651 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2652 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2660 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2662 if (ret == 0 && cnt < 2)
2664 error = NFSERR_BADOWNER;
2672 * Convert a gid to a string.
2673 * gid - the group id
2674 * cpp - points to a buffer of size NFSV4_SMALLSTR
2675 * (malloc a larger one, as required)
2676 * retlenp - pointer to length to be returned
2679 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2682 struct nfsusrgrp *usrp;
2685 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2690 if (nfsrv_dnsname) {
2692 * Always map nfsrv_defaultgid to "nogroup".
2694 if (gid == nfsrv_defaultgid) {
2695 i = nfsrv_dnsnamelen + 8;
2698 if (len > NFSV4_SMALLSTR)
2699 free(cp, M_NFSSTRING);
2700 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2706 NFSBCOPY("nogroup@", cp, 8);
2708 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2713 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2714 if (usrp->lug_gid == gid) {
2715 if (usrp->lug_expiry < NFSD_MONOSEC)
2718 * If the name doesn't already have an '@'
2719 * in it, append @domainname to it.
2721 for (i = 0; i < usrp->lug_namelen; i++) {
2722 if (usrp->lug_name[i] == '@') {
2728 i = usrp->lug_namelen;
2730 i = usrp->lug_namelen +
2731 nfsrv_dnsnamelen + 1;
2734 if (len > NFSV4_SMALLSTR)
2735 free(cp, M_NFSSTRING);
2736 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2742 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2743 if (!hasampersand) {
2744 cp += usrp->lug_namelen;
2746 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2748 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2749 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2756 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2758 if (ret == 0 && cnt < 2)
2765 * No match, just return a string of digits.
2769 while (tmp || i == 0) {
2773 len = (i > len) ? len : i;
2777 for (i = 0; i < len; i++) {
2778 *cp-- = '0' + (tmp % 10);
2785 * Convert a string to a gid.
2788 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2792 struct nfsusrgrp *usrp;
2797 error = NFSERR_BADOWNER;
2804 for (i = 0; i < len; i++)
2812 * If an '@' is found and the dns name matches, search for the name
2813 * with the dns stripped off.
2815 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2816 (len - 1 - i) == nfsrv_dnsnamelen &&
2817 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2818 len -= (nfsrv_dnsnamelen + 1);
2823 * Check for the special case of "nogroup".
2825 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2826 *gidp = nfsrv_defaultgid;
2832 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2833 if (usrp->lug_namelen == len &&
2834 !NFSBCMP(usrp->lug_name, str, len)) {
2835 if (usrp->lug_expiry < NFSD_MONOSEC)
2837 *gidp = usrp->lug_gid;
2838 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2839 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2847 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2849 if (ret == 0 && cnt < 2)
2851 error = NFSERR_BADOWNER;
2859 * Cmp len chars, allowing mixed case in the first argument to match lower
2860 * case in the second, but not if the first argument is all upper case.
2861 * Return 0 for a match, 1 otherwise.
2864 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2870 for (i = 0; i < len; i++) {
2871 if (*cp >= 'A' && *cp <= 'Z') {
2872 tmp = *cp++ + ('a' - 'A');
2875 if (tmp >= 'a' && tmp <= 'z')
2888 * Set the port for the nfsuserd.
2891 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2893 struct nfssockreq *rp;
2894 struct sockaddr_in *ad;
2898 if (nfsrv_nfsuserd) {
2906 * Set up the socket record and connect.
2908 rp = &nfsrv_nfsuserdsock;
2909 rp->nr_client = NULL;
2910 rp->nr_sotype = SOCK_DGRAM;
2911 rp->nr_soproto = IPPROTO_UDP;
2912 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2914 NFSSOCKADDRALLOC(rp->nr_nam);
2915 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2916 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2917 ad->sin_family = AF_INET;
2918 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2919 ad->sin_port = port;
2920 rp->nr_prog = RPCPROG_NFSUSERD;
2921 rp->nr_vers = RPCNFSUSERD_VERS;
2922 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2924 NFSSOCKADDRFREE(rp->nr_nam);
2933 * Delete the nfsuserd port.
2936 nfsrv_nfsuserddelport(void)
2940 if (nfsrv_nfsuserd == 0) {
2946 newnfs_disconnect(&nfsrv_nfsuserdsock);
2947 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2951 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2953 * Returns 0 upon success, non-zero otherwise.
2956 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2959 struct nfsrv_descript *nd;
2961 struct nfsrv_descript nfsd;
2966 if (nfsrv_nfsuserd == 0) {
2973 cred = newnfs_getcred();
2974 nd->nd_flag = ND_GSSINITREPLY;
2977 nd->nd_procnum = procnum;
2978 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2979 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2980 if (procnum == RPCNFSUSERD_GETUID)
2981 *tl = txdr_unsigned(uid);
2983 *tl = txdr_unsigned(gid);
2986 (void) nfsm_strtom(nd, name, len);
2988 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2989 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2992 mbuf_freem(nd->nd_mrep);
2993 error = nd->nd_repstat;
3001 * This function is called from the nfssvc(2) system call, to update the
3002 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3005 nfssvc_idname(struct nfsd_idargs *nidp)
3007 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3008 struct nfsuserhashhead *hp;
3013 if (nidp->nid_flag & NFSID_INITIALIZE) {
3014 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3015 M_NFSSTRING, M_WAITOK);
3016 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3019 if (nfsrv_dnsname) {
3021 * Free up all the old stuff and reinitialize hash lists.
3023 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3024 nfsrv_removeuser(usrp);
3026 free(nfsrv_dnsname, M_NFSSTRING);
3027 nfsrv_dnsname = NULL;
3029 TAILQ_INIT(&nfsuserlruhead);
3030 for (i = 0; i < NFSUSERHASHSIZE; i++)
3031 LIST_INIT(&nfsuserhash[i]);
3032 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3033 LIST_INIT(&nfsgrouphash[i]);
3034 for (i = 0; i < NFSUSERHASHSIZE; i++)
3035 LIST_INIT(&nfsusernamehash[i]);
3036 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3037 LIST_INIT(&nfsgroupnamehash[i]);
3040 * Put name in "DNS" string.
3044 nfsrv_dnsnamelen = nidp->nid_namelen;
3045 nfsrv_defaultuid = nidp->nid_uid;
3046 nfsrv_defaultgid = nidp->nid_gid;
3048 nfsrv_usermax = nidp->nid_usermax;
3052 free(cp, M_NFSSTRING);
3057 * malloc the new one now, so any potential sleep occurs before
3058 * manipulation of the lists.
3060 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3061 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3062 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3065 free((caddr_t)newusrp, M_NFSUSERGROUP);
3068 newusrp->lug_namelen = nidp->nid_namelen;
3072 * Delete old entries, as required.
3074 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3075 hp = NFSUSERHASH(nidp->nid_uid);
3076 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3077 if (usrp->lug_uid == nidp->nid_uid)
3078 nfsrv_removeuser(usrp);
3081 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3082 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3083 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3084 if (usrp->lug_namelen == newusrp->lug_namelen &&
3085 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3087 nfsrv_removeuser(usrp);
3090 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3091 hp = NFSGROUPHASH(nidp->nid_gid);
3092 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3093 if (usrp->lug_gid == nidp->nid_gid)
3094 nfsrv_removeuser(usrp);
3097 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3098 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3099 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3100 if (usrp->lug_namelen == newusrp->lug_namelen &&
3101 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3103 nfsrv_removeuser(usrp);
3106 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3107 if (usrp->lug_expiry < NFSD_MONOSEC)
3108 nfsrv_removeuser(usrp);
3110 while (nfsrv_usercnt >= nfsrv_usermax) {
3111 usrp = TAILQ_FIRST(&nfsuserlruhead);
3112 nfsrv_removeuser(usrp);
3116 * Now, we can add the new one.
3118 if (nidp->nid_usertimeout)
3119 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3121 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3122 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3123 newusrp->lug_uid = nidp->nid_uid;
3124 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3126 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3127 newusrp->lug_namelen), newusrp, lug_namehash);
3128 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3130 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3131 newusrp->lug_gid = nidp->nid_gid;
3132 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3134 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3135 newusrp->lug_namelen), newusrp, lug_namehash);
3136 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3139 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3147 * Remove a user/group name element.
3150 nfsrv_removeuser(struct nfsusrgrp *usrp)
3153 NFSNAMEIDREQUIRED();
3154 LIST_REMOVE(usrp, lug_numhash);
3155 LIST_REMOVE(usrp, lug_namehash);
3156 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3158 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3162 * This function scans a byte string and checks for UTF-8 compliance.
3163 * It returns 0 if it conforms and NFSERR_INVAL if not.
3166 nfsrv_checkutf8(u_int8_t *cp, int len)
3168 u_int32_t val = 0x0;
3169 int cnt = 0, gotd = 0, shift = 0;
3171 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3175 * Here are what the variables are used for:
3176 * val - the calculated value of a multibyte char, used to check
3177 * that it was coded with the correct range
3178 * cnt - the number of 10xxxxxx bytes to follow
3179 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3180 * shift - lower order bits of range (ie. "val >> shift" should
3181 * not be 0, in other words, dividing by the lower bound
3182 * of the range should get a non-zero value)
3183 * byte - used to calculate cnt
3187 /* This handles the 10xxxxxx bytes */
3188 if ((*cp & 0xc0) != 0x80 ||
3189 (gotd && (*cp & 0x20))) {
3190 error = NFSERR_INVAL;
3195 val |= (*cp & 0x3f);
3197 if (cnt == 0 && (val >> shift) == 0x0) {
3198 error = NFSERR_INVAL;
3201 } else if (*cp & 0x80) {
3202 /* first byte of multi byte char */
3204 while ((byte & 0x40) && cnt < 6) {
3208 if (cnt == 0 || cnt == 6) {
3209 error = NFSERR_INVAL;
3212 val = (*cp & (0x3f >> cnt));
3213 shift = utf8_shift[cnt - 1];
3214 if (cnt == 2 && val == 0xd)
3215 /* Check for the 0xd800-0xdfff case */
3222 error = NFSERR_INVAL;
3230 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3231 * strings, one with the root path in it and the other with the list of
3232 * locations. The list is in the same format as is found in nfr_refs.
3233 * It is a "," separated list of entries, where each of them is of the
3234 * form <server>:<rootpath>. For example
3235 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3236 * The nilp argument is set to 1 for the special case of a null fs_root
3237 * and an empty server list.
3238 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3239 * number of xdr bytes parsed in sump.
3242 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3243 int *sump, int *nilp)
3246 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3247 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3249 SLIST_ENTRY(list) next;
3253 SLIST_HEAD(, list) head;
3260 * Get the fs_root path and check for the special case of null path
3261 * and 0 length server list.
3263 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3264 len = fxdr_unsigned(int, *tl);
3265 if (len < 0 || len > 10240) {
3266 error = NFSERR_BADXDR;
3270 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3272 error = NFSERR_BADXDR;
3276 *sump = 2 * NFSX_UNSIGNED;
3280 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3281 error = nfsrv_mtostr(nd, cp, len);
3283 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3284 cnt = fxdr_unsigned(int, *tl);
3286 error = NFSERR_BADXDR;
3292 * Now, loop through the location list and make up the srvlist.
3294 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3295 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3298 for (i = 0; i < cnt; i++) {
3300 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3301 nsrv = fxdr_unsigned(int, *tl);
3303 error = NFSERR_BADXDR;
3308 * Handle the first server by putting it in the srvstr.
3310 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3311 len = fxdr_unsigned(int, *tl);
3312 if (len <= 0 || len > 1024) {
3313 error = NFSERR_BADXDR;
3316 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3321 error = nfsrv_mtostr(nd, cp3, len);
3327 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3328 for (j = 1; j < nsrv; j++) {
3330 * Yuck, put them in an slist and process them later.
3332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3333 len = fxdr_unsigned(int, *tl);
3334 if (len <= 0 || len > 1024) {
3335 error = NFSERR_BADXDR;
3338 lsp = (struct list *)malloc(sizeof (struct list)
3339 + len, M_TEMP, M_WAITOK);
3340 error = nfsrv_mtostr(nd, lsp->host, len);
3343 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3345 SLIST_INSERT_HEAD(&head, lsp, next);
3349 * Finally, we can get the path.
3351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3352 len = fxdr_unsigned(int, *tl);
3353 if (len <= 0 || len > 1024) {
3354 error = NFSERR_BADXDR;
3357 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3358 error = nfsrv_mtostr(nd, cp3, len);
3361 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3366 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3367 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3370 NFSBCOPY(lsp->host, cp3, lsp->len);
3373 NFSBCOPY(str, cp3, stringlen);
3376 siz += (lsp->len + stringlen + 2);
3377 free((caddr_t)lsp, M_TEMP);
3383 NFSEXITCODE2(0, nd);
3387 free(cp, M_NFSSTRING);
3389 free(cp2, M_NFSSTRING);
3390 NFSEXITCODE2(error, nd);
3395 * Make the malloc'd space large enough. This is a pain, but the xdr
3396 * doesn't set an upper bound on the side, so...
3399 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3406 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3407 NFSBCOPY(*cpp, cp, *slenp);
3408 free(*cpp, M_NFSSTRING);
3412 *slenp = siz + 1024;
3416 * Initialize the reply header data structures.
3419 nfsrvd_rephead(struct nfsrv_descript *nd)
3424 * If this is a big reply, use a cluster.
3426 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3427 nfs_bigreply[nd->nd_procnum]) {
3428 NFSMCLGET(mreq, M_WAIT);
3436 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3437 mbuf_setlen(mreq, 0);
3439 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3440 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3444 * Lock a socket against others.
3445 * Currently used to serialize connect/disconnect attempts.
3448 newnfs_sndlock(int *flagp)
3453 while (*flagp & NFSR_SNDLOCK) {
3454 *flagp |= NFSR_WANTSND;
3457 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3458 PZERO - 1, "nfsndlck", &ts);
3460 *flagp |= NFSR_SNDLOCK;
3466 * Unlock the stream socket for others.
3469 newnfs_sndunlock(int *flagp)
3473 if ((*flagp & NFSR_SNDLOCK) == 0)
3474 panic("nfs sndunlock");
3475 *flagp &= ~NFSR_SNDLOCK;
3476 if (*flagp & NFSR_WANTSND) {
3477 *flagp &= ~NFSR_WANTSND;
3478 wakeup((caddr_t)flagp);