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 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
682 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
684 FREE((caddr_t)nfhp, M_NFSFH);
690 NFSEXITCODE2(error, nd);
695 * Break down the nfsv4 acl.
696 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
699 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
700 int *aclsizep, __unused NFSPROC_T *p)
704 int acecnt, error = 0, aceerr = 0, acesize;
710 * Parse out the ace entries and expect them to conform to
711 * what can be supported by R/W/X bits.
713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
714 aclsize = NFSX_UNSIGNED;
715 acecnt = fxdr_unsigned(int, *tl);
716 if (acecnt > ACL_MAX_ENTRIES)
717 aceerr = NFSERR_ATTRNOTSUPP;
718 if (nfsrv_useacl == 0)
719 aceerr = NFSERR_ATTRNOTSUPP;
720 for (i = 0; i < acecnt; i++) {
722 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
723 &aceerr, &acesize, p);
725 error = nfsrv_skipace(nd, &acesize);
731 aclp->acl_cnt = acecnt;
737 NFSEXITCODE2(error, nd);
742 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
745 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
750 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
751 len = fxdr_unsigned(int, *(tl + 3));
752 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
754 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
755 NFSEXITCODE2(error, nd);
760 * Get attribute bits from an mbuf list.
761 * Returns EBADRPC for a parsing error, 0 otherwise.
762 * If the clearinvalid flag is set, clear the bits not supported.
765 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
773 cnt = fxdr_unsigned(int, *tl);
775 error = NFSERR_BADXDR;
778 if (cnt > NFSATTRBIT_MAXWORDS)
779 outcnt = NFSATTRBIT_MAXWORDS;
782 NFSZERO_ATTRBIT(attrbitp);
784 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
785 for (i = 0; i < outcnt; i++)
786 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
788 for (i = 0; i < (cnt - outcnt); i++) {
789 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
790 if (retnotsupp != NULL && *tl != 0)
791 *retnotsupp = NFSERR_ATTRNOTSUPP;
794 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
796 NFSEXITCODE2(error, nd);
801 * Get the attributes for V4.
802 * If the compare flag is true, test for any attribute changes,
803 * otherwise return the attribute values.
804 * These attributes cover fields in "struct vattr", "struct statfs",
805 * "struct nfsfsinfo", the file handle and the lease duration.
806 * The value of retcmpp is set to 1 if all attributes are the same,
808 * Returns EBADRPC if it can't be parsed, 0 otherwise.
811 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
812 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
813 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
814 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
815 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
818 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
819 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
820 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
821 nfsattrbit_t attrbits, retattrbits, checkattrbits;
823 struct nfsreferral *refp;
826 struct timespec temptime;
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((caddr_t)tnfhp, M_NFSFH);
1204 } else if (nfhpp != NULL) {
1207 FREE((caddr_t)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 NFSSOCKADDRFREE(sad);
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 NFSSOCKADDRALLOC(rp->nr_nam);
3092 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3093 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3094 ad->sin_family = AF_INET;
3095 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);
3096 ad->sin_port = port;
3098 rp->nr_prog = RPCPROG_NFSUSERD;
3099 rp->nr_vers = RPCNFSUSERD_VERS;
3100 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3102 NFSSOCKADDRFREE(rp->nr_nam);
3111 * Delete the nfsuserd port.
3114 nfsrv_nfsuserddelport(void)
3118 if (nfsrv_nfsuserd == 0) {
3124 newnfs_disconnect(&nfsrv_nfsuserdsock);
3125 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3129 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3131 * Returns 0 upon success, non-zero otherwise.
3134 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3137 struct nfsrv_descript *nd;
3139 struct nfsrv_descript nfsd;
3144 if (nfsrv_nfsuserd == 0) {
3151 cred = newnfs_getcred();
3152 nd->nd_flag = ND_GSSINITREPLY;
3155 nd->nd_procnum = procnum;
3156 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3158 if (procnum == RPCNFSUSERD_GETUID)
3159 *tl = txdr_unsigned(uid);
3161 *tl = txdr_unsigned(gid);
3164 (void) nfsm_strtom(nd, name, len);
3166 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3167 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3170 mbuf_freem(nd->nd_mrep);
3171 error = nd->nd_repstat;
3179 * This function is called from the nfssvc(2) system call, to update the
3180 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3183 nfssvc_idname(struct nfsd_idargs *nidp)
3185 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3186 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3187 int i, group_locked, groupname_locked, user_locked, username_locked;
3192 static int onethread = 0;
3193 static time_t lasttime = 0;
3195 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3199 if (nidp->nid_flag & NFSID_INITIALIZE) {
3200 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3201 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3204 free(cp, M_NFSSTRING);
3207 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3209 * Free up all the old stuff and reinitialize hash
3210 * lists. All mutexes for both lists must be locked,
3211 * with the user/group name ones before the uid/gid
3212 * ones, to avoid a LOR.
3214 for (i = 0; i < nfsrv_lughashsize; i++)
3215 mtx_lock(&nfsusernamehash[i].mtx);
3216 for (i = 0; i < nfsrv_lughashsize; i++)
3217 mtx_lock(&nfsuserhash[i].mtx);
3218 for (i = 0; i < nfsrv_lughashsize; i++)
3219 TAILQ_FOREACH_SAFE(usrp,
3220 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3221 nfsrv_removeuser(usrp, 1);
3222 for (i = 0; i < nfsrv_lughashsize; i++)
3223 mtx_unlock(&nfsuserhash[i].mtx);
3224 for (i = 0; i < nfsrv_lughashsize; i++)
3225 mtx_unlock(&nfsusernamehash[i].mtx);
3226 for (i = 0; i < nfsrv_lughashsize; i++)
3227 mtx_lock(&nfsgroupnamehash[i].mtx);
3228 for (i = 0; i < nfsrv_lughashsize; i++)
3229 mtx_lock(&nfsgrouphash[i].mtx);
3230 for (i = 0; i < nfsrv_lughashsize; i++)
3231 TAILQ_FOREACH_SAFE(usrp,
3232 &nfsgrouphash[i].lughead, lug_numhash,
3234 nfsrv_removeuser(usrp, 0);
3235 for (i = 0; i < nfsrv_lughashsize; i++)
3236 mtx_unlock(&nfsgrouphash[i].mtx);
3237 for (i = 0; i < nfsrv_lughashsize; i++)
3238 mtx_unlock(&nfsgroupnamehash[i].mtx);
3239 free(nfsrv_dnsname, M_NFSSTRING);
3240 nfsrv_dnsname = NULL;
3242 if (nfsuserhash == NULL) {
3243 /* Allocate the hash tables. */
3244 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3245 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3249 NULL, MTX_DEF | MTX_DUPOK);
3250 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3251 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 mtx_init(&nfsusernamehash[i].mtx,
3255 "nfsusrhash", NULL, MTX_DEF |
3257 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3258 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3260 for (i = 0; i < nfsrv_lughashsize; i++)
3261 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3262 NULL, MTX_DEF | MTX_DUPOK);
3263 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3264 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3266 for (i = 0; i < nfsrv_lughashsize; i++)
3267 mtx_init(&nfsgroupnamehash[i].mtx,
3268 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3270 /* (Re)initialize the list heads. */
3271 for (i = 0; i < nfsrv_lughashsize; i++)
3272 TAILQ_INIT(&nfsuserhash[i].lughead);
3273 for (i = 0; i < nfsrv_lughashsize; i++)
3274 TAILQ_INIT(&nfsusernamehash[i].lughead);
3275 for (i = 0; i < nfsrv_lughashsize; i++)
3276 TAILQ_INIT(&nfsgrouphash[i].lughead);
3277 for (i = 0; i < nfsrv_lughashsize; i++)
3278 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3281 * Put name in "DNS" string.
3284 nfsrv_defaultuid = nidp->nid_uid;
3285 nfsrv_defaultgid = nidp->nid_gid;
3287 nfsrv_usermax = nidp->nid_usermax;
3288 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3293 * malloc the new one now, so any potential sleep occurs before
3294 * manipulation of the lists.
3296 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3297 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3298 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3300 if (error == 0 && nidp->nid_ngroup > 0 &&
3301 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3302 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3304 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3305 sizeof(gid_t) * nidp->nid_ngroup);
3308 * Create a credential just like svc_getcred(),
3309 * but using the group list provided.
3312 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3313 crsetgroups(cr, nidp->nid_ngroup, grps);
3314 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3315 cr->cr_prison = &prison0;
3316 prison_hold(cr->cr_prison);
3318 mac_cred_associate_nfsd(cr);
3320 newusrp->lug_cred = cr;
3325 free(newusrp, M_NFSUSERGROUP);
3328 newusrp->lug_namelen = nidp->nid_namelen;
3331 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3332 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3333 * The flags user_locked, username_locked, group_locked and
3334 * groupname_locked are set to indicate all of those hash lists are
3335 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3336 * the respective one mutex is locked.
3338 user_locked = username_locked = group_locked = groupname_locked = 0;
3339 hp_name = hp_idnum = NULL;
3342 * Delete old entries, as required.
3344 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3345 /* Must lock all username hash lists first, to avoid a LOR. */
3346 for (i = 0; i < nfsrv_lughashsize; i++)
3347 mtx_lock(&nfsusernamehash[i].mtx);
3348 username_locked = 1;
3349 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3350 mtx_lock(&hp_idnum->mtx);
3351 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3353 if (usrp->lug_uid == nidp->nid_uid)
3354 nfsrv_removeuser(usrp, 1);
3356 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3357 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3358 newusrp->lug_namelen);
3359 mtx_lock(&hp_name->mtx);
3360 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3362 if (usrp->lug_namelen == newusrp->lug_namelen &&
3363 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3364 usrp->lug_namelen)) {
3365 thp = NFSUSERHASH(usrp->lug_uid);
3366 mtx_lock(&thp->mtx);
3367 nfsrv_removeuser(usrp, 1);
3368 mtx_unlock(&thp->mtx);
3371 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3372 mtx_lock(&hp_idnum->mtx);
3373 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3374 /* Must lock all groupname hash lists first, to avoid a LOR. */
3375 for (i = 0; i < nfsrv_lughashsize; i++)
3376 mtx_lock(&nfsgroupnamehash[i].mtx);
3377 groupname_locked = 1;
3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3379 mtx_lock(&hp_idnum->mtx);
3380 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3382 if (usrp->lug_gid == nidp->nid_gid)
3383 nfsrv_removeuser(usrp, 0);
3385 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3386 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3387 newusrp->lug_namelen);
3388 mtx_lock(&hp_name->mtx);
3389 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3391 if (usrp->lug_namelen == newusrp->lug_namelen &&
3392 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3393 usrp->lug_namelen)) {
3394 thp = NFSGROUPHASH(usrp->lug_gid);
3395 mtx_lock(&thp->mtx);
3396 nfsrv_removeuser(usrp, 0);
3397 mtx_unlock(&thp->mtx);
3400 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3401 mtx_lock(&hp_idnum->mtx);
3405 * Now, we can add the new one.
3407 if (nidp->nid_usertimeout)
3408 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3410 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3411 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3412 newusrp->lug_uid = nidp->nid_uid;
3413 thp = NFSUSERHASH(newusrp->lug_uid);
3414 mtx_assert(&thp->mtx, MA_OWNED);
3415 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3416 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3417 mtx_assert(&thp->mtx, MA_OWNED);
3418 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3419 atomic_add_int(&nfsrv_usercnt, 1);
3420 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3421 newusrp->lug_gid = nidp->nid_gid;
3422 thp = NFSGROUPHASH(newusrp->lug_gid);
3423 mtx_assert(&thp->mtx, MA_OWNED);
3424 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3425 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3426 mtx_assert(&thp->mtx, MA_OWNED);
3427 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3428 atomic_add_int(&nfsrv_usercnt, 1);
3430 if (newusrp->lug_cred != NULL)
3431 crfree(newusrp->lug_cred);
3432 free(newusrp, M_NFSUSERGROUP);
3436 * Once per second, allow one thread to trim the cache.
3438 if (lasttime < NFSD_MONOSEC &&
3439 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3441 * First, unlock the single mutexes, so that all entries
3442 * can be locked and any LOR is avoided.
3444 if (hp_name != NULL) {
3445 mtx_unlock(&hp_name->mtx);
3448 if (hp_idnum != NULL) {
3449 mtx_unlock(&hp_idnum->mtx);
3453 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3454 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3455 if (username_locked == 0) {
3456 for (i = 0; i < nfsrv_lughashsize; i++)
3457 mtx_lock(&nfsusernamehash[i].mtx);
3458 username_locked = 1;
3460 KASSERT(user_locked == 0,
3461 ("nfssvc_idname: user_locked"));
3462 for (i = 0; i < nfsrv_lughashsize; i++)
3463 mtx_lock(&nfsuserhash[i].mtx);
3465 for (i = 0; i < nfsrv_lughashsize; i++) {
3466 TAILQ_FOREACH_SAFE(usrp,
3467 &nfsuserhash[i].lughead, lug_numhash,
3469 if (usrp->lug_expiry < NFSD_MONOSEC)
3470 nfsrv_removeuser(usrp, 1);
3472 for (i = 0; i < nfsrv_lughashsize; i++) {
3474 * Trim the cache using an approximate LRU
3475 * algorithm. This code deletes the least
3476 * recently used entry on each hash list.
3478 if (nfsrv_usercnt <= nfsrv_usermax)
3480 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3482 nfsrv_removeuser(usrp, 1);
3485 if (groupname_locked == 0) {
3486 for (i = 0; i < nfsrv_lughashsize; i++)
3487 mtx_lock(&nfsgroupnamehash[i].mtx);
3488 groupname_locked = 1;
3490 KASSERT(group_locked == 0,
3491 ("nfssvc_idname: group_locked"));
3492 for (i = 0; i < nfsrv_lughashsize; i++)
3493 mtx_lock(&nfsgrouphash[i].mtx);
3495 for (i = 0; i < nfsrv_lughashsize; i++) {
3496 TAILQ_FOREACH_SAFE(usrp,
3497 &nfsgrouphash[i].lughead, lug_numhash,
3499 if (usrp->lug_expiry < NFSD_MONOSEC)
3500 nfsrv_removeuser(usrp, 0);
3502 for (i = 0; i < nfsrv_lughashsize; i++) {
3504 * Trim the cache using an approximate LRU
3505 * algorithm. This code deletes the least
3506 * recently user entry on each hash list.
3508 if (nfsrv_usercnt <= nfsrv_usermax)
3510 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3512 nfsrv_removeuser(usrp, 0);
3515 lasttime = NFSD_MONOSEC;
3516 atomic_store_rel_int(&onethread, 0);
3519 /* Now, unlock all locked mutexes. */
3520 if (hp_idnum != NULL)
3521 mtx_unlock(&hp_idnum->mtx);
3522 if (hp_name != NULL)
3523 mtx_unlock(&hp_name->mtx);
3524 if (user_locked != 0)
3525 for (i = 0; i < nfsrv_lughashsize; i++)
3526 mtx_unlock(&nfsuserhash[i].mtx);
3527 if (username_locked != 0)
3528 for (i = 0; i < nfsrv_lughashsize; i++)
3529 mtx_unlock(&nfsusernamehash[i].mtx);
3530 if (group_locked != 0)
3531 for (i = 0; i < nfsrv_lughashsize; i++)
3532 mtx_unlock(&nfsgrouphash[i].mtx);
3533 if (groupname_locked != 0)
3534 for (i = 0; i < nfsrv_lughashsize; i++)
3535 mtx_unlock(&nfsgroupnamehash[i].mtx);
3542 * Remove a user/group name element.
3545 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3547 struct nfsrv_lughash *hp;
3550 hp = NFSUSERHASH(usrp->lug_uid);
3551 mtx_assert(&hp->mtx, MA_OWNED);
3552 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3553 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3554 mtx_assert(&hp->mtx, MA_OWNED);
3555 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3557 hp = NFSGROUPHASH(usrp->lug_gid);
3558 mtx_assert(&hp->mtx, MA_OWNED);
3559 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3560 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3561 mtx_assert(&hp->mtx, MA_OWNED);
3562 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3564 atomic_add_int(&nfsrv_usercnt, -1);
3565 if (usrp->lug_cred != NULL)
3566 crfree(usrp->lug_cred);
3567 free(usrp, M_NFSUSERGROUP);
3571 * Free up all the allocations related to the name<-->id cache.
3572 * This function should only be called when the nfsuserd daemon isn't
3573 * running, since it doesn't do any locking.
3574 * This function is meant to be used when the nfscommon module is unloaded.
3577 nfsrv_cleanusergroup(void)
3579 struct nfsrv_lughash *hp, *hp2;
3580 struct nfsusrgrp *nusrp, *usrp;
3583 if (nfsuserhash == NULL)
3586 for (i = 0; i < nfsrv_lughashsize; i++) {
3587 hp = &nfsuserhash[i];
3588 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3589 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3590 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3592 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3593 if (usrp->lug_cred != NULL)
3594 crfree(usrp->lug_cred);
3595 free(usrp, M_NFSUSERGROUP);
3597 hp = &nfsgrouphash[i];
3598 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3599 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3600 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3602 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3603 if (usrp->lug_cred != NULL)
3604 crfree(usrp->lug_cred);
3605 free(usrp, M_NFSUSERGROUP);
3607 mtx_destroy(&nfsuserhash[i].mtx);
3608 mtx_destroy(&nfsusernamehash[i].mtx);
3609 mtx_destroy(&nfsgroupnamehash[i].mtx);
3610 mtx_destroy(&nfsgrouphash[i].mtx);
3612 free(nfsuserhash, M_NFSUSERGROUP);
3613 free(nfsusernamehash, M_NFSUSERGROUP);
3614 free(nfsgrouphash, M_NFSUSERGROUP);
3615 free(nfsgroupnamehash, M_NFSUSERGROUP);
3616 free(nfsrv_dnsname, M_NFSSTRING);
3620 * This function scans a byte string and checks for UTF-8 compliance.
3621 * It returns 0 if it conforms and NFSERR_INVAL if not.
3624 nfsrv_checkutf8(u_int8_t *cp, int len)
3626 u_int32_t val = 0x0;
3627 int cnt = 0, gotd = 0, shift = 0;
3629 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3633 * Here are what the variables are used for:
3634 * val - the calculated value of a multibyte char, used to check
3635 * that it was coded with the correct range
3636 * cnt - the number of 10xxxxxx bytes to follow
3637 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3638 * shift - lower order bits of range (ie. "val >> shift" should
3639 * not be 0, in other words, dividing by the lower bound
3640 * of the range should get a non-zero value)
3641 * byte - used to calculate cnt
3645 /* This handles the 10xxxxxx bytes */
3646 if ((*cp & 0xc0) != 0x80 ||
3647 (gotd && (*cp & 0x20))) {
3648 error = NFSERR_INVAL;
3653 val |= (*cp & 0x3f);
3655 if (cnt == 0 && (val >> shift) == 0x0) {
3656 error = NFSERR_INVAL;
3659 } else if (*cp & 0x80) {
3660 /* first byte of multi byte char */
3662 while ((byte & 0x40) && cnt < 6) {
3666 if (cnt == 0 || cnt == 6) {
3667 error = NFSERR_INVAL;
3670 val = (*cp & (0x3f >> cnt));
3671 shift = utf8_shift[cnt - 1];
3672 if (cnt == 2 && val == 0xd)
3673 /* Check for the 0xd800-0xdfff case */
3680 error = NFSERR_INVAL;
3688 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3689 * strings, one with the root path in it and the other with the list of
3690 * locations. The list is in the same format as is found in nfr_refs.
3691 * It is a "," separated list of entries, where each of them is of the
3692 * form <server>:<rootpath>. For example
3693 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3694 * The nilp argument is set to 1 for the special case of a null fs_root
3695 * and an empty server list.
3696 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3697 * number of xdr bytes parsed in sump.
3700 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3701 int *sump, int *nilp)
3704 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3705 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3707 SLIST_ENTRY(list) next;
3711 SLIST_HEAD(, list) head;
3718 * Get the fs_root path and check for the special case of null path
3719 * and 0 length server list.
3721 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3722 len = fxdr_unsigned(int, *tl);
3723 if (len < 0 || len > 10240) {
3724 error = NFSERR_BADXDR;
3728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3730 error = NFSERR_BADXDR;
3734 *sump = 2 * NFSX_UNSIGNED;
3738 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3739 error = nfsrv_mtostr(nd, cp, len);
3741 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3742 cnt = fxdr_unsigned(int, *tl);
3744 error = NFSERR_BADXDR;
3750 * Now, loop through the location list and make up the srvlist.
3752 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3753 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3756 for (i = 0; i < cnt; i++) {
3758 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3759 nsrv = fxdr_unsigned(int, *tl);
3761 error = NFSERR_BADXDR;
3766 * Handle the first server by putting it in the srvstr.
3768 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3769 len = fxdr_unsigned(int, *tl);
3770 if (len <= 0 || len > 1024) {
3771 error = NFSERR_BADXDR;
3774 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3779 error = nfsrv_mtostr(nd, cp3, len);
3785 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3786 for (j = 1; j < nsrv; j++) {
3788 * Yuck, put them in an slist and process them later.
3790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3791 len = fxdr_unsigned(int, *tl);
3792 if (len <= 0 || len > 1024) {
3793 error = NFSERR_BADXDR;
3796 lsp = (struct list *)malloc(sizeof (struct list)
3797 + len, M_TEMP, M_WAITOK);
3798 error = nfsrv_mtostr(nd, lsp->host, len);
3801 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3803 SLIST_INSERT_HEAD(&head, lsp, next);
3807 * Finally, we can get the path.
3809 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3810 len = fxdr_unsigned(int, *tl);
3811 if (len <= 0 || len > 1024) {
3812 error = NFSERR_BADXDR;
3815 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3816 error = nfsrv_mtostr(nd, cp3, len);
3819 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3824 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3825 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3828 NFSBCOPY(lsp->host, cp3, lsp->len);
3831 NFSBCOPY(str, cp3, stringlen);
3834 siz += (lsp->len + stringlen + 2);
3835 free((caddr_t)lsp, M_TEMP);
3841 NFSEXITCODE2(0, nd);
3845 free(cp, M_NFSSTRING);
3847 free(cp2, M_NFSSTRING);
3848 NFSEXITCODE2(error, nd);
3853 * Make the malloc'd space large enough. This is a pain, but the xdr
3854 * doesn't set an upper bound on the side, so...
3857 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3864 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3865 NFSBCOPY(*cpp, cp, *slenp);
3866 free(*cpp, M_NFSSTRING);
3870 *slenp = siz + 1024;
3874 * Initialize the reply header data structures.
3877 nfsrvd_rephead(struct nfsrv_descript *nd)
3882 * If this is a big reply, use a cluster.
3884 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3885 nfs_bigreply[nd->nd_procnum]) {
3886 NFSMCLGET(mreq, M_WAITOK);
3894 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3895 mbuf_setlen(mreq, 0);
3897 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3898 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3902 * Lock a socket against others.
3903 * Currently used to serialize connect/disconnect attempts.
3906 newnfs_sndlock(int *flagp)
3911 while (*flagp & NFSR_SNDLOCK) {
3912 *flagp |= NFSR_WANTSND;
3915 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3916 PZERO - 1, "nfsndlck", &ts);
3918 *flagp |= NFSR_SNDLOCK;
3924 * Unlock the stream socket for others.
3927 newnfs_sndunlock(int *flagp)
3931 if ((*flagp & NFSR_SNDLOCK) == 0)
3932 panic("nfs sndunlock");
3933 *flagp &= ~NFSR_SNDLOCK;
3934 if (*flagp & NFSR_WANTSND) {
3935 *flagp &= ~NFSR_WANTSND;
3936 wakeup((caddr_t)flagp);
3942 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
3943 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
3945 struct in_addr saddr;
3946 uint32_t portnum, *tl;
3948 sa_family_t af = AF_UNSPEC;
3949 char addr[64], protocol[5], *cp;
3950 int cantparse = 0, error = 0;
3953 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3954 i = fxdr_unsigned(int, *tl);
3955 if (i >= 3 && i <= 4) {
3956 error = nfsrv_mtostr(nd, protocol, i);
3959 if (strcmp(protocol, "tcp") == 0) {
3962 } else if (strcmp(protocol, "udp") == 0) {
3965 } else if (strcmp(protocol, "tcp6") == 0) {
3968 } else if (strcmp(protocol, "udp6") == 0) {
3976 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3981 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3982 i = fxdr_unsigned(int, *tl);
3984 error = NFSERR_BADXDR;
3986 } else if (cantparse == 0 && i >= 11 && i < 64) {
3988 * The shortest address is 11chars and the longest is < 64.
3990 error = nfsrv_mtostr(nd, addr, i);
3994 /* Find the port# at the end and extract that. */
3998 /* Count back two '.'s from end to get port# field. */
3999 for (j = 0; j < i; j++) {
4009 * The NFSv4 port# is appended as .N.N, where N is
4010 * a decimal # in the range 0-255, just like an inet4
4011 * address. Cheat and use inet_aton(), which will
4012 * return a Class A address and then shift the high
4013 * order 8bits over to convert it to the port#.
4016 if (inet_aton(cp, &saddr) == 1) {
4017 portnum = ntohl(saddr.s_addr);
4018 portv = (uint16_t)((portnum >> 16) |
4024 if (cantparse == 0) {
4025 if (af == AF_INET) {
4026 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4027 sin->sin_len = sizeof(*sin);
4028 sin->sin_family = AF_INET;
4029 sin->sin_port = htons(portv);
4034 if (inet_pton(af, addr, &sin6->sin6_addr)
4036 sin6->sin6_len = sizeof(*sin6);
4037 sin6->sin6_family = AF_INET6;
4038 sin6->sin6_port = htons(portv);
4046 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4057 * Handle an NFSv4.1 Sequence request for the session.
4058 * If reply != NULL, use it to return the cached reply, as required.
4059 * The client gets a cached reply via this call for callbacks, however the
4060 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4063 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4064 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4071 if (slotid > maxslot)
4072 return (NFSERR_BADSLOT);
4073 if (seqid == slots[slotid].nfssl_seq) {
4075 if (slots[slotid].nfssl_inprog != 0)
4076 error = NFSERR_DELAY;
4077 else if (slots[slotid].nfssl_reply != NULL) {
4078 if (reply != NULL) {
4079 *reply = slots[slotid].nfssl_reply;
4080 slots[slotid].nfssl_reply = NULL;
4082 slots[slotid].nfssl_inprog = 1;
4083 error = NFSERR_REPLYFROMCACHE;
4085 /* No reply cached, so just do it. */
4086 slots[slotid].nfssl_inprog = 1;
4087 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4088 if (slots[slotid].nfssl_reply != NULL)
4089 m_freem(slots[slotid].nfssl_reply);
4090 slots[slotid].nfssl_reply = NULL;
4091 slots[slotid].nfssl_inprog = 1;
4092 slots[slotid].nfssl_seq++;
4094 error = NFSERR_SEQMISORDERED;
4099 * Cache this reply for the slot.
4100 * Use the "rep" argument to return the cached reply if repstat is set to
4101 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4104 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4108 if (repstat == NFSERR_REPLYFROMCACHE) {
4109 *rep = slots[slotid].nfssl_reply;
4110 slots[slotid].nfssl_reply = NULL;
4112 if (slots[slotid].nfssl_reply != NULL)
4113 m_freem(slots[slotid].nfssl_reply);
4114 slots[slotid].nfssl_reply = *rep;
4116 slots[slotid].nfssl_inprog = 0;
4120 * Generate the xdr for an NFSv4.1 Sequence Operation.
4123 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4124 struct nfsclsession *sep, int dont_replycache)
4126 uint32_t *tl, slotseq = 0;
4127 int error, maxslot, slotpos;
4128 uint8_t sessionid[NFSX_V4SESSIONID];
4130 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4133 /* Build the Sequence arguments. */
4134 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4135 nd->nd_sequence = tl;
4136 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4137 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4138 nd->nd_slotseq = tl;
4140 *tl++ = txdr_unsigned(slotseq);
4141 *tl++ = txdr_unsigned(slotpos);
4142 *tl++ = txdr_unsigned(maxslot);
4143 if (dont_replycache == 0)
4149 * There are two errors and the rest of the session can
4151 * NFSERR_BADSESSION: This bad session should just generate
4152 * the same error again when the RPC is retried.
4153 * ESTALE: A forced dismount is in progress and will cause the
4154 * RPC to fail later.
4161 nd->nd_flag |= ND_HASSEQUENCE;
4165 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4166 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4168 int i, maxslot, slotpos;
4171 /* Find an unused slot. */
4174 mtx_lock(&sep->nfsess_mtx);
4176 if (nmp != NULL && sep->nfsess_defunct != 0) {
4177 /* Just return the bad session. */
4178 bcopy(sep->nfsess_sessionid, sessionid,
4180 mtx_unlock(&sep->nfsess_mtx);
4181 return (NFSERR_BADSESSION);
4184 for (i = 0; i < sep->nfsess_foreslots; i++) {
4185 if ((bitval & sep->nfsess_slots) == 0) {
4187 sep->nfsess_slots |= bitval;
4188 sep->nfsess_slotseq[i]++;
4189 *slotseqp = sep->nfsess_slotseq[i];
4194 if (slotpos == -1) {
4196 * If a forced dismount is in progress, just return.
4197 * This RPC attempt will fail when it calls
4200 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4201 mtx_unlock(&sep->nfsess_mtx);
4204 /* Wake up once/sec, to check for a forced dismount. */
4205 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4206 PZERO, "nfsclseq", hz);
4208 } while (slotpos == -1);
4209 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4211 for (i = 0; i < 64; i++) {
4212 if ((bitval & sep->nfsess_slots) != 0)
4216 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4217 mtx_unlock(&sep->nfsess_mtx);
4218 *slotposp = slotpos;
4219 *maxslotp = maxslot;
4224 * Free a session slot.
4227 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4234 mtx_lock(&sep->nfsess_mtx);
4235 if ((bitval & sep->nfsess_slots) == 0)
4236 printf("freeing free slot!!\n");
4237 sep->nfsess_slots &= ~bitval;
4238 wakeup(&sep->nfsess_slots);
4239 mtx_unlock(&sep->nfsess_mtx);