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.
44 #include "opt_inet6.h"
46 #include <fs/nfs/nfsport.h>
48 #include <security/mac/mac_framework.h>
51 * Data items converted to xdr at startup, since they are constant
52 * This is kinda hokey, but may save a little time doing byte swaps
54 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
56 /* And other global data */
57 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
59 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
60 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
61 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
64 struct nfssockreq nfsrv_nfsuserdsock;
65 int nfsrv_nfsuserd = 0;
66 struct nfsreqhead nfsd_reqq;
67 uid_t nfsrv_defaultuid = UID_NOBODY;
68 gid_t nfsrv_defaultgid = GID_NOGROUP;
69 int nfsrv_lease = NFSRV_LEASE;
70 int ncl_mbuf_mlen = MLEN;
71 int nfsd_enable_stringtouid = 0;
72 static int nfs_enable_uidtostring = 0;
75 extern int nfsrv_lughashsize;
77 SYSCTL_DECL(_vfs_nfs);
78 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
79 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
82 * This array of structures indicates, for V4:
83 * retfh - which of 3 types of calling args are used
84 * 0 - doesn't change cfh or use a sfh
85 * 1 - replaces cfh with a new one (unless it returns an error status)
86 * 2 - uses cfh and sfh
87 * needscfh - if the op wants a cfh and premtime
88 * 0 - doesn't use a cfh
89 * 1 - uses a cfh, but doesn't want pre-op attributes
90 * 2 - uses a cfh and wants pre-op attributes
91 * savereply - indicates a non-idempotent Op
92 * 0 - not non-idempotent
94 * Ops that are ordered via seqid# are handled separately from these
96 * Define it here, since it is used by both the client and server.
98 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
99 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
101 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
102 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
104 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
105 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
106 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
108 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
109 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
110 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
112 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
114 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
115 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
116 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
117 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
118 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
119 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
120 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
121 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
122 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
123 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
124 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
125 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
126 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
128 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
133 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
137 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
159 #endif /* !APPLEKEXT */
161 static int ncl_mbuf_mhlen = MHLEN;
162 static int nfsrv_usercnt = 0;
163 static int nfsrv_dnsnamelen;
164 static u_char *nfsrv_dnsname = NULL;
165 static int nfsrv_usermax = 999999999;
166 struct nfsrv_lughash {
168 struct nfsuserhashhead lughead;
170 static struct nfsrv_lughash *nfsuserhash;
171 static struct nfsrv_lughash *nfsusernamehash;
172 static struct nfsrv_lughash *nfsgrouphash;
173 static struct nfsrv_lughash *nfsgroupnamehash;
176 * This static array indicates whether or not the RPC generates a large
177 * reply. This is used by nfs_reply() to decide whether or not an mbuf
178 * cluster should be allocated. (If a cluster is required by an RPC
179 * marked 0 in this array, the code will still work, just not quite as
182 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
183 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,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
186 /* local functions */
187 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
188 static void nfsv4_wanted(struct nfsv4lock *lp);
189 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
190 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
192 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
193 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
195 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
200 * copies mbuf chain to the uio scatter/gather list
203 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
205 char *mbufcp, *uiocp;
212 mbufcp = nd->nd_dpos;
213 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
214 rem = NFSM_RNDUP(siz) - siz;
216 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
220 left = uiop->uio_iov->iov_len;
221 uiocp = uiop->uio_iov->iov_base;
232 mbufcp = NFSMTOD(mp, caddr_t);
235 ("len %d, corrupted mbuf?", len));
237 xfer = (left > len) ? len : left;
240 if (uiop->uio_iov->iov_op != NULL)
241 (*(uiop->uio_iov->iov_op))
242 (mbufcp, uiocp, xfer);
245 if (uiop->uio_segflg == UIO_SYSSPACE)
246 NFSBCOPY(mbufcp, uiocp, xfer);
248 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
253 uiop->uio_offset += xfer;
254 uiop->uio_resid -= xfer;
256 if (uiop->uio_iov->iov_len <= siz) {
260 uiop->uio_iov->iov_base = (void *)
261 ((char *)uiop->uio_iov->iov_base + uiosiz);
262 uiop->uio_iov->iov_len -= uiosiz;
266 nd->nd_dpos = mbufcp;
270 error = nfsm_advance(nd, rem, len);
276 NFSEXITCODE2(error, nd);
282 * Help break down an mbuf chain by setting the first siz bytes contiguous
283 * pointed to by returned val.
284 * This is used by the macro NFSM_DISSECT for tough
288 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
297 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
299 nd->nd_md = mbuf_next(nd->nd_md);
300 if (nd->nd_md == NULL)
302 left = mbuf_len(nd->nd_md);
303 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
308 } else if (mbuf_next(nd->nd_md) == NULL) {
310 } else if (siz > ncl_mbuf_mhlen) {
311 panic("nfs S too big");
313 MGET(mp2, MT_DATA, how);
316 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
317 mbuf_setnext(nd->nd_md, mp2);
318 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
320 retp = p = NFSMTOD(mp2, caddr_t);
321 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
324 mp2 = mbuf_next(mp2);
325 /* Loop around copying up the siz2 bytes */
329 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
331 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
332 NFSM_DATAP(mp2, xfer);
333 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
338 mp2 = mbuf_next(mp2);
340 mbuf_setlen(nd->nd_md, siz);
342 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
348 * Advance the position in the mbuf chain.
349 * If offs == 0, this is a no-op, but it is simpler to just return from
350 * here than check for offs > 0 for all calls to nfsm_advance.
351 * If left == -1, it should be calculated here.
354 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
361 * A negative offs should be considered a serious problem.
364 panic("nfsrv_advance");
367 * If left == -1, calculate it here.
370 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
374 * Loop around, advancing over the mbuf data.
376 while (offs > left) {
378 nd->nd_md = mbuf_next(nd->nd_md);
379 if (nd->nd_md == NULL) {
383 left = mbuf_len(nd->nd_md);
384 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
394 * Copy a string into mbuf(s).
395 * Return the number of bytes output, including XDR overheads.
398 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
407 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
408 *tl = txdr_unsigned(siz);
409 rem = NFSM_RNDUP(siz) - siz;
410 bytesize = NFSX_UNSIGNED + siz + rem;
413 left = M_TRAILINGSPACE(m2);
416 * Loop around copying the string to mbuf(s).
420 if (siz > ncl_mbuf_mlen)
421 NFSMCLGET(m1, M_WAITOK);
425 mbuf_setnext(m2, m1);
427 cp2 = NFSMTOD(m2, caddr_t);
428 left = M_TRAILINGSPACE(m2);
434 NFSBCOPY(cp, cp2, xfer);
436 mbuf_setlen(m2, mbuf_len(m2) + xfer);
439 if (siz == 0 && rem) {
441 panic("nfsm_strtom");
442 NFSBZERO(cp2 + xfer, rem);
443 mbuf_setlen(m2, mbuf_len(m2) + rem);
447 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
452 * Called once to initialize data structures...
457 static int nfs_inited = 0;
463 newnfs_true = txdr_unsigned(TRUE);
464 newnfs_false = txdr_unsigned(FALSE);
465 newnfs_xdrneg1 = txdr_unsigned(-1);
466 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
469 NFSSETBOOTTIME(nfsboottime);
472 * Initialize reply list and start timer
474 TAILQ_INIT(&nfsd_reqq);
479 * Put a file handle in an mbuf list.
480 * If the size argument == 0, just use the default size.
481 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
482 * Return the number of bytes output, including XDR overhead.
485 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
489 int fullsiz, rem, bytesize = 0;
493 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
495 if (size > NFSX_V2FH)
496 panic("fh size > NFSX_V2FH for NFSv2");
497 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
498 NFSBCOPY(fhp, cp, size);
499 if (size < NFSX_V2FH)
500 NFSBZERO(cp + size, NFSX_V2FH - size);
501 bytesize = NFSX_V2FH;
505 fullsiz = NFSM_RNDUP(size);
506 rem = fullsiz - size;
508 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
509 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
512 bytesize = NFSX_UNSIGNED + fullsiz;
514 (void) nfsm_strtom(nd, fhp, size);
521 * This function compares two net addresses by family and returns TRUE
522 * if they are the same host.
523 * If there is any doubt, return FALSE.
524 * The AF_INET family is handled as a special case so that address mbufs
525 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
528 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
530 struct sockaddr_in *inetaddr;
534 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
535 if (inetaddr->sin_family == AF_INET &&
536 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
542 struct sockaddr_in6 *inetaddr6;
544 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
545 /* XXX - should test sin6_scope_id ? */
546 if (inetaddr6->sin6_family == AF_INET6 &&
547 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
558 * Similar to the above, but takes to NFSSOCKADDR_T args.
561 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
563 struct sockaddr_in *addr1, *addr2;
564 struct sockaddr *inaddr;
566 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
567 switch (inaddr->sa_family) {
569 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
570 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
571 if (addr2->sin_family == AF_INET &&
572 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
578 struct sockaddr_in6 *inet6addr1, *inet6addr2;
580 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
581 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
582 /* XXX - should test sin6_scope_id ? */
583 if (inet6addr2->sin6_family == AF_INET6 &&
584 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
585 &inet6addr2->sin6_addr))
596 * Trim the stuff already dissected off the mbuf list.
599 newnfs_trimleading(nd)
600 struct nfsrv_descript *nd;
606 * First, free up leading mbufs.
608 if (nd->nd_mrep != nd->nd_md) {
610 while (mbuf_next(m) != nd->nd_md) {
611 if (mbuf_next(m) == NULL)
612 panic("nfsm trim leading");
615 mbuf_setnext(m, NULL);
616 mbuf_freem(nd->nd_mrep);
621 * Now, adjust this mbuf, based on nd_dpos.
623 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
624 if (offs == mbuf_len(m)) {
628 panic("nfsm trim leading2");
629 mbuf_setnext(n, NULL);
631 } else if (offs > 0) {
632 mbuf_setlen(m, mbuf_len(m) - offs);
635 panic("nfsm trimleading offs");
638 nd->nd_dpos = NFSMTOD(m, caddr_t);
642 * Trim trailing data off the mbuf list being built.
645 newnfs_trimtrailing(nd, mb, bpos)
646 struct nfsrv_descript *nd;
652 mbuf_freem(mbuf_next(mb));
653 mbuf_setnext(mb, NULL);
655 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
661 * Dissect a file handle on the client.
664 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
671 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
672 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
673 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
680 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
682 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
684 FREE((caddr_t)nfhp, M_NFSFH);
690 NFSEXITCODE2(error, nd);
695 * Break down the nfsv4 acl.
696 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
699 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
700 int *aclsizep, __unused NFSPROC_T *p)
704 int acecnt, error = 0, aceerr = 0, acesize;
710 * Parse out the ace entries and expect them to conform to
711 * what can be supported by R/W/X bits.
713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
714 aclsize = NFSX_UNSIGNED;
715 acecnt = fxdr_unsigned(int, *tl);
716 if (acecnt > ACL_MAX_ENTRIES)
717 aceerr = NFSERR_ATTRNOTSUPP;
718 if (nfsrv_useacl == 0)
719 aceerr = NFSERR_ATTRNOTSUPP;
720 for (i = 0; i < acecnt; i++) {
722 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
723 &aceerr, &acesize, p);
725 error = nfsrv_skipace(nd, &acesize);
731 aclp->acl_cnt = acecnt;
737 NFSEXITCODE2(error, nd);
742 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
745 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
750 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
751 len = fxdr_unsigned(int, *(tl + 3));
752 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
754 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
755 NFSEXITCODE2(error, nd);
760 * Get attribute bits from an mbuf list.
761 * Returns EBADRPC for a parsing error, 0 otherwise.
762 * If the clearinvalid flag is set, clear the bits not supported.
765 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
773 cnt = fxdr_unsigned(int, *tl);
775 error = NFSERR_BADXDR;
778 if (cnt > NFSATTRBIT_MAXWORDS)
779 outcnt = NFSATTRBIT_MAXWORDS;
782 NFSZERO_ATTRBIT(attrbitp);
784 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
785 for (i = 0; i < outcnt; i++)
786 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
788 for (i = 0; i < (cnt - outcnt); i++) {
789 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
790 if (retnotsupp != NULL && *tl != 0)
791 *retnotsupp = NFSERR_ATTRNOTSUPP;
794 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
796 NFSEXITCODE2(error, nd);
801 * Get the attributes for V4.
802 * If the compare flag is true, test for any attribute changes,
803 * otherwise return the attribute values.
804 * These attributes cover fields in "struct vattr", "struct statfs",
805 * "struct nfsfsinfo", the file handle and the lease duration.
806 * The value of retcmpp is set to 1 if all attributes are the same,
808 * Returns EBADRPC if it can't be parsed, 0 otherwise.
811 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
812 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
813 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
814 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
815 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
818 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
819 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
820 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
821 nfsattrbit_t attrbits, retattrbits, checkattrbits;
823 struct nfsreferral *refp;
826 struct timespec temptime;
830 u_int32_t freenum = 0, tuint;
831 u_int64_t uquad = 0, thyp, thyp2;
836 static struct timeval last64fileid;
837 static size_t count64fileid;
838 static struct timeval last64mountfileid;
839 static size_t count64mountfileid;
840 static struct timeval warninterval = { 60, 0 };
844 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
846 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
852 *retcmpp = retnotsup;
855 * Just set default values to some of the important ones.
860 nap->na_rdev = (NFSDEV_T)0;
861 nap->na_mtime.tv_sec = 0;
862 nap->na_mtime.tv_nsec = 0;
865 nap->na_blocksize = NFS_FABLKSIZE;
868 sbp->f_bsize = NFS_FABLKSIZE;
876 fsp->fs_rtmax = 8192;
877 fsp->fs_rtpref = 8192;
878 fsp->fs_maxname = NFS_MAXNAMLEN;
879 fsp->fs_wtmax = 8192;
880 fsp->fs_wtpref = 8192;
881 fsp->fs_wtmult = NFS_FABLKSIZE;
882 fsp->fs_dtpref = 8192;
883 fsp->fs_maxfilesize = 0xffffffffffffffffull;
884 fsp->fs_timedelta.tv_sec = 0;
885 fsp->fs_timedelta.tv_nsec = 1;
886 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
887 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
890 pc->pc_linkmax = LINK_MAX;
891 pc->pc_namemax = NAME_MAX;
893 pc->pc_chownrestricted = 0;
894 pc->pc_caseinsensitive = 0;
895 pc->pc_casepreserving = 1;
898 sfp->sf_ffiles = UINT64_MAX;
899 sfp->sf_tfiles = UINT64_MAX;
900 sfp->sf_afiles = UINT64_MAX;
901 sfp->sf_fbytes = UINT64_MAX;
902 sfp->sf_tbytes = UINT64_MAX;
903 sfp->sf_abytes = UINT64_MAX;
908 * Loop around getting the attributes.
910 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
911 attrsize = fxdr_unsigned(int, *tl);
912 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
913 if (attrsum > attrsize) {
914 error = NFSERR_BADXDR;
917 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
919 case NFSATTRBIT_SUPPORTEDATTRS:
921 if (compare || nap == NULL)
922 error = nfsrv_getattrbits(nd, &retattrbits,
925 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
929 if (compare && !(*retcmpp)) {
930 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
931 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
933 *retcmpp = NFSERR_NOTSAME;
937 case NFSATTRBIT_TYPE:
938 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
941 if (nap->na_type != nfsv34tov_type(*tl))
942 *retcmpp = NFSERR_NOTSAME;
944 } else if (nap != NULL) {
945 nap->na_type = nfsv34tov_type(*tl);
947 attrsum += NFSX_UNSIGNED;
949 case NFSATTRBIT_FHEXPIRETYPE:
950 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
951 if (compare && !(*retcmpp)) {
952 if (fxdr_unsigned(int, *tl) !=
953 NFSV4FHTYPE_PERSISTENT)
954 *retcmpp = NFSERR_NOTSAME;
956 attrsum += NFSX_UNSIGNED;
958 case NFSATTRBIT_CHANGE:
959 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
962 if (nap->na_filerev != fxdr_hyper(tl))
963 *retcmpp = NFSERR_NOTSAME;
965 } else if (nap != NULL) {
966 nap->na_filerev = fxdr_hyper(tl);
968 attrsum += NFSX_HYPER;
970 case NFSATTRBIT_SIZE:
971 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
974 if (nap->na_size != fxdr_hyper(tl))
975 *retcmpp = NFSERR_NOTSAME;
977 } else if (nap != NULL) {
978 nap->na_size = fxdr_hyper(tl);
980 attrsum += NFSX_HYPER;
982 case NFSATTRBIT_LINKSUPPORT:
983 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
986 if (fsp->fs_properties & NFSV3_FSFLINK) {
987 if (*tl == newnfs_false)
988 *retcmpp = NFSERR_NOTSAME;
990 if (*tl == newnfs_true)
991 *retcmpp = NFSERR_NOTSAME;
994 } else if (fsp != NULL) {
995 if (*tl == newnfs_true)
996 fsp->fs_properties |= NFSV3_FSFLINK;
998 fsp->fs_properties &= ~NFSV3_FSFLINK;
1000 attrsum += NFSX_UNSIGNED;
1002 case NFSATTRBIT_SYMLINKSUPPORT:
1003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1006 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1007 if (*tl == newnfs_false)
1008 *retcmpp = NFSERR_NOTSAME;
1010 if (*tl == newnfs_true)
1011 *retcmpp = NFSERR_NOTSAME;
1014 } else if (fsp != NULL) {
1015 if (*tl == newnfs_true)
1016 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1018 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1020 attrsum += NFSX_UNSIGNED;
1022 case NFSATTRBIT_NAMEDATTR:
1023 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1024 if (compare && !(*retcmpp)) {
1025 if (*tl != newnfs_false)
1026 *retcmpp = NFSERR_NOTSAME;
1028 attrsum += NFSX_UNSIGNED;
1030 case NFSATTRBIT_FSID:
1031 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1032 thyp = fxdr_hyper(tl);
1034 thyp2 = fxdr_hyper(tl);
1036 if (*retcmpp == 0) {
1037 if (thyp != (u_int64_t)
1038 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1039 thyp2 != (u_int64_t)
1040 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1041 *retcmpp = NFSERR_NOTSAME;
1043 } else if (nap != NULL) {
1044 nap->na_filesid[0] = thyp;
1045 nap->na_filesid[1] = thyp2;
1047 attrsum += (4 * NFSX_UNSIGNED);
1049 case NFSATTRBIT_UNIQUEHANDLES:
1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1051 if (compare && !(*retcmpp)) {
1052 if (*tl != newnfs_true)
1053 *retcmpp = NFSERR_NOTSAME;
1055 attrsum += NFSX_UNSIGNED;
1057 case NFSATTRBIT_LEASETIME:
1058 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1060 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1062 *retcmpp = NFSERR_NOTSAME;
1063 } else if (leasep != NULL) {
1064 *leasep = fxdr_unsigned(u_int32_t, *tl);
1066 attrsum += NFSX_UNSIGNED;
1068 case NFSATTRBIT_RDATTRERROR:
1069 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1072 *retcmpp = NFSERR_INVAL;
1073 } else if (rderrp != NULL) {
1074 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1076 attrsum += NFSX_UNSIGNED;
1078 case NFSATTRBIT_ACL:
1084 naclp = acl_alloc(M_WAITOK);
1085 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1091 if (aceerr || aclp == NULL ||
1092 nfsrv_compareacl(aclp, naclp))
1093 *retcmpp = NFSERR_NOTSAME;
1096 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1098 *retcmpp = NFSERR_ATTRNOTSUPP;
1102 if (vp != NULL && aclp != NULL)
1103 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1106 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1113 case NFSATTRBIT_ACLSUPPORT:
1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1115 if (compare && !(*retcmpp)) {
1117 if (fxdr_unsigned(u_int32_t, *tl) !=
1119 *retcmpp = NFSERR_NOTSAME;
1121 *retcmpp = NFSERR_ATTRNOTSUPP;
1124 attrsum += NFSX_UNSIGNED;
1126 case NFSATTRBIT_ARCHIVE:
1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1128 if (compare && !(*retcmpp))
1129 *retcmpp = NFSERR_ATTRNOTSUPP;
1130 attrsum += NFSX_UNSIGNED;
1132 case NFSATTRBIT_CANSETTIME:
1133 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1136 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1137 if (*tl == newnfs_false)
1138 *retcmpp = NFSERR_NOTSAME;
1140 if (*tl == newnfs_true)
1141 *retcmpp = NFSERR_NOTSAME;
1144 } else if (fsp != NULL) {
1145 if (*tl == newnfs_true)
1146 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1148 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1150 attrsum += NFSX_UNSIGNED;
1152 case NFSATTRBIT_CASEINSENSITIVE:
1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1156 if (*tl != newnfs_false)
1157 *retcmpp = NFSERR_NOTSAME;
1159 } else if (pc != NULL) {
1160 pc->pc_caseinsensitive =
1161 fxdr_unsigned(u_int32_t, *tl);
1163 attrsum += NFSX_UNSIGNED;
1165 case NFSATTRBIT_CASEPRESERVING:
1166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1169 if (*tl != newnfs_true)
1170 *retcmpp = NFSERR_NOTSAME;
1172 } else if (pc != NULL) {
1173 pc->pc_casepreserving =
1174 fxdr_unsigned(u_int32_t, *tl);
1176 attrsum += NFSX_UNSIGNED;
1178 case NFSATTRBIT_CHOWNRESTRICTED:
1179 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1182 if (*tl != newnfs_true)
1183 *retcmpp = NFSERR_NOTSAME;
1185 } else if (pc != NULL) {
1186 pc->pc_chownrestricted =
1187 fxdr_unsigned(u_int32_t, *tl);
1189 attrsum += NFSX_UNSIGNED;
1191 case NFSATTRBIT_FILEHANDLE:
1192 error = nfsm_getfh(nd, &tnfhp);
1195 tfhsize = tnfhp->nfh_len;
1198 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1200 *retcmpp = NFSERR_NOTSAME;
1201 FREE((caddr_t)tnfhp, M_NFSFH);
1202 } else if (nfhpp != NULL) {
1205 FREE((caddr_t)tnfhp, M_NFSFH);
1207 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1209 case NFSATTRBIT_FILEID:
1210 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1211 thyp = fxdr_hyper(tl);
1214 if ((u_int64_t)nap->na_fileid != thyp)
1215 *retcmpp = NFSERR_NOTSAME;
1217 } else if (nap != NULL) {
1220 if (ratecheck(&last64fileid, &warninterval)) {
1221 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1226 nap->na_fileid = thyp;
1228 attrsum += NFSX_HYPER;
1230 case NFSATTRBIT_FILESAVAIL:
1231 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1234 sfp->sf_afiles != fxdr_hyper(tl))
1235 *retcmpp = NFSERR_NOTSAME;
1236 } else if (sfp != NULL) {
1237 sfp->sf_afiles = fxdr_hyper(tl);
1239 attrsum += NFSX_HYPER;
1241 case NFSATTRBIT_FILESFREE:
1242 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1245 sfp->sf_ffiles != fxdr_hyper(tl))
1246 *retcmpp = NFSERR_NOTSAME;
1247 } else if (sfp != NULL) {
1248 sfp->sf_ffiles = fxdr_hyper(tl);
1250 attrsum += NFSX_HYPER;
1252 case NFSATTRBIT_FILESTOTAL:
1253 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1256 sfp->sf_tfiles != fxdr_hyper(tl))
1257 *retcmpp = NFSERR_NOTSAME;
1258 } else if (sfp != NULL) {
1259 sfp->sf_tfiles = fxdr_hyper(tl);
1261 attrsum += NFSX_HYPER;
1263 case NFSATTRBIT_FSLOCATIONS:
1264 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1268 if (compare && !(*retcmpp)) {
1269 refp = nfsv4root_getreferral(vp, NULL, 0);
1271 if (cp == NULL || cp2 == NULL ||
1273 strcmp(cp2, refp->nfr_srvlist))
1274 *retcmpp = NFSERR_NOTSAME;
1275 } else if (m == 0) {
1276 *retcmpp = NFSERR_NOTSAME;
1280 free(cp, M_NFSSTRING);
1282 free(cp2, M_NFSSTRING);
1284 case NFSATTRBIT_HIDDEN:
1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1286 if (compare && !(*retcmpp))
1287 *retcmpp = NFSERR_ATTRNOTSUPP;
1288 attrsum += NFSX_UNSIGNED;
1290 case NFSATTRBIT_HOMOGENEOUS:
1291 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1294 if (fsp->fs_properties &
1295 NFSV3_FSFHOMOGENEOUS) {
1296 if (*tl == newnfs_false)
1297 *retcmpp = NFSERR_NOTSAME;
1299 if (*tl == newnfs_true)
1300 *retcmpp = NFSERR_NOTSAME;
1303 } else if (fsp != NULL) {
1304 if (*tl == newnfs_true)
1305 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1307 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1309 attrsum += NFSX_UNSIGNED;
1311 case NFSATTRBIT_MAXFILESIZE:
1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1313 tnfsquad.qval = fxdr_hyper(tl);
1316 tquad = NFSRV_MAXFILESIZE;
1317 if (tquad != tnfsquad.qval)
1318 *retcmpp = NFSERR_NOTSAME;
1320 } else if (fsp != NULL) {
1321 fsp->fs_maxfilesize = tnfsquad.qval;
1323 attrsum += NFSX_HYPER;
1325 case NFSATTRBIT_MAXLINK:
1326 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1329 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1330 *retcmpp = NFSERR_NOTSAME;
1332 } else if (pc != NULL) {
1333 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1335 attrsum += NFSX_UNSIGNED;
1337 case NFSATTRBIT_MAXNAME:
1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1341 if (fsp->fs_maxname !=
1342 fxdr_unsigned(u_int32_t, *tl))
1343 *retcmpp = NFSERR_NOTSAME;
1346 tuint = fxdr_unsigned(u_int32_t, *tl);
1348 * Some Linux NFSv4 servers report this
1349 * as 0 or 4billion, so I'll set it to
1350 * NFS_MAXNAMLEN. If a server actually creates
1351 * a name longer than NFS_MAXNAMLEN, it will
1352 * get an error back.
1354 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1355 tuint = NFS_MAXNAMLEN;
1357 fsp->fs_maxname = tuint;
1359 pc->pc_namemax = tuint;
1361 attrsum += NFSX_UNSIGNED;
1363 case NFSATTRBIT_MAXREAD:
1364 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1367 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1368 *(tl + 1)) || *tl != 0)
1369 *retcmpp = NFSERR_NOTSAME;
1371 } else if (fsp != NULL) {
1372 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1373 fsp->fs_rtpref = fsp->fs_rtmax;
1374 fsp->fs_dtpref = fsp->fs_rtpref;
1376 attrsum += NFSX_HYPER;
1378 case NFSATTRBIT_MAXWRITE:
1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1382 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1383 *(tl + 1)) || *tl != 0)
1384 *retcmpp = NFSERR_NOTSAME;
1386 } else if (fsp != NULL) {
1387 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1388 fsp->fs_wtpref = fsp->fs_wtmax;
1390 attrsum += NFSX_HYPER;
1392 case NFSATTRBIT_MIMETYPE:
1393 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1394 i = fxdr_unsigned(int, *tl);
1395 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1396 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1399 if (compare && !(*retcmpp))
1400 *retcmpp = NFSERR_ATTRNOTSUPP;
1402 case NFSATTRBIT_MODE:
1403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1406 if (nap->na_mode != nfstov_mode(*tl))
1407 *retcmpp = NFSERR_NOTSAME;
1409 } else if (nap != NULL) {
1410 nap->na_mode = nfstov_mode(*tl);
1412 attrsum += NFSX_UNSIGNED;
1414 case NFSATTRBIT_NOTRUNC:
1415 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1418 if (*tl != newnfs_true)
1419 *retcmpp = NFSERR_NOTSAME;
1421 } else if (pc != NULL) {
1422 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1424 attrsum += NFSX_UNSIGNED;
1426 case NFSATTRBIT_NUMLINKS:
1427 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1428 tuint = fxdr_unsigned(u_int32_t, *tl);
1431 if ((u_int32_t)nap->na_nlink != tuint)
1432 *retcmpp = NFSERR_NOTSAME;
1434 } else if (nap != NULL) {
1435 nap->na_nlink = tuint;
1437 attrsum += NFSX_UNSIGNED;
1439 case NFSATTRBIT_OWNER:
1440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1441 j = fxdr_unsigned(int, *tl);
1443 error = NFSERR_BADXDR;
1446 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1447 if (j > NFSV4_SMALLSTR)
1448 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1451 error = nfsrv_mtostr(nd, cp, j);
1453 if (j > NFSV4_SMALLSTR)
1454 free(cp, M_NFSSTRING);
1459 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1461 *retcmpp = NFSERR_NOTSAME;
1463 } else if (nap != NULL) {
1464 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1465 nap->na_uid = nfsrv_defaultuid;
1469 if (j > NFSV4_SMALLSTR)
1470 free(cp, M_NFSSTRING);
1472 case NFSATTRBIT_OWNERGROUP:
1473 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1474 j = fxdr_unsigned(int, *tl);
1476 error = NFSERR_BADXDR;
1479 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1480 if (j > NFSV4_SMALLSTR)
1481 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1484 error = nfsrv_mtostr(nd, cp, j);
1486 if (j > NFSV4_SMALLSTR)
1487 free(cp, M_NFSSTRING);
1492 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1494 *retcmpp = NFSERR_NOTSAME;
1496 } else if (nap != NULL) {
1497 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1498 nap->na_gid = nfsrv_defaultgid;
1502 if (j > NFSV4_SMALLSTR)
1503 free(cp, M_NFSSTRING);
1505 case NFSATTRBIT_QUOTAHARD:
1506 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1508 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1509 freenum = sbp->f_bfree;
1511 freenum = sbp->f_bavail;
1514 * ufs_quotactl() insists that the uid argument
1515 * equal p_ruid for non-root quota access, so
1516 * we'll just make sure that's the case.
1518 savuid = p->p_cred->p_ruid;
1519 p->p_cred->p_ruid = cred->cr_uid;
1520 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1521 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1522 freenum = min(dqb.dqb_bhardlimit, freenum);
1523 p->p_cred->p_ruid = savuid;
1525 uquad = (u_int64_t)freenum;
1526 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1528 if (compare && !(*retcmpp)) {
1529 if (uquad != fxdr_hyper(tl))
1530 *retcmpp = NFSERR_NOTSAME;
1532 attrsum += NFSX_HYPER;
1534 case NFSATTRBIT_QUOTASOFT:
1535 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1537 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1538 freenum = sbp->f_bfree;
1540 freenum = sbp->f_bavail;
1543 * ufs_quotactl() insists that the uid argument
1544 * equal p_ruid for non-root quota access, so
1545 * we'll just make sure that's the case.
1547 savuid = p->p_cred->p_ruid;
1548 p->p_cred->p_ruid = cred->cr_uid;
1549 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1550 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1551 freenum = min(dqb.dqb_bsoftlimit, freenum);
1552 p->p_cred->p_ruid = savuid;
1554 uquad = (u_int64_t)freenum;
1555 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1557 if (compare && !(*retcmpp)) {
1558 if (uquad != fxdr_hyper(tl))
1559 *retcmpp = NFSERR_NOTSAME;
1561 attrsum += NFSX_HYPER;
1563 case NFSATTRBIT_QUOTAUSED:
1564 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1569 * ufs_quotactl() insists that the uid argument
1570 * equal p_ruid for non-root quota access, so
1571 * we'll just make sure that's the case.
1573 savuid = p->p_cred->p_ruid;
1574 p->p_cred->p_ruid = cred->cr_uid;
1575 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1576 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1577 freenum = dqb.dqb_curblocks;
1578 p->p_cred->p_ruid = savuid;
1580 uquad = (u_int64_t)freenum;
1581 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1583 if (compare && !(*retcmpp)) {
1584 if (uquad != fxdr_hyper(tl))
1585 *retcmpp = NFSERR_NOTSAME;
1587 attrsum += NFSX_HYPER;
1589 case NFSATTRBIT_RAWDEV:
1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1591 j = fxdr_unsigned(int, *tl++);
1592 k = fxdr_unsigned(int, *tl);
1595 if (nap->na_rdev != NFSMAKEDEV(j, k))
1596 *retcmpp = NFSERR_NOTSAME;
1598 } else if (nap != NULL) {
1599 nap->na_rdev = NFSMAKEDEV(j, k);
1601 attrsum += NFSX_V4SPECDATA;
1603 case NFSATTRBIT_SPACEAVAIL:
1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1607 sfp->sf_abytes != fxdr_hyper(tl))
1608 *retcmpp = NFSERR_NOTSAME;
1609 } else if (sfp != NULL) {
1610 sfp->sf_abytes = fxdr_hyper(tl);
1612 attrsum += NFSX_HYPER;
1614 case NFSATTRBIT_SPACEFREE:
1615 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1618 sfp->sf_fbytes != fxdr_hyper(tl))
1619 *retcmpp = NFSERR_NOTSAME;
1620 } else if (sfp != NULL) {
1621 sfp->sf_fbytes = fxdr_hyper(tl);
1623 attrsum += NFSX_HYPER;
1625 case NFSATTRBIT_SPACETOTAL:
1626 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1629 sfp->sf_tbytes != fxdr_hyper(tl))
1630 *retcmpp = NFSERR_NOTSAME;
1631 } else if (sfp != NULL) {
1632 sfp->sf_tbytes = fxdr_hyper(tl);
1634 attrsum += NFSX_HYPER;
1636 case NFSATTRBIT_SPACEUSED:
1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1638 thyp = fxdr_hyper(tl);
1641 if ((u_int64_t)nap->na_bytes != thyp)
1642 *retcmpp = NFSERR_NOTSAME;
1644 } else if (nap != NULL) {
1645 nap->na_bytes = thyp;
1647 attrsum += NFSX_HYPER;
1649 case NFSATTRBIT_SYSTEM:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1651 if (compare && !(*retcmpp))
1652 *retcmpp = NFSERR_ATTRNOTSUPP;
1653 attrsum += NFSX_UNSIGNED;
1655 case NFSATTRBIT_TIMEACCESS:
1656 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1657 fxdr_nfsv4time(tl, &temptime);
1660 if (!NFS_CMPTIME(temptime, nap->na_atime))
1661 *retcmpp = NFSERR_NOTSAME;
1663 } else if (nap != NULL) {
1664 nap->na_atime = temptime;
1666 attrsum += NFSX_V4TIME;
1668 case NFSATTRBIT_TIMEACCESSSET:
1669 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1670 attrsum += NFSX_UNSIGNED;
1671 i = fxdr_unsigned(int, *tl);
1672 if (i == NFSV4SATTRTIME_TOCLIENT) {
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1674 attrsum += NFSX_V4TIME;
1676 if (compare && !(*retcmpp))
1677 *retcmpp = NFSERR_INVAL;
1679 case NFSATTRBIT_TIMEBACKUP:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1681 if (compare && !(*retcmpp))
1682 *retcmpp = NFSERR_ATTRNOTSUPP;
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMECREATE:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1687 if (compare && !(*retcmpp))
1688 *retcmpp = NFSERR_ATTRNOTSUPP;
1689 attrsum += NFSX_V4TIME;
1691 case NFSATTRBIT_TIMEDELTA:
1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1696 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1697 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1698 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1699 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1702 *retcmpp = NFSERR_NOTSAME;
1705 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1708 attrsum += NFSX_V4TIME;
1710 case NFSATTRBIT_TIMEMETADATA:
1711 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1712 fxdr_nfsv4time(tl, &temptime);
1715 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1716 *retcmpp = NFSERR_NOTSAME;
1718 } else if (nap != NULL) {
1719 nap->na_ctime = temptime;
1721 attrsum += NFSX_V4TIME;
1723 case NFSATTRBIT_TIMEMODIFY:
1724 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1725 fxdr_nfsv4time(tl, &temptime);
1728 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1729 *retcmpp = NFSERR_NOTSAME;
1731 } else if (nap != NULL) {
1732 nap->na_mtime = temptime;
1734 attrsum += NFSX_V4TIME;
1736 case NFSATTRBIT_TIMEMODIFYSET:
1737 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1738 attrsum += NFSX_UNSIGNED;
1739 i = fxdr_unsigned(int, *tl);
1740 if (i == NFSV4SATTRTIME_TOCLIENT) {
1741 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1742 attrsum += NFSX_V4TIME;
1744 if (compare && !(*retcmpp))
1745 *retcmpp = NFSERR_INVAL;
1747 case NFSATTRBIT_MOUNTEDONFILEID:
1748 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1749 thyp = fxdr_hyper(tl);
1753 *retcmpp = NFSERR_NOTSAME;
1755 if (!vp || !nfsrv_atroot(vp, &fid))
1756 fid = nap->na_fileid;
1757 if ((u_int64_t)fid != thyp)
1758 *retcmpp = NFSERR_NOTSAME;
1761 } else if (nap != NULL) {
1763 count64mountfileid++;
1764 if (ratecheck(&last64mountfileid, &warninterval)) {
1765 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1766 count64mountfileid);
1767 count64mountfileid = 0;
1770 nap->na_mntonfileno = thyp;
1772 attrsum += NFSX_HYPER;
1774 case NFSATTRBIT_SUPPATTREXCLCREAT:
1776 error = nfsrv_getattrbits(nd, &retattrbits,
1780 if (compare && !(*retcmpp)) {
1781 NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1782 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
1783 NFSCLRBIT_ATTRBIT(&checkattrbits,
1784 NFSATTRBIT_TIMEACCESSSET);
1785 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1787 *retcmpp = NFSERR_NOTSAME;
1792 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1794 if (compare && !(*retcmpp))
1795 *retcmpp = NFSERR_ATTRNOTSUPP;
1797 * and get out of the loop, since we can't parse
1798 * the unknown attrbute data.
1800 bitpos = NFSATTRBIT_MAX;
1806 * some clients pad the attrlist, so we need to skip over the
1809 if (attrsum > attrsize) {
1810 error = NFSERR_BADXDR;
1812 attrsize = NFSM_RNDUP(attrsize);
1813 if (attrsum < attrsize)
1814 error = nfsm_advance(nd, attrsize - attrsum, -1);
1817 NFSEXITCODE2(error, nd);
1822 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1823 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1824 * The first argument is a pointer to an nfsv4lock structure.
1825 * The second argument is 1 iff a blocking lock is wanted.
1826 * If this argument is 0, the call waits until no thread either wants nor
1827 * holds an exclusive lock.
1828 * It returns 1 if the lock was acquired, 0 otherwise.
1829 * If several processes call this function concurrently wanting the exclusive
1830 * lock, one will get the lock and the rest will return without getting the
1831 * lock. (If the caller must have the lock, it simply calls this function in a
1832 * loop until the function returns 1 to indicate the lock was acquired.)
1833 * Any usecnt must be decremented by calling nfsv4_relref() before
1834 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1835 * be called in a loop.
1836 * The isleptp argument is set to indicate if the call slept, iff not NULL
1837 * and the mp argument indicates to check for a forced dismount, iff not
1841 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1842 void *mutex, struct mount *mp)
1848 * If a lock is wanted, loop around until the lock is acquired by
1849 * someone and then released. If I want the lock, try to acquire it.
1850 * For a lock to be issued, no lock must be in force and the usecnt
1854 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1855 lp->nfslock_usecnt == 0) {
1856 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1857 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1860 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1862 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1863 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1864 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1867 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1870 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1871 PZERO - 1, "nfsv4lck", NULL);
1872 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1873 lp->nfslock_usecnt == 0) {
1874 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1875 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1883 * Release the lock acquired by nfsv4_lock().
1884 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1885 * incremented, as well.
1888 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1891 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1893 lp->nfslock_usecnt++;
1898 * Release a reference cnt.
1901 nfsv4_relref(struct nfsv4lock *lp)
1904 if (lp->nfslock_usecnt <= 0)
1905 panic("nfsv4root ref cnt");
1906 lp->nfslock_usecnt--;
1907 if (lp->nfslock_usecnt == 0)
1912 * Get a reference cnt.
1913 * This function will wait for any exclusive lock to be released, but will
1914 * not wait for threads that want the exclusive lock. If priority needs
1915 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1916 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1917 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1918 * return without getting a refcnt for that case.
1921 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1929 * Wait for a lock held.
1931 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1932 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1934 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1937 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1938 PZERO - 1, "nfsv4gr", NULL);
1940 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1943 lp->nfslock_usecnt++;
1947 * Get a reference as above, but return failure instead of sleeping if
1948 * an exclusive lock is held.
1951 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1954 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1957 lp->nfslock_usecnt++;
1962 * Test for a lock. Return 1 if locked, 0 otherwise.
1965 nfsv4_testlock(struct nfsv4lock *lp)
1968 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1969 lp->nfslock_usecnt == 0)
1975 * Wake up anyone sleeping, waiting for this lock.
1978 nfsv4_wanted(struct nfsv4lock *lp)
1981 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1982 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1983 wakeup((caddr_t)&lp->nfslock_lock);
1988 * Copy a string from an mbuf list into a character array.
1989 * Return EBADRPC if there is an mbuf error,
1993 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2002 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2003 rem = NFSM_RNDUP(siz) - siz;
2009 NFSBCOPY(cp, str, xfer);
2018 cp = NFSMTOD(mp, caddr_t);
2030 error = nfsm_advance(nd, rem, len);
2036 NFSEXITCODE2(error, nd);
2041 * Fill in the attributes as marked by the bitmap (V4).
2044 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2045 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2046 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2047 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2049 int bitpos, retnum = 0;
2051 int siz, prefixnum, error;
2052 u_char *cp, namestr[NFSV4_SMALLSTR];
2053 nfsattrbit_t attrbits, retbits;
2054 nfsattrbit_t *retbitp = &retbits;
2055 u_int32_t freenum, *retnump;
2058 struct nfsfsinfo fsinf;
2059 struct timespec temptime;
2060 NFSACL_T *aclp, *naclp = NULL;
2067 * First, set the bits that can be filled and get fsinfo.
2069 NFSSET_ATTRBIT(retbitp, attrbitp);
2071 * If both p and cred are NULL, it is a client side setattr call.
2072 * If both p and cred are not NULL, it is a server side reply call.
2073 * If p is not NULL and cred is NULL, it is a client side callback
2076 if (p == NULL && cred == NULL) {
2077 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2080 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2081 naclp = acl_alloc(M_WAITOK);
2084 nfsvno_getfs(&fsinf, isdgram);
2087 * Get the VFS_STATFS(), since some attributes need them.
2089 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2090 error = VFS_STATFS(mp, &fs);
2093 nd->nd_repstat = NFSERR_ACCES;
2096 NFSCLRSTATFS_ATTRBIT(retbitp);
2102 * And the NFSv4 ACL...
2104 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2105 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2106 supports_nfsv4acls == 0))) {
2107 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2109 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2110 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2111 supports_nfsv4acls == 0)) {
2112 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2113 } else if (naclp != NULL) {
2114 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2115 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2117 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2119 NFSVOPUNLOCK(vp, 0);
2121 error = NFSERR_PERM;
2124 nd->nd_repstat = NFSERR_ACCES;
2127 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2132 * Put out the attribute bitmap for the ones being filled in
2133 * and get the field for the number of attributes returned.
2135 prefixnum = nfsrv_putattrbit(nd, retbitp);
2136 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2137 prefixnum += NFSX_UNSIGNED;
2140 * Now, loop around filling in the attributes for each bit set.
2142 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2143 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2145 case NFSATTRBIT_SUPPORTEDATTRS:
2146 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2147 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2148 && supports_nfsv4acls == 0)) {
2149 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2150 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2152 retnum += nfsrv_putattrbit(nd, &attrbits);
2154 case NFSATTRBIT_TYPE:
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2156 *tl = vtonfsv34_type(vap->va_type);
2157 retnum += NFSX_UNSIGNED;
2159 case NFSATTRBIT_FHEXPIRETYPE:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2161 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2162 retnum += NFSX_UNSIGNED;
2164 case NFSATTRBIT_CHANGE:
2165 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2166 txdr_hyper(vap->va_filerev, tl);
2167 retnum += NFSX_HYPER;
2169 case NFSATTRBIT_SIZE:
2170 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2171 txdr_hyper(vap->va_size, tl);
2172 retnum += NFSX_HYPER;
2174 case NFSATTRBIT_LINKSUPPORT:
2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2176 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2180 retnum += NFSX_UNSIGNED;
2182 case NFSATTRBIT_SYMLINKSUPPORT:
2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2184 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2188 retnum += NFSX_UNSIGNED;
2190 case NFSATTRBIT_NAMEDATTR:
2191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2193 retnum += NFSX_UNSIGNED;
2195 case NFSATTRBIT_FSID:
2196 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2198 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2200 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2201 retnum += NFSX_V4FSID;
2203 case NFSATTRBIT_UNIQUEHANDLES:
2204 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2206 retnum += NFSX_UNSIGNED;
2208 case NFSATTRBIT_LEASETIME:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2210 *tl = txdr_unsigned(nfsrv_lease);
2211 retnum += NFSX_UNSIGNED;
2213 case NFSATTRBIT_RDATTRERROR:
2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2215 *tl = txdr_unsigned(rderror);
2216 retnum += NFSX_UNSIGNED;
2219 * Recommended Attributes. (Only the supported ones.)
2221 case NFSATTRBIT_ACL:
2222 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2224 case NFSATTRBIT_ACLSUPPORT:
2225 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2226 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2227 retnum += NFSX_UNSIGNED;
2229 case NFSATTRBIT_CANSETTIME:
2230 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2231 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2235 retnum += NFSX_UNSIGNED;
2237 case NFSATTRBIT_CASEINSENSITIVE:
2238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2240 retnum += NFSX_UNSIGNED;
2242 case NFSATTRBIT_CASEPRESERVING:
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2245 retnum += NFSX_UNSIGNED;
2247 case NFSATTRBIT_CHOWNRESTRICTED:
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2250 retnum += NFSX_UNSIGNED;
2252 case NFSATTRBIT_FILEHANDLE:
2253 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2255 case NFSATTRBIT_FILEID:
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2258 *tl = txdr_unsigned(vap->va_fileid);
2259 retnum += NFSX_HYPER;
2261 case NFSATTRBIT_FILESAVAIL:
2263 * Check quota and use min(quota, f_ffree).
2265 freenum = fs.f_ffree;
2268 * ufs_quotactl() insists that the uid argument
2269 * equal p_ruid for non-root quota access, so
2270 * we'll just make sure that's the case.
2272 savuid = p->p_cred->p_ruid;
2273 p->p_cred->p_ruid = cred->cr_uid;
2274 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2275 cred->cr_uid, (caddr_t)&dqb))
2276 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2278 p->p_cred->p_ruid = savuid;
2280 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2282 *tl = txdr_unsigned(freenum);
2283 retnum += NFSX_HYPER;
2285 case NFSATTRBIT_FILESFREE:
2286 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2288 *tl = txdr_unsigned(fs.f_ffree);
2289 retnum += NFSX_HYPER;
2291 case NFSATTRBIT_FILESTOTAL:
2292 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2294 *tl = txdr_unsigned(fs.f_files);
2295 retnum += NFSX_HYPER;
2297 case NFSATTRBIT_FSLOCATIONS:
2298 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2301 retnum += 2 * NFSX_UNSIGNED;
2303 case NFSATTRBIT_HOMOGENEOUS:
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2305 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2309 retnum += NFSX_UNSIGNED;
2311 case NFSATTRBIT_MAXFILESIZE:
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2313 uquad = NFSRV_MAXFILESIZE;
2314 txdr_hyper(uquad, tl);
2315 retnum += NFSX_HYPER;
2317 case NFSATTRBIT_MAXLINK:
2318 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2319 *tl = txdr_unsigned(LINK_MAX);
2320 retnum += NFSX_UNSIGNED;
2322 case NFSATTRBIT_MAXNAME:
2323 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2324 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2325 retnum += NFSX_UNSIGNED;
2327 case NFSATTRBIT_MAXREAD:
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2330 *tl = txdr_unsigned(fsinf.fs_rtmax);
2331 retnum += NFSX_HYPER;
2333 case NFSATTRBIT_MAXWRITE:
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2336 *tl = txdr_unsigned(fsinf.fs_wtmax);
2337 retnum += NFSX_HYPER;
2339 case NFSATTRBIT_MODE:
2340 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2341 *tl = vtonfsv34_mode(vap->va_mode);
2342 retnum += NFSX_UNSIGNED;
2344 case NFSATTRBIT_NOTRUNC:
2345 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2347 retnum += NFSX_UNSIGNED;
2349 case NFSATTRBIT_NUMLINKS:
2350 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2351 *tl = txdr_unsigned(vap->va_nlink);
2352 retnum += NFSX_UNSIGNED;
2354 case NFSATTRBIT_OWNER:
2356 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2357 retnum += nfsm_strtom(nd, cp, siz);
2359 free(cp, M_NFSSTRING);
2361 case NFSATTRBIT_OWNERGROUP:
2363 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2364 retnum += nfsm_strtom(nd, cp, siz);
2366 free(cp, M_NFSSTRING);
2368 case NFSATTRBIT_QUOTAHARD:
2369 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2370 freenum = fs.f_bfree;
2372 freenum = fs.f_bavail;
2375 * ufs_quotactl() insists that the uid argument
2376 * equal p_ruid for non-root quota access, so
2377 * we'll just make sure that's the case.
2379 savuid = p->p_cred->p_ruid;
2380 p->p_cred->p_ruid = cred->cr_uid;
2381 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2382 cred->cr_uid, (caddr_t)&dqb))
2383 freenum = min(dqb.dqb_bhardlimit, freenum);
2384 p->p_cred->p_ruid = savuid;
2386 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2387 uquad = (u_int64_t)freenum;
2388 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2389 txdr_hyper(uquad, tl);
2390 retnum += NFSX_HYPER;
2392 case NFSATTRBIT_QUOTASOFT:
2393 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2394 freenum = fs.f_bfree;
2396 freenum = fs.f_bavail;
2399 * ufs_quotactl() insists that the uid argument
2400 * equal p_ruid for non-root quota access, so
2401 * we'll just make sure that's the case.
2403 savuid = p->p_cred->p_ruid;
2404 p->p_cred->p_ruid = cred->cr_uid;
2405 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2406 cred->cr_uid, (caddr_t)&dqb))
2407 freenum = min(dqb.dqb_bsoftlimit, freenum);
2408 p->p_cred->p_ruid = savuid;
2410 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2411 uquad = (u_int64_t)freenum;
2412 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2413 txdr_hyper(uquad, tl);
2414 retnum += NFSX_HYPER;
2416 case NFSATTRBIT_QUOTAUSED:
2420 * ufs_quotactl() insists that the uid argument
2421 * equal p_ruid for non-root quota access, so
2422 * we'll just make sure that's the case.
2424 savuid = p->p_cred->p_ruid;
2425 p->p_cred->p_ruid = cred->cr_uid;
2426 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2427 cred->cr_uid, (caddr_t)&dqb))
2428 freenum = dqb.dqb_curblocks;
2429 p->p_cred->p_ruid = savuid;
2431 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2432 uquad = (u_int64_t)freenum;
2433 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2434 txdr_hyper(uquad, tl);
2435 retnum += NFSX_HYPER;
2437 case NFSATTRBIT_RAWDEV:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2439 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2440 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2441 retnum += NFSX_V4SPECDATA;
2443 case NFSATTRBIT_SPACEAVAIL:
2444 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2445 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2446 uquad = (u_int64_t)fs.f_bfree;
2448 uquad = (u_int64_t)fs.f_bavail;
2449 uquad *= fs.f_bsize;
2450 txdr_hyper(uquad, tl);
2451 retnum += NFSX_HYPER;
2453 case NFSATTRBIT_SPACEFREE:
2454 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2455 uquad = (u_int64_t)fs.f_bfree;
2456 uquad *= fs.f_bsize;
2457 txdr_hyper(uquad, tl);
2458 retnum += NFSX_HYPER;
2460 case NFSATTRBIT_SPACETOTAL:
2461 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2462 uquad = (u_int64_t)fs.f_blocks;
2463 uquad *= fs.f_bsize;
2464 txdr_hyper(uquad, tl);
2465 retnum += NFSX_HYPER;
2467 case NFSATTRBIT_SPACEUSED:
2468 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2469 txdr_hyper(vap->va_bytes, tl);
2470 retnum += NFSX_HYPER;
2472 case NFSATTRBIT_TIMEACCESS:
2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2474 txdr_nfsv4time(&vap->va_atime, tl);
2475 retnum += NFSX_V4TIME;
2477 case NFSATTRBIT_TIMEACCESSSET:
2478 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2479 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2480 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2481 txdr_nfsv4time(&vap->va_atime, tl);
2482 retnum += NFSX_V4SETTIME;
2484 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2485 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2486 retnum += NFSX_UNSIGNED;
2489 case NFSATTRBIT_TIMEDELTA:
2490 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2491 temptime.tv_sec = 0;
2492 temptime.tv_nsec = 1000000000 / hz;
2493 txdr_nfsv4time(&temptime, tl);
2494 retnum += NFSX_V4TIME;
2496 case NFSATTRBIT_TIMEMETADATA:
2497 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2498 txdr_nfsv4time(&vap->va_ctime, tl);
2499 retnum += NFSX_V4TIME;
2501 case NFSATTRBIT_TIMEMODIFY:
2502 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2503 txdr_nfsv4time(&vap->va_mtime, tl);
2504 retnum += NFSX_V4TIME;
2506 case NFSATTRBIT_TIMEMODIFYSET:
2507 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2508 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2509 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2510 txdr_nfsv4time(&vap->va_mtime, tl);
2511 retnum += NFSX_V4SETTIME;
2513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2514 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2515 retnum += NFSX_UNSIGNED;
2518 case NFSATTRBIT_MOUNTEDONFILEID:
2519 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2521 uquad = mounted_on_fileno;
2523 uquad = (u_int64_t)vap->va_fileid;
2524 txdr_hyper(uquad, tl);
2525 retnum += NFSX_HYPER;
2527 case NFSATTRBIT_SUPPATTREXCLCREAT:
2528 NFSSETSUPP_ATTRBIT(&attrbits, nd);
2529 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2530 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2531 retnum += nfsrv_putattrbit(nd, &attrbits);
2534 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2540 *retnump = txdr_unsigned(retnum);
2541 return (retnum + prefixnum);
2545 * Put the attribute bits onto an mbuf list.
2546 * Return the number of bytes of output generated.
2549 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2552 int cnt, i, bytesize;
2554 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2555 if (attrbitp->bits[cnt - 1])
2557 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2558 NFSM_BUILD(tl, u_int32_t *, bytesize);
2559 *tl++ = txdr_unsigned(cnt);
2560 for (i = 0; i < cnt; i++)
2561 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2566 * Convert a uid to a string.
2567 * If the lookup fails, just output the digits.
2569 * cpp - points to a buffer of size NFSV4_SMALLSTR
2570 * (malloc a larger one, as required)
2571 * retlenp - pointer to length to be returned
2574 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2577 struct nfsusrgrp *usrp;
2580 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2581 struct nfsrv_lughash *hp;
2585 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2587 * Always map nfsrv_defaultuid to "nobody".
2589 if (uid == nfsrv_defaultuid) {
2590 i = nfsrv_dnsnamelen + 7;
2592 if (len > NFSV4_SMALLSTR)
2593 free(cp, M_NFSSTRING);
2594 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2600 NFSBCOPY("nobody@", cp, 7);
2602 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2606 hp = NFSUSERHASH(uid);
2608 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2609 if (usrp->lug_uid == uid) {
2610 if (usrp->lug_expiry < NFSD_MONOSEC)
2613 * If the name doesn't already have an '@'
2614 * in it, append @domainname to it.
2616 for (i = 0; i < usrp->lug_namelen; i++) {
2617 if (usrp->lug_name[i] == '@') {
2623 i = usrp->lug_namelen;
2625 i = usrp->lug_namelen +
2626 nfsrv_dnsnamelen + 1;
2628 mtx_unlock(&hp->mtx);
2629 if (len > NFSV4_SMALLSTR)
2630 free(cp, M_NFSSTRING);
2631 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2637 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2638 if (!hasampersand) {
2639 cp += usrp->lug_namelen;
2641 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2643 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2644 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2646 mtx_unlock(&hp->mtx);
2650 mtx_unlock(&hp->mtx);
2652 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2654 if (ret == 0 && cnt < 2)
2659 * No match, just return a string of digits.
2663 while (tmp || i == 0) {
2667 len = (i > len) ? len : i;
2671 for (i = 0; i < len; i++) {
2672 *cp-- = '0' + (tmp % 10);
2679 * Get a credential for the uid with the server's group list.
2680 * If none is found, just return the credential passed in after
2681 * logging a warning message.
2684 nfsrv_getgrpscred(struct ucred *oldcred)
2686 struct nfsusrgrp *usrp;
2687 struct ucred *newcred;
2690 struct nfsrv_lughash *hp;
2693 uid = oldcred->cr_uid;
2695 if (nfsrv_dnsnamelen > 0) {
2696 hp = NFSUSERHASH(uid);
2698 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2699 if (usrp->lug_uid == uid) {
2700 if (usrp->lug_expiry < NFSD_MONOSEC)
2702 if (usrp->lug_cred != NULL) {
2703 newcred = crhold(usrp->lug_cred);
2707 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2708 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2710 mtx_unlock(&hp->mtx);
2714 mtx_unlock(&hp->mtx);
2716 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2718 if (ret == 0 && cnt < 2)
2725 * Convert a string to a uid.
2726 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2728 * If this is called from a client side mount using AUTH_SYS and the
2729 * string is made up entirely of digits, just convert the string to
2733 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2737 char *cp, *endstr, *str0;
2738 struct nfsusrgrp *usrp;
2742 struct nfsrv_lughash *hp, *hp2;
2745 error = NFSERR_BADOWNER;
2748 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2750 tuid = (uid_t)strtoul(str0, &endstr, 10);
2751 if ((endstr - str0) == len) {
2752 /* A numeric string. */
2753 if ((nd->nd_flag & ND_KERBV) == 0 &&
2754 ((nd->nd_flag & ND_NFSCL) != 0 ||
2755 nfsd_enable_stringtouid != 0))
2758 error = NFSERR_BADOWNER;
2764 cp = strchr(str0, '@');
2766 i = (int)(cp++ - str0);
2772 if (nfsrv_dnsnamelen > 0) {
2774 * If an '@' is found and the domain name matches, search for
2775 * the name with dns stripped off.
2776 * Mixed case alpahbetics will match for the domain name, but
2777 * all upper case will not.
2779 if (cnt == 0 && i < len && i > 0 &&
2780 (len - 1 - i) == nfsrv_dnsnamelen &&
2781 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2782 len -= (nfsrv_dnsnamelen + 1);
2787 * Check for the special case of "nobody".
2789 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2790 *uidp = nfsrv_defaultuid;
2795 hp = NFSUSERNAMEHASH(str, len);
2797 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2798 if (usrp->lug_namelen == len &&
2799 !NFSBCMP(usrp->lug_name, str, len)) {
2800 if (usrp->lug_expiry < NFSD_MONOSEC)
2802 hp2 = NFSUSERHASH(usrp->lug_uid);
2803 mtx_lock(&hp2->mtx);
2804 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2805 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2807 *uidp = usrp->lug_uid;
2808 mtx_unlock(&hp2->mtx);
2809 mtx_unlock(&hp->mtx);
2814 mtx_unlock(&hp->mtx);
2816 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2818 if (ret == 0 && cnt < 2)
2821 error = NFSERR_BADOWNER;
2829 * Convert a gid to a string.
2830 * gid - the group id
2831 * cpp - points to a buffer of size NFSV4_SMALLSTR
2832 * (malloc a larger one, as required)
2833 * retlenp - pointer to length to be returned
2836 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2839 struct nfsusrgrp *usrp;
2842 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2843 struct nfsrv_lughash *hp;
2847 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2849 * Always map nfsrv_defaultgid to "nogroup".
2851 if (gid == nfsrv_defaultgid) {
2852 i = nfsrv_dnsnamelen + 8;
2854 if (len > NFSV4_SMALLSTR)
2855 free(cp, M_NFSSTRING);
2856 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2862 NFSBCOPY("nogroup@", cp, 8);
2864 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2868 hp = NFSGROUPHASH(gid);
2870 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2871 if (usrp->lug_gid == gid) {
2872 if (usrp->lug_expiry < NFSD_MONOSEC)
2875 * If the name doesn't already have an '@'
2876 * in it, append @domainname to it.
2878 for (i = 0; i < usrp->lug_namelen; i++) {
2879 if (usrp->lug_name[i] == '@') {
2885 i = usrp->lug_namelen;
2887 i = usrp->lug_namelen +
2888 nfsrv_dnsnamelen + 1;
2890 mtx_unlock(&hp->mtx);
2891 if (len > NFSV4_SMALLSTR)
2892 free(cp, M_NFSSTRING);
2893 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2899 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2900 if (!hasampersand) {
2901 cp += usrp->lug_namelen;
2903 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2905 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2906 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2908 mtx_unlock(&hp->mtx);
2912 mtx_unlock(&hp->mtx);
2914 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2916 if (ret == 0 && cnt < 2)
2921 * No match, just return a string of digits.
2925 while (tmp || i == 0) {
2929 len = (i > len) ? len : i;
2933 for (i = 0; i < len; i++) {
2934 *cp-- = '0' + (tmp % 10);
2941 * Convert a string to a gid.
2942 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2944 * If this is called from a client side mount using AUTH_SYS and the
2945 * string is made up entirely of digits, just convert the string to
2949 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2953 char *cp, *endstr, *str0;
2954 struct nfsusrgrp *usrp;
2958 struct nfsrv_lughash *hp, *hp2;
2961 error = NFSERR_BADOWNER;
2964 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2966 tgid = (gid_t)strtoul(str0, &endstr, 10);
2967 if ((endstr - str0) == len) {
2968 /* A numeric string. */
2969 if ((nd->nd_flag & ND_KERBV) == 0 &&
2970 ((nd->nd_flag & ND_NFSCL) != 0 ||
2971 nfsd_enable_stringtouid != 0))
2974 error = NFSERR_BADOWNER;
2980 cp = strchr(str0, '@');
2982 i = (int)(cp++ - str0);
2988 if (nfsrv_dnsnamelen > 0) {
2990 * If an '@' is found and the dns name matches, search for the
2991 * name with the dns stripped off.
2993 if (cnt == 0 && i < len && i > 0 &&
2994 (len - 1 - i) == nfsrv_dnsnamelen &&
2995 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2996 len -= (nfsrv_dnsnamelen + 1);
3001 * Check for the special case of "nogroup".
3003 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3004 *gidp = nfsrv_defaultgid;
3009 hp = NFSGROUPNAMEHASH(str, len);
3011 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3012 if (usrp->lug_namelen == len &&
3013 !NFSBCMP(usrp->lug_name, str, len)) {
3014 if (usrp->lug_expiry < NFSD_MONOSEC)
3016 hp2 = NFSGROUPHASH(usrp->lug_gid);
3017 mtx_lock(&hp2->mtx);
3018 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3019 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3021 *gidp = usrp->lug_gid;
3022 mtx_unlock(&hp2->mtx);
3023 mtx_unlock(&hp->mtx);
3028 mtx_unlock(&hp->mtx);
3030 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3032 if (ret == 0 && cnt < 2)
3035 error = NFSERR_BADOWNER;
3043 * Cmp len chars, allowing mixed case in the first argument to match lower
3044 * case in the second, but not if the first argument is all upper case.
3045 * Return 0 for a match, 1 otherwise.
3048 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3054 for (i = 0; i < len; i++) {
3055 if (*cp >= 'A' && *cp <= 'Z') {
3056 tmp = *cp++ + ('a' - 'A');
3059 if (tmp >= 'a' && tmp <= 'z')
3072 * Set the port for the nfsuserd.
3075 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3077 struct nfssockreq *rp;
3079 struct sockaddr_in *ad;
3082 struct sockaddr_in6 *ad6;
3083 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3088 if (nfsrv_nfsuserd) {
3096 * Set up the socket record and connect.
3098 rp = &nfsrv_nfsuserdsock;
3099 rp->nr_client = NULL;
3100 rp->nr_sotype = SOCK_DGRAM;
3101 rp->nr_soproto = IPPROTO_UDP;
3102 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3104 rp->nr_prog = RPCPROG_NFSUSERD;
3106 switch (nargs->nuserd_family) {
3109 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3111 ad = (struct sockaddr_in *)rp->nr_nam;
3112 ad->sin_len = sizeof(struct sockaddr_in);
3113 ad->sin_family = AF_INET;
3114 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3115 ad->sin_port = nargs->nuserd_port;
3120 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3122 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3123 ad6->sin6_len = sizeof(struct sockaddr_in6);
3124 ad6->sin6_family = AF_INET6;
3125 ad6->sin6_addr = in6loopback;
3126 ad6->sin6_port = nargs->nuserd_port;
3132 rp->nr_vers = RPCNFSUSERD_VERS;
3134 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3136 free(rp->nr_nam, M_SONAME);
3145 * Delete the nfsuserd port.
3148 nfsrv_nfsuserddelport(void)
3152 if (nfsrv_nfsuserd == 0) {
3158 newnfs_disconnect(&nfsrv_nfsuserdsock);
3159 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3163 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3165 * Returns 0 upon success, non-zero otherwise.
3168 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3171 struct nfsrv_descript *nd;
3173 struct nfsrv_descript nfsd;
3178 if (nfsrv_nfsuserd == 0) {
3185 cred = newnfs_getcred();
3186 nd->nd_flag = ND_GSSINITREPLY;
3189 nd->nd_procnum = procnum;
3190 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3192 if (procnum == RPCNFSUSERD_GETUID)
3193 *tl = txdr_unsigned(uid);
3195 *tl = txdr_unsigned(gid);
3198 (void) nfsm_strtom(nd, name, len);
3200 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3201 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3204 mbuf_freem(nd->nd_mrep);
3205 error = nd->nd_repstat;
3213 * This function is called from the nfssvc(2) system call, to update the
3214 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3217 nfssvc_idname(struct nfsd_idargs *nidp)
3219 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3220 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3221 int i, group_locked, groupname_locked, user_locked, username_locked;
3226 static int onethread = 0;
3227 static time_t lasttime = 0;
3229 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3233 if (nidp->nid_flag & NFSID_INITIALIZE) {
3234 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3235 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3238 free(cp, M_NFSSTRING);
3241 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3243 * Free up all the old stuff and reinitialize hash
3244 * lists. All mutexes for both lists must be locked,
3245 * with the user/group name ones before the uid/gid
3246 * ones, to avoid a LOR.
3248 for (i = 0; i < nfsrv_lughashsize; i++)
3249 mtx_lock(&nfsusernamehash[i].mtx);
3250 for (i = 0; i < nfsrv_lughashsize; i++)
3251 mtx_lock(&nfsuserhash[i].mtx);
3252 for (i = 0; i < nfsrv_lughashsize; i++)
3253 TAILQ_FOREACH_SAFE(usrp,
3254 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3255 nfsrv_removeuser(usrp, 1);
3256 for (i = 0; i < nfsrv_lughashsize; i++)
3257 mtx_unlock(&nfsuserhash[i].mtx);
3258 for (i = 0; i < nfsrv_lughashsize; i++)
3259 mtx_unlock(&nfsusernamehash[i].mtx);
3260 for (i = 0; i < nfsrv_lughashsize; i++)
3261 mtx_lock(&nfsgroupnamehash[i].mtx);
3262 for (i = 0; i < nfsrv_lughashsize; i++)
3263 mtx_lock(&nfsgrouphash[i].mtx);
3264 for (i = 0; i < nfsrv_lughashsize; i++)
3265 TAILQ_FOREACH_SAFE(usrp,
3266 &nfsgrouphash[i].lughead, lug_numhash,
3268 nfsrv_removeuser(usrp, 0);
3269 for (i = 0; i < nfsrv_lughashsize; i++)
3270 mtx_unlock(&nfsgrouphash[i].mtx);
3271 for (i = 0; i < nfsrv_lughashsize; i++)
3272 mtx_unlock(&nfsgroupnamehash[i].mtx);
3273 free(nfsrv_dnsname, M_NFSSTRING);
3274 nfsrv_dnsname = NULL;
3276 if (nfsuserhash == NULL) {
3277 /* Allocate the hash tables. */
3278 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3279 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3281 for (i = 0; i < nfsrv_lughashsize; i++)
3282 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3283 NULL, MTX_DEF | MTX_DUPOK);
3284 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3285 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3287 for (i = 0; i < nfsrv_lughashsize; i++)
3288 mtx_init(&nfsusernamehash[i].mtx,
3289 "nfsusrhash", NULL, MTX_DEF |
3291 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3292 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3294 for (i = 0; i < nfsrv_lughashsize; i++)
3295 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3296 NULL, MTX_DEF | MTX_DUPOK);
3297 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3298 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3300 for (i = 0; i < nfsrv_lughashsize; i++)
3301 mtx_init(&nfsgroupnamehash[i].mtx,
3302 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3304 /* (Re)initialize the list heads. */
3305 for (i = 0; i < nfsrv_lughashsize; i++)
3306 TAILQ_INIT(&nfsuserhash[i].lughead);
3307 for (i = 0; i < nfsrv_lughashsize; i++)
3308 TAILQ_INIT(&nfsusernamehash[i].lughead);
3309 for (i = 0; i < nfsrv_lughashsize; i++)
3310 TAILQ_INIT(&nfsgrouphash[i].lughead);
3311 for (i = 0; i < nfsrv_lughashsize; i++)
3312 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3315 * Put name in "DNS" string.
3318 nfsrv_defaultuid = nidp->nid_uid;
3319 nfsrv_defaultgid = nidp->nid_gid;
3321 nfsrv_usermax = nidp->nid_usermax;
3322 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3327 * malloc the new one now, so any potential sleep occurs before
3328 * manipulation of the lists.
3330 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3331 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3332 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3334 if (error == 0 && nidp->nid_ngroup > 0 &&
3335 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3336 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3338 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3339 sizeof(gid_t) * nidp->nid_ngroup);
3342 * Create a credential just like svc_getcred(),
3343 * but using the group list provided.
3346 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3347 crsetgroups(cr, nidp->nid_ngroup, grps);
3348 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3349 cr->cr_prison = &prison0;
3350 prison_hold(cr->cr_prison);
3352 mac_cred_associate_nfsd(cr);
3354 newusrp->lug_cred = cr;
3359 free(newusrp, M_NFSUSERGROUP);
3362 newusrp->lug_namelen = nidp->nid_namelen;
3365 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3366 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3367 * The flags user_locked, username_locked, group_locked and
3368 * groupname_locked are set to indicate all of those hash lists are
3369 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3370 * the respective one mutex is locked.
3372 user_locked = username_locked = group_locked = groupname_locked = 0;
3373 hp_name = hp_idnum = NULL;
3376 * Delete old entries, as required.
3378 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3379 /* Must lock all username hash lists first, to avoid a LOR. */
3380 for (i = 0; i < nfsrv_lughashsize; i++)
3381 mtx_lock(&nfsusernamehash[i].mtx);
3382 username_locked = 1;
3383 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3384 mtx_lock(&hp_idnum->mtx);
3385 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3387 if (usrp->lug_uid == nidp->nid_uid)
3388 nfsrv_removeuser(usrp, 1);
3390 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3391 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3392 newusrp->lug_namelen);
3393 mtx_lock(&hp_name->mtx);
3394 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3396 if (usrp->lug_namelen == newusrp->lug_namelen &&
3397 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3398 usrp->lug_namelen)) {
3399 thp = NFSUSERHASH(usrp->lug_uid);
3400 mtx_lock(&thp->mtx);
3401 nfsrv_removeuser(usrp, 1);
3402 mtx_unlock(&thp->mtx);
3405 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3406 mtx_lock(&hp_idnum->mtx);
3407 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3408 /* Must lock all groupname hash lists first, to avoid a LOR. */
3409 for (i = 0; i < nfsrv_lughashsize; i++)
3410 mtx_lock(&nfsgroupnamehash[i].mtx);
3411 groupname_locked = 1;
3412 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3413 mtx_lock(&hp_idnum->mtx);
3414 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3416 if (usrp->lug_gid == nidp->nid_gid)
3417 nfsrv_removeuser(usrp, 0);
3419 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3420 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3421 newusrp->lug_namelen);
3422 mtx_lock(&hp_name->mtx);
3423 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3425 if (usrp->lug_namelen == newusrp->lug_namelen &&
3426 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3427 usrp->lug_namelen)) {
3428 thp = NFSGROUPHASH(usrp->lug_gid);
3429 mtx_lock(&thp->mtx);
3430 nfsrv_removeuser(usrp, 0);
3431 mtx_unlock(&thp->mtx);
3434 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3435 mtx_lock(&hp_idnum->mtx);
3439 * Now, we can add the new one.
3441 if (nidp->nid_usertimeout)
3442 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3444 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3445 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3446 newusrp->lug_uid = nidp->nid_uid;
3447 thp = NFSUSERHASH(newusrp->lug_uid);
3448 mtx_assert(&thp->mtx, MA_OWNED);
3449 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3450 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3451 mtx_assert(&thp->mtx, MA_OWNED);
3452 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3453 atomic_add_int(&nfsrv_usercnt, 1);
3454 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3455 newusrp->lug_gid = nidp->nid_gid;
3456 thp = NFSGROUPHASH(newusrp->lug_gid);
3457 mtx_assert(&thp->mtx, MA_OWNED);
3458 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3459 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3460 mtx_assert(&thp->mtx, MA_OWNED);
3461 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3462 atomic_add_int(&nfsrv_usercnt, 1);
3464 if (newusrp->lug_cred != NULL)
3465 crfree(newusrp->lug_cred);
3466 free(newusrp, M_NFSUSERGROUP);
3470 * Once per second, allow one thread to trim the cache.
3472 if (lasttime < NFSD_MONOSEC &&
3473 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3475 * First, unlock the single mutexes, so that all entries
3476 * can be locked and any LOR is avoided.
3478 if (hp_name != NULL) {
3479 mtx_unlock(&hp_name->mtx);
3482 if (hp_idnum != NULL) {
3483 mtx_unlock(&hp_idnum->mtx);
3487 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3488 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3489 if (username_locked == 0) {
3490 for (i = 0; i < nfsrv_lughashsize; i++)
3491 mtx_lock(&nfsusernamehash[i].mtx);
3492 username_locked = 1;
3494 KASSERT(user_locked == 0,
3495 ("nfssvc_idname: user_locked"));
3496 for (i = 0; i < nfsrv_lughashsize; i++)
3497 mtx_lock(&nfsuserhash[i].mtx);
3499 for (i = 0; i < nfsrv_lughashsize; i++) {
3500 TAILQ_FOREACH_SAFE(usrp,
3501 &nfsuserhash[i].lughead, lug_numhash,
3503 if (usrp->lug_expiry < NFSD_MONOSEC)
3504 nfsrv_removeuser(usrp, 1);
3506 for (i = 0; i < nfsrv_lughashsize; i++) {
3508 * Trim the cache using an approximate LRU
3509 * algorithm. This code deletes the least
3510 * recently used entry on each hash list.
3512 if (nfsrv_usercnt <= nfsrv_usermax)
3514 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3516 nfsrv_removeuser(usrp, 1);
3519 if (groupname_locked == 0) {
3520 for (i = 0; i < nfsrv_lughashsize; i++)
3521 mtx_lock(&nfsgroupnamehash[i].mtx);
3522 groupname_locked = 1;
3524 KASSERT(group_locked == 0,
3525 ("nfssvc_idname: group_locked"));
3526 for (i = 0; i < nfsrv_lughashsize; i++)
3527 mtx_lock(&nfsgrouphash[i].mtx);
3529 for (i = 0; i < nfsrv_lughashsize; i++) {
3530 TAILQ_FOREACH_SAFE(usrp,
3531 &nfsgrouphash[i].lughead, lug_numhash,
3533 if (usrp->lug_expiry < NFSD_MONOSEC)
3534 nfsrv_removeuser(usrp, 0);
3536 for (i = 0; i < nfsrv_lughashsize; i++) {
3538 * Trim the cache using an approximate LRU
3539 * algorithm. This code deletes the least
3540 * recently user entry on each hash list.
3542 if (nfsrv_usercnt <= nfsrv_usermax)
3544 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3546 nfsrv_removeuser(usrp, 0);
3549 lasttime = NFSD_MONOSEC;
3550 atomic_store_rel_int(&onethread, 0);
3553 /* Now, unlock all locked mutexes. */
3554 if (hp_idnum != NULL)
3555 mtx_unlock(&hp_idnum->mtx);
3556 if (hp_name != NULL)
3557 mtx_unlock(&hp_name->mtx);
3558 if (user_locked != 0)
3559 for (i = 0; i < nfsrv_lughashsize; i++)
3560 mtx_unlock(&nfsuserhash[i].mtx);
3561 if (username_locked != 0)
3562 for (i = 0; i < nfsrv_lughashsize; i++)
3563 mtx_unlock(&nfsusernamehash[i].mtx);
3564 if (group_locked != 0)
3565 for (i = 0; i < nfsrv_lughashsize; i++)
3566 mtx_unlock(&nfsgrouphash[i].mtx);
3567 if (groupname_locked != 0)
3568 for (i = 0; i < nfsrv_lughashsize; i++)
3569 mtx_unlock(&nfsgroupnamehash[i].mtx);
3576 * Remove a user/group name element.
3579 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3581 struct nfsrv_lughash *hp;
3584 hp = NFSUSERHASH(usrp->lug_uid);
3585 mtx_assert(&hp->mtx, MA_OWNED);
3586 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3587 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3588 mtx_assert(&hp->mtx, MA_OWNED);
3589 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3591 hp = NFSGROUPHASH(usrp->lug_gid);
3592 mtx_assert(&hp->mtx, MA_OWNED);
3593 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3594 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3595 mtx_assert(&hp->mtx, MA_OWNED);
3596 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3598 atomic_add_int(&nfsrv_usercnt, -1);
3599 if (usrp->lug_cred != NULL)
3600 crfree(usrp->lug_cred);
3601 free(usrp, M_NFSUSERGROUP);
3605 * Free up all the allocations related to the name<-->id cache.
3606 * This function should only be called when the nfsuserd daemon isn't
3607 * running, since it doesn't do any locking.
3608 * This function is meant to be used when the nfscommon module is unloaded.
3611 nfsrv_cleanusergroup(void)
3613 struct nfsrv_lughash *hp, *hp2;
3614 struct nfsusrgrp *nusrp, *usrp;
3617 if (nfsuserhash == NULL)
3620 for (i = 0; i < nfsrv_lughashsize; i++) {
3621 hp = &nfsuserhash[i];
3622 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3623 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3624 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3626 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3627 if (usrp->lug_cred != NULL)
3628 crfree(usrp->lug_cred);
3629 free(usrp, M_NFSUSERGROUP);
3631 hp = &nfsgrouphash[i];
3632 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3633 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3634 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3636 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3637 if (usrp->lug_cred != NULL)
3638 crfree(usrp->lug_cred);
3639 free(usrp, M_NFSUSERGROUP);
3641 mtx_destroy(&nfsuserhash[i].mtx);
3642 mtx_destroy(&nfsusernamehash[i].mtx);
3643 mtx_destroy(&nfsgroupnamehash[i].mtx);
3644 mtx_destroy(&nfsgrouphash[i].mtx);
3646 free(nfsuserhash, M_NFSUSERGROUP);
3647 free(nfsusernamehash, M_NFSUSERGROUP);
3648 free(nfsgrouphash, M_NFSUSERGROUP);
3649 free(nfsgroupnamehash, M_NFSUSERGROUP);
3650 free(nfsrv_dnsname, M_NFSSTRING);
3654 * This function scans a byte string and checks for UTF-8 compliance.
3655 * It returns 0 if it conforms and NFSERR_INVAL if not.
3658 nfsrv_checkutf8(u_int8_t *cp, int len)
3660 u_int32_t val = 0x0;
3661 int cnt = 0, gotd = 0, shift = 0;
3663 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3667 * Here are what the variables are used for:
3668 * val - the calculated value of a multibyte char, used to check
3669 * that it was coded with the correct range
3670 * cnt - the number of 10xxxxxx bytes to follow
3671 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3672 * shift - lower order bits of range (ie. "val >> shift" should
3673 * not be 0, in other words, dividing by the lower bound
3674 * of the range should get a non-zero value)
3675 * byte - used to calculate cnt
3679 /* This handles the 10xxxxxx bytes */
3680 if ((*cp & 0xc0) != 0x80 ||
3681 (gotd && (*cp & 0x20))) {
3682 error = NFSERR_INVAL;
3687 val |= (*cp & 0x3f);
3689 if (cnt == 0 && (val >> shift) == 0x0) {
3690 error = NFSERR_INVAL;
3693 } else if (*cp & 0x80) {
3694 /* first byte of multi byte char */
3696 while ((byte & 0x40) && cnt < 6) {
3700 if (cnt == 0 || cnt == 6) {
3701 error = NFSERR_INVAL;
3704 val = (*cp & (0x3f >> cnt));
3705 shift = utf8_shift[cnt - 1];
3706 if (cnt == 2 && val == 0xd)
3707 /* Check for the 0xd800-0xdfff case */
3714 error = NFSERR_INVAL;
3722 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3723 * strings, one with the root path in it and the other with the list of
3724 * locations. The list is in the same format as is found in nfr_refs.
3725 * It is a "," separated list of entries, where each of them is of the
3726 * form <server>:<rootpath>. For example
3727 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3728 * The nilp argument is set to 1 for the special case of a null fs_root
3729 * and an empty server list.
3730 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3731 * number of xdr bytes parsed in sump.
3734 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3735 int *sump, int *nilp)
3738 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3739 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3741 SLIST_ENTRY(list) next;
3745 SLIST_HEAD(, list) head;
3752 * Get the fs_root path and check for the special case of null path
3753 * and 0 length server list.
3755 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3756 len = fxdr_unsigned(int, *tl);
3757 if (len < 0 || len > 10240) {
3758 error = NFSERR_BADXDR;
3762 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3764 error = NFSERR_BADXDR;
3768 *sump = 2 * NFSX_UNSIGNED;
3772 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3773 error = nfsrv_mtostr(nd, cp, len);
3775 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3776 cnt = fxdr_unsigned(int, *tl);
3778 error = NFSERR_BADXDR;
3784 * Now, loop through the location list and make up the srvlist.
3786 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3787 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3790 for (i = 0; i < cnt; i++) {
3792 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3793 nsrv = fxdr_unsigned(int, *tl);
3795 error = NFSERR_BADXDR;
3800 * Handle the first server by putting it in the srvstr.
3802 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3803 len = fxdr_unsigned(int, *tl);
3804 if (len <= 0 || len > 1024) {
3805 error = NFSERR_BADXDR;
3808 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3813 error = nfsrv_mtostr(nd, cp3, len);
3819 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3820 for (j = 1; j < nsrv; j++) {
3822 * Yuck, put them in an slist and process them later.
3824 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3825 len = fxdr_unsigned(int, *tl);
3826 if (len <= 0 || len > 1024) {
3827 error = NFSERR_BADXDR;
3830 lsp = (struct list *)malloc(sizeof (struct list)
3831 + len, M_TEMP, M_WAITOK);
3832 error = nfsrv_mtostr(nd, lsp->host, len);
3835 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3837 SLIST_INSERT_HEAD(&head, lsp, next);
3841 * Finally, we can get the path.
3843 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3844 len = fxdr_unsigned(int, *tl);
3845 if (len <= 0 || len > 1024) {
3846 error = NFSERR_BADXDR;
3849 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3850 error = nfsrv_mtostr(nd, cp3, len);
3853 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3858 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3859 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3862 NFSBCOPY(lsp->host, cp3, lsp->len);
3865 NFSBCOPY(str, cp3, stringlen);
3868 siz += (lsp->len + stringlen + 2);
3869 free((caddr_t)lsp, M_TEMP);
3875 NFSEXITCODE2(0, nd);
3879 free(cp, M_NFSSTRING);
3881 free(cp2, M_NFSSTRING);
3882 NFSEXITCODE2(error, nd);
3887 * Make the malloc'd space large enough. This is a pain, but the xdr
3888 * doesn't set an upper bound on the side, so...
3891 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3898 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3899 NFSBCOPY(*cpp, cp, *slenp);
3900 free(*cpp, M_NFSSTRING);
3904 *slenp = siz + 1024;
3908 * Initialize the reply header data structures.
3911 nfsrvd_rephead(struct nfsrv_descript *nd)
3916 * If this is a big reply, use a cluster.
3918 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3919 nfs_bigreply[nd->nd_procnum]) {
3920 NFSMCLGET(mreq, M_WAITOK);
3928 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3929 mbuf_setlen(mreq, 0);
3931 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3932 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3936 * Lock a socket against others.
3937 * Currently used to serialize connect/disconnect attempts.
3940 newnfs_sndlock(int *flagp)
3945 while (*flagp & NFSR_SNDLOCK) {
3946 *flagp |= NFSR_WANTSND;
3949 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3950 PZERO - 1, "nfsndlck", &ts);
3952 *flagp |= NFSR_SNDLOCK;
3958 * Unlock the stream socket for others.
3961 newnfs_sndunlock(int *flagp)
3965 if ((*flagp & NFSR_SNDLOCK) == 0)
3966 panic("nfs sndunlock");
3967 *flagp &= ~NFSR_SNDLOCK;
3968 if (*flagp & NFSR_WANTSND) {
3969 *flagp &= ~NFSR_WANTSND;
3970 wakeup((caddr_t)flagp);
3976 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3979 struct sockaddr_in *sad;
3980 struct sockaddr_in6 *sad6;
3981 struct in_addr saddr;
3982 uint32_t portnum, *tl;
3983 int af = 0, i, j, k;
3984 char addr[64], protocol[5], *cp;
3985 int cantparse = 0, error = 0;
3988 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3989 i = fxdr_unsigned(int, *tl);
3990 if (i >= 3 && i <= 4) {
3991 error = nfsrv_mtostr(nd, protocol, i);
3994 if (strcmp(protocol, "tcp") == 0) {
3997 } else if (strcmp(protocol, "udp") == 0) {
4000 } else if (strcmp(protocol, "tcp6") == 0) {
4003 } else if (strcmp(protocol, "udp6") == 0) {
4011 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4016 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4017 i = fxdr_unsigned(int, *tl);
4019 error = NFSERR_BADXDR;
4021 } else if (cantparse == 0 && i >= 11 && i < 64) {
4023 * The shortest address is 11chars and the longest is < 64.
4025 error = nfsrv_mtostr(nd, addr, i);
4029 /* Find the port# at the end and extract that. */
4033 /* Count back two '.'s from end to get port# field. */
4034 for (j = 0; j < i; j++) {
4044 * The NFSv4 port# is appended as .N.N, where N is
4045 * a decimal # in the range 0-255, just like an inet4
4046 * address. Cheat and use inet_aton(), which will
4047 * return a Class A address and then shift the high
4048 * order 8bits over to convert it to the port#.
4051 if (inet_aton(cp, &saddr) == 1) {
4052 portnum = ntohl(saddr.s_addr);
4053 portv = (uint16_t)((portnum >> 16) |
4059 if (cantparse == 0) {
4060 if (af == AF_INET) {
4061 sad = (struct sockaddr_in *)sa;
4062 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4063 sad->sin_len = sizeof(*sad);
4064 sad->sin_family = AF_INET;
4065 sad->sin_port = htons(portv);
4069 sad6 = (struct sockaddr_in6 *)sa;
4070 if (inet_pton(af, addr, &sad6->sin6_addr)
4072 sad6->sin6_len = sizeof(*sad6);
4073 sad6->sin6_family = AF_INET6;
4074 sad6->sin6_port = htons(portv);
4081 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4092 * Handle an NFSv4.1 Sequence request for the session.
4093 * If reply != NULL, use it to return the cached reply, as required.
4094 * The client gets a cached reply via this call for callbacks, however the
4095 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4098 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4099 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4106 if (slotid > maxslot)
4107 return (NFSERR_BADSLOT);
4108 if (seqid == slots[slotid].nfssl_seq) {
4110 if (slots[slotid].nfssl_inprog != 0)
4111 error = NFSERR_DELAY;
4112 else if (slots[slotid].nfssl_reply != NULL) {
4113 if (reply != NULL) {
4114 *reply = slots[slotid].nfssl_reply;
4115 slots[slotid].nfssl_reply = NULL;
4117 slots[slotid].nfssl_inprog = 1;
4118 error = NFSERR_REPLYFROMCACHE;
4120 /* No reply cached, so just do it. */
4121 slots[slotid].nfssl_inprog = 1;
4122 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4123 if (slots[slotid].nfssl_reply != NULL)
4124 m_freem(slots[slotid].nfssl_reply);
4125 slots[slotid].nfssl_reply = NULL;
4126 slots[slotid].nfssl_inprog = 1;
4127 slots[slotid].nfssl_seq++;
4129 error = NFSERR_SEQMISORDERED;
4134 * Cache this reply for the slot.
4135 * Use the "rep" argument to return the cached reply if repstat is set to
4136 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4139 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4143 if (repstat == NFSERR_REPLYFROMCACHE) {
4144 *rep = slots[slotid].nfssl_reply;
4145 slots[slotid].nfssl_reply = NULL;
4147 if (slots[slotid].nfssl_reply != NULL)
4148 m_freem(slots[slotid].nfssl_reply);
4149 slots[slotid].nfssl_reply = *rep;
4151 slots[slotid].nfssl_inprog = 0;
4155 * Generate the xdr for an NFSv4.1 Sequence Operation.
4158 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4159 struct nfsclsession *sep, int dont_replycache)
4161 uint32_t *tl, slotseq = 0;
4162 int error, maxslot, slotpos;
4163 uint8_t sessionid[NFSX_V4SESSIONID];
4165 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4168 /* Build the Sequence arguments. */
4169 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4170 nd->nd_sequence = tl;
4171 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4172 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4173 nd->nd_slotseq = tl;
4175 *tl++ = txdr_unsigned(slotseq);
4176 *tl++ = txdr_unsigned(slotpos);
4177 *tl++ = txdr_unsigned(maxslot);
4178 if (dont_replycache == 0)
4184 * There are two errors and the rest of the session can
4186 * NFSERR_BADSESSION: This bad session should just generate
4187 * the same error again when the RPC is retried.
4188 * ESTALE: A forced dismount is in progress and will cause the
4189 * RPC to fail later.
4196 nd->nd_flag |= ND_HASSEQUENCE;
4200 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4201 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4203 int i, maxslot, slotpos;
4206 /* Find an unused slot. */
4209 mtx_lock(&sep->nfsess_mtx);
4211 if (nmp != NULL && sep->nfsess_defunct != 0) {
4212 /* Just return the bad session. */
4213 bcopy(sep->nfsess_sessionid, sessionid,
4215 mtx_unlock(&sep->nfsess_mtx);
4216 return (NFSERR_BADSESSION);
4219 for (i = 0; i < sep->nfsess_foreslots; i++) {
4220 if ((bitval & sep->nfsess_slots) == 0) {
4222 sep->nfsess_slots |= bitval;
4223 sep->nfsess_slotseq[i]++;
4224 *slotseqp = sep->nfsess_slotseq[i];
4229 if (slotpos == -1) {
4231 * If a forced dismount is in progress, just return.
4232 * This RPC attempt will fail when it calls
4236 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
4238 mtx_unlock(&sep->nfsess_mtx);
4241 /* Wake up once/sec, to check for a forced dismount. */
4242 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4243 PZERO, "nfsclseq", hz);
4245 } while (slotpos == -1);
4246 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4248 for (i = 0; i < 64; i++) {
4249 if ((bitval & sep->nfsess_slots) != 0)
4253 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4254 mtx_unlock(&sep->nfsess_mtx);
4255 *slotposp = slotpos;
4256 *maxslotp = maxslot;
4261 * Free a session slot.
4264 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4271 mtx_lock(&sep->nfsess_mtx);
4272 if ((bitval & sep->nfsess_slots) == 0)
4273 printf("freeing free slot!!\n");
4274 sep->nfsess_slots &= ~bitval;
4275 wakeup(&sep->nfsess_slots);
4276 mtx_unlock(&sep->nfsess_mtx);