2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
45 #include "opt_inet6.h"
47 #include <fs/nfs/nfsport.h>
49 #include <security/mac/mac_framework.h>
52 * Data items converted to xdr at startup, since they are constant
53 * This is kinda hokey, but may save a little time doing byte swaps
55 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
57 /* And other global data */
58 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
60 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
61 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
62 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
65 struct nfssockreq nfsrv_nfsuserdsock;
66 int nfsrv_nfsuserd = 0;
67 struct nfsreqhead nfsd_reqq;
68 uid_t nfsrv_defaultuid = UID_NOBODY;
69 gid_t nfsrv_defaultgid = GID_NOGROUP;
70 int nfsrv_lease = NFSRV_LEASE;
71 int ncl_mbuf_mlen = MLEN;
72 int nfsd_enable_stringtouid = 0;
73 static int nfs_enable_uidtostring = 0;
76 extern int nfsrv_lughashsize;
78 SYSCTL_DECL(_vfs_nfs);
79 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
80 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
83 * This array of structures indicates, for V4:
84 * retfh - which of 3 types of calling args are used
85 * 0 - doesn't change cfh or use a sfh
86 * 1 - replaces cfh with a new one (unless it returns an error status)
87 * 2 - uses cfh and sfh
88 * needscfh - if the op wants a cfh and premtime
89 * 0 - doesn't use a cfh
90 * 1 - uses a cfh, but doesn't want pre-op attributes
91 * 2 - uses a cfh and wants pre-op attributes
92 * savereply - indicates a non-idempotent Op
93 * 0 - not non-idempotent
95 * Ops that are ordered via seqid# are handled separately from these
97 * Define it here, since it is used by both the client and server.
99 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
101 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
102 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
103 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
104 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
105 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
106 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
107 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
108 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
109 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
110 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
111 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
112 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
115 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
116 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
117 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
118 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
119 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
120 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
122 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
123 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
124 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
125 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
126 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
127 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
128 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
129 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
134 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
137 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
138 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
160 #endif /* !APPLEKEXT */
162 static int ncl_mbuf_mhlen = MHLEN;
163 static int nfsrv_usercnt = 0;
164 static int nfsrv_dnsnamelen;
165 static u_char *nfsrv_dnsname = NULL;
166 static int nfsrv_usermax = 999999999;
167 struct nfsrv_lughash {
169 struct nfsuserhashhead lughead;
171 static struct nfsrv_lughash *nfsuserhash;
172 static struct nfsrv_lughash *nfsusernamehash;
173 static struct nfsrv_lughash *nfsgrouphash;
174 static struct nfsrv_lughash *nfsgroupnamehash;
177 * This static array indicates whether or not the RPC generates a large
178 * reply. This is used by nfs_reply() to decide whether or not an mbuf
179 * cluster should be allocated. (If a cluster is required by an RPC
180 * marked 0 in this array, the code will still work, just not quite as
183 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
184 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,
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
187 /* local functions */
188 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
189 static void nfsv4_wanted(struct nfsv4lock *lp);
190 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
191 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
193 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
194 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
196 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
201 * copies mbuf chain to the uio scatter/gather list
204 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
206 char *mbufcp, *uiocp;
213 mbufcp = nd->nd_dpos;
214 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
215 rem = NFSM_RNDUP(siz) - siz;
217 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
221 left = uiop->uio_iov->iov_len;
222 uiocp = uiop->uio_iov->iov_base;
233 mbufcp = NFSMTOD(mp, caddr_t);
236 ("len %d, corrupted mbuf?", len));
238 xfer = (left > len) ? len : left;
241 if (uiop->uio_iov->iov_op != NULL)
242 (*(uiop->uio_iov->iov_op))
243 (mbufcp, uiocp, xfer);
246 if (uiop->uio_segflg == UIO_SYSSPACE)
247 NFSBCOPY(mbufcp, uiocp, xfer);
249 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
254 uiop->uio_offset += xfer;
255 uiop->uio_resid -= xfer;
257 if (uiop->uio_iov->iov_len <= siz) {
261 uiop->uio_iov->iov_base = (void *)
262 ((char *)uiop->uio_iov->iov_base + uiosiz);
263 uiop->uio_iov->iov_len -= uiosiz;
267 nd->nd_dpos = mbufcp;
271 error = nfsm_advance(nd, rem, len);
277 NFSEXITCODE2(error, nd);
283 * Help break down an mbuf chain by setting the first siz bytes contiguous
284 * pointed to by returned val.
285 * This is used by the macro NFSM_DISSECT for tough
289 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
298 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
300 nd->nd_md = mbuf_next(nd->nd_md);
301 if (nd->nd_md == NULL)
303 left = mbuf_len(nd->nd_md);
304 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
309 } else if (mbuf_next(nd->nd_md) == NULL) {
311 } else if (siz > ncl_mbuf_mhlen) {
312 panic("nfs S too big");
314 MGET(mp2, MT_DATA, how);
317 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
318 mbuf_setnext(nd->nd_md, mp2);
319 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
321 retp = p = NFSMTOD(mp2, caddr_t);
322 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
325 mp2 = mbuf_next(mp2);
326 /* Loop around copying up the siz2 bytes */
330 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
332 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
333 NFSM_DATAP(mp2, xfer);
334 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
339 mp2 = mbuf_next(mp2);
341 mbuf_setlen(nd->nd_md, siz);
343 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
349 * Advance the position in the mbuf chain.
350 * If offs == 0, this is a no-op, but it is simpler to just return from
351 * here than check for offs > 0 for all calls to nfsm_advance.
352 * If left == -1, it should be calculated here.
355 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
362 * A negative offs should be considered a serious problem.
365 panic("nfsrv_advance");
368 * If left == -1, calculate it here.
371 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
375 * Loop around, advancing over the mbuf data.
377 while (offs > left) {
379 nd->nd_md = mbuf_next(nd->nd_md);
380 if (nd->nd_md == NULL) {
384 left = mbuf_len(nd->nd_md);
385 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
395 * Copy a string into mbuf(s).
396 * Return the number of bytes output, including XDR overheads.
399 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
408 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
409 *tl = txdr_unsigned(siz);
410 rem = NFSM_RNDUP(siz) - siz;
411 bytesize = NFSX_UNSIGNED + siz + rem;
414 left = M_TRAILINGSPACE(m2);
417 * Loop around copying the string to mbuf(s).
421 if (siz > ncl_mbuf_mlen)
422 NFSMCLGET(m1, M_WAITOK);
426 mbuf_setnext(m2, m1);
428 cp2 = NFSMTOD(m2, caddr_t);
429 left = M_TRAILINGSPACE(m2);
435 NFSBCOPY(cp, cp2, xfer);
437 mbuf_setlen(m2, mbuf_len(m2) + xfer);
440 if (siz == 0 && rem) {
442 panic("nfsm_strtom");
443 NFSBZERO(cp2 + xfer, rem);
444 mbuf_setlen(m2, mbuf_len(m2) + rem);
448 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
453 * Called once to initialize data structures...
458 static int nfs_inited = 0;
464 newnfs_true = txdr_unsigned(TRUE);
465 newnfs_false = txdr_unsigned(FALSE);
466 newnfs_xdrneg1 = txdr_unsigned(-1);
467 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
470 NFSSETBOOTTIME(nfsboottime);
473 * Initialize reply list and start timer
475 TAILQ_INIT(&nfsd_reqq);
480 * Put a file handle in an mbuf list.
481 * If the size argument == 0, just use the default size.
482 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
483 * Return the number of bytes output, including XDR overhead.
486 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
490 int fullsiz, bytesize = 0;
494 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
496 if (size > NFSX_V2FH)
497 panic("fh size > NFSX_V2FH for NFSv2");
498 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
499 NFSBCOPY(fhp, cp, size);
500 if (size < NFSX_V2FH)
501 NFSBZERO(cp + size, NFSX_V2FH - size);
502 bytesize = NFSX_V2FH;
506 fullsiz = NFSM_RNDUP(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 nfhp = malloc(sizeof (struct nfsfh) + len,
682 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
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;
829 u_int32_t freenum = 0, tuint;
830 u_int64_t uquad = 0, thyp, thyp2;
836 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
839 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
841 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
847 *retcmpp = retnotsup;
850 * Just set default values to some of the important ones.
855 nap->na_rdev = (NFSDEV_T)0;
856 nap->na_mtime.tv_sec = 0;
857 nap->na_mtime.tv_nsec = 0;
860 nap->na_blocksize = NFS_FABLKSIZE;
863 sbp->f_bsize = NFS_FABLKSIZE;
871 fsp->fs_rtmax = 8192;
872 fsp->fs_rtpref = 8192;
873 fsp->fs_maxname = NFS_MAXNAMLEN;
874 fsp->fs_wtmax = 8192;
875 fsp->fs_wtpref = 8192;
876 fsp->fs_wtmult = NFS_FABLKSIZE;
877 fsp->fs_dtpref = 8192;
878 fsp->fs_maxfilesize = 0xffffffffffffffffull;
879 fsp->fs_timedelta.tv_sec = 0;
880 fsp->fs_timedelta.tv_nsec = 1;
881 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
882 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
885 pc->pc_linkmax = NFS_LINK_MAX;
886 pc->pc_namemax = NAME_MAX;
888 pc->pc_chownrestricted = 0;
889 pc->pc_caseinsensitive = 0;
890 pc->pc_casepreserving = 1;
893 sfp->sf_ffiles = UINT64_MAX;
894 sfp->sf_tfiles = UINT64_MAX;
895 sfp->sf_afiles = UINT64_MAX;
896 sfp->sf_fbytes = UINT64_MAX;
897 sfp->sf_tbytes = UINT64_MAX;
898 sfp->sf_abytes = UINT64_MAX;
903 * Loop around getting the attributes.
905 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
906 attrsize = fxdr_unsigned(int, *tl);
907 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
908 if (attrsum > attrsize) {
909 error = NFSERR_BADXDR;
912 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
914 case NFSATTRBIT_SUPPORTEDATTRS:
916 if (compare || nap == NULL)
917 error = nfsrv_getattrbits(nd, &retattrbits,
920 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
924 if (compare && !(*retcmpp)) {
925 NFSSETSUPP_ATTRBIT(&checkattrbits);
927 /* Some filesystem do not support NFSv4ACL */
928 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
929 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
930 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
932 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
934 *retcmpp = NFSERR_NOTSAME;
938 case NFSATTRBIT_TYPE:
939 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
942 if (nap->na_type != nfsv34tov_type(*tl))
943 *retcmpp = NFSERR_NOTSAME;
945 } else if (nap != NULL) {
946 nap->na_type = nfsv34tov_type(*tl);
948 attrsum += NFSX_UNSIGNED;
950 case NFSATTRBIT_FHEXPIRETYPE:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
952 if (compare && !(*retcmpp)) {
953 if (fxdr_unsigned(int, *tl) !=
954 NFSV4FHTYPE_PERSISTENT)
955 *retcmpp = NFSERR_NOTSAME;
957 attrsum += NFSX_UNSIGNED;
959 case NFSATTRBIT_CHANGE:
960 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
963 if (nap->na_filerev != fxdr_hyper(tl))
964 *retcmpp = NFSERR_NOTSAME;
966 } else if (nap != NULL) {
967 nap->na_filerev = fxdr_hyper(tl);
969 attrsum += NFSX_HYPER;
971 case NFSATTRBIT_SIZE:
972 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
975 if (nap->na_size != fxdr_hyper(tl))
976 *retcmpp = NFSERR_NOTSAME;
978 } else if (nap != NULL) {
979 nap->na_size = fxdr_hyper(tl);
981 attrsum += NFSX_HYPER;
983 case NFSATTRBIT_LINKSUPPORT:
984 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987 if (fsp->fs_properties & NFSV3_FSFLINK) {
988 if (*tl == newnfs_false)
989 *retcmpp = NFSERR_NOTSAME;
991 if (*tl == newnfs_true)
992 *retcmpp = NFSERR_NOTSAME;
995 } else if (fsp != NULL) {
996 if (*tl == newnfs_true)
997 fsp->fs_properties |= NFSV3_FSFLINK;
999 fsp->fs_properties &= ~NFSV3_FSFLINK;
1001 attrsum += NFSX_UNSIGNED;
1003 case NFSATTRBIT_SYMLINKSUPPORT:
1004 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1007 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1008 if (*tl == newnfs_false)
1009 *retcmpp = NFSERR_NOTSAME;
1011 if (*tl == newnfs_true)
1012 *retcmpp = NFSERR_NOTSAME;
1015 } else if (fsp != NULL) {
1016 if (*tl == newnfs_true)
1017 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1019 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1021 attrsum += NFSX_UNSIGNED;
1023 case NFSATTRBIT_NAMEDATTR:
1024 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1025 if (compare && !(*retcmpp)) {
1026 if (*tl != newnfs_false)
1027 *retcmpp = NFSERR_NOTSAME;
1029 attrsum += NFSX_UNSIGNED;
1031 case NFSATTRBIT_FSID:
1032 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1033 thyp = fxdr_hyper(tl);
1035 thyp2 = fxdr_hyper(tl);
1037 if (*retcmpp == 0) {
1038 if (thyp != (u_int64_t)
1039 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1040 thyp2 != (u_int64_t)
1041 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1042 *retcmpp = NFSERR_NOTSAME;
1044 } else if (nap != NULL) {
1045 nap->na_filesid[0] = thyp;
1046 nap->na_filesid[1] = thyp2;
1048 attrsum += (4 * NFSX_UNSIGNED);
1050 case NFSATTRBIT_UNIQUEHANDLES:
1051 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1052 if (compare && !(*retcmpp)) {
1053 if (*tl != newnfs_true)
1054 *retcmpp = NFSERR_NOTSAME;
1056 attrsum += NFSX_UNSIGNED;
1058 case NFSATTRBIT_LEASETIME:
1059 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1061 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1063 *retcmpp = NFSERR_NOTSAME;
1064 } else if (leasep != NULL) {
1065 *leasep = fxdr_unsigned(u_int32_t, *tl);
1067 attrsum += NFSX_UNSIGNED;
1069 case NFSATTRBIT_RDATTRERROR:
1070 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1073 *retcmpp = NFSERR_INVAL;
1074 } else if (rderrp != NULL) {
1075 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1077 attrsum += NFSX_UNSIGNED;
1079 case NFSATTRBIT_ACL:
1082 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1085 naclp = acl_alloc(M_WAITOK);
1086 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1092 if (aceerr || aclp == NULL ||
1093 nfsrv_compareacl(aclp, naclp))
1094 *retcmpp = NFSERR_NOTSAME;
1097 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1099 *retcmpp = NFSERR_ATTRNOTSUPP;
1103 if (vp != NULL && aclp != NULL)
1104 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1107 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1115 case NFSATTRBIT_ACLSUPPORT:
1116 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1117 if (compare && !(*retcmpp)) {
1118 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1119 if (fxdr_unsigned(u_int32_t, *tl) !=
1121 *retcmpp = NFSERR_NOTSAME;
1123 *retcmpp = NFSERR_ATTRNOTSUPP;
1126 attrsum += NFSX_UNSIGNED;
1128 case NFSATTRBIT_ARCHIVE:
1129 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1130 if (compare && !(*retcmpp))
1131 *retcmpp = NFSERR_ATTRNOTSUPP;
1132 attrsum += NFSX_UNSIGNED;
1134 case NFSATTRBIT_CANSETTIME:
1135 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1138 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1139 if (*tl == newnfs_false)
1140 *retcmpp = NFSERR_NOTSAME;
1142 if (*tl == newnfs_true)
1143 *retcmpp = NFSERR_NOTSAME;
1146 } else if (fsp != NULL) {
1147 if (*tl == newnfs_true)
1148 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1150 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1152 attrsum += NFSX_UNSIGNED;
1154 case NFSATTRBIT_CASEINSENSITIVE:
1155 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1158 if (*tl != newnfs_false)
1159 *retcmpp = NFSERR_NOTSAME;
1161 } else if (pc != NULL) {
1162 pc->pc_caseinsensitive =
1163 fxdr_unsigned(u_int32_t, *tl);
1165 attrsum += NFSX_UNSIGNED;
1167 case NFSATTRBIT_CASEPRESERVING:
1168 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1171 if (*tl != newnfs_true)
1172 *retcmpp = NFSERR_NOTSAME;
1174 } else if (pc != NULL) {
1175 pc->pc_casepreserving =
1176 fxdr_unsigned(u_int32_t, *tl);
1178 attrsum += NFSX_UNSIGNED;
1180 case NFSATTRBIT_CHOWNRESTRICTED:
1181 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1184 if (*tl != newnfs_true)
1185 *retcmpp = NFSERR_NOTSAME;
1187 } else if (pc != NULL) {
1188 pc->pc_chownrestricted =
1189 fxdr_unsigned(u_int32_t, *tl);
1191 attrsum += NFSX_UNSIGNED;
1193 case NFSATTRBIT_FILEHANDLE:
1194 error = nfsm_getfh(nd, &tnfhp);
1197 tfhsize = tnfhp->nfh_len;
1200 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1202 *retcmpp = NFSERR_NOTSAME;
1203 free(tnfhp, M_NFSFH);
1204 } else if (nfhpp != NULL) {
1207 free(tnfhp, M_NFSFH);
1209 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1211 case NFSATTRBIT_FILEID:
1212 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1213 thyp = fxdr_hyper(tl);
1216 if (nap->na_fileid != thyp)
1217 *retcmpp = NFSERR_NOTSAME;
1219 } else if (nap != NULL)
1220 nap->na_fileid = thyp;
1221 attrsum += NFSX_HYPER;
1223 case NFSATTRBIT_FILESAVAIL:
1224 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1227 sfp->sf_afiles != fxdr_hyper(tl))
1228 *retcmpp = NFSERR_NOTSAME;
1229 } else if (sfp != NULL) {
1230 sfp->sf_afiles = fxdr_hyper(tl);
1232 attrsum += NFSX_HYPER;
1234 case NFSATTRBIT_FILESFREE:
1235 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1238 sfp->sf_ffiles != fxdr_hyper(tl))
1239 *retcmpp = NFSERR_NOTSAME;
1240 } else if (sfp != NULL) {
1241 sfp->sf_ffiles = fxdr_hyper(tl);
1243 attrsum += NFSX_HYPER;
1245 case NFSATTRBIT_FILESTOTAL:
1246 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1249 sfp->sf_tfiles != fxdr_hyper(tl))
1250 *retcmpp = NFSERR_NOTSAME;
1251 } else if (sfp != NULL) {
1252 sfp->sf_tfiles = fxdr_hyper(tl);
1254 attrsum += NFSX_HYPER;
1256 case NFSATTRBIT_FSLOCATIONS:
1257 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1261 if (compare && !(*retcmpp)) {
1262 refp = nfsv4root_getreferral(vp, NULL, 0);
1264 if (cp == NULL || cp2 == NULL ||
1266 strcmp(cp2, refp->nfr_srvlist))
1267 *retcmpp = NFSERR_NOTSAME;
1268 } else if (m == 0) {
1269 *retcmpp = NFSERR_NOTSAME;
1273 free(cp, M_NFSSTRING);
1275 free(cp2, M_NFSSTRING);
1277 case NFSATTRBIT_HIDDEN:
1278 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1279 if (compare && !(*retcmpp))
1280 *retcmpp = NFSERR_ATTRNOTSUPP;
1281 attrsum += NFSX_UNSIGNED;
1283 case NFSATTRBIT_HOMOGENEOUS:
1284 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1287 if (fsp->fs_properties &
1288 NFSV3_FSFHOMOGENEOUS) {
1289 if (*tl == newnfs_false)
1290 *retcmpp = NFSERR_NOTSAME;
1292 if (*tl == newnfs_true)
1293 *retcmpp = NFSERR_NOTSAME;
1296 } else if (fsp != NULL) {
1297 if (*tl == newnfs_true)
1298 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1300 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1302 attrsum += NFSX_UNSIGNED;
1304 case NFSATTRBIT_MAXFILESIZE:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1306 tnfsquad.qval = fxdr_hyper(tl);
1309 tquad = NFSRV_MAXFILESIZE;
1310 if (tquad != tnfsquad.qval)
1311 *retcmpp = NFSERR_NOTSAME;
1313 } else if (fsp != NULL) {
1314 fsp->fs_maxfilesize = tnfsquad.qval;
1316 attrsum += NFSX_HYPER;
1318 case NFSATTRBIT_MAXLINK:
1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1322 if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1323 *retcmpp = NFSERR_NOTSAME;
1325 } else if (pc != NULL) {
1326 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1328 attrsum += NFSX_UNSIGNED;
1330 case NFSATTRBIT_MAXNAME:
1331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1334 if (fsp->fs_maxname !=
1335 fxdr_unsigned(u_int32_t, *tl))
1336 *retcmpp = NFSERR_NOTSAME;
1339 tuint = fxdr_unsigned(u_int32_t, *tl);
1341 * Some Linux NFSv4 servers report this
1342 * as 0 or 4billion, so I'll set it to
1343 * NFS_MAXNAMLEN. If a server actually creates
1344 * a name longer than NFS_MAXNAMLEN, it will
1345 * get an error back.
1347 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1348 tuint = NFS_MAXNAMLEN;
1350 fsp->fs_maxname = tuint;
1352 pc->pc_namemax = tuint;
1354 attrsum += NFSX_UNSIGNED;
1356 case NFSATTRBIT_MAXREAD:
1357 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1360 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1361 *(tl + 1)) || *tl != 0)
1362 *retcmpp = NFSERR_NOTSAME;
1364 } else if (fsp != NULL) {
1365 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1366 fsp->fs_rtpref = fsp->fs_rtmax;
1367 fsp->fs_dtpref = fsp->fs_rtpref;
1369 attrsum += NFSX_HYPER;
1371 case NFSATTRBIT_MAXWRITE:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1375 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1376 *(tl + 1)) || *tl != 0)
1377 *retcmpp = NFSERR_NOTSAME;
1379 } else if (fsp != NULL) {
1380 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1381 fsp->fs_wtpref = fsp->fs_wtmax;
1383 attrsum += NFSX_HYPER;
1385 case NFSATTRBIT_MIMETYPE:
1386 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1387 i = fxdr_unsigned(int, *tl);
1388 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1389 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1392 if (compare && !(*retcmpp))
1393 *retcmpp = NFSERR_ATTRNOTSUPP;
1395 case NFSATTRBIT_MODE:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1399 if (nap->na_mode != nfstov_mode(*tl))
1400 *retcmpp = NFSERR_NOTSAME;
1402 } else if (nap != NULL) {
1403 nap->na_mode = nfstov_mode(*tl);
1405 attrsum += NFSX_UNSIGNED;
1407 case NFSATTRBIT_NOTRUNC:
1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1411 if (*tl != newnfs_true)
1412 *retcmpp = NFSERR_NOTSAME;
1414 } else if (pc != NULL) {
1415 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1417 attrsum += NFSX_UNSIGNED;
1419 case NFSATTRBIT_NUMLINKS:
1420 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1421 tuint = fxdr_unsigned(u_int32_t, *tl);
1424 if ((u_int32_t)nap->na_nlink != tuint)
1425 *retcmpp = NFSERR_NOTSAME;
1427 } else if (nap != NULL) {
1428 nap->na_nlink = tuint;
1430 attrsum += NFSX_UNSIGNED;
1432 case NFSATTRBIT_OWNER:
1433 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1434 j = fxdr_unsigned(int, *tl);
1436 error = NFSERR_BADXDR;
1439 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1440 if (j > NFSV4_SMALLSTR)
1441 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1444 error = nfsrv_mtostr(nd, cp, j);
1446 if (j > NFSV4_SMALLSTR)
1447 free(cp, M_NFSSTRING);
1452 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1454 *retcmpp = NFSERR_NOTSAME;
1456 } else if (nap != NULL) {
1457 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1458 nap->na_uid = nfsrv_defaultuid;
1462 if (j > NFSV4_SMALLSTR)
1463 free(cp, M_NFSSTRING);
1465 case NFSATTRBIT_OWNERGROUP:
1466 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1467 j = fxdr_unsigned(int, *tl);
1469 error = NFSERR_BADXDR;
1472 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1473 if (j > NFSV4_SMALLSTR)
1474 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1477 error = nfsrv_mtostr(nd, cp, j);
1479 if (j > NFSV4_SMALLSTR)
1480 free(cp, M_NFSSTRING);
1485 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1487 *retcmpp = NFSERR_NOTSAME;
1489 } else if (nap != NULL) {
1490 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1491 nap->na_gid = nfsrv_defaultgid;
1495 if (j > NFSV4_SMALLSTR)
1496 free(cp, M_NFSSTRING);
1498 case NFSATTRBIT_QUOTAHARD:
1499 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1501 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1502 freenum = sbp->f_bfree;
1504 freenum = sbp->f_bavail;
1507 * ufs_quotactl() insists that the uid argument
1508 * equal p_ruid for non-root quota access, so
1509 * we'll just make sure that's the case.
1511 savuid = p->p_cred->p_ruid;
1512 p->p_cred->p_ruid = cred->cr_uid;
1513 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1514 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1515 freenum = min(dqb.dqb_bhardlimit, freenum);
1516 p->p_cred->p_ruid = savuid;
1518 uquad = (u_int64_t)freenum;
1519 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1521 if (compare && !(*retcmpp)) {
1522 if (uquad != fxdr_hyper(tl))
1523 *retcmpp = NFSERR_NOTSAME;
1525 attrsum += NFSX_HYPER;
1527 case NFSATTRBIT_QUOTASOFT:
1528 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1530 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1531 freenum = sbp->f_bfree;
1533 freenum = sbp->f_bavail;
1536 * ufs_quotactl() insists that the uid argument
1537 * equal p_ruid for non-root quota access, so
1538 * we'll just make sure that's the case.
1540 savuid = p->p_cred->p_ruid;
1541 p->p_cred->p_ruid = cred->cr_uid;
1542 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1543 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1544 freenum = min(dqb.dqb_bsoftlimit, freenum);
1545 p->p_cred->p_ruid = savuid;
1547 uquad = (u_int64_t)freenum;
1548 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1550 if (compare && !(*retcmpp)) {
1551 if (uquad != fxdr_hyper(tl))
1552 *retcmpp = NFSERR_NOTSAME;
1554 attrsum += NFSX_HYPER;
1556 case NFSATTRBIT_QUOTAUSED:
1557 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1562 * ufs_quotactl() insists that the uid argument
1563 * equal p_ruid for non-root quota access, so
1564 * we'll just make sure that's the case.
1566 savuid = p->p_cred->p_ruid;
1567 p->p_cred->p_ruid = cred->cr_uid;
1568 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1569 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1570 freenum = dqb.dqb_curblocks;
1571 p->p_cred->p_ruid = savuid;
1573 uquad = (u_int64_t)freenum;
1574 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1576 if (compare && !(*retcmpp)) {
1577 if (uquad != fxdr_hyper(tl))
1578 *retcmpp = NFSERR_NOTSAME;
1580 attrsum += NFSX_HYPER;
1582 case NFSATTRBIT_RAWDEV:
1583 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1584 j = fxdr_unsigned(int, *tl++);
1585 k = fxdr_unsigned(int, *tl);
1588 if (nap->na_rdev != NFSMAKEDEV(j, k))
1589 *retcmpp = NFSERR_NOTSAME;
1591 } else if (nap != NULL) {
1592 nap->na_rdev = NFSMAKEDEV(j, k);
1594 attrsum += NFSX_V4SPECDATA;
1596 case NFSATTRBIT_SPACEAVAIL:
1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1600 sfp->sf_abytes != fxdr_hyper(tl))
1601 *retcmpp = NFSERR_NOTSAME;
1602 } else if (sfp != NULL) {
1603 sfp->sf_abytes = fxdr_hyper(tl);
1605 attrsum += NFSX_HYPER;
1607 case NFSATTRBIT_SPACEFREE:
1608 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1611 sfp->sf_fbytes != fxdr_hyper(tl))
1612 *retcmpp = NFSERR_NOTSAME;
1613 } else if (sfp != NULL) {
1614 sfp->sf_fbytes = fxdr_hyper(tl);
1616 attrsum += NFSX_HYPER;
1618 case NFSATTRBIT_SPACETOTAL:
1619 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1622 sfp->sf_tbytes != fxdr_hyper(tl))
1623 *retcmpp = NFSERR_NOTSAME;
1624 } else if (sfp != NULL) {
1625 sfp->sf_tbytes = fxdr_hyper(tl);
1627 attrsum += NFSX_HYPER;
1629 case NFSATTRBIT_SPACEUSED:
1630 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1631 thyp = fxdr_hyper(tl);
1634 if ((u_int64_t)nap->na_bytes != thyp)
1635 *retcmpp = NFSERR_NOTSAME;
1637 } else if (nap != NULL) {
1638 nap->na_bytes = thyp;
1640 attrsum += NFSX_HYPER;
1642 case NFSATTRBIT_SYSTEM:
1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1644 if (compare && !(*retcmpp))
1645 *retcmpp = NFSERR_ATTRNOTSUPP;
1646 attrsum += NFSX_UNSIGNED;
1648 case NFSATTRBIT_TIMEACCESS:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1650 fxdr_nfsv4time(tl, &temptime);
1653 if (!NFS_CMPTIME(temptime, nap->na_atime))
1654 *retcmpp = NFSERR_NOTSAME;
1656 } else if (nap != NULL) {
1657 nap->na_atime = temptime;
1659 attrsum += NFSX_V4TIME;
1661 case NFSATTRBIT_TIMEACCESSSET:
1662 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1663 attrsum += NFSX_UNSIGNED;
1664 i = fxdr_unsigned(int, *tl);
1665 if (i == NFSV4SATTRTIME_TOCLIENT) {
1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1667 attrsum += NFSX_V4TIME;
1669 if (compare && !(*retcmpp))
1670 *retcmpp = NFSERR_INVAL;
1672 case NFSATTRBIT_TIMEBACKUP:
1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1674 if (compare && !(*retcmpp))
1675 *retcmpp = NFSERR_ATTRNOTSUPP;
1676 attrsum += NFSX_V4TIME;
1678 case NFSATTRBIT_TIMECREATE:
1679 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1680 if (compare && !(*retcmpp))
1681 *retcmpp = NFSERR_ATTRNOTSUPP;
1682 attrsum += NFSX_V4TIME;
1684 case NFSATTRBIT_TIMEDELTA:
1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1689 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1690 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1691 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1692 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1695 *retcmpp = NFSERR_NOTSAME;
1698 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1701 attrsum += NFSX_V4TIME;
1703 case NFSATTRBIT_TIMEMETADATA:
1704 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1705 fxdr_nfsv4time(tl, &temptime);
1708 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1709 *retcmpp = NFSERR_NOTSAME;
1711 } else if (nap != NULL) {
1712 nap->na_ctime = temptime;
1714 attrsum += NFSX_V4TIME;
1716 case NFSATTRBIT_TIMEMODIFY:
1717 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1718 fxdr_nfsv4time(tl, &temptime);
1721 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1722 *retcmpp = NFSERR_NOTSAME;
1724 } else if (nap != NULL) {
1725 nap->na_mtime = temptime;
1727 attrsum += NFSX_V4TIME;
1729 case NFSATTRBIT_TIMEMODIFYSET:
1730 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1731 attrsum += NFSX_UNSIGNED;
1732 i = fxdr_unsigned(int, *tl);
1733 if (i == NFSV4SATTRTIME_TOCLIENT) {
1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1735 attrsum += NFSX_V4TIME;
1737 if (compare && !(*retcmpp))
1738 *retcmpp = NFSERR_INVAL;
1740 case NFSATTRBIT_MOUNTEDONFILEID:
1741 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1742 thyp = fxdr_hyper(tl);
1745 if (!vp || !nfsrv_atroot(vp, &thyp2))
1746 thyp2 = nap->na_fileid;
1748 *retcmpp = NFSERR_NOTSAME;
1750 } else if (nap != NULL)
1751 nap->na_mntonfileno = thyp;
1752 attrsum += NFSX_HYPER;
1754 case NFSATTRBIT_SUPPATTREXCLCREAT:
1756 error = nfsrv_getattrbits(nd, &retattrbits,
1760 if (compare && !(*retcmpp)) {
1761 NFSSETSUPP_ATTRBIT(&checkattrbits);
1762 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1763 NFSCLRBIT_ATTRBIT(&checkattrbits,
1764 NFSATTRBIT_TIMEACCESSSET);
1765 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1767 *retcmpp = NFSERR_NOTSAME;
1772 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1774 if (compare && !(*retcmpp))
1775 *retcmpp = NFSERR_ATTRNOTSUPP;
1777 * and get out of the loop, since we can't parse
1778 * the unknown attrbute data.
1780 bitpos = NFSATTRBIT_MAX;
1786 * some clients pad the attrlist, so we need to skip over the
1789 if (attrsum > attrsize) {
1790 error = NFSERR_BADXDR;
1792 attrsize = NFSM_RNDUP(attrsize);
1793 if (attrsum < attrsize)
1794 error = nfsm_advance(nd, attrsize - attrsum, -1);
1797 NFSEXITCODE2(error, nd);
1802 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1803 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1804 * The first argument is a pointer to an nfsv4lock structure.
1805 * The second argument is 1 iff a blocking lock is wanted.
1806 * If this argument is 0, the call waits until no thread either wants nor
1807 * holds an exclusive lock.
1808 * It returns 1 if the lock was acquired, 0 otherwise.
1809 * If several processes call this function concurrently wanting the exclusive
1810 * lock, one will get the lock and the rest will return without getting the
1811 * lock. (If the caller must have the lock, it simply calls this function in a
1812 * loop until the function returns 1 to indicate the lock was acquired.)
1813 * Any usecnt must be decremented by calling nfsv4_relref() before
1814 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1815 * be called in a loop.
1816 * The isleptp argument is set to indicate if the call slept, iff not NULL
1817 * and the mp argument indicates to check for a forced dismount, iff not
1821 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1822 void *mutex, struct mount *mp)
1828 * If a lock is wanted, loop around until the lock is acquired by
1829 * someone and then released. If I want the lock, try to acquire it.
1830 * For a lock to be issued, no lock must be in force and the usecnt
1834 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1835 lp->nfslock_usecnt == 0) {
1836 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1837 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1840 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1842 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1843 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
1844 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1847 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1850 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1851 PZERO - 1, "nfsv4lck", NULL);
1852 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1853 lp->nfslock_usecnt == 0) {
1854 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1855 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1863 * Release the lock acquired by nfsv4_lock().
1864 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1865 * incremented, as well.
1868 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1871 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1873 lp->nfslock_usecnt++;
1878 * Release a reference cnt.
1881 nfsv4_relref(struct nfsv4lock *lp)
1884 if (lp->nfslock_usecnt <= 0)
1885 panic("nfsv4root ref cnt");
1886 lp->nfslock_usecnt--;
1887 if (lp->nfslock_usecnt == 0)
1892 * Get a reference cnt.
1893 * This function will wait for any exclusive lock to be released, but will
1894 * not wait for threads that want the exclusive lock. If priority needs
1895 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1896 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1897 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
1898 * return without getting a refcnt for that case.
1901 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1909 * Wait for a lock held.
1911 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1912 if (mp != NULL && NFSCL_FORCEDISM(mp))
1914 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1917 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1918 PZERO - 1, "nfsv4gr", NULL);
1920 if (mp != NULL && NFSCL_FORCEDISM(mp))
1923 lp->nfslock_usecnt++;
1927 * Get a reference as above, but return failure instead of sleeping if
1928 * an exclusive lock is held.
1931 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1934 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1937 lp->nfslock_usecnt++;
1942 * Test for a lock. Return 1 if locked, 0 otherwise.
1945 nfsv4_testlock(struct nfsv4lock *lp)
1948 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1949 lp->nfslock_usecnt == 0)
1955 * Wake up anyone sleeping, waiting for this lock.
1958 nfsv4_wanted(struct nfsv4lock *lp)
1961 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1962 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1963 wakeup((caddr_t)&lp->nfslock_lock);
1968 * Copy a string from an mbuf list into a character array.
1969 * Return EBADRPC if there is an mbuf error,
1973 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1982 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1983 rem = NFSM_RNDUP(siz) - siz;
1989 NFSBCOPY(cp, str, xfer);
1998 cp = NFSMTOD(mp, caddr_t);
2010 error = nfsm_advance(nd, rem, len);
2016 NFSEXITCODE2(error, nd);
2021 * Fill in the attributes as marked by the bitmap (V4).
2024 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2025 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2026 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2027 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2029 int bitpos, retnum = 0;
2031 int siz, prefixnum, error;
2032 u_char *cp, namestr[NFSV4_SMALLSTR];
2033 nfsattrbit_t attrbits, retbits;
2034 nfsattrbit_t *retbitp = &retbits;
2035 u_int32_t freenum, *retnump;
2038 struct nfsfsinfo fsinf;
2039 struct timespec temptime;
2040 NFSACL_T *aclp, *naclp = NULL;
2047 * First, set the bits that can be filled and get fsinfo.
2049 NFSSET_ATTRBIT(retbitp, attrbitp);
2051 * If both p and cred are NULL, it is a client side setattr call.
2052 * If both p and cred are not NULL, it is a server side reply call.
2053 * If p is not NULL and cred is NULL, it is a client side callback
2056 if (p == NULL && cred == NULL) {
2057 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2060 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2061 naclp = acl_alloc(M_WAITOK);
2064 nfsvno_getfs(&fsinf, isdgram);
2067 * Get the VFS_STATFS(), since some attributes need them.
2069 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2070 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2071 error = VFS_STATFS(mp, fs);
2074 nd->nd_repstat = NFSERR_ACCES;
2078 NFSCLRSTATFS_ATTRBIT(retbitp);
2084 * And the NFSv4 ACL...
2086 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2087 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2088 supports_nfsv4acls == 0))) {
2089 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2091 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2092 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2093 supports_nfsv4acls == 0)) {
2094 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2095 } else if (naclp != NULL) {
2096 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2097 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2099 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2101 NFSVOPUNLOCK(vp, 0);
2103 error = NFSERR_PERM;
2106 nd->nd_repstat = NFSERR_ACCES;
2110 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2116 * Put out the attribute bitmap for the ones being filled in
2117 * and get the field for the number of attributes returned.
2119 prefixnum = nfsrv_putattrbit(nd, retbitp);
2120 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2121 prefixnum += NFSX_UNSIGNED;
2124 * Now, loop around filling in the attributes for each bit set.
2126 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2127 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2129 case NFSATTRBIT_SUPPORTEDATTRS:
2130 NFSSETSUPP_ATTRBIT(&attrbits);
2131 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2132 && supports_nfsv4acls == 0)) {
2133 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2134 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2136 retnum += nfsrv_putattrbit(nd, &attrbits);
2138 case NFSATTRBIT_TYPE:
2139 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2140 *tl = vtonfsv34_type(vap->va_type);
2141 retnum += NFSX_UNSIGNED;
2143 case NFSATTRBIT_FHEXPIRETYPE:
2144 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2145 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2146 retnum += NFSX_UNSIGNED;
2148 case NFSATTRBIT_CHANGE:
2149 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2150 txdr_hyper(vap->va_filerev, tl);
2151 retnum += NFSX_HYPER;
2153 case NFSATTRBIT_SIZE:
2154 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2155 txdr_hyper(vap->va_size, tl);
2156 retnum += NFSX_HYPER;
2158 case NFSATTRBIT_LINKSUPPORT:
2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2160 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2164 retnum += NFSX_UNSIGNED;
2166 case NFSATTRBIT_SYMLINKSUPPORT:
2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2168 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2172 retnum += NFSX_UNSIGNED;
2174 case NFSATTRBIT_NAMEDATTR:
2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2177 retnum += NFSX_UNSIGNED;
2179 case NFSATTRBIT_FSID:
2180 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2182 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2184 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2185 retnum += NFSX_V4FSID;
2187 case NFSATTRBIT_UNIQUEHANDLES:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 retnum += NFSX_UNSIGNED;
2192 case NFSATTRBIT_LEASETIME:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2194 *tl = txdr_unsigned(nfsrv_lease);
2195 retnum += NFSX_UNSIGNED;
2197 case NFSATTRBIT_RDATTRERROR:
2198 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2199 *tl = txdr_unsigned(rderror);
2200 retnum += NFSX_UNSIGNED;
2203 * Recommended Attributes. (Only the supported ones.)
2205 case NFSATTRBIT_ACL:
2206 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2208 case NFSATTRBIT_ACLSUPPORT:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2210 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2211 retnum += NFSX_UNSIGNED;
2213 case NFSATTRBIT_CANSETTIME:
2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2215 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2219 retnum += NFSX_UNSIGNED;
2221 case NFSATTRBIT_CASEINSENSITIVE:
2222 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2224 retnum += NFSX_UNSIGNED;
2226 case NFSATTRBIT_CASEPRESERVING:
2227 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2229 retnum += NFSX_UNSIGNED;
2231 case NFSATTRBIT_CHOWNRESTRICTED:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2234 retnum += NFSX_UNSIGNED;
2236 case NFSATTRBIT_FILEHANDLE:
2237 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2239 case NFSATTRBIT_FILEID:
2240 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2241 uquad = vap->va_fileid;
2242 txdr_hyper(uquad, tl);
2243 retnum += NFSX_HYPER;
2245 case NFSATTRBIT_FILESAVAIL:
2247 * Check quota and use min(quota, f_ffree).
2249 freenum = fs->f_ffree;
2252 * ufs_quotactl() insists that the uid argument
2253 * equal p_ruid for non-root quota access, so
2254 * we'll just make sure that's the case.
2256 savuid = p->p_cred->p_ruid;
2257 p->p_cred->p_ruid = cred->cr_uid;
2258 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2259 cred->cr_uid, (caddr_t)&dqb))
2260 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2262 p->p_cred->p_ruid = savuid;
2264 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2266 *tl = txdr_unsigned(freenum);
2267 retnum += NFSX_HYPER;
2269 case NFSATTRBIT_FILESFREE:
2270 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2272 *tl = txdr_unsigned(fs->f_ffree);
2273 retnum += NFSX_HYPER;
2275 case NFSATTRBIT_FILESTOTAL:
2276 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2278 *tl = txdr_unsigned(fs->f_files);
2279 retnum += NFSX_HYPER;
2281 case NFSATTRBIT_FSLOCATIONS:
2282 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2285 retnum += 2 * NFSX_UNSIGNED;
2287 case NFSATTRBIT_HOMOGENEOUS:
2288 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2289 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2293 retnum += NFSX_UNSIGNED;
2295 case NFSATTRBIT_MAXFILESIZE:
2296 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2297 uquad = NFSRV_MAXFILESIZE;
2298 txdr_hyper(uquad, tl);
2299 retnum += NFSX_HYPER;
2301 case NFSATTRBIT_MAXLINK:
2302 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2303 *tl = txdr_unsigned(NFS_LINK_MAX);
2304 retnum += NFSX_UNSIGNED;
2306 case NFSATTRBIT_MAXNAME:
2307 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2308 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2309 retnum += NFSX_UNSIGNED;
2311 case NFSATTRBIT_MAXREAD:
2312 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2314 *tl = txdr_unsigned(fsinf.fs_rtmax);
2315 retnum += NFSX_HYPER;
2317 case NFSATTRBIT_MAXWRITE:
2318 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2320 *tl = txdr_unsigned(fsinf.fs_wtmax);
2321 retnum += NFSX_HYPER;
2323 case NFSATTRBIT_MODE:
2324 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2325 *tl = vtonfsv34_mode(vap->va_mode);
2326 retnum += NFSX_UNSIGNED;
2328 case NFSATTRBIT_NOTRUNC:
2329 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2331 retnum += NFSX_UNSIGNED;
2333 case NFSATTRBIT_NUMLINKS:
2334 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2335 *tl = txdr_unsigned(vap->va_nlink);
2336 retnum += NFSX_UNSIGNED;
2338 case NFSATTRBIT_OWNER:
2340 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2341 retnum += nfsm_strtom(nd, cp, siz);
2343 free(cp, M_NFSSTRING);
2345 case NFSATTRBIT_OWNERGROUP:
2347 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2348 retnum += nfsm_strtom(nd, cp, siz);
2350 free(cp, M_NFSSTRING);
2352 case NFSATTRBIT_QUOTAHARD:
2353 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2354 freenum = fs->f_bfree;
2356 freenum = fs->f_bavail;
2359 * ufs_quotactl() insists that the uid argument
2360 * equal p_ruid for non-root quota access, so
2361 * we'll just make sure that's the case.
2363 savuid = p->p_cred->p_ruid;
2364 p->p_cred->p_ruid = cred->cr_uid;
2365 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2366 cred->cr_uid, (caddr_t)&dqb))
2367 freenum = min(dqb.dqb_bhardlimit, freenum);
2368 p->p_cred->p_ruid = savuid;
2370 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2371 uquad = (u_int64_t)freenum;
2372 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2373 txdr_hyper(uquad, tl);
2374 retnum += NFSX_HYPER;
2376 case NFSATTRBIT_QUOTASOFT:
2377 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2378 freenum = fs->f_bfree;
2380 freenum = fs->f_bavail;
2383 * ufs_quotactl() insists that the uid argument
2384 * equal p_ruid for non-root quota access, so
2385 * we'll just make sure that's the case.
2387 savuid = p->p_cred->p_ruid;
2388 p->p_cred->p_ruid = cred->cr_uid;
2389 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2390 cred->cr_uid, (caddr_t)&dqb))
2391 freenum = min(dqb.dqb_bsoftlimit, freenum);
2392 p->p_cred->p_ruid = savuid;
2394 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2395 uquad = (u_int64_t)freenum;
2396 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2397 txdr_hyper(uquad, tl);
2398 retnum += NFSX_HYPER;
2400 case NFSATTRBIT_QUOTAUSED:
2404 * ufs_quotactl() insists that the uid argument
2405 * equal p_ruid for non-root quota access, so
2406 * we'll just make sure that's the case.
2408 savuid = p->p_cred->p_ruid;
2409 p->p_cred->p_ruid = cred->cr_uid;
2410 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2411 cred->cr_uid, (caddr_t)&dqb))
2412 freenum = dqb.dqb_curblocks;
2413 p->p_cred->p_ruid = savuid;
2415 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2416 uquad = (u_int64_t)freenum;
2417 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2418 txdr_hyper(uquad, tl);
2419 retnum += NFSX_HYPER;
2421 case NFSATTRBIT_RAWDEV:
2422 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2423 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2424 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2425 retnum += NFSX_V4SPECDATA;
2427 case NFSATTRBIT_SPACEAVAIL:
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2429 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2430 uquad = (u_int64_t)fs->f_bfree;
2432 uquad = (u_int64_t)fs->f_bavail;
2433 uquad *= fs->f_bsize;
2434 txdr_hyper(uquad, tl);
2435 retnum += NFSX_HYPER;
2437 case NFSATTRBIT_SPACEFREE:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2439 uquad = (u_int64_t)fs->f_bfree;
2440 uquad *= fs->f_bsize;
2441 txdr_hyper(uquad, tl);
2442 retnum += NFSX_HYPER;
2444 case NFSATTRBIT_SPACETOTAL:
2445 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2446 uquad = (u_int64_t)fs->f_blocks;
2447 uquad *= fs->f_bsize;
2448 txdr_hyper(uquad, tl);
2449 retnum += NFSX_HYPER;
2451 case NFSATTRBIT_SPACEUSED:
2452 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2453 txdr_hyper(vap->va_bytes, tl);
2454 retnum += NFSX_HYPER;
2456 case NFSATTRBIT_TIMEACCESS:
2457 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2458 txdr_nfsv4time(&vap->va_atime, tl);
2459 retnum += NFSX_V4TIME;
2461 case NFSATTRBIT_TIMEACCESSSET:
2462 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2463 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2464 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2465 txdr_nfsv4time(&vap->va_atime, tl);
2466 retnum += NFSX_V4SETTIME;
2468 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2469 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2470 retnum += NFSX_UNSIGNED;
2473 case NFSATTRBIT_TIMEDELTA:
2474 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2475 temptime.tv_sec = 0;
2476 temptime.tv_nsec = 1000000000 / hz;
2477 txdr_nfsv4time(&temptime, tl);
2478 retnum += NFSX_V4TIME;
2480 case NFSATTRBIT_TIMEMETADATA:
2481 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2482 txdr_nfsv4time(&vap->va_ctime, tl);
2483 retnum += NFSX_V4TIME;
2485 case NFSATTRBIT_TIMEMODIFY:
2486 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2487 txdr_nfsv4time(&vap->va_mtime, tl);
2488 retnum += NFSX_V4TIME;
2490 case NFSATTRBIT_TIMEMODIFYSET:
2491 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2492 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2493 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2494 txdr_nfsv4time(&vap->va_mtime, tl);
2495 retnum += NFSX_V4SETTIME;
2497 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2498 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2499 retnum += NFSX_UNSIGNED;
2502 case NFSATTRBIT_MOUNTEDONFILEID:
2503 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2505 uquad = mounted_on_fileno;
2507 uquad = vap->va_fileid;
2508 txdr_hyper(uquad, tl);
2509 retnum += NFSX_HYPER;
2511 case NFSATTRBIT_SUPPATTREXCLCREAT:
2512 NFSSETSUPP_ATTRBIT(&attrbits);
2513 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2514 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2515 retnum += nfsrv_putattrbit(nd, &attrbits);
2518 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2525 *retnump = txdr_unsigned(retnum);
2526 return (retnum + prefixnum);
2530 * Put the attribute bits onto an mbuf list.
2531 * Return the number of bytes of output generated.
2534 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2537 int cnt, i, bytesize;
2539 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2540 if (attrbitp->bits[cnt - 1])
2542 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2543 NFSM_BUILD(tl, u_int32_t *, bytesize);
2544 *tl++ = txdr_unsigned(cnt);
2545 for (i = 0; i < cnt; i++)
2546 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2551 * Convert a uid to a string.
2552 * If the lookup fails, just output the digits.
2554 * cpp - points to a buffer of size NFSV4_SMALLSTR
2555 * (malloc a larger one, as required)
2556 * retlenp - pointer to length to be returned
2559 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2562 struct nfsusrgrp *usrp;
2565 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2566 struct nfsrv_lughash *hp;
2570 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2572 * Always map nfsrv_defaultuid to "nobody".
2574 if (uid == nfsrv_defaultuid) {
2575 i = nfsrv_dnsnamelen + 7;
2577 if (len > NFSV4_SMALLSTR)
2578 free(cp, M_NFSSTRING);
2579 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2585 NFSBCOPY("nobody@", cp, 7);
2587 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2591 hp = NFSUSERHASH(uid);
2593 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2594 if (usrp->lug_uid == uid) {
2595 if (usrp->lug_expiry < NFSD_MONOSEC)
2598 * If the name doesn't already have an '@'
2599 * in it, append @domainname to it.
2601 for (i = 0; i < usrp->lug_namelen; i++) {
2602 if (usrp->lug_name[i] == '@') {
2608 i = usrp->lug_namelen;
2610 i = usrp->lug_namelen +
2611 nfsrv_dnsnamelen + 1;
2613 mtx_unlock(&hp->mtx);
2614 if (len > NFSV4_SMALLSTR)
2615 free(cp, M_NFSSTRING);
2616 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2622 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2623 if (!hasampersand) {
2624 cp += usrp->lug_namelen;
2626 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2628 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2629 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2631 mtx_unlock(&hp->mtx);
2635 mtx_unlock(&hp->mtx);
2637 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2639 if (ret == 0 && cnt < 2)
2644 * No match, just return a string of digits.
2648 while (tmp || i == 0) {
2652 len = (i > len) ? len : i;
2656 for (i = 0; i < len; i++) {
2657 *cp-- = '0' + (tmp % 10);
2664 * Get a credential for the uid with the server's group list.
2665 * If none is found, just return the credential passed in after
2666 * logging a warning message.
2669 nfsrv_getgrpscred(struct ucred *oldcred)
2671 struct nfsusrgrp *usrp;
2672 struct ucred *newcred;
2675 struct nfsrv_lughash *hp;
2678 uid = oldcred->cr_uid;
2680 if (nfsrv_dnsnamelen > 0) {
2681 hp = NFSUSERHASH(uid);
2683 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2684 if (usrp->lug_uid == uid) {
2685 if (usrp->lug_expiry < NFSD_MONOSEC)
2687 if (usrp->lug_cred != NULL) {
2688 newcred = crhold(usrp->lug_cred);
2692 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2693 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2695 mtx_unlock(&hp->mtx);
2699 mtx_unlock(&hp->mtx);
2701 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2703 if (ret == 0 && cnt < 2)
2710 * Convert a string to a uid.
2711 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2713 * If this is called from a client side mount using AUTH_SYS and the
2714 * string is made up entirely of digits, just convert the string to
2718 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2722 char *cp, *endstr, *str0;
2723 struct nfsusrgrp *usrp;
2727 struct nfsrv_lughash *hp, *hp2;
2730 error = NFSERR_BADOWNER;
2733 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2735 tuid = (uid_t)strtoul(str0, &endstr, 10);
2736 if ((endstr - str0) == len) {
2737 /* A numeric string. */
2738 if ((nd->nd_flag & ND_KERBV) == 0 &&
2739 ((nd->nd_flag & ND_NFSCL) != 0 ||
2740 nfsd_enable_stringtouid != 0))
2743 error = NFSERR_BADOWNER;
2749 cp = strchr(str0, '@');
2751 i = (int)(cp++ - str0);
2757 if (nfsrv_dnsnamelen > 0) {
2759 * If an '@' is found and the domain name matches, search for
2760 * the name with dns stripped off.
2761 * Mixed case alpahbetics will match for the domain name, but
2762 * all upper case will not.
2764 if (cnt == 0 && i < len && i > 0 &&
2765 (len - 1 - i) == nfsrv_dnsnamelen &&
2766 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2767 len -= (nfsrv_dnsnamelen + 1);
2772 * Check for the special case of "nobody".
2774 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2775 *uidp = nfsrv_defaultuid;
2780 hp = NFSUSERNAMEHASH(str, len);
2782 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2783 if (usrp->lug_namelen == len &&
2784 !NFSBCMP(usrp->lug_name, str, len)) {
2785 if (usrp->lug_expiry < NFSD_MONOSEC)
2787 hp2 = NFSUSERHASH(usrp->lug_uid);
2788 mtx_lock(&hp2->mtx);
2789 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2790 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2792 *uidp = usrp->lug_uid;
2793 mtx_unlock(&hp2->mtx);
2794 mtx_unlock(&hp->mtx);
2799 mtx_unlock(&hp->mtx);
2801 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2803 if (ret == 0 && cnt < 2)
2806 error = NFSERR_BADOWNER;
2814 * Convert a gid to a string.
2815 * gid - the group id
2816 * cpp - points to a buffer of size NFSV4_SMALLSTR
2817 * (malloc a larger one, as required)
2818 * retlenp - pointer to length to be returned
2821 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2824 struct nfsusrgrp *usrp;
2827 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2828 struct nfsrv_lughash *hp;
2832 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2834 * Always map nfsrv_defaultgid to "nogroup".
2836 if (gid == nfsrv_defaultgid) {
2837 i = nfsrv_dnsnamelen + 8;
2839 if (len > NFSV4_SMALLSTR)
2840 free(cp, M_NFSSTRING);
2841 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2847 NFSBCOPY("nogroup@", cp, 8);
2849 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2853 hp = NFSGROUPHASH(gid);
2855 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2856 if (usrp->lug_gid == gid) {
2857 if (usrp->lug_expiry < NFSD_MONOSEC)
2860 * If the name doesn't already have an '@'
2861 * in it, append @domainname to it.
2863 for (i = 0; i < usrp->lug_namelen; i++) {
2864 if (usrp->lug_name[i] == '@') {
2870 i = usrp->lug_namelen;
2872 i = usrp->lug_namelen +
2873 nfsrv_dnsnamelen + 1;
2875 mtx_unlock(&hp->mtx);
2876 if (len > NFSV4_SMALLSTR)
2877 free(cp, M_NFSSTRING);
2878 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2884 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2885 if (!hasampersand) {
2886 cp += usrp->lug_namelen;
2888 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2890 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2891 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2893 mtx_unlock(&hp->mtx);
2897 mtx_unlock(&hp->mtx);
2899 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2901 if (ret == 0 && cnt < 2)
2906 * No match, just return a string of digits.
2910 while (tmp || i == 0) {
2914 len = (i > len) ? len : i;
2918 for (i = 0; i < len; i++) {
2919 *cp-- = '0' + (tmp % 10);
2926 * Convert a string to a gid.
2927 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2929 * If this is called from a client side mount using AUTH_SYS and the
2930 * string is made up entirely of digits, just convert the string to
2934 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2938 char *cp, *endstr, *str0;
2939 struct nfsusrgrp *usrp;
2943 struct nfsrv_lughash *hp, *hp2;
2946 error = NFSERR_BADOWNER;
2949 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2951 tgid = (gid_t)strtoul(str0, &endstr, 10);
2952 if ((endstr - str0) == len) {
2953 /* A numeric string. */
2954 if ((nd->nd_flag & ND_KERBV) == 0 &&
2955 ((nd->nd_flag & ND_NFSCL) != 0 ||
2956 nfsd_enable_stringtouid != 0))
2959 error = NFSERR_BADOWNER;
2965 cp = strchr(str0, '@');
2967 i = (int)(cp++ - str0);
2973 if (nfsrv_dnsnamelen > 0) {
2975 * If an '@' is found and the dns name matches, search for the
2976 * name with the dns stripped off.
2978 if (cnt == 0 && i < len && i > 0 &&
2979 (len - 1 - i) == nfsrv_dnsnamelen &&
2980 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2981 len -= (nfsrv_dnsnamelen + 1);
2986 * Check for the special case of "nogroup".
2988 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2989 *gidp = nfsrv_defaultgid;
2994 hp = NFSGROUPNAMEHASH(str, len);
2996 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2997 if (usrp->lug_namelen == len &&
2998 !NFSBCMP(usrp->lug_name, str, len)) {
2999 if (usrp->lug_expiry < NFSD_MONOSEC)
3001 hp2 = NFSGROUPHASH(usrp->lug_gid);
3002 mtx_lock(&hp2->mtx);
3003 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3004 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3006 *gidp = usrp->lug_gid;
3007 mtx_unlock(&hp2->mtx);
3008 mtx_unlock(&hp->mtx);
3013 mtx_unlock(&hp->mtx);
3015 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3017 if (ret == 0 && cnt < 2)
3020 error = NFSERR_BADOWNER;
3028 * Cmp len chars, allowing mixed case in the first argument to match lower
3029 * case in the second, but not if the first argument is all upper case.
3030 * Return 0 for a match, 1 otherwise.
3033 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3039 for (i = 0; i < len; i++) {
3040 if (*cp >= 'A' && *cp <= 'Z') {
3041 tmp = *cp++ + ('a' - 'A');
3044 if (tmp >= 'a' && tmp <= 'z')
3057 * Set the port for the nfsuserd.
3060 nfsrv_nfsuserdport(struct sockaddr *sad, u_short port, NFSPROC_T *p)
3062 struct nfssockreq *rp;
3063 struct sockaddr_in *ad;
3067 if (nfsrv_nfsuserd) {
3070 free(sad, M_SONAME);
3076 * Set up the socket record and connect.
3078 rp = &nfsrv_nfsuserdsock;
3079 rp->nr_client = NULL;
3081 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3083 /* Use the AF_LOCAL socket address passed in. */
3084 rp->nr_sotype = SOCK_STREAM;
3088 /* Use the port# for a UDP socket (old nfsuserd). */
3089 rp->nr_sotype = SOCK_DGRAM;
3090 rp->nr_soproto = IPPROTO_UDP;
3091 rp->nr_nam = malloc(sizeof(*rp->nr_nam), M_SONAME, M_WAITOK |
3093 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3094 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3095 ad->sin_family = AF_INET;
3096 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);
3097 ad->sin_port = port;
3099 rp->nr_prog = RPCPROG_NFSUSERD;
3100 rp->nr_vers = RPCNFSUSERD_VERS;
3101 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3103 free(rp->nr_nam, M_SONAME);
3112 * Delete the nfsuserd port.
3115 nfsrv_nfsuserddelport(void)
3119 if (nfsrv_nfsuserd == 0) {
3125 newnfs_disconnect(&nfsrv_nfsuserdsock);
3126 free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3130 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3132 * Returns 0 upon success, non-zero otherwise.
3135 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3138 struct nfsrv_descript *nd;
3140 struct nfsrv_descript nfsd;
3145 if (nfsrv_nfsuserd == 0) {
3152 cred = newnfs_getcred();
3153 nd->nd_flag = ND_GSSINITREPLY;
3156 nd->nd_procnum = procnum;
3157 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3158 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3159 if (procnum == RPCNFSUSERD_GETUID)
3160 *tl = txdr_unsigned(uid);
3162 *tl = txdr_unsigned(gid);
3165 (void) nfsm_strtom(nd, name, len);
3167 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3168 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3171 mbuf_freem(nd->nd_mrep);
3172 error = nd->nd_repstat;
3180 * This function is called from the nfssvc(2) system call, to update the
3181 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3184 nfssvc_idname(struct nfsd_idargs *nidp)
3186 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3187 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3188 int i, group_locked, groupname_locked, user_locked, username_locked;
3193 static int onethread = 0;
3194 static time_t lasttime = 0;
3196 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3200 if (nidp->nid_flag & NFSID_INITIALIZE) {
3201 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3202 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3205 free(cp, M_NFSSTRING);
3208 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3210 * Free up all the old stuff and reinitialize hash
3211 * lists. All mutexes for both lists must be locked,
3212 * with the user/group name ones before the uid/gid
3213 * ones, to avoid a LOR.
3215 for (i = 0; i < nfsrv_lughashsize; i++)
3216 mtx_lock(&nfsusernamehash[i].mtx);
3217 for (i = 0; i < nfsrv_lughashsize; i++)
3218 mtx_lock(&nfsuserhash[i].mtx);
3219 for (i = 0; i < nfsrv_lughashsize; i++)
3220 TAILQ_FOREACH_SAFE(usrp,
3221 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3222 nfsrv_removeuser(usrp, 1);
3223 for (i = 0; i < nfsrv_lughashsize; i++)
3224 mtx_unlock(&nfsuserhash[i].mtx);
3225 for (i = 0; i < nfsrv_lughashsize; i++)
3226 mtx_unlock(&nfsusernamehash[i].mtx);
3227 for (i = 0; i < nfsrv_lughashsize; i++)
3228 mtx_lock(&nfsgroupnamehash[i].mtx);
3229 for (i = 0; i < nfsrv_lughashsize; i++)
3230 mtx_lock(&nfsgrouphash[i].mtx);
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 TAILQ_FOREACH_SAFE(usrp,
3233 &nfsgrouphash[i].lughead, lug_numhash,
3235 nfsrv_removeuser(usrp, 0);
3236 for (i = 0; i < nfsrv_lughashsize; i++)
3237 mtx_unlock(&nfsgrouphash[i].mtx);
3238 for (i = 0; i < nfsrv_lughashsize; i++)
3239 mtx_unlock(&nfsgroupnamehash[i].mtx);
3240 free(nfsrv_dnsname, M_NFSSTRING);
3241 nfsrv_dnsname = NULL;
3243 if (nfsuserhash == NULL) {
3244 /* Allocate the hash tables. */
3245 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3246 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3248 for (i = 0; i < nfsrv_lughashsize; i++)
3249 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3250 NULL, MTX_DEF | MTX_DUPOK);
3251 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3252 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3254 for (i = 0; i < nfsrv_lughashsize; i++)
3255 mtx_init(&nfsusernamehash[i].mtx,
3256 "nfsusrhash", NULL, MTX_DEF |
3258 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3259 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3261 for (i = 0; i < nfsrv_lughashsize; i++)
3262 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3263 NULL, MTX_DEF | MTX_DUPOK);
3264 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3265 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3267 for (i = 0; i < nfsrv_lughashsize; i++)
3268 mtx_init(&nfsgroupnamehash[i].mtx,
3269 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3271 /* (Re)initialize the list heads. */
3272 for (i = 0; i < nfsrv_lughashsize; i++)
3273 TAILQ_INIT(&nfsuserhash[i].lughead);
3274 for (i = 0; i < nfsrv_lughashsize; i++)
3275 TAILQ_INIT(&nfsusernamehash[i].lughead);
3276 for (i = 0; i < nfsrv_lughashsize; i++)
3277 TAILQ_INIT(&nfsgrouphash[i].lughead);
3278 for (i = 0; i < nfsrv_lughashsize; i++)
3279 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3282 * Put name in "DNS" string.
3285 nfsrv_defaultuid = nidp->nid_uid;
3286 nfsrv_defaultgid = nidp->nid_gid;
3288 nfsrv_usermax = nidp->nid_usermax;
3289 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3294 * malloc the new one now, so any potential sleep occurs before
3295 * manipulation of the lists.
3297 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3298 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3299 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3301 if (error == 0 && nidp->nid_ngroup > 0 &&
3302 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3303 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3305 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3306 sizeof(gid_t) * nidp->nid_ngroup);
3309 * Create a credential just like svc_getcred(),
3310 * but using the group list provided.
3313 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3314 crsetgroups(cr, nidp->nid_ngroup, grps);
3315 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3316 cr->cr_prison = &prison0;
3317 prison_hold(cr->cr_prison);
3319 mac_cred_associate_nfsd(cr);
3321 newusrp->lug_cred = cr;
3326 free(newusrp, M_NFSUSERGROUP);
3329 newusrp->lug_namelen = nidp->nid_namelen;
3332 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3333 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3334 * The flags user_locked, username_locked, group_locked and
3335 * groupname_locked are set to indicate all of those hash lists are
3336 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3337 * the respective one mutex is locked.
3339 user_locked = username_locked = group_locked = groupname_locked = 0;
3340 hp_name = hp_idnum = NULL;
3343 * Delete old entries, as required.
3345 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3346 /* Must lock all username hash lists first, to avoid a LOR. */
3347 for (i = 0; i < nfsrv_lughashsize; i++)
3348 mtx_lock(&nfsusernamehash[i].mtx);
3349 username_locked = 1;
3350 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3351 mtx_lock(&hp_idnum->mtx);
3352 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3354 if (usrp->lug_uid == nidp->nid_uid)
3355 nfsrv_removeuser(usrp, 1);
3357 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3358 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3359 newusrp->lug_namelen);
3360 mtx_lock(&hp_name->mtx);
3361 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3363 if (usrp->lug_namelen == newusrp->lug_namelen &&
3364 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3365 usrp->lug_namelen)) {
3366 thp = NFSUSERHASH(usrp->lug_uid);
3367 mtx_lock(&thp->mtx);
3368 nfsrv_removeuser(usrp, 1);
3369 mtx_unlock(&thp->mtx);
3372 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3373 mtx_lock(&hp_idnum->mtx);
3374 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3375 /* Must lock all groupname hash lists first, to avoid a LOR. */
3376 for (i = 0; i < nfsrv_lughashsize; i++)
3377 mtx_lock(&nfsgroupnamehash[i].mtx);
3378 groupname_locked = 1;
3379 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3380 mtx_lock(&hp_idnum->mtx);
3381 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3383 if (usrp->lug_gid == nidp->nid_gid)
3384 nfsrv_removeuser(usrp, 0);
3386 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3387 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3388 newusrp->lug_namelen);
3389 mtx_lock(&hp_name->mtx);
3390 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3392 if (usrp->lug_namelen == newusrp->lug_namelen &&
3393 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3394 usrp->lug_namelen)) {
3395 thp = NFSGROUPHASH(usrp->lug_gid);
3396 mtx_lock(&thp->mtx);
3397 nfsrv_removeuser(usrp, 0);
3398 mtx_unlock(&thp->mtx);
3401 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3402 mtx_lock(&hp_idnum->mtx);
3406 * Now, we can add the new one.
3408 if (nidp->nid_usertimeout)
3409 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3411 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3412 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3413 newusrp->lug_uid = nidp->nid_uid;
3414 thp = NFSUSERHASH(newusrp->lug_uid);
3415 mtx_assert(&thp->mtx, MA_OWNED);
3416 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3417 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3418 mtx_assert(&thp->mtx, MA_OWNED);
3419 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3420 atomic_add_int(&nfsrv_usercnt, 1);
3421 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3422 newusrp->lug_gid = nidp->nid_gid;
3423 thp = NFSGROUPHASH(newusrp->lug_gid);
3424 mtx_assert(&thp->mtx, MA_OWNED);
3425 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3426 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3427 mtx_assert(&thp->mtx, MA_OWNED);
3428 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3429 atomic_add_int(&nfsrv_usercnt, 1);
3431 if (newusrp->lug_cred != NULL)
3432 crfree(newusrp->lug_cred);
3433 free(newusrp, M_NFSUSERGROUP);
3437 * Once per second, allow one thread to trim the cache.
3439 if (lasttime < NFSD_MONOSEC &&
3440 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3442 * First, unlock the single mutexes, so that all entries
3443 * can be locked and any LOR is avoided.
3445 if (hp_name != NULL) {
3446 mtx_unlock(&hp_name->mtx);
3449 if (hp_idnum != NULL) {
3450 mtx_unlock(&hp_idnum->mtx);
3454 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3455 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3456 if (username_locked == 0) {
3457 for (i = 0; i < nfsrv_lughashsize; i++)
3458 mtx_lock(&nfsusernamehash[i].mtx);
3459 username_locked = 1;
3461 KASSERT(user_locked == 0,
3462 ("nfssvc_idname: user_locked"));
3463 for (i = 0; i < nfsrv_lughashsize; i++)
3464 mtx_lock(&nfsuserhash[i].mtx);
3466 for (i = 0; i < nfsrv_lughashsize; i++) {
3467 TAILQ_FOREACH_SAFE(usrp,
3468 &nfsuserhash[i].lughead, lug_numhash,
3470 if (usrp->lug_expiry < NFSD_MONOSEC)
3471 nfsrv_removeuser(usrp, 1);
3473 for (i = 0; i < nfsrv_lughashsize; i++) {
3475 * Trim the cache using an approximate LRU
3476 * algorithm. This code deletes the least
3477 * recently used entry on each hash list.
3479 if (nfsrv_usercnt <= nfsrv_usermax)
3481 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3483 nfsrv_removeuser(usrp, 1);
3486 if (groupname_locked == 0) {
3487 for (i = 0; i < nfsrv_lughashsize; i++)
3488 mtx_lock(&nfsgroupnamehash[i].mtx);
3489 groupname_locked = 1;
3491 KASSERT(group_locked == 0,
3492 ("nfssvc_idname: group_locked"));
3493 for (i = 0; i < nfsrv_lughashsize; i++)
3494 mtx_lock(&nfsgrouphash[i].mtx);
3496 for (i = 0; i < nfsrv_lughashsize; i++) {
3497 TAILQ_FOREACH_SAFE(usrp,
3498 &nfsgrouphash[i].lughead, lug_numhash,
3500 if (usrp->lug_expiry < NFSD_MONOSEC)
3501 nfsrv_removeuser(usrp, 0);
3503 for (i = 0; i < nfsrv_lughashsize; i++) {
3505 * Trim the cache using an approximate LRU
3506 * algorithm. This code deletes the least
3507 * recently user entry on each hash list.
3509 if (nfsrv_usercnt <= nfsrv_usermax)
3511 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3513 nfsrv_removeuser(usrp, 0);
3516 lasttime = NFSD_MONOSEC;
3517 atomic_store_rel_int(&onethread, 0);
3520 /* Now, unlock all locked mutexes. */
3521 if (hp_idnum != NULL)
3522 mtx_unlock(&hp_idnum->mtx);
3523 if (hp_name != NULL)
3524 mtx_unlock(&hp_name->mtx);
3525 if (user_locked != 0)
3526 for (i = 0; i < nfsrv_lughashsize; i++)
3527 mtx_unlock(&nfsuserhash[i].mtx);
3528 if (username_locked != 0)
3529 for (i = 0; i < nfsrv_lughashsize; i++)
3530 mtx_unlock(&nfsusernamehash[i].mtx);
3531 if (group_locked != 0)
3532 for (i = 0; i < nfsrv_lughashsize; i++)
3533 mtx_unlock(&nfsgrouphash[i].mtx);
3534 if (groupname_locked != 0)
3535 for (i = 0; i < nfsrv_lughashsize; i++)
3536 mtx_unlock(&nfsgroupnamehash[i].mtx);
3543 * Remove a user/group name element.
3546 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3548 struct nfsrv_lughash *hp;
3551 hp = NFSUSERHASH(usrp->lug_uid);
3552 mtx_assert(&hp->mtx, MA_OWNED);
3553 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3554 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3555 mtx_assert(&hp->mtx, MA_OWNED);
3556 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3558 hp = NFSGROUPHASH(usrp->lug_gid);
3559 mtx_assert(&hp->mtx, MA_OWNED);
3560 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3561 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3562 mtx_assert(&hp->mtx, MA_OWNED);
3563 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3565 atomic_add_int(&nfsrv_usercnt, -1);
3566 if (usrp->lug_cred != NULL)
3567 crfree(usrp->lug_cred);
3568 free(usrp, M_NFSUSERGROUP);
3572 * Free up all the allocations related to the name<-->id cache.
3573 * This function should only be called when the nfsuserd daemon isn't
3574 * running, since it doesn't do any locking.
3575 * This function is meant to be used when the nfscommon module is unloaded.
3578 nfsrv_cleanusergroup(void)
3580 struct nfsrv_lughash *hp, *hp2;
3581 struct nfsusrgrp *nusrp, *usrp;
3584 if (nfsuserhash == NULL)
3587 for (i = 0; i < nfsrv_lughashsize; i++) {
3588 hp = &nfsuserhash[i];
3589 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3590 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3591 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3593 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3594 if (usrp->lug_cred != NULL)
3595 crfree(usrp->lug_cred);
3596 free(usrp, M_NFSUSERGROUP);
3598 hp = &nfsgrouphash[i];
3599 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3600 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3601 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3603 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3604 if (usrp->lug_cred != NULL)
3605 crfree(usrp->lug_cred);
3606 free(usrp, M_NFSUSERGROUP);
3608 mtx_destroy(&nfsuserhash[i].mtx);
3609 mtx_destroy(&nfsusernamehash[i].mtx);
3610 mtx_destroy(&nfsgroupnamehash[i].mtx);
3611 mtx_destroy(&nfsgrouphash[i].mtx);
3613 free(nfsuserhash, M_NFSUSERGROUP);
3614 free(nfsusernamehash, M_NFSUSERGROUP);
3615 free(nfsgrouphash, M_NFSUSERGROUP);
3616 free(nfsgroupnamehash, M_NFSUSERGROUP);
3617 free(nfsrv_dnsname, M_NFSSTRING);
3621 * This function scans a byte string and checks for UTF-8 compliance.
3622 * It returns 0 if it conforms and NFSERR_INVAL if not.
3625 nfsrv_checkutf8(u_int8_t *cp, int len)
3627 u_int32_t val = 0x0;
3628 int cnt = 0, gotd = 0, shift = 0;
3630 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3634 * Here are what the variables are used for:
3635 * val - the calculated value of a multibyte char, used to check
3636 * that it was coded with the correct range
3637 * cnt - the number of 10xxxxxx bytes to follow
3638 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3639 * shift - lower order bits of range (ie. "val >> shift" should
3640 * not be 0, in other words, dividing by the lower bound
3641 * of the range should get a non-zero value)
3642 * byte - used to calculate cnt
3646 /* This handles the 10xxxxxx bytes */
3647 if ((*cp & 0xc0) != 0x80 ||
3648 (gotd && (*cp & 0x20))) {
3649 error = NFSERR_INVAL;
3654 val |= (*cp & 0x3f);
3656 if (cnt == 0 && (val >> shift) == 0x0) {
3657 error = NFSERR_INVAL;
3660 } else if (*cp & 0x80) {
3661 /* first byte of multi byte char */
3663 while ((byte & 0x40) && cnt < 6) {
3667 if (cnt == 0 || cnt == 6) {
3668 error = NFSERR_INVAL;
3671 val = (*cp & (0x3f >> cnt));
3672 shift = utf8_shift[cnt - 1];
3673 if (cnt == 2 && val == 0xd)
3674 /* Check for the 0xd800-0xdfff case */
3681 error = NFSERR_INVAL;
3689 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3690 * strings, one with the root path in it and the other with the list of
3691 * locations. The list is in the same format as is found in nfr_refs.
3692 * It is a "," separated list of entries, where each of them is of the
3693 * form <server>:<rootpath>. For example
3694 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3695 * The nilp argument is set to 1 for the special case of a null fs_root
3696 * and an empty server list.
3697 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3698 * number of xdr bytes parsed in sump.
3701 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3702 int *sump, int *nilp)
3705 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3706 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3708 SLIST_ENTRY(list) next;
3712 SLIST_HEAD(, list) head;
3719 * Get the fs_root path and check for the special case of null path
3720 * and 0 length server list.
3722 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3723 len = fxdr_unsigned(int, *tl);
3724 if (len < 0 || len > 10240) {
3725 error = NFSERR_BADXDR;
3729 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3731 error = NFSERR_BADXDR;
3735 *sump = 2 * NFSX_UNSIGNED;
3739 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3740 error = nfsrv_mtostr(nd, cp, len);
3742 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3743 cnt = fxdr_unsigned(int, *tl);
3745 error = NFSERR_BADXDR;
3751 * Now, loop through the location list and make up the srvlist.
3753 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3754 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3757 for (i = 0; i < cnt; i++) {
3759 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3760 nsrv = fxdr_unsigned(int, *tl);
3762 error = NFSERR_BADXDR;
3767 * Handle the first server by putting it in the srvstr.
3769 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3770 len = fxdr_unsigned(int, *tl);
3771 if (len <= 0 || len > 1024) {
3772 error = NFSERR_BADXDR;
3775 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3780 error = nfsrv_mtostr(nd, cp3, len);
3786 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3787 for (j = 1; j < nsrv; j++) {
3789 * Yuck, put them in an slist and process them later.
3791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3792 len = fxdr_unsigned(int, *tl);
3793 if (len <= 0 || len > 1024) {
3794 error = NFSERR_BADXDR;
3797 lsp = (struct list *)malloc(sizeof (struct list)
3798 + len, M_TEMP, M_WAITOK);
3799 error = nfsrv_mtostr(nd, lsp->host, len);
3802 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3804 SLIST_INSERT_HEAD(&head, lsp, next);
3808 * Finally, we can get the path.
3810 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3811 len = fxdr_unsigned(int, *tl);
3812 if (len <= 0 || len > 1024) {
3813 error = NFSERR_BADXDR;
3816 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3817 error = nfsrv_mtostr(nd, cp3, len);
3820 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3825 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3826 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3829 NFSBCOPY(lsp->host, cp3, lsp->len);
3832 NFSBCOPY(str, cp3, stringlen);
3835 siz += (lsp->len + stringlen + 2);
3842 NFSEXITCODE2(0, nd);
3846 free(cp, M_NFSSTRING);
3848 free(cp2, M_NFSSTRING);
3849 NFSEXITCODE2(error, nd);
3854 * Make the malloc'd space large enough. This is a pain, but the xdr
3855 * doesn't set an upper bound on the side, so...
3858 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3865 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3866 NFSBCOPY(*cpp, cp, *slenp);
3867 free(*cpp, M_NFSSTRING);
3871 *slenp = siz + 1024;
3875 * Initialize the reply header data structures.
3878 nfsrvd_rephead(struct nfsrv_descript *nd)
3883 * If this is a big reply, use a cluster.
3885 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3886 nfs_bigreply[nd->nd_procnum]) {
3887 NFSMCLGET(mreq, M_WAITOK);
3895 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3896 mbuf_setlen(mreq, 0);
3898 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3899 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3903 * Lock a socket against others.
3904 * Currently used to serialize connect/disconnect attempts.
3907 newnfs_sndlock(int *flagp)
3912 while (*flagp & NFSR_SNDLOCK) {
3913 *flagp |= NFSR_WANTSND;
3916 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3917 PZERO - 1, "nfsndlck", &ts);
3919 *flagp |= NFSR_SNDLOCK;
3925 * Unlock the stream socket for others.
3928 newnfs_sndunlock(int *flagp)
3932 if ((*flagp & NFSR_SNDLOCK) == 0)
3933 panic("nfs sndunlock");
3934 *flagp &= ~NFSR_SNDLOCK;
3935 if (*flagp & NFSR_WANTSND) {
3936 *flagp &= ~NFSR_WANTSND;
3937 wakeup((caddr_t)flagp);
3943 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
3944 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
3946 struct in_addr saddr;
3947 uint32_t portnum, *tl;
3949 sa_family_t af = AF_UNSPEC;
3950 char addr[64], protocol[5], *cp;
3951 int cantparse = 0, error = 0;
3954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3955 i = fxdr_unsigned(int, *tl);
3956 if (i >= 3 && i <= 4) {
3957 error = nfsrv_mtostr(nd, protocol, i);
3960 if (strcmp(protocol, "tcp") == 0) {
3963 } else if (strcmp(protocol, "udp") == 0) {
3966 } else if (strcmp(protocol, "tcp6") == 0) {
3969 } else if (strcmp(protocol, "udp6") == 0) {
3977 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3983 i = fxdr_unsigned(int, *tl);
3985 error = NFSERR_BADXDR;
3987 } else if (cantparse == 0 && i >= 11 && i < 64) {
3989 * The shortest address is 11chars and the longest is < 64.
3991 error = nfsrv_mtostr(nd, addr, i);
3995 /* Find the port# at the end and extract that. */
3999 /* Count back two '.'s from end to get port# field. */
4000 for (j = 0; j < i; j++) {
4010 * The NFSv4 port# is appended as .N.N, where N is
4011 * a decimal # in the range 0-255, just like an inet4
4012 * address. Cheat and use inet_aton(), which will
4013 * return a Class A address and then shift the high
4014 * order 8bits over to convert it to the port#.
4017 if (inet_aton(cp, &saddr) == 1) {
4018 portnum = ntohl(saddr.s_addr);
4019 portv = (uint16_t)((portnum >> 16) |
4025 if (cantparse == 0) {
4026 if (af == AF_INET) {
4027 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4028 sin->sin_len = sizeof(*sin);
4029 sin->sin_family = AF_INET;
4030 sin->sin_port = htons(portv);
4035 if (inet_pton(af, addr, &sin6->sin6_addr)
4037 sin6->sin6_len = sizeof(*sin6);
4038 sin6->sin6_family = AF_INET6;
4039 sin6->sin6_port = htons(portv);
4047 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4058 * Handle an NFSv4.1 Sequence request for the session.
4059 * If reply != NULL, use it to return the cached reply, as required.
4060 * The client gets a cached reply via this call for callbacks, however the
4061 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4064 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4065 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4072 if (slotid > maxslot)
4073 return (NFSERR_BADSLOT);
4074 if (seqid == slots[slotid].nfssl_seq) {
4076 if (slots[slotid].nfssl_inprog != 0)
4077 error = NFSERR_DELAY;
4078 else if (slots[slotid].nfssl_reply != NULL) {
4079 if (reply != NULL) {
4080 *reply = slots[slotid].nfssl_reply;
4081 slots[slotid].nfssl_reply = NULL;
4083 slots[slotid].nfssl_inprog = 1;
4084 error = NFSERR_REPLYFROMCACHE;
4086 /* No reply cached, so just do it. */
4087 slots[slotid].nfssl_inprog = 1;
4088 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4089 if (slots[slotid].nfssl_reply != NULL)
4090 m_freem(slots[slotid].nfssl_reply);
4091 slots[slotid].nfssl_reply = NULL;
4092 slots[slotid].nfssl_inprog = 1;
4093 slots[slotid].nfssl_seq++;
4095 error = NFSERR_SEQMISORDERED;
4100 * Cache this reply for the slot.
4101 * Use the "rep" argument to return the cached reply if repstat is set to
4102 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4105 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4109 if (repstat == NFSERR_REPLYFROMCACHE) {
4110 *rep = slots[slotid].nfssl_reply;
4111 slots[slotid].nfssl_reply = NULL;
4113 if (slots[slotid].nfssl_reply != NULL)
4114 m_freem(slots[slotid].nfssl_reply);
4115 slots[slotid].nfssl_reply = *rep;
4117 slots[slotid].nfssl_inprog = 0;
4121 * Generate the xdr for an NFSv4.1 Sequence Operation.
4124 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4125 struct nfsclsession *sep, int dont_replycache)
4127 uint32_t *tl, slotseq = 0;
4128 int error, maxslot, slotpos;
4129 uint8_t sessionid[NFSX_V4SESSIONID];
4131 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4134 /* Build the Sequence arguments. */
4135 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4136 nd->nd_sequence = tl;
4137 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4138 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4139 nd->nd_slotseq = tl;
4141 *tl++ = txdr_unsigned(slotseq);
4142 *tl++ = txdr_unsigned(slotpos);
4143 *tl++ = txdr_unsigned(maxslot);
4144 if (dont_replycache == 0)
4150 * There are two errors and the rest of the session can
4152 * NFSERR_BADSESSION: This bad session should just generate
4153 * the same error again when the RPC is retried.
4154 * ESTALE: A forced dismount is in progress and will cause the
4155 * RPC to fail later.
4162 nd->nd_flag |= ND_HASSEQUENCE;
4166 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4167 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4169 int i, maxslot, slotpos;
4172 /* Find an unused slot. */
4175 mtx_lock(&sep->nfsess_mtx);
4177 if (nmp != NULL && sep->nfsess_defunct != 0) {
4178 /* Just return the bad session. */
4179 bcopy(sep->nfsess_sessionid, sessionid,
4181 mtx_unlock(&sep->nfsess_mtx);
4182 return (NFSERR_BADSESSION);
4185 for (i = 0; i < sep->nfsess_foreslots; i++) {
4186 if ((bitval & sep->nfsess_slots) == 0) {
4188 sep->nfsess_slots |= bitval;
4189 sep->nfsess_slotseq[i]++;
4190 *slotseqp = sep->nfsess_slotseq[i];
4195 if (slotpos == -1) {
4197 * If a forced dismount is in progress, just return.
4198 * This RPC attempt will fail when it calls
4201 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4202 mtx_unlock(&sep->nfsess_mtx);
4205 /* Wake up once/sec, to check for a forced dismount. */
4206 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4207 PZERO, "nfsclseq", hz);
4209 } while (slotpos == -1);
4210 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4212 for (i = 0; i < 64; i++) {
4213 if ((bitval & sep->nfsess_slots) != 0)
4217 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4218 mtx_unlock(&sep->nfsess_mtx);
4219 *slotposp = slotpos;
4220 *maxslotp = maxslot;
4225 * Free a session slot.
4228 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4235 mtx_lock(&sep->nfsess_mtx);
4236 if ((bitval & sep->nfsess_slots) == 0)
4237 printf("freeing free slot!!\n");
4238 sep->nfsess_slots &= ~bitval;
4239 wakeup(&sep->nfsess_slots);
4240 mtx_unlock(&sep->nfsess_mtx);