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 }, /* undef */
88 { 0, 0, 0, 0 }, /* undef */
89 { 0, 0, 0, 0 }, /* undef */
90 { 0, 1, 0, 0 }, /* Access */
91 { 0, 1, 0, 0 }, /* Close */
92 { 0, 2, 0, 1 }, /* Commit */
93 { 1, 2, 1, 1 }, /* Create */
94 { 0, 0, 0, 0 }, /* Delegpurge */
95 { 0, 1, 0, 0 }, /* Delegreturn */
96 { 0, 1, 0, 0 }, /* Getattr */
97 { 0, 1, 0, 0 }, /* GetFH */
98 { 2, 1, 1, 1 }, /* Link */
99 { 0, 1, 0, 0 }, /* Lock */
100 { 0, 1, 0, 0 }, /* LockT */
101 { 0, 1, 0, 0 }, /* LockU */
102 { 1, 1, 0, 0 }, /* Lookup */
103 { 1, 1, 0, 0 }, /* Lookupp */
104 { 0, 1, 0, 0 }, /* NVerify */
105 { 1, 1, 0, 1 }, /* Open */
106 { 1, 1, 0, 0 }, /* OpenAttr */
107 { 0, 1, 0, 0 }, /* OpenConfirm */
108 { 0, 1, 0, 0 }, /* OpenDowngrade */
109 { 1, 0, 0, 0 }, /* PutFH */
110 { 1, 0, 0, 0 }, /* PutPubFH */
111 { 1, 0, 0, 0 }, /* PutRootFH */
112 { 0, 1, 0, 0 }, /* Read */
113 { 0, 1, 0, 0 }, /* Readdir */
114 { 0, 1, 0, 0 }, /* ReadLink */
115 { 0, 2, 1, 1 }, /* Remove */
116 { 2, 1, 1, 1 }, /* Rename */
117 { 0, 0, 0, 0 }, /* Renew */
118 { 0, 0, 0, 0 }, /* RestoreFH */
119 { 0, 1, 0, 0 }, /* SaveFH */
120 { 0, 1, 0, 0 }, /* SecInfo */
121 { 0, 2, 1, 1 }, /* Setattr */
122 { 0, 0, 0, 0 }, /* SetClientID */
123 { 0, 0, 0, 0 }, /* SetClientIDConfirm */
124 { 0, 1, 0, 0 }, /* Verify */
125 { 0, 2, 1, 1 }, /* Write */
126 { 0, 0, 0, 0 }, /* 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)
184 left = uiop->uio_iov->iov_len;
185 uiocp = uiop->uio_iov->iov_base;
194 mbufcp = NFSMTOD(mp, caddr_t);
197 xfer = (left > len) ? len : left;
200 if (uiop->uio_iov->iov_op != NULL)
201 (*(uiop->uio_iov->iov_op))
202 (mbufcp, uiocp, xfer);
205 if (uiop->uio_segflg == UIO_SYSSPACE)
206 NFSBCOPY(mbufcp, uiocp, xfer);
208 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
213 uiop->uio_offset += xfer;
214 uiop->uio_resid -= xfer;
216 if (uiop->uio_iov->iov_len <= siz) {
220 uiop->uio_iov->iov_base = (void *)
221 ((char *)uiop->uio_iov->iov_base + uiosiz);
222 uiop->uio_iov->iov_len -= uiosiz;
226 nd->nd_dpos = mbufcp;
230 error = nfsm_advance(nd, rem, len);
239 * Help break down an mbuf chain by setting the first siz bytes contiguous
240 * pointed to by returned val.
241 * This is used by the macro NFSM_DISSECT for tough
245 nfsm_dissct(struct nfsrv_descript *nd, int siz)
254 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
256 nd->nd_md = mbuf_next(nd->nd_md);
257 if (nd->nd_md == NULL)
259 left = mbuf_len(nd->nd_md);
260 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
265 } else if (mbuf_next(nd->nd_md) == NULL) {
267 } else if (siz > ncl_mbuf_mhlen) {
268 panic("nfs S too big");
271 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
272 mbuf_setnext(nd->nd_md, mp2);
273 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
275 retp = p = NFSMTOD(mp2, caddr_t);
276 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
279 mp2 = mbuf_next(mp2);
280 /* Loop around copying up the siz2 bytes */
284 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
286 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
287 NFSM_DATAP(mp2, xfer);
288 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
293 mp2 = mbuf_next(mp2);
295 mbuf_setlen(nd->nd_md, siz);
297 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
303 * Advance the position in the mbuf chain.
304 * If offs == 0, this is a no-op, but it is simpler to just return from
305 * here than check for offs > 0 for all calls to nfsm_advance.
306 * If left == -1, it should be calculated here.
309 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
315 * A negative offs should be considered a serious problem.
318 panic("nfsrv_advance");
321 * If left == -1, calculate it here.
324 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
328 * Loop around, advancing over the mbuf data.
330 while (offs > left) {
332 nd->nd_md = mbuf_next(nd->nd_md);
333 if (nd->nd_md == NULL)
335 left = mbuf_len(nd->nd_md);
336 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
343 * Copy a string into mbuf(s).
344 * Return the number of bytes output, including XDR overheads.
347 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
357 *tl = txdr_unsigned(siz);
358 rem = NFSM_RNDUP(siz) - siz;
359 bytesize = NFSX_UNSIGNED + siz + rem;
362 left = M_TRAILINGSPACE(m2);
365 * Loop around copying the string to mbuf(s).
369 if (siz > ncl_mbuf_mlen)
370 NFSMCLGET(m1, M_WAIT);
374 mbuf_setnext(m2, m1);
376 cp2 = NFSMTOD(m2, caddr_t);
377 left = M_TRAILINGSPACE(m2);
383 NFSBCOPY(cp, cp2, xfer);
385 mbuf_setlen(m2, mbuf_len(m2) + xfer);
388 if (siz == 0 && rem) {
390 panic("nfsm_strtom");
391 NFSBZERO(cp2 + xfer, rem);
392 mbuf_setlen(m2, mbuf_len(m2) + rem);
396 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
401 * Called once to initialize data structures...
406 static int nfs_inited = 0;
412 newnfs_true = txdr_unsigned(TRUE);
413 newnfs_false = txdr_unsigned(FALSE);
414 newnfs_xdrneg1 = txdr_unsigned(-1);
415 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
418 NFSSETBOOTTIME(nfsboottime);
421 * Initialize reply list and start timer
423 TAILQ_INIT(&nfsd_reqq);
428 * Put a file handle in an mbuf list.
429 * If the size argument == 0, just use the default size.
430 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
431 * Return the number of bytes output, including XDR overhead.
434 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
438 int fullsiz, rem, bytesize = 0;
442 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
444 if (size > NFSX_V2FH)
445 panic("fh size > NFSX_V2FH for NFSv2");
446 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
447 NFSBCOPY(fhp, cp, size);
448 if (size < NFSX_V2FH)
449 NFSBZERO(cp + size, NFSX_V2FH - size);
450 bytesize = NFSX_V2FH;
454 fullsiz = NFSM_RNDUP(size);
455 rem = fullsiz - size;
457 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
458 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
461 bytesize = NFSX_UNSIGNED + fullsiz;
463 (void) nfsm_strtom(nd, fhp, size);
470 * This function compares two net addresses by family and returns TRUE
471 * if they are the same host.
472 * If there is any doubt, return FALSE.
473 * The AF_INET family is handled as a special case so that address mbufs
474 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
477 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
479 struct sockaddr_in *inetaddr;
483 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
484 if (inetaddr->sin_family == AF_INET &&
485 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
491 struct sockaddr_in6 *inetaddr6;
493 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
494 /* XXX - should test sin6_scope_id ? */
495 if (inetaddr6->sin6_family == AF_INET6 &&
496 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
507 * Similar to the above, but takes to NFSSOCKADDR_T args.
510 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
512 struct sockaddr_in *addr1, *addr2;
513 struct sockaddr *inaddr;
515 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
516 switch (inaddr->sa_family) {
518 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
519 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
520 if (addr2->sin_family == AF_INET &&
521 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
527 struct sockaddr_in6 *inet6addr1, *inet6addr2;
529 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
530 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
531 /* XXX - should test sin6_scope_id ? */
532 if (inet6addr2->sin6_family == AF_INET6 &&
533 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
534 &inet6addr2->sin6_addr))
545 * Trim the stuff already dissected off the mbuf list.
548 newnfs_trimleading(nd)
549 struct nfsrv_descript *nd;
555 * First, free up leading mbufs.
557 if (nd->nd_mrep != nd->nd_md) {
559 while (mbuf_next(m) != nd->nd_md) {
560 if (mbuf_next(m) == NULL)
561 panic("nfsm trim leading");
564 mbuf_setnext(m, NULL);
565 mbuf_freem(nd->nd_mrep);
570 * Now, adjust this mbuf, based on nd_dpos.
572 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
573 if (offs == mbuf_len(m)) {
577 panic("nfsm trim leading2");
578 mbuf_setnext(n, NULL);
580 } else if (offs > 0) {
581 mbuf_setlen(m, mbuf_len(m) - offs);
584 panic("nfsm trimleading offs");
587 nd->nd_dpos = NFSMTOD(m, caddr_t);
591 * Trim trailing data off the mbuf list being built.
594 newnfs_trimtrailing(nd, mb, bpos)
595 struct nfsrv_descript *nd;
601 mbuf_freem(mbuf_next(mb));
602 mbuf_setnext(mb, NULL);
604 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
610 * Dissect a file handle on the client.
613 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
620 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
621 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
622 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
627 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
629 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
631 FREE((caddr_t)nfhp, M_NFSFH);
641 * Break down the nfsv4 acl.
642 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
645 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
646 int *aclsizep, __unused NFSPROC_T *p)
650 int acecnt, error = 0, aceerr = 0, acesize;
653 #ifdef NFS4_ACL_EXTATTR_NAME
658 * Parse out the ace entries and expect them to conform to
659 * what can be supported by R/W/X bits.
661 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
662 aclsize = NFSX_UNSIGNED;
663 acecnt = fxdr_unsigned(int, *tl);
664 #ifdef NFS4_ACL_EXTATTR_NAME
665 if (acecnt > ACL_MAX_ENTRIES)
668 if (nfsrv_useacl == 0)
670 for (i = 0; i < acecnt; i++) {
671 #ifdef NFS4_ACL_EXTATTR_NAME
673 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
674 &aceerr, &acesize, p);
677 error = nfsrv_skipace(nd, &acesize);
682 #ifdef NFS4_ACL_EXTATTR_NAME
684 aclp->acl_cnt = acecnt;
695 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
698 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
703 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
704 len = fxdr_unsigned(int, *(tl + 3));
705 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
707 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
712 * Get attribute bits from an mbuf list.
713 * Returns EBADRPC for a parsing error, 0 otherwise.
714 * If the clearinvalid flag is set, clear the bits not supported.
717 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
724 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
725 cnt = fxdr_unsigned(int, *tl);
727 return (NFSERR_BADXDR);
728 if (cnt > NFSATTRBIT_MAXWORDS) {
729 outcnt = NFSATTRBIT_MAXWORDS;
731 *retnotsupp = NFSERR_ATTRNOTSUPP;
735 NFSZERO_ATTRBIT(attrbitp);
737 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
738 for (i = 0; i < outcnt; i++)
739 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
742 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
744 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
750 * Get the attributes for V4.
751 * If the compare flag is true, test for any attribute changes,
752 * otherwise return the attribute values.
753 * These attributes cover fields in "struct vattr", "struct statfs",
754 * "struct nfsfsinfo", the file handle and the lease duration.
755 * The value of retcmpp is set to 1 if all attributes are the same,
757 * Returns EBADRPC if it can't be parsed, 0 otherwise.
760 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
761 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
762 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
763 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
764 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
767 int i = 0, j, k, l, m, bitpos, attrsum = 0;
768 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
769 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
770 nfsattrbit_t attrbits, retattrbits, checkattrbits;
772 struct nfsreferral *refp;
775 struct timespec temptime;
779 u_int32_t freenum = 0, tuint;
780 u_int64_t uquad = 0, thyp, thyp2;
788 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
790 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
796 *retcmpp = retnotsup;
799 * Just set default values to some of the important ones.
804 nap->na_rdev = (NFSDEV_T)0;
805 nap->na_mtime.tv_sec = 0;
806 nap->na_mtime.tv_nsec = 0;
809 nap->na_blocksize = NFS_FABLKSIZE;
812 sbp->f_bsize = NFS_FABLKSIZE;
820 fsp->fs_rtmax = 8192;
821 fsp->fs_rtpref = 8192;
822 fsp->fs_maxname = NFS_MAXNAMLEN;
823 fsp->fs_wtmax = 8192;
824 fsp->fs_wtpref = 8192;
825 fsp->fs_wtmult = NFS_FABLKSIZE;
826 fsp->fs_dtpref = 8192;
827 fsp->fs_maxfilesize = 0xffffffffffffffffull;
828 fsp->fs_timedelta.tv_sec = 0;
829 fsp->fs_timedelta.tv_nsec = 1;
830 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
831 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
834 pc->pc_linkmax = LINK_MAX;
835 pc->pc_namemax = NAME_MAX;
837 pc->pc_chownrestricted = 0;
838 pc->pc_caseinsensitive = 0;
839 pc->pc_casepreserving = 1;
844 * Loop around getting the attributes.
846 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
847 attrsize = fxdr_unsigned(int, *tl);
848 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
849 if (attrsum > attrsize) {
850 error = NFSERR_BADXDR;
853 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
855 case NFSATTRBIT_SUPPORTEDATTRS:
857 if (compare || nap == NULL)
858 error = nfsrv_getattrbits(nd, &retattrbits,
861 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
865 if (compare && !(*retcmpp)) {
866 NFSSETSUPP_ATTRBIT(&checkattrbits);
867 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
869 *retcmpp = NFSERR_NOTSAME;
873 case NFSATTRBIT_TYPE:
874 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
877 if (nap->na_type != nfsv34tov_type(*tl))
878 *retcmpp = NFSERR_NOTSAME;
880 } else if (nap != NULL) {
881 nap->na_type = nfsv34tov_type(*tl);
883 attrsum += NFSX_UNSIGNED;
885 case NFSATTRBIT_FHEXPIRETYPE:
886 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
887 if (compare && !(*retcmpp)) {
888 if (fxdr_unsigned(int, *tl) !=
889 NFSV4FHTYPE_PERSISTENT)
890 *retcmpp = NFSERR_NOTSAME;
892 attrsum += NFSX_UNSIGNED;
894 case NFSATTRBIT_CHANGE:
895 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
898 if (nap->na_filerev != fxdr_hyper(tl))
899 *retcmpp = NFSERR_NOTSAME;
901 } else if (nap != NULL) {
902 nap->na_filerev = fxdr_hyper(tl);
904 attrsum += NFSX_HYPER;
906 case NFSATTRBIT_SIZE:
907 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
910 if (nap->na_size != fxdr_hyper(tl))
911 *retcmpp = NFSERR_NOTSAME;
913 } else if (nap != NULL) {
914 nap->na_size = fxdr_hyper(tl);
916 attrsum += NFSX_HYPER;
918 case NFSATTRBIT_LINKSUPPORT:
919 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
922 if (fsp->fs_properties & NFSV3_FSFLINK) {
923 if (*tl == newnfs_false)
924 *retcmpp = NFSERR_NOTSAME;
926 if (*tl == newnfs_true)
927 *retcmpp = NFSERR_NOTSAME;
930 } else if (fsp != NULL) {
931 if (*tl == newnfs_true)
932 fsp->fs_properties |= NFSV3_FSFLINK;
934 fsp->fs_properties &= ~NFSV3_FSFLINK;
936 attrsum += NFSX_UNSIGNED;
938 case NFSATTRBIT_SYMLINKSUPPORT:
939 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
942 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
943 if (*tl == newnfs_false)
944 *retcmpp = NFSERR_NOTSAME;
946 if (*tl == newnfs_true)
947 *retcmpp = NFSERR_NOTSAME;
950 } else if (fsp != NULL) {
951 if (*tl == newnfs_true)
952 fsp->fs_properties |= NFSV3_FSFSYMLINK;
954 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
956 attrsum += NFSX_UNSIGNED;
958 case NFSATTRBIT_NAMEDATTR:
959 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960 if (compare && !(*retcmpp)) {
961 if (*tl != newnfs_false)
962 *retcmpp = NFSERR_NOTSAME;
964 attrsum += NFSX_UNSIGNED;
966 case NFSATTRBIT_FSID:
967 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
968 thyp = fxdr_hyper(tl);
970 thyp2 = fxdr_hyper(tl);
973 if (thyp != (u_int64_t)
974 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
976 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
977 *retcmpp = NFSERR_NOTSAME;
979 } else if (nap != NULL) {
980 nap->na_filesid[0] = thyp;
981 nap->na_filesid[1] = thyp2;
983 attrsum += (4 * NFSX_UNSIGNED);
985 case NFSATTRBIT_UNIQUEHANDLES:
986 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987 if (compare && !(*retcmpp)) {
988 if (*tl != newnfs_true)
989 *retcmpp = NFSERR_NOTSAME;
991 attrsum += NFSX_UNSIGNED;
993 case NFSATTRBIT_LEASETIME:
994 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
996 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
998 *retcmpp = NFSERR_NOTSAME;
999 } else if (leasep != NULL) {
1000 *leasep = fxdr_unsigned(u_int32_t, *tl);
1002 attrsum += NFSX_UNSIGNED;
1004 case NFSATTRBIT_RDATTRERROR:
1005 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1008 *retcmpp = NFSERR_INVAL;
1009 } else if (rderrp != NULL) {
1010 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1012 attrsum += NFSX_UNSIGNED;
1014 case NFSATTRBIT_ACL:
1017 #ifdef NFS4_ACL_EXTATTR_NAME
1021 naclp = acl_alloc(M_WAITOK);
1022 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1028 if (aceerr || nfsrv_compareacl(aclp, naclp))
1029 *retcmpp = NFSERR_NOTSAME;
1034 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1036 *retcmpp = NFSERR_ATTRNOTSUPP;
1040 if (vp != NULL && aclp != NULL)
1041 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1044 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1051 case NFSATTRBIT_ACLSUPPORT:
1052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053 if (compare && !(*retcmpp)) {
1055 if (fxdr_unsigned(u_int32_t, *tl) !=
1057 *retcmpp = NFSERR_NOTSAME;
1059 *retcmpp = NFSERR_ATTRNOTSUPP;
1062 attrsum += NFSX_UNSIGNED;
1064 case NFSATTRBIT_ARCHIVE:
1065 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1066 if (compare && !(*retcmpp))
1067 *retcmpp = NFSERR_ATTRNOTSUPP;
1068 attrsum += NFSX_UNSIGNED;
1070 case NFSATTRBIT_CANSETTIME:
1071 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1074 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1075 if (*tl == newnfs_false)
1076 *retcmpp = NFSERR_NOTSAME;
1078 if (*tl == newnfs_true)
1079 *retcmpp = NFSERR_NOTSAME;
1082 } else if (fsp != NULL) {
1083 if (*tl == newnfs_true)
1084 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1086 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1088 attrsum += NFSX_UNSIGNED;
1090 case NFSATTRBIT_CASEINSENSITIVE:
1091 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1094 if (*tl != newnfs_false)
1095 *retcmpp = NFSERR_NOTSAME;
1097 } else if (pc != NULL) {
1098 pc->pc_caseinsensitive =
1099 fxdr_unsigned(u_int32_t, *tl);
1101 attrsum += NFSX_UNSIGNED;
1103 case NFSATTRBIT_CASEPRESERVING:
1104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1107 if (*tl != newnfs_true)
1108 *retcmpp = NFSERR_NOTSAME;
1110 } else if (pc != NULL) {
1111 pc->pc_casepreserving =
1112 fxdr_unsigned(u_int32_t, *tl);
1114 attrsum += NFSX_UNSIGNED;
1116 case NFSATTRBIT_CHOWNRESTRICTED:
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_chownrestricted =
1125 fxdr_unsigned(u_int32_t, *tl);
1127 attrsum += NFSX_UNSIGNED;
1129 case NFSATTRBIT_FILEHANDLE:
1130 error = nfsm_getfh(nd, &tnfhp);
1133 tfhsize = tnfhp->nfh_len;
1136 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1138 *retcmpp = NFSERR_NOTSAME;
1139 FREE((caddr_t)tnfhp, M_NFSFH);
1140 } else if (nfhpp != NULL) {
1143 FREE((caddr_t)tnfhp, M_NFSFH);
1145 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1147 case NFSATTRBIT_FILEID:
1148 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1149 thyp = fxdr_hyper(tl);
1152 if ((u_int64_t)nap->na_fileid != thyp)
1153 *retcmpp = NFSERR_NOTSAME;
1155 } else if (nap != NULL) {
1157 printf("NFSv4 fileid > 32bits\n");
1158 nap->na_fileid = thyp;
1160 attrsum += NFSX_HYPER;
1162 case NFSATTRBIT_FILESAVAIL:
1163 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1166 sfp->sf_afiles != fxdr_hyper(tl))
1167 *retcmpp = NFSERR_NOTSAME;
1168 } else if (sfp != NULL) {
1169 sfp->sf_afiles = fxdr_hyper(tl);
1171 attrsum += NFSX_HYPER;
1173 case NFSATTRBIT_FILESFREE:
1174 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1177 sfp->sf_ffiles != fxdr_hyper(tl))
1178 *retcmpp = NFSERR_NOTSAME;
1179 } else if (sfp != NULL) {
1180 sfp->sf_ffiles = fxdr_hyper(tl);
1182 attrsum += NFSX_HYPER;
1184 case NFSATTRBIT_FILESTOTAL:
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1188 sfp->sf_tfiles != fxdr_hyper(tl))
1189 *retcmpp = NFSERR_NOTSAME;
1190 } else if (sfp != NULL) {
1191 sfp->sf_tfiles = fxdr_hyper(tl);
1193 attrsum += NFSX_HYPER;
1195 case NFSATTRBIT_FSLOCATIONS:
1196 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1200 if (compare && !(*retcmpp)) {
1201 refp = nfsv4root_getreferral(vp, NULL, 0);
1203 if (cp == NULL || cp2 == NULL ||
1205 strcmp(cp2, refp->nfr_srvlist))
1206 *retcmpp = NFSERR_NOTSAME;
1207 } else if (m == 0) {
1208 *retcmpp = NFSERR_NOTSAME;
1212 free(cp, M_NFSSTRING);
1214 free(cp2, M_NFSSTRING);
1216 case NFSATTRBIT_HIDDEN:
1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1218 if (compare && !(*retcmpp))
1219 *retcmpp = NFSERR_ATTRNOTSUPP;
1220 attrsum += NFSX_UNSIGNED;
1222 case NFSATTRBIT_HOMOGENEOUS:
1223 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1226 if (fsp->fs_properties &
1227 NFSV3_FSFHOMOGENEOUS) {
1228 if (*tl == newnfs_false)
1229 *retcmpp = NFSERR_NOTSAME;
1231 if (*tl == newnfs_true)
1232 *retcmpp = NFSERR_NOTSAME;
1235 } else if (fsp != NULL) {
1236 if (*tl == newnfs_true)
1237 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1239 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1241 attrsum += NFSX_UNSIGNED;
1243 case NFSATTRBIT_MAXFILESIZE:
1244 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1245 tnfsquad.qval = fxdr_hyper(tl);
1248 tquad = NFSRV_MAXFILESIZE;
1249 if (tquad != tnfsquad.qval)
1250 *retcmpp = NFSERR_NOTSAME;
1252 } else if (fsp != NULL) {
1253 fsp->fs_maxfilesize = tnfsquad.qval;
1255 attrsum += NFSX_HYPER;
1257 case NFSATTRBIT_MAXLINK:
1258 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1261 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1262 *retcmpp = NFSERR_NOTSAME;
1264 } else if (pc != NULL) {
1265 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1267 attrsum += NFSX_UNSIGNED;
1269 case NFSATTRBIT_MAXNAME:
1270 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1273 if (fsp->fs_maxname !=
1274 fxdr_unsigned(u_int32_t, *tl))
1275 *retcmpp = NFSERR_NOTSAME;
1278 tuint = fxdr_unsigned(u_int32_t, *tl);
1280 * Some Linux NFSv4 servers report this
1281 * as 0 or 4billion, so I'll set it to
1282 * NFS_MAXNAMLEN. If a server actually creates
1283 * a name longer than NFS_MAXNAMLEN, it will
1284 * get an error back.
1286 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1287 tuint = NFS_MAXNAMLEN;
1289 fsp->fs_maxname = tuint;
1291 pc->pc_namemax = tuint;
1293 attrsum += NFSX_UNSIGNED;
1295 case NFSATTRBIT_MAXREAD:
1296 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1299 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1300 *(tl + 1)) || *tl != 0)
1301 *retcmpp = NFSERR_NOTSAME;
1303 } else if (fsp != NULL) {
1304 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1305 fsp->fs_rtpref = fsp->fs_rtmax;
1306 fsp->fs_dtpref = fsp->fs_rtpref;
1308 attrsum += NFSX_HYPER;
1310 case NFSATTRBIT_MAXWRITE:
1311 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1314 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1315 *(tl + 1)) || *tl != 0)
1316 *retcmpp = NFSERR_NOTSAME;
1318 } else if (fsp != NULL) {
1319 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1320 fsp->fs_wtpref = fsp->fs_wtmax;
1322 attrsum += NFSX_HYPER;
1324 case NFSATTRBIT_MIMETYPE:
1325 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1326 i = fxdr_unsigned(int, *tl);
1327 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1328 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1331 if (compare && !(*retcmpp))
1332 *retcmpp = NFSERR_ATTRNOTSUPP;
1334 case NFSATTRBIT_MODE:
1335 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1338 if (nap->na_mode != nfstov_mode(*tl))
1339 *retcmpp = NFSERR_NOTSAME;
1341 } else if (nap != NULL) {
1342 nap->na_mode = nfstov_mode(*tl);
1344 attrsum += NFSX_UNSIGNED;
1346 case NFSATTRBIT_NOTRUNC:
1347 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1350 if (*tl != newnfs_true)
1351 *retcmpp = NFSERR_NOTSAME;
1353 } else if (pc != NULL) {
1354 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1356 attrsum += NFSX_UNSIGNED;
1358 case NFSATTRBIT_NUMLINKS:
1359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1360 tuint = fxdr_unsigned(u_int32_t, *tl);
1363 if ((u_int32_t)nap->na_nlink != tuint)
1364 *retcmpp = NFSERR_NOTSAME;
1366 } else if (nap != NULL) {
1367 nap->na_nlink = tuint;
1369 attrsum += NFSX_UNSIGNED;
1371 case NFSATTRBIT_OWNER:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 j = fxdr_unsigned(int, *tl);
1375 return (NFSERR_BADXDR);
1376 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1377 if (j > NFSV4_SMALLSTR)
1378 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1381 error = nfsrv_mtostr(nd, cp, j);
1383 if (j > NFSV4_SMALLSTR)
1384 free(cp, M_NFSSTRING);
1389 if (nfsv4_strtouid(cp, j, &uid, p) ||
1391 *retcmpp = NFSERR_NOTSAME;
1393 } else if (nap != NULL) {
1394 if (nfsv4_strtouid(cp, j, &uid, p))
1395 nap->na_uid = nfsrv_defaultuid;
1399 if (j > NFSV4_SMALLSTR)
1400 free(cp, M_NFSSTRING);
1402 case NFSATTRBIT_OWNERGROUP:
1403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404 j = fxdr_unsigned(int, *tl);
1406 return (NFSERR_BADXDR);
1407 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1408 if (j > NFSV4_SMALLSTR)
1409 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1412 error = nfsrv_mtostr(nd, cp, j);
1414 if (j > NFSV4_SMALLSTR)
1415 free(cp, M_NFSSTRING);
1420 if (nfsv4_strtogid(cp, j, &gid, p) ||
1422 *retcmpp = NFSERR_NOTSAME;
1424 } else if (nap != NULL) {
1425 if (nfsv4_strtogid(cp, j, &gid, p))
1426 nap->na_gid = nfsrv_defaultgid;
1430 if (j > NFSV4_SMALLSTR)
1431 free(cp, M_NFSSTRING);
1433 case NFSATTRBIT_QUOTAHARD:
1434 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1436 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1437 freenum = sbp->f_bfree;
1439 freenum = sbp->f_bavail;
1442 * ufs_quotactl() insists that the uid argument
1443 * equal p_ruid for non-root quota access, so
1444 * we'll just make sure that's the case.
1446 savuid = p->p_cred->p_ruid;
1447 p->p_cred->p_ruid = cred->cr_uid;
1448 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1449 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1450 freenum = min(dqb.dqb_bhardlimit, freenum);
1451 p->p_cred->p_ruid = savuid;
1453 uquad = (u_int64_t)freenum;
1454 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1456 if (compare && !(*retcmpp)) {
1457 if (uquad != fxdr_hyper(tl))
1458 *retcmpp = NFSERR_NOTSAME;
1460 attrsum += NFSX_HYPER;
1462 case NFSATTRBIT_QUOTASOFT:
1463 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1465 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1466 freenum = sbp->f_bfree;
1468 freenum = sbp->f_bavail;
1471 * ufs_quotactl() insists that the uid argument
1472 * equal p_ruid for non-root quota access, so
1473 * we'll just make sure that's the case.
1475 savuid = p->p_cred->p_ruid;
1476 p->p_cred->p_ruid = cred->cr_uid;
1477 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1478 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1479 freenum = min(dqb.dqb_bsoftlimit, freenum);
1480 p->p_cred->p_ruid = savuid;
1482 uquad = (u_int64_t)freenum;
1483 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1485 if (compare && !(*retcmpp)) {
1486 if (uquad != fxdr_hyper(tl))
1487 *retcmpp = NFSERR_NOTSAME;
1489 attrsum += NFSX_HYPER;
1491 case NFSATTRBIT_QUOTAUSED:
1492 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1497 * ufs_quotactl() insists that the uid argument
1498 * equal p_ruid for non-root quota access, so
1499 * we'll just make sure that's the case.
1501 savuid = p->p_cred->p_ruid;
1502 p->p_cred->p_ruid = cred->cr_uid;
1503 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1504 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1505 freenum = dqb.dqb_curblocks;
1506 p->p_cred->p_ruid = savuid;
1508 uquad = (u_int64_t)freenum;
1509 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1511 if (compare && !(*retcmpp)) {
1512 if (uquad != fxdr_hyper(tl))
1513 *retcmpp = NFSERR_NOTSAME;
1515 attrsum += NFSX_HYPER;
1517 case NFSATTRBIT_RAWDEV:
1518 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1519 j = fxdr_unsigned(int, *tl++);
1520 k = fxdr_unsigned(int, *tl);
1523 if (nap->na_rdev != NFSMAKEDEV(j, k))
1524 *retcmpp = NFSERR_NOTSAME;
1526 } else if (nap != NULL) {
1527 nap->na_rdev = NFSMAKEDEV(j, k);
1529 attrsum += NFSX_V4SPECDATA;
1531 case NFSATTRBIT_SPACEAVAIL:
1532 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1535 sfp->sf_abytes != fxdr_hyper(tl))
1536 *retcmpp = NFSERR_NOTSAME;
1537 } else if (sfp != NULL) {
1538 sfp->sf_abytes = fxdr_hyper(tl);
1540 attrsum += NFSX_HYPER;
1542 case NFSATTRBIT_SPACEFREE:
1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1546 sfp->sf_fbytes != fxdr_hyper(tl))
1547 *retcmpp = NFSERR_NOTSAME;
1548 } else if (sfp != NULL) {
1549 sfp->sf_fbytes = fxdr_hyper(tl);
1551 attrsum += NFSX_HYPER;
1553 case NFSATTRBIT_SPACETOTAL:
1554 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1557 sfp->sf_tbytes != fxdr_hyper(tl))
1558 *retcmpp = NFSERR_NOTSAME;
1559 } else if (sfp != NULL) {
1560 sfp->sf_tbytes = fxdr_hyper(tl);
1562 attrsum += NFSX_HYPER;
1564 case NFSATTRBIT_SPACEUSED:
1565 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1566 thyp = fxdr_hyper(tl);
1569 if ((u_int64_t)nap->na_bytes != thyp)
1570 *retcmpp = NFSERR_NOTSAME;
1572 } else if (nap != NULL) {
1573 nap->na_bytes = thyp;
1575 attrsum += NFSX_HYPER;
1577 case NFSATTRBIT_SYSTEM:
1578 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1579 if (compare && !(*retcmpp))
1580 *retcmpp = NFSERR_ATTRNOTSUPP;
1581 attrsum += NFSX_UNSIGNED;
1583 case NFSATTRBIT_TIMEACCESS:
1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1585 fxdr_nfsv4time(tl, &temptime);
1588 if (!NFS_CMPTIME(temptime, nap->na_atime))
1589 *retcmpp = NFSERR_NOTSAME;
1591 } else if (nap != NULL) {
1592 nap->na_atime = temptime;
1594 attrsum += NFSX_V4TIME;
1596 case NFSATTRBIT_TIMEACCESSSET:
1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1598 attrsum += NFSX_UNSIGNED;
1599 i = fxdr_unsigned(int, *tl);
1600 if (i == NFSV4SATTRTIME_TOCLIENT) {
1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1602 attrsum += NFSX_V4TIME;
1604 if (compare && !(*retcmpp))
1605 *retcmpp = NFSERR_INVAL;
1607 case NFSATTRBIT_TIMEBACKUP:
1608 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1609 if (compare && !(*retcmpp))
1610 *retcmpp = NFSERR_ATTRNOTSUPP;
1611 attrsum += NFSX_V4TIME;
1613 case NFSATTRBIT_TIMECREATE:
1614 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1615 if (compare && !(*retcmpp))
1616 *retcmpp = NFSERR_ATTRNOTSUPP;
1617 attrsum += NFSX_V4TIME;
1619 case NFSATTRBIT_TIMEDELTA:
1620 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1624 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1625 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1626 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1627 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1630 *retcmpp = NFSERR_NOTSAME;
1633 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1636 attrsum += NFSX_V4TIME;
1638 case NFSATTRBIT_TIMEMETADATA:
1639 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1640 fxdr_nfsv4time(tl, &temptime);
1643 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1644 *retcmpp = NFSERR_NOTSAME;
1646 } else if (nap != NULL) {
1647 nap->na_ctime = temptime;
1649 attrsum += NFSX_V4TIME;
1651 case NFSATTRBIT_TIMEMODIFY:
1652 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1653 fxdr_nfsv4time(tl, &temptime);
1656 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1657 *retcmpp = NFSERR_NOTSAME;
1659 } else if (nap != NULL) {
1660 nap->na_mtime = temptime;
1662 attrsum += NFSX_V4TIME;
1664 case NFSATTRBIT_TIMEMODIFYSET:
1665 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1666 attrsum += NFSX_UNSIGNED;
1667 i = fxdr_unsigned(int, *tl);
1668 if (i == NFSV4SATTRTIME_TOCLIENT) {
1669 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1670 attrsum += NFSX_V4TIME;
1672 if (compare && !(*retcmpp))
1673 *retcmpp = NFSERR_INVAL;
1675 case NFSATTRBIT_MOUNTEDONFILEID:
1676 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1677 thyp = fxdr_hyper(tl);
1681 *retcmpp = NFSERR_NOTSAME;
1683 if (!vp || !nfsrv_atroot(vp, &fid))
1684 fid = nap->na_fileid;
1685 if ((u_int64_t)fid != thyp)
1686 *retcmpp = NFSERR_NOTSAME;
1689 } else if (nap != NULL) {
1691 printf("NFSv4 mounted on fileid > 32bits\n");
1692 nap->na_mntonfileno = thyp;
1694 attrsum += NFSX_HYPER;
1697 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1699 if (compare && !(*retcmpp))
1700 *retcmpp = NFSERR_ATTRNOTSUPP;
1702 * and get out of the loop, since we can't parse
1703 * the unknown attrbute data.
1705 bitpos = NFSATTRBIT_MAX;
1711 * some clients pad the attrlist, so we need to skip over the
1714 if (attrsum > attrsize) {
1715 error = NFSERR_BADXDR;
1717 attrsize = NFSM_RNDUP(attrsize);
1718 if (attrsum < attrsize)
1719 error = nfsm_advance(nd, attrsize - attrsum, -1);
1726 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1727 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1728 * The first argument is a pointer to an nfsv4lock structure.
1729 * The second argument is 1 iff a blocking lock is wanted.
1730 * If this argument is 0, the call waits until no thread either wants nor
1731 * holds an exclusive lock.
1732 * It returns 1 if the lock was acquired, 0 otherwise.
1733 * If several processes call this function concurrently wanting the exclusive
1734 * lock, one will get the lock and the rest will return without getting the
1735 * lock. (If the caller must have the lock, it simply calls this function in a
1736 * loop until the function returns 1 to indicate the lock was acquired.)
1737 * Any usecnt must be decremented by calling nfsv4_relref() before
1738 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1739 * be called in a loop.
1740 * The last argument is set to indicate if the call slept, iff not NULL.
1743 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1750 * If a lock is wanted, loop around until the lock is acquired by
1751 * someone and then released. If I want the lock, try to acquire it.
1752 * For a lock to be issued, no lock must be in force and the usecnt
1756 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1757 lp->nfslock_usecnt == 0) {
1758 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1759 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1762 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1764 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1765 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1768 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1769 PZERO - 1, "nfsv4lck", NULL);
1770 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1771 lp->nfslock_usecnt == 0) {
1772 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1773 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1781 * Release the lock acquired by nfsv4_lock().
1782 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1783 * incremented, as well.
1786 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1789 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1791 lp->nfslock_usecnt++;
1796 * Release a reference cnt.
1799 nfsv4_relref(struct nfsv4lock *lp)
1802 if (lp->nfslock_usecnt <= 0)
1803 panic("nfsv4root ref cnt");
1804 lp->nfslock_usecnt--;
1805 if (lp->nfslock_usecnt == 0)
1810 * Get a reference cnt.
1811 * This function will wait for any exclusive lock to be released, but will
1812 * not wait for threads that want the exclusive lock. If priority needs
1813 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1814 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1817 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
1824 * Wait for a lock held.
1826 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1827 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1830 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1831 PZERO - 1, "nfsv4lck", NULL);
1834 lp->nfslock_usecnt++;
1838 * Test for a lock. Return 1 if locked, 0 otherwise.
1841 nfsv4_testlock(struct nfsv4lock *lp)
1844 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1845 lp->nfslock_usecnt == 0)
1851 * Wake up anyone sleeping, waiting for this lock.
1854 nfsv4_wanted(struct nfsv4lock *lp)
1857 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1858 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1859 wakeup((caddr_t)&lp->nfslock_lock);
1864 * Copy a string from an mbuf list into a character array.
1865 * Return EBADRPC if there is an mbuf error,
1869 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1878 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1879 rem = NFSM_RNDUP(siz) - siz;
1885 NFSBCOPY(cp, str, xfer);
1892 cp = NFSMTOD(mp, caddr_t);
1904 error = nfsm_advance(nd, rem, len);
1912 * Fill in the attributes as marked by the bitmap (V4).
1915 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
1916 struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1917 struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
1919 int bitpos, retnum = 0;
1921 int siz, prefixnum, error;
1922 u_char *cp, namestr[NFSV4_SMALLSTR];
1923 nfsattrbit_t attrbits, retbits;
1924 nfsattrbit_t *retbitp = &retbits;
1925 u_int32_t freenum, *retnump;
1929 struct nfsfsinfo fsinf;
1930 struct timespec temptime;
1931 struct timeval curtime;
1932 NFSACL_T *aclp, *naclp = NULL;
1939 * First, set the bits that can be filled and get fsinfo.
1941 NFSSET_ATTRBIT(retbitp, attrbitp);
1942 /* If p and cred are NULL, it is a client side call */
1943 if (p == NULL && cred == NULL) {
1944 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1947 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1948 #ifdef NFS4_ACL_EXTATTR_NAME
1949 naclp = acl_alloc(M_WAITOK);
1953 nfsvno_getfs(&fsinf, isdgram);
1956 * Get the VFS_STATFS(), since some attributes need them.
1958 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
1959 error = VFS_STATFS(vnode_mount(vp), &fs);
1962 nd->nd_repstat = NFSERR_ACCES;
1965 NFSCLRSTATFS_ATTRBIT(retbitp);
1971 * And the NFSv4 ACL...
1973 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT)
1974 #ifdef NFS4_ACL_EXTATTR_NAME
1975 && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1976 !NFSHASNFS4ACL(vnode_mount(vp))))
1979 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1981 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1982 #ifdef NFS4_ACL_EXTATTR_NAME
1983 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1984 !NFSHASNFS4ACL(vnode_mount(vp)))) {
1986 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1987 #ifdef NFS4_ACL_EXTATTR_NAME
1988 } else if (naclp != NULL) {
1989 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
1990 error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
1992 error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
1994 NFSVOPUNLOCK(vp, 0, p);
1997 nd->nd_repstat = NFSERR_ACCES;
2000 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2006 * Put out the attribute bitmap for the ones being filled in
2007 * and get the field for the number of attributes returned.
2009 prefixnum = nfsrv_putattrbit(nd, retbitp);
2010 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2011 prefixnum += NFSX_UNSIGNED;
2014 * Now, loop around filling in the attributes for each bit set.
2016 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2017 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2019 case NFSATTRBIT_SUPPORTEDATTRS:
2020 NFSSETSUPP_ATTRBIT(&attrbits);
2021 #ifdef NFS4_ACL_EXTATTR_NAME
2022 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2023 && !NFSHASNFS4ACL(vnode_mount(vp))))
2026 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2027 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2029 retnum += nfsrv_putattrbit(nd, &attrbits);
2031 case NFSATTRBIT_TYPE:
2032 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2033 *tl = vtonfsv34_type(vap->va_type);
2034 retnum += NFSX_UNSIGNED;
2036 case NFSATTRBIT_FHEXPIRETYPE:
2037 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2038 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2039 retnum += NFSX_UNSIGNED;
2041 case NFSATTRBIT_CHANGE:
2042 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2043 txdr_hyper(vap->va_filerev, tl);
2044 retnum += NFSX_HYPER;
2046 case NFSATTRBIT_SIZE:
2047 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2048 txdr_hyper(vap->va_size, tl);
2049 retnum += NFSX_HYPER;
2051 case NFSATTRBIT_LINKSUPPORT:
2052 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2053 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2057 retnum += NFSX_UNSIGNED;
2059 case NFSATTRBIT_SYMLINKSUPPORT:
2060 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2061 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2065 retnum += NFSX_UNSIGNED;
2067 case NFSATTRBIT_NAMEDATTR:
2068 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2070 retnum += NFSX_UNSIGNED;
2072 case NFSATTRBIT_FSID:
2073 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2075 *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
2077 *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
2078 retnum += NFSX_V4FSID;
2080 case NFSATTRBIT_UNIQUEHANDLES:
2081 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2083 retnum += NFSX_UNSIGNED;
2085 case NFSATTRBIT_LEASETIME:
2086 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2087 *tl = txdr_unsigned(nfsrv_lease);
2088 retnum += NFSX_UNSIGNED;
2090 case NFSATTRBIT_RDATTRERROR:
2091 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2092 *tl = txdr_unsigned(rderror);
2093 retnum += NFSX_UNSIGNED;
2096 * Recommended Attributes. (Only the supported ones.)
2098 #ifdef NFS4_ACL_EXTATTR_NAME
2099 case NFSATTRBIT_ACL:
2100 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2102 case NFSATTRBIT_ACLSUPPORT:
2103 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2104 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2105 retnum += NFSX_UNSIGNED;
2108 case NFSATTRBIT_CANSETTIME:
2109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2114 retnum += NFSX_UNSIGNED;
2116 case NFSATTRBIT_CASEINSENSITIVE:
2117 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2119 retnum += NFSX_UNSIGNED;
2121 case NFSATTRBIT_CASEPRESERVING:
2122 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2124 retnum += NFSX_UNSIGNED;
2126 case NFSATTRBIT_CHOWNRESTRICTED:
2127 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2129 retnum += NFSX_UNSIGNED;
2131 case NFSATTRBIT_FILEHANDLE:
2132 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2134 case NFSATTRBIT_FILEID:
2135 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2137 *tl = txdr_unsigned(vap->va_fileid);
2138 retnum += NFSX_HYPER;
2140 case NFSATTRBIT_FILESAVAIL:
2142 * Check quota and use min(quota, f_ffree).
2144 freenum = fs.f_ffree;
2147 * ufs_quotactl() insists that the uid argument
2148 * equal p_ruid for non-root quota access, so
2149 * we'll just make sure that's the case.
2151 savuid = p->p_cred->p_ruid;
2152 p->p_cred->p_ruid = cred->cr_uid;
2153 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2154 cred->cr_uid, (caddr_t)&dqb))
2155 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2157 p->p_cred->p_ruid = savuid;
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2161 *tl = txdr_unsigned(freenum);
2162 retnum += NFSX_HYPER;
2164 case NFSATTRBIT_FILESFREE:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2167 *tl = txdr_unsigned(fs.f_ffree);
2168 retnum += NFSX_HYPER;
2170 case NFSATTRBIT_FILESTOTAL:
2171 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2173 *tl = txdr_unsigned(fs.f_files);
2174 retnum += NFSX_HYPER;
2176 case NFSATTRBIT_FSLOCATIONS:
2177 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2180 retnum += 2 * NFSX_UNSIGNED;
2182 case NFSATTRBIT_HOMOGENEOUS:
2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2184 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2188 retnum += NFSX_UNSIGNED;
2190 case NFSATTRBIT_MAXFILESIZE:
2191 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2192 uquad = NFSRV_MAXFILESIZE;
2193 txdr_hyper(uquad, tl);
2194 retnum += NFSX_HYPER;
2196 case NFSATTRBIT_MAXLINK:
2197 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2198 *tl = txdr_unsigned(LINK_MAX);
2199 retnum += NFSX_UNSIGNED;
2201 case NFSATTRBIT_MAXNAME:
2202 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2203 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2204 retnum += NFSX_UNSIGNED;
2206 case NFSATTRBIT_MAXREAD:
2207 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2209 *tl = txdr_unsigned(fsinf.fs_rtmax);
2210 retnum += NFSX_HYPER;
2212 case NFSATTRBIT_MAXWRITE:
2213 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2215 *tl = txdr_unsigned(fsinf.fs_wtmax);
2216 retnum += NFSX_HYPER;
2218 case NFSATTRBIT_MODE:
2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2220 *tl = vtonfsv34_mode(vap->va_mode);
2221 retnum += NFSX_UNSIGNED;
2223 case NFSATTRBIT_NOTRUNC:
2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2226 retnum += NFSX_UNSIGNED;
2228 case NFSATTRBIT_NUMLINKS:
2229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2230 *tl = txdr_unsigned(vap->va_nlink);
2231 retnum += NFSX_UNSIGNED;
2233 case NFSATTRBIT_OWNER:
2235 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2236 retnum += nfsm_strtom(nd, cp, siz);
2238 free(cp, M_NFSSTRING);
2240 case NFSATTRBIT_OWNERGROUP:
2242 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2243 retnum += nfsm_strtom(nd, cp, siz);
2245 free(cp, M_NFSSTRING);
2247 case NFSATTRBIT_QUOTAHARD:
2248 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2249 freenum = fs.f_bfree;
2251 freenum = fs.f_bavail;
2254 * ufs_quotactl() insists that the uid argument
2255 * equal p_ruid for non-root quota access, so
2256 * we'll just make sure that's the case.
2258 savuid = p->p_cred->p_ruid;
2259 p->p_cred->p_ruid = cred->cr_uid;
2260 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2261 cred->cr_uid, (caddr_t)&dqb))
2262 freenum = min(dqb.dqb_bhardlimit, freenum);
2263 p->p_cred->p_ruid = savuid;
2265 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2266 uquad = (u_int64_t)freenum;
2267 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2268 txdr_hyper(uquad, tl);
2269 retnum += NFSX_HYPER;
2271 case NFSATTRBIT_QUOTASOFT:
2272 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2273 freenum = fs.f_bfree;
2275 freenum = fs.f_bavail;
2278 * ufs_quotactl() insists that the uid argument
2279 * equal p_ruid for non-root quota access, so
2280 * we'll just make sure that's the case.
2282 savuid = p->p_cred->p_ruid;
2283 p->p_cred->p_ruid = cred->cr_uid;
2284 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2285 cred->cr_uid, (caddr_t)&dqb))
2286 freenum = min(dqb.dqb_bsoftlimit, freenum);
2287 p->p_cred->p_ruid = savuid;
2289 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2290 uquad = (u_int64_t)freenum;
2291 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2292 txdr_hyper(uquad, tl);
2293 retnum += NFSX_HYPER;
2295 case NFSATTRBIT_QUOTAUSED:
2299 * ufs_quotactl() insists that the uid argument
2300 * equal p_ruid for non-root quota access, so
2301 * we'll just make sure that's the case.
2303 savuid = p->p_cred->p_ruid;
2304 p->p_cred->p_ruid = cred->cr_uid;
2305 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2306 cred->cr_uid, (caddr_t)&dqb))
2307 freenum = dqb.dqb_curblocks;
2308 p->p_cred->p_ruid = savuid;
2310 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2311 uquad = (u_int64_t)freenum;
2312 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2313 txdr_hyper(uquad, tl);
2314 retnum += NFSX_HYPER;
2316 case NFSATTRBIT_RAWDEV:
2317 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2318 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2319 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2320 retnum += NFSX_V4SPECDATA;
2322 case NFSATTRBIT_SPACEAVAIL:
2323 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2324 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2325 uquad = (u_int64_t)fs.f_bfree;
2327 uquad = (u_int64_t)fs.f_bavail;
2328 uquad *= fs.f_bsize;
2329 txdr_hyper(uquad, tl);
2330 retnum += NFSX_HYPER;
2332 case NFSATTRBIT_SPACEFREE:
2333 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2334 uquad = (u_int64_t)fs.f_bfree;
2335 uquad *= fs.f_bsize;
2336 txdr_hyper(uquad, tl);
2337 retnum += NFSX_HYPER;
2339 case NFSATTRBIT_SPACETOTAL:
2340 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2341 uquad = (u_int64_t)fs.f_blocks;
2342 uquad *= fs.f_bsize;
2343 txdr_hyper(uquad, tl);
2344 retnum += NFSX_HYPER;
2346 case NFSATTRBIT_SPACEUSED:
2347 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2348 txdr_hyper(vap->va_bytes, tl);
2349 retnum += NFSX_HYPER;
2351 case NFSATTRBIT_TIMEACCESS:
2352 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2353 txdr_nfsv4time(&vap->va_atime, tl);
2354 retnum += NFSX_V4TIME;
2356 case NFSATTRBIT_TIMEACCESSSET:
2357 NFSGETTIME(&curtime);
2358 if (vap->va_atime.tv_sec != curtime.tv_sec) {
2359 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2360 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2361 txdr_nfsv4time(&vap->va_atime, tl);
2362 retnum += NFSX_V4SETTIME;
2364 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2365 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2366 retnum += NFSX_UNSIGNED;
2369 case NFSATTRBIT_TIMEDELTA:
2370 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2371 temptime.tv_sec = 0;
2372 temptime.tv_nsec = 1000000000 / hz;
2373 txdr_nfsv4time(&temptime, tl);
2374 retnum += NFSX_V4TIME;
2376 case NFSATTRBIT_TIMEMETADATA:
2377 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2378 txdr_nfsv4time(&vap->va_ctime, tl);
2379 retnum += NFSX_V4TIME;
2381 case NFSATTRBIT_TIMEMODIFY:
2382 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2383 txdr_nfsv4time(&vap->va_mtime, tl);
2384 retnum += NFSX_V4TIME;
2386 case NFSATTRBIT_TIMEMODIFYSET:
2387 NFSGETTIME(&curtime);
2388 if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2389 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2390 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2391 txdr_nfsv4time(&vap->va_mtime, tl);
2392 retnum += NFSX_V4SETTIME;
2394 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2395 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2396 retnum += NFSX_UNSIGNED;
2399 case NFSATTRBIT_MOUNTEDONFILEID:
2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2402 if (nfsrv_atroot(vp, &fid))
2403 *tl = txdr_unsigned(fid);
2405 *tl = txdr_unsigned(vap->va_fileid);
2406 retnum += NFSX_HYPER;
2409 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2413 #ifdef NFS4_ACL_EXTATTR_NAME
2417 *retnump = txdr_unsigned(retnum);
2418 return (retnum + prefixnum);
2422 * Put the attribute bits onto an mbuf list.
2423 * Return the number of bytes of output generated.
2426 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2429 int cnt, i, bytesize;
2431 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2432 if (attrbitp->bits[cnt - 1])
2434 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2435 NFSM_BUILD(tl, u_int32_t *, bytesize);
2436 *tl++ = txdr_unsigned(cnt);
2437 for (i = 0; i < cnt; i++)
2438 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2443 * Convert a uid to a string.
2444 * If the lookup fails, just output the digits.
2446 * cpp - points to a buffer of size NFSV4_SMALLSTR
2447 * (malloc a larger one, as required)
2448 * retlenp - pointer to length to be returned
2451 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2454 struct nfsusrgrp *usrp;
2457 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2462 if (nfsrv_dnsname) {
2464 * Always map nfsrv_defaultuid to "nobody".
2466 if (uid == nfsrv_defaultuid) {
2467 i = nfsrv_dnsnamelen + 7;
2470 if (len > NFSV4_SMALLSTR)
2471 free(cp, M_NFSSTRING);
2472 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2478 NFSBCOPY("nobody@", cp, 7);
2480 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2485 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2486 if (usrp->lug_uid == uid) {
2487 if (usrp->lug_expiry < NFSD_MONOSEC)
2490 * If the name doesn't already have an '@'
2491 * in it, append @domainname to it.
2493 for (i = 0; i < usrp->lug_namelen; i++) {
2494 if (usrp->lug_name[i] == '@') {
2500 i = usrp->lug_namelen;
2502 i = usrp->lug_namelen +
2503 nfsrv_dnsnamelen + 1;
2506 if (len > NFSV4_SMALLSTR)
2507 free(cp, M_NFSSTRING);
2508 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2514 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2515 if (!hasampersand) {
2516 cp += usrp->lug_namelen;
2518 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2520 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2521 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2528 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2530 if (ret == 0 && cnt < 2)
2537 * No match, just return a string of digits.
2541 while (tmp || i == 0) {
2545 len = (i > len) ? len : i;
2549 for (i = 0; i < len; i++) {
2550 *cp-- = '0' + (tmp % 10);
2557 * Convert a string to a uid.
2558 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2562 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2566 struct nfsusrgrp *usrp;
2570 return (NFSERR_BADOWNER);
2575 for (i = 0; i < len; i++)
2583 * If an '@' is found and the domain name matches, search for the name
2584 * with dns stripped off.
2585 * Mixed case alpahbetics will match for the domain name, but all
2586 * upper case will not.
2588 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2589 (len - 1 - i) == nfsrv_dnsnamelen &&
2590 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2591 len -= (nfsrv_dnsnamelen + 1);
2596 * Check for the special case of "nobody".
2598 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2599 *uidp = nfsrv_defaultuid;
2604 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2605 if (usrp->lug_namelen == len &&
2606 !NFSBCMP(usrp->lug_name, str, len)) {
2607 if (usrp->lug_expiry < NFSD_MONOSEC)
2609 *uidp = usrp->lug_uid;
2610 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2611 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2618 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2620 if (ret == 0 && cnt < 2)
2622 return (NFSERR_BADOWNER);
2626 * Convert a gid to a string.
2627 * gid - the group id
2628 * cpp - points to a buffer of size NFSV4_SMALLSTR
2629 * (malloc a larger one, as required)
2630 * retlenp - pointer to length to be returned
2633 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2636 struct nfsusrgrp *usrp;
2639 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2644 if (nfsrv_dnsname) {
2646 * Always map nfsrv_defaultgid to "nogroup".
2648 if (gid == nfsrv_defaultgid) {
2649 i = nfsrv_dnsnamelen + 8;
2652 if (len > NFSV4_SMALLSTR)
2653 free(cp, M_NFSSTRING);
2654 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2660 NFSBCOPY("nogroup@", cp, 8);
2662 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2667 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2668 if (usrp->lug_gid == gid) {
2669 if (usrp->lug_expiry < NFSD_MONOSEC)
2672 * If the name doesn't already have an '@'
2673 * in it, append @domainname to it.
2675 for (i = 0; i < usrp->lug_namelen; i++) {
2676 if (usrp->lug_name[i] == '@') {
2682 i = usrp->lug_namelen;
2684 i = usrp->lug_namelen +
2685 nfsrv_dnsnamelen + 1;
2688 if (len > NFSV4_SMALLSTR)
2689 free(cp, M_NFSSTRING);
2690 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2696 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2697 if (!hasampersand) {
2698 cp += usrp->lug_namelen;
2700 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2702 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2703 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2710 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2712 if (ret == 0 && cnt < 2)
2719 * No match, just return a string of digits.
2723 while (tmp || i == 0) {
2727 len = (i > len) ? len : i;
2731 for (i = 0; i < len; i++) {
2732 *cp-- = '0' + (tmp % 10);
2739 * Convert a string to a gid.
2742 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2746 struct nfsusrgrp *usrp;
2750 return (NFSERR_BADOWNER);
2755 for (i = 0; i < len; i++)
2763 * If an '@' is found and the dns name matches, search for the name
2764 * with the dns stripped off.
2766 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2767 (len - 1 - i) == nfsrv_dnsnamelen &&
2768 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2769 len -= (nfsrv_dnsnamelen + 1);
2774 * Check for the special case of "nogroup".
2776 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2777 *gidp = nfsrv_defaultgid;
2782 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2783 if (usrp->lug_namelen == len &&
2784 !NFSBCMP(usrp->lug_name, str, len)) {
2785 if (usrp->lug_expiry < NFSD_MONOSEC)
2787 *gidp = usrp->lug_gid;
2788 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2789 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2796 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2798 if (ret == 0 && cnt < 2)
2800 return (NFSERR_BADOWNER);
2804 * Cmp len chars, allowing mixed case in the first argument to match lower
2805 * case in the second, but not if the first argument is all upper case.
2806 * Return 0 for a match, 1 otherwise.
2809 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2815 for (i = 0; i < len; i++) {
2816 if (*cp >= 'A' && *cp <= 'Z') {
2817 tmp = *cp++ + ('a' - 'A');
2820 if (tmp >= 'a' && tmp <= 'z')
2833 * Set the port for the nfsuserd.
2836 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2838 struct nfssockreq *rp;
2839 struct sockaddr_in *ad;
2843 if (nfsrv_nfsuserd) {
2850 * Set up the socket record and connect.
2852 rp = &nfsrv_nfsuserdsock;
2853 rp->nr_client = NULL;
2854 rp->nr_sotype = SOCK_DGRAM;
2855 rp->nr_soproto = IPPROTO_UDP;
2856 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2858 NFSSOCKADDRALLOC(rp->nr_nam);
2859 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2860 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2861 ad->sin_family = AF_INET;
2862 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2863 ad->sin_port = port;
2864 rp->nr_prog = RPCPROG_NFSUSERD;
2865 rp->nr_vers = RPCNFSUSERD_VERS;
2866 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2868 NFSSOCKADDRFREE(rp->nr_nam);
2875 * Delete the nfsuserd port.
2878 nfsrv_nfsuserddelport(void)
2882 if (nfsrv_nfsuserd == 0) {
2888 newnfs_disconnect(&nfsrv_nfsuserdsock);
2889 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2893 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2895 * Returns 0 upon success, non-zero otherwise.
2898 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2901 struct nfsrv_descript *nd;
2903 struct nfsrv_descript nfsd;
2908 if (nfsrv_nfsuserd == 0) {
2914 cred = newnfs_getcred();
2915 nd->nd_flag = ND_GSSINITREPLY;
2918 nd->nd_procnum = procnum;
2919 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2920 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2921 if (procnum == RPCNFSUSERD_GETUID)
2922 *tl = txdr_unsigned(uid);
2924 *tl = txdr_unsigned(gid);
2927 (void) nfsm_strtom(nd, name, len);
2929 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2930 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2933 mbuf_freem(nd->nd_mrep);
2934 error = nd->nd_repstat;
2940 * This function is called from the nfssvc(2) system call, to update the
2941 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2944 nfssvc_idname(struct nfsd_idargs *nidp)
2946 struct nfsusrgrp *nusrp, *usrp, *newusrp;
2947 struct nfsuserhashhead *hp;
2952 if (nidp->nid_flag & NFSID_INITIALIZE) {
2953 cp = (u_char *)malloc(nidp->nid_namelen + 1,
2954 M_NFSSTRING, M_WAITOK);
2955 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2958 if (nfsrv_dnsname) {
2960 * Free up all the old stuff and reinitialize hash lists.
2962 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2963 nfsrv_removeuser(usrp);
2965 free(nfsrv_dnsname, M_NFSSTRING);
2966 nfsrv_dnsname = NULL;
2968 TAILQ_INIT(&nfsuserlruhead);
2969 for (i = 0; i < NFSUSERHASHSIZE; i++)
2970 LIST_INIT(&nfsuserhash[i]);
2971 for (i = 0; i < NFSGROUPHASHSIZE; i++)
2972 LIST_INIT(&nfsgrouphash[i]);
2973 for (i = 0; i < NFSUSERHASHSIZE; i++)
2974 LIST_INIT(&nfsusernamehash[i]);
2975 for (i = 0; i < NFSGROUPHASHSIZE; i++)
2976 LIST_INIT(&nfsgroupnamehash[i]);
2979 * Put name in "DNS" string.
2983 nfsrv_dnsnamelen = nidp->nid_namelen;
2984 nfsrv_defaultuid = nidp->nid_uid;
2985 nfsrv_defaultgid = nidp->nid_gid;
2987 nfsrv_usermax = nidp->nid_usermax;
2991 free(cp, M_NFSSTRING);
2996 * malloc the new one now, so any potential sleep occurs before
2997 * manipulation of the lists.
2999 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3000 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3001 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3004 free((caddr_t)newusrp, M_NFSUSERGROUP);
3007 newusrp->lug_namelen = nidp->nid_namelen;
3011 * Delete old entries, as required.
3013 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3014 hp = NFSUSERHASH(nidp->nid_uid);
3015 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3016 if (usrp->lug_uid == nidp->nid_uid)
3017 nfsrv_removeuser(usrp);
3020 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3021 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3022 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3023 if (usrp->lug_namelen == newusrp->lug_namelen &&
3024 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3026 nfsrv_removeuser(usrp);
3029 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3030 hp = NFSGROUPHASH(nidp->nid_gid);
3031 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3032 if (usrp->lug_gid == nidp->nid_gid)
3033 nfsrv_removeuser(usrp);
3036 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3037 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3038 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3039 if (usrp->lug_namelen == newusrp->lug_namelen &&
3040 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3042 nfsrv_removeuser(usrp);
3045 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3046 if (usrp->lug_expiry < NFSD_MONOSEC)
3047 nfsrv_removeuser(usrp);
3049 while (nfsrv_usercnt >= nfsrv_usermax) {
3050 usrp = TAILQ_FIRST(&nfsuserlruhead);
3051 nfsrv_removeuser(usrp);
3055 * Now, we can add the new one.
3057 if (nidp->nid_usertimeout)
3058 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3060 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3061 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3062 newusrp->lug_uid = nidp->nid_uid;
3063 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3065 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3066 newusrp->lug_namelen), newusrp, lug_namehash);
3067 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3069 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3070 newusrp->lug_gid = nidp->nid_gid;
3071 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3073 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3074 newusrp->lug_namelen), newusrp, lug_namehash);
3075 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3078 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3084 * Remove a user/group name element.
3087 nfsrv_removeuser(struct nfsusrgrp *usrp)
3090 NFSNAMEIDREQUIRED();
3091 LIST_REMOVE(usrp, lug_numhash);
3092 LIST_REMOVE(usrp, lug_namehash);
3093 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3095 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3099 * This function scans a byte string and checks for UTF-8 compliance.
3100 * It returns 0 if it conforms and NFSERR_INVAL if not.
3103 nfsrv_checkutf8(u_int8_t *cp, int len)
3105 u_int32_t val = 0x0;
3106 int cnt = 0, gotd = 0, shift = 0;
3108 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3111 * Here are what the variables are used for:
3112 * val - the calculated value of a multibyte char, used to check
3113 * that it was coded with the correct range
3114 * cnt - the number of 10xxxxxx bytes to follow
3115 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3116 * shift - lower order bits of range (ie. "val >> shift" should
3117 * not be 0, in other words, dividing by the lower bound
3118 * of the range should get a non-zero value)
3119 * byte - used to calculate cnt
3123 /* This handles the 10xxxxxx bytes */
3124 if ((*cp & 0xc0) != 0x80 ||
3125 (gotd && (*cp & 0x20)))
3126 return (NFSERR_INVAL);
3129 val |= (*cp & 0x3f);
3131 if (cnt == 0 && (val >> shift) == 0x0)
3132 return (NFSERR_INVAL);
3133 } else if (*cp & 0x80) {
3134 /* first byte of multi byte char */
3136 while ((byte & 0x40) && cnt < 6) {
3140 if (cnt == 0 || cnt == 6)
3141 return (NFSERR_INVAL);
3142 val = (*cp & (0x3f >> cnt));
3143 shift = utf8_shift[cnt - 1];
3144 if (cnt == 2 && val == 0xd)
3145 /* Check for the 0xd800-0xdfff case */
3152 return (NFSERR_INVAL);
3157 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3158 * strings, one with the root path in it and the other with the list of
3159 * locations. The list is in the same format as is found in nfr_refs.
3160 * It is a "," separated list of entries, where each of them is of the
3161 * form <server>:<rootpath>. For example
3162 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3163 * The nilp argument is set to 1 for the special case of a null fs_root
3164 * and an empty server list.
3165 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3166 * number of xdr bytes parsed in sump.
3169 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3170 int *sump, int *nilp)
3173 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3174 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3176 SLIST_ENTRY(list) next;
3180 SLIST_HEAD(, list) head;
3187 * Get the fs_root path and check for the special case of null path
3188 * and 0 length server list.
3190 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3191 len = fxdr_unsigned(int, *tl);
3192 if (len < 0 || len > 10240)
3193 return (NFSERR_BADXDR);
3195 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3197 return (NFSERR_BADXDR);
3199 *sump = 2 * NFSX_UNSIGNED;
3202 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3203 error = nfsrv_mtostr(nd, cp, len);
3205 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3206 cnt = fxdr_unsigned(int, *tl);
3208 error = NFSERR_BADXDR;
3211 free(cp, M_NFSSTRING);
3216 * Now, loop through the location list and make up the srvlist.
3218 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3219 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3222 for (i = 0; i < cnt; i++) {
3224 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3225 nsrv = fxdr_unsigned(int, *tl);
3227 free(cp, M_NFSSTRING);
3228 free(cp2, M_NFSSTRING);
3229 return (NFSERR_BADXDR);
3233 * Handle the first server by putting it in the srvstr.
3235 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3236 len = fxdr_unsigned(int, *tl);
3237 if (len <= 0 || len > 1024) {
3238 free(cp, M_NFSSTRING);
3239 free(cp2, M_NFSSTRING);
3240 return (NFSERR_BADXDR);
3242 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3247 error = nfsrv_mtostr(nd, cp3, len);
3249 free(cp, M_NFSSTRING);
3250 free(cp2, M_NFSSTRING);
3256 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3257 for (j = 1; j < nsrv; j++) {
3259 * Yuck, put them in an slist and process them later.
3261 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3262 len = fxdr_unsigned(int, *tl);
3263 if (len <= 0 || len > 1024) {
3264 free(cp, M_NFSSTRING);
3265 free(cp2, M_NFSSTRING);
3266 return (NFSERR_BADXDR);
3268 lsp = (struct list *)malloc(sizeof (struct list)
3269 + len, M_TEMP, M_WAITOK);
3270 error = nfsrv_mtostr(nd, lsp->host, len);
3272 free(cp, M_NFSSTRING);
3273 free(cp2, M_NFSSTRING);
3276 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3278 SLIST_INSERT_HEAD(&head, lsp, next);
3282 * Finally, we can get the path.
3284 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3285 len = fxdr_unsigned(int, *tl);
3286 if (len <= 0 || len > 1024) {
3287 free(cp, M_NFSSTRING);
3288 free(cp2, M_NFSSTRING);
3289 return (NFSERR_BADXDR);
3291 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3292 error = nfsrv_mtostr(nd, cp3, len);
3294 free(cp, M_NFSSTRING);
3295 free(cp2, M_NFSSTRING);
3298 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3303 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3304 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3307 NFSBCOPY(lsp->host, cp3, lsp->len);
3310 NFSBCOPY(str, cp3, stringlen);
3313 siz += (lsp->len + stringlen + 2);
3314 free((caddr_t)lsp, M_TEMP);
3323 free(cp, M_NFSSTRING);
3325 free(cp2, M_NFSSTRING);
3330 * Make the malloc'd space large enough. This is a pain, but the xdr
3331 * doesn't set an upper bound on the side, so...
3334 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3341 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3342 NFSBCOPY(*cpp, cp, *slenp);
3343 free(*cpp, M_NFSSTRING);
3347 *slenp = siz + 1024;
3351 * Initialize the reply header data structures.
3354 nfsrvd_rephead(struct nfsrv_descript *nd)
3359 * If this is a big reply, use a cluster.
3361 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3362 nfs_bigreply[nd->nd_procnum]) {
3363 NFSMCLGET(mreq, M_WAIT);
3371 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3372 mbuf_setlen(mreq, 0);
3374 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3375 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3379 * Lock a socket against others.
3380 * Currently used to serialize connect/disconnect attempts.
3383 newnfs_sndlock(int *flagp)
3388 while (*flagp & NFSR_SNDLOCK) {
3389 *flagp |= NFSR_WANTSND;
3392 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3393 PZERO - 1, "nfsndlck", &ts);
3395 *flagp |= NFSR_SNDLOCK;
3401 * Unlock the stream socket for others.
3404 newnfs_sndunlock(int *flagp)
3408 if ((*flagp & NFSR_SNDLOCK) == 0)
3409 panic("nfs sndunlock");
3410 *flagp &= ~NFSR_SNDLOCK;
3411 if (*flagp & NFSR_WANTSND) {
3412 *flagp &= ~NFSR_WANTSND;
3413 wakeup((caddr_t)flagp);