2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include "opt_inet6.h"
45 #include <fs/nfs/nfsport.h>
47 #include <security/mac/mac_framework.h>
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid = UID_NOBODY;
67 gid_t nfsrv_defaultgid = GID_NOGROUP;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 int nfsd_enable_stringtouid = 0;
71 static int nfs_enable_uidtostring = 0;
72 static int nfs_suppress_32bits_warning = 0;
75 extern int nfsrv_lughashsize;
77 SYSCTL_DECL(_vfs_nfs);
78 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
79 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
80 SYSCTL_INT(_vfs_nfs, OID_AUTO, suppress_32bits_warning, CTLFLAG_RW,
81 &nfs_suppress_32bits_warning, 0, "Suppress \"> 32 bits\" warnings");
84 * This array of structures indicates, for V4:
85 * retfh - which of 3 types of calling args are used
86 * 0 - doesn't change cfh or use a sfh
87 * 1 - replaces cfh with a new one (unless it returns an error status)
88 * 2 - uses cfh and sfh
89 * needscfh - if the op wants a cfh and premtime
90 * 0 - doesn't use a cfh
91 * 1 - uses a cfh, but doesn't want pre-op attributes
92 * 2 - uses a cfh and wants pre-op attributes
93 * savereply - indicates a non-idempotent Op
94 * 0 - not non-idempotent
96 * Ops that are ordered via seqid# are handled separately from these
98 * Define it here, since it is used by both the client and server.
100 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
101 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
102 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
103 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
104 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
106 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
107 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
108 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
109 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
110 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
112 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
114 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
115 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
116 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
117 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
118 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
119 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
120 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
121 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
122 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
123 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
124 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
125 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
126 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
127 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
128 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
129 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
130 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
133 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
134 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
135 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
138 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */
139 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
140 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
141 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
142 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
151 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
152 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
156 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
158 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
159 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
161 #endif /* !APPLEKEXT */
163 static int ncl_mbuf_mhlen = MHLEN;
164 static int nfsrv_usercnt = 0;
165 static int nfsrv_dnsnamelen;
166 static u_char *nfsrv_dnsname = NULL;
167 static int nfsrv_usermax = 999999999;
168 struct nfsrv_lughash {
170 struct nfsuserhashhead lughead;
172 static struct nfsrv_lughash *nfsuserhash;
173 static struct nfsrv_lughash *nfsusernamehash;
174 static struct nfsrv_lughash *nfsgrouphash;
175 static struct nfsrv_lughash *nfsgroupnamehash;
178 * This static array indicates whether or not the RPC generates a large
179 * reply. This is used by nfs_reply() to decide whether or not an mbuf
180 * cluster should be allocated. (If a cluster is required by an RPC
181 * marked 0 in this array, the code will still work, just not quite as
184 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
185 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,
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
188 /* local functions */
189 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
190 static void nfsv4_wanted(struct nfsv4lock *lp);
191 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
192 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
194 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
195 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
197 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
202 * copies mbuf chain to the uio scatter/gather list
205 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
207 char *mbufcp, *uiocp;
214 mbufcp = nd->nd_dpos;
215 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
216 rem = NFSM_RNDUP(siz) - siz;
218 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
222 left = uiop->uio_iov->iov_len;
223 uiocp = uiop->uio_iov->iov_base;
234 mbufcp = NFSMTOD(mp, caddr_t);
237 ("len %d, corrupted mbuf?", len));
239 xfer = (left > len) ? len : left;
242 if (uiop->uio_iov->iov_op != NULL)
243 (*(uiop->uio_iov->iov_op))
244 (mbufcp, uiocp, xfer);
247 if (uiop->uio_segflg == UIO_SYSSPACE)
248 NFSBCOPY(mbufcp, uiocp, xfer);
250 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
255 uiop->uio_offset += xfer;
256 uiop->uio_resid -= xfer;
258 if (uiop->uio_iov->iov_len <= siz) {
262 uiop->uio_iov->iov_base = (void *)
263 ((char *)uiop->uio_iov->iov_base + uiosiz);
264 uiop->uio_iov->iov_len -= uiosiz;
268 nd->nd_dpos = mbufcp;
272 error = nfsm_advance(nd, rem, len);
278 NFSEXITCODE2(error, nd);
284 * Help break down an mbuf chain by setting the first siz bytes contiguous
285 * pointed to by returned val.
286 * This is used by the macro NFSM_DISSECT for tough
290 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
299 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
301 nd->nd_md = mbuf_next(nd->nd_md);
302 if (nd->nd_md == NULL)
304 left = mbuf_len(nd->nd_md);
305 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
310 } else if (mbuf_next(nd->nd_md) == NULL) {
312 } else if (siz > ncl_mbuf_mhlen) {
313 panic("nfs S too big");
315 MGET(mp2, MT_DATA, how);
318 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
319 mbuf_setnext(nd->nd_md, mp2);
320 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
322 retp = p = NFSMTOD(mp2, caddr_t);
323 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
326 mp2 = mbuf_next(mp2);
327 /* Loop around copying up the siz2 bytes */
331 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
333 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
334 NFSM_DATAP(mp2, xfer);
335 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
340 mp2 = mbuf_next(mp2);
342 mbuf_setlen(nd->nd_md, siz);
344 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
350 * Advance the position in the mbuf chain.
351 * If offs == 0, this is a no-op, but it is simpler to just return from
352 * here than check for offs > 0 for all calls to nfsm_advance.
353 * If left == -1, it should be calculated here.
356 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
363 * A negative offs might indicate a corrupted mbuf chain and,
364 * as such, a printf is logged.
367 printf("nfsrv_advance: negative offs\n");
373 * If left == -1, calculate it here.
376 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
380 * Loop around, advancing over the mbuf data.
382 while (offs > left) {
384 nd->nd_md = mbuf_next(nd->nd_md);
385 if (nd->nd_md == NULL) {
389 left = mbuf_len(nd->nd_md);
390 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
400 * Copy a string into mbuf(s).
401 * Return the number of bytes output, including XDR overheads.
404 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
413 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
414 *tl = txdr_unsigned(siz);
415 rem = NFSM_RNDUP(siz) - siz;
416 bytesize = NFSX_UNSIGNED + siz + rem;
419 left = M_TRAILINGSPACE(m2);
422 * Loop around copying the string to mbuf(s).
426 if (siz > ncl_mbuf_mlen)
427 NFSMCLGET(m1, M_WAITOK);
431 mbuf_setnext(m2, m1);
433 cp2 = NFSMTOD(m2, caddr_t);
434 left = M_TRAILINGSPACE(m2);
440 NFSBCOPY(cp, cp2, xfer);
442 mbuf_setlen(m2, mbuf_len(m2) + xfer);
445 if (siz == 0 && rem) {
447 panic("nfsm_strtom");
448 NFSBZERO(cp2 + xfer, rem);
449 mbuf_setlen(m2, mbuf_len(m2) + rem);
453 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
458 * Called once to initialize data structures...
463 static int nfs_inited = 0;
469 newnfs_true = txdr_unsigned(TRUE);
470 newnfs_false = txdr_unsigned(FALSE);
471 newnfs_xdrneg1 = txdr_unsigned(-1);
472 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
475 NFSSETBOOTTIME(nfsboottime);
478 * Initialize reply list and start timer
480 TAILQ_INIT(&nfsd_reqq);
485 * Put a file handle in an mbuf list.
486 * If the size argument == 0, just use the default size.
487 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
488 * Return the number of bytes output, including XDR overhead.
491 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
495 int fullsiz, rem, bytesize = 0;
499 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
501 if (size > NFSX_V2FH)
502 panic("fh size > NFSX_V2FH for NFSv2");
503 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
504 NFSBCOPY(fhp, cp, size);
505 if (size < NFSX_V2FH)
506 NFSBZERO(cp + size, NFSX_V2FH - size);
507 bytesize = NFSX_V2FH;
511 fullsiz = NFSM_RNDUP(size);
512 rem = fullsiz - size;
514 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
515 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
518 bytesize = NFSX_UNSIGNED + fullsiz;
520 (void) nfsm_strtom(nd, fhp, size);
527 * This function compares two net addresses by family and returns TRUE
528 * if they are the same host.
529 * If there is any doubt, return FALSE.
530 * The AF_INET family is handled as a special case so that address mbufs
531 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
534 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
536 struct sockaddr_in *inetaddr;
540 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
541 if (inetaddr->sin_family == AF_INET &&
542 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
548 struct sockaddr_in6 *inetaddr6;
550 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
551 /* XXX - should test sin6_scope_id ? */
552 if (inetaddr6->sin6_family == AF_INET6 &&
553 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
564 * Similar to the above, but takes to NFSSOCKADDR_T args.
567 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
569 struct sockaddr_in *addr1, *addr2;
570 struct sockaddr *inaddr;
572 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
573 switch (inaddr->sa_family) {
575 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
576 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
577 if (addr2->sin_family == AF_INET &&
578 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
584 struct sockaddr_in6 *inet6addr1, *inet6addr2;
586 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
587 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
588 /* XXX - should test sin6_scope_id ? */
589 if (inet6addr2->sin6_family == AF_INET6 &&
590 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
591 &inet6addr2->sin6_addr))
602 * Trim the stuff already dissected off the mbuf list.
605 newnfs_trimleading(nd)
606 struct nfsrv_descript *nd;
612 * First, free up leading mbufs.
614 if (nd->nd_mrep != nd->nd_md) {
616 while (mbuf_next(m) != nd->nd_md) {
617 if (mbuf_next(m) == NULL)
618 panic("nfsm trim leading");
621 mbuf_setnext(m, NULL);
622 mbuf_freem(nd->nd_mrep);
627 * Now, adjust this mbuf, based on nd_dpos.
629 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
630 if (offs == mbuf_len(m)) {
634 panic("nfsm trim leading2");
635 mbuf_setnext(n, NULL);
637 } else if (offs > 0) {
638 mbuf_setlen(m, mbuf_len(m) - offs);
641 panic("nfsm trimleading offs");
644 nd->nd_dpos = NFSMTOD(m, caddr_t);
648 * Trim trailing data off the mbuf list being built.
651 newnfs_trimtrailing(nd, mb, bpos)
652 struct nfsrv_descript *nd;
658 mbuf_freem(mbuf_next(mb));
659 mbuf_setnext(mb, NULL);
661 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
667 * Dissect a file handle on the client.
670 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
677 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
678 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
679 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
686 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
688 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
690 FREE((caddr_t)nfhp, M_NFSFH);
696 NFSEXITCODE2(error, nd);
701 * Break down the nfsv4 acl.
702 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
705 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
706 int *aclsizep, __unused NFSPROC_T *p)
710 int acecnt, error = 0, aceerr = 0, acesize;
716 * Parse out the ace entries and expect them to conform to
717 * what can be supported by R/W/X bits.
719 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
720 aclsize = NFSX_UNSIGNED;
721 acecnt = fxdr_unsigned(int, *tl);
722 if (acecnt > ACL_MAX_ENTRIES)
723 aceerr = NFSERR_ATTRNOTSUPP;
724 if (nfsrv_useacl == 0)
725 aceerr = NFSERR_ATTRNOTSUPP;
726 for (i = 0; i < acecnt; i++) {
728 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
729 &aceerr, &acesize, p);
731 error = nfsrv_skipace(nd, &acesize);
737 aclp->acl_cnt = acecnt;
743 NFSEXITCODE2(error, nd);
748 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
751 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
756 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
757 len = fxdr_unsigned(int, *(tl + 3));
758 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
760 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
761 NFSEXITCODE2(error, nd);
766 * Get attribute bits from an mbuf list.
767 * Returns EBADRPC for a parsing error, 0 otherwise.
768 * If the clearinvalid flag is set, clear the bits not supported.
771 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
778 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
779 cnt = fxdr_unsigned(int, *tl);
781 error = NFSERR_BADXDR;
784 if (cnt > NFSATTRBIT_MAXWORDS)
785 outcnt = NFSATTRBIT_MAXWORDS;
788 NFSZERO_ATTRBIT(attrbitp);
790 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
791 for (i = 0; i < outcnt; i++)
792 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
794 for (i = 0; i < (cnt - outcnt); i++) {
795 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
796 if (retnotsupp != NULL && *tl != 0)
797 *retnotsupp = NFSERR_ATTRNOTSUPP;
800 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
802 NFSEXITCODE2(error, nd);
807 * Get the attributes for V4.
808 * If the compare flag is true, test for any attribute changes,
809 * otherwise return the attribute values.
810 * These attributes cover fields in "struct vattr", "struct statfs",
811 * "struct nfsfsinfo", the file handle and the lease duration.
812 * The value of retcmpp is set to 1 if all attributes are the same,
814 * Returns EBADRPC if it can't be parsed, 0 otherwise.
817 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
818 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
819 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
820 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
821 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
824 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
825 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
826 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
827 nfsattrbit_t attrbits, retattrbits, checkattrbits;
829 struct nfsreferral *refp;
832 struct timespec temptime;
836 u_int32_t freenum = 0, tuint;
837 u_int64_t uquad = 0, thyp, thyp2;
842 static struct timeval last64fileid;
843 static size_t count64fileid;
844 static struct timeval last64mountfileid;
845 static size_t count64mountfileid;
846 struct timeval warninterval =
847 { nfs_suppress_32bits_warning ? 86400 : 60, 0 };
851 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
853 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
859 *retcmpp = retnotsup;
862 * Just set default values to some of the important ones.
867 nap->na_rdev = (NFSDEV_T)0;
868 nap->na_mtime.tv_sec = 0;
869 nap->na_mtime.tv_nsec = 0;
872 nap->na_blocksize = NFS_FABLKSIZE;
875 sbp->f_bsize = NFS_FABLKSIZE;
883 fsp->fs_rtmax = 8192;
884 fsp->fs_rtpref = 8192;
885 fsp->fs_maxname = NFS_MAXNAMLEN;
886 fsp->fs_wtmax = 8192;
887 fsp->fs_wtpref = 8192;
888 fsp->fs_wtmult = NFS_FABLKSIZE;
889 fsp->fs_dtpref = 8192;
890 fsp->fs_maxfilesize = 0xffffffffffffffffull;
891 fsp->fs_timedelta.tv_sec = 0;
892 fsp->fs_timedelta.tv_nsec = 1;
893 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
894 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
897 pc->pc_linkmax = LINK_MAX;
898 pc->pc_namemax = NAME_MAX;
900 pc->pc_chownrestricted = 0;
901 pc->pc_caseinsensitive = 0;
902 pc->pc_casepreserving = 1;
905 sfp->sf_ffiles = UINT64_MAX;
906 sfp->sf_tfiles = UINT64_MAX;
907 sfp->sf_afiles = UINT64_MAX;
908 sfp->sf_fbytes = UINT64_MAX;
909 sfp->sf_tbytes = UINT64_MAX;
910 sfp->sf_abytes = UINT64_MAX;
915 * Loop around getting the attributes.
917 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
918 attrsize = fxdr_unsigned(int, *tl);
919 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
920 if (attrsum > attrsize) {
921 error = NFSERR_BADXDR;
924 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
926 case NFSATTRBIT_SUPPORTEDATTRS:
928 if (compare || nap == NULL)
929 error = nfsrv_getattrbits(nd, &retattrbits,
932 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
936 if (compare && !(*retcmpp)) {
937 NFSSETSUPP_ATTRBIT(&checkattrbits);
939 /* Some filesystem do not support NFSv4ACL */
940 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
941 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
942 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
944 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
946 *retcmpp = NFSERR_NOTSAME;
950 case NFSATTRBIT_TYPE:
951 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
954 if (nap->na_type != nfsv34tov_type(*tl))
955 *retcmpp = NFSERR_NOTSAME;
957 } else if (nap != NULL) {
958 nap->na_type = nfsv34tov_type(*tl);
960 attrsum += NFSX_UNSIGNED;
962 case NFSATTRBIT_FHEXPIRETYPE:
963 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
964 if (compare && !(*retcmpp)) {
965 if (fxdr_unsigned(int, *tl) !=
966 NFSV4FHTYPE_PERSISTENT)
967 *retcmpp = NFSERR_NOTSAME;
969 attrsum += NFSX_UNSIGNED;
971 case NFSATTRBIT_CHANGE:
972 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
975 if (nap->na_filerev != fxdr_hyper(tl))
976 *retcmpp = NFSERR_NOTSAME;
978 } else if (nap != NULL) {
979 nap->na_filerev = fxdr_hyper(tl);
981 attrsum += NFSX_HYPER;
983 case NFSATTRBIT_SIZE:
984 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
987 if (nap->na_size != fxdr_hyper(tl))
988 *retcmpp = NFSERR_NOTSAME;
990 } else if (nap != NULL) {
991 nap->na_size = fxdr_hyper(tl);
993 attrsum += NFSX_HYPER;
995 case NFSATTRBIT_LINKSUPPORT:
996 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
999 if (fsp->fs_properties & NFSV3_FSFLINK) {
1000 if (*tl == newnfs_false)
1001 *retcmpp = NFSERR_NOTSAME;
1003 if (*tl == newnfs_true)
1004 *retcmpp = NFSERR_NOTSAME;
1007 } else if (fsp != NULL) {
1008 if (*tl == newnfs_true)
1009 fsp->fs_properties |= NFSV3_FSFLINK;
1011 fsp->fs_properties &= ~NFSV3_FSFLINK;
1013 attrsum += NFSX_UNSIGNED;
1015 case NFSATTRBIT_SYMLINKSUPPORT:
1016 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1019 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1020 if (*tl == newnfs_false)
1021 *retcmpp = NFSERR_NOTSAME;
1023 if (*tl == newnfs_true)
1024 *retcmpp = NFSERR_NOTSAME;
1027 } else if (fsp != NULL) {
1028 if (*tl == newnfs_true)
1029 fsp->fs_properties |= NFSV3_FSFSYMLINK;
1031 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1033 attrsum += NFSX_UNSIGNED;
1035 case NFSATTRBIT_NAMEDATTR:
1036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1037 if (compare && !(*retcmpp)) {
1038 if (*tl != newnfs_false)
1039 *retcmpp = NFSERR_NOTSAME;
1041 attrsum += NFSX_UNSIGNED;
1043 case NFSATTRBIT_FSID:
1044 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1045 thyp = fxdr_hyper(tl);
1047 thyp2 = fxdr_hyper(tl);
1049 if (*retcmpp == 0) {
1050 if (thyp != (u_int64_t)
1051 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1052 thyp2 != (u_int64_t)
1053 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1054 *retcmpp = NFSERR_NOTSAME;
1056 } else if (nap != NULL) {
1057 nap->na_filesid[0] = thyp;
1058 nap->na_filesid[1] = thyp2;
1060 attrsum += (4 * NFSX_UNSIGNED);
1062 case NFSATTRBIT_UNIQUEHANDLES:
1063 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1064 if (compare && !(*retcmpp)) {
1065 if (*tl != newnfs_true)
1066 *retcmpp = NFSERR_NOTSAME;
1068 attrsum += NFSX_UNSIGNED;
1070 case NFSATTRBIT_LEASETIME:
1071 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1073 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1075 *retcmpp = NFSERR_NOTSAME;
1076 } else if (leasep != NULL) {
1077 *leasep = fxdr_unsigned(u_int32_t, *tl);
1079 attrsum += NFSX_UNSIGNED;
1081 case NFSATTRBIT_RDATTRERROR:
1082 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1085 *retcmpp = NFSERR_INVAL;
1086 } else if (rderrp != NULL) {
1087 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1089 attrsum += NFSX_UNSIGNED;
1091 case NFSATTRBIT_ACL:
1094 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1097 naclp = acl_alloc(M_WAITOK);
1098 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1104 if (aceerr || aclp == NULL ||
1105 nfsrv_compareacl(aclp, naclp))
1106 *retcmpp = NFSERR_NOTSAME;
1109 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1111 *retcmpp = NFSERR_ATTRNOTSUPP;
1115 if (vp != NULL && aclp != NULL)
1116 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1119 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1127 case NFSATTRBIT_ACLSUPPORT:
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (compare && !(*retcmpp)) {
1130 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1131 if (fxdr_unsigned(u_int32_t, *tl) !=
1133 *retcmpp = NFSERR_NOTSAME;
1135 *retcmpp = NFSERR_ATTRNOTSUPP;
1138 attrsum += NFSX_UNSIGNED;
1140 case NFSATTRBIT_ARCHIVE:
1141 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1142 if (compare && !(*retcmpp))
1143 *retcmpp = NFSERR_ATTRNOTSUPP;
1144 attrsum += NFSX_UNSIGNED;
1146 case NFSATTRBIT_CANSETTIME:
1147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1150 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1151 if (*tl == newnfs_false)
1152 *retcmpp = NFSERR_NOTSAME;
1154 if (*tl == newnfs_true)
1155 *retcmpp = NFSERR_NOTSAME;
1158 } else if (fsp != NULL) {
1159 if (*tl == newnfs_true)
1160 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1162 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1164 attrsum += NFSX_UNSIGNED;
1166 case NFSATTRBIT_CASEINSENSITIVE:
1167 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1170 if (*tl != newnfs_false)
1171 *retcmpp = NFSERR_NOTSAME;
1173 } else if (pc != NULL) {
1174 pc->pc_caseinsensitive =
1175 fxdr_unsigned(u_int32_t, *tl);
1177 attrsum += NFSX_UNSIGNED;
1179 case NFSATTRBIT_CASEPRESERVING:
1180 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1183 if (*tl != newnfs_true)
1184 *retcmpp = NFSERR_NOTSAME;
1186 } else if (pc != NULL) {
1187 pc->pc_casepreserving =
1188 fxdr_unsigned(u_int32_t, *tl);
1190 attrsum += NFSX_UNSIGNED;
1192 case NFSATTRBIT_CHOWNRESTRICTED:
1193 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1196 if (*tl != newnfs_true)
1197 *retcmpp = NFSERR_NOTSAME;
1199 } else if (pc != NULL) {
1200 pc->pc_chownrestricted =
1201 fxdr_unsigned(u_int32_t, *tl);
1203 attrsum += NFSX_UNSIGNED;
1205 case NFSATTRBIT_FILEHANDLE:
1206 error = nfsm_getfh(nd, &tnfhp);
1209 tfhsize = tnfhp->nfh_len;
1212 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1214 *retcmpp = NFSERR_NOTSAME;
1215 FREE((caddr_t)tnfhp, M_NFSFH);
1216 } else if (nfhpp != NULL) {
1219 FREE((caddr_t)tnfhp, M_NFSFH);
1221 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1223 case NFSATTRBIT_FILEID:
1224 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1225 thyp = fxdr_hyper(tl);
1228 if ((u_int64_t)nap->na_fileid != thyp)
1229 *retcmpp = NFSERR_NOTSAME;
1231 } else if (nap != NULL) {
1234 if (ratecheck(&last64fileid, &warninterval)) {
1235 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
1240 nap->na_fileid = thyp;
1242 attrsum += NFSX_HYPER;
1244 case NFSATTRBIT_FILESAVAIL:
1245 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1248 sfp->sf_afiles != fxdr_hyper(tl))
1249 *retcmpp = NFSERR_NOTSAME;
1250 } else if (sfp != NULL) {
1251 sfp->sf_afiles = fxdr_hyper(tl);
1253 attrsum += NFSX_HYPER;
1255 case NFSATTRBIT_FILESFREE:
1256 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1259 sfp->sf_ffiles != fxdr_hyper(tl))
1260 *retcmpp = NFSERR_NOTSAME;
1261 } else if (sfp != NULL) {
1262 sfp->sf_ffiles = fxdr_hyper(tl);
1264 attrsum += NFSX_HYPER;
1266 case NFSATTRBIT_FILESTOTAL:
1267 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1270 sfp->sf_tfiles != fxdr_hyper(tl))
1271 *retcmpp = NFSERR_NOTSAME;
1272 } else if (sfp != NULL) {
1273 sfp->sf_tfiles = fxdr_hyper(tl);
1275 attrsum += NFSX_HYPER;
1277 case NFSATTRBIT_FSLOCATIONS:
1278 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1282 if (compare && !(*retcmpp)) {
1283 refp = nfsv4root_getreferral(vp, NULL, 0);
1285 if (cp == NULL || cp2 == NULL ||
1287 strcmp(cp2, refp->nfr_srvlist))
1288 *retcmpp = NFSERR_NOTSAME;
1289 } else if (m == 0) {
1290 *retcmpp = NFSERR_NOTSAME;
1294 free(cp, M_NFSSTRING);
1296 free(cp2, M_NFSSTRING);
1298 case NFSATTRBIT_HIDDEN:
1299 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1300 if (compare && !(*retcmpp))
1301 *retcmpp = NFSERR_ATTRNOTSUPP;
1302 attrsum += NFSX_UNSIGNED;
1304 case NFSATTRBIT_HOMOGENEOUS:
1305 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1308 if (fsp->fs_properties &
1309 NFSV3_FSFHOMOGENEOUS) {
1310 if (*tl == newnfs_false)
1311 *retcmpp = NFSERR_NOTSAME;
1313 if (*tl == newnfs_true)
1314 *retcmpp = NFSERR_NOTSAME;
1317 } else if (fsp != NULL) {
1318 if (*tl == newnfs_true)
1319 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1321 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1323 attrsum += NFSX_UNSIGNED;
1325 case NFSATTRBIT_MAXFILESIZE:
1326 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1327 tnfsquad.qval = fxdr_hyper(tl);
1330 tquad = NFSRV_MAXFILESIZE;
1331 if (tquad != tnfsquad.qval)
1332 *retcmpp = NFSERR_NOTSAME;
1334 } else if (fsp != NULL) {
1335 fsp->fs_maxfilesize = tnfsquad.qval;
1337 attrsum += NFSX_HYPER;
1339 case NFSATTRBIT_MAXLINK:
1340 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1343 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1344 *retcmpp = NFSERR_NOTSAME;
1346 } else if (pc != NULL) {
1347 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1349 attrsum += NFSX_UNSIGNED;
1351 case NFSATTRBIT_MAXNAME:
1352 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1355 if (fsp->fs_maxname !=
1356 fxdr_unsigned(u_int32_t, *tl))
1357 *retcmpp = NFSERR_NOTSAME;
1360 tuint = fxdr_unsigned(u_int32_t, *tl);
1362 * Some Linux NFSv4 servers report this
1363 * as 0 or 4billion, so I'll set it to
1364 * NFS_MAXNAMLEN. If a server actually creates
1365 * a name longer than NFS_MAXNAMLEN, it will
1366 * get an error back.
1368 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1369 tuint = NFS_MAXNAMLEN;
1371 fsp->fs_maxname = tuint;
1373 pc->pc_namemax = tuint;
1375 attrsum += NFSX_UNSIGNED;
1377 case NFSATTRBIT_MAXREAD:
1378 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1381 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1382 *(tl + 1)) || *tl != 0)
1383 *retcmpp = NFSERR_NOTSAME;
1385 } else if (fsp != NULL) {
1386 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1387 fsp->fs_rtpref = fsp->fs_rtmax;
1388 fsp->fs_dtpref = fsp->fs_rtpref;
1390 attrsum += NFSX_HYPER;
1392 case NFSATTRBIT_MAXWRITE:
1393 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1396 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1397 *(tl + 1)) || *tl != 0)
1398 *retcmpp = NFSERR_NOTSAME;
1400 } else if (fsp != NULL) {
1401 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1402 fsp->fs_wtpref = fsp->fs_wtmax;
1404 attrsum += NFSX_HYPER;
1406 case NFSATTRBIT_MIMETYPE:
1407 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1408 i = fxdr_unsigned(int, *tl);
1409 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1410 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1413 if (compare && !(*retcmpp))
1414 *retcmpp = NFSERR_ATTRNOTSUPP;
1416 case NFSATTRBIT_MODE:
1417 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1420 if (nap->na_mode != nfstov_mode(*tl))
1421 *retcmpp = NFSERR_NOTSAME;
1423 } else if (nap != NULL) {
1424 nap->na_mode = nfstov_mode(*tl);
1426 attrsum += NFSX_UNSIGNED;
1428 case NFSATTRBIT_NOTRUNC:
1429 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1432 if (*tl != newnfs_true)
1433 *retcmpp = NFSERR_NOTSAME;
1435 } else if (pc != NULL) {
1436 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1438 attrsum += NFSX_UNSIGNED;
1440 case NFSATTRBIT_NUMLINKS:
1441 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1442 tuint = fxdr_unsigned(u_int32_t, *tl);
1445 if ((u_int32_t)nap->na_nlink != tuint)
1446 *retcmpp = NFSERR_NOTSAME;
1448 } else if (nap != NULL) {
1449 nap->na_nlink = tuint;
1451 attrsum += NFSX_UNSIGNED;
1453 case NFSATTRBIT_OWNER:
1454 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1455 j = fxdr_unsigned(int, *tl);
1457 error = NFSERR_BADXDR;
1460 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1461 if (j > NFSV4_SMALLSTR)
1462 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1465 error = nfsrv_mtostr(nd, cp, j);
1467 if (j > NFSV4_SMALLSTR)
1468 free(cp, M_NFSSTRING);
1473 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1475 *retcmpp = NFSERR_NOTSAME;
1477 } else if (nap != NULL) {
1478 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1479 nap->na_uid = nfsrv_defaultuid;
1483 if (j > NFSV4_SMALLSTR)
1484 free(cp, M_NFSSTRING);
1486 case NFSATTRBIT_OWNERGROUP:
1487 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1488 j = fxdr_unsigned(int, *tl);
1490 error = NFSERR_BADXDR;
1493 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1494 if (j > NFSV4_SMALLSTR)
1495 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1498 error = nfsrv_mtostr(nd, cp, j);
1500 if (j > NFSV4_SMALLSTR)
1501 free(cp, M_NFSSTRING);
1506 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1508 *retcmpp = NFSERR_NOTSAME;
1510 } else if (nap != NULL) {
1511 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1512 nap->na_gid = nfsrv_defaultgid;
1516 if (j > NFSV4_SMALLSTR)
1517 free(cp, M_NFSSTRING);
1519 case NFSATTRBIT_QUOTAHARD:
1520 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1522 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1523 freenum = sbp->f_bfree;
1525 freenum = sbp->f_bavail;
1528 * ufs_quotactl() insists that the uid argument
1529 * equal p_ruid for non-root quota access, so
1530 * we'll just make sure that's the case.
1532 savuid = p->p_cred->p_ruid;
1533 p->p_cred->p_ruid = cred->cr_uid;
1534 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1535 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1536 freenum = min(dqb.dqb_bhardlimit, freenum);
1537 p->p_cred->p_ruid = savuid;
1539 uquad = (u_int64_t)freenum;
1540 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1542 if (compare && !(*retcmpp)) {
1543 if (uquad != fxdr_hyper(tl))
1544 *retcmpp = NFSERR_NOTSAME;
1546 attrsum += NFSX_HYPER;
1548 case NFSATTRBIT_QUOTASOFT:
1549 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1551 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1552 freenum = sbp->f_bfree;
1554 freenum = sbp->f_bavail;
1557 * ufs_quotactl() insists that the uid argument
1558 * equal p_ruid for non-root quota access, so
1559 * we'll just make sure that's the case.
1561 savuid = p->p_cred->p_ruid;
1562 p->p_cred->p_ruid = cred->cr_uid;
1563 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1564 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1565 freenum = min(dqb.dqb_bsoftlimit, freenum);
1566 p->p_cred->p_ruid = savuid;
1568 uquad = (u_int64_t)freenum;
1569 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1571 if (compare && !(*retcmpp)) {
1572 if (uquad != fxdr_hyper(tl))
1573 *retcmpp = NFSERR_NOTSAME;
1575 attrsum += NFSX_HYPER;
1577 case NFSATTRBIT_QUOTAUSED:
1578 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1583 * ufs_quotactl() insists that the uid argument
1584 * equal p_ruid for non-root quota access, so
1585 * we'll just make sure that's the case.
1587 savuid = p->p_cred->p_ruid;
1588 p->p_cred->p_ruid = cred->cr_uid;
1589 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1590 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1591 freenum = dqb.dqb_curblocks;
1592 p->p_cred->p_ruid = savuid;
1594 uquad = (u_int64_t)freenum;
1595 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1597 if (compare && !(*retcmpp)) {
1598 if (uquad != fxdr_hyper(tl))
1599 *retcmpp = NFSERR_NOTSAME;
1601 attrsum += NFSX_HYPER;
1603 case NFSATTRBIT_RAWDEV:
1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1605 j = fxdr_unsigned(int, *tl++);
1606 k = fxdr_unsigned(int, *tl);
1609 if (nap->na_rdev != NFSMAKEDEV(j, k))
1610 *retcmpp = NFSERR_NOTSAME;
1612 } else if (nap != NULL) {
1613 nap->na_rdev = NFSMAKEDEV(j, k);
1615 attrsum += NFSX_V4SPECDATA;
1617 case NFSATTRBIT_SPACEAVAIL:
1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1621 sfp->sf_abytes != fxdr_hyper(tl))
1622 *retcmpp = NFSERR_NOTSAME;
1623 } else if (sfp != NULL) {
1624 sfp->sf_abytes = fxdr_hyper(tl);
1626 attrsum += NFSX_HYPER;
1628 case NFSATTRBIT_SPACEFREE:
1629 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1632 sfp->sf_fbytes != fxdr_hyper(tl))
1633 *retcmpp = NFSERR_NOTSAME;
1634 } else if (sfp != NULL) {
1635 sfp->sf_fbytes = fxdr_hyper(tl);
1637 attrsum += NFSX_HYPER;
1639 case NFSATTRBIT_SPACETOTAL:
1640 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1643 sfp->sf_tbytes != fxdr_hyper(tl))
1644 *retcmpp = NFSERR_NOTSAME;
1645 } else if (sfp != NULL) {
1646 sfp->sf_tbytes = fxdr_hyper(tl);
1648 attrsum += NFSX_HYPER;
1650 case NFSATTRBIT_SPACEUSED:
1651 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1652 thyp = fxdr_hyper(tl);
1655 if ((u_int64_t)nap->na_bytes != thyp)
1656 *retcmpp = NFSERR_NOTSAME;
1658 } else if (nap != NULL) {
1659 nap->na_bytes = thyp;
1661 attrsum += NFSX_HYPER;
1663 case NFSATTRBIT_SYSTEM:
1664 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1665 if (compare && !(*retcmpp))
1666 *retcmpp = NFSERR_ATTRNOTSUPP;
1667 attrsum += NFSX_UNSIGNED;
1669 case NFSATTRBIT_TIMEACCESS:
1670 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1671 fxdr_nfsv4time(tl, &temptime);
1674 if (!NFS_CMPTIME(temptime, nap->na_atime))
1675 *retcmpp = NFSERR_NOTSAME;
1677 } else if (nap != NULL) {
1678 nap->na_atime = temptime;
1680 attrsum += NFSX_V4TIME;
1682 case NFSATTRBIT_TIMEACCESSSET:
1683 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1684 attrsum += NFSX_UNSIGNED;
1685 i = fxdr_unsigned(int, *tl);
1686 if (i == NFSV4SATTRTIME_TOCLIENT) {
1687 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1688 attrsum += NFSX_V4TIME;
1690 if (compare && !(*retcmpp))
1691 *retcmpp = NFSERR_INVAL;
1693 case NFSATTRBIT_TIMEBACKUP:
1694 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1695 if (compare && !(*retcmpp))
1696 *retcmpp = NFSERR_ATTRNOTSUPP;
1697 attrsum += NFSX_V4TIME;
1699 case NFSATTRBIT_TIMECREATE:
1700 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1701 if (compare && !(*retcmpp))
1702 *retcmpp = NFSERR_ATTRNOTSUPP;
1703 attrsum += NFSX_V4TIME;
1705 case NFSATTRBIT_TIMEDELTA:
1706 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1710 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1711 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1712 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1713 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1716 *retcmpp = NFSERR_NOTSAME;
1719 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1722 attrsum += NFSX_V4TIME;
1724 case NFSATTRBIT_TIMEMETADATA:
1725 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1726 fxdr_nfsv4time(tl, &temptime);
1729 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1730 *retcmpp = NFSERR_NOTSAME;
1732 } else if (nap != NULL) {
1733 nap->na_ctime = temptime;
1735 attrsum += NFSX_V4TIME;
1737 case NFSATTRBIT_TIMEMODIFY:
1738 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1739 fxdr_nfsv4time(tl, &temptime);
1742 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1743 *retcmpp = NFSERR_NOTSAME;
1745 } else if (nap != NULL) {
1746 nap->na_mtime = temptime;
1748 attrsum += NFSX_V4TIME;
1750 case NFSATTRBIT_TIMEMODIFYSET:
1751 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1752 attrsum += NFSX_UNSIGNED;
1753 i = fxdr_unsigned(int, *tl);
1754 if (i == NFSV4SATTRTIME_TOCLIENT) {
1755 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1756 attrsum += NFSX_V4TIME;
1758 if (compare && !(*retcmpp))
1759 *retcmpp = NFSERR_INVAL;
1761 case NFSATTRBIT_MOUNTEDONFILEID:
1762 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1763 thyp = fxdr_hyper(tl);
1767 *retcmpp = NFSERR_NOTSAME;
1769 if (!vp || !nfsrv_atroot(vp, &fid))
1770 fid = nap->na_fileid;
1771 if ((u_int64_t)fid != thyp)
1772 *retcmpp = NFSERR_NOTSAME;
1775 } else if (nap != NULL) {
1777 count64mountfileid++;
1778 if (ratecheck(&last64mountfileid, &warninterval)) {
1779 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
1780 count64mountfileid);
1781 count64mountfileid = 0;
1784 nap->na_mntonfileno = thyp;
1786 attrsum += NFSX_HYPER;
1788 case NFSATTRBIT_SUPPATTREXCLCREAT:
1790 error = nfsrv_getattrbits(nd, &retattrbits,
1794 if (compare && !(*retcmpp)) {
1795 NFSSETSUPP_ATTRBIT(&checkattrbits);
1796 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
1797 NFSCLRBIT_ATTRBIT(&checkattrbits,
1798 NFSATTRBIT_TIMEACCESSSET);
1799 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1801 *retcmpp = NFSERR_NOTSAME;
1806 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1808 if (compare && !(*retcmpp))
1809 *retcmpp = NFSERR_ATTRNOTSUPP;
1811 * and get out of the loop, since we can't parse
1812 * the unknown attrbute data.
1814 bitpos = NFSATTRBIT_MAX;
1820 * some clients pad the attrlist, so we need to skip over the
1823 if (attrsum > attrsize) {
1824 error = NFSERR_BADXDR;
1826 attrsize = NFSM_RNDUP(attrsize);
1827 if (attrsum < attrsize)
1828 error = nfsm_advance(nd, attrsize - attrsum, -1);
1831 NFSEXITCODE2(error, nd);
1836 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1837 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1838 * The first argument is a pointer to an nfsv4lock structure.
1839 * The second argument is 1 iff a blocking lock is wanted.
1840 * If this argument is 0, the call waits until no thread either wants nor
1841 * holds an exclusive lock.
1842 * It returns 1 if the lock was acquired, 0 otherwise.
1843 * If several processes call this function concurrently wanting the exclusive
1844 * lock, one will get the lock and the rest will return without getting the
1845 * lock. (If the caller must have the lock, it simply calls this function in a
1846 * loop until the function returns 1 to indicate the lock was acquired.)
1847 * Any usecnt must be decremented by calling nfsv4_relref() before
1848 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1849 * be called in a loop.
1850 * The isleptp argument is set to indicate if the call slept, iff not NULL
1851 * and the mp argument indicates to check for a forced dismount, iff not
1855 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1856 void *mutex, struct mount *mp)
1862 * If a lock is wanted, loop around until the lock is acquired by
1863 * someone and then released. If I want the lock, try to acquire it.
1864 * For a lock to be issued, no lock must be in force and the usecnt
1868 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1869 lp->nfslock_usecnt == 0) {
1870 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1871 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1874 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1876 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1877 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
1878 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1881 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1884 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1885 PZERO - 1, "nfsv4lck", NULL);
1886 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1887 lp->nfslock_usecnt == 0) {
1888 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1889 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1897 * Release the lock acquired by nfsv4_lock().
1898 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1899 * incremented, as well.
1902 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1905 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1907 lp->nfslock_usecnt++;
1912 * Release a reference cnt.
1915 nfsv4_relref(struct nfsv4lock *lp)
1918 if (lp->nfslock_usecnt <= 0)
1919 panic("nfsv4root ref cnt");
1920 lp->nfslock_usecnt--;
1921 if (lp->nfslock_usecnt == 0)
1926 * Get a reference cnt.
1927 * This function will wait for any exclusive lock to be released, but will
1928 * not wait for threads that want the exclusive lock. If priority needs
1929 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1930 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1931 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
1932 * return without getting a refcnt for that case.
1935 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1943 * Wait for a lock held.
1945 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1946 if (mp != NULL && NFSCL_FORCEDISM(mp))
1948 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1951 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1952 PZERO - 1, "nfsv4gr", NULL);
1954 if (mp != NULL && NFSCL_FORCEDISM(mp))
1957 lp->nfslock_usecnt++;
1961 * Get a reference as above, but return failure instead of sleeping if
1962 * an exclusive lock is held.
1965 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1968 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1971 lp->nfslock_usecnt++;
1976 * Test for a lock. Return 1 if locked, 0 otherwise.
1979 nfsv4_testlock(struct nfsv4lock *lp)
1982 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1983 lp->nfslock_usecnt == 0)
1989 * Wake up anyone sleeping, waiting for this lock.
1992 nfsv4_wanted(struct nfsv4lock *lp)
1995 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1996 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1997 wakeup((caddr_t)&lp->nfslock_lock);
2002 * Copy a string from an mbuf list into a character array.
2003 * Return EBADRPC if there is an mbuf error,
2007 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2016 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2017 rem = NFSM_RNDUP(siz) - siz;
2023 NFSBCOPY(cp, str, xfer);
2032 cp = NFSMTOD(mp, caddr_t);
2044 error = nfsm_advance(nd, rem, len);
2050 NFSEXITCODE2(error, nd);
2055 * Fill in the attributes as marked by the bitmap (V4).
2058 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2059 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2060 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2061 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
2063 int bitpos, retnum = 0;
2065 int siz, prefixnum, error;
2066 u_char *cp, namestr[NFSV4_SMALLSTR];
2067 nfsattrbit_t attrbits, retbits;
2068 nfsattrbit_t *retbitp = &retbits;
2069 u_int32_t freenum, *retnump;
2072 struct nfsfsinfo fsinf;
2073 struct timespec temptime;
2074 NFSACL_T *aclp, *naclp = NULL;
2081 * First, set the bits that can be filled and get fsinfo.
2083 NFSSET_ATTRBIT(retbitp, attrbitp);
2085 * If both p and cred are NULL, it is a client side setattr call.
2086 * If both p and cred are not NULL, it is a server side reply call.
2087 * If p is not NULL and cred is NULL, it is a client side callback
2090 if (p == NULL && cred == NULL) {
2091 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2094 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2095 naclp = acl_alloc(M_WAITOK);
2098 nfsvno_getfs(&fsinf, isdgram);
2101 * Get the VFS_STATFS(), since some attributes need them.
2103 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2104 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2105 error = VFS_STATFS(mp, fs);
2108 nd->nd_repstat = NFSERR_ACCES;
2112 NFSCLRSTATFS_ATTRBIT(retbitp);
2118 * And the NFSv4 ACL...
2120 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2121 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2122 supports_nfsv4acls == 0))) {
2123 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2125 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2126 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2127 supports_nfsv4acls == 0)) {
2128 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2129 } else if (naclp != NULL) {
2130 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2131 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2133 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2135 NFSVOPUNLOCK(vp, 0);
2137 error = NFSERR_PERM;
2140 nd->nd_repstat = NFSERR_ACCES;
2144 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2150 * Put out the attribute bitmap for the ones being filled in
2151 * and get the field for the number of attributes returned.
2153 prefixnum = nfsrv_putattrbit(nd, retbitp);
2154 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2155 prefixnum += NFSX_UNSIGNED;
2158 * Now, loop around filling in the attributes for each bit set.
2160 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2161 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2163 case NFSATTRBIT_SUPPORTEDATTRS:
2164 NFSSETSUPP_ATTRBIT(&attrbits);
2165 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2166 && supports_nfsv4acls == 0)) {
2167 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2168 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2170 retnum += nfsrv_putattrbit(nd, &attrbits);
2172 case NFSATTRBIT_TYPE:
2173 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2174 *tl = vtonfsv34_type(vap->va_type);
2175 retnum += NFSX_UNSIGNED;
2177 case NFSATTRBIT_FHEXPIRETYPE:
2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2179 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2180 retnum += NFSX_UNSIGNED;
2182 case NFSATTRBIT_CHANGE:
2183 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2184 txdr_hyper(vap->va_filerev, tl);
2185 retnum += NFSX_HYPER;
2187 case NFSATTRBIT_SIZE:
2188 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2189 txdr_hyper(vap->va_size, tl);
2190 retnum += NFSX_HYPER;
2192 case NFSATTRBIT_LINKSUPPORT:
2193 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2194 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2198 retnum += NFSX_UNSIGNED;
2200 case NFSATTRBIT_SYMLINKSUPPORT:
2201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2202 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2206 retnum += NFSX_UNSIGNED;
2208 case NFSATTRBIT_NAMEDATTR:
2209 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2211 retnum += NFSX_UNSIGNED;
2213 case NFSATTRBIT_FSID:
2214 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2216 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2218 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2219 retnum += NFSX_V4FSID;
2221 case NFSATTRBIT_UNIQUEHANDLES:
2222 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2224 retnum += NFSX_UNSIGNED;
2226 case NFSATTRBIT_LEASETIME:
2227 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2228 *tl = txdr_unsigned(nfsrv_lease);
2229 retnum += NFSX_UNSIGNED;
2231 case NFSATTRBIT_RDATTRERROR:
2232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2233 *tl = txdr_unsigned(rderror);
2234 retnum += NFSX_UNSIGNED;
2237 * Recommended Attributes. (Only the supported ones.)
2239 case NFSATTRBIT_ACL:
2240 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2242 case NFSATTRBIT_ACLSUPPORT:
2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2245 retnum += NFSX_UNSIGNED;
2247 case NFSATTRBIT_CANSETTIME:
2248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2249 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2253 retnum += NFSX_UNSIGNED;
2255 case NFSATTRBIT_CASEINSENSITIVE:
2256 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2258 retnum += NFSX_UNSIGNED;
2260 case NFSATTRBIT_CASEPRESERVING:
2261 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 retnum += NFSX_UNSIGNED;
2265 case NFSATTRBIT_CHOWNRESTRICTED:
2266 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2268 retnum += NFSX_UNSIGNED;
2270 case NFSATTRBIT_FILEHANDLE:
2271 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2273 case NFSATTRBIT_FILEID:
2274 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2276 *tl = txdr_unsigned(vap->va_fileid);
2277 retnum += NFSX_HYPER;
2279 case NFSATTRBIT_FILESAVAIL:
2281 * Check quota and use min(quota, f_ffree).
2283 freenum = fs->f_ffree;
2286 * ufs_quotactl() insists that the uid argument
2287 * equal p_ruid for non-root quota access, so
2288 * we'll just make sure that's the case.
2290 savuid = p->p_cred->p_ruid;
2291 p->p_cred->p_ruid = cred->cr_uid;
2292 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2293 cred->cr_uid, (caddr_t)&dqb))
2294 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2296 p->p_cred->p_ruid = savuid;
2298 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2300 *tl = txdr_unsigned(freenum);
2301 retnum += NFSX_HYPER;
2303 case NFSATTRBIT_FILESFREE:
2304 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2306 *tl = txdr_unsigned(fs->f_ffree);
2307 retnum += NFSX_HYPER;
2309 case NFSATTRBIT_FILESTOTAL:
2310 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2312 *tl = txdr_unsigned(fs->f_files);
2313 retnum += NFSX_HYPER;
2315 case NFSATTRBIT_FSLOCATIONS:
2316 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2319 retnum += 2 * NFSX_UNSIGNED;
2321 case NFSATTRBIT_HOMOGENEOUS:
2322 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2323 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2327 retnum += NFSX_UNSIGNED;
2329 case NFSATTRBIT_MAXFILESIZE:
2330 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2331 uquad = NFSRV_MAXFILESIZE;
2332 txdr_hyper(uquad, tl);
2333 retnum += NFSX_HYPER;
2335 case NFSATTRBIT_MAXLINK:
2336 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2337 *tl = txdr_unsigned(LINK_MAX);
2338 retnum += NFSX_UNSIGNED;
2340 case NFSATTRBIT_MAXNAME:
2341 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2342 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2343 retnum += NFSX_UNSIGNED;
2345 case NFSATTRBIT_MAXREAD:
2346 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2348 *tl = txdr_unsigned(fsinf.fs_rtmax);
2349 retnum += NFSX_HYPER;
2351 case NFSATTRBIT_MAXWRITE:
2352 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2354 *tl = txdr_unsigned(fsinf.fs_wtmax);
2355 retnum += NFSX_HYPER;
2357 case NFSATTRBIT_MODE:
2358 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2359 *tl = vtonfsv34_mode(vap->va_mode);
2360 retnum += NFSX_UNSIGNED;
2362 case NFSATTRBIT_NOTRUNC:
2363 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2365 retnum += NFSX_UNSIGNED;
2367 case NFSATTRBIT_NUMLINKS:
2368 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2369 *tl = txdr_unsigned(vap->va_nlink);
2370 retnum += NFSX_UNSIGNED;
2372 case NFSATTRBIT_OWNER:
2374 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2375 retnum += nfsm_strtom(nd, cp, siz);
2377 free(cp, M_NFSSTRING);
2379 case NFSATTRBIT_OWNERGROUP:
2381 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2382 retnum += nfsm_strtom(nd, cp, siz);
2384 free(cp, M_NFSSTRING);
2386 case NFSATTRBIT_QUOTAHARD:
2387 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2388 freenum = fs->f_bfree;
2390 freenum = fs->f_bavail;
2393 * ufs_quotactl() insists that the uid argument
2394 * equal p_ruid for non-root quota access, so
2395 * we'll just make sure that's the case.
2397 savuid = p->p_cred->p_ruid;
2398 p->p_cred->p_ruid = cred->cr_uid;
2399 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2400 cred->cr_uid, (caddr_t)&dqb))
2401 freenum = min(dqb.dqb_bhardlimit, freenum);
2402 p->p_cred->p_ruid = savuid;
2404 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2405 uquad = (u_int64_t)freenum;
2406 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2407 txdr_hyper(uquad, tl);
2408 retnum += NFSX_HYPER;
2410 case NFSATTRBIT_QUOTASOFT:
2411 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2412 freenum = fs->f_bfree;
2414 freenum = fs->f_bavail;
2417 * ufs_quotactl() insists that the uid argument
2418 * equal p_ruid for non-root quota access, so
2419 * we'll just make sure that's the case.
2421 savuid = p->p_cred->p_ruid;
2422 p->p_cred->p_ruid = cred->cr_uid;
2423 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2424 cred->cr_uid, (caddr_t)&dqb))
2425 freenum = min(dqb.dqb_bsoftlimit, freenum);
2426 p->p_cred->p_ruid = savuid;
2428 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2429 uquad = (u_int64_t)freenum;
2430 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2431 txdr_hyper(uquad, tl);
2432 retnum += NFSX_HYPER;
2434 case NFSATTRBIT_QUOTAUSED:
2438 * ufs_quotactl() insists that the uid argument
2439 * equal p_ruid for non-root quota access, so
2440 * we'll just make sure that's the case.
2442 savuid = p->p_cred->p_ruid;
2443 p->p_cred->p_ruid = cred->cr_uid;
2444 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2445 cred->cr_uid, (caddr_t)&dqb))
2446 freenum = dqb.dqb_curblocks;
2447 p->p_cred->p_ruid = savuid;
2449 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2450 uquad = (u_int64_t)freenum;
2451 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2452 txdr_hyper(uquad, tl);
2453 retnum += NFSX_HYPER;
2455 case NFSATTRBIT_RAWDEV:
2456 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2457 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2458 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2459 retnum += NFSX_V4SPECDATA;
2461 case NFSATTRBIT_SPACEAVAIL:
2462 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2463 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2464 uquad = (u_int64_t)fs->f_bfree;
2466 uquad = (u_int64_t)fs->f_bavail;
2467 uquad *= fs->f_bsize;
2468 txdr_hyper(uquad, tl);
2469 retnum += NFSX_HYPER;
2471 case NFSATTRBIT_SPACEFREE:
2472 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2473 uquad = (u_int64_t)fs->f_bfree;
2474 uquad *= fs->f_bsize;
2475 txdr_hyper(uquad, tl);
2476 retnum += NFSX_HYPER;
2478 case NFSATTRBIT_SPACETOTAL:
2479 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2480 uquad = (u_int64_t)fs->f_blocks;
2481 uquad *= fs->f_bsize;
2482 txdr_hyper(uquad, tl);
2483 retnum += NFSX_HYPER;
2485 case NFSATTRBIT_SPACEUSED:
2486 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2487 txdr_hyper(vap->va_bytes, tl);
2488 retnum += NFSX_HYPER;
2490 case NFSATTRBIT_TIMEACCESS:
2491 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2492 txdr_nfsv4time(&vap->va_atime, tl);
2493 retnum += NFSX_V4TIME;
2495 case NFSATTRBIT_TIMEACCESSSET:
2496 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2497 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2498 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2499 txdr_nfsv4time(&vap->va_atime, tl);
2500 retnum += NFSX_V4SETTIME;
2502 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2503 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2504 retnum += NFSX_UNSIGNED;
2507 case NFSATTRBIT_TIMEDELTA:
2508 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2509 temptime.tv_sec = 0;
2510 temptime.tv_nsec = 1000000000 / hz;
2511 txdr_nfsv4time(&temptime, tl);
2512 retnum += NFSX_V4TIME;
2514 case NFSATTRBIT_TIMEMETADATA:
2515 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2516 txdr_nfsv4time(&vap->va_ctime, tl);
2517 retnum += NFSX_V4TIME;
2519 case NFSATTRBIT_TIMEMODIFY:
2520 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2521 txdr_nfsv4time(&vap->va_mtime, tl);
2522 retnum += NFSX_V4TIME;
2524 case NFSATTRBIT_TIMEMODIFYSET:
2525 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2526 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2527 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2528 txdr_nfsv4time(&vap->va_mtime, tl);
2529 retnum += NFSX_V4SETTIME;
2531 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2532 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2533 retnum += NFSX_UNSIGNED;
2536 case NFSATTRBIT_MOUNTEDONFILEID:
2537 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2539 uquad = mounted_on_fileno;
2541 uquad = (u_int64_t)vap->va_fileid;
2542 txdr_hyper(uquad, tl);
2543 retnum += NFSX_HYPER;
2545 case NFSATTRBIT_SUPPATTREXCLCREAT:
2546 NFSSETSUPP_ATTRBIT(&attrbits);
2547 NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
2548 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2549 retnum += nfsrv_putattrbit(nd, &attrbits);
2552 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2559 *retnump = txdr_unsigned(retnum);
2560 return (retnum + prefixnum);
2564 * Put the attribute bits onto an mbuf list.
2565 * Return the number of bytes of output generated.
2568 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2571 int cnt, i, bytesize;
2573 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2574 if (attrbitp->bits[cnt - 1])
2576 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2577 NFSM_BUILD(tl, u_int32_t *, bytesize);
2578 *tl++ = txdr_unsigned(cnt);
2579 for (i = 0; i < cnt; i++)
2580 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2585 * Convert a uid to a string.
2586 * If the lookup fails, just output the digits.
2588 * cpp - points to a buffer of size NFSV4_SMALLSTR
2589 * (malloc a larger one, as required)
2590 * retlenp - pointer to length to be returned
2593 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2596 struct nfsusrgrp *usrp;
2599 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2600 struct nfsrv_lughash *hp;
2604 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2606 * Always map nfsrv_defaultuid to "nobody".
2608 if (uid == nfsrv_defaultuid) {
2609 i = nfsrv_dnsnamelen + 7;
2611 if (len > NFSV4_SMALLSTR)
2612 free(cp, M_NFSSTRING);
2613 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2619 NFSBCOPY("nobody@", cp, 7);
2621 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2625 hp = NFSUSERHASH(uid);
2627 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2628 if (usrp->lug_uid == uid) {
2629 if (usrp->lug_expiry < NFSD_MONOSEC)
2632 * If the name doesn't already have an '@'
2633 * in it, append @domainname to it.
2635 for (i = 0; i < usrp->lug_namelen; i++) {
2636 if (usrp->lug_name[i] == '@') {
2642 i = usrp->lug_namelen;
2644 i = usrp->lug_namelen +
2645 nfsrv_dnsnamelen + 1;
2647 mtx_unlock(&hp->mtx);
2648 if (len > NFSV4_SMALLSTR)
2649 free(cp, M_NFSSTRING);
2650 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2656 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2657 if (!hasampersand) {
2658 cp += usrp->lug_namelen;
2660 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2662 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2663 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2665 mtx_unlock(&hp->mtx);
2669 mtx_unlock(&hp->mtx);
2671 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2673 if (ret == 0 && cnt < 2)
2678 * No match, just return a string of digits.
2682 while (tmp || i == 0) {
2686 len = (i > len) ? len : i;
2690 for (i = 0; i < len; i++) {
2691 *cp-- = '0' + (tmp % 10);
2698 * Get a credential for the uid with the server's group list.
2699 * If none is found, just return the credential passed in after
2700 * logging a warning message.
2703 nfsrv_getgrpscred(struct ucred *oldcred)
2705 struct nfsusrgrp *usrp;
2706 struct ucred *newcred;
2709 struct nfsrv_lughash *hp;
2712 uid = oldcred->cr_uid;
2714 if (nfsrv_dnsnamelen > 0) {
2715 hp = NFSUSERHASH(uid);
2717 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2718 if (usrp->lug_uid == uid) {
2719 if (usrp->lug_expiry < NFSD_MONOSEC)
2721 if (usrp->lug_cred != NULL) {
2722 newcred = crhold(usrp->lug_cred);
2726 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2727 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2729 mtx_unlock(&hp->mtx);
2733 mtx_unlock(&hp->mtx);
2735 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2737 if (ret == 0 && cnt < 2)
2744 * Convert a string to a uid.
2745 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2747 * If this is called from a client side mount using AUTH_SYS and the
2748 * string is made up entirely of digits, just convert the string to
2752 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2756 char *cp, *endstr, *str0;
2757 struct nfsusrgrp *usrp;
2761 struct nfsrv_lughash *hp, *hp2;
2764 error = NFSERR_BADOWNER;
2767 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2769 tuid = (uid_t)strtoul(str0, &endstr, 10);
2770 if ((endstr - str0) == len) {
2771 /* A numeric string. */
2772 if ((nd->nd_flag & ND_KERBV) == 0 &&
2773 ((nd->nd_flag & ND_NFSCL) != 0 ||
2774 nfsd_enable_stringtouid != 0))
2777 error = NFSERR_BADOWNER;
2783 cp = strchr(str0, '@');
2785 i = (int)(cp++ - str0);
2791 if (nfsrv_dnsnamelen > 0) {
2793 * If an '@' is found and the domain name matches, search for
2794 * the name with dns stripped off.
2795 * Mixed case alpahbetics will match for the domain name, but
2796 * all upper case will not.
2798 if (cnt == 0 && i < len && i > 0 &&
2799 (len - 1 - i) == nfsrv_dnsnamelen &&
2800 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2801 len -= (nfsrv_dnsnamelen + 1);
2806 * Check for the special case of "nobody".
2808 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2809 *uidp = nfsrv_defaultuid;
2814 hp = NFSUSERNAMEHASH(str, len);
2816 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2817 if (usrp->lug_namelen == len &&
2818 !NFSBCMP(usrp->lug_name, str, len)) {
2819 if (usrp->lug_expiry < NFSD_MONOSEC)
2821 hp2 = NFSUSERHASH(usrp->lug_uid);
2822 mtx_lock(&hp2->mtx);
2823 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2824 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2826 *uidp = usrp->lug_uid;
2827 mtx_unlock(&hp2->mtx);
2828 mtx_unlock(&hp->mtx);
2833 mtx_unlock(&hp->mtx);
2835 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2837 if (ret == 0 && cnt < 2)
2840 error = NFSERR_BADOWNER;
2848 * Convert a gid to a string.
2849 * gid - the group id
2850 * cpp - points to a buffer of size NFSV4_SMALLSTR
2851 * (malloc a larger one, as required)
2852 * retlenp - pointer to length to be returned
2855 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2858 struct nfsusrgrp *usrp;
2861 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2862 struct nfsrv_lughash *hp;
2866 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
2868 * Always map nfsrv_defaultgid to "nogroup".
2870 if (gid == nfsrv_defaultgid) {
2871 i = nfsrv_dnsnamelen + 8;
2873 if (len > NFSV4_SMALLSTR)
2874 free(cp, M_NFSSTRING);
2875 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2881 NFSBCOPY("nogroup@", cp, 8);
2883 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2887 hp = NFSGROUPHASH(gid);
2889 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2890 if (usrp->lug_gid == gid) {
2891 if (usrp->lug_expiry < NFSD_MONOSEC)
2894 * If the name doesn't already have an '@'
2895 * in it, append @domainname to it.
2897 for (i = 0; i < usrp->lug_namelen; i++) {
2898 if (usrp->lug_name[i] == '@') {
2904 i = usrp->lug_namelen;
2906 i = usrp->lug_namelen +
2907 nfsrv_dnsnamelen + 1;
2909 mtx_unlock(&hp->mtx);
2910 if (len > NFSV4_SMALLSTR)
2911 free(cp, M_NFSSTRING);
2912 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2918 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2919 if (!hasampersand) {
2920 cp += usrp->lug_namelen;
2922 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2924 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2925 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2927 mtx_unlock(&hp->mtx);
2931 mtx_unlock(&hp->mtx);
2933 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2935 if (ret == 0 && cnt < 2)
2940 * No match, just return a string of digits.
2944 while (tmp || i == 0) {
2948 len = (i > len) ? len : i;
2952 for (i = 0; i < len; i++) {
2953 *cp-- = '0' + (tmp % 10);
2960 * Convert a string to a gid.
2961 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2963 * If this is called from a client side mount using AUTH_SYS and the
2964 * string is made up entirely of digits, just convert the string to
2968 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2972 char *cp, *endstr, *str0;
2973 struct nfsusrgrp *usrp;
2977 struct nfsrv_lughash *hp, *hp2;
2980 error = NFSERR_BADOWNER;
2983 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2985 tgid = (gid_t)strtoul(str0, &endstr, 10);
2986 if ((endstr - str0) == len) {
2987 /* A numeric string. */
2988 if ((nd->nd_flag & ND_KERBV) == 0 &&
2989 ((nd->nd_flag & ND_NFSCL) != 0 ||
2990 nfsd_enable_stringtouid != 0))
2993 error = NFSERR_BADOWNER;
2999 cp = strchr(str0, '@');
3001 i = (int)(cp++ - str0);
3007 if (nfsrv_dnsnamelen > 0) {
3009 * If an '@' is found and the dns name matches, search for the
3010 * name with the dns stripped off.
3012 if (cnt == 0 && i < len && i > 0 &&
3013 (len - 1 - i) == nfsrv_dnsnamelen &&
3014 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3015 len -= (nfsrv_dnsnamelen + 1);
3020 * Check for the special case of "nogroup".
3022 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3023 *gidp = nfsrv_defaultgid;
3028 hp = NFSGROUPNAMEHASH(str, len);
3030 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3031 if (usrp->lug_namelen == len &&
3032 !NFSBCMP(usrp->lug_name, str, len)) {
3033 if (usrp->lug_expiry < NFSD_MONOSEC)
3035 hp2 = NFSGROUPHASH(usrp->lug_gid);
3036 mtx_lock(&hp2->mtx);
3037 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3038 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3040 *gidp = usrp->lug_gid;
3041 mtx_unlock(&hp2->mtx);
3042 mtx_unlock(&hp->mtx);
3047 mtx_unlock(&hp->mtx);
3049 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3051 if (ret == 0 && cnt < 2)
3054 error = NFSERR_BADOWNER;
3062 * Cmp len chars, allowing mixed case in the first argument to match lower
3063 * case in the second, but not if the first argument is all upper case.
3064 * Return 0 for a match, 1 otherwise.
3067 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3073 for (i = 0; i < len; i++) {
3074 if (*cp >= 'A' && *cp <= 'Z') {
3075 tmp = *cp++ + ('a' - 'A');
3078 if (tmp >= 'a' && tmp <= 'z')
3091 * Set the port for the nfsuserd.
3094 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
3096 struct nfssockreq *rp;
3097 struct sockaddr_in *ad;
3101 if (nfsrv_nfsuserd) {
3109 * Set up the socket record and connect.
3111 rp = &nfsrv_nfsuserdsock;
3112 rp->nr_client = NULL;
3113 rp->nr_sotype = SOCK_DGRAM;
3114 rp->nr_soproto = IPPROTO_UDP;
3115 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3117 NFSSOCKADDRALLOC(rp->nr_nam);
3118 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
3119 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
3120 ad->sin_family = AF_INET;
3121 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
3122 ad->sin_port = port;
3123 rp->nr_prog = RPCPROG_NFSUSERD;
3124 rp->nr_vers = RPCNFSUSERD_VERS;
3125 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3127 NFSSOCKADDRFREE(rp->nr_nam);
3136 * Delete the nfsuserd port.
3139 nfsrv_nfsuserddelport(void)
3143 if (nfsrv_nfsuserd == 0) {
3149 newnfs_disconnect(&nfsrv_nfsuserdsock);
3150 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
3154 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3156 * Returns 0 upon success, non-zero otherwise.
3159 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3162 struct nfsrv_descript *nd;
3164 struct nfsrv_descript nfsd;
3169 if (nfsrv_nfsuserd == 0) {
3176 cred = newnfs_getcred();
3177 nd->nd_flag = ND_GSSINITREPLY;
3180 nd->nd_procnum = procnum;
3181 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3182 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3183 if (procnum == RPCNFSUSERD_GETUID)
3184 *tl = txdr_unsigned(uid);
3186 *tl = txdr_unsigned(gid);
3189 (void) nfsm_strtom(nd, name, len);
3191 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3192 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3195 mbuf_freem(nd->nd_mrep);
3196 error = nd->nd_repstat;
3204 * This function is called from the nfssvc(2) system call, to update the
3205 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3208 nfssvc_idname(struct nfsd_idargs *nidp)
3210 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3211 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3212 int i, group_locked, groupname_locked, user_locked, username_locked;
3217 static int onethread = 0;
3218 static time_t lasttime = 0;
3220 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3224 if (nidp->nid_flag & NFSID_INITIALIZE) {
3225 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3226 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3229 free(cp, M_NFSSTRING);
3232 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3234 * Free up all the old stuff and reinitialize hash
3235 * lists. All mutexes for both lists must be locked,
3236 * with the user/group name ones before the uid/gid
3237 * ones, to avoid a LOR.
3239 for (i = 0; i < nfsrv_lughashsize; i++)
3240 mtx_lock(&nfsusernamehash[i].mtx);
3241 for (i = 0; i < nfsrv_lughashsize; i++)
3242 mtx_lock(&nfsuserhash[i].mtx);
3243 for (i = 0; i < nfsrv_lughashsize; i++)
3244 TAILQ_FOREACH_SAFE(usrp,
3245 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3246 nfsrv_removeuser(usrp, 1);
3247 for (i = 0; i < nfsrv_lughashsize; i++)
3248 mtx_unlock(&nfsuserhash[i].mtx);
3249 for (i = 0; i < nfsrv_lughashsize; i++)
3250 mtx_unlock(&nfsusernamehash[i].mtx);
3251 for (i = 0; i < nfsrv_lughashsize; i++)
3252 mtx_lock(&nfsgroupnamehash[i].mtx);
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 mtx_lock(&nfsgrouphash[i].mtx);
3255 for (i = 0; i < nfsrv_lughashsize; i++)
3256 TAILQ_FOREACH_SAFE(usrp,
3257 &nfsgrouphash[i].lughead, lug_numhash,
3259 nfsrv_removeuser(usrp, 0);
3260 for (i = 0; i < nfsrv_lughashsize; i++)
3261 mtx_unlock(&nfsgrouphash[i].mtx);
3262 for (i = 0; i < nfsrv_lughashsize; i++)
3263 mtx_unlock(&nfsgroupnamehash[i].mtx);
3264 free(nfsrv_dnsname, M_NFSSTRING);
3265 nfsrv_dnsname = NULL;
3267 if (nfsuserhash == NULL) {
3268 /* Allocate the hash tables. */
3269 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3270 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3272 for (i = 0; i < nfsrv_lughashsize; i++)
3273 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3274 NULL, MTX_DEF | MTX_DUPOK);
3275 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3276 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3278 for (i = 0; i < nfsrv_lughashsize; i++)
3279 mtx_init(&nfsusernamehash[i].mtx,
3280 "nfsusrhash", NULL, MTX_DEF |
3282 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3283 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3285 for (i = 0; i < nfsrv_lughashsize; i++)
3286 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3287 NULL, MTX_DEF | MTX_DUPOK);
3288 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3289 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3291 for (i = 0; i < nfsrv_lughashsize; i++)
3292 mtx_init(&nfsgroupnamehash[i].mtx,
3293 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3295 /* (Re)initialize the list heads. */
3296 for (i = 0; i < nfsrv_lughashsize; i++)
3297 TAILQ_INIT(&nfsuserhash[i].lughead);
3298 for (i = 0; i < nfsrv_lughashsize; i++)
3299 TAILQ_INIT(&nfsusernamehash[i].lughead);
3300 for (i = 0; i < nfsrv_lughashsize; i++)
3301 TAILQ_INIT(&nfsgrouphash[i].lughead);
3302 for (i = 0; i < nfsrv_lughashsize; i++)
3303 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3306 * Put name in "DNS" string.
3309 nfsrv_defaultuid = nidp->nid_uid;
3310 nfsrv_defaultgid = nidp->nid_gid;
3312 nfsrv_usermax = nidp->nid_usermax;
3313 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3318 * malloc the new one now, so any potential sleep occurs before
3319 * manipulation of the lists.
3321 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3322 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3323 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3325 if (error == 0 && nidp->nid_ngroup > 0 &&
3326 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3327 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3329 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3330 sizeof(gid_t) * nidp->nid_ngroup);
3333 * Create a credential just like svc_getcred(),
3334 * but using the group list provided.
3337 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3338 crsetgroups(cr, nidp->nid_ngroup, grps);
3339 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3340 cr->cr_prison = &prison0;
3341 prison_hold(cr->cr_prison);
3343 mac_cred_associate_nfsd(cr);
3345 newusrp->lug_cred = cr;
3350 free(newusrp, M_NFSUSERGROUP);
3353 newusrp->lug_namelen = nidp->nid_namelen;
3356 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3357 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3358 * The flags user_locked, username_locked, group_locked and
3359 * groupname_locked are set to indicate all of those hash lists are
3360 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3361 * the respective one mutex is locked.
3363 user_locked = username_locked = group_locked = groupname_locked = 0;
3364 hp_name = hp_idnum = NULL;
3367 * Delete old entries, as required.
3369 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3370 /* Must lock all username hash lists first, to avoid a LOR. */
3371 for (i = 0; i < nfsrv_lughashsize; i++)
3372 mtx_lock(&nfsusernamehash[i].mtx);
3373 username_locked = 1;
3374 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3375 mtx_lock(&hp_idnum->mtx);
3376 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3378 if (usrp->lug_uid == nidp->nid_uid)
3379 nfsrv_removeuser(usrp, 1);
3381 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3382 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3383 newusrp->lug_namelen);
3384 mtx_lock(&hp_name->mtx);
3385 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3387 if (usrp->lug_namelen == newusrp->lug_namelen &&
3388 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3389 usrp->lug_namelen)) {
3390 thp = NFSUSERHASH(usrp->lug_uid);
3391 mtx_lock(&thp->mtx);
3392 nfsrv_removeuser(usrp, 1);
3393 mtx_unlock(&thp->mtx);
3396 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3397 mtx_lock(&hp_idnum->mtx);
3398 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3399 /* Must lock all groupname hash lists first, to avoid a LOR. */
3400 for (i = 0; i < nfsrv_lughashsize; i++)
3401 mtx_lock(&nfsgroupnamehash[i].mtx);
3402 groupname_locked = 1;
3403 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3404 mtx_lock(&hp_idnum->mtx);
3405 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3407 if (usrp->lug_gid == nidp->nid_gid)
3408 nfsrv_removeuser(usrp, 0);
3410 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3411 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3412 newusrp->lug_namelen);
3413 mtx_lock(&hp_name->mtx);
3414 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3416 if (usrp->lug_namelen == newusrp->lug_namelen &&
3417 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3418 usrp->lug_namelen)) {
3419 thp = NFSGROUPHASH(usrp->lug_gid);
3420 mtx_lock(&thp->mtx);
3421 nfsrv_removeuser(usrp, 0);
3422 mtx_unlock(&thp->mtx);
3425 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3426 mtx_lock(&hp_idnum->mtx);
3430 * Now, we can add the new one.
3432 if (nidp->nid_usertimeout)
3433 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3435 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3436 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3437 newusrp->lug_uid = nidp->nid_uid;
3438 thp = NFSUSERHASH(newusrp->lug_uid);
3439 mtx_assert(&thp->mtx, MA_OWNED);
3440 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3441 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3442 mtx_assert(&thp->mtx, MA_OWNED);
3443 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3444 atomic_add_int(&nfsrv_usercnt, 1);
3445 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3446 newusrp->lug_gid = nidp->nid_gid;
3447 thp = NFSGROUPHASH(newusrp->lug_gid);
3448 mtx_assert(&thp->mtx, MA_OWNED);
3449 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3450 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3451 mtx_assert(&thp->mtx, MA_OWNED);
3452 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3453 atomic_add_int(&nfsrv_usercnt, 1);
3455 if (newusrp->lug_cred != NULL)
3456 crfree(newusrp->lug_cred);
3457 free(newusrp, M_NFSUSERGROUP);
3461 * Once per second, allow one thread to trim the cache.
3463 if (lasttime < NFSD_MONOSEC &&
3464 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3466 * First, unlock the single mutexes, so that all entries
3467 * can be locked and any LOR is avoided.
3469 if (hp_name != NULL) {
3470 mtx_unlock(&hp_name->mtx);
3473 if (hp_idnum != NULL) {
3474 mtx_unlock(&hp_idnum->mtx);
3478 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3479 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3480 if (username_locked == 0) {
3481 for (i = 0; i < nfsrv_lughashsize; i++)
3482 mtx_lock(&nfsusernamehash[i].mtx);
3483 username_locked = 1;
3485 KASSERT(user_locked == 0,
3486 ("nfssvc_idname: user_locked"));
3487 for (i = 0; i < nfsrv_lughashsize; i++)
3488 mtx_lock(&nfsuserhash[i].mtx);
3490 for (i = 0; i < nfsrv_lughashsize; i++) {
3491 TAILQ_FOREACH_SAFE(usrp,
3492 &nfsuserhash[i].lughead, lug_numhash,
3494 if (usrp->lug_expiry < NFSD_MONOSEC)
3495 nfsrv_removeuser(usrp, 1);
3497 for (i = 0; i < nfsrv_lughashsize; i++) {
3499 * Trim the cache using an approximate LRU
3500 * algorithm. This code deletes the least
3501 * recently used entry on each hash list.
3503 if (nfsrv_usercnt <= nfsrv_usermax)
3505 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3507 nfsrv_removeuser(usrp, 1);
3510 if (groupname_locked == 0) {
3511 for (i = 0; i < nfsrv_lughashsize; i++)
3512 mtx_lock(&nfsgroupnamehash[i].mtx);
3513 groupname_locked = 1;
3515 KASSERT(group_locked == 0,
3516 ("nfssvc_idname: group_locked"));
3517 for (i = 0; i < nfsrv_lughashsize; i++)
3518 mtx_lock(&nfsgrouphash[i].mtx);
3520 for (i = 0; i < nfsrv_lughashsize; i++) {
3521 TAILQ_FOREACH_SAFE(usrp,
3522 &nfsgrouphash[i].lughead, lug_numhash,
3524 if (usrp->lug_expiry < NFSD_MONOSEC)
3525 nfsrv_removeuser(usrp, 0);
3527 for (i = 0; i < nfsrv_lughashsize; i++) {
3529 * Trim the cache using an approximate LRU
3530 * algorithm. This code deletes the least
3531 * recently user entry on each hash list.
3533 if (nfsrv_usercnt <= nfsrv_usermax)
3535 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3537 nfsrv_removeuser(usrp, 0);
3540 lasttime = NFSD_MONOSEC;
3541 atomic_store_rel_int(&onethread, 0);
3544 /* Now, unlock all locked mutexes. */
3545 if (hp_idnum != NULL)
3546 mtx_unlock(&hp_idnum->mtx);
3547 if (hp_name != NULL)
3548 mtx_unlock(&hp_name->mtx);
3549 if (user_locked != 0)
3550 for (i = 0; i < nfsrv_lughashsize; i++)
3551 mtx_unlock(&nfsuserhash[i].mtx);
3552 if (username_locked != 0)
3553 for (i = 0; i < nfsrv_lughashsize; i++)
3554 mtx_unlock(&nfsusernamehash[i].mtx);
3555 if (group_locked != 0)
3556 for (i = 0; i < nfsrv_lughashsize; i++)
3557 mtx_unlock(&nfsgrouphash[i].mtx);
3558 if (groupname_locked != 0)
3559 for (i = 0; i < nfsrv_lughashsize; i++)
3560 mtx_unlock(&nfsgroupnamehash[i].mtx);
3567 * Remove a user/group name element.
3570 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3572 struct nfsrv_lughash *hp;
3575 hp = NFSUSERHASH(usrp->lug_uid);
3576 mtx_assert(&hp->mtx, MA_OWNED);
3577 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3578 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3579 mtx_assert(&hp->mtx, MA_OWNED);
3580 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3582 hp = NFSGROUPHASH(usrp->lug_gid);
3583 mtx_assert(&hp->mtx, MA_OWNED);
3584 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3585 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3586 mtx_assert(&hp->mtx, MA_OWNED);
3587 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3589 atomic_add_int(&nfsrv_usercnt, -1);
3590 if (usrp->lug_cred != NULL)
3591 crfree(usrp->lug_cred);
3592 free(usrp, M_NFSUSERGROUP);
3596 * Free up all the allocations related to the name<-->id cache.
3597 * This function should only be called when the nfsuserd daemon isn't
3598 * running, since it doesn't do any locking.
3599 * This function is meant to be used when the nfscommon module is unloaded.
3602 nfsrv_cleanusergroup(void)
3604 struct nfsrv_lughash *hp, *hp2;
3605 struct nfsusrgrp *nusrp, *usrp;
3608 if (nfsuserhash == NULL)
3611 for (i = 0; i < nfsrv_lughashsize; i++) {
3612 hp = &nfsuserhash[i];
3613 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3614 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3615 hp2 = NFSUSERNAMEHASH(usrp->lug_name,
3617 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3618 if (usrp->lug_cred != NULL)
3619 crfree(usrp->lug_cred);
3620 free(usrp, M_NFSUSERGROUP);
3622 hp = &nfsgrouphash[i];
3623 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
3624 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3625 hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
3627 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
3628 if (usrp->lug_cred != NULL)
3629 crfree(usrp->lug_cred);
3630 free(usrp, M_NFSUSERGROUP);
3632 mtx_destroy(&nfsuserhash[i].mtx);
3633 mtx_destroy(&nfsusernamehash[i].mtx);
3634 mtx_destroy(&nfsgroupnamehash[i].mtx);
3635 mtx_destroy(&nfsgrouphash[i].mtx);
3637 free(nfsuserhash, M_NFSUSERGROUP);
3638 free(nfsusernamehash, M_NFSUSERGROUP);
3639 free(nfsgrouphash, M_NFSUSERGROUP);
3640 free(nfsgroupnamehash, M_NFSUSERGROUP);
3641 free(nfsrv_dnsname, M_NFSSTRING);
3645 * This function scans a byte string and checks for UTF-8 compliance.
3646 * It returns 0 if it conforms and NFSERR_INVAL if not.
3649 nfsrv_checkutf8(u_int8_t *cp, int len)
3651 u_int32_t val = 0x0;
3652 int cnt = 0, gotd = 0, shift = 0;
3654 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3658 * Here are what the variables are used for:
3659 * val - the calculated value of a multibyte char, used to check
3660 * that it was coded with the correct range
3661 * cnt - the number of 10xxxxxx bytes to follow
3662 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3663 * shift - lower order bits of range (ie. "val >> shift" should
3664 * not be 0, in other words, dividing by the lower bound
3665 * of the range should get a non-zero value)
3666 * byte - used to calculate cnt
3670 /* This handles the 10xxxxxx bytes */
3671 if ((*cp & 0xc0) != 0x80 ||
3672 (gotd && (*cp & 0x20))) {
3673 error = NFSERR_INVAL;
3678 val |= (*cp & 0x3f);
3680 if (cnt == 0 && (val >> shift) == 0x0) {
3681 error = NFSERR_INVAL;
3684 } else if (*cp & 0x80) {
3685 /* first byte of multi byte char */
3687 while ((byte & 0x40) && cnt < 6) {
3691 if (cnt == 0 || cnt == 6) {
3692 error = NFSERR_INVAL;
3695 val = (*cp & (0x3f >> cnt));
3696 shift = utf8_shift[cnt - 1];
3697 if (cnt == 2 && val == 0xd)
3698 /* Check for the 0xd800-0xdfff case */
3705 error = NFSERR_INVAL;
3713 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3714 * strings, one with the root path in it and the other with the list of
3715 * locations. The list is in the same format as is found in nfr_refs.
3716 * It is a "," separated list of entries, where each of them is of the
3717 * form <server>:<rootpath>. For example
3718 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3719 * The nilp argument is set to 1 for the special case of a null fs_root
3720 * and an empty server list.
3721 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3722 * number of xdr bytes parsed in sump.
3725 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3726 int *sump, int *nilp)
3729 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3730 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3732 SLIST_ENTRY(list) next;
3736 SLIST_HEAD(, list) head;
3743 * Get the fs_root path and check for the special case of null path
3744 * and 0 length server list.
3746 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3747 len = fxdr_unsigned(int, *tl);
3748 if (len < 0 || len > 10240) {
3749 error = NFSERR_BADXDR;
3753 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3755 error = NFSERR_BADXDR;
3759 *sump = 2 * NFSX_UNSIGNED;
3763 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3764 error = nfsrv_mtostr(nd, cp, len);
3766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3767 cnt = fxdr_unsigned(int, *tl);
3769 error = NFSERR_BADXDR;
3775 * Now, loop through the location list and make up the srvlist.
3777 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3778 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3781 for (i = 0; i < cnt; i++) {
3783 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3784 nsrv = fxdr_unsigned(int, *tl);
3786 error = NFSERR_BADXDR;
3791 * Handle the first server by putting it in the srvstr.
3793 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3794 len = fxdr_unsigned(int, *tl);
3795 if (len <= 0 || len > 1024) {
3796 error = NFSERR_BADXDR;
3799 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3804 error = nfsrv_mtostr(nd, cp3, len);
3810 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3811 for (j = 1; j < nsrv; j++) {
3813 * Yuck, put them in an slist and process them later.
3815 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3816 len = fxdr_unsigned(int, *tl);
3817 if (len <= 0 || len > 1024) {
3818 error = NFSERR_BADXDR;
3821 lsp = (struct list *)malloc(sizeof (struct list)
3822 + len, M_TEMP, M_WAITOK);
3823 error = nfsrv_mtostr(nd, lsp->host, len);
3826 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3828 SLIST_INSERT_HEAD(&head, lsp, next);
3832 * Finally, we can get the path.
3834 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3835 len = fxdr_unsigned(int, *tl);
3836 if (len <= 0 || len > 1024) {
3837 error = NFSERR_BADXDR;
3840 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3841 error = nfsrv_mtostr(nd, cp3, len);
3844 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3849 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3850 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3853 NFSBCOPY(lsp->host, cp3, lsp->len);
3856 NFSBCOPY(str, cp3, stringlen);
3859 siz += (lsp->len + stringlen + 2);
3860 free((caddr_t)lsp, M_TEMP);
3866 NFSEXITCODE2(0, nd);
3870 free(cp, M_NFSSTRING);
3872 free(cp2, M_NFSSTRING);
3873 NFSEXITCODE2(error, nd);
3878 * Make the malloc'd space large enough. This is a pain, but the xdr
3879 * doesn't set an upper bound on the side, so...
3882 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3889 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3890 NFSBCOPY(*cpp, cp, *slenp);
3891 free(*cpp, M_NFSSTRING);
3895 *slenp = siz + 1024;
3899 * Initialize the reply header data structures.
3902 nfsrvd_rephead(struct nfsrv_descript *nd)
3907 * If this is a big reply, use a cluster.
3909 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3910 nfs_bigreply[nd->nd_procnum]) {
3911 NFSMCLGET(mreq, M_WAITOK);
3919 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3920 mbuf_setlen(mreq, 0);
3922 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3923 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3927 * Lock a socket against others.
3928 * Currently used to serialize connect/disconnect attempts.
3931 newnfs_sndlock(int *flagp)
3936 while (*flagp & NFSR_SNDLOCK) {
3937 *flagp |= NFSR_WANTSND;
3940 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3941 PZERO - 1, "nfsndlck", &ts);
3943 *flagp |= NFSR_SNDLOCK;
3949 * Unlock the stream socket for others.
3952 newnfs_sndunlock(int *flagp)
3956 if ((*flagp & NFSR_SNDLOCK) == 0)
3957 panic("nfs sndunlock");
3958 *flagp &= ~NFSR_SNDLOCK;
3959 if (*flagp & NFSR_WANTSND) {
3960 *flagp &= ~NFSR_WANTSND;
3961 wakeup((caddr_t)flagp);
3967 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3970 struct sockaddr_in *sad;
3971 struct sockaddr_in6 *sad6;
3972 struct in_addr saddr;
3973 uint32_t portnum, *tl;
3974 int af = 0, i, j, k;
3975 char addr[64], protocol[5], *cp;
3976 int cantparse = 0, error = 0;
3979 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3980 i = fxdr_unsigned(int, *tl);
3981 if (i >= 3 && i <= 4) {
3982 error = nfsrv_mtostr(nd, protocol, i);
3985 if (strcmp(protocol, "tcp") == 0) {
3988 } else if (strcmp(protocol, "udp") == 0) {
3991 } else if (strcmp(protocol, "tcp6") == 0) {
3994 } else if (strcmp(protocol, "udp6") == 0) {
4002 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4007 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4008 i = fxdr_unsigned(int, *tl);
4010 error = NFSERR_BADXDR;
4012 } else if (cantparse == 0 && i >= 11 && i < 64) {
4014 * The shortest address is 11chars and the longest is < 64.
4016 error = nfsrv_mtostr(nd, addr, i);
4020 /* Find the port# at the end and extract that. */
4024 /* Count back two '.'s from end to get port# field. */
4025 for (j = 0; j < i; j++) {
4035 * The NFSv4 port# is appended as .N.N, where N is
4036 * a decimal # in the range 0-255, just like an inet4
4037 * address. Cheat and use inet_aton(), which will
4038 * return a Class A address and then shift the high
4039 * order 8bits over to convert it to the port#.
4042 if (inet_aton(cp, &saddr) == 1) {
4043 portnum = ntohl(saddr.s_addr);
4044 portv = (uint16_t)((portnum >> 16) |
4050 if (cantparse == 0) {
4051 if (af == AF_INET) {
4052 sad = (struct sockaddr_in *)sa;
4053 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
4054 sad->sin_len = sizeof(*sad);
4055 sad->sin_family = AF_INET;
4056 sad->sin_port = htons(portv);
4060 sad6 = (struct sockaddr_in6 *)sa;
4061 if (inet_pton(af, addr, &sad6->sin6_addr)
4063 sad6->sin6_len = sizeof(*sad6);
4064 sad6->sin6_family = AF_INET6;
4065 sad6->sin6_port = htons(portv);
4072 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4083 * Handle an NFSv4.1 Sequence request for the session.
4084 * If reply != NULL, use it to return the cached reply, as required.
4085 * The client gets a cached reply via this call for callbacks, however the
4086 * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4089 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4090 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4097 if (slotid > maxslot)
4098 return (NFSERR_BADSLOT);
4099 if (seqid == slots[slotid].nfssl_seq) {
4101 if (slots[slotid].nfssl_inprog != 0)
4102 error = NFSERR_DELAY;
4103 else if (slots[slotid].nfssl_reply != NULL) {
4104 if (reply != NULL) {
4105 *reply = slots[slotid].nfssl_reply;
4106 slots[slotid].nfssl_reply = NULL;
4108 slots[slotid].nfssl_inprog = 1;
4109 error = NFSERR_REPLYFROMCACHE;
4111 /* No reply cached, so just do it. */
4112 slots[slotid].nfssl_inprog = 1;
4113 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4114 if (slots[slotid].nfssl_reply != NULL)
4115 m_freem(slots[slotid].nfssl_reply);
4116 slots[slotid].nfssl_reply = NULL;
4117 slots[slotid].nfssl_inprog = 1;
4118 slots[slotid].nfssl_seq++;
4120 error = NFSERR_SEQMISORDERED;
4125 * Cache this reply for the slot.
4126 * Use the "rep" argument to return the cached reply if repstat is set to
4127 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4130 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4134 if (repstat == NFSERR_REPLYFROMCACHE) {
4135 *rep = slots[slotid].nfssl_reply;
4136 slots[slotid].nfssl_reply = NULL;
4138 if (slots[slotid].nfssl_reply != NULL)
4139 m_freem(slots[slotid].nfssl_reply);
4140 slots[slotid].nfssl_reply = *rep;
4142 slots[slotid].nfssl_inprog = 0;
4146 * Generate the xdr for an NFSv4.1 Sequence Operation.
4149 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4150 struct nfsclsession *sep, int dont_replycache)
4152 uint32_t *tl, slotseq = 0;
4153 int error, maxslot, slotpos;
4154 uint8_t sessionid[NFSX_V4SESSIONID];
4156 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4159 /* Build the Sequence arguments. */
4160 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4161 nd->nd_sequence = tl;
4162 bcopy(sessionid, tl, NFSX_V4SESSIONID);
4163 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4164 nd->nd_slotseq = tl;
4166 *tl++ = txdr_unsigned(slotseq);
4167 *tl++ = txdr_unsigned(slotpos);
4168 *tl++ = txdr_unsigned(maxslot);
4169 if (dont_replycache == 0)
4175 * There are two errors and the rest of the session can
4177 * NFSERR_BADSESSION: This bad session should just generate
4178 * the same error again when the RPC is retried.
4179 * ESTALE: A forced dismount is in progress and will cause the
4180 * RPC to fail later.
4187 nd->nd_flag |= ND_HASSEQUENCE;
4191 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4192 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4194 int i, maxslot, slotpos;
4197 /* Find an unused slot. */
4200 mtx_lock(&sep->nfsess_mtx);
4202 if (nmp != NULL && sep->nfsess_defunct != 0) {
4203 /* Just return the bad session. */
4204 bcopy(sep->nfsess_sessionid, sessionid,
4206 mtx_unlock(&sep->nfsess_mtx);
4207 return (NFSERR_BADSESSION);
4210 for (i = 0; i < sep->nfsess_foreslots; i++) {
4211 if ((bitval & sep->nfsess_slots) == 0) {
4213 sep->nfsess_slots |= bitval;
4214 sep->nfsess_slotseq[i]++;
4215 *slotseqp = sep->nfsess_slotseq[i];
4220 if (slotpos == -1) {
4222 * If a forced dismount is in progress, just return.
4223 * This RPC attempt will fail when it calls
4226 if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4227 mtx_unlock(&sep->nfsess_mtx);
4230 /* Wake up once/sec, to check for a forced dismount. */
4231 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4232 PZERO, "nfsclseq", hz);
4234 } while (slotpos == -1);
4235 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4237 for (i = 0; i < 64; i++) {
4238 if ((bitval & sep->nfsess_slots) != 0)
4242 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4243 mtx_unlock(&sep->nfsess_mtx);
4244 *slotposp = slotpos;
4245 *maxslotp = maxslot;
4250 * Free a session slot.
4253 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4260 mtx_lock(&sep->nfsess_mtx);
4261 if ((bitval & sep->nfsess_slots) == 0)
4262 printf("freeing free slot!!\n");
4263 sep->nfsess_slots &= ~bitval;
4264 wakeup(&sep->nfsess_slots);
4265 mtx_unlock(&sep->nfsess_mtx);