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, rem, 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);
507 rem = fullsiz - size;
509 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
510 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
513 bytesize = NFSX_UNSIGNED + fullsiz;
515 (void) nfsm_strtom(nd, fhp, size);
522 * This function compares two net addresses by family and returns TRUE
523 * if they are the same host.
524 * If there is any doubt, return FALSE.
525 * The AF_INET family is handled as a special case so that address mbufs
526 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
529 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
531 struct sockaddr_in *inetaddr;
535 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
536 if (inetaddr->sin_family == AF_INET &&
537 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
543 struct sockaddr_in6 *inetaddr6;
545 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
546 /* XXX - should test sin6_scope_id ? */
547 if (inetaddr6->sin6_family == AF_INET6 &&
548 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
559 * Similar to the above, but takes to NFSSOCKADDR_T args.
562 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
564 struct sockaddr_in *addr1, *addr2;
565 struct sockaddr *inaddr;
567 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
568 switch (inaddr->sa_family) {
570 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
571 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
572 if (addr2->sin_family == AF_INET &&
573 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
579 struct sockaddr_in6 *inet6addr1, *inet6addr2;
581 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
582 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
583 /* XXX - should test sin6_scope_id ? */
584 if (inet6addr2->sin6_family == AF_INET6 &&
585 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
586 &inet6addr2->sin6_addr))
597 * Trim the stuff already dissected off the mbuf list.
600 newnfs_trimleading(nd)
601 struct nfsrv_descript *nd;
607 * First, free up leading mbufs.
609 if (nd->nd_mrep != nd->nd_md) {
611 while (mbuf_next(m) != nd->nd_md) {
612 if (mbuf_next(m) == NULL)
613 panic("nfsm trim leading");
616 mbuf_setnext(m, NULL);
617 mbuf_freem(nd->nd_mrep);
622 * Now, adjust this mbuf, based on nd_dpos.
624 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
625 if (offs == mbuf_len(m)) {
629 panic("nfsm trim leading2");
630 mbuf_setnext(n, NULL);
632 } else if (offs > 0) {
633 mbuf_setlen(m, mbuf_len(m) - offs);
636 panic("nfsm trimleading offs");
639 nd->nd_dpos = NFSMTOD(m, caddr_t);
643 * Trim trailing data off the mbuf list being built.
646 newnfs_trimtrailing(nd, mb, bpos)
647 struct nfsrv_descript *nd;
653 mbuf_freem(mbuf_next(mb));
654 mbuf_setnext(mb, NULL);
656 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
662 * Dissect a file handle on the client.
665 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
672 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
673 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
674 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
681 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
683 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
685 FREE((caddr_t)nfhp, M_NFSFH);
691 NFSEXITCODE2(error, nd);
696 * Break down the nfsv4 acl.
697 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
700 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
701 int *aclsizep, __unused NFSPROC_T *p)
705 int acecnt, error = 0, aceerr = 0, acesize;
711 * Parse out the ace entries and expect them to conform to
712 * what can be supported by R/W/X bits.
714 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
715 aclsize = NFSX_UNSIGNED;
716 acecnt = fxdr_unsigned(int, *tl);
717 if (acecnt > ACL_MAX_ENTRIES)
718 aceerr = NFSERR_ATTRNOTSUPP;
719 if (nfsrv_useacl == 0)
720 aceerr = NFSERR_ATTRNOTSUPP;
721 for (i = 0; i < acecnt; i++) {
723 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
724 &aceerr, &acesize, p);
726 error = nfsrv_skipace(nd, &acesize);
732 aclp->acl_cnt = acecnt;
738 NFSEXITCODE2(error, nd);
743 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
746 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
751 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
752 len = fxdr_unsigned(int, *(tl + 3));
753 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
755 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
756 NFSEXITCODE2(error, nd);
761 * Get attribute bits from an mbuf list.
762 * Returns EBADRPC for a parsing error, 0 otherwise.
763 * If the clearinvalid flag is set, clear the bits not supported.
766 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
773 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
774 cnt = fxdr_unsigned(int, *tl);
776 error = NFSERR_BADXDR;
779 if (cnt > NFSATTRBIT_MAXWORDS)
780 outcnt = NFSATTRBIT_MAXWORDS;
783 NFSZERO_ATTRBIT(attrbitp);
785 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
786 for (i = 0; i < outcnt; i++)
787 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
789 for (i = 0; i < (cnt - outcnt); i++) {
790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
791 if (retnotsupp != NULL && *tl != 0)
792 *retnotsupp = NFSERR_ATTRNOTSUPP;
795 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
797 NFSEXITCODE2(error, nd);
802 * Get the attributes for V4.
803 * If the compare flag is true, test for any attribute changes,
804 * otherwise return the attribute values.
805 * These attributes cover fields in "struct vattr", "struct statfs",
806 * "struct nfsfsinfo", the file handle and the lease duration.
807 * The value of retcmpp is set to 1 if all attributes are the same,
809 * Returns EBADRPC if it can't be parsed, 0 otherwise.
812 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
813 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
814 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
815 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
816 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
819 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
820 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
821 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
822 nfsattrbit_t attrbits, retattrbits, checkattrbits;
824 struct nfsreferral *refp;
827 struct timespec temptime;
830 u_int32_t freenum = 0, tuint;
831 u_int64_t uquad = 0, thyp, thyp2;
837 CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
840 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
842 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
848 *retcmpp = retnotsup;
851 * Just set default values to some of the important ones.
856 nap->na_rdev = (NFSDEV_T)0;
857 nap->na_mtime.tv_sec = 0;
858 nap->na_mtime.tv_nsec = 0;
861 nap->na_blocksize = NFS_FABLKSIZE;
864 sbp->f_bsize = NFS_FABLKSIZE;
872 fsp->fs_rtmax = 8192;
873 fsp->fs_rtpref = 8192;
874 fsp->fs_maxname = NFS_MAXNAMLEN;
875 fsp->fs_wtmax = 8192;
876 fsp->fs_wtpref = 8192;
877 fsp->fs_wtmult = NFS_FABLKSIZE;
878 fsp->fs_dtpref = 8192;
879 fsp->fs_maxfilesize = 0xffffffffffffffffull;
880 fsp->fs_timedelta.tv_sec = 0;
881 fsp->fs_timedelta.tv_nsec = 1;
882 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
883 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
886 pc->pc_linkmax = LINK_MAX;
887 pc->pc_namemax = NAME_MAX;
889 pc->pc_chownrestricted = 0;
890 pc->pc_caseinsensitive = 0;
891 pc->pc_casepreserving = 1;
894 sfp->sf_ffiles = UINT64_MAX;
895 sfp->sf_tfiles = UINT64_MAX;
896 sfp->sf_afiles = UINT64_MAX;
897 sfp->sf_fbytes = UINT64_MAX;
898 sfp->sf_tbytes = UINT64_MAX;
899 sfp->sf_abytes = UINT64_MAX;
904 * Loop around getting the attributes.
906 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
907 attrsize = fxdr_unsigned(int, *tl);
908 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
909 if (attrsum > attrsize) {
910 error = NFSERR_BADXDR;
913 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
915 case NFSATTRBIT_SUPPORTEDATTRS:
917 if (compare || nap == NULL)
918 error = nfsrv_getattrbits(nd, &retattrbits,
921 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
925 if (compare && !(*retcmpp)) {
926 NFSSETSUPP_ATTRBIT(&checkattrbits);
928 /* Some filesystem do not support NFSv4ACL */
929 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
930 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
931 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
933 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
935 *retcmpp = NFSERR_NOTSAME;
939 case NFSATTRBIT_TYPE:
940 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
943 if (nap->na_type != nfsv34tov_type(*tl))
944 *retcmpp = NFSERR_NOTSAME;
946 } else if (nap != NULL) {
947 nap->na_type = nfsv34tov_type(*tl);
949 attrsum += NFSX_UNSIGNED;
951 case NFSATTRBIT_FHEXPIRETYPE:
952 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
953 if (compare && !(*retcmpp)) {
954 if (fxdr_unsigned(int, *tl) !=
955 NFSV4FHTYPE_PERSISTENT)
956 *retcmpp = NFSERR_NOTSAME;
958 attrsum += NFSX_UNSIGNED;
960 case NFSATTRBIT_CHANGE:
961 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
964 if (nap->na_filerev != fxdr_hyper(tl))
965 *retcmpp = NFSERR_NOTSAME;
967 } else if (nap != NULL) {
968 nap->na_filerev = fxdr_hyper(tl);
970 attrsum += NFSX_HYPER;
972 case NFSATTRBIT_SIZE:
973 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
976 if (nap->na_size != fxdr_hyper(tl))
977 *retcmpp = NFSERR_NOTSAME;
979 } else if (nap != NULL) {
980 nap->na_size = fxdr_hyper(tl);
982 attrsum += NFSX_HYPER;
984 case NFSATTRBIT_LINKSUPPORT:
985 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
988 if (fsp->fs_properties & NFSV3_FSFLINK) {
989 if (*tl == newnfs_false)
990 *retcmpp = NFSERR_NOTSAME;
992 if (*tl == newnfs_true)
993 *retcmpp = NFSERR_NOTSAME;
996 } else if (fsp != NULL) {
997 if (*tl == newnfs_true)
998 fsp->fs_properties |= NFSV3_FSFLINK;
1000 fsp->fs_properties &= ~NFSV3_FSFLINK;
1002 attrsum += NFSX_UNSIGNED;
1004 case NFSATTRBIT_SYMLINKSUPPORT:
1005 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1008 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1009 if (*tl == newnfs_false)
1010 *retcmpp = NFSERR_NOTSAME;
1012 if (*tl == newnfs_true)
1013 *retcmpp = NFSERR_NOTSAME;
1016 } else if (fsp != NULL) {
1017 if (*tl == newnfs_true)
1018 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1020 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1022 attrsum += NFSX_UNSIGNED;
1024 case NFSATTRBIT_NAMEDATTR:
1025 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1026 if (compare && !(*retcmpp)) {
1027 if (*tl != newnfs_false)
1028 *retcmpp = NFSERR_NOTSAME;
1030 attrsum += NFSX_UNSIGNED;
1032 case NFSATTRBIT_FSID:
1033 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1034 thyp = fxdr_hyper(tl);
1036 thyp2 = fxdr_hyper(tl);
1038 if (*retcmpp == 0) {
1039 if (thyp != (u_int64_t)
1040 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1041 thyp2 != (u_int64_t)
1042 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1043 *retcmpp = NFSERR_NOTSAME;
1045 } else if (nap != NULL) {
1046 nap->na_filesid[0] = thyp;
1047 nap->na_filesid[1] = thyp2;
1049 attrsum += (4 * NFSX_UNSIGNED);
1051 case NFSATTRBIT_UNIQUEHANDLES:
1052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053 if (compare && !(*retcmpp)) {
1054 if (*tl != newnfs_true)
1055 *retcmpp = NFSERR_NOTSAME;
1057 attrsum += NFSX_UNSIGNED;
1059 case NFSATTRBIT_LEASETIME:
1060 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1062 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1064 *retcmpp = NFSERR_NOTSAME;
1065 } else if (leasep != NULL) {
1066 *leasep = fxdr_unsigned(u_int32_t, *tl);
1068 attrsum += NFSX_UNSIGNED;
1070 case NFSATTRBIT_RDATTRERROR:
1071 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1074 *retcmpp = NFSERR_INVAL;
1075 } else if (rderrp != NULL) {
1076 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1078 attrsum += NFSX_UNSIGNED;
1080 case NFSATTRBIT_ACL:
1083 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1086 naclp = acl_alloc(M_WAITOK);
1087 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1093 if (aceerr || aclp == NULL ||
1094 nfsrv_compareacl(aclp, naclp))
1095 *retcmpp = NFSERR_NOTSAME;
1098 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1100 *retcmpp = NFSERR_ATTRNOTSUPP;
1104 if (vp != NULL && aclp != NULL)
1105 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1108 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1116 case NFSATTRBIT_ACLSUPPORT:
1117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118 if (compare && !(*retcmpp)) {
1119 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1120 if (fxdr_unsigned(u_int32_t, *tl) !=
1122 *retcmpp = NFSERR_NOTSAME;
1124 *retcmpp = NFSERR_ATTRNOTSUPP;
1127 attrsum += NFSX_UNSIGNED;
1129 case NFSATTRBIT_ARCHIVE:
1130 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1131 if (compare && !(*retcmpp))
1132 *retcmpp = NFSERR_ATTRNOTSUPP;
1133 attrsum += NFSX_UNSIGNED;
1135 case NFSATTRBIT_CANSETTIME:
1136 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1139 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1140 if (*tl == newnfs_false)
1141 *retcmpp = NFSERR_NOTSAME;
1143 if (*tl == newnfs_true)
1144 *retcmpp = NFSERR_NOTSAME;
1147 } else if (fsp != NULL) {
1148 if (*tl == newnfs_true)
1149 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1151 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1153 attrsum += NFSX_UNSIGNED;
1155 case NFSATTRBIT_CASEINSENSITIVE:
1156 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1159 if (*tl != newnfs_false)
1160 *retcmpp = NFSERR_NOTSAME;
1162 } else if (pc != NULL) {
1163 pc->pc_caseinsensitive =
1164 fxdr_unsigned(u_int32_t, *tl);
1166 attrsum += NFSX_UNSIGNED;
1168 case NFSATTRBIT_CASEPRESERVING:
1169 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1172 if (*tl != newnfs_true)
1173 *retcmpp = NFSERR_NOTSAME;
1175 } else if (pc != NULL) {
1176 pc->pc_casepreserving =
1177 fxdr_unsigned(u_int32_t, *tl);
1179 attrsum += NFSX_UNSIGNED;
1181 case NFSATTRBIT_CHOWNRESTRICTED:
1182 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1185 if (*tl != newnfs_true)
1186 *retcmpp = NFSERR_NOTSAME;
1188 } else if (pc != NULL) {
1189 pc->pc_chownrestricted =
1190 fxdr_unsigned(u_int32_t, *tl);
1192 attrsum += NFSX_UNSIGNED;
1194 case NFSATTRBIT_FILEHANDLE:
1195 error = nfsm_getfh(nd, &tnfhp);
1198 tfhsize = tnfhp->nfh_len;
1201 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1203 *retcmpp = NFSERR_NOTSAME;
1204 FREE((caddr_t)tnfhp, M_NFSFH);
1205 } else if (nfhpp != NULL) {
1208 FREE((caddr_t)tnfhp, M_NFSFH);
1210 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1212 case NFSATTRBIT_FILEID:
1213 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1214 thyp = fxdr_hyper(tl);
1217 if (nap->na_fileid != thyp)
1218 *retcmpp = NFSERR_NOTSAME;
1220 } else if (nap != NULL)
1221 nap->na_fileid = thyp;
1222 attrsum += NFSX_HYPER;
1224 case NFSATTRBIT_FILESAVAIL:
1225 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1228 sfp->sf_afiles != fxdr_hyper(tl))
1229 *retcmpp = NFSERR_NOTSAME;
1230 } else if (sfp != NULL) {
1231 sfp->sf_afiles = fxdr_hyper(tl);
1233 attrsum += NFSX_HYPER;
1235 case NFSATTRBIT_FILESFREE:
1236 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1239 sfp->sf_ffiles != fxdr_hyper(tl))
1240 *retcmpp = NFSERR_NOTSAME;
1241 } else if (sfp != NULL) {
1242 sfp->sf_ffiles = fxdr_hyper(tl);
1244 attrsum += NFSX_HYPER;
1246 case NFSATTRBIT_FILESTOTAL:
1247 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1250 sfp->sf_tfiles != fxdr_hyper(tl))
1251 *retcmpp = NFSERR_NOTSAME;
1252 } else if (sfp != NULL) {
1253 sfp->sf_tfiles = fxdr_hyper(tl);
1255 attrsum += NFSX_HYPER;
1257 case NFSATTRBIT_FSLOCATIONS:
1258 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1262 if (compare && !(*retcmpp)) {
1263 refp = nfsv4root_getreferral(vp, NULL, 0);
1265 if (cp == NULL || cp2 == NULL ||
1267 strcmp(cp2, refp->nfr_srvlist))
1268 *retcmpp = NFSERR_NOTSAME;
1269 } else if (m == 0) {
1270 *retcmpp = NFSERR_NOTSAME;
1274 free(cp, M_NFSSTRING);
1276 free(cp2, M_NFSSTRING);
1278 case NFSATTRBIT_HIDDEN:
1279 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1280 if (compare && !(*retcmpp))
1281 *retcmpp = NFSERR_ATTRNOTSUPP;
1282 attrsum += NFSX_UNSIGNED;
1284 case NFSATTRBIT_HOMOGENEOUS:
1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1288 if (fsp->fs_properties &
1289 NFSV3_FSFHOMOGENEOUS) {
1290 if (*tl == newnfs_false)
1291 *retcmpp = NFSERR_NOTSAME;
1293 if (*tl == newnfs_true)
1294 *retcmpp = NFSERR_NOTSAME;
1297 } else if (fsp != NULL) {
1298 if (*tl == newnfs_true)
1299 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1301 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1303 attrsum += NFSX_UNSIGNED;
1305 case NFSATTRBIT_MAXFILESIZE:
1306 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1307 tnfsquad.qval = fxdr_hyper(tl);
1310 tquad = NFSRV_MAXFILESIZE;
1311 if (tquad != tnfsquad.qval)
1312 *retcmpp = NFSERR_NOTSAME;
1314 } else if (fsp != NULL) {
1315 fsp->fs_maxfilesize = tnfsquad.qval;
1317 attrsum += NFSX_HYPER;
1319 case NFSATTRBIT_MAXLINK:
1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1323 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1324 *retcmpp = NFSERR_NOTSAME;
1326 } else if (pc != NULL) {
1327 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1329 attrsum += NFSX_UNSIGNED;
1331 case NFSATTRBIT_MAXNAME:
1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1335 if (fsp->fs_maxname !=
1336 fxdr_unsigned(u_int32_t, *tl))
1337 *retcmpp = NFSERR_NOTSAME;
1340 tuint = fxdr_unsigned(u_int32_t, *tl);
1342 * Some Linux NFSv4 servers report this
1343 * as 0 or 4billion, so I'll set it to
1344 * NFS_MAXNAMLEN. If a server actually creates
1345 * a name longer than NFS_MAXNAMLEN, it will
1346 * get an error back.
1348 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1349 tuint = NFS_MAXNAMLEN;
1351 fsp->fs_maxname = tuint;
1353 pc->pc_namemax = tuint;
1355 attrsum += NFSX_UNSIGNED;
1357 case NFSATTRBIT_MAXREAD:
1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1361 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1362 *(tl + 1)) || *tl != 0)
1363 *retcmpp = NFSERR_NOTSAME;
1365 } else if (fsp != NULL) {
1366 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1367 fsp->fs_rtpref = fsp->fs_rtmax;
1368 fsp->fs_dtpref = fsp->fs_rtpref;
1370 attrsum += NFSX_HYPER;
1372 case NFSATTRBIT_MAXWRITE:
1373 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1376 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1377 *(tl + 1)) || *tl != 0)
1378 *retcmpp = NFSERR_NOTSAME;
1380 } else if (fsp != NULL) {
1381 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1382 fsp->fs_wtpref = fsp->fs_wtmax;
1384 attrsum += NFSX_HYPER;
1386 case NFSATTRBIT_MIMETYPE:
1387 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1388 i = fxdr_unsigned(int, *tl);
1389 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1390 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1393 if (compare && !(*retcmpp))
1394 *retcmpp = NFSERR_ATTRNOTSUPP;
1396 case NFSATTRBIT_MODE:
1397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1400 if (nap->na_mode != nfstov_mode(*tl))
1401 *retcmpp = NFSERR_NOTSAME;
1403 } else if (nap != NULL) {
1404 nap->na_mode = nfstov_mode(*tl);
1406 attrsum += NFSX_UNSIGNED;
1408 case NFSATTRBIT_NOTRUNC:
1409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1412 if (*tl != newnfs_true)
1413 *retcmpp = NFSERR_NOTSAME;
1415 } else if (pc != NULL) {
1416 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1418 attrsum += NFSX_UNSIGNED;
1420 case NFSATTRBIT_NUMLINKS:
1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 tuint = fxdr_unsigned(u_int32_t, *tl);
1425 if ((u_int32_t)nap->na_nlink != tuint)
1426 *retcmpp = NFSERR_NOTSAME;
1428 } else if (nap != NULL) {
1429 nap->na_nlink = tuint;
1431 attrsum += NFSX_UNSIGNED;
1433 case NFSATTRBIT_OWNER:
1434 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1435 j = fxdr_unsigned(int, *tl);
1437 error = NFSERR_BADXDR;
1440 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1441 if (j > NFSV4_SMALLSTR)
1442 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1445 error = nfsrv_mtostr(nd, cp, j);
1447 if (j > NFSV4_SMALLSTR)
1448 free(cp, M_NFSSTRING);
1453 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1455 *retcmpp = NFSERR_NOTSAME;
1457 } else if (nap != NULL) {
1458 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1459 nap->na_uid = nfsrv_defaultuid;
1463 if (j > NFSV4_SMALLSTR)
1464 free(cp, M_NFSSTRING);
1466 case NFSATTRBIT_OWNERGROUP:
1467 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1468 j = fxdr_unsigned(int, *tl);
1470 error = NFSERR_BADXDR;
1473 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1474 if (j > NFSV4_SMALLSTR)
1475 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1478 error = nfsrv_mtostr(nd, cp, j);
1480 if (j > NFSV4_SMALLSTR)
1481 free(cp, M_NFSSTRING);
1486 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1488 *retcmpp = NFSERR_NOTSAME;
1490 } else if (nap != NULL) {
1491 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1492 nap->na_gid = nfsrv_defaultgid;
1496 if (j > NFSV4_SMALLSTR)
1497 free(cp, M_NFSSTRING);
1499 case NFSATTRBIT_QUOTAHARD:
1500 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1502 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1503 freenum = sbp->f_bfree;
1505 freenum = sbp->f_bavail;
1508 * ufs_quotactl() insists that the uid argument
1509 * equal p_ruid for non-root quota access, so
1510 * we'll just make sure that's the case.
1512 savuid = p->p_cred->p_ruid;
1513 p->p_cred->p_ruid = cred->cr_uid;
1514 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1515 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1516 freenum = min(dqb.dqb_bhardlimit, freenum);
1517 p->p_cred->p_ruid = savuid;
1519 uquad = (u_int64_t)freenum;
1520 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1522 if (compare && !(*retcmpp)) {
1523 if (uquad != fxdr_hyper(tl))
1524 *retcmpp = NFSERR_NOTSAME;
1526 attrsum += NFSX_HYPER;
1528 case NFSATTRBIT_QUOTASOFT:
1529 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1531 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1532 freenum = sbp->f_bfree;
1534 freenum = sbp->f_bavail;
1537 * ufs_quotactl() insists that the uid argument
1538 * equal p_ruid for non-root quota access, so
1539 * we'll just make sure that's the case.
1541 savuid = p->p_cred->p_ruid;
1542 p->p_cred->p_ruid = cred->cr_uid;
1543 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1544 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1545 freenum = min(dqb.dqb_bsoftlimit, freenum);
1546 p->p_cred->p_ruid = savuid;
1548 uquad = (u_int64_t)freenum;
1549 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1551 if (compare && !(*retcmpp)) {
1552 if (uquad != fxdr_hyper(tl))
1553 *retcmpp = NFSERR_NOTSAME;
1555 attrsum += NFSX_HYPER;
1557 case NFSATTRBIT_QUOTAUSED:
1558 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1563 * ufs_quotactl() insists that the uid argument
1564 * equal p_ruid for non-root quota access, so
1565 * we'll just make sure that's the case.
1567 savuid = p->p_cred->p_ruid;
1568 p->p_cred->p_ruid = cred->cr_uid;
1569 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1570 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1571 freenum = dqb.dqb_curblocks;
1572 p->p_cred->p_ruid = savuid;
1574 uquad = (u_int64_t)freenum;
1575 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1577 if (compare && !(*retcmpp)) {
1578 if (uquad != fxdr_hyper(tl))
1579 *retcmpp = NFSERR_NOTSAME;
1581 attrsum += NFSX_HYPER;
1583 case NFSATTRBIT_RAWDEV:
1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1585 j = fxdr_unsigned(int, *tl++);
1586 k = fxdr_unsigned(int, *tl);
1589 if (nap->na_rdev != NFSMAKEDEV(j, k))
1590 *retcmpp = NFSERR_NOTSAME;
1592 } else if (nap != NULL) {
1593 nap->na_rdev = NFSMAKEDEV(j, k);
1595 attrsum += NFSX_V4SPECDATA;
1597 case NFSATTRBIT_SPACEAVAIL:
1598 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1601 sfp->sf_abytes != fxdr_hyper(tl))
1602 *retcmpp = NFSERR_NOTSAME;
1603 } else if (sfp != NULL) {
1604 sfp->sf_abytes = fxdr_hyper(tl);
1606 attrsum += NFSX_HYPER;
1608 case NFSATTRBIT_SPACEFREE:
1609 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1612 sfp->sf_fbytes != fxdr_hyper(tl))
1613 *retcmpp = NFSERR_NOTSAME;
1614 } else if (sfp != NULL) {
1615 sfp->sf_fbytes = fxdr_hyper(tl);
1617 attrsum += NFSX_HYPER;
1619 case NFSATTRBIT_SPACETOTAL:
1620 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1623 sfp->sf_tbytes != fxdr_hyper(tl))
1624 *retcmpp = NFSERR_NOTSAME;
1625 } else if (sfp != NULL) {
1626 sfp->sf_tbytes = fxdr_hyper(tl);
1628 attrsum += NFSX_HYPER;
1630 case NFSATTRBIT_SPACEUSED:
1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 thyp = fxdr_hyper(tl);
1635 if ((u_int64_t)nap->na_bytes != thyp)
1636 *retcmpp = NFSERR_NOTSAME;
1638 } else if (nap != NULL) {
1639 nap->na_bytes = thyp;
1641 attrsum += NFSX_HYPER;
1643 case NFSATTRBIT_SYSTEM:
1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1645 if (compare && !(*retcmpp))
1646 *retcmpp = NFSERR_ATTRNOTSUPP;
1647 attrsum += NFSX_UNSIGNED;
1649 case NFSATTRBIT_TIMEACCESS:
1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1651 fxdr_nfsv4time(tl, &temptime);
1654 if (!NFS_CMPTIME(temptime, nap->na_atime))
1655 *retcmpp = NFSERR_NOTSAME;
1657 } else if (nap != NULL) {
1658 nap->na_atime = temptime;
1660 attrsum += NFSX_V4TIME;
1662 case NFSATTRBIT_TIMEACCESSSET:
1663 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1664 attrsum += NFSX_UNSIGNED;
1665 i = fxdr_unsigned(int, *tl);
1666 if (i == NFSV4SATTRTIME_TOCLIENT) {
1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1668 attrsum += NFSX_V4TIME;
1670 if (compare && !(*retcmpp))
1671 *retcmpp = NFSERR_INVAL;
1673 case NFSATTRBIT_TIMEBACKUP:
1674 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1675 if (compare && !(*retcmpp))
1676 *retcmpp = NFSERR_ATTRNOTSUPP;
1677 attrsum += NFSX_V4TIME;
1679 case NFSATTRBIT_TIMECREATE:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1681 if (compare && !(*retcmpp))
1682 *retcmpp = NFSERR_ATTRNOTSUPP;
1683 attrsum += NFSX_V4TIME;
1685 case NFSATTRBIT_TIMEDELTA:
1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1690 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1691 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1692 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1693 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1696 *retcmpp = NFSERR_NOTSAME;
1699 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1702 attrsum += NFSX_V4TIME;
1704 case NFSATTRBIT_TIMEMETADATA:
1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1706 fxdr_nfsv4time(tl, &temptime);
1709 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1710 *retcmpp = NFSERR_NOTSAME;
1712 } else if (nap != NULL) {
1713 nap->na_ctime = temptime;
1715 attrsum += NFSX_V4TIME;
1717 case NFSATTRBIT_TIMEMODIFY:
1718 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1719 fxdr_nfsv4time(tl, &temptime);
1722 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1723 *retcmpp = NFSERR_NOTSAME;
1725 } else if (nap != NULL) {
1726 nap->na_mtime = temptime;
1728 attrsum += NFSX_V4TIME;
1730 case NFSATTRBIT_TIMEMODIFYSET:
1731 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1732 attrsum += NFSX_UNSIGNED;
1733 i = fxdr_unsigned(int, *tl);
1734 if (i == NFSV4SATTRTIME_TOCLIENT) {
1735 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1736 attrsum += NFSX_V4TIME;
1738 if (compare && !(*retcmpp))
1739 *retcmpp = NFSERR_INVAL;
1741 case NFSATTRBIT_MOUNTEDONFILEID:
1742 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1743 thyp = fxdr_hyper(tl);
1746 if (!vp || !nfsrv_atroot(vp, &thyp2))
1747 thyp2 = nap->na_fileid;
1749 *retcmpp = NFSERR_NOTSAME;
1751 } else if (nap != NULL)
1752 nap->na_mntonfileno = thyp;
1753 attrsum += NFSX_HYPER;
1755 case NFSATTRBIT_SUPPATTREXCLCREAT:
1757 error = nfsrv_getattrbits(nd, &retattrbits,
1761 if (compare && !(*retcmpp)) {
1762 NFSSETSUPP_ATTRBIT(&checkattrbits);
1763 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1764 NFSCLRBIT_ATTRBIT(&checkattrbits,
1765 NFSATTRBIT_TIMEACCESSSET);
1766 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1768 *retcmpp = NFSERR_NOTSAME;
1773 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1775 if (compare && !(*retcmpp))
1776 *retcmpp = NFSERR_ATTRNOTSUPP;
1778 * and get out of the loop, since we can't parse
1779 * the unknown attrbute data.
1781 bitpos = NFSATTRBIT_MAX;
1787 * some clients pad the attrlist, so we need to skip over the
1790 if (attrsum > attrsize) {
1791 error = NFSERR_BADXDR;
1793 attrsize = NFSM_RNDUP(attrsize);
1794 if (attrsum < attrsize)
1795 error = nfsm_advance(nd, attrsize - attrsum, -1);
1798 NFSEXITCODE2(error, nd);
1803 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1804 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1805 * The first argument is a pointer to an nfsv4lock structure.
1806 * The second argument is 1 iff a blocking lock is wanted.
1807 * If this argument is 0, the call waits until no thread either wants nor
1808 * holds an exclusive lock.
1809 * It returns 1 if the lock was acquired, 0 otherwise.
1810 * If several processes call this function concurrently wanting the exclusive
1811 * lock, one will get the lock and the rest will return without getting the
1812 * lock. (If the caller must have the lock, it simply calls this function in a
1813 * loop until the function returns 1 to indicate the lock was acquired.)
1814 * Any usecnt must be decremented by calling nfsv4_relref() before
1815 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1816 * be called in a loop.
1817 * The isleptp argument is set to indicate if the call slept, iff not NULL
1818 * and the mp argument indicates to check for a forced dismount, iff not
1822 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1823 void *mutex, struct mount *mp)
1829 * If a lock is wanted, loop around until the lock is acquired by
1830 * someone and then released. If I want the lock, try to acquire it.
1831 * For a lock to be issued, no lock must be in force and the usecnt
1835 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1836 lp->nfslock_usecnt == 0) {
1837 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1838 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1841 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1843 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1844 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
1845 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1848 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1851 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1852 PZERO - 1, "nfsv4lck", NULL);
1853 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1854 lp->nfslock_usecnt == 0) {
1855 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1856 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1864 * Release the lock acquired by nfsv4_lock().
1865 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1866 * incremented, as well.
1869 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1872 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1874 lp->nfslock_usecnt++;
1879 * Release a reference cnt.
1882 nfsv4_relref(struct nfsv4lock *lp)
1885 if (lp->nfslock_usecnt <= 0)
1886 panic("nfsv4root ref cnt");
1887 lp->nfslock_usecnt--;
1888 if (lp->nfslock_usecnt == 0)
1893 * Get a reference cnt.
1894 * This function will wait for any exclusive lock to be released, but will
1895 * not wait for threads that want the exclusive lock. If priority needs
1896 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1897 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1898 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
1899 * return without getting a refcnt for that case.
1902 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1910 * Wait for a lock held.
1912 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1913 if (mp != NULL && NFSCL_FORCEDISM(mp))
1915 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1918 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1919 PZERO - 1, "nfsv4gr", NULL);
1921 if (mp != NULL && NFSCL_FORCEDISM(mp))
1924 lp->nfslock_usecnt++;
1928 * Get a reference as above, but return failure instead of sleeping if
1929 * an exclusive lock is held.
1932 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1935 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1938 lp->nfslock_usecnt++;
1943 * Test for a lock. Return 1 if locked, 0 otherwise.
1946 nfsv4_testlock(struct nfsv4lock *lp)
1949 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1950 lp->nfslock_usecnt == 0)
1956 * Wake up anyone sleeping, waiting for this lock.
1959 nfsv4_wanted(struct nfsv4lock *lp)
1962 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1963 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1964 wakeup((caddr_t)&lp->nfslock_lock);
1969 * Copy a string from an mbuf list into a character array.
1970 * Return EBADRPC if there is an mbuf error,
1974 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1983 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1984 rem = NFSM_RNDUP(siz) - siz;
1990 NFSBCOPY(cp, str, xfer);
1999 cp = NFSMTOD(mp, caddr_t);
2011 error = nfsm_advance(nd, rem, len);
2017 NFSEXITCODE2(error, nd);
2022 * Fill in the attributes as marked by the bitmap (V4).
2025 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2026 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2027 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2028 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2030 int bitpos, retnum = 0;
2032 int siz, prefixnum, error;
2033 u_char *cp, namestr[NFSV4_SMALLSTR];
2034 nfsattrbit_t attrbits, retbits;
2035 nfsattrbit_t *retbitp = &retbits;
2036 u_int32_t freenum, *retnump;
2039 struct nfsfsinfo fsinf;
2040 struct timespec temptime;
2041 NFSACL_T *aclp, *naclp = NULL;
2048 * First, set the bits that can be filled and get fsinfo.
2050 NFSSET_ATTRBIT(retbitp, attrbitp);
2052 * If both p and cred are NULL, it is a client side setattr call.
2053 * If both p and cred are not NULL, it is a server side reply call.
2054 * If p is not NULL and cred is NULL, it is a client side callback
2057 if (p == NULL && cred == NULL) {
2058 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2061 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2062 naclp = acl_alloc(M_WAITOK);
2065 nfsvno_getfs(&fsinf, isdgram);
2068 * Get the VFS_STATFS(), since some attributes need them.
2070 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2071 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2072 error = VFS_STATFS(mp, fs);
2075 nd->nd_repstat = NFSERR_ACCES;
2079 NFSCLRSTATFS_ATTRBIT(retbitp);
2085 * And the NFSv4 ACL...
2087 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2088 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2089 supports_nfsv4acls == 0))) {
2090 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2092 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2093 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2094 supports_nfsv4acls == 0)) {
2095 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2096 } else if (naclp != NULL) {
2097 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2098 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2100 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2102 NFSVOPUNLOCK(vp, 0);
2104 error = NFSERR_PERM;
2107 nd->nd_repstat = NFSERR_ACCES;
2111 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2117 * Put out the attribute bitmap for the ones being filled in
2118 * and get the field for the number of attributes returned.
2120 prefixnum = nfsrv_putattrbit(nd, retbitp);
2121 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2122 prefixnum += NFSX_UNSIGNED;
2125 * Now, loop around filling in the attributes for each bit set.
2127 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2128 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2130 case NFSATTRBIT_SUPPORTEDATTRS:
2131 NFSSETSUPP_ATTRBIT(&attrbits);
2132 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2133 && supports_nfsv4acls == 0)) {
2134 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2135 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2137 retnum += nfsrv_putattrbit(nd, &attrbits);
2139 case NFSATTRBIT_TYPE:
2140 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2141 *tl = vtonfsv34_type(vap->va_type);
2142 retnum += NFSX_UNSIGNED;
2144 case NFSATTRBIT_FHEXPIRETYPE:
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2147 retnum += NFSX_UNSIGNED;
2149 case NFSATTRBIT_CHANGE:
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2151 txdr_hyper(vap->va_filerev, tl);
2152 retnum += NFSX_HYPER;
2154 case NFSATTRBIT_SIZE:
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2156 txdr_hyper(vap->va_size, tl);
2157 retnum += NFSX_HYPER;
2159 case NFSATTRBIT_LINKSUPPORT:
2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2161 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2165 retnum += NFSX_UNSIGNED;
2167 case NFSATTRBIT_SYMLINKSUPPORT:
2168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2169 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2173 retnum += NFSX_UNSIGNED;
2175 case NFSATTRBIT_NAMEDATTR:
2176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 retnum += NFSX_UNSIGNED;
2180 case NFSATTRBIT_FSID:
2181 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2183 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2185 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2186 retnum += NFSX_V4FSID;
2188 case NFSATTRBIT_UNIQUEHANDLES:
2189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2191 retnum += NFSX_UNSIGNED;
2193 case NFSATTRBIT_LEASETIME:
2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2195 *tl = txdr_unsigned(nfsrv_lease);
2196 retnum += NFSX_UNSIGNED;
2198 case NFSATTRBIT_RDATTRERROR:
2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2200 *tl = txdr_unsigned(rderror);
2201 retnum += NFSX_UNSIGNED;
2204 * Recommended Attributes. (Only the supported ones.)
2206 case NFSATTRBIT_ACL:
2207 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2209 case NFSATTRBIT_ACLSUPPORT:
2210 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2211 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2212 retnum += NFSX_UNSIGNED;
2214 case NFSATTRBIT_CANSETTIME:
2215 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2216 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2220 retnum += NFSX_UNSIGNED;
2222 case NFSATTRBIT_CASEINSENSITIVE:
2223 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 retnum += NFSX_UNSIGNED;
2227 case NFSATTRBIT_CASEPRESERVING:
2228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2230 retnum += NFSX_UNSIGNED;
2232 case NFSATTRBIT_CHOWNRESTRICTED:
2233 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2235 retnum += NFSX_UNSIGNED;
2237 case NFSATTRBIT_FILEHANDLE:
2238 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2240 case NFSATTRBIT_FILEID:
2241 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2242 uquad = vap->va_fileid;
2243 txdr_hyper(uquad, tl);
2244 retnum += NFSX_HYPER;
2246 case NFSATTRBIT_FILESAVAIL:
2248 * Check quota and use min(quota, f_ffree).
2250 freenum = fs->f_ffree;
2253 * ufs_quotactl() insists that the uid argument
2254 * equal p_ruid for non-root quota access, so
2255 * we'll just make sure that's the case.
2257 savuid = p->p_cred->p_ruid;
2258 p->p_cred->p_ruid = cred->cr_uid;
2259 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2260 cred->cr_uid, (caddr_t)&dqb))
2261 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2263 p->p_cred->p_ruid = savuid;
2265 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2267 *tl = txdr_unsigned(freenum);
2268 retnum += NFSX_HYPER;
2270 case NFSATTRBIT_FILESFREE:
2271 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2273 *tl = txdr_unsigned(fs->f_ffree);
2274 retnum += NFSX_HYPER;
2276 case NFSATTRBIT_FILESTOTAL:
2277 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2279 *tl = txdr_unsigned(fs->f_files);
2280 retnum += NFSX_HYPER;
2282 case NFSATTRBIT_FSLOCATIONS:
2283 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2286 retnum += 2 * NFSX_UNSIGNED;
2288 case NFSATTRBIT_HOMOGENEOUS:
2289 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2290 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2294 retnum += NFSX_UNSIGNED;
2296 case NFSATTRBIT_MAXFILESIZE:
2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2298 uquad = NFSRV_MAXFILESIZE;
2299 txdr_hyper(uquad, tl);
2300 retnum += NFSX_HYPER;
2302 case NFSATTRBIT_MAXLINK:
2303 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2304 *tl = txdr_unsigned(LINK_MAX);
2305 retnum += NFSX_UNSIGNED;
2307 case NFSATTRBIT_MAXNAME:
2308 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2309 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2310 retnum += NFSX_UNSIGNED;
2312 case NFSATTRBIT_MAXREAD:
2313 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2315 *tl = txdr_unsigned(fsinf.fs_rtmax);
2316 retnum += NFSX_HYPER;
2318 case NFSATTRBIT_MAXWRITE:
2319 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2321 *tl = txdr_unsigned(fsinf.fs_wtmax);
2322 retnum += NFSX_HYPER;
2324 case NFSATTRBIT_MODE:
2325 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2326 *tl = vtonfsv34_mode(vap->va_mode);
2327 retnum += NFSX_UNSIGNED;
2329 case NFSATTRBIT_NOTRUNC:
2330 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2332 retnum += NFSX_UNSIGNED;
2334 case NFSATTRBIT_NUMLINKS:
2335 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2336 *tl = txdr_unsigned(vap->va_nlink);
2337 retnum += NFSX_UNSIGNED;
2339 case NFSATTRBIT_OWNER:
2341 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2342 retnum += nfsm_strtom(nd, cp, siz);
2344 free(cp, M_NFSSTRING);
2346 case NFSATTRBIT_OWNERGROUP:
2348 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2349 retnum += nfsm_strtom(nd, cp, siz);
2351 free(cp, M_NFSSTRING);
2353 case NFSATTRBIT_QUOTAHARD:
2354 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2355 freenum = fs->f_bfree;
2357 freenum = fs->f_bavail;
2360 * ufs_quotactl() insists that the uid argument
2361 * equal p_ruid for non-root quota access, so
2362 * we'll just make sure that's the case.
2364 savuid = p->p_cred->p_ruid;
2365 p->p_cred->p_ruid = cred->cr_uid;
2366 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2367 cred->cr_uid, (caddr_t)&dqb))
2368 freenum = min(dqb.dqb_bhardlimit, freenum);
2369 p->p_cred->p_ruid = savuid;
2371 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2372 uquad = (u_int64_t)freenum;
2373 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2374 txdr_hyper(uquad, tl);
2375 retnum += NFSX_HYPER;
2377 case NFSATTRBIT_QUOTASOFT:
2378 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2379 freenum = fs->f_bfree;
2381 freenum = fs->f_bavail;
2384 * ufs_quotactl() insists that the uid argument
2385 * equal p_ruid for non-root quota access, so
2386 * we'll just make sure that's the case.
2388 savuid = p->p_cred->p_ruid;
2389 p->p_cred->p_ruid = cred->cr_uid;
2390 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2391 cred->cr_uid, (caddr_t)&dqb))
2392 freenum = min(dqb.dqb_bsoftlimit, freenum);
2393 p->p_cred->p_ruid = savuid;
2395 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2396 uquad = (u_int64_t)freenum;
2397 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2398 txdr_hyper(uquad, tl);
2399 retnum += NFSX_HYPER;
2401 case NFSATTRBIT_QUOTAUSED:
2405 * ufs_quotactl() insists that the uid argument
2406 * equal p_ruid for non-root quota access, so
2407 * we'll just make sure that's the case.
2409 savuid = p->p_cred->p_ruid;
2410 p->p_cred->p_ruid = cred->cr_uid;
2411 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2412 cred->cr_uid, (caddr_t)&dqb))
2413 freenum = dqb.dqb_curblocks;
2414 p->p_cred->p_ruid = savuid;
2416 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2417 uquad = (u_int64_t)freenum;
2418 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2419 txdr_hyper(uquad, tl);
2420 retnum += NFSX_HYPER;
2422 case NFSATTRBIT_RAWDEV:
2423 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2424 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2425 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2426 retnum += NFSX_V4SPECDATA;
2428 case NFSATTRBIT_SPACEAVAIL:
2429 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2430 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2431 uquad = (u_int64_t)fs->f_bfree;
2433 uquad = (u_int64_t)fs->f_bavail;
2434 uquad *= fs->f_bsize;
2435 txdr_hyper(uquad, tl);
2436 retnum += NFSX_HYPER;
2438 case NFSATTRBIT_SPACEFREE:
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2440 uquad = (u_int64_t)fs->f_bfree;
2441 uquad *= fs->f_bsize;
2442 txdr_hyper(uquad, tl);
2443 retnum += NFSX_HYPER;
2445 case NFSATTRBIT_SPACETOTAL:
2446 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2447 uquad = (u_int64_t)fs->f_blocks;
2448 uquad *= fs->f_bsize;
2449 txdr_hyper(uquad, tl);
2450 retnum += NFSX_HYPER;
2452 case NFSATTRBIT_SPACEUSED:
2453 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2454 txdr_hyper(vap->va_bytes, tl);
2455 retnum += NFSX_HYPER;
2457 case NFSATTRBIT_TIMEACCESS:
2458 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2459 txdr_nfsv4time(&vap->va_atime, tl);
2460 retnum += NFSX_V4TIME;
2462 case NFSATTRBIT_TIMEACCESSSET:
2463 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2464 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2465 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2466 txdr_nfsv4time(&vap->va_atime, tl);
2467 retnum += NFSX_V4SETTIME;
2469 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2470 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2471 retnum += NFSX_UNSIGNED;
2474 case NFSATTRBIT_TIMEDELTA:
2475 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2476 temptime.tv_sec = 0;
2477 temptime.tv_nsec = 1000000000 / hz;
2478 txdr_nfsv4time(&temptime, tl);
2479 retnum += NFSX_V4TIME;
2481 case NFSATTRBIT_TIMEMETADATA:
2482 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2483 txdr_nfsv4time(&vap->va_ctime, tl);
2484 retnum += NFSX_V4TIME;
2486 case NFSATTRBIT_TIMEMODIFY:
2487 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2488 txdr_nfsv4time(&vap->va_mtime, tl);
2489 retnum += NFSX_V4TIME;
2491 case NFSATTRBIT_TIMEMODIFYSET:
2492 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2493 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2494 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2495 txdr_nfsv4time(&vap->va_mtime, tl);
2496 retnum += NFSX_V4SETTIME;
2498 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2499 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2500 retnum += NFSX_UNSIGNED;
2503 case NFSATTRBIT_MOUNTEDONFILEID:
2504 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2506 uquad = mounted_on_fileno;
2508 uquad = vap->va_fileid;
2509 txdr_hyper(uquad, tl);
2510 retnum += NFSX_HYPER;
2512 case NFSATTRBIT_SUPPATTREXCLCREAT:
2513 NFSSETSUPP_ATTRBIT(&attrbits);
2514 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2515 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2516 retnum += nfsrv_putattrbit(nd, &attrbits);
2519 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2526 *retnump = txdr_unsigned(retnum);
2527 return (retnum + prefixnum);
2531 * Put the attribute bits onto an mbuf list.
2532 * Return the number of bytes of output generated.
2535 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2538 int cnt, i, bytesize;
2540 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2541 if (attrbitp->bits[cnt - 1])
2543 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2544 NFSM_BUILD(tl, u_int32_t *, bytesize);
2545 *tl++ = txdr_unsigned(cnt);
2546 for (i = 0; i < cnt; i++)
2547 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2552 * Convert a uid to a string.
2553 * If the lookup fails, just output the digits.
2555 * cpp - points to a buffer of size NFSV4_SMALLSTR
2556 * (malloc a larger one, as required)
2557 * retlenp - pointer to length to be returned
2560 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2563 struct nfsusrgrp *usrp;
2566 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2567 struct nfsrv_lughash *hp;
2571 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2573 * Always map nfsrv_defaultuid to "nobody".
2575 if (uid == nfsrv_defaultuid) {
2576 i = nfsrv_dnsnamelen + 7;
2578 if (len > NFSV4_SMALLSTR)
2579 free(cp, M_NFSSTRING);
2580 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2586 NFSBCOPY("nobody@", cp, 7);
2588 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2592 hp = NFSUSERHASH(uid);
2594 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2595 if (usrp->lug_uid == uid) {
2596 if (usrp->lug_expiry < NFSD_MONOSEC)
2599 * If the name doesn't already have an '@'
2600 * in it, append @domainname to it.
2602 for (i = 0; i < usrp->lug_namelen; i++) {
2603 if (usrp->lug_name[i] == '@') {
2609 i = usrp->lug_namelen;
2611 i = usrp->lug_namelen +
2612 nfsrv_dnsnamelen + 1;
2614 mtx_unlock(&hp->mtx);
2615 if (len > NFSV4_SMALLSTR)
2616 free(cp, M_NFSSTRING);
2617 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2623 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2624 if (!hasampersand) {
2625 cp += usrp->lug_namelen;
2627 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2629 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2630 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2632 mtx_unlock(&hp->mtx);
2636 mtx_unlock(&hp->mtx);
2638 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2640 if (ret == 0 && cnt < 2)
2645 * No match, just return a string of digits.
2649 while (tmp || i == 0) {
2653 len = (i > len) ? len : i;
2657 for (i = 0; i < len; i++) {
2658 *cp-- = '0' + (tmp % 10);
2665 * Get a credential for the uid with the server's group list.
2666 * If none is found, just return the credential passed in after
2667 * logging a warning message.
2670 nfsrv_getgrpscred(struct ucred *oldcred)
2672 struct nfsusrgrp *usrp;
2673 struct ucred *newcred;
2676 struct nfsrv_lughash *hp;
2679 uid = oldcred->cr_uid;
2681 if (nfsrv_dnsnamelen > 0) {
2682 hp = NFSUSERHASH(uid);
2684 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2685 if (usrp->lug_uid == uid) {
2686 if (usrp->lug_expiry < NFSD_MONOSEC)
2688 if (usrp->lug_cred != NULL) {
2689 newcred = crhold(usrp->lug_cred);
2693 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2694 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2696 mtx_unlock(&hp->mtx);
2700 mtx_unlock(&hp->mtx);
2702 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2704 if (ret == 0 && cnt < 2)
2711 * Convert a string to a uid.
2712 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2714 * If this is called from a client side mount using AUTH_SYS and the
2715 * string is made up entirely of digits, just convert the string to
2719 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2723 char *cp, *endstr, *str0;
2724 struct nfsusrgrp *usrp;
2728 struct nfsrv_lughash *hp, *hp2;
2731 error = NFSERR_BADOWNER;
2734 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2736 tuid = (uid_t)strtoul(str0, &endstr, 10);
2737 if ((endstr - str0) == len) {
2738 /* A numeric string. */
2739 if ((nd->nd_flag & ND_KERBV) == 0 &&
2740 ((nd->nd_flag & ND_NFSCL) != 0 ||
2741 nfsd_enable_stringtouid != 0))
2744 error = NFSERR_BADOWNER;
2750 cp = strchr(str0, '@');
2752 i = (int)(cp++ - str0);
2758 if (nfsrv_dnsnamelen > 0) {
2760 * If an '@' is found and the domain name matches, search for
2761 * the name with dns stripped off.
2762 * Mixed case alpahbetics will match for the domain name, but
2763 * all upper case will not.
2765 if (cnt == 0 && i < len && i > 0 &&
2766 (len - 1 - i) == nfsrv_dnsnamelen &&
2767 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2768 len -= (nfsrv_dnsnamelen + 1);
2773 * Check for the special case of "nobody".
2775 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2776 *uidp = nfsrv_defaultuid;
2781 hp = NFSUSERNAMEHASH(str, len);
2783 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2784 if (usrp->lug_namelen == len &&
2785 !NFSBCMP(usrp->lug_name, str, len)) {
2786 if (usrp->lug_expiry < NFSD_MONOSEC)
2788 hp2 = NFSUSERHASH(usrp->lug_uid);
2789 mtx_lock(&hp2->mtx);
2790 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2791 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2793 *uidp = usrp->lug_uid;
2794 mtx_unlock(&hp2->mtx);
2795 mtx_unlock(&hp->mtx);
2800 mtx_unlock(&hp->mtx);
2802 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2804 if (ret == 0 && cnt < 2)
2807 error = NFSERR_BADOWNER;
2815 * Convert a gid to a string.
2816 * gid - the group id
2817 * cpp - points to a buffer of size NFSV4_SMALLSTR
2818 * (malloc a larger one, as required)
2819 * retlenp - pointer to length to be returned
2822 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2825 struct nfsusrgrp *usrp;
2828 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2829 struct nfsrv_lughash *hp;
2833 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2835 * Always map nfsrv_defaultgid to "nogroup".
2837 if (gid == nfsrv_defaultgid) {
2838 i = nfsrv_dnsnamelen + 8;
2840 if (len > NFSV4_SMALLSTR)
2841 free(cp, M_NFSSTRING);
2842 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2848 NFSBCOPY("nogroup@", cp, 8);
2850 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2854 hp = NFSGROUPHASH(gid);
2856 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2857 if (usrp->lug_gid == gid) {
2858 if (usrp->lug_expiry < NFSD_MONOSEC)
2861 * If the name doesn't already have an '@'
2862 * in it, append @domainname to it.
2864 for (i = 0; i < usrp->lug_namelen; i++) {
2865 if (usrp->lug_name[i] == '@') {
2871 i = usrp->lug_namelen;
2873 i = usrp->lug_namelen +
2874 nfsrv_dnsnamelen + 1;
2876 mtx_unlock(&hp->mtx);
2877 if (len > NFSV4_SMALLSTR)
2878 free(cp, M_NFSSTRING);
2879 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2885 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2886 if (!hasampersand) {
2887 cp += usrp->lug_namelen;
2889 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2891 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2892 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2894 mtx_unlock(&hp->mtx);
2898 mtx_unlock(&hp->mtx);
2900 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2902 if (ret == 0 && cnt < 2)
2907 * No match, just return a string of digits.
2911 while (tmp || i == 0) {
2915 len = (i > len) ? len : i;
2919 for (i = 0; i < len; i++) {
2920 *cp-- = '0' + (tmp % 10);
2927 * Convert a string to a gid.
2928 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2930 * If this is called from a client side mount using AUTH_SYS and the
2931 * string is made up entirely of digits, just convert the string to
2935 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2939 char *cp, *endstr, *str0;
2940 struct nfsusrgrp *usrp;
2944 struct nfsrv_lughash *hp, *hp2;
2947 error = NFSERR_BADOWNER;
2950 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2952 tgid = (gid_t)strtoul(str0, &endstr, 10);
2953 if ((endstr - str0) == len) {
2954 /* A numeric string. */
2955 if ((nd->nd_flag & ND_KERBV) == 0 &&
2956 ((nd->nd_flag & ND_NFSCL) != 0 ||
2957 nfsd_enable_stringtouid != 0))
2960 error = NFSERR_BADOWNER;
2966 cp = strchr(str0, '@');
2968 i = (int)(cp++ - str0);
2974 if (nfsrv_dnsnamelen > 0) {
2976 * If an '@' is found and the dns name matches, search for the
2977 * name with the dns stripped off.
2979 if (cnt == 0 && i < len && i > 0 &&
2980 (len - 1 - i) == nfsrv_dnsnamelen &&
2981 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2982 len -= (nfsrv_dnsnamelen + 1);
2987 * Check for the special case of "nogroup".
2989 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2990 *gidp = nfsrv_defaultgid;
2995 hp = NFSGROUPNAMEHASH(str, len);
2997 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2998 if (usrp->lug_namelen == len &&
2999 !NFSBCMP(usrp->lug_name, str, len)) {
3000 if (usrp->lug_expiry < NFSD_MONOSEC)
3002 hp2 = NFSGROUPHASH(usrp->lug_gid);
3003 mtx_lock(&hp2->mtx);
3004 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3005 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3007 *gidp = usrp->lug_gid;
3008 mtx_unlock(&hp2->mtx);
3009 mtx_unlock(&hp->mtx);
3014 mtx_unlock(&hp->mtx);
3016 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3018 if (ret == 0 && cnt < 2)
3021 error = NFSERR_BADOWNER;
3029 * Cmp len chars, allowing mixed case in the first argument to match lower
3030 * case in the second, but not if the first argument is all upper case.
3031 * Return 0 for a match, 1 otherwise.
3034 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3040 for (i = 0; i < len; i++) {
3041 if (*cp >= 'A' && *cp <= 'Z') {
3042 tmp = *cp++ + ('a' - 'A');
3045 if (tmp >= 'a' && tmp <= 'z')
3058 * Set the port for the nfsuserd.
3061 nfsrv_nfsuserdport(struct sockaddr *sad, u_short port, NFSPROC_T *p)
3063 struct nfssockreq *rp;
3064 struct sockaddr_in *ad;
3068 if (nfsrv_nfsuserd) {
3071 NFSSOCKADDRFREE(sad);
3077 * Set up the socket record and connect.
3079 rp = &nfsrv_nfsuserdsock;
3080 rp->nr_client = NULL;
3082 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3084 /* Use the AF_LOCAL socket address passed in. */
3085 rp->nr_sotype = SOCK_STREAM;
3089 /* Use the port# for a UDP socket (old nfsuserd). */
3090 rp->nr_sotype = SOCK_DGRAM;
3091 rp->nr_soproto = IPPROTO_UDP;
3092 NFSSOCKADDRALLOC(rp->nr_nam);
3093 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3094 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3095 ad->sin_family = AF_INET;
3096 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);
3097 ad->sin_port = port;
3099 rp->nr_prog = RPCPROG_NFSUSERD;
3100 rp->nr_vers = RPCNFSUSERD_VERS;
3101 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3103 NFSSOCKADDRFREE(rp->nr_nam);
3112 * Delete the nfsuserd port.
3115 nfsrv_nfsuserddelport(void)
3119 if (nfsrv_nfsuserd == 0) {
3125 newnfs_disconnect(&nfsrv_nfsuserdsock);
3126 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3130 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3132 * Returns 0 upon success, non-zero otherwise.
3135 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3138 struct nfsrv_descript *nd;
3140 struct nfsrv_descript nfsd;
3145 if (nfsrv_nfsuserd == 0) {
3152 cred = newnfs_getcred();
3153 nd->nd_flag = ND_GSSINITREPLY;
3156 nd->nd_procnum = procnum;
3157 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3158 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3159 if (procnum == RPCNFSUSERD_GETUID)
3160 *tl = txdr_unsigned(uid);
3162 *tl = txdr_unsigned(gid);
3165 (void) nfsm_strtom(nd, name, len);
3167 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3168 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3171 mbuf_freem(nd->nd_mrep);
3172 error = nd->nd_repstat;
3180 * This function is called from the nfssvc(2) system call, to update the
3181 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3184 nfssvc_idname(struct nfsd_idargs *nidp)
3186 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3187 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3188 int i, group_locked, groupname_locked, user_locked, username_locked;
3193 static int onethread = 0;
3194 static time_t lasttime = 0;
3196 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3200 if (nidp->nid_flag & NFSID_INITIALIZE) {
3201 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3202 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3205 free(cp, M_NFSSTRING);
3208 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3210 * Free up all the old stuff and reinitialize hash
3211 * lists. All mutexes for both lists must be locked,
3212 * with the user/group name ones before the uid/gid
3213 * ones, to avoid a LOR.
3215 for (i = 0; i < nfsrv_lughashsize; i++)
3216 mtx_lock(&nfsusernamehash[i].mtx);
3217 for (i = 0; i < nfsrv_lughashsize; i++)
3218 mtx_lock(&nfsuserhash[i].mtx);
3219 for (i = 0; i < nfsrv_lughashsize; i++)
3220 TAILQ_FOREACH_SAFE(usrp,
3221 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3222 nfsrv_removeuser(usrp, 1);
3223 for (i = 0; i < nfsrv_lughashsize; i++)
3224 mtx_unlock(&nfsuserhash[i].mtx);
3225 for (i = 0; i < nfsrv_lughashsize; i++)
3226 mtx_unlock(&nfsusernamehash[i].mtx);
3227 for (i = 0; i < nfsrv_lughashsize; i++)
3228 mtx_lock(&nfsgroupnamehash[i].mtx);
3229 for (i = 0; i < nfsrv_lughashsize; i++)
3230 mtx_lock(&nfsgrouphash[i].mtx);
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 TAILQ_FOREACH_SAFE(usrp,
3233 &nfsgrouphash[i].lughead, lug_numhash,
3235 nfsrv_removeuser(usrp, 0);
3236 for (i = 0; i < nfsrv_lughashsize; i++)
3237 mtx_unlock(&nfsgrouphash[i].mtx);
3238 for (i = 0; i < nfsrv_lughashsize; i++)
3239 mtx_unlock(&nfsgroupnamehash[i].mtx);
3240 free(nfsrv_dnsname, M_NFSSTRING);
3241 nfsrv_dnsname = NULL;
3243 if (nfsuserhash == NULL) {
3244 /* Allocate the hash tables. */
3245 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3246 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3248 for (i = 0; i < nfsrv_lughashsize; i++)
3249 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3250 NULL, MTX_DEF | MTX_DUPOK);
3251 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3252 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3254 for (i = 0; i < nfsrv_lughashsize; i++)
3255 mtx_init(&nfsusernamehash[i].mtx,
3256 "nfsusrhash", NULL, MTX_DEF |
3258 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3259 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3261 for (i = 0; i < nfsrv_lughashsize; i++)
3262 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3263 NULL, MTX_DEF | MTX_DUPOK);
3264 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3265 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3267 for (i = 0; i < nfsrv_lughashsize; i++)
3268 mtx_init(&nfsgroupnamehash[i].mtx,
3269 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3271 /* (Re)initialize the list heads. */
3272 for (i = 0; i < nfsrv_lughashsize; i++)
3273 TAILQ_INIT(&nfsuserhash[i].lughead);
3274 for (i = 0; i < nfsrv_lughashsize; i++)
3275 TAILQ_INIT(&nfsusernamehash[i].lughead);
3276 for (i = 0; i < nfsrv_lughashsize; i++)
3277 TAILQ_INIT(&nfsgrouphash[i].lughead);
3278 for (i = 0; i < nfsrv_lughashsize; i++)
3279 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3282 * Put name in "DNS" string.
3285 nfsrv_defaultuid = nidp->nid_uid;
3286 nfsrv_defaultgid = nidp->nid_gid;
3288 nfsrv_usermax = nidp->nid_usermax;
3289 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3294 * malloc the new one now, so any potential sleep occurs before
3295 * manipulation of the lists.
3297 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3298 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3299 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3301 if (error == 0 && nidp->nid_ngroup > 0 &&
3302 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3303 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3305 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3306 sizeof(gid_t) * nidp->nid_ngroup);
3309 * Create a credential just like svc_getcred(),
3310 * but using the group list provided.
3313 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3314 crsetgroups(cr, nidp->nid_ngroup, grps);
3315 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3316 cr->cr_prison = &prison0;
3317 prison_hold(cr->cr_prison);
3319 mac_cred_associate_nfsd(cr);
3321 newusrp->lug_cred = cr;
3326 free(newusrp, M_NFSUSERGROUP);
3329 newusrp->lug_namelen = nidp->nid_namelen;
3332 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3333 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3334 * The flags user_locked, username_locked, group_locked and
3335 * groupname_locked are set to indicate all of those hash lists are
3336 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3337 * the respective one mutex is locked.
3339 user_locked = username_locked = group_locked = groupname_locked = 0;
3340 hp_name = hp_idnum = NULL;
3343 * Delete old entries, as required.
3345 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3346 /* Must lock all username hash lists first, to avoid a LOR. */
3347 for (i = 0; i < nfsrv_lughashsize; i++)
3348 mtx_lock(&nfsusernamehash[i].mtx);
3349 username_locked = 1;
3350 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3351 mtx_lock(&hp_idnum->mtx);
3352 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3354 if (usrp->lug_uid == nidp->nid_uid)
3355 nfsrv_removeuser(usrp, 1);
3357 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3358 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3359 newusrp->lug_namelen);
3360 mtx_lock(&hp_name->mtx);
3361 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3363 if (usrp->lug_namelen == newusrp->lug_namelen &&
3364 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3365 usrp->lug_namelen)) {
3366 thp = NFSUSERHASH(usrp->lug_uid);
3367 mtx_lock(&thp->mtx);
3368 nfsrv_removeuser(usrp, 1);
3369 mtx_unlock(&thp->mtx);
3372 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3373 mtx_lock(&hp_idnum->mtx);
3374 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3375 /* Must lock all groupname hash lists first, to avoid a LOR. */
3376 for (i = 0; i < nfsrv_lughashsize; i++)
3377 mtx_lock(&nfsgroupnamehash[i].mtx);
3378 groupname_locked = 1;
3379 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3380 mtx_lock(&hp_idnum->mtx);
3381 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3383 if (usrp->lug_gid == nidp->nid_gid)
3384 nfsrv_removeuser(usrp, 0);
3386 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3387 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3388 newusrp->lug_namelen);
3389 mtx_lock(&hp_name->mtx);
3390 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3392 if (usrp->lug_namelen == newusrp->lug_namelen &&
3393 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3394 usrp->lug_namelen)) {
3395 thp = NFSGROUPHASH(usrp->lug_gid);
3396 mtx_lock(&thp->mtx);
3397 nfsrv_removeuser(usrp, 0);
3398 mtx_unlock(&thp->mtx);
3401 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3402 mtx_lock(&hp_idnum->mtx);
3406 * Now, we can add the new one.
3408 if (nidp->nid_usertimeout)
3409 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3411 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3412 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3413 newusrp->lug_uid = nidp->nid_uid;
3414 thp = NFSUSERHASH(newusrp->lug_uid);
3415 mtx_assert(&thp->mtx, MA_OWNED);
3416 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3417 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3418 mtx_assert(&thp->mtx, MA_OWNED);
3419 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3420 atomic_add_int(&nfsrv_usercnt, 1);
3421 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3422 newusrp->lug_gid = nidp->nid_gid;
3423 thp = NFSGROUPHASH(newusrp->lug_gid);
3424 mtx_assert(&thp->mtx, MA_OWNED);
3425 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3426 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3427 mtx_assert(&thp->mtx, MA_OWNED);
3428 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3429 atomic_add_int(&nfsrv_usercnt, 1);
3431 if (newusrp->lug_cred != NULL)
3432 crfree(newusrp->lug_cred);
3433 free(newusrp, M_NFSUSERGROUP);
3437 * Once per second, allow one thread to trim the cache.
3439 if (lasttime < NFSD_MONOSEC &&
3440 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3442 * First, unlock the single mutexes, so that all entries
3443 * can be locked and any LOR is avoided.
3445 if (hp_name != NULL) {
3446 mtx_unlock(&hp_name->mtx);
3449 if (hp_idnum != NULL) {
3450 mtx_unlock(&hp_idnum->mtx);
3454 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3455 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3456 if (username_locked == 0) {
3457 for (i = 0; i < nfsrv_lughashsize; i++)
3458 mtx_lock(&nfsusernamehash[i].mtx);
3459 username_locked = 1;
3461 KASSERT(user_locked == 0,
3462 ("nfssvc_idname: user_locked"));
3463 for (i = 0; i < nfsrv_lughashsize; i++)
3464 mtx_lock(&nfsuserhash[i].mtx);
3466 for (i = 0; i < nfsrv_lughashsize; i++) {
3467 TAILQ_FOREACH_SAFE(usrp,
3468 &nfsuserhash[i].lughead, lug_numhash,
3470 if (usrp->lug_expiry < NFSD_MONOSEC)
3471 nfsrv_removeuser(usrp, 1);
3473 for (i = 0; i < nfsrv_lughashsize; i++) {
3475 * Trim the cache using an approximate LRU
3476 * algorithm. This code deletes the least
3477 * recently used entry on each hash list.
3479 if (nfsrv_usercnt <= nfsrv_usermax)
3481 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3483 nfsrv_removeuser(usrp, 1);
3486 if (groupname_locked == 0) {
3487 for (i = 0; i < nfsrv_lughashsize; i++)
3488 mtx_lock(&nfsgroupnamehash[i].mtx);
3489 groupname_locked = 1;
3491 KASSERT(group_locked == 0,
3492 ("nfssvc_idname: group_locked"));
3493 for (i = 0; i < nfsrv_lughashsize; i++)
3494 mtx_lock(&nfsgrouphash[i].mtx);
3496 for (i = 0; i < nfsrv_lughashsize; i++) {
3497 TAILQ_FOREACH_SAFE(usrp,
3498 &nfsgrouphash[i].lughead, lug_numhash,
3500 if (usrp->lug_expiry < NFSD_MONOSEC)
3501 nfsrv_removeuser(usrp, 0);
3503 for (i = 0; i < nfsrv_lughashsize; i++) {
3505 * Trim the cache using an approximate LRU
3506 * algorithm. This code deletes the least
3507 * recently user entry on each hash list.
3509 if (nfsrv_usercnt <= nfsrv_usermax)
3511 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3513 nfsrv_removeuser(usrp, 0);
3516 lasttime = NFSD_MONOSEC;
3517 atomic_store_rel_int(&onethread, 0);
3520 /* Now, unlock all locked mutexes. */
3521 if (hp_idnum != NULL)
3522 mtx_unlock(&hp_idnum->mtx);
3523 if (hp_name != NULL)
3524 mtx_unlock(&hp_name->mtx);
3525 if (user_locked != 0)
3526 for (i = 0; i < nfsrv_lughashsize; i++)
3527 mtx_unlock(&nfsuserhash[i].mtx);
3528 if (username_locked != 0)
3529 for (i = 0; i < nfsrv_lughashsize; i++)
3530 mtx_unlock(&nfsusernamehash[i].mtx);
3531 if (group_locked != 0)
3532 for (i = 0; i < nfsrv_lughashsize; i++)
3533 mtx_unlock(&nfsgrouphash[i].mtx);
3534 if (groupname_locked != 0)
3535 for (i = 0; i < nfsrv_lughashsize; i++)
3536 mtx_unlock(&nfsgroupnamehash[i].mtx);
3543 * Remove a user/group name element.
3546 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3548 struct nfsrv_lughash *hp;
3551 hp = NFSUSERHASH(usrp->lug_uid);
3552 mtx_assert(&hp->mtx, MA_OWNED);
3553 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3554 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3555 mtx_assert(&hp->mtx, MA_OWNED);
3556 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3558 hp = NFSGROUPHASH(usrp->lug_gid);
3559 mtx_assert(&hp->mtx, MA_OWNED);
3560 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3561 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3562 mtx_assert(&hp->mtx, MA_OWNED);
3563 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3565 atomic_add_int(&nfsrv_usercnt, -1);
3566 if (usrp->lug_cred != NULL)
3567 crfree(usrp->lug_cred);
3568 free(usrp, M_NFSUSERGROUP);
3572 * Free up all the allocations related to the name<-->id cache.
3573 * This function should only be called when the nfsuserd daemon isn't
3574 * running, since it doesn't do any locking.
3575 * This function is meant to be used when the nfscommon module is unloaded.
3578 nfsrv_cleanusergroup(void)
3580 struct nfsrv_lughash *hp, *hp2;
3581 struct nfsusrgrp *nusrp, *usrp;
3584 if (nfsuserhash == NULL)
3587 for (i = 0; i < nfsrv_lughashsize; i++) {
3588 hp = &nfsuserhash[i];
3589 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3590 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3591 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3593 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3594 if (usrp->lug_cred != NULL)
3595 crfree(usrp->lug_cred);
3596 free(usrp, M_NFSUSERGROUP);
3598 hp = &nfsgrouphash[i];
3599 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3600 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3601 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3603 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3604 if (usrp->lug_cred != NULL)
3605 crfree(usrp->lug_cred);
3606 free(usrp, M_NFSUSERGROUP);
3608 mtx_destroy(&nfsuserhash[i].mtx);
3609 mtx_destroy(&nfsusernamehash[i].mtx);
3610 mtx_destroy(&nfsgroupnamehash[i].mtx);
3611 mtx_destroy(&nfsgrouphash[i].mtx);
3613 free(nfsuserhash, M_NFSUSERGROUP);
3614 free(nfsusernamehash, M_NFSUSERGROUP);
3615 free(nfsgrouphash, M_NFSUSERGROUP);
3616 free(nfsgroupnamehash, M_NFSUSERGROUP);
3617 free(nfsrv_dnsname, M_NFSSTRING);
3621 * This function scans a byte string and checks for UTF-8 compliance.
3622 * It returns 0 if it conforms and NFSERR_INVAL if not.
3625 nfsrv_checkutf8(u_int8_t *cp, int len)
3627 u_int32_t val = 0x0;
3628 int cnt = 0, gotd = 0, shift = 0;
3630 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3634 * Here are what the variables are used for:
3635 * val - the calculated value of a multibyte char, used to check
3636 * that it was coded with the correct range
3637 * cnt - the number of 10xxxxxx bytes to follow
3638 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3639 * shift - lower order bits of range (ie. "val >> shift" should
3640 * not be 0, in other words, dividing by the lower bound
3641 * of the range should get a non-zero value)
3642 * byte - used to calculate cnt
3646 /* This handles the 10xxxxxx bytes */
3647 if ((*cp & 0xc0) != 0x80 ||
3648 (gotd && (*cp & 0x20))) {
3649 error = NFSERR_INVAL;
3654 val |= (*cp & 0x3f);
3656 if (cnt == 0 && (val >> shift) == 0x0) {
3657 error = NFSERR_INVAL;
3660 } else if (*cp & 0x80) {
3661 /* first byte of multi byte char */
3663 while ((byte & 0x40) && cnt < 6) {
3667 if (cnt == 0 || cnt == 6) {
3668 error = NFSERR_INVAL;
3671 val = (*cp & (0x3f >> cnt));
3672 shift = utf8_shift[cnt - 1];
3673 if (cnt == 2 && val == 0xd)
3674 /* Check for the 0xd800-0xdfff case */
3681 error = NFSERR_INVAL;
3689 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3690 * strings, one with the root path in it and the other with the list of
3691 * locations. The list is in the same format as is found in nfr_refs.
3692 * It is a "," separated list of entries, where each of them is of the
3693 * form <server>:<rootpath>. For example
3694 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3695 * The nilp argument is set to 1 for the special case of a null fs_root
3696 * and an empty server list.
3697 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3698 * number of xdr bytes parsed in sump.
3701 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3702 int *sump, int *nilp)
3705 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3706 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3708 SLIST_ENTRY(list) next;
3712 SLIST_HEAD(, list) head;
3719 * Get the fs_root path and check for the special case of null path
3720 * and 0 length server list.
3722 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3723 len = fxdr_unsigned(int, *tl);
3724 if (len < 0 || len > 10240) {
3725 error = NFSERR_BADXDR;
3729 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3731 error = NFSERR_BADXDR;
3735 *sump = 2 * NFSX_UNSIGNED;
3739 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3740 error = nfsrv_mtostr(nd, cp, len);
3742 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3743 cnt = fxdr_unsigned(int, *tl);
3745 error = NFSERR_BADXDR;
3751 * Now, loop through the location list and make up the srvlist.
3753 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3754 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3757 for (i = 0; i < cnt; i++) {
3759 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3760 nsrv = fxdr_unsigned(int, *tl);
3762 error = NFSERR_BADXDR;
3767 * Handle the first server by putting it in the srvstr.
3769 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3770 len = fxdr_unsigned(int, *tl);
3771 if (len <= 0 || len > 1024) {
3772 error = NFSERR_BADXDR;
3775 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3780 error = nfsrv_mtostr(nd, cp3, len);
3786 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3787 for (j = 1; j < nsrv; j++) {
3789 * Yuck, put them in an slist and process them later.
3791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3792 len = fxdr_unsigned(int, *tl);
3793 if (len <= 0 || len > 1024) {
3794 error = NFSERR_BADXDR;
3797 lsp = (struct list *)malloc(sizeof (struct list)
3798 + len, M_TEMP, M_WAITOK);
3799 error = nfsrv_mtostr(nd, lsp->host, len);
3802 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3804 SLIST_INSERT_HEAD(&head, lsp, next);
3808 * Finally, we can get the path.
3810 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3811 len = fxdr_unsigned(int, *tl);
3812 if (len <= 0 || len > 1024) {
3813 error = NFSERR_BADXDR;
3816 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3817 error = nfsrv_mtostr(nd, cp3, len);
3820 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3825 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3826 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3829 NFSBCOPY(lsp->host, cp3, lsp->len);
3832 NFSBCOPY(str, cp3, stringlen);
3835 siz += (lsp->len + stringlen + 2);
3836 free((caddr_t)lsp, M_TEMP);
3842 NFSEXITCODE2(0, nd);
3846 free(cp, M_NFSSTRING);
3848 free(cp2, M_NFSSTRING);
3849 NFSEXITCODE2(error, nd);
3854 * Make the malloc'd space large enough. This is a pain, but the xdr
3855 * doesn't set an upper bound on the side, so...
3858 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3865 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3866 NFSBCOPY(*cpp, cp, *slenp);
3867 free(*cpp, M_NFSSTRING);
3871 *slenp = siz + 1024;
3875 * Initialize the reply header data structures.
3878 nfsrvd_rephead(struct nfsrv_descript *nd)
3883 * If this is a big reply, use a cluster.
3885 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3886 nfs_bigreply[nd->nd_procnum]) {
3887 NFSMCLGET(mreq, M_WAITOK);
3895 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3896 mbuf_setlen(mreq, 0);
3898 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3899 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3903 * Lock a socket against others.
3904 * Currently used to serialize connect/disconnect attempts.
3907 newnfs_sndlock(int *flagp)
3912 while (*flagp & NFSR_SNDLOCK) {
3913 *flagp |= NFSR_WANTSND;
3916 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3917 PZERO - 1, "nfsndlck", &ts);
3919 *flagp |= NFSR_SNDLOCK;
3925 * Unlock the stream socket for others.
3928 newnfs_sndunlock(int *flagp)
3932 if ((*flagp & NFSR_SNDLOCK) == 0)
3933 panic("nfs sndunlock");
3934 *flagp &= ~NFSR_SNDLOCK;
3935 if (*flagp & NFSR_WANTSND) {
3936 *flagp &= ~NFSR_WANTSND;
3937 wakeup((caddr_t)flagp);
3943 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
3944 struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
3946 struct in_addr saddr;
3947 uint32_t portnum, *tl;
3949 sa_family_t af = AF_UNSPEC;
3950 char addr[64], protocol[5], *cp;
3951 int cantparse = 0, error = 0;
3954 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3955 i = fxdr_unsigned(int, *tl);
3956 if (i >= 3 && i <= 4) {
3957 error = nfsrv_mtostr(nd, protocol, i);
3960 if (strcmp(protocol, "tcp") == 0) {
3963 } else if (strcmp(protocol, "udp") == 0) {
3966 } else if (strcmp(protocol, "tcp6") == 0) {
3969 } else if (strcmp(protocol, "udp6") == 0) {
3977 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3983 i = fxdr_unsigned(int, *tl);
3985 error = NFSERR_BADXDR;
3987 } else if (cantparse == 0 && i >= 11 && i < 64) {
3989 * The shortest address is 11chars and the longest is < 64.
3991 error = nfsrv_mtostr(nd, addr, i);
3995 /* Find the port# at the end and extract that. */
3999 /* Count back two '.'s from end to get port# field. */
4000 for (j = 0; j < i; j++) {
4010 * The NFSv4 port# is appended as .N.N, where N is
4011 * a decimal # in the range 0-255, just like an inet4
4012 * address. Cheat and use inet_aton(), which will
4013 * return a Class A address and then shift the high
4014 * order 8bits over to convert it to the port#.
4017 if (inet_aton(cp, &saddr) == 1) {
4018 portnum = ntohl(saddr.s_addr);
4019 portv = (uint16_t)((portnum >> 16) |
4025 if (cantparse == 0) {
4026 if (af == AF_INET) {
4027 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4028 sin->sin_len = sizeof(*sin);
4029 sin->sin_family = AF_INET;
4030 sin->sin_port = htons(portv);
4035 if (inet_pton(af, addr, &sin6->sin6_addr)
4037 sin6->sin6_len = sizeof(*sin6);
4038 sin6->sin6_family = AF_INET6;
4039 sin6->sin6_port = htons(portv);
4047 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4058 * Handle an NFSv4.1 Sequence request for the session.
4059 * If reply != NULL, use it to return the cached reply, as required.
4060 * The client gets a cached reply via this call for callbacks, however the
4061 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4064 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4065 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4072 if (slotid > maxslot)
4073 return (NFSERR_BADSLOT);
4074 if (seqid == slots[slotid].nfssl_seq) {
4076 if (slots[slotid].nfssl_inprog != 0)
4077 error = NFSERR_DELAY;
4078 else if (slots[slotid].nfssl_reply != NULL) {
4079 if (reply != NULL) {
4080 *reply = slots[slotid].nfssl_reply;
4081 slots[slotid].nfssl_reply = NULL;
4083 slots[slotid].nfssl_inprog = 1;
4084 error = NFSERR_REPLYFROMCACHE;
4086 /* No reply cached, so just do it. */
4087 slots[slotid].nfssl_inprog = 1;
4088 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4089 if (slots[slotid].nfssl_reply != NULL)
4090 m_freem(slots[slotid].nfssl_reply);
4091 slots[slotid].nfssl_reply = NULL;
4092 slots[slotid].nfssl_inprog = 1;
4093 slots[slotid].nfssl_seq++;
4095 error = NFSERR_SEQMISORDERED;
4100 * Cache this reply for the slot.
4101 * Use the "rep" argument to return the cached reply if repstat is set to
4102 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4105 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4109 if (repstat == NFSERR_REPLYFROMCACHE) {
4110 *rep = slots[slotid].nfssl_reply;
4111 slots[slotid].nfssl_reply = NULL;
4113 if (slots[slotid].nfssl_reply != NULL)
4114 m_freem(slots[slotid].nfssl_reply);
4115 slots[slotid].nfssl_reply = *rep;
4117 slots[slotid].nfssl_inprog = 0;
4121 * Generate the xdr for an NFSv4.1 Sequence Operation.
4124 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4125 struct nfsclsession *sep, int dont_replycache)
4127 uint32_t *tl, slotseq = 0;
4128 int error, maxslot, slotpos;
4129 uint8_t sessionid[NFSX_V4SESSIONID];
4131 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4134 /* Build the Sequence arguments. */
4135 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4136 nd->nd_sequence = tl;
4137 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4138 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4139 nd->nd_slotseq = tl;
4141 *tl++ = txdr_unsigned(slotseq);
4142 *tl++ = txdr_unsigned(slotpos);
4143 *tl++ = txdr_unsigned(maxslot);
4144 if (dont_replycache == 0)
4150 * There are two errors and the rest of the session can
4152 * NFSERR_BADSESSION: This bad session should just generate
4153 * the same error again when the RPC is retried.
4154 * ESTALE: A forced dismount is in progress and will cause the
4155 * RPC to fail later.
4162 nd->nd_flag |= ND_HASSEQUENCE;
4166 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4167 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4169 int i, maxslot, slotpos;
4172 /* Find an unused slot. */
4175 mtx_lock(&sep->nfsess_mtx);
4177 if (nmp != NULL && sep->nfsess_defunct != 0) {
4178 /* Just return the bad session. */
4179 bcopy(sep->nfsess_sessionid, sessionid,
4181 mtx_unlock(&sep->nfsess_mtx);
4182 return (NFSERR_BADSESSION);
4185 for (i = 0; i < sep->nfsess_foreslots; i++) {
4186 if ((bitval & sep->nfsess_slots) == 0) {
4188 sep->nfsess_slots |= bitval;
4189 sep->nfsess_slotseq[i]++;
4190 *slotseqp = sep->nfsess_slotseq[i];
4195 if (slotpos == -1) {
4197 * If a forced dismount is in progress, just return.
4198 * This RPC attempt will fail when it calls
4201 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4202 mtx_unlock(&sep->nfsess_mtx);
4205 /* Wake up once/sec, to check for a forced dismount. */
4206 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4207 PZERO, "nfsclseq", hz);
4209 } while (slotpos == -1);
4210 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4212 for (i = 0; i < 64; i++) {
4213 if ((bitval & sep->nfsess_slots) != 0)
4217 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4218 mtx_unlock(&sep->nfsess_mtx);
4219 *slotposp = slotpos;
4220 *maxslotp = maxslot;
4225 * Free a session slot.
4228 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4235 mtx_lock(&sep->nfsess_mtx);
4236 if ((bitval & sep->nfsess_slots) == 0)
4237 printf("freeing free slot!!\n");
4238 sep->nfsess_slots &= ~bitval;
4239 wakeup(&sep->nfsess_slots);
4240 mtx_unlock(&sep->nfsess_mtx);