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 <fs/nfs/nfsport.h>
46 * Data items converted to xdr at startup, since they are constant
47 * This is kinda hokey, but may save a little time doing byte swaps
49 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
51 /* And other global data */
52 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
54 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
55 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
56 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
59 struct nfssockreq nfsrv_nfsuserdsock;
60 int nfsrv_nfsuserd = 0;
61 struct nfsreqhead nfsd_reqq;
62 uid_t nfsrv_defaultuid;
63 gid_t nfsrv_defaultgid;
64 int nfsrv_lease = NFSRV_LEASE;
65 int ncl_mbuf_mlen = MLEN;
70 * This array of structures indicates, for V4:
71 * retfh - which of 3 types of calling args are used
72 * 0 - doesn't change cfh or use a sfh
73 * 1 - replaces cfh with a new one (unless it returns an error status)
74 * 2 - uses cfh and sfh
75 * needscfh - if the op wants a cfh and premtime
76 * 0 - doesn't use a cfh
77 * 1 - uses a cfh, but doesn't want pre-op attributes
78 * 2 - uses a cfh and wants pre-op attributes
79 * savereply - indicates a non-idempotent Op
80 * 0 - not non-idempotent
82 * Ops that are ordered via seqid# are handled separately from these
84 * Define it here, since it is used by both the client and server.
86 struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
87 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
88 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
89 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */
90 { 0, 1, 0, 0, LK_SHARED }, /* Access */
91 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Close */
92 { 0, 2, 0, 1, LK_EXCLUSIVE }, /* Commit */
93 { 1, 2, 1, 1, LK_EXCLUSIVE }, /* Create */
94 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Delegpurge */
95 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Delegreturn */
96 { 0, 1, 0, 0, LK_SHARED }, /* Getattr */
97 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* GetFH */
98 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Link */
99 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Lock */
100 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockT */
101 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockU */
102 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* Lookup */
103 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* Lookupp */
104 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* NVerify */
105 { 1, 1, 0, 1, LK_EXCLUSIVE }, /* Open */
106 { 1, 1, 0, 0, LK_EXCLUSIVE }, /* OpenAttr */
107 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenConfirm */
108 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenDowngrade */
109 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutFH */
110 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutPubFH */
111 { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutRootFH */
112 { 0, 1, 0, 0, LK_SHARED }, /* Read */
113 { 0, 1, 0, 0, LK_SHARED }, /* Readdir */
114 { 0, 1, 0, 0, LK_SHARED }, /* ReadLink */
115 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Remove */
116 { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Rename */
117 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Renew */
118 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* RestoreFH */
119 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SaveFH */
120 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SecInfo */
121 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Setattr */
122 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientID */
123 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientIDConfirm */
124 { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Verify */
125 { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Write */
126 { 0, 0, 0, 0, LK_EXCLUSIVE }, /* ReleaseLockOwner */
128 #endif /* !APPLEKEXT */
130 static int ncl_mbuf_mhlen = MHLEN;
131 static int nfsrv_usercnt = 0;
132 static int nfsrv_dnsnamelen;
133 static u_char *nfsrv_dnsname = NULL;
134 static int nfsrv_usermax = 999999999;
135 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
136 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
137 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
138 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
139 static struct nfsuserlruhead nfsuserlruhead;
142 * This static array indicates whether or not the RPC generates a large
143 * reply. This is used by nfs_reply() to decide whether or not an mbuf
144 * cluster should be allocated. (If a cluster is required by an RPC
145 * marked 0 in this array, the code will still work, just not quite as
148 static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
149 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,
152 /* local functions */
153 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
154 static void nfsv4_wanted(struct nfsv4lock *lp);
155 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
156 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
158 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
159 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
161 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
166 * copies mbuf chain to the uio scatter/gather list
169 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
171 char *mbufcp, *uiocp;
178 mbufcp = nd->nd_dpos;
179 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
180 rem = NFSM_RNDUP(siz) - siz;
182 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
186 left = uiop->uio_iov->iov_len;
187 uiocp = uiop->uio_iov->iov_base;
198 mbufcp = NFSMTOD(mp, caddr_t);
201 xfer = (left > len) ? len : left;
204 if (uiop->uio_iov->iov_op != NULL)
205 (*(uiop->uio_iov->iov_op))
206 (mbufcp, uiocp, xfer);
209 if (uiop->uio_segflg == UIO_SYSSPACE)
210 NFSBCOPY(mbufcp, uiocp, xfer);
212 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
217 uiop->uio_offset += xfer;
218 uiop->uio_resid -= xfer;
220 if (uiop->uio_iov->iov_len <= siz) {
224 uiop->uio_iov->iov_base = (void *)
225 ((char *)uiop->uio_iov->iov_base + uiosiz);
226 uiop->uio_iov->iov_len -= uiosiz;
230 nd->nd_dpos = mbufcp;
234 error = nfsm_advance(nd, rem, len);
240 NFSEXITCODE2(error, nd);
246 * Help break down an mbuf chain by setting the first siz bytes contiguous
247 * pointed to by returned val.
248 * This is used by the macro NFSM_DISSECT for tough
252 nfsm_dissct(struct nfsrv_descript *nd, int siz)
261 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
263 nd->nd_md = mbuf_next(nd->nd_md);
264 if (nd->nd_md == NULL)
266 left = mbuf_len(nd->nd_md);
267 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
272 } else if (mbuf_next(nd->nd_md) == NULL) {
274 } else if (siz > ncl_mbuf_mhlen) {
275 panic("nfs S too big");
278 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
279 mbuf_setnext(nd->nd_md, mp2);
280 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
282 retp = p = NFSMTOD(mp2, caddr_t);
283 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
286 mp2 = mbuf_next(mp2);
287 /* Loop around copying up the siz2 bytes */
291 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
293 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
294 NFSM_DATAP(mp2, xfer);
295 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
300 mp2 = mbuf_next(mp2);
302 mbuf_setlen(nd->nd_md, siz);
304 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
310 * Advance the position in the mbuf chain.
311 * If offs == 0, this is a no-op, but it is simpler to just return from
312 * here than check for offs > 0 for all calls to nfsm_advance.
313 * If left == -1, it should be calculated here.
316 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
323 * A negative offs should be considered a serious problem.
326 panic("nfsrv_advance");
329 * If left == -1, calculate it here.
332 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
336 * Loop around, advancing over the mbuf data.
338 while (offs > left) {
340 nd->nd_md = mbuf_next(nd->nd_md);
341 if (nd->nd_md == NULL) {
345 left = mbuf_len(nd->nd_md);
346 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
356 * Copy a string into mbuf(s).
357 * Return the number of bytes output, including XDR overheads.
360 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
369 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
370 *tl = txdr_unsigned(siz);
371 rem = NFSM_RNDUP(siz) - siz;
372 bytesize = NFSX_UNSIGNED + siz + rem;
375 left = M_TRAILINGSPACE(m2);
378 * Loop around copying the string to mbuf(s).
382 if (siz > ncl_mbuf_mlen)
383 NFSMCLGET(m1, M_WAIT);
387 mbuf_setnext(m2, m1);
389 cp2 = NFSMTOD(m2, caddr_t);
390 left = M_TRAILINGSPACE(m2);
396 NFSBCOPY(cp, cp2, xfer);
398 mbuf_setlen(m2, mbuf_len(m2) + xfer);
401 if (siz == 0 && rem) {
403 panic("nfsm_strtom");
404 NFSBZERO(cp2 + xfer, rem);
405 mbuf_setlen(m2, mbuf_len(m2) + rem);
409 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
414 * Called once to initialize data structures...
419 static int nfs_inited = 0;
425 newnfs_true = txdr_unsigned(TRUE);
426 newnfs_false = txdr_unsigned(FALSE);
427 newnfs_xdrneg1 = txdr_unsigned(-1);
428 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
431 NFSSETBOOTTIME(nfsboottime);
434 * Initialize reply list and start timer
436 TAILQ_INIT(&nfsd_reqq);
441 * Put a file handle in an mbuf list.
442 * If the size argument == 0, just use the default size.
443 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
444 * Return the number of bytes output, including XDR overhead.
447 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
451 int fullsiz, rem, bytesize = 0;
455 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
457 if (size > NFSX_V2FH)
458 panic("fh size > NFSX_V2FH for NFSv2");
459 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
460 NFSBCOPY(fhp, cp, size);
461 if (size < NFSX_V2FH)
462 NFSBZERO(cp + size, NFSX_V2FH - size);
463 bytesize = NFSX_V2FH;
467 fullsiz = NFSM_RNDUP(size);
468 rem = fullsiz - size;
470 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
471 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
474 bytesize = NFSX_UNSIGNED + fullsiz;
476 (void) nfsm_strtom(nd, fhp, size);
483 * This function compares two net addresses by family and returns TRUE
484 * if they are the same host.
485 * If there is any doubt, return FALSE.
486 * The AF_INET family is handled as a special case so that address mbufs
487 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
490 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
492 struct sockaddr_in *inetaddr;
496 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
497 if (inetaddr->sin_family == AF_INET &&
498 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
504 struct sockaddr_in6 *inetaddr6;
506 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
507 /* XXX - should test sin6_scope_id ? */
508 if (inetaddr6->sin6_family == AF_INET6 &&
509 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
520 * Similar to the above, but takes to NFSSOCKADDR_T args.
523 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
525 struct sockaddr_in *addr1, *addr2;
526 struct sockaddr *inaddr;
528 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
529 switch (inaddr->sa_family) {
531 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
532 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
533 if (addr2->sin_family == AF_INET &&
534 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
540 struct sockaddr_in6 *inet6addr1, *inet6addr2;
542 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
543 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
544 /* XXX - should test sin6_scope_id ? */
545 if (inet6addr2->sin6_family == AF_INET6 &&
546 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
547 &inet6addr2->sin6_addr))
558 * Trim the stuff already dissected off the mbuf list.
561 newnfs_trimleading(nd)
562 struct nfsrv_descript *nd;
568 * First, free up leading mbufs.
570 if (nd->nd_mrep != nd->nd_md) {
572 while (mbuf_next(m) != nd->nd_md) {
573 if (mbuf_next(m) == NULL)
574 panic("nfsm trim leading");
577 mbuf_setnext(m, NULL);
578 mbuf_freem(nd->nd_mrep);
583 * Now, adjust this mbuf, based on nd_dpos.
585 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
586 if (offs == mbuf_len(m)) {
590 panic("nfsm trim leading2");
591 mbuf_setnext(n, NULL);
593 } else if (offs > 0) {
594 mbuf_setlen(m, mbuf_len(m) - offs);
597 panic("nfsm trimleading offs");
600 nd->nd_dpos = NFSMTOD(m, caddr_t);
604 * Trim trailing data off the mbuf list being built.
607 newnfs_trimtrailing(nd, mb, bpos)
608 struct nfsrv_descript *nd;
614 mbuf_freem(mbuf_next(mb));
615 mbuf_setnext(mb, NULL);
617 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
623 * Dissect a file handle on the client.
626 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
633 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
634 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
635 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
642 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
644 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
646 FREE((caddr_t)nfhp, M_NFSFH);
652 NFSEXITCODE2(error, nd);
657 * Break down the nfsv4 acl.
658 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
661 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
662 int *aclsizep, __unused NFSPROC_T *p)
666 int acecnt, error = 0, aceerr = 0, acesize;
672 * Parse out the ace entries and expect them to conform to
673 * what can be supported by R/W/X bits.
675 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
676 aclsize = NFSX_UNSIGNED;
677 acecnt = fxdr_unsigned(int, *tl);
678 if (acecnt > ACL_MAX_ENTRIES)
679 aceerr = NFSERR_ATTRNOTSUPP;
680 if (nfsrv_useacl == 0)
681 aceerr = NFSERR_ATTRNOTSUPP;
682 for (i = 0; i < acecnt; i++) {
684 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
685 &aceerr, &acesize, p);
687 error = nfsrv_skipace(nd, &acesize);
693 aclp->acl_cnt = acecnt;
699 NFSEXITCODE2(error, nd);
704 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
707 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
712 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
713 len = fxdr_unsigned(int, *(tl + 3));
714 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
716 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
717 NFSEXITCODE2(error, nd);
722 * Get attribute bits from an mbuf list.
723 * Returns EBADRPC for a parsing error, 0 otherwise.
724 * If the clearinvalid flag is set, clear the bits not supported.
727 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
734 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
735 cnt = fxdr_unsigned(int, *tl);
737 error = NFSERR_BADXDR;
740 if (cnt > NFSATTRBIT_MAXWORDS) {
741 outcnt = NFSATTRBIT_MAXWORDS;
743 *retnotsupp = NFSERR_ATTRNOTSUPP;
747 NFSZERO_ATTRBIT(attrbitp);
749 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
750 for (i = 0; i < outcnt; i++)
751 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
754 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
756 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
758 NFSEXITCODE2(error, nd);
763 * Get the attributes for V4.
764 * If the compare flag is true, test for any attribute changes,
765 * otherwise return the attribute values.
766 * These attributes cover fields in "struct vattr", "struct statfs",
767 * "struct nfsfsinfo", the file handle and the lease duration.
768 * The value of retcmpp is set to 1 if all attributes are the same,
770 * Returns EBADRPC if it can't be parsed, 0 otherwise.
773 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
774 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
775 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
776 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
777 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
780 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
781 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
782 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
783 nfsattrbit_t attrbits, retattrbits, checkattrbits;
785 struct nfsreferral *refp;
788 struct timespec temptime;
792 u_int32_t freenum = 0, tuint;
793 u_int64_t uquad = 0, thyp, thyp2;
801 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
803 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
809 *retcmpp = retnotsup;
812 * Just set default values to some of the important ones.
817 nap->na_rdev = (NFSDEV_T)0;
818 nap->na_mtime.tv_sec = 0;
819 nap->na_mtime.tv_nsec = 0;
822 nap->na_blocksize = NFS_FABLKSIZE;
825 sbp->f_bsize = NFS_FABLKSIZE;
833 fsp->fs_rtmax = 8192;
834 fsp->fs_rtpref = 8192;
835 fsp->fs_maxname = NFS_MAXNAMLEN;
836 fsp->fs_wtmax = 8192;
837 fsp->fs_wtpref = 8192;
838 fsp->fs_wtmult = NFS_FABLKSIZE;
839 fsp->fs_dtpref = 8192;
840 fsp->fs_maxfilesize = 0xffffffffffffffffull;
841 fsp->fs_timedelta.tv_sec = 0;
842 fsp->fs_timedelta.tv_nsec = 1;
843 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
844 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
847 pc->pc_linkmax = LINK_MAX;
848 pc->pc_namemax = NAME_MAX;
850 pc->pc_chownrestricted = 0;
851 pc->pc_caseinsensitive = 0;
852 pc->pc_casepreserving = 1;
857 * Loop around getting the attributes.
859 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
860 attrsize = fxdr_unsigned(int, *tl);
861 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
862 if (attrsum > attrsize) {
863 error = NFSERR_BADXDR;
866 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
868 case NFSATTRBIT_SUPPORTEDATTRS:
870 if (compare || nap == NULL)
871 error = nfsrv_getattrbits(nd, &retattrbits,
874 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
878 if (compare && !(*retcmpp)) {
879 NFSSETSUPP_ATTRBIT(&checkattrbits);
880 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
882 *retcmpp = NFSERR_NOTSAME;
886 case NFSATTRBIT_TYPE:
887 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
890 if (nap->na_type != nfsv34tov_type(*tl))
891 *retcmpp = NFSERR_NOTSAME;
893 } else if (nap != NULL) {
894 nap->na_type = nfsv34tov_type(*tl);
896 attrsum += NFSX_UNSIGNED;
898 case NFSATTRBIT_FHEXPIRETYPE:
899 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
900 if (compare && !(*retcmpp)) {
901 if (fxdr_unsigned(int, *tl) !=
902 NFSV4FHTYPE_PERSISTENT)
903 *retcmpp = NFSERR_NOTSAME;
905 attrsum += NFSX_UNSIGNED;
907 case NFSATTRBIT_CHANGE:
908 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
911 if (nap->na_filerev != fxdr_hyper(tl))
912 *retcmpp = NFSERR_NOTSAME;
914 } else if (nap != NULL) {
915 nap->na_filerev = fxdr_hyper(tl);
917 attrsum += NFSX_HYPER;
919 case NFSATTRBIT_SIZE:
920 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
923 if (nap->na_size != fxdr_hyper(tl))
924 *retcmpp = NFSERR_NOTSAME;
926 } else if (nap != NULL) {
927 nap->na_size = fxdr_hyper(tl);
929 attrsum += NFSX_HYPER;
931 case NFSATTRBIT_LINKSUPPORT:
932 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
935 if (fsp->fs_properties & NFSV3_FSFLINK) {
936 if (*tl == newnfs_false)
937 *retcmpp = NFSERR_NOTSAME;
939 if (*tl == newnfs_true)
940 *retcmpp = NFSERR_NOTSAME;
943 } else if (fsp != NULL) {
944 if (*tl == newnfs_true)
945 fsp->fs_properties |= NFSV3_FSFLINK;
947 fsp->fs_properties &= ~NFSV3_FSFLINK;
949 attrsum += NFSX_UNSIGNED;
951 case NFSATTRBIT_SYMLINKSUPPORT:
952 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
955 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
956 if (*tl == newnfs_false)
957 *retcmpp = NFSERR_NOTSAME;
959 if (*tl == newnfs_true)
960 *retcmpp = NFSERR_NOTSAME;
963 } else if (fsp != NULL) {
964 if (*tl == newnfs_true)
965 fsp->fs_properties |= NFSV3_FSFSYMLINK;
967 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
969 attrsum += NFSX_UNSIGNED;
971 case NFSATTRBIT_NAMEDATTR:
972 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
973 if (compare && !(*retcmpp)) {
974 if (*tl != newnfs_false)
975 *retcmpp = NFSERR_NOTSAME;
977 attrsum += NFSX_UNSIGNED;
979 case NFSATTRBIT_FSID:
980 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
981 thyp = fxdr_hyper(tl);
983 thyp2 = fxdr_hyper(tl);
986 if (thyp != (u_int64_t)
987 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
989 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
990 *retcmpp = NFSERR_NOTSAME;
992 } else if (nap != NULL) {
993 nap->na_filesid[0] = thyp;
994 nap->na_filesid[1] = thyp2;
996 attrsum += (4 * NFSX_UNSIGNED);
998 case NFSATTRBIT_UNIQUEHANDLES:
999 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1000 if (compare && !(*retcmpp)) {
1001 if (*tl != newnfs_true)
1002 *retcmpp = NFSERR_NOTSAME;
1004 attrsum += NFSX_UNSIGNED;
1006 case NFSATTRBIT_LEASETIME:
1007 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1009 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1011 *retcmpp = NFSERR_NOTSAME;
1012 } else if (leasep != NULL) {
1013 *leasep = fxdr_unsigned(u_int32_t, *tl);
1015 attrsum += NFSX_UNSIGNED;
1017 case NFSATTRBIT_RDATTRERROR:
1018 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1021 *retcmpp = NFSERR_INVAL;
1022 } else if (rderrp != NULL) {
1023 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1025 attrsum += NFSX_UNSIGNED;
1027 case NFSATTRBIT_ACL:
1033 naclp = acl_alloc(M_WAITOK);
1034 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1040 if (aceerr || aclp == NULL ||
1041 nfsrv_compareacl(aclp, naclp))
1042 *retcmpp = NFSERR_NOTSAME;
1045 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1047 *retcmpp = NFSERR_ATTRNOTSUPP;
1051 if (vp != NULL && aclp != NULL)
1052 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1055 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1062 case NFSATTRBIT_ACLSUPPORT:
1063 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1064 if (compare && !(*retcmpp)) {
1066 if (fxdr_unsigned(u_int32_t, *tl) !=
1068 *retcmpp = NFSERR_NOTSAME;
1070 *retcmpp = NFSERR_ATTRNOTSUPP;
1073 attrsum += NFSX_UNSIGNED;
1075 case NFSATTRBIT_ARCHIVE:
1076 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1077 if (compare && !(*retcmpp))
1078 *retcmpp = NFSERR_ATTRNOTSUPP;
1079 attrsum += NFSX_UNSIGNED;
1081 case NFSATTRBIT_CANSETTIME:
1082 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1085 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1086 if (*tl == newnfs_false)
1087 *retcmpp = NFSERR_NOTSAME;
1089 if (*tl == newnfs_true)
1090 *retcmpp = NFSERR_NOTSAME;
1093 } else if (fsp != NULL) {
1094 if (*tl == newnfs_true)
1095 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1097 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1099 attrsum += NFSX_UNSIGNED;
1101 case NFSATTRBIT_CASEINSENSITIVE:
1102 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1105 if (*tl != newnfs_false)
1106 *retcmpp = NFSERR_NOTSAME;
1108 } else if (pc != NULL) {
1109 pc->pc_caseinsensitive =
1110 fxdr_unsigned(u_int32_t, *tl);
1112 attrsum += NFSX_UNSIGNED;
1114 case NFSATTRBIT_CASEPRESERVING:
1115 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118 if (*tl != newnfs_true)
1119 *retcmpp = NFSERR_NOTSAME;
1121 } else if (pc != NULL) {
1122 pc->pc_casepreserving =
1123 fxdr_unsigned(u_int32_t, *tl);
1125 attrsum += NFSX_UNSIGNED;
1127 case NFSATTRBIT_CHOWNRESTRICTED:
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1131 if (*tl != newnfs_true)
1132 *retcmpp = NFSERR_NOTSAME;
1134 } else if (pc != NULL) {
1135 pc->pc_chownrestricted =
1136 fxdr_unsigned(u_int32_t, *tl);
1138 attrsum += NFSX_UNSIGNED;
1140 case NFSATTRBIT_FILEHANDLE:
1141 error = nfsm_getfh(nd, &tnfhp);
1144 tfhsize = tnfhp->nfh_len;
1147 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1149 *retcmpp = NFSERR_NOTSAME;
1150 FREE((caddr_t)tnfhp, M_NFSFH);
1151 } else if (nfhpp != NULL) {
1154 FREE((caddr_t)tnfhp, M_NFSFH);
1156 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1158 case NFSATTRBIT_FILEID:
1159 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1160 thyp = fxdr_hyper(tl);
1163 if ((u_int64_t)nap->na_fileid != thyp)
1164 *retcmpp = NFSERR_NOTSAME;
1166 } else if (nap != NULL) {
1168 printf("NFSv4 fileid > 32bits\n");
1169 nap->na_fileid = thyp;
1171 attrsum += NFSX_HYPER;
1173 case NFSATTRBIT_FILESAVAIL:
1174 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1177 sfp->sf_afiles != fxdr_hyper(tl))
1178 *retcmpp = NFSERR_NOTSAME;
1179 } else if (sfp != NULL) {
1180 sfp->sf_afiles = fxdr_hyper(tl);
1182 attrsum += NFSX_HYPER;
1184 case NFSATTRBIT_FILESFREE:
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1188 sfp->sf_ffiles != fxdr_hyper(tl))
1189 *retcmpp = NFSERR_NOTSAME;
1190 } else if (sfp != NULL) {
1191 sfp->sf_ffiles = fxdr_hyper(tl);
1193 attrsum += NFSX_HYPER;
1195 case NFSATTRBIT_FILESTOTAL:
1196 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1199 sfp->sf_tfiles != fxdr_hyper(tl))
1200 *retcmpp = NFSERR_NOTSAME;
1201 } else if (sfp != NULL) {
1202 sfp->sf_tfiles = fxdr_hyper(tl);
1204 attrsum += NFSX_HYPER;
1206 case NFSATTRBIT_FSLOCATIONS:
1207 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1211 if (compare && !(*retcmpp)) {
1212 refp = nfsv4root_getreferral(vp, NULL, 0);
1214 if (cp == NULL || cp2 == NULL ||
1216 strcmp(cp2, refp->nfr_srvlist))
1217 *retcmpp = NFSERR_NOTSAME;
1218 } else if (m == 0) {
1219 *retcmpp = NFSERR_NOTSAME;
1223 free(cp, M_NFSSTRING);
1225 free(cp2, M_NFSSTRING);
1227 case NFSATTRBIT_HIDDEN:
1228 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1229 if (compare && !(*retcmpp))
1230 *retcmpp = NFSERR_ATTRNOTSUPP;
1231 attrsum += NFSX_UNSIGNED;
1233 case NFSATTRBIT_HOMOGENEOUS:
1234 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1237 if (fsp->fs_properties &
1238 NFSV3_FSFHOMOGENEOUS) {
1239 if (*tl == newnfs_false)
1240 *retcmpp = NFSERR_NOTSAME;
1242 if (*tl == newnfs_true)
1243 *retcmpp = NFSERR_NOTSAME;
1246 } else if (fsp != NULL) {
1247 if (*tl == newnfs_true)
1248 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1250 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1252 attrsum += NFSX_UNSIGNED;
1254 case NFSATTRBIT_MAXFILESIZE:
1255 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1256 tnfsquad.qval = fxdr_hyper(tl);
1259 tquad = NFSRV_MAXFILESIZE;
1260 if (tquad != tnfsquad.qval)
1261 *retcmpp = NFSERR_NOTSAME;
1263 } else if (fsp != NULL) {
1264 fsp->fs_maxfilesize = tnfsquad.qval;
1266 attrsum += NFSX_HYPER;
1268 case NFSATTRBIT_MAXLINK:
1269 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1272 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1273 *retcmpp = NFSERR_NOTSAME;
1275 } else if (pc != NULL) {
1276 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1278 attrsum += NFSX_UNSIGNED;
1280 case NFSATTRBIT_MAXNAME:
1281 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1284 if (fsp->fs_maxname !=
1285 fxdr_unsigned(u_int32_t, *tl))
1286 *retcmpp = NFSERR_NOTSAME;
1289 tuint = fxdr_unsigned(u_int32_t, *tl);
1291 * Some Linux NFSv4 servers report this
1292 * as 0 or 4billion, so I'll set it to
1293 * NFS_MAXNAMLEN. If a server actually creates
1294 * a name longer than NFS_MAXNAMLEN, it will
1295 * get an error back.
1297 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1298 tuint = NFS_MAXNAMLEN;
1300 fsp->fs_maxname = tuint;
1302 pc->pc_namemax = tuint;
1304 attrsum += NFSX_UNSIGNED;
1306 case NFSATTRBIT_MAXREAD:
1307 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1310 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1311 *(tl + 1)) || *tl != 0)
1312 *retcmpp = NFSERR_NOTSAME;
1314 } else if (fsp != NULL) {
1315 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1316 fsp->fs_rtpref = fsp->fs_rtmax;
1317 fsp->fs_dtpref = fsp->fs_rtpref;
1319 attrsum += NFSX_HYPER;
1321 case NFSATTRBIT_MAXWRITE:
1322 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1325 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1326 *(tl + 1)) || *tl != 0)
1327 *retcmpp = NFSERR_NOTSAME;
1329 } else if (fsp != NULL) {
1330 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1331 fsp->fs_wtpref = fsp->fs_wtmax;
1333 attrsum += NFSX_HYPER;
1335 case NFSATTRBIT_MIMETYPE:
1336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1337 i = fxdr_unsigned(int, *tl);
1338 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1339 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1342 if (compare && !(*retcmpp))
1343 *retcmpp = NFSERR_ATTRNOTSUPP;
1345 case NFSATTRBIT_MODE:
1346 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1349 if (nap->na_mode != nfstov_mode(*tl))
1350 *retcmpp = NFSERR_NOTSAME;
1352 } else if (nap != NULL) {
1353 nap->na_mode = nfstov_mode(*tl);
1355 attrsum += NFSX_UNSIGNED;
1357 case NFSATTRBIT_NOTRUNC:
1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1361 if (*tl != newnfs_true)
1362 *retcmpp = NFSERR_NOTSAME;
1364 } else if (pc != NULL) {
1365 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1367 attrsum += NFSX_UNSIGNED;
1369 case NFSATTRBIT_NUMLINKS:
1370 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1371 tuint = fxdr_unsigned(u_int32_t, *tl);
1374 if ((u_int32_t)nap->na_nlink != tuint)
1375 *retcmpp = NFSERR_NOTSAME;
1377 } else if (nap != NULL) {
1378 nap->na_nlink = tuint;
1380 attrsum += NFSX_UNSIGNED;
1382 case NFSATTRBIT_OWNER:
1383 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1384 j = fxdr_unsigned(int, *tl);
1386 error = NFSERR_BADXDR;
1389 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1390 if (j > NFSV4_SMALLSTR)
1391 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1394 error = nfsrv_mtostr(nd, cp, j);
1396 if (j > NFSV4_SMALLSTR)
1397 free(cp, M_NFSSTRING);
1402 if (nfsv4_strtouid(cp, j, &uid, p) ||
1404 *retcmpp = NFSERR_NOTSAME;
1406 } else if (nap != NULL) {
1407 if (nfsv4_strtouid(cp, j, &uid, p))
1408 nap->na_uid = nfsrv_defaultuid;
1412 if (j > NFSV4_SMALLSTR)
1413 free(cp, M_NFSSTRING);
1415 case NFSATTRBIT_OWNERGROUP:
1416 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1417 j = fxdr_unsigned(int, *tl);
1419 error = NFSERR_BADXDR;
1422 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1423 if (j > NFSV4_SMALLSTR)
1424 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1427 error = nfsrv_mtostr(nd, cp, j);
1429 if (j > NFSV4_SMALLSTR)
1430 free(cp, M_NFSSTRING);
1435 if (nfsv4_strtogid(cp, j, &gid, p) ||
1437 *retcmpp = NFSERR_NOTSAME;
1439 } else if (nap != NULL) {
1440 if (nfsv4_strtogid(cp, j, &gid, p))
1441 nap->na_gid = nfsrv_defaultgid;
1445 if (j > NFSV4_SMALLSTR)
1446 free(cp, M_NFSSTRING);
1448 case NFSATTRBIT_QUOTAHARD:
1449 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1451 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1452 freenum = sbp->f_bfree;
1454 freenum = sbp->f_bavail;
1457 * ufs_quotactl() insists that the uid argument
1458 * equal p_ruid for non-root quota access, so
1459 * we'll just make sure that's the case.
1461 savuid = p->p_cred->p_ruid;
1462 p->p_cred->p_ruid = cred->cr_uid;
1463 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1464 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1465 freenum = min(dqb.dqb_bhardlimit, freenum);
1466 p->p_cred->p_ruid = savuid;
1468 uquad = (u_int64_t)freenum;
1469 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1471 if (compare && !(*retcmpp)) {
1472 if (uquad != fxdr_hyper(tl))
1473 *retcmpp = NFSERR_NOTSAME;
1475 attrsum += NFSX_HYPER;
1477 case NFSATTRBIT_QUOTASOFT:
1478 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1480 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1481 freenum = sbp->f_bfree;
1483 freenum = sbp->f_bavail;
1486 * ufs_quotactl() insists that the uid argument
1487 * equal p_ruid for non-root quota access, so
1488 * we'll just make sure that's the case.
1490 savuid = p->p_cred->p_ruid;
1491 p->p_cred->p_ruid = cred->cr_uid;
1492 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1493 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1494 freenum = min(dqb.dqb_bsoftlimit, freenum);
1495 p->p_cred->p_ruid = savuid;
1497 uquad = (u_int64_t)freenum;
1498 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1500 if (compare && !(*retcmpp)) {
1501 if (uquad != fxdr_hyper(tl))
1502 *retcmpp = NFSERR_NOTSAME;
1504 attrsum += NFSX_HYPER;
1506 case NFSATTRBIT_QUOTAUSED:
1507 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1512 * ufs_quotactl() insists that the uid argument
1513 * equal p_ruid for non-root quota access, so
1514 * we'll just make sure that's the case.
1516 savuid = p->p_cred->p_ruid;
1517 p->p_cred->p_ruid = cred->cr_uid;
1518 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1519 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1520 freenum = dqb.dqb_curblocks;
1521 p->p_cred->p_ruid = savuid;
1523 uquad = (u_int64_t)freenum;
1524 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1526 if (compare && !(*retcmpp)) {
1527 if (uquad != fxdr_hyper(tl))
1528 *retcmpp = NFSERR_NOTSAME;
1530 attrsum += NFSX_HYPER;
1532 case NFSATTRBIT_RAWDEV:
1533 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1534 j = fxdr_unsigned(int, *tl++);
1535 k = fxdr_unsigned(int, *tl);
1538 if (nap->na_rdev != NFSMAKEDEV(j, k))
1539 *retcmpp = NFSERR_NOTSAME;
1541 } else if (nap != NULL) {
1542 nap->na_rdev = NFSMAKEDEV(j, k);
1544 attrsum += NFSX_V4SPECDATA;
1546 case NFSATTRBIT_SPACEAVAIL:
1547 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1550 sfp->sf_abytes != fxdr_hyper(tl))
1551 *retcmpp = NFSERR_NOTSAME;
1552 } else if (sfp != NULL) {
1553 sfp->sf_abytes = fxdr_hyper(tl);
1555 attrsum += NFSX_HYPER;
1557 case NFSATTRBIT_SPACEFREE:
1558 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1561 sfp->sf_fbytes != fxdr_hyper(tl))
1562 *retcmpp = NFSERR_NOTSAME;
1563 } else if (sfp != NULL) {
1564 sfp->sf_fbytes = fxdr_hyper(tl);
1566 attrsum += NFSX_HYPER;
1568 case NFSATTRBIT_SPACETOTAL:
1569 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1572 sfp->sf_tbytes != fxdr_hyper(tl))
1573 *retcmpp = NFSERR_NOTSAME;
1574 } else if (sfp != NULL) {
1575 sfp->sf_tbytes = fxdr_hyper(tl);
1577 attrsum += NFSX_HYPER;
1579 case NFSATTRBIT_SPACEUSED:
1580 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1581 thyp = fxdr_hyper(tl);
1584 if ((u_int64_t)nap->na_bytes != thyp)
1585 *retcmpp = NFSERR_NOTSAME;
1587 } else if (nap != NULL) {
1588 nap->na_bytes = thyp;
1590 attrsum += NFSX_HYPER;
1592 case NFSATTRBIT_SYSTEM:
1593 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1594 if (compare && !(*retcmpp))
1595 *retcmpp = NFSERR_ATTRNOTSUPP;
1596 attrsum += NFSX_UNSIGNED;
1598 case NFSATTRBIT_TIMEACCESS:
1599 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1600 fxdr_nfsv4time(tl, &temptime);
1603 if (!NFS_CMPTIME(temptime, nap->na_atime))
1604 *retcmpp = NFSERR_NOTSAME;
1606 } else if (nap != NULL) {
1607 nap->na_atime = temptime;
1609 attrsum += NFSX_V4TIME;
1611 case NFSATTRBIT_TIMEACCESSSET:
1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1613 attrsum += NFSX_UNSIGNED;
1614 i = fxdr_unsigned(int, *tl);
1615 if (i == NFSV4SATTRTIME_TOCLIENT) {
1616 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1617 attrsum += NFSX_V4TIME;
1619 if (compare && !(*retcmpp))
1620 *retcmpp = NFSERR_INVAL;
1622 case NFSATTRBIT_TIMEBACKUP:
1623 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1624 if (compare && !(*retcmpp))
1625 *retcmpp = NFSERR_ATTRNOTSUPP;
1626 attrsum += NFSX_V4TIME;
1628 case NFSATTRBIT_TIMECREATE:
1629 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1630 if (compare && !(*retcmpp))
1631 *retcmpp = NFSERR_ATTRNOTSUPP;
1632 attrsum += NFSX_V4TIME;
1634 case NFSATTRBIT_TIMEDELTA:
1635 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1639 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1640 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1641 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1642 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1645 *retcmpp = NFSERR_NOTSAME;
1648 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1651 attrsum += NFSX_V4TIME;
1653 case NFSATTRBIT_TIMEMETADATA:
1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1655 fxdr_nfsv4time(tl, &temptime);
1658 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1659 *retcmpp = NFSERR_NOTSAME;
1661 } else if (nap != NULL) {
1662 nap->na_ctime = temptime;
1664 attrsum += NFSX_V4TIME;
1666 case NFSATTRBIT_TIMEMODIFY:
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1668 fxdr_nfsv4time(tl, &temptime);
1671 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1672 *retcmpp = NFSERR_NOTSAME;
1674 } else if (nap != NULL) {
1675 nap->na_mtime = temptime;
1677 attrsum += NFSX_V4TIME;
1679 case NFSATTRBIT_TIMEMODIFYSET:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1681 attrsum += NFSX_UNSIGNED;
1682 i = fxdr_unsigned(int, *tl);
1683 if (i == NFSV4SATTRTIME_TOCLIENT) {
1684 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1685 attrsum += NFSX_V4TIME;
1687 if (compare && !(*retcmpp))
1688 *retcmpp = NFSERR_INVAL;
1690 case NFSATTRBIT_MOUNTEDONFILEID:
1691 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1692 thyp = fxdr_hyper(tl);
1696 *retcmpp = NFSERR_NOTSAME;
1698 if (!vp || !nfsrv_atroot(vp, &fid))
1699 fid = nap->na_fileid;
1700 if ((u_int64_t)fid != thyp)
1701 *retcmpp = NFSERR_NOTSAME;
1704 } else if (nap != NULL) {
1706 printf("NFSv4 mounted on fileid > 32bits\n");
1707 nap->na_mntonfileno = thyp;
1709 attrsum += NFSX_HYPER;
1712 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1714 if (compare && !(*retcmpp))
1715 *retcmpp = NFSERR_ATTRNOTSUPP;
1717 * and get out of the loop, since we can't parse
1718 * the unknown attrbute data.
1720 bitpos = NFSATTRBIT_MAX;
1726 * some clients pad the attrlist, so we need to skip over the
1729 if (attrsum > attrsize) {
1730 error = NFSERR_BADXDR;
1732 attrsize = NFSM_RNDUP(attrsize);
1733 if (attrsum < attrsize)
1734 error = nfsm_advance(nd, attrsize - attrsum, -1);
1737 NFSEXITCODE2(error, nd);
1742 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1743 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1744 * The first argument is a pointer to an nfsv4lock structure.
1745 * The second argument is 1 iff a blocking lock is wanted.
1746 * If this argument is 0, the call waits until no thread either wants nor
1747 * holds an exclusive lock.
1748 * It returns 1 if the lock was acquired, 0 otherwise.
1749 * If several processes call this function concurrently wanting the exclusive
1750 * lock, one will get the lock and the rest will return without getting the
1751 * lock. (If the caller must have the lock, it simply calls this function in a
1752 * loop until the function returns 1 to indicate the lock was acquired.)
1753 * Any usecnt must be decremented by calling nfsv4_relref() before
1754 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1755 * be called in a loop.
1756 * The isleptp argument is set to indicate if the call slept, iff not NULL
1757 * and the mp argument indicates to check for a forced dismount, iff not
1761 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1762 void *mutex, struct mount *mp)
1768 * If a lock is wanted, loop around until the lock is acquired by
1769 * someone and then released. If I want the lock, try to acquire it.
1770 * For a lock to be issued, no lock must be in force and the usecnt
1774 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1775 lp->nfslock_usecnt == 0) {
1776 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1777 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1780 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1782 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1783 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1784 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1787 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1790 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1791 PZERO - 1, "nfsv4lck", NULL);
1792 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1793 lp->nfslock_usecnt == 0) {
1794 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1795 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1803 * Release the lock acquired by nfsv4_lock().
1804 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1805 * incremented, as well.
1808 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1811 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1813 lp->nfslock_usecnt++;
1818 * Release a reference cnt.
1821 nfsv4_relref(struct nfsv4lock *lp)
1824 if (lp->nfslock_usecnt <= 0)
1825 panic("nfsv4root ref cnt");
1826 lp->nfslock_usecnt--;
1827 if (lp->nfslock_usecnt == 0)
1832 * Get a reference cnt.
1833 * This function will wait for any exclusive lock to be released, but will
1834 * not wait for threads that want the exclusive lock. If priority needs
1835 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1836 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1837 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1838 * return without getting a refcnt for that case.
1841 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1849 * Wait for a lock held.
1851 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1852 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1854 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1857 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1858 PZERO - 1, "nfsv4lck", NULL);
1860 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1863 lp->nfslock_usecnt++;
1867 * Get a reference as above, but return failure instead of sleeping if
1868 * an exclusive lock is held.
1871 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1874 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1877 lp->nfslock_usecnt++;
1882 * Test for a lock. Return 1 if locked, 0 otherwise.
1885 nfsv4_testlock(struct nfsv4lock *lp)
1888 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1889 lp->nfslock_usecnt == 0)
1895 * Wake up anyone sleeping, waiting for this lock.
1898 nfsv4_wanted(struct nfsv4lock *lp)
1901 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1902 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1903 wakeup((caddr_t)&lp->nfslock_lock);
1908 * Copy a string from an mbuf list into a character array.
1909 * Return EBADRPC if there is an mbuf error,
1913 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1922 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1923 rem = NFSM_RNDUP(siz) - siz;
1929 NFSBCOPY(cp, str, xfer);
1938 cp = NFSMTOD(mp, caddr_t);
1950 error = nfsm_advance(nd, rem, len);
1956 NFSEXITCODE2(error, nd);
1961 * Fill in the attributes as marked by the bitmap (V4).
1964 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1965 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1966 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1967 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1969 int bitpos, retnum = 0;
1971 int siz, prefixnum, error;
1972 u_char *cp, namestr[NFSV4_SMALLSTR];
1973 nfsattrbit_t attrbits, retbits;
1974 nfsattrbit_t *retbitp = &retbits;
1975 u_int32_t freenum, *retnump;
1978 struct nfsfsinfo fsinf;
1979 struct timespec temptime;
1980 struct timeval curtime;
1981 NFSACL_T *aclp, *naclp = NULL;
1988 * First, set the bits that can be filled and get fsinfo.
1990 NFSSET_ATTRBIT(retbitp, attrbitp);
1991 /* If p and cred are NULL, it is a client side call */
1992 if (p == NULL && cred == NULL) {
1993 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1996 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1997 naclp = acl_alloc(M_WAITOK);
2000 nfsvno_getfs(&fsinf, isdgram);
2003 * Get the VFS_STATFS(), since some attributes need them.
2005 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2006 error = VFS_STATFS(mp, &fs);
2009 nd->nd_repstat = NFSERR_ACCES;
2012 NFSCLRSTATFS_ATTRBIT(retbitp);
2018 * And the NFSv4 ACL...
2020 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2021 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2022 supports_nfsv4acls == 0))) {
2023 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2025 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2026 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2027 supports_nfsv4acls == 0)) {
2028 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2029 } else if (naclp != NULL) {
2030 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2031 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2033 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2035 NFSVOPUNLOCK(vp, 0);
2037 error = NFSERR_PERM;
2040 nd->nd_repstat = NFSERR_ACCES;
2043 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2048 * Put out the attribute bitmap for the ones being filled in
2049 * and get the field for the number of attributes returned.
2051 prefixnum = nfsrv_putattrbit(nd, retbitp);
2052 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2053 prefixnum += NFSX_UNSIGNED;
2056 * Now, loop around filling in the attributes for each bit set.
2058 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2059 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2061 case NFSATTRBIT_SUPPORTEDATTRS:
2062 NFSSETSUPP_ATTRBIT(&attrbits);
2063 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2064 && supports_nfsv4acls == 0)) {
2065 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2066 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2068 retnum += nfsrv_putattrbit(nd, &attrbits);
2070 case NFSATTRBIT_TYPE:
2071 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2072 *tl = vtonfsv34_type(vap->va_type);
2073 retnum += NFSX_UNSIGNED;
2075 case NFSATTRBIT_FHEXPIRETYPE:
2076 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2077 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2078 retnum += NFSX_UNSIGNED;
2080 case NFSATTRBIT_CHANGE:
2081 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2082 txdr_hyper(vap->va_filerev, tl);
2083 retnum += NFSX_HYPER;
2085 case NFSATTRBIT_SIZE:
2086 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2087 txdr_hyper(vap->va_size, tl);
2088 retnum += NFSX_HYPER;
2090 case NFSATTRBIT_LINKSUPPORT:
2091 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2092 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2096 retnum += NFSX_UNSIGNED;
2098 case NFSATTRBIT_SYMLINKSUPPORT:
2099 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2100 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2104 retnum += NFSX_UNSIGNED;
2106 case NFSATTRBIT_NAMEDATTR:
2107 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2109 retnum += NFSX_UNSIGNED;
2111 case NFSATTRBIT_FSID:
2112 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2114 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2116 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2117 retnum += NFSX_V4FSID;
2119 case NFSATTRBIT_UNIQUEHANDLES:
2120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2122 retnum += NFSX_UNSIGNED;
2124 case NFSATTRBIT_LEASETIME:
2125 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2126 *tl = txdr_unsigned(nfsrv_lease);
2127 retnum += NFSX_UNSIGNED;
2129 case NFSATTRBIT_RDATTRERROR:
2130 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2131 *tl = txdr_unsigned(rderror);
2132 retnum += NFSX_UNSIGNED;
2135 * Recommended Attributes. (Only the supported ones.)
2137 case NFSATTRBIT_ACL:
2138 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2140 case NFSATTRBIT_ACLSUPPORT:
2141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2142 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2143 retnum += NFSX_UNSIGNED;
2145 case NFSATTRBIT_CANSETTIME:
2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2147 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2151 retnum += NFSX_UNSIGNED;
2153 case NFSATTRBIT_CASEINSENSITIVE:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2156 retnum += NFSX_UNSIGNED;
2158 case NFSATTRBIT_CASEPRESERVING:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2161 retnum += NFSX_UNSIGNED;
2163 case NFSATTRBIT_CHOWNRESTRICTED:
2164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2166 retnum += NFSX_UNSIGNED;
2168 case NFSATTRBIT_FILEHANDLE:
2169 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2171 case NFSATTRBIT_FILEID:
2172 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2174 *tl = txdr_unsigned(vap->va_fileid);
2175 retnum += NFSX_HYPER;
2177 case NFSATTRBIT_FILESAVAIL:
2179 * Check quota and use min(quota, f_ffree).
2181 freenum = fs.f_ffree;
2184 * ufs_quotactl() insists that the uid argument
2185 * equal p_ruid for non-root quota access, so
2186 * we'll just make sure that's the case.
2188 savuid = p->p_cred->p_ruid;
2189 p->p_cred->p_ruid = cred->cr_uid;
2190 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2191 cred->cr_uid, (caddr_t)&dqb))
2192 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2194 p->p_cred->p_ruid = savuid;
2196 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2198 *tl = txdr_unsigned(freenum);
2199 retnum += NFSX_HYPER;
2201 case NFSATTRBIT_FILESFREE:
2202 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2204 *tl = txdr_unsigned(fs.f_ffree);
2205 retnum += NFSX_HYPER;
2207 case NFSATTRBIT_FILESTOTAL:
2208 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2210 *tl = txdr_unsigned(fs.f_files);
2211 retnum += NFSX_HYPER;
2213 case NFSATTRBIT_FSLOCATIONS:
2214 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2217 retnum += 2 * NFSX_UNSIGNED;
2219 case NFSATTRBIT_HOMOGENEOUS:
2220 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2221 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2225 retnum += NFSX_UNSIGNED;
2227 case NFSATTRBIT_MAXFILESIZE:
2228 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2229 uquad = NFSRV_MAXFILESIZE;
2230 txdr_hyper(uquad, tl);
2231 retnum += NFSX_HYPER;
2233 case NFSATTRBIT_MAXLINK:
2234 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2235 *tl = txdr_unsigned(LINK_MAX);
2236 retnum += NFSX_UNSIGNED;
2238 case NFSATTRBIT_MAXNAME:
2239 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2240 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2241 retnum += NFSX_UNSIGNED;
2243 case NFSATTRBIT_MAXREAD:
2244 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2246 *tl = txdr_unsigned(fsinf.fs_rtmax);
2247 retnum += NFSX_HYPER;
2249 case NFSATTRBIT_MAXWRITE:
2250 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 *tl = txdr_unsigned(fsinf.fs_wtmax);
2253 retnum += NFSX_HYPER;
2255 case NFSATTRBIT_MODE:
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2257 *tl = vtonfsv34_mode(vap->va_mode);
2258 retnum += NFSX_UNSIGNED;
2260 case NFSATTRBIT_NOTRUNC:
2261 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 retnum += NFSX_UNSIGNED;
2265 case NFSATTRBIT_NUMLINKS:
2266 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2267 *tl = txdr_unsigned(vap->va_nlink);
2268 retnum += NFSX_UNSIGNED;
2270 case NFSATTRBIT_OWNER:
2272 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2273 retnum += nfsm_strtom(nd, cp, siz);
2275 free(cp, M_NFSSTRING);
2277 case NFSATTRBIT_OWNERGROUP:
2279 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2280 retnum += nfsm_strtom(nd, cp, siz);
2282 free(cp, M_NFSSTRING);
2284 case NFSATTRBIT_QUOTAHARD:
2285 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2286 freenum = fs.f_bfree;
2288 freenum = fs.f_bavail;
2291 * ufs_quotactl() insists that the uid argument
2292 * equal p_ruid for non-root quota access, so
2293 * we'll just make sure that's the case.
2295 savuid = p->p_cred->p_ruid;
2296 p->p_cred->p_ruid = cred->cr_uid;
2297 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2298 cred->cr_uid, (caddr_t)&dqb))
2299 freenum = min(dqb.dqb_bhardlimit, freenum);
2300 p->p_cred->p_ruid = savuid;
2302 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2303 uquad = (u_int64_t)freenum;
2304 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2305 txdr_hyper(uquad, tl);
2306 retnum += NFSX_HYPER;
2308 case NFSATTRBIT_QUOTASOFT:
2309 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2310 freenum = fs.f_bfree;
2312 freenum = fs.f_bavail;
2315 * ufs_quotactl() insists that the uid argument
2316 * equal p_ruid for non-root quota access, so
2317 * we'll just make sure that's the case.
2319 savuid = p->p_cred->p_ruid;
2320 p->p_cred->p_ruid = cred->cr_uid;
2321 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2322 cred->cr_uid, (caddr_t)&dqb))
2323 freenum = min(dqb.dqb_bsoftlimit, freenum);
2324 p->p_cred->p_ruid = savuid;
2326 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2327 uquad = (u_int64_t)freenum;
2328 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2329 txdr_hyper(uquad, tl);
2330 retnum += NFSX_HYPER;
2332 case NFSATTRBIT_QUOTAUSED:
2336 * ufs_quotactl() insists that the uid argument
2337 * equal p_ruid for non-root quota access, so
2338 * we'll just make sure that's the case.
2340 savuid = p->p_cred->p_ruid;
2341 p->p_cred->p_ruid = cred->cr_uid;
2342 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2343 cred->cr_uid, (caddr_t)&dqb))
2344 freenum = dqb.dqb_curblocks;
2345 p->p_cred->p_ruid = savuid;
2347 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2348 uquad = (u_int64_t)freenum;
2349 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2350 txdr_hyper(uquad, tl);
2351 retnum += NFSX_HYPER;
2353 case NFSATTRBIT_RAWDEV:
2354 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2355 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2356 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2357 retnum += NFSX_V4SPECDATA;
2359 case NFSATTRBIT_SPACEAVAIL:
2360 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2361 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2362 uquad = (u_int64_t)fs.f_bfree;
2364 uquad = (u_int64_t)fs.f_bavail;
2365 uquad *= fs.f_bsize;
2366 txdr_hyper(uquad, tl);
2367 retnum += NFSX_HYPER;
2369 case NFSATTRBIT_SPACEFREE:
2370 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2371 uquad = (u_int64_t)fs.f_bfree;
2372 uquad *= fs.f_bsize;
2373 txdr_hyper(uquad, tl);
2374 retnum += NFSX_HYPER;
2376 case NFSATTRBIT_SPACETOTAL:
2377 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2378 uquad = (u_int64_t)fs.f_blocks;
2379 uquad *= fs.f_bsize;
2380 txdr_hyper(uquad, tl);
2381 retnum += NFSX_HYPER;
2383 case NFSATTRBIT_SPACEUSED:
2384 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2385 txdr_hyper(vap->va_bytes, tl);
2386 retnum += NFSX_HYPER;
2388 case NFSATTRBIT_TIMEACCESS:
2389 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2390 txdr_nfsv4time(&vap->va_atime, tl);
2391 retnum += NFSX_V4TIME;
2393 case NFSATTRBIT_TIMEACCESSSET:
2394 NFSGETTIME(&curtime);
2395 if (vap->va_atime.tv_sec != curtime.tv_sec) {
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 NFSGETTIME(&curtime);
2425 if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2426 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2427 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2428 txdr_nfsv4time(&vap->va_mtime, tl);
2429 retnum += NFSX_V4SETTIME;
2431 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2432 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2433 retnum += NFSX_UNSIGNED;
2436 case NFSATTRBIT_MOUNTEDONFILEID:
2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2439 uquad = mounted_on_fileno;
2441 uquad = (u_int64_t)vap->va_fileid;
2442 txdr_hyper(uquad, tl);
2443 retnum += NFSX_HYPER;
2446 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2452 *retnump = txdr_unsigned(retnum);
2453 return (retnum + prefixnum);
2457 * Put the attribute bits onto an mbuf list.
2458 * Return the number of bytes of output generated.
2461 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2464 int cnt, i, bytesize;
2466 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2467 if (attrbitp->bits[cnt - 1])
2469 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2470 NFSM_BUILD(tl, u_int32_t *, bytesize);
2471 *tl++ = txdr_unsigned(cnt);
2472 for (i = 0; i < cnt; i++)
2473 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2478 * Convert a uid to a string.
2479 * If the lookup fails, just output the digits.
2481 * cpp - points to a buffer of size NFSV4_SMALLSTR
2482 * (malloc a larger one, as required)
2483 * retlenp - pointer to length to be returned
2486 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2489 struct nfsusrgrp *usrp;
2492 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2497 if (nfsrv_dnsname) {
2499 * Always map nfsrv_defaultuid to "nobody".
2501 if (uid == nfsrv_defaultuid) {
2502 i = nfsrv_dnsnamelen + 7;
2505 if (len > NFSV4_SMALLSTR)
2506 free(cp, M_NFSSTRING);
2507 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2513 NFSBCOPY("nobody@", cp, 7);
2515 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2520 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2521 if (usrp->lug_uid == uid) {
2522 if (usrp->lug_expiry < NFSD_MONOSEC)
2525 * If the name doesn't already have an '@'
2526 * in it, append @domainname to it.
2528 for (i = 0; i < usrp->lug_namelen; i++) {
2529 if (usrp->lug_name[i] == '@') {
2535 i = usrp->lug_namelen;
2537 i = usrp->lug_namelen +
2538 nfsrv_dnsnamelen + 1;
2541 if (len > NFSV4_SMALLSTR)
2542 free(cp, M_NFSSTRING);
2543 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2549 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2550 if (!hasampersand) {
2551 cp += usrp->lug_namelen;
2553 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2555 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2556 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2563 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2565 if (ret == 0 && cnt < 2)
2572 * No match, just return a string of digits.
2576 while (tmp || i == 0) {
2580 len = (i > len) ? len : i;
2584 for (i = 0; i < len; i++) {
2585 *cp-- = '0' + (tmp % 10);
2592 * Convert a string to a uid.
2593 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2597 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2601 struct nfsusrgrp *usrp;
2606 error = NFSERR_BADOWNER;
2613 for (i = 0; i < len; i++)
2621 * If an '@' is found and the domain name matches, search for the name
2622 * with dns stripped off.
2623 * Mixed case alpahbetics will match for the domain name, but all
2624 * upper case will not.
2626 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2627 (len - 1 - i) == nfsrv_dnsnamelen &&
2628 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2629 len -= (nfsrv_dnsnamelen + 1);
2634 * Check for the special case of "nobody".
2636 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2637 *uidp = nfsrv_defaultuid;
2643 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2644 if (usrp->lug_namelen == len &&
2645 !NFSBCMP(usrp->lug_name, str, len)) {
2646 if (usrp->lug_expiry < NFSD_MONOSEC)
2648 *uidp = usrp->lug_uid;
2649 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2650 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2658 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2660 if (ret == 0 && cnt < 2)
2662 error = NFSERR_BADOWNER;
2670 * Convert a gid to a string.
2671 * gid - the group id
2672 * cpp - points to a buffer of size NFSV4_SMALLSTR
2673 * (malloc a larger one, as required)
2674 * retlenp - pointer to length to be returned
2677 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2680 struct nfsusrgrp *usrp;
2683 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2688 if (nfsrv_dnsname) {
2690 * Always map nfsrv_defaultgid to "nogroup".
2692 if (gid == nfsrv_defaultgid) {
2693 i = nfsrv_dnsnamelen + 8;
2696 if (len > NFSV4_SMALLSTR)
2697 free(cp, M_NFSSTRING);
2698 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2704 NFSBCOPY("nogroup@", cp, 8);
2706 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2711 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2712 if (usrp->lug_gid == gid) {
2713 if (usrp->lug_expiry < NFSD_MONOSEC)
2716 * If the name doesn't already have an '@'
2717 * in it, append @domainname to it.
2719 for (i = 0; i < usrp->lug_namelen; i++) {
2720 if (usrp->lug_name[i] == '@') {
2726 i = usrp->lug_namelen;
2728 i = usrp->lug_namelen +
2729 nfsrv_dnsnamelen + 1;
2732 if (len > NFSV4_SMALLSTR)
2733 free(cp, M_NFSSTRING);
2734 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2740 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2741 if (!hasampersand) {
2742 cp += usrp->lug_namelen;
2744 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2746 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2747 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2754 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2756 if (ret == 0 && cnt < 2)
2763 * No match, just return a string of digits.
2767 while (tmp || i == 0) {
2771 len = (i > len) ? len : i;
2775 for (i = 0; i < len; i++) {
2776 *cp-- = '0' + (tmp % 10);
2783 * Convert a string to a gid.
2786 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2790 struct nfsusrgrp *usrp;
2795 error = NFSERR_BADOWNER;
2802 for (i = 0; i < len; i++)
2810 * If an '@' is found and the dns name matches, search for the name
2811 * with the dns stripped off.
2813 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2814 (len - 1 - i) == nfsrv_dnsnamelen &&
2815 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2816 len -= (nfsrv_dnsnamelen + 1);
2821 * Check for the special case of "nogroup".
2823 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2824 *gidp = nfsrv_defaultgid;
2830 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2831 if (usrp->lug_namelen == len &&
2832 !NFSBCMP(usrp->lug_name, str, len)) {
2833 if (usrp->lug_expiry < NFSD_MONOSEC)
2835 *gidp = usrp->lug_gid;
2836 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2837 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2845 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2847 if (ret == 0 && cnt < 2)
2849 error = NFSERR_BADOWNER;
2857 * Cmp len chars, allowing mixed case in the first argument to match lower
2858 * case in the second, but not if the first argument is all upper case.
2859 * Return 0 for a match, 1 otherwise.
2862 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2868 for (i = 0; i < len; i++) {
2869 if (*cp >= 'A' && *cp <= 'Z') {
2870 tmp = *cp++ + ('a' - 'A');
2873 if (tmp >= 'a' && tmp <= 'z')
2886 * Set the port for the nfsuserd.
2889 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2891 struct nfssockreq *rp;
2892 struct sockaddr_in *ad;
2896 if (nfsrv_nfsuserd) {
2904 * Set up the socket record and connect.
2906 rp = &nfsrv_nfsuserdsock;
2907 rp->nr_client = NULL;
2908 rp->nr_sotype = SOCK_DGRAM;
2909 rp->nr_soproto = IPPROTO_UDP;
2910 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2912 NFSSOCKADDRALLOC(rp->nr_nam);
2913 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2914 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2915 ad->sin_family = AF_INET;
2916 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2917 ad->sin_port = port;
2918 rp->nr_prog = RPCPROG_NFSUSERD;
2919 rp->nr_vers = RPCNFSUSERD_VERS;
2920 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2922 NFSSOCKADDRFREE(rp->nr_nam);
2931 * Delete the nfsuserd port.
2934 nfsrv_nfsuserddelport(void)
2938 if (nfsrv_nfsuserd == 0) {
2944 newnfs_disconnect(&nfsrv_nfsuserdsock);
2945 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2949 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2951 * Returns 0 upon success, non-zero otherwise.
2954 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2957 struct nfsrv_descript *nd;
2959 struct nfsrv_descript nfsd;
2964 if (nfsrv_nfsuserd == 0) {
2971 cred = newnfs_getcred();
2972 nd->nd_flag = ND_GSSINITREPLY;
2975 nd->nd_procnum = procnum;
2976 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2977 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2978 if (procnum == RPCNFSUSERD_GETUID)
2979 *tl = txdr_unsigned(uid);
2981 *tl = txdr_unsigned(gid);
2984 (void) nfsm_strtom(nd, name, len);
2986 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2987 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2990 mbuf_freem(nd->nd_mrep);
2991 error = nd->nd_repstat;
2999 * This function is called from the nfssvc(2) system call, to update the
3000 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3003 nfssvc_idname(struct nfsd_idargs *nidp)
3005 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3006 struct nfsuserhashhead *hp;
3011 if (nidp->nid_flag & NFSID_INITIALIZE) {
3012 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3013 M_NFSSTRING, M_WAITOK);
3014 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3017 if (nfsrv_dnsname) {
3019 * Free up all the old stuff and reinitialize hash lists.
3021 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3022 nfsrv_removeuser(usrp);
3024 free(nfsrv_dnsname, M_NFSSTRING);
3025 nfsrv_dnsname = NULL;
3027 TAILQ_INIT(&nfsuserlruhead);
3028 for (i = 0; i < NFSUSERHASHSIZE; i++)
3029 LIST_INIT(&nfsuserhash[i]);
3030 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3031 LIST_INIT(&nfsgrouphash[i]);
3032 for (i = 0; i < NFSUSERHASHSIZE; i++)
3033 LIST_INIT(&nfsusernamehash[i]);
3034 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3035 LIST_INIT(&nfsgroupnamehash[i]);
3038 * Put name in "DNS" string.
3042 nfsrv_dnsnamelen = nidp->nid_namelen;
3043 nfsrv_defaultuid = nidp->nid_uid;
3044 nfsrv_defaultgid = nidp->nid_gid;
3046 nfsrv_usermax = nidp->nid_usermax;
3050 free(cp, M_NFSSTRING);
3055 * malloc the new one now, so any potential sleep occurs before
3056 * manipulation of the lists.
3058 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3059 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3060 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3063 free((caddr_t)newusrp, M_NFSUSERGROUP);
3066 newusrp->lug_namelen = nidp->nid_namelen;
3070 * Delete old entries, as required.
3072 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3073 hp = NFSUSERHASH(nidp->nid_uid);
3074 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3075 if (usrp->lug_uid == nidp->nid_uid)
3076 nfsrv_removeuser(usrp);
3079 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3080 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3081 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3082 if (usrp->lug_namelen == newusrp->lug_namelen &&
3083 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3085 nfsrv_removeuser(usrp);
3088 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3089 hp = NFSGROUPHASH(nidp->nid_gid);
3090 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3091 if (usrp->lug_gid == nidp->nid_gid)
3092 nfsrv_removeuser(usrp);
3095 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3096 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3097 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3098 if (usrp->lug_namelen == newusrp->lug_namelen &&
3099 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3101 nfsrv_removeuser(usrp);
3104 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3105 if (usrp->lug_expiry < NFSD_MONOSEC)
3106 nfsrv_removeuser(usrp);
3108 while (nfsrv_usercnt >= nfsrv_usermax) {
3109 usrp = TAILQ_FIRST(&nfsuserlruhead);
3110 nfsrv_removeuser(usrp);
3114 * Now, we can add the new one.
3116 if (nidp->nid_usertimeout)
3117 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3119 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3120 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3121 newusrp->lug_uid = nidp->nid_uid;
3122 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3124 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3125 newusrp->lug_namelen), newusrp, lug_namehash);
3126 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3128 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3129 newusrp->lug_gid = nidp->nid_gid;
3130 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3132 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3133 newusrp->lug_namelen), newusrp, lug_namehash);
3134 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3137 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3145 * Remove a user/group name element.
3148 nfsrv_removeuser(struct nfsusrgrp *usrp)
3151 NFSNAMEIDREQUIRED();
3152 LIST_REMOVE(usrp, lug_numhash);
3153 LIST_REMOVE(usrp, lug_namehash);
3154 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3156 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3160 * This function scans a byte string and checks for UTF-8 compliance.
3161 * It returns 0 if it conforms and NFSERR_INVAL if not.
3164 nfsrv_checkutf8(u_int8_t *cp, int len)
3166 u_int32_t val = 0x0;
3167 int cnt = 0, gotd = 0, shift = 0;
3169 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3173 * Here are what the variables are used for:
3174 * val - the calculated value of a multibyte char, used to check
3175 * that it was coded with the correct range
3176 * cnt - the number of 10xxxxxx bytes to follow
3177 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3178 * shift - lower order bits of range (ie. "val >> shift" should
3179 * not be 0, in other words, dividing by the lower bound
3180 * of the range should get a non-zero value)
3181 * byte - used to calculate cnt
3185 /* This handles the 10xxxxxx bytes */
3186 if ((*cp & 0xc0) != 0x80 ||
3187 (gotd && (*cp & 0x20))) {
3188 error = NFSERR_INVAL;
3193 val |= (*cp & 0x3f);
3195 if (cnt == 0 && (val >> shift) == 0x0) {
3196 error = NFSERR_INVAL;
3199 } else if (*cp & 0x80) {
3200 /* first byte of multi byte char */
3202 while ((byte & 0x40) && cnt < 6) {
3206 if (cnt == 0 || cnt == 6) {
3207 error = NFSERR_INVAL;
3210 val = (*cp & (0x3f >> cnt));
3211 shift = utf8_shift[cnt - 1];
3212 if (cnt == 2 && val == 0xd)
3213 /* Check for the 0xd800-0xdfff case */
3220 error = NFSERR_INVAL;
3228 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3229 * strings, one with the root path in it and the other with the list of
3230 * locations. The list is in the same format as is found in nfr_refs.
3231 * It is a "," separated list of entries, where each of them is of the
3232 * form <server>:<rootpath>. For example
3233 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3234 * The nilp argument is set to 1 for the special case of a null fs_root
3235 * and an empty server list.
3236 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3237 * number of xdr bytes parsed in sump.
3240 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3241 int *sump, int *nilp)
3244 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3245 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3247 SLIST_ENTRY(list) next;
3251 SLIST_HEAD(, list) head;
3258 * Get the fs_root path and check for the special case of null path
3259 * and 0 length server list.
3261 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3262 len = fxdr_unsigned(int, *tl);
3263 if (len < 0 || len > 10240) {
3264 error = NFSERR_BADXDR;
3268 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3270 error = NFSERR_BADXDR;
3274 *sump = 2 * NFSX_UNSIGNED;
3278 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3279 error = nfsrv_mtostr(nd, cp, len);
3281 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3282 cnt = fxdr_unsigned(int, *tl);
3284 error = NFSERR_BADXDR;
3290 * Now, loop through the location list and make up the srvlist.
3292 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3293 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3296 for (i = 0; i < cnt; i++) {
3298 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3299 nsrv = fxdr_unsigned(int, *tl);
3301 error = NFSERR_BADXDR;
3306 * Handle the first server by putting it in the srvstr.
3308 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3309 len = fxdr_unsigned(int, *tl);
3310 if (len <= 0 || len > 1024) {
3311 error = NFSERR_BADXDR;
3314 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3319 error = nfsrv_mtostr(nd, cp3, len);
3325 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3326 for (j = 1; j < nsrv; j++) {
3328 * Yuck, put them in an slist and process them later.
3330 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3331 len = fxdr_unsigned(int, *tl);
3332 if (len <= 0 || len > 1024) {
3333 error = NFSERR_BADXDR;
3336 lsp = (struct list *)malloc(sizeof (struct list)
3337 + len, M_TEMP, M_WAITOK);
3338 error = nfsrv_mtostr(nd, lsp->host, len);
3341 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3343 SLIST_INSERT_HEAD(&head, lsp, next);
3347 * Finally, we can get the path.
3349 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3350 len = fxdr_unsigned(int, *tl);
3351 if (len <= 0 || len > 1024) {
3352 error = NFSERR_BADXDR;
3355 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3356 error = nfsrv_mtostr(nd, cp3, len);
3359 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3364 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3365 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3368 NFSBCOPY(lsp->host, cp3, lsp->len);
3371 NFSBCOPY(str, cp3, stringlen);
3374 siz += (lsp->len + stringlen + 2);
3375 free((caddr_t)lsp, M_TEMP);
3381 NFSEXITCODE2(0, nd);
3385 free(cp, M_NFSSTRING);
3387 free(cp2, M_NFSSTRING);
3388 NFSEXITCODE2(error, nd);
3393 * Make the malloc'd space large enough. This is a pain, but the xdr
3394 * doesn't set an upper bound on the side, so...
3397 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3404 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3405 NFSBCOPY(*cpp, cp, *slenp);
3406 free(*cpp, M_NFSSTRING);
3410 *slenp = siz + 1024;
3414 * Initialize the reply header data structures.
3417 nfsrvd_rephead(struct nfsrv_descript *nd)
3422 * If this is a big reply, use a cluster.
3424 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3425 nfs_bigreply[nd->nd_procnum]) {
3426 NFSMCLGET(mreq, M_WAIT);
3434 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3435 mbuf_setlen(mreq, 0);
3437 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3438 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3442 * Lock a socket against others.
3443 * Currently used to serialize connect/disconnect attempts.
3446 newnfs_sndlock(int *flagp)
3451 while (*flagp & NFSR_SNDLOCK) {
3452 *flagp |= NFSR_WANTSND;
3455 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3456 PZERO - 1, "nfsndlck", &ts);
3458 *flagp |= NFSR_SNDLOCK;
3464 * Unlock the stream socket for others.
3467 newnfs_sndunlock(int *flagp)
3471 if ((*flagp & NFSR_SNDLOCK) == 0)
3472 panic("nfs sndunlock");
3473 *flagp &= ~NFSR_SNDLOCK;
3474 if (*flagp & NFSR_WANTSND) {
3475 *flagp &= ~NFSR_WANTSND;
3476 wakeup((caddr_t)flagp);